]> git.saurik.com Git - wxWidgets.git/blob - utils/ogl/src/basic.cpp
Changes mostly as a result of __WXSTUBS__ compilation. The stubs code now
[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 == "")
1539 {
1540 wxString hex(oglColourToHex(m_pen->GetColour()));
1541 hex = wxString("#") + hex;
1542 clause->AddAttributeValueString("pen_colour", hex);
1543 }
1544 else if (penColour != "BLACK")
1545 clause->AddAttributeValueString("pen_colour", penColour);
1546 }
1547
1548 if (m_brush)
1549 {
1550 wxString brushColour = wxTheColourDatabase->FindName(m_brush->GetColour());
1551
1552 if (brushColour == "")
1553 {
1554 wxString hex(oglColourToHex(m_brush->GetColour()));
1555 hex = wxString("#") + hex;
1556 clause->AddAttributeValueString("brush_colour", hex);
1557 }
1558 else if (brushColour != "WHITE")
1559 clause->AddAttributeValueString("brush_colour", brushColour);
1560
1561 if (m_brush->GetStyle() != wxSOLID)
1562 clause->AddAttributeValue("brush_style", (long)m_brush->GetStyle());
1563 }
1564
1565 // Output line ids
1566
1567 int n_lines = m_lines.Number();
1568 if (n_lines > 0)
1569 {
1570 wxExpr *list = new wxExpr(PrologList);
1571 wxNode *node = m_lines.First();
1572 while (node)
1573 {
1574 wxShape *line = (wxShape *)node->Data();
1575 wxExpr *id_expr = new wxExpr(line->GetId());
1576 list->Append(id_expr);
1577 node = node->Next();
1578 }
1579 clause->AddAttributeValue("arcs", list);
1580 }
1581
1582 // Miscellaneous members
1583 if (m_attachmentMode != 0)
1584 clause->AddAttributeValue("use_attachments", (long)m_attachmentMode);
1585 if (m_sensitivity != OP_ALL)
1586 clause->AddAttributeValue("sensitivity", (long)m_sensitivity);
1587 if (!m_spaceAttachments)
1588 clause->AddAttributeValue("space_attachments", (long)m_spaceAttachments);
1589 if (m_fixedWidth)
1590 clause->AddAttributeValue("fixed_width", (long)m_fixedWidth);
1591 if (m_fixedHeight)
1592 clause->AddAttributeValue("fixed_height", (long)m_fixedHeight);
1593 if (m_shadowMode != SHADOW_NONE)
1594 clause->AddAttributeValue("shadow_mode", (long)m_shadowMode);
1595 if (m_centreResize != TRUE)
1596 clause->AddAttributeValue("centre_resize", (long)0);
1597 if (m_highlighted != FALSE)
1598 clause->AddAttributeValue("hilite", (long)m_highlighted);
1599
1600 if (m_parent) // For composite objects
1601 clause->AddAttributeValue("parent", (long)m_parent->GetId());
1602
1603 if (m_rotation != 0.0)
1604 clause->AddAttributeValue("rotation", m_rotation);
1605
1606 // Write user-defined attachment points, if any
1607 if (m_attachmentPoints.Number() > 0)
1608 {
1609 wxExpr *attachmentList = new wxExpr(PrologList);
1610 wxNode *node = m_attachmentPoints.First();
1611 while (node)
1612 {
1613 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
1614 wxExpr *pointExpr = new wxExpr(PrologList);
1615 pointExpr->Append(new wxExpr((long)point->m_id));
1616 pointExpr->Append(new wxExpr(point->m_x));
1617 pointExpr->Append(new wxExpr(point->m_y));
1618 attachmentList->Append(pointExpr);
1619 node = node->Next();
1620 }
1621 clause->AddAttributeValue("user_attachments", attachmentList);
1622 }
1623
1624 // Write text regions
1625 WriteRegions(clause);
1626 }
1627
1628 void wxShape::WriteRegions(wxExpr *clause)
1629 {
1630 // Output regions as region1 = (...), region2 = (...), etc
1631 // and formatted text as text1 = (...), text2 = (...) etc.
1632 int regionNo = 1;
1633 char regionNameBuf[20];
1634 char textNameBuf[20];
1635 wxNode *node = m_regions.First();
1636 while (node)
1637 {
1638 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1639 sprintf(regionNameBuf, "region%d", regionNo);
1640 sprintf(textNameBuf, "text%d", regionNo);
1641
1642 // Original text and region attributes:
1643 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1644 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1645 wxExpr *regionExpr = new wxExpr(PrologList);
1646 regionExpr->Append(new wxExpr(PrologString, (region->m_regionName ? region->m_regionName : "")));
1647 regionExpr->Append(new wxExpr(PrologString, (region->m_regionText ? region->m_regionText : "")));
1648
1649 regionExpr->Append(new wxExpr(region->m_x));
1650 regionExpr->Append(new wxExpr(region->m_y));
1651 regionExpr->Append(new wxExpr(region->GetWidth()));
1652 regionExpr->Append(new wxExpr(region->GetHeight()));
1653
1654 regionExpr->Append(new wxExpr(region->m_minWidth));
1655 regionExpr->Append(new wxExpr(region->m_minHeight));
1656 regionExpr->Append(new wxExpr(region->m_regionProportionX));
1657 regionExpr->Append(new wxExpr(region->m_regionProportionY));
1658
1659 regionExpr->Append(new wxExpr((long)region->m_formatMode));
1660
1661 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetPointSize() : 10)));
1662 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetFamily() : wxDEFAULT)));
1663 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetStyle() : wxDEFAULT)));
1664 regionExpr->Append(new wxExpr((long)(region->m_font ? region->m_font->GetWeight() : wxNORMAL)));
1665 regionExpr->Append(new wxExpr(PrologString, region->m_textColour ? region->m_textColour : "BLACK"));
1666
1667 // New members for pen colour/style
1668 regionExpr->Append(new wxExpr(PrologString, region->m_penColour ? region->m_penColour : "BLACK"));
1669 regionExpr->Append(new wxExpr((long)region->m_penStyle));
1670
1671 // Formatted text:
1672 // text1 = ((x y string) (x y string) ...)
1673 wxExpr *textExpr = new wxExpr(PrologList);
1674
1675 wxNode *textNode = region->m_formattedText.First();
1676 while (textNode)
1677 {
1678 wxShapeTextLine *line = (wxShapeTextLine *)textNode->Data();
1679 wxExpr *list2 = new wxExpr(PrologList);
1680 list2->Append(new wxExpr(line->GetX()));
1681 list2->Append(new wxExpr(line->GetY()));
1682 list2->Append(new wxExpr(PrologString, line->GetText()));
1683 textExpr->Append(list2);
1684 textNode = textNode->Next();
1685 }
1686
1687 // Now add both attributes to the clause
1688 clause->AddAttributeValue(regionNameBuf, regionExpr);
1689 clause->AddAttributeValue(textNameBuf, textExpr);
1690
1691 node = node->Next();
1692 regionNo ++;
1693 }
1694 }
1695
1696 void wxShape::ReadPrologAttributes(wxExpr *clause)
1697 {
1698 clause->GetAttributeValue("id", m_id);
1699 RegisterId(m_id);
1700
1701 clause->GetAttributeValue("x", m_xpos);
1702 clause->GetAttributeValue("y", m_ypos);
1703
1704 // Input text strings (FOR COMPATIBILITY WITH OLD FILES ONLY. SEE REGION CODE BELOW.)
1705 ClearText();
1706 wxExpr *strings = clause->AttributeValue("text");
1707 if (strings && strings->Type() == PrologList)
1708 {
1709 m_formatted = TRUE; // Assume text is formatted unless we prove otherwise
1710 wxExpr *node = strings->value.first;
1711 while (node)
1712 {
1713 wxExpr *string_expr = node;
1714 float the_x = 0.0;
1715 float the_y = 0.0;
1716 wxString the_string("");
1717
1718 // string_expr can either be a string, or a list of
1719 // 3 elements: x, y, and string.
1720 if (string_expr->Type() == PrologString)
1721 {
1722 the_string = string_expr->StringValue();
1723 m_formatted = FALSE;
1724 }
1725 else if (string_expr->Type() == PrologList)
1726 {
1727 wxExpr *first = string_expr->value.first;
1728 wxExpr *second = first ? first->next : NULL;
1729 wxExpr *third = second ? second->next : NULL;
1730
1731 if (first && second && third &&
1732 (first->Type() == PrologReal || first->Type() == PrologInteger) &&
1733 (second->Type() == PrologReal || second->Type() == PrologInteger) &&
1734 third->Type() == PrologString)
1735 {
1736 if (first->Type() == PrologReal)
1737 the_x = first->RealValue();
1738 else the_x = (float)first->IntegerValue();
1739
1740 if (second->Type() == PrologReal)
1741 the_y = second->RealValue();
1742 else the_y = (float)second->IntegerValue();
1743
1744 the_string = third->StringValue();
1745 }
1746 }
1747 wxShapeTextLine *line =
1748 new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string);
1749 m_text.Append(line);
1750
1751 node = node->next;
1752 }
1753 }
1754
1755 wxString pen_string = "";
1756 wxString brush_string = "";
1757 int pen_width = 1;
1758 int pen_style = wxSOLID;
1759 int brush_style = wxSOLID;
1760 m_attachmentMode = FALSE;
1761
1762 clause->GetAttributeValue("pen_colour", pen_string);
1763 clause->GetAttributeValue("text_colour", m_textColourName);
1764
1765 SetTextColour(m_textColourName);
1766
1767 clause->GetAttributeValue("region_name", m_regionName);
1768
1769 clause->GetAttributeValue("brush_colour", brush_string);
1770 clause->GetAttributeValue("pen_width", pen_width);
1771 clause->GetAttributeValue("pen_style", pen_style);
1772 clause->GetAttributeValue("brush_style", brush_style);
1773
1774 int iVal = (int) m_attachmentMode;
1775 clause->GetAttributeValue("use_attachments", iVal);
1776 m_attachmentMode = (iVal != 0);
1777
1778 clause->GetAttributeValue("sensitivity", m_sensitivity);
1779
1780 iVal = (int) m_spaceAttachments;
1781 clause->GetAttributeValue("space_attachments", iVal);
1782 m_spaceAttachments = (iVal != 0);
1783
1784 iVal = (int) m_fixedWidth;
1785 clause->GetAttributeValue("fixed_width", iVal);
1786 m_fixedWidth = (iVal != 0);
1787
1788 iVal = (int) m_fixedHeight;
1789 clause->GetAttributeValue("fixed_height", iVal);
1790 m_fixedHeight = (iVal != 0);
1791
1792 clause->GetAttributeValue("format_mode", m_formatMode);
1793 clause->GetAttributeValue("shadow_mode", m_shadowMode);
1794
1795 iVal = (int) m_centreResize;
1796 clause->GetAttributeValue("centre_resize", iVal);
1797 m_centreResize = (iVal != 0);
1798
1799 iVal = (int) m_highlighted;
1800 clause->GetAttributeValue("hilite", iVal);
1801 m_highlighted = (iVal != 0);
1802
1803 clause->GetAttributeValue("rotation", m_rotation);
1804
1805 if (pen_string == "")
1806 pen_string = "BLACK";
1807 if (brush_string == "")
1808 brush_string = "WHITE";
1809
1810 if (pen_string[0] == '#')
1811 {
1812 wxColour col(oglHexToColour(pen_string.After('#')));
1813 m_pen = wxThePenList->FindOrCreatePen(col, pen_width, pen_style);
1814 }
1815 else
1816 m_pen = wxThePenList->FindOrCreatePen(pen_string, pen_width, pen_style);
1817
1818 if (!m_pen)
1819 m_pen = wxBLACK_PEN;
1820
1821 if (brush_string[0] == '#')
1822 {
1823 wxColour col(oglHexToColour(brush_string.After('#')));
1824 m_brush = wxTheBrushList->FindOrCreateBrush(col, brush_style);
1825 }
1826 else
1827 m_brush = wxTheBrushList->FindOrCreateBrush(brush_string, brush_style);
1828
1829 if (!m_brush)
1830 m_brush = wxWHITE_BRUSH;
1831
1832 int point_size = 10;
1833 clause->GetAttributeValue("point_size", point_size);
1834 SetFont(MatchFont(point_size));
1835
1836 // Read user-defined attachment points, if any
1837 wxExpr *attachmentList = clause->AttributeValue("user_attachments");
1838 if (attachmentList)
1839 {
1840 wxExpr *pointExpr = attachmentList->GetFirst();
1841 while (pointExpr)
1842 {
1843 wxExpr *idExpr = pointExpr->Nth(0);
1844 wxExpr *xExpr = pointExpr->Nth(1);
1845 wxExpr *yExpr = pointExpr->Nth(2);
1846 if (idExpr && xExpr && yExpr)
1847 {
1848 wxAttachmentPoint *point = new wxAttachmentPoint;
1849 point->m_id = (int)idExpr->IntegerValue();
1850 point->m_x = xExpr->RealValue();
1851 point->m_y = yExpr->RealValue();
1852 m_attachmentPoints.Append((wxObject *)point);
1853 }
1854 pointExpr = pointExpr->GetNext();
1855 }
1856 }
1857
1858 // Read text regions
1859 ReadRegions(clause);
1860 }
1861
1862 void wxShape::ReadRegions(wxExpr *clause)
1863 {
1864 ClearRegions();
1865
1866 // region1 = (regionName regionText x y width height minWidth minHeight proportionX proportionY
1867 // formatMode fontSize fontFamily fontStyle fontWeight textColour)
1868 int regionNo = 1;
1869 char regionNameBuf[20];
1870 char textNameBuf[20];
1871
1872 wxExpr *regionExpr = NULL;
1873 wxExpr *textExpr = NULL;
1874 sprintf(regionNameBuf, "region%d", regionNo);
1875 sprintf(textNameBuf, "text%d", regionNo);
1876
1877 m_formatted = TRUE; // Assume text is formatted unless we prove otherwise
1878
1879 while (regionExpr = clause->AttributeValue(regionNameBuf))
1880 {
1881 /*
1882 * Get the region information
1883 *
1884 */
1885
1886 wxString regionName("");
1887 wxString regionText("");
1888 float x = 0.0;
1889 float y = 0.0;
1890 float width = 0.0;
1891 float height = 0.0;
1892 float minWidth = 5.0;
1893 float minHeight = 5.0;
1894 float m_regionProportionX = -1.0;
1895 float m_regionProportionY = -1.0;
1896 int formatMode = FORMAT_NONE;
1897 int fontSize = 10;
1898 int fontFamily = wxSWISS;
1899 int fontStyle = wxNORMAL;
1900 int fontWeight = wxNORMAL;
1901 wxString regionTextColour("");
1902 wxString penColour("");
1903 int penStyle = wxSOLID;
1904
1905 if (regionExpr->Type() == PrologList)
1906 {
1907 wxExpr *nameExpr = regionExpr->Nth(0);
1908 wxExpr *textExpr = regionExpr->Nth(1);
1909 wxExpr *xExpr = regionExpr->Nth(2);
1910 wxExpr *yExpr = regionExpr->Nth(3);
1911 wxExpr *widthExpr = regionExpr->Nth(4);
1912 wxExpr *heightExpr = regionExpr->Nth(5);
1913 wxExpr *minWidthExpr = regionExpr->Nth(6);
1914 wxExpr *minHeightExpr = regionExpr->Nth(7);
1915 wxExpr *propXExpr = regionExpr->Nth(8);
1916 wxExpr *propYExpr = regionExpr->Nth(9);
1917 wxExpr *formatExpr = regionExpr->Nth(10);
1918 wxExpr *sizeExpr = regionExpr->Nth(11);
1919 wxExpr *familyExpr = regionExpr->Nth(12);
1920 wxExpr *styleExpr = regionExpr->Nth(13);
1921 wxExpr *weightExpr = regionExpr->Nth(14);
1922 wxExpr *colourExpr = regionExpr->Nth(15);
1923 wxExpr *penColourExpr = regionExpr->Nth(16);
1924 wxExpr *penStyleExpr = regionExpr->Nth(17);
1925
1926 regionName = nameExpr->StringValue();
1927 regionText = textExpr->StringValue();
1928
1929 x = xExpr->RealValue();
1930 y = yExpr->RealValue();
1931
1932 width = widthExpr->RealValue();
1933 height = heightExpr->RealValue();
1934
1935 minWidth = minWidthExpr->RealValue();
1936 minHeight = minHeightExpr->RealValue();
1937
1938 m_regionProportionX = propXExpr->RealValue();
1939 m_regionProportionY = propYExpr->RealValue();
1940
1941 formatMode = (int) formatExpr->IntegerValue();
1942 fontSize = (int)sizeExpr->IntegerValue();
1943 fontFamily = (int)familyExpr->IntegerValue();
1944 fontStyle = (int)styleExpr->IntegerValue();
1945 fontWeight = (int)weightExpr->IntegerValue();
1946
1947 if (colourExpr)
1948 {
1949 regionTextColour = colourExpr->StringValue();
1950 }
1951 else
1952 regionTextColour = "BLACK";
1953
1954 if (penColourExpr)
1955 penColour = penColourExpr->StringValue();
1956 if (penStyleExpr)
1957 penStyle = (int)penStyleExpr->IntegerValue();
1958 }
1959 wxFont *font = wxTheFontList->FindOrCreateFont(fontSize, fontFamily, fontStyle, fontWeight);
1960
1961 wxShapeRegion *region = new wxShapeRegion;
1962 region->SetProportions(m_regionProportionX, m_regionProportionY);
1963 region->SetFont(font);
1964 region->SetSize(width, height);
1965 region->SetPosition(x, y);
1966 region->SetMinSize(minWidth, minHeight);
1967 region->SetFormatMode(formatMode);
1968 region->SetPenStyle(penStyle);
1969 if (penColour != "")
1970 region->SetPenColour(penColour);
1971
1972 region->m_textColour = regionTextColour;
1973 region->m_regionText = regionText;
1974 region->m_regionName = regionName;
1975
1976 m_regions.Append(region);
1977
1978 /*
1979 * Get the formatted text strings
1980 *
1981 */
1982 textExpr = clause->AttributeValue(textNameBuf);
1983 if (textExpr && (textExpr->Type() == PrologList))
1984 {
1985 wxExpr *node = textExpr->value.first;
1986 while (node)
1987 {
1988 wxExpr *string_expr = node;
1989 float the_x = 0.0;
1990 float the_y = 0.0;
1991 wxString the_string("");
1992
1993 // string_expr can either be a string, or a list of
1994 // 3 elements: x, y, and string.
1995 if (string_expr->Type() == PrologString)
1996 {
1997 the_string = string_expr->StringValue();
1998 m_formatted = FALSE;
1999 }
2000 else if (string_expr->Type() == PrologList)
2001 {
2002 wxExpr *first = string_expr->value.first;
2003 wxExpr *second = first ? first->next : NULL;
2004 wxExpr *third = second ? second->next : NULL;
2005
2006 if (first && second && third &&
2007 (first->Type() == PrologReal || first->Type() == PrologInteger) &&
2008 (second->Type() == PrologReal || second->Type() == PrologInteger) &&
2009 third->Type() == PrologString)
2010 {
2011 if (first->Type() == PrologReal)
2012 the_x = first->RealValue();
2013 else the_x = (float)first->IntegerValue();
2014
2015 if (second->Type() == PrologReal)
2016 the_y = second->RealValue();
2017 else the_y = (float)second->IntegerValue();
2018
2019 the_string = third->StringValue();
2020 }
2021 }
2022 if (the_string)
2023 {
2024 wxShapeTextLine *line =
2025 new wxShapeTextLine(the_x, the_y, (char*) (const char*) the_string);
2026 region->m_formattedText.Append(line);
2027 }
2028 node = node->next;
2029 }
2030 }
2031
2032 regionNo ++;
2033 sprintf(regionNameBuf, "region%d", regionNo);
2034 sprintf(textNameBuf, "text%d", regionNo);
2035 }
2036
2037 // Compatibility: check for no regions (old file).
2038 // Lines and divided rectangles must deal with this compatibility
2039 // theirselves. Composites _may_ not have any regions anyway.
2040 if ((m_regions.Number() == 0) &&
2041 !this->IsKindOf(CLASSINFO(wxLineShape)) && !this->IsKindOf(CLASSINFO(wxDividedShape)) &&
2042 !this->IsKindOf(CLASSINFO(wxCompositeShape)))
2043 {
2044 wxShapeRegion *newRegion = new wxShapeRegion;
2045 newRegion->SetName("0");
2046 m_regions.Append((wxObject *)newRegion);
2047 if (m_text.Number() > 0)
2048 {
2049 newRegion->ClearText();
2050 wxNode *node = m_text.First();
2051 while (node)
2052 {
2053 wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data();
2054 wxNode *next = node->Next();
2055 newRegion->GetFormattedText().Append((wxObject *)textLine);
2056 delete node;
2057 node = next;
2058 }
2059 }
2060 }
2061 }
2062
2063 #endif
2064
2065 void wxShape::Copy(wxShape& copy)
2066 {
2067 copy.m_id = m_id;
2068 copy.m_xpos = m_xpos;
2069 copy.m_ypos = m_ypos;
2070 copy.m_pen = m_pen;
2071 copy.m_brush = m_brush;
2072 copy.m_textColour = m_textColour;
2073 copy.m_centreResize = m_centreResize;
2074 copy.m_attachmentMode = m_attachmentMode;
2075 copy.m_spaceAttachments = m_spaceAttachments;
2076 copy.m_highlighted = m_highlighted;
2077 copy.m_rotation = m_rotation;
2078 copy.m_textColourName = m_textColourName;
2079 copy.m_regionName = m_regionName;
2080
2081 copy.m_sensitivity = m_sensitivity;
2082 copy.m_draggable = m_draggable;
2083 copy.m_fixedWidth = m_fixedWidth;
2084 copy.m_fixedHeight = m_fixedHeight;
2085 copy.m_formatMode = m_formatMode;
2086 copy.m_drawHandles = m_drawHandles;
2087
2088 copy.m_visible = m_visible;
2089 copy.m_shadowMode = m_shadowMode;
2090 copy.m_shadowOffsetX = m_shadowOffsetX;
2091 copy.m_shadowOffsetY = m_shadowOffsetY;
2092 copy.m_shadowBrush = m_shadowBrush;
2093
2094 // Copy text regions
2095 copy.ClearRegions();
2096 wxNode *node = m_regions.First();
2097 while (node)
2098 {
2099 wxShapeRegion *region = (wxShapeRegion *)node->Data();
2100 wxShapeRegion *newRegion = new wxShapeRegion(*region);
2101 copy.m_regions.Append(newRegion);
2102 node = node->Next();
2103 }
2104
2105 // Copy attachments
2106 copy.ClearAttachments();
2107 node = m_attachmentPoints.First();
2108 while (node)
2109 {
2110 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2111 wxAttachmentPoint *newPoint = new wxAttachmentPoint;
2112 newPoint->m_id = point->m_id;
2113 newPoint->m_x = point->m_x;
2114 newPoint->m_y = point->m_y;
2115 copy.m_attachmentPoints.Append((wxObject *)newPoint);
2116 node = node->Next();
2117 }
2118 }
2119
2120 // Create and return a new, fully copied object.
2121 wxShape *wxShape::CreateNewCopy(bool resetMapping, bool recompute)
2122 {
2123 if (resetMapping)
2124 wxObjectCopyMapping.Clear();
2125
2126 wxShape* newObject = (wxShape*) GetClassInfo()->CreateObject();
2127
2128 wxASSERT( (newObject != NULL) );
2129 wxASSERT( (newObject->IsKindOf(CLASSINFO(wxShape))) );
2130
2131 Copy(*newObject);
2132
2133 if (GetEventHandler() != this)
2134 {
2135 wxShapeEvtHandler* newHandler = GetEventHandler()->CreateNewCopy();
2136 newObject->SetEventHandler(newHandler);
2137 newObject->SetPreviousHandler(NULL);
2138 newHandler->SetPreviousHandler(newObject);
2139 newHandler->SetShape(newObject);
2140 }
2141
2142 if (recompute)
2143 newObject->Recompute();
2144 return newObject;
2145 }
2146
2147 // Does the copying for this object, including copying event
2148 // handler data if any. Calls the virtual Copy function.
2149 void wxShape::CopyWithHandler(wxShape& copy)
2150 {
2151 Copy(copy);
2152
2153 if (GetEventHandler() != this)
2154 {
2155 wxASSERT( copy.GetEventHandler() != NULL );
2156 wxASSERT( copy.GetEventHandler() != (&copy) );
2157 wxASSERT( GetEventHandler()->GetClassInfo() == copy.GetEventHandler()->GetClassInfo() );
2158 GetEventHandler()->CopyData(* (copy.GetEventHandler()));
2159 }
2160 }
2161
2162
2163 // Default - make 6 control points
2164 void wxShape::MakeControlPoints()
2165 {
2166 float maxX, maxY, minX, minY;
2167
2168 GetBoundingBoxMax(&maxX, &maxY);
2169 GetBoundingBoxMin(&minX, &minY);
2170
2171 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
2172 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
2173
2174 // Offsets from main object
2175 float top = (float)(- (heightMin / 2.0));
2176 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
2177 float left = (float)(- (widthMin / 2.0));
2178 float right = (float)(widthMin / 2.0 + (maxX - minX));
2179
2180 wxControlPoint *control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, top,
2181 CONTROL_POINT_DIAGONAL);
2182 m_canvas->AddShape(control);
2183 m_controlPoints.Append(control);
2184
2185 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, top,
2186 CONTROL_POINT_VERTICAL);
2187 m_canvas->AddShape(control);
2188 m_controlPoints.Append(control);
2189
2190 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, top,
2191 CONTROL_POINT_DIAGONAL);
2192 m_canvas->AddShape(control);
2193 m_controlPoints.Append(control);
2194
2195 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, 0,
2196 CONTROL_POINT_HORIZONTAL);
2197 m_canvas->AddShape(control);
2198 m_controlPoints.Append(control);
2199
2200 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, right, bottom,
2201 CONTROL_POINT_DIAGONAL);
2202 m_canvas->AddShape(control);
2203 m_controlPoints.Append(control);
2204
2205 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, 0, bottom,
2206 CONTROL_POINT_VERTICAL);
2207 m_canvas->AddShape(control);
2208 m_controlPoints.Append(control);
2209
2210 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, bottom,
2211 CONTROL_POINT_DIAGONAL);
2212 m_canvas->AddShape(control);
2213 m_controlPoints.Append(control);
2214
2215 control = new wxControlPoint(m_canvas, this, CONTROL_POINT_SIZE, left, 0,
2216 CONTROL_POINT_HORIZONTAL);
2217 m_canvas->AddShape(control);
2218 m_controlPoints.Append(control);
2219
2220 }
2221
2222 void wxShape::MakeMandatoryControlPoints()
2223 {
2224 wxNode *node = m_children.First();
2225 while (node)
2226 {
2227 wxShape *child = (wxShape *)node->Data();
2228 child->MakeMandatoryControlPoints();
2229 node = node->Next();
2230 }
2231 }
2232
2233 void wxShape::ResetMandatoryControlPoints()
2234 {
2235 wxNode *node = m_children.First();
2236 while (node)
2237 {
2238 wxShape *child = (wxShape *)node->Data();
2239 child->ResetMandatoryControlPoints();
2240 node = node->Next();
2241 }
2242 }
2243
2244 void wxShape::ResetControlPoints()
2245 {
2246 ResetMandatoryControlPoints();
2247
2248 if (m_controlPoints.Number() < 1)
2249 return;
2250
2251 float maxX, maxY, minX, minY;
2252
2253 GetBoundingBoxMax(&maxX, &maxY);
2254 GetBoundingBoxMin(&minX, &minY);
2255
2256 float widthMin = (float)(minX + CONTROL_POINT_SIZE + 2);
2257 float heightMin = (float)(minY + CONTROL_POINT_SIZE + 2);
2258
2259 // Offsets from main object
2260 float top = (float)(- (heightMin / 2.0));
2261 float bottom = (float)(heightMin / 2.0 + (maxY - minY));
2262 float left = (float)(- (widthMin / 2.0));
2263 float right = (float)(widthMin / 2.0 + (maxX - minX));
2264
2265 wxNode *node = m_controlPoints.First();
2266 wxControlPoint *control = (wxControlPoint *)node->Data();
2267 control->m_xoffset = left; control->m_yoffset = top;
2268
2269 node = node->Next(); control = (wxControlPoint *)node->Data();
2270 control->m_xoffset = 0; control->m_yoffset = top;
2271
2272 node = node->Next(); control = (wxControlPoint *)node->Data();
2273 control->m_xoffset = right; control->m_yoffset = top;
2274
2275 node = node->Next(); control = (wxControlPoint *)node->Data();
2276 control->m_xoffset = right; control->m_yoffset = 0;
2277
2278 node = node->Next(); control = (wxControlPoint *)node->Data();
2279 control->m_xoffset = right; control->m_yoffset = bottom;
2280
2281 node = node->Next(); control = (wxControlPoint *)node->Data();
2282 control->m_xoffset = 0; control->m_yoffset = bottom;
2283
2284 node = node->Next(); control = (wxControlPoint *)node->Data();
2285 control->m_xoffset = left; control->m_yoffset = bottom;
2286
2287 node = node->Next(); control = (wxControlPoint *)node->Data();
2288 control->m_xoffset = left; control->m_yoffset = 0;
2289 }
2290
2291 void wxShape::DeleteControlPoints(wxDC *dc)
2292 {
2293 wxNode *node = m_controlPoints.First();
2294 while (node)
2295 {
2296 wxControlPoint *control = (wxControlPoint *)node->Data();
2297 if (dc)
2298 control->GetEventHandler()->OnErase(*dc);
2299 m_canvas->RemoveShape(control);
2300 delete control;
2301 delete node;
2302 node = m_controlPoints.First();
2303 }
2304 // Children of divisions are contained objects,
2305 // so stop here
2306 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2307 {
2308 node = m_children.First();
2309 while (node)
2310 {
2311 wxShape *child = (wxShape *)node->Data();
2312 child->DeleteControlPoints(dc);
2313 node = node->Next();
2314 }
2315 }
2316 }
2317
2318 void wxShape::OnDrawControlPoints(wxDC& dc)
2319 {
2320 if (!m_drawHandles)
2321 return;
2322
2323 dc.SetBrush(wxBLACK_BRUSH);
2324 dc.SetPen(wxBLACK_PEN);
2325
2326 wxNode *node = m_controlPoints.First();
2327 while (node)
2328 {
2329 wxControlPoint *control = (wxControlPoint *)node->Data();
2330 control->Draw(dc);
2331 node = node->Next();
2332 }
2333 // Children of divisions are contained objects,
2334 // so stop here.
2335 // This test bypasses the type facility for speed
2336 // (critical when drawing)
2337 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2338 {
2339 node = m_children.First();
2340 while (node)
2341 {
2342 wxShape *child = (wxShape *)node->Data();
2343 child->GetEventHandler()->OnDrawControlPoints(dc);
2344 node = node->Next();
2345 }
2346 }
2347 }
2348
2349 void wxShape::OnEraseControlPoints(wxDC& dc)
2350 {
2351 wxNode *node = m_controlPoints.First();
2352 while (node)
2353 {
2354 wxControlPoint *control = (wxControlPoint *)node->Data();
2355 control->Erase(dc);
2356 node = node->Next();
2357 }
2358 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2359 {
2360 node = m_children.First();
2361 while (node)
2362 {
2363 wxShape *child = (wxShape *)node->Data();
2364 child->GetEventHandler()->OnEraseControlPoints(dc);
2365 node = node->Next();
2366 }
2367 }
2368 }
2369
2370 void wxShape::Select(bool select, wxDC* dc)
2371 {
2372 m_selected = select;
2373 if (select)
2374 {
2375 MakeControlPoints();
2376 // Children of divisions are contained objects,
2377 // so stop here
2378 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2379 {
2380 wxNode *node = m_children.First();
2381 while (node)
2382 {
2383 wxShape *child = (wxShape *)node->Data();
2384 child->MakeMandatoryControlPoints();
2385 node = node->Next();
2386 }
2387 }
2388 if (dc)
2389 GetEventHandler()->OnDrawControlPoints(*dc);
2390 }
2391 if (!select)
2392 {
2393 DeleteControlPoints(dc);
2394 if (!IsKindOf(CLASSINFO(wxDivisionShape)))
2395 {
2396 wxNode *node = m_children.First();
2397 while (node)
2398 {
2399 wxShape *child = (wxShape *)node->Data();
2400 child->DeleteControlPoints(dc);
2401 node = node->Next();
2402 }
2403 }
2404 }
2405 }
2406
2407 bool wxShape::Selected() const
2408 {
2409 return m_selected;
2410 }
2411
2412 bool wxShape::AncestorSelected() const
2413 {
2414 if (m_selected) return TRUE;
2415 if (!GetParent())
2416 return FALSE;
2417 else
2418 return GetParent()->AncestorSelected();
2419 }
2420
2421 int wxShape::GetNumberOfAttachments()
2422 {
2423 // Should return the MAXIMUM attachment point id here,
2424 // so higher-level functions can iterate through all attachments,
2425 // even if they're not contiguous.
2426 if (m_attachmentPoints.Number() == 0)
2427 return 4;
2428 else
2429 {
2430 int maxN = 3;
2431 wxNode *node = m_attachmentPoints.First();
2432 while (node)
2433 {
2434 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2435 if (point->m_id > maxN)
2436 maxN = point->m_id;
2437 node = node->Next();
2438 }
2439 return maxN+1;;
2440 }
2441 }
2442
2443 bool wxShape::AttachmentIsValid(int attachment)
2444 {
2445 if ((attachment >= 0) && (attachment < 4))
2446 return TRUE;
2447
2448 wxNode *node = m_attachmentPoints.First();
2449 while (node)
2450 {
2451 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2452 if (point->m_id == attachment)
2453 return TRUE;
2454 node = node->Next();
2455 }
2456 return FALSE;
2457 }
2458
2459 bool wxShape::GetAttachmentPosition(int attachment, float *x, float *y,
2460 int nth, int no_arcs, wxLineShape *line)
2461 {
2462 if (!m_attachmentMode)
2463 {
2464 *x = m_xpos; *y = m_ypos;
2465 return TRUE;
2466 }
2467 else
2468 {
2469 wxNode *node = m_attachmentPoints.First();
2470 while (node)
2471 {
2472 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
2473 if (point->m_id == attachment)
2474 {
2475 *x = (float)(m_xpos + point->m_x);
2476 *y = (float)(m_ypos + point->m_y);
2477 return TRUE;
2478 }
2479 node = node->Next();
2480 }
2481 *x = m_xpos; *y = m_ypos;
2482 return FALSE;
2483 }
2484 }
2485
2486 void wxShape::GetBoundingBoxMax(float *w, float *h)
2487 {
2488 float ww, hh;
2489 GetBoundingBoxMin(&ww, &hh);
2490 if (m_shadowMode != SHADOW_NONE)
2491 {
2492 ww += m_shadowOffsetX;
2493 hh += m_shadowOffsetY;
2494 }
2495 *w = ww;
2496 *h = hh;
2497 }
2498
2499 // Returns TRUE if image is a descendant of this composite
2500 bool wxShape::HasDescendant(wxShape *image)
2501 {
2502 if (image == this)
2503 return TRUE;
2504 wxNode *node = m_children.First();
2505 while (node)
2506 {
2507 wxShape *child = (wxShape *)node->Data();
2508 bool ans = child->HasDescendant(image);
2509 if (ans)
2510 return TRUE;
2511 node = node->Next();
2512 }
2513 return FALSE;
2514 }
2515
2516 // Clears points from a list of wxRealPoints, and clears list
2517 void wxShape::ClearPointList(wxList& list)
2518 {
2519 wxNode* node = list.First();
2520 while (node)
2521 {
2522 wxRealPoint* pt = (wxRealPoint*) node->Data();
2523 delete pt;
2524
2525 node = node->Next();
2526 }
2527 list.Clear();
2528 }
2529