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