]> git.saurik.com Git - wxWidgets.git/blob - contrib/samples/ogl/studio/view.cpp
fix menubar sizing (at least under windows)
[wxWidgets.git] / contrib / samples / ogl / studio / view.cpp
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$
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 }