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