]> git.saurik.com Git - wxWidgets.git/blob - utils/ogl/src/basic2.cpp
More wxMotif work, OGL enhancements, USE_ macro corrections, object.cpp delete
[wxWidgets.git] / utils / ogl / src / basic2.cpp
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
30 #if wxUSE_IOSTREAMH
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
60 IMPLEMENT_DYNAMIC_CLASS(wxPolygonShape, wxShape)
61
62 wxPolygonShape::wxPolygonShape()
63 {
64 m_points = NULL;
65 m_originalPoints = NULL;
66 }
67
68 void wxPolygonShape::Create(wxList *the_points)
69 {
70 ClearPoints();
71
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
91 wxPolygonShape::~wxPolygonShape()
92 {
93 ClearPoints();
94 }
95
96 void wxPolygonShape::ClearPoints()
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;
109 m_points = NULL;
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;
122 m_originalPoints = NULL;
123 }
124 }
125
126
127 // Width and height. Centre of object is centre of box.
128 void wxPolygonShape::GetBoundingBoxMin(double *width, double *height)
129 {
130 *width = m_boundWidth;
131 *height = m_boundHeight;
132 }
133
134 void wxPolygonShape::CalculateBoundingBox()
135 {
136 // Calculate bounding box at construction (and presumably resize) time
137 double left = 10000;
138 double right = -10000;
139 double top = 10000;
140 double bottom = -10000;
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.
163 void wxPolygonShape::CalculatePolygonCentre()
164 {
165 double left = 10000;
166 double right = -10000;
167 double top = 10000;
168 double bottom = -10000;
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 }
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));
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
200 bool PolylineHitTest(double n, double xvec[], double yvec[],
201 double x1, double y1, double x2, double y2)
202 {
203 bool isAHit = FALSE;
204 int i;
205 double lastx = xvec[0];
206 double lasty = yvec[0];
207
208 double min_ratio = 1.0;
209 double line_ratio;
210 double other_ratio;
211
212 // char buf[300];
213 for (i = 1; i < n; i++)
214 {
215 oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[i], yvec[i],
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
228 // Do last (implicit) line if last and first doubles are not identical
229 if (!(xvec[0] == lastx && yvec[0] == lasty))
230 {
231 oglCheckLineIntersection(x1, y1, x2, y2, lastx, lasty, xvec[0], yvec[0],
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
245 bool wxPolygonShape::HitTest(double x, double y, int *attachment, double *distance)
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.
250 double endPointsX[4];
251 double endPointsY[4];
252 // North
253 endPointsX[0] = x;
254 endPointsY[0] = (double)(y - 1000.0);
255 // East
256 endPointsX[1] = (double)(x + 1000.0);
257 endPointsY[1] = y;
258 // South
259 endPointsX[2] = x;
260 endPointsY[2] = (double)(y + 1000.0);
261 // West
262 endPointsX[3] = (double)(x - 1000.0);
263 endPointsY[3] = y;
264
265 // Store polygon points in an array
266 int np = m_points->Number();
267 double *xpoints = new double[np];
268 double *ypoints = new double[np];
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();
306 double nearest = 999999.0;
307
308 for (i = 0; i < n; i++)
309 {
310 double xp, yp;
311 if (GetAttachmentPositionEdge(i, &xp, &yp))
312 {
313 double l = (double)sqrt(((xp - x) * (xp - x)) +
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.
329 void wxPolygonShape::SetSize(double new_width, double new_height, bool recursive)
330 {
331 SetAttachmentSize(new_width, new_height);
332
333 // Multiply all points by proportion of new size to old size
334 double x_proportion = (double)(fabs(new_width/m_originalWidth));
335 double y_proportion = (double)(fabs(new_height/m_originalHeight));
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();
352 m_boundWidth = (double)fabs(new_width);
353 m_boundHeight = (double)fabs(new_height);
354 SetDefaultRegionSize();
355 }
356
357 // Make the original points the same as the working points
358 void 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
386 void 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
396 double x = (double)((secondPoint->x - firstPoint->x)/2.0 + firstPoint->x);
397 double y = (double)((secondPoint->y - firstPoint->y)/2.0 + firstPoint->y);
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
414 void 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)
432 bool wxPolygonShape::GetPerimeterPoint(double x1, double y1,
433 double x2, double y2,
434 double *x3, double *y3)
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 --
440 // oglFindEndForPolyline can't cope with this (the arrow
441 // gets drawn to the wrong place).
442 if ((m_attachmentMode == ATTACHMENT_MODE_NONE) && (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
469 double *xpoints = new double[n];
470 double *ypoints = new double[n];
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 }
482
483 oglFindEndForPolyline(n, xpoints, ypoints,
484 x1, y1, x2, y2, x3, y3);
485
486 delete[] xpoints;
487 delete[] ypoints;
488
489 return TRUE;
490 }
491
492 void 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();
500 intPoints[i].x = WXROUND(point->x);
501 intPoints[i].y = WXROUND(point->y);
502 }
503
504 if (m_shadowMode != SHADOW_NONE)
505 {
506 if (m_shadowBrush)
507 dc.SetBrush(m_shadowBrush);
508 dc.SetPen(g_oglTransparentPen);
509
510 dc.DrawPolygon(n, intPoints, WXROUND(m_xpos + m_shadowOffsetX), WXROUND(m_ypos + m_shadowOffsetY));
511 }
512
513 if (m_pen)
514 {
515 if (m_pen->GetWidth() == 0)
516 dc.SetPen(g_oglTransparentPen);
517 else
518 dc.SetPen(m_pen);
519 }
520 if (m_brush)
521 dc.SetBrush(m_brush);
522 dc.DrawPolygon(n, intPoints, WXROUND(m_xpos), WXROUND(m_ypos));
523
524 delete[] intPoints;
525 }
526
527 void wxPolygonShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
528 {
529 dc.SetBrush(wxTRANSPARENT_BRUSH);
530 // Multiply all points by proportion of new size to old size
531 double x_proportion = (double)(fabs(w/m_originalWidth));
532 double y_proportion = (double)(fabs(h/m_originalHeight));
533
534 int n = m_originalPoints->Number();
535 wxPoint *intPoints = new wxPoint[n];
536 int i;
537 for (i = 0; i < n; i++)
538 {
539 wxRealPoint* point = (wxRealPoint*) m_originalPoints->Nth(i)->Data();
540 intPoints[i].x = WXROUND(x_proportion * point->x);
541 intPoints[i].y = WXROUND(y_proportion * point->y);
542 }
543 dc.DrawPolygon(n, intPoints, WXROUND(x), WXROUND(y));
544 delete[] intPoints;
545 }
546
547 // Make as many control points as there are vertices.
548 void 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 }
560 }
561
562 void 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 }
578 }
579
580
581 #ifdef PROLOGIO
582 void wxPolygonShape::WriteAttributes(wxExpr *clause)
583 {
584 wxShape::WriteAttributes(clause);
585
586 clause->AddAttributeValue("x", m_xpos);
587 clause->AddAttributeValue("y", m_ypos);
588
589 // Make a list of lists for the coordinates
590 wxExpr *list = new wxExpr(wxExprList);
591 wxNode *node = m_points->First();
592 while (node)
593 {
594 wxRealPoint *point = (wxRealPoint *)node->Data();
595 wxExpr *point_list = new wxExpr(wxExprList);
596 wxExpr *x_expr = new wxExpr((double)point->x);
597 wxExpr *y_expr = new wxExpr((double)point->y);
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
608 list = new wxExpr(wxExprList);
609 node = m_originalPoints->First();
610 while (node)
611 {
612 wxRealPoint *point = (wxRealPoint *)node->Data();
613 wxExpr *point_list = new wxExpr(wxExprList);
614 wxExpr *x_expr = new wxExpr((double) point->x);
615 wxExpr *y_expr = new wxExpr((double) point->y);
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
625 void wxPolygonShape::ReadAttributes(wxExpr *clause)
626 {
627 wxShape::ReadAttributes(clause);
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.
637 double the_height = 100.0;
638 double the_width = 100.0;
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
668 wxRealPoint *point = new wxRealPoint((double)x, (double)y);
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;
702 double min_x = 1000;
703 double min_y = 1000;
704 double max_x = -1000;
705 double max_y = -1000;
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
714 wxRealPoint *point = new wxRealPoint((double)x, (double)y);
715 m_originalPoints->Append((wxObject*) point);
716
717 if (x < min_x)
718 min_x = (double)x;
719 if (y < min_y)
720 min_y = (double)y;
721 if (x > max_x)
722 max_x = (double)x;
723 if (y > max_y)
724 max_y = (double)y;
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
736 void wxPolygonShape::Copy(wxShape& copy)
737 {
738 wxShape::Copy(copy);
739
740 wxASSERT( copy.IsKindOf(CLASSINFO(wxPolygonShape)) );
741
742 wxPolygonShape& polyCopy = (wxPolygonShape&) copy;
743
744 polyCopy.ClearPoints();
745
746 polyCopy.m_points = new wxList;
747 polyCopy.m_originalPoints = new wxList;
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);
754 polyCopy.m_points->Append((wxObject*) new_point);
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);
762 polyCopy.m_originalPoints->Append((wxObject*) new_point);
763 node = node->Next();
764 }
765 polyCopy.m_boundWidth = m_boundWidth;
766 polyCopy.m_boundHeight = m_boundHeight;
767 polyCopy.m_originalWidth = m_originalWidth;
768 polyCopy.m_originalHeight = m_originalHeight;
769 }
770
771 int wxPolygonShape::GetNumberOfAttachments() const
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
785 bool wxPolygonShape::GetAttachmentPosition(int attachment, double *x, double *y,
786 int nth, int no_arcs, wxLineShape *line)
787 {
788 if ((m_attachmentMode == ATTACHMENT_MODE_EDGE) && 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
799 bool 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
818 // Rotate about the given axis by the given amount in radians
819 void 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
865 // Rectangle object
866
867 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape, wxShape)
868
869 wxRectangleShape::wxRectangleShape(double w, double h)
870 {
871 m_width = w; m_height = h; m_cornerRadius = 0.0;
872 SetDefaultRegionSize();
873 }
874
875 void wxRectangleShape::OnDraw(wxDC& dc)
876 {
877 double x1 = (double)(m_xpos - m_width/2.0);
878 double y1 = (double)(m_ypos - m_height/2.0);
879
880 if (m_shadowMode != SHADOW_NONE)
881 {
882 if (m_shadowBrush)
883 dc.SetBrush(m_shadowBrush);
884 dc.SetPen(g_oglTransparentPen);
885
886 if (m_cornerRadius != 0.0)
887 dc.DrawRoundedRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY),
888 WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
889 else
890 dc.DrawRectangle(WXROUND(x1 + m_shadowOffsetX), WXROUND(y1 + m_shadowOffsetY), WXROUND(m_width), WXROUND(m_height));
891 }
892
893 if (m_pen)
894 {
895 if (m_pen->GetWidth() == 0)
896 dc.SetPen(g_oglTransparentPen);
897 else
898 dc.SetPen(m_pen);
899 }
900 if (m_brush)
901 dc.SetBrush(m_brush);
902
903 if (m_cornerRadius != 0.0)
904 dc.DrawRoundedRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height), m_cornerRadius);
905 else
906 dc.DrawRectangle(WXROUND(x1), WXROUND(y1), WXROUND(m_width), WXROUND(m_height));
907 }
908
909 void wxRectangleShape::GetBoundingBoxMin(double *the_width, double *the_height)
910 {
911 *the_width = m_width;
912 *the_height = m_height;
913 }
914
915 void wxRectangleShape::SetSize(double x, double y, bool recursive)
916 {
917 SetAttachmentSize(x, y);
918 m_width = (double)wxMax(x, 1.0);
919 m_height = (double)wxMax(y, 1.0);
920 SetDefaultRegionSize();
921 }
922
923 void wxRectangleShape::SetCornerRadius(double rad)
924 {
925 m_cornerRadius = rad;
926 }
927
928 // Assume (x1, y1) is centre of box (most generally, line end at box)
929 bool wxRectangleShape::GetPerimeterPoint(double x1, double y1,
930 double x2, double y2,
931 double *x3, double *y3)
932 {
933 double bound_x, bound_y;
934 GetBoundingBoxMax(&bound_x, &bound_y);
935 oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
936
937 return TRUE;
938 }
939
940 #ifdef PROLOGIO
941 void wxRectangleShape::WriteAttributes(wxExpr *clause)
942 {
943 wxShape::WriteAttributes(clause);
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
953 void wxRectangleShape::ReadAttributes(wxExpr *clause)
954 {
955 wxShape::ReadAttributes(clause);
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
969 void wxRectangleShape::Copy(wxShape& copy)
970 {
971 wxShape::Copy(copy);
972
973 wxASSERT( copy.IsKindOf(CLASSINFO(wxRectangleShape)) );
974
975 wxRectangleShape& rectCopy = (wxRectangleShape&) copy;
976 rectCopy.m_width = m_width;
977 rectCopy.m_height = m_height;
978 rectCopy.m_cornerRadius = m_cornerRadius;
979 }
980
981 int wxRectangleShape::GetNumberOfAttachments() const
982 {
983 return wxShape::GetNumberOfAttachments();
984 }
985
986
987 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
988 // 3 = left.
989 bool wxRectangleShape::GetAttachmentPosition(int attachment, double *x, double *y,
990 int nth, int no_arcs, wxLineShape *line)
991 {
992 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
993 }
994
995 // Text object (no box)
996
997 IMPLEMENT_DYNAMIC_CLASS(wxTextShape, wxRectangleShape)
998
999 wxTextShape::wxTextShape(double width, double height):
1000 wxRectangleShape(width, height)
1001 {
1002 }
1003
1004 void wxTextShape::OnDraw(wxDC& dc)
1005 {
1006 }
1007
1008 void wxTextShape::Copy(wxShape& copy)
1009 {
1010 wxRectangleShape::Copy(copy);
1011 }
1012
1013 #ifdef PROLOGIO
1014 void wxTextShape::WriteAttributes(wxExpr *clause)
1015 {
1016 wxRectangleShape::WriteAttributes(clause);
1017 }
1018 #endif
1019
1020 // Ellipse object
1021
1022 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape, wxShape)
1023
1024 wxEllipseShape::wxEllipseShape(double w, double h)
1025 {
1026 m_width = w; m_height = h;
1027 SetDefaultRegionSize();
1028 }
1029
1030 void wxEllipseShape::GetBoundingBoxMin(double *w, double *h)
1031 {
1032 *w = m_width; *h = m_height;
1033 }
1034
1035 bool wxEllipseShape::GetPerimeterPoint(double x1, double y1,
1036 double x2, double y2,
1037 double *x3, double *y3)
1038 {
1039 double bound_x, bound_y;
1040 GetBoundingBoxMax(&bound_x, &bound_y);
1041
1042 // oglFindEndForBox(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1043 oglDrawArcToEllipse(m_xpos, m_ypos, bound_x, bound_y, x2, y2, x1, y1, x3, y3);
1044
1045 return TRUE;
1046 }
1047
1048 void wxEllipseShape::OnDraw(wxDC& dc)
1049 {
1050 if (m_shadowMode != SHADOW_NONE)
1051 {
1052 if (m_shadowBrush)
1053 dc.SetBrush(m_shadowBrush);
1054 dc.SetPen(g_oglTransparentPen);
1055 dc.DrawEllipse((m_xpos - GetWidth()/2) + m_shadowOffsetX,
1056 (m_ypos - GetHeight()/2) + m_shadowOffsetY,
1057 GetWidth(), GetHeight());
1058 }
1059
1060 if (m_pen)
1061 {
1062 if (m_pen->GetWidth() == 0)
1063 dc.SetPen(g_oglTransparentPen);
1064 else
1065 dc.SetPen(m_pen);
1066 }
1067 if (m_brush)
1068 dc.SetBrush(m_brush);
1069 dc.DrawEllipse((m_xpos - GetWidth()/2), (m_ypos - GetHeight()/2), GetWidth(), GetHeight());
1070 }
1071
1072 void wxEllipseShape::SetSize(double x, double y, bool recursive)
1073 {
1074 SetAttachmentSize(x, y);
1075 m_width = x;
1076 m_height = y;
1077 SetDefaultRegionSize();
1078 }
1079
1080 #ifdef PROLOGIO
1081 void wxEllipseShape::WriteAttributes(wxExpr *clause)
1082 {
1083 wxShape::WriteAttributes(clause);
1084 clause->AddAttributeValue("x", m_xpos);
1085 clause->AddAttributeValue("y", m_ypos);
1086
1087 clause->AddAttributeValue("width", m_width);
1088 clause->AddAttributeValue("height", m_height);
1089 }
1090
1091 void wxEllipseShape::ReadAttributes(wxExpr *clause)
1092 {
1093 wxShape::ReadAttributes(clause);
1094 clause->AssignAttributeValue("width", &m_width);
1095 clause->AssignAttributeValue("height", &m_height);
1096
1097 // In case we're reading an old file, set the region's size
1098 if (m_regions.Number() == 1)
1099 {
1100 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
1101 region->SetSize(m_width, m_height);
1102 }
1103 }
1104 #endif
1105
1106 void wxEllipseShape::Copy(wxShape& copy)
1107 {
1108 wxShape::Copy(copy);
1109
1110 wxASSERT( copy.IsKindOf(CLASSINFO(wxEllipseShape)) );
1111
1112 wxEllipseShape& ellipseCopy = (wxEllipseShape&) copy;
1113
1114 ellipseCopy.m_width = m_width;
1115 ellipseCopy.m_height = m_height;
1116 }
1117
1118 int wxEllipseShape::GetNumberOfAttachments() const
1119 {
1120 return wxShape::GetNumberOfAttachments();
1121 }
1122
1123 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1124 // 3 = left.
1125 bool wxEllipseShape::GetAttachmentPosition(int attachment, double *x, double *y,
1126 int nth, int no_arcs, wxLineShape *line)
1127 {
1128 if (m_attachmentMode == ATTACHMENT_MODE_BRANCHING)
1129 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
1130
1131 if (m_attachmentMode != ATTACHMENT_MODE_NONE)
1132 {
1133 double top = (double)(m_ypos + m_height/2.0);
1134 double bottom = (double)(m_ypos - m_height/2.0);
1135 double left = (double)(m_xpos - m_width/2.0);
1136 double right = (double)(m_xpos + m_width/2.0);
1137
1138 int physicalAttachment = LogicalToPhysicalAttachment(attachment);
1139
1140 switch (physicalAttachment)
1141 {
1142 case 0:
1143 {
1144 if (m_spaceAttachments)
1145 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1146 else *x = m_xpos;
1147 *y = top;
1148 // We now have the point on the bounding box: but get the point on the ellipse
1149 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1150 // the ellipse.
1151 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos-m_height-500), *x, m_ypos, x, y);
1152 break;
1153 }
1154 case 1:
1155 {
1156 *x = right;
1157 if (m_spaceAttachments)
1158 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1159 else *y = m_ypos;
1160 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos+m_width+500), *y, m_xpos, *y, x, y);
1161 break;
1162 }
1163 case 2:
1164 {
1165 if (m_spaceAttachments)
1166 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1167 else *x = m_xpos;
1168 *y = bottom;
1169 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, *x, (double)(m_ypos+m_height+500), *x, m_ypos, x, y);
1170 break;
1171 }
1172 case 3:
1173 {
1174 *x = left;
1175 if (m_spaceAttachments)
1176 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1177 else *y = m_ypos;
1178 oglDrawArcToEllipse(m_xpos, m_ypos, m_width, m_height, (double)(m_xpos-m_width-500), *y, m_xpos, *y, x, y);
1179 break;
1180 }
1181 default:
1182 {
1183 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
1184 break;
1185 }
1186 }
1187 return TRUE;
1188 }
1189 else
1190 { *x = m_xpos; *y = m_ypos; return TRUE; }
1191 }
1192
1193
1194 // Circle object
1195 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape, wxEllipseShape)
1196
1197 wxCircleShape::wxCircleShape(double diameter):wxEllipseShape(diameter, diameter)
1198 {
1199 SetMaintainAspectRatio(TRUE);
1200 }
1201
1202 void wxCircleShape::Copy(wxShape& copy)
1203 {
1204 wxEllipseShape::Copy(copy);
1205 }
1206
1207 bool wxCircleShape::GetPerimeterPoint(double x1, double y1,
1208 double x2, double y2,
1209 double *x3, double *y3)
1210 {
1211 oglFindEndForCircle(m_width/2,
1212 m_xpos, m_ypos, // Centre of circle
1213 x2, y2, // Other end of line
1214 x3, y3);
1215
1216 return TRUE;
1217 }
1218
1219 // Control points
1220
1221 double wxControlPoint::sm_controlPointDragStartX = 0.0;
1222 double wxControlPoint::sm_controlPointDragStartY = 0.0;
1223 double wxControlPoint::sm_controlPointDragStartWidth = 0.0;
1224 double wxControlPoint::sm_controlPointDragStartHeight = 0.0;
1225 double wxControlPoint::sm_controlPointDragEndWidth = 0.0;
1226 double wxControlPoint::sm_controlPointDragEndHeight = 0.0;
1227 double wxControlPoint::sm_controlPointDragPosX = 0.0;
1228 double wxControlPoint::sm_controlPointDragPosY = 0.0;
1229
1230 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint, wxRectangleShape)
1231
1232 wxControlPoint::wxControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size, double the_xoffset, double the_yoffset, int the_type):wxRectangleShape(size, size)
1233 {
1234 m_canvas = theCanvas;
1235 m_shape = object;
1236 m_xoffset = the_xoffset;
1237 m_yoffset = the_yoffset;
1238 m_type = the_type;
1239 SetPen(g_oglBlackForegroundPen);
1240 SetBrush(wxBLACK_BRUSH);
1241 m_oldCursor = NULL;
1242 m_visible = TRUE;
1243 m_eraseObject = TRUE;
1244 }
1245
1246 wxControlPoint::~wxControlPoint()
1247 {
1248 }
1249
1250 // Don't even attempt to draw any text - waste of time!
1251 void wxControlPoint::OnDrawContents(wxDC& dc)
1252 {
1253 }
1254
1255 void wxControlPoint::OnDraw(wxDC& dc)
1256 {
1257 m_xpos = m_shape->GetX() + m_xoffset;
1258 m_ypos = m_shape->GetY() + m_yoffset;
1259 wxRectangleShape::OnDraw(dc);
1260 }
1261
1262 void wxControlPoint::OnErase(wxDC& dc)
1263 {
1264 wxRectangleShape::OnErase(dc);
1265 }
1266
1267 // Implement resizing of canvas object
1268 void wxControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
1269 {
1270 m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
1271 }
1272
1273 void wxControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
1274 {
1275 m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
1276 }
1277
1278 void wxControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
1279 {
1280 m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
1281 }
1282
1283 int wxControlPoint::GetNumberOfAttachments() const
1284 {
1285 return 1;
1286 }
1287
1288 bool wxControlPoint::GetAttachmentPosition(int attachment, double *x, double *y,
1289 int nth, int no_arcs, wxLineShape *line)
1290 {
1291 *x = m_xpos; *y = m_ypos;
1292 return TRUE;
1293 }
1294
1295 // Control points ('handles') redirect control to the actual shape, to make it easier
1296 // to override sizing behaviour.
1297 void wxShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
1298 {
1299 double bound_x;
1300 double bound_y;
1301 this->GetBoundingBoxMin(&bound_x, &bound_y);
1302
1303 wxClientDC dc(GetCanvas());
1304 GetCanvas()->PrepareDC(dc);
1305
1306 dc.SetLogicalFunction(wxXOR);
1307
1308 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1309 dc.SetPen(dottedPen);
1310 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1311
1312 if (this->GetCentreResize())
1313 {
1314 // Maintain the same centre point.
1315 double new_width = (double)(2.0*fabs(x - this->GetX()));
1316 double new_height = (double)(2.0*fabs(y - this->GetY()));
1317
1318 // Constrain sizing according to what control point you're dragging
1319 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
1320 {
1321 if (GetMaintainAspectRatio())
1322 {
1323 new_height = bound_y*(new_width/bound_x);
1324 }
1325 else
1326 new_height = bound_y;
1327 }
1328 else if (pt->m_type == CONTROL_POINT_VERTICAL)
1329 {
1330 if (GetMaintainAspectRatio())
1331 {
1332 new_width = bound_x*(new_height/bound_y);
1333 }
1334 else
1335 new_width = bound_x;
1336 }
1337 else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
1338 new_height = bound_y*(new_width/bound_x);
1339
1340 if (this->GetFixedWidth())
1341 new_width = bound_x;
1342
1343 if (this->GetFixedHeight())
1344 new_height = bound_y;
1345
1346 pt->sm_controlPointDragEndWidth = new_width;
1347 pt->sm_controlPointDragEndHeight = new_height;
1348
1349 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
1350 new_width, new_height);
1351 }
1352 else
1353 {
1354 // Don't maintain the same centre point!
1355 double newX1 = wxMin(pt->sm_controlPointDragStartX, x);
1356 double newY1 = wxMin(pt->sm_controlPointDragStartY, y);
1357 double newX2 = wxMax(pt->sm_controlPointDragStartX, x);
1358 double newY2 = wxMax(pt->sm_controlPointDragStartY, y);
1359 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
1360 {
1361 newY1 = pt->sm_controlPointDragStartY;
1362 newY2 = newY1 + pt->sm_controlPointDragStartHeight;
1363 }
1364 else if (pt->m_type == CONTROL_POINT_VERTICAL)
1365 {
1366 newX1 = pt->sm_controlPointDragStartX;
1367 newX2 = newX1 + pt->sm_controlPointDragStartWidth;
1368 }
1369 else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio()))
1370 {
1371 double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth));
1372 if (GetY() > pt->sm_controlPointDragStartY)
1373 newY2 = (double)(newY1 + newH);
1374 else
1375 newY1 = (double)(newY2 - newH);
1376 }
1377 double newWidth = (double)(newX2 - newX1);
1378 double newHeight = (double)(newY2 - newY1);
1379
1380 if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio())
1381 {
1382 newWidth = bound_x * (newHeight/bound_y) ;
1383 }
1384
1385 if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio())
1386 {
1387 newHeight = bound_y * (newWidth/bound_x) ;
1388 }
1389
1390 pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0));
1391 pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0));
1392 if (this->GetFixedWidth())
1393 newWidth = bound_x;
1394
1395 if (this->GetFixedHeight())
1396 newHeight = bound_y;
1397
1398 pt->sm_controlPointDragEndWidth = newWidth;
1399 pt->sm_controlPointDragEndHeight = newHeight;
1400 this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight);
1401 }
1402 }
1403
1404 void wxShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
1405 {
1406 m_canvas->CaptureMouse();
1407
1408 wxClientDC dc(GetCanvas());
1409 GetCanvas()->PrepareDC(dc);
1410 /*
1411 if (pt->m_eraseObject)
1412 this->Erase(dc);
1413 */
1414
1415 dc.SetLogicalFunction(wxXOR);
1416
1417 double bound_x;
1418 double bound_y;
1419 this->GetBoundingBoxMin(&bound_x, &bound_y);
1420
1421 // Choose the 'opposite corner' of the object as the stationary
1422 // point in case this is non-centring resizing.
1423 if (pt->GetX() < this->GetX())
1424 pt->sm_controlPointDragStartX = (double)(this->GetX() + (bound_x/2.0));
1425 else
1426 pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0));
1427
1428 if (pt->GetY() < this->GetY())
1429 pt->sm_controlPointDragStartY = (double)(this->GetY() + (bound_y/2.0));
1430 else
1431 pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0));
1432
1433 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
1434 pt->sm_controlPointDragStartY = (double)(this->GetY() - (bound_y/2.0));
1435 else if (pt->m_type == CONTROL_POINT_VERTICAL)
1436 pt->sm_controlPointDragStartX = (double)(this->GetX() - (bound_x/2.0));
1437
1438 // We may require the old width and height.
1439 pt->sm_controlPointDragStartWidth = bound_x;
1440 pt->sm_controlPointDragStartHeight = bound_y;
1441
1442 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1443 dc.SetPen(dottedPen);
1444 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1445
1446 if (this->GetCentreResize())
1447 {
1448 double new_width = (double)(2.0*fabs(x - this->GetX()));
1449 double new_height = (double)(2.0*fabs(y - this->GetY()));
1450
1451 // Constrain sizing according to what control point you're dragging
1452 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
1453 {
1454 if (GetMaintainAspectRatio())
1455 {
1456 new_height = bound_y*(new_width/bound_x);
1457 }
1458 else
1459 new_height = bound_y;
1460 }
1461 else if (pt->m_type == CONTROL_POINT_VERTICAL)
1462 {
1463 if (GetMaintainAspectRatio())
1464 {
1465 new_width = bound_x*(new_height/bound_y);
1466 }
1467 else
1468 new_width = bound_x;
1469 }
1470 else if (pt->m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
1471 new_height = bound_y*(new_width/bound_x);
1472
1473 if (this->GetFixedWidth())
1474 new_width = bound_x;
1475
1476 if (this->GetFixedHeight())
1477 new_height = bound_y;
1478
1479 pt->sm_controlPointDragEndWidth = new_width;
1480 pt->sm_controlPointDragEndHeight = new_height;
1481 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
1482 new_width, new_height);
1483 }
1484 else
1485 {
1486 // Don't maintain the same centre point!
1487 double newX1 = wxMin(pt->sm_controlPointDragStartX, x);
1488 double newY1 = wxMin(pt->sm_controlPointDragStartY, y);
1489 double newX2 = wxMax(pt->sm_controlPointDragStartX, x);
1490 double newY2 = wxMax(pt->sm_controlPointDragStartY, y);
1491 if (pt->m_type == CONTROL_POINT_HORIZONTAL)
1492 {
1493 newY1 = pt->sm_controlPointDragStartY;
1494 newY2 = newY1 + pt->sm_controlPointDragStartHeight;
1495 }
1496 else if (pt->m_type == CONTROL_POINT_VERTICAL)
1497 {
1498 newX1 = pt->sm_controlPointDragStartX;
1499 newX2 = newX1 + pt->sm_controlPointDragStartWidth;
1500 }
1501 else if (pt->m_type == CONTROL_POINT_DIAGONAL && ((keys & KEY_SHIFT) || GetMaintainAspectRatio()))
1502 {
1503 double newH = (double)((newX2 - newX1)*(pt->sm_controlPointDragStartHeight/pt->sm_controlPointDragStartWidth));
1504 if (pt->GetY() > pt->sm_controlPointDragStartY)
1505 newY2 = (double)(newY1 + newH);
1506 else
1507 newY1 = (double)(newY2 - newH);
1508 }
1509 double newWidth = (double)(newX2 - newX1);
1510 double newHeight = (double)(newY2 - newY1);
1511
1512 if (pt->m_type == CONTROL_POINT_VERTICAL && GetMaintainAspectRatio())
1513 {
1514 newWidth = bound_x * (newHeight/bound_y) ;
1515 }
1516
1517 if (pt->m_type == CONTROL_POINT_HORIZONTAL && GetMaintainAspectRatio())
1518 {
1519 newHeight = bound_y * (newWidth/bound_x) ;
1520 }
1521
1522 pt->sm_controlPointDragPosX = (double)(newX1 + (newWidth/2.0));
1523 pt->sm_controlPointDragPosY = (double)(newY1 + (newHeight/2.0));
1524 if (this->GetFixedWidth())
1525 newWidth = bound_x;
1526
1527 if (this->GetFixedHeight())
1528 newHeight = bound_y;
1529
1530 pt->sm_controlPointDragEndWidth = newWidth;
1531 pt->sm_controlPointDragEndHeight = newHeight;
1532 this->GetEventHandler()->OnDrawOutline(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY, newWidth, newHeight);
1533 }
1534 }
1535
1536 void wxShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
1537 {
1538 wxClientDC dc(GetCanvas());
1539 GetCanvas()->PrepareDC(dc);
1540
1541 m_canvas->ReleaseMouse();
1542 dc.SetLogicalFunction(wxCOPY);
1543 this->Recompute();
1544 this->ResetControlPoints();
1545
1546 this->Erase(dc);
1547 /*
1548 if (!pt->m_eraseObject)
1549 this->Show(FALSE);
1550 */
1551
1552 this->SetSize(pt->sm_controlPointDragEndWidth, pt->sm_controlPointDragEndHeight);
1553
1554 // The next operation could destroy this control point (it does for label objects,
1555 // via formatting the text), so save all values we're going to use, or
1556 // we'll be accessing garbage.
1557 wxShape *theObject = this;
1558 wxShapeCanvas *theCanvas = m_canvas;
1559 bool eraseIt = pt->m_eraseObject;
1560
1561 if (theObject->GetCentreResize())
1562 theObject->Move(dc, theObject->GetX(), theObject->GetY());
1563 else
1564 theObject->Move(dc, pt->sm_controlPointDragPosX, pt->sm_controlPointDragPosY);
1565
1566 /*
1567 if (!eraseIt)
1568 theObject->Show(TRUE);
1569 */
1570
1571 // Recursively redraw links if we have a composite.
1572 if (theObject->GetChildren().Number() > 0)
1573 theObject->DrawLinks(dc, -1, TRUE);
1574
1575 double width, height;
1576 theObject->GetBoundingBoxMax(&width, &height);
1577 theObject->GetEventHandler()->OnEndSize(width, height);
1578
1579 if (!theCanvas->GetQuickEditMode() && eraseIt) theCanvas->Redraw(dc);
1580 }
1581
1582
1583
1584 // Polygon control points
1585
1586 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint, wxControlPoint)
1587
1588 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas *theCanvas, wxShape *object, double size,
1589 wxRealPoint *vertex, double the_xoffset, double the_yoffset):
1590 wxControlPoint(theCanvas, object, size, the_xoffset, the_yoffset, 0)
1591 {
1592 m_polygonVertex = vertex;
1593 m_originalDistance = 0.0;
1594 }
1595
1596 wxPolygonControlPoint::~wxPolygonControlPoint()
1597 {
1598 }
1599
1600 // Calculate what new size would be, at end of resize
1601 void wxPolygonControlPoint::CalculateNewSize(double x, double y)
1602 {
1603 double bound_x;
1604 double bound_y;
1605 GetShape()->GetBoundingBoxMin(&bound_x, &bound_y);
1606
1607 double dist = (double)sqrt((x - m_shape->GetX())*(x - m_shape->GetX()) +
1608 (y - m_shape->GetY())*(y - m_shape->GetY()));
1609
1610 m_newSize.x = (double)(dist/this->m_originalDistance)*this->m_originalSize.x;
1611 m_newSize.y = (double)(dist/this->m_originalDistance)*this->m_originalSize.y;
1612 }
1613
1614
1615 // Implement resizing polygon or moving the vertex.
1616 void wxPolygonControlPoint::OnDragLeft(bool draw, double x, double y, int keys, int attachment)
1617 {
1618 m_shape->GetEventHandler()->OnSizingDragLeft(this, draw, x, y, keys, attachment);
1619 }
1620
1621 void wxPolygonControlPoint::OnBeginDragLeft(double x, double y, int keys, int attachment)
1622 {
1623 m_shape->GetEventHandler()->OnSizingBeginDragLeft(this, x, y, keys, attachment);
1624 }
1625
1626 void wxPolygonControlPoint::OnEndDragLeft(double x, double y, int keys, int attachment)
1627 {
1628 m_shape->GetEventHandler()->OnSizingEndDragLeft(this, x, y, keys, attachment);
1629 }
1630
1631 // Control points ('handles') redirect control to the actual shape, to make it easier
1632 // to override sizing behaviour.
1633 void wxPolygonShape::OnSizingDragLeft(wxControlPoint* pt, bool draw, double x, double y, int keys, int attachment)
1634 {
1635 wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
1636
1637 wxClientDC dc(GetCanvas());
1638 GetCanvas()->PrepareDC(dc);
1639
1640 dc.SetLogicalFunction(wxXOR);
1641
1642 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1643 dc.SetPen(dottedPen);
1644 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1645
1646 if (0) // keys & KEY_CTRL)
1647 {
1648 // TODO: mend this code. Currently we rely on altering the
1649 // actual points, but we should assume we're not, as per
1650 // the normal sizing case.
1651 m_canvas->Snap(&x, &y);
1652
1653 // Move point
1654 ppt->m_polygonVertex->x = x - this->GetX();
1655 ppt->m_polygonVertex->y = y - this->GetY();
1656 ppt->SetX(x);
1657 ppt->SetY(y);
1658 ((wxPolygonShape *)this)->CalculateBoundingBox();
1659 ((wxPolygonShape *)this)->CalculatePolygonCentre();
1660 }
1661 else
1662 {
1663 ppt->CalculateNewSize(x, y);
1664 }
1665
1666 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
1667 ppt->GetNewSize().x, ppt->GetNewSize().y);
1668 }
1669
1670 void wxPolygonShape::OnSizingBeginDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
1671 {
1672 wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
1673
1674 wxClientDC dc(GetCanvas());
1675 GetCanvas()->PrepareDC(dc);
1676
1677 this->Erase(dc);
1678
1679 dc.SetLogicalFunction(wxXOR);
1680
1681 double bound_x;
1682 double bound_y;
1683 this->GetBoundingBoxMin(&bound_x, &bound_y);
1684
1685 double dist = (double)sqrt((x - this->GetX())*(x - this->GetX()) +
1686 (y - this->GetY())*(y - this->GetY()));
1687 ppt->m_originalDistance = dist;
1688 ppt->m_originalSize.x = bound_x;
1689 ppt->m_originalSize.y = bound_y;
1690
1691 if (ppt->m_originalDistance == 0.0) ppt->m_originalDistance = (double) 0.0001;
1692
1693 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1694 dc.SetPen(dottedPen);
1695 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1696
1697 if (0) // keys & KEY_CTRL)
1698 {
1699 // TODO: mend this code. Currently we rely on altering the
1700 // actual points, but we should assume we're not, as per
1701 // the normal sizing case.
1702 m_canvas->Snap(&x, &y);
1703
1704 // Move point
1705 ppt->m_polygonVertex->x = x - this->GetX();
1706 ppt->m_polygonVertex->y = y - this->GetY();
1707 ppt->SetX(x);
1708 ppt->SetY(y);
1709 ((wxPolygonShape *)this)->CalculateBoundingBox();
1710 ((wxPolygonShape *)this)->CalculatePolygonCentre();
1711 }
1712 else
1713 {
1714 ppt->CalculateNewSize(x, y);
1715 }
1716
1717 this->GetEventHandler()->OnDrawOutline(dc, this->GetX(), this->GetY(),
1718 ppt->GetNewSize().x, ppt->GetNewSize().y);
1719
1720 m_canvas->CaptureMouse();
1721 }
1722
1723 void wxPolygonShape::OnSizingEndDragLeft(wxControlPoint* pt, double x, double y, int keys, int attachment)
1724 {
1725 wxPolygonControlPoint* ppt = (wxPolygonControlPoint*) pt;
1726
1727 wxClientDC dc(GetCanvas());
1728 GetCanvas()->PrepareDC(dc);
1729
1730 m_canvas->ReleaseMouse();
1731 dc.SetLogicalFunction(wxCOPY);
1732
1733 // If we're changing shape, must reset the original points
1734 if (keys & KEY_CTRL)
1735 {
1736 ((wxPolygonShape *)this)->CalculateBoundingBox();
1737 ((wxPolygonShape *)this)->UpdateOriginalPoints();
1738 }
1739 else
1740 {
1741 SetSize(ppt->GetNewSize().x, ppt->GetNewSize().y);
1742 }
1743
1744 ((wxPolygonShape *)this)->CalculateBoundingBox();
1745 ((wxPolygonShape *)this)->CalculatePolygonCentre();
1746
1747 this->Recompute();
1748 this->ResetControlPoints();
1749 this->Move(dc, this->GetX(), this->GetY());
1750 if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1751 }
1752
1753 /*
1754 * Object region
1755 *
1756 */
1757 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion, wxObject)
1758
1759 wxShapeRegion::wxShapeRegion()
1760 {
1761 m_regionText = "";
1762 m_font = g_oglNormalFont;
1763 m_minHeight = 5.0;
1764 m_minWidth = 5.0;
1765 m_width = 0.0;
1766 m_height = 0.0;
1767 m_x = 0.0;
1768 m_y = 0.0;
1769
1770 m_regionProportionX = -1.0;
1771 m_regionProportionY = -1.0;
1772 m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
1773 m_regionName = "";
1774 m_textColour = "BLACK";
1775 m_penColour = "BLACK";
1776 m_penStyle = wxSOLID;
1777 m_actualColourObject = NULL;
1778 m_actualPenObject = NULL;
1779 }
1780
1781 wxShapeRegion::wxShapeRegion(wxShapeRegion& region)
1782 {
1783 m_regionText = region.m_regionText;
1784 m_regionName = region.m_regionName;
1785 m_textColour = region.m_textColour;
1786
1787 m_font = region.m_font;
1788 m_minHeight = region.m_minHeight;
1789 m_minWidth = region.m_minWidth;
1790 m_width = region.m_width;
1791 m_height = region.m_height;
1792 m_x = region.m_x;
1793 m_y = region.m_y;
1794
1795 m_regionProportionX = region.m_regionProportionX;
1796 m_regionProportionY = region.m_regionProportionY;
1797 m_formatMode = region.m_formatMode;
1798 m_actualColourObject = NULL;
1799 m_actualPenObject = NULL;
1800 m_penStyle = region.m_penStyle;
1801 m_penColour = region.m_penColour;
1802
1803 ClearText();
1804 wxNode *node = region.m_formattedText.First();
1805 while (node)
1806 {
1807 wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
1808 wxShapeTextLine *new_line =
1809 new wxShapeTextLine(line->GetX(), line->GetY(), line->GetText());
1810 m_formattedText.Append(new_line);
1811 node = node->Next();
1812 }
1813 }
1814
1815 wxShapeRegion::~wxShapeRegion()
1816 {
1817 ClearText();
1818 }
1819
1820 void wxShapeRegion::ClearText()
1821 {
1822 wxNode *node = m_formattedText.First();
1823 while (node)
1824 {
1825 wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
1826 wxNode *next = node->Next();
1827 delete line;
1828 delete node;
1829 node = next;
1830 }
1831 }
1832
1833 void wxShapeRegion::SetFont(wxFont *f)
1834 {
1835 m_font = f;
1836 }
1837
1838 void wxShapeRegion::SetMinSize(double w, double h)
1839 {
1840 m_minWidth = w;
1841 m_minHeight = h;
1842 }
1843
1844 void wxShapeRegion::SetSize(double w, double h)
1845 {
1846 m_width = w;
1847 m_height = h;
1848 }
1849
1850 void wxShapeRegion::SetPosition(double xp, double yp)
1851 {
1852 m_x = xp;
1853 m_y = yp;
1854 }
1855
1856 void wxShapeRegion::SetProportions(double xp, double yp)
1857 {
1858 m_regionProportionX = xp;
1859 m_regionProportionY = yp;
1860 }
1861
1862 void wxShapeRegion::SetFormatMode(int mode)
1863 {
1864 m_formatMode = mode;
1865 }
1866
1867 void wxShapeRegion::SetColour(const wxString& col)
1868 {
1869 m_textColour = col;
1870 m_actualColourObject = NULL;
1871 }
1872
1873 wxColour *wxShapeRegion::GetActualColourObject()
1874 {
1875 if (!m_actualColourObject)
1876 m_actualColourObject = wxTheColourDatabase->FindColour(GetColour());
1877 if (!m_actualColourObject)
1878 m_actualColourObject = wxBLACK;
1879 return m_actualColourObject;
1880 }
1881
1882 void wxShapeRegion::SetPenColour(const wxString& col)
1883 {
1884 m_penColour = col;
1885 m_actualPenObject = NULL;
1886 }
1887
1888 // Returns NULL if the pen is invisible
1889 // (different to pen being transparent; indicates that
1890 // region boundary should not be drawn.)
1891 wxPen *wxShapeRegion::GetActualPen()
1892 {
1893 if (m_actualPenObject)
1894 return m_actualPenObject;
1895
1896 if (!m_penColour) return NULL;
1897 if (m_penColour == "Invisible")
1898 return NULL;
1899 m_actualPenObject = wxThePenList->FindOrCreatePen(m_penColour, 1, m_penStyle);
1900 return m_actualPenObject;
1901 }
1902
1903