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