home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / contrib / samples / ogl / studio / view.cpp < prev    next >
C/C++ Source or Header  |  2001-10-30  |  32KB  |  1,040 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        view.cpp
  3. // Purpose:     Implements view functionality
  4. // Author:      Julian Smart
  5. // Modified by:
  6. // Created:     12/07/98
  7. // RCS-ID:      $Id: view.cpp,v 1.2 2001/10/30 13:28:45 GT Exp $
  8. // Copyright:   (c) Julian Smart
  9. // Licence:
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. // #pragma implementation
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20. #pragma hdrstop
  21. #endif
  22.  
  23. #ifndef WX_PRECOMP
  24. #include <wx/wx.h>
  25. #endif
  26.  
  27. #include <wx/colordlg.h>
  28.  
  29. #if !wxUSE_DOC_VIEW_ARCHITECTURE
  30. #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
  31. #endif
  32.  
  33. #include "studio.h"
  34. #include "doc.h"
  35. #include "view.h"
  36. #include "cspalette.h"
  37. #include "symbols.h"
  38. #include "dialogs.h"
  39. #include <wx/ogl/basicp.h>
  40. #include <wx/ogl/linesp.h>
  41.  
  42. IMPLEMENT_DYNAMIC_CLASS(csDiagramView, wxView)
  43.  
  44. BEGIN_EVENT_TABLE(csDiagramView, wxView)
  45.     EVT_MENU(wxID_CUT, csDiagramView::OnCut)
  46.     EVT_MENU(wxID_COPY, csDiagramView::OnCopy)
  47.     EVT_MENU(wxID_CLEAR, csDiagramView::OnClear)
  48.     EVT_MENU(wxID_PASTE, csDiagramView::OnPaste)
  49.     EVT_MENU(wxID_DUPLICATE, csDiagramView::OnDuplicate)
  50.     EVT_MENU(ID_CS_CHANGE_BACKGROUND_COLOUR, csDiagramView::OnChangeBackgroundColour)
  51.     EVT_MENU(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditProperties)
  52.     EVT_MENU(ID_CS_SELECT_ALL, csDiagramView::OnSelectAll)
  53.     EVT_TOOL(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowTool)
  54.     EVT_COMBOBOX(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboSel)
  55.     EVT_COMBOBOX(ID_WINDOW_ZOOM_COMBOBOX, csDiagramView::OnZoomSel)
  56.     EVT_TEXT(ID_WINDOW_POINT_SIZE_COMBOBOX, csDiagramView::OnPointSizeComboText)
  57.     EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlign)
  58.     EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlign)
  59.     EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlign)
  60.     EVT_TOOL(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlign)
  61.     EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlign)
  62.     EVT_TOOL(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlign)
  63.     EVT_TOOL(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlign)
  64.     EVT_TOOL(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePoint)
  65.     EVT_TOOL(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePoint)
  66.     EVT_TOOL(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLines)
  67.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNL, csDiagramView::OnAlignUpdate)
  68.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNR, csDiagramView::OnAlignUpdate)
  69.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNB, csDiagramView::OnAlignUpdate)
  70.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGNT, csDiagramView::OnAlignUpdate)
  71.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_HORIZ, csDiagramView::OnAlignUpdate)
  72.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_ALIGN_VERT, csDiagramView::OnAlignUpdate)
  73.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_COPY_SIZE, csDiagramView::OnAlignUpdate)
  74.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_NEW_POINT, csDiagramView::OnNewLinePointUpdate)
  75.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_CUT_POINT, csDiagramView::OnCutLinePointUpdate)
  76.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_STRAIGHTEN, csDiagramView::OnStraightenLinesUpdate)
  77.     EVT_UPDATE_UI(DIAGRAM_TOOLBAR_LINE_ARROW, csDiagramView::OnToggleArrowToolUpdate)
  78.     EVT_UPDATE_UI(wxID_CUT, csDiagramView::OnCutUpdate)
  79.     EVT_UPDATE_UI(wxID_COPY, csDiagramView::OnCopyUpdate)
  80.     EVT_UPDATE_UI(wxID_CLEAR, csDiagramView::OnClearUpdate)
  81.     EVT_UPDATE_UI(wxID_PASTE, csDiagramView::OnPasteUpdate)
  82.     EVT_UPDATE_UI(wxID_DUPLICATE, csDiagramView::OnDuplicateUpdate)
  83.     EVT_UPDATE_UI(ID_CS_EDIT_PROPERTIES, csDiagramView::OnEditPropertiesUpdate)
  84.     EVT_UPDATE_UI(wxID_UNDO, csDiagramView::OnUndoUpdate)
  85.     EVT_UPDATE_UI(wxID_REDO, csDiagramView::OnRedoUpdate)
  86. END_EVENT_TABLE()
  87.  
  88. // What to do when a view is created. Creates actual
  89. // windows for displaying the view.
  90. bool csDiagramView::OnCreate(wxDocument *doc, long flags)
  91. {
  92.   wxMenu* editMenu;
  93.   frame = wxGetApp().CreateChildFrame(doc, this, &editMenu);
  94.   canvas = wxGetApp().CreateCanvas(this, frame);
  95.   canvas->SetView(this);
  96.  
  97.   SetFrame(frame);
  98.   Activate(TRUE);
  99.  
  100.   // Initialize the edit menu Undo and Redo items
  101.   doc->GetCommandProcessor()->SetEditMenu(editMenu);
  102.   doc->GetCommandProcessor()->Initialize();
  103.  
  104.   wxShapeCanvas *shapeCanvas = (wxShapeCanvas *)canvas;
  105.   csDiagramDocument *diagramDoc = (csDiagramDocument *)doc;
  106.   shapeCanvas->SetDiagram(diagramDoc->GetDiagram());
  107.   diagramDoc->GetDiagram()->SetCanvas(shapeCanvas);
  108.  
  109.   diagramDoc->GetDiagram()->SetGridSpacing((double) wxGetApp().GetGridSpacing());
  110.  
  111.     switch (wxGetApp().GetGridStyle())
  112.     {
  113.         case csGRID_STYLE_NONE:
  114.         {
  115.             diagramDoc->GetDiagram()->SetSnapToGrid(FALSE);
  116.             break;
  117.         }
  118.         case csGRID_STYLE_INVISIBLE:
  119.         {
  120.             diagramDoc->GetDiagram()->SetSnapToGrid(TRUE);
  121.             break;
  122.         }
  123.         case csGRID_STYLE_DOTTED:
  124.         {
  125.             // TODO (not implemented in OGL)
  126.             break;
  127.         }
  128.     }
  129.  
  130.  
  131.   return TRUE;
  132. }
  133.  
  134. csDiagramView::~csDiagramView(void)
  135. {
  136.     if (frame)
  137.     {
  138.         ((wxDocMDIChildFrame*)frame)->SetView(NULL);
  139.     }
  140. }
  141.  
  142. // Sneakily gets used for default print/preview
  143. // as well as drawing on the screen.
  144. void csDiagramView::OnDraw(wxDC *dc)
  145. {
  146. }
  147.  
  148. void csDiagramView::OnUpdate(wxView *sender, wxObject *hint)
  149. {
  150.   if (canvas)
  151.     canvas->Refresh();
  152. }
  153.  
  154. // Clean up windows used for displaying the view.
  155. bool csDiagramView::OnClose(bool deleteWindow)
  156. {
  157.   if (!GetDocument()->Close())
  158.     return FALSE;
  159.  
  160.   csDiagramDocument *diagramDoc = (csDiagramDocument *)GetDocument();
  161.   diagramDoc->GetDiagram()->SetCanvas(NULL);
  162.  
  163.   canvas->Clear();
  164.   canvas->SetDiagram(NULL);
  165.   canvas->SetView(NULL);
  166.   canvas = NULL;
  167.  
  168.   wxMenu* fileMenu = frame->GetMenuBar()->GetMenu(0);
  169.  
  170.   // Remove file menu from those managed by the command history
  171.   wxGetApp().GetDocManager()->FileHistoryRemoveMenu(fileMenu);
  172.  
  173.   Activate(FALSE);
  174.   frame->Show(FALSE);
  175.  
  176.   if (deleteWindow)
  177.   {
  178.     frame->Destroy();
  179.   }
  180.   
  181.   return TRUE;
  182. }
  183.  
  184. // Adds or removes shape from m_selections
  185. void csDiagramView::SelectShape(wxShape* shape, bool select)
  186. {
  187.     if (select && !m_selections.Member(shape))
  188.         m_selections.Append(shape);
  189.     else if (!select)
  190.         m_selections.DeleteObject(shape);
  191. }
  192.  
  193. void csDiagramView::OnSelectAll(wxCommandEvent& event)
  194. {
  195.     SelectAll(TRUE);
  196. }
  197.  
  198. wxShape *csDiagramView::FindFirstSelectedShape(void)
  199. {
  200.   csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  201.   wxShape *theShape = NULL;
  202.   wxNode *node = doc->GetDiagram()->GetShapeList()->First();
  203.   while (node)
  204.   {
  205.     wxShape *eachShape = (wxShape *)node->Data();
  206.     if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected())
  207.     {
  208.       theShape = eachShape;
  209.       node = NULL;
  210.     }
  211.     else node = node->Next();
  212.   }
  213.   return theShape;
  214. }
  215.  
  216. void csDiagramView::FindSelectedShapes(wxList& selections, wxClassInfo* toFind)
  217. {
  218.   csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  219.   wxNode *node = doc->GetDiagram()->GetShapeList()->First();
  220.   while (node)
  221.   {
  222.     wxShape *eachShape = (wxShape *)node->Data();
  223.     if ((eachShape->GetParent() == NULL) && !eachShape->IsKindOf(CLASSINFO(wxLabelShape)) && eachShape->Selected() && ((toFind == NULL) || (eachShape->IsKindOf(toFind))))
  224.     {
  225.       selections.Append(eachShape);
  226.     }
  227.     node = node->Next();
  228.   }
  229. }
  230.  
  231. void csDiagramView::OnUndoUpdate(wxUpdateUIEvent& event)
  232. {
  233.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  234.     event.Enable(doc->GetCommandProcessor()->CanUndo());
  235. }
  236.  
  237. void csDiagramView::OnRedoUpdate(wxUpdateUIEvent& event)
  238. {
  239.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  240.     event.Enable(doc->GetCommandProcessor()->CanRedo());
  241. }
  242.  
  243. void csDiagramView::OnCut(wxCommandEvent& event)
  244. {
  245.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  246.  
  247.     // Copy the shapes to the clipboard
  248.     wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram());
  249.  
  250.     wxList selections;
  251.     FindSelectedShapes(selections);
  252.  
  253.     DoCut(selections);
  254. }
  255.  
  256. void csDiagramView::OnClear(wxCommandEvent& event)
  257. {
  258.     wxList selections;
  259.     FindSelectedShapes(selections);
  260.  
  261.     DoCut(selections);
  262. }
  263.  
  264. void csDiagramView::OnCopy(wxCommandEvent& event)
  265. {
  266.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  267.  
  268.     // Copy the shapes to the clipboard
  269.     if (wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram()))
  270.     {
  271. #ifdef __WXMSW__
  272.         // Copy to the Windows clipboard
  273.         wxGetApp().GetDiagramClipboard().CopyToClipboard(1.0);
  274. #endif
  275.     }
  276. }
  277.  
  278. void csDiagramView::OnPaste(wxCommandEvent& event)
  279. {
  280.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  281.  
  282.     wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram());
  283. }
  284.  
  285. void csDiagramView::OnDuplicate(wxCommandEvent& event)
  286. {
  287.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  288.  
  289.     // Do a copy, then a paste
  290.     wxGetApp().GetDiagramClipboard().Copy(doc->GetDiagram());
  291.  
  292.     // Apply an offset. Really, this offset should keep being incremented,
  293.     // but where do we reset it again?
  294.     wxGetApp().GetDiagramClipboard().Paste(doc->GetDiagram(), NULL, 20, 20);
  295. }
  296.  
  297. void csDiagramView::OnCutUpdate(wxUpdateUIEvent& event)
  298. {
  299.     event.Enable( (m_selections.Number() > 0) );
  300. }
  301.  
  302. void csDiagramView::OnClearUpdate(wxUpdateUIEvent& event)
  303. {
  304.     event.Enable( (m_selections.Number() > 0) );
  305. }
  306.  
  307. void csDiagramView::OnCopyUpdate(wxUpdateUIEvent& event)
  308. {
  309.     event.Enable( (m_selections.Number() > 0) );
  310. }
  311.  
  312. void csDiagramView::OnPasteUpdate(wxUpdateUIEvent& event)
  313. {
  314.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  315.  
  316.     int n = wxGetApp().GetDiagramClipboard().GetCount();
  317.  
  318.     event.Enable( (n > 0) );
  319. }
  320.  
  321. void csDiagramView::OnDuplicateUpdate(wxUpdateUIEvent& event)
  322. {
  323.     event.Enable( (m_selections.Number() > 0) );
  324. }
  325.  
  326. void csDiagramView::DoCut(wxList& shapes)
  327. {
  328.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  329.  
  330.     if (shapes.Number() > 0)
  331.     {
  332.         csDiagramCommand* cmd = new csDiagramCommand("Cut", doc);
  333.  
  334.         wxNode* node = shapes.First();
  335.         while (node)
  336.         {
  337.             wxShape *theShape = (wxShape*) node->Data();
  338.             csCommandState* state = new csCommandState(ID_CS_CUT, NULL, theShape);
  339.  
  340.             // Insert lines at the front, so they are cut first.
  341.             // Otherwise we may try to remove a shape with a line still
  342.             // attached.
  343.             if (theShape->IsKindOf(CLASSINFO(wxLineShape)))
  344.                 cmd->InsertState(state);
  345.             else
  346.                 cmd->AddState(state);
  347.  
  348.             node = node->Next();
  349.         }
  350.         cmd->RemoveLines(); // Schedule any connected lines, not already mentioned,
  351.                             // to be removed first
  352.  
  353.         doc->GetCommandProcessor()->Submit(cmd);
  354.     }
  355. }
  356.  
  357. // Generalised command
  358. void csDiagramView::DoCmd(wxList& shapes, wxList& oldShapes, int cmd, const wxString& op)
  359. {
  360.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  361.  
  362.     if (shapes.Number() > 0)
  363.     {
  364.         csDiagramCommand* command = new csDiagramCommand(op, doc);
  365.  
  366.         wxNode* node = shapes.First();
  367.         wxNode* node1 = oldShapes.First();
  368.         while (node && node1)
  369.         {
  370.             wxShape *theShape = (wxShape*) node->Data();
  371.             wxShape *oldShape = (wxShape*) node1->Data();
  372.             csCommandState* state = new csCommandState(cmd, theShape, oldShape);
  373.             command->AddState(state);
  374.  
  375.             node = node->Next();
  376.             node1 = node1->Next();
  377.         }
  378.         doc->GetCommandProcessor()->Submit(command);
  379.     }
  380. }
  381.  
  382. void csDiagramView::OnChangeBackgroundColour(wxCommandEvent& event)
  383. {
  384.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  385.  
  386.     wxList selections;
  387.     FindSelectedShapes(selections);
  388.  
  389.     if (selections.Number() > 0)
  390.     {
  391.         wxColourData data;
  392.         data.SetChooseFull(TRUE);
  393.         if (selections.Number() == 1)
  394.         {
  395.             wxShape* firstShape = (wxShape*) selections.First()->Data();
  396.             data.SetColour(firstShape->GetBrush()->GetColour());
  397.         }
  398.  
  399.         wxColourDialog *dialog = new wxColourDialog(frame, &data);
  400.         wxBrush *theBrush = NULL;
  401.         if (dialog->ShowModal() == wxID_OK)
  402.         {
  403.           wxColourData retData = dialog->GetColourData();
  404.           wxColour col = retData.GetColour();
  405.           theBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID);
  406.         }
  407.         dialog->Close(TRUE);
  408.         if (!theBrush)
  409.             return;
  410.  
  411.         csDiagramCommand* cmd = new csDiagramCommand("Change colour", doc);
  412.  
  413.         wxNode* node = selections.First();
  414.         while (node)
  415.         {
  416.             wxShape *theShape = (wxShape*) node->Data();
  417.             wxShape* newShape = theShape->CreateNewCopy();
  418.             newShape->SetBrush(theBrush);
  419.  
  420.             csCommandState* state = new csCommandState(ID_CS_CHANGE_BACKGROUND_COLOUR, newShape, theShape);
  421.             cmd->AddState(state);
  422.  
  423.             node = node->Next();
  424.         }
  425.         doc->GetCommandProcessor()->Submit(cmd);
  426.     }
  427. }
  428.  
  429. void csDiagramView::OnEditProperties(wxCommandEvent& event)
  430. {
  431.       wxShape *theShape = FindFirstSelectedShape();
  432.       if (theShape)
  433.         ((csEvtHandler *)theShape->GetEventHandler())->EditProperties();
  434. }
  435.  
  436. void csDiagramView::OnEditPropertiesUpdate(wxUpdateUIEvent& event)
  437. {
  438.     wxList selections;
  439.     FindSelectedShapes(selections);
  440.     event.Enable( (selections.Number() > 0) );
  441. }
  442.  
  443. void csDiagramView::OnPointSizeComboSel(wxCommandEvent& event)
  444. {
  445.     wxComboBox* combo = (wxComboBox*) event.GetEventObject();
  446.     wxASSERT( combo != NULL );
  447.  
  448.     int newPointSize = (combo->GetSelection() + 1);
  449.  
  450.     ApplyPointSize(newPointSize);
  451.  
  452. }
  453.  
  454. // TODO: must find out how to intercept the Return key, rather than
  455. // every key stroke. But for now, do every key stroke.
  456. void csDiagramView::OnPointSizeComboText(wxCommandEvent& event)
  457. {
  458.     wxComboBox* combo = (wxComboBox*) event.GetEventObject();
  459.     wxASSERT( combo != NULL );
  460.  
  461.     wxString str(combo->GetValue());
  462.     int newPointSize = atoi((const char*) str);
  463.  
  464.     if (newPointSize < 2)
  465.         return;
  466.  
  467.     ApplyPointSize(newPointSize);
  468. }
  469.  
  470. void csDiagramView::ApplyPointSize(int pointSize)
  471. {
  472.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  473.  
  474.     wxList selections;
  475.     FindSelectedShapes(selections);
  476.  
  477.     if (selections.Number() > 0)
  478.     {
  479.         csDiagramCommand* cmd = new csDiagramCommand("Point size", doc);
  480.  
  481.         wxNode* node = selections.First();
  482.         while (node)
  483.         {
  484.             wxShape *theShape = (wxShape*) node->Data();
  485.             wxShape *newShape = theShape->CreateNewCopy();
  486.  
  487.             wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
  488.                 theShape->GetFont()->GetFamily(),
  489.                 theShape->GetFont()->GetStyle(),
  490.                 theShape->GetFont()->GetWeight(),
  491.                 theShape->GetFont()->GetUnderlined(),
  492.                 theShape->GetFont()->GetFaceName());
  493.  
  494.             newShape->SetFont(newFont);
  495.  
  496.             csCommandState* state = new csCommandState(ID_CS_FONT_CHANGE, newShape, theShape);
  497.  
  498.             cmd->AddState(state);
  499.  
  500.             node = node->Next();
  501.         }
  502.         doc->GetCommandProcessor()->Submit(cmd);
  503.     }
  504. }
  505.  
  506. void csDiagramView::OnZoomSel(wxCommandEvent& event)
  507. {
  508.     int maxZoom = 200;
  509.     int minZoom = 5;
  510.     int inc = 5;
  511.     int noStrings = (maxZoom - minZoom)/inc ;
  512.  
  513.     wxComboBox* combo = (wxComboBox*) event.GetEventObject();
  514.     wxASSERT( combo != NULL );
  515.  
  516.     int scale = (int) ((noStrings - combo->GetSelection() - 1)*inc + minZoom);
  517.  
  518.     canvas->SetScale((double) (scale/100.0), (double) (scale/100.0));
  519.     canvas->Refresh();
  520. }
  521.  
  522. // Select or deselect all
  523. void csDiagramView::SelectAll(bool select)
  524. {
  525.     wxClientDC dc(canvas);
  526.     canvas->PrepareDC(dc);
  527.  
  528.     if (!select)
  529.     {
  530.         wxList selections;
  531.         FindSelectedShapes(selections);
  532.  
  533.         wxNode* node = selections.First();
  534.         while (node)
  535.         {
  536.             wxShape *theShape = (wxShape*) node->Data();
  537.             theShape->Select(FALSE, &dc);
  538.             SelectShape(theShape, FALSE);
  539.  
  540.             node = node->Next();
  541.         }
  542.     }
  543.     else
  544.     {
  545.         csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  546.         wxNode *node = doc->GetDiagram()->GetShapeList()->First();
  547.         while (node)
  548.         {
  549.             wxShape *eachShape = (wxShape *)node->Data();
  550.             if (eachShape->GetParent() == NULL &&
  551.                 !eachShape->IsKindOf(CLASSINFO(wxControlPoint)) &&
  552.                 !eachShape->IsKindOf(CLASSINFO(wxLabelShape)))
  553.             {
  554.                 eachShape->Select(TRUE, &dc);
  555.                 SelectShape(eachShape, TRUE);
  556.             }
  557.             node = node->Next();
  558.         }
  559.     }
  560. }
  561.  
  562.  
  563. void csDiagramView::OnToggleArrowTool(wxCommandEvent& event)
  564. {
  565.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  566.  
  567.     bool state = wxGetApp().GetDiagramToolBar()->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
  568.     wxString stateName;
  569.     if (state)
  570.         stateName = "Arrow on";
  571.     else
  572.         stateName = "Arrow off";
  573.  
  574.     wxList selections;
  575.     FindSelectedShapes(selections, CLASSINFO(wxLineShape));
  576.  
  577.     if (selections.Number() > 0)
  578.     {
  579.         csDiagramCommand* cmd = new csDiagramCommand(stateName, doc);
  580.  
  581.         wxNode* node = selections.First();
  582.         while (node)
  583.         {
  584.             wxLineShape *theShape = (wxLineShape*) node->Data();
  585.             wxLineShape *newShape = NULL;
  586.  
  587.             if (state)
  588.             {
  589.                 // Add arrow
  590.                 if (theShape->GetArrows().Number() == 0)
  591.                 {
  592.                     newShape = (wxLineShape*) theShape->CreateNewCopy();
  593.                     newShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, "Normal arrowhead");
  594.                 }
  595.             }
  596.             else
  597.             {
  598.                 if (theShape->GetArrows().Number() > 0)
  599.                 {
  600.                     newShape = (wxLineShape*) theShape->CreateNewCopy();
  601.                     newShape->ClearArrowsAtPosition();
  602.                 }
  603.             }
  604.  
  605.             // If the new state is the same as the old, don't bother adding it to the command state.
  606.             if (newShape)
  607.             {
  608.                 csCommandState* state = new csCommandState(ID_CS_ARROW_CHANGE, newShape, theShape);
  609.                 cmd->AddState(state);
  610.             }
  611.  
  612.             node = node->Next();
  613.         }
  614.         doc->GetCommandProcessor()->Submit(cmd);
  615.     }
  616. }
  617.  
  618. void csDiagramView::OnToggleArrowToolUpdate(wxUpdateUIEvent& event)
  619. {
  620.     wxList selections;
  621.     FindSelectedShapes(selections, CLASSINFO(wxLineShape));
  622.     event.Enable( (selections.Number() > 0) );
  623. }
  624.  
  625. // Make the point size combobox reflect this
  626. void csDiagramView::ReflectPointSize(int pointSize)
  627. {
  628.     wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
  629.     comboBox->SetSelection(pointSize -1);
  630. }
  631.  
  632. // Make the arrow toggle button reflect the state of the line
  633. void csDiagramView::ReflectArrowState(wxLineShape* lineShape)
  634. {
  635.     bool haveArrow = FALSE;
  636.     wxNode *node = lineShape->GetArrows().First();
  637.     while (node)
  638.     {
  639.       wxArrowHead *arrow = (wxArrowHead *)node->Data();
  640.       if (ARROW_POSITION_MIDDLE == arrow->GetArrowEnd())
  641.         haveArrow = TRUE;
  642.       node = node->Next();
  643.     }
  644.  
  645.     wxGetApp().GetDiagramToolBar()->ToggleTool(DIAGRAM_TOOLBAR_LINE_ARROW, haveArrow);
  646. }
  647.  
  648. void csDiagramView::OnAlign(wxCommandEvent& event)
  649. {
  650.     // Make a copy of the selections, keeping only those shapes
  651.     // that are top-level non-line shapes.
  652.     wxList selections;
  653.     wxNode* node = GetSelectionList().First();
  654.     while (node)
  655.     {
  656.         wxShape* shape = (wxShape*) node->Data();
  657.         if ((shape->GetParent() == NULL) && (!shape->IsKindOf(CLASSINFO(wxLineShape))))
  658.         {
  659.             selections.Append(shape);
  660.         }
  661.         node = node->Next();
  662.     }
  663.  
  664.     if (selections.Number() == 0)
  665.         return;
  666.  
  667.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  668.     csDiagramCommand* cmd = new csDiagramCommand("Align", doc);
  669.  
  670.     node = selections.First();
  671.     wxShape* firstShape = (wxShape*) node->Data();
  672.  
  673.     double x = firstShape->GetX();
  674.     double y = firstShape->GetY();
  675.     double width, height;
  676.     firstShape->GetBoundingBoxMax(&width, &height);
  677.  
  678.     node = selections.First();
  679.     while (node)
  680.     {
  681.         wxShape* shape = (wxShape*) node->Data();
  682.         if (shape != firstShape)
  683.         {
  684.             double x1 = shape->GetX();
  685.             double y1 = shape->GetY();
  686.             double width1, height1;
  687.             shape->GetBoundingBoxMax(& width1, & height1);
  688.  
  689.             wxShape* newShape = shape->CreateNewCopy();
  690.  
  691.             switch (event.GetId())
  692.             {
  693.                 case DIAGRAM_TOOLBAR_ALIGNL:
  694.                 {
  695.                     double x2 = (double)(x - (width/2.0) + (width1/2.0));
  696.                     newShape->SetX(x2);
  697.                     break;
  698.                 }
  699.                 case DIAGRAM_TOOLBAR_ALIGNR:
  700.                 {
  701.                     double x2 = (double)(x + (width/2.0) - (width1/2.0));
  702.                     newShape->SetX(x2);
  703.                     break;
  704.                 }
  705.                 case DIAGRAM_TOOLBAR_ALIGNB:
  706.                 {
  707.                     double y2 = (double)(y + (height/2.0) - (height1/2.0));
  708.                     newShape->SetY(y2);
  709.                     break;
  710.                 }
  711.                 case DIAGRAM_TOOLBAR_ALIGNT:
  712.                 {
  713.                     double y2 = (double)(y - (height/2.0) + (height1/2.0));
  714.                     newShape->SetY(y2);
  715.                     break;
  716.                 }
  717.                 case DIAGRAM_TOOLBAR_ALIGN_HORIZ:
  718.                 {
  719.                     newShape->SetX(x);
  720.                     break;
  721.                 }
  722.                 case DIAGRAM_TOOLBAR_ALIGN_VERT:
  723.                 {
  724.                     newShape->SetY(y);
  725.                     break;
  726.                 }
  727.                 case DIAGRAM_TOOLBAR_COPY_SIZE:
  728.                 {
  729.                     newShape->SetSize(width, height);
  730.                     break;
  731.                 }
  732.             }
  733.             csCommandState* state = new csCommandState(ID_CS_ALIGN, newShape, shape);
  734.             cmd->AddState(state);
  735.         }
  736.         node = node->Next();
  737.     }
  738.     doc->GetCommandProcessor()->Submit(cmd);
  739. }
  740.  
  741. void csDiagramView::OnAlignUpdate(wxUpdateUIEvent& event)
  742. {
  743.     // This is an approximation, since there may be lines
  744.     // amongst the selections.
  745.     event.Enable( (m_selections.Number() > 1) ) ;
  746. }
  747.  
  748. void csDiagramView::OnNewLinePoint(wxCommandEvent& event)
  749. {
  750.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  751.     csDiagramCommand* cmd = new csDiagramCommand("New line point", doc);
  752.  
  753.     wxNode* node = m_selections.First();
  754.     while (node)
  755.     {
  756.         wxShape* shape = (wxShape*) node->Data();
  757.         if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  758.         {
  759.             wxShape* newShape = shape->CreateNewCopy();
  760.             ((wxLineShape*)newShape)->InsertLineControlPoint(NULL);
  761.             csCommandState* state = new csCommandState(ID_CS_NEW_POINT, newShape, shape);
  762.             cmd->AddState(state);
  763.         }
  764.         node = node->Next();
  765.     }
  766.     doc->GetCommandProcessor()->Submit(cmd);
  767. }
  768.  
  769. void csDiagramView::OnCutLinePoint(wxCommandEvent& event)
  770. {
  771.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  772.     csDiagramCommand* cmd = new csDiagramCommand("Cut line point", doc);
  773.  
  774.     wxNode* node = m_selections.First();
  775.     while (node)
  776.     {
  777.         wxShape* shape = (wxShape*) node->Data();
  778.         if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  779.         {
  780.             wxShape* newShape = shape->CreateNewCopy();
  781.             ((wxLineShape*)newShape)->DeleteLineControlPoint();
  782.             csCommandState* state = new csCommandState(ID_CS_CUT_POINT, newShape, shape);
  783.             cmd->AddState(state);
  784.         }
  785.         node = node->Next();
  786.     }
  787.     doc->GetCommandProcessor()->Submit(cmd);
  788. }
  789.  
  790. void csDiagramView::OnStraightenLines(wxCommandEvent& event)
  791. {
  792.     csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
  793.     csDiagramCommand* cmd = new csDiagramCommand("Straighten lines", doc);
  794.  
  795.     wxNode* node = m_selections.First();
  796.     while (node)
  797.     {
  798.         wxShape* shape = (wxShape*) node->Data();
  799.         if (shape->IsKindOf(CLASSINFO(wxLineShape)))
  800.         {
  801.             wxShape* newShape = shape->CreateNewCopy();
  802.             ((wxLineShape*)newShape)->Straighten();
  803.             csCommandState* state = new csCommandState(ID_CS_STRAIGHTEN, newShape, shape);
  804.             cmd->AddState(state);
  805.         }
  806.         node = node->Next();
  807.     }
  808.     doc->GetCommandProcessor()->Submit(cmd);
  809. }
  810.  
  811. void csDiagramView::OnNewLinePointUpdate(wxUpdateUIEvent& event)
  812. {
  813.     wxList selections;
  814.     FindSelectedShapes(selections, CLASSINFO(wxLineShape));
  815.     event.Enable( (selections.Number() > 0) );
  816. }
  817.  
  818. void csDiagramView::OnCutLinePointUpdate(wxUpdateUIEvent& event)
  819. {
  820.     wxList selections;
  821.     FindSelectedShapes(selections, CLASSINFO(wxLineShape));
  822.     event.Enable( (selections.Number() > 0) );
  823. }
  824.  
  825. void csDiagramView::OnStraightenLinesUpdate(wxUpdateUIEvent& event)
  826. {
  827.     wxList selections;
  828.     FindSelectedShapes(selections, CLASSINFO(wxLineShape));
  829.     event.Enable( (selections.Number() > 0) );
  830. }
  831.  
  832. /*
  833.  * Window implementations
  834.  */
  835.  
  836. IMPLEMENT_CLASS(csCanvas, wxShapeCanvas)
  837.  
  838. BEGIN_EVENT_TABLE(csCanvas, wxShapeCanvas)
  839.     EVT_MOUSE_EVENTS(csCanvas::OnMouseEvent)
  840.     EVT_PAINT(csCanvas::OnPaint)
  841. END_EVENT_TABLE()
  842.  
  843. // Define a constructor for my canvas
  844. csCanvas::csCanvas(csDiagramView *v, wxWindow *parent, wxWindowID id, const wxPoint& pos,
  845.     const wxSize& size, long style):
  846.  wxShapeCanvas(parent, id, pos, size, style)
  847. {
  848.   m_view = v;
  849. }
  850.  
  851. csCanvas::~csCanvas(void)
  852. {
  853. }
  854.  
  855. void csCanvas::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2)
  856. {
  857.     wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
  858.     dc.SetPen(dottedPen);
  859.     dc.SetBrush(* wxTRANSPARENT_BRUSH);
  860.  
  861.     dc.DrawRectangle((long) x1, (long) y1, (long) (x2 - x1), (long) (y2 - y1));
  862. }
  863.  
  864. void csCanvas::OnLeftClick(double x, double y, int keys)
  865. {
  866.     csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
  867.  
  868.     if (palette->GetSelection() == PALETTE_ARROW)
  869.     {
  870.         GetView()->SelectAll(FALSE);
  871.  
  872.         wxClientDC dc(this);
  873.         PrepareDC(dc);
  874.  
  875.         Redraw(dc);
  876.         return;
  877.     }
  878.  
  879.     if (palette->GetSelection() == PALETTE_TEXT_TOOL)
  880.     {
  881.         // Ask for a label and create a new free-floating text region
  882.         csLabelEditingDialog* dialog = new csLabelEditingDialog(GetParent());
  883.  
  884.         dialog->SetShapeLabel("");
  885.         dialog->SetTitle("New text box");
  886.         if (dialog->ShowModal() == wxID_CANCEL)
  887.         {
  888.             dialog->Destroy();
  889.             return;
  890.         }
  891.  
  892.         wxString newLabel = dialog->GetShapeLabel();
  893.         dialog->Destroy();
  894.  
  895.         wxShape* shape = new csTextBoxShape;
  896.         shape->AssignNewIds();
  897.         shape->SetEventHandler(new csEvtHandler(shape, shape, newLabel));
  898.  
  899.         wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
  900.         wxString str(comboBox->GetValue());
  901.         int pointSize = atoi((const char*) str);
  902.  
  903.         wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
  904.                 shape->GetFont()->GetFamily(),
  905.                 shape->GetFont()->GetStyle(),
  906.                 shape->GetFont()->GetWeight(),
  907.                 shape->GetFont()->GetUnderlined(),
  908.                 shape->GetFont()->GetFaceName());
  909.  
  910.         shape->SetFont(newFont);
  911.  
  912.         shape->SetX(x);
  913.         shape->SetY(y);
  914.  
  915.         csDiagramCommand* cmd = new csDiagramCommand("Text box",
  916.             (csDiagramDocument *)GetView()->GetDocument(),
  917.             new csCommandState(ID_CS_ADD_SHAPE, shape, NULL));
  918.         GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
  919.  
  920.         palette->SetSelection(PALETTE_ARROW);
  921.  
  922.         return;
  923.     }
  924.  
  925.     csSymbol* symbol = wxGetApp().GetSymbolDatabase()->FindSymbol(palette->GetSelection());
  926.     if (symbol)
  927.     {
  928.         wxShape* theShape = symbol->GetShape()->CreateNewCopy();
  929.  
  930.         wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
  931.         wxString str(comboBox->GetValue());
  932.         int pointSize = atoi((const char*) str);
  933.  
  934.         wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
  935.                 symbol->GetShape()->GetFont()->GetFamily(),
  936.                 symbol->GetShape()->GetFont()->GetStyle(),
  937.                 symbol->GetShape()->GetFont()->GetWeight(),
  938.                 symbol->GetShape()->GetFont()->GetUnderlined(),
  939.                 symbol->GetShape()->GetFont()->GetFaceName());
  940.  
  941.         theShape->SetFont(newFont);
  942.  
  943.         theShape->AssignNewIds();
  944.         theShape->SetX(x);
  945.         theShape->SetY(y);
  946.  
  947.         csDiagramCommand* cmd = new csDiagramCommand(symbol->GetName(),
  948.             (csDiagramDocument *)GetView()->GetDocument(),
  949.             new csCommandState(ID_CS_ADD_SHAPE, theShape, NULL));
  950.         GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
  951.  
  952.         palette->SetSelection(PALETTE_ARROW);
  953.     }
  954. }
  955.  
  956. void csCanvas::OnRightClick(double x, double y, int keys)
  957. {
  958. }
  959.  
  960. // Initial point
  961. static double sg_initialX, sg_initialY;
  962.  
  963. void csCanvas::OnDragLeft(bool draw, double x, double y, int keys)
  964. {
  965.     wxClientDC dc(this);
  966.     PrepareDC(dc);
  967.  
  968.     dc.SetLogicalFunction(OGLRBLF);
  969.     DrawOutline(dc, sg_initialX, sg_initialY, x, y);
  970. }
  971.  
  972. void csCanvas::OnBeginDragLeft(double x, double y, int keys)
  973. {
  974.     sg_initialX = x;
  975.     sg_initialY = y;
  976.  
  977.     wxClientDC dc(this);
  978.     PrepareDC(dc);
  979.  
  980.     dc.SetLogicalFunction(OGLRBLF);
  981.     DrawOutline(dc, sg_initialX, sg_initialY, x, y);
  982.     CaptureMouse();
  983. }
  984.  
  985. void csCanvas::OnEndDragLeft(double x, double y, int keys)
  986. {
  987.     ReleaseMouse();
  988.  
  989.     wxClientDC dc(this);
  990.     PrepareDC(dc);
  991.  
  992.     // Select all images within the rectangle
  993.     float min_x, max_x, min_y, max_y;
  994.     min_x = wxMin(x, sg_initialX);
  995.     max_x = wxMax(x, sg_initialX);
  996.     min_y = wxMin(y, sg_initialY);
  997.     max_y = wxMax(y, sg_initialY);
  998.  
  999.     wxNode *node = GetDiagram()->GetShapeList()->First();
  1000.     while (node)
  1001.     {
  1002.         wxShape *shape = (wxShape *)node->Data();
  1003.         if (shape->GetParent() == NULL && !shape->IsKindOf(CLASSINFO(wxControlPoint)))
  1004.         {
  1005.             float image_x = shape->GetX();
  1006.             float image_y = shape->GetY();
  1007.             if (image_x >= min_x && image_x <= max_x &&
  1008.                 image_y >= min_y && image_y <= max_y)
  1009.             {
  1010.                 shape->Select(TRUE, &dc);
  1011.                 GetView()->SelectShape(shape, TRUE);
  1012.             }
  1013.         }
  1014.         node = node->Next();
  1015.     }
  1016. }
  1017.  
  1018. void csCanvas::OnDragRight(bool draw, double x, double y, int keys)
  1019. {
  1020. }
  1021.  
  1022. void csCanvas::OnBeginDragRight(double x, double y, int keys)
  1023. {
  1024. }
  1025.  
  1026. void csCanvas::OnEndDragRight(double x, double y, int keys)
  1027. {
  1028. }
  1029.  
  1030. void csCanvas::OnMouseEvent(wxMouseEvent& event)
  1031. {
  1032.     wxShapeCanvas::OnMouseEvent(event);
  1033. }
  1034.  
  1035. void csCanvas::OnPaint(wxPaintEvent& event)
  1036. {
  1037. //  if (GetDiagram())
  1038.     wxShapeCanvas::OnPaint(event);
  1039. }
  1040.