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