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