]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/basic.cpp
added test for wxScopeGuard
[wxWidgets.git] / contrib / src / ogl / basic.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: basic.cpp
3 // Purpose: Basic OGL classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 12/07/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "basic.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <wx/wx.h>
25 #endif
26
27 #if wxUSE_PROLOGIO
28 #include <wx/deprecated/wxexpr.h>
29 #endif
30
31 #ifdef new
32 #undef new
33 #endif
34
35 #include <stdio.h>
36 #include <ctype.h>
37
38 #include "wx/ogl/ogl.h"
39
40
41 // Control point types
42 // Rectangle and most other shapes
43 #define CONTROL_POINT_VERTICAL 1
44 #define CONTROL_POINT_HORIZONTAL 2
45 #define CONTROL_POINT_DIAGONAL 3
46
47 // Line
48 #define CONTROL_POINT_ENDPOINT_TO 4
49 #define CONTROL_POINT_ENDPOINT_FROM 5
50 #define CONTROL_POINT_LINE 6
51
52 IMPLEMENT_DYNAMIC_CLASS(wxShapeTextLine, wxObject)
53 IMPLEMENT_DYNAMIC_CLASS(wxAttachmentPoint, wxObject)
54
55 wxShapeTextLine::wxShapeTextLine(double the_x, double the_y, const wxString& the_line)
56 {
57 m_x = the_x; m_y = the_y; m_line = the_line;
58 }
59
60 wxShapeTextLine::~wxShapeTextLine()
61 {
62 }
63
64 IMPLEMENT_ABSTRACT_CLASS(wxShapeEvtHandler, wxObject)
65
66 wxShapeEvtHandler::wxShapeEvtHandler(wxShapeEvtHandler *prev, wxShape *shape)
67 {
68 m_previousHandler = prev;
69 m_handlerShape = shape;
70 }
71
72 wxShapeEvtHandler::~wxShapeEvtHandler()
73 {
74 }
75
76 // Creates a copy of this event handler.
77 wxShapeEvtHandler* wxShapeEvtHandler::CreateNewCopy()
78 {
79 wxShapeEvtHandler* newObject = (wxShapeEvtHandler*) GetClassInfo()->CreateObject();
80
81 wxASSERT( (newObject != NULL) );
82 wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShapeEvtHandler))) );
83
84 newObject->m_previousHandler = newObject;
85
86 CopyData(*newObject);
87
88 return newObject;
89 }
90
91
92 void wxShapeEvtHandler::OnDelete()
93 {
94 if (this != GetShape())
95 delete this;
96 }
97
98 void wxShapeEvtHandler::OnDraw(wxDC& dc)
99 {
100 if (m_previousHandler)
101 m_previousHandler->OnDraw(dc);
102 }
103
104 void wxShapeEvtHandler::OnMoveLinks(wxDC& dc)
105 {
106 if (m_previousHandler)
107 m_previousHandler->OnMoveLinks(dc);
108 }
109
110 void wxShapeEvtHandler::OnMoveLink(wxDC& dc, bool moveControlPoints)
111 {
112 if (m_previousHandler)
113 m_previousHandler->OnMoveLink(dc, moveControlPoints);
114 }
115
116 void wxShapeEvtHandler::OnDrawContents(wxDC& dc)
117 {
118 if (m_previousHandler)
119 m_previousHandler->OnDrawContents(dc);
120 }
121
122 void wxShapeEvtHandler::OnDrawBranches(wxDC& dc, bool erase)
123 {
124 if (m_previousHandler)
125 m_previousHandler->OnDrawBranches(dc, erase);
126 }
127
128 void wxShapeEvtHandler::OnSize(double x, double y)
129 {
130 if (m_previousHandler)
131 m_previousHandler->OnSize(x, y);
132 }
133
134 bool wxShapeEvtHandler::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
135 {
136 if (m_previousHandler)
137 return m_previousHandler->OnMovePre(dc, x, y, old_x, old_y, display);
138 else
139 return true;
140 }
141
142 void wxShapeEvtHandler::OnMovePost(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
143 {
144 if (m_previousHandler)
145 m_previousHandler->OnMovePost(dc, x, y, old_x, old_y, display);
146 }
147
148 void wxShapeEvtHandler::OnErase(wxDC& dc)
149 {
150 if (m_previousHandler)
151 m_previousHandler->OnErase(dc);
152 }
153
154 void wxShapeEvtHandler::OnEraseContents(wxDC& dc)
155 {
156 if (m_previousHandler)
157 m_previousHandler->OnEraseContents(dc);
158 }
159
160 void wxShapeEvtHandler::OnHighlight(wxDC& dc)
161 {
162 if (m_previousHandler)
163 m_previousHandler->OnHighlight(dc);
164 }
165
166 void wxShapeEvtHandler::OnLeftClick(double x, double y, int keys, int attachment)
167 {
168 if (m_previousHandler)
169 m_previousHandler->OnLeftClick(x, y, keys, attachment);
170 }
171
172 void wxShapeEvtHandler::OnLeftDoubleClick(double x, double y, int keys, int attachment)
173 {
174 if (m_previousHandler)
175 m_previousHandler->OnLeftDoubleClick(x, y, keys, attachment);
176 }
177
178 void wxShapeEvtHandler::OnRightClick(double x, double y, int keys, int attachment)
179 {
180 if (m_previousHandler)
181 m_previousHandler->OnRightClick(x, y, keys, attachment);
182 }
183
184 void wxShapeEvtHandler::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
185 {
186 if (m_previousHandler)
187 m_previousHandler->OnDragLeft(draw, x, y, keys, attachment);
188 }
189
190 void wxShapeEvtHandler::OnBeginDragLeft(double x, double y, int keys, int attachment)
191 {
192 if (m_previousHandler)
193 m_previousHandler->OnBeginDragLeft(x, y, keys, attachment);
194 }
195
196 void wxShapeEvtHandler::OnEndDragLeft(double x, double y, int keys, int attachment)
197 {
198 if (m_previousHandler)
199 m_previousHandler->OnEndDragLeft(x, y, keys, attachment);
200 }
201
202 void wxShapeEvtHandler::OnDragRight(bool draw, double x, double y, int keys, int attachment)
203 {
204 if (m_previousHandler)
205 m_previousHandler->OnDragRight(draw, x, y, keys, attachment);
206 }
207
208 void wxShapeEvtHandler::OnBeginDragRight(double x, double y, int keys, int attachment)
209 {
210 if (m_previousHandler)
211 m_previousHandler->OnBeginDragRight(x, y, keys, attachment);
212 }
213
214 void wxShapeEvtHandler::OnEndDragRight(double x, double y, int keys, int attachment)
215 {
216 if (m_previousHandler)
217 m_previousHandler->OnEndDragRight(x, y, keys, attachment);
218 }
219
220 // Control points ('handles') redirect control to the actual shape, to make it easier
221 // to override sizing behaviour.
222 void wxShapeEvtHandler::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
223 {
224 if (m_previousHandler)
225 m_previousHandler->OnSizingDragLeft(pt, draw, x, y, keys, attachment);
226 }
227
228 void wxShapeEvtHandler::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
229 {
230 if (m_previousHandler)
231 m_previousHandler->OnSizingBeginDragLeft(pt, x, y, keys, attachment);
232 }
233
234 void wxShapeEvtHandler::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
235 {
236 if (m_previousHandler)
237 m_previousHandler->OnSizingEndDragLeft(pt, x, y, keys, attachment);
238 }
239
240 void wxShapeEvtHandler::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
241 {
242 if (m_previousHandler)
243 m_previousHandler->OnDrawOutline(dc, x, y, w, h);
244 }
245
246 void wxShapeEvtHandler::OnDrawControlPoints(wxDC& dc)
247 {
248 if (m_previousHandler)
249 m_previousHandler->OnDrawControlPoints(dc);
250 }
251
252 void wxShapeEvtHandler::OnEraseControlPoints(wxDC& dc)
253 {
254 if (m_previousHandler)
255 m_previousHandler->OnEraseControlPoints(dc);
256 }
257
258 // Can override this to prevent or intercept line reordering.
259 void wxShapeEvtHandler::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
260 {
261 if (m_previousHandler)
262 m_previousHandler->OnChangeAttachment(attachment, line, ordering);
263 }
264
265 IMPLEMENT_ABSTRACT_CLASS(wxShape, wxShapeEvtHandler)
266
267 wxShape::wxShape(wxShapeCanvas *can)
268 {
269 m_eventHandler = this;
270 SetShape(this);
271 m_id = 0;
272 m_formatted = false;
273 m_canvas = can;
274 m_xpos = 0.0; m_ypos = 0.0;
275 m_pen = g_oglBlackPen;
276 m_brush = wxWHITE_BRUSH;
277 m_font = g_oglNormalFont;
278 m_textColour = wxT("BLACK");
279 m_textColourName = wxT("BLACK");
280 m_visible = false;
281 m_selected = false;
282 m_attachmentMode = ATTACHMENT_MODE_NONE;
283 m_spaceAttachments = true;
284 m_disableLabel = false;
285 m_fixedWidth = false;
286 m_fixedHeight = false;
287 m_drawHandles = true;
288 m_sensitivity = OP_ALL;
289 m_draggable = true;
290 m_parent = NULL;
291 m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
292 m_shadowMode = SHADOW_NONE;
293 m_shadowOffsetX = 6;
294 m_shadowOffsetY = 6;
295 m_shadowBrush = wxBLACK_BRUSH;
296 m_textMarginX = 5;
297 m_textMarginY = 5;
298 m_regionName = wxT("0");
299 m_centreResize = true;
300 m_maintainAspectRatio = false;
301 m_highlighted = false;
302 m_rotation = 0.0;
303 m_branchNeckLength = 10;
304 m_branchStemLength = 10;
305 m_branchSpacing = 10;
306 m_branchStyle = BRANCHING_ATTACHMENT_NORMAL;
307
308 // Set up a default region. Much of the above will be put into
309 // the region eventually (the duplication is for compatibility)
310 wxShapeRegion *region = new wxShapeRegion;
311 m_regions.Append(region);
312 region->SetName(wxT("0"));
313 region->SetFont(g_oglNormalFont);
314 region->SetFormatMode(FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT);
315 region->SetColour(wxT("BLACK"));
316 }
317
318 wxShape::~wxShape()
319 {
320 if (m_parent)
321 m_parent->GetChildren().DeleteObject(this);
322
323 ClearText();
324 ClearRegions();
325 ClearAttachments();
326
327 if (m_canvas)
328 m_canvas->RemoveShape(this);
329
330 GetEventHandler()->OnDelete();
331 }
332
333 void wxShape::SetHighlight(bool hi, bool recurse)
334 {
335 m_highlighted = hi;
336 if (recurse)
337 {
338 wxNode *node = m_children.GetFirst();
339 while (node)
340 {
341 wxShape *child = (wxShape *)node->GetData();
342 child->SetHighlight(hi, recurse);
343 node = node->GetNext();
344 }
345 }
346 }
347
348 void wxShape::SetSensitivityFilter(int sens, bool recursive)
349 {
350 if (sens & OP_DRAG_LEFT)
351 m_draggable = true;
352 else
353 m_draggable = false;
354
355 m_sensitivity = sens;
356 if (recursive)
357 {
358 wxNode *node = m_children.GetFirst();
359 while (node)
360 {
361 wxShape *obj = (wxShape *)node->GetData();
362 obj->SetSensitivityFilter(sens, true);
363 node = node->GetNext();
364 }
365 }
366 }
367
368 void wxShape::SetDraggable(bool drag, bool recursive)
369 {
370 m_draggable = drag;
371 if (m_draggable)
372 m_sensitivity |= OP_DRAG_LEFT;
373 else
374 if (m_sensitivity & OP_DRAG_LEFT)
375 m_sensitivity = m_sensitivity - OP_DRAG_LEFT;
376
377 if (recursive)
378 {
379 wxNode *node = m_children.GetFirst();
380 while (node)
381 {
382 wxShape *obj = (wxShape *)node->GetData();
383 obj->SetDraggable(drag, true);
384 node = node->GetNext();
385 }
386 }
387 }
388
389 void wxShape::SetDrawHandles(bool drawH)
390 {
391 m_drawHandles = drawH;
392 wxNode *node = m_children.GetFirst();
393 while (node)
394 {
395 wxShape *obj = (wxShape *)node->GetData();
396 obj->SetDrawHandles(drawH);
397 node = node->GetNext();
398 }
399 }
400
401 void wxShape::SetShadowMode(int mode, bool redraw)
402 {
403 if (redraw && GetCanvas())
404 {
405 wxClientDC dc(GetCanvas());
406 GetCanvas()->PrepareDC(dc);
407 Erase(dc);
408
409 m_shadowMode = mode;
410
411 Draw(dc);
412 }
413 else
414 {
415 m_shadowMode = mode;
416 }
417 }
418
419 void wxShape::SetCanvas(wxShapeCanvas *theCanvas)
420 {
421 m_canvas = theCanvas;
422 wxNode *node = m_children.GetFirst();
423 while (node)
424 {
425 wxShape *child = (wxShape *)node->GetData();
426 child->SetCanvas(theCanvas);
427 node = node->GetNext();
428 }
429 }
430
431 void wxShape::AddToCanvas(wxShapeCanvas *theCanvas, wxShape *addAfter)
432 {
433 theCanvas->AddShape(this, addAfter);
434 wxNode *node = m_children.GetFirst();
435 wxShape *lastImage = this;
436 while (node)
437 {
438 wxShape *object = (wxShape *)node->GetData();
439 object->AddToCanvas(theCanvas, lastImage);
440 lastImage = object;
441
442 node = node->GetNext();
443 }
444 }
445
446 // Insert at front of canvas
447 void wxShape::InsertInCanvas(wxShapeCanvas *theCanvas)
448 {
449 theCanvas->InsertShape(this);
450 wxNode *node = m_children.GetFirst();
451 wxShape *lastImage = this;
452 while (node)
453 {
454 wxShape *object = (wxShape *)node->GetData();
455 object->AddToCanvas(theCanvas, lastImage);
456 lastImage = object;
457
458 node = node->GetNext();
459 }
460 }
461
462 void wxShape::RemoveFromCanvas(wxShapeCanvas *theCanvas)
463 {
464 if (Selected())
465 Select(false);
466 theCanvas->RemoveShape(this);
467 wxNode *node = m_children.GetFirst();
468 while (node)
469 {
470 wxShape *object = (wxShape *)node->GetData();
471 object->RemoveFromCanvas(theCanvas);
472
473 node = node->GetNext();
474 }
475 }
476
477 void wxShape::ClearAttachments()
478 {
479 wxNode *node = m_attachmentPoints.GetFirst();
480 while (node)
481 {
482 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
483 delete point;
484 node = node->GetNext();
485 }
486 m_attachmentPoints.Clear();
487 }
488
489 void wxShape::ClearText(int regionId)
490 {
491 if (regionId == 0)
492 {
493 m_text.DeleteContents(true);
494 m_text.Clear();
495 m_text.DeleteContents(false);
496 }
497 wxNode *node = m_regions.Item(regionId);
498 if (!node)
499 return;
500 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
501 region->ClearText();
502 }
503
504 void wxShape::ClearRegions()
505 {
506 wxNode *node = m_regions.GetFirst();
507 while (node)
508 {
509 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
510 wxNode *next = node->GetNext();
511 delete region;
512 delete node;
513 node = next;
514 }
515 }
516
517 void wxShape::AddRegion(wxShapeRegion *region)
518 {
519 m_regions.Append(region);
520 }
521
522 void wxShape::SetDefaultRegionSize()
523 {
524 wxNode *node = m_regions.GetFirst();
525 if (!node) return;
526 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
527 double w, h;
528 GetBoundingBoxMin(&w, &h);
529 region->SetSize(w, h);
530 }
531
532 bool wxShape::HitTest(double x, double y, int *attachment, double *distance)
533 {
534 // if (!sensitive)
535 // return false;
536
537 double width = 0.0, height = 0.0;
538 GetBoundingBoxMin(&width, &height);
539 if (fabs(width) < 4.0) width = 4.0;
540 if (fabs(height) < 4.0) height = 4.0;
541
542 width += (double)4.0; height += (double)4.0; // Allowance for inaccurate mousing
543
544 double left = (double)(m_xpos - (width/2.0));
545 double top = (double)(m_ypos - (height/2.0));
546 double right = (double)(m_xpos + (width/2.0));
547 double bottom = (double)(m_ypos + (height/2.0));
548
549 int nearest_attachment = 0;
550
551 // If within the bounding box, check the attachment points
552 // within the object.
553
554 if (x >= left && x <= right && y >= top && y <= bottom)
555 {
556 int n = GetNumberOfAttachments();
557 double nearest = 999999.0;
558
559 // GetAttachmentPosition[Edge] takes a logical attachment position,
560 // i.e. if it's rotated through 90%, position 0 is East-facing.
561
562 for (int i = 0; i < n; i++)
563 {
564 double xp, yp;
565 if (GetAttachmentPositionEdge(i, &xp, &yp))
566 {
567 double l = (double)sqrt(((xp - x) * (xp - x)) +
568 ((yp - y) * (yp - y)));
569
570 if (l < nearest)
571 {
572 nearest = l;
573 nearest_attachment = i;
574 }
575 }
576 }
577 *attachment = nearest_attachment;
578 *distance = nearest;
579 return true;
580 }
581 else return false;
582 }
583
584 // Format a text string according to the region size, adding
585 // strings with positions to region text list
586
587 static bool GraphicsInSizeToContents = false; // Infinite recursion elimination
588 void wxShape::FormatText(wxDC& dc, const wxString& s, int i)
589 {
590 double w, h;
591 ClearText(i);
592
593 if (m_regions.GetCount() < 1)
594 return;
595 wxNode *node = m_regions.Item(i);
596 if (!node)
597 return;
598
599 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
600 // region->SetText(s); // don't set the formatted text yet, it will be done below
601 region->m_regionText = s;
602 dc.SetFont(* region->GetFont());
603
604 region->GetSize(&w, &h);
605
606 wxStringList *stringList = oglFormatText(dc, s, (w-2*m_textMarginX), (h-2*m_textMarginY), region->GetFormatMode());
607 node = (wxNode*)stringList->GetFirst();
608 while (node)
609 {
610 wxChar *s = (wxChar *)node->GetData();
611 wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
612 region->GetFormattedText().Append((wxObject *)line);
613 node = node->GetNext();
614 }
615 delete stringList;
616 double actualW = w;
617 double actualH = h;
618 // Don't try to resize an object with more than one image (this case should be dealt
619 // with by overriden handlers)
620 if ((region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS) &&
621 (region->GetFormattedText().GetCount() > 0) &&
622 (m_regions.GetCount() == 1) && !GraphicsInSizeToContents)
623 {
624 oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
625 if ((actualW+2*m_textMarginX != w ) || (actualH+2*m_textMarginY != h))
626 {
627 // If we are a descendant of a composite, must make sure the composite gets
628 // resized properly
629 wxShape *topAncestor = GetTopAncestor();
630
631 if (topAncestor != this)
632 {
633 // Make sure we don't recurse infinitely
634 GraphicsInSizeToContents = true;
635
636 wxCompositeShape *composite = (wxCompositeShape *)topAncestor;
637 composite->Erase(dc);
638 SetSize(actualW+2*m_textMarginX, actualH+2*m_textMarginY);
639 Move(dc, m_xpos, m_ypos);
640 composite->CalculateSize();
641 if (composite->Selected())
642 {
643 composite->DeleteControlPoints(& dc);
644 composite->MakeControlPoints();
645 composite->MakeMandatoryControlPoints();
646 }
647 // Where infinite recursion might happen if we didn't stop it
648 composite->Draw(dc);
649
650 GraphicsInSizeToContents = false;
651 }
652 else
653 {
654 Erase(dc);
655 SetSize(actualW+2*m_textMarginX, actualH+2*m_textMarginY);
656 Move(dc, m_xpos, m_ypos);
657 }
658 SetSize(actualW+2*m_textMarginX, actualH+2*m_textMarginY);
659 Move(dc, m_xpos, m_ypos);
660 EraseContents(dc);
661 }
662 }
663 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW-2*m_textMarginX, actualH-2*m_textMarginY, region->GetFormatMode());
664 m_formatted = true;
665 }
666
667 void wxShape::Recentre(wxDC& dc)
668 {
669 double w, h;
670 GetBoundingBoxMin(&w, &h);
671
672 int noRegions = m_regions.GetCount();
673 for (int i = 0; i < noRegions; i++)
674 {
675 wxNode *node = m_regions.Item(i);
676 if (node)
677 {
678 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
679 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w-2*m_textMarginX, h-2*m_textMarginY, region->GetFormatMode());
680 }
681 }
682 }
683
684 bool wxShape::GetPerimeterPoint(double WXUNUSED(x1), double WXUNUSED(y1),
685 double WXUNUSED(x2), double WXUNUSED(y2),
686 double *WXUNUSED(x3), double *WXUNUSED(y3))
687 {
688 return false;
689 }
690
691 void wxShape::SetPen(wxPen *the_pen)
692 {
693 m_pen = the_pen;
694 }
695
696 void wxShape::SetBrush(wxBrush *the_brush)
697 {
698 m_brush = the_brush;
699 }
700
701 // Get the top-most (non-division) ancestor, or self
702 wxShape *wxShape::GetTopAncestor()
703 {
704 if (!GetParent())
705 return this;
706
707 if (GetParent()->IsKindOf(CLASSINFO(wxDivisionShape)))
708 return this;
709 else return GetParent()->GetTopAncestor();
710 }
711
712 /*
713 * Region functions
714 *
715 */
716 void wxShape::SetFont(wxFont *the_font, int regionId)
717 {
718 m_font = the_font;
719 wxNode *node = m_regions.Item(regionId);
720 if (!node)
721 return;
722 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
723 region->SetFont(the_font);
724 }
725
726 wxFont *wxShape::GetFont(int n) const
727 {
728 wxNode *node = m_regions.Item(n);
729 if (!node)
730 return NULL;
731 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
732 return region->GetFont();
733 }
734
735 void wxShape::SetFormatMode(int mode, int regionId)
736 {
737 wxNode *node = m_regions.Item(regionId);
738 if (!node)
739 return;
740 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
741 region->SetFormatMode(mode);
742 }
743
744 int wxShape::GetFormatMode(int regionId) const
745 {
746 wxNode *node = m_regions.Item(regionId);
747 if (!node)
748 return 0;
749 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
750 return region->GetFormatMode();
751 }
752
753 void wxShape::SetTextColour(const wxString& the_colour, int regionId)
754 {
755 m_textColour = wxTheColourDatabase->Find(the_colour);
756 m_textColourName = the_colour;
757
758 wxNode *node = m_regions.Item(regionId);
759 if (!node)
760 return;
761 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
762 region->SetColour(the_colour);
763 }
764
765 wxString wxShape::GetTextColour(int regionId) const
766 {
767 wxNode *node = m_regions.Item(regionId);
768 if (!node)
769 return wxEmptyString;
770 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
771 return region->GetColour();
772 }
773
774 void wxShape::SetRegionName(const wxString& name, int regionId)
775 {
776 wxNode *node = m_regions.Item(regionId);
777 if (!node)
778 return;
779 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
780 region->SetName(name);
781 }
782
783 wxString wxShape::GetRegionName(int regionId)
784 {
785 wxNode *node = m_regions.Item(regionId);
786 if (!node)
787 return wxEmptyString;
788 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
789 return region->GetName();
790 }
791
792 int wxShape::GetRegionId(const wxString& name)
793 {
794 wxNode *node = m_regions.GetFirst();
795 int i = 0;
796 while (node)
797 {
798 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
799 if (region->GetName() == name)
800 return i;
801 node = node->GetNext();
802 i ++;
803 }
804 return -1;
805 }
806
807 // Name all m_regions in all subimages recursively.
808 void wxShape::NameRegions(const wxString& parentName)
809 {
810 int n = GetNumberOfTextRegions();
811 wxString buff;
812 for (int i = 0; i < n; i++)
813 {
814 if (parentName.Length() > 0)
815 buff << parentName << wxT(".") << i;
816 else
817 buff << i;
818 SetRegionName(buff, i);
819 }
820 wxNode *node = m_children.GetFirst();
821 int j = 0;
822 while (node)
823 {
824 buff.Empty();
825 wxShape *child = (wxShape *)node->GetData();
826 if (parentName.Length() > 0)
827 buff << parentName << wxT(".") << j;
828 else
829 buff << j;
830 child->NameRegions(buff);
831 node = node->GetNext();
832 j ++;
833 }
834 }
835
836 // Get a region by name, possibly looking recursively into composites.
837 wxShape *wxShape::FindRegion(const wxString& name, int *regionId)
838 {
839 int id = GetRegionId(name);
840 if (id > -1)
841 {
842 *regionId = id;
843 return this;
844 }
845
846 wxNode *node = m_children.GetFirst();
847 while (node)
848 {
849 wxShape *child = (wxShape *)node->GetData();
850 wxShape *actualImage = child->FindRegion(name, regionId);
851 if (actualImage)
852 return actualImage;
853 node = node->GetNext();
854 }
855 return NULL;
856 }
857
858 // Finds all region names for this image (composite or simple).
859 // Supply empty string list.
860 void wxShape::FindRegionNames(wxStringList& list)
861 {
862 int n = GetNumberOfTextRegions();
863 for (int i = 0; i < n; i++)
864 {
865 wxString name(GetRegionName(i));
866 list.Add(name);
867 }
868
869 wxNode *node = m_children.GetFirst();
870 while (node)
871 {
872 wxShape *child = (wxShape *)node->GetData();
873 child->FindRegionNames(list);
874 node = node->GetNext();
875 }
876 }
877
878 void wxShape::AssignNewIds()
879 {
880 // if (m_id == 0)
881 m_id = wxNewId();
882 wxNode *node = m_children.GetFirst();
883 while (node)
884 {
885 wxShape *child = (wxShape *)node->GetData();
886 child->AssignNewIds();
887 node = node->GetNext();
888 }
889 }
890
891 void wxShape::OnDraw(wxDC& WXUNUSED(dc))
892 {
893 }
894
895 void wxShape::OnMoveLinks(wxDC& dc)
896 {
897 // Want to set the ends of all attached links
898 // to point to/from this object
899
900 wxNode *current = m_lines.GetFirst();
901 while (current)
902 {
903 wxLineShape *line = (wxLineShape *)current->GetData();
904 line->GetEventHandler()->OnMoveLink(dc);
905 current = current->GetNext();
906 }
907 }
908
909
910 void wxShape::OnDrawContents(wxDC& dc)
911 {
912 double bound_x, bound_y;
913 GetBoundingBoxMin(&bound_x, &bound_y);
914 if (m_regions.GetCount() < 1) return;
915
916 if (m_pen) dc.SetPen(* m_pen);
917
918 wxShapeRegion *region = (wxShapeRegion *)m_regions.GetFirst()->GetData();
919 if (region->GetFont()) dc.SetFont(* region->GetFont());
920
921 dc.SetTextForeground(region->GetActualColourObject());
922 dc.SetBackgroundMode(wxTRANSPARENT);
923 if (!m_formatted)
924 {
925 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x-2*m_textMarginX, bound_y-2*m_textMarginY, region->GetFormatMode());
926 m_formatted = true;
927 }
928 if (!GetDisableLabel())
929 {
930 oglDrawFormattedText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, bound_x-2*m_textMarginX, bound_y-2*m_textMarginY, region->GetFormatMode());
931 }
932 }
933
934 void wxShape::DrawContents(wxDC& dc)
935 {
936 GetEventHandler()->OnDrawContents(dc);
937 }
938
939 void wxShape::OnSize(double WXUNUSED(x), double WXUNUSED(y))
940 {
941 }
942
943 bool wxShape::OnMovePre(wxDC& WXUNUSED(dc), double WXUNUSED(x), double WXUNUSED(y), double WXUNUSED(old_x), double WXUNUSED(old_y), bool WXUNUSED(display))
944 {
945 return true;
946 }
947
948 void wxShape::OnMovePost(wxDC& WXUNUSED(dc), double WXUNUSED(x), double WXUNUSED(y), double WXUNUSED(old_x), double WXUNUSED(old_y), bool WXUNUSED(display))
949 {
950 }
951
952 void wxShape::OnErase(wxDC& dc)
953 {
954 if (!m_visible)
955 return;
956
957 // Erase links
958 wxNode *current = m_lines.GetFirst();
959 while (current)
960 {
961 wxLineShape *line = (wxLineShape *)current->GetData();
962 line->GetEventHandler()->OnErase(dc);
963 current = current->GetNext();
964 }
965 GetEventHandler()->OnEraseContents(dc);
966 }
967
968 void wxShape::OnEraseContents(wxDC& dc)
969 {
970 if (!m_visible)
971 return;
972
973 double maxX, maxY, minX, minY;
974 double xp = GetX();
975 double yp = GetY();
976 GetBoundingBoxMin(&minX, &minY);
977 GetBoundingBoxMax(&maxX, &maxY);
978 double topLeftX = (double)(xp - (maxX / 2.0) - 2.0);
979 double topLeftY = (double)(yp - (maxY / 2.0) - 2.0);
980
981 int penWidth = 0;
982 if (m_pen)
983 penWidth = m_pen->GetWidth();
984
985 dc.SetPen(GetBackgroundPen());
986 dc.SetBrush(GetBackgroundBrush());
987
988 dc.DrawRectangle(WXROUND(topLeftX - penWidth), WXROUND(topLeftY - penWidth),
989 WXROUND(maxX + penWidth*2.0 + 4.0), WXROUND(maxY + penWidth*2.0 + 4.0));
990 }
991
992 void wxShape::EraseLinks(wxDC& dc, int attachment, bool recurse)
993 {
994 if (!m_visible)
995 return;
996
997 wxNode *current = m_lines.GetFirst();
998 while (current)
999 {
1000 wxLineShape *line = (wxLineShape *)current->GetData();
1001 if (attachment == -1 || ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1002 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment)))
1003 line->GetEventHandler()->OnErase(dc);
1004 current = current->GetNext();
1005 }
1006 if (recurse)
1007 {
1008 wxNode *node = m_children.GetFirst();
1009 while (node)
1010 {
1011 wxShape *child = (wxShape *)node->GetData();
1012 child->EraseLinks(dc, attachment, recurse);
1013 node = node->GetNext();
1014 }
1015 }
1016 }
1017
1018 void wxShape::DrawLinks(wxDC& dc, int attachment, bool recurse)
1019 {
1020 if (!m_visible)
1021 return;
1022
1023 wxNode *current = m_lines.GetFirst();
1024 while (current)
1025 {
1026 wxLineShape *line = (wxLineShape *)current->GetData();
1027 if (attachment == -1 ||
1028 (line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1029 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
1030 line->Draw(dc);
1031 current = current->GetNext();
1032 }
1033 if (recurse)
1034 {
1035 wxNode *node = m_children.GetFirst();
1036 while (node)
1037 {
1038 wxShape *child = (wxShape *)node->GetData();
1039 child->DrawLinks(dc, attachment, recurse);
1040 node = node->GetNext();
1041 }
1042 }
1043 }
1044
1045 // Returns true if pt1 <= pt2 in the sense that one point comes before another on an
1046 // edge of the shape.
1047 // attachmentPoint is the attachment point (= side) in question.
1048
1049 // This is the default, rectangular implementation.
1050 bool wxShape::AttachmentSortTest(int attachmentPoint, const wxRealPoint& pt1, const wxRealPoint& pt2)
1051 {
1052 int physicalAttachment = LogicalToPhysicalAttachment(attachmentPoint);
1053 switch (physicalAttachment)
1054 {
1055 case 0:
1056 case 2:
1057 {
1058 return (pt1.x <= pt2.x) ;
1059 }
1060 case 1:
1061 case 3:
1062 {
1063 return (pt1.y <= pt2.y) ;
1064 }
1065 }
1066
1067 return false;
1068 }
1069
1070 bool wxShape::MoveLineToNewAttachment(wxDC& dc, wxLineShape *to_move,
1071 double x, double y)
1072 {
1073 if (GetAttachmentMode() == ATTACHMENT_MODE_NONE)
1074 return false;
1075
1076 int newAttachment, oldAttachment;
1077 double distance;
1078
1079 // Is (x, y) on this object? If so, find the new attachment point
1080 // the user has moved the point to
1081 bool hit = HitTest(x, y, &newAttachment, &distance);
1082 if (!hit)
1083 return false;
1084
1085 EraseLinks(dc);
1086
1087 if (to_move->GetTo() == this)
1088 oldAttachment = to_move->GetAttachmentTo();
1089 else
1090 oldAttachment = to_move->GetAttachmentFrom();
1091
1092 // The links in a new ordering.
1093 wxList newOrdering;
1094
1095 // First, add all links to the new list.
1096 wxNode *node = m_lines.GetFirst();
1097 while (node)
1098 {
1099 newOrdering.Append(node->GetData());
1100 node = node->GetNext();
1101 }
1102
1103 // Delete the line object from the list of links; we're going to move
1104 // it to another position in the list
1105 newOrdering.DeleteObject(to_move);
1106
1107 double old_x = (double) -99999.9;
1108 double old_y = (double) -99999.9;
1109
1110 node = newOrdering.GetFirst();
1111 bool found = false;
1112
1113 while (!found && node)
1114 {
1115 wxLineShape *line = (wxLineShape *)node->GetData();
1116 if ((line->GetTo() == this && oldAttachment == line->GetAttachmentTo()) ||
1117 (line->GetFrom() == this && oldAttachment == line->GetAttachmentFrom()))
1118 {
1119 double startX, startY, endX, endY;
1120 double xp, yp;
1121 line->GetEnds(&startX, &startY, &endX, &endY);
1122 if (line->GetTo() == this)
1123 {
1124 xp = endX;
1125 yp = endY;
1126 } else
1127 {
1128 xp = startX;
1129 yp = startY;
1130 }
1131
1132 wxRealPoint thisPoint(xp, yp);
1133 wxRealPoint lastPoint(old_x, old_y);
1134 wxRealPoint newPoint(x, y);
1135
1136 if (AttachmentSortTest(newAttachment, newPoint, thisPoint) && AttachmentSortTest(newAttachment, lastPoint, newPoint))
1137 {
1138 found = true;
1139 newOrdering.Insert(node, to_move);
1140 }
1141
1142 old_x = xp;
1143 old_y = yp;
1144 }
1145 node = node->GetNext();
1146 }
1147
1148 if (!found)
1149 newOrdering.Append(to_move);
1150
1151 GetEventHandler()->OnChangeAttachment(newAttachment, to_move, newOrdering);
1152
1153 return true;
1154 }
1155
1156 void wxShape::OnChangeAttachment(int attachment, wxLineShape* line, wxList& ordering)
1157 {
1158 if (line->GetTo() == this)
1159 line->SetAttachmentTo(attachment);
1160 else
1161 line->SetAttachmentFrom(attachment);
1162
1163 ApplyAttachmentOrdering(ordering);
1164
1165 wxClientDC dc(GetCanvas());
1166 GetCanvas()->PrepareDC(dc);
1167
1168 MoveLinks(dc);
1169
1170 if (!GetCanvas()->GetQuickEditMode()) GetCanvas()->Redraw(dc);
1171 }
1172
1173 // Reorders the lines according to the given list.
1174 void wxShape::ApplyAttachmentOrdering(wxList& linesToSort)
1175 {
1176 // This is a temporary store of all the lines.
1177 wxList linesStore;
1178
1179 wxNode *node = m_lines.GetFirst();
1180 while (node)
1181 {
1182 wxLineShape *line = (wxLineShape *)node->GetData();
1183 linesStore.Append(line);
1184 node = node->GetNext();;
1185 }
1186
1187 m_lines.Clear();
1188
1189 node = linesToSort.GetFirst();
1190 while (node)
1191 {
1192 wxLineShape *line = (wxLineShape *)node->GetData();
1193 if (linesStore.Member(line))
1194 {
1195 // Done this one
1196 linesStore.DeleteObject(line);
1197 m_lines.Append(line);
1198 }
1199 node = node->GetNext();
1200 }
1201
1202 // Now add any lines that haven't been listed in linesToSort.
1203 node = linesStore.GetFirst();
1204 while (node)
1205 {
1206 wxLineShape *line = (wxLineShape *)node->GetData();
1207 m_lines.Append(line);
1208 node = node->GetNext();
1209 }
1210 }
1211
1212 // Reorders the lines coming into the node image at this attachment
1213 // position, in the order in which they appear in linesToSort.
1214 // Any remaining lines not in the list will be added to the end.
1215 void wxShape::SortLines(int attachment, wxList& linesToSort)
1216 {
1217 // This is a temporary store of all the lines at this attachment
1218 // point. We'll tick them off as we've processed them.
1219 wxList linesAtThisAttachment;
1220
1221 wxNode *node = m_lines.GetFirst();
1222 while (node)
1223 {
1224 wxLineShape *line = (wxLineShape *)node->GetData();
1225 wxNode *next = node->GetNext();
1226 if ((line->GetTo() == this && line->GetAttachmentTo() == attachment) ||
1227 (line->GetFrom() == this && line->GetAttachmentFrom() == attachment))
1228 {
1229 linesAtThisAttachment.Append(line);
1230 delete node;
1231 node = next;
1232 }
1233 else node = node->GetNext();
1234 }
1235
1236 node = linesToSort.GetFirst();
1237 while (node)
1238 {
1239 wxLineShape *line = (wxLineShape *)node->GetData();
1240 if (linesAtThisAttachment.Member(line))
1241 {
1242 // Done this one
1243 linesAtThisAttachment.DeleteObject(line);
1244 m_lines.Append(line);
1245 }
1246 node = node->GetNext();
1247 }
1248
1249 // Now add any lines that haven't been listed in linesToSort.
1250 node = linesAtThisAttachment.GetFirst();
1251 while (node)
1252 {
1253 wxLineShape *line = (wxLineShape *)node->GetData();
1254 m_lines.Append(line);
1255 node = node->GetNext();
1256 }
1257 }
1258
1259 void wxShape::OnHighlight(wxDC& WXUNUSED(dc))
1260 {
1261 }
1262
1263 void wxShape::OnLeftClick(double x, double y, int keys, int attachment)
1264 {
1265 if ((m_sensitivity & OP_CLICK_LEFT) != OP_CLICK_LEFT)
1266 {
1267 attachment = 0;
1268 double dist;
1269 if (m_parent)
1270 {
1271 m_parent->HitTest(x, y, &attachment, &dist);
1272 m_parent->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
1273 }
1274 return;
1275 }
1276 }
1277
1278 void wxShape::OnRightClick(double x, double y, int keys, int attachment)
1279 {
1280 if ((m_sensitivity & OP_CLICK_RIGHT) != OP_CLICK_RIGHT)
1281 {
1282 attachment = 0;
1283 double dist;
1284 if (m_parent)
1285 {
1286 m_parent->HitTest(x, y, &attachment, &dist);
1287 m_parent->GetEventHandler()->OnRightClick(x, y, keys, attachment);
1288 }
1289 return;
1290 }
1291 }
1292
1293 double DragOffsetX = 0.0;
1294 double DragOffsetY = 0.0;
1295
1296 void wxShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
1297 {
1298 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1299 {
1300 attachment = 0;
1301 double dist;
1302 if (m_parent)
1303 {
1304 m_parent->HitTest(x, y, &attachment, &dist);
1305 m_parent->GetEventHandler()->OnDragLeft(draw, x, y, keys, attachment);
1306 }
1307 return;
1308 }
1309
1310 wxClientDC dc(GetCanvas());
1311 GetCanvas()->PrepareDC(dc);
1312
1313 dc.SetLogicalFunction(OGLRBLF);
1314
1315 wxPen dottedPen(*wxBLACK, 1, wxDOT);
1316 dc.SetPen(dottedPen);
1317 dc.SetBrush(* wxTRANSPARENT_BRUSH);
1318
1319 double xx, yy;
1320 xx = x + DragOffsetX;
1321 yy = y + DragOffsetY;
1322
1323 m_canvas->Snap(&xx, &yy);
1324 // m_xpos = xx; m_ypos = yy;
1325 double w, h;
1326 GetBoundingBoxMax(&w, &h);
1327 GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
1328 }
1329
1330 void wxShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
1331 {
1332 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1333 {
1334 attachment = 0;
1335 double dist;
1336 if (m_parent)
1337 {
1338 m_parent->HitTest(x, y, &attachment, &dist);
1339 m_parent->GetEventHandler()->OnBeginDragLeft(x, y, keys, attachment);
1340 }
1341 return;
1342 }
1343
1344 DragOffsetX = m_xpos - x;
1345 DragOffsetY = m_ypos - y;
1346
1347 wxClientDC dc(GetCanvas());
1348 GetCanvas()->PrepareDC(dc);
1349
1350 // New policy: don't erase shape until end of drag.
1351 // Erase(dc);
1352
1353 double xx, yy;
1354 xx = x + DragOffsetX;
1355 yy = y + DragOffsetY;
1356 m_canvas->Snap(&xx, &yy);
1357 // m_xpos = xx; m_ypos = yy;
1358 dc.SetLogicalFunction(OGLRBLF);
1359
1360 wxPen dottedPen(*wxBLACK, 1, wxDOT);
1361 dc.SetPen(dottedPen);
1362 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1363
1364 double w, h;
1365 GetBoundingBoxMax(&w, &h);
1366 GetEventHandler()->OnDrawOutline(dc, xx, yy, w, h);
1367 m_canvas->CaptureMouse();
1368 }
1369
1370 void wxShape::OnEndDragLeft(double x, double y, int keys, int attachment)
1371 {
1372 if (!m_draggable)
1373 return;
1374 m_canvas->ReleaseMouse();
1375 if ((m_sensitivity & OP_DRAG_LEFT) != OP_DRAG_LEFT)
1376 {
1377 attachment = 0;
1378 double dist;
1379 if (m_parent)
1380 {
1381 m_parent->HitTest(x, y, &attachment, &dist);
1382 m_parent->GetEventHandler()->OnEndDragLeft(x, y, keys, attachment);
1383 }
1384 return;
1385 }
1386
1387 wxClientDC dc(GetCanvas());
1388 GetCanvas()->PrepareDC(dc);
1389
1390 dc.SetLogicalFunction(wxCOPY);
1391
1392 double xx = x + DragOffsetX;
1393 double yy = y + DragOffsetY;
1394 m_canvas->Snap(&xx, &yy);
1395 // canvas->Snap(&m_xpos, &m_ypos);
1396
1397 // New policy: erase shape at end of drag.
1398 Erase(dc);
1399
1400 Move(dc, xx, yy);
1401 if (m_canvas && !m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1402 }
1403
1404 void wxShape::OnDragRight(bool draw, double x, double y, int keys, int attachment)
1405 {
1406 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1407 {
1408 attachment = 0;
1409 double dist;
1410 if (m_parent)
1411 {
1412 m_parent->HitTest(x, y, &attachment, &dist);
1413 m_parent->GetEventHandler()->OnDragRight(draw, x, y, keys, attachment);
1414 }
1415 return;
1416 }
1417 }
1418
1419 void wxShape::OnBeginDragRight(double x, double y, int keys, int attachment)
1420 {
1421 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1422 {
1423 attachment = 0;
1424 double dist;
1425 if (m_parent)
1426 {
1427 m_parent->HitTest(x, y, &attachment, &dist);
1428 m_parent->GetEventHandler()->OnBeginDragRight(x, y, keys, attachment);
1429 }
1430 return;
1431 }
1432 }
1433
1434 void wxShape::OnEndDragRight(double x, double y, int keys, int attachment)
1435 {
1436 if ((m_sensitivity & OP_DRAG_RIGHT) != OP_DRAG_RIGHT)
1437 {
1438 attachment = 0;
1439 double dist;
1440 if (m_parent)
1441 {
1442 m_parent->HitTest(x, y, &attachment, &dist);
1443 m_parent->GetEventHandler()->OnEndDragRight(x, y, keys, attachment);
1444 }
1445 return;
1446 }
1447 }
1448
1449 void wxShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
1450 {
1451 double top_left_x = (double)(x - w/2.0);
1452 double top_left_y = (double)(y - h/2.0);
1453 double top_right_x = (double)(top_left_x + w);
1454 double top_right_y = (double)top_left_y;
1455 double bottom_left_x = (double)top_left_x;
1456 double bottom_left_y = (double)(top_left_y + h);
1457 double bottom_right_x = (double)top_right_x;
1458 double bottom_right_y = (double)bottom_left_y;
1459
1460 wxPoint points[5];
1461 points[0].x = WXROUND(top_left_x); points[0].y = WXROUND(top_left_y);
1462 points[1].x = WXROUND(top_right_x); points[1].y = WXROUND(top_right_y);
1463 points[2].x = WXROUND(bottom_right_x); points[2].y = WXROUND(bottom_right_y);
1464 points[3].x = WXROUND(bottom_left_x); points[3].y = WXROUND(bottom_left_y);
1465 points[4].x = WXROUND(top_left_x); points[4].y = WXROUND(top_left_y);
1466
1467 dc.DrawLines(5, points);
1468 }
1469
1470 void wxShape::Attach(wxShapeCanvas *can)
1471 {
1472 m_canvas = can;
1473 }
1474
1475 void wxShape::Detach()
1476 {
1477 m_canvas = NULL;
1478 }
1479
1480 void wxShape::Move(wxDC& dc, double x, double y, bool display)
1481 {
1482 double old_x = m_xpos;
1483 double old_y = m_ypos;
1484
1485 if (!GetEventHandler()->OnMovePre(dc, x, y, old_x, old_y, display))
1486 {
1487 // m_xpos = old_x;
1488 // m_ypos = old_y;
1489 return;
1490 }
1491
1492 m_xpos = x; m_ypos = y;
1493
1494 ResetControlPoints();
1495
1496 if (display)
1497 Draw(dc);
1498
1499 MoveLinks(dc);
1500
1501 GetEventHandler()->OnMovePost(dc, x, y, old_x, old_y, display);
1502 }
1503
1504 void wxShape::MoveLinks(wxDC& dc)
1505 {
1506 GetEventHandler()->OnMoveLinks(dc);
1507 }
1508
1509
1510 void wxShape::Draw(wxDC& dc)
1511 {
1512 if (m_visible)
1513 {
1514 GetEventHandler()->OnDraw(dc);
1515 GetEventHandler()->OnDrawContents(dc);
1516 GetEventHandler()->OnDrawControlPoints(dc);
1517 GetEventHandler()->OnDrawBranches(dc);
1518 }
1519 }
1520
1521 void wxShape::Flash()
1522 {
1523 if (GetCanvas())
1524 {
1525 wxClientDC dc(GetCanvas());
1526 GetCanvas()->PrepareDC(dc);
1527
1528 dc.SetLogicalFunction(OGLRBLF);
1529 Draw(dc);
1530 dc.SetLogicalFunction(wxCOPY);
1531 Draw(dc);
1532 }
1533 }
1534
1535 void wxShape::Show(bool show)
1536 {
1537 m_visible = show;
1538 wxNode *node = m_children.GetFirst();
1539 while (node)
1540 {
1541 wxShape *image = (wxShape *)node->GetData();
1542 image->Show(show);
1543 node = node->GetNext();
1544 }
1545 }
1546
1547 void wxShape::Erase(wxDC& dc)
1548 {
1549 GetEventHandler()->OnErase(dc);
1550 GetEventHandler()->OnEraseControlPoints(dc);
1551 GetEventHandler()->OnDrawBranches(dc, true);
1552 }
1553
1554 void wxShape::EraseContents(wxDC& dc)
1555 {
1556 GetEventHandler()->OnEraseContents(dc);
1557 }
1558
1559 void wxShape::AddText(const wxString& string)
1560 {
1561 wxNode *node = m_regions.GetFirst();
1562 if (!node)
1563 return;
1564 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
1565 region->ClearText();
1566 wxShapeTextLine *new_line =
1567 new wxShapeTextLine(0.0, 0.0, string);
1568 region->GetFormattedText().Append(new_line);
1569
1570 m_formatted = false;
1571 }
1572
1573 void wxShape::SetSize(double x, double y, bool WXUNUSED(recursive))
1574 {
1575 SetAttachmentSize(x, y);
1576 SetDefaultRegionSize();
1577 }
1578
1579 void wxShape::SetAttachmentSize(double w, double h)
1580 {
1581 double scaleX;
1582 double scaleY;
1583 double width, height;
1584 GetBoundingBoxMin(&width, &height);
1585 if (width == 0.0)
1586 scaleX = 1.0;
1587 else scaleX = w/width;
1588 if (height == 0.0)
1589 scaleY = 1.0;
1590 else scaleY = h/height;
1591
1592 wxNode *node = m_attachmentPoints.GetFirst();
1593 while (node)
1594 {
1595 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
1596 point->m_x = (double)(point->m_x * scaleX);
1597 point->m_y = (double)(point->m_y * scaleY);
1598 node = node->GetNext();
1599 }
1600 }
1601
1602 // Add line FROM this object
1603 void wxShape::AddLine(wxLineShape *line, wxShape *other,
1604 int attachFrom, int attachTo,
1605 // The line ordering
1606 int positionFrom, int positionTo)
1607 {
1608 if (positionFrom == -1)
1609 {
1610 if (!m_lines.Member(line))
1611 m_lines.Append(line);
1612 }
1613 else
1614 {
1615 // Don't preserve old ordering if we have new ordering instructions
1616 m_lines.DeleteObject(line);
1617 if (positionFrom < (int) m_lines.GetCount())
1618 {
1619 wxNode* node = m_lines.Item(positionFrom);
1620 m_lines.Insert(node, line);
1621 }
1622 else
1623 m_lines.Append(line);
1624 }
1625
1626 if (positionTo == -1)
1627 {
1628 if (!other->m_lines.Member(line))
1629 other->m_lines.Append(line);
1630 }
1631 else
1632 {
1633 // Don't preserve old ordering if we have new ordering instructions
1634 other->m_lines.DeleteObject(line);
1635 if (positionTo < (int) other->m_lines.GetCount())
1636 {
1637 wxNode* node = other->m_lines.Item(positionTo);
1638 other->m_lines.Insert(node, line);
1639 }
1640 else
1641 other->m_lines.Append(line);
1642 }
1643 #if 0
1644 // Wrong: doesn't preserve ordering of shape already linked
1645 m_lines.DeleteObject(line);
1646 other->m_lines.DeleteObject(line);
1647
1648 if (positionFrom == -1)
1649 m_lines.Append(line);
1650 else
1651 {
1652 if (positionFrom < m_lines.GetCount())
1653 {
1654 wxNode* node = m_lines.Item(positionFrom);
1655 m_lines.Insert(node, line);
1656 }
1657 else
1658 m_lines.Append(line);
1659 }
1660
1661 if (positionTo == -1)
1662 other->m_lines.Append(line);
1663 else
1664 {
1665 if (positionTo < other->m_lines.GetCount())
1666 {
1667 wxNode* node = other->m_lines.Item(positionTo);
1668 other->m_lines.Insert(node, line);
1669 }
1670 else
1671 other->m_lines.Append(line);
1672 }
1673 #endif
1674
1675 line->SetFrom(this);
1676 line->SetTo(other);
1677 line->SetAttachments(attachFrom, attachTo);
1678 }
1679
1680 void wxShape::RemoveLine(wxLineShape *line)
1681 {
1682 if (line->GetFrom() == this)
1683 line->GetTo()->m_lines.DeleteObject(line);
1684 else
1685 line->GetFrom()->m_lines.DeleteObject(line);
1686
1687 m_lines.DeleteObject(line);
1688 }
1689
1690 #if wxUSE_PROLOGIO
1691 void wxShape::WriteAttributes(wxExpr *clause)
1692 {
1693 clause->AddAttributeValueString(_T("type"), GetClassInfo()->GetClassName());
1694 clause->AddAttributeValue(_T("id"), m_id);
1695
1696 if (m_pen)
1697 {
1698 int penWidth = m_pen->GetWidth();
1699 int penStyle = m_pen->GetStyle();
1700 if (penWidth != 1)
1701 clause->AddAttributeValue(_T("pen_width"), (long)penWidth);
1702 if (penStyle != wxSOLID)
1703 clause->AddAttributeValue(_T("pen_style"), (long)penStyle);
1704
1705 wxString penColour = wxTheColourDatabase->FindName(m_pen->GetColour());
1706 if (penColour == wxEmptyString)
1707 {
1708 wxString hex(oglColourToHex(m_pen->GetColour()));
1709 hex = wxString(_T("#")) + hex;
1710 clause->AddAttributeValueString(_T("pen_colour"), hex);
1711 }
1712 else if (penColour != _T("BLACK"))
1713 clause->AddAttributeValueString(_T("pen_colour"), penColour);
1714 }
1715
1716 if (m_brush)
1717 {
1718 wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour());
1719
1720 if (brushColour == wxEmptyString)
1721 {
1722 wxString hex(oglColourToHex(m_brush->GetColour()));
1723 hex = wxString(_T("#")) + hex;
1724 clause->AddAttributeValueString(_T("brush_colour"), hex);
1725 }
1726 else if (brushColour != _T("WHITE"))
1727 clause->AddAttributeValueString(_T("brush_colour"), brushColour);
1728
1729 if (m_brush->GetStyle() != wxSOLID)
1730 clause->AddAttributeValue(_T("brush_style"), (long)m_brush->GetStyle());
1731 }
1732
1733 // Output line ids
1734
1735 int n_lines = m_lines.GetCount();
1736 if (n_lines > 0)
1737 {
1738 wxExpr *list = new wxExpr(wxExprList);
1739 wxNode *node = m_lines.GetFirst();
1740 while (node)
1741 {
1742 wxShape *line = (wxShape *)node->GetData();
1743 wxExpr *id_expr = new wxExpr(line->GetId());
1744 list->Append(id_expr);
1745 node = node->GetNext();
1746 }
1747 clause->AddAttributeValue(_T("arcs"), list);
1748 }
1749
1750 // Miscellaneous members
1751 if (m_attachmentMode != 0)
1752 clause->AddAttributeValue(_T("use_attachments"), (long)m_attachmentMode);
1753 if (m_sensitivity != OP_ALL)
1754 clause->AddAttributeValue(_T("sensitivity"), (long)m_sensitivity);
1755 if (!m_spaceAttachments)
1756 clause->AddAttributeValue(_T("space_attachments"), (long)m_spaceAttachments);
1757 if (m_fixedWidth)
1758 clause->AddAttributeValue(_T("fixed_width"), (long)m_fixedWidth);
1759 if (m_fixedHeight)
1760 clause->AddAttributeValue(_T("fixed_height"), (long)m_fixedHeight);
1761 if (m_shadowMode != SHADOW_NONE)
1762 clause->AddAttributeValue(_T("shadow_mode"), (long)m_shadowMode);
1763 if (m_centreResize != true)
1764 clause->AddAttributeValue(_T("centre_resize"), (long)0);
1765 clause->AddAttributeValue(_T("maintain_aspect_ratio"), (long) m_maintainAspectRatio);
1766 if (m_highlighted != false)
1767 clause->AddAttributeValue(_T("hilite"), (long)m_highlighted);
1768
1769 if (m_parent) // For composite objects
1770 clause->AddAttributeValue(_T("parent"), (long)m_parent->GetId());
1771
1772 if (m_rotation != 0.0)
1773 clause->AddAttributeValue(_T("rotation"), m_rotation);
1774
1775 if (!this->IsKindOf(CLASSINFO(wxLineShape)))
1776 {
1777 clause->AddAttributeValue(_T("neck_length"), (long) m_branchNeckLength);
1778 clause->AddAttributeValue(_T("stem_length"), (long) m_branchStemLength);
1779 clause->AddAttributeValue(_T("branch_spacing"), (long) m_branchSpacing);
1780 clause->AddAttributeValue(_T("branch_style"), (long) m_branchStyle);
1781 }
1782
1783 // Write user-defined attachment points, if any
1784 if (m_attachmentPoints.GetCount() > 0)
1785 {
1786 wxExpr *attachmentList = new wxExpr(wxExprList);
1787 wxNode *node = m_attachmentPoints.GetFirst();
1788 while (node)
1789 {
1790 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
1791 wxExpr *pointExpr = new wxExpr(wxExprList);
1792 pointExpr->Append(new wxExpr((long)point->m_id));
1793 pointExpr->Append(new wxExpr(point->m_x));
1794 pointExpr->Append(new wxExpr(point->m_y));
1795 attachmentList->Append(pointExpr);
1796 node = node->GetNext();
1797 }
1798 clause->AddAttributeValue(_T("user_attachments"), attachmentList);
1799 }
1800
1801 // Write text regions
1802 WriteRegions(clause);
1803 }
1804
1805 void wxShape::WriteRegions(wxExpr *clause)
1806 {
1807 // Output regions as region1 = (...), region2 = (...), etc
1808 // and formatted text as text1 = (...), text2 = (...) etc.
1809 int regionNo = 1;
1810 wxChar regionNameBuf[20];
1811 wxChar textNameBuf[20];
1812 wxNode *node = m_regions.GetFirst();
1813 while (node)
1814 {
1815 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
1816 wxSprintf(regionNameBuf, _T("region%d"), regionNo);
1817 wxSprintf(textNameBuf, _T("text%d"), regionNo);
1818
1819 // Original text and region attributes:
1820 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1821 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1822 wxExpr *regionExpr = new wxExpr(wxExprList);
1823 regionExpr->Append(new wxExpr(wxExprString, region->m_regionName));
1824 regionExpr->Append(new wxExpr(wxExprString, region->m_regionText));
1825
1826 regionExpr->Append(new wxExpr(region->m_x));
1827 regionExpr->Append(new wxExpr(region->m_y));
1828 regionExpr->Append(new wxExpr(region->GetWidth()));
1829 regionExpr->Append(new wxExpr(region->GetHeight()));
1830
1831 regionExpr->Append(new wxExpr(region->m_minWidth));
1832 regionExpr->Append(new wxExpr(region->m_minHeight));
1833 regionExpr->Append(new wxExpr(region->m_regionProportionX));
1834 regionExpr->Append(new wxExpr(region->m_regionProportionY));
1835
1836 regionExpr->Append(new wxExpr((long)region->m_formatMode));
1837
1838 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetPointSize() : 10)));
1839 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT)));
1840 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT)));
1841 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL)));
1842 regionExpr->Append(new wxExpr(wxExprString, region->m_textColour));
1843
1844 // New members for pen colour/style
1845 regionExpr->Append(new wxExpr(wxExprString, region->m_penColour));
1846 regionExpr->Append(new wxExpr((long)region->m_penStyle));
1847
1848 // Formatted text:
1849 // text1 = ((x y string) (x y string) ...)
1850 wxExpr *textExpr = new wxExpr(wxExprList);
1851
1852 wxNode *textNode = region->m_formattedText.GetFirst();
1853 while (textNode)
1854 {
1855 wxShapeTextLine *line = (wxShapeTextLine *)textNode->GetData();
1856 wxExpr *list2 = new wxExpr(wxExprList);
1857 list2->Append(new wxExpr(line->GetX()));
1858 list2->Append(new wxExpr(line->GetY()));
1859 list2->Append(new wxExpr(wxExprString, line->GetText()));
1860 textExpr->Append(list2);
1861 textNode = textNode->GetNext();
1862 }
1863
1864 // Now add both attributes to the clause
1865 clause->AddAttributeValue(regionNameBuf, regionExpr);
1866 clause->AddAttributeValue(textNameBuf, textExpr);
1867
1868 node = node->GetNext();
1869 regionNo ++;
1870 }
1871 }
1872
1873 void wxShape::ReadAttributes(wxExpr *clause)
1874 {
1875 clause->GetAttributeValue(_T("id"), m_id);
1876 wxRegisterId(m_id);
1877
1878 clause->GetAttributeValue(_T("x"), m_xpos);
1879 clause->GetAttributeValue(_T("y"), m_ypos);
1880
1881 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1882 ClearText();
1883 wxExpr *strings = clause->AttributeValue(_T("text"));
1884 if (strings && strings->Type() == wxExprList)
1885 {
1886 m_formatted = true; // Assume text is formatted unless we prove otherwise
1887 wxExpr *node = strings->value.first;
1888 while (node)
1889 {
1890 wxExpr *string_expr = node;
1891 double the_x = 0.0;
1892 double the_y = 0.0;
1893 wxString the_string = wxEmptyString;
1894
1895 // string_expr can either be a string, or a list of
1896 // 3 elements: x, y, and string.
1897 if (string_expr->Type() == wxExprString)
1898 {
1899 the_string = string_expr->StringValue();
1900 m_formatted = false;
1901 }
1902 else if (string_expr->Type() == wxExprList)
1903 {
1904 wxExpr *first = string_expr->value.first;
1905 wxExpr *second = first ? first->next : (wxExpr*) NULL;
1906 wxExpr *third = second ? second->next : (wxExpr*) NULL;
1907
1908 if (first && second && third &&
1909 (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
1910 (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
1911 third->Type() == wxExprString)
1912 {
1913 if (first->Type() == wxExprReal)
1914 the_x = first->RealValue();
1915 else the_x = (double)first->IntegerValue();
1916
1917 if (second->Type() == wxExprReal)
1918 the_y = second->RealValue();
1919 else the_y = (double)second->IntegerValue();
1920
1921 the_string = third->StringValue();
1922 }
1923 }
1924 wxShapeTextLine *line =
1925 new wxShapeTextLine(the_x, the_y, the_string);
1926 m_text.Append(line);
1927
1928 node = node->next;
1929 }
1930 }
1931
1932 wxString pen_string = wxEmptyString;
1933 wxString brush_string = wxEmptyString;
1934 int pen_width = 1;
1935 int pen_style = wxSOLID;
1936 int brush_style = wxSOLID;
1937 m_attachmentMode = ATTACHMENT_MODE_NONE;
1938
1939 clause->GetAttributeValue(_T("pen_colour"), pen_string);
1940 clause->GetAttributeValue(_T("text_colour"), m_textColourName);
1941
1942 SetTextColour(m_textColourName);
1943
1944 clause->GetAttributeValue(_T("region_name"), m_regionName);
1945
1946 clause->GetAttributeValue(_T("brush_colour"), brush_string);
1947 clause->GetAttributeValue(_T("pen_width"), pen_width);
1948 clause->GetAttributeValue(_T("pen_style"), pen_style);
1949 clause->GetAttributeValue(_T("brush_style"), brush_style);
1950
1951 int iVal = (int) m_attachmentMode;
1952 clause->GetAttributeValue(_T("use_attachments"), iVal);
1953 m_attachmentMode = iVal;
1954
1955 clause->GetAttributeValue(_T("sensitivity"), m_sensitivity);
1956
1957 iVal = (int) m_spaceAttachments;
1958 clause->GetAttributeValue(_T("space_attachments"), iVal);
1959 m_spaceAttachments = (iVal != 0);
1960
1961 iVal = (int) m_fixedWidth;
1962 clause->GetAttributeValue(_T("fixed_width"), iVal);
1963 m_fixedWidth = (iVal != 0);
1964
1965 iVal = (int) m_fixedHeight;
1966 clause->GetAttributeValue(_T("fixed_height"), iVal);
1967 m_fixedHeight = (iVal != 0);
1968
1969 clause->GetAttributeValue(_T("format_mode"), m_formatMode);
1970 clause->GetAttributeValue(_T("shadow_mode"), m_shadowMode);
1971
1972 iVal = m_branchNeckLength;
1973 clause->GetAttributeValue(_T("neck_length"), iVal);
1974 m_branchNeckLength = iVal;
1975
1976 iVal = m_branchStemLength;
1977 clause->GetAttributeValue(_T("stem_length"), iVal);
1978 m_branchStemLength = iVal;
1979
1980 iVal = m_branchSpacing;
1981 clause->GetAttributeValue(_T("branch_spacing"), iVal);
1982 m_branchSpacing = iVal;
1983
1984 clause->GetAttributeValue(_T("branch_style"), m_branchStyle);
1985
1986 iVal = (int) m_centreResize;
1987 clause->GetAttributeValue(_T("centre_resize"), iVal);
1988 m_centreResize = (iVal != 0);
1989
1990 iVal = (int) m_maintainAspectRatio;
1991 clause->GetAttributeValue(_T("maintain_aspect_ratio"), iVal);
1992 m_maintainAspectRatio = (iVal != 0);
1993
1994 iVal = (int) m_highlighted;
1995 clause->GetAttributeValue(_T("hilite"), iVal);
1996 m_highlighted = (iVal != 0);
1997
1998 clause->GetAttributeValue(_T("rotation"), m_rotation);
1999
2000 if (pen_string == wxEmptyString)
2001 pen_string = _T("BLACK");
2002 if (brush_string == wxEmptyString)
2003 brush_string = _T("WHITE");
2004
2005 if (pen_string.GetChar(0) == '#')
2006 {
2007 wxColour col(oglHexToColour(pen_string.After('#')));
2008 m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style);
2009 }
2010 else
2011 m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
2012
2013 if (!m_pen)
2014 m_pen = wxBLACK_PEN;
2015
2016 if (brush_string.GetChar(0) == '#')
2017 {
2018 wxColour col(oglHexToColour(brush_string.After('#')));
2019 m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style);
2020 }
2021 else
2022 m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
2023
2024 if (!m_brush)
2025 m_brush = wxWHITE_BRUSH;
2026
2027 int point_size = 10;
2028 clause->GetAttributeValue(_T("point_size"), point_size);
2029 SetFont(oglMatchFont(point_size));
2030
2031 // Read user-defined attachment points, if any
2032 wxExpr *attachmentList = clause->AttributeValue(_T("user_attachments"));
2033 if (attachmentList)
2034 {
2035 wxExpr *pointExpr = attachmentList->GetFirst();
2036 while (pointExpr)
2037 {
2038 wxExpr *idExpr = pointExpr->Nth(0);
2039 wxExpr *xExpr = pointExpr->Nth(1);
2040 wxExpr *yExpr = pointExpr->Nth(2);
2041 if (idExpr && xExpr && yExpr)
2042 {
2043 wxAttachmentPoint *point = new wxAttachmentPoint;
2044 point->m_id = (int)idExpr->IntegerValue();
2045 point->m_x = xExpr->RealValue();
2046 point->m_y = yExpr->RealValue();
2047 m_attachmentPoints.Append((wxObject *)point);
2048 }
2049 pointExpr = pointExpr->GetNext();
2050 }
2051 }
2052
2053 // Read text regions
2054 ReadRegions(clause);
2055 }
2056
2057 void wxShape::ReadRegions(wxExpr *clause)
2058 {
2059 ClearRegions();
2060
2061 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
2062 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
2063 int regionNo = 1;
2064 wxChar regionNameBuf[20];
2065 wxChar textNameBuf[20];
2066
2067 wxExpr *regionExpr;
2068 wxExpr *textExpr = NULL;
2069 wxSprintf(regionNameBuf, _T("region%d"), regionNo);
2070 wxSprintf(textNameBuf, _T("text%d"), regionNo);
2071
2072 m_formatted = true; // Assume text is formatted unless we prove otherwise
2073
2074 while ((regionExpr = clause->AttributeValue(regionNameBuf)) != NULL)
2075 {
2076 /*
2077 * Get the region information
2078 *
2079 */
2080
2081 wxString regionName = wxEmptyString;
2082 wxString regionText = wxEmptyString;
2083 double x = 0.0;
2084 double y = 0.0;
2085 double width = 0.0;
2086 double height = 0.0;
2087 double minWidth = 5.0;
2088 double minHeight = 5.0;
2089 double m_regionProportionX = -1.0;
2090 double m_regionProportionY = -1.0;
2091 int formatMode = FORMAT_NONE;
2092 int fontSize = 10;
2093 int fontFamily = wxSWISS;
2094 int fontStyle = wxNORMAL;
2095 int fontWeight = wxNORMAL;
2096 wxString regionTextColour = wxEmptyString;
2097 wxString penColour = wxEmptyString;
2098 int penStyle = wxSOLID;
2099
2100 if (regionExpr->Type() == wxExprList)
2101 {
2102 wxExpr *nameExpr = regionExpr->Nth(0);
2103 wxExpr *textExpr = regionExpr->Nth(1);
2104 wxExpr *xExpr = regionExpr->Nth(2);
2105 wxExpr *yExpr = regionExpr->Nth(3);
2106 wxExpr *widthExpr = regionExpr->Nth(4);
2107 wxExpr *heightExpr = regionExpr->Nth(5);
2108 wxExpr *minWidthExpr = regionExpr->Nth(6);
2109 wxExpr *minHeightExpr = regionExpr->Nth(7);
2110 wxExpr *propXExpr = regionExpr->Nth(8);
2111 wxExpr *propYExpr = regionExpr->Nth(9);
2112 wxExpr *formatExpr = regionExpr->Nth(10);
2113 wxExpr *sizeExpr = regionExpr->Nth(11);
2114 wxExpr *familyExpr = regionExpr->Nth(12);
2115 wxExpr *styleExpr = regionExpr->Nth(13);
2116 wxExpr *weightExpr = regionExpr->Nth(14);
2117 wxExpr *colourExpr = regionExpr->Nth(15);
2118 wxExpr *penColourExpr = regionExpr->Nth(16);
2119 wxExpr *penStyleExpr = regionExpr->Nth(17);
2120
2121 regionName = nameExpr->StringValue();
2122 regionText = textExpr->StringValue();
2123
2124 x = xExpr->RealValue();
2125 y = yExpr->RealValue();
2126
2127 width = widthExpr->RealValue();
2128 height = heightExpr->RealValue();
2129
2130 minWidth = minWidthExpr->RealValue();
2131 minHeight = minHeightExpr->RealValue();
2132
2133 m_regionProportionX = propXExpr->RealValue();
2134 m_regionProportionY = propYExpr->RealValue();
2135
2136 formatMode = (int) formatExpr->IntegerValue();
2137 fontSize = (int)sizeExpr->IntegerValue();
2138 fontFamily = (int)familyExpr->IntegerValue();
2139 fontStyle = (int)styleExpr->IntegerValue();
2140 fontWeight = (int)weightExpr->IntegerValue();
2141
2142 if (colourExpr)
2143 {
2144 regionTextColour = colourExpr->StringValue();
2145 }
2146 else
2147 regionTextColour = _T("BLACK");
2148
2149 if (penColourExpr)
2150 penColour = penColourExpr->StringValue();
2151 if (penStyleExpr)
2152 penStyle = (int)penStyleExpr->IntegerValue();
2153 }
2154 wxFont *font = wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight);
2155
2156 wxShapeRegion *region = new wxShapeRegion;
2157 region->SetProportions(m_regionProportionX, m_regionProportionY);
2158 region->SetFont(font);
2159 region->SetSize(width, height);
2160 region->SetPosition(x, y);
2161 region->SetMinSize(minWidth, minHeight);
2162 region->SetFormatMode(formatMode);
2163 region->SetPenStyle(penStyle);
2164 if (penColour != wxEmptyString)
2165 region->SetPenColour(penColour);
2166
2167 region->m_textColour = regionTextColour;
2168 region->m_regionText = regionText;
2169 region->m_regionName = regionName;
2170
2171 m_regions.Append(region);
2172
2173 /*
2174 * Get the formatted text strings
2175 *
2176 */
2177 textExpr = clause->AttributeValue(textNameBuf);
2178 if (textExpr && (textExpr->Type() == wxExprList))
2179 {
2180 wxExpr *node = textExpr->value.first;
2181 while (node)
2182 {
2183 wxExpr *string_expr = node;
2184 double the_x = 0.0;
2185 double the_y = 0.0;
2186 wxString the_string = wxEmptyString;
2187
2188 // string_expr can either be a string, or a list of
2189 // 3 elements: x, y, and string.
2190 if (string_expr->Type() == wxExprString)
2191 {
2192 the_string = string_expr->StringValue();
2193 m_formatted = false;
2194 }
2195 else if (string_expr->Type() == wxExprList)
2196 {
2197 wxExpr *first = string_expr->value.first;
2198 wxExpr *second = first ? first->next : (wxExpr*) NULL;
2199 wxExpr *third = second ? second->next : (wxExpr*) NULL;
2200
2201 if (first && second && third &&
2202 (first->Type() == wxExprReal || first->Type() == wxExprInteger) &&
2203 (second->Type() == wxExprReal || second->Type() == wxExprInteger) &&
2204 third->Type() == wxExprString)
2205 {
2206 if (first->Type() == wxExprReal)
2207 the_x = first->RealValue();
2208 else the_x = (double)first->IntegerValue();
2209
2210 if (second->Type() == wxExprReal)
2211 the_y = second->RealValue();
2212 else the_y = (double)second->IntegerValue();
2213
2214 the_string = third->StringValue();
2215 }
2216 }
2217 if (the_string)
2218 {
2219 wxShapeTextLine *line =
2220 new wxShapeTextLine(the_x, the_y, the_string);
2221 region->m_formattedText.Append(line);
2222 }
2223 node = node->next;
2224 }
2225 }
2226
2227 regionNo ++;
2228 wxSprintf(regionNameBuf, _T("region%d"), regionNo);
2229 wxSprintf(textNameBuf, _T("text%d"), regionNo);
2230 }
2231
2232 // Compatibility: check for no regions (old file).
2233 // Lines and divided rectangles must deal with this compatibility
2234 // theirselves. Composites _may_ not have any regions anyway.
2235 if ((m_regions.GetCount() == 0) &&
2236 !this->IsKindOf(CLASSINFO(wxLineShape)) && !this->IsKindOf(CLASSINFO(wxDividedShape)) &&
2237 !this->IsKindOf(CLASSINFO(wxCompositeShape)))
2238 {
2239 wxShapeRegion *newRegion = new wxShapeRegion;
2240 newRegion->SetName(_T("0"));
2241 m_regions.Append((wxObject *)newRegion);
2242 if (m_text.GetCount() > 0)
2243 {
2244 newRegion->ClearText();
2245 wxNode *node = m_text.GetFirst();
2246 while (node)
2247 {
2248 wxShapeTextLine *textLine = (wxShapeTextLine *)node->GetData();
2249 wxNode *next = node->GetNext();
2250 newRegion->GetFormattedText().Append((wxObject *)textLine);
2251 delete node;
2252 node = next;
2253 }
2254 }
2255 }
2256 }
2257
2258 #endif
2259
2260 void wxShape::Copy(wxShape& copy)
2261 {
2262 copy.m_id = m_id;
2263 copy.m_xpos = m_xpos;
2264 copy.m_ypos = m_ypos;
2265 copy.m_pen = m_pen;
2266 copy.m_brush = m_brush;
2267 copy.m_textColour = m_textColour;
2268 copy.m_centreResize = m_centreResize;
2269 copy.m_maintainAspectRatio = m_maintainAspectRatio;
2270 copy.m_attachmentMode = m_attachmentMode;
2271 copy.m_spaceAttachments = m_spaceAttachments;
2272 copy.m_highlighted = m_highlighted;
2273 copy.m_rotation = m_rotation;
2274 copy.m_textColourName = m_textColourName;
2275 copy.m_regionName = m_regionName;
2276
2277 copy.m_sensitivity = m_sensitivity;
2278 copy.m_draggable = m_draggable;
2279 copy.m_fixedWidth = m_fixedWidth;
2280 copy.m_fixedHeight = m_fixedHeight;
2281 copy.m_formatMode = m_formatMode;
2282 copy.m_drawHandles = m_drawHandles;
2283
2284 copy.m_visible = m_visible;
2285 copy.m_shadowMode = m_shadowMode;
2286 copy.m_shadowOffsetX = m_shadowOffsetX;
2287 copy.m_shadowOffsetY = m_shadowOffsetY;
2288 copy.m_shadowBrush = m_shadowBrush;
2289
2290 copy.m_branchNeckLength = m_branchNeckLength;
2291 copy.m_branchStemLength = m_branchStemLength;
2292 copy.m_branchSpacing = m_branchSpacing;
2293
2294 // Copy text regions
2295 copy.ClearRegions();
2296 wxNode *node = m_regions.GetFirst();
2297 while (node)
2298 {
2299 wxShapeRegion *region = (wxShapeRegion *)node->GetData();
2300 wxShapeRegion *newRegion = new wxShapeRegion(*region);
2301 copy.m_regions.Append(newRegion);
2302 node = node->GetNext();
2303 }
2304
2305 // Copy attachments
2306 copy.ClearAttachments();
2307 node = m_attachmentPoints.GetFirst();
2308 while (node)
2309 {
2310 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
2311 wxAttachmentPoint *newPoint = new wxAttachmentPoint;
2312 newPoint->m_id = point->m_id;
2313 newPoint->m_x = point->m_x;
2314 newPoint->m_y = point->m_y;
2315 copy.m_attachmentPoints.Append((wxObject *)newPoint);
2316 node = node->GetNext();
2317 }
2318
2319 // Copy lines
2320 copy.m_lines.Clear();
2321 node = m_lines.GetFirst();
2322 while (node)
2323 {
2324 wxLineShape* line = (wxLineShape*) node->GetData();
2325 copy.m_lines.Append(line);
2326 node = node->GetNext();
2327 }
2328 }
2329
2330 // Create and return a new, fully copied object.
2331 wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute)
2332 {
2333 if (resetMapping)
2334 oglObjectCopyMapping.Clear();
2335
2336 wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject();
2337
2338 wxASSERT( (newObject != NULL) );
2339 wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShape))) );
2340
2341 Copy(*newObject);
2342
2343 if (GetEventHandler() != this)
2344 {
2345 wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy();
2346 newObject->SetEventHandler(newHandler);
2347 newObject->SetPreviousHandler(NULL);
2348 newHandler->SetPreviousHandler(newObject);
2349 newHandler->SetShape(newObject);
2350 }
2351
2352 if (recompute)
2353 newObject->Recompute();
2354 return newObject;
2355 }
2356
2357 // Does the copying for this object, including copying event
2358 // handler data if any. Calls the virtual Copy function.
2359 void wxShape::CopyWithHandler(wxShape& copy)
2360 {
2361 Copy(copy);
2362
2363 if (GetEventHandler() != this)
2364 {
2365 wxASSERT( copy.GetEventHandler() != NULL );
2366 wxASSERT( copy.GetEventHandler() != (&copy) );
2367 wxASSERT( GetEventHandler()->GetClassInfo() == copy.GetEventHandler()->GetClassInfo() );
2368 GetEventHandler()->CopyData(* (copy.GetEventHandler()));
2369 }
2370 }
2371
2372
2373 // Default - make 6 control points
2374 void wxShape::MakeControlPoints()
2375 {
2376 double maxX, maxY, minX, minY;
2377
2378 GetBoundingBoxMax(&maxX, &maxY);
2379 GetBoundingBoxMin(&minX, &minY);
2380
2381 double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
2382 double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
2383
2384 // Offsets from main object
2385 double top = (double)(- (heightMin / 2.0));
2386 double bottom = (double)(heightMin / 2.0 + (maxY - minY));
2387 double left = (double)(- (widthMin / 2.0));
2388 double right = (double)(widthMin / 2.0 + (maxX - minX));
2389
2390 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
2391 CONTROL_POINT_DIAGONAL);
2392 m_canvas->AddShape(control);
2393 m_controlPoints.Append(control);
2394
2395 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
2396 CONTROL_POINT_VERTICAL);
2397 m_canvas->AddShape(control);
2398 m_controlPoints.Append(control);
2399
2400 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
2401 CONTROL_POINT_DIAGONAL);
2402 m_canvas->AddShape(control);
2403 m_controlPoints.Append(control);
2404
2405 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
2406 CONTROL_POINT_HORIZONTAL);
2407 m_canvas->AddShape(control);
2408 m_controlPoints.Append(control);
2409
2410 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
2411 CONTROL_POINT_DIAGONAL);
2412 m_canvas->AddShape(control);
2413 m_controlPoints.Append(control);
2414
2415 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
2416 CONTROL_POINT_VERTICAL);
2417 m_canvas->AddShape(control);
2418 m_controlPoints.Append(control);
2419
2420 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
2421 CONTROL_POINT_DIAGONAL);
2422 m_canvas->AddShape(control);
2423 m_controlPoints.Append(control);
2424
2425 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
2426 CONTROL_POINT_HORIZONTAL);
2427 m_canvas->AddShape(control);
2428 m_controlPoints.Append(control);
2429
2430 }
2431
2432 void wxShape::MakeMandatoryControlPoints()
2433 {
2434 wxNode *node = m_children.GetFirst();
2435 while (node)
2436 {
2437 wxShape *child = (wxShape *)node->GetData();
2438 child->MakeMandatoryControlPoints();
2439 node = node->GetNext();
2440 }
2441 }
2442
2443 void wxShape::ResetMandatoryControlPoints()
2444 {
2445 wxNode *node = m_children.GetFirst();
2446 while (node)
2447 {
2448 wxShape *child = (wxShape *)node->GetData();
2449 child->ResetMandatoryControlPoints();
2450 node = node->GetNext();
2451 }
2452 }
2453
2454 void wxShape::ResetControlPoints()
2455 {
2456 ResetMandatoryControlPoints();
2457
2458 if (m_controlPoints.GetCount() < 1)
2459 return;
2460
2461 double maxX, maxY, minX, minY;
2462
2463 GetBoundingBoxMax(&maxX, &maxY);
2464 GetBoundingBoxMin(&minX, &minY);
2465
2466 double widthMin = (double)(minX + CONTROL_POINT_SIZE + 2);
2467 double heightMin = (double)(minY + CONTROL_POINT_SIZE + 2);
2468
2469 // Offsets from main object
2470 double top = (double)(- (heightMin / 2.0));
2471 double bottom = (double)(heightMin / 2.0 + (maxY - minY));
2472 double left = (double)(- (widthMin / 2.0));
2473 double right = (double)(widthMin / 2.0 + (maxX - minX));
2474
2475 wxNode *node = m_controlPoints.GetFirst();
2476 wxControlPoint *control = (wxControlPoint *)node->GetData();
2477 control->m_xoffset = left; control->m_yoffset = top;
2478
2479 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2480 control->m_xoffset = 0; control->m_yoffset = top;
2481
2482 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2483 control->m_xoffset = right; control->m_yoffset = top;
2484
2485 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2486 control->m_xoffset = right; control->m_yoffset = 0;
2487
2488 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2489 control->m_xoffset = right; control->m_yoffset = bottom;
2490
2491 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2492 control->m_xoffset = 0; control->m_yoffset = bottom;
2493
2494 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2495 control->m_xoffset = left; control->m_yoffset = bottom;
2496
2497 node = node->GetNext(); control = (wxControlPoint *)node->GetData();
2498 control->m_xoffset = left; control->m_yoffset = 0;
2499 }
2500
2501 void wxShape::DeleteControlPoints(wxDC *dc)
2502 {
2503 wxNode *node = m_controlPoints.GetFirst();
2504 while (node)
2505 {
2506 wxControlPoint *control = (wxControlPoint *)node->GetData();
2507 if (dc)
2508 control->GetEventHandler()->OnErase(*dc);
2509 m_canvas->RemoveShape(control);
2510 delete control;
2511 delete node;
2512 node = m_controlPoints.GetFirst();
2513 }
2514 // Children of divisions are contained objects,
2515 // so stop here
2516 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2517 {
2518 node = m_children.GetFirst();
2519 while (node)
2520 {
2521 wxShape *child = (wxShape *)node->GetData();
2522 child->DeleteControlPoints(dc);
2523 node = node->GetNext();
2524 }
2525 }
2526 }
2527
2528 void wxShape::OnDrawControlPoints(wxDC& dc)
2529 {
2530 if (!m_drawHandles)
2531 return;
2532
2533 dc.SetBrush(* wxBLACK_BRUSH);
2534 dc.SetPen(* wxBLACK_PEN);
2535
2536 wxNode *node = m_controlPoints.GetFirst();
2537 while (node)
2538 {
2539 wxControlPoint *control = (wxControlPoint *)node->GetData();
2540 control->Draw(dc);
2541 node = node->GetNext();
2542 }
2543 // Children of divisions are contained objects,
2544 // so stop here.
2545 // This test bypasses the type facility for speed
2546 // (critical when drawing)
2547 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2548 {
2549 node = m_children.GetFirst();
2550 while (node)
2551 {
2552 wxShape *child = (wxShape *)node->GetData();
2553 child->GetEventHandler()->OnDrawControlPoints(dc);
2554 node = node->GetNext();
2555 }
2556 }
2557 }
2558
2559 void wxShape::OnEraseControlPoints(wxDC& dc)
2560 {
2561 wxNode *node = m_controlPoints.GetFirst();
2562 while (node)
2563 {
2564 wxControlPoint *control = (wxControlPoint *)node->GetData();
2565 control->Erase(dc);
2566 node = node->GetNext();
2567 }
2568 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2569 {
2570 node = m_children.GetFirst();
2571 while (node)
2572 {
2573 wxShape *child = (wxShape *)node->GetData();
2574 child->GetEventHandler()->OnEraseControlPoints(dc);
2575 node = node->GetNext();
2576 }
2577 }
2578 }
2579
2580 void wxShape::Select(bool select, wxDC* dc)
2581 {
2582 m_selected = select;
2583 if (select)
2584 {
2585 MakeControlPoints();
2586 // Children of divisions are contained objects,
2587 // so stop here
2588 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2589 {
2590 wxNode *node = m_children.GetFirst();
2591 while (node)
2592 {
2593 wxShape *child = (wxShape *)node->GetData();
2594 child->MakeMandatoryControlPoints();
2595 node = node->GetNext();
2596 }
2597 }
2598 if (dc)
2599 GetEventHandler()->OnDrawControlPoints(*dc);
2600 }
2601 if (!select)
2602 {
2603 DeleteControlPoints(dc);
2604 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2605 {
2606 wxNode *node = m_children.GetFirst();
2607 while (node)
2608 {
2609 wxShape *child = (wxShape *)node->GetData();
2610 child->DeleteControlPoints(dc);
2611 node = node->GetNext();
2612 }
2613 }
2614 }
2615 }
2616
2617 bool wxShape::Selected() const
2618 {
2619 return m_selected;
2620 }
2621
2622 bool wxShape::AncestorSelected() const
2623 {
2624 if (m_selected) return true;
2625 if (!GetParent())
2626 return false;
2627 else
2628 return GetParent()->AncestorSelected();
2629 }
2630
2631 int wxShape::GetNumberOfAttachments() const
2632 {
2633 // Should return the MAXIMUM attachment point id here,
2634 // so higher-level functions can iterate through all attachments,
2635 // even if they're not contiguous.
2636 if (m_attachmentPoints.GetCount() == 0)
2637 return 4;
2638 else
2639 {
2640 int maxN = 3;
2641 wxNode *node = m_attachmentPoints.GetFirst();
2642 while (node)
2643 {
2644 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
2645 if (point->m_id > maxN)
2646 maxN = point->m_id;
2647 node = node->GetNext();
2648 }
2649 return maxN+1;;
2650 }
2651 }
2652
2653 bool wxShape::AttachmentIsValid(int attachment) const
2654 {
2655 if (m_attachmentPoints.GetCount() == 0)
2656 {
2657 return ((attachment >= 0) && (attachment < 4)) ;
2658 }
2659
2660 wxNode *node = m_attachmentPoints.GetFirst();
2661 while (node)
2662 {
2663 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
2664 if (point->m_id == attachment)
2665 return true;
2666 node = node->GetNext();
2667 }
2668 return false;
2669 }
2670
2671 bool wxShape::GetAttachmentPosition(int attachment, double *x, double *y,
2672 int nth, int no_arcs, wxLineShape *line)
2673 {
2674 if (m_attachmentMode == ATTACHMENT_MODE_NONE)
2675 {
2676 *x = m_xpos; *y = m_ypos;
2677 return true;
2678 }
2679 else if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
2680 {
2681 wxRealPoint pt, stemPt;
2682 GetBranchingAttachmentPoint(attachment, nth, pt, stemPt);
2683 *x = pt.x;
2684 *y = pt.y;
2685 return true;
2686 }
2687 else if (m_attachmentMode == ATTACHMENT_MODE_EDGE)
2688 {
2689 if (m_attachmentPoints.GetCount() > 0)
2690 {
2691 wxNode *node = m_attachmentPoints.GetFirst();
2692 while (node)
2693 {
2694 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
2695 if (point->m_id == attachment)
2696 {
2697 *x = (double)(m_xpos + point->m_x);
2698 *y = (double)(m_ypos + point->m_y);
2699 return true;
2700 }
2701 node = node->GetNext();
2702 }
2703 *x = m_xpos; *y = m_ypos;
2704 return false;
2705 }
2706 else
2707 {
2708 // Assume is rectangular
2709 double w, h;
2710 GetBoundingBoxMax(&w, &h);
2711 double top = (double)(m_ypos + h/2.0);
2712 double bottom = (double)(m_ypos - h/2.0);
2713 double left = (double)(m_xpos - w/2.0);
2714 double right = (double)(m_xpos + w/2.0);
2715
2716 #if 0
2717 /* bool isEnd = */ (line && line->IsEnd(this));
2718 #endif
2719
2720 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
2721
2722 // Simplified code
2723 switch (physicalAttachment)
2724 {
2725 case 0:
2726 {
2727 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom),
2728 nth, no_arcs, line);
2729
2730 *x = pt.x; *y = pt.y;
2731 break;
2732 }
2733 case 1:
2734 {
2735 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top),
2736 nth, no_arcs, line);
2737
2738 *x = pt.x; *y = pt.y;
2739 break;
2740 }
2741 case 2:
2742 {
2743 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top),
2744 nth, no_arcs, line);
2745
2746 *x = pt.x; *y = pt.y;
2747 break;
2748 }
2749 case 3:
2750 {
2751 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top),
2752 nth, no_arcs, line);
2753
2754 *x = pt.x; *y = pt.y;
2755 break;
2756 }
2757 default:
2758 {
2759 return false;
2760 }
2761 }
2762 return true;
2763 }
2764 }
2765 return false;
2766 }
2767
2768 void wxShape::GetBoundingBoxMax(double *w, double *h)
2769 {
2770 double ww, hh;
2771 GetBoundingBoxMin(&ww, &hh);
2772 if (m_shadowMode != SHADOW_NONE)
2773 {
2774 ww += m_shadowOffsetX;
2775 hh += m_shadowOffsetY;
2776 }
2777 *w = ww;
2778 *h = hh;
2779 }
2780
2781 // Returns true if image is a descendant of this composite
2782 bool wxShape::HasDescendant(wxShape *image)
2783 {
2784 if (image == this)
2785 return true;
2786 wxNode *node = m_children.GetFirst();
2787 while (node)
2788 {
2789 wxShape *child = (wxShape *)node->GetData();
2790 bool ans = child->HasDescendant(image);
2791 if (ans)
2792 return true;
2793 node = node->GetNext();
2794 }
2795 return false;
2796 }
2797
2798 // Clears points from a list of wxRealPoints, and clears list
2799 void wxShape::ClearPointList(wxList& list)
2800 {
2801 wxNode* node = list.GetFirst();
2802 while (node)
2803 {
2804 wxRealPoint* pt = (wxRealPoint*) node->GetData();
2805 delete pt;
2806
2807 node = node->GetNext();
2808 }
2809 list.Clear();
2810 }
2811
2812 // Assuming the attachment lies along a vertical or horizontal line,
2813 // calculate the position on that point.
2814 wxRealPoint wxShape::CalcSimpleAttachment(const wxRealPoint& pt1, const wxRealPoint& pt2,
2815 int nth, int noArcs, wxLineShape* line)
2816 {
2817 bool isEnd = (line && line->IsEnd(this));
2818
2819 // Are we horizontal or vertical?
2820 bool isHorizontal = (oglRoughlyEqual(pt1.y, pt2.y) == true);
2821
2822 double x, y;
2823
2824 if (isHorizontal)
2825 {
2826 wxRealPoint firstPoint, secondPoint;
2827 if (pt1.x > pt2.x)
2828 {
2829 firstPoint = pt2;
2830 secondPoint = pt1;
2831 }
2832 else
2833 {
2834 firstPoint = pt1;
2835 secondPoint = pt2;
2836 }
2837
2838 if (m_spaceAttachments)
2839 {
2840 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
2841 {
2842 // Align line according to the next handle along
2843 wxRealPoint *point = line->GetNextControlPoint(this);
2844 if (point->x < firstPoint.x)
2845 x = firstPoint.x;
2846 else if (point->x > secondPoint.x)
2847 x = secondPoint.x;
2848 else
2849 x = point->x;
2850 }
2851 else
2852 x = firstPoint.x + (nth + 1)*(secondPoint.x - firstPoint.x)/(noArcs + 1);
2853 }
2854 else x = (secondPoint.x - firstPoint.x)/2.0; // Midpoint
2855
2856 y = pt1.y;
2857 }
2858 else
2859 {
2860 wxASSERT( oglRoughlyEqual(pt1.x, pt2.x) == true );
2861
2862 wxRealPoint firstPoint, secondPoint;
2863 if (pt1.y > pt2.y)
2864 {
2865 firstPoint = pt2;
2866 secondPoint = pt1;
2867 }
2868 else
2869 {
2870 firstPoint = pt1;
2871 secondPoint = pt2;
2872 }
2873
2874 if (m_spaceAttachments)
2875 {
2876 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
2877 {
2878 // Align line according to the next handle along
2879 wxRealPoint *point = line->GetNextControlPoint(this);
2880 if (point->y < firstPoint.y)
2881 y = firstPoint.y;
2882 else if (point->y > secondPoint.y)
2883 y = secondPoint.y;
2884 else
2885 y = point->y;
2886 }
2887 else
2888 y = firstPoint.y + (nth + 1)*(secondPoint.y - firstPoint.y)/(noArcs + 1);
2889 }
2890 else y = (secondPoint.y - firstPoint.y)/2.0; // Midpoint
2891
2892 x = pt1.x;
2893 }
2894
2895 return wxRealPoint(x, y);
2896 }
2897
2898 // Return the zero-based position in m_lines of line.
2899 int wxShape::GetLinePosition(wxLineShape* line)
2900 {
2901 for (size_t i = 0; i < m_lines.GetCount(); i++)
2902 if ((wxLineShape*) (m_lines.Item(i)->GetData()) == line)
2903 return i;
2904
2905 return 0;
2906 }
2907
2908 //
2909 // |________|
2910 // | <- root
2911 // | <- neck
2912 // shoulder1 ->---------<- shoulder2
2913 // | | | | |
2914 // <- branching attachment point N-1
2915
2916 // This function gets information about where branching connections go.
2917 // Returns false if there are no lines at this attachment.
2918 bool wxShape::GetBranchingAttachmentInfo(int attachment, wxRealPoint& root, wxRealPoint& neck,
2919 wxRealPoint& shoulder1, wxRealPoint& shoulder2)
2920 {
2921 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
2922
2923 // Number of lines at this attachment.
2924 int lineCount = GetAttachmentLineCount(attachment);
2925
2926 if (lineCount == 0)
2927 return false;
2928
2929 int totalBranchLength = m_branchSpacing * (lineCount - 1);
2930
2931 root = GetBranchingAttachmentRoot(attachment);
2932
2933 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
2934 switch (physicalAttachment)
2935 {
2936 case 0:
2937 {
2938 neck.x = GetX();
2939 neck.y = root.y - m_branchNeckLength;
2940
2941 shoulder1.x = root.x - (totalBranchLength/2.0) ;
2942 shoulder2.x = root.x + (totalBranchLength/2.0) ;
2943
2944 shoulder1.y = neck.y;
2945 shoulder2.y = neck.y;
2946 break;
2947 }
2948 case 1:
2949 {
2950 neck.x = root.x + m_branchNeckLength;
2951 neck.y = root.y;
2952
2953 shoulder1.x = neck.x ;
2954 shoulder2.x = neck.x ;
2955
2956 shoulder1.y = neck.y - (totalBranchLength/2.0) ;
2957 shoulder2.y = neck.y + (totalBranchLength/2.0) ;
2958 break;
2959 }
2960 case 2:
2961 {
2962 neck.x = GetX();
2963 neck.y = root.y + m_branchNeckLength;
2964
2965 shoulder1.x = root.x - (totalBranchLength/2.0) ;
2966 shoulder2.x = root.x + (totalBranchLength/2.0) ;
2967
2968 shoulder1.y = neck.y;
2969 shoulder2.y = neck.y;
2970 break;
2971 }
2972 case 3:
2973 {
2974 neck.x = root.x - m_branchNeckLength;
2975 neck.y = root.y ;
2976
2977 shoulder1.x = neck.x ;
2978 shoulder2.x = neck.x ;
2979
2980 shoulder1.y = neck.y - (totalBranchLength/2.0) ;
2981 shoulder2.y = neck.y + (totalBranchLength/2.0) ;
2982 break;
2983 }
2984 default:
2985 {
2986 wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentInfo.") );
2987 break;
2988 }
2989 }
2990 return true;
2991 }
2992
2993 // n is the number of the adjoining line, from 0 to N-1 where N is the number of lines
2994 // at this attachment point.
2995 // Get the attachment point where the arc joins the stem, and also the point where the
2996 // the stem meets the shoulder.
2997 bool wxShape::GetBranchingAttachmentPoint(int attachment, int n, wxRealPoint& pt, wxRealPoint& stemPt)
2998 {
2999 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
3000
3001 wxRealPoint root, neck, shoulder1, shoulder2;
3002 GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
3003
3004 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3005 switch (physicalAttachment)
3006 {
3007 case 0:
3008 {
3009 pt.y = neck.y - m_branchStemLength;
3010 pt.x = shoulder1.x + n*m_branchSpacing;
3011
3012 stemPt.x = pt.x;
3013 stemPt.y = neck.y;
3014 break;
3015 }
3016 case 2:
3017 {
3018 pt.y = neck.y + m_branchStemLength;
3019 pt.x = shoulder1.x + n*m_branchSpacing;
3020
3021 stemPt.x = pt.x;
3022 stemPt.y = neck.y;
3023 break;
3024 }
3025 case 1:
3026 {
3027 pt.x = neck.x + m_branchStemLength;
3028 pt.y = shoulder1.y + n*m_branchSpacing;
3029
3030 stemPt.x = neck.x;
3031 stemPt.y = pt.y;
3032 break;
3033 }
3034 case 3:
3035 {
3036 pt.x = neck.x - m_branchStemLength;
3037 pt.y = shoulder1.y + n*m_branchSpacing;
3038
3039 stemPt.x = neck.x;
3040 stemPt.y = pt.y;
3041 break;
3042 }
3043 default:
3044 {
3045 wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentPoint.") );
3046 break;
3047 }
3048 }
3049
3050 return true;
3051 }
3052
3053 // Get the number of lines at this attachment position.
3054 int wxShape::GetAttachmentLineCount(int attachment) const
3055 {
3056 int count = 0;
3057 wxNode* node = m_lines.GetFirst();
3058 while (node)
3059 {
3060 wxLineShape* lineShape = (wxLineShape*) node->GetData();
3061 if ((lineShape->GetFrom() == this) && (lineShape->GetAttachmentFrom() == attachment))
3062 count ++;
3063 else if ((lineShape->GetTo() == this) && (lineShape->GetAttachmentTo() == attachment))
3064 count ++;
3065
3066 node = node->GetNext();
3067 }
3068 return count;
3069 }
3070
3071 // This function gets the root point at the given attachment.
3072 wxRealPoint wxShape::GetBranchingAttachmentRoot(int attachment)
3073 {
3074 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
3075
3076 wxRealPoint root;
3077
3078 double width, height;
3079 GetBoundingBoxMax(& width, & height);
3080
3081 // Assume that we have attachment points 0 to 3: top, right, bottom, left.
3082 switch (physicalAttachment)
3083 {
3084 case 0:
3085 {
3086 root.x = GetX() ;
3087 root.y = GetY() - height/2.0;
3088 break;
3089 }
3090 case 1:
3091 {
3092 root.x = GetX() + width/2.0;
3093 root.y = GetY() ;
3094 break;
3095 }
3096 case 2:
3097 {
3098 root.x = GetX() ;
3099 root.y = GetY() + height/2.0;
3100 break;
3101 }
3102 case 3:
3103 {
3104 root.x = GetX() - width/2.0;
3105 root.y = GetY() ;
3106 break;
3107 }
3108 default:
3109 {
3110 wxFAIL_MSG( wxT("Unrecognised attachment point in GetBranchingAttachmentRoot.") );
3111 break;
3112 }
3113 }
3114 return root;
3115 }
3116
3117 // Draw or erase the branches (not the actual arcs though)
3118 void wxShape::OnDrawBranches(wxDC& dc, int attachment, bool erase)
3119 {
3120 int count = GetAttachmentLineCount(attachment);
3121 if (count == 0)
3122 return;
3123
3124 wxRealPoint root, neck, shoulder1, shoulder2;
3125 GetBranchingAttachmentInfo(attachment, root, neck, shoulder1, shoulder2);
3126
3127 if (erase)
3128 {
3129 dc.SetPen(*wxWHITE_PEN);
3130 dc.SetBrush(*wxWHITE_BRUSH);
3131 }
3132 else
3133 {
3134 dc.SetPen(*wxBLACK_PEN);
3135 dc.SetBrush(*wxBLACK_BRUSH);
3136 }
3137
3138 // Draw neck
3139 dc.DrawLine((long) root.x, (long) root.y, (long) neck.x, (long) neck.y);
3140
3141 if (count > 1)
3142 {
3143 // Draw shoulder-to-shoulder line
3144 dc.DrawLine((long) shoulder1.x, (long) shoulder1.y, (long) shoulder2.x, (long) shoulder2.y);
3145 }
3146 // Draw all the little branches
3147 int i;
3148 for (i = 0; i < count; i++)
3149 {
3150 wxRealPoint pt, stemPt;
3151 GetBranchingAttachmentPoint(attachment, i, pt, stemPt);
3152 dc.DrawLine((long) stemPt.x, (long) stemPt.y, (long) pt.x, (long) pt.y);
3153
3154 if ((GetBranchStyle() & BRANCHING_ATTACHMENT_BLOB) && (count > 1))
3155 {
3156 long blobSize=6;
3157 // dc.DrawEllipse((long) (stemPt.x + 0.5 - (blobSize/2.0)), (long) (stemPt.y + 0.5 - (blobSize/2.0)), blobSize, blobSize);
3158 dc.DrawEllipse((long) (stemPt.x - (blobSize/2.0)), (long) (stemPt.y - (blobSize/2.0)), blobSize, blobSize);
3159 }
3160 }
3161 }
3162
3163 // Draw or erase the branches (not the actual arcs though)
3164 void wxShape::OnDrawBranches(wxDC& dc, bool erase)
3165 {
3166 if (m_attachmentMode != ATTACHMENT_MODE_BRANCHING)
3167 return;
3168
3169 int count = GetNumberOfAttachments();
3170 int i;
3171 for (i = 0; i < count; i++)
3172 OnDrawBranches(dc, i, erase);
3173 }
3174
3175 // Only get the attachment position at the _edge_ of the shape, ignoring
3176 // branching mode. This is used e.g. to indicate the edge of interest, not the point
3177 // on the attachment branch.
3178 bool wxShape::GetAttachmentPositionEdge(int attachment, double *x, double *y,
3179 int nth, int no_arcs, wxLineShape *line)
3180 {
3181 int oldMode = m_attachmentMode;
3182
3183 // Calculate as if to edge, not branch
3184 if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
3185 m_attachmentMode = ATTACHMENT_MODE_EDGE;
3186 bool success = GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
3187 m_attachmentMode = oldMode;
3188
3189 return success;
3190 }
3191
3192 // Rotate the standard attachment point from physical (0 is always North)
3193 // to logical (0 -> 1 if rotated by 90 degrees)
3194 int wxShape::PhysicalToLogicalAttachment(int physicalAttachment) const
3195 {
3196 const double pi = M_PI ;
3197 int i;
3198 if (oglRoughlyEqual(GetRotation(), 0.0))
3199 {
3200 i = physicalAttachment;
3201 }
3202 else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
3203 {
3204 i = physicalAttachment - 1;
3205 }
3206 else if (oglRoughlyEqual(GetRotation(), pi))
3207 {
3208 i = physicalAttachment - 2;
3209 }
3210 else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
3211 {
3212 i = physicalAttachment - 3;
3213 }
3214 else
3215 // Can't handle -- assume the same.
3216 return physicalAttachment;
3217
3218 if (i < 0)
3219 i += 4;
3220
3221 return i;
3222 }
3223
3224 // Rotate the standard attachment point from logical
3225 // to physical (0 is always North)
3226 int wxShape::LogicalToPhysicalAttachment(int logicalAttachment) const
3227 {
3228 const double pi = M_PI ;
3229 int i;
3230 if (oglRoughlyEqual(GetRotation(), 0.0))
3231 {
3232 i = logicalAttachment;
3233 }
3234 else if (oglRoughlyEqual(GetRotation(), (pi/2.0)))
3235 {
3236 i = logicalAttachment + 1;
3237 }
3238 else if (oglRoughlyEqual(GetRotation(), pi))
3239 {
3240 i = logicalAttachment + 2;
3241 }
3242 else if (oglRoughlyEqual(GetRotation(), (3.0*pi/2.0)))
3243 {
3244 i = logicalAttachment + 3;
3245 }
3246 else
3247 // Can't handle -- assume the same.
3248 return logicalAttachment;
3249
3250 if (i > 3)
3251 i -= 4;
3252
3253 return i;
3254 }
3255
3256 void wxShape::Rotate(double WXUNUSED(x), double WXUNUSED(y), double theta)
3257 {
3258 const double pi = M_PI ;
3259 m_rotation = theta;
3260 if (m_rotation < 0.0)
3261 {
3262 m_rotation += 2*pi;
3263 }
3264 else if (m_rotation > 2*pi)
3265 {
3266 m_rotation -= 2*pi;
3267 }
3268 }
3269
3270
3271 wxPen wxShape::GetBackgroundPen()
3272 {
3273 if (GetCanvas())
3274 {
3275 wxColour c = GetCanvas()->GetBackgroundColour();
3276 return wxPen(c, 1, wxSOLID);
3277 }
3278 return * g_oglWhiteBackgroundPen;
3279 }
3280
3281
3282 wxBrush wxShape::GetBackgroundBrush()
3283 {
3284 if (GetCanvas())
3285 {
3286 wxColour c = GetCanvas()->GetBackgroundColour();
3287 return wxBrush(c, wxSOLID);
3288 }
3289 return * g_oglWhiteBackgroundBrush;
3290 }
3291