///////////////////////////////////////////////////////////////////////////// // Name: view.cpp // Purpose: Implements view functionality // Author: Julian Smart // Modified by: // Created: 12/07/98 // RCS-ID: $Id$ // Copyright: (c) Julian Smart // Licence: ///////////////////////////////////////////////////////////////////////////// #ifdef __GNUG__ // #pragma implementation #endif // For compilers that support precompilation, includes "wx.h". #include #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include #endif #include #if !wxUSE_DOC_VIEW_ARCHITECTURE #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h! #endif #include "studio.h" #include "doc.h" #include "view.h" #include "cspalette.h" #include "symbols.h" #include "dialogs.h" #include "basicp.h" #include "linesp.h" IMPLEMENT_DYNAMIC_CLASS(csDiagramView, wxView) BEGIN_EVENT_TABLE(csDiagramView, wxView) EVT_MENU(wxID_CUT, csDiagramView::OnCut) EVT_MENU(wxID_COPY, csDiagramView::OnCopy) EVT_MENU(wxID_CLEAR, csDiagramView::OnClear) EVT_MENU(wxID_PASTE, csDiagramView::OnPaste) EVT_MENU(wxID_DUPLICATE, csDiagramView::OnDuplicate) EVT_MENU(ID_CS_CHANGE_BACKGROUND_COLOUR, csDiagramView::OnChangeBackgroundColour) EVT_MENU(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditProperties) EVT_MENU(ID_CS_SELECT_ALL, csDiagramView::OnSelectAll) EVT_TOOL(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowTool) EVT_COMBOBOX(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboSel) EVT_COMBOBOX(ID_WINDOW_ZOOM_COMBOBOX, csDiagramView::OnZoomSel) EVT_TEXT(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboText) EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlign) EVT_TOOL(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePoint) EVT_TOOL(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePoint) EVT_TOOL(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLines) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlignUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePointUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePointUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLinesUpdate) EVT_UPDATE_UI(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowToolUpdate) EVT_UPDATE_UI(wxID_CUT, csDiagramView::OnCutUpdate) EVT_UPDATE_UI(wxID_COPY, csDiagramView::OnCopyUpdate) EVT_UPDATE_UI(wxID_CLEAR, csDiagramView::OnClearUpdate) EVT_UPDATE_UI(wxID_PASTE, csDiagramView::OnPasteUpdate) EVT_UPDATE_UI(wxID_DUPLICATE, csDiagramView::OnDuplicateUpdate) EVT_UPDATE_UI(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditPropertiesUpdate) EVT_UPDATE_UI(wxID_UNDO, csDiagramView::OnUndoUpdate) EVT_UPDATE_UI(wxID_REDO, csDiagramView::OnRedoUpdate) END_EVENT_TABLE() // What to do when a view is created. Creates actual // windows for displaying the view. bool csDiagramView::OnCreate(wxDocument *doc, long flags) { wxMenu* editMenu; frame = wxGetApp().CreateChildFrame(doc, this, &editMenu); canvas = wxGetApp().CreateCanvas(this, frame); canvas->SetView(this); SetFrame(frame); Activate(TRUE); // Initialize the edit menu Undo and Redo items doc->GetCommandProcessor()->SetEditMenu(editMenu); doc->GetCommandProcessor()->Initialize(); wxShapeCanvas *shapeCanvas = (wxShapeCanvas *)canvas; csDiagramDocument *diagramDoc = (csDiagramDocument *)doc; shapeCanvas->SetDiagram(diagramDoc->GetDiagram()); diagramDoc->GetDiagram()->SetCanvas(shapeCanvas); diagramDoc->GetDiagram()->SetGridSpacing((double) wxGetApp().GetGridSpacing()); switch (wxGetApp().GetGridStyle()) { case csGRID_STYLE_NONE: { diagramDoc->GetDiagram()->SetSnapToGrid(FALSE); break; } case csGRID_STYLE_INVISIBLE: { diagramDoc->GetDiagram()->SetSnapToGrid(TRUE); break; } case csGRID_STYLE_DOTTED: { // TODO (not implemented in OGL) break; } } return TRUE; } csDiagramView::~csDiagramView(void) { if (frame) { ((wxDocMDIChildFrame*)frame)->SetView(NULL); } } // Sneakily gets used for default print/preview // as well as drawing on the screen. void csDiagramView::OnDraw(wxDC *dc) { } void csDiagramView::OnUpdate(wxView *sender, wxObject *hint) { if (canvas) canvas->Refresh(); } // Clean up windows used for displaying the view. bool csDiagramView::OnClose(bool deleteWindow) { if (!GetDocument()->Close()) return FALSE; csDiagramDocument *diagramDoc = (csDiagramDocument *)GetDocument(); diagramDoc->GetDiagram()->SetCanvas(NULL); canvas->Clear(); canvas->SetDiagram(NULL); canvas->SetView(NULL); canvas = NULL; wxMenu* fileMenu = frame->GetMenuBar()->GetMenu(0); // Remove file menu from those managed by the command history wxGetApp().GetDocManager()->FileHistoryRemoveMenu(fileMenu); Activate(FALSE); frame->Show(FALSE); if (deleteWindow) { frame->Destroy(); } return TRUE; } // Adds or removes shape from m_selections void csDiagramView::SelectShape(wxShape* shape, bool select) { if (select && !m_selections.Member(shape)) m_selections.Append(shape); else if (!select) m_selections.DeleteObject(shape); } void csDiagramView::OnSelectAll(wxCommandEvent& event) { SelectAll(TRUE); } wxShape *csDiagramView::FindFirstSelectedShape(void) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); wxShape *theShape = NULL; wxNode *node = doc->GetDiagram()->GetShapeList()->First(); while (node) { wxShape *eachShape = (wxShape *)node->Data(); if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected()) { theShape = eachShape; node = NULL; } else node = node->Next(); } return theShape; } void csDiagramView::FindSelectedShapes(wxList& selections, wxClassInfo* toFind) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); wxNode *node = doc->GetDiagram()->GetShapeList()->First(); while (node) { wxShape *eachShape = (wxShape *)node->Data(); if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected() && ((toFind == NULL) || (eachShape->IsKindOf(toFind)))) { selections.Append(eachShape); } node = node->Next(); } } void csDiagramView::OnUndoUpdate(wxUpdateUIEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); event.Enable(doc->GetCommandProcessor()->CanUndo()); } void csDiagramView::OnRedoUpdate(wxUpdateUIEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); event.Enable(doc->GetCommandProcessor()->CanRedo()); } void csDiagramView::OnCut(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); // Copy the shapes to the clipboard wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram()); wxList selections; FindSelectedShapes(selections); DoCut(selections); } void csDiagramView::OnClear(wxCommandEvent& event) { wxList selections; FindSelectedShapes(selections); DoCut(selections); } void csDiagramView::OnCopy(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); // Copy the shapes to the clipboard if (wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram())) { #ifdef __WXMSW__ // Copy to the Windows clipboard wxGetApp().GetDiagramClipboard().CopyToClipboard(1.0); #endif } } void csDiagramView::OnPaste(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram()); } void csDiagramView::OnDuplicate(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); // Do a copy, then a paste wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram()); // Apply an offset. Really, this offset should keep being incremented, // but where do we reset it again? wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram(), NULL, 20, 20); } void csDiagramView::OnCutUpdate(wxUpdateUIEvent& event) { event.Enable( (m_selections.Number() > 0) ); } void csDiagramView::OnClearUpdate(wxUpdateUIEvent& event) { event.Enable( (m_selections.Number() > 0) ); } void csDiagramView::OnCopyUpdate(wxUpdateUIEvent& event) { event.Enable( (m_selections.Number() > 0) ); } void csDiagramView::OnPasteUpdate(wxUpdateUIEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); int n = wxGetApp().GetDiagramClipboard().GetCount(); event.Enable( (n > 0) ); } void csDiagramView::OnDuplicateUpdate(wxUpdateUIEvent& event) { event.Enable( (m_selections.Number() > 0) ); } void csDiagramView::DoCut(wxList& shapes) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); if (shapes.Number() > 0) { csDiagramCommand* cmd = new csDiagramCommand("Cut", doc); wxNode* node = shapes.First(); while (node) { wxShape *theShape = (wxShape*) node->Data(); csCommandState* state = new csCommandState(ID_CS_CUT, NULL, theShape); // Insert lines at the front, so they are cut first. // Otherwise we may try to remove a shape with a line still // attached. if (theShape->IsKindOf(CLASSINFO(wxLineShape))) cmd->InsertState(state); else cmd->AddState(state); node = node->Next(); } cmd->RemoveLines(); // Schedule any connected lines, not already mentioned, // to be removed first doc->GetCommandProcessor()->Submit(cmd); } } // Generalised command void csDiagramView::DoCmd(wxList& shapes, wxList& oldShapes, int cmd, const wxString& op) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); if (shapes.Number() > 0) { csDiagramCommand* command = new csDiagramCommand(op, doc); wxNode* node = shapes.First(); wxNode* node1 = oldShapes.First(); while (node && node1) { wxShape *theShape = (wxShape*) node->Data(); wxShape *oldShape = (wxShape*) node1->Data(); csCommandState* state = new csCommandState(cmd, theShape, oldShape); command->AddState(state); node = node->Next(); node1 = node1->Next(); } doc->GetCommandProcessor()->Submit(command); } } void csDiagramView::OnChangeBackgroundColour(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); wxList selections; FindSelectedShapes(selections); if (selections.Number() > 0) { wxColourData data; data.SetChooseFull(TRUE); if (selections.Number() == 1) { wxShape* firstShape = (wxShape*) selections.First()->Data(); data.SetColour(firstShape->GetBrush()->GetColour()); } wxColourDialog *dialog = new wxColourDialog(frame, &data); wxBrush *theBrush = NULL; if (dialog->ShowModal() == wxID_OK) { wxColourData retData = dialog->GetColourData(); wxColour col = retData.GetColour(); theBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID); } dialog->Close(TRUE); if (!theBrush) return; csDiagramCommand* cmd = new csDiagramCommand("Change colour", doc); wxNode* node = selections.First(); while (node) { wxShape *theShape = (wxShape*) node->Data(); wxShape* newShape = theShape->CreateNewCopy(); newShape->SetBrush(theBrush); csCommandState* state = new csCommandState(ID_CS_CHANGE_BACKGROUND_COLOUR, newShape, theShape); cmd->AddState(state); node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } } void csDiagramView::OnEditProperties(wxCommandEvent& event) { wxShape *theShape = FindFirstSelectedShape(); if (theShape) ((csEvtHandler *)theShape->GetEventHandler())->EditProperties(); } void csDiagramView::OnEditPropertiesUpdate(wxUpdateUIEvent& event) { wxList selections; FindSelectedShapes(selections); event.Enable( (selections.Number() > 0) ); } void csDiagramView::OnPointSizeComboSel(wxCommandEvent& event) { wxComboBox* combo = (wxComboBox*) event.GetEventObject(); wxASSERT( combo != NULL ); int newPointSize = (combo->GetSelection() + 1); ApplyPointSize(newPointSize); } // TODO: must find out how to intercept the Return key, rather than // every key stroke. But for now, do every key stroke. void csDiagramView::OnPointSizeComboText(wxCommandEvent& event) { wxComboBox* combo = (wxComboBox*) event.GetEventObject(); wxASSERT( combo != NULL ); wxString str(combo->GetValue()); int newPointSize = atoi((const char*) str); if (newPointSize < 2) return; ApplyPointSize(newPointSize); } void csDiagramView::ApplyPointSize(int pointSize) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); wxList selections; FindSelectedShapes(selections); if (selections.Number() > 0) { csDiagramCommand* cmd = new csDiagramCommand("Point size", doc); wxNode* node = selections.First(); while (node) { wxShape *theShape = (wxShape*) node->Data(); wxShape *newShape = theShape->CreateNewCopy(); wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize, theShape->GetFont()->GetFamily(), theShape->GetFont()->GetStyle(), theShape->GetFont()->GetWeight(), theShape->GetFont()->GetUnderlined(), theShape->GetFont()->GetFaceName()); newShape->SetFont(newFont); csCommandState* state = new csCommandState(ID_CS_FONT_CHANGE, newShape, theShape); cmd->AddState(state); node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } } void csDiagramView::OnZoomSel(wxCommandEvent& event) { int maxZoom = 200; int minZoom = 5; int inc = 5; int noStrings = (maxZoom - minZoom)/inc ; wxComboBox* combo = (wxComboBox*) event.GetEventObject(); wxASSERT( combo != NULL ); int scale = (int) ((noStrings - combo->GetSelection() - 1)*inc + minZoom); canvas->SetScale((double) (scale/100.0), (double) (scale/100.0)); canvas->Refresh(); } // Select or deselect all void csDiagramView::SelectAll(bool select) { wxClientDC dc(canvas); canvas->PrepareDC(dc); if (!select) { wxList selections; FindSelectedShapes(selections); wxNode* node = selections.First(); while (node) { wxShape *theShape = (wxShape*) node->Data(); theShape->Select(FALSE, &dc); SelectShape(theShape, FALSE); node = node->Next(); } } else { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); wxNode *node = doc->GetDiagram()->GetShapeList()->First(); while (node) { wxShape *eachShape = (wxShape *)node->Data(); if (eachShape->GetParent() == NULL && !eachShape->IsKindOf(CLASSINFO(wxControlPoint)) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape))) { eachShape->Select(TRUE, &dc); SelectShape(eachShape, TRUE); } node = node->Next(); } } } void csDiagramView::OnToggleArrowTool(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); bool state = wxGetApp().GetDiagramToolBar()->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW); wxString stateName; if (state) stateName = "Arrow on"; else stateName = "Arrow off"; wxList selections; FindSelectedShapes(selections, CLASSINFO(wxLineShape)); if (selections.Number() > 0) { csDiagramCommand* cmd = new csDiagramCommand(stateName, doc); wxNode* node = selections.First(); while (node) { wxLineShape *theShape = (wxLineShape*) node->Data(); wxLineShape *newShape = NULL; if (state) { // Add arrow if (theShape->GetArrows().Number() == 0) { newShape = (wxLineShape*) theShape->CreateNewCopy(); newShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead"); } } else { if (theShape->GetArrows().Number() > 0) { newShape = (wxLineShape*) theShape->CreateNewCopy(); newShape->ClearArrowsAtPosition(); } } // If the new state is the same as the old, don't bother adding it to the command state. if (newShape) { csCommandState* state = new csCommandState(ID_CS_ARROW_CHANGE, newShape, theShape); cmd->AddState(state); } node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } } void csDiagramView::OnToggleArrowToolUpdate(wxUpdateUIEvent& event) { wxList selections; FindSelectedShapes(selections, CLASSINFO(wxLineShape)); event.Enable( (selections.Number() > 0) ); } // Make the point size combobox reflect this void csDiagramView::ReflectPointSize(int pointSize) { wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox(); comboBox->SetSelection(pointSize -1); } // Make the arrow toggle button reflect the state of the line void csDiagramView::ReflectArrowState(wxLineShape* lineShape) { bool haveArrow = FALSE; wxNode *node = lineShape->GetArrows().First(); while (node) { wxArrowHead *arrow = (wxArrowHead *)node->Data(); if (ARROW_POSITION_MIDDLE == arrow->GetArrowEnd()) haveArrow = TRUE; node = node->Next(); } wxGetApp().GetDiagramToolBar()->ToggleTool(DIAGRAM_TOOLBAR_LINE_ARROW, haveArrow); } void csDiagramView::OnAlign(wxCommandEvent& event) { // Make a copy of the selections, keeping only those shapes // that are top-level non-line shapes. wxList selections; wxNode* node = GetSelectionList().First(); while (node) { wxShape* shape = (wxShape*) node->Data(); if ((shape->GetParent() == NULL) && (!shape->IsKindOf(CLASSINFO(wxLineShape)))) { selections.Append(shape); } node = node->Next(); } if (selections.Number() == 0) return; csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); csDiagramCommand* cmd = new csDiagramCommand("Align", doc); node = selections.First(); wxShape* firstShape = (wxShape*) node->Data(); double x = firstShape->GetX(); double y = firstShape->GetY(); double width, height; firstShape->GetBoundingBoxMax(&width, &height); node = selections.First(); while (node) { wxShape* shape = (wxShape*) node->Data(); if (shape != firstShape) { double x1 = shape->GetX(); double y1 = shape->GetY(); double width1, height1; shape->GetBoundingBoxMax(& width1, & height1); wxShape* newShape = shape->CreateNewCopy(); switch (event.GetId()) { case DIAGRAM_TOOLBAR_ALIGNL: { double x2 = (double)(x - (width/2.0) + (width1/2.0)); newShape->SetX(x2); break; } case DIAGRAM_TOOLBAR_ALIGNR: { double x2 = (double)(x + (width/2.0) - (width1/2.0)); newShape->SetX(x2); break; } case DIAGRAM_TOOLBAR_ALIGNB: { double y2 = (double)(y + (height/2.0) - (height1/2.0)); newShape->SetY(y2); break; } case DIAGRAM_TOOLBAR_ALIGNT: { double y2 = (double)(y - (height/2.0) + (height1/2.0)); newShape->SetY(y2); break; } case DIAGRAM_TOOLBAR_ALIGN_HORIZ: { newShape->SetX(x); break; } case DIAGRAM_TOOLBAR_ALIGN_VERT: { newShape->SetY(y); break; } case DIAGRAM_TOOLBAR_COPY_SIZE: { newShape->SetSize(width, height); break; } } csCommandState* state = new csCommandState(ID_CS_ALIGN, newShape, shape); cmd->AddState(state); } node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } void csDiagramView::OnAlignUpdate(wxUpdateUIEvent& event) { // This is an approximation, since there may be lines // amongst the selections. event.Enable( (m_selections.Number() > 1) ) ; } void csDiagramView::OnNewLinePoint(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); csDiagramCommand* cmd = new csDiagramCommand("New line point", doc); wxNode* node = m_selections.First(); while (node) { wxShape* shape = (wxShape*) node->Data(); if (shape->IsKindOf(CLASSINFO(wxLineShape))) { wxShape* newShape = shape->CreateNewCopy(); ((wxLineShape*)newShape)->InsertLineControlPoint(NULL); csCommandState* state = new csCommandState(ID_CS_NEW_POINT, newShape, shape); cmd->AddState(state); } node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } void csDiagramView::OnCutLinePoint(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); csDiagramCommand* cmd = new csDiagramCommand("Cut line point", doc); wxNode* node = m_selections.First(); while (node) { wxShape* shape = (wxShape*) node->Data(); if (shape->IsKindOf(CLASSINFO(wxLineShape))) { wxShape* newShape = shape->CreateNewCopy(); ((wxLineShape*)newShape)->DeleteLineControlPoint(); csCommandState* state = new csCommandState(ID_CS_CUT_POINT, newShape, shape); cmd->AddState(state); } node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } void csDiagramView::OnStraightenLines(wxCommandEvent& event) { csDiagramDocument *doc = (csDiagramDocument *)GetDocument(); csDiagramCommand* cmd = new csDiagramCommand("Straighten lines", doc); wxNode* node = m_selections.First(); while (node) { wxShape* shape = (wxShape*) node->Data(); if (shape->IsKindOf(CLASSINFO(wxLineShape))) { wxShape* newShape = shape->CreateNewCopy(); ((wxLineShape*)newShape)->Straighten(); csCommandState* state = new csCommandState(ID_CS_STRAIGHTEN, newShape, shape); cmd->AddState(state); } node = node->Next(); } doc->GetCommandProcessor()->Submit(cmd); } void csDiagramView::OnNewLinePointUpdate(wxUpdateUIEvent& event) { wxList selections; FindSelectedShapes(selections, CLASSINFO(wxLineShape)); event.Enable( (selections.Number() > 0) ); } void csDiagramView::OnCutLinePointUpdate(wxUpdateUIEvent& event) { wxList selections; FindSelectedShapes(selections, CLASSINFO(wxLineShape)); event.Enable( (selections.Number() > 0) ); } void csDiagramView::OnStraightenLinesUpdate(wxUpdateUIEvent& event) { wxList selections; FindSelectedShapes(selections, CLASSINFO(wxLineShape)); event.Enable( (selections.Number() > 0) ); } /* * Window implementations */ IMPLEMENT_CLASS(csCanvas, wxShapeCanvas) BEGIN_EVENT_TABLE(csCanvas, wxShapeCanvas) EVT_MOUSE_EVENTS(csCanvas::OnMouseEvent) EVT_PAINT(csCanvas::OnPaint) END_EVENT_TABLE() // Define a constructor for my canvas csCanvas::csCanvas(csDiagramView *v, wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style): wxShapeCanvas(parent, id, pos, size, style) { m_view = v; } csCanvas::~csCanvas(void) { } void csCanvas::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2) { wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT); dc.SetPen(dottedPen); dc.SetBrush(* wxTRANSPARENT_BRUSH); dc.DrawRectangle((long) x1, (long) y1, (long) (x2 - x1), (long) (y2 - y1)); } void csCanvas::OnLeftClick(double x, double y, int keys) { csEditorToolPalette *palette = wxGetApp().GetDiagramPalette(); if (palette->GetSelection() == PALETTE_ARROW) { GetView()->SelectAll(FALSE); wxClientDC dc(this); PrepareDC(dc); Redraw(dc); return; } if (palette->GetSelection() == PALETTE_TEXT_TOOL) { // Ask for a label and create a new free-floating text region csLabelEditingDialog* dialog = new csLabelEditingDialog(GetParent()); dialog->SetShapeLabel(""); dialog->SetTitle("New text box"); if (dialog->ShowModal() == wxID_CANCEL) { dialog->Destroy(); return; } wxString newLabel = dialog->GetShapeLabel(); dialog->Destroy(); wxShape* shape = new csTextBoxShape; shape->AssignNewIds(); shape->SetEventHandler(new csEvtHandler(shape, shape, newLabel)); wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox(); wxString str(comboBox->GetValue()); int pointSize = atoi((const char*) str); wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize, shape->GetFont()->GetFamily(), shape->GetFont()->GetStyle(), shape->GetFont()->GetWeight(), shape->GetFont()->GetUnderlined(), shape->GetFont()->GetFaceName()); shape->SetFont(newFont); shape->SetX(x); shape->SetY(y); csDiagramCommand* cmd = new csDiagramCommand("Text box", (csDiagramDocument *)GetView()->GetDocument(), new csCommandState(ID_CS_ADD_SHAPE, shape, NULL)); GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd); palette->SetSelection(PALETTE_ARROW); return; } csSymbol* symbol = wxGetApp().GetSymbolDatabase()->FindSymbol(palette->GetSelection()); if (symbol) { wxShape* theShape = symbol->GetShape()->CreateNewCopy(); wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox(); wxString str(comboBox->GetValue()); int pointSize = atoi((const char*) str); wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize, symbol->GetShape()->GetFont()->GetFamily(), symbol->GetShape()->GetFont()->GetStyle(), symbol->GetShape()->GetFont()->GetWeight(), symbol->GetShape()->GetFont()->GetUnderlined(), symbol->GetShape()->GetFont()->GetFaceName()); theShape->SetFont(newFont); theShape->AssignNewIds(); theShape->SetX(x); theShape->SetY(y); csDiagramCommand* cmd = new csDiagramCommand(symbol->GetName(), (csDiagramDocument *)GetView()->GetDocument(), new csCommandState(ID_CS_ADD_SHAPE, theShape, NULL)); GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd); palette->SetSelection(PALETTE_ARROW); } } void csCanvas::OnRightClick(double x, double y, int keys) { } // Initial point static double sg_initialX, sg_initialY; void csCanvas::OnDragLeft(bool draw, double x, double y, int keys) { wxClientDC dc(this); PrepareDC(dc); dc.SetLogicalFunction(wxXOR); DrawOutline(dc, sg_initialX, sg_initialY, x, y); } void csCanvas::OnBeginDragLeft(double x, double y, int keys) { sg_initialX = x; sg_initialY = y; wxClientDC dc(this); PrepareDC(dc); dc.SetLogicalFunction(wxXOR); DrawOutline(dc, sg_initialX, sg_initialY, x, y); CaptureMouse(); } void csCanvas::OnEndDragLeft(double x, double y, int keys) { ReleaseMouse(); wxClientDC dc(this); PrepareDC(dc); // Select all images within the rectangle float min_x, max_x, min_y, max_y; min_x = wxMin(x, sg_initialX); max_x = wxMax(x, sg_initialX); min_y = wxMin(y, sg_initialY); max_y = wxMax(y, sg_initialY); wxNode *node = GetDiagram()->GetShapeList()->First(); while (node) { wxShape *shape = (wxShape *)node->Data(); if (shape->GetParent() == NULL && !shape->IsKindOf(CLASSINFO(wxControlPoint))) { float image_x = shape->GetX(); float image_y = shape->GetY(); if (image_x >= min_x && image_x <= max_x && image_y >= min_y && image_y <= max_y) { shape->Select(TRUE, &dc); GetView()->SelectShape(shape, TRUE); } } node = node->Next(); } } void csCanvas::OnDragRight(bool draw, double x, double y, int keys) { } void csCanvas::OnBeginDragRight(double x, double y, int keys) { } void csCanvas::OnEndDragRight(double x, double y, int keys) { } void csCanvas::OnMouseEvent(wxMouseEvent& event) { wxShapeCanvas::OnMouseEvent(event); } void csCanvas::OnPaint(wxPaintEvent& event) { // if (GetDiagram()) wxShapeCanvas::OnPaint(event); }