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