]> git.saurik.com Git - wxWidgets.git/blob - utils/ogl/src/basic2.cpp
bff1defda1166be69f1919d3b5825ac0357fa606
[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(wxPolygonShape& copy)
830 {
831 wxShape::Copy(copy);
832
833 if (copy.m_points)
834 delete copy.m_points;
835
836 copy.m_points = new wxList;
837
838 if (copy.m_originalPoints)
839 delete copy.m_originalPoints;
840
841 copy.m_originalPoints = new wxList;
842
843 wxNode *node = m_points->First();
844 while (node)
845 {
846 wxRealPoint *point = (wxRealPoint *)node->Data();
847 wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
848 copy.m_points->Append((wxObject*) new_point);
849 node = node->Next();
850 }
851 node = m_originalPoints->First();
852 while (node)
853 {
854 wxRealPoint *point = (wxRealPoint *)node->Data();
855 wxRealPoint *new_point = new wxRealPoint(point->x, point->y);
856 copy.m_originalPoints->Append((wxObject*) new_point);
857 node = node->Next();
858 }
859 copy.m_boundWidth = m_boundWidth;
860 copy.m_boundHeight = m_boundHeight;
861 copy.m_originalWidth = m_originalWidth;
862 copy.m_originalHeight = m_originalHeight;
863 }
864
865 wxShape *wxPolygonShape::PrivateCopy()
866 {
867 wxPolygonShape *obj = new wxPolygonShape;
868 Copy(*obj);
869 return obj;
870 }
871
872 int wxPolygonShape::GetNumberOfAttachments()
873 {
874 int maxN = (m_points ? (m_points->Number() - 1) : 0);
875 wxNode *node = m_attachmentPoints.First();
876 while (node)
877 {
878 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
879 if (point->m_id > maxN)
880 maxN = point->m_id;
881 node = node->Next();
882 }
883 return maxN+1;;
884 }
885
886 bool wxPolygonShape::GetAttachmentPosition(int attachment, float *x, float *y,
887 int nth, int no_arcs, wxLineShape *line)
888 {
889 if (m_attachmentMode && m_points && attachment < m_points->Number())
890 {
891 wxRealPoint *point = (wxRealPoint *)m_points->Nth(attachment)->Data();
892 *x = point->x + m_xpos;
893 *y = point->y + m_ypos;
894 return TRUE;
895 }
896 else
897 { return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line); }
898 }
899
900 bool wxPolygonShape::AttachmentIsValid(int attachment)
901 {
902 if (!m_points)
903 return FALSE;
904
905 if ((attachment >= 0) && (attachment < m_points->Number()))
906 return TRUE;
907
908 wxNode *node = m_attachmentPoints.First();
909 while (node)
910 {
911 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
912 if (point->m_id == attachment)
913 return TRUE;
914 node = node->Next();
915 }
916 return FALSE;
917 }
918
919 // Rectangle object
920
921 IMPLEMENT_DYNAMIC_CLASS(wxRectangleShape, wxShape)
922
923 wxRectangleShape::wxRectangleShape(float w, float h)
924 {
925 m_width = w; m_height = h; m_cornerRadius = 0.0;
926 SetDefaultRegionSize();
927 }
928
929 void wxRectangleShape::OnDraw(wxDC& dc)
930 {
931 float x1 = (float)(m_xpos - m_width/2.0);
932 float y1 = (float)(m_ypos - m_height/2.0);
933
934 if (m_shadowMode != SHADOW_NONE)
935 {
936 if (m_shadowBrush)
937 dc.SetBrush(m_shadowBrush);
938 dc.SetPen(transparent_pen);
939
940 if (m_cornerRadius != 0.0)
941 dc.DrawRoundedRectangle(x1 + m_shadowOffsetX, y1 + m_shadowOffsetY,
942 m_width, m_height, m_cornerRadius);
943 else
944 dc.DrawRectangle(x1 + m_shadowOffsetX, y1 + m_shadowOffsetY, m_width, m_height);
945 }
946
947 if (m_pen)
948 {
949 if (m_pen->GetWidth() == 0)
950 dc.SetPen(transparent_pen);
951 else
952 dc.SetPen(m_pen);
953 }
954 if (m_brush)
955 dc.SetBrush(m_brush);
956
957 if (m_cornerRadius != 0.0)
958 dc.DrawRoundedRectangle(x1, y1, m_width, m_height, m_cornerRadius);
959 else
960 dc.DrawRectangle(x1, y1, m_width, m_height);
961 }
962
963 void wxRectangleShape::GetBoundingBoxMin(float *the_width, float *the_height)
964 {
965 *the_width = m_width;
966 *the_height = m_height;
967 }
968
969 void wxRectangleShape::SetSize(float x, float y, bool recursive)
970 {
971 SetAttachmentSize(x, y);
972 m_width = (float)wxMax(x, 1.0);
973 m_height = (float)wxMax(y, 1.0);
974 SetDefaultRegionSize();
975 }
976
977 void wxRectangleShape::SetCornerRadius(float rad)
978 {
979 m_cornerRadius = rad;
980 }
981
982 // Assume (x1, y1) is centre of box (most generally, line end at box)
983 bool wxRectangleShape::GetPerimeterPoint(float x1, float y1,
984 float x2, float y2,
985 float *x3, float *y3)
986 {
987 float bound_x, bound_y;
988 GetBoundingBoxMax(&bound_x, &bound_y);
989 find_end_for_box(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
990
991 return TRUE;
992 }
993
994 #ifdef PROLOGIO
995 void wxRectangleShape::WritePrologAttributes(wxExpr *clause)
996 {
997 wxShape::WritePrologAttributes(clause);
998 clause->AddAttributeValue("x", m_xpos);
999 clause->AddAttributeValue("y", m_ypos);
1000
1001 clause->AddAttributeValue("width", m_width);
1002 clause->AddAttributeValue("height", m_height);
1003 if (m_cornerRadius != 0.0)
1004 clause->AddAttributeValue("corner", m_cornerRadius);
1005 }
1006
1007 void wxRectangleShape::ReadPrologAttributes(wxExpr *clause)
1008 {
1009 wxShape::ReadPrologAttributes(clause);
1010 clause->AssignAttributeValue("width", &m_width);
1011 clause->AssignAttributeValue("height", &m_height);
1012 clause->AssignAttributeValue("corner", &m_cornerRadius);
1013
1014 // In case we're reading an old file, set the region's size
1015 if (m_regions.Number() == 1)
1016 {
1017 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
1018 region->SetSize(m_width, m_height);
1019 }
1020 }
1021 #endif
1022
1023 void wxRectangleShape::Copy(wxRectangleShape& copy)
1024 {
1025 wxShape::Copy(copy);
1026 copy.m_width = m_width;
1027 copy.m_height = m_height;
1028 copy.m_cornerRadius = m_cornerRadius;
1029 }
1030
1031 wxShape *wxRectangleShape::PrivateCopy()
1032 {
1033 wxRectangleShape *obj = new wxRectangleShape(0.0, 0.0);
1034 Copy(*obj);
1035 return obj;
1036 }
1037
1038
1039 int wxRectangleShape::GetNumberOfAttachments()
1040 {
1041 return wxShape::GetNumberOfAttachments();
1042 }
1043
1044 // There are 4 attachment points on a rectangle - 0 = top, 1 = right, 2 = bottom,
1045 // 3 = left.
1046 bool wxRectangleShape::GetAttachmentPosition(int attachment, float *x, float *y,
1047 int nth, int no_arcs, wxLineShape *line)
1048 {
1049 if (m_attachmentMode)
1050 {
1051 float top = (float)(m_ypos + m_height/2.0);
1052 float bottom = (float)(m_ypos - m_height/2.0);
1053 float left = (float)(m_xpos - m_width/2.0);
1054 float right = (float)(m_xpos + m_width/2.0);
1055
1056 bool isEnd = (line && line->IsEnd(this));
1057
1058 switch (attachment)
1059 {
1060 case 0:
1061 {
1062 if (m_spaceAttachments)
1063 {
1064 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
1065 {
1066 // Align line according to the next handle along
1067 wxRealPoint *point = line->GetNextControlPoint(this);
1068 if (point->x < left)
1069 *x = left;
1070 else if (point->x > right)
1071 *x = right;
1072 else
1073 *x = point->x;
1074 }
1075 else
1076 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1077 }
1078 else *x = m_xpos;
1079
1080 *y = bottom;
1081 break;
1082 }
1083 case 1:
1084 {
1085 *x = right;
1086 if (m_spaceAttachments)
1087 {
1088 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
1089 {
1090 // Align line according to the next handle along
1091 wxRealPoint *point = line->GetNextControlPoint(this);
1092 if (point->y < bottom)
1093 *y = bottom;
1094 else if (point->y > top)
1095 *y = top;
1096 else
1097 *y = point->y;
1098 }
1099 else
1100 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1101 }
1102 else *y = m_ypos;
1103 break;
1104 }
1105 case 2:
1106 {
1107 if (m_spaceAttachments)
1108 {
1109 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
1110 {
1111 // Align line according to the next handle along
1112 wxRealPoint *point = line->GetNextControlPoint(this);
1113 if (point->x < left)
1114 *x = left;
1115 else if (point->x > right)
1116 *x = right;
1117 else
1118 *x = point->x;
1119 }
1120 else
1121 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1122 }
1123 else *x = m_xpos;
1124 *y = top;
1125 break;
1126 }
1127 case 3:
1128 {
1129 *x = left;
1130 if (m_spaceAttachments)
1131 {
1132 if (line && (line->GetAlignmentType(isEnd) == LINE_ALIGNMENT_TO_NEXT_HANDLE))
1133 {
1134 // Align line according to the next handle along
1135 wxRealPoint *point = line->GetNextControlPoint(this);
1136 if (point->y < bottom)
1137 *y = bottom;
1138 else if (point->y > top)
1139 *y = top;
1140 else
1141 *y = point->y;
1142 }
1143 else
1144 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1145 }
1146 else *y = m_ypos;
1147 break;
1148 }
1149 default:
1150 {
1151 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
1152 break;
1153 }
1154 }
1155 return TRUE;
1156 }
1157 else
1158 { *x = m_xpos; *y = m_ypos; return TRUE; }
1159 }
1160
1161 // Text object (no box)
1162
1163 IMPLEMENT_DYNAMIC_CLASS(wxTextShape, wxRectangleShape)
1164
1165 wxTextShape::wxTextShape(float width, float height):
1166 wxRectangleShape(width, height)
1167 {
1168 }
1169
1170 void wxTextShape::OnDraw(wxDC& dc)
1171 {
1172 }
1173
1174 wxShape *wxTextShape::PrivateCopy()
1175 {
1176 wxTextShape *obj = new wxTextShape(0.0, 0.0);
1177 Copy(*obj);
1178 return obj;
1179 }
1180
1181 void wxTextShape::Copy(wxTextShape& copy)
1182 {
1183 wxRectangleShape::Copy(copy);
1184 }
1185
1186 #ifdef PROLOGIO
1187 void wxTextShape::WritePrologAttributes(wxExpr *clause)
1188 {
1189 wxRectangleShape::WritePrologAttributes(clause);
1190 }
1191 #endif
1192
1193 // Ellipse object
1194
1195 IMPLEMENT_DYNAMIC_CLASS(wxEllipseShape, wxShape)
1196
1197 wxEllipseShape::wxEllipseShape(float w, float h)
1198 {
1199 m_width = w; m_height = h;
1200 SetDefaultRegionSize();
1201 }
1202
1203 void wxEllipseShape::GetBoundingBoxMin(float *w, float *h)
1204 {
1205 *w = m_width; *h = m_height;
1206 }
1207
1208 bool wxEllipseShape::GetPerimeterPoint(float x1, float y1,
1209 float x2, float y2,
1210 float *x3, float *y3)
1211 {
1212 float bound_x, bound_y;
1213 GetBoundingBoxMax(&bound_x, &bound_y);
1214
1215 // find_end_for_box(bound_x, bound_y, m_xpos, m_ypos, x2, y2, x3, y3);
1216 draw_arc_to_ellipse(m_xpos, m_ypos, bound_x, bound_y, x2, y2, x1, y1, x3, y3);
1217
1218 return TRUE;
1219 }
1220
1221 void wxEllipseShape::OnDraw(wxDC& dc)
1222 {
1223 if (m_shadowMode != SHADOW_NONE)
1224 {
1225 if (m_shadowBrush)
1226 dc.SetBrush(m_shadowBrush);
1227 dc.SetPen(transparent_pen);
1228 dc.DrawEllipse((m_xpos - GetWidth()/2) + m_shadowOffsetX,
1229 (m_ypos - GetHeight()/2) + m_shadowOffsetY,
1230 GetWidth(), GetHeight());
1231 }
1232
1233 if (m_pen)
1234 {
1235 if (m_pen->GetWidth() == 0)
1236 dc.SetPen(transparent_pen);
1237 else
1238 dc.SetPen(m_pen);
1239 }
1240 if (m_brush)
1241 dc.SetBrush(m_brush);
1242 dc.DrawEllipse((m_xpos - GetWidth()/2), (m_ypos - GetHeight()/2), GetWidth(), GetHeight());
1243 }
1244
1245 void wxEllipseShape::SetSize(float x, float y, bool recursive)
1246 {
1247 SetAttachmentSize(x, y);
1248 m_width = x;
1249 m_height = y;
1250 SetDefaultRegionSize();
1251 }
1252
1253 #ifdef PROLOGIO
1254 void wxEllipseShape::WritePrologAttributes(wxExpr *clause)
1255 {
1256 wxShape::WritePrologAttributes(clause);
1257 clause->AddAttributeValue("x", m_xpos);
1258 clause->AddAttributeValue("y", m_ypos);
1259
1260 clause->AddAttributeValue("width", m_width);
1261 clause->AddAttributeValue("height", m_height);
1262 }
1263
1264 void wxEllipseShape::ReadPrologAttributes(wxExpr *clause)
1265 {
1266 wxShape::ReadPrologAttributes(clause);
1267 clause->AssignAttributeValue("width", &m_width);
1268 clause->AssignAttributeValue("height", &m_height);
1269
1270 // In case we're reading an old file, set the region's size
1271 if (m_regions.Number() == 1)
1272 {
1273 wxShapeRegion *region = (wxShapeRegion *)m_regions.First()->Data();
1274 region->SetSize(m_width, m_height);
1275 }
1276 }
1277 #endif
1278
1279 void wxEllipseShape::Copy(wxEllipseShape& copy)
1280 {
1281 wxShape::Copy(copy);
1282
1283 copy.m_width = m_width;
1284 copy.m_height = m_height;
1285 }
1286
1287 wxShape *wxEllipseShape::PrivateCopy()
1288 {
1289 wxEllipseShape *obj = new wxEllipseShape(0.0, 0.0);
1290 Copy(*obj);
1291 return obj;
1292 }
1293
1294 int wxEllipseShape::GetNumberOfAttachments()
1295 {
1296 return wxShape::GetNumberOfAttachments();
1297 }
1298
1299 // There are 4 attachment points on an ellipse - 0 = top, 1 = right, 2 = bottom,
1300 // 3 = left.
1301 bool wxEllipseShape::GetAttachmentPosition(int attachment, float *x, float *y,
1302 int nth, int no_arcs, wxLineShape *line)
1303 {
1304 if (m_attachmentMode)
1305 {
1306 float top = (float)(m_ypos + m_height/2.0);
1307 float bottom = (float)(m_ypos - m_height/2.0);
1308 float left = (float)(m_xpos - m_width/2.0);
1309 float right = (float)(m_xpos + m_width/2.0);
1310 switch (attachment)
1311 {
1312 case 0:
1313 {
1314 if (m_spaceAttachments)
1315 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1316 else *x = m_xpos;
1317 *y = top;
1318 // We now have the point on the bounding box: but get the point on the ellipse
1319 // by imagining a vertical line from (*x, m_ypos - m_height- 500) to (*x, m_ypos) intersecting
1320 // the ellipse.
1321 draw_arc_to_ellipse(m_xpos, m_ypos, m_width, m_height, *x, (float)(m_ypos-m_height-500), *x, m_ypos, x, y);
1322 break;
1323 }
1324 case 1:
1325 {
1326 *x = right;
1327 if (m_spaceAttachments)
1328 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1329 else *y = m_ypos;
1330 draw_arc_to_ellipse(m_xpos, m_ypos, m_width, m_height, (float)(m_xpos+m_width+500), *y, m_xpos, *y, x, y);
1331 break;
1332 }
1333 case 2:
1334 {
1335 if (m_spaceAttachments)
1336 *x = left + (nth + 1)*m_width/(no_arcs + 1);
1337 else *x = m_xpos;
1338 *y = bottom;
1339 draw_arc_to_ellipse(m_xpos, m_ypos, m_width, m_height, *x, (float)(m_ypos+m_height+500), *x, m_ypos, x, y);
1340 break;
1341 }
1342 case 3:
1343 {
1344 *x = left;
1345 if (m_spaceAttachments)
1346 *y = bottom + (nth + 1)*m_height/(no_arcs + 1);
1347 else *y = m_ypos;
1348 draw_arc_to_ellipse(m_xpos, m_ypos, m_width, m_height, (float)(m_xpos-m_width-500), *y, m_xpos, *y, x, y);
1349 break;
1350 }
1351 default:
1352 {
1353 return wxShape::GetAttachmentPosition(attachment, x, y, nth, no_arcs, line);
1354 break;
1355 }
1356 }
1357 return TRUE;
1358 }
1359 else
1360 { *x = m_xpos; *y = m_ypos; return TRUE; }
1361 }
1362
1363
1364 // Circle object
1365 IMPLEMENT_DYNAMIC_CLASS(wxCircleShape, wxEllipseShape)
1366
1367 wxCircleShape::wxCircleShape(float diameter):wxEllipseShape(diameter, diameter)
1368 {
1369 }
1370
1371 wxShape *wxCircleShape::PrivateCopy()
1372 {
1373 wxCircleShape *obj = new wxCircleShape(0.0);
1374 Copy(*obj);
1375 return obj;
1376 }
1377
1378 void wxCircleShape::Copy(wxCircleShape& copy)
1379 {
1380 wxEllipseShape::Copy(copy);
1381 }
1382
1383 bool wxCircleShape::GetPerimeterPoint(float x1, float y1,
1384 float x2, float y2,
1385 float *x3, float *y3)
1386 {
1387 find_end_for_circle(m_width/2,
1388 m_xpos, m_ypos, // Centre of circle
1389 x2, y2, // Other end of line
1390 x3, y3);
1391
1392 return TRUE;
1393 }
1394
1395 // Control points
1396
1397 IMPLEMENT_DYNAMIC_CLASS(wxControlPoint, wxRectangleShape)
1398
1399 wxControlPoint::wxControlPoint(wxShapeCanvas *theCanvas, wxShape *object, float size, float the_xoffset, float the_yoffset, int the_type):wxRectangleShape(size, size)
1400 {
1401 m_canvas = theCanvas;
1402 m_shape = object;
1403 m_xoffset = the_xoffset;
1404 m_yoffset = the_yoffset;
1405 m_type = the_type;
1406 SetPen(black_foreground_pen);
1407 SetBrush(wxBLACK_BRUSH);
1408 m_oldCursor = NULL;
1409 m_visible = TRUE;
1410 m_eraseObject = TRUE;
1411 }
1412
1413 wxControlPoint::~wxControlPoint()
1414 {
1415 }
1416
1417 // Don't even attempt to draw any text - waste of time!
1418 void wxControlPoint::OnDrawContents(wxDC& dc)
1419 {
1420 }
1421
1422 void wxControlPoint::OnDraw(wxDC& dc)
1423 {
1424 m_xpos = m_shape->GetX() + m_xoffset;
1425 m_ypos = m_shape->GetY() + m_yoffset;
1426 wxRectangleShape::OnDraw(dc);
1427 }
1428
1429 void wxControlPoint::OnErase(wxDC& dc)
1430 {
1431 wxRectangleShape::OnErase(dc);
1432 }
1433
1434 /*
1435 * Store original top-left, bottom-right coordinates
1436 * in case we're doing non-vertical resizing.
1437 */
1438 static float controlPointDragStartX = 0.0;
1439 static float controlPointDragStartY = 0.0;
1440 static float controlPointDragStartWidth = 0.0;
1441 static float controlPointDragStartHeight = 0.0;
1442 static float controlPointDragEndWidth = 0.0;
1443 static float controlPointDragEndHeight = 0.0;
1444 static float controlPointDragPosX = 0.0;
1445 static float controlPointDragPosY = 0.0;
1446
1447 // Implement resizing of canvas object
1448 void wxControlPoint::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
1449 {
1450 float bound_x;
1451 float bound_y;
1452 m_shape->GetBoundingBoxMin(&bound_x, &bound_y);
1453
1454 wxClientDC dc(GetCanvas());
1455 GetCanvas()->PrepareDC(dc);
1456
1457 dc.SetLogicalFunction(wxXOR);
1458
1459 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1460 dc.SetPen(dottedPen);
1461 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1462
1463 if (m_shape->GetCentreResize())
1464 {
1465 // Maintain the same centre point.
1466 float new_width = (float)(2.0*fabs(x - m_shape->GetX()));
1467 float new_height = (float)(2.0*fabs(y - m_shape->GetY()));
1468
1469 // Constrain sizing according to what control point you're dragging
1470 if (m_type == CONTROL_POINT_HORIZONTAL)
1471 new_height = bound_y;
1472 else if (m_type == CONTROL_POINT_VERTICAL)
1473 new_width = bound_x;
1474 else if (m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
1475 new_height = bound_y*(new_width/bound_x);
1476
1477 // m_shape->OnBeginSize(m_shape->m_fixedWidth ? bound_x : new_width,
1478 // m_shape->m_fixedHeight ? bound_y : new_height);
1479
1480 // m_shape->SetSize(m_shape->m_fixedWidth ? bound_x : new_width,
1481 // m_shape->m_fixedHeight ? bound_y : new_height);
1482 if (m_shape->GetFixedWidth())
1483 new_width = bound_x;
1484
1485 if (m_shape->GetFixedHeight())
1486 new_height = bound_y;
1487
1488 controlPointDragEndWidth = new_width;
1489 controlPointDragEndHeight = new_height;
1490
1491 m_shape->GetEventHandler()->OnDrawOutline(dc, m_shape->GetX(), m_shape->GetY(),
1492 new_width, new_height);
1493 }
1494 else
1495 {
1496 // Don't maintain the same centre point!
1497 float newX1 = wxMin(controlPointDragStartX, x);
1498 float newY1 = wxMin(controlPointDragStartY, y);
1499 float newX2 = wxMax(controlPointDragStartX, x);
1500 float newY2 = wxMax(controlPointDragStartY, y);
1501 if (m_type == CONTROL_POINT_HORIZONTAL)
1502 {
1503 newY1 = controlPointDragStartY;
1504 newY2 = newY1 + controlPointDragStartHeight;
1505 }
1506 else if (m_type == CONTROL_POINT_VERTICAL)
1507 {
1508 newX1 = controlPointDragStartX;
1509 newX2 = newX1 + controlPointDragStartWidth;
1510 }
1511 else if (m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
1512 {
1513 float newH = (float)((newX2 - newX1)*(controlPointDragStartHeight/controlPointDragStartWidth));
1514 if (GetY() > controlPointDragStartY)
1515 newY2 = (float)(newY1 + newH);
1516 else
1517 newY1 = (float)(newY2 - newH);
1518 }
1519 float newWidth = (float)(newX2 - newX1);
1520 float newHeight = (float)(newY2 - newY1);
1521
1522 // m_shape->OnBeginSize(newWidth,
1523 // newHeight);
1524
1525 // m_shape->SetSize(newWidth,
1526 // newHeight);
1527 controlPointDragPosX = (float)(newX1 + (newWidth/2.0));
1528 controlPointDragPosY = (float)(newY1 + (newHeight/2.0));
1529 if (m_shape->GetFixedWidth())
1530 newWidth = bound_x;
1531
1532 if (m_shape->GetFixedHeight())
1533 newHeight = bound_y;
1534
1535 controlPointDragEndWidth = newWidth;
1536 controlPointDragEndHeight = newHeight;
1537 m_shape->GetEventHandler()->OnDrawOutline(dc, controlPointDragPosX, controlPointDragPosY, newWidth, newHeight);
1538 }
1539 }
1540
1541 void wxControlPoint::OnBeginDragLeft(float x, float y, int keys, int attachment)
1542 {
1543 m_canvas->CaptureMouse();
1544
1545 wxClientDC dc(GetCanvas());
1546 GetCanvas()->PrepareDC(dc);
1547
1548 if (m_eraseObject)
1549 m_shape->Erase(dc);
1550
1551 dc.SetLogicalFunction(wxXOR);
1552
1553 float bound_x;
1554 float bound_y;
1555 m_shape->GetBoundingBoxMin(&bound_x, &bound_y);
1556
1557 // Choose the 'opposite corner' of the object as the stationary
1558 // point in case this is non-centring resizing.
1559 if (GetX() < m_shape->GetX())
1560 controlPointDragStartX = (float)(m_shape->GetX() + (bound_x/2.0));
1561 else
1562 controlPointDragStartX = (float)(m_shape->GetX() - (bound_x/2.0));
1563
1564 if (GetY() < m_shape->GetY())
1565 controlPointDragStartY = (float)(m_shape->GetY() + (bound_y/2.0));
1566 else
1567 controlPointDragStartY = (float)(m_shape->GetY() - (bound_y/2.0));
1568
1569 if (m_type == CONTROL_POINT_HORIZONTAL)
1570 controlPointDragStartY = (float)(m_shape->GetY() - (bound_y/2.0));
1571 else if (m_type == CONTROL_POINT_VERTICAL)
1572 controlPointDragStartX = (float)(m_shape->GetX() - (bound_x/2.0));
1573
1574 // We may require the old width and height.
1575 controlPointDragStartWidth = bound_x;
1576 controlPointDragStartHeight = bound_y;
1577
1578 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1579 dc.SetPen(dottedPen);
1580 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1581
1582 if (m_shape->GetCentreResize())
1583 {
1584 float new_width = (float)(2.0*fabs(x - m_shape->GetX()));
1585 float new_height = (float)(2.0*fabs(y - m_shape->GetY()));
1586
1587 // Constrain sizing according to what control point you're dragging
1588 if (m_type == CONTROL_POINT_HORIZONTAL)
1589 new_height = bound_y;
1590 else if (m_type == CONTROL_POINT_VERTICAL)
1591 new_width = bound_x;
1592 else if (m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
1593 new_height = bound_y*(new_width/bound_x);
1594
1595 // Non-recursive SetSize for speed
1596 // m_shape->SetSize(new_width, new_height, FALSE);
1597
1598 if (m_shape->GetFixedWidth())
1599 new_width = bound_x;
1600
1601 if (m_shape->GetFixedHeight())
1602 new_height = bound_y;
1603
1604 controlPointDragEndWidth = new_width;
1605 controlPointDragEndHeight = new_height;
1606 m_shape->GetEventHandler()->OnDrawOutline(dc, m_shape->GetX(), m_shape->GetY(),
1607 new_width, new_height);
1608 }
1609 else
1610 {
1611 // Don't maintain the same centre point!
1612 float newX1 = wxMin(controlPointDragStartX, x);
1613 float newY1 = wxMin(controlPointDragStartY, y);
1614 float newX2 = wxMax(controlPointDragStartX, x);
1615 float newY2 = wxMax(controlPointDragStartY, y);
1616 if (m_type == CONTROL_POINT_HORIZONTAL)
1617 {
1618 newY1 = controlPointDragStartY;
1619 newY2 = newY1 + controlPointDragStartHeight;
1620 }
1621 else if (m_type == CONTROL_POINT_VERTICAL)
1622 {
1623 newX1 = controlPointDragStartX;
1624 newX2 = newX1 + controlPointDragStartWidth;
1625 }
1626 else if (m_type == CONTROL_POINT_DIAGONAL && (keys & KEY_SHIFT))
1627 {
1628 float newH = (float)((newX2 - newX1)*(controlPointDragStartHeight/controlPointDragStartWidth));
1629 if (GetY() > controlPointDragStartY)
1630 newY2 = (float)(newY1 + newH);
1631 else
1632 newY1 = (float)(newY2 - newH);
1633 }
1634 float newWidth = (float)(newX2 - newX1);
1635 float newHeight = (float)(newY2 - newY1);
1636
1637 // m_shape->OnBeginSize(newWidth,
1638 // newHeight);
1639
1640 // m_shape->SetSize(newWidth,
1641 // newHeight);
1642 controlPointDragPosX = (float)(newX1 + (newWidth/2.0));
1643 controlPointDragPosY = (float)(newY1 + (newHeight/2.0));
1644 if (m_shape->GetFixedWidth())
1645 newWidth = bound_x;
1646
1647 if (m_shape->GetFixedHeight())
1648 newHeight = bound_y;
1649
1650 controlPointDragEndWidth = newWidth;
1651 controlPointDragEndHeight = newHeight;
1652 m_shape->GetEventHandler()->OnDrawOutline(dc, controlPointDragPosX, controlPointDragPosY, newWidth, newHeight);
1653 }
1654 }
1655
1656 void wxControlPoint::OnEndDragLeft(float x, float y, int keys, int attachment)
1657 {
1658 wxClientDC dc(GetCanvas());
1659 GetCanvas()->PrepareDC(dc);
1660
1661 m_canvas->ReleaseMouse();
1662 dc.SetLogicalFunction(wxCOPY);
1663 m_shape->Recompute();
1664 m_shape->ResetControlPoints();
1665
1666 if (!m_eraseObject)
1667 m_shape->Show(FALSE);
1668
1669 m_shape->SetSize(controlPointDragEndWidth, controlPointDragEndHeight);
1670
1671 // The next operation could destroy this control point (it does for label objects,
1672 // via formatting the text), so save all values we're going to use, or
1673 // we'll be accessing garbage.
1674 wxShape *theObject = m_shape;
1675 wxShapeCanvas *theCanvas = m_canvas;
1676 bool eraseIt = m_eraseObject;
1677
1678 if (theObject->GetCentreResize())
1679 theObject->Move(dc, theObject->GetX(), theObject->GetY());
1680 else
1681 theObject->Move(dc, controlPointDragPosX, controlPointDragPosY);
1682
1683 if (!eraseIt)
1684 theObject->Show(TRUE);
1685
1686 // Recursively redraw links if we have a composite.
1687 if (theObject->GetChildren().Number() > 0)
1688 theObject->DrawLinks(dc, -1, TRUE);
1689
1690 float width, height;
1691 theObject->GetBoundingBoxMax(&width, &height);
1692 theObject->GetEventHandler()->OnEndSize(width, height);
1693
1694 if (!theCanvas->GetQuickEditMode() && eraseIt) theCanvas->Redraw(dc);
1695 }
1696
1697 int wxControlPoint::GetNumberOfAttachments()
1698 {
1699 return 1;
1700 }
1701
1702 bool wxControlPoint::GetAttachmentPosition(int attachment, float *x, float *y,
1703 int nth, int no_arcs, wxLineShape *line)
1704 {
1705 *x = m_xpos; *y = m_ypos;
1706 return TRUE;
1707 }
1708
1709
1710 // Polygon control points
1711
1712 IMPLEMENT_DYNAMIC_CLASS(wxPolygonControlPoint, wxControlPoint)
1713
1714 wxPolygonControlPoint::wxPolygonControlPoint(wxShapeCanvas *theCanvas, wxShape *object, float size,
1715 wxRealPoint *vertex, float the_xoffset, float the_yoffset):
1716 wxControlPoint(theCanvas, object, size, the_xoffset, the_yoffset, 0)
1717 {
1718 m_polygonVertex = vertex;
1719 }
1720
1721 wxPolygonControlPoint::~wxPolygonControlPoint()
1722 {
1723 }
1724
1725 // Implement resizing polygon or moving the vertex.
1726 void wxPolygonControlPoint::OnDragLeft(bool draw, float x, float y, int keys, int attachment)
1727 {
1728 wxClientDC dc(GetCanvas());
1729 GetCanvas()->PrepareDC(dc);
1730
1731 dc.SetLogicalFunction(wxXOR);
1732
1733 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1734 dc.SetPen(dottedPen);
1735 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1736
1737 float bound_x;
1738 float bound_y;
1739 m_shape->GetBoundingBoxMin(&bound_x, &bound_y);
1740 /*
1741 float new_width = (float)(2.0*fabs(x - m_shape->GetX()));
1742 float new_height = (float)(2.0*fabs(y - m_shape->GetY()));
1743 */
1744 float dist = (float)sqrt((x - m_shape->GetX())*(x - m_shape->GetX()) +
1745 (y - m_shape->GetY())*(y - m_shape->GetY()));
1746
1747 if (keys & KEY_CTRL)
1748 {
1749 m_canvas->Snap(&x, &y);
1750
1751 // Move point
1752 m_polygonVertex->x = x - m_shape->GetX();
1753 m_polygonVertex->y = y - m_shape->GetY();
1754 m_xpos = x;
1755 m_xpos = y;
1756 ((wxPolygonShape *)m_shape)->CalculateBoundingBox();
1757 ((wxPolygonShape *)m_shape)->CalculatePolygonCentre();
1758 }
1759 else
1760 {
1761 float new_width = (float)(dist/m_originalDistance)*m_originalSize.x;
1762 float new_height = (float)(dist/m_originalDistance)*m_originalSize.y;
1763
1764 // Non-recursive SetSize for speed
1765 m_shape->SetSize(new_width, new_height, FALSE);
1766 }
1767 float w, h;
1768 m_shape->GetBoundingBoxMax(&w, &h);
1769 m_shape->GetEventHandler()->OnDrawOutline(dc, m_shape->GetX(), m_shape->GetY(), w, h);
1770 }
1771
1772 void wxPolygonControlPoint::OnBeginDragLeft(float x, float y, int keys, int attachment)
1773 {
1774 wxClientDC dc(GetCanvas());
1775 GetCanvas()->PrepareDC(dc);
1776
1777 m_shape->Erase(dc);
1778
1779 dc.SetLogicalFunction(wxXOR);
1780
1781 float bound_x;
1782 float bound_y;
1783 m_shape->GetBoundingBoxMin(&bound_x, &bound_y);
1784
1785 float dist = (float)sqrt((x - m_shape->GetX())*(x - m_shape->GetX()) +
1786 (y - m_shape->GetY())*(y - m_shape->GetY()));
1787
1788 m_originalDistance = dist;
1789 m_originalSize.x = bound_x;
1790 m_originalSize.y = bound_y;
1791
1792 if (m_originalDistance == 0.0) m_originalDistance = (float) 0.0001;
1793
1794 wxPen dottedPen(wxColour(0, 0, 0), 1, wxDOT);
1795 dc.SetPen(dottedPen);
1796 dc.SetBrush((* wxTRANSPARENT_BRUSH));
1797
1798 if (keys & KEY_CTRL)
1799 {
1800 m_canvas->Snap(&x, &y);
1801
1802 // Move point
1803 m_polygonVertex->x = x - m_shape->GetX();
1804 m_polygonVertex->y = y - m_shape->GetY();
1805 m_xpos = x;
1806 m_xpos = y;
1807 ((wxPolygonShape *)m_shape)->CalculateBoundingBox();
1808 ((wxPolygonShape *)m_shape)->CalculatePolygonCentre();
1809 }
1810 else
1811 {
1812 float new_width = (float)(dist/m_originalDistance)*m_originalSize.x;
1813 float new_height = (float)(dist/m_originalDistance)*m_originalSize.y;
1814
1815 // Non-recursive SetSize for speed
1816 m_shape->SetSize(new_width, new_height, FALSE);
1817 }
1818
1819 float w, h;
1820 m_shape->GetBoundingBoxMax(&w, &h);
1821 m_shape->GetEventHandler()->OnDrawOutline(dc, m_shape->GetX(), m_shape->GetY(), w, h);
1822
1823 m_canvas->CaptureMouse();
1824 }
1825
1826 void wxPolygonControlPoint::OnEndDragLeft(float x, float y, int keys, int attachment)
1827 {
1828 wxClientDC dc(GetCanvas());
1829 GetCanvas()->PrepareDC(dc);
1830
1831 m_canvas->ReleaseMouse();
1832 dc.SetLogicalFunction(wxCOPY);
1833
1834 // If we're changing shape, must reset the original points
1835 if (keys & KEY_CTRL)
1836 {
1837 ((wxPolygonShape *)m_shape)->CalculateBoundingBox();
1838 ((wxPolygonShape *)m_shape)->UpdateOriginalPoints();
1839 }
1840
1841 ((wxPolygonShape *)m_shape)->CalculateBoundingBox();
1842 ((wxPolygonShape *)m_shape)->CalculatePolygonCentre();
1843
1844 m_shape->Recompute();
1845 m_shape->ResetControlPoints();
1846 m_shape->Move(dc, m_shape->GetX(), m_shape->GetY());
1847 if (!m_canvas->GetQuickEditMode()) m_canvas->Redraw(dc);
1848 }
1849
1850
1851 /*
1852 * Object region
1853 *
1854 */
1855 IMPLEMENT_DYNAMIC_CLASS(wxShapeRegion, wxObject)
1856
1857 wxShapeRegion::wxShapeRegion()
1858 {
1859 m_regionText = "";
1860 m_font = g_oglNormalFont;
1861 m_minHeight = 5.0;
1862 m_minWidth = 5.0;
1863 m_width = 0.0;
1864 m_height = 0.0;
1865 m_x = 0.0;
1866 m_y = 0.0;
1867
1868 m_regionProportionX = -1.0;
1869 m_regionProportionY = -1.0;
1870 m_formatMode = FORMAT_CENTRE_HORIZ | FORMAT_CENTRE_VERT;
1871 m_regionName = "";
1872 m_textColour = "BLACK";
1873 m_penColour = "BLACK";
1874 m_penStyle = wxSOLID;
1875 m_actualColourObject = NULL;
1876 m_actualPenObject = NULL;
1877 }
1878
1879 wxShapeRegion::wxShapeRegion(wxShapeRegion& region)
1880 {
1881 m_regionText = region.m_regionText;
1882 m_regionName = region.m_regionName;
1883 m_textColour = region.m_textColour;
1884
1885 m_font = region.m_font;
1886 m_minHeight = region.m_minHeight;
1887 m_minWidth = region.m_minWidth;
1888 m_width = region.m_width;
1889 m_height = region.m_height;
1890 m_x = region.m_x;
1891 m_y = region.m_y;
1892
1893 m_regionProportionX = region.m_regionProportionX;
1894 m_regionProportionY = region.m_regionProportionY;
1895 m_formatMode = region.m_formatMode;
1896 m_actualColourObject = NULL;
1897 m_actualPenObject = NULL;
1898 m_penStyle = region.m_penStyle;
1899 m_penColour = region.m_penColour;
1900
1901 ClearText();
1902 wxNode *node = region.m_formattedText.First();
1903 while (node)
1904 {
1905 wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
1906 wxShapeTextLine *new_line =
1907 new wxShapeTextLine(line->GetX(), line->GetY(), line->GetText());
1908 m_formattedText.Append(new_line);
1909 node = node->Next();
1910 }
1911 }
1912
1913 wxShapeRegion::~wxShapeRegion()
1914 {
1915 ClearText();
1916 }
1917
1918 void wxShapeRegion::ClearText()
1919 {
1920 wxNode *node = m_formattedText.First();
1921 while (node)
1922 {
1923 wxShapeTextLine *line = (wxShapeTextLine *)node->Data();
1924 wxNode *next = node->Next();
1925 delete line;
1926 delete node;
1927 node = next;
1928 }
1929 }
1930
1931 void wxShapeRegion::SetFont(wxFont *f)
1932 {
1933 m_font = f;
1934 }
1935
1936 void wxShapeRegion::SetMinSize(float w, float h)
1937 {
1938 m_minWidth = w;
1939 m_minHeight = h;
1940 }
1941
1942 void wxShapeRegion::SetSize(float w, float h)
1943 {
1944 m_width = w;
1945 m_height = h;
1946 }
1947
1948 void wxShapeRegion::SetPosition(float xp, float yp)
1949 {
1950 m_x = xp;
1951 m_y = yp;
1952 }
1953
1954 void wxShapeRegion::SetProportions(float xp, float yp)
1955 {
1956 m_regionProportionX = xp;
1957 m_regionProportionY = yp;
1958 }
1959
1960 void wxShapeRegion::SetFormatMode(int mode)
1961 {
1962 m_formatMode = mode;
1963 }
1964
1965 void wxShapeRegion::SetColour(const wxString& col)
1966 {
1967 m_textColour = col;
1968 m_actualColourObject = NULL;
1969 }
1970
1971 wxColour *wxShapeRegion::GetActualColourObject()
1972 {
1973 if (!m_actualColourObject)
1974 m_actualColourObject = wxTheColourDatabase->FindColour(GetColour());
1975 if (!m_actualColourObject)
1976 m_actualColourObject = wxBLACK;
1977 return m_actualColourObject;
1978 }
1979
1980 void wxShapeRegion::SetPenColour(const wxString& col)
1981 {
1982 m_penColour = col;
1983 m_actualPenObject = NULL;
1984 }
1985
1986 // Returns NULL if the pen is invisible
1987 // (different to pen being transparent; indicates that
1988 // region boundary should not be drawn.)
1989 wxPen *wxShapeRegion::GetActualPen()
1990 {
1991 if (m_actualPenObject)
1992 return m_actualPenObject;
1993
1994 if (!m_penColour) return NULL;
1995 if (m_penColour == "Invisible")
1996 return NULL;
1997 m_actualPenObject = wxThePenList->FindOrCreatePen(m_penColour, 1, m_penStyle);
1998 return m_actualPenObject;
1999 }
2000
2001