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