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