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