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