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