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