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