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