]> git.saurik.com Git - wxWidgets.git/blame - contrib/src/ogl/drawn.cpp
Deprecated lib tweaks
[wxWidgets.git] / contrib / src / ogl / drawn.cpp
CommitLineData
1fc25a89
JS
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".
92a19c2e 18#include "wx/wxprec.h"
1fc25a89
JS
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
2b5f62a0
VZ
38#include <math.h>
39
1fc25a89
JS
40static void IntToHex(unsigned int dec, char *buf);
41static unsigned long HexToInt(char *buf);
42extern 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
53IMPLEMENT_DYNAMIC_CLASS(wxDrawnShape, wxRectangleShape)
54
55wxDrawnShape::wxDrawnShape():wxRectangleShape(100.0, 50.0)
56{
57 m_saveToFile = TRUE;
58 m_currentAngle = oglDRAWN_ANGLE_0;
59}
60
61wxDrawnShape::~wxDrawnShape()
62{
63}
64
65void 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 }
c1fa2fda 76
1fc25a89
JS
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
82void 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
106void 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
119void 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
133void 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;
c1fa2fda 142
1fc25a89
JS
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);
b9ac87bc 151 wxNode *node = m_attachmentPoints.GetFirst();
1fc25a89
JS
152 while (node)
153 {
b9ac87bc 154 wxAttachmentPoint *point = (wxAttachmentPoint *)node->GetData();
1fc25a89
JS
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;
b9ac87bc 159 node = node->GetNext();
1fc25a89
JS
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
169int 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
203void wxDrawnShape::OnDrawOutline(wxDC& dc, double x, double y, double w, double h)
204{
205 if (m_metafiles[m_currentAngle].GetOutlineOp() != -1)
206 {
b9ac87bc 207 wxNode* node = m_metafiles[m_currentAngle].GetOps().Item(m_metafiles[m_currentAngle].GetOutlineOp());
1fc25a89 208 wxASSERT (node != NULL);
b9ac87bc 209 wxDrawOp* op = (wxDrawOp*) node->GetData();
1fc25a89
JS
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
221bool 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 {
b9ac87bc 227 wxNode* node = m_metafiles[m_currentAngle].GetOps().Item(m_metafiles[m_currentAngle].GetOutlineOp());
1fc25a89 228 wxASSERT (node != NULL);
b9ac87bc 229 wxDrawOp* op = (wxDrawOp*) node->GetData();
1fc25a89
JS
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
2b5f62a0 239#if wxUSE_PROLOGIO
1fc25a89
JS
240void 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
257void 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
278void 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
9e053640 295bool wxDrawnShape::LoadFromMetaFile(const wxString& filename)
1fc25a89
JS
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
304void wxDrawnShape::DrawLine(const wxPoint& pt1, const wxPoint& pt2)
305{
306 m_metafiles[m_currentAngle].DrawLine(pt1, pt2);
307}
308
309void wxDrawnShape::DrawRectangle(const wxRect& rect)
310{
311 m_metafiles[m_currentAngle].DrawRectangle(rect);
312}
313
314void wxDrawnShape::DrawRoundedRectangle(const wxRect& rect, double radius)
315{
316 m_metafiles[m_currentAngle].DrawRoundedRectangle(rect, radius);
317}
318
319void wxDrawnShape::DrawEllipse(const wxRect& rect)
320{
321 m_metafiles[m_currentAngle].DrawEllipse(rect);
322}
323
324void wxDrawnShape::DrawArc(const wxPoint& centrePt, const wxPoint& startPt, const wxPoint& endPt)
325{
326 m_metafiles[m_currentAngle].DrawArc(centrePt, startPt, endPt);
327}
328
329void wxDrawnShape::DrawEllipticArc(const wxRect& rect, double startAngle, double endAngle)
330{
331 m_metafiles[m_currentAngle].DrawEllipticArc(rect, startAngle, endAngle);
332}
333
334void wxDrawnShape::DrawPoint(const wxPoint& pt)
335{
336 m_metafiles[m_currentAngle].DrawPoint(pt);
337}
338
339void wxDrawnShape::DrawText(const wxString& text, const wxPoint& pt)
340{
341 m_metafiles[m_currentAngle].DrawText(text, pt);
342}
343
344void wxDrawnShape::DrawLines(int n, wxPoint pts[])
345{
346 m_metafiles[m_currentAngle].DrawLines(n, pts);
347}
348
349void 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
361void wxDrawnShape::DrawSpline(int n, wxPoint pts[])
362{
363 m_metafiles[m_currentAngle].DrawSpline(n, pts);
364}
365
366void wxDrawnShape::SetClippingRect(const wxRect& rect)
367{
368 m_metafiles[m_currentAngle].SetClippingRect(rect);
369}
370
371void wxDrawnShape::DestroyClippingRect()
372{
373 m_metafiles[m_currentAngle].DestroyClippingRect();
374}
375
376void wxDrawnShape::SetDrawnPen(wxPen* pen, bool isOutline)
377{
378 m_metafiles[m_currentAngle].SetPen(pen, isOutline);
379}
380
381void wxDrawnShape::SetDrawnBrush(wxBrush* brush, bool isFill)
382{
383 m_metafiles[m_currentAngle].SetBrush(brush, isFill);
384}
385
386void wxDrawnShape::SetDrawnFont(wxFont* font)
387{
388 m_metafiles[m_currentAngle].SetFont(font);
389}
390
391void wxDrawnShape::SetDrawnTextColour(const wxColour& colour)
392{
393 m_metafiles[m_currentAngle].SetTextColour(colour);
394}
395
396void wxDrawnShape::SetDrawnBackgroundColour(const wxColour& colour)
397{
398 m_metafiles[m_currentAngle].SetBackgroundColour(colour);
399}
400
401void wxDrawnShape::SetDrawnBackgroundMode(int mode)
402{
403 m_metafiles[m_currentAngle].SetBackgroundMode(mode);
404}
405
406
407/*
408 * Individual operations
409 *
410 */
c1fa2fda 411
1fc25a89
JS
412/*
413 * Set font, brush, text colour
414 *
415 */
c1fa2fda 416
1fc25a89
JS
417wxOpSetGDI::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
425void 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 {
b9ac87bc 440 wxNode *node = m_image->m_gdiObjects.Item(m_gdiIndex);
1fc25a89
JS
441 if (node)
442 {
b9ac87bc 443 wxPen *pen = (wxPen *)node->GetData();
1fc25a89
JS
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 {
b9ac87bc 473 wxNode *node = m_image->m_gdiObjects.Item(m_gdiIndex);
1fc25a89
JS
474 if (node)
475 {
b9ac87bc 476 wxBrush *brush = (wxBrush *)node->GetData();
1fc25a89
JS
477 if (brush)
478 dc.SetBrush(* brush);
479 }
480 }
481 break;
482 }
483 case DRAWOP_SET_FONT:
484 {
b9ac87bc 485 wxNode *node = m_image->m_gdiObjects.Item(m_gdiIndex);
1fc25a89
JS
486 if (node)
487 {
b9ac87bc 488 wxFont *font = (wxFont *)node->GetData();
1fc25a89
JS
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
516wxDrawOp *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
2b5f62a0 525#if wxUSE_PROLOGIO
1fc25a89
JS
526wxExpr *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
558void 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 {
b9ac87bc 566 m_gdiIndex = (int)expr->Item(1)->IntegerValue();
1fc25a89
JS
567 break;
568 }
569 case DRAWOP_SET_TEXT_COLOUR:
570 case DRAWOP_SET_BK_COLOUR:
571 {
b9ac87bc
RD
572 m_r = (unsigned char)expr->Item(1)->IntegerValue();
573 m_g = (unsigned char)expr->Item(2)->IntegerValue();
574 m_b = (unsigned char)expr->Item(3)->IntegerValue();
1fc25a89
JS
575 break;
576 }
577 case DRAWOP_SET_BK_MODE:
578 {
b9ac87bc 579 m_mode = (int)expr->Item(1)->IntegerValue();
1fc25a89
JS
580 break;
581 }
582 default:
583 break;
584 }
585}
2b5f62a0 586#endif
1fc25a89
JS
587
588/*
589 * Set/destroy clipping
590 *
591 */
c1fa2fda 592
1fc25a89
JS
593wxOpSetClipping::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
602wxDrawOp *wxOpSetClipping::Copy(wxPseudoMetaFile *newImage)
603{
604 wxOpSetClipping *newOp = new wxOpSetClipping(m_op, m_x1, m_y1, m_x2, m_y2);
605 return newOp;
606}
c1fa2fda 607
1fc25a89
JS
608void 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
627void 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
635void wxOpSetClipping::Translate(double x, double y)
636{
637 m_x1 += x;
638 m_y1 += y;
639}
640
2b5f62a0 641#if wxUSE_PROLOGIO
1fc25a89
JS
642wxExpr *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
662void wxOpSetClipping::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr)
663{
664 switch (m_op)
665 {
666 case DRAWOP_SET_CLIPPING_RECT:
667 {
b9ac87bc
RD
668 m_x1 = expr->Item(1)->RealValue();
669 m_y1 = expr->Item(2)->RealValue();
670 m_x2 = expr->Item(3)->RealValue();
671 m_y2 = expr->Item(4)->RealValue();
1fc25a89
JS
672 break;
673 }
674 default:
675 break;
676 }
677}
2b5f62a0 678#endif
1fc25a89
JS
679
680/*
681 * Draw line, rectangle, rounded rectangle, ellipse, point, arc, text
682 *
683 */
c1fa2fda 684
1fc25a89 685wxOpDraw::wxOpDraw(int theOp, double theX1, double theY1, double theX2, double theY2,
c1fa2fda 686 double theRadius, wxChar *s) : wxDrawOp(theOp)
1fc25a89
JS
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
699wxOpDraw::~wxOpDraw()
700{
701 if (m_textString) delete[] m_textString;
702}
703
704wxDrawOp *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
712void 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
769void 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
785void 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
815void 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
2b5f62a0 887#if wxUSE_PROLOGIO
1fc25a89
JS
888wxExpr *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
945void 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 {
b9ac87bc
RD
953 m_x1 = expr->Item(1)->RealValue();
954 m_y1 = expr->Item(2)->RealValue();
955 m_x2 = expr->Item(3)->RealValue();
956 m_y2 = expr->Item(4)->RealValue();
1fc25a89
JS
957 break;
958 }
959 case DRAWOP_DRAW_ROUNDED_RECT:
960 {
b9ac87bc
RD
961 m_x1 = expr->Item(1)->RealValue();
962 m_y1 = expr->Item(2)->RealValue();
963 m_x2 = expr->Item(3)->RealValue();
964 m_y2 = expr->Item(4)->RealValue();
965 m_radius = expr->Item(5)->RealValue();
1fc25a89
JS
966 break;
967 }
968 case DRAWOP_DRAW_POINT:
969 {
b9ac87bc
RD
970 m_x1 = expr->Item(1)->RealValue();
971 m_y1 = expr->Item(2)->RealValue();
1fc25a89
JS
972 break;
973 }
974 case DRAWOP_DRAW_TEXT:
975 {
b9ac87bc
RD
976 m_x1 = expr->Item(1)->RealValue();
977 m_y1 = expr->Item(2)->RealValue();
978 wxString str(expr->Item(3)->StringValue());
c1fa2fda 979 m_textString = copystring(str);
1fc25a89
JS
980 break;
981 }
982 case DRAWOP_DRAW_ARC:
983 case DRAWOP_DRAW_ELLIPTIC_ARC:
984 {
b9ac87bc
RD
985 m_x1 = expr->Item(1)->RealValue();
986 m_y1 = expr->Item(2)->RealValue();
987 m_x2 = expr->Item(3)->RealValue();
988 m_y2 = expr->Item(4)->RealValue();
989 m_x3 = expr->Item(5)->RealValue();
990 m_y3 = expr->Item(6)->RealValue();
1fc25a89
JS
991 break;
992 }
993 default:
994 {
995 break;
996 }
997 }
998}
2b5f62a0 999#endif
1fc25a89
JS
1000
1001/*
1002 * Draw polygon, polyline, spline
1003 *
1004 */
1005
1006wxOpPolyDraw::wxOpPolyDraw(int theOp, int n, wxRealPoint *thePoints):wxDrawOp(theOp)
1007{
1008 m_noPoints = n;
1009 m_points = thePoints;
1010}
1011
1012wxOpPolyDraw::~wxOpPolyDraw()
1013{
1014 delete[] m_points;
1015}
1016
1017wxDrawOp *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
1029void 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
1084void 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
1093void 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
1102void 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
2b5f62a0 1113#if wxUSE_PROLOGIO
1fc25a89
JS
1114wxExpr *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 */
c1fa2fda 1131
1fc25a89
JS
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);
c1fa2fda 1140
1fc25a89
JS
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
1157void wxOpPolyDraw::ReadExpr(wxPseudoMetaFile *image, wxExpr *expr)
1158{
b9ac87bc 1159 m_noPoints = (int)expr->Item(1)->IntegerValue();
1fc25a89
JS
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;
b9ac87bc 1167 wxString hexString = expr->Item(2)->StringValue();
1fc25a89
JS
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;
c1fa2fda 1175
1fc25a89
JS
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}
2b5f62a0 1202#endif
1fc25a89
JS
1203
1204// Draw an outline using the current operation.
1205bool 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)
1227bool 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 }
c1fa2fda 1264
1fc25a89
JS
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
c1fa2fda 1276 oglFindEndForPolyline(n, xpoints, ypoints,
1fc25a89
JS
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
1291static 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
1295static 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);
c1fa2fda 1301
1fc25a89
JS
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
1310static 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
1353static 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
1368IMPLEMENT_DYNAMIC_CLASS(wxPseudoMetaFile, wxObject)
1369
1370wxPseudoMetaFile::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
1381wxPseudoMetaFile::wxPseudoMetaFile(wxPseudoMetaFile& mf)
1382{
1383 mf.Copy(*this);
1384}
1385
1386wxPseudoMetaFile::~wxPseudoMetaFile()
1387{
1388 Clear();
1389}
1390
1391void wxPseudoMetaFile::Clear()
1392{
b9ac87bc 1393 wxNode *node = m_ops.GetFirst();
1fc25a89
JS
1394 while (node)
1395 {
b9ac87bc 1396 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89 1397 delete op;
b9ac87bc 1398 node = node->GetNext();
1fc25a89
JS
1399 }
1400 m_ops.Clear();
1401 m_gdiObjects.Clear();
1402 m_outlineColours.Clear();
1403 m_fillColours.Clear();
1404 m_outlineOp = -1;
1405}
1406
1407void wxPseudoMetaFile::Draw(wxDC& dc, double xoffset, double yoffset)
1408{
b9ac87bc 1409 wxNode *node = m_ops.GetFirst();
1fc25a89
JS
1410 while (node)
1411 {
b9ac87bc 1412 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89 1413 op->Do(dc, xoffset, yoffset);
b9ac87bc 1414 node = node->GetNext();
1fc25a89
JS
1415 }
1416}
1417
1418void wxPseudoMetaFile::Scale(double sx, double sy)
1419{
b9ac87bc 1420 wxNode *node = m_ops.GetFirst();
1fc25a89
JS
1421 while (node)
1422 {
b9ac87bc 1423 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89 1424 op->Scale(sx, sy);
b9ac87bc 1425 node = node->GetNext();
1fc25a89
JS
1426 }
1427 m_width *= sx;
1428 m_height *= sy;
1429}
1430
1431void wxPseudoMetaFile::Translate(double x, double y)
1432{
b9ac87bc 1433 wxNode *node = m_ops.GetFirst();
1fc25a89
JS
1434 while (node)
1435 {
b9ac87bc 1436 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89 1437 op->Translate(x, y);
b9ac87bc 1438 node = node->GetNext();
1fc25a89
JS
1439 }
1440}
1441
1442void 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
b9ac87bc 1449 wxNode *node = m_ops.GetFirst();
1fc25a89
JS
1450 while (node)
1451 {
b9ac87bc 1452 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89 1453 op->Rotate(x, y, theta, sinTheta, cosTheta);
b9ac87bc 1454 node = node->GetNext();
1fc25a89
JS
1455 }
1456 m_currentRotation = theta;
1457}
1458
2b5f62a0 1459#if wxUSE_PROLOGIO
1fc25a89
JS
1460void wxPseudoMetaFile::WriteAttributes(wxExpr *clause, int whichAngle)
1461{
1462 wxString widthStr;
c1fa2fda 1463 widthStr.Printf(wxT("meta_width%d"), whichAngle);
1fc25a89
JS
1464
1465 wxString heightStr;
c1fa2fda 1466 heightStr.Printf(wxT("meta_height%d"), whichAngle);
1fc25a89
JS
1467
1468 wxString outlineStr;
c1fa2fda 1469 outlineStr.Printf(wxT("outline_op%d"), whichAngle);
1fc25a89
JS
1470
1471 wxString rotateableStr;
c1fa2fda 1472 rotateableStr.Printf(wxT("meta_rotateable%d"), whichAngle);
1fc25a89
JS
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;
b9ac87bc 1483 wxNode *node = m_gdiObjects.GetFirst();
1fc25a89
JS
1484 while (node)
1485 {
1486 sprintf(buf, "gdi%d_%d", whichAngle, i);
b9ac87bc 1487 wxObject *obj = (wxObject *)node->GetData();
1fc25a89
JS
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 }
b9ac87bc 1536 node = node->GetNext();
1fc25a89
JS
1537 }
1538
1539 // Write drawing operations
1540 i = 1;
b9ac87bc 1541 node = m_ops.GetFirst();
1fc25a89
JS
1542 while (node)
1543 {
1544 sprintf(buf, "op%d_%d", whichAngle, i);
b9ac87bc 1545 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89
JS
1546 wxExpr *expr = op->WriteExpr(this);
1547 if (expr)
1548 {
1549 clause->AddAttributeValue(buf, expr);
1550 i ++;
1551 }
b9ac87bc 1552 node = node->GetNext();
1fc25a89
JS
1553 }
1554
1555 // Write outline and fill GDI op lists (if any)
b9ac87bc 1556 if (m_outlineColours.GetCount() > 0)
1fc25a89
JS
1557 {
1558 wxExpr *outlineExpr = new wxExpr(wxExprList);
b9ac87bc 1559 node = m_outlineColours.GetFirst();
1fc25a89
JS
1560 while (node)
1561 {
b9ac87bc
RD
1562 outlineExpr->Append(new wxExpr((long)node->GetData()));
1563 node = node->GetNext();
1fc25a89
JS
1564 }
1565 wxString outlineObjectsStr;
c1fa2fda 1566 outlineObjectsStr.Printf(wxT("outline_objects%d"), whichAngle);
1fc25a89
JS
1567
1568 clause->AddAttributeValue(outlineObjectsStr, outlineExpr);
1569 }
b9ac87bc 1570 if (m_fillColours.GetCount() > 0)
1fc25a89
JS
1571 {
1572 wxExpr *fillExpr = new wxExpr(wxExprList);
b9ac87bc 1573 node = m_fillColours.GetFirst();
1fc25a89
JS
1574 while (node)
1575 {
b9ac87bc
RD
1576 fillExpr->Append(new wxExpr((long)node->GetData()));
1577 node = node->GetNext();
1fc25a89
JS
1578 }
1579 wxString fillObjectsStr;
c1fa2fda 1580 fillObjectsStr.Printf(wxT("fill_objects%d"), whichAngle);
1fc25a89
JS
1581
1582 clause->AddAttributeValue(fillObjectsStr, fillExpr);
1583 }
c1fa2fda 1584
1fc25a89
JS
1585}
1586
1587void wxPseudoMetaFile::ReadAttributes(wxExpr *clause, int whichAngle)
1588{
1589 wxString widthStr;
c1fa2fda 1590 widthStr.Printf(wxT("meta_width%d"), whichAngle);
1fc25a89
JS
1591
1592 wxString heightStr;
c1fa2fda 1593 heightStr.Printf(wxT("meta_height%d"), whichAngle);
1fc25a89
JS
1594
1595 wxString outlineStr;
c1fa2fda 1596 outlineStr.Printf(wxT("outline_op%d"), whichAngle);
1fc25a89
JS
1597
1598 wxString rotateableStr;
c1fa2fda 1599 rotateableStr.Printf(wxT("meta_rotateable%d"), whichAngle);
1fc25a89
JS
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 {
b9ac87bc 1624 wxExpr *idExpr = expr->Item(0);
1fc25a89
JS
1625 switch (idExpr->IntegerValue())
1626 {
1627 case gyTYPE_PEN:
1628 {
b9ac87bc
RD
1629 int penWidth = (int)expr->Item(1)->IntegerValue();
1630 int penStyle = (int)expr->Item(2)->IntegerValue();
1631 int penRed = (int)expr->Item(3)->IntegerValue();
1632 int penGreen = (int)expr->Item(4)->IntegerValue();
1633 int penBlue = (int)expr->Item(5)->IntegerValue();
1fc25a89
JS
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 {
b9ac87bc
RD
1643 int brushStyle = (int)expr->Item(1)->IntegerValue();
1644 int brushRed = (int)expr->Item(2)->IntegerValue();
1645 int brushGreen = (int)expr->Item(3)->IntegerValue();
1646 int brushBlue = (int)expr->Item(4)->IntegerValue();
1fc25a89
JS
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 {
b9ac87bc
RD
1656 int fontPointSize = (int)expr->Item(1)->IntegerValue();
1657 int fontFamily = (int)expr->Item(2)->IntegerValue();
1658 int fontStyle = (int)expr->Item(3)->IntegerValue();
1659 int fontWeight = (int)expr->Item(4)->IntegerValue();
1660 int fontUnderlined = (int)expr->Item(5)->IntegerValue();
1fc25a89
JS
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 {
b9ac87bc 1690 wxExpr *idExpr = expr->Item(0);
1fc25a89
JS
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 }
c1fa2fda 1706
1fc25a89
JS
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;
c1fa2fda 1746 outlineObjectsStr.Printf(wxT("outline_objects%d"), whichAngle);
1fc25a89
JS
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;
c1fa2fda 1761 fillObjectsStr.Printf(wxT("fill_objects%d"), whichAngle);
1fc25a89
JS
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
1777void 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
b9ac87bc 1790 wxNode *node = m_gdiObjects.GetFirst();
1fc25a89
JS
1791 while (node)
1792 {
b9ac87bc 1793 wxObject *obj = (wxObject *)node->GetData();
1fc25a89 1794 copy.m_gdiObjects.Append(obj);
b9ac87bc 1795 node = node->GetNext();
1fc25a89 1796 }
c1fa2fda 1797
1fc25a89 1798 // Copy the operations
b9ac87bc 1799 node = m_ops.GetFirst();
1fc25a89
JS
1800 while (node)
1801 {
b9ac87bc 1802 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89 1803 copy.m_ops.Append(op->Copy(&copy));
b9ac87bc 1804 node = node->GetNext();
1fc25a89
JS
1805 }
1806
1807 // Copy the outline/fill operations
b9ac87bc 1808 node = m_outlineColours.GetFirst();
1fc25a89
JS
1809 while (node)
1810 {
b9ac87bc
RD
1811 copy.m_outlineColours.Append((wxObject *)node->GetData());
1812 node = node->GetNext();
1fc25a89 1813 }
b9ac87bc 1814 node = m_fillColours.GetFirst();
1fc25a89
JS
1815 while (node)
1816 {
b9ac87bc
RD
1817 copy.m_fillColours.Append((wxObject *)node->GetData());
1818 node = node->GetNext();
1fc25a89
JS
1819 }
1820}
1821
1822/*
1823 * Pass size of existing image; scale height to
1824 * fit width and return new width and height.
1825 *
1826 */
c1fa2fda 1827
9e053640 1828bool wxPseudoMetaFile::LoadFromMetaFile(const wxString& filename, double *rwidth, double *rheight)
1fc25a89 1829{
2b5f62a0 1830 if (!wxFileExists(filename))
b9ac87bc 1831 return FALSE;
c1fa2fda 1832
1fc25a89 1833 wxXMetaFile *metaFile = new wxXMetaFile;
c1fa2fda 1834
1fc25a89
JS
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
b9ac87bc 1845 wxNode *node = metaFile->metaRecords.GetFirst();
1fc25a89
JS
1846 while (node)
1847 {
b9ac87bc 1848 wxMetaRecord *record = (wxMetaRecord *)node->GetData();
1fc25a89
JS
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 }
c1fa2fda 1990
1fc25a89
JS
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 }
c1fa2fda 2004
1fc25a89
JS
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.
b9ac87bc 2020 wxNode *recNode = metaFile->gdiObjects.Item((int)record->param2);
1fc25a89
JS
2021 if (recNode)
2022 {
b9ac87bc 2023 wxMetaRecord *gdiRec = (wxMetaRecord *)recNode->GetData();
1fc25a89
JS
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 }
b9ac87bc 2138 node = node->GetNext();
1fc25a89
JS
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
2179void 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
2188void 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
b9ac87bc 2195 wxNode *node = m_ops.GetFirst();
1fc25a89
JS
2196 while (node)
2197 {
b9ac87bc 2198 wxDrawOp *op = (wxDrawOp *)node->GetData();
1fc25a89
JS
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 }
b9ac87bc 2265 node = node->GetNext();
1fc25a89
JS
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
2279void 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
2298void 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
2306void 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
2314void 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
2324void 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
2332void 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
2343void 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
2359void 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
2367void 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
2377void 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
2390void 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)
b9ac87bc 2403 m_outlineOp = (m_ops.GetCount() - 1);
1fc25a89
JS
2404}
2405
2406void 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
2419void 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
2425void 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
2433void wxPseudoMetaFile::SetPen(wxPen* pen, bool isOutline)
2434{
2435 m_gdiObjects.Append(pen);
b9ac87bc 2436 int n = m_gdiObjects.GetCount();
1fc25a89
JS
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
2448void wxPseudoMetaFile::SetBrush(wxBrush* brush, bool isFill)
2449{
2450 m_gdiObjects.Append(brush);
b9ac87bc 2451 int n = m_gdiObjects.GetCount();
1fc25a89
JS
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
2463void wxPseudoMetaFile::SetFont(wxFont* font)
2464{
2465 m_gdiObjects.Append(font);
b9ac87bc 2466 int n = m_gdiObjects.GetCount();
1fc25a89
JS
2467
2468 wxOpSetGDI* theOp = new wxOpSetGDI(DRAWOP_SET_FONT, this, n - 1);
2469
2470 m_ops.Append(theOp);
2471}
2472
2473void 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
2483void 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
2493void 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