]> git.saurik.com Git - wxWidgets.git/blame - contrib/samples/ogl/studio/view.cpp
Document wxTextCtrl::XYToPosition, PositionToXY and GetLineLength change
[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{
1fc25a89
JS
312 int n = wxGetApp().GetDiagramClipboard().GetCount();
313
314 event.Enable( (n > 0) );
315}
316
317void csDiagramView::OnDuplicateUpdate(wxUpdateUIEvent& event)
318{
8552e6f0 319 event.Enable( (m_selections.GetCount() > 0) );
1fc25a89
JS
320}
321
322void csDiagramView::DoCut(wxList& shapes)
323{
324 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
325
8552e6f0 326 if (shapes.GetCount() > 0)
1fc25a89 327 {
1484b5cc 328 csDiagramCommand* cmd = new csDiagramCommand(_T("Cut"), doc);
1fc25a89 329
36ca94a2 330 wxObjectList::compatibility_iterator node = shapes.GetFirst();
1fc25a89
JS
331 while (node)
332 {
8552e6f0 333 wxShape *theShape = (wxShape*) node->GetData();
1fc25a89
JS
334 csCommandState* state = new csCommandState(ID_CS_CUT, NULL, theShape);
335
336 // Insert lines at the front, so they are cut first.
337 // Otherwise we may try to remove a shape with a line still
338 // attached.
339 if (theShape->IsKindOf(CLASSINFO(wxLineShape)))
340 cmd->InsertState(state);
341 else
342 cmd->AddState(state);
343
8552e6f0 344 node = node->GetNext();
1fc25a89
JS
345 }
346 cmd->RemoveLines(); // Schedule any connected lines, not already mentioned,
347 // to be removed first
348
349 doc->GetCommandProcessor()->Submit(cmd);
350 }
351}
352
353// Generalised command
354void csDiagramView::DoCmd(wxList& shapes, wxList& oldShapes, int cmd, const wxString& op)
355{
356 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
357
8552e6f0 358 if (shapes.GetCount() > 0)
1fc25a89
JS
359 {
360 csDiagramCommand* command = new csDiagramCommand(op, doc);
361
36ca94a2
WS
362 wxObjectList::compatibility_iterator node = shapes.GetFirst();
363 wxObjectList::compatibility_iterator node1 = oldShapes.GetFirst();
1fc25a89
JS
364 while (node && node1)
365 {
8552e6f0
MB
366 wxShape *theShape = (wxShape*) node->GetData();
367 wxShape *oldShape = (wxShape*) node1->GetData();
1fc25a89
JS
368 csCommandState* state = new csCommandState(cmd, theShape, oldShape);
369 command->AddState(state);
370
8552e6f0
MB
371 node = node->GetNext();
372 node1 = node1->GetNext();
1fc25a89
JS
373 }
374 doc->GetCommandProcessor()->Submit(command);
375 }
376}
377
1484b5cc 378void csDiagramView::OnChangeBackgroundColour(wxCommandEvent& WXUNUSED(event))
1fc25a89
JS
379{
380 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
381
382 wxList selections;
383 FindSelectedShapes(selections);
384
8552e6f0 385 if (selections.GetCount() > 0)
1fc25a89
JS
386 {
387 wxColourData data;
2ba06d5a 388 data.SetChooseFull(true);
8552e6f0 389 if (selections.GetCount() == 1)
1fc25a89 390 {
8552e6f0 391 wxShape* firstShape = (wxShape*) selections.GetFirst()->GetData();
1fc25a89
JS
392 data.SetColour(firstShape->GetBrush()->GetColour());
393 }
394
395 wxColourDialog *dialog = new wxColourDialog(frame, &data);
396 wxBrush *theBrush = NULL;
397 if (dialog->ShowModal() == wxID_OK)
398 {
399 wxColourData retData = dialog->GetColourData();
400 wxColour col = retData.GetColour();
401 theBrush = wxTheBrushList->FindOrCreateBrush(col, wxSOLID);
402 }
2ba06d5a 403 dialog->Close(true);
1fc25a89
JS
404 if (!theBrush)
405 return;
406
1484b5cc 407 csDiagramCommand* cmd = new csDiagramCommand(_T("Change colour"), doc);
1fc25a89 408
36ca94a2 409 wxObjectList::compatibility_iterator node = selections.GetFirst();
1fc25a89
JS
410 while (node)
411 {
8552e6f0 412 wxShape *theShape = (wxShape*) node->GetData();
1fc25a89
JS
413 wxShape* newShape = theShape->CreateNewCopy();
414 newShape->SetBrush(theBrush);
415
416 csCommandState* state = new csCommandState(ID_CS_CHANGE_BACKGROUND_COLOUR, newShape, theShape);
417 cmd->AddState(state);
418
8552e6f0 419 node = node->GetNext();
1fc25a89
JS
420 }
421 doc->GetCommandProcessor()->Submit(cmd);
422 }
423}
424
1484b5cc 425void csDiagramView::OnEditProperties(wxCommandEvent& WXUNUSED(event))
1fc25a89
JS
426{
427 wxShape *theShape = FindFirstSelectedShape();
428 if (theShape)
429 ((csEvtHandler *)theShape->GetEventHandler())->EditProperties();
430}
431
432void csDiagramView::OnEditPropertiesUpdate(wxUpdateUIEvent& event)
433{
434 wxList selections;
435 FindSelectedShapes(selections);
8552e6f0 436 event.Enable( (selections.GetCount() > 0) );
1fc25a89
JS
437}
438
439void csDiagramView::OnPointSizeComboSel(wxCommandEvent& event)
440{
441 wxComboBox* combo = (wxComboBox*) event.GetEventObject();
442 wxASSERT( combo != NULL );
443
444 int newPointSize = (combo->GetSelection() + 1);
445
446 ApplyPointSize(newPointSize);
447
448}
449
450// TODO: must find out how to intercept the Return key, rather than
451// every key stroke. But for now, do every key stroke.
452void csDiagramView::OnPointSizeComboText(wxCommandEvent& event)
453{
454 wxComboBox* combo = (wxComboBox*) event.GetEventObject();
455 wxASSERT( combo != NULL );
456
457 wxString str(combo->GetValue());
1484b5cc
VS
458 long newPointSize;
459 str.ToLong( &newPointSize );
1fc25a89
JS
460
461 if (newPointSize < 2)
462 return;
463
464 ApplyPointSize(newPointSize);
465}
466
467void csDiagramView::ApplyPointSize(int pointSize)
468{
469 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
470
471 wxList selections;
472 FindSelectedShapes(selections);
473
8552e6f0 474 if (selections.GetCount() > 0)
1fc25a89 475 {
1484b5cc 476 csDiagramCommand* cmd = new csDiagramCommand(_T("Point size"), doc);
1fc25a89 477
36ca94a2 478 wxObjectList::compatibility_iterator node = selections.GetFirst();
1fc25a89
JS
479 while (node)
480 {
8552e6f0 481 wxShape *theShape = (wxShape*) node->GetData();
1fc25a89
JS
482 wxShape *newShape = theShape->CreateNewCopy();
483
484 wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
485 theShape->GetFont()->GetFamily(),
486 theShape->GetFont()->GetStyle(),
487 theShape->GetFont()->GetWeight(),
488 theShape->GetFont()->GetUnderlined(),
489 theShape->GetFont()->GetFaceName());
490
491 newShape->SetFont(newFont);
492
493 csCommandState* state = new csCommandState(ID_CS_FONT_CHANGE, newShape, theShape);
494
495 cmd->AddState(state);
496
8552e6f0 497 node = node->GetNext();
1fc25a89
JS
498 }
499 doc->GetCommandProcessor()->Submit(cmd);
500 }
501}
502
503void csDiagramView::OnZoomSel(wxCommandEvent& event)
504{
505 int maxZoom = 200;
506 int minZoom = 5;
507 int inc = 5;
508 int noStrings = (maxZoom - minZoom)/inc ;
509
510 wxComboBox* combo = (wxComboBox*) event.GetEventObject();
511 wxASSERT( combo != NULL );
512
513 int scale = (int) ((noStrings - combo->GetSelection() - 1)*inc + minZoom);
514
515 canvas->SetScale((double) (scale/100.0), (double) (scale/100.0));
516 canvas->Refresh();
517}
518
519// Select or deselect all
520void csDiagramView::SelectAll(bool select)
521{
522 wxClientDC dc(canvas);
523 canvas->PrepareDC(dc);
524
525 if (!select)
526 {
527 wxList selections;
528 FindSelectedShapes(selections);
529
36ca94a2 530 wxObjectList::compatibility_iterator node = selections.GetFirst();
1fc25a89
JS
531 while (node)
532 {
8552e6f0 533 wxShape *theShape = (wxShape*) node->GetData();
2ba06d5a
WS
534 theShape->Select(false, &dc);
535 SelectShape(theShape, false);
1fc25a89 536
8552e6f0 537 node = node->GetNext();
1fc25a89
JS
538 }
539 }
540 else
541 {
542 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
36ca94a2 543 wxObjectList::compatibility_iterator node = doc->GetDiagram()->GetShapeList()->GetFirst();
1fc25a89
JS
544 while (node)
545 {
8552e6f0 546 wxShape *eachShape = (wxShape *)node->GetData();
1fc25a89
JS
547 if (eachShape->GetParent() == NULL &&
548 !eachShape->IsKindOf(CLASSINFO(wxControlPoint)) &&
549 !eachShape->IsKindOf(CLASSINFO(wxLabelShape)))
550 {
2ba06d5a
WS
551 eachShape->Select(true, &dc);
552 SelectShape(eachShape, true);
1fc25a89 553 }
8552e6f0 554 node = node->GetNext();
1fc25a89
JS
555 }
556 }
557}
558
559
1484b5cc 560void csDiagramView::OnToggleArrowTool(wxCommandEvent& WXUNUSED(event))
1fc25a89
JS
561{
562 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
563
564 bool state = wxGetApp().GetDiagramToolBar()->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
565 wxString stateName;
566 if (state)
1484b5cc 567 stateName = _T("Arrow on");
1fc25a89 568 else
1484b5cc 569 stateName = _T("Arrow off");
1fc25a89
JS
570
571 wxList selections;
572 FindSelectedShapes(selections, CLASSINFO(wxLineShape));
573
8552e6f0 574 if (selections.GetCount() > 0)
1fc25a89
JS
575 {
576 csDiagramCommand* cmd = new csDiagramCommand(stateName, doc);
577
5e0dbc8d 578 wxObjectList::compatibility_iterator node = selections.GetFirst();
1fc25a89
JS
579 while (node)
580 {
8552e6f0 581 wxLineShape *theShape = (wxLineShape*) node->GetData();
1fc25a89
JS
582 wxLineShape *newShape = NULL;
583
584 if (state)
585 {
586 // Add arrow
8552e6f0 587 if (theShape->GetArrows().GetCount() == 0)
1fc25a89
JS
588 {
589 newShape = (wxLineShape*) theShape->CreateNewCopy();
1484b5cc 590 newShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, _T("Normal arrowhead"));
1fc25a89
JS
591 }
592 }
593 else
594 {
8552e6f0 595 if (theShape->GetArrows().GetCount() > 0)
1fc25a89
JS
596 {
597 newShape = (wxLineShape*) theShape->CreateNewCopy();
598 newShape->ClearArrowsAtPosition();
599 }
600 }
601
602 // If the new state is the same as the old, don't bother adding it to the command state.
603 if (newShape)
604 {
605 csCommandState* state = new csCommandState(ID_CS_ARROW_CHANGE, newShape, theShape);
606 cmd->AddState(state);
607 }
608
8552e6f0 609 node = node->GetNext();
1fc25a89
JS
610 }
611 doc->GetCommandProcessor()->Submit(cmd);
612 }
613}
614
615void csDiagramView::OnToggleArrowToolUpdate(wxUpdateUIEvent& event)
616{
617 wxList selections;
618 FindSelectedShapes(selections, CLASSINFO(wxLineShape));
8552e6f0 619 event.Enable( (selections.GetCount() > 0) );
1fc25a89
JS
620}
621
622// Make the point size combobox reflect this
623void csDiagramView::ReflectPointSize(int pointSize)
624{
625 wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
626 comboBox->SetSelection(pointSize -1);
627}
628
629// Make the arrow toggle button reflect the state of the line
630void csDiagramView::ReflectArrowState(wxLineShape* lineShape)
631{
2ba06d5a 632 bool haveArrow = false;
5e0dbc8d 633 wxObjectList::compatibility_iterator node = lineShape->GetArrows().GetFirst();
1fc25a89
JS
634 while (node)
635 {
8552e6f0 636 wxArrowHead *arrow = (wxArrowHead *)node->GetData();
1fc25a89 637 if (ARROW_POSITION_MIDDLE == arrow->GetArrowEnd())
2ba06d5a 638 haveArrow = true;
8552e6f0 639 node = node->GetNext();
1fc25a89
JS
640 }
641
642 wxGetApp().GetDiagramToolBar()->ToggleTool(DIAGRAM_TOOLBAR_LINE_ARROW, haveArrow);
643}
644
645void csDiagramView::OnAlign(wxCommandEvent& event)
646{
647 // Make a copy of the selections, keeping only those shapes
648 // that are top-level non-line shapes.
649 wxList selections;
5e0dbc8d 650 wxObjectList::compatibility_iterator node = GetSelectionList().GetFirst();
1fc25a89
JS
651 while (node)
652 {
8552e6f0 653 wxShape* shape = (wxShape*) node->GetData();
1fc25a89
JS
654 if ((shape->GetParent() == NULL) && (!shape->IsKindOf(CLASSINFO(wxLineShape))))
655 {
656 selections.Append(shape);
657 }
8552e6f0 658 node = node->GetNext();
1fc25a89
JS
659 }
660
8552e6f0 661 if (selections.GetCount() == 0)
1fc25a89
JS
662 return;
663
664 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
1484b5cc 665 csDiagramCommand* cmd = new csDiagramCommand(_T("Align"), doc);
1fc25a89 666
8552e6f0
MB
667 node = selections.GetFirst();
668 wxShape* firstShape = (wxShape*) node->GetData();
1fc25a89
JS
669
670 double x = firstShape->GetX();
671 double y = firstShape->GetY();
672 double width, height;
673 firstShape->GetBoundingBoxMax(&width, &height);
674
8552e6f0 675 node = selections.GetFirst();
1fc25a89
JS
676 while (node)
677 {
8552e6f0 678 wxShape* shape = (wxShape*) node->GetData();
1fc25a89
JS
679 if (shape != firstShape)
680 {
1484b5cc
VS
681 /* double x1 = */ shape->GetX();
682 /* double y1 = */ shape->GetY();
1fc25a89
JS
683 double width1, height1;
684 shape->GetBoundingBoxMax(& width1, & height1);
685
686 wxShape* newShape = shape->CreateNewCopy();
687
688 switch (event.GetId())
689 {
690 case DIAGRAM_TOOLBAR_ALIGNL:
691 {
692 double x2 = (double)(x - (width/2.0) + (width1/2.0));
693 newShape->SetX(x2);
694 break;
695 }
696 case DIAGRAM_TOOLBAR_ALIGNR:
697 {
698 double x2 = (double)(x + (width/2.0) - (width1/2.0));
699 newShape->SetX(x2);
700 break;
701 }
702 case DIAGRAM_TOOLBAR_ALIGNB:
703 {
704 double y2 = (double)(y + (height/2.0) - (height1/2.0));
705 newShape->SetY(y2);
706 break;
707 }
708 case DIAGRAM_TOOLBAR_ALIGNT:
709 {
710 double y2 = (double)(y - (height/2.0) + (height1/2.0));
711 newShape->SetY(y2);
712 break;
713 }
714 case DIAGRAM_TOOLBAR_ALIGN_HORIZ:
715 {
716 newShape->SetX(x);
717 break;
718 }
719 case DIAGRAM_TOOLBAR_ALIGN_VERT:
720 {
721 newShape->SetY(y);
722 break;
723 }
724 case DIAGRAM_TOOLBAR_COPY_SIZE:
725 {
726 newShape->SetSize(width, height);
727 break;
728 }
729 }
730 csCommandState* state = new csCommandState(ID_CS_ALIGN, newShape, shape);
731 cmd->AddState(state);
732 }
8552e6f0 733 node = node->GetNext();
1fc25a89
JS
734 }
735 doc->GetCommandProcessor()->Submit(cmd);
736}
737
738void csDiagramView::OnAlignUpdate(wxUpdateUIEvent& event)
739{
740 // This is an approximation, since there may be lines
741 // amongst the selections.
8552e6f0 742 event.Enable( (m_selections.GetCount() > 1) ) ;
1fc25a89
JS
743}
744
1484b5cc 745void csDiagramView::OnNewLinePoint(wxCommandEvent& WXUNUSED(event))
1fc25a89
JS
746{
747 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
1484b5cc 748 csDiagramCommand* cmd = new csDiagramCommand(_T("New line point"), doc);
1fc25a89 749
5e0dbc8d 750 wxObjectList::compatibility_iterator node = m_selections.GetFirst();
1fc25a89
JS
751 while (node)
752 {
8552e6f0 753 wxShape* shape = (wxShape*) node->GetData();
1fc25a89
JS
754 if (shape->IsKindOf(CLASSINFO(wxLineShape)))
755 {
756 wxShape* newShape = shape->CreateNewCopy();
757 ((wxLineShape*)newShape)->InsertLineControlPoint(NULL);
758 csCommandState* state = new csCommandState(ID_CS_NEW_POINT, newShape, shape);
759 cmd->AddState(state);
760 }
8552e6f0 761 node = node->GetNext();
1fc25a89
JS
762 }
763 doc->GetCommandProcessor()->Submit(cmd);
764}
765
1484b5cc 766void csDiagramView::OnCutLinePoint(wxCommandEvent& WXUNUSED(event))
1fc25a89
JS
767{
768 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
1484b5cc 769 csDiagramCommand* cmd = new csDiagramCommand(_T("Cut line point"), doc);
1fc25a89 770
5e0dbc8d 771 wxObjectList::compatibility_iterator node = m_selections.GetFirst();
1fc25a89
JS
772 while (node)
773 {
8552e6f0 774 wxShape* shape = (wxShape*) node->GetData();
1fc25a89
JS
775 if (shape->IsKindOf(CLASSINFO(wxLineShape)))
776 {
777 wxShape* newShape = shape->CreateNewCopy();
778 ((wxLineShape*)newShape)->DeleteLineControlPoint();
779 csCommandState* state = new csCommandState(ID_CS_CUT_POINT, newShape, shape);
780 cmd->AddState(state);
781 }
8552e6f0 782 node = node->GetNext();
1fc25a89
JS
783 }
784 doc->GetCommandProcessor()->Submit(cmd);
785}
786
1484b5cc 787void csDiagramView::OnStraightenLines(wxCommandEvent& WXUNUSED(event))
1fc25a89
JS
788{
789 csDiagramDocument *doc = (csDiagramDocument *)GetDocument();
1484b5cc 790 csDiagramCommand* cmd = new csDiagramCommand(_T("Straighten lines"), doc);
1fc25a89 791
5e0dbc8d 792 wxObjectList::compatibility_iterator node = m_selections.GetFirst();
1fc25a89
JS
793 while (node)
794 {
8552e6f0 795 wxShape* shape = (wxShape*) node->GetData();
1fc25a89
JS
796 if (shape->IsKindOf(CLASSINFO(wxLineShape)))
797 {
798 wxShape* newShape = shape->CreateNewCopy();
799 ((wxLineShape*)newShape)->Straighten();
800 csCommandState* state = new csCommandState(ID_CS_STRAIGHTEN, newShape, shape);
801 cmd->AddState(state);
802 }
8552e6f0 803 node = node->GetNext();
1fc25a89
JS
804 }
805 doc->GetCommandProcessor()->Submit(cmd);
806}
807
808void csDiagramView::OnNewLinePointUpdate(wxUpdateUIEvent& event)
809{
810 wxList selections;
811 FindSelectedShapes(selections, CLASSINFO(wxLineShape));
8552e6f0 812 event.Enable( (selections.GetCount() > 0) );
1fc25a89
JS
813}
814
815void csDiagramView::OnCutLinePointUpdate(wxUpdateUIEvent& event)
816{
817 wxList selections;
818 FindSelectedShapes(selections, CLASSINFO(wxLineShape));
8552e6f0 819 event.Enable( (selections.GetCount() > 0) );
1fc25a89
JS
820}
821
822void csDiagramView::OnStraightenLinesUpdate(wxUpdateUIEvent& event)
823{
824 wxList selections;
825 FindSelectedShapes(selections, CLASSINFO(wxLineShape));
8552e6f0 826 event.Enable( (selections.GetCount() > 0) );
1fc25a89
JS
827}
828
829/*
830 * Window implementations
831 */
832
833IMPLEMENT_CLASS(csCanvas, wxShapeCanvas)
834
835BEGIN_EVENT_TABLE(csCanvas, wxShapeCanvas)
836 EVT_MOUSE_EVENTS(csCanvas::OnMouseEvent)
837 EVT_PAINT(csCanvas::OnPaint)
838END_EVENT_TABLE()
839
840// Define a constructor for my canvas
841csCanvas::csCanvas(csDiagramView *v, wxWindow *parent, wxWindowID id, const wxPoint& pos,
842 const wxSize& size, long style):
843 wxShapeCanvas(parent, id, pos, size, style)
844{
845 m_view = v;
846}
847
848csCanvas::~csCanvas(void)
849{
850}
851
852void csCanvas::DrawOutline(wxDC& dc, double x1, double y1, double x2, double y2)
853{
55c91e8a 854 wxPen dottedPen(*wxBLACK, 1, wxDOT);
1fc25a89
JS
855 dc.SetPen(dottedPen);
856 dc.SetBrush(* wxTRANSPARENT_BRUSH);
857
858 dc.DrawRectangle((long) x1, (long) y1, (long) (x2 - x1), (long) (y2 - y1));
859}
860
1484b5cc 861void csCanvas::OnLeftClick(double x, double y, int WXUNUSED(keys))
1fc25a89
JS
862{
863 csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
864
865 if (palette->GetSelection() == PALETTE_ARROW)
866 {
2ba06d5a 867 GetView()->SelectAll(false);
1fc25a89
JS
868
869 wxClientDC dc(this);
870 PrepareDC(dc);
871
872 Redraw(dc);
873 return;
874 }
875
876 if (palette->GetSelection() == PALETTE_TEXT_TOOL)
877 {
cecdcad1
WS
878 wxString newLabel;
879
880#if wxUSE_WX_RESOURCES
1fc25a89
JS
881 // Ask for a label and create a new free-floating text region
882 csLabelEditingDialog* dialog = new csLabelEditingDialog(GetParent());
883
1484b5cc
VS
884 dialog->SetShapeLabel( wxEmptyString );
885 dialog->SetTitle(_T("New text box"));
1fc25a89
JS
886 if (dialog->ShowModal() == wxID_CANCEL)
887 {
888 dialog->Destroy();
889 return;
890 }
891
cecdcad1 892 newLabel = dialog->GetShapeLabel();
1fc25a89 893 dialog->Destroy();
cecdcad1 894#endif // wxUSE_WX_RESOURCES
1fc25a89
JS
895
896 wxShape* shape = new csTextBoxShape;
897 shape->AssignNewIds();
898 shape->SetEventHandler(new csEvtHandler(shape, shape, newLabel));
899
900 wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
901 wxString str(comboBox->GetValue());
1484b5cc
VS
902 long pointSize;
903 str.ToLong( &pointSize );
1fc25a89
JS
904
905 wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
906 shape->GetFont()->GetFamily(),
907 shape->GetFont()->GetStyle(),
908 shape->GetFont()->GetWeight(),
909 shape->GetFont()->GetUnderlined(),
910 shape->GetFont()->GetFaceName());
911
912 shape->SetFont(newFont);
913
914 shape->SetX(x);
915 shape->SetY(y);
916
1484b5cc 917 csDiagramCommand* cmd = new csDiagramCommand(_T("Text box"),
1fc25a89
JS
918 (csDiagramDocument *)GetView()->GetDocument(),
919 new csCommandState(ID_CS_ADD_SHAPE, shape, NULL));
920 GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
921
922 palette->SetSelection(PALETTE_ARROW);
923
924 return;
925 }
926
927 csSymbol* symbol = wxGetApp().GetSymbolDatabase()->FindSymbol(palette->GetSelection());
928 if (symbol)
929 {
930 wxShape* theShape = symbol->GetShape()->CreateNewCopy();
931
932 wxComboBox* comboBox = wxGetApp().GetPointSizeComboBox();
933 wxString str(comboBox->GetValue());
1484b5cc
VS
934 long pointSize;
935 str.ToLong( &pointSize );
1fc25a89
JS
936
937 wxFont* newFont = wxTheFontList->FindOrCreateFont(pointSize,
938 symbol->GetShape()->GetFont()->GetFamily(),
939 symbol->GetShape()->GetFont()->GetStyle(),
940 symbol->GetShape()->GetFont()->GetWeight(),
941 symbol->GetShape()->GetFont()->GetUnderlined(),
942 symbol->GetShape()->GetFont()->GetFaceName());
943
944 theShape->SetFont(newFont);
945
946 theShape->AssignNewIds();
947 theShape->SetX(x);
948 theShape->SetY(y);
949
950 csDiagramCommand* cmd = new csDiagramCommand(symbol->GetName(),
951 (csDiagramDocument *)GetView()->GetDocument(),
952 new csCommandState(ID_CS_ADD_SHAPE, theShape, NULL));
953 GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
954
955 palette->SetSelection(PALETTE_ARROW);
956 }
957}
958
1484b5cc 959void csCanvas::OnRightClick(double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys))
1fc25a89
JS
960{
961}
962
963// Initial point
964static double sg_initialX, sg_initialY;
965
1484b5cc 966void csCanvas::OnDragLeft(bool WXUNUSED(draw), double x, double y, int WXUNUSED(keys))
1fc25a89
JS
967{
968 wxClientDC dc(this);
969 PrepareDC(dc);
970
971 dc.SetLogicalFunction(OGLRBLF);
972 DrawOutline(dc, sg_initialX, sg_initialY, x, y);
973}
974
1484b5cc 975void csCanvas::OnBeginDragLeft(double x, double y, int WXUNUSED(keys))
1fc25a89
JS
976{
977 sg_initialX = x;
978 sg_initialY = y;
979
980 wxClientDC dc(this);
981 PrepareDC(dc);
982
983 dc.SetLogicalFunction(OGLRBLF);
984 DrawOutline(dc, sg_initialX, sg_initialY, x, y);
985 CaptureMouse();
986}
987
1484b5cc 988void csCanvas::OnEndDragLeft(double x, double y, int WXUNUSED(keys))
1fc25a89
JS
989{
990 ReleaseMouse();
991
992 wxClientDC dc(this);
993 PrepareDC(dc);
994
995 // Select all images within the rectangle
996 float min_x, max_x, min_y, max_y;
997 min_x = wxMin(x, sg_initialX);
998 max_x = wxMax(x, sg_initialX);
999 min_y = wxMin(y, sg_initialY);
1000 max_y = wxMax(y, sg_initialY);
1001
5e0dbc8d 1002 wxObjectList::compatibility_iterator node = GetDiagram()->GetShapeList()->GetFirst();
1fc25a89
JS
1003 while (node)
1004 {
8552e6f0 1005 wxShape *shape = (wxShape *)node->GetData();
1fc25a89
JS
1006 if (shape->GetParent() == NULL && !shape->IsKindOf(CLASSINFO(wxControlPoint)))
1007 {
1008 float image_x = shape->GetX();
1009 float image_y = shape->GetY();
1010 if (image_x >= min_x && image_x <= max_x &&
1011 image_y >= min_y && image_y <= max_y)
1012 {
2ba06d5a
WS
1013 shape->Select(true, &dc);
1014 GetView()->SelectShape(shape, true);
1fc25a89
JS
1015 }
1016 }
8552e6f0 1017 node = node->GetNext();
1fc25a89
JS
1018 }
1019}
1020
1484b5cc 1021void csCanvas::OnDragRight(bool WXUNUSED(draw), double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys))
1fc25a89
JS
1022{
1023}
1024
1484b5cc 1025void csCanvas::OnBeginDragRight(double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys))
1fc25a89
JS
1026{
1027}
1028
1484b5cc 1029void csCanvas::OnEndDragRight(double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys))
1fc25a89
JS
1030{
1031}
1032
1033void csCanvas::OnMouseEvent(wxMouseEvent& event)
1034{
1035 wxShapeCanvas::OnMouseEvent(event);
1036}
1037
1038void csCanvas::OnPaint(wxPaintEvent& event)
1039{
1040// if (GetDiagram())
1041 wxShapeCanvas::OnPaint(event);
1042}