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