]> git.saurik.com Git - wxWidgets.git/blame - src/common/dcbase.cpp
vc6 did not like this (void function returning a value)
[wxWidgets.git] / src / common / dcbase.cpp
CommitLineData
dbe94982 1/////////////////////////////////////////////////////////////////////////////
06052f3f 2// Name: src/common/dcbase.cpp
1e6feb95
VZ
3// Purpose: generic methods of the wxDC Class
4// Author: Vadim Zeitlin
dbe94982
BM
5// Modified by:
6// Created: 05/25/99
7// RCS-ID: $Id$
77ffb593 8// Copyright: (c) wxWidgets team
65571936 9// Licence: wxWindows licence
dbe94982
BM
10/////////////////////////////////////////////////////////////////////////////
11
1e6feb95
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
1e6feb95
VZ
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
dbe94982
BM
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
bd1e9c12 24 #pragma hdrstop
dbe94982
BM
25#endif
26
dbe94982 27#include "wx/dc.h"
ab171e95
RR
28#include "wx/dcclient.h"
29#include "wx/dcmemory.h"
30#include "wx/dcscreen.h"
653752be 31#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS
18680f86
WS
32
33#ifndef WX_PRECOMP
34 #include "wx/math.h"
35#endif
dbe94982 36
2970ae54
RR
37
38
39#if wxUSE_NEW_DC
40
41//----------------------------------------------------------------------------
42// wxDCFactory
43//----------------------------------------------------------------------------
44
45wxDCFactory *wxDCFactory::m_factory = NULL;
46
47void wxDCFactory::SetDCFactory( wxDCFactory *factory )
48{
49 if (wxDCFactory::m_factory)
50 delete wxDCFactory::m_factory;
51
52 wxDCFactory::m_factory = factory;
53}
54
55wxDCFactory *wxDCFactory::GetFactory()
56{
57 if (!wxDCFactory::m_factory)
58 wxDCFactory::m_factory = new wxNativeDCFactory;
59
60 return wxDCFactory::m_factory;
61}
62
63//-----------------------------------------------------------------------------
64// wxNativeDCFactory
65//-----------------------------------------------------------------------------
66
ab171e95 67wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner )
2970ae54
RR
68{
69#if defined(__WXMSW__)
ab171e95 70 return new wxWindowsWindowImplDC( owner );
2970ae54 71#elif defined(__WXGTK20__)
ab171e95 72 return new wxGTKWindowImplDC( owner );
2970ae54 73#elif defined(__WXGTK__)
ab171e95 74 return new wxGTKWindowImplDC( owner );
2970ae54 75#elif defined(__WXMAC__)
ab171e95 76 return new wxMacWindowImplDC( owner );
2970ae54 77#elif defined(__WXCOCOA__)
ab171e95 78 return new wxCocoaWindowImplDC( owner );
2970ae54 79#elif defined(__WXMOTIF__)
ab171e95 80 return new wxMotifWindowImplDC( owner );
2970ae54 81#elif defined(__WXX11__)
ab171e95 82 return new wxX11WindowImplDC( owner );
2970ae54 83#elif defined(__WXMGL__)
ab171e95 84 return new wxMGLWindowImplDC( owner );
2970ae54 85#elif defined(__WXDFB__)
ab171e95 86 return new wxDFBWindowImplDC( owner );
2970ae54 87#elif defined(__WXPM__)
ab171e95 88 return new wxPMWindowImplDC( owner );
2970ae54 89#elif defined(__PALMOS__)
ab171e95 90 return new wxPalmWindowImplDC( owner );
2970ae54
RR
91#endif
92}
93
ab171e95 94wxImplDC* wxNativeDCFactory::CreateWindowDC( wxWindowDC *owner, wxWindow *window )
2970ae54
RR
95{
96#if defined(__WXMSW__)
ab171e95 97 return new wxWindowsWindowImplDC( owner, window );
2970ae54 98#elif defined(__WXGTK20__)
ab171e95 99 return new wxGTKWindowImplDC( owner, window );
2970ae54 100#elif defined(__WXGTK__)
ab171e95 101 return new wxGTKWindowImplDC( owner, window );
2970ae54 102#elif defined(__WXMAC__)
ab171e95 103 return new wxMacWindowImplDC( owner, window );
2970ae54 104#elif defined(__WXCOCOA__)
ab171e95 105 return new wxCocoaWindowImplDC( owner, window );
2970ae54 106#elif defined(__WXMOTIF__)
ab171e95 107 return new wxMotifWindowImplDC( owner, window );
2970ae54 108#elif defined(__WXX11__)
ab171e95 109 return new wxX11WindowImplDC( owner, window );
2970ae54 110#elif defined(__WXMGL__)
ab171e95 111 return new wxMGLWindowImplDC( owner, window );
2970ae54 112#elif defined(__WXDFB__)
ab171e95 113 return new wxDFBWindowImplDC( owner, window );
2970ae54 114#elif defined(__WXPM__)
ab171e95 115 return new wxPMWindowImplDC( owner, window );
2970ae54 116#elif defined(__PALMOS__)
ab171e95 117 return new wxPalmWindowImplDC( owner, window );
2970ae54
RR
118#endif
119}
120
ab171e95 121wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner )
2970ae54
RR
122{
123#if defined(__WXMSW__)
ab171e95 124 return new wxWindowsClientImplDC( owner );
2970ae54 125#elif defined(__WXGTK20__)
ab171e95 126 return new wxGTKClientImplDC( owner );
2970ae54 127#elif defined(__WXGTK__)
ab171e95 128 return new wxGTKClientImplDC( owner );
2970ae54 129#elif defined(__WXMAC__)
ab171e95 130 return new wxMacClientImplDC( owner );
2970ae54 131#elif defined(__WXCOCOA__)
ab171e95 132 return new wxCocoaClientImplDC( owner );
2970ae54 133#elif defined(__WXMOTIF__)
ab171e95 134 return new wxMotifClientImplDC( owner );
2970ae54 135#elif defined(__WXX11__)
ab171e95 136 return new wxX11ClientImplDC( owner );
2970ae54 137#elif defined(__WXMGL__)
ab171e95 138 return new wxMGLClientImplDC( owner );
2970ae54 139#elif defined(__WXDFB__)
ab171e95 140 return new wxDFBClientImplDC( owner );
2970ae54 141#elif defined(__WXPM__)
ab171e95 142 return new wxPMClientImplDC( owner );
2970ae54 143#elif defined(__PALMOS__)
ab171e95 144 return new wxPalmClientImplDC( owner );
2970ae54
RR
145#endif
146}
147
ab171e95 148wxImplDC* wxNativeDCFactory::CreateClientDC( wxClientDC *owner, wxWindow *window )
2970ae54
RR
149{
150#if defined(__WXMSW__)
ab171e95 151 return new wxWindowsClientImplDC( owner, window );
2970ae54 152#elif defined(__WXGTK20__)
ab171e95 153 return new wxGTKClientImplDC( owner, window );
2970ae54 154#elif defined(__WXGTK__)
ab171e95 155 return new wxGTKClientImplDC( owner, window );
2970ae54 156#elif defined(__WXMAC__)
ab171e95 157 return new wxMacClientImplDC( owner, window );
2970ae54 158#elif defined(__WXCOCOA__)
ab171e95 159 return new wxCocoaClientImplDC( owner, window );
2970ae54 160#elif defined(__WXMOTIF__)
ab171e95 161 return new wxMotifClientImplDC( owner, window );
2970ae54 162#elif defined(__WXX11__)
ab171e95 163 return new wxX11ClientImplDC( owner, window );
2970ae54 164#elif defined(__WXMGL__)
ab171e95 165 return new wxMGLClientImplDC( owner, window );
2970ae54 166#elif defined(__WXDFB__)
ab171e95 167 return new wxDFBClientImplDC( owner, window );
2970ae54 168#elif defined(__WXPM__)
ab171e95 169 return new wxPMClientImplDC( owner, window );
2970ae54 170#elif defined(__PALMOS__)
ab171e95 171 return new wxPalmClientImplDC( owner, window );
2970ae54
RR
172#endif
173}
174
ab171e95 175wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner )
2970ae54
RR
176{
177#if defined(__WXMSW__)
ab171e95 178 return new wxWindowsPaintImplDC( owner );
2970ae54 179#elif defined(__WXGTK20__)
ab171e95 180 return new wxGTKPaintImplDC( owner );
2970ae54 181#elif defined(__WXGTK__)
ab171e95 182 return new wxGTKPaintImplDC( owner );
2970ae54 183#elif defined(__WXMAC__)
ab171e95 184 return new wxMacPaintImplDC( owner );
2970ae54 185#elif defined(__WXCOCOA__)
ab171e95 186 return new wxCocoaPaintImplDC( owner );
2970ae54 187#elif defined(__WXMOTIF__)
ab171e95 188 return new wxMotifPaintImplDC( owner );
2970ae54 189#elif defined(__WXX11__)
ab171e95 190 return new wxX11PaintImplDC( owner );
2970ae54 191#elif defined(__WXMGL__)
ab171e95 192 return new wxMGLPaintImplDC( owner );
2970ae54 193#elif defined(__WXDFB__)
ab171e95 194 return new wxDFBPaintImplDC( owner );
2970ae54 195#elif defined(__WXPM__)
ab171e95 196 return new wxPMPaintImplDC( owner );
2970ae54 197#elif defined(__PALMOS__)
ab171e95 198 return new wxPalmPaintImplDC( owner );
2970ae54
RR
199#endif
200}
201
ab171e95 202wxImplDC* wxNativeDCFactory::CreatePaintDC( wxPaintDC *owner, wxWindow *window )
2970ae54
RR
203{
204#if defined(__WXMSW__)
ab171e95 205 return new wxWindowsPaintImplDC( owner, window );
2970ae54 206#elif defined(__WXGTK20__)
ab171e95 207 return new wxGTKPaintImplDC( owner, window );
2970ae54 208#elif defined(__WXGTK__)
ab171e95 209 return new wxGTKPaintImplDC( owner, window );
2970ae54 210#elif defined(__WXMAC__)
ab171e95 211 return new wxMacPaintImplDC( owner, window );
2970ae54 212#elif defined(__WXCOCOA__)
ab171e95 213 return new wxCocoaPaintImplDC( owner, window );
2970ae54 214#elif defined(__WXMOTIF__)
ab171e95 215 return new wxMotifPaintImplDC( owner, window );
2970ae54 216#elif defined(__WXX11__)
ab171e95 217 return new wxX11PaintImplDC( owner, window );
2970ae54 218#elif defined(__WXMGL__)
ab171e95 219 return new wxMGLPaintImplDC( owner, window );
2970ae54 220#elif defined(__WXDFB__)
ab171e95 221 return new wxDFBPaintImplDC( owner, window );
2970ae54 222#elif defined(__WXPM__)
ab171e95 223 return new wxPMPaintImplDC( owner, window );
2970ae54 224#elif defined(__PALMOS__)
ab171e95 225 return new wxPalmPaintImplDC( owner, window );
2970ae54
RR
226#endif
227}
228
ab171e95 229wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner )
2970ae54
RR
230{
231#if defined(__WXMSW__)
ab171e95 232 return new wxWindowsMemoryImplDC( owner );
2970ae54 233#elif defined(__WXGTK20__)
ab171e95 234 return new wxGTKMemoryImplDC( owner );
2970ae54 235#elif defined(__WXGTK__)
ab171e95 236 return new wxGTKMemoryImplDC( owner );
2970ae54 237#elif defined(__WXMAC__)
ab171e95 238 return new wxMacMemoryImplDC( owner );
2970ae54 239#elif defined(__WXCOCOA__)
ab171e95 240 return new wxCocoaMemoryImplDC( owner );
2970ae54 241#elif defined(__WXMOTIF__)
ab171e95 242 return new wxMotifMemoryImplDC( owner );
2970ae54 243#elif defined(__WXX11__)
ab171e95 244 return new wxX11MemoryImplDC( owner );
2970ae54 245#elif defined(__WXMGL__)
ab171e95 246 return new wxMGLMemoryImplDC( owner );
2970ae54 247#elif defined(__WXDFB__)
ab171e95 248 return new wxDFBMemoryImplDC( owner );
2970ae54 249#elif defined(__WXPM__)
ab171e95 250 return new wxPMMemoryImplDC( owner );
2970ae54 251#elif defined(__PALMOS__)
ab171e95 252 return new wxPalmMemoryImplDC( owner );
2970ae54
RR
253#endif
254}
255
ab171e95 256wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxBitmap &bitmap )
2970ae54
RR
257{
258#if defined(__WXMSW__)
ab171e95 259 return new wxWindowsMemoryImplDC( owner, bitmap );
2970ae54 260#elif defined(__WXGTK20__)
ab171e95 261 return new wxGTKMemoryImplDC( owner, bitmap );
2970ae54 262#elif defined(__WXGTK__)
ab171e95 263 return new wxGTKMemoryImplDC( owner, bitmap );
2970ae54 264#elif defined(__WXMAC__)
ab171e95 265 return new wxMacMemoryImplDC( owner, bitmap );
2970ae54 266#elif defined(__WXCOCOA__)
ab171e95 267 return new wxCocoaMemoryImplDC( owner, bitmap );
2970ae54 268#elif defined(__WXMOTIF__)
ab171e95 269 return new wxMotifMemoryImplDC( owner, bitmap );
2970ae54 270#elif defined(__WXX11__)
ab171e95 271 return new wxX11MemoryImplDC( owner, bitmap );
2970ae54 272#elif defined(__WXMGL__)
ab171e95 273 return new wxMGLMemoryImplDC( owner, bitmap );
2970ae54 274#elif defined(__WXDFB__)
ab171e95 275 return new wxDFBMemoryImplDC( owner, bitmap );
2970ae54 276#elif defined(__WXPM__)
ab171e95 277 return new wxPMMemoryImplDC( owner, bitmap );
2970ae54 278#elif defined(__PALMOS__)
ab171e95 279 return new wxPalmMemoryImplDC( owner, bitmap );
2970ae54
RR
280#endif
281}
282
ab171e95 283wxImplDC* wxNativeDCFactory::CreateMemoryDC( wxMemoryDC *owner, wxDC *dc )
2970ae54
RR
284{
285#if defined(__WXMSW__)
ab171e95 286 return new wxWindowsMemoryImplDC( owner, dc );
2970ae54 287#elif defined(__WXGTK20__)
ab171e95 288 return new wxGTKMemoryImplDC( owner, dc );
2970ae54 289#elif defined(__WXGTK__)
ab171e95 290 return new wxGTKMemoryImplDC( owner, dc );
2970ae54 291#elif defined(__WXMAC__)
ab171e95 292 return new wxMacMemoryImplDC( owner, dc );
2970ae54 293#elif defined(__WXCOCOA__)
ab171e95 294 return new wxCocoaMemoryImplDC( owner, dc );
2970ae54 295#elif defined(__WXMOTIF__)
ab171e95 296 return new wxMotifMemoryImplDC( owner, dc );
2970ae54 297#elif defined(__WXX11__)
ab171e95 298 return new wxX11MemoryImplDC( owner, dc );
2970ae54 299#elif defined(__WXMGL__)
ab171e95 300 return new wxMGLMemoryImplDC( owner, dc );
2970ae54 301#elif defined(__WXDFB__)
ab171e95 302 return new wxDFBMemoryImplDC( owner, dc );
2970ae54 303#elif defined(__WXPM__)
ab171e95 304 return new wxPMMemoryImplDC( owner, dc );
2970ae54 305#elif defined(__PALMOS__)
ab171e95
RR
306 return new wxPalmMemoryImplDC( owner, dc );
307#endif
308}
309
310wxImplDC* wxNativeDCFactory::CreateScreenDC( wxScreenDC *owner )
311{
312#if defined(__WXMSW__)
313 return new wxWindowsScreenImplDC( owner );
314#elif defined(__WXGTK20__)
315 return new wxGTKScreenImplDC( owner );
316#elif defined(__WXGTK__)
317 return new wxGTKScreenImplDC( owner );
318#elif defined(__WXMAC__)
319 return new wxMacScreenImplDC( owner );
320#elif defined(__WXCOCOA__)
321 return new wxCocoaScreenImplDC( owner );
322#elif defined(__WXMOTIF__)
323 return new wxMotifScreenImplDC( owner );
324#elif defined(__WXX11__)
325 return new wxX11ScreenImplDC( owner );
326#elif defined(__WXMGL__)
327 return new wxMGLScreenImplDC( owner );
328#elif defined(__WXDFB__)
329 return new wxDFBScreenImplDC( owner );
330#elif defined(__WXPM__)
331 return new wxPMScreenImplDC( owner );
332#elif defined(__PALMOS__)
333 return new wxPalmScreenImplDC( owner );
2970ae54
RR
334#endif
335}
336
337//-----------------------------------------------------------------------------
338// wxWindowDC
339//-----------------------------------------------------------------------------
340
341IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
342
ab171e95 343wxWindowDC::wxWindowDC()
2970ae54
RR
344{
345 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 346 m_pimpl = factory->CreateWindowDC( this );
2970ae54
RR
347}
348
ab171e95 349wxWindowDC::wxWindowDC( wxWindow *win )
2970ae54
RR
350{
351 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 352 m_pimpl = factory->CreateWindowDC( this, win );
2970ae54
RR
353}
354
355//-----------------------------------------------------------------------------
356// wxClientDC
357//-----------------------------------------------------------------------------
358
359IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxDC)
360
361wxClientDC::wxClientDC()
362{
363 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 364 m_pimpl = factory->CreateClientDC( this );
2970ae54
RR
365}
366
367wxClientDC::wxClientDC( wxWindow *win )
368{
369 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 370 m_pimpl = factory->CreateClientDC( this, win );
2970ae54
RR
371}
372
373//-----------------------------------------------------------------------------
374// wxMemoryDC
375//-----------------------------------------------------------------------------
376
377IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC, wxDC)
378
379wxMemoryDC::wxMemoryDC()
380{
381 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 382 m_pimpl = factory->CreateMemoryDC( this );
2970ae54
RR
383}
384
385wxMemoryDC::wxMemoryDC( wxBitmap& bitmap )
386{
387 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 388 m_pimpl = factory->CreateMemoryDC( this, bitmap );
2970ae54
RR
389}
390
391wxMemoryDC::wxMemoryDC( wxDC *dc )
392{
393 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95
RR
394 m_pimpl = factory->CreateMemoryDC( this, dc );
395}
396
397void wxMemoryDC::SelectObject(wxBitmap& bmp)
398{
399 // make sure that the given wxBitmap is not sharing its data with other
400 // wxBitmap instances as its contents will be modified by any drawing
401 // operation done on this DC
402 if (bmp.IsOk())
403 bmp.UnShare();
404
405#ifdef __WXGTK__
406 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
407#else
408 // TODO
409#endif
410 if (mem_pimpl)
411 mem_pimpl->DoSelect(bmp);
412}
413
414void wxMemoryDC::SelectObjectAsSource(const wxBitmap& bmp)
415{
416#ifdef __WXGTK__
417 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
418#else
419 // TODO
420#endif
421 mem_pimpl->DoSelect(bmp);
2970ae54 422}
ab171e95
RR
423
424const wxBitmap& wxMemoryDC::GetSelectedBitmap() const
425{
426#ifdef __WXGTK__
427 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
428#else
429 // TODO
430#endif
431 if (mem_pimpl)
432 return mem_pimpl->DoGetSelectedBitmap();
433
434 return wxNullBitmap;
435}
436
437wxBitmap& wxMemoryDC::GetSelectedBitmap()
438{
439#ifdef __WXGTK__
440 wxGTKMemoryImplDC *mem_pimpl = wxDynamicCast( m_pimpl, wxGTKMemoryImplDC );
441#else
442 // TODO
443#endif
444
445 if (mem_pimpl)
446 return mem_pimpl->DoGetSelectedBitmap();
447
448 return wxNullBitmap;
449}
450
2970ae54
RR
451
452//-----------------------------------------------------------------------------
453// wxPaintDC
454//-----------------------------------------------------------------------------
455
456IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxDC)
457
458wxPaintDC::wxPaintDC()
459{
460 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95 461 m_pimpl = factory->CreatePaintDC( this );
2970ae54
RR
462}
463
464wxPaintDC::wxPaintDC( wxWindow *win )
465{
466 wxDCFactory *factory = wxDCFactory::GetFactory();
ab171e95
RR
467 m_pimpl = factory->CreatePaintDC( this, win );
468}
469
470//-----------------------------------------------------------------------------
471// wxScreenDC
472//-----------------------------------------------------------------------------
473
474IMPLEMENT_DYNAMIC_CLASS(wxScreenDC, wxWindowDC)
475
476wxScreenDC::wxScreenDC()
477{
478 wxDCFactory *factory = wxDCFactory::GetFactory();
479 m_pimpl = factory->CreateScreenDC( this );
2970ae54
RR
480}
481
482//-----------------------------------------------------------------------------
483// wxImplDC
484//-----------------------------------------------------------------------------
485
486IMPLEMENT_ABSTRACT_CLASS(wxImplDC, wxObject)
487
488wxImplDC::wxImplDC( wxDC *owner )
489 : m_colour(wxColourDisplay())
490 , m_ok(true)
491 , m_clipping(false)
492 , m_isInteractive(0)
493 , m_isBBoxValid(false)
494 , m_logicalOriginX(0), m_logicalOriginY(0)
495 , m_deviceOriginX(0), m_deviceOriginY(0)
496 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
497 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
498 , m_userScaleX(1.0), m_userScaleY(1.0)
499 , m_scaleX(1.0), m_scaleY(1.0)
500 , m_signX(1), m_signY(1)
501 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
502 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
503 , m_logicalFunction(wxCOPY)
504 , m_backgroundMode(wxTRANSPARENT)
505 , m_mappingMode(wxMM_TEXT)
506 , m_pen()
507 , m_brush()
508 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
509 , m_textForegroundColour(*wxBLACK)
510 , m_textBackgroundColour(*wxWHITE)
511 , m_font()
512#if wxUSE_PALETTE
513 , m_palette()
514 , m_hasCustomPalette(false)
515#endif // wxUSE_PALETTE
516{
517 m_owner = owner;
518
519 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
520 (double)wxGetDisplaySizeMM().GetWidth();
521 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
522 (double)wxGetDisplaySizeMM().GetHeight();
523
524 ResetBoundingBox();
525 ResetClipping();
526}
527
528wxImplDC::~wxImplDC()
529{
530}
531
2970ae54
RR
532// ----------------------------------------------------------------------------
533// coordinate conversions and transforms
534// ----------------------------------------------------------------------------
535
536wxCoord wxImplDC::DeviceToLogicalX(wxCoord x) const
537{
538 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
539}
540
541wxCoord wxImplDC::DeviceToLogicalY(wxCoord y) const
542{
543 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
544}
545
546wxCoord wxImplDC::DeviceToLogicalXRel(wxCoord x) const
547{
548 return wxRound((double)(x) / m_scaleX);
549}
550
551wxCoord wxImplDC::DeviceToLogicalYRel(wxCoord y) const
552{
553 return wxRound((double)(y) / m_scaleY);
554}
555
556wxCoord wxImplDC::LogicalToDeviceX(wxCoord x) const
557{
02255e07 558 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX * m_signY + m_deviceLocalOriginX;
2970ae54
RR
559}
560
561wxCoord wxImplDC::LogicalToDeviceY(wxCoord y) const
562{
02255e07 563 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY * m_signY + m_deviceLocalOriginY;
2970ae54
RR
564}
565
566wxCoord wxImplDC::LogicalToDeviceXRel(wxCoord x) const
567{
568 return wxRound((double)(x) * m_scaleX);
569}
570
571wxCoord wxImplDC::LogicalToDeviceYRel(wxCoord y) const
572{
573 return wxRound((double)(y) * m_scaleY);
574}
575
576void wxImplDC::ComputeScaleAndOrigin()
577{
578 m_scaleX = m_logicalScaleX * m_userScaleX;
579 m_scaleY = m_logicalScaleY * m_userScaleY;
580}
581
582void wxImplDC::SetMapMode( int mode )
583{
584 switch (mode)
585 {
586 case wxMM_TWIPS:
587 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
588 break;
589 case wxMM_POINTS:
590 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
591 break;
592 case wxMM_METRIC:
593 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
594 break;
595 case wxMM_LOMETRIC:
596 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
597 break;
598 default:
599 case wxMM_TEXT:
600 SetLogicalScale( 1.0, 1.0 );
601 break;
602 }
603 m_mappingMode = mode;
604}
605
606void wxImplDC::SetUserScale( double x, double y )
607{
608 // allow negative ? -> no
609 m_userScaleX = x;
610 m_userScaleY = y;
611 ComputeScaleAndOrigin();
612}
613
614void wxImplDC::SetLogicalScale( double x, double y )
615{
616 // allow negative ?
617 m_logicalScaleX = x;
618 m_logicalScaleY = y;
619 ComputeScaleAndOrigin();
620}
621
622void wxImplDC::SetLogicalOrigin( wxCoord x, wxCoord y )
623{
624 m_logicalOriginX = x * m_signX;
625 m_logicalOriginY = y * m_signY;
626 ComputeScaleAndOrigin();
627}
628
629void wxImplDC::SetDeviceOrigin( wxCoord x, wxCoord y )
630{
631 m_deviceOriginX = x;
632 m_deviceOriginY = y;
633 ComputeScaleAndOrigin();
634}
635
636void wxImplDC::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
637{
638 m_deviceLocalOriginX = x;
639 m_deviceLocalOriginY = y;
640 ComputeScaleAndOrigin();
641}
642
643void wxImplDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
644{
645 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 646 // wxWidgets 2.9: no longer override it
2970ae54
RR
647 m_signX = (xLeftRight ? 1 : -1);
648 m_signY = (yBottomUp ? -1 : 1);
649 ComputeScaleAndOrigin();
650}
651
652
653// Each element of the widths array will be the width of the string up to and
654// including the corresponding character in text. This is the generic
655// implementation, the port-specific classes should do this with native APIs
656// if available and if faster. Note: pango_layout_index_to_pos is much slower
657// than calling GetTextExtent!!
658
659#define FWC_SIZE 256
660
661class FontWidthCache
662{
663public:
664 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
665 ~FontWidthCache() { delete []m_widths; }
666
667 void Reset()
668 {
669 if (!m_widths)
670 m_widths = new int[FWC_SIZE];
671
672 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
673 }
674
675 wxFont m_font;
676 double m_scaleX;
677 int *m_widths;
678};
679
680static FontWidthCache s_fontWidthCache;
681
682bool wxImplDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
683{
684 int totalWidth = 0;
685
686 const size_t len = text.length();
687 widths.Empty();
688 widths.Add(0, len);
689
690 // reset the cache if font or horizontal scale have changed
691 if ( !s_fontWidthCache.m_widths ||
692 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
693 (s_fontWidthCache.m_font != GetFont()) )
694 {
695 s_fontWidthCache.Reset();
696 s_fontWidthCache.m_font = GetFont();
697 s_fontWidthCache.m_scaleX = m_scaleX;
698 }
699
700 // Calculate the position of each character based on the widths of
701 // the previous characters
702 int w, h;
703 for ( size_t i = 0; i < len; i++ )
704 {
705 const wxChar c = text[i];
706 unsigned int c_int = (unsigned int)c;
707
708 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
709 {
710 w = s_fontWidthCache.m_widths[c_int];
711 }
712 else
713 {
ab171e95 714 DoGetTextExtent(c, &w, &h);
2970ae54
RR
715 if (c_int < FWC_SIZE)
716 s_fontWidthCache.m_widths[c_int] = w;
717 }
718
719 totalWidth += w;
720 widths[i] = totalWidth;
721 }
722
723 return true;
724}
725
726void wxImplDC::GetMultiLineTextExtent(const wxString& text,
727 wxCoord *x,
728 wxCoord *y,
729 wxCoord *h,
730 const wxFont *font) const
731{
732 wxCoord widthTextMax = 0, widthLine,
733 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
734
735 wxString curLine;
736 for ( const wxChar *pc = text; ; pc++ )
737 {
738 if ( *pc == _T('\n') || *pc == _T('\0') )
739 {
740 if ( curLine.empty() )
741 {
742 // we can't use GetTextExtent - it will return 0 for both width
743 // and height and an empty line should count in height
744 // calculation
745
746 // assume that this line has the same height as the previous
747 // one
748 if ( !heightLineDefault )
749 heightLineDefault = heightLine;
750
751 if ( !heightLineDefault )
752 {
753 // but we don't know it yet - choose something reasonable
754 DoGetTextExtent(_T("W"), NULL, &heightLineDefault,
755 NULL, NULL, font);
756 }
757
758 heightTextTotal += heightLineDefault;
759 }
760 else
761 {
762 DoGetTextExtent(curLine, &widthLine, &heightLine,
763 NULL, NULL, font);
764 if ( widthLine > widthTextMax )
765 widthTextMax = widthLine;
766 heightTextTotal += heightLine;
767 }
768
769 if ( *pc == _T('\n') )
770 {
771 curLine.clear();
772 }
773 else
774 {
775 // the end of string
776 break;
777 }
778 }
779 else
780 {
781 curLine += *pc;
782 }
783 }
784
785 if ( x )
786 *x = widthTextMax;
787 if ( y )
788 *y = heightTextTotal;
789 if ( h )
790 *h = heightLine;
791}
792
793void wxImplDC::DoDrawCheckMark(wxCoord x1, wxCoord y1,
794 wxCoord width, wxCoord height)
795{
ab171e95 796 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
797
798 wxCoord x2 = x1 + width,
799 y2 = y1 + height;
800
801 // the pen width is calibrated to give 3 for width == height == 10
ab171e95 802 wxDCPenChanger pen( *m_owner, wxPen(GetTextForeground(), (width + height + 1)/7));
2970ae54
RR
803
804 // we're drawing a scaled version of wx/generic/tick.xpm here
805 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
806 y3 = y1 + height / 2; // y of the left tick branch
807 DoDrawLine(x1, y3, x3, y2);
808 DoDrawLine(x3, y2, x2, y1);
809
810 CalcBoundingBox(x1, y1);
811 CalcBoundingBox(x2, y2);
812}
813
814bool
815wxImplDC::DoStretchBlit(wxCoord xdest, wxCoord ydest,
816 wxCoord dstWidth, wxCoord dstHeight,
817 wxDC *source,
818 wxCoord xsrc, wxCoord ysrc,
819 wxCoord srcWidth, wxCoord srcHeight,
820 int rop,
821 bool useMask,
822 wxCoord xsrcMask,
823 wxCoord ysrcMask)
824{
825 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
826 _T("invalid blit size") );
827
828 // emulate the stretching by modifying the DC scale
829 double xscale = (double)srcWidth/dstWidth,
830 yscale = (double)srcHeight/dstHeight;
831
832 double xscaleOld, yscaleOld;
833 GetUserScale(&xscaleOld, &yscaleOld);
834 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
835
836 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
837 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
838 source,
839 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
840
841 SetUserScale(xscaleOld, yscaleOld);
842
843 return rc;
844}
845
ab171e95 846#if 0
2970ae54
RR
847void wxImplDC::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
848{
849 int n = list->GetCount();
850 wxPoint *points = new wxPoint[n];
851
852 int i = 0;
853 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
854 {
855 wxPoint *point = (wxPoint *)node->GetData();
856 points[i].x = point->x;
857 points[i].y = point->y;
858 }
859
860 DoDrawLines(n, points, xoffset, yoffset);
861
862 delete [] points;
863}
864
865void wxImplDC::DrawPolygon(const wxList *list,
866 wxCoord xoffset, wxCoord yoffset,
867 int fillStyle)
868{
869 int n = list->GetCount();
870 wxPoint *points = new wxPoint[n];
871
872 int i = 0;
873 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
874 {
875 wxPoint *point = (wxPoint *)node->GetData();
876 points[i].x = point->x;
877 points[i].y = point->y;
878 }
879
880 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
881
882 delete [] points;
883}
ab171e95 884#endif
2970ae54
RR
885
886void
887wxImplDC::DoDrawPolyPolygon(int n,
888 int count[],
889 wxPoint points[],
890 wxCoord xoffset, wxCoord yoffset,
891 int fillStyle)
892{
893 if ( n == 1 )
894 {
895 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
896 return;
897 }
898
899 int i, j, lastOfs;
900 wxPoint* pts;
901 wxPen pen;
902
903 for (i = j = lastOfs = 0; i < n; i++)
904 {
905 lastOfs = j;
906 j += count[i];
907 }
908 pts = new wxPoint[j+n-1];
909 for (i = 0; i < j; i++)
910 pts[i] = points[i];
911 for (i = 2; i <= n; i++)
912 {
913 lastOfs -= count[n-i];
914 pts[j++] = pts[lastOfs];
915 }
916
917 pen = GetPen();
918 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
919 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
920 SetPen(pen);
921 for (i = j = 0; i < n; i++)
922 {
923 DoDrawLines(count[i], pts+j, xoffset, yoffset);
924 j += count[i];
925 }
926 delete[] pts;
927}
928
929#if wxUSE_SPLINES
930
931// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
ab171e95 932void wxImplDC::DoDrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
2970ae54
RR
933{
934 wxList point_list;
935
936 wxPoint *point1 = new wxPoint;
937 point1->x = x1; point1->y = y1;
938 point_list.Append((wxObject*)point1);
939
940 wxPoint *point2 = new wxPoint;
941 point2->x = x2; point2->y = y2;
942 point_list.Append((wxObject*)point2);
943
944 wxPoint *point3 = new wxPoint;
945 point3->x = x3; point3->y = y3;
946 point_list.Append((wxObject*)point3);
947
ab171e95 948 DoDrawSpline(&point_list);
2970ae54
RR
949
950 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
951 {
952 wxPoint *p = (wxPoint *)node->GetData();
953 delete p;
954 }
955}
956
ab171e95 957void wxImplDC::DoDrawSpline(int n, wxPoint points[])
2970ae54
RR
958{
959 wxList list;
960 for (int i =0; i < n; i++)
961 {
962 list.Append((wxObject*)&points[i]);
963 }
964
ab171e95 965 DoDrawSpline(&list);
2970ae54
RR
966}
967
968// ----------------------------------- spline code ----------------------------------------
969
970void wx_quadratic_spline(double a1, double b1, double a2, double b2,
971 double a3, double b3, double a4, double b4);
972void wx_clear_stack();
973int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
974 double *y3, double *x4, double *y4);
975void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
976 double x4, double y4);
977static bool wx_spline_add_point(double x, double y);
ab171e95 978static void wx_spline_draw_point_array(wxDC *dc);
2970ae54
RR
979
980wxList wx_spline_point_list;
981
982#define half(z1, z2) ((z1+z2)/2.0)
983#define THRESHOLD 5
984
985/* iterative version */
986
987void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
988 double b4)
989{
990 register double xmid, ymid;
991 double x1, y1, x2, y2, x3, y3, x4, y4;
992
993 wx_clear_stack();
994 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
995
996 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
997 xmid = (double)half(x2, x3);
998 ymid = (double)half(y2, y3);
999 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1000 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1001 wx_spline_add_point( x1, y1 );
1002 wx_spline_add_point( xmid, ymid );
1003 } else {
1004 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1005 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1006 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1007 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1008 }
1009 }
1010}
1011
1012/* utilities used by spline drawing routines */
1013
1014typedef struct wx_spline_stack_struct {
1015 double x1, y1, x2, y2, x3, y3, x4, y4;
1016} Stack;
1017
1018#define SPLINE_STACK_DEPTH 20
1019static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
1020static Stack *wx_stack_top;
1021static int wx_stack_count;
1022
1023void wx_clear_stack()
1024{
1025 wx_stack_top = wx_spline_stack;
1026 wx_stack_count = 0;
1027}
1028
1029void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
1030{
1031 wx_stack_top->x1 = x1;
1032 wx_stack_top->y1 = y1;
1033 wx_stack_top->x2 = x2;
1034 wx_stack_top->y2 = y2;
1035 wx_stack_top->x3 = x3;
1036 wx_stack_top->y3 = y3;
1037 wx_stack_top->x4 = x4;
1038 wx_stack_top->y4 = y4;
1039 wx_stack_top++;
1040 wx_stack_count++;
1041}
1042
1043int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
1044 double *x3, double *y3, double *x4, double *y4)
1045{
1046 if (wx_stack_count == 0)
1047 return (0);
1048 wx_stack_top--;
1049 wx_stack_count--;
1050 *x1 = wx_stack_top->x1;
1051 *y1 = wx_stack_top->y1;
1052 *x2 = wx_stack_top->x2;
1053 *y2 = wx_stack_top->y2;
1054 *x3 = wx_stack_top->x3;
1055 *y3 = wx_stack_top->y3;
1056 *x4 = wx_stack_top->x4;
1057 *y4 = wx_stack_top->y4;
1058 return (1);
1059}
1060
1061static bool wx_spline_add_point(double x, double y)
1062{
1063 wxPoint *point = new wxPoint ;
1064 point->x = (int) x;
1065 point->y = (int) y;
1066 wx_spline_point_list.Append((wxObject*)point);
1067 return true;
1068}
1069
1070static void wx_spline_draw_point_array(wxDC *dc)
1071{
ab171e95 1072// dc->DrawLines(&wx_spline_point_list, 0, 0 ); wxList
2970ae54
RR
1073 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
1074 while (node)
1075 {
1076 wxPoint *point = (wxPoint *)node->GetData();
1077 delete point;
1078 wx_spline_point_list.Erase(node);
1079 node = wx_spline_point_list.GetFirst();
1080 }
1081}
1082
1083void wxImplDC::DoDrawSpline( wxList *points )
1084{
ab171e95 1085 wxCHECK_RET( IsOk(), wxT("invalid window dc") );
2970ae54
RR
1086
1087 wxPoint *p;
1088 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
1089 double x1, y1, x2, y2;
1090
1091 wxList::compatibility_iterator node = points->GetFirst();
1092 if (!node)
1093 // empty list
1094 return;
1095
1096 p = (wxPoint *)node->GetData();
1097
1098 x1 = p->x;
1099 y1 = p->y;
1100
1101 node = node->GetNext();
1102 p = (wxPoint *)node->GetData();
1103
1104 x2 = p->x;
1105 y2 = p->y;
1106 cx1 = (double)((x1 + x2) / 2);
1107 cy1 = (double)((y1 + y2) / 2);
1108 cx2 = (double)((cx1 + x2) / 2);
1109 cy2 = (double)((cy1 + y2) / 2);
1110
1111 wx_spline_add_point(x1, y1);
1112
1113 while ((node = node->GetNext())
1114#if !wxUSE_STL
1115 != NULL
1116#endif // !wxUSE_STL
1117 )
1118 {
1119 p = (wxPoint *)node->GetData();
1120 x1 = x2;
1121 y1 = y2;
1122 x2 = p->x;
1123 y2 = p->y;
1124 cx4 = (double)(x1 + x2) / 2;
1125 cy4 = (double)(y1 + y2) / 2;
1126 cx3 = (double)(x1 + cx4) / 2;
1127 cy3 = (double)(y1 + cy4) / 2;
1128
1129 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
1130
1131 cx1 = cx4;
1132 cy1 = cy4;
1133 cx2 = (double)(cx1 + x2) / 2;
1134 cy2 = (double)(cy1 + y2) / 2;
1135 }
1136
1137 wx_spline_add_point( cx1, cy1 );
1138 wx_spline_add_point( x2, y2 );
1139
1140 wx_spline_draw_point_array( m_owner );
1141}
1142
1143#endif // wxUSE_SPLINES
1144
1145
2970ae54
RR
1146
1147void wxImplDC::DoGradientFillLinear(const wxRect& rect,
1148 const wxColour& initialColour,
1149 const wxColour& destColour,
1150 wxDirection nDirection)
1151{
1152 // save old pen
1153 wxPen oldPen = m_pen;
1154 wxBrush oldBrush = m_brush;
1155
1156 wxUint8 nR1 = initialColour.Red();
1157 wxUint8 nG1 = initialColour.Green();
1158 wxUint8 nB1 = initialColour.Blue();
1159 wxUint8 nR2 = destColour.Red();
1160 wxUint8 nG2 = destColour.Green();
1161 wxUint8 nB2 = destColour.Blue();
1162 wxUint8 nR, nG, nB;
1163
1164 if ( nDirection == wxEAST || nDirection == wxWEST )
1165 {
1166 wxInt32 x = rect.GetWidth();
1167 wxInt32 w = x; // width of area to shade
1168 wxInt32 xDelta = w/256; // height of one shade bend
1169 if (xDelta < 1)
1170 xDelta = 1;
1171
1172 while (x >= xDelta)
1173 {
1174 x -= xDelta;
1175 if (nR1 > nR2)
1176 nR = nR1 - (nR1-nR2)*(w-x)/w;
1177 else
1178 nR = nR1 + (nR2-nR1)*(w-x)/w;
1179
1180 if (nG1 > nG2)
1181 nG = nG1 - (nG1-nG2)*(w-x)/w;
1182 else
1183 nG = nG1 + (nG2-nG1)*(w-x)/w;
1184
1185 if (nB1 > nB2)
1186 nB = nB1 - (nB1-nB2)*(w-x)/w;
1187 else
1188 nB = nB1 + (nB2-nB1)*(w-x)/w;
1189
1190 wxColour colour(nR,nG,nB);
1191 SetPen(wxPen(colour, 1, wxSOLID));
1192 SetBrush(wxBrush(colour));
1193 if(nDirection == wxEAST)
5f77ee3b 1194 DoDrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
2970ae54
RR
1195 xDelta, rect.GetHeight());
1196 else //nDirection == wxWEST
1197 DoDrawRectangle(rect.GetLeft()+x, rect.GetTop(),
1198 xDelta, rect.GetHeight());
1199 }
1200 }
1201 else // nDirection == wxNORTH || nDirection == wxSOUTH
1202 {
1203 wxInt32 y = rect.GetHeight();
1204 wxInt32 w = y; // height of area to shade
1205 wxInt32 yDelta = w/255; // height of one shade bend
1206 if (yDelta < 1)
1207 yDelta = 1;
1208
1209 while (y > 0)
1210 {
1211 y -= yDelta;
1212 if (nR1 > nR2)
1213 nR = nR1 - (nR1-nR2)*(w-y)/w;
1214 else
1215 nR = nR1 + (nR2-nR1)*(w-y)/w;
1216
1217 if (nG1 > nG2)
1218 nG = nG1 - (nG1-nG2)*(w-y)/w;
1219 else
1220 nG = nG1 + (nG2-nG1)*(w-y)/w;
1221
1222 if (nB1 > nB2)
1223 nB = nB1 - (nB1-nB2)*(w-y)/w;
1224 else
1225 nB = nB1 + (nB2-nB1)*(w-y)/w;
1226
1227 wxColour colour(nR,nG,nB);
1228 SetPen(wxPen(colour, 1, wxSOLID));
1229 SetBrush(wxBrush(colour));
1230 if(nDirection == wxNORTH)
1231 DoDrawRectangle(rect.GetLeft(), rect.GetTop()+y,
1232 rect.GetWidth(), yDelta);
1233 else //nDirection == wxSOUTH
5f77ee3b 1234 DoDrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
2970ae54
RR
1235 rect.GetWidth(), yDelta);
1236 }
1237 }
1238
1239 SetPen(oldPen);
1240 SetBrush(oldBrush);
1241}
1242
1243void wxImplDC::DoGradientFillConcentric(const wxRect& rect,
1244 const wxColour& initialColour,
1245 const wxColour& destColour,
1246 const wxPoint& circleCenter)
1247{
1248 //save the old pen color
1249 wxColour oldPenColour = m_pen.GetColour();
1250
1251 wxUint8 nR1 = destColour.Red();
1252 wxUint8 nG1 = destColour.Green();
1253 wxUint8 nB1 = destColour.Blue();
1254 wxUint8 nR2 = initialColour.Red();
1255 wxUint8 nG2 = initialColour.Green();
1256 wxUint8 nB2 = initialColour.Blue();
1257 wxUint8 nR, nG, nB;
1258
1259
1260 //Radius
1261 wxInt32 cx = rect.GetWidth() / 2;
1262 wxInt32 cy = rect.GetHeight() / 2;
1263 wxInt32 nRadius;
1264 if (cx < cy)
1265 nRadius = cx;
1266 else
1267 nRadius = cy;
1268
1269 //Offset of circle
1270 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
1271 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
1272
1273 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
1274 {
1275 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
1276 {
1277 //get color difference
1278 wxInt32 nGradient = ((nRadius -
1279 (wxInt32)sqrt(
1280 pow((double)(x - cx - nCircleOffX), 2) +
1281 pow((double)(y - cy - nCircleOffY), 2)
1282 )) * 100) / nRadius;
1283
1284 //normalize Gradient
1285 if (nGradient < 0 )
1286 nGradient = 0;
1287
1288 //get dest colors
1289 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
1290 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
1291 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
1292
1293 //set the pixel
1294 m_pen.SetColour(wxColour(nR,nG,nB));
ab171e95 1295 DoDrawPoint(x + rect.GetLeft(), y + rect.GetTop());
2970ae54
RR
1296 }
1297 }
1298 //return old pen color
1299 m_pen.SetColour(oldPenColour);
1300}
1301
1302//-----------------------------------------------------------------------------
1303// wxDC
1304//-----------------------------------------------------------------------------
1305
1306IMPLEMENT_ABSTRACT_CLASS(wxDC, wxObject)
1307
ab171e95
RR
1308void wxDC::DrawLabel(const wxString& text,
1309 const wxBitmap& bitmap,
1310 const wxRect& rect,
1311 int alignment,
1312 int indexAccel,
1313 wxRect *rectBounding)
1314{
1315 // find the text position
1316 wxCoord widthText, heightText, heightLine;
1317 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
1318
1319 wxCoord width, height;
1320 if ( bitmap.Ok() )
1321 {
1322 width = widthText + bitmap.GetWidth();
1323 height = bitmap.GetHeight();
1324 }
1325 else // no bitmap
1326 {
1327 width = widthText;
1328 height = heightText;
1329 }
1330
1331 wxCoord x, y;
1332 if ( alignment & wxALIGN_RIGHT )
1333 {
1334 x = rect.GetRight() - width;
1335 }
1336 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1337 {
1338 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
1339 }
1340 else // alignment & wxALIGN_LEFT
1341 {
1342 x = rect.GetLeft();
1343 }
1344
1345 if ( alignment & wxALIGN_BOTTOM )
1346 {
1347 y = rect.GetBottom() - height;
1348 }
1349 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
1350 {
1351 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
1352 }
1353 else // alignment & wxALIGN_TOP
1354 {
1355 y = rect.GetTop();
1356 }
1357
1358 // draw the bitmap first
1359 wxCoord x0 = x,
1360 y0 = y,
1361 width0 = width;
1362 if ( bitmap.Ok() )
1363 {
1364 DrawBitmap(bitmap, x, y, true /* use mask */);
1365
1366 wxCoord offset = bitmap.GetWidth() + 4;
1367 x += offset;
1368 width -= offset;
1369
1370 y += (height - heightText) / 2;
1371 }
1372
1373 // we will draw the underscore under the accel char later
1374 wxCoord startUnderscore = 0,
1375 endUnderscore = 0,
1376 yUnderscore = 0;
1377
1378 // split the string into lines and draw each of them separately
1379 wxString curLine;
1380 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1381 {
1382 if ( *pc == _T('\n') || pc == text.end() )
1383 {
1384 int xRealStart = x; // init it here to avoid compielr warnings
1385
1386 if ( !curLine.empty() )
1387 {
1388 // NB: can't test for !(alignment & wxALIGN_LEFT) because
1389 // wxALIGN_LEFT is 0
1390 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
1391 {
1392 wxCoord widthLine;
1393 GetTextExtent(curLine, &widthLine, NULL);
1394
1395 if ( alignment & wxALIGN_RIGHT )
1396 {
1397 xRealStart += width - widthLine;
1398 }
1399 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
1400 {
1401 xRealStart += (width - widthLine) / 2;
1402 }
1403 }
1404 //else: left aligned, nothing to do
1405
1406 DrawText(curLine, xRealStart, y);
1407 }
1408
1409 y += heightLine;
1410
1411 // do we have underscore in this line? we can check yUnderscore
1412 // because it is set below to just y + heightLine if we do
1413 if ( y == yUnderscore )
1414 {
1415 // adjust the horz positions to account for the shift
1416 startUnderscore += xRealStart;
1417 endUnderscore += xRealStart;
1418 }
1419
1420 if ( pc == text.end() )
1421 break;
1422
1423 curLine.clear();
1424 }
1425 else // not end of line
1426 {
1427 if ( pc - text.begin() == indexAccel )
1428 {
1429 // remeber to draw underscore here
1430 GetTextExtent(curLine, &startUnderscore, NULL);
1431 curLine += *pc;
1432 GetTextExtent(curLine, &endUnderscore, NULL);
1433
1434 yUnderscore = y + heightLine;
1435 }
1436 else
1437 {
1438 curLine += *pc;
1439 }
1440 }
1441 }
1442
1443 // draw the underscore if found
1444 if ( startUnderscore != endUnderscore )
1445 {
1446 // it should be of the same colour as text
1447 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
1448
1449 yUnderscore--;
1450
1451 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
1452 }
1453
1454 // return bounding rect if requested
1455 if ( rectBounding )
1456 {
1457 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
1458 }
1459
1460 CalcBoundingBox(x0, y0);
1461 CalcBoundingBox(x0 + width0, y0 + height);
1462}
1463
2970ae54
RR
1464#if WXWIN_COMPATIBILITY_2_8
1465 // for compatibility with the old code when wxCoord was long everywhere
1466void wxDC::GetTextExtent(const wxString& string,
1467 long *x, long *y,
1468 long *descent,
1469 long *externalLeading,
1470 const wxFont *theFont) const
1471 {
1472 wxCoord x2, y2, descent2, externalLeading2;
1473 m_pimpl->DoGetTextExtent(string, &x2, &y2,
1474 &descent2, &externalLeading2,
1475 theFont);
1476 if ( x )
1477 *x = x2;
1478 if ( y )
1479 *y = y2;
1480 if ( descent )
1481 *descent = descent2;
1482 if ( externalLeading )
1483 *externalLeading = externalLeading2;
1484 }
1485
1486void wxDC::GetLogicalOrigin(long *x, long *y) const
1487 {
1488 wxCoord x2, y2;
1489 m_pimpl->DoGetLogicalOrigin(&x2, &y2);
1490 if ( x )
1491 *x = x2;
1492 if ( y )
1493 *y = y2;
1494 }
1495
1496void wxDC::GetDeviceOrigin(long *x, long *y) const
1497 {
1498 wxCoord x2, y2;
1499 m_pimpl->DoGetDeviceOrigin(&x2, &y2);
1500 if ( x )
1501 *x = x2;
1502 if ( y )
1503 *y = y2;
1504 }
1505
1506void wxDC::GetClippingBox(long *x, long *y, long *w, long *h) const
1507 {
1508 wxCoord xx,yy,ww,hh;
1509 m_pimpl->DoGetClippingBox(&xx, &yy, &ww, &hh);
1510 if (x) *x = xx;
1511 if (y) *y = yy;
1512 if (w) *w = ww;
1513 if (h) *h = hh;
1514 }
1515
1516#endif // WXWIN_COMPATIBILITY_2_8
1517
1518
1519#else // wxUSE_NEW_DC
1520
1521
68379eaf 1522// bool wxDCBase::sm_cacheing = false;
0cbff120 1523
e7445ff8
PC
1524IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject)
1525
1e6feb95
VZ
1526// ============================================================================
1527// implementation
1528// ============================================================================
1529
653752be
MB
1530IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC)
1531IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC)
1532
04ab8b6d
RR
1533wxDCBase::wxDCBase()
1534 : m_colour(wxColourDisplay())
1535 , m_ok(true)
1536 , m_clipping(false)
1537 , m_isInteractive(0)
1538 , m_isBBoxValid(false)
1539 , m_logicalOriginX(0), m_logicalOriginY(0)
1540 , m_deviceOriginX(0), m_deviceOriginY(0)
1541 , m_deviceLocalOriginX(0), m_deviceLocalOriginY(0)
1542 , m_logicalScaleX(1.0), m_logicalScaleY(1.0)
1543 , m_userScaleX(1.0), m_userScaleY(1.0)
1544 , m_scaleX(1.0), m_scaleY(1.0)
1545 , m_signX(1), m_signY(1)
1546 , m_minX(0), m_minY(0), m_maxX(0), m_maxY(0)
1547 , m_clipX1(0), m_clipY1(0), m_clipX2(0), m_clipY2(0)
1548 , m_logicalFunction(wxCOPY)
1549 , m_backgroundMode(wxTRANSPARENT)
1550 , m_mappingMode(wxMM_TEXT)
1551 , m_pen()
1552 , m_brush()
1553 , m_backgroundBrush(*wxTRANSPARENT_BRUSH)
1554 , m_textForegroundColour(*wxBLACK)
1555 , m_textBackgroundColour(*wxWHITE)
1556 , m_font()
1557#if wxUSE_PALETTE
1558 , m_palette()
1559 , m_hasCustomPalette(false)
1560#endif // wxUSE_PALETTE
1561{
1562 m_mm_to_pix_x = (double)wxGetDisplaySize().GetWidth() /
1563 (double)wxGetDisplaySizeMM().GetWidth();
1564 m_mm_to_pix_y = (double)wxGetDisplaySize().GetHeight() /
1565 (double)wxGetDisplaySizeMM().GetHeight();
1566
1567 ResetBoundingBox();
1568 ResetClipping();
1569}
1570
1571wxDCBase::~wxDCBase()
1572{
1573}
1574
68df211f
JG
1575#if WXWIN_COMPATIBILITY_2_6
1576void wxDCBase::BeginDrawing()
1577{
1578}
1579
1580void wxDCBase::EndDrawing()
1581{
1582}
1583#endif // WXWIN_COMPATIBILITY_2_6
1584
cfa87e81
RR
1585#if WXWIN_COMPATIBILITY_2_8
1586 // for compatibility with the old code when wxCoord was long everywhere
1587void wxDCBase::GetTextExtent(const wxString& string,
1588 long *x, long *y,
27ee942f
PC
1589 long *descent,
1590 long *externalLeading,
1591 const wxFont *theFont) const
cfa87e81
RR
1592 {
1593 wxCoord x2, y2, descent2, externalLeading2;
1594 DoGetTextExtent(string, &x2, &y2,
1595 &descent2, &externalLeading2,
1596 theFont);
1597 if ( x )
1598 *x = x2;
1599 if ( y )
1600 *y = y2;
1601 if ( descent )
1602 *descent = descent2;
1603 if ( externalLeading )
1604 *externalLeading = externalLeading2;
1605 }
1606
1607void wxDCBase::GetLogicalOrigin(long *x, long *y) const
1608 {
1609 wxCoord x2, y2;
1610 DoGetLogicalOrigin(&x2, &y2);
1611 if ( x )
1612 *x = x2;
1613 if ( y )
1614 *y = y2;
1615 }
1616
1617void wxDCBase::GetDeviceOrigin(long *x, long *y) const
1618 {
1619 wxCoord x2, y2;
1620 DoGetDeviceOrigin(&x2, &y2);
1621 if ( x )
1622 *x = x2;
1623 if ( y )
1624 *y = y2;
1625 }
1626
1627void wxDCBase::GetClippingBox(long *x, long *y, long *w, long *h) const
1628 {
1629 wxCoord xx,yy,ww,hh;
1630 DoGetClippingBox(&xx, &yy, &ww, &hh);
1631 if (x) *x = xx;
1632 if (y) *y = yy;
1633 if (w) *w = ww;
1634 if (h) *h = hh;
1635 }
1636#endif // WXWIN_COMPATIBILITY_2_8
1637
1638
1639
04ab8b6d
RR
1640// ----------------------------------------------------------------------------
1641// coordinate conversions and transforms
1642// ----------------------------------------------------------------------------
1643
1644wxCoord wxDCBase::DeviceToLogicalX(wxCoord x) const
1645{
1646 return wxRound((double)(x - m_deviceOriginX - m_deviceLocalOriginX) / m_scaleX) * m_signX + m_logicalOriginX;
1647}
1648
1649wxCoord wxDCBase::DeviceToLogicalY(wxCoord y) const
1650{
1651 return wxRound((double)(y - m_deviceOriginY - m_deviceLocalOriginY) / m_scaleY) * m_signY + m_logicalOriginY;
1652}
1653
1654wxCoord wxDCBase::DeviceToLogicalXRel(wxCoord x) const
1655{
1656 return wxRound((double)(x) / m_scaleX);
1657}
1658
1659wxCoord wxDCBase::DeviceToLogicalYRel(wxCoord y) const
1660{
1661 return wxRound((double)(y) / m_scaleY);
1662}
1663
1664wxCoord wxDCBase::LogicalToDeviceX(wxCoord x) const
1665{
1666 return wxRound((double)(x - m_logicalOriginX) * m_scaleX) * m_signX + m_deviceOriginX + m_deviceLocalOriginX;
1667}
1668
1669wxCoord wxDCBase::LogicalToDeviceY(wxCoord y) const
1670{
1671 return wxRound((double)(y - m_logicalOriginY) * m_scaleY) * m_signY + m_deviceOriginY + m_deviceLocalOriginY;
1672}
1673
1674wxCoord wxDCBase::LogicalToDeviceXRel(wxCoord x) const
1675{
1676 return wxRound((double)(x) * m_scaleX);
1677}
1678
1679wxCoord wxDCBase::LogicalToDeviceYRel(wxCoord y) const
1680{
1681 return wxRound((double)(y) * m_scaleY);
1682}
1683
1684void wxDCBase::ComputeScaleAndOrigin()
1685{
1686 m_scaleX = m_logicalScaleX * m_userScaleX;
1687 m_scaleY = m_logicalScaleY * m_userScaleY;
1688}
1689
1690void wxDCBase::SetMapMode( int mode )
1691{
1692 switch (mode)
1693 {
1694 case wxMM_TWIPS:
1695 SetLogicalScale( twips2mm*m_mm_to_pix_x, twips2mm*m_mm_to_pix_y );
1696 break;
1697 case wxMM_POINTS:
1698 SetLogicalScale( pt2mm*m_mm_to_pix_x, pt2mm*m_mm_to_pix_y );
1699 break;
1700 case wxMM_METRIC:
1701 SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y );
1702 break;
1703 case wxMM_LOMETRIC:
1704 SetLogicalScale( m_mm_to_pix_x/10.0, m_mm_to_pix_y/10.0 );
1705 break;
1706 default:
1707 case wxMM_TEXT:
1708 SetLogicalScale( 1.0, 1.0 );
1709 break;
1710 }
1711 m_mappingMode = mode;
1712}
1713
1714void wxDCBase::SetUserScale( double x, double y )
1715{
1716 // allow negative ? -> no
1717 m_userScaleX = x;
1718 m_userScaleY = y;
1719 ComputeScaleAndOrigin();
1720}
1721
1722void wxDCBase::SetLogicalScale( double x, double y )
1723{
1724 // allow negative ?
1725 m_logicalScaleX = x;
1726 m_logicalScaleY = y;
1727 ComputeScaleAndOrigin();
1728}
1729
1730void wxDCBase::SetLogicalOrigin( wxCoord x, wxCoord y )
1731{
1732 m_logicalOriginX = x * m_signX;
1733 m_logicalOriginY = y * m_signY;
1734 ComputeScaleAndOrigin();
1735}
1736
1737void wxDCBase::SetDeviceOrigin( wxCoord x, wxCoord y )
1738{
1739 m_deviceOriginX = x;
1740 m_deviceOriginY = y;
1741 ComputeScaleAndOrigin();
1742}
1743
1744void wxDCBase::SetDeviceLocalOrigin( wxCoord x, wxCoord y )
1745{
1746 m_deviceLocalOriginX = x;
1747 m_deviceLocalOriginY = y;
1748 ComputeScaleAndOrigin();
1749}
1750
1751void wxDCBase::SetAxisOrientation( bool xLeftRight, bool yBottomUp )
1752{
1753 // only wxPostScripDC has m_signX = -1, we override SetAxisOrientation there
02255e07 1754 // wxWidgets 2.9: no longer override it
04ab8b6d
RR
1755 m_signX = (xLeftRight ? 1 : -1);
1756 m_signY = (yBottomUp ? -1 : 1);
1757 ComputeScaleAndOrigin();
1758}
1759
1e6feb95
VZ
1760// ----------------------------------------------------------------------------
1761// special symbols
1762// ----------------------------------------------------------------------------
1763
cd9da200
VZ
1764void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1,
1765 wxCoord width, wxCoord height)
1766{
1767 wxCHECK_RET( Ok(), wxT("invalid window dc") );
1768
1769 wxCoord x2 = x1 + width,
1770 y2 = y1 + height;
1771
860a4018
VZ
1772 // the pen width is calibrated to give 3 for width == height == 10
1773 wxDCPenChanger pen((wxDC&)*this,
1774 wxPen(GetTextForeground(), (width + height + 1)/7));
cd9da200
VZ
1775
1776 // we're drawing a scaled version of wx/generic/tick.xpm here
1777 wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom
1778 y3 = y1 + height / 2; // y of the left tick branch
1779 DoDrawLine(x1, y3, x3, y2);
1780 DoDrawLine(x3, y2, x2, y1);
1781
1782 CalcBoundingBox(x1, y1);
1783 CalcBoundingBox(x2, y2);
1784}
1785
e3b81044
VZ
1786// ----------------------------------------------------------------------------
1787// stubs for functions not implemented in all ports
1788// ----------------------------------------------------------------------------
1789
1790bool
1791wxDCBase::DoStretchBlit(wxCoord xdest, wxCoord ydest,
1792 wxCoord dstWidth, wxCoord dstHeight,
1793 wxDC *source,
1794 wxCoord xsrc, wxCoord ysrc,
ce2fe5bc 1795 wxCoord srcWidth, wxCoord srcHeight,
e3b81044
VZ
1796 int rop,
1797 bool useMask,
1798 wxCoord xsrcMask,
1799 wxCoord ysrcMask)
1800{
ce2fe5bc
VZ
1801 wxCHECK_MSG( srcWidth && srcHeight && dstWidth && dstHeight, false,
1802 _T("invalid blit size") );
1803
1804 // emulate the stretching by modifying the DC scale
1805 double xscale = (double)srcWidth/dstWidth,
1806 yscale = (double)srcHeight/dstHeight;
1807
1808 double xscaleOld, yscaleOld;
1809 GetUserScale(&xscaleOld, &yscaleOld);
1810 SetUserScale(xscaleOld/xscale, yscaleOld/yscale);
1811
1812 bool rc = DoBlit(wxCoord(xdest*xscale), wxCoord(ydest*yscale),
1813 wxCoord(dstWidth*xscale), wxCoord(dstHeight*yscale),
1814 source,
1815 xsrc, ysrc, rop, useMask, xsrcMask, ysrcMask);
1816
1817 SetUserScale(xscaleOld, yscaleOld);
1818
1819 return rc;
e3b81044
VZ
1820}
1821
1e6feb95
VZ
1822// ----------------------------------------------------------------------------
1823// line/polygons
1824// ----------------------------------------------------------------------------
1825
72cdf4c9 1826void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset)
dbe94982 1827{
b1d4dd7a 1828 int n = list->GetCount();
dbe94982
BM
1829 wxPoint *points = new wxPoint[n];
1830
1831 int i = 0;
222ed1d6 1832 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1833 {
b1d4dd7a 1834 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
1835 points[i].x = point->x;
1836 points[i].y = point->y;
1837 }
1838
1839 DoDrawLines(n, points, xoffset, yoffset);
1840
1841 delete [] points;
1842}
1843
1844
1845void wxDCBase::DrawPolygon(const wxList *list,
72cdf4c9 1846 wxCoord xoffset, wxCoord yoffset,
dbe94982
BM
1847 int fillStyle)
1848{
b1d4dd7a 1849 int n = list->GetCount();
dbe94982
BM
1850 wxPoint *points = new wxPoint[n];
1851
1852 int i = 0;
222ed1d6 1853 for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ )
dbe94982 1854 {
b1d4dd7a 1855 wxPoint *point = (wxPoint *)node->GetData();
dbe94982
BM
1856 points[i].x = point->x;
1857 points[i].y = point->y;
1858 }
1859
1860 DoDrawPolygon(n, points, xoffset, yoffset, fillStyle);
1861
1862 delete [] points;
1863}
1864
63b9e659
VZ
1865void
1866wxDCBase::DoDrawPolyPolygon(int n,
793db755 1867 int count[],
63b9e659
VZ
1868 wxPoint points[],
1869 wxCoord xoffset, wxCoord yoffset,
1870 int fillStyle)
1871{
1872 if ( n == 1 )
1873 {
793db755 1874 DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle);
63b9e659
VZ
1875 return;
1876 }
1877
1878 int i, j, lastOfs;
1879 wxPoint* pts;
1880 wxPen pen;
1881
1882 for (i = j = lastOfs = 0; i < n; i++)
1883 {
1884 lastOfs = j;
793db755 1885 j += count[i];
63b9e659
VZ
1886 }
1887 pts = new wxPoint[j+n-1];
1888 for (i = 0; i < j; i++)
1889 pts[i] = points[i];
1890 for (i = 2; i <= n; i++)
1891 {
793db755 1892 lastOfs -= count[n-i];
63b9e659
VZ
1893 pts[j++] = pts[lastOfs];
1894 }
1895
1896 pen = GetPen();
1897 SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT));
1898 DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle);
1899 SetPen(pen);
1900 for (i = j = 0; i < n; i++)
1901 {
793db755
VZ
1902 DoDrawLines(count[i], pts+j, xoffset, yoffset);
1903 j += count[i];
63b9e659 1904 }
6db1f43b 1905 delete[] pts;
63b9e659
VZ
1906}
1907
1e6feb95
VZ
1908// ----------------------------------------------------------------------------
1909// splines
1910// ----------------------------------------------------------------------------
dbe94982 1911
88ac883a 1912#if wxUSE_SPLINES
dbe94982
BM
1913
1914// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?)
72cdf4c9 1915void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3)
dbe94982
BM
1916{
1917 wxList point_list;
1918
1919 wxPoint *point1 = new wxPoint;
1920 point1->x = x1; point1->y = y1;
1921 point_list.Append((wxObject*)point1);
1922
1923 wxPoint *point2 = new wxPoint;
1924 point2->x = x2; point2->y = y2;
1925 point_list.Append((wxObject*)point2);
1926
1927 wxPoint *point3 = new wxPoint;
1928 point3->x = x3; point3->y = y3;
1929 point_list.Append((wxObject*)point3);
1930
1931 DrawSpline(&point_list);
1932
222ed1d6 1933 for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() )
dbe94982 1934 {
b1d4dd7a 1935 wxPoint *p = (wxPoint *)node->GetData();
dbe94982
BM
1936 delete p;
1937 }
1938}
1939
1940void wxDCBase::DrawSpline(int n, wxPoint points[])
1941{
1942 wxList list;
1943 for (int i =0; i < n; i++)
1944 {
1945 list.Append((wxObject*)&points[i]);
1946 }
1947
1948 DrawSpline(&list);
1949}
1950
fe2e4366
VS
1951// ----------------------------------- spline code ----------------------------------------
1952
1953void wx_quadratic_spline(double a1, double b1, double a2, double b2,
1954 double a3, double b3, double a4, double b4);
1955void wx_clear_stack();
1956int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3,
1957 double *y3, double *x4, double *y4);
1958void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3,
1959 double x4, double y4);
1960static bool wx_spline_add_point(double x, double y);
1961static void wx_spline_draw_point_array(wxDCBase *dc);
1962
1963wxList wx_spline_point_list;
1964
1965#define half(z1, z2) ((z1+z2)/2.0)
1966#define THRESHOLD 5
1967
1968/* iterative version */
1969
1970void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4,
1971 double b4)
1972{
1973 register double xmid, ymid;
1974 double x1, y1, x2, y2, x3, y3, x4, y4;
1975
1976 wx_clear_stack();
1977 wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4);
1978
1979 while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) {
1980 xmid = (double)half(x2, x3);
1981 ymid = (double)half(y2, y3);
1982 if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD &&
1983 fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) {
1984 wx_spline_add_point( x1, y1 );
1985 wx_spline_add_point( xmid, ymid );
1986 } else {
1987 wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3),
1988 (double)half(x3, x4), (double)half(y3, y4), x4, y4);
1989 wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2),
1990 (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid);
1991 }
1992 }
1993}
1994
1995/* utilities used by spline drawing routines */
1996
1997typedef struct wx_spline_stack_struct {
1998 double x1, y1, x2, y2, x3, y3, x4, y4;
1999} Stack;
2000
2001#define SPLINE_STACK_DEPTH 20
2002static Stack wx_spline_stack[SPLINE_STACK_DEPTH];
2003static Stack *wx_stack_top;
2004static int wx_stack_count;
2005
2006void wx_clear_stack()
2007{
2008 wx_stack_top = wx_spline_stack;
2009 wx_stack_count = 0;
2010}
2011
2012void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
2013{
2014 wx_stack_top->x1 = x1;
2015 wx_stack_top->y1 = y1;
2016 wx_stack_top->x2 = x2;
2017 wx_stack_top->y2 = y2;
2018 wx_stack_top->x3 = x3;
2019 wx_stack_top->y3 = y3;
2020 wx_stack_top->x4 = x4;
2021 wx_stack_top->y4 = y4;
2022 wx_stack_top++;
2023 wx_stack_count++;
2024}
2025
2026int wx_spline_pop(double *x1, double *y1, double *x2, double *y2,
2027 double *x3, double *y3, double *x4, double *y4)
2028{
2029 if (wx_stack_count == 0)
2030 return (0);
2031 wx_stack_top--;
2032 wx_stack_count--;
2033 *x1 = wx_stack_top->x1;
2034 *y1 = wx_stack_top->y1;
2035 *x2 = wx_stack_top->x2;
2036 *y2 = wx_stack_top->y2;
2037 *x3 = wx_stack_top->x3;
2038 *y3 = wx_stack_top->y3;
2039 *x4 = wx_stack_top->x4;
2040 *y4 = wx_stack_top->y4;
2041 return (1);
2042}
2043
2044static bool wx_spline_add_point(double x, double y)
2045{
2046 wxPoint *point = new wxPoint ;
2047 point->x = (int) x;
2048 point->y = (int) y;
2049 wx_spline_point_list.Append((wxObject*)point);
68379eaf 2050 return true;
fe2e4366
VS
2051}
2052
2053static void wx_spline_draw_point_array(wxDCBase *dc)
2054{
2055 dc->DrawLines(&wx_spline_point_list, 0, 0 );
222ed1d6 2056 wxList::compatibility_iterator node = wx_spline_point_list.GetFirst();
fe2e4366
VS
2057 while (node)
2058 {
b1d4dd7a 2059 wxPoint *point = (wxPoint *)node->GetData();
fe2e4366 2060 delete point;
222ed1d6 2061 wx_spline_point_list.Erase(node);
b1d4dd7a 2062 node = wx_spline_point_list.GetFirst();
fe2e4366
VS
2063 }
2064}
2065
2066void wxDCBase::DoDrawSpline( wxList *points )
2067{
2068 wxCHECK_RET( Ok(), wxT("invalid window dc") );
2069
2070 wxPoint *p;
2071 double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4;
2072 double x1, y1, x2, y2;
2073
222ed1d6 2074 wxList::compatibility_iterator node = points->GetFirst();
ef419e3b 2075 if (!node)
410bb8c1
RD
2076 // empty list
2077 return;
e0d31471 2078
b1d4dd7a 2079 p = (wxPoint *)node->GetData();
fe2e4366
VS
2080
2081 x1 = p->x;
2082 y1 = p->y;
2083
b1d4dd7a
RL
2084 node = node->GetNext();
2085 p = (wxPoint *)node->GetData();
fe2e4366
VS
2086
2087 x2 = p->x;
2088 y2 = p->y;
2089 cx1 = (double)((x1 + x2) / 2);
2090 cy1 = (double)((y1 + y2) / 2);
2091 cx2 = (double)((cx1 + x2) / 2);
2092 cy2 = (double)((cy1 + y2) / 2);
2093
2094 wx_spline_add_point(x1, y1);
2095
28b4db7f
VZ
2096 while ((node = node->GetNext())
2097#if !wxUSE_STL
2098 != NULL
2099#endif // !wxUSE_STL
2100 )
fe2e4366 2101 {
b1d4dd7a 2102 p = (wxPoint *)node->GetData();
fe2e4366
VS
2103 x1 = x2;
2104 y1 = y2;
2105 x2 = p->x;
2106 y2 = p->y;
2107 cx4 = (double)(x1 + x2) / 2;
2108 cy4 = (double)(y1 + y2) / 2;
2109 cx3 = (double)(x1 + cx4) / 2;
2110 cy3 = (double)(y1 + cy4) / 2;
2111
2112 wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
2113
2114 cx1 = cx4;
2115 cy1 = cy4;
2116 cx2 = (double)(cx1 + x2) / 2;
2117 cy2 = (double)(cy1 + y2) / 2;
2118 }
2119
2120 wx_spline_add_point( cx1, cy1 );
2121 wx_spline_add_point( x2, y2 );
2122
2123 wx_spline_draw_point_array( this );
2124}
2125
88ac883a 2126#endif // wxUSE_SPLINES
1e6feb95 2127
0919e93e
RD
2128// ----------------------------------------------------------------------------
2129// Partial Text Extents
2130// ----------------------------------------------------------------------------
2131
2132
174ee1b3 2133// Each element of the widths array will be the width of the string up to and
3103e8a9 2134// including the corresponding character in text. This is the generic
0919e93e 2135// implementation, the port-specific classes should do this with native APIs
174ee1b3
RD
2136// if available and if faster. Note: pango_layout_index_to_pos is much slower
2137// than calling GetTextExtent!!
2138
06fe86b7 2139#define FWC_SIZE 256
174ee1b3
RD
2140
2141class FontWidthCache
2142{
2143public:
2144 FontWidthCache() : m_scaleX(1), m_widths(NULL) { }
2145 ~FontWidthCache() { delete []m_widths; }
2aaa050c
VZ
2146
2147 void Reset()
2148 {
2149 if (!m_widths)
2150 m_widths = new int[FWC_SIZE];
2151
2152 memset(m_widths, 0, sizeof(int)*FWC_SIZE);
2153 }
2154
174ee1b3
RD
2155 wxFont m_font;
2156 double m_scaleX;
2157 int *m_widths;
2158};
2159
2160static FontWidthCache s_fontWidthCache;
0919e93e
RD
2161
2162bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const
2163{
2164 int totalWidth = 0;
0919e93e 2165
18680f86 2166 const size_t len = text.length();
0919e93e 2167 widths.Empty();
174ee1b3 2168 widths.Add(0, len);
2aaa050c 2169
174ee1b3 2170 // reset the cache if font or horizontal scale have changed
c77a6796
VZ
2171 if ( !s_fontWidthCache.m_widths ||
2172 !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) ||
2173 (s_fontWidthCache.m_font != GetFont()) )
174ee1b3
RD
2174 {
2175 s_fontWidthCache.Reset();
2176 s_fontWidthCache.m_font = GetFont();
2177 s_fontWidthCache.m_scaleX = m_scaleX;
2178 }
2179
0919e93e
RD
2180 // Calculate the position of each character based on the widths of
2181 // the previous characters
c77a6796
VZ
2182 int w, h;
2183 for ( size_t i = 0; i < len; i++ )
174ee1b3
RD
2184 {
2185 const wxChar c = text[i];
2186 unsigned int c_int = (unsigned int)c;
2187
2aaa050c 2188 if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0))
174ee1b3
RD
2189 {
2190 w = s_fontWidthCache.m_widths[c_int];
2191 }
2aaa050c 2192 else
174ee1b3
RD
2193 {
2194 GetTextExtent(c, &w, &h);
2195 if (c_int < FWC_SIZE)
2196 s_fontWidthCache.m_widths[c_int] = w;
2197 }
2198
0919e93e
RD
2199 totalWidth += w;
2200 widths[i] = totalWidth;
2201 }
2aaa050c 2202
0919e93e
RD
2203 return true;
2204}
2205
2206
1e6feb95
VZ
2207// ----------------------------------------------------------------------------
2208// enhanced text drawing
2209// ----------------------------------------------------------------------------
2210
2211void wxDCBase::GetMultiLineTextExtent(const wxString& text,
2212 wxCoord *x,
2213 wxCoord *y,
2214 wxCoord *h,
c94f845b 2215 const wxFont *font) const
1e6feb95 2216{
c7aaa64f
VS
2217 wxCoord widthTextMax = 0, widthLine,
2218 heightTextTotal = 0, heightLineDefault = 0, heightLine = 0;
1e6feb95
VZ
2219
2220 wxString curLine;
86501081 2221 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2222 {
86501081 2223 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2224 {
2225 if ( curLine.empty() )
2226 {
2227 // we can't use GetTextExtent - it will return 0 for both width
2228 // and height and an empty line should count in height
2229 // calculation
2230
2231 // assume that this line has the same height as the previous
2232 // one
2233 if ( !heightLineDefault )
2234 heightLineDefault = heightLine;
2235
2236 if ( !heightLineDefault )
2237 {
2238 // but we don't know it yet - choose something reasonable
2239 GetTextExtent(_T("W"), NULL, &heightLineDefault,
2240 NULL, NULL, font);
2241 }
2242
2243 heightTextTotal += heightLineDefault;
2244 }
2245 else
2246 {
2247 GetTextExtent(curLine, &widthLine, &heightLine,
2248 NULL, NULL, font);
2249 if ( widthLine > widthTextMax )
2250 widthTextMax = widthLine;
2251 heightTextTotal += heightLine;
2252 }
2253
86501081 2254 if ( pc == text.end() )
1e6feb95 2255 {
86501081 2256 break;
1e6feb95 2257 }
86501081 2258 else // '\n'
1e6feb95 2259 {
86501081 2260 curLine.clear();
1e6feb95
VZ
2261 }
2262 }
2263 else
2264 {
2265 curLine += *pc;
2266 }
2267 }
2268
2269 if ( x )
2270 *x = widthTextMax;
2271 if ( y )
2272 *y = heightTextTotal;
2273 if ( h )
2274 *h = heightLine;
2275}
2276
2277void wxDCBase::DrawLabel(const wxString& text,
2278 const wxBitmap& bitmap,
2279 const wxRect& rect,
2280 int alignment,
2281 int indexAccel,
2282 wxRect *rectBounding)
2283{
2284 // find the text position
2285 wxCoord widthText, heightText, heightLine;
2286 GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine);
2287
2288 wxCoord width, height;
2289 if ( bitmap.Ok() )
2290 {
2291 width = widthText + bitmap.GetWidth();
2292 height = bitmap.GetHeight();
2293 }
2294 else // no bitmap
2295 {
2296 width = widthText;
2297 height = heightText;
2298 }
2299
2300 wxCoord x, y;
2301 if ( alignment & wxALIGN_RIGHT )
2302 {
2303 x = rect.GetRight() - width;
2304 }
2305 else if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2306 {
2307 x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2;
2308 }
2309 else // alignment & wxALIGN_LEFT
2310 {
2311 x = rect.GetLeft();
2312 }
2313
2314 if ( alignment & wxALIGN_BOTTOM )
2315 {
2316 y = rect.GetBottom() - height;
2317 }
2318 else if ( alignment & wxALIGN_CENTRE_VERTICAL )
2319 {
2320 y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2;
2321 }
2322 else // alignment & wxALIGN_TOP
2323 {
2324 y = rect.GetTop();
2325 }
2326
2327 // draw the bitmap first
2328 wxCoord x0 = x,
2329 y0 = y,
2330 width0 = width;
2331 if ( bitmap.Ok() )
2332 {
68379eaf 2333 DrawBitmap(bitmap, x, y, true /* use mask */);
1e6feb95
VZ
2334
2335 wxCoord offset = bitmap.GetWidth() + 4;
2336 x += offset;
2337 width -= offset;
2338
2339 y += (height - heightText) / 2;
2340 }
2341
2342 // we will draw the underscore under the accel char later
2343 wxCoord startUnderscore = 0,
2344 endUnderscore = 0,
2345 yUnderscore = 0;
2346
2347 // split the string into lines and draw each of them separately
2348 wxString curLine;
c9f78968 2349 for ( wxString::const_iterator pc = text.begin(); ; ++pc )
1e6feb95 2350 {
f5595af6 2351 if ( pc == text.end() || *pc == _T('\n') )
1e6feb95
VZ
2352 {
2353 int xRealStart = x; // init it here to avoid compielr warnings
2354
2355 if ( !curLine.empty() )
2356 {
2357 // NB: can't test for !(alignment & wxALIGN_LEFT) because
2358 // wxALIGN_LEFT is 0
2359 if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) )
2360 {
2361 wxCoord widthLine;
2362 GetTextExtent(curLine, &widthLine, NULL);
2363
2364 if ( alignment & wxALIGN_RIGHT )
2365 {
2366 xRealStart += width - widthLine;
2367 }
2368 else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL )
2369 {
2370 xRealStart += (width - widthLine) / 2;
2371 }
2372 }
2373 //else: left aligned, nothing to do
2374
2375 DrawText(curLine, xRealStart, y);
2376 }
2377
2378 y += heightLine;
2379
2380 // do we have underscore in this line? we can check yUnderscore
2381 // because it is set below to just y + heightLine if we do
2382 if ( y == yUnderscore )
2383 {
2384 // adjust the horz positions to account for the shift
2385 startUnderscore += xRealStart;
2386 endUnderscore += xRealStart;
2387 }
2388
c9f78968 2389 if ( pc == text.end() )
1e6feb95
VZ
2390 break;
2391
2392 curLine.clear();
2393 }
2394 else // not end of line
2395 {
9daaea28 2396 if ( pc - text.begin() == indexAccel )
1e6feb95
VZ
2397 {
2398 // remeber to draw underscore here
2399 GetTextExtent(curLine, &startUnderscore, NULL);
2400 curLine += *pc;
2401 GetTextExtent(curLine, &endUnderscore, NULL);
2402
2403 yUnderscore = y + heightLine;
2404 }
2405 else
2406 {
2407 curLine += *pc;
2408 }
2409 }
2410 }
2411
2412 // draw the underscore if found
2413 if ( startUnderscore != endUnderscore )
2414 {
2415 // it should be of the same colour as text
2416 SetPen(wxPen(GetTextForeground(), 0, wxSOLID));
2417
2418 yUnderscore--;
2419
2420 DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore);
2421 }
2422
2423 // return bounding rect if requested
2424 if ( rectBounding )
2425 {
2426 *rectBounding = wxRect(x, y - heightText, widthText, heightText);
2427 }
2428
2429 CalcBoundingBox(x0, y0);
2430 CalcBoundingBox(x0 + width0, y0 + height);
2431}
12bdd77c 2432
213ad8e7
VZ
2433
2434void wxDCBase::DoGradientFillLinear(const wxRect& rect,
2435 const wxColour& initialColour,
2436 const wxColour& destColour,
2437 wxDirection nDirection)
2438{
2439 // save old pen
2440 wxPen oldPen = m_pen;
a983a3cf 2441 wxBrush oldBrush = m_brush;
213ad8e7 2442
6dff0e29
BW
2443 wxUint8 nR1 = initialColour.Red();
2444 wxUint8 nG1 = initialColour.Green();
2445 wxUint8 nB1 = initialColour.Blue();
2446 wxUint8 nR2 = destColour.Red();
2447 wxUint8 nG2 = destColour.Green();
2448 wxUint8 nB2 = destColour.Blue();
213ad8e7
VZ
2449 wxUint8 nR, nG, nB;
2450
2451 if ( nDirection == wxEAST || nDirection == wxWEST )
2452 {
2453 wxInt32 x = rect.GetWidth();
2454 wxInt32 w = x; // width of area to shade
2455 wxInt32 xDelta = w/256; // height of one shade bend
2456 if (xDelta < 1)
2457 xDelta = 1;
2458
2459 while (x >= xDelta)
2460 {
2461 x -= xDelta;
2462 if (nR1 > nR2)
2463 nR = nR1 - (nR1-nR2)*(w-x)/w;
2464 else
2465 nR = nR1 + (nR2-nR1)*(w-x)/w;
2466
2467 if (nG1 > nG2)
2468 nG = nG1 - (nG1-nG2)*(w-x)/w;
2469 else
2470 nG = nG1 + (nG2-nG1)*(w-x)/w;
2471
2472 if (nB1 > nB2)
2473 nB = nB1 - (nB1-nB2)*(w-x)/w;
2474 else
2475 nB = nB1 + (nB2-nB1)*(w-x)/w;
2476
e3b81044 2477 wxColour colour(nR,nG,nB);
1dab6da9
BW
2478 SetPen(wxPen(colour, 1, wxSOLID));
2479 SetBrush(wxBrush(colour));
213ad8e7 2480 if(nDirection == wxEAST)
5f77ee3b 2481 DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(),
213ad8e7
VZ
2482 xDelta, rect.GetHeight());
2483 else //nDirection == wxWEST
1dab6da9 2484 DrawRectangle(rect.GetLeft()+x, rect.GetTop(),
213ad8e7
VZ
2485 xDelta, rect.GetHeight());
2486 }
2487 }
2488 else // nDirection == wxNORTH || nDirection == wxSOUTH
2489 {
2490 wxInt32 y = rect.GetHeight();
2491 wxInt32 w = y; // height of area to shade
2492 wxInt32 yDelta = w/255; // height of one shade bend
2493 if (yDelta < 1)
2494 yDelta = 1;
2495
2496 while (y > 0)
2497 {
2498 y -= yDelta;
2499 if (nR1 > nR2)
2500 nR = nR1 - (nR1-nR2)*(w-y)/w;
2501 else
2502 nR = nR1 + (nR2-nR1)*(w-y)/w;
2503
2504 if (nG1 > nG2)
2505 nG = nG1 - (nG1-nG2)*(w-y)/w;
2506 else
2507 nG = nG1 + (nG2-nG1)*(w-y)/w;
2508
2509 if (nB1 > nB2)
2510 nB = nB1 - (nB1-nB2)*(w-y)/w;
2511 else
2512 nB = nB1 + (nB2-nB1)*(w-y)/w;
2513
e3b81044 2514 wxColour colour(nR,nG,nB);
1dab6da9
BW
2515 SetPen(wxPen(colour, 1, wxSOLID));
2516 SetBrush(wxBrush(colour));
213ad8e7
VZ
2517 if(nDirection == wxNORTH)
2518 DrawRectangle(rect.GetLeft(), rect.GetTop()+y,
2519 rect.GetWidth(), yDelta);
2520 else //nDirection == wxSOUTH
5f77ee3b 2521 DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1,
213ad8e7
VZ
2522 rect.GetWidth(), yDelta);
2523 }
2524 }
2525
2526 SetPen(oldPen);
a983a3cf 2527 SetBrush(oldBrush);
213ad8e7
VZ
2528}
2529
fb63a242 2530void wxDCBase::DoGradientFillConcentric(const wxRect& rect,
213ad8e7
VZ
2531 const wxColour& initialColour,
2532 const wxColour& destColour,
2533 const wxPoint& circleCenter)
2534{
2535 //save the old pen color
2536 wxColour oldPenColour = m_pen.GetColour();
2537
2538 wxUint8 nR1 = destColour.Red();
2539 wxUint8 nG1 = destColour.Green();
2540 wxUint8 nB1 = destColour.Blue();
2541 wxUint8 nR2 = initialColour.Red();
2542 wxUint8 nG2 = initialColour.Green();
2543 wxUint8 nB2 = initialColour.Blue();
2544 wxUint8 nR, nG, nB;
2545
2546
213ad8e7
VZ
2547 //Radius
2548 wxInt32 cx = rect.GetWidth() / 2;
2549 wxInt32 cy = rect.GetHeight() / 2;
2550 wxInt32 nRadius;
2551 if (cx < cy)
2552 nRadius = cx;
2553 else
2554 nRadius = cy;
2555
2556 //Offset of circle
2557 wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2);
2558 wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2);
2559
e35d07b9 2560 for ( wxInt32 x = 0; x < rect.GetWidth(); x++ )
213ad8e7 2561 {
e35d07b9 2562 for ( wxInt32 y = 0; y < rect.GetHeight(); y++ )
213ad8e7
VZ
2563 {
2564 //get color difference
e35d07b9
VZ
2565 wxInt32 nGradient = ((nRadius -
2566 (wxInt32)sqrt(
2567 pow((double)(x - cx - nCircleOffX), 2) +
2568 pow((double)(y - cy - nCircleOffY), 2)
2569 )) * 100) / nRadius;
213ad8e7
VZ
2570
2571 //normalize Gradient
2572 if (nGradient < 0 )
2573 nGradient = 0;
2574
2575 //get dest colors
06052f3f
WS
2576 nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100));
2577 nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100));
2578 nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100));
213ad8e7
VZ
2579
2580 //set the pixel
2581 m_pen.SetColour(wxColour(nR,nG,nB));
2582 DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop()));
2583 }
2584 }
2585 //return old pen color
2586 m_pen.SetColour(oldPenColour);
2587}
2588
12bdd77c 2589/*
77ffb593 2590Notes for wxWidgets DrawEllipticArcRot(...)
12bdd77c
JS
2591
2592wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse.
2593It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...),
2594which are also new.
2595
2596All methods are generic, so they can be implemented in wxDCBase.
2597DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper
2598methods like (WinCE) wxDC::DoDrawArc(...).
2599
2600CalculateEllipticPoints(...) fills a given list of wxPoints with some points
2aaa050c 2601of an elliptic arc. The algorithm is pixel-based: In every row (in flat
12bdd77c
JS
2602parts) or every column (in steep parts) only one pixel is calculated.
2603Trigonometric calculation (sin, cos, tan, atan) is only done if the
2aaa050c 2604starting angle is not equal to the ending angle. The calculation of the
12bdd77c
JS
2605pixels is done using simple arithmetic only and should perform not too
2606bad even on devices without floating point processor. I didn't test this yet.
2607
2608Rotate(...) rotates a list of point pixel-based, you will see rounding errors.
2aaa050c 2609For instance: an ellipse rotated 180 degrees is drawn
12bdd77c
JS
2610slightly different from the original.
2611
2aaa050c
VZ
2612The points are then moved to an array and used to draw a polyline and/or polygon
2613(with center added, the pie).
12bdd77c
JS
2614The result looks quite similar to the native ellipse, only e few pixels differ.
2615
2616The performance on a desktop system (Athlon 1800, WinXP) is about 7 times
2617slower as DrawEllipse(...), which calls the native API.
2618An rotated ellipse outside the clipping region takes nearly the same time,
2619while an native ellipse outside takes nearly no time to draw.
2620
2aaa050c 2621If you draw an arc with this new method, you will see the starting and ending angles
12bdd77c
JS
2622are calculated properly.
2623If you use DrawEllipticArc(...), you will see they are only correct for circles
2624and not properly calculated for ellipses.
2625
2626Peter Lenhard
2627p.lenhard@t-online.de
2628*/
2629
2630#ifdef __WXWINCE__
2aaa050c
VZ
2631void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y,
2632 wxCoord w, wxCoord h,
12bdd77c
JS
2633 double sa, double ea, double angle )
2634{
2635 wxList list;
2636
2637 CalculateEllipticPoints( &list, x, y, w, h, sa, ea );
2638 Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) );
2639
2640 // Add center (for polygon/pie)
2641 list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) );
2642
2643 // copy list into array and delete list elements
2c3ebf8b 2644 int n = list.GetCount();
12bdd77c
JS
2645 wxPoint *points = new wxPoint[n];
2646 int i = 0;
2aaa050c 2647 wxNode* node = 0;
2c3ebf8b 2648 for ( node = list.GetFirst(); node; node = node->GetNext(), i++ )
12bdd77c 2649 {
2c3ebf8b 2650 wxPoint *point = (wxPoint *)node->GetData();
12bdd77c
JS
2651 points[i].x = point->x;
2652 points[i].y = point->y;
2653 delete point;
2654 }
2655
2656 // first draw the pie without pen, if necessary
63b9e659 2657 if( GetBrush() != *wxTRANSPARENT_BRUSH )
12bdd77c
JS
2658 {
2659 wxPen tempPen( GetPen() );
2660 SetPen( *wxTRANSPARENT_PEN );
2661 DoDrawPolygon( n, points, 0, 0 );
2662 SetPen( tempPen );
2663 }
2664
2665 // then draw the arc without brush, if necessary
63b9e659 2666 if( GetPen() != *wxTRANSPARENT_PEN )
12bdd77c
JS
2667 {
2668 // without center
2669 DoDrawLines( n-1, points, 0, 0 );
2670 }
2671
2672 delete [] points;
2673
2674} // DrawEllipticArcRot
2675
2676void wxDCBase::Rotate( wxList* points, double angle, wxPoint center )
2677{
2678 if( angle != 0.0 )
2679 {
e0d31471 2680 double pi(M_PI);
12bdd77c
JS
2681 double dSinA = -sin(angle*2.0*pi/360.0);
2682 double dCosA = cos(angle*2.0*pi/360.0);
2c3ebf8b 2683 for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() )
12bdd77c 2684 {
2c3ebf8b 2685 wxPoint* point = (wxPoint*)node->GetData();
2aaa050c 2686
12bdd77c
JS
2687 // transform coordinates, if necessary
2688 if( center.x ) point->x -= center.x;
2689 if( center.y ) point->y -= center.y;
2690
2691 // calculate rotation, rounding simply by implicit cast to integer
2692 int xTemp = point->x * dCosA - point->y * dSinA;
2693 point->y = point->x * dSinA + point->y * dCosA;
2694 point->x = xTemp;
2695
2696 // back transform coordinates, if necessary
2697 if( center.x ) point->x += center.x;
2698 if( center.y ) point->y += center.y;
2699 }
2700 }
2701}
2702
2aaa050c
VZ
2703void wxDCBase::CalculateEllipticPoints( wxList* points,
2704 wxCoord xStart, wxCoord yStart,
2705 wxCoord w, wxCoord h,
12bdd77c
JS
2706 double sa, double ea )
2707{
e0d31471 2708 double pi = M_PI;
12bdd77c
JS
2709 double sar = 0;
2710 double ear = 0;
2711 int xsa = 0;
2712 int ysa = 0;
2713 int xea = 0;
2714 int yea = 0;
2715 int sq = 0;
2716 int eq = 0;
2717 bool bUseAngles = false;
2718 if( w<0 ) w = -w;
2719 if( h<0 ) h = -h;
2720 // half-axes
2721 wxCoord a = w/2;
2722 wxCoord b = h/2;
2723 // decrement 1 pixel if ellipse is smaller than 2*a, 2*b
2724 int decrX = 0;
2aaa050c 2725 if( 2*a == w ) decrX = 1;
12bdd77c 2726 int decrY = 0;
2aaa050c 2727 if( 2*b == h ) decrY = 1;
12bdd77c
JS
2728 // center
2729 wxCoord xCenter = xStart + a;
2730 wxCoord yCenter = yStart + b;
2731 // calculate data for start and end, if necessary
2732 if( sa != ea )
2733 {
2734 bUseAngles = true;
2735 // normalisation of angles
2736 while( sa<0 ) sa += 360;
2737 while( ea<0 ) ea += 360;
2738 while( sa>=360 ) sa -= 360;
2739 while( ea>=360 ) ea -= 360;
2740 // calculate quadrant numbers
2741 if( sa > 270 ) sq = 3;
2742 else if( sa > 180 ) sq = 2;
2743 else if( sa > 90 ) sq = 1;
2744 if( ea > 270 ) eq = 3;
2745 else if( ea > 180 ) eq = 2;
2746 else if( ea > 90 ) eq = 1;
2747 sar = sa * pi / 180.0;
2748 ear = ea * pi / 180.0;
2749 // correct angle circle -> ellipse
2750 sar = atan( -a/(double)b * tan( sar ) );
2aaa050c 2751 if ( sq == 1 || sq == 2 ) sar += pi;
12bdd77c
JS
2752 ear = atan( -a/(double)b * tan( ear ) );
2753 if ( eq == 1 || eq == 2 ) ear += pi;
2754 // coordinates of points
2755 xsa = xCenter + a * cos( sar );
2756 if( sq == 0 || sq == 3 ) xsa -= decrX;
2757 ysa = yCenter + b * sin( sar );
2758 if( sq == 2 || sq == 3 ) ysa -= decrY;
2759 xea = xCenter + a * cos( ear );
2760 if( eq == 0 || eq == 3 ) xea -= decrX;
2761 yea = yCenter + b * sin( ear );
2762 if( eq == 2 || eq == 3 ) yea -= decrY;
2763 } // if iUseAngles
2764 // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2
2765 double c1 = b * b;
2766 double c2 = 2.0 / w;
2767 c2 *= c2;
2768 c2 *= c1;
2769 wxCoord x = 0;
2770 wxCoord y = b;
2771 long x2 = 1;
2772 long y2 = y*y;
2773 long y2_old = 0;
2774 long y_old = 0;
2775 // Lists for quadrant 1 to 4
2776 wxList pointsarray[4];
2777 // Calculate points for first quadrant and set in all quadrants
2778 for( x = 0; x <= a; ++x )
2779 {
2780 x2 = x2+x+x-1;
2781 y2_old = y2;
2782 y_old = y;
2783 bool bNewPoint = false;
2784 while( y2 > c1 - c2 * x2 && y > 0 )
2785 {
2786 bNewPoint = true;
2787 y2 = y2-y-y+1;
2788 --y;
2789 }
2aaa050c 2790 // old y now to big: set point with old y, old x
12bdd77c
JS
2791 if( bNewPoint && x>1)
2792 {
2793 int x1 = x - 1;
2794 // remove points on the same line
2795 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) );
2796 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) );
2797 pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) );
2798 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) );
2799 } // set point
2800 } // calculate point
2aaa050c 2801
12bdd77c
JS
2802 // Starting and/or ending points for the quadrants, first quadrant gets both.
2803 pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
2804 pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) );
2805 pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) );
2806 pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) );
2807 pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) );
2808
2809 // copy quadrants in original list
2810 if( bUseAngles )
2811 {
2812 // Copy the right part of the points in the lists
2813 // and delete the wxPoints, because they do not leave this method.
2814 points->Append( (wxObject*) new wxPoint( xsa, ysa ) );
2815 int q = sq;
2816 bool bStarted = false;
2817 bool bReady = false;
2818 bool bForceTurn = ( sq == eq && sa > ea );
2819 while( !bReady )
2820 {
2c3ebf8b 2821 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c
JS
2822 {
2823 // once: go to starting point in start quadrant
2824 if( !bStarted &&
2aaa050c 2825 (
2c3ebf8b 2826 ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1
2aaa050c 2827 ||
2c3ebf8b 2828 ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2
12bdd77c 2829 )
2aaa050c 2830 )
12bdd77c
JS
2831 {
2832 bStarted = true;
2833 }
2834
2835 // copy point, if not at ending point
2836 if( bStarted )
2837 {
2838 if( q != eq || bForceTurn
2839 ||
2c3ebf8b 2840 ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1
2aaa050c 2841 ||
2c3ebf8b 2842 ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2
12bdd77c
JS
2843 )
2844 {
2845 // copy point
2c3ebf8b 2846 wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) );
12bdd77c
JS
2847 points->Append( (wxObject*) pPoint );
2848 }
2c3ebf8b 2849 else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea)
12bdd77c 2850 {
2aaa050c 2851 bReady = true;
12bdd77c
JS
2852 }
2853 }
2854 } // for node
2855 ++q;
2856 if( q > 3 ) q = 0;
2857 bForceTurn = false;
2858 bStarted = true;
2859 } // while not bReady
2860 points->Append( (wxObject*) new wxPoint( xea, yea ) );
2861
2862 // delete points
2863 for( q = 0; q < 4; ++q )
2864 {
2c3ebf8b 2865 for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() )
12bdd77c 2866 {
2c3ebf8b 2867 wxPoint *p = (wxPoint *)node->GetData();
12bdd77c
JS
2868 delete p;
2869 }
2aaa050c 2870 }
12bdd77c
JS
2871 }
2872 else
2873 {
b1c6a00e 2874 wxNode* node;
12bdd77c 2875 // copy whole ellipse, wxPoints will be deleted outside
2c3ebf8b 2876 for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() )
12bdd77c 2877 {
2c3ebf8b 2878 wxObject *p = node->GetData();
12bdd77c
JS
2879 points->Append( p );
2880 }
2c3ebf8b 2881 for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() )
12bdd77c 2882 {
2c3ebf8b 2883 wxObject *p = node->GetData();
12bdd77c
JS
2884 points->Append( p );
2885 }
2c3ebf8b 2886 for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() )
12bdd77c 2887 {
2c3ebf8b 2888 wxObject *p = node->GetData();
12bdd77c
JS
2889 points->Append( p );
2890 }
2c3ebf8b 2891 for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() )
12bdd77c 2892 {
2c3ebf8b 2893 wxObject *p = node->GetData();
12bdd77c
JS
2894 points->Append( p );
2895 }
2896 } // not iUseAngles
2897} // CalculateEllipticPoints
2898
e3b81044 2899#endif // __WXWINCE__
2970ae54
RR
2900
2901#endif // wxUSE_NEW_DC