/**** * * Implementation of idraw-interface.h * */ #include "commands.h" #include "dialogbox.h" #include "drawing.h" #include "drawingview-interface.h" #include "drawingview.h" #include "editor.h" #include "errhandler.h" #include "history.h" #include "idraw-interface.h" #include "idraw.h" #include "istring.h" #include "listchange.h" #include "listselectn.h" #include "mapipaint.h" #include "mapkey.h" #include "rubbands.h" #include "selection.h" #include "slellipses.h" #include "sllines.h" #include "slpolygons.h" #include "slsplines.h" #include "sltext.h" #include "state.h" #include "stateviews.h" #include "textedit.h" #include "tools.h" #include "version.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // The default constructor performs appropriate initialiation. IdrawInterface::IdrawInterface (Screen* s) : Idraw(0, NULL){ this->s = s; InitPPaint(); Init(); } // IdrawInterface parses its command line and initializes its members. IdrawInterface::IdrawInterface (Screen* s, int argc, char** argv) : Idraw(argc, argv) { ParseArgs(argc, argv); this->s = s; InitPPaint(); Init(); } // Nothing needs be done here, since all data member deletion is handled by the // parent Idraw destructor. IdrawInterface::~IdrawInterface () { } // Show displays this in the Screen (aka, World) sent into the constructor. void IdrawInterface::Show () { s->InsertApplication(this); } // Run opens the initial file if one was given before starting to run. void IdrawInterface::Run () { if (initialfile != nil) { SetCursor(hourglass); editor->Open(initialfile); SetCursor(defaultCursor); } Interactor::Run(); } // Handle does nothing by default. It can be specialized to handle events on // that occur on the drawing area, since DrawingView::Handle forwards all of // its events here. void IdrawInterface::Handle (Event& e) { } // Update gets the picture's total tranformation matrix whenever it // changes and stores it in State for creating new graphics. void IdrawInterface::Update () { Transformer t; drawing->GetPictureTT(t); state->SetGraphicT(t); } // GetDrawing returns this' drawing data member for access to lower level // drawing functions, such as PickSelectionIntersecting. Drawing* IdrawInterface::GetDrawing() { return drawing; } // ParseArgs stores the name of an initial file to open if any. void IdrawInterface::ParseArgs (int argc, char** argv) { initialfile = nil; if (argc == 2) { initialfile = argv[1]; } else if (argc > 2) { fprintf(stderr, "too many arguments, usage: idraw [file]\n"); const int PARSINGERROR = 1; exit(PARSINGERROR); } } // Init creates a sensor to catch keystrokes, creates members and // initializes links between them, and composes them into a view with // boxes, borders, glue, and frames. void IdrawInterface::Init () { input = new Sensor; input->Catch(KeyEvent); drawing = new Drawing(8.5*inches, 11*inches, 0.05*inch); drawingview = new DrawingViewInterface(drawing->GetPage(), this); editor = new Editor(this); errhandler = new ErrHandler; mapkey = new MapKey; state = new State(this, drawing->GetPage()); tools = new Tools(editor, mapkey); drawingview->GetPerspective()->Attach(this); drawingview->SetSelectionList(drawing->GetSelectionList()); drawingview->SetState(state); drawingview->SetTools(tools); editor->SetDrawing(drawing); editor->SetDrawingView(drawingview); editor->SetState(state); errhandler->SetEditor(editor); errhandler->Install(); /* * Go ahead and build all the pieces of the full UI, such as menubar and * tools, but do not install them in the default view. This will allow us * to add some of these things back if we want to at some future date. */ VBox* status = new VBox( new HBox( new ModifStatusView(state), new DrawingNameView(state), new GriddingView(state), new FontView(state), new MagnifView(state, drawingview) ), new HBorder ); HBox* indics = new HBox( new BrushView(state), new VBorder, new PatternView(state) ); HBox* cmds = new HBox( new Commands(editor, mapkey, state), new HGlue ); VBox* panel = new VBox( tools, new VGlue, new HBorder, new Panner(drawingview) ); panel->Propagate(false); HBorder* hborder = new HBorder; VBorder* vborder = new VBorder; Tray* t = new Tray(drawingview); /* * The commented out items that follow compose the full UI as is done for * a regular idraw. They are replaced by the single preceding line that * simply inserts the drawingview into the outer containing tray. * Tray* t = new Tray(); t->HBox(t, status, t); t->HBox(t, indics, vborder, cmds, t); t->HBox(t, hborder, t); t->HBox(t, panel, vborder, drawingview, t); t->VBox(t, status, indics, hborder, panel, t); t->VBox(t, status, vborder, t); t->VBox(t, status, cmds, hborder, drawingview, t); * */ Insert(new Frame(t, 1)); } void IdrawInterface::Select(Selection* s) { if (s != nil) { drawing->Ungrasp(s); /* In case it's already selected. */ drawing->Extend(s); drawingview->DrawHandles(); } } void IdrawInterface::Unselect(Selection* s) { if (s != nil) { drawingview->ErasePickedHandles(s); drawing->Ungrasp(s); drawingview->DrawHandles(); } } /* void IdrawInterface::SelectAlso(Selection* s) {} */ void IdrawInterface::SelectMultiple(SelectionList* sl) {} void IdrawInterface::UnselectMultiple(SelectionList* s) {} void IdrawInterface::Move(Coord l, Coord b) { Coord oldl, oldb, oldr, oldt; drawing->GetBox(oldl, oldb, oldr, oldt); if ((l != 0) || (b != 0)) { float x0, y0, x1, y1; Transformer t; drawing->GetPictureTT(t); t.InvTransform(float(oldl), float(oldb), x0, y0); t.InvTransform(float(l+oldl), float(b+oldb), x1, y1); editor->Do(new MoveChange(drawing, drawingview, x1 - x0, y1 - y0)); } } void IdrawInterface::Move(Selection* s, Coord l, Coord b) { Select(s); Move(l, b); Unselect(s); } void IdrawInterface::Scale(float factor) { if (factor != 0) { editor->Do(new ScaleChange(drawing, drawingview, factor, factor)); } } void IdrawInterface::Scale(Selection* s, float factor) { Select(s); Scale(factor); Unselect(s); } void IdrawInterface::Stretch(Alignment side, float amount) { if (amount != 0) { editor->Do(new StretchChange(drawing, drawingview, amount, side)); } } void IdrawInterface::Stretch(Selection* s, Alignment side, float factor) { Select(s); Stretch(side, factor); Unselect(s); } void IdrawInterface::Rotate(float degrees) { if (degrees != 0) { editor->Do(new RotateChange(drawing, drawingview, degrees)); } } /* void IdrawInterface::Rotate(Selection* s, float degrees) { Select(s); Rotate(degrees); Unselect(s); } */ void IdrawInterface::Rotate(Selection* s, float radians) { Coord l, b, r, t; float cx, cy, angle; Select(s); s->GetBox(l,b,r,t); s->GetCenter(cx,cy); RotatingRect* rotatingrect = new RotatingRect(nil, nil, l, b, r, t, round(cx), round(cy), 0, 0); angle = rotatingrect->ConvertTrackToRotation(radians); delete rotatingrect; Rotate(angle); Unselect(s); } void IdrawInterface::Reshape(Coord x0, Coord y0, Coord x1, Coord y1) { Selection* pick = drawing->PickSelectionShapedBy(x0, y0); Selection* reshapedpick; char* name; Event dummyevent; if (pick) { Rubberband* shape = pick->CreateShape(x1, y1); dummyevent.eventType = UpEvent; drawingview->Manipulate(dummyevent, shape, UpEvent); shape->Track(x1, y1); reshapedpick = pick->GetReshapedCopy(); editor->Do(new ReplaceChange( drawing, drawingview, pick, reshapedpick)); } } #ifdef DEMO void IdrawInterface::Reshape(Selection* s, Coord x0, Coord y0, int index, Coord x1, Coord y1) { Selection* reshapedpick; char* name; ObjectTabEntry* o; if (s) { reshapedpick = s->ReshapeSelection(x1,y1,index); reshapedpick->SetName(name = s->GetName()); o = idraw->LookupObject(name); o->SetCurSelection(reshapedpick); editor->Do(new ReplaceChange( drawing, drawingview, s, reshapedpick)); } } #endif void IdrawInterface::Magnify(Coord x0, Coord y0, Coord x1, Coord y1) { drawingview->Magnify(x0, y0, x1, y1); } void IdrawInterface::Magnify(Selection* s, Coord x0, Coord y0, Coord x1, Coord y1) { Select(s); Magnify(x0, y0, x1, y1); Unselect(s); } Selection* IdrawInterface::DrawText(Coord l, Coord b, char* text) { int len = strlen(text); Selection* rtn; drawingview->EraseHandles(); drawing->Clear(); if (len > 0) { state->SetTextGS(l, b, state->GetTextPainter()); drawing-> Select(new TextSelection(text, len, state->GetTextGS())); editor->Do(new AddChange(drawing, drawingview)); } //Move(l, b); rtn = drawing->GetSelections()->First()->GetSelection(); drawingview->EraseHandles(); drawing->Clear(); return rtn; } Selection* IdrawInterface::DrawLine(Coord x0, Coord y0, Coord x1, Coord y1) { Selection* rtn; if (x0 != x1 || y0 != y1) { drawing->Select( new LineSelection(x0, y0, x1, y1, state->GetGraphicGS())); editor->Do(new AddChange(drawing, drawingview)); } rtn = drawing->GetSelections()->First()->GetSelection(); drawingview->EraseHandles(); drawing->Clear(); return rtn; } Selection* IdrawInterface::DrawMultiLine(Coord* x, Coord* y, int n) { Selection* rtn; if (n != 2 || x[0] != x[1] || y[0] != y[1]) { drawing->Select( new MultiLineSelection(x, y, n, state->GetGraphicGS())); editor->Do(new AddChange(drawing, drawingview)); } rtn = drawing->GetSelections()->First()->GetSelection(); drawingview->EraseHandles(); drawing->Clear(); return rtn; } Selection* IdrawInterface::DrawOpenSpline(Coord* x, Coord* y, int n) { Selection* rtn; if (n != 2 || x[0] != x[1] || y[0] != y[1]) { drawing->Select( new BSplineSelection(x, y, n, state->GetGraphicGS())); editor->Do(new AddChange(drawing, drawingview)); } rtn = drawing->GetSelections()->First()->GetSelection(); drawingview->EraseHandles(); drawing->Clear(); return rtn; } Selection* IdrawInterface::DrawEllipse(Coord cx, Coord cy, Coord xr, Coord yr) { Selection* rtn; if (xr > 0 || yr > 0) { drawing->Select( new EllipseSelection(cx, cy, xr, yr, state->GetGraphicGS())); editor->Do(new AddChange(drawing, drawingview)); } rtn = drawing->GetSelections()->First()->GetSelection(); drawingview->EraseHandles(); drawing->Clear(); return rtn; } Selection* IdrawInterface::DrawRect(Coord l, Coord b, Coord r, Coord t) { Selection* rtn; drawingview->EraseHandles(); drawing-> Select(new RectSelection(l, b, r, t, state->GetGraphicGS())); editor->Do(new AddChange(drawing, drawingview)); rtn = drawing->GetSelections()->First()->GetSelection(); drawingview->EraseHandles(); drawing->Clear(); return rtn; } Selection* IdrawInterface::DrawPolygon(Coord* x, Coord* y, int n) { return (Selection*) 0; } Selection* IdrawInterface::DrawClosedSpline(Coord* x, Coord* y, int n) { return (Selection*) 0; } void IdrawInterface::TextInsert(char* text) { } void IdrawInterface::TextSelect(int starpos, int endpos) { } void IdrawInterface::TextDelete() { editor->Do(new DeleteChange(drawing, drawingview)); } void IdrawInterface::TextForwardChar() { } void IdrawInterface::TextBackwardChar() { } void IdrawInterface::TextNextLine() { } void IdrawInterface::TextPreviousLine() { } void IdrawInterface::TextBeginningOfLine() { } void IdrawInterface::TextEndOfLine() { } void IdrawInterface::TextBeginningOfText() { } void IdrawInterface::TextEndOfText() { } void IdrawInterface::TextPutCursor(int charpos) { } void IdrawInterface::FileNew(int width, int height, int x, int y) { char geom[30]; sprintf(geom, "%dx%d+%d+%d\0", width, height, x, y); } void IdrawInterface::FileRevert() { } void IdrawInterface::FileOpen(const char* filename) { editor->Open(filename); } void IdrawInterface::FileSave() { editor->Save(); } void IdrawInterface::FileSaveAs(char* filename) { drawing->WritePicture(filename, state); } void IdrawInterface::FilePrint(char* command) { } void IdrawInterface::FileQuit() { } void IdrawInterface::EditUndo() { editor->history->Undo(); } void IdrawInterface::EditRedo() { editor->history->Redo(); } void IdrawInterface::EditCut() { editor->Do(new CutChange(drawing, drawingview)); } void IdrawInterface::EditCopy() { editor->Do(new CopyChange(drawing, drawingview)); } void IdrawInterface::EditPaste() { editor->Do(new PasteChange(drawing, drawingview, state)); } void IdrawInterface::EditDuplicate() { editor->Do(new DuplicateChange(drawing, drawingview)); } void IdrawInterface::EditDelete() { editor->Do(new DeleteChange(drawing, drawingview)); } void IdrawInterface::EditSelectAll() { drawing->SelectAll(); drawingview->DrawHandles(); } void IdrawInterface::EditUnselectAll() { drawingview->EraseHandles(); drawing->Clear(); } void IdrawInterface::EditFlipHorizontal() { editor->Do(new ScaleChange(drawing, drawingview, -1, 1)); } void IdrawInterface::EditFlipVertical() { editor->Do(new ScaleChange(drawing, drawingview, 1, -1)); } void IdrawInterface::Edit90Clockwise() { editor->Do(new RotateChange(drawing, drawingview, -90.)); } void IdrawInterface::Edit90CounterClockwise() { editor->Do(new RotateChange(drawing, drawingview, 90.)); } void IdrawInterface::EditPreciseMove(int x, int y) { if ((x != 0) || (y != 0)) { editor->Do(new MoveChange(drawing, drawingview, x, y)); } } void IdrawInterface::EditPreciseScale(float factor) { if (factor != 0) { editor->Do(new ScaleChange(drawing, drawingview, factor, factor)); } } void IdrawInterface::EditPreciseRotate(float degrees) { if (degrees != 0) { editor->Do(new RotateChange(drawing, drawingview, degrees)); } } Selection* IdrawInterface::StructureGroup() { editor->Do(new GroupChange(drawing, drawingview)); return (Selection*) 0; } Selection* IdrawInterface::StructureUngroup() { editor->Do(new UngroupChange(drawing, drawingview)); return (Selection*) 0; } void IdrawInterface::StructureBringToFront() { editor->Do(new BringToFrontChange(drawing, drawingview)); } void IdrawInterface::StructureSendToBack() { editor->Do(new SendToBackChange(drawing, drawingview)); } int IdrawInterface::StructureNumberOfGraphics() { return drawing->GetNumberOfGraphics(); } void IdrawInterface::FontSelect(int fontnumber) { MapIFont* ifont = state->GetMapIFont(); if ((fontnumber >= 0) && (fontnumber < ifont->Size())) editor->SetFont(ifont->Index(fontnumber)); } void IdrawInterface::BrushSelect(int brushnumber) { MapIBrush* ibrush = state->GetMapIBrush(); if ((brushnumber >= 0) && (brushnumber < ibrush->Size())) editor->SetBrush(ibrush->Index(brushnumber)); } void IdrawInterface::PatternSelect(int patternnumber) { MapIPattern* ipat = state->GetMapIPattern(); if ((patternnumber >= 0) && (patternnumber < ipat->Size())) editor->SetPattern(ipat->Index(patternnumber)); } void IdrawInterface::FgColorSelect(int colornumber) { MapIColor* icolor = state->GetMapIFgColor(); if ((colornumber >= 0) && (colornumber < icolor->Size())) editor->SetFgColor(icolor->Index(colornumber)); } void IdrawInterface::BgColorSelect(int colornumber) { MapIColor* icolor = state->GetMapIBgColor(); if ((colornumber >= 0) && (colornumber < icolor->Size())) editor->SetBgColor(icolor->Index(colornumber)); } void IdrawInterface::AlignLeftSides() { editor->Do(new AlignChange(drawing, drawingview, Left, Left)); } void IdrawInterface::AlignRightSides() { editor->Do(new AlignChange(drawing, drawingview, Right, Right)); } void IdrawInterface::AlignBottoms() { editor->Do(new AlignChange(drawing, drawingview, Bottom, Bottom)); } void IdrawInterface::AlignTops() { editor->Do(new AlignChange(drawing, drawingview, Top, Top)); } void IdrawInterface::AlignVertCenters() { editor->Do(new AlignChange(drawing, drawingview, VertCenter, VertCenter)); } void IdrawInterface::AlignHorizCenters() { editor->Do(new AlignChange(drawing, drawingview, HorizCenter, HorizCenter)); } void IdrawInterface::AlignCenters() { editor->Do(new AlignChange(drawing, drawingview, Center, Center)); } void IdrawInterface::AlignLeftToRight() { editor->Do(new AlignChange(drawing, drawingview, Right, Left)); } void IdrawInterface::AlignRightToLeft() { editor->Do(new AlignChange(drawing, drawingview, Left, Right)); } void IdrawInterface::AlignBottomToTop() { editor->Do(new AlignChange(drawing, drawingview, Top, Bottom)); } void IdrawInterface::AlignTopToBottom() { editor->Do(new AlignChange(drawing, drawingview, Bottom, Top)); } void IdrawInterface::AlignToGrid() { editor->Do(new AlignToGridChange(drawing, drawingview)); } void IdrawInterface::OptionReduce() { editor->drawingview->Reduce(); } void IdrawInterface::OptionEnlarge() { drawingview->Enlarge(); } void IdrawInterface::OptionNormalSize() { drawingview->NormalSize(); } void IdrawInterface::OptionReduceToFit() { drawingview->ReduceToFit(); } void IdrawInterface::OptionShrinkWrap() { } void IdrawInterface::OptionCenterPage() { drawingview->CenterPage(); } void IdrawInterface::OptionRedrawPage() { drawingview->Draw(); } void IdrawInterface::OptionGriddingOnOff(bool on) { state->SetGridGravity(!state->GetGridGravity()); state->UpdateViews(); } void IdrawInterface::OptionGridVisibleInvisible(bool visible) { state->SetGridVisibility(!state->GetGridVisibility()); drawingview->Draw(); } void IdrawInterface::OptionGridSpacing(int gridsize) { } void IdrawInterface::OptionOrientation() { state->ToggleOrientation(); drawingview->Update(); } void IdrawInterface::WaitForLeftMouseDown(Event& e) { bool found = false; /* * This loop looks at *all* input events, checking each to see if it is a * left mouse down on the drawing area. If it is such an event, it * returns, with the event data stored in the reference parameter e. If * the event is not of the desired type, then it is forwarded to the the * Handle function of whatever target object the event happned on. It is * important to note that this forwarding is critical to the normal * operation of the UI. Without this forwarding, all events not of * interest here would go unhandled, which would effectly lock up the UI * for any event except a mouse down on the drawing area. */ while (not found) { /* * Read the next input event of any type. */ Read(e); /* * Check if the event is a left mouse down on the drawing area. If so, * return this event. */ if ((e.eventType == DownEvent) && (e.button == LEFTMOUSE) && (e.target == drawingview)) { found = true; } /* * If the event is not a left down on the drawing area, forward it to * its appropriate handler. */ e.target->Handle(e); } } Selection* IdrawInterface::TrackMove(Coord& l, Coord& b, Coord& r, Coord& t) { Event e; Selection* pick; WaitForLeftMouseDown(e); pick = drawing->PickSelectionIntersecting(e.x, e.y); if (pick != nil) { drawingview->EraseUngraspedHandles(pick); drawing->Grasp(pick); drawingview->DrawHandles(); drawing->GetBox(l, b, r, t); state->Constrain(e.x, e.y); SlidingRect* slidingrect = new SlidingRect(nil, nil, l, b, r, t, e.x, e.y); drawingview->Manipulate(e, slidingrect, UpEvent); slidingrect->GetCurrent(l, b, r, t); delete slidingrect; return pick; } return NULL; } Selection* IdrawInterface::TrackScale(Coord& l, Coord& b, Coord& r, Coord& t) { Event e; Selection* pick; WaitForLeftMouseDown(e); pick = drawing->PickSelectionIntersecting(e.x, e.y); if (pick != nil) { drawingview->EraseUngraspedHandles(pick); drawing->Grasp(pick); drawingview->DrawHandles(); float l, b, r, t; pick->GetBounds(l, b, r, t); float cx, cy; pick->GetCenter(cx, cy); ScalingRect* scalingrect = new ScalingRect(nil, nil, round(l), round(b), round(r), round(t), round(cx), round(cy)); drawingview->Manipulate(e, scalingrect, UpEvent); float scale = scalingrect->CurrentScaling(); delete scalingrect; return pick; } return NULL; } Selection* IdrawInterface::TrackStretch( Coord& l, Coord& b, Coord& r, Coord& t) { Event e; Selection* pick; WaitForLeftMouseDown(e); if (pick != nil) { drawingview->EraseUngraspedHandles(pick); drawing->Grasp(pick); drawingview->DrawHandles(); float l, b, r, t; pick->GetBounds(l, b, r, t); IStretchingRect* istretchingrect = new IStretchingRect(nil, nil, round(l), round(b), round(r), round(t)); drawingview->Manipulate(e, istretchingrect, UpEvent); float stretch = istretchingrect->CurrentStretching(); Alignment side = istretchingrect->CurrentSide(drawing->GetLandscape()); delete istretchingrect; return pick; } return NULL; } Selection* IdrawInterface::TrackRotate( Coord& l, Coord& b, Coord& r, Coord& t) { Event e; Selection* pick; WaitForLeftMouseDown(e); pick = drawing->PickSelectionIntersecting(e.x, e.y); if (pick != nil) { drawingview->EraseUngraspedHandles(pick); drawing->Grasp(pick); drawingview->DrawHandles(); Coord l, b, r, t; pick->GetBox(l, b, r, t); float cx, cy; pick->GetCenter(cx, cy); state->Constrain(e.x, e.y); RotatingRect* rotatingrect = new RotatingRect(nil, nil, l, b, r, t, round(cx), round(cy), e.x, e.y); drawingview->Manipulate(e, rotatingrect, UpEvent); float angle = rotatingrect->CurrentAngle(); delete rotatingrect; return pick; } return NULL; } Selection* IdrawInterface::TrackReshape( Coord& l, Coord& b, Coord& r, Coord& t) { Event e; Selection* pick; WaitForLeftMouseDown(e); pick = drawing->PickSelectionIntersecting(e.x, e.y); if (pick != nil) { drawingview->EraseHandles(); drawing->Select(pick); drawingview->DrawHandles(); Selection* reshapedpick = nil; if (pick->IsA(TEXTSELECTION)) { int len; const char* text = ((TextSelection*) pick)->GetOriginal(len); TextEdit* textedit = new TextEdit(text, len); drawingview->EraseHandles(); drawingview->Edit(e, textedit, pick); text = textedit->GetText(len); reshapedpick = new TextSelection(text, len, pick); delete textedit; reshapedpick->GetBox(l, b, r, t); return reshapedpick; } else { Rubberband* shape = pick->CreateShape(e.x, e.y); drawingview->Manipulate(e, shape, UpEvent); reshapedpick = pick->GetReshapedCopy(); reshapedpick->GetBox(l, b, r, t); return reshapedpick; } } return NULL; } void IdrawInterface::TrackLine(Coord& x0, Coord& x1, Coord& y0, Coord& y1, bool constrained) { Event e; WaitForLeftMouseDown(e); drawingview->EraseHandles(); state->Constrain(e.x, e.y); RubberLine* rubberline = editor->NewRubberLineOrAxis(e); drawingview->Manipulate(e, rubberline, UpEvent); rubberline->GetCurrent(x0, y0, x1, y1); delete rubberline; } void IdrawInterface::TrackMultiLine(Coord*& x, Coord*& y, int& n, bool constrained) { Event e; WaitForLeftMouseDown(e); drawingview->EraseHandles(); editor->InputVertices(e, x, y, n); } void IdrawInterface::TrackEllipse(Coord& cx, Coord& cy, Coord& rx, Coord& ry, bool constrained) { Event e; int xr, yr; WaitForLeftMouseDown(e); drawingview->EraseHandles(); state->Constrain(e.x, e.y); RubberEllipse* rubberellipse = editor->NewRubberEllipseOrCircle(e); drawingview->Manipulate(e, rubberellipse, UpEvent); rubberellipse->GetCurrent(cx, cy, rx, ry); rubberellipse->CurrentRadii(xr, yr); delete rubberellipse; } void IdrawInterface::TrackRectangle(Coord& l, Coord& b, Coord& r, Coord& t, bool constrained) { Event e; WaitForLeftMouseDown(e); drawingview->EraseHandles(); state->Constrain(e.x, e.y); RubberRect* rubberrect = editor->NewRubberRectOrSquare(e); drawingview->Manipulate(e, rubberrect, UpEvent); rubberrect->GetCurrent(l, b, r, t); delete rubberrect; }