MODULESetup might be called more than once during the run! (KMP); IMPORT Filter, StringSearchViewClass, View, ZeusPanel, ColorName, PaintOp, Grid, Text, MG, MGV, Font, ScaleFilter, VBT, ViewsBase, Thread; CONST MaxPatLen = 12; (* 16 chars *) RestartPos = 4; EndLimit = 4; SlideLen = 8; (* must be > RestartPos *) EllipsisLen = 3; Decoration = 2 * EllipsisLen; MovieLen = RestartPos + MaxPatLen + SlideLen + EndLimit + Decoration; RectSize = 20.0; VAR SliderFont := Font.FromName( ARRAY OF TEXT{"-*-courier-bold-r-*-*-*-180-*-*-*-*-*-*"}); TYPE T = StringSearchViewClass.T OBJECT grid : Grid.V; pat, str : TEXT; startStr : INTEGER; (* First char from str in grid *) posPat : INTEGER; (* Position of pattern in grid *) lasti, lastj : CARDINAL; (* Last probe values *) m : CARDINAL; (* Length of pattern *) lMi, lMj, lMlen: CARDINAL; (* last match i, j, length *) endLimit : CARDINAL := EndLimit; jumpSkip : BOOLEAN := FALSE; (* a is used to remember complete matches during sliding. Not needed if we go for RestartPos=0. The lenght of a is Length(str)+MovieLen, to allow for space after the last redisplay of text. *) a: REF ARRAY OF PaintOp.ColorScheme; OVERRIDES oeSetup := Setup; oeProbe := Probe; oeResult := Result; oePartialMatch := PartialMatch; oePartialMatchClear := PartialMatchClear; oeCompleteMatch := CompleteMatch; oeSlideTo := SlideTo; END; TopT = T OBJECT OVERRIDES oeSetup := TopSetup; oeSlideTo := TopSlideTo; END; OverViewT = T OBJECT OVERRIDES oeSetup := OverViewSetup; oeKMPSetup := KMPSetup; END; PROCEDURE SliderView Color (color: TEXT): PaintOp.T = <* FATAL ColorName.NotFound *> VAR rgb := ColorName.ToRGB(color); BEGIN RETURN PaintOp.FromRGB(rgb.r, rgb.g, rgb.b); END Color; VAR (* Color options; actually constants *) TrueCS := PaintOp.MakeColorScheme( fg := PaintOp.Fg, bg := Color(ViewsBase.TrueC)); FalseCS := PaintOp.MakeColorScheme(fg := PaintOp.Fg, bg := Color(ViewsBase.FalseC)); PartialCS := PaintOp.MakeColorScheme( fg := PaintOp.Fg, bg := Color(ViewsBase.PartialC)); CompleteCS := PaintOp.MakeColorScheme( fg := PaintOp.Fg, bg := Color(ViewsBase.CompleteC)); ProbeCS := PaintOp.MakeColorScheme( fg := PaintOp.Bg, bg := PaintOp.Fg); ClearCS := PaintOp.bgFg;
PROCEDURESetup (self: T; p, s: TEXT) RAISES {Thread.Alerted} = VAR m := Text.Length(p); n := Text.Length(s); BEGIN self.pat := p; self.str := s; IF m > MaxPatLen THEN ZeusPanel.ReportError("Pattern too long for Slider View"); RETURN; ELSE self.m := m; END; self.a := NEW(REF ARRAY OF PaintOp.ColorScheme, n + MovieLen); FOR j := 0 TO n + MovieLen - 1 DO self.a[j] := ClearCS END; LOCK self.grid.mu DO FOR j := EllipsisLen TO MovieLen - 1 - EllipsisLen DO self.grid.a[0, j].setColor(self.grid, ClearCS); self.grid.a[0, j].setLabel( self.grid, Text.Sub(self.str, j - EllipsisLen, 1)); self.grid.a[1, j].setVisible(self.grid, 0.0); END; (* start left-justified *) FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setColor(self.grid, ClearCS); self.grid.a[0, j].setVisible(self.grid, 1.0); self.grid.a[1, j].setVisible(self.grid, 0.0); END; (* but maybe not right-justified *) FOR j := MovieLen - EllipsisLen TO MovieLen - 1 DO self.grid.a[0, j].setColor(self.grid, ClearCS); self.grid.a[0, j].setVisible(self.grid, 1.0); IF MovieLen - 1 - EllipsisLen < n THEN self.grid.a[0, j].setLabel(self.grid, "."); END; self.grid.a[1, j].setVisible(self.grid, 0.0); END; FOR j := EllipsisLen TO m - 1 + EllipsisLen DO self.grid.a[1, j].setColor(self.grid, ClearCS); self.grid.a[1, j].setLabel( self.grid, Text.Sub(self.pat, j - EllipsisLen, 1)); self.grid.a[1, j].setVisible(self.grid, 1.0); END; self.posPat := 0; self.startStr := 0; self.lasti := 0; self.lastj := 0; self.lMi := 0; self.lMj := 0; self.lMlen := 0; END; MGV.Animation(self.grid); END Setup; PROCEDURETopSetup (self: T; p, s: TEXT) RAISES {Thread.Alerted} = VAR m := Text.Length(p); n := Text.Length(s); BEGIN self.pat := p; self.str := s; IF m > MaxPatLen THEN ZeusPanel.ReportError("Pattern too long for Slider View"); RETURN; ELSE self.m := m; END; self.a := NEW(REF ARRAY OF PaintOp.ColorScheme, n + MovieLen); FOR j := 0 TO n + MovieLen - 1 DO self.a[j] := ClearCS END; self.posPat := (MovieLen - m) DIV 2; self.startStr := -self.posPat; LOCK self.grid.mu DO FOR j := EllipsisLen TO MovieLen - 1 - EllipsisLen DO self.grid.a[0, j].setColor(self.grid, ClearCS); IF j >= self.posPat + EllipsisLen THEN self.grid.a[0, j].setLabel( self.grid, Text.Sub(self.str, j - self.posPat - EllipsisLen, 1)); ELSE self.grid.a[0, j].setLabel(self.grid, ""); END; self.grid.a[1, j].setVisible(self.grid, 0.0); END; (* start left-justified *) FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setColor(self.grid, ClearCS); self.grid.a[0, j].setVisible(self.grid, 1.0); self.grid.a[1, j].setVisible(self.grid, 0.0); END; (* but maybe not right-justified *) FOR j := MovieLen - EllipsisLen TO MovieLen - 1 DO self.grid.a[0, j].setColor(self.grid, ClearCS); self.grid.a[0, j].setVisible(self.grid, 1.0); IF self.startStr + MovieLen - Decoration < n THEN self.grid.a[0, j].setLabel(self.grid, "."); END; self.grid.a[1, j].setVisible(self.grid, 0.0); END; FOR j := EllipsisLen TO m - 1 + EllipsisLen DO self.grid.a[1, self.posPat + j].setColor(self.grid, ClearCS); self.grid.a[1, self.posPat + j].setLabel( self.grid, Text.Sub(self.pat, j - EllipsisLen, 1)); self.grid.a[1, self.posPat + j].setVisible(self.grid, 1.0); END; self.lasti := 0; self.lastj := 0; self.lMi := 0; self.lMj := 0; self.lMlen := 0; END; MGV.Animation(self.grid); END TopSetup; PROCEDUREOverViewSetup (self: T; p, s: TEXT) RAISES {Thread.Alerted} = VAR m := Text.Length(p); n := Text.Length(s); size := n + m + 1 + Decoration; g := NEW(Grid.V, doubleBuffer := FALSE).init( 2, size, RectSize, RectSize); BEGIN self.pat := p; self.str := s; IF m > MaxPatLen THEN ZeusPanel.ReportError("Pattern too long for Slider View"); RETURN; ELSE self.m := m; END; LOCK VBT.mu DO WITH scale = NEW(ScaleFilter.T).init(g) DO ScaleFilter.AutoScale(scale); EVAL Filter.Replace(self, scale); END; END; self.grid := g; self.a := NEW(REF ARRAY OF PaintOp.ColorScheme, 2 * n); FOR j := FIRST(self.a^) TO LAST(self.a^) DO self.a[j] := ClearCS END; LOCK self.grid.mu DO FOR j := FIRST(self.grid.a[0]) + EllipsisLen TO LAST(self.grid.a[0]) - EllipsisLen DO self.grid.a[0, j].setFont(self.grid, SliderFont); self.grid.a[0, j].setColor(self.grid, ClearCS); self.grid.a[0, j].setLabel( self.grid, Text.Sub(self.str, j - EllipsisLen, 1)); self.grid.a[1, j].setFont(self.grid, SliderFont); self.grid.a[1, j].setVisible(self.grid, 0.0); END; FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setVisible(self.grid, 0.0); self.grid.a[1, j].setVisible(self.grid, 0.0); END; FOR j := LAST(self.grid.a[0]) - EllipsisLen TO LAST(self.grid.a[0]) DO self.grid.a[0, j].setVisible(self.grid, 0.0); self.grid.a[1, j].setVisible(self.grid, 0.0); END; FOR j := EllipsisLen TO m - 1 + EllipsisLen DO self.grid.a[1, j].setColor(self.grid, ClearCS); self.grid.a[1, j].setLabel( self.grid, Text.Sub(self.pat, j - EllipsisLen, 1)); self.grid.a[1, j].setVisible(self.grid, 1.0); END; self.endLimit := 0; self.posPat := 0; self.startStr := 0; self.lasti := 0; self.lastj := 0; self.lMi := 0; self.lMj := 0; self.lMlen := 0; self.jumpSkip := TRUE; END; MGV.Animation(self.grid); END OverViewSetup; PROCEDUREKMPSetup (self: T; p: TEXT) RAISES {Thread.Alerted} = BEGIN OverViewSetup(self, p, p); END KMPSetup; PROCEDUREProbe (self: T; i, j: CARDINAL) RAISES {Thread.Alerted} = BEGIN LOCK self.grid.mu DO self.grid.a[0, j - self.startStr + EllipsisLen].setColor( self.grid, ProbeCS); self.grid.a[1, i + self.posPat + EllipsisLen].setColor( self.grid, ProbeCS); self.lasti := i; self.lastj := j; END; MGV.Animation(self.grid); END Probe; PROCEDUREResult (self: T; r: BOOLEAN) RAISES {Thread.Alerted} = BEGIN LOCK self.grid.mu DO IF r THEN self.grid.a[0, self.lastj - self.startStr + EllipsisLen].setColor( self.grid, TrueCS); self.grid.a[1, self.lasti + self.posPat + EllipsisLen].setColor( self.grid, TrueCS); ELSE self.grid.a[0, self.lastj - self.startStr + EllipsisLen].setColor( self.grid, FalseCS); self.grid.a[1, self.lasti + self.posPat + EllipsisLen].setColor( self.grid, FalseCS); END; END; MGV.Animation(self.grid); END Result; PROCEDUREPartialMatch (self: T; i, j, len: CARDINAL) RAISES {Thread.Alerted} = BEGIN self.lMi := i; self.lMj := j; self.lMlen := len; LOCK self.grid.mu DO self.grid.a[0, self.lastj - self.startStr + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.lasti + self.posPat + EllipsisLen].setColor( self.grid, ClearCS); FOR k := 0 TO len - 1 DO self.grid.a[0, j - self.startStr + k + EllipsisLen].setColor( self.grid, PartialCS); self.grid.a[1, i + self.posPat + k + EllipsisLen].setColor( self.grid, PartialCS); END; END; MGV.Animation(self.grid); END PartialMatch; PROCEDUREPartialMatchClear (self: T) RAISES {Thread.Alerted} = BEGIN LOCK self.grid.mu DO self.grid.a[0, self.lastj - self.startStr + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.lasti + self.posPat + EllipsisLen].setColor( self.grid, ClearCS); FOR k := 0 TO self.lMlen - 1 DO self.grid.a[0, self.lMj - self.startStr + k + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.lMi + self.posPat + k + EllipsisLen].setColor( self.grid, ClearCS); END; self.lMlen := 0; END; MGV.Animation(self.grid); END PartialMatchClear; PROCEDURECompleteMatch (self: T; j: CARDINAL) RAISES {Thread.Alerted} = BEGIN LOCK self.grid.mu DO (* Clear the old probe *) self.grid.a[0, self.lastj - self.startStr + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.lasti + self.posPat + EllipsisLen].setColor( self.grid, ClearCS); (* Clear the old match *) FOR k := 0 TO self.lMlen - 1 DO self.grid.a[0, self.lMj - self.startStr + k + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.lMi + self.posPat + k + EllipsisLen].setColor( self.grid, ClearCS); END; self.lMlen := 0; (* Set the complete match mark *) self.grid.a[0, j - self.startStr + EllipsisLen].setColor(self.grid, CompleteCS); self.a[j] := CompleteCS; END; MGV.Animation(self.grid); END CompleteMatch; PROCEDURETopSlideTo (self: T; newPos: CARDINAL) RAISES {Thread.Alerted} = VAR skip := newPos - self.startStr - self.posPat; duration: REAL; BEGIN IF skip = 0 THEN RETURN END; duration := 1.0 / FLOAT(skip); (* Clean old pattern *) IF skip > 0 THEN FOR i := 0 TO skip - 1 DO (* Redraw text *) INC(self.startStr); LOCK self.grid.mu DO FOR j := EllipsisLen TO MovieLen - 1 - EllipsisLen DO IF self.startStr - EllipsisLen + j >= 0 THEN self.grid.a[0, j].setLabel( self.grid, Text.Sub(self.str, self.startStr - EllipsisLen + j, 1)); self.grid.a[0, j].setColor( self.grid, self.a[self.startStr - EllipsisLen + j]); ELSE self.grid.a[0, j].setLabel(self.grid, ""); self.grid.a[0, j].setColor(self.grid, ClearCS); END; END; IF self.startStr > 0 THEN FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setLabel(self.grid, "."); END; ELSE FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setLabel(self.grid, ""); END; END; IF self.startStr + MovieLen - Decoration < Text.Length(self.str) THEN FOR j := MovieLen - EllipsisLen TO MovieLen - 1 DO self.grid.a[0, j].setLabel(self.grid, "."); END; ELSE FOR j := MovieLen - EllipsisLen TO MovieLen - 1 DO self.grid.a[0, j].setLabel(self.grid, ""); END; END; END; MGV.Animation(self.grid, duration); END; ELSE ZeusPanel.ReportError("Trying to slide backwards"); END; END TopSlideTo; PROCEDURESlideTo (self: T; newPos: CARDINAL) RAISES {Thread.Alerted} = VAR skip := newPos - self.startStr - self.posPat; duration: REAL; BEGIN IF skip = 0 THEN RETURN END; duration := 0.5 / FLOAT(skip); IF skip > 0 THEN IF self.posPat + self.m + skip > NUMBER(self.grid.a[0]) - self.endLimit - EllipsisLen THEN IF self.jumpSkip THEN Slide(self, 1.0, skip); ELSE FOR i := 0 TO skip - 1 DO Slide(self, duration, 1); END; END; END; IF self.startStr > 0 THEN FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setLabel(self.grid, "."); END; ELSE FOR j := 0 TO EllipsisLen - 1 DO self.grid.a[0, j].setLabel(self.grid, ""); END; END; IF self.startStr + NUMBER(self.grid.a[0]) - Decoration < Text.Length(self.str) THEN FOR j := NUMBER(self.grid.a[0]) - EllipsisLen TO LAST(self.grid.a[0]) DO self.grid.a[0, j].setLabel(self.grid, "."); END; ELSE FOR j := NUMBER(self.grid.a[0]) - EllipsisLen TO LAST(self.grid.a[0]) DO self.grid.a[0, j].setLabel(self.grid, ""); END; END; (* Move Pattern *) FOR i := 0 TO skip - 1 DO LOCK self.grid.mu DO self.grid.a[1, self.posPat + EllipsisLen].setVisible( self.grid, 0.0); INC(self.posPat); (* Now redraw pattern *) FOR j := MAX(0, -self.posPat) TO self.m - 1 DO self.grid.a[1, self.posPat + j + EllipsisLen].setVisible( self.grid, 1.0); self.grid.a[1, self.posPat + j + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.posPat + j + EllipsisLen].setLabel( self.grid, Text.Sub(self.pat, j, 1)); END; END; MGV.Animation(self.grid, duration); END; ELSE ZeusPanel.ReportError("Trying to slide backwards"); END; END SlideTo; PROCEDURESlide (self: T; duration: REAL; howMany: INTEGER) RAISES {Thread.Alerted} = BEGIN LOCK self.grid.mu DO FOR j := 0 TO self.m - 1 DO self.grid.a[1, self.posPat + j + EllipsisLen].setVisible( self.grid, 0.0); END; (* Redraw text *) INC(self.startStr, howMany); FOR j := EllipsisLen TO NUMBER(self.grid.a[0]) - 1 - EllipsisLen DO self.grid.a[0, j].setLabel( self.grid, Text.Sub(self.str, self.startStr - EllipsisLen + j, 1)); self.grid.a[0, j].setColor( self.grid, self.a[self.startStr - EllipsisLen + j]); END; (* Move pattern *) DEC(self.posPat, howMany); (* Now redraw pattern *) FOR j := MAX(0, -self.posPat) TO self.m - 1 DO self.grid.a[1, self.posPat + j + EllipsisLen].setVisible( self.grid, 1.0); self.grid.a[1, self.posPat + j + EllipsisLen].setColor( self.grid, ClearCS); self.grid.a[1, self.posPat + j + EllipsisLen].setLabel( self.grid, Text.Sub(self.pat, j, 1)); END; END; MGV.Animation(self.grid, duration); END Slide; PROCEDURENew (): View.T = VAR g := NEW(Grid.V).init(2, MovieLen, RectSize, RectSize); BEGIN FOR i := 0 TO MovieLen - 1 DO g.a[0, i].setFont(g, SliderFont); g.a[1, i].setFont(g, SliderFont); g.a[1, i].setVisible(g, 0.0); END; FOR j := 0 TO EllipsisLen - 1 DO g.a[0, j].setWeight(g, 0.0); END; FOR j := MovieLen - EllipsisLen TO MovieLen - 1 DO g.a[0, j].setWeight(g, 0.0); END; WITH scale = NEW(ScaleFilter.T).init(g) DO ScaleFilter.AutoScale(scale); RETURN NEW(T, grid := g).init(scale); END; END New; PROCEDURENew1 (): View.T = VAR g := NEW(Grid.V).init(2, MovieLen, RectSize, RectSize); BEGIN FOR i := 0 TO MovieLen - 1 DO g.a[0, i].setFont(g, SliderFont); g.a[1, i].setFont(g, SliderFont); g.a[1, i].setVisible(g, 0.0); END; FOR j := 0 TO EllipsisLen - 1 DO g.a[0, j].setWeight(g, 0.0); END; FOR j := MovieLen - EllipsisLen TO MovieLen - 1 DO g.a[0, j].setWeight(g, 0.0); END; WITH scale = NEW(ScaleFilter.T).init(g) DO ScaleFilter.AutoScale(scale); RETURN NEW(TopT, grid := g).init(scale); END; END New1; PROCEDURENew2 (): View.T = VAR g := NEW(Grid.V, doubleBuffer := FALSE).init( 2, MovieLen, RectSize, RectSize); BEGIN FOR i := 0 TO MovieLen - 1 DO g.a[0, i].setVisible(g, 0.0); g.a[1, i].setVisible(g, 0.0); END; WITH scale = NEW(ScaleFilter.T).init(g) DO ScaleFilter.AutoScale(scale); RETURN NEW(OverViewT, grid := g).init(scale); END; END New2; BEGIN ZeusPanel.RegisterView(New, "Slider", "StringSearch"); ZeusPanel.RegisterView(New1, "TopSlider", "StringSearch"); ZeusPanel.RegisterView(New2, "OverView", "StringSearch"); END SliderView.