<* PRAGMA LL *> <* PRAGMA SUBTYPE *> MODULE****** ZHandleVBT procedure & method definitions *******; IMPORT Attributes, Axis, Dialog, FeedbackVBT, Filter, FlexVBT, FormsVBT, Fmt, HighlightVBT, KnobsVBT, NodeVBT, PaintOp, Pixmap, Point, Rect, Region, SourceVBT, Split, Stdio, Text, Thread, VBT, VBTClass, VBTColors, Wr, ZGrowVBT, ZMoveVBT, ZSplit, ZSplitUtils; TYPE Style = {Grow, Move, None}; <* FATAL Split.NotAChild *> <* FATAL FormsVBT.Error *> <* FATAL FormsVBT.Unimplemented *> <* FATAL Wr.Failure *> <* FATAL Thread.Alerted *> REVEAL T = Public BRANDED "VO-ZHandleVBT" OBJECT active := Style.None; handler : Filter.T; knobs : KnobsVBT.T; mover : ZMoveVBT.T; grower : ZGrowVBT.T; handleOn := FALSE; top : BOOLEAN; child : VBT.T; hl : HighlightVBT.T; OVERRIDES init := Init; (* Since it is a ZSplit it decides which child is going to get the events *) on := ZOn; off := ZOff; getchild := GetChild; getDomain := GetDomain; replaceChild := ReplaceChild; END; Selection = PublicSelect BRANDED "VO-Selection" OBJECT size : CARDINAL; selectedObject: REF ARRAY OF T; selected : REF ARRAY OF BOOLEAN; singleMode := TRUE; dialog : Dialog.T; OVERRIDES init := InitSelection; on := On; off := Off; getSelectionSize := GetSelectionSize; getSelection := GetSelection; inSingleMode := InSingleMode; alignSelectedObjects := AlignSelectedObjects; shapeSelectedObjects := ShapeSelectedObjects; distributeSelectedObjects := DistributeSelectedObjects; END; ZHandleVBT
PROCEDUREInit (v: T; ch: VBT.T; selection: Selection := NIL): T = VAR f1, f2: FeedbackVBT.T; BEGIN v.child := ch; v.selection := selection; v.knobs := NEW(KnobsVBT.T).init(ch); f1 := NEW(Feedback).init(v.knobs); v.mover := NEW(Mover, zhandle := v).init(f1); f2 := NEW(FeedbackVBT.T).init(v.mover); v.grower := NEW(Grower, zhandle := v).init(f2); v.handler := NEW(Handler, zhandle := v).init(v.grower); RETURN ZSplit.T.init(v, v.handler) END Init; PROCEDURENewSelection (n : T; s : Selection) = BEGIN n.selection := s; END NewSelection; PROCEDUREZOn (v: T; singlemode: BOOLEAN) = BEGIN KnobsVBT.SetSingleMode(v.knobs, singlemode); KnobsVBT.Add(v.knobs); VBT.Mark(v.knobs); v.handleOn := TRUE END ZOn; PROCEDUREZOff (v: T) = BEGIN KnobsVBT.Remove(v.knobs); v.handleOn := FALSE; END ZOff; PROCEDUREGetChild (v: T): VBT.T = BEGIN RETURN v.child; END GetChild; PROCEDUREGetDomain (v: T): Rect.T = BEGIN RETURN VBT.Domain(v); END GetDomain; PROCEDUREReplaceChild (v: T; fv: VBT.T) = BEGIN EVAL Filter.Replace(v.knobs, fv); v.child := fv; END ReplaceChild; PROCEDUREGetGridSize (v: T) : INTEGER = (* fetches gridsize from selection's dialog *) BEGIN RETURN v.selection.dialog.grid; END GetGridSize;
**************************************************************************
TYPE (* This regulates the turning on/off of the handle and the passing of events *) Handler = Filter.T OBJECT zhandle : T; startpt, endpt : Point.T; controlledChange: BOOLEAN; changeInProgress: BOOLEAN; chordCancel : BOOLEAN; offclick : BOOLEAN; OVERRIDES mouse := Mouse; position := Position; END; PROCEDURE********* Selection methods and procedure definitions *************Mouse (h: Handler; READONLY cd: VBT.MouseRec) = VAR v := h.zhandle; par := VBT.Parent(v); singleMode : BOOLEAN; dom, innerdomain: Rect.T; switchedOn := FALSE; switchedOff := FALSE; child : VBT.T; grid := GetGridSize(v); doubleclick := (cd.clickType = VBT.ClickType.LastUp) AND (cd.clickCount = 3); newcd := cd; BEGIN IF doubleclick THEN Attributes.Invoke(Dialog.attributes, NARROW(v, NodeVBT.T)); NodeVBT.print("Invoking attributes for " & NARROW(v, NodeVBT.T).name & "\n"); newcd.clickType := VBT.ClickType.OtherDown; (* simulate a chord cancel *) Filter.T.mouse(h, newcd); RETURN; END; singleMode := NOT (VBT.Modifier.Control IN cd.modifiers); IF cd.clickType = VBT.ClickType.FirstDown THEN h.startpt := cd.cp.pt; v.top := Split.Succ(par, NIL) = v; (* This is set if v is the top child of the zsplit... here we assume that the parent of the ZHandle is a zsplit *) IF NOT v.handleOn THEN (* turn the handle on *) h.offclick := FALSE; switchedOn := TRUE; IF v.selection # NIL THEN v.selection.on(v, singleMode) ELSE v.on(TRUE) (* ignore modifier *) END ELSE h.offclick := TRUE (* the handle was previously on, maybe offclick *) END; END; IF cd.clickType = VBT.ClickType.FirstDown AND v.handleOn THEN IF KnobsVBT.Inside(v.knobs, cd.cp.pt) THEN v.active := Style.Grow; (* Since grow is starting - if this is a split node we need to set size constraints to accomadate the children *) IF ISTYPE(v, NodeVBT.SplitNode) THEN (* first compute the required minimum size of the split *) dom := ZSplit.GetDomain(v); innerdomain := dom; innerdomain.south := innerdomain.north + 50; innerdomain.east := innerdomain.west + 50; (* minimum size *) child := Split.Succ(v, NIL); (* Top *) WHILE child # h DO (* h should be bottom *) innerdomain := Rect.Join(innerdomain, VBT.Domain(child)); child := Split.Succ(v, child); END; (* innerdomain is the minimum sized rectangle *) dom := Rect.Join(dom, innerdomain); ZSplit.Move(v, dom); WITH fv = NARROW(v.child, FormsVBT.T), nv = NARROW(v, NodeVBT.T), flexvbt = NARROW(FormsVBT.GetVBT(fv, nv.name & "shape"), FlexVBT.T), vpixpermm = VBT.MMToPixels(v, 1.0, Axis.T.Ver), hpixpermm = VBT.MMToPixels(v, 1.0, Axis.T.Hor) DO FlexVBT.SetRange( flexvbt, Axis.T.Hor, FlexVBT.SizeRange{ FLOAT(Rect.HorSize(dom)) / hpixpermm, FLOAT(Rect.HorSize(dom) - Rect.HorSize(innerdomain)) / hpixpermm, FlexVBT.Infinity}); FlexVBT.SetRange( flexvbt, Axis.T.Ver, FlexVBT.SizeRange{ FLOAT(Rect.VerSize(dom)) / vpixpermm, FLOAT(Rect.VerSize(dom) - Rect.VerSize(innerdomain)) / vpixpermm, FlexVBT.Infinity}); END END ELSE v.active := Style.Move; END; h.chordCancel := FALSE; h.changeInProgress := TRUE; h.controlledChange := VBT.Modifier.Control IN cd.modifiers; ELSIF cd.clickType = VBT.ClickType.OtherDown THEN h.chordCancel := TRUE END; Filter.T.mouse(h, cd); IF cd.clickType = VBT.ClickType.LastUp THEN h.endpt := cd.cp.pt; IF NOT h.chordCancel AND v.top AND h.offclick AND Point.DistSquare(h.startpt, h.endpt) < 6 THEN (* Turn off *) IF v.selection # NIL THEN v.selection.off(v, singleMode) ELSE v.off() END; switchedOff := TRUE; END; (* if this was a successful change and control wasn't down clamp the domain *) IF h.changeInProgress AND NOT h.chordCancel AND NOT switchedOn AND NOT switchedOff THEN (* house-keeping *) IF NOT h.controlledChange THEN dom := ZSplit.GetDomain(v); ZSplit.Move( v, Rect.FromCorners(ClampToGrid(Rect.NorthWest(dom), grid), ClampToGrid(Rect.SouthEast(dom), grid))); END; END; h.changeInProgress := FALSE; v.active := Style.None; END END Mouse; PROCEDUREPosition (h: Handler; READONLY cd: VBT.PositionRec) = VAR nv := NARROW(h.zhandle, NodeVBT.T); r := VBT.Domain(nv); nw := Rect.NorthWest(r); dialog := nv.selection.dialog; BEGIN IF Rect.Member(cd.cp.pt, r) THEN WITH wid = Rect.HorSize(r), ht = Rect.VerSize(r) DO (* NodeVBT.print("Pointer entered " & nv.name & ":" & Fmt.Int(nw.h) & "," & Fmt.Int(nw.v) & ":" & Fmt.Int(wid) & "X" & Fmt.Int(ht) & "\n"); *) FormsVBT.PutText(dialog, "currentobject", nv.name & " = " & Fmt.Int(nw.h) & "," & Fmt.Int(nw.v) & " (H:" & Fmt.Int(wid) & ", V: " & Fmt.Int(ht) & ")", FALSE); END ELSE (* NodeVBT.print("Pointer exited " & nv.name & "\n") *) FormsVBT.PutText(dialog, "currentobject", "", FALSE); END; Filter.T.position(h, cd) END Position; TYPE Grower = ZGrowVBT.T OBJECT zhandle : T; clipregion: Rect.T; OVERRIDES shape := Shape; mouse := GrowMouse; position := GrowPosition END; PROCEDUREGrowMouse (v: Grower; READONLY cd: VBT.MouseRec) = VAR newcd := cd; parent: VBT.T; grid := GetGridSize(v.zhandle); BEGIN IF v.zhandle.active = Style.Grow THEN IF cd.clickType = VBT.ClickType.FirstDown THEN (* get parents domain and set clip region *) parent := VBT.Parent(v.zhandle); IF ISTYPE(parent, T) THEN v.clipregion := NARROW(parent, T).getDomain(); ELSE (* default *) v.clipregion := VBT.Domain(parent); END; (* to compensate for the open interval *) DEC(v.clipregion.east); DEC(v.clipregion.south); END; IF NOT (VBT.Modifier.Control IN cd.modifiers) AND grid > 1 THEN newcd.cp.pt := Clip(ClampToGrid(cd.cp.pt, grid), v.clipregion); END; ZGrowVBT.T.mouse(v, newcd) ELSE Filter.T.mouse(v, cd) END END GrowMouse; PROCEDUREGrowPosition (v: Grower; READONLY cd: VBT.PositionRec) = VAR newcd := cd; grid := GetGridSize(v.zhandle); BEGIN IF v.zhandle.active = Style.Grow THEN (* round off position points to grid points *) IF NOT (VBT.Modifier.Control IN cd.modifiers) AND grid > 1 THEN newcd.cp.pt := Clip(ClampToGrid(cd.cp.pt, grid), v.clipregion); (* Point.Mul(Point.Div(cd.cp.pt, grid), grid) *) END; ZGrowVBT.T.position(v, newcd) ELSE Filter.T.position(v, cd) END END GrowPosition; TYPE Mover = ZMoveVBT.T OBJECT zhandle : T; origin : Point.T; chordCancel: BOOLEAN; clipregion : Rect.T; innerdomain: Rect.T; op : PaintOp.T; last : Point.T; rect : Rect.T; beingMoved := FALSE; OVERRIDES shape := Shape; mouse := MoveMouse; position := MovePosition; during := During; repaint := Repaint; END; PROCEDUREClampToGrid (READONLY p: Point.T; READONLY gridstep: INTEGER): Point.T = BEGIN IF gridstep <= 1 THEN RETURN p ELSE RETURN Point.Mul(Point.Div(Point.Add(p, Point.T{gridstep DIV 2, gridstep DIV 2}), gridstep), gridstep); END END ClampToGrid; PROCEDUREClip (READONLY p: Point.T; READONLY reg: Rect.T): Point.T = VAR q := p; BEGIN IF q.h < reg.west THEN q.h := reg.west END; IF q.h > reg.east THEN q.h := reg.east END; IF q.v < reg.north THEN q.v := reg.north END; IF q.v > reg.south THEN q.v := reg.south END; RETURN q; END Clip; PROCEDUREMoveMouse (v: Mover; READONLY cd: VBT.MouseRec) = VAR newcd := cd; grid := GetGridSize(v.zhandle); delta : Point.T; selection := v.zhandle.selection; movee : T; parent : VBT.T; BEGIN IF v.zhandle.active = Style.Move THEN (* round off position points to grid points *) IF NOT (VBT.Modifier.Control IN cd.modifiers) AND grid > 1 THEN newcd.cp.pt := ClampToGrid(cd.cp.pt, grid); END; IF cd.clickType = VBT.ClickType.FirstDown THEN v.origin := newcd.cp.pt; v.chordCancel := FALSE; (* get parents domain and set clip region *) parent := VBT.Parent(v.zhandle); IF ISTYPE(parent, T) THEN v.clipregion := NARROW(parent, T).getDomain(); ELSE (* default *) v.clipregion := VBT.Domain(parent); END; (* to compensate for the open interval *) DEC(v.clipregion.east); DEC(v.clipregion.south); (* now subtract appropriate offsets *) v.innerdomain := Rect.Empty; WITH bg = Split.Pred(VBT.Parent(ZSplitUtils.FindZChild(v)), NIL) DO v.op := VBTColors.Get(bg).transparentSwap END; FOR i := FIRST(selection.selected^) TO LAST(selection.selected^) DO IF selection.selected[i] THEN WITH sel = selection.selectedObject[i] DO v.innerdomain := Rect.Join(VBT.Domain(sel), v.innerdomain); IF sel # v.zhandle THEN WITH mvr = NARROW(sel.mover, Mover) DO sel.hl := SourceVBT.GetHighlighter(sel.mover); mvr.op := v.op; (* is this valid ?*) mvr.rect := VBT.Domain(sel); mvr.beingMoved := TRUE; END END END END END; v.last := Point.T{0, 0}; v.clipregion := Rect.Change(v.clipregion, v.origin.h - v.innerdomain.west, v.origin.h - v.innerdomain.east, v.origin.v - v.innerdomain.north, v.origin.v - v.innerdomain.south); TRY (* DEBUG MODE *) Wr.PutText( Stdio.stdout, "Start Move = (" & Fmt.Int(newcd.cp.pt.h) & "," & Fmt.Int(newcd.cp.pt.v) & ")\n"); Wr.Flush(Stdio.stdout); EXCEPT ELSE END; ELSIF cd.clickType = VBT.ClickType.OtherDown THEN v.chordCancel := TRUE; ELSIF cd.clickType = VBT.ClickType.LastUp THEN TRY (* remove highlights *) FOR i := FIRST(selection.selected^) TO LAST(selection.selected^) DO IF selection.selected[i] THEN WITH sel = selection.selectedObject[i] DO IF sel # v.zhandle THEN HighlightVBT.SetRect(sel.hl, Rect.Empty); NARROW(sel.mover, Mover).beingMoved := FALSE; END END END END; (* DEBUG MODE *) IF NOT v.chordCancel THEN (* it was a valid move *) Wr.PutText( Stdio.stdout, "End Move = (" & Fmt.Int(newcd.cp.pt.h) & "," & Fmt.Int(newcd.cp.pt.v) & ")\n"); Wr.Flush(Stdio.stdout); newcd.cp.pt := Clip(newcd.cp.pt, v.clipregion); delta := Point.Sub(newcd.cp.pt, v.origin); selection := v.zhandle.selection; IF NOT selection.inSingleMode() THEN FOR i := FIRST(selection.selected^) TO LAST(selection.selected^) DO IF selection.selected[i] THEN (* if this is not our zhandle then move it *) IF selection.selectedObject[i] # v.zhandle THEN (* move it by delta *) movee := selection.selectedObject[i]; ZSplit.Move( movee, Rect.Add(ZSplit.GetDomain(movee), delta)) END END END END; ELSE Wr.PutText(Stdio.stdout, "Chord Cancel - Move Abandoned\n"); Wr.Flush(Stdio.stdout); END; EXCEPT ELSE Wr.PutText(Stdio.stdout, "Error !#@\n"); Wr.Flush(Stdio.stdout); END; END; ZMoveVBT.T.mouse(v, newcd); ELSE Filter.T.mouse(v, cd) END END MoveMouse; PROCEDURERepaint (v: Mover; READONLY badR: Region.T) RAISES {} = VAR Thickness := ROUND(MAX(VBT.MMToPixels(v, 0.75, Axis.T.Hor), VBT.MMToPixels(v, 0.75, Axis.T.Ver))); BEGIN ZMoveVBT.T.repaint(v, badR); IF v.beingMoved THEN WITH newRect = v.rect DO HighlightVBT.SetTexture( v.zhandle.hl, Pixmap.Gray, Point.Origin, v.op); HighlightVBT.SetRect(v.zhandle.hl, newRect, Thickness); END END; END Repaint; PROCEDUREDuring (v: Mover; READONLY cd: VBT.PositionRec) = VAR selection := v.zhandle.selection; Thickness := ROUND(MAX(VBT.MMToPixels(v, 0.75, Axis.T.Hor), VBT.MMToPixels(v, 0.75, Axis.T.Ver))); BEGIN ZMoveVBT.T.during(v, cd); IF NOT Point.Equal(cd.cp.pt, v.last) THEN IF NOT selection.inSingleMode() THEN FOR i := FIRST(selection.selected^) TO LAST(selection.selected^) DO IF selection.selected[i] THEN (* if this ISTYPE not our zhandle then move its highlight *) IF selection.selectedObject[i] # v.zhandle THEN WITH newRect = Rect.Move( VBT.Domain(selection.selectedObject[i]), Point.Sub(cd.cp.pt, v.origin)), sel = selection.selectedObject[i] DO HighlightVBT.SetTexture( sel.hl, Pixmap.Gray, Point.Origin, v.op); HighlightVBT.SetRect(sel.hl, newRect, Thickness); v.rect := newRect; END END END END END END; v.last := cd.cp.pt; (* This should have drawn highlights for all the other selected objects *) END During; PROCEDUREMovePosition (v: Mover; READONLY cd: VBT.PositionRec) = VAR newcd := cd; grid := GetGridSize(v.zhandle); BEGIN IF v.zhandle.active = Style.Move THEN (* round off position points to grid points *) IF NOT (VBT.Modifier.Control IN cd.modifiers) AND grid > 1 THEN newcd.cp.pt := ClampToGrid(cd.cp.pt, grid); (* Point.Mul(Point.Div(cd.cp.pt, grid), grid) *) END; newcd.cp.pt := Clip(newcd.cp.pt, v.clipregion); ZMoveVBT.T.position(v, newcd) ELSE Filter.T.position(v, cd) END END MovePosition; PROCEDUREShape (v: Filter.T; ax: Axis.T; n: CARDINAL): VBT.SizeRange = BEGIN RETURN VBTClass.GetShape(Filter.Child(v), ax, n) END Shape; TYPE Feedback = FeedbackVBT.T OBJECT OVERRIDES mouse := BlockMouse; position := BlockPosition; END; PROCEDUREBlockMouse (<* UNUSED *> v : Feedback; <* UNUSED *> READONLY cd: VBT.MouseRec) = BEGIN END BlockMouse; PROCEDUREBlockPosition (<* UNUSED *> v : Feedback; <* UNUSED *> READONLY cd: VBT.PositionRec) = BEGIN END BlockPosition;
PROCEDUREHere we implement the policy - override if necessaryInitSelection (self : Selection; size : CARDINAL; singlemode: BOOLEAN; dialog : FormsVBT.T) = BEGIN self.dialog := NARROW(dialog, Dialog.T); self.selectedObject := NEW(REF ARRAY OF T, size); self.selected := NEW(REF ARRAY OF BOOLEAN, size); self.size := size; FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO self.selected[i] := FALSE END; self.singleMode := singlemode; END InitSelection; PROCEDUREFlush (sel: Selection) = BEGIN FOR i := FIRST(sel.selected^) TO LAST(sel.selected^) DO IF sel.selected[i] THEN sel.selected[i] := FALSE; sel.selectedObject[i].off() (* hey turn that thing off *) END; END END Flush;
PROCEDURE********** End of Selection Methods and Procedures **********On (self: Selection; v: T; singlemode: BOOLEAN) = VAR par : VBT.Split; other : T; actuallySingle := TRUE; stored := FALSE; BEGIN (* Assert : The ZHandleVBT v is not currently selected *) IF (singlemode) THEN (* Flush selection *) Flush(self); self.selected[FIRST(self.selected^)] := TRUE; self.selectedObject[FIRST(self.selected^)] := v; v.on(TRUE); (* make it turn its feedback on in single mode *) self.singleMode := TRUE; ELSE par := VBT.Parent(v); FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN (* selected ZHandleVBT *) other := self.selectedObject[i]; IF par = VBT.Parent(other) THEN (* it is a sibling - so make it gray *) actuallySingle := FALSE; other.on(FALSE); (* turn feedback on in multiple mode *) ELSE other.off(); (* turn feedback off *) self.selected[i] := FALSE; END END; IF NOT (stored OR self.selected[i]) THEN self.selected[i] := TRUE; self.selectedObject[i] := v; stored := TRUE; END (* store new ZHandle in first free slot *) END; v.on(actuallySingle); (* actuallySingle will decide whether it is in multiple mode or not *) self.singleMode := actuallySingle; END; END On; PROCEDUREOff (self: Selection; v: T; singlemode: BOOLEAN) = VAR multiplicity := 0; last : T; BEGIN (* Assert : The ZHandleVBT.T v is currently ON and in the selection list *) IF (singlemode) THEN Flush(self); self.singleMode := TRUE; (* Nothing selected senor *) ELSE (* turn off only current element *) FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN IF self.selectedObject[i] = v THEN self.selected[i] := FALSE ELSE INC(multiplicity); last := self.selectedObject[i]; END END END; (* Any on handles should currently be in multiple mode *) self.singleMode := (multiplicity < 2); (* If multiplicity is 1 then it is now single mode and last needs to *) (* be switched to single mode *) IF multiplicity = 1 THEN last.on(TRUE); (* multiple to single *) END; END; v.off(); END Off; PROCEDUREGetSelectionSize (self: Selection): CARDINAL = VAR ct: CARDINAL := 0; BEGIN FOR o := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[o] THEN INC(ct) END; END; RETURN ct; END GetSelectionSize; PROCEDUREGetSelection (self: Selection; indx: CARDINAL): T = VAR selno := 0; BEGIN FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN INC(selno) END; IF selno = indx THEN RETURN self.selectedObject[i]; END END; RETURN NIL; END GetSelection; PROCEDUREInSingleMode (self: Selection): BOOLEAN = BEGIN RETURN self.singleMode END InSingleMode; PROCEDUREComputeCumulative (style: TEXT; cumulative: INTEGER; val: INTEGER): INTEGER = BEGIN (* uninitialized *) IF cumulative = -1 THEN RETURN val; END; IF Text.Equal(style, "alignAvg") OR Text.Equal(style, "useAvg") THEN RETURN cumulative + val; ELSIF ((Text.Equal(style, "alignMin") OR Text.Equal(style, "useMin")) AND val < cumulative) OR ((Text.Equal(style, "alignMax") OR Text.Equal(style, "useMax")) AND val > cumulative) THEN RETURN val; ELSE RETURN cumulative (* This works for First as well *) END; END ComputeCumulative; PROCEDUREShapeSelectedObjects (self: Selection; mode: TEXT; shapingStyle: TEXT) = VAR ct := self.getSelectionSize(); cumulative : INTEGER := -1; BEGIN IF ct < 2 THEN Dialog.message(self.dialog, "The Shaping Operation Is Not Currently Applicable"); RETURN; END; (* Not Applicable *) (* So far only 2 modes at this pt : EqualWidth and EqualHeight *) (* Pass 1 - compute the cumulative side length*) FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN WITH rc = ZSplit.GetDomain(self.selectedObject[i]) DO IF Text.Equal(mode, "EqualWidth") THEN cumulative := ComputeCumulative(shapingStyle, cumulative, rc.east - rc.west); ELSE cumulative := ComputeCumulative(shapingStyle, cumulative, rc.south - rc.north); END (* IF *) END (* WITH *) END END (* FOR *); IF Text.Equal(shapingStyle, "useAvg") THEN cumulative := cumulative DIV ct; END; FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN VAR rect := ZSplit.GetDomain(self.selectedObject[i]); BEGIN IF Text.Equal(mode, "EqualWidth") THEN WITH objwid = rect.east - rect.west, increasedWid = cumulative - objwid, changePerSide = increasedWid DIV 2 DO rect.east := rect.east + changePerSide; rect.west := rect.west - changePerSide; END (* WITH *) ELSE (* EqualHt ! *) WITH objht = rect.south - rect.north, increasedHt = cumulative - objht, changePerSide = increasedHt DIV 2 DO rect.south := rect.south + changePerSide; rect.north := rect.north - changePerSide; END (* WITH *) END (* IF *); ZSplit.Move(self.selectedObject[i], rect); END (* BEGIN *) END (* IF *) END (* FOR *) END ShapeSelectedObjects; PROCEDUREAlignSelectedObjects (self: Selection; mode: TEXT; alignmentStyle: TEXT; dontStretch: BOOLEAN:=FALSE) = VAR ct := self.getSelectionSize(); cumulative : INTEGER := -1; BEGIN IF ct < 2 THEN Dialog.message(self.dialog, "The Alignment Operation Is Not Currently Applicable"); RETURN; END; (* Not Applicable *) (* Pass 1 - compute the cumulative edge coord*) FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN WITH rc = ZSplit.GetDomain(self.selectedObject[i]) DO IF Text.Equal(mode, "AlignNorth") THEN cumulative := ComputeCumulative(alignmentStyle, cumulative, rc.north); ELSIF Text.Equal(mode, "AlignSouth") THEN cumulative := ComputeCumulative(alignmentStyle, cumulative, rc.south); ELSIF Text.Equal(mode, "AlignEast") THEN cumulative := ComputeCumulative(alignmentStyle, cumulative, rc.east); ELSIF Text.Equal(mode, "AlignWest") THEN cumulative := ComputeCumulative(alignmentStyle, cumulative, rc.west); ELSIF Text.Equal(mode, "AlignCenVert") THEN cumulative := ComputeCumulative(alignmentStyle, cumulative, (rc.east + rc.west) DIV 2); ELSIF Text.Equal(mode, "AlignCenHoriz") THEN cumulative := ComputeCumulative(alignmentStyle, cumulative, (rc.north + rc.south) DIV 2); END (* IF *) END (* WITH *) END (* IF *); END (* FOR *); IF Text.Equal(alignmentStyle, "alignAvg") THEN cumulative := cumulative DIV ct; END; (* Pass 2 - set value to cumulative *) FOR i := FIRST(self.selected^) TO LAST(self.selected^) DO IF self.selected[i] THEN VAR rect := ZSplit.GetDomain(self.selectedObject[i]); BEGIN IF Text.Equal(mode, "AlignNorth") THEN IF dontStretch THEN rect.south := rect.south + cumulative - rect.north; END; (* IF *) IF cumulative < rect.south OR dontStretch THEN rect.north := cumulative; END; (* IF *) ELSIF Text.Equal(mode, "AlignSouth") THEN IF dontStretch THEN rect.north := rect.north + cumulative - rect.south; END; (* IF *) IF cumulative > rect.north OR dontStretch THEN rect.south := cumulative; END; (* IF *) ELSIF Text.Equal(mode, "AlignEast") THEN IF dontStretch THEN rect.west := rect.west + cumulative - rect.east; END; (* IF *) IF cumulative > rect.west OR dontStretch THEN rect.east := cumulative; END; (* IF *) ELSIF Text.Equal(mode, "AlignWest") THEN IF dontStretch THEN rect.east := rect.east + cumulative - rect.west; END; (* IF *) IF cumulative < rect.east OR dontStretch THEN rect.west := cumulative; END; (* IF *) ELSIF Text.Equal(mode, "AlignCenVert") THEN WITH horizontalShift =cumulative - (rect.east + rect.west) DIV 2 DO rect.east := rect.east + horizontalShift; rect.west := rect.west + horizontalShift; END (* WITH *) ELSIF Text.Equal(mode, "AlignCenHoriz") THEN WITH verticalShift = cumulative - (rect.north + rect.south) DIV 2 DO rect.north := rect.north + verticalShift; rect.south := rect.south + verticalShift; END (* WITH *) END (* IF *); ZSplit.Move(self.selectedObject[i], rect); END (* BEGIN *) END (* IF *) END (* FOR *) END AlignSelectedObjects; PROCEDUREDistributeSelectedObjects (self: Selection; mode: TEXT) = VAR ct := self.getSelectionSize(); tmp := NEW(REF ARRAY OF T, ct); tmpsize := NEW(REF ARRAY OF INTEGER, ct); horizontally := Text.Equal(mode, "DistHoriz"); sigma_dimension : INTEGER := 0; avail_space, max_edge : INTEGER; objrect : Rect.T; par : VBT.T; BEGIN IF ct < 1 THEN Dialog.message(self.dialog, "No Objects Selected !"); RETURN; END; (* Not Applicable *) (* Copy the selected objects to another array and compute sigma-dimension at the same time *) FOR i := 0 TO ct-1 DO WITH q = FIRST(self.selectedObject^) + i, rect = ZSplit.GetDomain(self.selectedObject[q]), r = FIRST(tmp^) + i DO tmp[r] := self.selectedObject[q]; IF horizontally THEN tmpsize[r] := rect.east - rect.west + 1; ELSE tmpsize[r] := rect.south - rect.north + 1; END (* IF *); sigma_dimension := sigma_dimension + tmpsize[r]; END (* WITH *) END (* FOR *); par := VBT.Parent(tmp[FIRST(tmp^)]); IF NOT ISTYPE(par, T) THEN Dialog.message(self.dialog, "There is no use in moving a form!"); RETURN; END; WITH rpar = ZSplit.GetDomain(par) DO IF horizontally THEN avail_space := rpar.east - rpar.west + 1; max_edge := rpar.east; ELSE avail_space := rpar.south - rpar.north + 1; max_edge := rpar.south; END (* IF *) END (* WITH *); IF avail_space < sigma_dimension THEN Dialog.message(self.dialog, "No space to distribute !"); RETURN; END; (* Not Applicable *) (* Bubble-sort the array based on tmp_center_coord *) WITH leeway = avail_space - sigma_dimension, leewayPerWidget = leeway DIV (ct + 1) DO FOR swapsNotNeeded := 1 TO ct DO (* Do a ripple *) FOR ix := FIRST (tmp^) TO LAST(tmp^) - swapsNotNeeded DO WITH rect1 = ZSplit.GetDomain(tmp[ix]), rect2 = ZSplit.GetDomain(tmp[ix+1]) DO (* if ix > ix+1 then swap *) IF (horizontally AND (Rect.Middle(rect1).h > Rect.Middle(rect2).h)) OR (NOT horizontally AND (Rect.Middle(rect1).v > Rect.Middle(rect2).v)) THEN VAR t := tmp[ix]; tsize := tmpsize[ix]; BEGIN (* swap *) tmp[ix] := tmp[ix+1]; tmp[ix+1] := t; tmpsize[ix] := tmpsize[ix+1]; tmpsize[ix+1] := tsize; END (* BEGIN *); END (* IF *) END (* WITH *) END (* FOR ix*); (* The LAST(tmp^) - swapsNotNeeded + 1 th element is in place so move it *) WITH elem = LAST(tmp^) - swapsNotNeeded + 1, element = tmp[elem], (* larger edge should be at avail_space - leewayPerWidget *) largerEdge = max_edge - leewayPerWidget, smallerEdge = largerEdge - tmpsize[elem] + 1 DO objrect := ZSplit.GetDomain(element); IF horizontally THEN objrect.west := smallerEdge; objrect.east := largerEdge; ELSE objrect.north := smallerEdge; objrect.south := largerEdge; END; (* move the blighter *) ZSplit.Move(element, objrect); max_edge := max_edge - leewayPerWidget - tmpsize[elem]; END (* WITH *) END (* FOR swapsNotNeeded*) END (* WITH *); END DistributeSelectedObjects;
BEGIN END ZHandleVBT.