]> git.saurik.com Git - wxWidgets.git/blame - utils/ogl/src/basic2.cpp
Added sys/types.h needed for Solaris.
[wxWidgets.git] / utils / ogl / src / basic2.cpp
CommitLineData
0fc1a713
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: basic2.cpp
3// Purpose: Basic OGL classes (2)
4// Author: Julian Smart
5// Modified by:
6// Created: 12/07/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#endif
14
15// For compilers that support precompilation, includes "wx.h".
16#include <wx/wxprec.h>
17
18#ifdef __BORLANDC__
19#pragma hdrstop
20#endif
21
22#ifndef WX_PRECOMP
23#include <wx/wx.h>
24#endif
25
26#ifdef PROLOGIO
27#include <wx/wxexpr.h>
28#endif
29
47d67540 30#if wxUSE_IOSTREAMH
0fc1a713
JS
31#include <iostream.h>
32#else
33#include <iostream>
34#endif
35
36#include <stdio.h>
37#include <ctype.h>
38#include <math.h>
39
40#include "basic.h"
41#include "basicp.h"
42#include "composit.h"
43#include "lines.h"
44#include "canvas.h"
45#include "divided.h"
46#include "misc.h"
47
48// Control point types
49// Rectangle and most other shapes
50#define CONTROL_POINT_VERTICAL 1
51#define CONTROL_POINT_HORIZONTAL 2
52#define CONTROL_POINT_DIAGONAL 3
53
54// Line
55#define CONTROL_POINT_ENDPOINT_TO 4
56#define CONTROL_POINT_ENDPOINT_FROM 5
57#define CONTROL_POINT_LINE 6
58
59// Two stage construction: need to call Create
60IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape, wxShape)
61
62wxPolygonShape::wxPolygonShape()
63{
64 m_points = NULL;
65 m_originalPoints = NULL;
66}
67
68void wxPolygonShape::Create(wxList *the_points)
69{
5de76427
JS
70 ClearPoints();
71
0fc1a713
JS
72 m_originalPoints = the_points;
73
74 // Duplicate the list of points
75 m_points = new wxList;
76
77 wxNode *node = the_points->First();
78 while (node)
79 {
80 wxRealPoint *point = (wxRealPoint *)node->Data();
81 wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
82 m_points->Append((wxObject*) new_point);
83 node = node->Next();
84 }
85 CalculateBoundingBox();
86 m_originalWidth = m_boundWidth;
87 m_originalHeight = m_boundHeight;
88 SetDefaultRegionSize();
89}
90
91wxPolygonShape::~wxPolygonShape()
5de76427
JS
92{
93 ClearPoints();
94}
95
96void wxPolygonShape::ClearPoints()
0fc1a713
JS
97{
98 if (m_points)
99 {
100 wxNode *node = m_points->First();
101 while (node)
102 {
103 wxRealPoint *point = (wxRealPoint *)node->Data();
104 delete point;
105 delete node;
106 node = m_points->First();
107 }
108 delete m_points;
5de76427 109 m_points = NULL;
0fc1a713
JS
110 }
111 if (m_originalPoints)
112 {
113 wxNode *node = m_originalPoints->First();
114 while (node)
115 {
116 wxRealPoint *point = (wxRealPoint *)node->Data();
117 delete point;
118 delete node;
119 node = m_originalPoints->First();
120 }
121 delete m_originalPoints;
5de76427 122 m_originalPoints = NULL;
0fc1a713
JS
123 }
124}
125
126
127// Width and height. Centre of object is centre of box.
42cfaf8c 128void wxPolygonShape::GetBoundingBoxMin(double *width, double *height)
0fc1a713
JS
129{
130 *width = m_boundWidth;
131 *height = m_boundHeight;
132}
133
134void wxPolygonShape::CalculateBoundingBox()
135{
136 // Calculate bounding box at construction (and presumably resize) time
42cfaf8c
JS
137 double left = 10000;
138 double right = -10000;
139 double top = 10000;
140 double bottom = -10000;
0fc1a713
JS
141
142 wxNode *node = m_points->First();
143 while (node)
144 {
145 wxRealPoint *point = (wxRealPoint *)node->Data();
146 if (point->x < left) left = point->x;
147 if (point->x > right) right = point->x;
148
149 if (point->y < top) top = point->y;
150 if (point->y > bottom) bottom = point->y;
151
152 node = node->Next();
153 }
154 m_boundWidth = right - left;
155 m_boundHeight = bottom - top;
156}
157
158// Recalculates the centre of the polygon, and
159// readjusts the point offsets accordingly.
160// Necessary since the centre of the polygon
161// is expected to be the real centre of the bounding
162// box.
163void wxPolygonShape::CalculatePolygonCentre()
164{
42cfaf8c
JS
165 double left = 10000;
166 double right = -10000;
167 double top = 10000;
168 double bottom = -10000;
0fc1a713
JS
169
170 wxNode *node = m_points->First();
171 while (node)
172 {
173 wxRealPoint *point = (wxRealPoint *)node->Data();
174 if (point->x < left) left = point->x;
175 if (point->x > right) right = point->x;
176
177 if (point->y < top) top = point->y;
178 if (point->y > bottom) bottom = point->y;
179
180 node = node->Next();
181 }
42cfaf8c
JS
182 double bwidth = right - left;
183 double bheight = bottom - top;
184
185 double newCentreX = (double)(left + (bwidth/2.0));
186 double newCentreY = (double)(top + (bheight/2.0));
0fc1a713
JS
187
188 node = m_points->First();
189 while (node)
190 {
191 wxRealPoint *point = (wxRealPoint *)node->Data();
192 point->x -= newCentreX;
193 point->y -= newCentreY;
194 node = node->Next();
195 }
196 m_xpos += newCentreX;
197 m_ypos += newCentreY;
198}
199
42cfaf8c
JS
200bool PolylineHitTest(double n, double xvec[], double yvec[],
201 double x1, double y1, double x2, double y2)
0fc1a713
JS
202{
203 bool isAHit = FALSE;
204 int i;
42cfaf8c
JS
205 double lastx = xvec[0];
206 double lasty = yvec[0];
0fc1a713 207
42cfaf8c
JS
208 double min_ratio = 1.0;
209 double line_ratio;
210 double other_ratio;
0fc1a713
JS
211
212// char buf[300];
213 for (i = 1; i < n; i++)
214 {
42cfaf8c 215 oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i],
0fc1a713
JS
216 &line_ratio, &other_ratio);
217 if (line_ratio != 1.0)
218 isAHit = TRUE;
219// sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
220// ClipsErrorFunction(buf);
221 lastx = xvec[i];
222 lasty = yvec[i];
223
224 if (line_ratio < min_ratio)
225 min_ratio = line_ratio;
226 }
227
42cfaf8c 228 // Do last (implicit) line if last and first doubles are not identical
0fc1a713
JS
229 if (!(xvec[0] == lastx && yvec[0] == lasty))
230 {
42cfaf8c 231 oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0],
0fc1a713
JS
232 &line_ratio, &other_ratio);
233 if (line_ratio != 1.0)
234 isAHit = TRUE;
235// sprintf(buf, "Line ratio = %.2f, other ratio = %.2f\n", line_ratio, other_ratio);
236// ClipsErrorFunction(buf);
237
238 if (line_ratio < min_ratio)
239 min_ratio = line_ratio;
240 }
241// ClipsErrorFunction("\n");
242 return isAHit;
243}
244
42cfaf8c 245bool wxPolygonShape::HitTest(double x, double y, int *attachment, double *distance)
0fc1a713
JS
246{
247 // Imagine four lines radiating from this point. If all of these lines hit the polygon,
248 // we're inside it, otherwise we're not. Obviously we'd need more radiating lines
249 // to be sure of correct results for very strange (concave) shapes.
42cfaf8c
JS
250 double endPointsX[4];
251 double endPointsY[4];
0fc1a713
JS
252 // North
253 endPointsX[0] = x;
42cfaf8c 254 endPointsY[0] = (double)(y - 1000.0);
0fc1a713 255 // East
42cfaf8c 256 endPointsX[1] = (double)(x + 1000.0);
0fc1a713
JS
257 endPointsY[1] = y;
258 // South
259 endPointsX[2] = x;
42cfaf8c 260 endPointsY[2] = (double)(y + 1000.0);
0fc1a713 261 // West
42cfaf8c 262 endPointsX[3] = (double)(x - 1000.0);
0fc1a713
JS
263 endPointsY[3] = y;
264
265 // Store polygon points in an array
266 int np = m_points->Number();
42cfaf8c
JS
267 double *xpoints = new double[np];
268 double *ypoints = new double[np];
0fc1a713
JS
269 wxNode *node = m_points->First();
270 int i = 0;
271 while (node)
272 {
273 wxRealPoint *point = (wxRealPoint *)node->Data();
274 xpoints[i] = point->x + m_xpos;
275 ypoints[i] = point->y + m_ypos;
276 node = node->Next();
277 i ++;
278 }
279
280 // We assume it's inside the polygon UNLESS one or more
281 // lines don't hit the outline.
282 bool isContained = TRUE;
283
284 int noPoints = 4;
285 for (i = 0; i < noPoints; i++)
286 {
287 if (!PolylineHitTest(np, xpoints, ypoints, x, y, endPointsX[i], endPointsY[i]))
288 isContained = FALSE;
289 }
290/*
291 if (isContained)
292 ClipsErrorFunction("It's a hit!\n");
293 else
294 ClipsErrorFunction("No hit.\n");
295*/
296 delete[] xpoints;
297 delete[] ypoints;
298
299 if (!isContained)
300 return FALSE;
301
302 int nearest_attachment = 0;
303
304 // If a hit, check the attachment points within the object.
305 int n = GetNumberOfAttachments();
42cfaf8c 306 double nearest = 999999.0;
0fc1a713
JS
307
308 for (i = 0; i < n; i++)
309 {
42cfaf8c 310 double xp, yp;
0fc1a713
JS
311 if (GetAttachmentPosition(i, &xp, &yp))
312 {
42cfaf8c 313 double l = (double)sqrt(((xp - x) * (xp - x)) +
0fc1a713
JS
314 ((yp - y) * (yp - y)));
315 if (l < nearest)
316 {
317 nearest = l;
318 nearest_attachment = i;
319 }
320 }
321 }
322 *attachment = nearest_attachment;
323 *distance = nearest;
324 return TRUE;
325}
326
327// Really need to be able to reset the shape! Otherwise, if the
328// points ever go to zero, we've lost it, and can't resize.
42cfaf8c 329void wxPolygonShape::SetSize(double new_width, double new_height, bool recursive)
0fc1a713
JS
330{
331 SetAttachmentSize(new_width, new_height);
332
333 // Multiply all points by proportion of new size to old size
42cfaf8c
JS
334 double x_proportion = (double)(fabs(new_width/m_originalWidth));
335 double y_proportion = (double)(fabs(new_height/m_originalHeight));
0fc1a713
JS
336
337 wxNode *node = m_points->First();
338 wxNode *original_node = m_originalPoints->First();
339 while (node && original_node)
340 {
341 wxRealPoint *point = (wxRealPoint *)node->Data();
342 wxRealPoint *original_point = (wxRealPoint *)original_node->Data();
343
344 point->x = (original_point->x * x_proportion);
345 point->y = (original_point->y * y_proportion);
346
347 node = node->Next();
348 original_node = original_node->Next();
349 }
350
351// CalculateBoundingBox();
42cfaf8c
JS
352 m_boundWidth = (double)fabs(new_width);
353 m_boundHeight = (double)fabs(new_height);
0fc1a713
JS
354 SetDefaultRegionSize();
355}
356
357// Make the original points the same as the working points
358void wxPolygonShape::UpdateOriginalPoints()
359{
360 if (!m_originalPoints) m_originalPoints = new wxList;
361 wxNode *original_node = m_originalPoints->First();
362 while (original_node)
363 {
364 wxNode *next_node = original_node->Next();
365 wxRealPoint *original_point = (wxRealPoint *)original_node->Data();
366 delete original_point;
367 delete original_node;
368
369 original_node = next_node;
370 }
371
372 wxNode *node = m_points->First();
373 while (node)
374 {
375 wxRealPoint *point = (wxRealPoint *)node->Data();
376 wxRealPoint *original_point = new wxRealPoint(point->x, point->y);
377 m_originalPoints->Append((wxObject*) original_point);
378
379 node = node->Next();
380 }
381 CalculateBoundingBox();
382 m_originalWidth = m_boundWidth;
383 m_originalHeight = m_boundHeight;
384}
385
386void wxPolygonShape::AddPolygonPoint(int pos)
387{
388 wxNode *node = m_points->Nth(pos);
389 if (!node) node = m_points->First();
390 wxRealPoint *firstPoint = (wxRealPoint *)node->Data();
391
392 wxNode *node2 = m_points->Nth(pos + 1);
393 if (!node2) node2 = m_points->First();
394 wxRealPoint *secondPoint = (wxRealPoint *)node2->Data();
395
42cfaf8c
JS
396 double x = (double)((secondPoint->x - firstPoint->x)/2.0 + firstPoint->x);
397 double y = (double)((secondPoint->y - firstPoint->y)/2.0 + firstPoint->y);
0fc1a713
JS
398 wxRealPoint *point = new wxRealPoint(x, y);
399
400 if (pos >= (m_points->Number() - 1))
401 m_points->Append((wxObject*) point);
402 else
403 m_points->Insert(node2, (wxObject*) point);
404
405 UpdateOriginalPoints();
406
407 if (m_selected)
408 {
409 DeleteControlPoints();
410 MakeControlPoints();
411 }
412}
413
414void wxPolygonShape::DeletePolygonPoint(int pos)
415{
416 wxNode *node = m_points->Nth(pos);
417 if (node)
418 {
419 wxRealPoint *point = (wxRealPoint *)node->Data();
420 delete point;
421 delete node;
422 UpdateOriginalPoints();
423 if (m_selected)
424 {
425 DeleteControlPoints();
426 MakeControlPoints();
427 }
428 }
429}
430
431// Assume (x1, y1) is centre of box (most generally, line end at box)
42cfaf8c
JS
432bool wxPolygonShape::GetPerimeterPoint(double x1, double y1,
433 double x2, double y2,
434 double *x3, double *y3)
0fc1a713
JS
435{
436 int n = m_points->Number();
437
438 // First check for situation where the line is vertical,
439 // and we would want to connect to a point on that vertical --
42cfaf8c 440 // oglFindEndForPolyline can't cope with this (the arrow
0fc1a713
JS
441 // gets drawn to the wrong place).
442 if ((!m_attachmentMode) && (x1 == x2))
443 {
444 // Look for the point we'd be connecting to. This is
445 // a heuristic...
446 wxNode *node = m_points->First();
447 while (node)
448 {
449 wxRealPoint *point = (wxRealPoint *)node->Data();
450 if (point->x == 0.0)
451 {
452 if ((y2 > y1) && (point->y > 0.0))
453 {
454 *x3 = point->x + m_xpos;
455 *y3 = point->y + m_ypos;
456 return TRUE;
457 }
458 else if ((y2 < y1) && (point->y < 0.0))
459 {
460 *x3 = point->x + m_xpos;
461 *y3 = point->y + m_ypos;
462 return TRUE;
463 }
464 }
465 node = node->Next();
466 }
467 }
468
42cfaf8c
JS
469 double *xpoints = new double[n];
470 double *ypoints = new double[n];
0fc1a713
JS
471
472 wxNode *node = m_points->First();
473 int i = 0;
474 while (node)
475 {
476 wxRealPoint *point = (wxRealPoint *)node->Data();
477 xpoints[i] = point->x + m_xpos;
478 ypoints[i] = point->y + m_ypos;
479 node = node->Next();
480 i ++;
481 }
0fc1a713 482
42cfaf8c 483 oglFindEndForPolyline(n, xpoints, ypoints,
0fc1a713
JS
484 x1, y1, x2, y2, x3, y3);
485
42cfaf8c
JS
486 delete[] xpoints;
487 delete[] ypoints;
0fc1a713
JS
488
489 return TRUE;
490}
491
492void wxPolygonShape::OnDraw(wxDC& dc)
493{
494 int n = m_points->Number();
495 wxPoint *intPoints = new wxPoint[n];
496 int i;
497 for (i = 0; i < n; i++)
498 {
499 wxRealPoint* point = (wxRealPoint*) m_points->Nth(i)->Data();
42cfaf8c
JS
500 intPoints[i].x = WXROUND(point->x);
501 intPoints[i].y = WXROUND(point->y);
0fc1a713
JS
502 }
503
504 if (m_shadowMode != SHADOW_NONE)
505 {
506 if (m_shadowBrush)
507 dc.SetBrush(m_shadowBrush);
42cfaf8c 508 dc.SetPen(g_oglTransparentPen);
0fc1a713 509
42cfaf8c 510 dc.DrawPolygon(n, intPoints, WXROUND(m_xpos + m_shadowOffsetX), WXROUND(m_ypos + m_shadowOffsetY));
0fc1a713
JS
511 }
512
513 if (m_pen)
514 {
515 if (m_pen->GetWidth() == 0)
42cfaf8c 516 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
517 else
518 dc.SetPen(m_pen);
519 }
520 if (m_brush)
521 dc.SetBrush(m_brush);
42cfaf8c 522 dc.DrawPolygon(n, intPoints, WXROUND(m_xpos), WXROUND(m_ypos));
0fc1a713
JS
523
524 delete[] intPoints;
525}
526
42cfaf8c 527void wxPolygonShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
0fc1a713
JS
528{
529 dc.SetBrush(wxTRANSPARENT_BRUSH);
34138703 530 // Multiply all points by proportion of new size to old size
42cfaf8c
JS
531 double x_proportion = (double)(fabs(w/m_originalWidth));
532 double y_proportion = (double)(fabs(h/m_originalHeight));
0fc1a713 533
34138703 534 int n = m_originalPoints->Number();
0fc1a713
JS
535 wxPoint *intPoints = new wxPoint[n];
536 int i;
537 for (i = 0; i < n; i++)
538 {
34138703 539 wxRealPoint* point = (wxRealPoint*) m_originalPoints->Nth(i)->Data();
42cfaf8c
JS
540 intPoints[i].x = WXROUND(x_proportion * point->x);
541 intPoints[i].y = WXROUND(y_proportion * point->y);
0fc1a713 542 }
42cfaf8c 543 dc.DrawPolygon(n, intPoints, WXROUND(x), WXROUND(y));
5de76427 544 delete[] intPoints;
0fc1a713
JS
545}
546
547// Make as many control points as there are vertices.
548void wxPolygonShape::MakeControlPoints()
549{
550 wxNode *node = m_points->First();
551 while (node)
552 {
553 wxRealPoint *point = (wxRealPoint *)node->Data();
554 wxPolygonControlPoint *control = new wxPolygonControlPoint(m_canvas, this, CONTROL_POINT_SIZE,
555 point, point->x, point->y);
556 m_canvas->AddShape(control);
557 m_controlPoints.Append(control);
558 node = node->Next();
559 }
0fc1a713
JS
560}
561
562void wxPolygonShape::ResetControlPoints()
563{
564 wxNode *node = m_points->First();
565 wxNode *controlPointNode = m_controlPoints.First();
566 while (node && controlPointNode)
567 {
568 wxRealPoint *point = (wxRealPoint *)node->Data();
569 wxPolygonControlPoint *controlPoint = (wxPolygonControlPoint *)controlPointNode->Data();
570
571 controlPoint->m_xoffset = point->x;
572 controlPoint->m_yoffset = point->y;
573 controlPoint->m_polygonVertex = point;
574
575 node = node->Next();
576 controlPointNode = controlPointNode->Next();
577 }
0fc1a713
JS
578}
579
580
581#ifdef PROLOGIO
6f5f3ca0 582void wxPolygonShape::WriteAttributes(wxExpr *clause)
0fc1a713 583{
6f5f3ca0 584 wxShape::WriteAttributes(clause);
0fc1a713
JS
585
586 clause->AddAttributeValue("x", m_xpos);
587 clause->AddAttributeValue("y", m_ypos);
588
589 // Make a list of lists for the coordinates
f93ce4da 590 wxExpr *list = new wxExpr(wxExprList);
0fc1a713
JS
591 wxNode *node = m_points->First();
592 while (node)
593 {
594 wxRealPoint *point = (wxRealPoint *)node->Data();
f93ce4da 595 wxExpr *point_list = new wxExpr(wxExprList);
42cfaf8c
JS
596 wxExpr *x_expr = new wxExpr((double)point->x);
597 wxExpr *y_expr = new wxExpr((double)point->y);
0fc1a713
JS
598
599 point_list->Append(x_expr);
600 point_list->Append(y_expr);
601 list->Append(point_list);
602
603 node = node->Next();
604 }
605 clause->AddAttributeValue("points", list);
606
607 // Save the original (unscaled) points
f93ce4da 608 list = new wxExpr(wxExprList);
0fc1a713
JS
609 node = m_originalPoints->First();
610 while (node)
611 {
612 wxRealPoint *point = (wxRealPoint *)node->Data();
f93ce4da 613 wxExpr *point_list = new wxExpr(wxExprList);
42cfaf8c
JS
614 wxExpr *x_expr = new wxExpr((double) point->x);
615 wxExpr *y_expr = new wxExpr((double) point->y);
0fc1a713
JS
616 point_list->Append(x_expr);
617 point_list->Append(y_expr);
618 list->Append(point_list);
619
620 node = node->Next();
621 }
622 clause->AddAttributeValue("m_originalPoints", list);
623}
624
6f5f3ca0 625void wxPolygonShape::ReadAttributes(wxExpr *clause)
0fc1a713 626{
6f5f3ca0 627 wxShape::ReadAttributes(clause);
0fc1a713
JS
628
629 // Read a list of lists
630 m_points = new wxList;
631 m_originalPoints = new wxList;
632
633 wxExpr *points_list = NULL;
634 clause->AssignAttributeValue("points", &points_list);
635
636 // If no points_list, don't crash!! Assume a diamond instead.
42cfaf8c
JS
637 double the_height = 100.0;
638 double the_width = 100.0;
0fc1a713
JS
639 if (!points_list)
640 {
641 wxRealPoint *point = new wxRealPoint(0.0, (-the_height/2));
642 m_points->Append((wxObject*) point);
643
644 point = new wxRealPoint((the_width/2), 0.0);
645 m_points->Append((wxObject*) point);
646
647 point = new wxRealPoint(0.0, (the_height/2));
648 m_points->Append((wxObject*) point);
649
650 point = new wxRealPoint((-the_width/2), 0.0);
651 m_points->Append((wxObject*) point);
652
653 point = new wxRealPoint(0.0, (-the_height/2));
654 m_points->Append((wxObject*) point);
655 }
656 else
657 {
658 wxExpr *node = points_list->value.first;
659
660 while (node)
661 {
662 wxExpr *xexpr = node->value.first;
663 long x = xexpr->IntegerValue();
664
665 wxExpr *yexpr = xexpr->next;
666 long y = yexpr->IntegerValue();
667
42cfaf8c 668 wxRealPoint *point = new wxRealPoint((double)x, (double)y);
0fc1a713
JS
669 m_points->Append((wxObject*) point);
670
671 node = node->next;
672 }
673 }
674
675 points_list = NULL;
676 clause->AssignAttributeValue("m_originalPoints", &points_list);
677
678 // If no points_list, don't crash!! Assume a diamond instead.
679 if (!points_list)
680 {
681 wxRealPoint *point = new wxRealPoint(0.0, (-the_height/2));
682 m_originalPoints->Append((wxObject*) point);
683
684 point = new wxRealPoint((the_width/2), 0.0);
685 m_originalPoints->Append((wxObject*) point);
686
687 point = new wxRealPoint(0.0, (the_height/2));
688 m_originalPoints->Append((wxObject*) point);
689
690 point = new wxRealPoint((-the_width/2), 0.0);
691 m_originalPoints->Append((wxObject*) point);
692
693 point = new wxRealPoint(0.0, (-the_height/2));
694 m_originalPoints->Append((wxObject*) point);
695
696 m_originalWidth = the_width;
697 m_originalHeight = the_height;
698 }
699 else
700 {
701 wxExpr *node = points_list->value.first;
42cfaf8c
JS
702 double min_x = 1000;
703 double min_y = 1000;
704 double max_x = -1000;
705 double max_y = -1000;
0fc1a713
JS
706 while (node)
707 {
708 wxExpr *xexpr = node->value.first;
709 long x = xexpr->IntegerValue();
710
711 wxExpr *yexpr = xexpr->next;
712 long y = yexpr->IntegerValue();
713
42cfaf8c 714 wxRealPoint *point = new wxRealPoint((double)x, (double)y);
0fc1a713
JS
715 m_originalPoints->Append((wxObject*) point);
716
717 if (x < min_x)
42cfaf8c 718 min_x = (double)x;
0fc1a713 719 if (y < min_y)
42cfaf8c 720 min_y = (double)y;
0fc1a713 721 if (x > max_x)
42cfaf8c 722 max_x = (double)x;
0fc1a713 723 if (y > max_y)
42cfaf8c 724 max_y = (double)y;
0fc1a713
JS
725
726 node = node->next;
727 }
728 m_originalWidth = max_x - min_x;
729 m_originalHeight = max_y - min_y;
730 }
731
732 CalculateBoundingBox();
733}
734#endif
735
2bb0cd28 736void wxPolygonShape::Copy(wxShape& copy)
0fc1a713
JS
737{
738 wxShape::Copy(copy);
739
2bb0cd28 740 wxASSERT( copy.IsKindOf(CLASSINFO(wxPolygonShape)) );
0fc1a713 741
2bb0cd28 742 wxPolygonShape& polyCopy = (wxPolygonShape&) copy;
0fc1a713 743
5de76427 744 polyCopy.ClearPoints();
0fc1a713 745
2bb0cd28 746 polyCopy.m_points = new wxList;
2bb0cd28 747 polyCopy.m_originalPoints = new wxList;
0fc1a713
JS
748
749 wxNode *node = m_points->First();
750 while (node)
751 {
752 wxRealPoint *point = (wxRealPoint *)node->Data();
753 wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
2bb0cd28 754 polyCopy.m_points->Append((wxObject*) new_point);
0fc1a713
JS
755 node = node->Next();
756 }
757 node = m_originalPoints->First();
758 while (node)
759 {
760 wxRealPoint *point = (wxRealPoint *)node->Data();
761 wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
2bb0cd28 762 polyCopy.m_originalPoints->Append((wxObject*) new_point);
0fc1a713
JS
763 node = node->Next();
764 }
2bb0cd28
JS
765 polyCopy.m_boundWidth = m_boundWidth;
766 polyCopy.m_boundHeight = m_boundHeight;
767 polyCopy.m_originalWidth = m_originalWidth;
768 polyCopy.m_originalHeight = m_originalHeight;
0fc1a713
JS
769}
770
6f5f3ca0 771int wxPolygonShape::GetNumberOfAttachments() const
0fc1a713
JS
772{
773 int maxN = (m_points ? (m_points->Number() - 1) : 0);
774 wxNode *node = m_attachmentPoints.First();
775 while (node)
776 {
777 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
778 if (point->m_id > maxN)
779 maxN = point->m_id;
780 node = node->Next();
781 }
782 return maxN+1;;
783}
784
42cfaf8c 785bool wxPolygonShape::GetAttachmentPosition(int attachment, double *x, double *y,
0fc1a713
JS
786 int nth, int no_arcs, wxLineShape *line)
787{
788 if (m_attachmentMode && m_points && attachment < m_points->Number())
789 {
790 wxRealPoint *point = (wxRealPoint *)m_points->Nth(attachment)->Data();
791 *x = point->x + m_xpos;
792 *y = point->y + m_ypos;
793 return TRUE;
794 }
795 else
796 { return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); }
797}
798
799bool wxPolygonShape::AttachmentIsValid(int attachment)
800{
801 if (!m_points)
802 return FALSE;
803
804 if ((attachment >= 0) && (attachment < m_points->Number()))
805 return TRUE;
806
807 wxNode *node = m_attachmentPoints.First();
808 while (node)
809 {
810 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
811 if (point->m_id == attachment)
812 return TRUE;
813 node = node->Next();
814 }
815 return FALSE;
816}
817
f93ce4da
JS
818// Rotate about the given axis by the given amount in radians
819void wxPolygonShape::Rotate(double x, double y, double theta)
820{
821 double actualTheta = theta-m_rotation;
822
823 // Rotate attachment points
824 double sinTheta = (double)sin(actualTheta);
825 double cosTheta = (double)cos(actualTheta);
826 wxNode *node = m_attachmentPoints.First();
827 while (node)
828 {
829 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
830 double x1 = point->m_x;
831 double y1 = point->m_y;
832 point->m_x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
833 point->m_y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
834 node = node->Next();
835 }
836
837 node = m_points->First();
838 while (node)
839 {
840 wxRealPoint *point = (wxRealPoint *)node->Data();
841 double x1 = point->x;
842 double y1 = point->y;
843 point->x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
844 point->y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
845 node = node->Next();
846 }
847 node = m_originalPoints->First();
848 while (node)
849 {
850 wxRealPoint *point = (wxRealPoint *)node->Data();
851 double x1 = point->x;
852 double y1 = point->y;
853 point->x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
854 point->y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
855 node = node->Next();
856 }
857
858 m_rotation = theta;
859
860 CalculatePolygonCentre();
861 CalculateBoundingBox();
862 ResetControlPoints();
863}
864
0fc1a713
JS
865// Rectangle object
866
867IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape, wxShape)
868
42cfaf8c 869wxRectangleShape::wxRectangleShape(double w, double h)
0fc1a713
JS
870{
871 m_width = w; m_height = h; m_cornerRadius = 0.0;
872 SetDefaultRegionSize();
873}
874
875void wxRectangleShape::OnDraw(wxDC& dc)
876{
42cfaf8c
JS
877 double x1 = (double)(m_xpos - m_width/2.0);
878 double y1 = (double)(m_ypos - m_height/2.0);
0fc1a713
JS
879
880 if (m_shadowMode != SHADOW_NONE)
881 {
882 if (m_shadowBrush)
883 dc.SetBrush(m_shadowBrush);
42cfaf8c 884 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
885
886 if (m_cornerRadius != 0.0)
42cfaf8c
JS
887 dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY),
888 WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
0fc1a713 889 else
42cfaf8c 890 dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height));
0fc1a713
JS
891 }
892
893 if (m_pen)
894 {
895 if (m_pen->GetWidth() == 0)
42cfaf8c 896 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
897 else
898 dc.SetPen(m_pen);
899 }
900 if (m_brush)
901 dc.SetBrush(m_brush);
902
903 if (m_cornerRadius != 0.0)
42cfaf8c 904 dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
0fc1a713 905 else
42cfaf8c 906 dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height));
0fc1a713
JS
907}
908
42cfaf8c 909void wxRectangleShape::GetBoundingBoxMin(double *the_width, double *the_height)
0fc1a713
JS
910{
911 *the_width = m_width;
912 *the_height = m_height;
913}
914
42cfaf8c 915void wxRectangleShape::SetSize(double x, double y, bool recursive)
0fc1a713
JS
916{
917 SetAttachmentSize(x, y);
42cfaf8c
JS
918 m_width = (double)wxMax(x, 1.0);
919 m_height = (double)wxMax(y, 1.0);
0fc1a713
JS
920 SetDefaultRegionSize();
921}
922
42cfaf8c 923void wxRectangleShape::SetCornerRadius(double rad)
0fc1a713
JS
924{
925 m_cornerRadius = rad;
926}
927
928// Assume (x1, y1) is centre of box (most generally, line end at box)
42cfaf8c
JS
929bool wxRectangleShape::GetPerimeterPoint(double x1, double y1,
930 double x2, double y2,
931 double *x3, double *y3)
0fc1a713 932{
42cfaf8c 933 double bound_x, bound_y;
0fc1a713 934 GetBoundingBoxMax(&bound_x, &bound_y);
42cfaf8c 935 oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
0fc1a713
JS
936
937 return TRUE;
938}
939
940#ifdef PROLOGIO
6f5f3ca0 941void wxRectangleShape::WriteAttributes(wxExpr *clause)
0fc1a713 942{
6f5f3ca0 943 wxShape::WriteAttributes(clause);
0fc1a713
JS
944 clause->AddAttributeValue("x", m_xpos);
945 clause->AddAttributeValue("y", m_ypos);
946
947 clause->AddAttributeValue("width", m_width);
948 clause->AddAttributeValue("height", m_height);
949 if (m_cornerRadius != 0.0)
950 clause->AddAttributeValue("corner", m_cornerRadius);
951}
952
6f5f3ca0 953void wxRectangleShape::ReadAttributes(wxExpr *clause)
0fc1a713 954{
6f5f3ca0 955 wxShape::ReadAttributes(clause);
0fc1a713
JS
956 clause->AssignAttributeValue("width", &m_width);
957 clause->AssignAttributeValue("height", &m_height);
958 clause->AssignAttributeValue("corner", &m_cornerRadius);
959
960 // In case we're reading an old file, set the region's size
961 if (m_regions.Number() == 1)
962 {
963 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
964 region->SetSize(m_width, m_height);
965 }
966}
967#endif
968
2bb0cd28 969void wxRectangleShape::Copy(wxShape& copy)
0fc1a713
JS
970{
971 wxShape::Copy(copy);
0fc1a713 972
2bb0cd28 973 wxASSERT( copy.IsKindOf(CLASSINFO(wxRectangleShape)) );
0fc1a713 974
2bb0cd28
JS
975 wxRectangleShape& rectCopy = (wxRectangleShape&) copy;
976 rectCopy.m_width = m_width;
977 rectCopy.m_height = m_height;
978 rectCopy.m_cornerRadius = m_cornerRadius;
979}
0fc1a713 980
6f5f3ca0 981int wxRectangleShape::GetNumberOfAttachments() const
0fc1a713
JS
982{
983 return wxShape::GetNumberOfAttachments();
984}
985
42cfaf8c 986
0fc1a713
JS
987// There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
988// 3 = left.
42cfaf8c 989bool wxRectangleShape::GetAttachmentPosition(int attachment, double *x, double *y,
0fc1a713
JS
990 int nth, int no_arcs, wxLineShape *line)
991{
992 if (m_attachmentMode)
993 {
42cfaf8c
JS
994 double top = (double)(m_ypos + m_height/2.0);
995 double bottom = (double)(m_ypos - m_height/2.0);
996 double left = (double)(m_xpos - m_width/2.0);
997 double right = (double)(m_xpos + m_width/2.0);
0fc1a713
JS
998
999 bool isEnd = (line && line->IsEnd(this));
1000
42cfaf8c
JS
1001 // Simplified code
1002 switch (attachment)
1003 {
1004 case 0:
1005 {
1006 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(right, bottom),
1007 nth, no_arcs, line);
1008
1009 *x = pt.x; *y = pt.y;
1010 break;
1011 }
1012 case 1:
1013 {
1014 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(right, bottom), wxRealPoint(right, top),
1015 nth, no_arcs, line);
1016
1017 *x = pt.x; *y = pt.y;
1018 break;
1019 }
1020 case 2:
1021 {
1022 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, top), wxRealPoint(right, top),
1023 nth, no_arcs, line);
1024
1025 *x = pt.x; *y = pt.y;
1026 break;
1027 }
1028 case 3:
1029 {
1030 wxRealPoint pt = CalcSimpleAttachment(wxRealPoint(left, bottom), wxRealPoint(left, top),
1031 nth, no_arcs, line);
1032
1033 *x = pt.x; *y = pt.y;
1034 break;
1035 }
1036 default:
1037 {
1038 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
1039 break;
1040 }
1041 }
1042
0fc1a713
JS
1043 return TRUE;
1044 }
1045 else
1046 { *x = m_xpos; *y = m_ypos; return TRUE; }
1047}
1048
1049// Text object (no box)
1050
1051IMPLEMENT_DYNAMIC_CLASS(wxTextShape, wxRectangleShape)
1052
42cfaf8c 1053wxTextShape::wxTextShape(double width, double height):
0fc1a713
JS
1054 wxRectangleShape(width, height)
1055{
1056}
1057
1058void wxTextShape::OnDraw(wxDC& dc)
1059{
1060}
1061
2bb0cd28 1062void wxTextShape::Copy(wxShape& copy)
0fc1a713
JS
1063{
1064 wxRectangleShape::Copy(copy);
1065}
1066
1067#ifdef PROLOGIO
6f5f3ca0 1068void wxTextShape::WriteAttributes(wxExpr *clause)
0fc1a713 1069{
6f5f3ca0 1070 wxRectangleShape::WriteAttributes(clause);
0fc1a713
JS
1071}
1072#endif
1073
1074// Ellipse object
1075
1076IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape, wxShape)
1077
42cfaf8c 1078wxEllipseShape::wxEllipseShape(double w, double h)
0fc1a713
JS
1079{
1080 m_width = w; m_height = h;
1081 SetDefaultRegionSize();
1082}
1083
42cfaf8c 1084void wxEllipseShape::GetBoundingBoxMin(double *w, double *h)
0fc1a713
JS
1085{
1086 *w = m_width; *h = m_height;
1087}
1088
42cfaf8c
JS
1089bool wxEllipseShape::GetPerimeterPoint(double x1, double y1,
1090 double x2, double y2,
1091 double *x3, double *y3)
0fc1a713 1092{
42cfaf8c 1093 double bound_x, bound_y;
0fc1a713
JS
1094 GetBoundingBoxMax(&bound_x, &bound_y);
1095
42cfaf8c
JS
1096// oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1097 oglDrawArcToEllipse(m_xpos, m_ypos, bound_x, bound_y, x2, y2, x1, y1, x3, y3);
0fc1a713
JS
1098
1099 return TRUE;
1100}
1101
1102void wxEllipseShape::OnDraw(wxDC& dc)
1103{
1104 if (m_shadowMode != SHADOW_NONE)
1105 {
1106 if (m_shadowBrush)
1107 dc.SetBrush(m_shadowBrush);
42cfaf8c 1108 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
1109 dc.DrawEllipse((m_xpos - GetWidth()/2) + m_shadowOffsetX,
1110 (m_ypos - GetHeight()/2) + m_shadowOffsetY,
1111 GetWidth(), GetHeight());
1112 }
1113
1114 if (m_pen)
1115 {
1116 if (m_pen->GetWidth() == 0)
42cfaf8c 1117 dc.SetPen(g_oglTransparentPen);
0fc1a713
JS
1118 else
1119 dc.SetPen(m_pen);
1120 }
1121 if (m_brush)
1122 dc.SetBrush(m_brush);
1123 dc.DrawEllipse((m_xpos - GetWidth()/2), (m_ypos - GetHeight()/2), GetWidth(), GetHeight());
1124}
1125
42cfaf8c 1126void wxEllipseShape::SetSize(double x, double y, bool recursive)
0fc1a713
JS
1127{
1128 SetAttachmentSize(x, y);
1129 m_width = x;
1130 m_height = y;
1131 SetDefaultRegionSize();
1132}
1133
1134#ifdef PROLOGIO
6f5f3ca0 1135void wxEllipseShape::WriteAttributes(wxExpr *clause)
0fc1a713 1136{
6f5f3ca0 1137 wxShape::WriteAttributes(clause);
0fc1a713
JS
1138 clause->AddAttributeValue("x", m_xpos);
1139 clause->AddAttributeValue("y", m_ypos);
1140
1141 clause->AddAttributeValue("width", m_width);
1142 clause->AddAttributeValue("height", m_height);
1143}
1144
6f5f3ca0 1145void wxEllipseShape::ReadAttributes(wxExpr *clause)
0fc1a713 1146{
6f5f3ca0 1147 wxShape::ReadAttributes(clause);
0fc1a713
JS
1148 clause->AssignAttributeValue("width", &m_width);
1149 clause->AssignAttributeValue("height", &m_height);
1150
1151 // In case we're reading an old file, set the region's size
1152 if (m_regions.Number() == 1)
1153 {
1154 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
1155 region->SetSize(m_width, m_height);
1156 }
1157}
1158#endif
1159
2bb0cd28 1160void wxEllipseShape::Copy(wxShape& copy)
0fc1a713
JS
1161{
1162 wxShape::Copy(copy);
1163
2bb0cd28 1164 wxASSERT( copy.IsKindOf(CLASSINFO(wxEllipseShape)) );
0fc1a713 1165
2bb0cd28
JS
1166 wxEllipseShape& ellipseCopy = (wxEllipseShape&) copy;
1167
1168 ellipseCopy.m_width = m_width;
1169 ellipseCopy.m_height = m_height;
0fc1a713
JS
1170}
1171
6f5f3ca0 1172int wxEllipseShape::GetNumberOfAttachments() const
0fc1a713
JS
1173{
1174 return wxShape::GetNumberOfAttachments();
1175}
1176
1177// There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1178// 3 = left.
42cfaf8c 1179bool wxEllipseShape::GetAttachmentPosition(int attachment, double *x, double *y,
0fc1a713
JS
1180 int nth, int no_arcs, wxLineShape *line)
1181{
1182 if (m_attachmentMode)
1183 {
42cfaf8c
JS
1184 double top = (double)(m_ypos + m_height/2.0);
1185 double bottom = (double)(m_ypos - m_height/2.0);
1186 double left = (double)(m_xpos - m_width/2.0);
1187 double right = (double)(m_xpos + m_width/2.0);
0fc1a713
JS
1188 switch (attachment)
1189 {
1190 case 0:
1191 {
1192 if (m_spaceAttachments)
1193 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1194 else *x = m_xpos;
1195 *y = top;
1196 // We now have the point on the bounding box: but get the point on the ellipse
1197 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1198 // the ellipse.
42cfaf8c 1199 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos-m_height-500), *x, m_ypos, x, y);
0fc1a713
JS
1200 break;
1201 }
1202 case 1:
1203 {
1204 *x = right;
1205 if (m_spaceAttachments)
1206 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1207 else *y = m_ypos;
42cfaf8c 1208 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos+m_width+500), *y, m_xpos, *y, x, y);
0fc1a713
JS
1209 break;
1210 }
1211 case 2:
1212 {
1213 if (m_spaceAttachments)
1214 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1215 else *x = m_xpos;
1216 *y = bottom;
42cfaf8c 1217 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos+m_height+500), *x, m_ypos, x, y);
0fc1a713
JS
1218 break;
1219 }
1220 case 3:
1221 {
1222 *x = left;
1223 if (m_spaceAttachments)
1224 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1225 else *y = m_ypos;
42cfaf8c 1226 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos-m_width-500), *y, m_xpos, *y, x, y);
0fc1a713
JS
1227 break;
1228 }
1229 default:
1230 {
1231 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
1232 break;
1233 }
1234 }
1235 return TRUE;
1236 }
1237 else
1238 { *x = m_xpos; *y = m_ypos; return TRUE; }
1239}
1240
1241
1242// Circle object
1243IMPLEMENT_DYNAMIC_CLASS(wxCircleShape, wxEllipseShape)
1244
42cfaf8c 1245wxCircleShape::wxCircleShape(double diameter):wxEllipseShape(diameter, diameter)
0fc1a713 1246{
f93ce4da 1247 SetMaintainAspectRatio(TRUE);
0fc1a713
JS
1248}
1249
2bb0cd28 1250void wxCircleShape::Copy(wxShape& copy)
0fc1a713
JS
1251{
1252 wxEllipseShape::Copy(copy);
1253}
1254
42cfaf8c
JS
1255bool wxCircleShape::GetPerimeterPoint(double x1, double y1,
1256 double x2, double y2,
1257 double *x3, double *y3)
0fc1a713 1258{
42cfaf8c 1259 oglFindEndForCircle(m_width/2,
0fc1a713
JS
1260 m_xpos, m_ypos, // Centre of circle
1261 x2, y2, // Other end of line
1262 x3, y3);
1263
1264 return TRUE;
1265}
1266
1267// Control points
1268
f93ce4da
JS
1269double wxControlPoint::sm_controlPointDragStartX = 0.0;
1270double wxControlPoint::sm_controlPointDragStartY = 0.0;
1271double wxControlPoint::sm_controlPointDragStartWidth = 0.0;
1272double wxControlPoint::sm_controlPointDragStartHeight = 0.0;
1273double wxControlPoint::sm_controlPointDragEndWidth = 0.0;
1274double wxControlPoint::sm_controlPointDragEndHeight = 0.0;
1275double wxControlPoint::sm_controlPointDragPosX = 0.0;
1276double wxControlPoint::sm_controlPointDragPosY = 0.0;
2bb0cd28 1277
0fc1a713
JS
1278IMPLEMENT_DYNAMIC_CLASS(wxControlPoint, wxRectangleShape)
1279
42cfaf8c 1280wxControlPoint::wxControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):wxRectangleShape(size, size)
0fc1a713
JS
1281{
1282 m_canvas = theCanvas;
1283 m_shape = object;
1284 m_xoffset = the_xoffset;
1285 m_yoffset = the_yoffset;
1286 m_type = the_type;
42cfaf8c 1287 SetPen(g_oglBlackForegroundPen);
0fc1a713
JS
1288 SetBrush(wxBLACK_BRUSH);
1289 m_oldCursor = NULL;
1290 m_visible = TRUE;
1291 m_eraseObject = TRUE;
1292}
1293
1294wxControlPoint::~wxControlPoint()
1295{
1296}
1297
1298// Don't even attempt to draw any text - waste of time!
1299void wxControlPoint::OnDrawContents(wxDC& dc)
1300{
1301}
1302
1303void wxControlPoint::OnDraw(wxDC& dc)
1304{
1305 m_xpos = m_shape->GetX() + m_xoffset;
1306 m_ypos = m_shape->GetY() + m_yoffset;
1307 wxRectangleShape::OnDraw(dc);
1308}
1309
1310void wxControlPoint::OnErase(wxDC& dc)
1311{
1312 wxRectangleShape::OnErase(dc);
1313}
1314
0fc1a713 1315// Implement resizing of canvas object
42cfaf8c 1316void wxControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
2bb0cd28
JS
1317{
1318 m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
1319}
1320
42cfaf8c 1321void wxControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
2bb0cd28
JS
1322{
1323 m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
1324}
1325
42cfaf8c 1326void wxControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
2bb0cd28
JS
1327{
1328 m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
1329}
1330
6f5f3ca0 1331int wxControlPoint::GetNumberOfAttachments() const
2bb0cd28
JS
1332{
1333 return 1;
1334}
1335
42cfaf8c 1336bool wxControlPoint::GetAttachmentPosition(int attachment, double *x, double *y,
2bb0cd28
JS
1337 int nth, int no_arcs, wxLineShape *line)
1338{
1339 *x = m_xpos; *y = m_ypos;
1340 return TRUE;
1341}
1342
1343// Control points ('handles') redirect control to the actual shape, to make it easier
1344// to override sizing behaviour.
42cfaf8c 1345void wxShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
0fc1a713 1346{
42cfaf8c
JS
1347 double bound_x;
1348 double bound_y;
2bb0cd28 1349 this->GetBoundingBoxMin(&bound_x, &bound_y);
0fc1a713
JS
1350
1351 wxClientDC dc(GetCanvas());
1352 GetCanvas()->PrepareDC(dc);
1353
1354 dc.SetLogicalFunction(wxXOR);
1355
1356 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1357 dc.SetPen(dottedPen);
1358 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1359
2bb0cd28 1360 if (this->GetCentreResize())
0fc1a713
JS
1361 {
1362 // Maintain the same centre point.
42cfaf8c
JS
1363 double new_width = (double)(2.0*fabs(x - this->GetX()));
1364 double new_height = (double)(2.0*fabs(y - this->GetY()));
0fc1a713
JS
1365
1366 // Constrain sizing according to what control point you're dragging
2bb0cd28 1367 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
f93ce4da
JS
1368 {
1369 if (GetMaintainAspectRatio())
1370 {
1371 new_height = bound_y*(new_width/bound_x);
1372 }
1373 else
1374 new_height = bound_y;
1375 }
2bb0cd28 1376 else if (pt->m_type == CONTROL_POINT_VERTICAL)
f93ce4da
JS
1377 {
1378 if (GetMaintainAspectRatio())
1379 {
1380 new_width = bound_x*(new_height/bound_y);
1381 }
1382 else
1383 new_width = bound_x;
1384 }
2bb0cd28 1385 else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
0fc1a713
JS
1386 new_height = bound_y*(new_width/bound_x);
1387
2bb0cd28 1388 if (this->GetFixedWidth())
0fc1a713
JS
1389 new_width = bound_x;
1390
2bb0cd28 1391 if (this->GetFixedHeight())
0fc1a713
JS
1392 new_height = bound_y;
1393
f93ce4da
JS
1394 pt->sm_controlPointDragEndWidth = new_width;
1395 pt->sm_controlPointDragEndHeight = new_height;
0fc1a713 1396
2bb0cd28 1397 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
0fc1a713
JS
1398 new_width, new_height);
1399 }
1400 else
1401 {
1402 // Don't maintain the same centre point!
f93ce4da
JS
1403 double newX1 = wxMin(pt->sm_controlPointDragStartX, x);
1404 double newY1 = wxMin(pt->sm_controlPointDragStartY, y);
1405 double newX2 = wxMax(pt->sm_controlPointDragStartX, x);
1406 double newY2 = wxMax(pt->sm_controlPointDragStartY, y);
2bb0cd28 1407 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
0fc1a713 1408 {
f93ce4da
JS
1409 newY1 = pt->sm_controlPointDragStartY;
1410 newY2 = newY1 + pt->sm_controlPointDragStartHeight;
0fc1a713 1411 }
2bb0cd28 1412 else if (pt->m_type == CONTROL_POINT_VERTICAL)
0fc1a713 1413 {
f93ce4da
JS
1414 newX1 = pt->sm_controlPointDragStartX;
1415 newX2 = newX1 + pt->sm_controlPointDragStartWidth;
0fc1a713 1416 }
f93ce4da 1417 else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio()))
0fc1a713 1418 {
f93ce4da
JS
1419 double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth));
1420 if (GetY() > pt->sm_controlPointDragStartY)
42cfaf8c 1421 newY2 = (double)(newY1 + newH);
0fc1a713 1422 else
42cfaf8c 1423 newY1 = (double)(newY2 - newH);
0fc1a713 1424 }
42cfaf8c
JS
1425 double newWidth = (double)(newX2 - newX1);
1426 double newHeight = (double)(newY2 - newY1);
0fc1a713 1427
f93ce4da
JS
1428 if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio())
1429 {
1430 newWidth = bound_x * (newHeight/bound_y) ;
1431 }
1432
1433 if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio())
1434 {
1435 newHeight = bound_y * (newWidth/bound_x) ;
1436 }
1437
1438 pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0));
1439 pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0));
2bb0cd28 1440 if (this->GetFixedWidth())
0fc1a713
JS
1441 newWidth = bound_x;
1442
2bb0cd28 1443 if (this->GetFixedHeight())
0fc1a713
JS
1444 newHeight = bound_y;
1445
f93ce4da
JS
1446 pt->sm_controlPointDragEndWidth = newWidth;
1447 pt->sm_controlPointDragEndHeight = newHeight;
1448 this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight);
0fc1a713
JS
1449 }
1450}
1451
42cfaf8c 1452void wxShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
0fc1a713
JS
1453{
1454 m_canvas->CaptureMouse();
1455
1456 wxClientDC dc(GetCanvas());
1457 GetCanvas()->PrepareDC(dc);
2e5ed787 1458/*
2bb0cd28
JS
1459 if (pt->m_eraseObject)
1460 this->Erase(dc);
2e5ed787 1461*/
0fc1a713
JS
1462
1463 dc.SetLogicalFunction(wxXOR);
1464
42cfaf8c
JS
1465 double bound_x;
1466 double bound_y;
2bb0cd28 1467 this->GetBoundingBoxMin(&bound_x, &bound_y);
0fc1a713
JS
1468
1469 // Choose the 'opposite corner' of the object as the stationary
1470 // point in case this is non-centring resizing.
2bb0cd28 1471 if (pt->GetX() < this->GetX())
f93ce4da 1472 pt->sm_controlPointDragStartX = (double)(this->GetX() + (bound_x/2.0));
0fc1a713 1473 else
f93ce4da 1474 pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0));
0fc1a713 1475
2bb0cd28 1476 if (pt->GetY() < this->GetY())
f93ce4da 1477 pt->sm_controlPointDragStartY = (double)(this->GetY() + (bound_y/2.0));
0fc1a713 1478 else
f93ce4da 1479 pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0));
0fc1a713 1480
2bb0cd28 1481 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
f93ce4da 1482 pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0));
2bb0cd28 1483 else if (pt->m_type == CONTROL_POINT_VERTICAL)
f93ce4da 1484 pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0));
0fc1a713
JS
1485
1486 // We may require the old width and height.
f93ce4da
JS
1487 pt->sm_controlPointDragStartWidth = bound_x;
1488 pt->sm_controlPointDragStartHeight = bound_y;
0fc1a713
JS
1489
1490 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1491 dc.SetPen(dottedPen);
1492 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1493
2bb0cd28 1494 if (this->GetCentreResize())
0fc1a713 1495 {
42cfaf8c
JS
1496 double new_width = (double)(2.0*fabs(x - this->GetX()));
1497 double new_height = (double)(2.0*fabs(y - this->GetY()));
0fc1a713
JS
1498
1499 // Constrain sizing according to what control point you're dragging
2bb0cd28 1500 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
f93ce4da
JS
1501 {
1502 if (GetMaintainAspectRatio())
1503 {
1504 new_height = bound_y*(new_width/bound_x);
1505 }
1506 else
1507 new_height = bound_y;
1508 }
2bb0cd28 1509 else if (pt->m_type == CONTROL_POINT_VERTICAL)
f93ce4da
JS
1510 {
1511 if (GetMaintainAspectRatio())
1512 {
1513 new_width = bound_x*(new_height/bound_y);
1514 }
1515 else
1516 new_width = bound_x;
1517 }
2bb0cd28 1518 else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
0fc1a713
JS
1519 new_height = bound_y*(new_width/bound_x);
1520
2bb0cd28 1521 if (this->GetFixedWidth())
0fc1a713
JS
1522 new_width = bound_x;
1523
2bb0cd28 1524 if (this->GetFixedHeight())
0fc1a713
JS
1525 new_height = bound_y;
1526
f93ce4da
JS
1527 pt->sm_controlPointDragEndWidth = new_width;
1528 pt->sm_controlPointDragEndHeight = new_height;
2bb0cd28 1529 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
0fc1a713
JS
1530 new_width, new_height);
1531 }
1532 else
1533 {
1534 // Don't maintain the same centre point!
f93ce4da
JS
1535 double newX1 = wxMin(pt->sm_controlPointDragStartX, x);
1536 double newY1 = wxMin(pt->sm_controlPointDragStartY, y);
1537 double newX2 = wxMax(pt->sm_controlPointDragStartX, x);
1538 double newY2 = wxMax(pt->sm_controlPointDragStartY, y);
2bb0cd28 1539 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
0fc1a713 1540 {
f93ce4da
JS
1541 newY1 = pt->sm_controlPointDragStartY;
1542 newY2 = newY1 + pt->sm_controlPointDragStartHeight;
0fc1a713 1543 }
2bb0cd28 1544 else if (pt->m_type == CONTROL_POINT_VERTICAL)
0fc1a713 1545 {
f93ce4da
JS
1546 newX1 = pt->sm_controlPointDragStartX;
1547 newX2 = newX1 + pt->sm_controlPointDragStartWidth;
0fc1a713 1548 }
f93ce4da 1549 else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio()))
0fc1a713 1550 {
f93ce4da
JS
1551 double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth));
1552 if (pt->GetY() > pt->sm_controlPointDragStartY)
42cfaf8c 1553 newY2 = (double)(newY1 + newH);
0fc1a713 1554 else
42cfaf8c 1555 newY1 = (double)(newY2 - newH);
0fc1a713 1556 }
42cfaf8c
JS
1557 double newWidth = (double)(newX2 - newX1);
1558 double newHeight = (double)(newY2 - newY1);
0fc1a713 1559
f93ce4da
JS
1560 if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio())
1561 {
1562 newWidth = bound_x * (newHeight/bound_y) ;
1563 }
1564
1565 if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio())
1566 {
1567 newHeight = bound_y * (newWidth/bound_x) ;
1568 }
1569
1570 pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0));
1571 pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0));
2bb0cd28 1572 if (this->GetFixedWidth())
0fc1a713
JS
1573 newWidth = bound_x;
1574
2bb0cd28 1575 if (this->GetFixedHeight())
0fc1a713
JS
1576 newHeight = bound_y;
1577
f93ce4da
JS
1578 pt->sm_controlPointDragEndWidth = newWidth;
1579 pt->sm_controlPointDragEndHeight = newHeight;
1580 this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight);
0fc1a713
JS
1581 }
1582}
1583
42cfaf8c 1584void wxShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
0fc1a713
JS
1585{
1586 wxClientDC dc(GetCanvas());
1587 GetCanvas()->PrepareDC(dc);
1588
1589 m_canvas->ReleaseMouse();
1590 dc.SetLogicalFunction(wxCOPY);
2bb0cd28
JS
1591 this->Recompute();
1592 this->ResetControlPoints();
0fc1a713 1593
2e5ed787
JS
1594 this->Erase(dc);
1595/*
2bb0cd28
JS
1596 if (!pt->m_eraseObject)
1597 this->Show(FALSE);
2e5ed787 1598*/
0fc1a713 1599
f93ce4da 1600 this->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
0fc1a713
JS
1601
1602 // The next operation could destroy this control point (it does for label objects,
1603 // via formatting the text), so save all values we're going to use, or
1604 // we'll be accessing garbage.
2bb0cd28 1605 wxShape *theObject = this;
0fc1a713 1606 wxShapeCanvas *theCanvas = m_canvas;
2bb0cd28 1607 bool eraseIt = pt->m_eraseObject;
0fc1a713
JS
1608
1609 if (theObject->GetCentreResize())
1610 theObject->Move(dc, theObject->GetX(), theObject->GetY());
1611 else
f93ce4da 1612 theObject->Move(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY);
0fc1a713 1613
2e5ed787 1614/*
0fc1a713
JS
1615 if (!eraseIt)
1616 theObject->Show(TRUE);
2e5ed787 1617*/
0fc1a713
JS
1618
1619 // Recursively redraw links if we have a composite.
1620 if (theObject->GetChildren().Number() > 0)
1621 theObject->DrawLinks(dc, -1, TRUE);
1622
42cfaf8c 1623 double width, height;
0fc1a713
JS
1624 theObject->GetBoundingBoxMax(&width, &height);
1625 theObject->GetEventHandler()->OnEndSize(width, height);
1626
1627 if (!theCanvas->GetQuickEditMode() && eraseIt) theCanvas->Redraw(dc);
1628}
1629
0fc1a713
JS
1630
1631
1632// Polygon control points
1633
1634IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint, wxControlPoint)
1635
42cfaf8c
JS
1636wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size,
1637 wxRealPoint *vertex, double the_xoffset, double the_yoffset):
0fc1a713
JS
1638 wxControlPoint(theCanvas, object, size, the_xoffset, the_yoffset, 0)
1639{
1640 m_polygonVertex = vertex;
2bb0cd28 1641 m_originalDistance = 0.0;
0fc1a713
JS
1642}
1643
1644wxPolygonControlPoint::~wxPolygonControlPoint()
1645{
1646}
1647
34138703 1648// Calculate what new size would be, at end of resize
42cfaf8c 1649void wxPolygonControlPoint::CalculateNewSize(double x, double y)
34138703 1650{
42cfaf8c
JS
1651 double bound_x;
1652 double bound_y;
34138703
JS
1653 GetShape()->GetBoundingBoxMin(&bound_x, &bound_y);
1654
42cfaf8c 1655 double dist = (double)sqrt((x - m_shape->GetX())*(x - m_shape->GetX()) +
34138703
JS
1656 (y - m_shape->GetY())*(y - m_shape->GetY()));
1657
42cfaf8c
JS
1658 m_newSize.x = (double)(dist/this->m_originalDistance)*this->m_originalSize.x;
1659 m_newSize.y = (double)(dist/this->m_originalDistance)*this->m_originalSize.y;
34138703
JS
1660}
1661
1662
0fc1a713 1663// Implement resizing polygon or moving the vertex.
42cfaf8c 1664void wxPolygonControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
0fc1a713 1665{
2bb0cd28
JS
1666 m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
1667}
1668
42cfaf8c 1669void wxPolygonControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
2bb0cd28
JS
1670{
1671 m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
1672}
1673
42cfaf8c 1674void wxPolygonControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
2bb0cd28
JS
1675{
1676 m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
1677}
1678
1679// Control points ('handles') redirect control to the actual shape, to make it easier
1680// to override sizing behaviour.
42cfaf8c 1681void wxPolygonShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
2bb0cd28
JS
1682{
1683 wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
1684
0fc1a713
JS
1685 wxClientDC dc(GetCanvas());
1686 GetCanvas()->PrepareDC(dc);
1687
1688 dc.SetLogicalFunction(wxXOR);
1689
1690 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1691 dc.SetPen(dottedPen);
1692 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1693
34138703 1694 if (0) // keys & KEY_CTRL)
0fc1a713 1695 {
34138703
JS
1696 // TODO: mend this code. Currently we rely on altering the
1697 // actual points, but we should assume we're not, as per
1698 // the normal sizing case.
0fc1a713
JS
1699 m_canvas->Snap(&x, &y);
1700
1701 // Move point
2bb0cd28
JS
1702 ppt->m_polygonVertex->x = x - this->GetX();
1703 ppt->m_polygonVertex->y = y - this->GetY();
1704 ppt->SetX(x);
1705 ppt->SetY(y);
1706 ((wxPolygonShape *)this)->CalculateBoundingBox();
1707 ((wxPolygonShape *)this)->CalculatePolygonCentre();
0fc1a713
JS
1708 }
1709 else
1710 {
34138703 1711 ppt->CalculateNewSize(x, y);
0fc1a713 1712 }
34138703
JS
1713
1714 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
1715 ppt->GetNewSize().x, ppt->GetNewSize().y);
0fc1a713
JS
1716}
1717
42cfaf8c 1718void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
0fc1a713 1719{
2bb0cd28
JS
1720 wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
1721
0fc1a713
JS
1722 wxClientDC dc(GetCanvas());
1723 GetCanvas()->PrepareDC(dc);
1724
2bb0cd28 1725 this->Erase(dc);
0fc1a713
JS
1726
1727 dc.SetLogicalFunction(wxXOR);
1728
42cfaf8c
JS
1729 double bound_x;
1730 double bound_y;
2bb0cd28 1731 this->GetBoundingBoxMin(&bound_x, &bound_y);
0fc1a713 1732
42cfaf8c 1733 double dist = (double)sqrt((x - this->GetX())*(x - this->GetX()) +
2bb0cd28 1734 (y - this->GetY())*(y - this->GetY()));
2bb0cd28
JS
1735 ppt->m_originalDistance = dist;
1736 ppt->m_originalSize.x = bound_x;
1737 ppt->m_originalSize.y = bound_y;
0fc1a713 1738
42cfaf8c 1739 if (ppt->m_originalDistance == 0.0) ppt->m_originalDistance = (double) 0.0001;
0fc1a713
JS
1740
1741 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1742 dc.SetPen(dottedPen);
1743 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1744
34138703 1745 if (0) // keys & KEY_CTRL)
0fc1a713 1746 {
34138703
JS
1747 // TODO: mend this code. Currently we rely on altering the
1748 // actual points, but we should assume we're not, as per
1749 // the normal sizing case.
0fc1a713
JS
1750 m_canvas->Snap(&x, &y);
1751
1752 // Move point
2bb0cd28
JS
1753 ppt->m_polygonVertex->x = x - this->GetX();
1754 ppt->m_polygonVertex->y = y - this->GetY();
1755 ppt->SetX(x);
1756 ppt->SetY(y);
1757 ((wxPolygonShape *)this)->CalculateBoundingBox();
1758 ((wxPolygonShape *)this)->CalculatePolygonCentre();
0fc1a713
JS
1759 }
1760 else
1761 {
34138703 1762 ppt->CalculateNewSize(x, y);
0fc1a713
JS
1763 }
1764
34138703
JS
1765 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
1766 ppt->GetNewSize().x, ppt->GetNewSize().y);
0fc1a713
JS
1767
1768 m_canvas->CaptureMouse();
1769}
1770
42cfaf8c 1771void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
0fc1a713 1772{
34138703
JS
1773 wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
1774
0fc1a713
JS
1775 wxClientDC dc(GetCanvas());
1776 GetCanvas()->PrepareDC(dc);
1777
1778 m_canvas->ReleaseMouse();
1779 dc.SetLogicalFunction(wxCOPY);
1780
1781 // If we're changing shape, must reset the original points
1782 if (keys & KEY_CTRL)
1783 {
2bb0cd28
JS
1784 ((wxPolygonShape *)this)->CalculateBoundingBox();
1785 ((wxPolygonShape *)this)->UpdateOriginalPoints();
0fc1a713 1786 }
34138703
JS
1787 else
1788 {
1789 SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
1790 }
0fc1a713 1791
2bb0cd28
JS
1792 ((wxPolygonShape *)this)->CalculateBoundingBox();
1793 ((wxPolygonShape *)this)->CalculatePolygonCentre();
0fc1a713 1794
2bb0cd28
JS
1795 this->Recompute();
1796 this->ResetControlPoints();
1797 this->Move(dc, this->GetX(), this->GetY());
0fc1a713
JS
1798 if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1799}
1800
0fc1a713
JS
1801/*
1802 * Object region
1803 *
1804 */
1805IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion, wxObject)
1806
1807wxShapeRegion::wxShapeRegion()
1808{
1809 m_regionText = "";
1810 m_font = g_oglNormalFont;
1811 m_minHeight = 5.0;
1812 m_minWidth = 5.0;
1813 m_width = 0.0;
1814 m_height = 0.0;
1815 m_x = 0.0;
1816 m_y = 0.0;
1817
1818 m_regionProportionX = -1.0;
1819 m_regionProportionY = -1.0;
1820 m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
1821 m_regionName = "";
1822 m_textColour = "BLACK";
1823 m_penColour = "BLACK";
1824 m_penStyle = wxSOLID;
1825 m_actualColourObject = NULL;
1826 m_actualPenObject = NULL;
1827}
1828
1829wxShapeRegion::wxShapeRegion(wxShapeRegion& region)
1830{
1831 m_regionText = region.m_regionText;
1832 m_regionName = region.m_regionName;
1833 m_textColour = region.m_textColour;
1834
1835 m_font = region.m_font;
1836 m_minHeight = region.m_minHeight;
1837 m_minWidth = region.m_minWidth;
1838 m_width = region.m_width;
1839 m_height = region.m_height;
1840 m_x = region.m_x;
1841 m_y = region.m_y;
1842
1843 m_regionProportionX = region.m_regionProportionX;
1844 m_regionProportionY = region.m_regionProportionY;
1845 m_formatMode = region.m_formatMode;
1846 m_actualColourObject = NULL;
1847 m_actualPenObject = NULL;
1848 m_penStyle = region.m_penStyle;
1849 m_penColour = region.m_penColour;
1850
1851 ClearText();
1852 wxNode *node = region.m_formattedText.First();
1853 while (node)
1854 {
1855 wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
1856 wxShapeTextLine *new_line =
1857 new wxShapeTextLine(line->GetX(), line->GetY(), line->GetText());
1858 m_formattedText.Append(new_line);
1859 node = node->Next();
1860 }
1861}
1862
1863wxShapeRegion::~wxShapeRegion()
1864{
1865 ClearText();
1866}
1867
1868void wxShapeRegion::ClearText()
1869{
1870 wxNode *node = m_formattedText.First();
1871 while (node)
1872 {
1873 wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
1874 wxNode *next = node->Next();
1875 delete line;
1876 delete node;
1877 node = next;
1878 }
1879}
1880
1881void wxShapeRegion::SetFont(wxFont *f)
1882{
1883 m_font = f;
1884}
1885
42cfaf8c 1886void wxShapeRegion::SetMinSize(double w, double h)
0fc1a713
JS
1887{
1888 m_minWidth = w;
1889 m_minHeight = h;
1890}
1891
42cfaf8c 1892void wxShapeRegion::SetSize(double w, double h)
0fc1a713
JS
1893{
1894 m_width = w;
1895 m_height = h;
1896}
1897
42cfaf8c 1898void wxShapeRegion::SetPosition(double xp, double yp)
0fc1a713
JS
1899{
1900 m_x = xp;
1901 m_y = yp;
1902}
1903
42cfaf8c 1904void wxShapeRegion::SetProportions(double xp, double yp)
0fc1a713
JS
1905{
1906 m_regionProportionX = xp;
1907 m_regionProportionY = yp;
1908}
1909
1910void wxShapeRegion::SetFormatMode(int mode)
1911{
1912 m_formatMode = mode;
1913}
1914
1915void wxShapeRegion::SetColour(const wxString& col)
1916{
1917 m_textColour = col;
1918 m_actualColourObject = NULL;
1919}
1920
1921wxColour *wxShapeRegion::GetActualColourObject()
1922{
1923 if (!m_actualColourObject)
1924 m_actualColourObject = wxTheColourDatabase->FindColour(GetColour());
1925 if (!m_actualColourObject)
1926 m_actualColourObject = wxBLACK;
1927 return m_actualColourObject;
1928}
1929
1930void wxShapeRegion::SetPenColour(const wxString& col)
1931{
1932 m_penColour = col;
1933 m_actualPenObject = NULL;
1934}
1935
1936// Returns NULL if the pen is invisible
1937// (different to pen being transparent; indicates that
1938// region boundary should not be drawn.)
1939wxPen *wxShapeRegion::GetActualPen()
1940{
1941 if (m_actualPenObject)
1942 return m_actualPenObject;
1943
1944 if (!m_penColour) return NULL;
1945 if (m_penColour == "Invisible")
1946 return NULL;
1947 m_actualPenObject = wxThePenList->FindOrCreatePen(m_penColour, 1, m_penStyle);
1948 return m_actualPenObject;
1949}
1950
1951