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