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