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