]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/ogl/drawn.cpp
added test for HitTest(m_dragPoint) bug to the sample
[wxWidgets.git] / contrib / src / ogl / drawn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: drawn.cpp
3 // Purpose: wxDrawnShape
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 "drawn.h"
14 #pragma implementation "drawnp.h"
15 #endif
16
17 // For compilers that support precompilation, includes "wx.h".
18 #include <wx/wxprec.h>
19
20 #ifdef __BORLANDC__
21 #pragma hdrstop
22 #endif
23
24 #ifndef WX_PRECOMP
25 #include <wx/wx.h>
26 #endif
27
28 #include <wx/wxexpr.h>
29
30 #include <wx/ogl/basic.h>
31 #include <wx/ogl/basicp.h>
32 #include <wx/ogl/canvas.h>
33 #include <wx/ogl/mfutils.h>
34 #include <wx/ogl/drawn.h>
35 #include <wx/ogl/drawnp.h>
36 #include <wx/ogl/misc.h>
37
38 static void IntToHex(unsigned int dec, char *buf);
39 static unsigned long HexToInt(char *buf);
40 extern char *oglBuffer;
41
42 #define gyTYPE_PEN 40
43 #define gyTYPE_BRUSH 41
44 #define gyTYPE_FONT 42
45
46 /*
47 * Drawn object
48 *
49 */
50
51 IMPLEMENT_DYNAMIC_CLASS(wxDrawnShape, wxRectangleShape)
52
53 wxDrawnShape::wxDrawnShape():wxRectangleShape(100.0, 50.0)
54 {
55 m_saveToFile = TRUE;
56 m_currentAngle = oglDRAWN_ANGLE_0;
57 }
58
59 wxDrawnShape::~wxDrawnShape()
60 {
61 }
62
63 void wxDrawnShape::OnDraw(wxDC& dc)
64 {
65 // Pass pen and brush in case we have force outline
66 // and fill colours
67 if (m_shadowMode != SHADOW_NONE)
68 {
69 if (m_shadowBrush)
70 m_metafiles[m_currentAngle].m_fillBrush = m_shadowBrush;
71 m_metafiles[m_currentAngle].m_outlinePen = g_oglTransparentPen;
72 m_metafiles[m_currentAngle].Draw(dc, m_xpos + m_shadowOffsetX, m_ypos + m_shadowOffsetY);
73 }
74
75 m_metafiles[m_currentAngle].m_outlinePen = m_pen;
76 m_metafiles[m_currentAngle].m_fillBrush = m_brush;
77 m_metafiles[m_currentAngle].Draw(dc, m_xpos, m_ypos);
78 }
79
80 void wxDrawnShape::SetSize(double w, double h, bool recursive)
81 {
82 SetAttachmentSize(w, h);
83
84 double scaleX;
85 double scaleY;
86 if (GetWidth() == 0.0)
87 scaleX = 1.0;
88 else scaleX = w/GetWidth();
89 if (GetHeight() == 0.0)
90 scaleY = 1.0;
91 else scaleY = h/GetHeight();
92
93 int i = 0;
94 for (i = 0; i < 4; i++)
95 {
96 if (m_metafiles[i].IsValid())
97 m_metafiles[i].Scale(scaleX, scaleY);
98 }
99 m_width = w;
100 m_height = h;
101 SetDefaultRegionSize();
102 }
103
104 void wxDrawnShape::Scale(double sx, double sy)
105 {
106 int i;
107 for (i = 0; i < 4; i++)
108 {
109 if (m_metafiles[i].IsValid())
110 {
111 m_metafiles[i].Scale(sx, sy);
112 m_metafiles[i].CalculateSize(this);
113 }
114 }
115 }
116
117 void wxDrawnShape::Translate(double x, double y)
118 {
119 int i;
120 for (i = 0; i < 4; i++)
121 {
122 if (m_metafiles[i].IsValid())
123 {
124 m_metafiles[i].Translate(x, y);
125 m_metafiles[i].CalculateSize(this);
126 }
127 }
128 }
129
130 // theta is absolute rotation from the zero position
131 void wxDrawnShape::Rotate(double x, double y, double theta)
132 {
133 m_currentAngle = DetermineMetaFile(theta);
134
135 if (m_currentAngle == 0)
136 {
137 // Rotate metafile
138 if (!m_metafiles[0].GetRotateable())
139 return;
140
141 m_metafiles[0].Rotate(x, y, theta);
142 }
143
144 double actualTheta = theta-m_rotation;
145
146 // Rotate attachment points
147 double sinTheta = (double)sin(actualTheta);
148 double cosTheta = (double)cos(actualTheta);
149 wxNode *node = m_attachmentPoints.First();
150 while (node)
151 {
152 wxAttachmentPoint *point = (wxAttachmentPoint *)node->Data();
153 double x1 = point->m_x;
154 double y1 = point->m_y;
155 point->m_x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
156 point->m_y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
157 node = node->Next();
158 }
159 m_rotation = theta;
160
161 m_metafiles[m_currentAngle].CalculateSize(this);
162 }
163
164 // Which metafile do we use now? Based on current rotation and validity
165 // of metafiles.
166
167 int wxDrawnShape::DetermineMetaFile(double rotation)
168 {
169 double tolerance = 0.0001;
170 const double pi = 3.1415926535897932384626433832795 ;
171 double angle1 = 0.0;
172 double angle2 = pi/2.0;
173 double angle3 = pi;
174 double angle4 = 3.0*pi/2.0;
175
176 int whichMetafile = 0;
177
178 if (oglRoughlyEqual(rotation, angle1, tolerance))
179 {
180 whichMetafile = 0;
181 }
182 else if (oglRoughlyEqual(rotation, angle2, tolerance))
183 {
184 whichMetafile = 1;
185 }
186 else if (oglRoughlyEqual(rotation, angle3, tolerance))
187 {
188 whichMetafile = 2;
189 }
190 else if (oglRoughlyEqual(rotation, angle4, tolerance))
191 {
192 whichMetafile = 3;
193 }
194
195 if ((whichMetafile > 0) && !m_metafiles[whichMetafile].IsValid())
196 whichMetafile = 0;
197
198 return whichMetafile;
199 }
200
201 void wxDrawnShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
202 {
203 if (m_metafiles[m_currentAngle].GetOutlineOp() != -1)
204 {
205 wxNode* node = m_metafiles[m_currentAngle].GetOps().Nth(m_metafiles[m_currentAngle].GetOutlineOp());
206 wxASSERT (node != NULL);
207 wxDrawOp* op = (wxDrawOp*) node->Data();
208
209 if (op->OnDrawOutline(dc, x, y, w, h, m_width, m_height))
210 return;
211 }
212
213 // Default... just use a rectangle
214 wxRectangleShape::OnDrawOutline(dc, x, y, w, h);
215 }
216
217 // Get the perimeter point using the special outline op, if there is one,
218 // otherwise use default wxRectangleShape scheme
219 bool wxDrawnShape::GetPerimeterPoint(double x1, double y1,
220 double x2, double y2,
221 double *x3, double *y3)
222 {
223 if (m_metafiles[m_currentAngle].GetOutlineOp() != -1)
224 {
225 wxNode* node = m_metafiles[m_currentAngle].GetOps().Nth(m_metafiles[m_currentAngle].GetOutlineOp());
226 wxASSERT (node != NULL);
227 wxDrawOp* op = (wxDrawOp*) node->Data();
228
229 if (op->GetPerimeterPoint(x1, y1, x2, y2, x3, y3, GetX(), GetY(), GetAttachmentMode()))
230 return TRUE;
231 }
232
233 // Default... just use a rectangle
234 return wxRectangleShape::GetPerimeterPoint(x1, y1, x2, y2, x3, y3);
235 }
236
237 #ifdef PROLOGIO
238 void wxDrawnShape::WriteAttributes(wxExpr *clause)
239 {
240 wxRectangleShape::WriteAttributes(clause);
241
242 clause->AddAttributeValue("current_angle", (long)m_currentAngle);
243 clause->AddAttributeValue("save_metafile", (long)m_saveToFile);
244 if (m_saveToFile)
245 {
246 int i = 0;
247 for (i = 0; i < 4; i++)
248 {
249 if (m_metafiles[i].IsValid())
250 m_metafiles[i].WriteAttributes(clause, i);
251 }
252 }
253 }
254
255 void wxDrawnShape::ReadAttributes(wxExpr *clause)
256 {
257 wxRectangleShape::ReadAttributes(clause);
258
259 int iVal = (int) m_saveToFile;
260 clause->GetAttributeValue("save_metafile", iVal);
261 clause->GetAttributeValue("current_angle", m_currentAngle);
262 m_saveToFile = (iVal != 0);
263
264 if (m_saveToFile)
265 {
266 int i = 0;
267 for (i = 0; i < 4; i++)
268 {
269 m_metafiles[i].ReadAttributes(clause, i);
270 }
271 }
272 }
273 #endif
274
275 // Does the copying for this object
276 void wxDrawnShape::Copy(wxShape& copy)
277 {
278 wxRectangleShape::Copy(copy);
279
280 wxASSERT( copy.IsKindOf(CLASSINFO(wxDrawnShape)) ) ;
281
282 wxDrawnShape& drawnCopy = (wxDrawnShape&) copy;
283
284 int i = 0;
285 for (i = 0; i < 4; i++)
286 {
287 m_metafiles[i].Copy(drawnCopy.m_metafiles[i]);
288 }
289 drawnCopy.m_saveToFile = m_saveToFile;
290 drawnCopy.m_currentAngle = m_currentAngle;
291 }
292
293 bool wxDrawnShape::LoadFromMetaFile(char *filename)
294 {
295 return m_metafiles[0].LoadFromMetaFile(filename, &m_width, &m_height);
296 }
297
298 // Set of functions for drawing into a pseudo metafile.
299 // They use integers, but doubles are used internally for accuracy
300 // when scaling.
301
302 void wxDrawnShape::DrawLine(const wxPoint& pt1, const wxPoint& pt2)
303 {
304 m_metafiles[m_currentAngle].DrawLine(pt1, pt2);
305 }
306
307 void wxDrawnShape::DrawRectangle(const wxRect& rect)
308 {
309 m_metafiles[m_currentAngle].DrawRectangle(rect);
310 }
311
312 void wxDrawnShape::DrawRoundedRectangle(const wxRect& rect, double radius)
313 {
314 m_metafiles[m_currentAngle].DrawRoundedRectangle(rect, radius);
315 }
316
317 void wxDrawnShape::DrawEllipse(const wxRect& rect)
318 {
319 m_metafiles[m_currentAngle].DrawEllipse(rect);
320 }
321
322 void wxDrawnShape::DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt)
323 {
324 m_metafiles[m_currentAngle].DrawArc(centrePt, startPt, endPt);
325 }
326
327 void wxDrawnShape::DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle)
328 {
329 m_metafiles[m_currentAngle].DrawEllipticArc(rect, startAngle, endAngle);
330 }
331
332 void wxDrawnShape::DrawPoint(const wxPoint& pt)
333 {
334 m_metafiles[m_currentAngle].DrawPoint(pt);
335 }
336
337 void wxDrawnShape::DrawText(const wxString& text, const wxPoint& pt)
338 {
339 m_metafiles[m_currentAngle].DrawText(text, pt);
340 }
341
342 void wxDrawnShape::DrawLines(int n, wxPoint pts[])
343 {
344 m_metafiles[m_currentAngle].DrawLines(n, pts);
345 }
346
347 void wxDrawnShape::DrawPolygon(int n, wxPoint pts[], int flags)
348 {
349 if (flags & oglMETAFLAGS_ATTACHMENTS)
350 {
351 ClearAttachments();
352 int i;
353 for (i = 0; i < n; i++)
354 m_attachmentPoints.Append(new wxAttachmentPoint(i, pts[i].x, pts[i].y));
355 }
356 m_metafiles[m_currentAngle].DrawPolygon(n, pts, flags);
357 }
358
359 void wxDrawnShape::DrawSpline(int n, wxPoint pts[])
360 {
361 m_metafiles[m_currentAngle].DrawSpline(n, pts);
362 }
363
364 void wxDrawnShape::SetClippingRect(const wxRect& rect)
365 {
366 m_metafiles[m_currentAngle].SetClippingRect(rect);
367 }
368
369 void wxDrawnShape::DestroyClippingRect()
370 {
371 m_metafiles[m_currentAngle].DestroyClippingRect();
372 }
373
374 void wxDrawnShape::SetDrawnPen(wxPen* pen, bool isOutline)
375 {
376 m_metafiles[m_currentAngle].SetPen(pen, isOutline);
377 }
378
379 void wxDrawnShape::SetDrawnBrush(wxBrush* brush, bool isFill)
380 {
381 m_metafiles[m_currentAngle].SetBrush(brush, isFill);
382 }
383
384 void wxDrawnShape::SetDrawnFont(wxFont* font)
385 {
386 m_metafiles[m_currentAngle].SetFont(font);
387 }
388
389 void wxDrawnShape::SetDrawnTextColour(const wxColour& colour)
390 {
391 m_metafiles[m_currentAngle].SetTextColour(colour);
392 }
393
394 void wxDrawnShape::SetDrawnBackgroundColour(const wxColour& colour)
395 {
396 m_metafiles[m_currentAngle].SetBackgroundColour(colour);
397 }
398
399 void wxDrawnShape::SetDrawnBackgroundMode(int mode)
400 {
401 m_metafiles[m_currentAngle].SetBackgroundMode(mode);
402 }
403
404
405 /*
406 * Individual operations
407 *
408 */
409
410 /*
411 * Set font, brush, text colour
412 *
413 */
414
415 wxOpSetGDI::wxOpSetGDI(int theOp, wxPseudoMetaFile *theImage, int theGdiIndex, int theMode):
416 wxDrawOp(theOp)
417 {
418 m_gdiIndex = theGdiIndex;
419 m_image = theImage;
420 m_mode = theMode;
421 }
422
423 void wxOpSetGDI::Do(wxDC& dc, double xoffset, double yoffset)
424 {
425 switch (m_op)
426 {
427 case DRAWOP_SET_PEN:
428 {
429 // Check for overriding this operation for outline
430 // colour
431 if (m_image->m_outlineColours.Member((wxObject *)m_gdiIndex))
432 {
433 if (m_image->m_outlinePen)
434 dc.SetPen(* m_image->m_outlinePen);
435 }
436 else
437 {
438 wxNode *node = m_image->m_gdiObjects.Nth(m_gdiIndex);
439 if (node)
440 {
441 wxPen *pen = (wxPen *)node->Data();
442 if (pen)
443 dc.SetPen(* pen);
444 }
445 }
446 break;
447 }
448 case DRAWOP_SET_BRUSH:
449 {
450 // Check for overriding this operation for outline or fill
451 // colour
452 if (m_image->m_outlineColours.Member((wxObject *)m_gdiIndex))
453 {
454 // Need to construct a brush to match the outline pen's colour
455 if (m_image->m_outlinePen)
456 {
457 wxBrush *br = wxTheBrushList->FindOrCreateBrush(m_image->m_outlinePen->GetColour(), wxSOLID);
458 if (br)
459 dc.SetBrush(* br);
460 }
461 }
462 else if (m_image->m_fillColours.Member((wxObject *)m_gdiIndex))
463 {
464 if (m_image->m_fillBrush)
465 {
466 dc.SetBrush(* m_image->m_fillBrush);
467 }
468 }
469 else
470 {
471 wxNode *node = m_image->m_gdiObjects.Nth(m_gdiIndex);
472 if (node)
473 {
474 wxBrush *brush = (wxBrush *)node->Data();
475 if (brush)
476 dc.SetBrush(* brush);
477 }
478 }
479 break;
480 }
481 case DRAWOP_SET_FONT:
482 {
483 wxNode *node = m_image->m_gdiObjects.Nth(m_gdiIndex);
484 if (node)
485 {
486 wxFont *font = (wxFont *)node->Data();
487 if (font)
488 dc.SetFont(* font);
489 }
490 break;
491 }
492 case DRAWOP_SET_TEXT_COLOUR:
493 {
494 wxColour col(m_r,m_g,m_b);
495 dc.SetTextForeground(col);
496 break;
497 }
498 case DRAWOP_SET_BK_COLOUR:
499 {
500 wxColour col(m_r,m_g,m_b);
501 dc.SetTextBackground(col);
502 break;
503 }
504 case DRAWOP_SET_BK_MODE:
505 {
506 dc.SetBackgroundMode(m_mode);
507 break;
508 }
509 default:
510 break;
511 }
512 }
513
514 wxDrawOp *wxOpSetGDI::Copy(wxPseudoMetaFile *newImage)
515 {
516 wxOpSetGDI *newOp = new wxOpSetGDI(m_op, newImage, m_gdiIndex, m_mode);
517 newOp->m_r = m_r;
518 newOp->m_g = m_g;
519 newOp->m_b = m_b;
520 return newOp;
521 }
522
523 wxExpr *wxOpSetGDI::WriteExpr(wxPseudoMetaFile *image)
524 {
525 wxExpr *expr = new wxExpr(wxExprList);
526 expr->Append(new wxExpr((long)m_op));
527 switch (m_op)
528 {
529 case DRAWOP_SET_PEN:
530 case DRAWOP_SET_BRUSH:
531 case DRAWOP_SET_FONT:
532 {
533 expr->Append(new wxExpr((long)m_gdiIndex));
534 break;
535 }
536 case DRAWOP_SET_TEXT_COLOUR:
537 case DRAWOP_SET_BK_COLOUR:
538 {
539 expr->Append(new wxExpr((long)m_r));
540 expr->Append(new wxExpr((long)m_g));
541 expr->Append(new wxExpr((long)m_b));
542 break;
543 }
544 case DRAWOP_SET_BK_MODE:
545 {
546 expr->Append(new wxExpr((long)m_mode));
547 break;
548 }
549 default:
550 break;
551 }
552 return expr;
553 }
554
555 void wxOpSetGDI::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr)
556 {
557 switch (m_op)
558 {
559 case DRAWOP_SET_PEN:
560 case DRAWOP_SET_BRUSH:
561 case DRAWOP_SET_FONT:
562 {
563 m_gdiIndex = (int)expr->Nth(1)->IntegerValue();
564 break;
565 }
566 case DRAWOP_SET_TEXT_COLOUR:
567 case DRAWOP_SET_BK_COLOUR:
568 {
569 m_r = (unsigned char)expr->Nth(1)->IntegerValue();
570 m_g = (unsigned char)expr->Nth(2)->IntegerValue();
571 m_b = (unsigned char)expr->Nth(3)->IntegerValue();
572 break;
573 }
574 case DRAWOP_SET_BK_MODE:
575 {
576 m_mode = (int)expr->Nth(1)->IntegerValue();
577 break;
578 }
579 default:
580 break;
581 }
582 }
583
584 /*
585 * Set/destroy clipping
586 *
587 */
588
589 wxOpSetClipping::wxOpSetClipping(int theOp, double theX1, double theY1,
590 double theX2, double theY2):wxDrawOp(theOp)
591 {
592 m_x1 = theX1;
593 m_y1 = theY1;
594 m_x2 = theX2;
595 m_y2 = theY2;
596 }
597
598 wxDrawOp *wxOpSetClipping::Copy(wxPseudoMetaFile *newImage)
599 {
600 wxOpSetClipping *newOp = new wxOpSetClipping(m_op, m_x1, m_y1, m_x2, m_y2);
601 return newOp;
602 }
603
604 void wxOpSetClipping::Do(wxDC& dc, double xoffset, double yoffset)
605 {
606 switch (m_op)
607 {
608 case DRAWOP_SET_CLIPPING_RECT:
609 {
610 dc.SetClippingRegion((long)(m_x1 + xoffset), (long)(m_y1 + yoffset), (long)(m_x2 + xoffset), (long)(m_y2 + yoffset));
611 break;
612 }
613 case DRAWOP_DESTROY_CLIPPING_RECT:
614 {
615 dc.DestroyClippingRegion();
616 break;
617 }
618 default:
619 break;
620 }
621 }
622
623 void wxOpSetClipping::Scale(double xScale, double yScale)
624 {
625 m_x1 *= xScale;
626 m_y1 *= yScale;
627 m_x2 *= xScale;
628 m_y2 *= yScale;
629 }
630
631 void wxOpSetClipping::Translate(double x, double y)
632 {
633 m_x1 += x;
634 m_y1 += y;
635 }
636
637 wxExpr *wxOpSetClipping::WriteExpr(wxPseudoMetaFile *image)
638 {
639 wxExpr *expr = new wxExpr(wxExprList);
640 expr->Append(new wxExpr((long)m_op));
641 switch (m_op)
642 {
643 case DRAWOP_SET_CLIPPING_RECT:
644 {
645 expr->Append(new wxExpr(m_x1));
646 expr->Append(new wxExpr(m_y1));
647 expr->Append(new wxExpr(m_x2));
648 expr->Append(new wxExpr(m_y2));
649 break;
650 }
651 default:
652 break;
653 }
654 return expr;
655 }
656
657 void wxOpSetClipping::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr)
658 {
659 switch (m_op)
660 {
661 case DRAWOP_SET_CLIPPING_RECT:
662 {
663 m_x1 = expr->Nth(1)->RealValue();
664 m_y1 = expr->Nth(2)->RealValue();
665 m_x2 = expr->Nth(3)->RealValue();
666 m_y2 = expr->Nth(4)->RealValue();
667 break;
668 }
669 default:
670 break;
671 }
672 }
673
674 /*
675 * Draw line, rectangle, rounded rectangle, ellipse, point, arc, text
676 *
677 */
678
679 wxOpDraw::wxOpDraw(int theOp, double theX1, double theY1, double theX2, double theY2,
680 double theRadius, char *s):wxDrawOp(theOp)
681 {
682 m_x1 = theX1;
683 m_y1 = theY1;
684 m_x2 = theX2;
685 m_y2 = theY2;
686 m_x3 = 0.0;
687 m_y3 = 0.0;
688 m_radius = theRadius;
689 if (s) m_textString = copystring(s);
690 else m_textString = NULL;
691 }
692
693 wxOpDraw::~wxOpDraw()
694 {
695 if (m_textString) delete[] m_textString;
696 }
697
698 wxDrawOp *wxOpDraw::Copy(wxPseudoMetaFile *newImage)
699 {
700 wxOpDraw *newOp = new wxOpDraw(m_op, m_x1, m_y1, m_x2, m_y2, m_radius, m_textString);
701 newOp->m_x3 = m_x3;
702 newOp->m_y3 = m_y3;
703 return newOp;
704 }
705
706 void wxOpDraw::Do(wxDC& dc, double xoffset, double yoffset)
707 {
708 switch (m_op)
709 {
710 case DRAWOP_DRAW_LINE:
711 {
712 dc.DrawLine(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2+xoffset), WXROUND(m_y2+yoffset));
713 break;
714 }
715 case DRAWOP_DRAW_RECT:
716 {
717 dc.DrawRectangle(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2), WXROUND(m_y2));
718 break;
719 }
720 case DRAWOP_DRAW_ROUNDED_RECT:
721 {
722 dc.DrawRoundedRectangle(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2), WXROUND(m_y2), m_radius);
723 break;
724 }
725 case DRAWOP_DRAW_ELLIPSE:
726 {
727 dc.DrawEllipse(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset), WXROUND(m_x2), WXROUND(m_y2));
728 break;
729 }
730 case DRAWOP_DRAW_ARC:
731 {
732 dc.DrawArc(WXROUND(m_x2+xoffset), WXROUND(m_y2+yoffset),
733 WXROUND(m_x3+xoffset), WXROUND(m_y3+yoffset),
734 WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset));
735 break;
736 }
737 case DRAWOP_DRAW_ELLIPTIC_ARC:
738 {
739 const double pi = 3.1415926535897932384626433832795 ;
740
741 // Convert back to degrees
742 dc.DrawEllipticArc(
743 WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset),
744 WXROUND(m_x2), WXROUND(m_y2),
745 WXROUND(m_x3*(360.0/(2.0*pi))), WXROUND(m_y3*(360.0/(2.0*pi))));
746 break;
747 }
748 case DRAWOP_DRAW_POINT:
749 {
750 dc.DrawPoint(WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset));
751 break;
752 }
753 case DRAWOP_DRAW_TEXT:
754 {
755 dc.DrawText(m_textString, WXROUND(m_x1+xoffset), WXROUND(m_y1+yoffset));
756 break;
757 }
758 default:
759 break;
760 }
761 }
762
763 void wxOpDraw::Scale(double scaleX, double scaleY)
764 {
765 m_x1 *= scaleX;
766 m_y1 *= scaleY;
767 m_x2 *= scaleX;
768 m_y2 *= scaleY;
769
770 if (m_op != DRAWOP_DRAW_ELLIPTIC_ARC)
771 {
772 m_x3 *= scaleX;
773 m_y3 *= scaleY;
774 }
775
776 m_radius *= scaleX;
777 }
778
779 void wxOpDraw::Translate(double x, double y)
780 {
781 m_x1 += x;
782 m_y1 += y;
783
784 switch (m_op)
785 {
786 case DRAWOP_DRAW_LINE:
787 {
788 m_x2 += x;
789 m_y2 += y;
790 break;
791 }
792 case DRAWOP_DRAW_ARC:
793 {
794 m_x2 += x;
795 m_y2 += y;
796 m_x3 += x;
797 m_y3 += y;
798 break;
799 }
800 case DRAWOP_DRAW_ELLIPTIC_ARC:
801 {
802 break;
803 }
804 default:
805 break;
806 }
807 }
808
809 void wxOpDraw::Rotate(double x, double y, double theta, double sinTheta, double cosTheta)
810 {
811 double newX1 = m_x1*cosTheta - m_y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
812 double newY1 = m_x1*sinTheta + m_y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
813
814 switch (m_op)
815 {
816 case DRAWOP_DRAW_LINE:
817 {
818 double newX2 = m_x2*cosTheta - m_y2*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
819 double newY2 = m_x2*sinTheta + m_y2*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
820
821 m_x1 = newX1;
822 m_y1 = newY1;
823 m_x2 = newX2;
824 m_y2 = newY2;
825 break;
826 }
827 case DRAWOP_DRAW_RECT:
828 case DRAWOP_DRAW_ROUNDED_RECT:
829 case DRAWOP_DRAW_ELLIPTIC_ARC:
830 {
831 // Assume only 0, 90, 180, 270 degree rotations.
832 // oldX1, oldY1 represents the top left corner. Find the
833 // bottom right, and rotate that. Then the width/height is the difference
834 // between x/y values.
835 double oldBottomRightX = m_x1 + m_x2;
836 double oldBottomRightY = m_y1 + m_y2;
837 double newBottomRightX = oldBottomRightX*cosTheta - oldBottomRightY*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
838 double newBottomRightY = oldBottomRightX*sinTheta + oldBottomRightY*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
839
840 // Now find the new top-left, bottom-right coordinates.
841 double minX = wxMin(newX1, newBottomRightX);
842 double minY = wxMin(newY1, newBottomRightY);
843 double maxX = wxMax(newX1, newBottomRightX);
844 double maxY = wxMax(newY1, newBottomRightY);
845
846 m_x1 = minX;
847 m_y1 = minY;
848 m_x2 = maxX - minX; // width
849 m_y2 = maxY - minY; // height
850
851 if (m_op == DRAWOP_DRAW_ELLIPTIC_ARC)
852 {
853 // Add rotation to angles
854 m_x3 += theta;
855 m_y3 += theta;
856 }
857
858 break;
859 }
860 case DRAWOP_DRAW_ARC:
861 {
862 double newX2 = m_x2*cosTheta - m_y2*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
863 double newY2 = m_x2*sinTheta + m_y2*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
864 double newX3 = m_x3*cosTheta - m_y3*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
865 double newY3 = m_x3*sinTheta + m_y3*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
866
867 m_x1 = newX1;
868 m_y1 = newY1;
869 m_x2 = newX2;
870 m_y2 = newY2;
871 m_x3 = newX3;
872 m_y3 = newY3;
873
874 break;
875 }
876 default:
877 break;
878 }
879 }
880
881 wxExpr *wxOpDraw::WriteExpr(wxPseudoMetaFile *image)
882 {
883 wxExpr *expr = new wxExpr(wxExprList);
884 expr->Append(new wxExpr((long)m_op));
885 switch (m_op)
886 {
887 case DRAWOP_DRAW_LINE:
888 case DRAWOP_DRAW_RECT:
889 case DRAWOP_DRAW_ELLIPSE:
890 {
891 expr->Append(new wxExpr(m_x1));
892 expr->Append(new wxExpr(m_y1));
893 expr->Append(new wxExpr(m_x2));
894 expr->Append(new wxExpr(m_y2));
895 break;
896 }
897 case DRAWOP_DRAW_ROUNDED_RECT:
898 {
899 expr->Append(new wxExpr(m_x1));
900 expr->Append(new wxExpr(m_y1));
901 expr->Append(new wxExpr(m_x2));
902 expr->Append(new wxExpr(m_y2));
903 expr->Append(new wxExpr(m_radius));
904 break;
905 }
906 case DRAWOP_DRAW_POINT:
907 {
908 expr->Append(new wxExpr(m_x1));
909 expr->Append(new wxExpr(m_y1));
910 break;
911 }
912 case DRAWOP_DRAW_TEXT:
913 {
914 expr->Append(new wxExpr(m_x1));
915 expr->Append(new wxExpr(m_y1));
916 expr->Append(new wxExpr(wxExprString, m_textString));
917 break;
918 }
919 case DRAWOP_DRAW_ARC:
920 case DRAWOP_DRAW_ELLIPTIC_ARC:
921 {
922 expr->Append(new wxExpr(m_x1));
923 expr->Append(new wxExpr(m_y1));
924 expr->Append(new wxExpr(m_x2));
925 expr->Append(new wxExpr(m_y2));
926 expr->Append(new wxExpr(m_x3));
927 expr->Append(new wxExpr(m_y3));
928 break;
929 }
930 default:
931 {
932 break;
933 }
934 }
935 return expr;
936 }
937
938 void wxOpDraw::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr)
939 {
940 switch (m_op)
941 {
942 case DRAWOP_DRAW_LINE:
943 case DRAWOP_DRAW_RECT:
944 case DRAWOP_DRAW_ELLIPSE:
945 {
946 m_x1 = expr->Nth(1)->RealValue();
947 m_y1 = expr->Nth(2)->RealValue();
948 m_x2 = expr->Nth(3)->RealValue();
949 m_y2 = expr->Nth(4)->RealValue();
950 break;
951 }
952 case DRAWOP_DRAW_ROUNDED_RECT:
953 {
954 m_x1 = expr->Nth(1)->RealValue();
955 m_y1 = expr->Nth(2)->RealValue();
956 m_x2 = expr->Nth(3)->RealValue();
957 m_y2 = expr->Nth(4)->RealValue();
958 m_radius = expr->Nth(5)->RealValue();
959 break;
960 }
961 case DRAWOP_DRAW_POINT:
962 {
963 m_x1 = expr->Nth(1)->RealValue();
964 m_y1 = expr->Nth(2)->RealValue();
965 break;
966 }
967 case DRAWOP_DRAW_TEXT:
968 {
969 m_x1 = expr->Nth(1)->RealValue();
970 m_y1 = expr->Nth(2)->RealValue();
971 wxString str(expr->Nth(3)->StringValue());
972 m_textString = copystring((const char*) str);
973 break;
974 }
975 case DRAWOP_DRAW_ARC:
976 case DRAWOP_DRAW_ELLIPTIC_ARC:
977 {
978 m_x1 = expr->Nth(1)->RealValue();
979 m_y1 = expr->Nth(2)->RealValue();
980 m_x2 = expr->Nth(3)->RealValue();
981 m_y2 = expr->Nth(4)->RealValue();
982 m_x3 = expr->Nth(5)->RealValue();
983 m_y3 = expr->Nth(6)->RealValue();
984 break;
985 }
986 default:
987 {
988 break;
989 }
990 }
991 }
992
993 /*
994 * Draw polygon, polyline, spline
995 *
996 */
997
998 wxOpPolyDraw::wxOpPolyDraw(int theOp, int n, wxRealPoint *thePoints):wxDrawOp(theOp)
999 {
1000 m_noPoints = n;
1001 m_points = thePoints;
1002 }
1003
1004 wxOpPolyDraw::~wxOpPolyDraw()
1005 {
1006 delete[] m_points;
1007 }
1008
1009 wxDrawOp *wxOpPolyDraw::Copy(wxPseudoMetaFile *newImage)
1010 {
1011 wxRealPoint *newPoints = new wxRealPoint[m_noPoints];
1012 for (int i = 0; i < m_noPoints; i++)
1013 {
1014 newPoints[i].x = m_points[i].x;
1015 newPoints[i].y = m_points[i].y;
1016 }
1017 wxOpPolyDraw *newOp = new wxOpPolyDraw(m_op, m_noPoints, newPoints);
1018 return newOp;
1019 }
1020
1021 void wxOpPolyDraw::Do(wxDC& dc, double xoffset, double yoffset)
1022 {
1023 switch (m_op)
1024 {
1025 case DRAWOP_DRAW_POLYLINE:
1026 {
1027 wxPoint *actualPoints = new wxPoint[m_noPoints];
1028 int i;
1029 for (i = 0; i < m_noPoints; i++)
1030 {
1031 actualPoints[i].x = WXROUND(m_points[i].x);
1032 actualPoints[i].y = WXROUND(m_points[i].y);
1033 }
1034
1035 dc.DrawLines(m_noPoints, actualPoints, WXROUND(xoffset), WXROUND(yoffset));
1036
1037 delete[] actualPoints;
1038 break;
1039 }
1040 case DRAWOP_DRAW_POLYGON:
1041 {
1042 wxPoint *actualPoints = new wxPoint[m_noPoints];
1043 int i;
1044 for (i = 0; i < m_noPoints; i++)
1045 {
1046 actualPoints[i].x = WXROUND(m_points[i].x);
1047 actualPoints[i].y = WXROUND(m_points[i].y);
1048 }
1049
1050 dc.DrawPolygon(m_noPoints, actualPoints, WXROUND(xoffset), WXROUND(yoffset));
1051
1052 delete[] actualPoints;
1053 break;
1054 }
1055 case DRAWOP_DRAW_SPLINE:
1056 {
1057 wxPoint *actualPoints = new wxPoint[m_noPoints];
1058 int i;
1059 for (i = 0; i < m_noPoints; i++)
1060 {
1061 actualPoints[i].x = WXROUND(m_points[i].x);
1062 actualPoints[i].y = WXROUND(m_points[i].y);
1063 }
1064
1065 dc.DrawSpline(m_noPoints, actualPoints); // no offsets in DrawSpline // , xoffset, yoffset);
1066
1067 delete[] actualPoints;
1068 break;
1069 break;
1070 }
1071 default:
1072 break;
1073 }
1074 }
1075
1076 void wxOpPolyDraw::Scale(double scaleX, double scaleY)
1077 {
1078 for (int i = 0; i < m_noPoints; i++)
1079 {
1080 m_points[i].x *= scaleX;
1081 m_points[i].y *= scaleY;
1082 }
1083 }
1084
1085 void wxOpPolyDraw::Translate(double x, double y)
1086 {
1087 for (int i = 0; i < m_noPoints; i++)
1088 {
1089 m_points[i].x += x;
1090 m_points[i].y += y;
1091 }
1092 }
1093
1094 void wxOpPolyDraw::Rotate(double x, double y, double theta, double sinTheta, double cosTheta)
1095 {
1096 for (int i = 0; i < m_noPoints; i++)
1097 {
1098 double x1 = m_points[i].x;
1099 double y1 = m_points[i].y;
1100 m_points[i].x = x1*cosTheta - y1*sinTheta + x*(1.0 - cosTheta) + y*sinTheta;
1101 m_points[i].y = x1*sinTheta + y1*cosTheta + y*(1.0 - cosTheta) + x*sinTheta;
1102 }
1103 }
1104
1105 wxExpr *wxOpPolyDraw::WriteExpr(wxPseudoMetaFile *image)
1106 {
1107 wxExpr *expr = new wxExpr(wxExprList);
1108 expr->Append(new wxExpr((long)m_op));
1109 expr->Append(new wxExpr((long)m_noPoints));
1110
1111 // char buf1[9];
1112 char buf2[5];
1113 char buf3[5];
1114
1115 oglBuffer[0] = 0;
1116
1117 /*
1118 * Store each coordinate pair in a hex string to save space.
1119 * E.g. "1B9080CD". 4 hex digits per coordinate pair.
1120 *
1121 */
1122
1123 for (int i = 0; i < m_noPoints; i++)
1124 {
1125 long signedX = (long)(m_points[i].x*100.0);
1126 long signedY = (long)(m_points[i].y*100.0);
1127
1128 // Scale to 0 -> 64K
1129 long unSignedX = (long)(signedX + 32767.0);
1130 long unSignedY = (long)(signedY + 32767.0);
1131
1132 // IntToHex((unsigned int)signedX, buf2);
1133 // IntToHex((unsigned int)signedY, buf3);
1134 IntToHex((int)unSignedX, buf2);
1135 IntToHex((int)unSignedY, buf3);
1136
1137 // Don't overrun the buffer
1138 if ((i*8) < 3000)
1139 {
1140 strcat(oglBuffer, buf2);
1141 strcat(oglBuffer, buf3);
1142 }
1143 }
1144 expr->Append(new wxExpr(wxExprString, oglBuffer));
1145 return expr;
1146 }
1147
1148 void wxOpPolyDraw::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr)
1149 {
1150 m_noPoints = (int)expr->Nth(1)->IntegerValue();
1151
1152 char buf1[5];
1153 char buf2[5];
1154
1155 m_points = new wxRealPoint[m_noPoints];
1156 int i = 0;
1157 int bufPtr = 0;
1158 wxString hexString = expr->Nth(2)->StringValue();
1159 while (i < m_noPoints)
1160 {
1161 buf1[0] = hexString[(size_t)bufPtr];
1162 buf1[1] = hexString[(size_t)(bufPtr + 1)];
1163 buf1[2] = hexString[(size_t)(bufPtr + 2)];
1164 buf1[3] = hexString[(size_t)(bufPtr + 3)];
1165 buf1[4] = 0;
1166
1167 buf2[0] = hexString[(size_t)(bufPtr + 4)];
1168 buf2[1] = hexString[(size_t)(bufPtr + 5)];
1169 buf2[2] = hexString[(size_t)(bufPtr + 6)];
1170 buf2[3] = hexString[(size_t)(bufPtr + 7)];
1171 buf2[4] = 0;
1172
1173 bufPtr += 8;
1174
1175 // int signedX = (signed int)HexToInt(buf1);
1176 // int signedY = (signed int)HexToInt(buf2);
1177 long unSignedX = HexToInt(buf1);
1178 long unSignedY = HexToInt(buf2);
1179 // Scale -32K -> +32K
1180 long signedX = unSignedX - 32767;
1181 long signedY = unSignedY - 32767;
1182 #ifdef __WXMSW__
1183 int testX = (signed int)unSignedX;
1184 int testY = (signed int)unSignedY;
1185 #endif
1186
1187 m_points[i].x = (double)(signedX / 100.0);
1188 m_points[i].y = (double)(signedY / 100.0);
1189
1190 i ++;
1191 }
1192 }
1193
1194 // Draw an outline using the current operation.
1195 bool wxOpPolyDraw::OnDrawOutline(wxDC& dc, double x, double y, double w, double h, double oldW, double oldH)
1196 {
1197 dc.SetBrush(* wxTRANSPARENT_BRUSH);
1198
1199 // Multiply all points by proportion of new size to old size
1200 double x_proportion = (double)(fabs(w/oldW));
1201 double y_proportion = (double)(fabs(h/oldH));
1202
1203 int n = m_noPoints;
1204 wxPoint *intPoints = new wxPoint[n];
1205 int i;
1206 for (i = 0; i < n; i++)
1207 {
1208 intPoints[i].x = WXROUND (x_proportion * m_points[i].x);
1209 intPoints[i].y = WXROUND (y_proportion * m_points[i].y);
1210 }
1211 dc.DrawPolygon(n, intPoints, (long) x, (long) y);
1212 delete[] intPoints;
1213 return TRUE;
1214 }
1215
1216 // Assume (x1, y1) is centre of box (most generally, line end at box)
1217 bool wxOpPolyDraw::GetPerimeterPoint(double x1, double y1,
1218 double x2, double y2,
1219 double *x3, double *y3,
1220 double xOffset, double yOffset,
1221 int attachmentMode)
1222 {
1223 int n = m_noPoints;
1224
1225 // First check for situation where the line is vertical,
1226 // and we would want to connect to a point on that vertical --
1227 // oglFindEndForPolyline can't cope with this (the arrow
1228 // gets drawn to the wrong place).
1229 if ((attachmentMode == ATTACHMENT_MODE_NONE) && (x1 == x2))
1230 {
1231 // Look for the point we'd be connecting to. This is
1232 // a heuristic...
1233 int i;
1234 for (i = 0; i < n; i++)
1235 {
1236 wxRealPoint *point = & (m_points[i]);
1237 if (point->x == 0.0)
1238 {
1239 if ((y2 > y1) && (point->y > 0.0))
1240 {
1241 *x3 = point->x + xOffset;
1242 *y3 = point->y + yOffset;
1243 return TRUE;
1244 }
1245 else if ((y2 < y1) && (point->y < 0.0))
1246 {
1247 *x3 = point->x + xOffset;
1248 *y3 = point->y + yOffset;
1249 return TRUE;
1250 }
1251 }
1252 }
1253 }
1254
1255 double *xpoints = new double[n];
1256 double *ypoints = new double[n];
1257
1258 int i = 0;
1259 for (i = 0; i < n; i++)
1260 {
1261 wxRealPoint *point = & (m_points[i]);
1262 xpoints[i] = point->x + xOffset;
1263 ypoints[i] = point->y + yOffset;
1264 }
1265
1266 oglFindEndForPolyline(n, xpoints, ypoints,
1267 x1, y1, x2, y2, x3, y3);
1268
1269 delete[] xpoints;
1270 delete[] ypoints;
1271
1272 return TRUE;
1273 }
1274
1275
1276 /*
1277 * Utilities
1278 *
1279 */
1280
1281 static char hexArray[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
1282 'C', 'D', 'E', 'F' };
1283
1284 // Convert unsigned 16-bit integer to 4-character hex string
1285 static void IntToHex(unsigned int dec, char *buf)
1286 {
1287 int digit1 = (int)(dec/4096);
1288 int digit2 = (int)((dec - (digit1*4096))/256);
1289 int digit3 = (int)((dec - (digit1*4096) - (digit2*256))/16);
1290 int digit4 = dec - (digit1*4096 + digit2*256 + digit3*16);
1291
1292 buf[0] = hexArray[digit1];
1293 buf[1] = hexArray[digit2];
1294 buf[2] = hexArray[digit3];
1295 buf[3] = hexArray[digit4];
1296 buf[4] = 0;
1297 }
1298
1299 // One hex digit to decimal number
1300 static int HexToInt1(char hex)
1301 {
1302 switch (hex)
1303 {
1304 case '0':
1305 return 0;
1306 case '1':
1307 return 1;
1308 case '2':
1309 return 2;
1310 case '3':
1311 return 3;
1312 case '4':
1313 return 4;
1314 case '5':
1315 return 5;
1316 case '6':
1317 return 6;
1318 case '7':
1319 return 7;
1320 case '8':
1321 return 8;
1322 case '9':
1323 return 9;
1324 case 'A':
1325 return 10;
1326 case 'B':
1327 return 11;
1328 case 'C':
1329 return 12;
1330 case 'D':
1331 return 13;
1332 case 'E':
1333 return 14;
1334 case 'F':
1335 return 15;
1336 default:
1337 return 0;
1338 }
1339 return 0;
1340 }
1341
1342 // 4-digit hex string to unsigned integer
1343 static unsigned long HexToInt(char *buf)
1344 {
1345 long d1 = (long)(HexToInt1(buf[0])*4096.0) ;
1346 long d2 = (long)(HexToInt1(buf[1])*256.0) ;
1347 long d3 = (long)(HexToInt1(buf[2])*16.0) ;
1348 long d4 = (long)(HexToInt1(buf[3])) ;
1349 unsigned long n = (long)(d1 + d2 + d3 + d4) ;
1350 return n;
1351 }
1352
1353 /*
1354 * wxPseudo meta-file
1355 *
1356 */
1357
1358 IMPLEMENT_DYNAMIC_CLASS(wxPseudoMetaFile, wxObject)
1359
1360 wxPseudoMetaFile::wxPseudoMetaFile()
1361 {
1362 m_currentRotation = 0;
1363 m_rotateable = TRUE;
1364 m_width = 0.0;
1365 m_height = 0.0;
1366 m_outlinePen = NULL;
1367 m_fillBrush = NULL;
1368 m_outlineOp = -1;
1369 }
1370
1371 wxPseudoMetaFile::wxPseudoMetaFile(wxPseudoMetaFile& mf)
1372 {
1373 mf.Copy(*this);
1374 }
1375
1376 wxPseudoMetaFile::~wxPseudoMetaFile()
1377 {
1378 Clear();
1379 }
1380
1381 void wxPseudoMetaFile::Clear()
1382 {
1383 wxNode *node = m_ops.First();
1384 while (node)
1385 {
1386 wxDrawOp *op = (wxDrawOp *)node->Data();
1387 delete op;
1388 node = node->Next();
1389 }
1390 m_ops.Clear();
1391 m_gdiObjects.Clear();
1392 m_outlineColours.Clear();
1393 m_fillColours.Clear();
1394 m_outlineOp = -1;
1395 }
1396
1397 void wxPseudoMetaFile::Draw(wxDC& dc, double xoffset, double yoffset)
1398 {
1399 wxNode *node = m_ops.First();
1400 while (node)
1401 {
1402 wxDrawOp *op = (wxDrawOp *)node->Data();
1403 op->Do(dc, xoffset, yoffset);
1404 node = node->Next();
1405 }
1406 }
1407
1408 void wxPseudoMetaFile::Scale(double sx, double sy)
1409 {
1410 wxNode *node = m_ops.First();
1411 while (node)
1412 {
1413 wxDrawOp *op = (wxDrawOp *)node->Data();
1414 op->Scale(sx, sy);
1415 node = node->Next();
1416 }
1417 m_width *= sx;
1418 m_height *= sy;
1419 }
1420
1421 void wxPseudoMetaFile::Translate(double x, double y)
1422 {
1423 wxNode *node = m_ops.First();
1424 while (node)
1425 {
1426 wxDrawOp *op = (wxDrawOp *)node->Data();
1427 op->Translate(x, y);
1428 node = node->Next();
1429 }
1430 }
1431
1432 void wxPseudoMetaFile::Rotate(double x, double y, double theta)
1433 {
1434 double theta1 = theta-m_currentRotation;
1435 if (theta1 == 0.0) return;
1436 double cosTheta = (double)cos(theta1);
1437 double sinTheta = (double)sin(theta1);
1438
1439 wxNode *node = m_ops.First();
1440 while (node)
1441 {
1442 wxDrawOp *op = (wxDrawOp *)node->Data();
1443 op->Rotate(x, y, theta, sinTheta, cosTheta);
1444 node = node->Next();
1445 }
1446 m_currentRotation = theta;
1447 }
1448
1449 #ifdef PROLOGIO
1450 void wxPseudoMetaFile::WriteAttributes(wxExpr *clause, int whichAngle)
1451 {
1452 wxString widthStr;
1453 widthStr.Printf("meta_width%d", whichAngle);
1454
1455 wxString heightStr;
1456 heightStr.Printf("meta_height%d", whichAngle);
1457
1458 wxString outlineStr;
1459 outlineStr.Printf("outline_op%d", whichAngle);
1460
1461 wxString rotateableStr;
1462 rotateableStr.Printf("meta_rotateable%d", whichAngle);
1463
1464 // Write width and height
1465 clause->AddAttributeValue(widthStr, m_width);
1466 clause->AddAttributeValue(heightStr, m_height);
1467 clause->AddAttributeValue(rotateableStr, (long)m_rotateable);
1468 clause->AddAttributeValue(outlineStr, (long)m_outlineOp);
1469
1470 // Write GDI objects
1471 char buf[50];
1472 int i = 1;
1473 wxNode *node = m_gdiObjects.First();
1474 while (node)
1475 {
1476 sprintf(buf, "gdi%d_%d", whichAngle, i);
1477 wxObject *obj = (wxObject *)node->Data();
1478 wxExpr *expr = NULL;
1479 if (obj)
1480 {
1481 if (obj->IsKindOf(CLASSINFO(wxPen)))
1482 {
1483 wxPen *thePen = (wxPen *)obj;
1484 expr = new wxExpr(wxExprList);
1485 expr->Append(new wxExpr((long)gyTYPE_PEN));
1486 expr->Append(new wxExpr((long)thePen->GetWidth()));
1487 expr->Append(new wxExpr((long)thePen->GetStyle()));
1488 expr->Append(new wxExpr((long)thePen->GetColour().Red()));
1489 expr->Append(new wxExpr((long)thePen->GetColour().Green()));
1490 expr->Append(new wxExpr((long)thePen->GetColour().Blue()));
1491 }
1492 else if (obj->IsKindOf(CLASSINFO(wxBrush)))
1493 {
1494 wxBrush *theBrush = (wxBrush *)obj;
1495 expr = new wxExpr(wxExprList);
1496 expr->Append(new wxExpr((long)gyTYPE_BRUSH));
1497 expr->Append(new wxExpr((long)theBrush->GetStyle()));
1498 expr->Append(new wxExpr((long)theBrush->GetColour().Red()));
1499 expr->Append(new wxExpr((long)theBrush->GetColour().Green()));
1500 expr->Append(new wxExpr((long)theBrush->GetColour().Blue()));
1501 }
1502 else if (obj->IsKindOf(CLASSINFO(wxFont)))
1503 {
1504 wxFont *theFont = (wxFont *)obj;
1505 expr = new wxExpr(wxExprList);
1506 expr->Append(new wxExpr((long)gyTYPE_FONT));
1507 expr->Append(new wxExpr((long)theFont->GetPointSize()));
1508 expr->Append(new wxExpr((long)theFont->GetFamily()));
1509 expr->Append(new wxExpr((long)theFont->GetStyle()));
1510 expr->Append(new wxExpr((long)theFont->GetWeight()));
1511 expr->Append(new wxExpr((long)theFont->GetUnderlined()));
1512 }
1513 }
1514 else
1515 {
1516 // If no recognised GDI object, append a place holder anyway.
1517 expr = new wxExpr(wxExprList);
1518 expr->Append(new wxExpr((long)0));
1519 }
1520
1521 if (expr)
1522 {
1523 clause->AddAttributeValue(buf, expr);
1524 i ++;
1525 }
1526 node = node->Next();
1527 }
1528
1529 // Write drawing operations
1530 i = 1;
1531 node = m_ops.First();
1532 while (node)
1533 {
1534 sprintf(buf, "op%d_%d", whichAngle, i);
1535 wxDrawOp *op = (wxDrawOp *)node->Data();
1536 wxExpr *expr = op->WriteExpr(this);
1537 if (expr)
1538 {
1539 clause->AddAttributeValue(buf, expr);
1540 i ++;
1541 }
1542 node = node->Next();
1543 }
1544
1545 // Write outline and fill GDI op lists (if any)
1546 if (m_outlineColours.Number() > 0)
1547 {
1548 wxExpr *outlineExpr = new wxExpr(wxExprList);
1549 node = m_outlineColours.First();
1550 while (node)
1551 {
1552 outlineExpr->Append(new wxExpr((long)node->Data()));
1553 node = node->Next();
1554 }
1555 wxString outlineObjectsStr;
1556 outlineObjectsStr.Printf("outline_objects%d", whichAngle);
1557
1558 clause->AddAttributeValue(outlineObjectsStr, outlineExpr);
1559 }
1560 if (m_fillColours.Number() > 0)
1561 {
1562 wxExpr *fillExpr = new wxExpr(wxExprList);
1563 node = m_fillColours.First();
1564 while (node)
1565 {
1566 fillExpr->Append(new wxExpr((long)node->Data()));
1567 node = node->Next();
1568 }
1569 wxString fillObjectsStr;
1570 fillObjectsStr.Printf("fill_objects%d", whichAngle);
1571
1572 clause->AddAttributeValue(fillObjectsStr, fillExpr);
1573 }
1574
1575 }
1576
1577 void wxPseudoMetaFile::ReadAttributes(wxExpr *clause, int whichAngle)
1578 {
1579 wxString widthStr;
1580 widthStr.Printf("meta_width%d", whichAngle);
1581
1582 wxString heightStr;
1583 heightStr.Printf("meta_height%d", whichAngle);
1584
1585 wxString outlineStr;
1586 outlineStr.Printf("outline_op%d", whichAngle);
1587
1588 wxString rotateableStr;
1589 rotateableStr.Printf("meta_rotateable%d", whichAngle);
1590
1591 clause->GetAttributeValue(widthStr, m_width);
1592 clause->GetAttributeValue(heightStr, m_height);
1593 clause->GetAttributeValue(outlineStr, m_outlineOp);
1594
1595 int iVal = (int) m_rotateable;
1596 clause->GetAttributeValue(rotateableStr, iVal);
1597 m_rotateable = (iVal != 0);
1598
1599 // Read GDI objects
1600 char buf[50];
1601 int i = 1;
1602 bool keepGoing = TRUE;
1603 while (keepGoing)
1604 {
1605 sprintf(buf, "gdi%d_%d", whichAngle, i);
1606 wxExpr *expr = NULL;
1607 clause->GetAttributeValue(buf, &expr);
1608 if (!expr)
1609 {
1610 keepGoing = FALSE;
1611 }
1612 else
1613 {
1614 wxExpr *idExpr = expr->Nth(0);
1615 switch (idExpr->IntegerValue())
1616 {
1617 case gyTYPE_PEN:
1618 {
1619 int penWidth = (int)expr->Nth(1)->IntegerValue();
1620 int penStyle = (int)expr->Nth(2)->IntegerValue();
1621 int penRed = (int)expr->Nth(3)->IntegerValue();
1622 int penGreen = (int)expr->Nth(4)->IntegerValue();
1623 int penBlue = (int)expr->Nth(5)->IntegerValue();
1624 wxColour col(penRed, penGreen, penBlue);
1625 wxPen *p = wxThePenList->FindOrCreatePen(col, penWidth, penStyle);
1626 if (!p)
1627 p = wxBLACK_PEN;
1628 m_gdiObjects.Append(p);
1629 break;
1630 }
1631 case gyTYPE_BRUSH:
1632 {
1633 int brushStyle = (int)expr->Nth(1)->IntegerValue();
1634 int brushRed = (int)expr->Nth(2)->IntegerValue();
1635 int brushGreen = (int)expr->Nth(3)->IntegerValue();
1636 int brushBlue = (int)expr->Nth(4)->IntegerValue();
1637 wxColour col(brushRed, brushGreen, brushBlue);
1638 wxBrush *b = wxTheBrushList->FindOrCreateBrush(col, brushStyle);
1639 if (!b)
1640 b = wxWHITE_BRUSH;
1641 m_gdiObjects.Append(b);
1642 break;
1643 }
1644 case gyTYPE_FONT:
1645 {
1646 int fontPointSize = (int)expr->Nth(1)->IntegerValue();
1647 int fontFamily = (int)expr->Nth(2)->IntegerValue();
1648 int fontStyle = (int)expr->Nth(3)->IntegerValue();
1649 int fontWeight = (int)expr->Nth(4)->IntegerValue();
1650 int fontUnderlined = (int)expr->Nth(5)->IntegerValue();
1651 m_gdiObjects.Append(wxTheFontList->FindOrCreateFont(fontPointSize,
1652 fontFamily, fontStyle, fontWeight, (fontUnderlined != 0)));
1653 break;
1654 }
1655 default:
1656 {
1657 // Place holder
1658 m_gdiObjects.Append(NULL);
1659 break;
1660 }
1661 }
1662 i ++;
1663 }
1664 }
1665
1666 // Now read in the operations
1667 keepGoing = TRUE;
1668 i = 1;
1669 while (keepGoing)
1670 {
1671 sprintf(buf, "op%d_%d", whichAngle, i);
1672 wxExpr *expr = NULL;
1673 clause->GetAttributeValue(buf, &expr);
1674 if (!expr)
1675 {
1676 keepGoing = FALSE;
1677 }
1678 else
1679 {
1680 wxExpr *idExpr = expr->Nth(0);
1681 int opId = (int)idExpr->IntegerValue();
1682 switch (opId)
1683 {
1684 case DRAWOP_SET_PEN:
1685 case DRAWOP_SET_BRUSH:
1686 case DRAWOP_SET_FONT:
1687 case DRAWOP_SET_TEXT_COLOUR:
1688 case DRAWOP_SET_BK_COLOUR:
1689 case DRAWOP_SET_BK_MODE:
1690 {
1691 wxOpSetGDI *theOp = new wxOpSetGDI(opId, this, 0);
1692 theOp->ReadExpr(this, expr);
1693 m_ops.Append(theOp);
1694 break;
1695 }
1696
1697 case DRAWOP_SET_CLIPPING_RECT:
1698 case DRAWOP_DESTROY_CLIPPING_RECT:
1699 {
1700 wxOpSetClipping *theOp = new wxOpSetClipping(opId, 0.0, 0.0, 0.0, 0.0);
1701 theOp->ReadExpr(this, expr);
1702 m_ops.Append(theOp);
1703 break;
1704 }
1705
1706 case DRAWOP_DRAW_LINE:
1707 case DRAWOP_DRAW_RECT:
1708 case DRAWOP_DRAW_ROUNDED_RECT:
1709 case DRAWOP_DRAW_ELLIPSE:
1710 case DRAWOP_DRAW_POINT:
1711 case DRAWOP_DRAW_ARC:
1712 case DRAWOP_DRAW_TEXT:
1713 {
1714 wxOpDraw *theOp = new wxOpDraw(opId, 0.0, 0.0, 0.0, 0.0);
1715 theOp->ReadExpr(this, expr);
1716 m_ops.Append(theOp);
1717 break;
1718 }
1719 case DRAWOP_DRAW_SPLINE:
1720 case DRAWOP_DRAW_POLYLINE:
1721 case DRAWOP_DRAW_POLYGON:
1722 {
1723 wxOpPolyDraw *theOp = new wxOpPolyDraw(opId, 0, NULL);
1724 theOp->ReadExpr(this, expr);
1725 m_ops.Append(theOp);
1726 break;
1727 }
1728 default:
1729 break;
1730 }
1731 }
1732 i ++;
1733 }
1734
1735 wxString outlineObjectsStr;
1736 outlineObjectsStr.Printf("outline_objects%d", whichAngle);
1737
1738 // Now read in the list of outline and fill operations, if any
1739 wxExpr *expr1 = clause->AttributeValue(outlineObjectsStr);
1740 if (expr1)
1741 {
1742 wxExpr *eachExpr = expr1->GetFirst();
1743 while (eachExpr)
1744 {
1745 m_outlineColours.Append((wxObject *)eachExpr->IntegerValue());
1746 eachExpr = eachExpr->GetNext();
1747 }
1748 }
1749
1750 wxString fillObjectsStr;
1751 fillObjectsStr.Printf("fill_objects%d", whichAngle);
1752
1753 expr1 = clause->AttributeValue(fillObjectsStr);
1754 if (expr1)
1755 {
1756 wxExpr *eachExpr = expr1->GetFirst();
1757 while (eachExpr)
1758 {
1759 m_fillColours.Append((wxObject *)eachExpr->IntegerValue());
1760 eachExpr = eachExpr->GetNext();
1761 }
1762 }
1763 }
1764 #endif
1765
1766 // Does the copying for this object
1767 void wxPseudoMetaFile::Copy(wxPseudoMetaFile& copy)
1768 {
1769 copy.Clear();
1770
1771 copy.m_currentRotation = m_currentRotation;
1772 copy.m_width = m_width;
1773 copy.m_height = m_height;
1774 copy.m_rotateable = m_rotateable;
1775 copy.m_fillBrush = m_fillBrush;
1776 copy.m_outlinePen = m_outlinePen;
1777 copy.m_outlineOp = m_outlineOp;
1778
1779 // Copy the GDI objects
1780 wxNode *node = m_gdiObjects.First();
1781 while (node)
1782 {
1783 wxObject *obj = (wxObject *)node->Data();
1784 copy.m_gdiObjects.Append(obj);
1785 node = node->Next();
1786 }
1787
1788 // Copy the operations
1789 node = m_ops.First();
1790 while (node)
1791 {
1792 wxDrawOp *op = (wxDrawOp *)node->Data();
1793 copy.m_ops.Append(op->Copy(&copy));
1794 node = node->Next();
1795 }
1796
1797 // Copy the outline/fill operations
1798 node = m_outlineColours.First();
1799 while (node)
1800 {
1801 copy.m_outlineColours.Append((wxObject *)node->Data());
1802 node = node->Next();
1803 }
1804 node = m_fillColours.First();
1805 while (node)
1806 {
1807 copy.m_fillColours.Append((wxObject *)node->Data());
1808 node = node->Next();
1809 }
1810 }
1811
1812 /*
1813 * Pass size of existing image; scale height to
1814 * fit width and return new width and height.
1815 *
1816 */
1817
1818 bool wxPseudoMetaFile::LoadFromMetaFile(char *filename, double *rwidth, double *rheight)
1819 {
1820 if (!FileExists(filename))
1821 return NULL;
1822
1823 wxXMetaFile *metaFile = new wxXMetaFile;
1824
1825 if (!metaFile->ReadFile(filename))
1826 {
1827 delete metaFile;
1828 return FALSE;
1829 }
1830
1831 double lastX = 0.0;
1832 double lastY = 0.0;
1833
1834 // Convert from metafile records to wxDrawnShape records
1835 wxNode *node = metaFile->metaRecords.First();
1836 while (node)
1837 {
1838 wxMetaRecord *record = (wxMetaRecord *)node->Data();
1839 switch (record->metaFunction)
1840 {
1841 case META_SETBKCOLOR:
1842 {
1843 wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_BK_COLOUR, this, 0);
1844 op->m_r = (unsigned char)record->param1;
1845 op->m_g = (unsigned char)record->param2;
1846 op->m_b = (unsigned char)record->param3;
1847 m_ops.Append(op);
1848 break;
1849 }
1850 case META_SETBKMODE:
1851 {
1852 wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_BK_MODE, this, 0, (int)record->param1);
1853 m_ops.Append(op);
1854 break;
1855 }
1856 case META_SETMAPMODE:
1857 {
1858 break;
1859 }
1860 // case META_SETROP2:
1861 // case META_SETRELABS:
1862 // case META_SETPOLYFILLMODE:
1863 // case META_SETSTRETCHBLTMODE:
1864 // case META_SETTEXTCHAREXTRA:
1865 case META_SETTEXTCOLOR:
1866 {
1867 wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_TEXT_COLOUR, this, 0);
1868 op->m_r = (unsigned char)record->param1;
1869 op->m_g = (unsigned char)record->param2;
1870 op->m_b = (unsigned char)record->param3;
1871 m_ops.Append(op);
1872 break;
1873 }
1874 // case META_SETTEXTJUSTIFICATION:
1875 // case META_SETWINDOWORG:
1876 // case META_SETWINDOWEXT:
1877 // case META_SETVIEWPORTORG:
1878 // case META_SETVIEWPORTEXT:
1879 // case META_OFFSETWINDOWORG:
1880 // case META_SCALEWINDOWEXT:
1881 // case META_OFFSETVIEWPORTORG:
1882 // case META_SCALEVIEWPORTEXT:
1883 case META_LINETO:
1884 {
1885 wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_LINE, (double)lastX, (double)lastY,
1886 (double)record->param1, (double)record->param2);
1887 m_ops.Append(op);
1888 break;
1889 }
1890 case META_MOVETO:
1891 {
1892 lastX = (double)record->param1;
1893 lastY = (double)record->param2;
1894 break;
1895 }
1896 case META_EXCLUDECLIPRECT:
1897 {
1898 /*
1899 wxMetaRecord *rec = new wxMetaRecord(META_EXCLUDECLIPRECT);
1900 rec->param4 = getshort(handle); // m_y2
1901 rec->param3 = getshort(handle); // x2
1902 rec->param2 = getshort(handle); // y1
1903 rec->param1 = getshort(handle); // x1
1904 */
1905 break;
1906 }
1907 case META_INTERSECTCLIPRECT:
1908 {
1909 /*
1910 rec->param4 = getshort(handle); // m_y2
1911 rec->param3 = getshort(handle); // x2
1912 rec->param2 = getshort(handle); // y1
1913 rec->param1 = getshort(handle); // x1
1914 */
1915 break;
1916 }
1917 // case META_ARC: // DO!!!
1918 case META_ELLIPSE:
1919 {
1920 wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_ELLIPSE,
1921 (double)record->param1, (double)record->param2,
1922 (double)(record->param3 - record->param1),
1923 (double)(record->param4 - record->param2));
1924 m_ops.Append(op);
1925 break;
1926 }
1927 // case META_FLOODFILL:
1928 // case META_PIE: // DO!!!
1929 case META_RECTANGLE:
1930 {
1931 wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_RECT,
1932 (double)record->param1, (double)record->param2,
1933 (double)(record->param3 - record->param1),
1934 (double)(record->param4 - record->param2));
1935 m_ops.Append(op);
1936 break;
1937 }
1938 case META_ROUNDRECT:
1939 {
1940 wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_ROUNDED_RECT,
1941 (double)record->param1, (double)record->param2,
1942 (double)(record->param3 - record->param1),
1943 (double)(record->param4 - record->param2), (double)record->param5);
1944 m_ops.Append(op);
1945 break;
1946 }
1947 // case META_PATBLT:
1948 // case META_SAVEDC:
1949 case META_SETPIXEL:
1950 {
1951 wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_POINT,
1952 (double)record->param1, (double)record->param2,
1953 0.0, 0.0);
1954
1955 // SHOULD SET THE COLOUR - SET PEN?
1956 // rec->param3 = getint(handle); // COLORREF
1957 m_ops.Append(op);
1958 break;
1959 }
1960 // case META_OFFSETCLIPRGN:
1961 case META_TEXTOUT:
1962 {
1963 wxOpDraw *op = new wxOpDraw(DRAWOP_DRAW_TEXT,
1964 (double)record->param1, (double)record->param2,
1965 0.0, 0.0, 0.0, record->stringParam);
1966 m_ops.Append(op);
1967 break;
1968 }
1969 // case META_BITBLT:
1970 // case META_STRETCHBLT:
1971 case META_POLYGON:
1972 {
1973 int n = (int)record->param1;
1974 wxRealPoint *newPoints = new wxRealPoint[n];
1975 for (int i = 0; i < n; i++)
1976 {
1977 newPoints[i].x = record->points[i].x;
1978 newPoints[i].y = record->points[i].y;
1979 }
1980
1981 wxOpPolyDraw *op = new wxOpPolyDraw(DRAWOP_DRAW_POLYGON, n, newPoints);
1982 m_ops.Append(op);
1983 break;
1984 }
1985 case META_POLYLINE:
1986 {
1987 int n = (int)record->param1;
1988 wxRealPoint *newPoints = new wxRealPoint[n];
1989 for (int i = 0; i < n; i++)
1990 {
1991 newPoints[i].x = record->points[i].x;
1992 newPoints[i].y = record->points[i].y;
1993 }
1994
1995 wxOpPolyDraw *op = new wxOpPolyDraw(DRAWOP_DRAW_POLYLINE, n, newPoints);
1996 m_ops.Append(op);
1997 break;
1998 }
1999 // case META_ESCAPE:
2000 // case META_RESTOREDC:
2001 // case META_FILLREGION:
2002 // case META_FRAMEREGION:
2003 // case META_INVERTREGION:
2004 // case META_PAINTREGION:
2005 // case META_SELECTCLIPREGION: // DO THIS!
2006 case META_SELECTOBJECT:
2007 {
2008 // The pen, brush etc. has already been created when the metafile
2009 // was read in, so we don't create it - we set it.
2010 wxNode *recNode = metaFile->gdiObjects.Nth((int)record->param2);
2011 if (recNode)
2012 {
2013 wxMetaRecord *gdiRec = (wxMetaRecord *)recNode->Data();
2014 if (gdiRec && (gdiRec->param1 != 0))
2015 {
2016 wxObject *obj = (wxObject *)gdiRec->param1;
2017 if (obj->IsKindOf(CLASSINFO(wxPen)))
2018 {
2019 wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_PEN, this, (int)record->param2);
2020 m_ops.Append(op);
2021 }
2022 else if (obj->IsKindOf(CLASSINFO(wxBrush)))
2023 {
2024 wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_BRUSH, this, (int)record->param2);
2025 m_ops.Append(op);
2026 }
2027 else if (obj->IsKindOf(CLASSINFO(wxFont)))
2028 {
2029 wxOpSetGDI *op = new wxOpSetGDI(DRAWOP_SET_FONT, this, (int)record->param2);
2030 m_ops.Append(op);
2031 }
2032 }
2033 }
2034 break;
2035 }
2036 // case META_SETTEXTALIGN:
2037 // case META_DRAWTEXT:
2038 // case META_CHORD:
2039 // case META_SETMAPPERFLAGS:
2040 // case META_EXTTEXTOUT:
2041 // case META_SETDIBTODEV:
2042 // case META_SELECTPALETTE:
2043 // case META_REALIZEPALETTE:
2044 // case META_ANIMATEPALETTE:
2045 // case META_SETPALENTRIES:
2046 // case META_POLYPOLYGON:
2047 // case META_RESIZEPALETTE:
2048 // case META_DIBBITBLT:
2049 // case META_DIBSTRETCHBLT:
2050 case META_DIBCREATEPATTERNBRUSH:
2051 {
2052 // Place holder
2053 m_gdiObjects.Append(NULL);
2054 break;
2055 }
2056 // case META_STRETCHDIB:
2057 // case META_EXTFLOODFILL:
2058 // case META_RESETDC:
2059 // case META_STARTDOC:
2060 // case META_STARTPAGE:
2061 // case META_ENDPAGE:
2062 // case META_ABORTDOC:
2063 // case META_ENDDOC:
2064 // case META_DELETEOBJECT: // DO!!
2065 case META_CREATEPALETTE:
2066 {
2067 // Place holder
2068 m_gdiObjects.Append(NULL);
2069 break;
2070 }
2071 case META_CREATEBRUSH:
2072 {
2073 // Place holder
2074 m_gdiObjects.Append(NULL);
2075 break;
2076 }
2077 case META_CREATEPATTERNBRUSH:
2078 {
2079 // Place holder
2080 m_gdiObjects.Append(NULL);
2081 break;
2082 }
2083 case META_CREATEPENINDIRECT:
2084 {
2085 // The pen is created when the metafile is read in.
2086 // We keep track of all the GDI objects needed for this
2087 // image so when reading the wxDrawnShape from file,
2088 // we can read in all the GDI objects, then refer
2089 // to them by an index starting from zero thereafter.
2090 m_gdiObjects.Append((wxObject *)record->param1);
2091 break;
2092 }
2093 case META_CREATEFONTINDIRECT:
2094 {
2095 m_gdiObjects.Append((wxObject *)record->param1);
2096 break;
2097 }
2098 case META_CREATEBRUSHINDIRECT:
2099 {
2100 // Don't have to do anything here: the pen is created
2101 // when the metafile is read in.
2102 m_gdiObjects.Append((wxObject *)record->param1);
2103 break;
2104 }
2105 case META_CREATEBITMAPINDIRECT:
2106 {
2107 // Place holder
2108 m_gdiObjects.Append(NULL);
2109 break;
2110 }
2111 case META_CREATEBITMAP:
2112 {
2113 // Place holder
2114 m_gdiObjects.Append(NULL);
2115 break;
2116 }
2117 case META_CREATEREGION:
2118 {
2119 // Place holder
2120 m_gdiObjects.Append(NULL);
2121 break;
2122 }
2123 default:
2124 {
2125 break;
2126 }
2127 }
2128 node = node->Next();
2129 }
2130 double actualWidth = (double)fabs(metaFile->right - metaFile->left);
2131 double actualHeight = (double)fabs(metaFile->bottom - metaFile->top);
2132
2133 double initialScaleX = 1.0;
2134 double initialScaleY = 1.0;
2135
2136 double xoffset, yoffset;
2137
2138 // Translate so origin is at centre of rectangle
2139 if (metaFile->bottom > metaFile->top)
2140 yoffset = - (double)((metaFile->bottom - metaFile->top)/2.0);
2141 else
2142 yoffset = - (double)((metaFile->top - metaFile->bottom)/2.0);
2143
2144 if (metaFile->right > metaFile->left)
2145 xoffset = - (double)((metaFile->right - metaFile->left)/2.0);
2146 else
2147 xoffset = - (double)((metaFile->left - metaFile->right)/2.0);
2148
2149 Translate(xoffset, yoffset);
2150
2151 // Scale to a reasonable size (take the width of this wxDrawnShape
2152 // as a guide)
2153 if (actualWidth != 0.0)
2154 {
2155 initialScaleX = (double)((*rwidth) / actualWidth);
2156 initialScaleY = initialScaleX;
2157 (*rheight) = initialScaleY*actualHeight;
2158 }
2159 Scale(initialScaleX, initialScaleY);
2160
2161 m_width = (actualWidth*initialScaleX);
2162 m_height = *rheight;
2163
2164 delete metaFile;
2165 return TRUE;
2166 }
2167
2168 // Scale to fit size
2169 void wxPseudoMetaFile::ScaleTo(double w, double h)
2170 {
2171 double scaleX = (double)(w/m_width);
2172 double scaleY = (double)(h/m_height);
2173
2174 // Do the scaling
2175 Scale(scaleX, scaleY);
2176 }
2177
2178 void wxPseudoMetaFile::GetBounds(double *boundMinX, double *boundMinY, double *boundMaxX, double *boundMaxY)
2179 {
2180 double maxX = (double) -99999.9;
2181 double maxY = (double) -99999.9;
2182 double minX = (double) 99999.9;
2183 double minY = (double) 99999.9;
2184
2185 wxNode *node = m_ops.First();
2186 while (node)
2187 {
2188 wxDrawOp *op = (wxDrawOp *)node->Data();
2189 switch (op->GetOp())
2190 {
2191 case DRAWOP_DRAW_LINE:
2192 case DRAWOP_DRAW_RECT:
2193 case DRAWOP_DRAW_ROUNDED_RECT:
2194 case DRAWOP_DRAW_ELLIPSE:
2195 case DRAWOP_DRAW_POINT:
2196 case DRAWOP_DRAW_TEXT:
2197 {
2198 wxOpDraw *opDraw = (wxOpDraw *)op;
2199 if (opDraw->m_x1 < minX) minX = opDraw->m_x1;
2200 if (opDraw->m_x1 > maxX) maxX = opDraw->m_x1;
2201 if (opDraw->m_y1 < minY) minY = opDraw->m_y1;
2202 if (opDraw->m_y1 > maxY) maxY = opDraw->m_y1;
2203 if (op->GetOp() == DRAWOP_DRAW_LINE)
2204 {
2205 if (opDraw->m_x2 < minX) minX = opDraw->m_x2;
2206 if (opDraw->m_x2 > maxX) maxX = opDraw->m_x2;
2207 if (opDraw->m_y2 < minY) minY = opDraw->m_y2;
2208 if (opDraw->m_y2 > maxY) maxY = opDraw->m_y2;
2209 }
2210 else if (op->GetOp() == DRAWOP_DRAW_RECT ||
2211 op->GetOp() == DRAWOP_DRAW_ROUNDED_RECT ||
2212 op->GetOp() == DRAWOP_DRAW_ELLIPSE)
2213 {
2214 if ((opDraw->m_x1 + opDraw->m_x2) < minX) minX = (opDraw->m_x1 + opDraw->m_x2);
2215 if ((opDraw->m_x1 + opDraw->m_x2) > maxX) maxX = (opDraw->m_x1 + opDraw->m_x2);
2216 if ((opDraw->m_y1 + opDraw->m_y2) < minY) minY = (opDraw->m_y1 + opDraw->m_y2);
2217 if ((opDraw->m_y1 + opDraw->m_y2) > maxY) maxY = (opDraw->m_y1 + opDraw->m_y2);
2218 }
2219 break;
2220 }
2221 case DRAWOP_DRAW_ARC:
2222 {
2223 // TODO: don't yet know how to calculate the bounding box
2224 // for an arc. So pretend it's a line; to get a correct
2225 // bounding box, draw a blank rectangle first, of the correct
2226 // size.
2227 wxOpDraw *opDraw = (wxOpDraw *)op;
2228 if (opDraw->m_x1 < minX) minX = opDraw->m_x1;
2229 if (opDraw->m_x1 > maxX) maxX = opDraw->m_x1;
2230 if (opDraw->m_y1 < minY) minY = opDraw->m_y1;
2231 if (opDraw->m_y1 > maxY) maxY = opDraw->m_y1;
2232 if (opDraw->m_x2 < minX) minX = opDraw->m_x2;
2233 if (opDraw->m_x2 > maxX) maxX = opDraw->m_x2;
2234 if (opDraw->m_y2 < minY) minY = opDraw->m_y2;
2235 if (opDraw->m_y2 > maxY) maxY = opDraw->m_y2;
2236 break;
2237 }
2238 case DRAWOP_DRAW_POLYLINE:
2239 case DRAWOP_DRAW_POLYGON:
2240 case DRAWOP_DRAW_SPLINE:
2241 {
2242 wxOpPolyDraw *poly = (wxOpPolyDraw *)op;
2243 for (int i = 0; i < poly->m_noPoints; i++)
2244 {
2245 if (poly->m_points[i].x < minX) minX = poly->m_points[i].x;
2246 if (poly->m_points[i].x > maxX) maxX = poly->m_points[i].x;
2247 if (poly->m_points[i].y < minY) minY = poly->m_points[i].y;
2248 if (poly->m_points[i].y > maxY) maxY = poly->m_points[i].y;
2249 }
2250 break;
2251 }
2252 default:
2253 break;
2254 }
2255 node = node->Next();
2256 }
2257
2258 *boundMinX = minX;
2259 *boundMinY = minY;
2260 *boundMaxX = maxX;
2261 *boundMaxY = maxY;
2262 /*
2263 *w = (double)fabs(maxX - minX);
2264 *h = (double)fabs(maxY - minY);
2265 */
2266 }
2267
2268 // Calculate size from current operations
2269 void wxPseudoMetaFile::CalculateSize(wxDrawnShape* shape)
2270 {
2271 double boundMinX, boundMinY, boundMaxX, boundMaxY;
2272
2273 GetBounds(& boundMinX, & boundMinY, & boundMaxX, & boundMaxY);
2274
2275 SetSize(boundMaxX - boundMinX, boundMaxY - boundMinY);
2276
2277 if (shape)
2278 {
2279 shape->SetWidth(m_width);
2280 shape->SetHeight(m_height);
2281 }
2282 }
2283
2284 // Set of functions for drawing into a pseudo metafile.
2285 // They use integers, but doubles are used internally for accuracy
2286 // when scaling.
2287
2288 void wxPseudoMetaFile::DrawLine(const wxPoint& pt1, const wxPoint& pt2)
2289 {
2290 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_LINE,
2291 (double) pt1.x, (double) pt1.y, (double) pt2.x, (double) pt2.y);
2292
2293 m_ops.Append(theOp);
2294 }
2295
2296 void wxPseudoMetaFile::DrawRectangle(const wxRect& rect)
2297 {
2298 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_RECT,
2299 (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
2300
2301 m_ops.Append(theOp);
2302 }
2303
2304 void wxPseudoMetaFile::DrawRoundedRectangle(const wxRect& rect, double radius)
2305 {
2306 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ROUNDED_RECT,
2307 (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
2308
2309 theOp->m_radius = radius;
2310
2311 m_ops.Append(theOp);
2312 }
2313
2314 void wxPseudoMetaFile::DrawEllipse(const wxRect& rect)
2315 {
2316 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ELLIPSE,
2317 (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
2318
2319 m_ops.Append(theOp);
2320 }
2321
2322 void wxPseudoMetaFile::DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt)
2323 {
2324 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ARC,
2325 (double) centrePt.x, (double) centrePt.y, (double) startPt.x, (double) startPt.y);
2326
2327 theOp->m_x3 = (double) endPt.x;
2328 theOp->m_y3 = (double) endPt.y;
2329
2330 m_ops.Append(theOp);
2331 }
2332
2333 void wxPseudoMetaFile::DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle)
2334 {
2335 const double pi = 3.1415926535897932384626433832795 ;
2336
2337 double startAngleRadians = startAngle* (pi*2.0/360.0);
2338 double endAngleRadians = endAngle* (pi*2.0/360.0);
2339
2340 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_ELLIPTIC_ARC,
2341 (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
2342
2343 theOp->m_x3 = startAngleRadians;
2344 theOp->m_y3 = endAngleRadians;
2345
2346 m_ops.Append(theOp);
2347 }
2348
2349 void wxPseudoMetaFile::DrawPoint(const wxPoint& pt)
2350 {
2351 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_POINT,
2352 (double) pt.x, (double) pt.y, 0.0, 0.0);
2353
2354 m_ops.Append(theOp);
2355 }
2356
2357 void wxPseudoMetaFile::DrawText(const wxString& text, const wxPoint& pt)
2358 {
2359 wxOpDraw *theOp = new wxOpDraw(DRAWOP_DRAW_TEXT,
2360 (double) pt.x, (double) pt.y, 0.0, 0.0);
2361
2362 theOp->m_textString = copystring(text);
2363
2364 m_ops.Append(theOp);
2365 }
2366
2367 void wxPseudoMetaFile::DrawLines(int n, wxPoint pts[])
2368 {
2369 wxRealPoint* realPoints = new wxRealPoint[n];
2370 int i;
2371 for (i = 0; i < n; i++)
2372 {
2373 realPoints[i].x = pts[i].x;
2374 realPoints[i].y = pts[i].y;
2375 }
2376 wxOpPolyDraw* theOp = new wxOpPolyDraw(DRAWOP_DRAW_POLYLINE, n, realPoints);
2377 m_ops.Append(theOp);
2378 }
2379
2380 void wxPseudoMetaFile::DrawPolygon(int n, wxPoint pts[], int flags)
2381 {
2382 wxRealPoint* realPoints = new wxRealPoint[n];
2383 int i;
2384 for (i = 0; i < n; i++)
2385 {
2386 realPoints[i].x = pts[i].x;
2387 realPoints[i].y = pts[i].y;
2388 }
2389 wxOpPolyDraw* theOp = new wxOpPolyDraw(DRAWOP_DRAW_POLYGON, n, realPoints);
2390 m_ops.Append(theOp);
2391
2392 if (flags & oglMETAFLAGS_OUTLINE)
2393 m_outlineOp = (m_ops.Number() - 1);
2394 }
2395
2396 void wxPseudoMetaFile::DrawSpline(int n, wxPoint pts[])
2397 {
2398 wxRealPoint* realPoints = new wxRealPoint[n];
2399 int i;
2400 for (i = 0; i < n; i++)
2401 {
2402 realPoints[i].x = pts[i].x;
2403 realPoints[i].y = pts[i].y;
2404 }
2405 wxOpPolyDraw* theOp = new wxOpPolyDraw(DRAWOP_DRAW_SPLINE, n, realPoints);
2406 m_ops.Append(theOp);
2407 }
2408
2409 void wxPseudoMetaFile::SetClippingRect(const wxRect& rect)
2410 {
2411 wxOpSetClipping* theOp = new wxOpSetClipping(DRAWOP_SET_CLIPPING_RECT,
2412 (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
2413 }
2414
2415 void wxPseudoMetaFile::DestroyClippingRect()
2416 {
2417 wxOpSetClipping* theOp = new wxOpSetClipping(DRAWOP_DESTROY_CLIPPING_RECT,
2418 0.0, 0.0, 0.0, 0.0);
2419
2420 m_ops.Append(theOp);
2421 }
2422
2423 void wxPseudoMetaFile::SetPen(wxPen* pen, bool isOutline)
2424 {
2425 m_gdiObjects.Append(pen);
2426 int n = m_gdiObjects.Number();
2427
2428 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_PEN, this, n - 1);
2429
2430 m_ops.Append(theOp);
2431
2432 if (isOutline)
2433 {
2434 m_outlineColours.Append((wxObject*) (n - 1));
2435 }
2436 }
2437
2438 void wxPseudoMetaFile::SetBrush(wxBrush* brush, bool isFill)
2439 {
2440 m_gdiObjects.Append(brush);
2441 int n = m_gdiObjects.Number();
2442
2443 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_BRUSH, this, n - 1);
2444
2445 m_ops.Append(theOp);
2446
2447 if (isFill)
2448 {
2449 m_fillColours.Append((wxObject*) (n - 1));
2450 }
2451 }
2452
2453 void wxPseudoMetaFile::SetFont(wxFont* font)
2454 {
2455 m_gdiObjects.Append(font);
2456 int n = m_gdiObjects.Number();
2457
2458 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_FONT, this, n - 1);
2459
2460 m_ops.Append(theOp);
2461 }
2462
2463 void wxPseudoMetaFile::SetTextColour(const wxColour& colour)
2464 {
2465 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_TEXT_COLOUR, this, 0);
2466 theOp->m_r = colour.Red();
2467 theOp->m_g = colour.Green();
2468 theOp->m_b = colour.Blue();
2469
2470 m_ops.Append(theOp);
2471 }
2472
2473 void wxPseudoMetaFile::SetBackgroundColour(const wxColour& colour)
2474 {
2475 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_BK_COLOUR, this, 0);
2476 theOp->m_r = colour.Red();
2477 theOp->m_g = colour.Green();
2478 theOp->m_b = colour.Blue();
2479
2480 m_ops.Append(theOp);
2481 }
2482
2483 void wxPseudoMetaFile::SetBackgroundMode(int mode)
2484 {
2485 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_BK_MODE, this, 0, mode);
2486
2487 m_ops.Append(theOp);
2488 }
2489