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