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