VAR shades: ARRAY[TColor] OF LPattern; arwBitMap: BitMap; METHODS OF TBox; FUNCTION {TBox.}CREATE{(object: TObject; itsHeap: THeap; itsShape: LRect; itsColor: TColor): TBox}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBox(object); WITH SELF DO BEGIN isSelected := FALSE; wasSelected := FALSE; shapeLRect := itsShape; color := itsColor; END; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TBox.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('shapeLRect: LRect'); Field('color: Byte'); Field('isSelected: BOOLEAN'); Field('wasSelected: BOOLEAN'); Field(''); END; {$ENDC} PROCEDURE {TBox.}Draw; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF LRectIsVisible(SELF.shapeLRect) THEN BEGIN PenNormal; PenSize(1, 1); FillLRect(SELF.shapeLRect, shades[SELF.color]); FrameLRect(SELF.shapeLRect); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBox.}EachHandleRect{(PROCEDURE DoToHandle(hRect: Rect))}; VAR hRect: Rect; shapeRect: Rect; dh, dv: INTEGER; PROCEDURE DoOffsetBy(hOffset, vOffset: INTEGER); BEGIN OffsetRect(hRect, hOffset, vOffset); DoToHandle(hRect); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SetRect(hRect, -3, -2, 3, 2); thePad.LRectToRect(SELF.shapeLRect, shapeRect); WITH shapeRect DO BEGIN dh := right - left; dv := bottom - top; DoOffsetBy(left, top); END; DoOffsetBy(dh, 0); DoOffsetBy(0, dv); DoOffsetBy(-dh, 0); IF dh > 15 THEN BEGIN DoOffsetBy(dh DIV 2, 0); DoOffsetBy(0, -dv); OffsetRect(hRect, -(dh DIV 2), dv); END; IF dv > 15 THEN BEGIN DoOffsetBy(0, -(dv DIV 2)); DoOffsetBy(dh, 0); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBox.}Highlight{(highTransit: THighTransit)}; VAR bounds: LRect; BEGIN {$IFC fTrace}BP(10);{$ENDC} bounds := SELF.shapeLRect; InsetLRect(bounds, -3, -2); IF LRectIsVisible(bounds) THEN BEGIN thePad.SetPenToHighlight(highTransit); SELF.EachHandleRect(PaintRect); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBox.}InvalInTheView{(view: TView)}; VAR bounds: LRect; BEGIN {$IFC fTrace}BP(10);{$ENDC} WITH SELF DO {$H-} BEGIN bounds := shapeLRect; IF isSelected OR wasSelected THEN InsetLRect(bounds, -3, -2); {$H+} END; view.panel.InvalLRect(bounds); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBox.}Outline; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF LRectIsVisible(SELF.shapeLRect) THEN BEGIN PenNormal; PenSize(1, 1); PenMode(patXor); FrameLRect(SELF.shapeLRect); END; {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TBoxProcess; FUNCTION {TBoxProcess.}CREATE{(object: TObject; itsHeap: THeap): TBoxProcess}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBoxProcess(TProcess.CREATE(object, itsHeap)); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxProcess.}Commence{(phraseVersion: INTEGER)}; BEGIN {$IFC fTrace}BP(10);{$ENDC} SUPERSELF.Commence(phraseVersion); shades[colorWhite] := lPatWhite; shades[colorLtGray] := lPatLtGray; shades[colorGray] := lPatGray; shades[colorDkGray] := lPatDkGray; shades[colorBlack] := lPatBlack; { build the arrow bitmap } WITH arwBitMap DO BEGIN rowBytes := 2; SetRect(bounds, 0, 0, 16, 16); baseAddr := @arrow.data; END; {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TBoxProcess.}NewDocManager{(volumePrefix: TFilePath; openAsTool: BOOLEAN): TDocManager}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF openAsTool THEN NewDocManager := NIL ELSE NewDocManager := TBoxDocManager.CREATE(NIL, mainHeap, volumePrefix); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TBoxDocManager; FUNCTION {TBoxDocManager.}CREATE{(object: TObject; itsHeap: THeap; itsPathPrefix: TFilePath) : TBoxDocManager}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBoxDocManager(TDocManager.CREATE(object, itsHeap, itsPathPrefix)); {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TBoxDocManager.}NewWindow{(heap: THeap; wmgrID: TWindowID):TWindow}; BEGIN {$IFC fTrace}BP(11);{$ENDC} NewWindow := TBoxWindow.CREATE(NIL, heap, wmgrID); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TBoxWindow; FUNCTION {TBoxWindow.}CREATE{(object: TObject; itsHeap: THeap; itsWmgrID: TWindowID): TWindow}; VAR box: TBox; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBoxWindow(TWindow.CREATE(object, itsHeap, itsWmgrID, TRUE)); WITH SELF DO BEGIN actions := NIL; boxes := NIL; END; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TBoxWindow.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('actions: TPanel'); Field('boxes: TPanel'); Field(''); END; {$ENDC} PROCEDURE {TBoxWindow.}BlankStationery; VAR docHeap: THeap; palBox: TBox; viewLRect: LRect; panel: TPanel; boxView: TBoxView; actView: TActView; selection: TSelection; BEGIN {$IFC fTrace}BP(10);{$ENDC} docHeap := SELF.Heap; palBox := TBox.CREATE(NIL, docHeap, zeroLRect, colorWhite); { make main panel first so it will be selectPanel & clickPanel} SetLRect(viewLRect, 0, 0, 100, 100); {+} {will get grown to 1 pg, then more as needed or requested} panel := TPanel.CREATE(NIL, docHeap, SELF, 30, 20, [aBar, aScroll, aSplit], [aScroll, aSplit]); boxView := TBoxView.CREATE(NIL, docHeap, panel, viewLRect, palBox, TList.CREATE(NIL,docHeap, 0)); SELF.boxes := panel; { make actions panel } panel := panel.Divide(h, palWidth+1, pixelsFromEdge, [], palWidth, [aScroll], [aBar]); actView := TActView.CREATE(NIL, docHeap, panel, palBox); selection := panel.selection.FreedAndReplacedBy(TPalSelection.CREATE(NIL, docHeap, actView)); SELF.actions := panel; { make the main selection only after all the panels are set up } selection := SELF.selectPanel.selection.FreedAndReplacedBy( TPickSelection.CREATE(NIL, docHeap, boxView, pickKind, zeroLPt)); {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TBoxWindow.}CanDoCommand{(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN}; BEGIN {$IFC fTrace}BP(11);{$ENDC} CASE cmdNumber OF uSelAll, uSplitH, uSplitV, uRemHSplit, uRemVSplit, uRemAllSplit: CanDoCommand := TRUE; uSaveSplits: BEGIN CanDoCommand := TRUE; checkIt := SELF.boxes.deletedSplits <> NIL; END; OTHERWISE CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt); END; {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TBoxWindow.}NewCommand{(cmdNumber: TCmdNumber): TCommand}; VAR palSelection: TPalSelection; boxPanel: TPanel; actView: TActView; vhs: VHSelect; topOrLeft: BOOLEAN; size: INTEGER; x: INTEGER; str: S255; band: TBand; scroller: TScroller; widestBand: TBand; s: TListScanner; firstPane: TPane; numSideBands: INTEGER; firstRegBand: INTEGER; tempBand: TBand; tempScrollBar: TScrollBar; a: TArray; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxPanel := SELF.boxes; NewCommand := NIL; CASE cmdNumber OF uSelAll: BEGIN SELF.SelectAll; {must go into select mode} SELF.SetAction(symArrow, TRUE); END; uSplitH, uSplitV, uRemHSplit, uRemVSplit: BEGIN IF (cmdNumber = uSplitH) OR (cmdNumber = uRemHSplit) THEN vhs := h ELSE vhs := v; IF (cmdNumber = uSplitH) OR (cmdNumber = uSplitV) THEN BEGIN widestBand := TBand(boxPanel.bands[vhs].At(1)); IF widestBand.scroller = NIL THEN {must be a sideband} widestBand := TSideBand(widestBand).CoBand; s := boxPanel.bands[vhs].Scanner; WHILE s.Scan(band) DO IF band.scroller <> NIL THEN {not a sideband} IF LengthRect(band.outerRect, vhs) > LengthRect(widestBand.outerRect, vhs) THEN widestBand := band; WITH widestBand.outerRect DO x := (topLeft.vh[vhs] + botRight.vh[vhs]) DIV 2; scroller := boxPanel.scrollBars[vhs].firstBox; {want the first scroller} END ELSE IF boxPanel.bands[vhs].Size < 2 THEN BEGIN scroller := NIL; process.Stop(phNoSplit); END ELSE BEGIN band := TBand(boxPanel.bands[vhs].Last); IF band.scroller = NIL THEN {must be a sideband} band := TSideBand(band).CoBand; scroller := band.scroller; x := MAXINT; END; IF scroller <> NIL THEN boxPanel.MoveSplitBefore(scroller, x); END; uRemAllSplit: BEGIN firstPane := TPane(boxPanel.panes.At(1)); FOR vhs := v TO h DO BEGIN numSideBands := 0; firstRegBand := 1; tempBand := TBand(boxPanel.bands[vhs].First); IF tempBand.scroller = NIL THEN BEGIN numSideBands := numSideBands + 1; firstRegBand := 2; END; tempBand := TBand(boxPanel.bands[vhs].Last); IF tempBand.scroller = NIL THEN numSideBands := numSideBands + 1; WHILE boxPanel.bands[vhs].Size-numSideBands > 1 DO BEGIN band := TBand(boxPanel.bands[vhs].At(firstRegBand+1)); boxPanel.MoveSplitBefore(band.scroller, MAXINT); END; END; IF boxPanel.deletedSplits <> NIL THEN boxPanel.deletedSplits.DelAll; END; uSaveSplits: IF boxPanel.deletedSplits = NIL THEN BEGIN a := TArray.CREATE(NIL, SELF.Heap, 0, SIZEOF(INTEGER)); boxPanel.deletedSplits := a; END ELSE BEGIN boxPanel.deletedSplits.Free; boxPanel.deletedSplits := NIL; END; OTHERWISE NewCommand := SUPERSELF.NewCommand(cmdNumber); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxWindow.}PutUpDialogBox(dialogBox: TDialogBox); BEGIN {$IFC fTrace}BP(10);{$ENDC} SUPERSELF.PutUpDialogBox(dialogBox); IF dialogBox = SELF.boxes.view.printManager.layoutDialogBox THEN BEGIN menuBar.Insert(mnuTypeStyle, 0); menuBar.Draw; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxWindow.}SelectAll; VAR panel: TPanel; boxView: TBoxView; PROCEDURE SelectBox(obj: TObject); BEGIN IF NOT TBox(obj).isSelected THEN boxView.ToggleHighlight(TBox(obj)); END; BEGIN {$IFC fTrace}BP(11);{$ENDC} panel := SELF.boxes; boxView := TBoxView(panel.view); boxView.EachVirtualPart(SelectBox); TPickSelection(panel.selection).ComputeBoundingBox; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxWindow.}SetAction{(action: INTEGER; doHilite: BOOLEAN)}; VAR actPanel: TPanel; BEGIN {$IFC fTrace}BP(11);{$ENDC} actPanel := SELF.actions; IF (action = symArrow) OR (action = symBox) THEN TPalSelection(actPanel.selection).SetSelection(1, action, doHilite, FALSE, TRUE); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxWindow.}TakeDownDialogBox; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF SELF.dialogBox = SELF.boxes.view.printManager.layoutDialogBox THEN BEGIN menuBar.Delete(mnuTypeStyle); menuBar.Draw; END; SUPERSELF.TakeDownDialogBox; {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TActView; FUNCTION {TActView.}CREATE{(object: TObject; itsHeap: THeap; itsPanel: TPanel; itsPalBox: TBox) : TActView}; VAR lr: LRect; box: TBox; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TActView(TPalView.CREATE(object, itsHeap, itsPanel, palWidth, palHeight, 1, 2)); SELF.extentLRect.bottom := 500; {increase view height so rest of palette will be white} SELF.GetBoxLRect(1, 2, lr); InsetLRect(lr, hPalMargin, vPalMargin); itsPalBox.shapeLRect := lr; SELF.palBox := itsPalBox; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TActView.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('palBox: TBox'); Field(''); END; {$ENDC} PROCEDURE {TActView.}DrawSymbol{(atCol, atRow: INTEGER)}; VAR lr: LRect; r: Rect; bounds: Rect; BEGIN {$IFC fTrace}BP(12);{$ENDC} IF atRow = symBox THEN SELF.palBox.Draw ELSE BEGIN SELF.GetBoxLRect(atCol, atRow, lr); thePad.lRectToRect(lr, r); SetRect(bounds, 0, 0, 16, 16); OffsetRect(bounds, r.left + (LengthRect(r, h)-8) DIV 2, r.top + (LengthRect(r, v)-16) DIV 2); CopyBits(arwBitMap, thePort^.portBits, arwBitMap.bounds, bounds, srcOr, NIL); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TActView.}MouseRelease; VAR panel: TPanel; palSelection: TPalSelection; boxWindow: TBoxWindow; boxView: TBoxView; PROCEDURE DeselectBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN boxView.ToggleHighlight(TBox(obj)); END; BEGIN {$IFC fTrace}BP(12);{$ENDC} panel := SELF.panel; palSelection := TPalSelection(panel.selection); palSelection.MouseRelease; IF SELF.palBox.isSelected THEN {user wants to draw another box -- deselect all boxes} BEGIN boxWindow := TBoxWindow(panel.window); boxView := TBoxView(boxWindow.boxes.view); boxView.EachVirtualPart(DeselectBox); TPickSelection(boxWindow.boxes.selection).ComputeBoundingBox; END; {$IFC fTrace}EP;{$ENDC} END; {Want to insure that when the palette box is marked isSelected if and only if that palette square is selected. Note that this is the ONLY place where we have to worry about this.} PROCEDURE {TPalView.}ChangedSelection(atCol, atRow: INTEGER); BEGIN SELF.palBox.isSelected := ((atCol = 1) AND (atRow = symBox)); END; END; METHODS OF TBoxView; FUNCTION {TBoxView.}CREATE{(object: TObject; itsHeap: THeap; itsPanel: TPanel; itsExtent: LRect; itsPalBox: TBox; itsBoxList: TList): TBoxView}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBoxView(itsPanel.NewView(object, itsExtent, TStdPrintManager.CREATE(NIL, itsHeap), stdMargins, TRUE)); WITH SELF DO BEGIN boxList := itsBoxList; palBox := itsPalBox; doingMove := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TBoxView.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('boxList: TList'); Field('palBox: TBox'); Field('doingMove: BOOLEAN'); END; {$ENDC} FUNCTION {TBoxView.}BoxWith{(LPt: LPoint): TBox}; PROCEDURE FindBox(obj: TObject); BEGIN IF LPtInLRect(LPt, TBox(obj).shapeLRect) THEN BoxWith := TBox(obj); {last one found (front one) is returned} END; BEGIN {$IFC fTrace}BP(11);{$ENDC} boxWith := NIL; SELF.EachVirtualPart(FindBox); {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TBoxView.}CursorAt{(mouseLPt: LPoint): TCursor}; VAR sketchSelection: TSketchSelection; shapeLRect: LRect; BEGIN {$IFC fTrace}BP(11);{$ENDC} CASE SELF.panel.selection.kind OF areaKind: CursorAt := fingerCursor; sketchKind: CursorAt := smCrossCursor; OTHERWISE IF SELF.palBox.isSelected THEN CursorAt := smCrossCursor ELSE CursorAt := arrowCursor; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxView.}Draw; VAR vhs: VHSelect; doneLCd: LONGINT; incLCd: LONGINT; startLPt: LPoint; endLPt: LPoint; str: S255; tempLRect: LRect; PROCEDURE DrawBox(obj: TObject); BEGIN IF NOT (TBox(obj).isSelected AND SELF.doingMove) THEN TBox(obj).Draw; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SELF.EachVirtualPart(DrawBox); {$IFC fTrace}EP;{$ENDC} END; {This is used when moving (for example) a group of boxes, to insure that no part of the bounding box of the group goes outside the view extent. bounds is the bounding box of the group of boxes and deltaLpt is the amount to offset the bounds. deltaLpt is adjusted so that the new bounds falls inside the view extent.} PROCEDURE {TBoxView.}FixLRectDelta{(bounds: LRect; VAR deltaLPt: LPoint)}; VAR diffLRect: LRect; realExtent: LRect; BEGIN {$IFC fTrace}BP(10);{$ENDC} realExtent := SELF.extentLRect; realExtent.topLeft := zeroLPt; LRectMinusLRect(realExtent, bounds, diffLRect); {diffLRect indicates the amount it is possible to move bounds in each direction without moving outside the view extent} LRectHaveLPt(diffLRect, deltaLPt); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxView.}InvalBounds{(bounds: LRect; isSelected: BOOLEAN)}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF isSelected THEN InsetLRect(bounds, -3, -2); thePad.InvalLRect(bounds); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxView.}MousePress{(mouseLPt: LPoint)}; VAR panel: TPanel; palSelection: TPalSelection; selection: TSelection; pickedBox: TBox; theKind: INTEGER; PROCEDURE DeselectBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN SELF.ToggleHighlight(TBox(obj)); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} panel := SELF.panel; IF clickState.fApple THEN {on Apple-click go into drawing mode} IF NOT SELF.palBox.isSelected THEN BEGIN panel.view.EachVirtualPart(DeselectBox); TBoxWindow(panel.window).SetAction(symBox, TRUE); END; IF SELF.palBox.isSelected THEN {user is drawing a box} selection := panel.selection.FreedAndReplacedBy( TSketchSelection.CREATE(NIL, SELF.Heap, SELF, mouseLPt)) ELSE BEGIN pickedBox := SELF.BoxWith(mouseLPt); theKind := pickKind; IF pickedBox = NIL THEN {user clicked outside all boxes -- make an area selection} selection := panel.selection.FreedAndReplacedBy( TAreaSelection.CREATE(NIL, SELF.Heap, SELF, mouseLPt, clickState.fShift)) ELSE BEGIN IF NOT (pickedBox.isSelected OR clickState.fShift)THEN SELF.EachVirtualPart(DeselectBox); {user clicked in an unselected box without shifting -- deselect the old boxes} IF clickState.fShift OR NOT pickedBox.isSelected THEN BEGIN {add/remove the box the user clicked in to the selection} IF pickedBox.isSelected THEN theKind := unPickKind; SELF.ToggleHighlight(pickedBox); END; selection := panel.selection.FreedAndReplacedBy( TPickSelection.CREATE(NIL, SELF.Heap, SELF, theKind, mouseLPt)); END; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxView.}EachActualPart{(PROCEDURE DoToObject(obj: TObject))}; BEGIN {$IFC fTrace}BP(11);{$ENDC} SELF.boxList.Each(DoToObject); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxView.}ToggleHighlight{(box: TBox)}; VAR isntSelected: BOOLEAN; highTransit: THighTransit; PROCEDURE ToggleOnThePad; BEGIN box.Highlight(highTransit); END; BEGIN {$IFC fTrace}BP(10);{$ENDC} isntSelected := NOT box.isSelected; highTransit := highToggle[isntSelected]; SELF.panel.OnAllPadsDo(ToggleOnThePad); box.isSelected := isntSelected; {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TPickSelection; FUNCTION {TPickSelection.}CREATE{(object: TObject; itsHeap: THeap; itsView: TView; itsKind: INTEGER; itsAnchorLPt: LPoint): TPickSelection}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TPickSelection(TSelection.CREATE(object, itsHeap, itsView, itsKind, itsAnchorLPt)); SELF.ComputeBoundingBox; {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TPickSelection.}CanDoCommand{(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN}; VAR boxView: TBoxView; BEGIN {$IFC fTrace}BP(11);{$ENDC} CASE cmdNumber OF uWhite, uLtGray, uGray, uDkGray, uBlack, uShades: BEGIN boxView := TBoxView(SELF.view); CanDoCommand := (SELF.kind <> nothingKind) OR (boxView.palBox.isSelected); END; uCut, uCopy, uClear, uFront, uBack, uDuplicate: CanDoCommand := SELF.kind <> nothingKind; uPaste: CanDoCommand := TRUE; OTHERWISE CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TPickSelection.}ComputeBoundingBox; VAR n: INTEGER; unitedLRect: LRect; boxWindow: TBoxWindow; PROCEDURE UniteBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN BEGIN IF n = 0 THEN unitedLRect := TBox(obj).shapeLRect ELSE UnionLRect(unitedLRect, TBox(obj).shapeLRect, unitedLRect); n := n + 1; END; END; BEGIN {$IFC fTrace}BP(11);{$ENDC} n := 0; SELF.view.EachVirtualPart(UniteBox); WITH SELF DO IF n = 0 THEN BEGIN kind := nothingKind; boundLRect := zeroLRect; END ELSE BEGIN IF kind = nothingKind THEN kind := pickKind; boundLRect := unitedLRect; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TPickSelection.}Highlight{(highTransit: THighTransit)}; VAR boxView: TBoxView; PROCEDURE HiliteBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN TBox(obj).Highlight(highTransit); END; PROCEDURE OutlineBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN TBox(obj).Outline; END; BEGIN {$IFC fTrace}BP(11);{$ENDC} boxView := TBoxView(SELF.view); IF boxView.doingMove THEN boxView.EachVirtualPart(OutlineBox) ELSE boxView.EachVirtualPart(HiliteBox); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TPickSelection.}MouseMove{(mouseLPt: LPoint)}; VAR boxView: TBoxView; panel: TPanel; diffLPt: LPoint; diffLRect: LRect; bbox: LRect; PROCEDURE MoveBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN {$H-} OffsetLRect(TBox(obj).shapeLRect, diffLPt.h, diffLPt.v); {$H+} END; BEGIN {$IFC fTrace}BP(11);{$ENDC} boxView := TBoxView(SELF.view); panel := SELF.panel; {First test if we want to drag this selection at all} IF SELF.kind = pickKind THEN BEGIN {How far did mouse move?} LPtMinusLPt(mouseLPt, SELF.currLPt, diffLPt); {Don't move past view boundaries} boxView.FixLRectDelta(SELF.boundLRect, diffLPt); {Move it if delta is nonzero} IF NOT EqualLPt(diffLPt, zeroLPt) THEN BEGIN IF NOT boxView.doingMove THEN {erase old boxes and change to outlines} BEGIN boxView.doingMove := TRUE; WITH SELF DO BEGIN {$H-} bbox := boundLRect; InsetLRect(bbox, -3, -2); panel.InvalLRect(bbox); {$H+} END; SELF.window.Update(TRUE); END; {$H-} OffsetLRect(SELF.boundLRect, diffLPt.h, diffLPt.v); {$H+} LPtPlusLPt(SELF.currLPt, diffLPt, mouseLPt); SELF.currLPt := mouseLPt; panel.Highlight(SELF, hOnToOff); boxView.EachVirtualPart(MoveBox); panel.Highlight(SELF, hOffToOn); END; END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TPickSelection.}MouseRelease; VAR deltaLPt: LPoint; actPanel: TPanel; BEGIN {$IFC fTrace}BP(11);{$ENDC} TBoxView(SELF.view).doingMove := FALSE; IF NOT EqualLPt(SELF.currLPt, SELF.anchorLPt) THEN BEGIN LPtMinusLPt(SELF.currLPt, SELF.anchorLPt, deltaLPt); {Must turn off highlighting in the palette, because the highlighting is already off in the other panel, so that the TMoveCmd does not turn off highlighting before performing, but does turn it on afterwards.} actPanel := TBoxWindow(SELF.window).actions; actPanel.Highlight(actPanel.selection, hOnToOff); SELF.window.PerformCommand(TMoveCmd.CREATE(NIL, SELF.Heap, uMoveBoxes, TBoxView(SELF.view), deltaLPt.h, deltaLPt.v)); END; {$IFC fTrace}EP;{$ENDC} END; FUNCTION {TPickSelection.}NewCommand{(cmdNumber: TCmdNumber): TCommand}; VAR pasteH: LONGINT; pasteV: LONGINT; boxView: TBoxView; heap: THeap; newColor: TColor; dialogWindow: TDialogWindow; dialog: TDialog; cluster: TCluster; checkbox: TCheckbox; okButton: TButton; cancelButton: TButton; PROCEDURE FindColor(obj: TObject); BEGIN IF TBox(obj).isSelected THEN newColor := TBox(obj).color; END; BEGIN {$IFC fTrace}BP(11);{$ENDC} NewCommand := NIL; boxView := TBoxView(SELF.view); heap := SELF.Heap; CASE cmdNumber OF uWhite, uLtGray, uGray, uDkGray, uBlack: BEGIN newColor := cmdNumber - uWhite + colorWhite; WITH boxView.palBox DO {$H-} IF isSelected THEN BEGIN color := newColor; TBoxWindow(SELF.window).actions.InvalLRect(shapeLRect); END ELSE IF SELF.kind = nothingKind THEN SELF.CantDoIt ELSE NewCommand := TRecolorCmd.CREATE(NIL, heap, cmdNumber, boxView, newColor); {$H+} END; uShades: BEGIN dialogWindow := NewStdDialogWindow(SELF.Heap, 120, diDismiss, diAccept, diDismiss); dialogWindow.freeOnDismissal := TRUE; {this dialog-box structure will vanish when it is taken down} dialog := dialogWindow.dialogView.AddNewDialog('SHAD'); cluster := dialog.AddStdCluster('Elmer', 60, 40); boxView.EachVirtualPart(FindColor); {will set var 'newColor' to the color of a selected box} checkbox := cluster.NewAlignedCheckbox(phWhite, newColor = colorWhite); checkbox := cluster.NewAlignedCheckbox(phLightGray, newColor = colorLtGray); checkbox := cluster.NewAlignedCheckbox(phGray, newColor = colorGray); checkbox := cluster.NewAlignedCheckbox(phDarkGray, newColor = colorDkGray); checkbox := cluster.NewAlignedCheckbox(phBlack, newColor = colorBlack); okButton := dialog.NewButton(phOK, stdButtonMetrics, NIL, uOKShades); cancelButton := dialog.NewButton(phCancel, stdButtonMetrics, okButton, noCmdNumber); dialog.SetDefaultButton(cancelButton); SELF.window.PutUpDialogBox(dialogWindow); NewCommand := NIL; END; uOKShades: {OK button was hit in the SHADES dialog} {+SW+} BEGIN checkbox := TCluster(TDialogWindow(SELF.window.dialogBox).mainDialog.children.First).hilitBox; CASE checkbox.idNumber OF phWhite: cmdNumber := uWhite; phLightGray: cmdNumber := uLtGray; phGray: cmdNumber := uGray; phDarkGray: cmdNumber := uDkGray; phBlack: cmdNumber := uBlack; END; NewCommand := SELF.NewCommand(cmdNumber); END; uDuplicate: NewCommand := TDuplicateCmd.CREATE(NIL, heap, cmdNumber, boxView, SELF); uClear: IF SELF.kind = nothingKind THEN SELF.CantDoIt ELSE NewCommand := TClearCmd.CREATE(NIL, heap, cmdNumber, boxView, SELF.boundLRect.topLeft); uCut, uCopy: IF SELF.kind = nothingKind THEN SELF.CantDoIt ELSE NewCommand := TBoxCutCopyCmd.CREATE(NIL, heap, cmdNumber, boxView, cmdNumber = uCut, SELF.boundLRect.topLeft); uPaste: BEGIN clipboard.Inspect; IF clipboard.hasView THEN BEGIN WITH SELF DO IF kind = nothingKind THEN BEGIN pasteH := boxView.clickLPt.h; pastev := boxView.clickLPt.v; END ELSE WITH boundLRect DO BEGIN pasteH := (left + right) DIV 2; pasteV := (top + bottom) DIV 2; END; NewCommand := TBoxPasteCmd.CREATE(NIL, heap, cmdNumber, boxView); END ELSE process.Stop(phUnkClip) END; uFront, uBack: NewCommand := TFrontBackCmd.CREATE(NIL, heap, cmdNumber, boxView, cmdNumber = uBack); OTHERWISE NewCommand := SUPERSELF.NewCommand(cmdNumber); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TPickSelection.Restore; PROCEDURE RestSel(obj: TObject); BEGIN TBox(obj).isSelected := TBox(obj).wasSelected; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SUPERSELF.Restore; SELF.view.EachVirtualPart(RestSel); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE TPickSelection.Save; PROCEDURE SaveSel(obj: TObject); BEGIN TBox(obj).wasSelected := TBox(obj).isSelected; END; BEGIN {$IFC fTrace}BP(10);{$ENDC} SUPERSELF.Save; SELF.view.EachVirtualPart(SaveSel); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TAreaSelection; FUNCTION {TAreaSelection.}CREATE{(object: TObject; itsHeap: THeap; itsView: TView; itsAnchorLPt: LPoint; itsShiftKey: BOOLEAN): TSketchSelection}; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TAreaSelection(TSelection.CREATE(object, itsHeap, itsView, areaKind, itsAnchorLPt)); SELF.shiftKey := itsShiftKey; SELF.ComputeBoundingBox; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TAreaSelection.}ComputeBoundingBox; BEGIN {$IFC fTrace}BP(12);{$ENDC} WITH SELF, boundLRect DO BEGIN topLeft := anchorLPt; botRight := currLPt; END; {$H-} RectifyLRect(SELF.boundLRect); {$H+} {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TAreaSelection.}Highlight{(highTransit: THighTransit)}; VAR lr: LRect; pat: Pattern; BEGIN {$IFC fTrace}BP(12);{$ENDC} {since area selections are created only when active, the highTransit should always be hOffToOn or hOnToOff; to highlight it, just draw a gray outline always} PenNormal; PenMode(patXor); thePad.LPatToPat(lPatGray, pat); PenPat(pat); FrameLRect(SELF.boundLRect); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TAreaSelection.}MouseMove{(mouseLPt: LPoint)}; VAR maxBoxLRect: LRect; diffLPt: LPoint; BEGIN {$IFC fTrace}BP(11);{$ENDC} WITH SELF.anchorLPt DO {$H-} SetLRect(maxBoxLRect, Max(h+10-MAXINT, 0), Max(v+10-MAXINT, 0), h+MAXINT-10, v+MAXINT-10); {$H+} LRectHaveLPt(maxBoxLRect, mouseLPt); LPtMinusLPt(mouseLPt, SELF.currLPt, diffLPt); IF NOT EqualLPt(diffLPt, zeroLPt) THEN BEGIN SELF.panel.Highlight(SELF, hOnToOff); SELF.currLPt := mouseLPt; SELF.ComputeBoundingBox; SELF.panel.Highlight(SELF, hOffToOn); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TAreaSelection.}MouseRelease; VAR boxView: TBoxView; selection: TSelection; PROCEDURE SelectInArea(obj: TObject); VAR inside: BOOLEAN; BEGIN WITH SELF DO BEGIN {$H-} inside := LRectsNest(boundLRect, TBox(obj).shapeLRect); IF (shiftKey AND inside) OR (NOT shiftKey AND (TBox(obj).isSelected <> inside)) THEN boxView.ToggleHighlight(TBox(obj)); {$H+} END; END; BEGIN {$IFC fTrace}BP(11);{$ENDC} SELF.panel.Highlight(SELF, hOnToOff); boxView := TBoxView(SELF.view); boxView.EachVirtualPart(SelectInArea); selection := SELF.FreedAndReplacedBy( TPickSelection.CREATE(NIL, SELF.Heap, boxView, pickKind, SELF.anchorLPt)); {don't refer to SELF after this} {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TSketchSelection; FUNCTION {TSketchSelection.}CREATE{(object: TObject; itsHeap: THeap; itsView: TBoxView; itsAnchorLPt: LPoint): TSketchSelection}; VAR box: TBox; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TSketchSelection(TSelection.CREATE(object, itsHeap, itsView, sketchKind, itsAnchorLPt)); box := TBox(itsView.palBox.Clone(itsHeap)); box.shapeLRect := zeroLRect; SELF.box := box; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TSketchSelection.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('box: TBox'); END; {$ENDC} PROCEDURE {TSketchSelection.}Highlight{(highTransit: THighTransit)}; BEGIN {$IFC fTrace}BP(12);{$ENDC} {since sketch selections are created only when creating a box, the highTransit should always be hOffToOn; to highlight it, just outline the box} SELF.box.Outline; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TSketchSelection.}MouseMove{(mouseLPt: LPoint)}; VAR maxBoxLRect: LRect; diffLPt: LPoint; box: TBox; BEGIN {$IFC fTrace}BP(11);{$ENDC} WITH SELF.anchorLPt DO {$H-} SetLRect(maxBoxLRect, h+10-MAXINT, v+10-MAXINT, h+MAXINT-10, v+MAXINT-10); {$H+} LRectHaveLPt(maxBoxLRect, mouseLPt); LPtMinusLPt(mouseLPt, SELF.currLPt, diffLPt); IF NOT EqualLPt(diffLPt, zeroLPt) THEN BEGIN SELF.currLPt := mouseLPt; box := SELF.box; SELF.panel.Highlight(SELF, hOnToOff); {NOTE: the first time this is done there is no highlighting. Normally, this statement would cause a problem, because it would be turning the highlighting ON. But the box shape is initially a zeroLRect, so it does not mess things up} box.shapeLRect.topLeft := SELF.anchorLPt; box.shapeLRect.botRight := mouseLPt; {$h-} RectifyLRect(box.shapeLRect); {$H+} SELF.panel.Highlight(SELF, hOffToOn); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TSketchSelection.}MouseRelease; VAR myPanel: TPanel; myBoxView: TBoxView; myBox: TBox; drawnLRect: LRect; pickSelection: TPickSelection; PROCEDURE DeselectBox(obj: TObject); BEGIN IF TBox(obj).isSelected THEN TBox(obj).isSelected := FALSE; END; BEGIN {$IFC fTrace}BP(11);{$ENDC} WITH SELF DO BEGIN myPanel := panel; myBoxView := TBoxView(view); myBox := box; END; drawnLRect := myBox.shapeLRect; {always need a pickSelection in the panel} pickSelection := TPickSelection(SELF.FreedAndReplacedBy( TPickSelection.CREATE(NIL, SELF.Heap, myBoxView, pickKind, SELF.anchorLPt))); {dont refer to SELF after this} IF (drawnLRect.right - drawnLRect.left <= 4) OR (drawnLRect.bottom - drawnLRect.top <= 4) THEN BEGIN {too small, so don't remember the box} myBoxView.EachVirtualPart(DeselectBox); {MousePress left the isSelected flags on} pickSelection.ComputeBoundingBox; {because we have now deselected the old selection} myBox.InvalInTheView(myBoxView); myBox.Free; END ELSE {this also turns isSelected off, but copies it into wasSelected first} myPanel.window.PerformCommand(TSketchBoxCmd.CREATE(NIL, pickSelection.Heap, uCreateBox, myBoxView, myBox)); {$IFC fTrace}EP;{$ENDC} END; END; {COMMAND CLASSES} {Called as the last thing in every .Perform method} PROCEDURE EndCommand(SELF: TBoxView); VAR panel: TPanel; BEGIN panel := SELF.panel; TPickSelection(panel.selection).ComputeBoundingBox; panel.selection.MarkChanged; TBoxWindow(panel.window).SetAction(symArrow, FALSE); {turning highlighting on is handled by Toolkit} END; {Called as the last thing in many .Perform methods; this invalidates all the boxes marked isSelected and calls EndCommand. (It avoids repeating the InvalBox procedure many times.)} PROCEDURE InvalSelection(boxView: TBoxView); PROCEDURE InvalBox(obj: TObject); VAR box: TBox; BEGIN box := TBox(obj); IF box.isSelected THEN box.InvalInTheView(boxView); END; BEGIN boxView.EachActualPart(InvalBox); EndCommand(boxView); END; {NOTE: Unless otherwise mentioned, we let the Toolkit managed the wasSelected and isSelected bits. Before command.Perform is called, the Toolkit calls selection.Restore (unless it is the doPhase). After command.Perform is called, the Toolkit calls selection.Save. Therefore on the doPhase the wasSelected bits have not been set, but the isSelected bits reflect the current selection. On undoPhase or redoPhase both isSelected and wasSelected reflect the current selection at the time the command was done. That is why the command.Perform methods always check the isSelected bits. command.FilterAndDo and command.EachVirtualPart must check wasSelected bits because when they are called, the current selection can be anything. You must be careful about calling TView.EachVirtualPart from within command.Perform because of the following: - On the doPhase the command object has already been installed and TView.EachVirtualPart will call command.EachVirtualPart. - But the selection is not saved until after command.Perform is done, so that the wasSelected have not been set yet. That is why TRecolorCmd.Perform (for example) calls TView.EachActualPart instead. } METHODS OF TRecolorCmd; FUNCTION {TRecolorCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView; itsColor: TColor): TRecolorCmd}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TRecolorCmd(TCommand.CREATE(object, itsHeap, itsCmdNumber, itsView, TRUE, revealAll)); SELF.newColor := itsColor; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TRecolorCmd.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('newColor: INTEGER'); END; {$ENDC} PROCEDURE {TRecolorCmd.}Commit; VAR s: TListScanner; color: TColor; box: TBox; BEGIN {$IFC fTrace}BP(12);{$ENDC} s := TBoxView(SELF.image).boxList.Scanner; color := SELF.newColor; WHILE s.Scan(box) DO IF box.wasSelected THEN box.color := color; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TRecolorCmd.}Perform{(cmdPhase: TCmdPhase)}; BEGIN {$IFC fTrace}BP(12);{$ENDC} InvalSelection(TBoxView(SELF.image)); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TRecolorCmd.}FilterAndDo{(actualObj: TObject; PROCEDURE DoToObject(filteredObj: TObject))}; VAR saveColor: TColor; box: TBox; BEGIN {$IFC fTrace}BP(12);{$ENDC} box := TBox(actualObj); IF box.wasSelected THEN BEGIN saveColor := box.color; box.color := SELF.newColor; DoToObject(box); box.color := saveColor; END ELSE DoToObject(box); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TMoveCmd; FUNCTION {TMoveCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView; itsHOffset, itsVOffset: LONGINT): TMoveCmd}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TMoveCmd(TCommand.CREATE(object, itsHeap, itsCmdNumber, itsView, TRUE, revealNone)); WITH SELF DO BEGIN unHiliteBefore[doPhase] := FALSE; hOffset := itsHOffset; vOffset := itsVOffset; END; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TMoveCmd.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('hOffset: LONGINT'); Field('vOffset: LONGINT'); END; {$ENDC} PROCEDURE {TMoveCmd.}Perform{(cmdPhase: TCmdPhase)}; VAR boxView: TBoxView; panel: TPanel; diffLPt: LPoint; aBox: TBox; PROCEDURE InvalOnThePad; BEGIN boxView.InvalBounds(aBox.shapeLRect, TRUE); END; PROCEDURE MoveBox(obj: TObject); BEGIN aBox := TBox(obj); IF aBox.isSelected THEN BEGIN IF cmdPhase <> doPhase THEN {on doPhase boxes have already been moved} BEGIN panel.OnAllPadsDo(InvalOnThePad); {invalidate old box position} {$H-} OffsetLRect(aBox.shapeLRect, diffLPt.h, diffLPt.v); {$H+} END; panel.OnAllPadsDo(InvalOnThePad); END; END; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxView := TBoxView(SELF.image); panel := boxView.panel; WITH SELF DO {$H-} CASE cmdPhase OF doPhase, redoPhase: SetLPt(diffLPt, hOffset, vOffset); undoPhase: SetLPt(diffLPt, -hOffset, -vOffset); END; {$H+} boxView.EachActualPart(MoveBox); EndCommand(boxView); boxView.panel.window.RevealSelection(TRUE {reveal ALL}, FALSE {don't highlight}); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TBoxCutCopyCmd; FUNCTION {TBoxCutCopyCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TView; isCutCmd: BOOLEAN; itsTopLeft: LPoint): TBoxCutCopyCmd}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBoxCutCopyCmd(TCutCopyCommand.CREATE(object, itsHeap, itsCmdNumber, itsView, isCutCmd)); SELF.selTopLeft := itsTopLeft; IF NOT isCutCmd THEN {no need to highlight on doPhase of a copy command} WITH SELF DO BEGIN unHiliteBefore[doPhase] := FALSE; hiliteAfter[doPhase] := FALSE; END; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TBoxCutCopyCmd.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('selTopLeft: LPoint'); END; {$ENDC} PROCEDURE {TBoxCutCopyCmd.}Commit; VAR s: TListScanner; box: TBox; BEGIN {$IFC fTrace}BP(12);{$ENDC} IF SELF.isCut THEN BEGIN s := TBoxView(SELF.image).boxList.Scanner; WHILE s.Scan(box) DO IF box.wasSelected THEN s.Delete(TRUE); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxCutCopyCmd.}DoCutCopy{(clipSelection: TSelection; deleteOriginal: BOOLEAN; cmdPhase: TCmdPhase)}; VAR boxView: TBoxView; pickSelection: TPickSelection; centerLPt: LPoint; clipHeap: THeap; clipPanel: TPanel; clipBoxList: TList; boundLRect: LRect; deltaH: LONGINT; deltaV: LONGINT; clipBoxView: TBoxView; clipPickSelection: TPickSelection; palBox: TBox; PROCEDURE DoCopy(obj: TObject); VAR box: TBox; clipBox: TBox; BEGIN box := TBox(obj); IF box.isSelected THEN BEGIN box.wasSelected := TRUE; {Need to do this because the saved selection reflects the state AFTER the command is performed. If this was a cut command, then the selected boxes are not part of the selection, so that their wasSelected bits would not be set properly.} clipBox := TBox(box.Clone(clipHeap)); clipBox.isSelected := TRUE; {$H-} OffsetLRect(clipBox.shapeLRect, deltaH, deltaV); {$H+} clipBoxList.InsLast(clipBox); END; END; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxView := TBoxView(SELF.image); pickSelection := TPickSelection(boxView.panel.selection); boundLRect := pickSelection.boundLRect; { set centerLPt to center of old boundLRect } WITH boundLRect DO SetLPt(centerLPt, (left+right) DIV 2, (top+bottom) DIV 2); IF cmdPhase = doPhase THEN BEGIN {prepare to copy} clipHeap := clipSelection.Heap; clipPanel := clipSelection.panel; clipBoxList := TList.CREATE(NIL, clipHeap, 0); WITH boundLRect DO BEGIN deltaH := -left; deltaV := -top; END; boxView.EachActualPart(DoCopy); {copy the selected boxes into the Clipboard} {make clipboard selection} OffsetLRect(boundLRect, deltaH, deltaV); palBox := TBox.CREATE(NIL, clipHeap, zeroLRect, colorWhite); PushFocus; clipboard.window.Focus; clipBoxView := TBoxView.CREATE(NIL, clipHeap, clipPanel, boundLRect, palBox, clipBoxList); PopFocus; clipPickSelection := TPickSelection(clipSelection.FreedAndReplacedBy( TPickSelection.CREATE(NIL, clipHeap, clipBoxView, pickKind, zeroLPt))); END; { set the selection's anchorLPt and currLPt so that a paste right after the cut will be a NOP } IF SELF.isCut THEN BEGIN IF cmdPhase <> undoPhase THEN WITH boxView.panel.selection DO BEGIN anchorLPt := centerLPt; currLPt := centerLPt; END; InvalSelection(boxView); {If we undo a cut, we don't want to see the current selection, we want to see the boxes that are being restored. Set up the command's revelation so that the Toolkit does not automatically reveal the selection ...} IF cmdPhase <> undoPhase THEN {next UNDO will be the undoPhase} SELF.revelation := revealNone ELSE BEGIN SELF.revelation := revealAll; {... then reveal the selection after the UNDO is finished} boxView.panel.window.RevealSelection(TRUE {reveal ALL}, FALSE {don't highlight}); {we don't highlight because the Toolkit will do that for us} END; END ELSE EndCommand(boxView); {don't need to invalidate on a copy} {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxCutCopyCmd.}EachVirtualPart{(PROCEDURE DoToObject(filteredObj: TObject))}; BEGIN {$IFC fTrace}BP(12);{$ENDC} IF SELF.isCut THEN SUPERSELF.EachVirtualPart(DoToObject) ELSE SELF.image.EachActualPart(DoToObject); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxCutCopyCmd.}FilterAndDo{(actualObj: TObject; PROCEDURE DoToObject(filteredObj: TObject))}; BEGIN {$IFC fTrace}BP(12);{$ENDC} IF NOT TBox(actualObj).wasSelected THEN DoToObject(actualObj); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TClearCmd; FUNCTION {TClearCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView; itsTopLeft: LPoint): TClearCmd}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TClearCmd(TBoxCutCopyCmd.CREATE(object, itsHeap, itsCmdNumber, itsView, TRUE, itsTopLeft)); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TClearCmd.}Perform{(cmdPhase: TCmdPhase)}; BEGIN {$IFC fTrace}BP(12);{$ENDC} InvalSelection(TBoxView(SELF.image)); {See the comment in TBoxCutCopyCmd.DoCutCopy above; the same thing applies here.} IF cmdPhase <> undoPhase THEN SELF.revelation := revealNone ELSE BEGIN SELF.revelation := revealAll; TView(SELF.image).panel.window.RevealSelection(TRUE {reveal ALL}, FALSE {don't highlight}); END; {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TBoxPasteCmd; FUNCTION {TBoxPasteCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView): TBoxPasteCmd}; VAR itsPasteBoxList: TList; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TBoxPasteCmd(TPasteCommand.CREATE(object, itsHeap, itsCmdNumber, itsView)); itsPasteBoxList := TList.CREATE(NIL, itsHeap, 0); SELF.pasteBoxList := itsPasteBoxList; SELF.revelation := revealNone; {when we do the paste we don't care what the current selection is, we want to see the pasted boxes} {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxPasteCmd.}Free; BEGIN {$IFC fTrace}BP(12);{$ENDC} SELF.pasteBoxList.Free; SUPERSELF.Free; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TBoxPasteCmd.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('pasteBoxList: TList'); END; {$ENDC} PROCEDURE {TBoxPasteCmd.}Commit; VAR boxList: TList; s: TListScanner; box: TBox; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxList := TBoxView(SELF.image).boxList; s := SELF.pasteBoxList.Scanner; WHILE s.Scan(box) DO BEGIN boxList.InsLast(box); s.Delete(FALSE); END; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxPasteCmd.}DoPaste{(clipSelection: TSelection; pic: PicHandle; cmdPhase: TCmdPhase)}; VAR boxView: TBoxView; panel: TPanel; docHeap: THeap; clipPickSelection: TPickSelection; pickSelection: TPickSelection; bbox: LRect; deltaLPt: LPoint; clipBoxView: TBoxView; pasteList: TList; s: TListScanner; clipBox: TBox; box: TBox; PROCEDURE Deselect(obj: TObject); BEGIN TBox(obj).isSelected := FALSE; END; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxView := TBoxView(SELF.image); panel := boxView.panel; docHeap := boxView.Heap; {Set up the pastBoxList} IF cmdPhase = doPhase THEN { If the clipboard selection is of class TBoxSelection then we can paste it into document, otherwise we have to do other things } IF NOT InClass(clipSelection, TPickSelection) THEN panel.selection.CantDoIt ELSE BEGIN clipPickSelection := TPickSelection(clipSelection); pickSelection := TPickSelection(panel.selection); bbox := clipPickSelection.boundLRect; { Figure out how much to move clipboard info for pasting } { First, set deltaLPt to point at which to paste center of clipboard: anchorLPt of selection if no selection, else center of selection bounding box } WITH pickSelection DO {$H-} IF kind = nothingKind THEN WITH anchorLPt DO SetLPt(deltaLPt, h, v) ELSE WITH boundLRect DO SetLPt(deltaLPt, (left+right) DIV 2, (top+bottom) DIV 2); {$H+} { Next, set deltaLPt to amount by which to offset clipPickSelection; NOTE: bbox.topLeft = zeroLRect } WITH deltaLPt, bbox DO BEGIN h := h - right DIV 2; v := v - bottom DIV 2; { Move bbox to its potential position } {$H-} OffsetLRect(bbox, h, v); {$H+} END; { Then, if paste bounds = current selection bounds, offset paste point a little more } IF EqualLRect(bbox, pickSelection.boundLRect) THEN WITH deltaLPt DO BEGIN h := h + hDupOffset; v := v + vDupOffset; END; { Finally, insure clipSelection.boundLRect is within the view } boxView.FixLRectDelta(clipPickSelection.boundLRect, deltaLPt); clipBoxView := TBoxView(clipPickSelection.view); pasteList := SELF.pasteBoxList; s := clipBoxView.boxList.Scanner; WHILE s.Scan(clipBox) DO BEGIN box := TBox(clipBox.Clone(docHeap)); WITH box DO BEGIN isSelected := TRUE; {$H-} OffsetLRect(shapeLRect, deltaLPt.h, deltaLPt.v); {$H+} END; pasteList.InsLast(box); END; END; SELF.FinishPaste(cmdPhase); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxPasteCmd.}EachVirtualPart{(PROCEDURE DoToObject(filteredObj: TObject))}; BEGIN {$IFC fTrace}BP(12);{$ENDC} SELF.image.EachActualPart(DoToObject); IF SELF.pasteBoxList <> NIL THEN SELF.pasteBoxList.Each(DoToObject); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TBoxPasteCmd.}FinishPaste{(cmdPhase: TCmdPhase)}; VAR boxView: TBoxView; panel: TPanel; box: TBox; s: TListScanner; PROCEDURE InvalPastedBox(obj: TObject); BEGIN {$IFC fTrace}BP(10);{$ENDC} TBox(obj).InvalInTheView(boxView); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE Deselect(obj: TObject); BEGIN TBox(obj).isSelected := FALSE; END; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxView := TBoxView(SELF.image); panel := boxView.panel; SELF.pasteBoxList.Each(InvalPastedBox); IF cmdPhase = doPhase THEN boxView.EachActualPart(Deselect); s := SELF.pasteBoxList.Scanner; WHILE s.Scan(box) DO box.InvalInTheView(boxView); EndCommand(boxView); {Similar to Cut/Clear. If we are on the doPhase or redoPhase we need to scroll the pasted boxes into view ourselves; on the undoPhase, we can let the Toolkit do it for us.} IF cmdPhase = undoPhase THEN {the next phase is doPhase or redoPhase} SELF.revelation := revealNone ELSE BEGIN SELF.revelation := revealAll; boxView.panel.window.RevealSelection(TRUE {reveal ALL}, FALSE {don't highlight}); END; {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TSketchBoxCmd; FUNCTION {TSketchBoxCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView; itsBox: TBox): TAddBoxesCmd}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TSketchBoxCmd(TBoxPasteCmd.CREATE(object, itsHeap, itsCmdNumber, itsView)); SELF.pasteBoxList.InsLast(itsBox); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TSketchBoxCmd.}Perform{(cmdPhase: TCmdPhase)}; BEGIN {$IFC fTrace}BP(12);{$ENDC} SELF.FinishPaste(cmdPhase); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TDuplicateCmd; FUNCTION {TDuplicateCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView; itsPickSelection: TPickSelection): TDuplicateCmd}; VAR deltaLPt: LPoint; list: TList; PROCEDURE DuplicateBox(obj: TObject); VAR box: TBox; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF TBox(obj).isSelected THEN BEGIN box := TBox(obj.Clone(itsHeap)); {$H-} OffsetLRect(box.shapeLRect, deltaLPt.h, deltaLPt.v); list.InsLast(box); END; {$IFC fTrace}EP;{$ENDC} END; BEGIN {$IFC fTrace}BP(11);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TDuplicateCmd(TBoxPasteCmd.CREATE(object, itsHeap, itsCmdNumber, itsView)); list := SELF.pasteBoxList; {Created by TBoxPasteCmd.CREATE} SetLPt(deltaLpt, hDupOffset, vDupOffset); itsView.FixLRectDelta(itsPickSelection.boundLRect, deltaLPt); itsView.EachVirtualPart(DuplicateBox); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TDuplicateCmd.}Perform{(cmdPhase: TCmdPhase)}; BEGIN {$IFC fTrace}BP(12);{$ENDC} SELF.FinishPaste(cmdPhase); {$IFC fTrace}EP;{$ENDC} END; END; METHODS OF TFrontBackCmd; FUNCTION {TFrontBackCmd.}CREATE{(object: TObject; itsHeap: THeap; itsCmdNumber: TCmdNumber; itsView: TBoxView; isSendToBack: BOOLEAN): TFrontBackCmd}; BEGIN {$IFC fTrace}BP(10);{$ENDC} IF object = NIL THEN object := NewObject(itsHeap, THISCLASS); SELF := TFrontBackCmd(TCommand.CREATE(object, itsHeap, itsCmdNumber, itsView, TRUE, revealAll)); SELF.sendToBack := isSendToBack; {$IFC fTrace}EP;{$ENDC} END; {$IFC fDebugMethods} PROCEDURE {TFrontBackCmd.}Fields{(PROCEDURE Field(nameAndType: S255))}; BEGIN SUPERSELF.Fields(Field); Field('sendToBack: BOOLEAN'); Field(''); END; {$ENDC} PROCEDURE {TFrontBackCmd.}Commit; VAR boxList: TList; tempList: TList; s: TListScanner; box: TBox; BEGIN {$IFC fTrace}BP(12);{$ENDC} tempList := TList.CREATE(NIL, SELF.Heap, 0); boxList := TBoxView(SELF.image).boxList; s := boxList.Scanner; WHILE s.Scan(box) DO IF box.wasSelected THEN BEGIN tempList.InsLast(box); s.Delete(FALSE); END; boxList.InsManyAt(boxList.size*ORD(NOT SELF.sendToBack) + 1, tempList, 1, tempList.Size); tempList.FreeObject; {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TFrontBackCmd.}Perform{(cmdPhase: TCmdPhase)}; VAR boxView: TBoxView; PROCEDURE InvalBox(obj: TObject); VAR box: TBox; BEGIN box := TBox(obj); IF box.isSelected THEN box.InvalInTheView(boxView); END; BEGIN {$IFC fTrace}BP(12);{$ENDC} boxView := TBoxView(SELF.image); boxView.EachActualPart(InvalBox); EndCommand(boxView); {$IFC fTrace}EP;{$ENDC} END; PROCEDURE {TFrontBackCmd.}EachVirtualPart{(PROCEDURE DoToObject(filteredObj: TObject))}; VAR wantChanged: BOOLEAN; PROCEDURE DoToFilteredBox(obj: TObject); BEGIN IF wantChanged = TBox(obj).wasSelected THEN DoToObject(obj); END; BEGIN {$IFC fTrace}BP(12);{$ENDC} wantChanged := SELF.sendToBack; SELF.image.EachActualPart(DoToFilteredBox); wantChanged := NOT wantChanged; SELF.image.EachActualPart(DoToFilteredBox); {$IFC fTrace}EP;{$ENDC} END; END;