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