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