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