• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/amule/wxWidgets-2.8.12/contrib/samples/ogl/studio/
1/////////////////////////////////////////////////////////////////////////////
2// Name:        contrib/samples/ogl/studio/shapes.cpp
3// Purpose:     Implements Studio shapes
4// Author:      Julian Smart
5// Modified by:
6// Created:     12/07/98
7// RCS-ID:      $Id: shapes.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#if !wxUSE_DOC_VIEW_ARCHITECTURE
24#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in wx_setup.h!
25#endif
26
27#include "wx/ogl/ogl.h" // base header of OGL, includes and adjusts wx/deprecated/setup.h
28
29#include "studio.h"
30#include "doc.h"
31#include "shapes.h"
32#include "view.h"
33#include "cspalette.h"
34#include "dialogs.h"
35
36#define csSTANDARD_SHAPE_WIDTH      100
37
38IMPLEMENT_CLASS(csDiagram, wxDiagram)
39
40csDiagram::~csDiagram()
41{
42    DeleteAllShapes();
43}
44
45void csDiagram::Redraw(wxDC& dc)
46{
47    wxDiagram::Redraw(dc);
48
49    // Draw line crossings
50    wxLineCrossings lineCrossings;
51    lineCrossings.FindCrossings(*this);
52    lineCrossings.DrawCrossings(*this, dc);
53}
54
55/*
56 * csEvtHandler: an event handler class for all shapes
57 */
58
59IMPLEMENT_DYNAMIC_CLASS(csEvtHandler, wxShapeEvtHandler)
60
61csEvtHandler::csEvtHandler(wxShapeEvtHandler *prev, wxShape *shape, const wxString& lab):
62  wxShapeEvtHandler(prev, shape)
63{
64    m_label = lab;
65}
66
67csEvtHandler::~csEvtHandler()
68{
69}
70
71// Copy any event handler data
72void csEvtHandler::CopyData(wxShapeEvtHandler& copy)
73{
74    wxShapeEvtHandler::CopyData(copy);
75
76    csEvtHandler& csCopy = (csEvtHandler&) copy;
77    csCopy.m_label = m_label;
78}
79
80void csEvtHandler::OnLeftClick(double WXUNUSED(x), double WXUNUSED(y), int keys, int WXUNUSED(attachment))
81{
82  wxClientDC dc(GetShape()->GetCanvas());
83  GetShape()->GetCanvas()->PrepareDC(dc);
84
85  csDiagramView* view = ((csCanvas*)GetShape()->GetCanvas())->GetView();
86  view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
87
88  if (GetShape()->IsKindOf(CLASSINFO(wxLineShape)))
89      view->ReflectArrowState((wxLineShape*) GetShape());
90
91  csEditorToolPalette *palette = wxGetApp().GetDiagramPalette();
92  if (palette->GetSelection() == PALETTE_TEXT_TOOL)
93  {
94        view->ReflectPointSize(GetShape()->GetFont()->GetPointSize());
95
96        EditProperties();
97#if 0
98        csLabelEditingDialog* dialog = new csLabelEditingDialog(GetShape()->GetCanvas()->GetParent());
99        dialog->SetShapeLabel(m_label);
100        if (dialog->ShowModal() == wxID_CANCEL)
101        {
102            dialog->Destroy();
103            return;
104        }
105
106        wxString newLabel = dialog->GetShapeLabel();
107        dialog->Destroy();
108
109        wxShape* newShape = GetShape()->CreateNewCopy();
110
111        csEvtHandler* handler = (csEvtHandler *)newShape->GetEventHandler();
112        handler->m_label = newLabel;
113
114        view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
115            new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, GetShape())));
116#endif
117        return;
118  }
119
120  if (keys == 0)
121  {
122    // If no shift key, then everything is deselected.
123    // If the shape was selected, deselect it and vice versa.
124    bool selected = GetShape()->Selected();
125
126    view->SelectAll(false);
127
128    selected = !selected;
129
130    GetShape()->Select(selected, &dc);
131    GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
132
133    view->SelectShape(GetShape(), selected);
134  }
135  else if (keys & KEY_SHIFT)
136  {
137    if (GetShape()->Selected())
138    {
139        GetShape()->Select(false, &dc);
140        view->SelectShape(GetShape(), false);
141    }
142    else
143    {
144        GetShape()->Select(true, &dc);
145        view->SelectShape(GetShape(), true);
146    }
147    GetShape()->GetCanvas()->Redraw(dc); // Redraw because bits of objects will be missing
148  }
149  else if (keys & KEY_CTRL)
150  {
151    // Do something for CONTROL
152  }
153  else
154  {
155#if wxUSE_STATUSBAR
156    ((wxFrame*)wxGetApp().GetTopWindow())->SetStatusText(m_label);
157#endif // wxUSE_STATUSBAR
158  }
159}
160
161void csEvtHandler::OnRightClick(double x, double y, int WXUNUSED(keys), int WXUNUSED(attachment))
162{
163    // Have to convert back to physical coordinates from logical coordinates.
164
165    int viewStartX, viewStartY;
166    int unitX, unitY;
167    GetShape()->GetCanvas()->GetViewStart(& viewStartX, & viewStartY);
168    GetShape()->GetCanvas()->GetScrollPixelsPerUnit(& unitX, & unitY);
169
170    int x1 = (int)(x * GetShape()->GetCanvas()->GetScaleX());
171    int y1 = (int)(y * GetShape()->GetCanvas()->GetScaleY());
172
173    int menuX = (int) (x1 - (viewStartX * unitX)) ;
174    int menuY = (int) (y1 - (viewStartY * unitY));
175
176    wxGetApp().GetShapeEditMenu()->SetClientData((char*) GetShape());
177    wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_CLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
178    wxGetApp().GetShapeEditMenu()->Enable(ID_CS_ROTATE_ANTICLOCKWISE, !GetShape()->IsKindOf(CLASSINFO(wxLineShape)));
179
180    GetShape()->GetCanvas()->PopupMenu(wxGetApp().GetShapeEditMenu(), menuX, menuY);
181}
182
183/*
184 * Implement connection of two shapes by right-dragging between them.
185 */
186
187void csEvtHandler::OnBeginDragRight(double x, double y, int WXUNUSED(keys), int attachment)
188{
189  wxClientDC dc(GetShape()->GetCanvas());
190  GetShape()->GetCanvas()->PrepareDC(dc);
191
192  wxPen dottedPen(*wxBLACK, 1, wxDOT);
193  dc.SetLogicalFunction(OGLRBLF);
194  dc.SetPen(dottedPen);
195  double xp, yp;
196  GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
197  dc.DrawLine((wxCoord)xp, (wxCoord)yp, (wxCoord)x, (wxCoord)y);
198  GetShape()->GetCanvas()->CaptureMouse();
199}
200
201void csEvtHandler::OnDragRight(bool WXUNUSED(draw), double x, double y, int WXUNUSED(keys), int attachment)
202{
203  wxClientDC dc(GetShape()->GetCanvas());
204  GetShape()->GetCanvas()->PrepareDC(dc);
205
206  wxPen dottedPen(*wxBLACK, 1, wxDOT);
207  dc.SetLogicalFunction(OGLRBLF);
208  dc.SetPen(dottedPen);
209  double xp, yp;
210  GetShape()->GetAttachmentPositionEdge(attachment, &xp, &yp);
211  dc.DrawLine((wxCoord)xp, (wxCoord)yp, (wxCoord)x, (wxCoord)y);
212}
213
214void csEvtHandler::OnEndDragRight(double x, double y, int WXUNUSED(keys), int attachment)
215{
216  GetShape()->GetCanvas()->ReleaseMouse();
217  csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
218
219  // Check if we're on an object
220  int new_attachment;
221  wxShape *otherShape = canvas->FindFirstSensitiveShape(x, y, &new_attachment, OP_DRAG_RIGHT);
222
223  if (otherShape && !otherShape->IsKindOf(CLASSINFO(wxLineShape)))
224  {
225        wxLineShape* theShape = new csLineShape;
226
227        theShape->AssignNewIds();
228        theShape->SetEventHandler(new csEvtHandler(theShape, theShape, wxEmptyString));
229        theShape->SetPen(wxBLACK_PEN);
230        theShape->SetBrush(wxRED_BRUSH);
231
232        wxToolBar* toolbar = wxGetApp().GetDiagramToolBar();
233        bool haveArrow = toolbar->GetToolState(DIAGRAM_TOOLBAR_LINE_ARROW);
234
235        wxLineShape *lineShape = (wxLineShape *)theShape;
236
237        // Yes, you can have more than 2 control points, in which case
238        // it becomes a multi-segment line.
239        lineShape->MakeLineControlPoints(2);
240
241        if (haveArrow)
242            lineShape->AddArrow(ARROW_ARROW, ARROW_POSITION_MIDDLE, 10.0, 0.0, _T("Normal arrowhead"));
243
244        lineShape->SetFrom(GetShape());
245        lineShape->SetTo(otherShape);
246        lineShape->SetAttachments(attachment, new_attachment);
247
248        canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(
249            new csDiagramCommand(_T("Line"), (csDiagramDocument *)canvas->GetView()->GetDocument(),
250                    new csCommandState(ID_CS_ADD_LINE, lineShape, NULL)));
251  }
252}
253
254static double g_DragOffsetX = 0.0;
255static double g_DragOffsetY = 0.0;
256static double g_DragStartX = 0.0;
257static double g_DragStartY = 0.0;
258
259void csEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
260{
261  if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
262  {
263    attachment = 0;
264    double dist;
265    if (GetShape()->GetParent())
266    {
267      GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
268      GetShape()->GetParent()->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
269    }
270    return;
271  }
272
273  wxClientDC dc(GetShape()->GetCanvas());
274  GetShape()->GetCanvas()->PrepareDC(dc);
275
276  dc.SetLogicalFunction(OGLRBLF);
277
278  wxPen dottedPen(*wxBLACK, 1, wxDOT);
279  dc.SetPen(dottedPen);
280  dc.SetBrush(* wxTRANSPARENT_BRUSH);
281
282  double xx, yy;
283  xx = x + g_DragOffsetX;
284  yy = y + g_DragOffsetY;
285
286  GetShape()->GetCanvas()->Snap(&xx, &yy);
287
288  double offsetX = xx - g_DragStartX;
289  double offsetY = yy - g_DragStartY;
290
291//  m_xpos = xx; m_ypos = yy;
292  double w, h;
293  GetShape()->GetBoundingBoxMax(&w, &h);
294  GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
295
296  // Draw bounding box for other selected shapes
297  wxObjectList::compatibility_iterator node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
298  while (node)
299  {
300     wxShape* shape = (wxShape*) node->GetData();
301     if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
302     {
303        shape->GetBoundingBoxMax(&w, &h);
304        shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
305     }
306     node = node->GetNext();
307  }
308}
309
310void csEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
311{
312  if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
313  {
314    attachment = 0;
315    double dist;
316    if (GetShape()->GetParent())
317    {
318      GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
319      GetShape()->GetParent()->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
320    }
321    return;
322  }
323
324  wxClientDC dc(GetShape()->GetCanvas());
325  GetShape()->GetCanvas()->PrepareDC(dc);
326
327  // New policy: don't erase shape until end of drag.
328//  Erase(dc);
329
330  g_DragOffsetX = GetShape()->GetX() - x;
331  g_DragOffsetY = GetShape()->GetY() - y;
332
333  double xx, yy;
334  xx = x + g_DragOffsetX;
335  yy = y + g_DragOffsetY;
336
337  GetShape()->GetCanvas()->Snap(&xx, &yy);
338
339  g_DragStartX = GetShape()->GetX();
340  g_DragStartY = GetShape()->GetY();
341
342  double offsetX = xx - g_DragStartX;
343  double offsetY = yy - g_DragStartY;
344
345  dc.SetLogicalFunction(OGLRBLF);
346
347  wxPen dottedPen(*wxBLACK, 1, wxDOT);
348  dc.SetPen(dottedPen);
349  dc.SetBrush((* wxTRANSPARENT_BRUSH));
350
351  double w, h;
352  GetShape()->GetBoundingBoxMax(&w, &h);
353  GetShape()->GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
354
355  // Draw bounding box for other selected shapes
356  wxObjectList::compatibility_iterator node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
357  while (node)
358  {
359     wxShape* shape = (wxShape*) node->GetData();
360     if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
361     {
362        shape->GetBoundingBoxMax(&w, &h);
363        shape->OnDrawOutline(dc, shape->GetX() + offsetX, shape->GetY() + offsetY, w, h);
364     }
365     node = node->GetNext();
366  }
367
368  GetShape()->GetCanvas()->CaptureMouse();
369}
370
371
372void csEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
373{
374  csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
375
376  canvas->ReleaseMouse();
377  if ((GetShape()->GetSensitivityFilter() & OP_DRAG_LEFT) != OP_DRAG_LEFT)
378  {
379    attachment = 0;
380    double dist;
381    if (GetShape()->GetParent())
382    {
383      GetShape()->GetParent()->HitTest(x, y, &attachment, &dist);
384      GetShape()->GetParent()->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
385    }
386    return;
387  }
388
389  wxClientDC dc(canvas);
390  canvas->PrepareDC(dc);
391
392  dc.SetLogicalFunction(wxCOPY);
393
394  double xx = x + g_DragOffsetX;
395  double yy = y + g_DragOffsetY;
396
397  canvas->Snap(&xx, &yy);
398
399  double offsetX = xx - g_DragStartX;
400  double offsetY = yy - g_DragStartY;
401
402  wxShape* newShape = GetShape()->CreateNewCopy();
403
404  newShape->SetX(xx);
405  newShape->SetY(yy);
406
407  csDiagramCommand* cmd = new csDiagramCommand(_T("Move"), (csDiagramDocument*)canvas->GetView()->GetDocument(),
408                new csCommandState(ID_CS_MOVE, newShape, GetShape()));
409
410  // Move line points
411  wxObjectList::compatibility_iterator node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
412  while (node)
413  {
414     wxShape* shape = (wxShape*) node->GetData();
415     // Only move the line point(s) if both ends move too
416     if (shape->IsKindOf(CLASSINFO(wxLineShape)) &&
417           ((wxLineShape*)shape)->GetTo()->Selected() && ((wxLineShape*)shape)->GetFrom()->Selected())
418     {
419        wxLineShape* lineShape = (wxLineShape*) shape;
420
421        if (lineShape->GetLineControlPoints()->GetCount() > 2)
422        {
423            wxLineShape* newLineShape = (wxLineShape*) lineShape->CreateNewCopy();
424
425            wxObjectList::compatibility_iterator node1 = newLineShape->GetLineControlPoints()->GetFirst();
426            while (node1)
427            {
428                wxRealPoint *point = (wxRealPoint *)node1->GetData();
429                point->x += offsetX;
430                point->y += offsetY;
431                node1 = node1->GetNext();
432            }
433            cmd->AddState(new csCommandState(ID_CS_MOVE_LINE_POINT, newLineShape, lineShape));
434            lineShape->Erase(dc);
435        }
436     }
437     node = node->GetNext();
438  }
439
440  // Add other selected node shapes, if any
441  node = GetShape()->GetCanvas()->GetDiagram()->GetShapeList()->GetFirst();
442  while (node)
443  {
444     wxShape* shape = (wxShape*) node->GetData();
445     if (shape->Selected() && !shape->IsKindOf(CLASSINFO(wxLineShape)) && (shape != GetShape()))
446     {
447        wxShape* newShape2 = shape->CreateNewCopy();
448        newShape2->SetX(shape->GetX() + offsetX);
449        newShape2->SetY(shape->GetY() + offsetY);
450        cmd->AddState(new csCommandState(ID_CS_MOVE, newShape2, shape));
451     }
452     node = node->GetNext();
453  }
454
455  canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
456}
457
458void csEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
459{
460  wxShape* shape = GetShape();
461  csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
462
463  if (shape->IsKindOf(CLASSINFO(wxLineShape)))
464  {
465    // TODO: Do/Undo support for line operations
466    ((wxLineShape*)shape)->wxLineShape::OnSizingEndDragLeft(pt, x, y, keys, attachment);
467#if 0
468        wxLineShape* lineShape = (wxLineShape*) shape;
469
470        wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
471
472        wxClientDC dc(canvas);
473        canvas->PrepareDC(dc);
474
475        shape->SetDisableLabel(false);
476
477        if (lpt->m_type == CONTROL_POINT_LINE)
478        {
479            canvas->Snap(&x, &y);
480
481            dc.SetLogicalFunction(wxCOPY);
482            lpt->SetX(x); lpt->SetY(y);
483            lpt->m_point->x = x; lpt->m_point->y = y;
484
485            this->OnMoveLink(dc);
486        }
487        if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
488        {
489            if (lpt->m_oldCursor)
490                canvas->SetCursor(lpt->m_oldCursor);
491            lineShape->Erase(dc);
492
493            lpt->SetX(x); lpt->SetY(y);
494
495            if (lineShape->GetFrom())
496            {
497                lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y);
498            }
499        }
500        if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
501        {
502            if (lpt->m_oldCursor)
503                canvas->SetCursor(lpt->m_oldCursor);
504
505            lpt->SetX(x); lpt->SetY(y);
506
507            if (lineShape->GetTo())
508            {
509                lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y);
510            }
511        }
512#endif
513        return;
514  }
515
516  wxClientDC dc(canvas);
517  canvas->PrepareDC(dc);
518
519  canvas->ReleaseMouse();
520  dc.SetLogicalFunction(wxCOPY);
521
522//  shape->Erase(dc);
523/*
524  shape->Recompute();
525  shape->ResetControlPoints();
526  if (!pt->m_eraseObject)
527    shape->Show(false);
528*/
529
530  wxShape* newShape = shape->CreateNewCopy();
531
532  if (newShape->IsKindOf(CLASSINFO(wxPolygonShape)))
533  {
534    wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
535    newShape->SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
536
537    ((wxPolygonShape *)newShape)->CalculateBoundingBox();
538    ((wxPolygonShape *)newShape)->CalculatePolygonCentre();
539    newShape->ResetControlPoints();
540  }
541  else
542  {
543    newShape->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
544    if (shape->GetCentreResize())
545    {
546      // Old position is fine
547    }
548    else
549    {
550      newShape->SetX(pt->sm_controlPointDragPosX);
551      newShape->SetY(pt->sm_controlPointDragPosY);
552    }
553  }
554
555  csDiagramCommand* cmd = new csDiagramCommand(_T("Size"), (csDiagramDocument*)canvas->GetView()->GetDocument(),
556                new csCommandState(ID_CS_SIZE, newShape, shape));
557
558  canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
559
560}
561
562void csEvtHandler::OnEndSize(double WXUNUSED(x), double WXUNUSED(y))
563{
564  wxClientDC dc(GetShape()->GetCanvas());
565  GetShape()->GetCanvas()->PrepareDC(dc);
566
567  GetShape()->FormatText(dc, m_label);
568}
569
570void csEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
571{
572    csCanvas *canvas = (csCanvas *)GetShape()->GetCanvas();
573
574    // We actually submit two different states: one to change the ordering, and another
575    // to change the attachment for the line.
576    // Problem. If we refresh after the attachment change, we'll get a flicker.
577    // We really want to do both in a oner.
578
579    csDiagramCommand* cmd = new csDiagramCommand(_T("Change attachment"), (csDiagramDocument*)canvas->GetView()->GetDocument());
580
581    wxLineShape* newLine = (wxLineShape*) line->CreateNewCopy();
582    if (line->GetTo() == GetShape())
583        newLine->SetAttachmentTo(attachment);
584    else
585        newLine->SetAttachmentFrom(attachment);
586
587    cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ATTACHMENT, newLine, line));
588
589    // Change ordering
590    wxShape* newShape = GetShape()->CreateNewCopy();
591    newShape->ApplyAttachmentOrdering(ordering);
592
593    cmd->AddState(new csCommandState(ID_CS_CHANGE_LINE_ORDERING, newShape, GetShape()));
594
595    canvas->GetView()->GetDocument()->GetCommandProcessor()->Submit(cmd);
596}
597
598void csEvtHandler::OnLeftDoubleClick(double WXUNUSED(x), double WXUNUSED(y), int WXUNUSED(keys), int WXUNUSED(attachment))
599{
600    EditProperties();
601}
602
603// Popup up a property dialog
604bool csEvtHandler::EditProperties()
605{
606    wxShape* shape = GetShape();
607
608    // For now, no line property editing
609    if (shape->IsKindOf(CLASSINFO(wxLineShape)))
610        return false;
611
612    csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
613
614    wxPanel* attributeDialog;
615    wxString attributeDialogName;
616    wxString title;
617
618    if (shape->IsKindOf(CLASSINFO(csThinRectangleShape)))
619    {
620        attributeDialog = new csThinRectangleDialog;
621        attributeDialogName = _T("thin_rectangle");
622        title = _T("Thin Rectangle Properties");
623    }
624    else if (shape->IsKindOf(CLASSINFO(csWideRectangleShape)))
625    {
626        attributeDialog = new csWideRectangleDialog;
627        attributeDialogName = _T("wide_rectangle");
628        title = _T("Wide Rectangle Properties");
629    }
630    else if (shape->IsKindOf(CLASSINFO(csTriangleShape)))
631    {
632        attributeDialog = new csTriangleDialog;
633        attributeDialogName = _T("triangle");
634        title = _T("Triangle Properties");
635    }
636    else if (shape->IsKindOf(CLASSINFO(csSemiCircleShape)))
637    {
638        attributeDialog = new csSemiCircleDialog;
639        attributeDialogName = _T("semi_circle");
640        title = _T("Semicircle Properties");
641    }
642    else if (shape->IsKindOf(CLASSINFO(csCircleShape)))
643    {
644        attributeDialog = new csCircleDialog;
645        attributeDialogName = _T("circle");
646        title = _T("Circle Properties");
647    }
648    else if (shape->IsKindOf(CLASSINFO(csCircleShadowShape)))
649    {
650        attributeDialog = new csCircleShadowDialog;
651        attributeDialogName = _T("circle_shadow");
652        title = _T("Circle Shadow Properties");
653    }
654    else if (shape->IsKindOf(CLASSINFO(csTextBoxShape)))
655    {
656        attributeDialog = new csTextBoxDialog;
657        attributeDialogName = _T("text_box");
658        title = _T("Text Box Properties");
659    }
660    else if (shape->IsKindOf(CLASSINFO(csGroupShape)))
661    {
662        attributeDialog = new csGroupDialog;
663        attributeDialogName = _T("group");
664        title = _T("Group Properties");
665    }
666    else if (shape->IsKindOf(CLASSINFO(csOctagonShape)))
667    {
668        attributeDialog = new csOctagonDialog;
669        attributeDialogName = _T("octagon");
670        title = _T("Octagon Properties");
671    }
672    else
673    {
674        wxMessageBox(_T("Unrecognised shape."), _T("Studio"), wxICON_EXCLAMATION);
675        return false;
676    }
677
678    wxString newLabel(m_label);
679
680#if wxUSE_WX_RESOURCES
681    csShapePropertiesDialog* dialog = new csShapePropertiesDialog(shape->GetCanvas()->GetParent(), title, attributeDialog, attributeDialogName);
682    dialog->GetGeneralPropertiesDialog()->SetShapeLabel(m_label);
683    if (dialog->ShowModal() == wxID_CANCEL)
684    {
685        dialog->Destroy();
686        return false;
687    }
688
689    newLabel = dialog->GetGeneralPropertiesDialog()->GetShapeLabel();
690    dialog->Destroy();
691#else
692    wxUnusedVar(attributeDialog);
693#endif // wxUSE_WX_RESOURCES
694
695    wxShape* newShape = shape->CreateNewCopy();
696
697    csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
698    handler2->m_label = newLabel;
699
700    view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Edit properties"), (csDiagramDocument*) view->GetDocument(),
701                new csCommandState(ID_CS_EDIT_PROPERTIES, newShape, shape)));
702
703    return true;
704}
705
706/*
707 * Diagram
708 */
709
710#if wxUSE_PROLOGIO
711bool csDiagram::OnShapeSave(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
712{
713  wxDiagram::OnShapeSave(db, shape, expr);
714  csEvtHandler *handler = (csEvtHandler *)shape.GetEventHandler();
715  expr.AddAttributeValueString(_T("label"), handler->m_label);
716  return true;
717}
718
719bool csDiagram::OnShapeLoad(wxExprDatabase& db, wxShape& shape, wxExpr& expr)
720{
721  wxDiagram::OnShapeLoad(db, shape, expr);
722  wxString label = wxEmptyString;
723  expr.GetAttributeValue(_T("label"), label);
724  csEvtHandler *handler = new csEvtHandler(&shape, &shape, label);
725  shape.SetEventHandler(handler);
726
727  return true;
728}
729#endif // wxUSE_PROLOGIO
730
731IMPLEMENT_DYNAMIC_CLASS(csThinRectangleShape, wxDrawnShape)
732
733csThinRectangleShape::csThinRectangleShape()
734{
735    SetDrawnPen(wxBLACK_PEN);
736    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
737    SetDrawnBrush(brush);
738
739    double w = csSTANDARD_SHAPE_WIDTH/2;
740    double h = csSTANDARD_SHAPE_WIDTH;
741
742    DrawRectangle(wxRect((int)(- w/2), (int)(- h/2), (int)(w), (int)(h)));
743    CalculateSize();
744
745    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
746    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
747    SetCentreResize(false);
748}
749
750IMPLEMENT_DYNAMIC_CLASS(csWideRectangleShape, wxDrawnShape)
751
752csWideRectangleShape::csWideRectangleShape()
753{
754    SetDrawnPen(wxBLACK_PEN);
755    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
756    SetDrawnBrush(brush);
757
758    double w = csSTANDARD_SHAPE_WIDTH;
759    double h = w/2.0;
760
761    DrawRoundedRectangle(wxRect((int)(- w/2), (int)(- h/2), (int)(w), (int)(h)), -0.3);
762    CalculateSize();
763
764    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
765    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
766    SetCentreResize(false);
767}
768
769IMPLEMENT_DYNAMIC_CLASS(csTriangleShape, wxDrawnShape)
770
771csTriangleShape::csTriangleShape()
772{
773    SetDrawnPen(wxBLACK_PEN);
774    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
775    SetDrawnBrush(brush);
776
777    double w = csSTANDARD_SHAPE_WIDTH;
778    double h = (csSTANDARD_SHAPE_WIDTH*2.0)/3.0;
779
780    // Triangle, from top vertex
781    wxPoint* points = new wxPoint[3];
782
783
784    points[0] = wxPoint( 0 ,  (int)(- h / 2) );
785    points[1] = wxPoint( (int)(w / 2) ,  (int)(h / 2) );
786    points[2] = wxPoint( (int)(-w / 2),  (int)(h / 2) );
787
788    DrawPolygon(3, points, oglMETAFLAGS_OUTLINE);
789
790    delete[] points;
791
792    // Add another triangle at the top for the black bit
793    SetDrawnBrush(wxBLACK_BRUSH);
794
795    points = new wxPoint[3];
796
797    // Calculate where the new points will be, using the proportions
798    // of the triangle.
799    double h1 = 8; // Height of little triangle.
800
801    /*
802        Formula: ((w/2) / h) = w1 / h1
803        w1 = ((w/2) / h) * h1;
804    */
805    double ratio = ((w/2.0) / h) ;
806    double w1 = ratio * h1;
807
808    points[0] = wxPoint(0  ,  (int) (- h / 2 ));
809    points[1] = wxPoint( (int) w1,  (int) (- h / 2 + h1));
810    points[2] = wxPoint( (int) -w1, (int) (- h / 2 + h1));
811
812    DrawPolygon(3, points);
813
814    delete[] points;
815
816    CalculateSize();
817
818    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
819    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
820    SetCentreResize(false);
821}
822
823IMPLEMENT_DYNAMIC_CLASS(csSemiCircleShape, wxDrawnShape)
824
825csSemiCircleShape::csSemiCircleShape()
826{
827    // Zero degrees
828    DrawAtAngle(oglDRAWN_ANGLE_0);
829
830    double w = csSTANDARD_SHAPE_WIDTH;
831    double h = w/2.0;
832
833    SetDrawnPen(wxTRANSPARENT_PEN);
834    SetDrawnBrush(wxTRANSPARENT_BRUSH);
835
836    // Draw a dummy rectangle that will be used for calculating the
837    // bounding box, since we can't calculate the bounding box for
838    // an arbitrary arc (not implemented)
839
840    DrawRectangle(wxRect((int)(-w/2.0), (int)(-h/2.0), (int)(w), (int)(h)));
841
842    SetDrawnPen(wxBLACK_PEN);
843    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
844    SetDrawnBrush(brush);
845
846    DrawEllipticArc(wxRect((int)(-w/2), (int)(-h/2), (int)(w), (int)(2*h)), 0.0, 180.0);
847    DrawLine(wxPoint((int)(-w/2), (int)(h/2)), wxPoint((int)(w/2), (int)(h/2)));
848
849    CalculateSize();
850
851    /// 90 degrees
852
853    w = csSTANDARD_SHAPE_WIDTH/2;
854    h = csSTANDARD_SHAPE_WIDTH;
855
856    DrawAtAngle(oglDRAWN_ANGLE_90);
857
858    SetDrawnPen(wxTRANSPARENT_PEN);
859    SetDrawnBrush(wxTRANSPARENT_BRUSH);
860
861    DrawRectangle(wxRect((int)(-w/2), (int)(-h/2), (int)(w), (int)(h)));
862
863    SetDrawnPen(wxBLACK_PEN);
864    SetDrawnBrush(brush);
865
866    DrawEllipticArc(wxRect((int)(-w/2 - w), (int)(-h/2), (int)(2*w), (int)(h)), 270.0, 90.0);
867    DrawLine(wxPoint((int)(-w/2), (int)(-h/2)), wxPoint((int)(-w/2), (int)(h/2)));
868
869    CalculateSize();
870
871    /// 180 degrees
872
873    DrawAtAngle(oglDRAWN_ANGLE_180);
874
875    w = csSTANDARD_SHAPE_WIDTH;
876    h = csSTANDARD_SHAPE_WIDTH/2;
877
878    SetDrawnPen(wxTRANSPARENT_PEN);
879    SetDrawnBrush(wxTRANSPARENT_BRUSH);
880
881    DrawRectangle(wxRect((int)(-w/2), (int)(-h/2), (int)(w), (int)(h)));
882
883    SetDrawnPen(wxBLACK_PEN);
884    SetDrawnBrush(brush);
885
886    DrawEllipticArc(wxRect((int)(-w/2), (int)(-h/2 - h), (int)(w), (int)(2*h)), 180.0, 0.0);
887    DrawLine(wxPoint((int)(-w/2), (int)(-h/2)), wxPoint((int)(w/2), (int)(-h/2)));
888
889    CalculateSize();
890
891    /// 270 degrees
892
893    DrawAtAngle(oglDRAWN_ANGLE_270);
894
895    w = csSTANDARD_SHAPE_WIDTH/2;
896    h = csSTANDARD_SHAPE_WIDTH;
897
898    SetDrawnPen(wxTRANSPARENT_PEN);
899    SetDrawnBrush(wxTRANSPARENT_BRUSH);
900
901    DrawRectangle(wxRect((int)(-w/2), (int)(-h/2), (int)(w), (int)(h)));
902
903    SetDrawnPen(wxBLACK_PEN);
904    SetDrawnBrush(brush);
905
906    DrawEllipticArc(wxRect((int)(-w/2), (int)(-h/2), (int)(2*w), (int)(h)), 90.0, 270.0);
907    DrawLine(wxPoint((int)(w/2),(int)(-h/2)), wxPoint((int)(w/2), (int)(h/2)));
908
909    CalculateSize();
910
911    // Reset to zero
912    DrawAtAngle(oglDRAWN_ANGLE_0);
913    CalculateSize();
914
915    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
916    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
917    SetCentreResize(false);
918}
919
920IMPLEMENT_DYNAMIC_CLASS(csCircleShape, wxCircleShape)
921
922csCircleShape::csCircleShape()
923{
924    SetPen(wxBLACK_PEN);
925    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
926    SetBrush(brush);
927
928    SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
929
930    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
931    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
932    SetCentreResize(false);
933}
934
935IMPLEMENT_DYNAMIC_CLASS(csCircleShadowShape, wxCircleShape)
936
937csCircleShadowShape::csCircleShadowShape()
938{
939    SetPen(wxBLACK_PEN);
940    wxBrush* brush = wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID);
941    SetBrush(brush);
942
943    SetSize(csSTANDARD_SHAPE_WIDTH*0.6, csSTANDARD_SHAPE_WIDTH*0.6);
944
945    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
946    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
947    SetCentreResize(false);
948    SetShadowMode(SHADOW_RIGHT);
949}
950
951IMPLEMENT_DYNAMIC_CLASS(csOctagonShape, wxPolygonShape)
952
953csOctagonShape::csOctagonShape()
954{
955    SetPen(wxBLACK_PEN);
956    SetBrush(wxTheBrushList->FindOrCreateBrush(wxColour(220, 220, 220), wxSOLID));
957
958    double w = csSTANDARD_SHAPE_WIDTH*0.5;
959    double h = csSTANDARD_SHAPE_WIDTH*0.5;
960
961    double prop = h/3.0;
962
963    wxList* points = new wxList;
964    points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, -h/2.0));
965    points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, -h/2.0));
966    points->Append((wxObject*) new wxRealPoint(w/2.0, -h/2.0 + prop));
967    points->Append((wxObject*) new wxRealPoint(w/2.0, h/2.0 - prop));
968    points->Append((wxObject*) new wxRealPoint(w/2.0 - prop, h/2.0));
969    points->Append((wxObject*) new wxRealPoint(-w/2.0 + prop, h/2.0));
970    points->Append((wxObject*) new wxRealPoint(-w/2.0, h/2.0 - prop));
971    points->Append((wxObject*) new wxRealPoint(-w/2.0, -h/2.0 + prop));
972
973    Create(points);
974
975    SetAttachmentMode(ATTACHMENT_MODE_BRANCHING);
976    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
977    SetCentreResize(false);
978}
979
980// This is a transparent shape for drawing around other shapes.
981IMPLEMENT_DYNAMIC_CLASS(csGroupShape, wxRectangleShape)
982
983csGroupShape::csGroupShape()
984{
985    SetPen(wxThePenList->FindOrCreatePen(_T("BLACK"), 1, wxDOT));
986    SetBrush(wxTRANSPARENT_BRUSH);
987
988    SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH);
989    SetCentreResize(false);
990}
991
992void csGroupShape::OnDraw(wxDC& dc)
993{
994    wxRectangleShape::OnDraw(dc);
995}
996
997// Must modify the hit-test so it doesn't obscure shapes that are inside.
998bool csGroupShape::HitTest(double x, double y, int* attachment, double* distance)
999{
1000    *attachment = 0;
1001    *distance = 0.0;
1002
1003    double width = 0.0, height = 0.0;
1004    GetBoundingBoxMin(&width, &height);
1005
1006    double x1 = GetX() - (width/2.0);
1007    double y1 = GetY() - (height/2.0);
1008    double x2 = GetX() + (width/2.0);
1009    double y2 = GetY() + (height/2.0);
1010
1011    double edgeTolerance = 4.0;
1012
1013    // Test each edge in turn
1014
1015    // Top/bottom edges
1016    if (x >= x1 && x <= x2)
1017    {
1018        if ((y >= y1 - edgeTolerance) && (y <= y1 + edgeTolerance))
1019            return true;
1020        if ((y <= y2 + edgeTolerance) && (y >= y2 - edgeTolerance))
1021            return true;
1022    }
1023    // Left/right edges
1024    if (y >= y1 && y <= y2)
1025    {
1026        if ((x >= x1 - edgeTolerance) && (x <= x1 + edgeTolerance))
1027            return true;
1028        if ((x <= x2 + edgeTolerance) && (x >= x2 - edgeTolerance))
1029            return true;
1030    }
1031
1032    return false;
1033}
1034
1035IMPLEMENT_DYNAMIC_CLASS(csTextBoxShape, wxRectangleShape)
1036
1037csTextBoxShape::csTextBoxShape()
1038{
1039    SetPen(wxTRANSPARENT_PEN);
1040    SetBrush(wxTRANSPARENT_BRUSH);
1041
1042    SetSize(csSTANDARD_SHAPE_WIDTH, csSTANDARD_SHAPE_WIDTH/2.0);
1043
1044    SetAttachmentMode(ATTACHMENT_MODE_NONE);
1045    SetBranchStyle(BRANCHING_ATTACHMENT_NORMAL|BRANCHING_ATTACHMENT_BLOB);
1046    SetCentreResize(false);
1047}
1048
1049IMPLEMENT_DYNAMIC_CLASS(csLineShape, wxLineShape)
1050
1051csLineShape::csLineShape()
1052{
1053}
1054
1055bool csLineShape::OnMoveMiddleControlPoint(wxDC& WXUNUSED(dc), wxLineControlPoint* lpt, const wxRealPoint& pt)
1056{
1057    csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
1058
1059    // Temporarily set the new shape properties so we can copy it
1060    lpt->SetX(pt.x); lpt->SetY(pt.y);
1061    lpt->m_point->x = pt.x; lpt->m_point->y = pt.y;
1062
1063    wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
1064
1065    // Now set them back again
1066    lpt->SetX(lpt->m_originalPos.x); lpt->SetY(lpt->m_originalPos.y);
1067    lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y;
1068
1069    view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand(_T("Move line point"), (csDiagramDocument*) view->GetDocument(),
1070                new csCommandState(ID_CS_MOVE_LINE_POINT, newShape, this)));
1071
1072    return true;
1073}
1074
1075wxLabelShape* csLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
1076{
1077    return new csLabelShape(parent, region, w, h);
1078}
1079
1080#if 0
1081bool csLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display)
1082{
1083    csDiagramView* view = ((csCanvas*)GetCanvas())->GetView();
1084
1085    wxLineShape* newShape = (wxLineShape*) this->CreateNewCopy();
1086
1087    wxLineShape::OnLabelMovePre(dc, labelShape, x, y, old_x, old_y, display);
1088
1089    view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Move label", (csDiagramDocument*) view->GetDocument(),
1090                new csCommandState(ID_CS_MOVE_LABEL, newShape, this)));
1091  return true;
1092}
1093#endif
1094
1095IMPLEMENT_DYNAMIC_CLASS(csLabelShape, wxLabelShape)
1096
1097csLabelShape::csLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):
1098  wxLabelShape(parent, region, w, h)
1099{
1100}
1101
1102// TODO: not sure how intercept normal behaviour (OnMovePre) to make
1103// label movement undo-able.
1104void csLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
1105{
1106    wxLabelShape::OnEndDragLeft(x, y, keys, attachment);
1107}
1108
1109
1110// Menu for editing shapes
1111void studioShapeEditProc(wxMenu& menu, wxCommandEvent& event)
1112{
1113    wxShape* shape = (wxShape*) menu.GetClientData();
1114    csDiagramView* view = ((csCanvas*)shape->GetCanvas())->GetView();
1115
1116    switch (event.GetId())
1117    {
1118        case ID_CS_EDIT_PROPERTIES:
1119        {
1120            csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
1121            handler1->EditProperties();
1122#if 0
1123            csEvtHandler* handler1 = (csEvtHandler *)shape->GetEventHandler();
1124            csLabelEditingDialog* dialog = new csLabelEditingDialog(shape->GetCanvas()->GetParent());
1125            dialog->SetShapeLabel(handler1->m_label);
1126            if (dialog->ShowModal() == wxID_CANCEL)
1127            {
1128                dialog->Destroy();
1129                return;
1130            }
1131
1132            wxString newLabel = dialog->GetShapeLabel();
1133            dialog->Destroy();
1134
1135            wxShape* newShape = shape->CreateNewCopy();
1136
1137            csEvtHandler* handler2 = (csEvtHandler *)newShape->GetEventHandler();
1138            handler2->m_label = newLabel;
1139
1140            view->GetDocument()->GetCommandProcessor()->Submit(new csDiagramCommand("Edit label", (csDiagramDocument*) view->GetDocument(),
1141                new csCommandState(ID_CS_EDIT_LABEL, newShape, shape)));
1142#endif
1143            break;
1144        }
1145        case wxID_CUT:
1146        {
1147            wxList list;
1148            list.Append(shape);
1149            view->DoCut(list);
1150            break;
1151        }
1152        case ID_CS_ROTATE_CLOCKWISE:
1153        case ID_CS_ROTATE_ANTICLOCKWISE:
1154        {
1155            if (shape->IsKindOf(CLASSINFO(wxLineShape)))
1156                break;
1157
1158            double theta = shape->GetRotation();
1159            const double myPi = M_PI;
1160            double ninetyDegrees = myPi/2.0;
1161
1162            wxString opStr;
1163            if (event.GetId() == ID_CS_ROTATE_CLOCKWISE)
1164            {
1165                theta += ninetyDegrees;
1166                opStr = _T("Rotate clockwise");
1167            }
1168            else
1169            {
1170                theta -= ninetyDegrees;
1171                opStr = _T("Rotate anticlockwise");
1172            }
1173
1174            if (theta >= 2.0*myPi || theta < 0.0)
1175                theta = 0.0;
1176            wxShape* newShape = shape->CreateNewCopy();
1177            newShape->Rotate(0.0, 0.0, theta);
1178            wxList newShapes;
1179            wxList oldShapes;
1180            newShapes.Append(newShape);
1181            oldShapes.Append(shape);
1182            view->DoCmd(newShapes, oldShapes, event.GetId(), opStr);
1183            break;
1184        }
1185        default:
1186            break;
1187    }
1188}
1189
1190BEGIN_EVENT_TABLE(ShapeEditMenu, wxMenu)
1191    EVT_COMMAND_RANGE(1, 65000, wxEVT_COMMAND_MENU_SELECTED, ShapeEditMenu::OnCommand)
1192END_EVENT_TABLE()
1193
1194void ShapeEditMenu::OnCommand(wxCommandEvent& event)
1195{
1196    studioShapeEditProc(*this, event);
1197}
1198