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