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