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