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