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