]> git.saurik.com Git - wxWidgets.git/blame - utils/ogl/src/lines.cpp
Rewrote wxRadioBox (recompile)
[wxWidgets.git] / utils / ogl / src / lines.cpp
CommitLineData
0fc1a713
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: lines.cpp
3// Purpose: wxLineShape
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 "lines.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 <ctype.h>
38#include <math.h>
39
40#include "basic.h"
41#include "basicp.h"
42#include "lines.h"
43#include "linesp.h"
44#include "drawn.h"
45#include "misc.h"
46#include "canvas.h"
47
48// Line shape
49IMPLEMENT_DYNAMIC_CLASS(wxLineShape, wxShape)
50
51wxLineShape::wxLineShape()
52{
53 m_sensitivity = OP_CLICK_LEFT | OP_CLICK_RIGHT;
54 m_draggable = FALSE;
55 m_attachmentTo = 0;
56 m_attachmentFrom = 0;
57/*
58 m_actualTextWidth = 0.0;
59 m_actualTextHeight = 0.0;
60*/
61 m_from = NULL;
62 m_to = NULL;
63 m_erasing = FALSE;
64 m_arrowSpacing = 5.0; // For the moment, don't bother saving this to file.
65 m_ignoreArrowOffsets = FALSE;
66 m_isSpline = FALSE;
67 m_maintainStraightLines = FALSE;
68 m_alignmentStart = 0;
69 m_alignmentEnd = 0;
70
71 m_lineControlPoints = NULL;
72
73 // Clear any existing regions (created in an earlier constructor)
74 // and make the three line regions.
75 ClearRegions();
76 wxShapeRegion *newRegion = new wxShapeRegion;
77 newRegion->SetName("Middle");
78 newRegion->SetSize(150, 50);
79 m_regions.Append((wxObject *)newRegion);
80
81 newRegion = new wxShapeRegion;
82 newRegion->SetName("Start");
83 newRegion->SetSize(150, 50);
84 m_regions.Append((wxObject *)newRegion);
85
86 newRegion = new wxShapeRegion;
87 newRegion->SetName("End");
88 newRegion->SetSize(150, 50);
89 m_regions.Append((wxObject *)newRegion);
90
91 for (int i = 0; i < 3; i++)
92 m_labelObjects[i] = NULL;
93}
94
95wxLineShape::~wxLineShape()
96{
97 if (m_lineControlPoints)
98 {
99 ClearPointList(*m_lineControlPoints);
100 delete m_lineControlPoints;
101 }
102 for (int i = 0; i < 3; i++)
103 {
104 if (m_labelObjects[i])
105 {
106 m_labelObjects[i]->Select(FALSE);
107 m_labelObjects[i]->RemoveFromCanvas(m_canvas);
108 delete m_labelObjects[i];
109 m_labelObjects[i] = NULL;
110 }
111 }
5de76427 112 ClearArrowsAtPosition(-1);
0fc1a713
JS
113}
114
115void wxLineShape::MakeLineControlPoints(int n)
116{
117 if (m_lineControlPoints)
118 {
119 ClearPointList(*m_lineControlPoints);
120 delete m_lineControlPoints;
121 }
122 m_lineControlPoints = new wxList;
123
124 int i = 0;
125 for (i = 0; i < n; i++)
126 {
127 wxRealPoint *point = new wxRealPoint(-999, -999);
128 m_lineControlPoints->Append((wxObject*) point);
129 }
130}
131
132wxNode *wxLineShape::InsertLineControlPoint(wxDC* dc)
133{
134 if (dc)
135 Erase(*dc);
136
137 wxNode *last = m_lineControlPoints->Last();
138 wxNode *second_last = last->Previous();
139 wxRealPoint *last_point = (wxRealPoint *)last->Data();
140 wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data();
141
142 // Choose a point half way between the last and penultimate points
42cfaf8c
JS
143 double line_x = ((last_point->x + second_last_point->x)/2);
144 double line_y = ((last_point->y + second_last_point->y)/2);
0fc1a713
JS
145
146 wxRealPoint *point = new wxRealPoint(line_x, line_y);
147 wxNode *node = m_lineControlPoints->Insert(last, (wxObject*) point);
148 return node;
149}
150
151bool wxLineShape::DeleteLineControlPoint()
152{
153 if (m_lineControlPoints->Number() < 3)
154 return FALSE;
155
156 wxNode *last = m_lineControlPoints->Last();
157 wxNode *second_last = last->Previous();
158
159 wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data();
160 delete second_last_point;
161 delete second_last;
162
163 return TRUE;
164}
165
166void wxLineShape::Initialise()
167{
168 if (m_lineControlPoints)
169 {
170 // Just move the first and last control points
171 wxNode *first = m_lineControlPoints->First();
172 wxRealPoint *first_point = (wxRealPoint *)first->Data();
173
174 wxNode *last = m_lineControlPoints->Last();
175 wxRealPoint *last_point = (wxRealPoint *)last->Data();
176
177 // If any of the line points are at -999, we must
178 // initialize them by placing them half way between the first
179 // and the last.
180 wxNode *node = first->Next();
181 while (node)
182 {
183 wxRealPoint *point = (wxRealPoint *)node->Data();
184 if (point->x == -999)
185 {
42cfaf8c 186 double x1, y1, x2, y2;
0fc1a713
JS
187 if (first_point->x < last_point->x)
188 { x1 = first_point->x; x2 = last_point->x; }
189 else
190 { x2 = first_point->x; x1 = last_point->x; }
191
192 if (first_point->y < last_point->y)
193 { y1 = first_point->y; y2 = last_point->y; }
194 else
195 { y2 = first_point->y; y1 = last_point->y; }
196
197 point->x = ((x2 - x1)/2 + x1);
198 point->y = ((y2 - y1)/2 + y1);
199 }
200 node = node->Next();
201 }
202 }
203}
204
205// Format a text string according to the region size, adding
206// strings with positions to region text list
207void wxLineShape::FormatText(wxDC& dc, const wxString& s, int i)
208{
42cfaf8c 209 double w, h;
0fc1a713
JS
210 ClearText(i);
211
212 if (m_regions.Number() < 1)
213 return;
214 wxNode *node = m_regions.Nth(i);
215 if (!node)
216 return;
217
218 wxShapeRegion *region = (wxShapeRegion *)node->Data();
219 region->SetText(s);
220 dc.SetFont(region->GetFont());
221
222 region->GetSize(&w, &h);
223 // Initialize the size if zero
224 if (((w == 0) || (h == 0)) && (strlen(s) > 0))
225 {
226 w = 100; h = 50;
227 region->SetSize(w, h);
228 }
229
42cfaf8c 230 wxStringList *string_list = oglFormatText(dc, s, (w-5), (h-5), region->GetFormatMode());
0fc1a713
JS
231 node = string_list->First();
232 while (node)
233 {
234 char *s = (char *)node->Data();
235 wxShapeTextLine *line = new wxShapeTextLine(0.0, 0.0, s);
236 region->GetFormattedText().Append((wxObject *)line);
42cfaf8c 237 node = node->Next();
0fc1a713
JS
238 }
239 delete string_list;
42cfaf8c
JS
240 double actualW = w;
241 double actualH = h;
0fc1a713
JS
242 if (region->GetFormatMode() & FORMAT_SIZE_TO_CONTENTS)
243 {
42cfaf8c 244 oglGetCentredTextExtent(dc, &(region->GetFormattedText()), m_xpos, m_ypos, w, h, &actualW, &actualH);
0fc1a713
JS
245 if ((actualW != w ) || (actualH != h))
246 {
42cfaf8c 247 double xx, yy;
0fc1a713
JS
248 GetLabelPosition(i, &xx, &yy);
249 EraseRegion(dc, region, xx, yy);
250 if (m_labelObjects[i])
251 {
2e5ed787 252 m_labelObjects[i]->Select(FALSE, &dc);
0fc1a713
JS
253 m_labelObjects[i]->Erase(dc);
254 m_labelObjects[i]->SetSize(actualW, actualH);
255 }
256
257 region->SetSize(actualW, actualH);
258
259 if (m_labelObjects[i])
260 {
261 m_labelObjects[i]->Select(TRUE, & dc);
262 m_labelObjects[i]->Draw(dc);
263 }
264 }
265 }
42cfaf8c 266 oglCentreText(dc, &(region->GetFormattedText()), m_xpos, m_ypos, actualW, actualH, region->GetFormatMode());
0fc1a713
JS
267 m_formatted = TRUE;
268}
269
42cfaf8c 270void wxLineShape::DrawRegion(wxDC& dc, wxShapeRegion *region, double x, double y)
0fc1a713
JS
271{
272 if (GetDisableLabel())
273 return;
274
42cfaf8c
JS
275 double w, h;
276 double xx, yy;
0fc1a713
JS
277 region->GetSize(&w, &h);
278
279 // Get offset from x, y
280 region->GetPosition(&xx, &yy);
281
42cfaf8c
JS
282 double xp = xx + x;
283 double yp = yy + y;
0fc1a713
JS
284
285 // First, clear a rectangle for the text IF there is any
286 if (region->GetFormattedText().Number() > 0)
287 {
42cfaf8c
JS
288 dc.SetPen(g_oglWhiteBackgroundPen);
289 dc.SetBrush(g_oglWhiteBackgroundBrush);
0fc1a713
JS
290
291 // Now draw the text
292 if (region->GetFont()) dc.SetFont(region->GetFont());
293
42cfaf8c 294 dc.DrawRectangle((double)(xp - w/2.0), (double)(yp - h/2.0), (double)w, (double)h);
0fc1a713
JS
295
296 if (m_pen) dc.SetPen(m_pen);
297 dc.SetTextForeground(* region->GetActualColourObject());
298
299#ifdef __WXMSW__
42cfaf8c 300 dc.SetTextBackground(g_oglWhiteBackgroundBrush->GetColour());
0fc1a713
JS
301#endif
302
42cfaf8c 303 oglDrawFormattedText(dc, &(region->GetFormattedText()), xp, yp, w, h, region->GetFormatMode());
0fc1a713
JS
304 }
305}
306
42cfaf8c 307void wxLineShape::EraseRegion(wxDC& dc, wxShapeRegion *region, double x, double y)
0fc1a713
JS
308{
309 if (GetDisableLabel())
310 return;
311
42cfaf8c
JS
312 double w, h;
313 double xx, yy;
0fc1a713
JS
314 region->GetSize(&w, &h);
315
316 // Get offset from x, y
317 region->GetPosition(&xx, &yy);
318
42cfaf8c
JS
319 double xp = xx + x;
320 double yp = yy + y;
0fc1a713
JS
321
322 if (region->GetFormattedText().Number() > 0)
323 {
42cfaf8c
JS
324 dc.SetPen(g_oglWhiteBackgroundPen);
325 dc.SetBrush(g_oglWhiteBackgroundBrush);
0fc1a713 326
42cfaf8c 327 dc.DrawRectangle((double)(xp - w/2.0), (double)(yp - h/2.0), (double)w, (double)h);
0fc1a713
JS
328 }
329}
330
331// Get the reference point for a label. Region x and y
332// are offsets from this.
333// position is 0, 1, 2
42cfaf8c 334void wxLineShape::GetLabelPosition(int position, double *x, double *y)
0fc1a713
JS
335{
336 switch (position)
337 {
338 case 0:
339 {
340 // Want to take the middle section for the label
341 int n = m_lineControlPoints->Number();
342 int half_way = (int)(n/2);
343
344 // Find middle of this line
345 wxNode *node = m_lineControlPoints->Nth(half_way - 1);
346 wxRealPoint *point = (wxRealPoint *)node->Data();
347 wxNode *next_node = node->Next();
348 wxRealPoint *next_point = (wxRealPoint *)next_node->Data();
349
42cfaf8c
JS
350 double dx = (next_point->x - point->x);
351 double dy = (next_point->y - point->y);
352 *x = (double)(point->x + dx/2.0);
353 *y = (double)(point->y + dy/2.0);
0fc1a713
JS
354 break;
355 }
356 case 1:
357 {
358 wxNode *node = m_lineControlPoints->First();
359 *x = ((wxRealPoint *)node->Data())->x;
360 *y = ((wxRealPoint *)node->Data())->y;
361 break;
362 }
363 case 2:
364 {
365 wxNode *node = m_lineControlPoints->Last();
366 *x = ((wxRealPoint *)node->Data())->x;
367 *y = ((wxRealPoint *)node->Data())->y;
368 break;
369 }
370 default:
371 break;
372 }
373}
374
375/*
376 * Find whether line is supposed to be vertical or horizontal and
377 * make it so.
378 *
379 */
380void GraphicsStraightenLine(wxRealPoint *point1, wxRealPoint *point2)
381{
42cfaf8c
JS
382 double dx = point2->x - point1->x;
383 double dy = point2->y - point1->y;
0fc1a713
JS
384
385 if (dx == 0.0)
386 return;
387 else if (fabs(dy/dx) > 1.0)
388 {
389 point2->x = point1->x;
390 }
391 else point2->y = point1->y;
392}
393
2e5ed787 394void wxLineShape::Straighten(wxDC *dc)
0fc1a713
JS
395{
396 if (!m_lineControlPoints || m_lineControlPoints->Number() < 3)
397 return;
398
2e5ed787
JS
399 if (dc)
400 Erase(* dc);
0fc1a713
JS
401
402 wxNode *first_point_node = m_lineControlPoints->First();
403 wxNode *last_point_node = m_lineControlPoints->Last();
404 wxNode *second_last_point_node = last_point_node->Previous();
405
406 wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data();
407 wxRealPoint *second_last_point = (wxRealPoint *)second_last_point_node->Data();
408
409 GraphicsStraightenLine(last_point, second_last_point);
410
411 wxNode *node = first_point_node;
412 while (node && (node != second_last_point_node))
413 {
414 wxRealPoint *point = (wxRealPoint *)node->Data();
415 wxRealPoint *next_point = (wxRealPoint *)(node->Next()->Data());
416
417 GraphicsStraightenLine(point, next_point);
418 node = node->Next();
419 }
420
2e5ed787
JS
421 if (dc)
422 Draw(* dc);
0fc1a713
JS
423}
424
425
426void wxLineShape::Unlink()
427{
428 if (m_to)
429 m_to->GetLines().DeleteObject(this);
430 if (m_from)
431 m_from->GetLines().DeleteObject(this);
432 m_to = NULL;
433 m_from = NULL;
434}
435
42cfaf8c 436void wxLineShape::SetEnds(double x1, double y1, double x2, double y2)
0fc1a713
JS
437{
438 // Find centre point
439 wxNode *first_point_node = m_lineControlPoints->First();
440 wxNode *last_point_node = m_lineControlPoints->Last();
441 wxRealPoint *first_point = (wxRealPoint *)first_point_node->Data();
442 wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data();
443
444 first_point->x = x1;
445 first_point->y = y1;
446 last_point->x = x2;
447 last_point->y = y2;
448
42cfaf8c
JS
449 m_xpos = (double)((x1 + x2)/2.0);
450 m_ypos = (double)((y1 + y2)/2.0);
0fc1a713
JS
451}
452
453// Get absolute positions of ends
42cfaf8c 454void wxLineShape::GetEnds(double *x1, double *y1, double *x2, double *y2)
0fc1a713
JS
455{
456 wxNode *first_point_node = m_lineControlPoints->First();
457 wxNode *last_point_node = m_lineControlPoints->Last();
458 wxRealPoint *first_point = (wxRealPoint *)first_point_node->Data();
459 wxRealPoint *last_point = (wxRealPoint *)last_point_node->Data();
460
461 *x1 = first_point->x; *y1 = first_point->y;
462 *x2 = last_point->x; *y2 = last_point->y;
463}
464
465void wxLineShape::SetAttachments(int from_attach, int to_attach)
466{
467 m_attachmentFrom = from_attach;
468 m_attachmentTo = to_attach;
469}
470
42cfaf8c 471bool wxLineShape::HitTest(double x, double y, int *attachment, double *distance)
0fc1a713
JS
472{
473 if (!m_lineControlPoints)
474 return FALSE;
475
476 // Look at label regions in case mouse is over a label
477 bool inLabelRegion = FALSE;
478 for (int i = 0; i < 3; i ++)
479 {
480 wxNode *regionNode = m_regions.Nth(i);
481 if (regionNode)
482 {
483 wxShapeRegion *region = (wxShapeRegion *)regionNode->Data();
484 if (region->m_formattedText.Number() > 0)
485 {
42cfaf8c 486 double xp, yp, cx, cy, cw, ch;
0fc1a713
JS
487 GetLabelPosition(i, &xp, &yp);
488 // Offset region from default label position
489 region->GetPosition(&cx, &cy);
490 region->GetSize(&cw, &ch);
491 cx += xp;
492 cy += yp;
42cfaf8c
JS
493 double rLeft = (double)(cx - (cw/2.0));
494 double rTop = (double)(cy - (ch/2.0));
495 double rRight = (double)(cx + (cw/2.0));
496 double rBottom = (double)(cy + (ch/2.0));
0fc1a713
JS
497 if (x > rLeft && x < rRight && y > rTop && y < rBottom)
498 {
499 inLabelRegion = TRUE;
500 i = 3;
501 }
502 }
503 }
504 }
505
506 wxNode *node = m_lineControlPoints->First();
507
508 while (node && node->Next())
509 {
510 wxRealPoint *point1 = (wxRealPoint *)node->Data();
511 wxRealPoint *point2 = (wxRealPoint *)node->Next()->Data();
512
513 // Allow for inaccurate mousing or vert/horiz lines
514 int extra = 4;
42cfaf8c
JS
515 double left = wxMin(point1->x, point2->x) - extra;
516 double right = wxMax(point1->x, point2->x) + extra;
0fc1a713 517
42cfaf8c
JS
518 double bottom = wxMin(point1->y, point2->y) - extra;
519 double top = wxMax(point1->y, point2->y) + extra;
0fc1a713
JS
520
521 if ((x > left && x < right && y > bottom && y < top) || inLabelRegion)
522 {
523 // Work out distance from centre of line
42cfaf8c
JS
524 double centre_x = (double)(left + (right - left)/2.0);
525 double centre_y = (double)(bottom + (top - bottom)/2.0);
0fc1a713
JS
526
527 *attachment = 0;
42cfaf8c 528 *distance = (double)sqrt((centre_x - x)*(centre_x - x) + (centre_y - y)*(centre_y - y));
0fc1a713
JS
529 return TRUE;
530 }
531
532 node = node->Next();
533 }
534 return FALSE;
535}
536
537void wxLineShape::DrawArrows(wxDC& dc)
538{
539 // Distance along line of each arrow: space them out evenly.
42cfaf8c
JS
540 double startArrowPos = 0.0;
541 double endArrowPos = 0.0;
542 double middleArrowPos = 0.0;
543
0fc1a713
JS
544 wxNode *node = m_arcArrows.First();
545 while (node)
546 {
547 wxArrowHead *arrow = (wxArrowHead *)node->Data();
548 switch (arrow->GetArrowEnd())
549 {
550 case ARROW_POSITION_START:
551 {
552 if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
553 // If specified, x offset is proportional to line length
554 DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
555 else
556 {
557 DrawArrow(dc, arrow, startArrowPos, FALSE); // Absolute distance
558 startArrowPos += arrow->GetSize() + arrow->GetSpacing();
559 }
560 break;
561 }
562 case ARROW_POSITION_END:
563 {
564 if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
565 DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
566 else
567 {
568 DrawArrow(dc, arrow, endArrowPos, FALSE);
569 endArrowPos += arrow->GetSize() + arrow->GetSpacing();
570 }
571 break;
572 }
573 case ARROW_POSITION_MIDDLE:
574 {
575 arrow->SetXOffset(middleArrowPos);
576 if ((arrow->GetXOffset() != 0.0) && !m_ignoreArrowOffsets)
577 DrawArrow(dc, arrow, arrow->GetXOffset(), TRUE);
578 else
579 {
580 DrawArrow(dc, arrow, middleArrowPos, FALSE);
581 middleArrowPos += arrow->GetSize() + arrow->GetSpacing();
582 }
583 break;
584 }
585 }
586 node = node->Next();
587 }
588}
589
42cfaf8c 590void wxLineShape::DrawArrow(wxDC& dc, wxArrowHead *arrow, double xOffset, bool proportionalOffset)
0fc1a713
JS
591{
592 wxNode *first_line_node = m_lineControlPoints->First();
593 wxRealPoint *first_line_point = (wxRealPoint *)first_line_node->Data();
594 wxNode *second_line_node = first_line_node->Next();
595 wxRealPoint *second_line_point = (wxRealPoint *)second_line_node->Data();
596
597 wxNode *last_line_node = m_lineControlPoints->Last();
598 wxRealPoint *last_line_point = (wxRealPoint *)last_line_node->Data();
599 wxNode *second_last_line_node = last_line_node->Previous();
600 wxRealPoint *second_last_line_point = (wxRealPoint *)second_last_line_node->Data();
601
602 // Position where we want to start drawing
42cfaf8c 603 double positionOnLineX, positionOnLineY;
0fc1a713
JS
604
605 // Position of start point of line, at the end of which we draw the arrow.
42cfaf8c 606 double startPositionX, startPositionY;
0fc1a713
JS
607
608 switch (arrow->GetPosition())
609 {
610 case ARROW_POSITION_START:
611 {
612 // If we're using a proportional offset, calculate just where this will
613 // be on the line.
42cfaf8c 614 double realOffset = xOffset;
0fc1a713
JS
615 if (proportionalOffset)
616 {
42cfaf8c
JS
617 double totalLength =
618 (double)sqrt((second_line_point->x - first_line_point->x)*(second_line_point->x - first_line_point->x) +
0fc1a713 619 (second_line_point->y - first_line_point->y)*(second_line_point->y - first_line_point->y));
42cfaf8c 620 realOffset = (double)(xOffset * totalLength);
0fc1a713
JS
621 }
622 GetPointOnLine(second_line_point->x, second_line_point->y,
623 first_line_point->x, first_line_point->y,
624 realOffset, &positionOnLineX, &positionOnLineY);
625 startPositionX = second_line_point->x;
626 startPositionY = second_line_point->y;
627 break;
628 }
629 case ARROW_POSITION_END:
630 {
631 // If we're using a proportional offset, calculate just where this will
632 // be on the line.
42cfaf8c 633 double realOffset = xOffset;
0fc1a713
JS
634 if (proportionalOffset)
635 {
42cfaf8c
JS
636 double totalLength =
637 (double)sqrt((second_last_line_point->x - last_line_point->x)*(second_last_line_point->x - last_line_point->x) +
0fc1a713 638 (second_last_line_point->y - last_line_point->y)*(second_last_line_point->y - last_line_point->y));
42cfaf8c 639 realOffset = (double)(xOffset * totalLength);
0fc1a713
JS
640 }
641 GetPointOnLine(second_last_line_point->x, second_last_line_point->y,
642 last_line_point->x, last_line_point->y,
643 realOffset, &positionOnLineX, &positionOnLineY);
644 startPositionX = second_last_line_point->x;
645 startPositionY = second_last_line_point->y;
646 break;
647 }
648 case ARROW_POSITION_MIDDLE:
649 {
650 // Choose a point half way between the last and penultimate points
42cfaf8c
JS
651 double x = ((last_line_point->x + second_last_line_point->x)/2);
652 double y = ((last_line_point->y + second_last_line_point->y)/2);
0fc1a713
JS
653
654 // If we're using a proportional offset, calculate just where this will
655 // be on the line.
42cfaf8c 656 double realOffset = xOffset;
0fc1a713
JS
657 if (proportionalOffset)
658 {
42cfaf8c
JS
659 double totalLength =
660 (double)sqrt((second_last_line_point->x - x)*(second_last_line_point->x - x) +
0fc1a713 661 (second_last_line_point->y - y)*(second_last_line_point->y - y));
42cfaf8c 662 realOffset = (double)(xOffset * totalLength);
0fc1a713
JS
663 }
664
665 GetPointOnLine(second_last_line_point->x, second_last_line_point->y,
666 x, y, realOffset, &positionOnLineX, &positionOnLineY);
667 startPositionX = second_last_line_point->x;
668 startPositionY = second_last_line_point->y;
669 break;
670 }
671 }
672
673 /*
674 * Add yOffset to arrow, if any
675 */
676
42cfaf8c 677 const double myPi = (double) 3.14159265;
0fc1a713 678 // The translation that the y offset may give
42cfaf8c
JS
679 double deltaX = 0.0;
680 double deltaY = 0.0;
0fc1a713
JS
681 if ((arrow->GetYOffset() != 0.0) && !m_ignoreArrowOffsets)
682 {
683 /*
684 |(x4, y4)
685 |d
686 |
687 (x1, y1)--------------(x3, y3)------------------(x2, y2)
688 x4 = x3 - d * sin(theta)
689 y4 = y3 + d * cos(theta)
690
691 Where theta = tan(-1) of (y3-y1)/(x3-x1)
692 */
42cfaf8c
JS
693 double x1 = startPositionX;
694 double y1 = startPositionY;
695 double x3 = positionOnLineX;
696 double y3 = positionOnLineY;
697 double d = -arrow->GetYOffset(); // Negate so +offset is above line
0fc1a713 698
42cfaf8c 699 double theta = 0.0;
0fc1a713 700 if (x3 == x1)
42cfaf8c 701 theta = (double)(myPi/2.0);
0fc1a713 702 else
42cfaf8c
JS
703 theta = (double)atan((y3-y1)/(x3-x1));
704
705 double x4 = (double)(x3 - (d*sin(theta)));
706 double y4 = (double)(y3 + (d*cos(theta)));
0fc1a713
JS
707
708 deltaX = x4 - positionOnLineX;
709 deltaY = y4 - positionOnLineY;
710 }
711
712 switch (arrow->_GetType())
713 {
714 case ARROW_ARROW:
715 {
42cfaf8c
JS
716 double arrowLength = arrow->GetSize();
717 double arrowWidth = (double)(arrowLength/3.0);
0fc1a713 718
42cfaf8c
JS
719 double tip_x, tip_y, side1_x, side1_y, side2_x, side2_y;
720 oglGetArrowPoints(startPositionX+deltaX, startPositionY+deltaY,
0fc1a713
JS
721 positionOnLineX+deltaX, positionOnLineY+deltaY,
722 arrowLength, arrowWidth, &tip_x, &tip_y,
723 &side1_x, &side1_y, &side2_x, &side2_y);
724
725 wxPoint points[4];
726 points[0].x = tip_x; points[0].y = tip_y;
727 points[1].x = side1_x; points[1].y = side1_y;
728 points[2].x = side2_x; points[2].y = side2_y;
729 points[3].x = tip_x; points[3].y = tip_y;
730
731 dc.SetPen(m_pen);
732 dc.SetBrush(m_brush);
733 dc.DrawPolygon(4, points);
734 break;
735 }
736 case ARROW_HOLLOW_CIRCLE:
737 case ARROW_FILLED_CIRCLE:
738 {
739 // Find point on line of centre of circle, which is a radius away
740 // from the end position
42cfaf8c
JS
741 double diameter = (double)(arrow->GetSize());
742 double x, y;
0fc1a713
JS
743 GetPointOnLine(startPositionX+deltaX, startPositionY+deltaY,
744 positionOnLineX+deltaX, positionOnLineY+deltaY,
42cfaf8c 745 (double)(diameter/2.0),
0fc1a713
JS
746 &x, &y);
747
748 // Convert ellipse centre to top-left coordinates
42cfaf8c
JS
749 double x1 = (double)(x - (diameter/2.0));
750 double y1 = (double)(y - (diameter/2.0));
0fc1a713
JS
751
752 dc.SetPen(m_pen);
753 if (arrow->_GetType() == ARROW_HOLLOW_CIRCLE)
42cfaf8c 754 dc.SetBrush(g_oglWhiteBackgroundBrush);
0fc1a713
JS
755 else
756 dc.SetBrush(m_brush);
757
758 dc.DrawEllipse(x1, y1, diameter, diameter);
759 break;
760 }
761 case ARROW_SINGLE_OBLIQUE:
762 {
763 break;
764 }
765 case ARROW_METAFILE:
766 {
767 if (arrow->GetMetaFile())
768 {
769 // Find point on line of centre of object, which is a half-width away
770 // from the end position
771 /*
772 * width
773 * <-- start pos <-----><-- positionOnLineX
774 * _____
775 * --------------| x | <-- e.g. rectangular arrowhead
776 * -----
777 */
42cfaf8c 778 double x, y;
0fc1a713
JS
779 GetPointOnLine(startPositionX, startPositionY,
780 positionOnLineX, positionOnLineY,
42cfaf8c 781 (double)(arrow->GetMetaFile()->m_width/2.0),
0fc1a713
JS
782 &x, &y);
783
784 // Calculate theta for rotating the metafile.
785 /*
786 |
787 | o(x2, y2) 'o' represents the arrowhead.
788 | /
789 | /
790 | /theta
791 | /(x1, y1)
792 |______________________
793 */
42cfaf8c
JS
794 double theta = 0.0;
795 double x1 = startPositionX;
796 double y1 = startPositionY;
797 double x2 = positionOnLineX;
798 double y2 = positionOnLineY;
0fc1a713
JS
799
800 if ((x1 == x2) && (y1 == y2))
801 theta = 0.0;
802
803 else if ((x1 == x2) && (y1 > y2))
42cfaf8c 804 theta = (double)(3.0*myPi/2.0);
0fc1a713
JS
805
806 else if ((x1 == x2) && (y2 > y1))
42cfaf8c 807 theta = (double)(myPi/2.0);
0fc1a713
JS
808
809 else if ((x2 > x1) && (y2 >= y1))
42cfaf8c 810 theta = (double)atan((y2 - y1)/(x2 - x1));
0fc1a713
JS
811
812 else if (x2 < x1)
42cfaf8c 813 theta = (double)(myPi + atan((y2 - y1)/(x2 - x1)));
0fc1a713
JS
814
815 else if ((x2 > x1) && (y2 < y1))
42cfaf8c 816 theta = (double)(2*myPi + atan((y2 - y1)/(x2 - x1)));
0fc1a713
JS
817
818 else
819 {
820 wxFatalError("Unknown arrowhead rotation case in lines.cc");
821 }
822
823 // Rotate about the centre of the object, then place
824 // the object on the line.
825 if (arrow->GetMetaFile()->GetRotateable())
826 arrow->GetMetaFile()->Rotate(0.0, 0.0, theta);
827
828 if (m_erasing)
829 {
830 // If erasing, just draw a rectangle.
42cfaf8c 831 double minX, minY, maxX, maxY;
0fc1a713
JS
832 arrow->GetMetaFile()->GetBounds(&minX, &minY, &maxX, &maxY);
833 // Make erasing rectangle slightly bigger or you get droppings.
834 int extraPixels = 4;
42cfaf8c
JS
835 dc.DrawRectangle((double)(deltaX + x + minX - (extraPixels/2.0)), (double)(deltaY + y + minY - (extraPixels/2.0)),
836 (double)(maxX - minX + extraPixels), (double)(maxY - minY + extraPixels));
0fc1a713
JS
837 }
838 else
839 arrow->GetMetaFile()->Draw(dc, x+deltaX, y+deltaY);
840 }
841 break;
842 }
843 default:
844 {
845 }
846 }
847}
848
849void wxLineShape::OnErase(wxDC& dc)
850{
851 wxPen *old_pen = m_pen;
852 wxBrush *old_brush = m_brush;
42cfaf8c
JS
853 SetPen(g_oglWhiteBackgroundPen);
854 SetBrush(g_oglWhiteBackgroundBrush);
0fc1a713 855
42cfaf8c 856 double bound_x, bound_y;
0fc1a713
JS
857 GetBoundingBoxMax(&bound_x, &bound_y);
858 if (m_font) dc.SetFont(m_font);
859
860 // Undraw text regions
861 for (int i = 0; i < 3; i++)
862 {
863 wxNode *node = m_regions.Nth(i);
864 if (node)
865 {
42cfaf8c 866 double x, y;
0fc1a713
JS
867 wxShapeRegion *region = (wxShapeRegion *)node->Data();
868 GetLabelPosition(i, &x, &y);
869 EraseRegion(dc, region, x, y);
870 }
871 }
872
873 // Undraw line
42cfaf8c
JS
874 dc.SetPen(g_oglWhiteBackgroundPen);
875 dc.SetBrush(g_oglWhiteBackgroundBrush);
0fc1a713
JS
876
877 // Drawing over the line only seems to work if the line has a thickness
878 // of 1.
879 if (old_pen && (old_pen->GetWidth() > 1))
880 {
42cfaf8c
JS
881 dc.DrawRectangle((double)(m_xpos - (bound_x/2.0) - 2.0), (double)(m_ypos - (bound_y/2.0) - 2.0),
882 (double)(bound_x+4.0), (double)(bound_y+4.0));
0fc1a713
JS
883 }
884 else
885 {
886 m_erasing = TRUE;
887 GetEventHandler()->OnDraw(dc);
888 GetEventHandler()->OnEraseControlPoints(dc);
889 m_erasing = FALSE;
890 }
891
892 if (old_pen) SetPen(old_pen);
893 if (old_brush) SetBrush(old_brush);
894}
895
42cfaf8c 896void wxLineShape::GetBoundingBoxMin(double *w, double *h)
0fc1a713 897{
42cfaf8c
JS
898 double x1 = 10000;
899 double y1 = 10000;
900 double x2 = -10000;
901 double y2 = -10000;
0fc1a713
JS
902
903 wxNode *node = m_lineControlPoints->First();
904 while (node)
905 {
906 wxRealPoint *point = (wxRealPoint *)node->Data();
907
908 if (point->x < x1) x1 = point->x;
909 if (point->y < y1) y1 = point->y;
910 if (point->x > x2) x2 = point->x;
911 if (point->y > y2) y2 = point->y;
912
913 node = node->Next();
914 }
42cfaf8c
JS
915 *w = (double)(x2 - x1);
916 *h = (double)(y2 - y1);
0fc1a713
JS
917}
918
919/*
920 * For a node image of interest, finds the position of this arc
921 * amongst all the arcs which are attached to THIS SIDE of the node image,
922 * and the number of same.
923 */
924void wxLineShape::FindNth(wxShape *image, int *nth, int *no_arcs, bool incoming)
925{
926 int n = -1;
927 int num = 0;
928 wxNode *node = image->GetLines().First();
929 int this_attachment;
930 if (image == m_to)
931 this_attachment = m_attachmentTo;
932 else
933 this_attachment = m_attachmentFrom;
934
935 // Find number of lines going into/out of this particular attachment point
936 while (node)
937 {
938 wxLineShape *line = (wxLineShape *)node->Data();
939
940 if (line->m_from == image)
941 {
942 // This is the nth line attached to 'image'
943 if ((line == this) && !incoming)
944 n = num;
945
946 // Increment num count if this is the same side (attachment number)
947 if (line->m_attachmentFrom == this_attachment)
948 num ++;
949 }
950
951 if (line->m_to == image)
952 {
953 // This is the nth line attached to 'image'
954 if ((line == this) && incoming)
955 n = num;
956
957 // Increment num count if this is the same side (attachment number)
958 if (line->m_attachmentTo == this_attachment)
959 num ++;
960 }
961
962 node = node->Next();
963 }
964 *nth = n;
965 *no_arcs = num;
966}
967
42cfaf8c 968void wxLineShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
0fc1a713
JS
969{
970 wxPen *old_pen = m_pen;
971 wxBrush *old_brush = m_brush;
972
973 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
974 SetPen(& dottedPen);
975 SetBrush( wxTRANSPARENT_BRUSH );
976
0fc1a713
JS
977 GetEventHandler()->OnDraw(dc);
978
979 if (old_pen) SetPen(old_pen);
980 else SetPen(NULL);
981 if (old_brush) SetBrush(old_brush);
982 else SetBrush(NULL);
983}
984
42cfaf8c 985bool wxLineShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
0fc1a713 986{
42cfaf8c
JS
987 double x_offset = x - old_x;
988 double y_offset = y - old_y;
0fc1a713
JS
989
990 if (m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
991 {
992 wxNode *node = m_lineControlPoints->First();
993 while (node)
994 {
995 wxRealPoint *point = (wxRealPoint *)node->Data();
996 point->x += x_offset;
997 point->y += y_offset;
998 node = node->Next();
999 }
1000
1001 }
1002
1003 // Move temporary label rectangles if necessary
1004 for (int i = 0; i < 3; i++)
1005 {
1006 if (m_labelObjects[i])
1007 {
1008 m_labelObjects[i]->Erase(dc);
42cfaf8c 1009 double xp, yp, xr, yr;
0fc1a713
JS
1010 GetLabelPosition(i, &xp, &yp);
1011 wxNode *node = m_regions.Nth(i);
1012 if (node)
1013 {
1014 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1015 region->GetPosition(&xr, &yr);
1016 }
1017 else
1018 {
1019 xr = 0.0; yr = 0.0;
1020 }
1021
1022 m_labelObjects[i]->Move(dc, xp+xr, yp+yr);
1023 }
1024 }
1025 return TRUE;
1026}
1027
1028void wxLineShape::OnMoveLink(wxDC& dc, bool moveControlPoints)
1029{
1030 if (!m_from || !m_to)
1031 return;
1032
1033 if (m_lineControlPoints->Number() > 2)
1034 Initialise();
1035
1036 // Do each end - nothing in the middle. User has to move other points
1037 // manually if necessary.
42cfaf8c
JS
1038 double end_x, end_y;
1039 double other_end_x, other_end_y;
0fc1a713
JS
1040
1041 FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y);
1042
1043 wxNode *first = m_lineControlPoints->First();
1044 wxRealPoint *first_point = (wxRealPoint *)first->Data();
1045 wxNode *last = m_lineControlPoints->Last();
1046 wxRealPoint *last_point = (wxRealPoint *)last->Data();
1047
1048/* This is redundant, surely? Done by SetEnds.
1049 first_point->x = end_x; first_point->y = end_y;
1050 last_point->x = other_end_x; last_point->y = other_end_y;
1051*/
1052
42cfaf8c
JS
1053 double oldX = m_xpos;
1054 double oldY = m_ypos;
0fc1a713
JS
1055
1056 SetEnds(end_x, end_y, other_end_x, other_end_y);
1057
1058 // Do a second time, because one may depend on the other.
1059 FindLineEndPoints(&end_x, &end_y, &other_end_x, &other_end_y);
1060 SetEnds(end_x, end_y, other_end_x, other_end_y);
1061
1062 // Try to move control points with the arc
42cfaf8c
JS
1063 double x_offset = m_xpos - oldX;
1064 double y_offset = m_ypos - oldY;
0fc1a713
JS
1065
1066// if (moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
1067 // Only move control points if it's a self link. And only works if attachment mode is ON.
1068 if ((m_from == m_to) && m_from->GetAttachmentMode() && moveControlPoints && m_lineControlPoints && !(x_offset == 0.0 && y_offset == 0.0))
1069 {
1070 wxNode *node = m_lineControlPoints->First();
1071 while (node)
1072 {
1073 if ((node != m_lineControlPoints->First()) && (node != m_lineControlPoints->Last()))
1074 {
1075 wxRealPoint *point = (wxRealPoint *)node->Data();
1076 point->x += x_offset;
1077 point->y += y_offset;
1078 }
1079 node = node->Next();
1080 }
1081 }
1082
1083 Move(dc, m_xpos, m_ypos);
1084}
1085
1086// Finds the x, y points at the two ends of the line.
1087// This function can be used by e.g. line-routing routines to
1088// get the actual points on the two node images where the lines will be drawn
1089// to/from.
42cfaf8c 1090void wxLineShape::FindLineEndPoints(double *fromX, double *fromY, double *toX, double *toY)
0fc1a713
JS
1091{
1092 if (!m_from || !m_to)
1093 return;
1094
1095 // Do each end - nothing in the middle. User has to move other points
1096 // manually if necessary.
42cfaf8c
JS
1097 double end_x, end_y;
1098 double other_end_x, other_end_y;
0fc1a713
JS
1099
1100 wxNode *first = m_lineControlPoints->First();
1101 wxRealPoint *first_point = (wxRealPoint *)first->Data();
1102 wxNode *last = m_lineControlPoints->Last();
1103 wxRealPoint *last_point = (wxRealPoint *)last->Data();
1104
1105 wxNode *second = first->Next();
1106 wxRealPoint *second_point = (wxRealPoint *)second->Data();
1107
1108 wxNode *second_last = last->Previous();
1109 wxRealPoint *second_last_point = (wxRealPoint *)second_last->Data();
1110
1111 if (m_lineControlPoints->Number() > 2)
1112 {
1113 if (m_from->GetAttachmentMode())
1114 {
1115 int nth, no_arcs;
1116 FindNth(m_from, &nth, &no_arcs, FALSE); // Not incoming
1117 m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this);
1118 }
1119 else
1120 (void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(),
42cfaf8c 1121 (double)second_point->x, (double)second_point->y,
0fc1a713
JS
1122 &end_x, &end_y);
1123
1124 if (m_to->GetAttachmentMode())
1125 {
1126 int nth, no_arcs;
1127 FindNth(m_to, &nth, &no_arcs, TRUE); // Incoming
1128 m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this);
1129 }
1130 else
1131 (void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(),
42cfaf8c 1132 (double)second_last_point->x, (double)second_last_point->y,
0fc1a713
JS
1133 &other_end_x, &other_end_y);
1134 }
1135 else
1136 {
42cfaf8c
JS
1137 double fromX = m_from->GetX();
1138 double fromY = m_from->GetY();
1139 double toX = m_to->GetX();
1140 double toY = m_to->GetY();
0fc1a713
JS
1141
1142 if (m_from->GetAttachmentMode())
1143 {
1144 int nth, no_arcs;
1145 FindNth(m_from, &nth, &no_arcs, FALSE);
1146 m_from->GetAttachmentPosition(m_attachmentFrom, &end_x, &end_y, nth, no_arcs, this);
1147 fromX = end_x;
1148 fromY = end_y;
1149 }
1150
1151 if (m_to->GetAttachmentMode())
1152 {
1153 int nth, no_arcs;
1154 FindNth(m_to, &nth, &no_arcs, TRUE);
1155 m_to->GetAttachmentPosition(m_attachmentTo, &other_end_x, &other_end_y, nth, no_arcs, this);
1156 toX = other_end_x;
1157 toY = other_end_y;
1158 }
1159
1160 if (!m_from->GetAttachmentMode())
1161 (void) m_from->GetPerimeterPoint(m_from->GetX(), m_from->GetY(),
1162 toX, toY,
1163 &end_x, &end_y);
1164
1165 if (!m_to->GetAttachmentMode())
1166 (void) m_to->GetPerimeterPoint(m_to->GetX(), m_to->GetY(),
1167 fromX, fromY,
1168 &other_end_x, &other_end_y);
1169 }
1170 *fromX = end_x;
1171 *fromY = end_y;
1172 *toX = other_end_x;
1173 *toY = other_end_y;
1174}
1175
1176void wxLineShape::OnDraw(wxDC& dc)
1177{
1178 if (m_lineControlPoints)
1179 {
1180 if (m_pen)
1181 dc.SetPen(m_pen);
1182 if (m_brush)
1183 dc.SetBrush(m_brush);
1184
1185 int n = m_lineControlPoints->Number();
1186 wxPoint *points = new wxPoint[n];
1187 int i;
1188 for (i = 0; i < n; i++)
1189 {
1190 wxRealPoint* point = (wxRealPoint*) m_lineControlPoints->Nth(i)->Data();
42cfaf8c
JS
1191 points[i].x = WXROUND(point->x);
1192 points[i].y = WXROUND(point->y);
0fc1a713
JS
1193 }
1194
1195 if (m_isSpline)
1196 dc.DrawSpline(n, points);
1197 else
1198 dc.DrawLines(n, points);
1199
42cfaf8c
JS
1200#ifdef __WXMSW__
1201 // For some reason, last point isn't drawn under Windows.
1202 dc.DrawPoint(points[n-1]);
1203#endif
1204
0fc1a713
JS
1205 delete[] points;
1206
42cfaf8c 1207
0fc1a713
JS
1208 // Problem with pen - if not a solid pen, does strange things
1209 // to the arrowhead. So make (get) a new pen that's solid.
1210 if (m_pen && (m_pen->GetStyle() != wxSOLID))
1211 {
1212 wxPen *solid_pen =
1213 wxThePenList->FindOrCreatePen(m_pen->GetColour(), 1, wxSOLID);
1214 if (solid_pen)
1215 dc.SetPen(solid_pen);
1216 }
1217 DrawArrows(dc);
1218 }
1219}
1220
1221void wxLineShape::OnDrawControlPoints(wxDC& dc)
1222{
1223 if (!m_drawHandles)
1224 return;
1225
1226 // Draw temporary label rectangles if necessary
1227 for (int i = 0; i < 3; i++)
1228 {
1229 if (m_labelObjects[i])
1230 m_labelObjects[i]->Draw(dc);
1231 }
1232 wxShape::OnDrawControlPoints(dc);
1233}
1234
1235void wxLineShape::OnEraseControlPoints(wxDC& dc)
1236{
1237 // Erase temporary label rectangles if necessary
1238 for (int i = 0; i < 3; i++)
1239 {
1240 if (m_labelObjects[i])
1241 m_labelObjects[i]->Erase(dc);
1242 }
1243 wxShape::OnEraseControlPoints(dc);
1244}
1245
42cfaf8c 1246void wxLineShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713
JS
1247{
1248}
1249
42cfaf8c 1250void wxLineShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
1251{
1252}
1253
42cfaf8c 1254void wxLineShape::OnEndDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
1255{
1256}
1257
1258/*
42cfaf8c 1259void wxLineShape::SetArrowSize(double length, double width)
0fc1a713
JS
1260{
1261 arrow_length = length;
1262 arrow_width = width;
1263}
1264
1265void wxLineShape::SetStartArrow(int style)
1266{
1267 start_style = style;
1268}
1269
1270void wxLineShape::SetMiddleArrow(int style)
1271{
1272 middle_style = style;
1273}
1274
1275void wxLineShape::SetEndArrow(int style)
1276{
1277 end_style = style;
1278}
1279*/
1280
1281void wxLineShape::OnDrawContents(wxDC& dc)
1282{
1283 if (GetDisableLabel())
1284 return;
1285
1286 for (int i = 0; i < 3; i++)
1287 {
1288 wxNode *node = m_regions.Nth(i);
1289 if (node)
1290 {
1291 wxShapeRegion *region = (wxShapeRegion *)node->Data();
42cfaf8c 1292 double x, y;
0fc1a713
JS
1293 GetLabelPosition(i, &x, &y);
1294 DrawRegion(dc, region, x, y);
1295 }
1296 }
1297}
1298
1299
1300#ifdef PROLOGIO
1301char *wxLineShape::GetFunctor()
1302{
1303 return "arc_image";
1304}
1305#endif
1306
1307void wxLineShape::SetTo(wxShape *object)
1308{
1309 m_to = object;
1310}
1311
1312void wxLineShape::SetFrom(wxShape *object)
1313{
1314 m_from = object;
1315}
1316
1317void wxLineShape::MakeControlPoints()
1318{
1319 if (m_canvas && m_lineControlPoints)
1320 {
1321 wxNode *first = m_lineControlPoints->First();
1322 wxNode *last = m_lineControlPoints->Last();
1323 wxRealPoint *first_point = (wxRealPoint *)first->Data();
1324 wxRealPoint *last_point = (wxRealPoint *)last->Data();
1325
1326 wxLineControlPoint *control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
1327 first_point->x, first_point->y,
1328 CONTROL_POINT_ENDPOINT_FROM);
1329 control->m_point = first_point;
1330 m_canvas->AddShape(control);
1331 m_controlPoints.Append(control);
1332
1333
1334 wxNode *node = first->Next();
1335 while (node != last)
1336 {
1337 wxRealPoint *point = (wxRealPoint *)node->Data();
1338
1339 control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
1340 point->x, point->y,
1341 CONTROL_POINT_LINE);
1342 control->m_point = point;
1343
1344 m_canvas->AddShape(control);
1345 m_controlPoints.Append(control);
1346
1347 node = node->Next();
1348 }
1349 control = new wxLineControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
1350 last_point->x, last_point->y,
1351 CONTROL_POINT_ENDPOINT_TO);
1352 control->m_point = last_point;
1353 m_canvas->AddShape(control);
1354 m_controlPoints.Append(control);
1355
1356 }
1357
1358}
1359
1360void wxLineShape::ResetControlPoints()
1361{
1362 if (m_canvas && m_lineControlPoints && m_controlPoints.Number() > 0)
1363 {
1364 wxNode *node = m_controlPoints.First();
1365 wxNode *control_node = m_lineControlPoints->First();
1366 while (node && control_node)
1367 {
1368 wxRealPoint *point = (wxRealPoint *)control_node->Data();
1369 wxLineControlPoint *control = (wxLineControlPoint *)node->Data();
1370 control->SetX(point->x);
1371 control->SetY(point->y);
1372
1373 node = node->Next();
1374 control_node = control_node->Next();
1375 }
1376 }
1377}
1378
1379#ifdef PROLOGIO
1380void wxLineShape::WritePrologAttributes(wxExpr *clause)
1381{
1382 wxShape::WritePrologAttributes(clause);
1383
1384 if (m_from)
1385 clause->AddAttributeValue("from", m_from->GetId());
1386 if (m_to)
1387 clause->AddAttributeValue("to", m_to->GetId());
1388
1389 if (m_attachmentTo != 0)
1390 clause->AddAttributeValue("attachment_to", (long)m_attachmentTo);
1391 if (m_attachmentFrom != 0)
1392 clause->AddAttributeValue("attachment_from", (long)m_attachmentFrom);
1393
1394 if (m_alignmentStart != 0)
1395 clause->AddAttributeValue("align_start", (long)m_alignmentStart);
1396 if (m_alignmentEnd != 0)
1397 clause->AddAttributeValue("align_end", (long)m_alignmentEnd);
1398
1399 clause->AddAttributeValue("is_spline", (long)m_isSpline);
1400 if (m_maintainStraightLines)
1401 clause->AddAttributeValue("keep_lines_straight", (long)m_maintainStraightLines);
1402
1403 // Make a list of lists for the (sp)line controls
1404 wxExpr *list = new wxExpr(PrologList);
1405 wxNode *node = m_lineControlPoints->First();
1406 while (node)
1407 {
1408 wxRealPoint *point = (wxRealPoint *)node->Data();
1409 wxExpr *point_list = new wxExpr(PrologList);
42cfaf8c
JS
1410 wxExpr *x_expr = new wxExpr((double) point->x);
1411 wxExpr *y_expr = new wxExpr((double) point->y);
0fc1a713
JS
1412 point_list->Append(x_expr);
1413 point_list->Append(y_expr);
1414 list->Append(point_list);
1415
1416 node = node->Next();
1417 }
1418 clause->AddAttributeValue("controls", list);
1419
1420 // Write arc arrows in new OGL format, if there are any.
1421 // This is a list of lists. Each sublist comprises:
1422 // (arrowType arrowEnd xOffset arrowSize)
1423 if (m_arcArrows.Number() > 0)
1424 {
1425 wxExpr *arrow_list = new wxExpr(PrologList);
1426 node = m_arcArrows.First();
1427 while (node)
1428 {
1429 wxArrowHead *head = (wxArrowHead *)node->Data();
1430 wxExpr *head_list = new wxExpr(PrologList);
1431 head_list->Append(new wxExpr((long)head->_GetType()));
1432 head_list->Append(new wxExpr((long)head->GetArrowEnd()));
1433 head_list->Append(new wxExpr(head->GetXOffset()));
1434 head_list->Append(new wxExpr(head->GetArrowSize()));
1435 head_list->Append(new wxExpr(PrologString, (head->GetName() ? head->GetName() : "")));
1436 head_list->Append(new wxExpr(head->GetId()));
1437
1438 // New members of wxArrowHead
1439 head_list->Append(new wxExpr(head->GetYOffset()));
1440 head_list->Append(new wxExpr(head->GetSpacing()));
1441
1442 arrow_list->Append(head_list);
1443
1444 node = node->Next();
1445 }
1446 clause->AddAttributeValue("arrows", arrow_list);
1447 }
1448}
1449
1450void wxLineShape::ReadPrologAttributes(wxExpr *clause)
1451{
1452 wxShape::ReadPrologAttributes(clause);
1453
1454 int iVal = (int) m_isSpline;
1455 clause->AssignAttributeValue("is_spline", &iVal);
1456 m_isSpline = (iVal != 0);
1457
1458 iVal = (int) m_maintainStraightLines;
1459 clause->AssignAttributeValue("keep_lines_straight", &iVal);
1460 m_maintainStraightLines = (iVal != 0);
1461
1462 clause->AssignAttributeValue("align_start", &m_alignmentStart);
1463 clause->AssignAttributeValue("align_end", &m_alignmentEnd);
1464
1465 // Compatibility: check for no regions.
1466 if (m_regions.Number() == 0)
1467 {
1468 wxShapeRegion *newRegion = new wxShapeRegion;
1469 newRegion->SetName("Middle");
1470 newRegion->SetSize(150, 50);
1471 m_regions.Append((wxObject *)newRegion);
1472 if (m_text.Number() > 0)
1473 {
1474 newRegion->ClearText();
1475 wxNode *node = m_text.First();
1476 while (node)
1477 {
1478 wxShapeTextLine *textLine = (wxShapeTextLine *)node->Data();
1479 wxNode *next = node->Next();
1480 newRegion->GetFormattedText().Append((wxObject *)textLine);
1481 delete node;
1482 node = next;
1483 }
1484 }
1485
1486 newRegion = new wxShapeRegion;
1487 newRegion->SetName("Start");
1488 newRegion->SetSize(150, 50);
1489 m_regions.Append((wxObject *)newRegion);
1490
1491 newRegion = new wxShapeRegion;
1492 newRegion->SetName("End");
1493 newRegion->SetSize(150, 50);
1494 m_regions.Append((wxObject *)newRegion);
1495 }
1496
1497 m_attachmentTo = 0;
1498 m_attachmentFrom = 0;
1499
1500 clause->AssignAttributeValue("attachment_to", &m_attachmentTo);
2e5ed787 1501 clause->AssignAttributeValue("attachment_from", &m_attachmentFrom);
0fc1a713
JS
1502
1503 wxExpr *line_list = NULL;
1504
1505 // When image is created, there are default control points. Override
1506 // them if there are some in the file.
1507 clause->AssignAttributeValue("controls", &line_list);
1508
1509 if (line_list)
1510 {
1511 // Read a list of lists for the spline controls
1512 if (m_lineControlPoints)
1513 {
1514 ClearPointList(*m_lineControlPoints);
1515 }
1516 else
1517 m_lineControlPoints = new wxList;
1518
1519 wxExpr *node = line_list->value.first;
1520
1521 while (node)
1522 {
1523 wxExpr *xexpr = node->value.first;
42cfaf8c 1524 double x = xexpr->RealValue();
0fc1a713
JS
1525
1526 wxExpr *yexpr = xexpr->next;
42cfaf8c 1527 double y = yexpr->RealValue();
0fc1a713
JS
1528
1529 wxRealPoint *point = new wxRealPoint(x, y);
1530 m_lineControlPoints->Append((wxObject*) point);
1531
1532 node = node->next;
1533 }
1534 }
1535
1536 // Read arrow list, for new OGL code
1537 wxExpr *arrow_list = NULL;
1538
1539 clause->AssignAttributeValue("arrows", &arrow_list);
1540 if (arrow_list)
1541 {
1542 wxExpr *node = arrow_list->value.first;
1543
1544 while (node)
1545 {
1546 WXTYPE arrowType = ARROW_ARROW;
1547 int arrowEnd = 0;
42cfaf8c
JS
1548 double xOffset = 0.0;
1549 double arrowSize = 0.0;
0fc1a713
JS
1550 wxString arrowName("");
1551 long arrowId = -1;
1552
1553 wxExpr *type_expr = node->Nth(0);
1554 wxExpr *end_expr = node->Nth(1);
1555 wxExpr *dist_expr = node->Nth(2);
1556 wxExpr *size_expr = node->Nth(3);
1557 wxExpr *name_expr = node->Nth(4);
1558 wxExpr *id_expr = node->Nth(5);
1559
1560 // New members of wxArrowHead
1561 wxExpr *yOffsetExpr = node->Nth(6);
1562 wxExpr *spacingExpr = node->Nth(7);
1563
1564 if (type_expr)
1565 arrowType = (int)type_expr->IntegerValue();
1566 if (end_expr)
1567 arrowEnd = (int)end_expr->IntegerValue();
1568 if (dist_expr)
1569 xOffset = dist_expr->RealValue();
1570 if (size_expr)
1571 arrowSize = size_expr->RealValue();
1572 if (name_expr)
1573 arrowName = name_expr->StringValue();
1574 if (id_expr)
1575 arrowId = id_expr->IntegerValue();
1576
1577 if (arrowId == -1)
1578 arrowId = NewId();
1579 else
1580 RegisterId(arrowId);
1581
1582 wxArrowHead *arrowHead = AddArrow(arrowType, arrowEnd, arrowSize, xOffset, (char*) (const char*) arrowName, NULL, arrowId);
1583 if (yOffsetExpr)
1584 arrowHead->SetYOffset(yOffsetExpr->RealValue());
1585 if (spacingExpr)
1586 arrowHead->SetSpacing(spacingExpr->RealValue());
1587
1588 node = node->next;
1589 }
1590 }
1591}
1592#endif
1593
2bb0cd28 1594void wxLineShape::Copy(wxShape& copy)
0fc1a713
JS
1595{
1596 wxShape::Copy(copy);
1597
2bb0cd28
JS
1598 wxASSERT( copy.IsKindOf(CLASSINFO(wxLineShape)) );
1599
1600 wxLineShape& lineCopy = (wxLineShape&) copy;
1601
42cfaf8c
JS
1602 lineCopy.m_to = m_to;
1603 lineCopy.m_from = m_from;
1604 lineCopy.m_attachmentTo = m_attachmentTo;
1605 lineCopy.m_attachmentFrom = m_attachmentFrom;
2bb0cd28
JS
1606 lineCopy.m_isSpline = m_isSpline;
1607 lineCopy.m_alignmentStart = m_alignmentStart;
1608 lineCopy.m_alignmentEnd = m_alignmentEnd;
1609 lineCopy.m_maintainStraightLines = m_maintainStraightLines;
1610 lineCopy.m_lineOrientations.Clear();
42cfaf8c 1611
0fc1a713
JS
1612 wxNode *node = m_lineOrientations.First();
1613 while (node)
1614 {
2bb0cd28 1615 lineCopy.m_lineOrientations.Append(node->Data());
0fc1a713
JS
1616 node = node->Next();
1617 }
1618
2bb0cd28 1619 if (lineCopy.m_lineControlPoints)
0fc1a713 1620 {
2bb0cd28
JS
1621 ClearPointList(*lineCopy.m_lineControlPoints);
1622 delete lineCopy.m_lineControlPoints;
0fc1a713
JS
1623 }
1624
2bb0cd28 1625 lineCopy.m_lineControlPoints = new wxList;
0fc1a713
JS
1626
1627 node = m_lineControlPoints->First();
1628 while (node)
1629 {
1630 wxRealPoint *point = (wxRealPoint *)node->Data();
1631 wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
2bb0cd28 1632 lineCopy.m_lineControlPoints->Append((wxObject*) new_point);
0fc1a713
JS
1633 node = node->Next();
1634 }
1635
42cfaf8c 1636 // Copy arrows
2bb0cd28 1637 lineCopy.ClearArrowsAtPosition(-1);
0fc1a713
JS
1638 node = m_arcArrows.First();
1639 while (node)
1640 {
1641 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2bb0cd28 1642 lineCopy.m_arcArrows.Append(new wxArrowHead(*arrow));
0fc1a713
JS
1643 node = node->Next();
1644 }
1645}
1646
0fc1a713
JS
1647// Override select, to create/delete temporary label-moving objects
1648void wxLineShape::Select(bool select, wxDC* dc)
1649{
34138703 1650 wxShape::Select(select, dc);
0fc1a713
JS
1651 if (select)
1652 {
1653 for (int i = 0; i < 3; i++)
1654 {
1655 wxNode *node = m_regions.Nth(i);
1656 if (node)
1657 {
1658 wxShapeRegion *region = (wxShapeRegion *)node->Data();
1659 if (region->m_formattedText.Number() > 0)
1660 {
42cfaf8c 1661 double w, h, x, y, xx, yy;
0fc1a713
JS
1662 region->GetSize(&w, &h);
1663 region->GetPosition(&x, &y);
1664 GetLabelPosition(i, &xx, &yy);
1665 if (m_labelObjects[i])
1666 {
1667 m_labelObjects[i]->Select(FALSE);
1668 m_labelObjects[i]->RemoveFromCanvas(m_canvas);
1669 delete m_labelObjects[i];
1670 }
2e5ed787 1671 m_labelObjects[i] = OnCreateLabelShape(this, region, w, h);
0fc1a713
JS
1672 m_labelObjects[i]->AddToCanvas(m_canvas);
1673 m_labelObjects[i]->Show(TRUE);
1674 if (dc)
42cfaf8c 1675 m_labelObjects[i]->Move(*dc, (double)(x + xx), (double)(y + yy));
2e5ed787 1676 m_labelObjects[i]->Select(TRUE, dc);
0fc1a713
JS
1677 }
1678 }
1679 }
1680 }
1681 else
1682 {
1683 for (int i = 0; i < 3; i++)
1684 {
1685 if (m_labelObjects[i])
1686 {
1687 m_labelObjects[i]->Select(FALSE, dc);
2e5ed787 1688 m_labelObjects[i]->Erase(*dc);
0fc1a713
JS
1689 m_labelObjects[i]->RemoveFromCanvas(m_canvas);
1690 delete m_labelObjects[i];
1691 m_labelObjects[i] = NULL;
1692 }
1693 }
1694 }
1695}
1696
1697/*
1698 * Line control point
1699 *
1700 */
1701
1702IMPLEMENT_DYNAMIC_CLASS(wxLineControlPoint, wxControlPoint)
1703
42cfaf8c 1704wxLineControlPoint::wxLineControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double x, double y, int the_type):
0fc1a713
JS
1705 wxControlPoint(theCanvas, object, size, x, y, the_type)
1706{
1707 m_xpos = x;
1708 m_ypos = y;
1709 m_type = the_type;
2e5ed787 1710 m_point = NULL;
0fc1a713
JS
1711}
1712
1713wxLineControlPoint::~wxLineControlPoint()
1714{
1715}
1716
1717void wxLineControlPoint::OnDraw(wxDC& dc)
1718{
1719 wxRectangleShape::OnDraw(dc);
1720}
1721
1722// Implement movement of Line point
42cfaf8c 1723void wxLineControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713 1724{
2bb0cd28
JS
1725 m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
1726}
1727
42cfaf8c 1728void wxLineControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
2bb0cd28
JS
1729{
1730 m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
1731}
1732
42cfaf8c 1733void wxLineControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
2bb0cd28
JS
1734{
1735 m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
1736}
1737
1738// Control points ('handles') redirect control to the actual shape, to make it easier
1739// to override sizing behaviour.
42cfaf8c 1740void wxLineShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
2bb0cd28
JS
1741{
1742 wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
1743
0fc1a713
JS
1744 wxClientDC dc(GetCanvas());
1745 GetCanvas()->PrepareDC(dc);
1746
1747 dc.SetLogicalFunction(wxXOR);
1748
1749 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1750 dc.SetPen(dottedPen);
1751 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1752
2bb0cd28 1753 if (lpt->m_type == CONTROL_POINT_LINE)
0fc1a713
JS
1754 {
1755 m_canvas->Snap(&x, &y);
1756
2bb0cd28
JS
1757 lpt->SetX(x); lpt->SetY(y);
1758 lpt->m_point->x = x; lpt->m_point->y = y;
0fc1a713 1759
2bb0cd28 1760 wxLineShape *lineShape = (wxLineShape *)this;
0fc1a713
JS
1761
1762 wxPen *old_pen = lineShape->GetPen();
1763 wxBrush *old_brush = lineShape->GetBrush();
1764
1765 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1766 lineShape->SetPen(& dottedPen);
1767 lineShape->SetBrush(wxTRANSPARENT_BRUSH);
1768
1769 lineShape->GetEventHandler()->OnMoveLink(dc, FALSE);
1770
1771 lineShape->SetPen(old_pen);
1772 lineShape->SetBrush(old_brush);
1773 }
1774
2bb0cd28 1775 if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
0fc1a713 1776 {
2e5ed787 1777// lpt->SetX(x); lpt->SetY(y);
0fc1a713
JS
1778 }
1779
1780}
1781
42cfaf8c 1782void wxLineShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
0fc1a713 1783{
2bb0cd28
JS
1784 wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
1785
0fc1a713
JS
1786 wxClientDC dc(GetCanvas());
1787 GetCanvas()->PrepareDC(dc);
1788
2bb0cd28
JS
1789 wxLineShape *lineShape = (wxLineShape *)this;
1790 if (lpt->m_type == CONTROL_POINT_LINE)
0fc1a713 1791 {
2e5ed787 1792 lpt->m_originalPos = * (lpt->m_point);
0fc1a713
JS
1793 m_canvas->Snap(&x, &y);
1794
2bb0cd28 1795 this->Erase(dc);
0fc1a713
JS
1796
1797 // Redraw start and end objects because we've left holes
1798 // when erasing the line
1799 lineShape->GetFrom()->OnDraw(dc);
1800 lineShape->GetFrom()->OnDrawContents(dc);
1801 lineShape->GetTo()->OnDraw(dc);
1802 lineShape->GetTo()->OnDrawContents(dc);
1803
2bb0cd28 1804 this->SetDisableLabel(TRUE);
0fc1a713
JS
1805 dc.SetLogicalFunction(wxXOR);
1806
2bb0cd28
JS
1807 lpt->m_xpos = x; lpt->m_ypos = y;
1808 lpt->m_point->x = x; lpt->m_point->y = y;
0fc1a713
JS
1809
1810 wxPen *old_pen = lineShape->GetPen();
1811 wxBrush *old_brush = lineShape->GetBrush();
1812
1813 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1814 lineShape->SetPen(& dottedPen);
1815 lineShape->SetBrush(wxTRANSPARENT_BRUSH);
1816
1817 lineShape->GetEventHandler()->OnMoveLink(dc, FALSE);
1818
1819 lineShape->SetPen(old_pen);
1820 lineShape->SetBrush(old_brush);
1821 }
1822
2bb0cd28 1823 if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM || lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
0fc1a713 1824 {
42cfaf8c 1825 m_canvas->SetCursor(g_oglBullseyeCursor);
2bb0cd28 1826 lpt->m_oldCursor = wxSTANDARD_CURSOR;
0fc1a713
JS
1827 }
1828}
2bb0cd28 1829
42cfaf8c 1830void wxLineShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
0fc1a713 1831{
2bb0cd28
JS
1832 wxLineControlPoint* lpt = (wxLineControlPoint*) pt;
1833
0fc1a713
JS
1834 wxClientDC dc(GetCanvas());
1835 GetCanvas()->PrepareDC(dc);
1836
2bb0cd28
JS
1837 this->SetDisableLabel(FALSE);
1838 wxLineShape *lineShape = (wxLineShape *)this;
0fc1a713 1839
2bb0cd28 1840 if (lpt->m_type == CONTROL_POINT_LINE)
0fc1a713
JS
1841 {
1842 m_canvas->Snap(&x, &y);
1843
2e5ed787
JS
1844 wxRealPoint pt = wxRealPoint(x, y);
1845
1846 // Move the control point back to where it was;
1847 // MoveControlPoint will move it to the new position
1848 // if it decides it wants. We only moved the position
1849 // during user feedback so we could redraw the line
1850 // as it changed shape.
1851 lpt->m_xpos = lpt->m_originalPos.x; lpt->m_ypos = lpt->m_originalPos.y;
1852 lpt->m_point->x = lpt->m_originalPos.x; lpt->m_point->y = lpt->m_originalPos.y;
0fc1a713 1853
2e5ed787 1854 OnMoveMiddleControlPoint(dc, lpt, pt);
0fc1a713 1855 }
2bb0cd28 1856 if (lpt->m_type == CONTROL_POINT_ENDPOINT_FROM)
0fc1a713 1857 {
2bb0cd28
JS
1858 if (lpt->m_oldCursor)
1859 m_canvas->SetCursor(lpt->m_oldCursor);
0fc1a713 1860
2e5ed787
JS
1861// this->Erase(dc);
1862
1863// lpt->m_xpos = x; lpt->m_ypos = y;
0fc1a713
JS
1864
1865 if (lineShape->GetFrom())
1866 {
1867 lineShape->GetFrom()->MoveLineToNewAttachment(dc, lineShape, x, y);
0fc1a713
JS
1868 }
1869 }
2bb0cd28 1870 if (lpt->m_type == CONTROL_POINT_ENDPOINT_TO)
0fc1a713 1871 {
2bb0cd28
JS
1872 if (lpt->m_oldCursor)
1873 m_canvas->SetCursor(lpt->m_oldCursor);
0fc1a713 1874
2e5ed787 1875// lpt->m_xpos = x; lpt->m_ypos = y;
0fc1a713
JS
1876
1877 if (lineShape->GetTo())
1878 {
1879 lineShape->GetTo()->MoveLineToNewAttachment(dc, lineShape, x, y);
0fc1a713
JS
1880 }
1881 }
42cfaf8c
JS
1882
1883 // Needed?
1884#if 0
0fc1a713
JS
1885 int i = 0;
1886 for (i = 0; i < lineShape->GetLineControlPoints()->Number(); i++)
2bb0cd28 1887 if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Nth(i)->Data())) == lpt->m_point)
0fc1a713
JS
1888 break;
1889
1890 // N.B. in OnMoveControlPoint, an event handler in Hardy could have deselected
1891 // the line and therefore deleted 'this'. -> GPF, intermittently.
1892 // So assume at this point that we've been blown away.
0fc1a713 1893
2e5ed787 1894 lineShape->OnMoveControlPoint(i+1, x, y);
42cfaf8c 1895#endif
0fc1a713
JS
1896}
1897
2e5ed787
JS
1898// This is called only when a non-end control point is moved.
1899bool wxLineShape::OnMoveMiddleControlPoint(wxDC& dc, wxLineControlPoint* lpt, const wxRealPoint& pt)
1900{
1901 lpt->m_xpos = pt.x; lpt->m_ypos = pt.y;
1902 lpt->m_point->x = pt.x; lpt->m_point->y = pt.y;
1903
1904 GetEventHandler()->OnMoveLink(dc);
1905
1906 return TRUE;
1907}
1908
0fc1a713 1909// Implement movement of endpoint to a new attachment
42cfaf8c
JS
1910// OBSOLETE: done by dragging with the left button.
1911
1912#if 0
1913void wxLineControlPoint::OnDragRight(bool draw, double x, double y, int keys, int attachment)
0fc1a713
JS
1914{
1915 if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO)
1916 {
1917 m_xpos = x; m_ypos = y;
1918 }
1919}
1920
42cfaf8c 1921void wxLineControlPoint::OnBeginDragRight(double x, double y, int keys, int attachment)
0fc1a713
JS
1922{
1923 wxClientDC dc(GetCanvas());
1924 GetCanvas()->PrepareDC(dc);
1925
1926 wxLineShape *lineShape = (wxLineShape *)m_shape;
1927 if (m_type == CONTROL_POINT_ENDPOINT_FROM || m_type == CONTROL_POINT_ENDPOINT_TO)
1928 {
1929 Erase(dc);
1930 lineShape->GetEventHandler()->OnDraw(dc);
1931 if (m_type == CONTROL_POINT_ENDPOINT_FROM)
1932 {
1933 lineShape->GetFrom()->GetEventHandler()->OnDraw(dc);
1934 lineShape->GetFrom()->GetEventHandler()->OnDrawContents(dc);
1935 }
1936 else
1937 {
1938 lineShape->GetTo()->GetEventHandler()->OnDraw(dc);
1939 lineShape->GetTo()->GetEventHandler()->OnDrawContents(dc);
1940 }
42cfaf8c 1941 m_canvas->SetCursor(g_oglBullseyeCursor);
0fc1a713
JS
1942 m_oldCursor = wxSTANDARD_CURSOR;
1943 }
1944}
1945
42cfaf8c 1946void wxLineControlPoint::OnEndDragRight(double x, double y, int keys, int attachment)
0fc1a713
JS
1947{
1948 wxClientDC dc(GetCanvas());
1949 GetCanvas()->PrepareDC(dc);
1950
1951 wxLineShape *lineShape = (wxLineShape *)m_shape;
1952 if (m_type == CONTROL_POINT_ENDPOINT_FROM)
1953 {
1954 if (m_oldCursor)
1955 m_canvas->SetCursor(m_oldCursor);
1956
1957 m_xpos = x; m_ypos = y;
1958
1959 if (lineShape->GetFrom())
1960 {
1961 lineShape->GetFrom()->EraseLinks(dc);
1962
1963 int new_attachment;
42cfaf8c 1964 double distance;
0fc1a713
JS
1965
1966 if (lineShape->GetFrom()->HitTest(x, y, &new_attachment, &distance))
1967 lineShape->SetAttachments(new_attachment, lineShape->GetAttachmentTo());
1968
1969 lineShape->GetFrom()->MoveLinks(dc);
1970 }
1971 }
1972 if (m_type == CONTROL_POINT_ENDPOINT_TO)
1973 {
1974 if (m_oldCursor)
1975 m_canvas->SetCursor(m_oldCursor);
1976 m_shape->Erase(dc);
1977
1978 m_xpos = x; m_ypos = y;
1979
1980 if (lineShape->GetTo())
1981 {
1982 lineShape->GetTo()->EraseLinks(dc);
1983
1984 int new_attachment;
42cfaf8c 1985 double distance;
0fc1a713
JS
1986 if (lineShape->GetTo()->HitTest(x, y, &new_attachment, &distance))
1987 lineShape->SetAttachments(lineShape->GetAttachmentFrom(), new_attachment);
1988
1989 lineShape->GetTo()->MoveLinks(dc);
1990 }
1991 }
1992 int i = 0;
1993 for (i = 0; i < lineShape->GetLineControlPoints()->Number(); i++)
1994 if (((wxRealPoint *)(lineShape->GetLineControlPoints()->Nth(i)->Data())) == m_point)
1995 break;
1996 lineShape->OnMoveControlPoint(i+1, x, y);
1997 if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1998}
42cfaf8c 1999#endif
0fc1a713
JS
2000
2001/*
2002 * Get the point on the given line (x1, y1) (x2, y2)
2003 * distance 'length' along from the end,
2004 * returned values in x and y
2005 */
2006
42cfaf8c
JS
2007void GetPointOnLine(double x1, double y1, double x2, double y2,
2008 double length, double *x, double *y)
0fc1a713 2009{
42cfaf8c 2010 double l = (double)sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1));
0fc1a713
JS
2011
2012 if (l < 0.01)
42cfaf8c 2013 l = (double) 0.01;
0fc1a713 2014
42cfaf8c
JS
2015 double i_bar = (x2 - x1)/l;
2016 double j_bar = (y2 - y1)/l;
0fc1a713
JS
2017
2018 *x = (- length*i_bar) + x2;
2019 *y = (- length*j_bar) + y2;
2020}
2021
42cfaf8c 2022wxArrowHead *wxLineShape::AddArrow(WXTYPE type, int end, double size, double xOffset,
0fc1a713
JS
2023 const wxString& name, wxPseudoMetaFile *mf, long arrowId)
2024{
2025 wxArrowHead *arrow = new wxArrowHead(type, end, size, xOffset, name, mf, arrowId);
2026 m_arcArrows.Append(arrow);
2027 return arrow;
2028}
2029
2030/*
2031 * Add arrowhead at a particular position in the arrowhead list.
2032 */
2033bool wxLineShape::AddArrowOrdered(wxArrowHead *arrow, wxList& referenceList, int end)
2034{
2035 wxNode *refNode = referenceList.First();
2036 wxNode *currNode = m_arcArrows.First();
2037 wxString targetName(arrow->GetName());
2038 if (!refNode) return FALSE;
2039
2040 // First check whether we need to insert in front of list,
2041 // because this arrowhead is the first in the reference
2042 // list and should therefore be first in the current list.
2043 wxArrowHead *refArrow = (wxArrowHead *)refNode->Data();
2044 if (refArrow->GetName() == targetName)
2045 {
2046 m_arcArrows.Insert(arrow);
2047 return TRUE;
2048 }
2049
2050 while (refNode && currNode)
2051 {
2052 wxArrowHead *currArrow = (wxArrowHead *)currNode->Data();
2053 refArrow = (wxArrowHead *)refNode->Data();
2054
2055 // Matching: advance current arrow pointer
2056 if ((currArrow->GetArrowEnd() == end) &&
2057 (currArrow->GetName() == refArrow->GetName()))
2058 {
2059 currNode = currNode->Next(); // Could be NULL now
2060 if (currNode)
2061 currArrow = (wxArrowHead *)currNode->Data();
2062 }
2063
2064 // Check if we're at the correct position in the
2065 // reference list
2066 if (targetName == refArrow->GetName())
2067 {
2068 if (currNode)
2069 m_arcArrows.Insert(currNode, arrow);
2070 else
2071 m_arcArrows.Append(arrow);
2072 return TRUE;
2073 }
2074 refNode = refNode->Next();
2075 }
2076 m_arcArrows.Append(arrow);
2077 return TRUE;
2078}
2079
2080void wxLineShape::ClearArrowsAtPosition(int end)
2081{
2082 wxNode *node = m_arcArrows.First();
2083 while (node)
2084 {
2085 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2086 wxNode *next = node->Next();
2087 switch (end)
2088 {
2089 case -1:
2090 {
2091 delete arrow;
2092 delete node;
2093 break;
2094 }
2095 case ARROW_POSITION_START:
2096 {
2097 if (arrow->GetArrowEnd() == ARROW_POSITION_START)
2098 {
2099 delete arrow;
2100 delete node;
2101 }
2102 break;
2103 }
2104 case ARROW_POSITION_END:
2105 {
2106 if (arrow->GetArrowEnd() == ARROW_POSITION_END)
2107 {
2108 delete arrow;
2109 delete node;
2110 }
2111 break;
2112 }
2113 case ARROW_POSITION_MIDDLE:
2114 {
2115 if (arrow->GetArrowEnd() == ARROW_POSITION_MIDDLE)
2116 {
2117 delete arrow;
2118 delete node;
2119 }
2120 break;
2121 }
2122 }
2123 node = next;
2124 }
2125}
2126
2127bool wxLineShape::ClearArrow(const wxString& name)
2128{
2129 wxNode *node = m_arcArrows.First();
2130 while (node)
2131 {
2132 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2133 if (arrow->GetName() == name)
2134 {
2135 delete arrow;
2136 delete node;
2137 return TRUE;
2138 }
2139 node = node->Next();
2140 }
2141 return FALSE;
2142}
2143
2144/*
2145 * Finds an arrowhead at the given position (if -1, any position)
2146 *
2147 */
2148
2149wxArrowHead *wxLineShape::FindArrowHead(int position, const wxString& name)
2150{
2151 wxNode *node = m_arcArrows.First();
2152 while (node)
2153 {
2154 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2155 if (((position == -1) || (position == arrow->GetArrowEnd())) &&
2156 (arrow->GetName() == name))
2157 return arrow;
2158 node = node->Next();
2159 }
2160 return NULL;
2161}
2162
2163wxArrowHead *wxLineShape::FindArrowHead(long arrowId)
2164{
2165 wxNode *node = m_arcArrows.First();
2166 while (node)
2167 {
2168 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2169 if (arrowId == arrow->GetId())
2170 return arrow;
2171 node = node->Next();
2172 }
2173 return NULL;
2174}
2175
2176/*
2177 * Deletes an arrowhead at the given position (if -1, any position)
2178 *
2179 */
2180
2181bool wxLineShape::DeleteArrowHead(int position, const wxString& name)
2182{
2183 wxNode *node = m_arcArrows.First();
2184 while (node)
2185 {
2186 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2187 if (((position == -1) || (position == arrow->GetArrowEnd())) &&
2188 (arrow->GetName() == name))
2189 {
2190 delete arrow;
2191 delete node;
2192 return TRUE;
2193 }
2194 node = node->Next();
2195 }
2196 return FALSE;
2197}
2198
2199// Overloaded DeleteArrowHead: pass arrowhead id.
2200bool wxLineShape::DeleteArrowHead(long id)
2201{
2202 wxNode *node = m_arcArrows.First();
2203 while (node)
2204 {
2205 wxArrowHead *arrow = (wxArrowHead *)node->Data();
2206 if (arrow->GetId() == id)
2207 {
2208 delete arrow;
2209 delete node;
2210 return TRUE;
2211 }
2212 node = node->Next();
2213 }
2214 return FALSE;
2215}
2216
2217/*
2218 * Calculate the minimum width a line
2219 * occupies, for the purposes of drawing lines in tools.
2220 *
2221 */
2222
42cfaf8c 2223double wxLineShape::FindMinimumWidth()
0fc1a713 2224{
42cfaf8c 2225 double minWidth = 0.0;
0fc1a713
JS
2226 wxNode *node = m_arcArrows.First();
2227 while (node)
2228 {
2229 wxArrowHead *arrowHead = (wxArrowHead *)node->Data();
2230 minWidth += arrowHead->GetSize();
2231 if (node->Next())
2232 minWidth += arrowHead->GetSpacing();
2233
2234 node = node->Next();
2235 }
2236 // We have ABSOLUTE minimum now. So
2237 // scale it to give it reasonable aesthetics
2238 // when drawing with line.
2239 if (minWidth > 0.0)
42cfaf8c 2240 minWidth = (double)(minWidth * 1.4);
0fc1a713
JS
2241 else
2242 minWidth = 20.0;
2243
2244 SetEnds(0.0, 0.0, minWidth, 0.0);
2245 Initialise();
2246
2247 return minWidth;
2248}
2249
2250// Find which position we're talking about at this (x, y).
2251// Returns ARROW_POSITION_START, ARROW_POSITION_MIDDLE, ARROW_POSITION_END
42cfaf8c 2252int wxLineShape::FindLinePosition(double x, double y)
0fc1a713 2253{
42cfaf8c 2254 double startX, startY, endX, endY;
0fc1a713
JS
2255 GetEnds(&startX, &startY, &endX, &endY);
2256
2257 // Find distances from centre, start and end. The smallest wins.
42cfaf8c
JS
2258 double centreDistance = (double)(sqrt((x - m_xpos)*(x - m_xpos) + (y - m_ypos)*(y - m_ypos)));
2259 double startDistance = (double)(sqrt((x - startX)*(x - startX) + (y - startY)*(y - startY)));
2260 double endDistance = (double)(sqrt((x - endX)*(x - endX) + (y - endY)*(y - endY)));
0fc1a713
JS
2261
2262 if (centreDistance < startDistance && centreDistance < endDistance)
2263 return ARROW_POSITION_MIDDLE;
2264 else if (startDistance < endDistance)
2265 return ARROW_POSITION_START;
2266 else
2267 return ARROW_POSITION_END;
2268}
2269
2270// Set alignment flags
2271void wxLineShape::SetAlignmentOrientation(bool isEnd, bool isHoriz)
2272{
2273 if (isEnd)
2274 {
2275 if (isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ))
2276 m_alignmentEnd |= LINE_ALIGNMENT_HORIZ;
2277 else if (!isHoriz && ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ))
2278 m_alignmentEnd -= LINE_ALIGNMENT_HORIZ;
2279 }
2280 else
2281 {
2282 if (isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) != LINE_ALIGNMENT_HORIZ))
2283 m_alignmentStart |= LINE_ALIGNMENT_HORIZ;
2284 else if (!isHoriz && ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ))
2285 m_alignmentStart -= LINE_ALIGNMENT_HORIZ;
2286 }
2287}
2288
2289void wxLineShape::SetAlignmentType(bool isEnd, int alignType)
2290{
2291 if (isEnd)
2292 {
2293 if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE)
2294 {
2295 if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE)
2296 m_alignmentEnd |= LINE_ALIGNMENT_TO_NEXT_HANDLE;
2297 }
2298 else if ((m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE)
2299 m_alignmentEnd -= LINE_ALIGNMENT_TO_NEXT_HANDLE;
2300 }
2301 else
2302 {
2303 if (alignType == LINE_ALIGNMENT_TO_NEXT_HANDLE)
2304 {
2305 if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) != LINE_ALIGNMENT_TO_NEXT_HANDLE)
2306 m_alignmentStart |= LINE_ALIGNMENT_TO_NEXT_HANDLE;
2307 }
2308 else if ((m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE) == LINE_ALIGNMENT_TO_NEXT_HANDLE)
2309 m_alignmentStart -= LINE_ALIGNMENT_TO_NEXT_HANDLE;
2310 }
2311}
2312
2313bool wxLineShape::GetAlignmentOrientation(bool isEnd)
2314{
2315 if (isEnd)
2316 return ((m_alignmentEnd & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ);
2317 else
2318 return ((m_alignmentStart & LINE_ALIGNMENT_HORIZ) == LINE_ALIGNMENT_HORIZ);
2319}
2320
2321int wxLineShape::GetAlignmentType(bool isEnd)
2322{
2323 if (isEnd)
2324 return (m_alignmentEnd & LINE_ALIGNMENT_TO_NEXT_HANDLE);
2325 else
2326 return (m_alignmentStart & LINE_ALIGNMENT_TO_NEXT_HANDLE);
2327}
2328
2329wxRealPoint *wxLineShape::GetNextControlPoint(wxShape *nodeObject)
2330{
2331 int n = m_lineControlPoints->Number();
2332 int nn = 0;
2333 if (m_to == nodeObject)
2334 {
2335 // Must be END of line, so we want (n - 1)th control point.
2336 // But indexing ends at n-1, so subtract 2.
2337 nn = n - 2;
2338 }
2339 else nn = 1;
2340 wxNode *node = m_lineControlPoints->Nth(nn);
2341 if (node)
2342 {
2343 return (wxRealPoint *)node->Data();
2344 }
2345 else
2346 return FALSE;
2347}
2348
2349/*
2350 * Arrowhead
2351 *
2352 */
2353
2354IMPLEMENT_DYNAMIC_CLASS(wxArrowHead, wxObject)
2355
42cfaf8c 2356wxArrowHead::wxArrowHead(WXTYPE type, int end, double size, double dist, const wxString& name,
0fc1a713
JS
2357 wxPseudoMetaFile *mf, long arrowId)
2358{
2359 m_arrowType = type; m_arrowEnd = end; m_arrowSize = size;
2360 m_xOffset = dist;
2361 m_yOffset = 0.0;
2362 m_spacing = 5.0;
2363
2364 m_arrowName = name;
2365 m_metaFile = mf;
2366 m_id = arrowId;
2367 if (m_id == -1)
2368 m_id = NewId();
2369}
2370
2371wxArrowHead::wxArrowHead(wxArrowHead& toCopy)
2372{
2373 m_arrowType = toCopy.m_arrowType; m_arrowEnd = toCopy.GetArrowEnd();
2374 m_arrowSize = toCopy.m_arrowSize;
2375 m_xOffset = toCopy.m_xOffset;
2376 m_yOffset = toCopy.m_yOffset;
2377 m_spacing = toCopy.m_spacing;
2378 m_arrowName = toCopy.m_arrowName ;
2379 if (toCopy.m_metaFile)
2380 m_metaFile = new wxPseudoMetaFile(*(toCopy.m_metaFile));
2381 else
2382 m_metaFile = NULL;
2383 m_id = NewId();
2384}
2385
2386wxArrowHead::~wxArrowHead()
2387{
2388 if (m_metaFile) delete m_metaFile;
2389}
2390
42cfaf8c 2391void wxArrowHead::SetSize(double size)
0fc1a713
JS
2392{
2393 m_arrowSize = size;
2394 if ((m_arrowType == ARROW_METAFILE) && m_metaFile)
2395 {
42cfaf8c 2396 double oldWidth = m_metaFile->m_width;
0fc1a713
JS
2397 if (oldWidth == 0.0)
2398 return;
2399
42cfaf8c 2400 double scale = (double)(size/oldWidth);
0fc1a713
JS
2401 if (scale != 1.0)
2402 m_metaFile->Scale(scale, scale);
2403 }
2404}
2405
2e5ed787
JS
2406// Can override this to create a different class of label shape
2407wxLabelShape* wxLineShape::OnCreateLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h)
2408{
2409 return new wxLabelShape(parent, region, w, h);
2410}
2411
0fc1a713
JS
2412/*
2413 * Label object
2414 *
2415 */
2416
2417IMPLEMENT_DYNAMIC_CLASS(wxLabelShape, wxRectangleShape)
2418
42cfaf8c 2419wxLabelShape::wxLabelShape(wxLineShape *parent, wxShapeRegion *region, double w, double h):wxRectangleShape(w, h)
0fc1a713
JS
2420{
2421 m_lineShape = parent;
2422 m_shapeRegion = region;
2423 SetPen(wxThePenList->FindOrCreatePen(wxColour(0, 0, 0), 1, wxDOT));
2424}
2425
2426wxLabelShape::~wxLabelShape()
2427{
2428}
2429
2430void wxLabelShape::OnDraw(wxDC& dc)
2431{
2432 if (m_lineShape && !m_lineShape->GetDrawHandles())
2433 return;
2434
42cfaf8c
JS
2435 double x1 = (double)(m_xpos - m_width/2.0);
2436 double y1 = (double)(m_ypos - m_height/2.0);
0fc1a713
JS
2437
2438 if (m_pen)
2439 {
2440 if (m_pen->GetWidth() == 0)
42cfaf8c 2441 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
2442 else
2443 dc.SetPen(m_pen);
2444 }
2445 dc.SetBrush(wxTRANSPARENT_BRUSH);
2446
2447 if (m_cornerRadius > 0.0)
42cfaf8c 2448 dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
0fc1a713 2449 else
42cfaf8c 2450 dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height));
0fc1a713
JS
2451}
2452
2453void wxLabelShape::OnDrawContents(wxDC& dc)
2454{
2455}
2456
42cfaf8c 2457void wxLabelShape::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713
JS
2458{
2459 wxRectangleShape::OnDragLeft(draw, x, y, keys, attachment);
2460}
2461
42cfaf8c 2462void wxLabelShape::OnBeginDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
2463{
2464 wxRectangleShape::OnBeginDragLeft(x, y, keys, attachment);
2465}
2466
42cfaf8c 2467void wxLabelShape::OnEndDragLeft(double x, double y, int keys, int attachment)
0fc1a713
JS
2468{
2469 wxRectangleShape::OnEndDragLeft(x, y, keys, attachment);
2470}
2471
42cfaf8c 2472bool wxLabelShape::OnMovePre(wxDC& dc, double x, double y, double old_x, double old_y, bool display)
0fc1a713 2473{
2e5ed787
JS
2474 return m_lineShape->OnLabelMovePre(dc, this, x, y, old_x, old_y, display);
2475}
2476
2477bool wxLineShape::OnLabelMovePre(wxDC& dc, wxLabelShape* labelShape, double x, double y, double old_x, double old_y, bool display)
2478{
2479 labelShape->m_shapeRegion->SetSize(labelShape->GetWidth(), labelShape->GetHeight());
0fc1a713
JS
2480
2481 // Find position in line's region list
2482 int i = 0;
2e5ed787 2483 wxNode *node = GetRegions().First();
0fc1a713
JS
2484 while (node)
2485 {
2e5ed787 2486 if (labelShape->m_shapeRegion == (wxShapeRegion *)node->Data())
0fc1a713
JS
2487 node = NULL;
2488 else
2489 {
2490 node = node->Next();
2491 i ++;
2492 }
2493 }
42cfaf8c 2494 double xx, yy;
2e5ed787 2495 GetLabelPosition(i, &xx, &yy);
0fc1a713
JS
2496 // Set the region's offset, relative to the default position for
2497 // each region.
2e5ed787
JS
2498 labelShape->m_shapeRegion->SetPosition((double)(x - xx), (double)(y - yy));
2499
2500 labelShape->SetX(x);
2501 labelShape->SetY(y);
0fc1a713
JS
2502
2503 // Need to reformat to fit region.
2e5ed787 2504 if (labelShape->m_shapeRegion->GetText())
0fc1a713
JS
2505 {
2506
2e5ed787
JS
2507 wxString s(labelShape->m_shapeRegion->GetText());
2508 labelShape->FormatText(dc, s, i);
2509 DrawRegion(dc, labelShape->m_shapeRegion, xx, yy);
0fc1a713
JS
2510 }
2511 return TRUE;
2512}
2513
2514// Divert left and right clicks to line object
42cfaf8c 2515void wxLabelShape::OnLeftClick(double x, double y, int keys, int attachment)
0fc1a713
JS
2516{
2517 m_lineShape->GetEventHandler()->OnLeftClick(x, y, keys, attachment);
2518}
2519
42cfaf8c 2520void wxLabelShape::OnRightClick(double x, double y, int keys, int attachment)
0fc1a713
JS
2521{
2522 m_lineShape->GetEventHandler()->OnRightClick(x, y, keys, attachment);
2523}
2524