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