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