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