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