OS/2 fixes
[wxWidgets.git] / src / os2 / dc.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dc.cpp
3 // Purpose: wxDC class
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/14/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifndef WX_PRECOMP
16 #include "wx/window.h"
17 #include "wx/dc.h"
18 #include "wx/utils.h"
19 #include "wx/dialog.h"
20 #include "wx/app.h"
21 #include "wx/bitmap.h"
22 #include "wx/dcmemory.h"
23 #include "wx/log.h"
24 #include "wx/icon.h"
25 #endif
26
27 #include "wx/dcprint.h"
28
29 #include <string.h>
30 #include <math.h>
31
32 #include "wx/os2/private.h"
33
34 IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
35
36 // ---------------------------------------------------------------------------
37 // constants
38 // ---------------------------------------------------------------------------
39
40 static const int VIEWPORT_EXTENT = 1000;
41
42 static const int MM_POINTS = 9;
43 static const int MM_METRIC = 10;
44
45 // usually this is defined in math.h
46 #ifndef M_PI
47 static const double M_PI = 3.14159265358979323846;
48 #endif // M_PI
49
50 // ---------------------------------------------------------------------------
51 // private functions
52 // ---------------------------------------------------------------------------
53
54 // convert degrees to radians
55 static inline double DegToRad(double deg) { return (deg * M_PI) / 180.0; }
56
57 int SetTextColor(
58 HPS hPS
59 , int nForegroundColour
60 )
61 {
62 CHARBUNDLE vCbnd;
63
64 vCbnd.lColor = nForegroundColour;
65 ::GpiSetAttrs( hPS // presentation-space handle
66 ,PRIM_CHAR // Char primitive.
67 ,CBB_COLOR // sets color.
68 ,0 //
69 ,&vCbnd // buffer for attributes.
70 );
71 return 0;
72 }
73
74 int QueryTextBkColor(
75 HPS hPS
76 )
77 {
78 CHARBUNDLE vCbnd;
79
80 ::GpiQueryAttrs( hPS // presentation-space handle
81 ,PRIM_CHAR // Char primitive.
82 ,CBB_BACK_COLOR // Background color.
83 ,&vCbnd // buffer for attributes.
84 );
85 return vCbnd.lBackColor;
86 }
87
88
89 int SetTextBkColor(
90 HPS hPS
91 , int nBackgroundColour
92 )
93 {
94 CHARBUNDLE vCbnd;
95 int rc;
96
97 rc = QueryTextBkColor(hPS);
98
99 vCbnd.lBackColor = nBackgroundColour;
100 ::GpiSetAttrs(hPS, // presentation-space handle
101 PRIM_CHAR, // Char primitive.
102 CBB_BACK_COLOR, // sets color.
103 0,
104 &vCbnd // buffer for attributes.
105 );
106 return rc;
107 }
108
109 int SetBkMode(
110 HPS hPS
111 , int nBackgroundMode
112 )
113 {
114 if(nBackgroundMode == wxTRANSPARENT)
115 ::GpiSetBackMix( hPS
116 ,BM_LEAVEALONE
117 );
118 else
119 // the background of the primitive takes over whatever is underneath.
120 ::GpiSetBackMix( hPS
121 ,BM_OVERPAINT
122 );
123 return 0;
124 }
125
126 // ===========================================================================
127 // implementation
128 // ===========================================================================
129
130 // ---------------------------------------------------------------------------
131 // wxDC
132 // ---------------------------------------------------------------------------
133
134 wxDC::wxDC(void)
135 {
136 m_pCanvas = NULL;
137
138 m_hOldBitmap = 0;
139 m_hOldPen = 0;
140 m_hOldBrush = 0;
141 m_hOldFont = 0;
142 m_hOldPalette = 0;
143
144 m_bOwnsDC = FALSE;
145 m_hDC = 0;
146 m_nDCCount = 0;
147 m_hOldPS = NULL;
148 m_hPS = NULL;
149 m_bIsPaintTime = FALSE;// True at Paint Time
150 };
151
152 wxDC::~wxDC(void)
153 {
154 // TODO:
155 };
156
157 // This will select current objects out of the DC,
158 // which is what you have to do before deleting the
159 // DC.
160 void wxDC::SelectOldObjects(WXHDC dc)
161 {
162 if (dc)
163 {
164 if (m_hOldBitmap)
165 {
166 // ::SelectObject((HDC) dc, (HBITMAP) m_oldBitmap);
167 if (m_vSelectedBitmap.Ok())
168 {
169 m_vSelectedBitmap.SetSelectedInto(NULL);
170 }
171 }
172 m_hOldBitmap = 0;
173 if (m_hOldPen)
174 {
175 // ::SelectObject((HDC) dc, (HPEN) m_oldPen);
176 }
177 m_hOldPen = 0;
178 if (m_hOldBrush)
179 {
180 // ::SelectObject((HDC) dc, (HBRUSH) m_oldBrush);
181 }
182 m_hOldBrush = 0;
183 if (m_hOldFont)
184 {
185 // ::SelectObject((HDC) dc, (HFONT) m_oldFont);
186 }
187 m_hOldFont = 0;
188 if (m_hOldPalette)
189 {
190 // ::SelectPalette((HDC) dc, (HPALETTE) m_oldPalette, TRUE);
191 }
192 m_hOldPalette = 0;
193 }
194
195 m_brush = wxNullBrush;
196 m_pen = wxNullPen;
197 m_palette = wxNullPalette;
198 m_font = wxNullFont;
199 m_backgroundBrush = wxNullBrush;
200 m_vSelectedBitmap = wxNullBitmap;
201 }
202
203 // ---------------------------------------------------------------------------
204 // clipping
205 // ---------------------------------------------------------------------------
206
207 #define DO_SET_CLIPPING_BOX() \
208 { \
209 RECT rect; \
210 \
211 GetClipBox(GetHdc(), &rect); \
212 \
213 m_clipX1 = (wxCoord) XDEV2LOG(rect.left); \
214 m_clipY1 = (wxCoord) YDEV2LOG(rect.top); \
215 m_clipX2 = (wxCoord) XDEV2LOG(rect.right); \
216 m_clipY2 = (wxCoord) YDEV2LOG(rect.bottom); \
217 }
218
219 void wxDC::DoSetClippingRegion( wxCoord x, wxCoord y
220 ,wxCoord width, wxCoord height
221 )
222 {
223 // TODO
224 }
225
226 void wxDC::DoSetClippingRegionAsRegion(const wxRegion& region)
227 {
228 // TODO
229 }
230
231 void wxDC::DestroyClippingRegion(void)
232 {
233 // TODO:
234 };
235
236 // ---------------------------------------------------------------------------
237 // query capabilities
238 // ---------------------------------------------------------------------------
239
240 bool wxDC::CanDrawBitmap() const
241 {
242 return TRUE;
243 }
244
245 bool wxDC::CanGetTextExtent() const
246 {
247 // What sort of display is it?
248 int technology = 0; // TODO: ::GetDeviceCaps(GetHdc(), TECHNOLOGY);
249
250 // TODO: return (technology == DT_RASDISPLAY) || (technology == DT_RASPRINTER);
251 return FALSE;
252 }
253
254 int wxDC::GetDepth() const
255 {
256 // TODO:
257 return (1);
258 }
259
260 // ---------------------------------------------------------------------------
261 // drawing
262 // ---------------------------------------------------------------------------
263
264 void wxDC::Clear()
265 {
266 // TODO
267 }
268
269 void wxDC::DoFloodFill( wxCoord x
270 ,wxCoord y
271 ,const wxColour& col
272 ,int style
273 )
274 {
275 // TODO
276 }
277
278 bool wxDC::DoGetPixel(wxCoord x, wxCoord y, wxColour *col) const
279 {
280 // TODO
281 return(TRUE);
282 }
283
284 void wxDC::DoCrossHair(wxCoord x, wxCoord y)
285 {
286 // TODO
287 }
288
289 void wxDC::DoDrawLine(
290 wxCoord vX1
291 , wxCoord vY1
292 , wxCoord vX2
293 , wxCoord vY2
294 )
295 {
296 POINTL vPoint[2];
297
298 vPoint[0].x = vX1;
299 vPoint[0].y = vY1;
300 vPoint[1].x = vX2;
301 vPoint[1].y = vY2;
302 // ::GpiSetColor(m_hPS,CLR_RED); //DEbug
303 ::GpiMove(m_hPS, &vPoint[0]);
304 ::GpiLine(m_hPS, &vPoint[1]);
305 }
306
307 void wxDC::DoDrawArc( wxCoord x1, wxCoord y1
308 ,wxCoord x2, wxCoord y2
309 ,wxCoord xc, wxCoord yc
310 )
311 {
312 // TODO
313 }
314
315 void wxDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
316 wxCoord width, wxCoord height)
317 {
318 // TODO
319 }
320
321 void wxDC::DoDrawPoint(wxCoord x, wxCoord y)
322 {
323 // TODO
324 }
325
326 void wxDC::DoDrawPolygon(int n, wxPoint points[]
327 ,wxCoord xoffset, wxCoord yoffset
328 ,int fillStyle
329 )
330 {
331 // TODO
332 }
333
334 void wxDC::DoDrawLines( int n, wxPoint points[]
335 ,wxCoord xoffset, wxCoord yoffset
336 )
337 {
338 // TODO
339 }
340
341 void wxDC::DoDrawRectangle(
342 wxCoord vX
343 , wxCoord vY
344 , wxCoord vWidth
345 , wxCoord vHeight
346 )
347 {
348 POINTL vPoint[2];
349
350 vPoint[0].x = vX;
351 vPoint[0].y = vY;
352 vPoint[1].x = vX + vWidth;
353 vPoint[1].y = vY - vHeight; //mustdie !!! ??
354
355 ::GpiMove(m_hPS, &vPoint[0]);
356 ::GpiBox( m_hPS // handle to a presentation space
357 ,DRO_OUTLINE // draw the box outline ? or ?
358 ,&vPoint[1] // address of the corner
359 ,0L // horizontal corner radius
360 ,0L // vertical corner radius
361 );
362 }
363
364 void wxDC::DoDrawRoundedRectangle(
365 wxCoord vX
366 , wxCoord vY
367 , wxCoord vWidth
368 , wxCoord vHeight
369 , double dRadius
370 )
371 {
372 POINTL vPoint[2];
373
374 vPoint[0].x = vX;
375 vPoint[0].y = vY;
376 vPoint[1].x = vX + vWidth;
377 vPoint[1].y = vY + vHeight; //or -height aka mustdie !!! ??
378
379 ::GpiMove(m_hPS, &vPoint[0]);
380 ::GpiBox( m_hPS // handle to a presentation space
381 ,DRO_OUTLINE // draw the box outline ? or ?
382 ,&vPoint[1] // address of the corner
383 ,(LONG)dRadius // horizontal corner radius
384 ,(LONG)dRadius // vertical corner radius
385 );
386 }
387
388 void wxDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord width, wxCoord height)
389 {
390 // TODO
391 }
392
393 void wxDC::DoDrawEllipticArc( wxCoord x
394 ,wxCoord y
395 ,wxCoord w
396 ,wxCoord h
397 ,double sa
398 ,double ea
399 )
400 {
401 // TODO
402 }
403
404 void wxDC::DoDrawIcon(const wxIcon& icon, wxCoord x, wxCoord y)
405 {
406 // TODO
407 }
408
409 void wxDC::DoDrawBitmap( const wxBitmap &bmp
410 ,wxCoord x, wxCoord y
411 ,bool useMask
412 )
413 {
414 // TODO
415 }
416
417 void wxDC::DoDrawText(
418 const wxString& rsText
419 , wxCoord vX
420 , wxCoord vY
421 )
422 {
423 DrawAnyText( rsText
424 ,vX
425 ,vY
426 );
427 }
428
429 void wxDC::DrawAnyText(
430 const wxString& rsText
431 , wxCoord vX
432 , wxCoord vY
433 )
434 {
435 int nOldBackground = 0;
436 POINTL vPtlStart;
437 LONG lHits;
438
439 //
440 // prepare for drawing the text
441 //
442
443 //
444 // Set text color attributes
445 //
446 if (m_textForegroundColour.Ok())
447 {
448 SetTextColor( m_hPS
449 ,(int)m_textForegroundColour.GetPixel()
450 );
451 }
452
453 if (m_textBackgroundColour.Ok())
454 {
455 nOldBackground = SetTextBkColor( m_hPS
456 ,(int)m_textBackgroundColour.GetPixel()
457 );
458 }
459 SetBkMode( m_hPS
460 ,m_backgroundMode
461 );
462 vPtlStart.x = vX;
463 vPtlStart.y = vY;
464
465 lHits = ::GpiCharStringAt( m_hPS
466 ,&vPtlStart
467 ,rsText.length()
468 ,(PCH)rsText.c_str()
469 );
470 if (lHits != GPI_OK)
471 {
472 wxLogLastError(wxT("TextOut"));
473 }
474
475 //
476 // Restore the old parameters (text foreground colour may be left because
477 // it never is set to anything else, but background should remain
478 // transparent even if we just drew an opaque string)
479 //
480 if (m_textBackgroundColour.Ok())
481 SetTextBkColor( m_hPS
482 ,nOldBackground
483 );
484 SetBkMode( m_hPS
485 ,wxTRANSPARENT
486 );
487 }
488
489 void wxDC::DoDrawRotatedText(
490 const wxString& rsText
491 , wxCoord vX
492 , wxCoord vY
493 , double dAngle
494 )
495 {
496 if (dAngle == 0.0)
497 {
498 DoDrawText( rsText
499 ,vX
500 ,vY
501 );
502 }
503
504 // TODO:
505 /*
506 if ( angle == 0.0 )
507 {
508 DoDrawText(text, x, y);
509 }
510 else
511 {
512 LOGFONT lf;
513 wxFillLogFont(&lf, &m_font);
514
515 // GDI wants the angle in tenth of degree
516 long angle10 = (long)(angle * 10);
517 lf.lfEscapement = angle10;
518 lf. lfOrientation = angle10;
519
520 HFONT hfont = ::CreateFontIndirect(&lf);
521 if ( !hfont )
522 {
523 wxLogLastError("CreateFont");
524 }
525 else
526 {
527 HFONT hfontOld = ::SelectObject(GetHdc(), hfont);
528
529 DrawAnyText(text, x, y);
530
531 (void)::SelectObject(GetHdc(), hfontOld);
532 }
533
534 // call the bounding box by adding all four vertices of the rectangle
535 // containing the text to it (simpler and probably not slower than
536 // determining which of them is really topmost/leftmost/...)
537 wxCoord w, h;
538 GetTextExtent(text, &w, &h);
539
540 double rad = DegToRad(angle);
541
542 // "upper left" and "upper right"
543 CalcBoundingBox(x, y);
544 CalcBoundingBox(x + w*cos(rad), y - h*sin(rad));
545 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
546
547 // "bottom left" and "bottom right"
548 x += (wxCoord)(h*sin(rad));
549 y += (wxCoord)(h*cos(rad));
550 CalcBoundingBox(x, y);
551 CalcBoundingBox(x + h*sin(rad), y + h*cos(rad));
552 }
553 */
554 }
555
556 // ---------------------------------------------------------------------------
557 // set GDI objects
558 // ---------------------------------------------------------------------------
559
560 void wxDC::SetPalette(const wxPalette& palette)
561 {
562 // TODO
563 }
564
565 void wxDC::SetFont(
566 const wxFont& rFont
567 )
568 {
569 //
570 // Set the old object temporarily, in case the assignment deletes an object
571 // that's not yet selected out.
572 //
573 if (m_hOldFont)
574 {
575 // ::SelectObject(GetHdc(), (HFONT) m_hOldFont);
576 m_hOldFont = 0;
577 }
578
579 m_font = rFont;
580
581 if (!rFont.Ok())
582 {
583 if (m_hOldFont)
584 // ::SelectObject(GetHdc(), (HFONT) m_hOldFont);
585 m_hOldFont = 0;
586 }
587
588 if (m_font.Ok() && m_font.GetResourceHandle())
589 {
590 HFONT hFont = (HFONT)0; //::SelectObject(GetHdc(), (HFONT) m_font.GetResourceHandle());
591 if (hFont == (HFONT) NULL)
592 {
593 wxLogDebug(wxT("::SelectObject failed in wxDC::SetFont."));
594 }
595 if (!m_hOldFont)
596 m_hOldFont = (WXHFONT) hFont;
597 }
598 }
599
600 void wxDC::SetPen(
601 const wxPen& rPen
602 )
603 {
604 wxCHECK_RET( Ok(), wxT("invalid window dc") );
605
606 if (m_pen == rPen)
607 return;
608 m_pen = rPen;
609 if (!m_pen.Ok())
610 return;
611
612 int nWidth = m_pen.GetWidth();
613
614 if (nWidth <= 0)
615 {
616 nWidth = 1;
617 }
618 else
619 {
620 double dW = 0.5 +
621 ( fabs((double) XLOG2DEVREL(nWidth)) +
622 fabs((double) YLOG2DEVREL(nWidth))
623 ) / 2.0;
624 nWidth = (int)dW;
625 }
626 wxColour vColor = m_pen.GetColour();
627
628 ::GpiSetColor( m_hPS
629 ,vColor.GetPixel()
630 ); //DEbug ??
631 }
632
633 void wxDC::SetBrush(const wxBrush& brush)
634 {
635 // TODO
636 }
637
638 void wxDC::SetBackground(const wxBrush& brush)
639 {
640 // TODO
641 }
642
643 void wxDC::SetBackgroundMode(
644 int nMode
645 )
646 {
647 m_backgroundMode = nMode;
648 }
649
650 void wxDC::SetLogicalFunction(int function)
651 {
652 // TODO
653 }
654
655 void wxDC::SetRop(WXHDC dc)
656 {
657 if (!dc || m_logicalFunction < 0)
658 return;
659
660 int c_rop;
661 // These may be wrong
662 switch (m_logicalFunction)
663 {
664 // TODO: Figure this stuff out
665 // case wxXOR: c_rop = R2_XORPEN; break;
666 // case wxXOR: c_rop = R2_NOTXORPEN; break;
667 // case wxINVERT: c_rop = R2_NOT; break;
668 // case wxOR_REVERSE: c_rop = R2_MERGEPENNOT; break;
669 // case wxAND_REVERSE: c_rop = R2_MASKPENNOT; break;
670 // case wxCLEAR: c_rop = R2_WHITE; break;
671 // case wxSET: c_rop = R2_BLACK; break;
672 // case wxSRC_INVERT: c_rop = R2_NOTCOPYPEN; break;
673 // case wxOR_INVERT: c_rop = R2_MERGENOTPEN; break;
674 // case wxAND: c_rop = R2_MASKPEN; break;
675 // case wxOR: c_rop = R2_MERGEPEN; break;
676 // case wxAND_INVERT: c_rop = R2_MASKNOTPEN; break;
677 // case wxEQUIV:
678 // case wxNAND:
679 // case wxCOPY:
680 default:
681 // c_rop = R2_COPYPEN;
682 break;
683 }
684 // SetROP2((HDC) dc, c_rop);
685 }
686
687 bool wxDC::StartDoc(const wxString& message)
688 {
689 // We might be previewing, so return TRUE to let it continue.
690 return TRUE;
691 }
692
693 void wxDC::EndDoc()
694 {
695 }
696
697 void wxDC::StartPage()
698 {
699 }
700
701 void wxDC::EndPage()
702 {
703 }
704
705 // ---------------------------------------------------------------------------
706 // text metrics
707 // ---------------------------------------------------------------------------
708
709 wxCoord wxDC::GetCharHeight() const
710 {
711 // TODO
712 return(8);
713 }
714
715 wxCoord wxDC::GetCharWidth() const
716 {
717 // TODO
718 return(8);
719 }
720
721 void wxDC::DoGetTextExtent(
722 const wxString& rsString
723 , wxCoord* pvX
724 , wxCoord* pvY
725 , wxCoord* pvDescent
726 , wxCoord* pvExternalLeading
727 , wxFont* pTheFont
728 ) const
729 {
730 POINTL avPoint[TXTBOX_COUNT];
731 POINTL vPtMin;
732 POINTL vPtMax;
733 int i;
734 int l;
735 FONTMETRICS vFM; // metrics structure
736 BOOL bRc;
737 char* pStr;
738 ERRORID vErrorCode; // last error id code
739 wxFont* pFontToUse = (wxFont*)pTheFont;
740
741 if (!pFontToUse)
742 pFontToUse = (wxFont*)&m_font;
743 l = rsString.length();
744 pStr = (PCH) rsString.c_str();
745
746 //
747 // In world coordinates.
748 //
749 bRc = ::GpiQueryTextBox( m_hPS
750 ,l
751 ,pStr
752 ,TXTBOX_COUNT // return maximum information
753 ,avPoint // array of coordinates points
754 );
755 if(!bRc)
756 {
757 vErrorCode = ::WinGetLastError(wxGetInstance());
758 }
759
760 vPtMin.x = avPoint[0].x;
761 vPtMax.x = avPoint[0].x;
762 vPtMin.y = avPoint[0].y;
763 vPtMax.y = avPoint[0].y;
764 for (i = 1; i < 4; i++)
765 {
766 if(vPtMin.x > avPoint[i].x) vPtMin.x = avPoint[i].x;
767 if(vPtMin.y > avPoint[i].y) vPtMin.y = avPoint[i].y;
768 if(vPtMax.x < avPoint[i].x) vPtMax.x = avPoint[i].x;
769 if(vPtMax.y < avPoint[i].y) vPtMax.y = avPoint[i].y;
770 }
771 ::GpiQueryFontMetrics( m_hPS
772 ,sizeof(FONTMETRICS)
773 ,&vFM
774 );
775
776 if (pvX)
777 *pvX = (wxCoord)(vPtMax.x - vPtMin.x + 1);
778 if (pvY)
779 *pvY = (wxCoord)(vPtMax.y - vPtMin.y + 1);
780 if (pvDescent)
781 *pvDescent = vFM.lMaxDescender;
782 if (pvExternalLeading)
783 *pvExternalLeading = vFM.lExternalLeading;
784 }
785
786 void wxDC::SetMapMode( int mode )
787 {
788 // TODO:
789 };
790
791 void wxDC::SetUserScale(double x, double y)
792 {
793 m_userScaleX = x;
794 m_userScaleY = y;
795
796 SetMapMode(m_mappingMode);
797 }
798
799 void wxDC::SetAxisOrientation(bool xLeftRight, bool yBottomUp)
800 {
801 m_signX = xLeftRight ? 1 : -1;
802 m_signY = yBottomUp ? -1 : 1;
803
804 SetMapMode(m_mappingMode);
805 }
806
807 void wxDC::SetSystemScale(double x, double y)
808 {
809 m_scaleX = x;
810 m_scaleY = y;
811
812 SetMapMode(m_mappingMode);
813 }
814
815 void wxDC::SetLogicalOrigin( wxCoord x, wxCoord y )
816 {
817 // TODO:
818 };
819
820 void wxDC::SetDeviceOrigin( wxCoord x, wxCoord y )
821 {
822 // TODO:
823 };
824
825 // ---------------------------------------------------------------------------
826 // coordinates transformations
827 // ---------------------------------------------------------------------------
828
829 wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
830 {
831 return (wxCoord) (((x) - m_deviceOriginX)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX) - m_logicalOriginX);
832 }
833
834 wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
835 {
836 return (wxCoord) ((x)/(m_logicalScaleX*m_userScaleX*m_signX*m_scaleX));
837 }
838
839 wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
840 {
841 return (wxCoord) (((y) - m_deviceOriginY)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY) - m_logicalOriginY);
842 }
843
844 wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
845 {
846 return (wxCoord) ((y)/(m_logicalScaleY*m_userScaleY*m_signY*m_scaleY));
847 }
848
849 wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
850 {
851 return (wxCoord) ((x - m_logicalOriginX)*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX + m_deviceOriginX);
852 }
853
854 wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
855 {
856 return (wxCoord) (x*m_logicalScaleX*m_userScaleX*m_signX*m_scaleX);
857 }
858
859 wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
860 {
861 return (wxCoord) ((y - m_logicalOriginY)*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY + m_deviceOriginY);
862 }
863
864 wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
865 {
866 return (wxCoord) (y*m_logicalScaleY*m_userScaleY*m_signY*m_scaleY);
867 }
868
869 // ---------------------------------------------------------------------------
870 // bit blit
871 // ---------------------------------------------------------------------------
872
873 bool wxDC::DoBlit( wxCoord xdest
874 ,wxCoord ydest
875 ,wxCoord width
876 ,wxCoord height
877 ,wxDC *source
878 ,wxCoord xsrc
879 ,wxCoord ysrc
880 ,int rop
881 ,bool useMask
882 )
883 {
884 // TODO
885 return(TRUE);
886 }
887
888 void wxDC::DoGetSize( int* width, int* height ) const
889 {
890 // TODO:
891 };
892
893 void wxDC::DoGetSizeMM( int* width, int* height ) const
894 {
895 // TODO:
896 };
897
898 wxSize wxDC::GetPPI() const
899 {
900 int x = 1;
901 int y = 1;
902 // TODO:
903 return (wxSize(x,y));
904 }
905
906 void wxDC::SetLogicalScale( double x, double y )
907 {
908 // TODO:
909 };
910
911 #if WXWIN_COMPATIBILITY
912 void wxDC::DoGetTextExtent(const wxString& string, float *x, float *y,
913 float *descent, float *externalLeading,
914 wxFont *theFont, bool use16bit) const
915 {
916 wxCoord x1, y1, descent1, externalLeading1;
917 GetTextExtent(string, & x1, & y1, & descent1, & externalLeading1, theFont, use16bit);
918 *x = x1; *y = y1;
919 if (descent)
920 *descent = descent1;
921 if (externalLeading)
922 *externalLeading = externalLeading1;
923 }
924 #endif
925
926 // ---------------------------------------------------------------------------
927 // spline drawing code
928 // ---------------------------------------------------------------------------
929
930 #if wxUSE_SPLINES
931
932 class wxSpline: public wxObject
933 {
934 public:
935 int type;
936 wxList *points;
937
938 wxSpline(wxList *list);
939 void DeletePoints();
940
941 // Doesn't delete points
942 ~wxSpline();
943 };
944
945 void wx_draw_open_spline(wxDC *dc, wxSpline *spline);
946
947 void wx_quadratic_spline(double a1, double b1, double a2, double b2,
948 double a3, double b3, double a4, double b4);
949 void wx_clear_stack();
950 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
951 double *y3, double *x4, double *y4);
952 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
953 double x4, double y4);
954 static bool wx_spline_add_point(double x, double y);
955 static void wx_spline_draw_point_array(wxDC *dc);
956 wxSpline *wx_make_spline(int x1, int y1, int x2, int y2, int x3, int y3);
957
958 void wxDC::DoDrawSpline(wxList *list)
959 {
960 wxSpline spline(list);
961
962 wx_draw_open_spline(this, &spline);
963 }
964
965 wxList wx_spline_point_list;
966
967 void wx_draw_open_spline(wxDC *dc, wxSpline *spline)
968 {
969 wxPoint *p;
970 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
971 double x1, y1, x2, y2;
972
973 wxNode *node = spline->points->First();
974 p = (wxPoint *)node->Data();
975
976 x1 = p->x;
977 y1 = p->y;
978
979 node = node->Next();
980 p = (wxPoint *)node->Data();
981
982 x2 = p->x;
983 y2 = p->y;
984 cx1 = (double)((x1 + x2) / 2);
985 cy1 = (double)((y1 + y2) / 2);
986 cx2 = (double)((cx1 + x2) / 2);
987 cy2 = (double)((cy1 + y2) / 2);
988
989 wx_spline_add_point(x1, y1);
990
991 while ((node = node->Next()) != NULL)
992 {
993 p = (wxPoint *)node->Data();
994 x1 = x2;
995 y1 = y2;
996 x2 = p->x;
997 y2 = p->y;
998 cx4 = (double)(x1 + x2) / 2;
999 cy4 = (double)(y1 + y2) / 2;
1000 cx3 = (double)(x1 + cx4) / 2;
1001 cy3 = (double)(y1 + cy4) / 2;
1002
1003 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1004
1005 cx1 = cx4;
1006 cy1 = cy4;
1007 cx2 = (double)(cx1 + x2) / 2;
1008 cy2 = (double)(cy1 + y2) / 2;
1009 }
1010
1011 wx_spline_add_point((double)wx_round(cx1), (double)wx_round(cy1));
1012 wx_spline_add_point(x2, y2);
1013
1014 wx_spline_draw_point_array(dc);
1015
1016 }
1017
1018 /********************* CURVES FOR SPLINES *****************************
1019
1020 The following spline drawing routine is from
1021
1022 "An Algorithm for High-Speed Curve Generation"
1023 by George Merrill Chaikin,
1024 Computer Graphics and Image Processing, 3, Academic Press,
1025 1974, 346-349.
1026
1027 and
1028
1029 "On Chaikin's Algorithm" by R. F. Riesenfeld,
1030 Computer Graphics and Image Processing, 4, Academic Press,
1031 1975, 304-310.
1032
1033 ***********************************************************************/
1034
1035 #define half(z1, z2) ((z1+z2)/2.0)
1036 #define THRESHOLD 5
1037
1038 /* iterative version */
1039
1040 void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1041 double b4)
1042 {
1043 register double xmid, ymid;
1044 double x1, y1, x2, y2, x3, y3, x4, y4;
1045
1046 wx_clear_stack();
1047 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1048
1049 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1050 xmid = (double)half(x2, x3);
1051 ymid = (double)half(y2, y3);
1052 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1053 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1054 wx_spline_add_point((double)wx_round(x1), (double)wx_round(y1));
1055 wx_spline_add_point((double)wx_round(xmid), (double)wx_round(ymid));
1056 } else {
1057 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1058 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1059 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1060 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1061 }
1062 }
1063 }
1064
1065
1066 /* utilities used by spline drawing routines */
1067
1068
1069 typedef struct wx_spline_stack_struct {
1070 double x1, y1, x2, y2, x3, y3, x4, y4;
1071 }
1072 Stack;
1073
1074 #define SPLINE_STACK_DEPTH 20
1075 static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1076 static Stack *wx_stack_top;
1077 static int wx_stack_count;
1078
1079 void wx_clear_stack()
1080 {
1081 wx_stack_top = wx_spline_stack;
1082 wx_stack_count = 0;
1083 }
1084
1085 void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1086 {
1087 wx_stack_top->x1 = x1;
1088 wx_stack_top->y1 = y1;
1089 wx_stack_top->x2 = x2;
1090 wx_stack_top->y2 = y2;
1091 wx_stack_top->x3 = x3;
1092 wx_stack_top->y3 = y3;
1093 wx_stack_top->x4 = x4;
1094 wx_stack_top->y4 = y4;
1095 wx_stack_top++;
1096 wx_stack_count++;
1097 }
1098
1099 int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1100 double *x3, double *y3, double *x4, double *y4)
1101 {
1102 if (wx_stack_count == 0)
1103 return (0);
1104 wx_stack_top--;
1105 wx_stack_count--;
1106 *x1 = wx_stack_top->x1;
1107 *y1 = wx_stack_top->y1;
1108 *x2 = wx_stack_top->x2;
1109 *y2 = wx_stack_top->y2;
1110 *x3 = wx_stack_top->x3;
1111 *y3 = wx_stack_top->y3;
1112 *x4 = wx_stack_top->x4;
1113 *y4 = wx_stack_top->y4;
1114 return (1);
1115 }
1116
1117 static bool wx_spline_add_point(double x, double y)
1118 {
1119 wxPoint *point = new wxPoint;
1120 point->x = (int) x;
1121 point->y = (int) y;
1122 wx_spline_point_list.Append((wxObject*)point);
1123 return TRUE;
1124 }
1125
1126 static void wx_spline_draw_point_array(wxDC *dc)
1127 {
1128 dc->DrawLines(&wx_spline_point_list, 0, 0);
1129 wxNode *node = wx_spline_point_list.First();
1130 while (node)
1131 {
1132 wxPoint *point = (wxPoint *)node->Data();
1133 delete point;
1134 delete node;
1135 node = wx_spline_point_list.First();
1136 }
1137 }
1138
1139 wxSpline::wxSpline(wxList *list)
1140 {
1141 points = list;
1142 }
1143
1144 wxSpline::~wxSpline()
1145 {
1146 }
1147
1148 void wxSpline::DeletePoints()
1149 {
1150 for(wxNode *node = points->First(); node; node = points->First())
1151 {
1152 wxPoint *point = (wxPoint *)node->Data();
1153 delete point;
1154 delete node;
1155 }
1156 delete points;
1157 }
1158
1159
1160 #endif // wxUSE_SPLINES
1161