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