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