]> git.saurik.com Git - wxWidgets.git/blob - src/msw/pen.cpp
supporting text foreground color, fixes #11903
[wxWidgets.git] / src / msw / pen.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/pen.cpp
3 // Purpose: wxPen
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin: refactored wxPen code to wxPenRefData
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #include "wx/pen.h"
28
29 #ifndef WX_PRECOMP
30 #include "wx/bitmap.h"
31 #include "wx/utils.h"
32 #endif
33
34 #include "wx/msw/private.h"
35
36 #define M_PENDATA ((wxPenRefData*)m_refData)
37
38 // Win32 has ExtCreatePen() but WinCE doesn't
39 #if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
40 #define wxHAVE_EXT_CREATE_PEN
41 #endif
42
43 // ----------------------------------------------------------------------------
44 // wxPenRefData: contains information about an HPEN and its handle
45 // ----------------------------------------------------------------------------
46
47 class WXDLLEXPORT wxPenRefData : public wxGDIRefData
48 {
49 public:
50 // ctors and dtor
51 // --------------
52
53 wxPenRefData();
54 wxPenRefData(const wxPenRefData& data);
55 wxPenRefData(const wxColour& col, int width, wxPenStyle style);
56 wxPenRefData(const wxBitmap& stipple, int width);
57 virtual ~wxPenRefData();
58
59 bool operator==(const wxPenRefData& data) const
60 {
61 // we intentionally don't compare m_hPen fields here
62 return m_style == data.m_style &&
63 m_width == data.m_width &&
64 m_join == data.m_join &&
65 m_cap == data.m_cap &&
66 m_colour == data.m_colour &&
67 (m_style != wxPENSTYLE_STIPPLE || m_stipple.IsSameAs(data.m_stipple)) &&
68 (m_style != wxPENSTYLE_USER_DASH ||
69 (m_nbDash == data.m_nbDash &&
70 memcmp(m_dash, data.m_dash, m_nbDash*sizeof(wxDash)) == 0));
71 }
72
73
74 // accessors and setters
75 // ---------------------
76
77 wxColour& GetColour() const { return const_cast<wxColour&>(m_colour); }
78 int GetWidth() const { return m_width; }
79 wxPenStyle GetStyle() const { return m_style; }
80 wxPenJoin GetJoin() const { return m_join; }
81 wxPenCap GetCap() const { return m_cap; }
82 wxDash* GetDash() const { return m_dash; }
83 int GetDashCount() const { return m_nbDash; }
84 wxBitmap* GetStipple() const { return const_cast<wxBitmap *>(&m_stipple); }
85
86 void SetColour(const wxColour& col) { Free(); m_colour = col; }
87 void SetWidth(int width) { Free(); m_width = width; }
88 void SetStyle(wxPenStyle style) { Free(); m_style = style; }
89 void SetStipple(const wxBitmap& stipple)
90 {
91 Free();
92
93 m_style = wxPENSTYLE_STIPPLE;
94 m_stipple = stipple;
95 }
96
97 void SetDashes(int nb_dashes, const wxDash *dash)
98 {
99 Free();
100
101 m_nbDash = nb_dashes;
102 m_dash = const_cast<wxDash *>(dash);
103 }
104
105 void SetJoin(wxPenJoin join) { Free(); m_join = join; }
106 void SetCap(wxPenCap cap) { Free(); m_cap = cap; }
107
108
109 // HPEN management
110 // ---------------
111
112 // create the HPEN if we don't have it yet
113 bool Alloc();
114
115 // get the HPEN creating it on demand
116 WXHPEN GetHPEN() const;
117
118 // return true if we have a valid HPEN
119 bool HasHPEN() const { return m_hPen != 0; }
120
121 // return true if we had a valid handle before, false otherwise
122 bool Free();
123
124 private:
125 // initialize the fields which have reasonable default values
126 //
127 // doesn't initialize m_width and m_style which must be initialize in ctor
128 void Init()
129 {
130 m_join = wxJOIN_ROUND;
131 m_cap = wxCAP_ROUND;
132 m_nbDash = 0;
133 m_dash = NULL;
134 m_hPen = 0;
135 }
136
137 int m_width;
138 wxPenStyle m_style;
139 wxPenJoin m_join;
140 wxPenCap m_cap;
141 wxBitmap m_stipple;
142 int m_nbDash;
143 wxDash * m_dash;
144 wxColour m_colour;
145 HPEN m_hPen;
146
147 wxDECLARE_NO_ASSIGN_CLASS(wxPenRefData);
148 };
149
150 // ============================================================================
151 // implementation
152 // ============================================================================
153
154 // ----------------------------------------------------------------------------
155 // wxPenRefData ctors/dtor
156 // ----------------------------------------------------------------------------
157
158 wxPenRefData::wxPenRefData()
159 {
160 Init();
161
162 m_style = wxPENSTYLE_SOLID;
163 m_width = 1;
164 }
165
166 wxPenRefData::wxPenRefData(const wxPenRefData& data)
167 :wxGDIRefData()
168 {
169 m_style = data.m_style;
170 m_width = data.m_width;
171 m_join = data.m_join;
172 m_cap = data.m_cap;
173 m_nbDash = data.m_nbDash;
174 m_dash = data.m_dash;
175 m_colour = data.m_colour;
176 m_hPen = 0;
177 }
178
179 wxPenRefData::wxPenRefData(const wxColour& col, int width, wxPenStyle style)
180 {
181 Init();
182
183 m_style = style;
184 m_width = width;
185
186 m_colour = col;
187 }
188
189 wxPenRefData::wxPenRefData(const wxBitmap& stipple, int width)
190 {
191 Init();
192
193 m_style = wxPENSTYLE_STIPPLE;
194 m_width = width;
195
196 m_stipple = stipple;
197 }
198
199 wxPenRefData::~wxPenRefData()
200 {
201 if ( m_hPen )
202 ::DeleteObject(m_hPen);
203 }
204
205 // ----------------------------------------------------------------------------
206 // wxPenRefData HPEN management
207 // ----------------------------------------------------------------------------
208
209 static int ConvertPenStyle(wxPenStyle style)
210 {
211 switch ( style )
212 {
213 case wxPENSTYLE_SHORT_DASH:
214 case wxPENSTYLE_LONG_DASH:
215 return PS_DASH;
216
217 case wxPENSTYLE_TRANSPARENT:
218 return PS_NULL;
219
220 default:
221 wxFAIL_MSG( wxT("unknown pen style") );
222 // fall through
223
224 #ifdef wxHAVE_EXT_CREATE_PEN
225 case wxPENSTYLE_DOT:
226 return PS_DOT;
227
228 case wxPENSTYLE_DOT_DASH:
229 return PS_DASHDOT;
230
231 case wxPENSTYLE_USER_DASH:
232 return PS_USERSTYLE;
233
234 case wxPENSTYLE_STIPPLE:
235 case wxPENSTYLE_BDIAGONAL_HATCH:
236 case wxPENSTYLE_CROSSDIAG_HATCH:
237 case wxPENSTYLE_FDIAGONAL_HATCH:
238 case wxPENSTYLE_CROSS_HATCH:
239 case wxPENSTYLE_HORIZONTAL_HATCH:
240 case wxPENSTYLE_VERTICAL_HATCH:
241 case wxPENSTYLE_SOLID:
242 #endif // wxHAVE_EXT_CREATE_PEN
243
244 return PS_SOLID;
245 }
246 }
247
248 #ifdef wxHAVE_EXT_CREATE_PEN
249
250 static int ConvertJoinStyle(wxPenJoin join)
251 {
252 switch( join )
253 {
254 case wxJOIN_BEVEL:
255 return PS_JOIN_BEVEL;
256
257 case wxJOIN_MITER:
258 return PS_JOIN_MITER;
259
260 default:
261 wxFAIL_MSG( wxT("unknown pen join style") );
262 // fall through
263
264 case wxJOIN_ROUND:
265 return PS_JOIN_ROUND;
266 }
267 }
268
269 static int ConvertCapStyle(wxPenCap cap)
270 {
271 switch ( cap )
272 {
273 case wxCAP_PROJECTING:
274 return PS_ENDCAP_SQUARE;
275
276 case wxCAP_BUTT:
277 return PS_ENDCAP_FLAT;
278
279 default:
280 wxFAIL_MSG( wxT("unknown pen cap style") );
281 // fall through
282
283 case wxCAP_ROUND:
284 return PS_ENDCAP_ROUND;
285 }
286 }
287
288 #endif // wxHAVE_EXT_CREATE_PEN
289
290 bool wxPenRefData::Alloc()
291 {
292 if ( m_hPen )
293 return false;
294
295 if ( m_style == wxPENSTYLE_TRANSPARENT )
296 {
297 m_hPen = (HPEN)::GetStockObject(NULL_PEN);
298 return true;
299 }
300
301 const COLORREF col = m_colour.GetPixel();
302
303 #ifdef wxHAVE_EXT_CREATE_PEN
304 // Only NT can display dashed or dotted lines with width > 1
305 static const int os = wxGetOsVersion();
306 if ( os != wxOS_WINDOWS_NT &&
307 (m_style == wxPENSTYLE_DOT ||
308 m_style == wxPENSTYLE_LONG_DASH ||
309 m_style == wxPENSTYLE_SHORT_DASH ||
310 m_style == wxPENSTYLE_DOT_DASH ||
311 m_style == wxPENSTYLE_USER_DASH) &&
312 m_width > 1 )
313 {
314 m_width = 1;
315 }
316
317 // check if it's a standard kind of pen which can be created with just
318 // CreatePen()
319 if ( m_join == wxJOIN_ROUND &&
320 m_cap == wxCAP_ROUND &&
321 m_style != wxPENSTYLE_USER_DASH &&
322 m_style != wxPENSTYLE_STIPPLE &&
323 (m_width <= 1 || m_style == wxPENSTYLE_SOLID) )
324 #endif // !wxHAVE_EXT_CREATE_PEN
325 {
326 m_hPen = ::CreatePen(ConvertPenStyle(m_style), m_width, col);
327 }
328 #ifdef wxHAVE_EXT_CREATE_PEN
329 else // need to use ExtCreatePen()
330 {
331 DWORD styleMSW = PS_GEOMETRIC |
332 ConvertPenStyle(m_style) |
333 ConvertJoinStyle(m_join) |
334 ConvertCapStyle(m_cap);
335
336 LOGBRUSH lb;
337 switch( m_style )
338 {
339 case wxPENSTYLE_STIPPLE:
340 lb.lbStyle = BS_PATTERN;
341 lb.lbHatch = wxPtrToUInt(m_stipple.GetHBITMAP());
342 break;
343
344 case wxPENSTYLE_BDIAGONAL_HATCH:
345 lb.lbStyle = BS_HATCHED;
346 lb.lbHatch = HS_BDIAGONAL;
347 break;
348
349 case wxPENSTYLE_CROSSDIAG_HATCH:
350 lb.lbStyle = BS_HATCHED;
351 lb.lbHatch = HS_DIAGCROSS;
352 break;
353
354 case wxPENSTYLE_FDIAGONAL_HATCH:
355 lb.lbStyle = BS_HATCHED;
356 lb.lbHatch = HS_FDIAGONAL;
357 break;
358
359 case wxPENSTYLE_CROSS_HATCH:
360 lb.lbStyle = BS_HATCHED;
361 lb.lbHatch = HS_CROSS;
362 break;
363
364 case wxPENSTYLE_HORIZONTAL_HATCH:
365 lb.lbStyle = BS_HATCHED;
366 lb.lbHatch = HS_HORIZONTAL;
367 break;
368
369 case wxPENSTYLE_VERTICAL_HATCH:
370 lb.lbStyle = BS_HATCHED;
371 lb.lbHatch = HS_VERTICAL;
372 break;
373
374 default:
375 lb.lbStyle = BS_SOLID;
376 // this should be unnecessary (it's unused) but suppresses the
377 // Purify messages about uninitialized memory read
378 lb.lbHatch = 0;
379 break;
380 }
381
382 lb.lbColor = col;
383
384 DWORD *dash;
385 if ( m_style == wxPENSTYLE_USER_DASH && m_nbDash && m_dash )
386 {
387 dash = new DWORD[m_nbDash];
388 int rw = m_width > 1 ? m_width : 1;
389 for ( int i = 0; i < m_nbDash; i++ )
390 dash[i] = m_dash[i] * rw;
391 }
392 else
393 {
394 dash = NULL;
395 }
396
397 m_hPen = ::ExtCreatePen(styleMSW, m_width, &lb, m_nbDash, (LPDWORD)dash);
398
399 delete [] dash;
400 }
401 #endif // wxHAVE_EXT_CREATE_PEN
402
403 return m_hPen != 0;
404 }
405
406 bool wxPenRefData::Free()
407 {
408 if ( !m_hPen )
409 return false;
410
411 ::DeleteObject(m_hPen);
412 m_hPen = 0;
413
414 return true;
415 }
416
417 WXHPEN wxPenRefData::GetHPEN() const
418 {
419 if ( !m_hPen )
420 const_cast<wxPenRefData *>(this)->Alloc();
421
422 return (WXHPEN)m_hPen;
423 }
424
425 // ----------------------------------------------------------------------------
426 // wxPen
427 // ----------------------------------------------------------------------------
428
429 IMPLEMENT_DYNAMIC_CLASS(wxPen, wxGDIObject)
430
431 wxPen::wxPen(const wxColour& col, int width, wxPenStyle style)
432 {
433 m_refData = new wxPenRefData(col, width, style);
434 }
435
436 #if FUTURE_WXWIN_COMPATIBILITY_3_0
437 wxPen::wxPen(const wxColour& colour, int width, int style)
438 {
439 m_refData = new wxPenRefData(colour, width, (wxPenStyle)style);
440 }
441 #endif
442
443 wxPen::wxPen(const wxBitmap& stipple, int width)
444 {
445 m_refData = new wxPenRefData(stipple, width);
446 }
447
448 bool wxPen::operator==(const wxPen& pen) const
449 {
450 const wxPenRefData *
451 penData = static_cast<const wxPenRefData *>(pen.m_refData);
452
453 // an invalid pen is only equal to another invalid pen
454 return m_refData ? penData && *M_PENDATA == *penData : !penData;
455 }
456
457 bool wxPen::RealizeResource()
458 {
459 return M_PENDATA && M_PENDATA->Alloc();
460 }
461
462 WXHANDLE wxPen::GetResourceHandle() const
463 {
464 return M_PENDATA ? M_PENDATA->GetHPEN() : 0;
465 }
466
467 bool wxPen::FreeResource(bool WXUNUSED(force))
468 {
469 return M_PENDATA && M_PENDATA->Free();
470 }
471
472 bool wxPen::IsFree() const
473 {
474 return M_PENDATA && !M_PENDATA->HasHPEN();
475 }
476
477 wxGDIRefData* wxPen::CreateGDIRefData() const
478 {
479 return new wxPenRefData;
480 }
481
482 wxGDIRefData* wxPen::CloneGDIRefData(const wxGDIRefData* data) const
483 {
484 return new wxPenRefData(*static_cast<const wxPenRefData*>(data));
485 }
486
487 void wxPen::SetColour(const wxColour& col)
488 {
489 AllocExclusive();
490
491 M_PENDATA->SetColour(col);
492 }
493
494 void wxPen::SetColour(unsigned char r, unsigned char g, unsigned char b)
495 {
496 SetColour(wxColour(r, g, b));
497 }
498
499 void wxPen::SetWidth(int width)
500 {
501 AllocExclusive();
502
503 M_PENDATA->SetWidth(width);
504 }
505
506 void wxPen::SetStyle(wxPenStyle style)
507 {
508 AllocExclusive();
509
510 M_PENDATA->SetStyle(style);
511 }
512
513 void wxPen::SetStipple(const wxBitmap& stipple)
514 {
515 AllocExclusive();
516
517 M_PENDATA->SetStipple(stipple);
518 }
519
520 void wxPen::SetDashes(int nb_dashes, const wxDash *dash)
521 {
522 AllocExclusive();
523
524 M_PENDATA->SetDashes(nb_dashes, dash);
525 }
526
527 void wxPen::SetJoin(wxPenJoin join)
528 {
529 AllocExclusive();
530
531 M_PENDATA->SetJoin(join);
532 }
533
534 void wxPen::SetCap(wxPenCap cap)
535 {
536 AllocExclusive();
537
538 M_PENDATA->SetCap(cap);
539 }
540
541 wxColour wxPen::GetColour() const
542 {
543 wxCHECK_MSG( Ok(), wxNullColour, wxT("invalid pen") );
544
545 return M_PENDATA->GetColour();
546 }
547
548 int wxPen::GetWidth() const
549 {
550 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
551
552 return M_PENDATA->GetWidth();
553 }
554
555 wxPenStyle wxPen::GetStyle() const
556 {
557 wxCHECK_MSG( Ok(), wxPENSTYLE_INVALID, wxT("invalid pen") );
558
559 return M_PENDATA->GetStyle();
560 }
561
562 wxPenJoin wxPen::GetJoin() const
563 {
564 wxCHECK_MSG( Ok(), wxJOIN_INVALID, wxT("invalid pen") );
565
566 return M_PENDATA->GetJoin();
567 }
568
569 wxPenCap wxPen::GetCap() const
570 {
571 wxCHECK_MSG( Ok(), wxCAP_INVALID, wxT("invalid pen") );
572
573 return M_PENDATA->GetCap();
574 }
575
576 int wxPen::GetDashes(wxDash** ptr) const
577 {
578 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
579
580 *ptr = M_PENDATA->GetDash();
581 return M_PENDATA->GetDashCount();
582 }
583
584 wxDash* wxPen::GetDash() const
585 {
586 wxCHECK_MSG( Ok(), NULL, wxT("invalid pen") );
587
588 return m_refData ? M_PENDATA->GetDash() : NULL;
589 }
590
591 int wxPen::GetDashCount() const
592 {
593 wxCHECK_MSG( Ok(), -1, wxT("invalid pen") );
594
595 return m_refData ? M_PENDATA->GetDashCount() : 0;
596 }
597
598 wxBitmap* wxPen::GetStipple() const
599 {
600 wxCHECK_MSG( Ok(), NULL, wxT("invalid pen") );
601
602 return m_refData ? M_PENDATA->GetStipple() : NULL;
603 }