1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/msw/pen.cpp
3// Purpose:     wxPen
4// Author:      Julian Smart
5// Modified by:
6// Created:     04/01/98
7// RCS-ID:      $Id: pen.cpp 44818 2007-03-15 09:40:24Z JS $
8// Copyright:   (c) Julian Smart
9// Licence:     wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// For compilers that support precompilation, includes "wx.h".
13#include "wx/wxprec.h"
14
15#ifdef __BORLANDC__
16    #pragma hdrstop
17#endif
18
19#include "wx/pen.h"
20
21#ifndef WX_PRECOMP
22    #include <stdio.h>
23    #include "wx/list.h"
24    #include "wx/utils.h"
25    #include "wx/app.h"
26#endif
27
28#include "wx/msw/private.h"
29
30static int wx2msPenStyle(int wx_style);
31
32IMPLEMENT_DYNAMIC_CLASS(wxPen, wxGDIObject)
33
34wxPenRefData::wxPenRefData()
35{
36  m_style = wxSOLID;
37  m_width = 1;
38  m_join = wxJOIN_ROUND ;
39  m_cap = wxCAP_ROUND ;
40  m_nbDash = 0 ;
41  m_dash = (wxDash*)NULL;
42  m_hPen = 0;
43}
44
45wxPenRefData::wxPenRefData(const wxPenRefData& data)
46             :wxGDIRefData()
47{
48    m_style = data.m_style;
49    m_width = data.m_width;
50    m_join = data.m_join;
51    m_cap = data.m_cap;
52    m_nbDash = data.m_nbDash;
53    m_dash = data.m_dash;
54    m_colour = data.m_colour;
55    m_hPen = 0;
56}
57
58wxPenRefData::~wxPenRefData()
59{
60    if ( m_hPen )
61        ::DeleteObject((HPEN) m_hPen);
62}
63
64// Pens
65
66wxPen::wxPen()
67{
68}
69
70wxPen::~wxPen()
71{
72}
73
74// Should implement Create
75wxPen::wxPen(const wxColour& col, int Width, int Style)
76{
77  m_refData = new wxPenRefData;
78
79  M_PENDATA->m_colour = col;
80//  M_PENDATA->m_stipple = NULL;
81  M_PENDATA->m_width = Width;
82  M_PENDATA->m_style = Style;
83  M_PENDATA->m_join = wxJOIN_ROUND ;
84  M_PENDATA->m_cap = wxCAP_ROUND ;
85  M_PENDATA->m_nbDash = 0 ;
86  M_PENDATA->m_dash = (wxDash*)NULL;
87  M_PENDATA->m_hPen = 0 ;
88
89  RealizeResource();
90}
91
92wxPen::wxPen(const wxBitmap& stipple, int Width)
93{
94    m_refData = new wxPenRefData;
95
96//  M_PENDATA->m_colour = col;
97    M_PENDATA->m_stipple = stipple;
98    M_PENDATA->m_width = Width;
99    M_PENDATA->m_style = wxSTIPPLE;
100    M_PENDATA->m_join = wxJOIN_ROUND ;
101    M_PENDATA->m_cap = wxCAP_ROUND ;
102    M_PENDATA->m_nbDash = 0 ;
103    M_PENDATA->m_dash = (wxDash*)NULL;
104    M_PENDATA->m_hPen = 0 ;
105
106    RealizeResource();
107}
108
109bool wxPen::RealizeResource()
110{
111   if ( !M_PENDATA || M_PENDATA->m_hPen )
112       return false;
113
114   if (M_PENDATA->m_style==wxTRANSPARENT)
115   {
116       M_PENDATA->m_hPen = (WXHPEN) ::GetStockObject(NULL_PEN);
117       return true;
118   }
119
120   static const int os = wxGetOsVersion();
121   COLORREF ms_colour = M_PENDATA->m_colour.GetPixel();
122
123   // Join style, Cap style, Pen Stippling
124#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
125   // Only NT can display dashed or dotted lines with width > 1
126   if ( os != wxOS_WINDOWS_NT &&
127           (M_PENDATA->m_style == wxDOT ||
128            M_PENDATA->m_style == wxLONG_DASH ||
129            M_PENDATA->m_style == wxSHORT_DASH ||
130            M_PENDATA->m_style == wxDOT_DASH ||
131            M_PENDATA->m_style == wxUSER_DASH) &&
132            M_PENDATA->m_width > 1 )
133   {
134       M_PENDATA->m_width = 1;
135   }
136
137   if (M_PENDATA->m_join==wxJOIN_ROUND        &&
138       M_PENDATA->m_cap==wxCAP_ROUND          &&
139       M_PENDATA->m_style!=wxUSER_DASH        &&
140       M_PENDATA->m_style!=wxSTIPPLE          &&
141       M_PENDATA->m_width <= 1)
142   {
143       M_PENDATA->m_hPen =
144         (WXHPEN) CreatePen( wx2msPenStyle(M_PENDATA->m_style),
145                             M_PENDATA->m_width,
146                             ms_colour );
147   }
148   else
149   {
150       DWORD ms_style = PS_GEOMETRIC | wx2msPenStyle(M_PENDATA->m_style);
151
152       switch(M_PENDATA->m_join)
153       {
154           case wxJOIN_BEVEL: ms_style |= PS_JOIN_BEVEL; break;
155           case wxJOIN_MITER: ms_style |= PS_JOIN_MITER; break;
156           default:
157           case wxJOIN_ROUND: ms_style |= PS_JOIN_ROUND; break;
158       }
159
160       switch(M_PENDATA->m_cap)
161       {
162           case wxCAP_PROJECTING: ms_style |= PS_ENDCAP_SQUARE;  break;
163           case wxCAP_BUTT:       ms_style |= PS_ENDCAP_FLAT;    break;
164           default:
165           case wxCAP_ROUND:      ms_style |= PS_ENDCAP_ROUND;   break;
166       }
167
168       LOGBRUSH logb;
169
170       switch(M_PENDATA->m_style)
171       {
172           case wxSTIPPLE:
173               logb.lbStyle = BS_PATTERN ;
174               if (M_PENDATA->m_stipple.Ok())
175                   logb.lbHatch = (LONG)M_PENDATA->m_stipple.GetHBITMAP();
176               else
177                   logb.lbHatch = (LONG)0;
178               break;
179           case wxBDIAGONAL_HATCH:
180               logb.lbStyle = BS_HATCHED;
181               logb.lbHatch = HS_BDIAGONAL;
182               break;
183           case wxCROSSDIAG_HATCH:
184               logb.lbStyle = BS_HATCHED;
185               logb.lbHatch = HS_DIAGCROSS;
186               break;
187           case wxFDIAGONAL_HATCH:
188               logb.lbStyle = BS_HATCHED;
189               logb.lbHatch = HS_FDIAGONAL;
190               break;
191           case wxCROSS_HATCH:
192               logb.lbStyle = BS_HATCHED;
193               logb.lbHatch = HS_CROSS;
194               break;
195           case wxHORIZONTAL_HATCH:
196               logb.lbStyle = BS_HATCHED;
197               logb.lbHatch = HS_HORIZONTAL;
198               break;
199           case wxVERTICAL_HATCH:
200               logb.lbStyle = BS_HATCHED;
201               logb.lbHatch = HS_VERTICAL;
202               break;
203           default:
204               logb.lbStyle = BS_SOLID;
205#ifdef __WXDEBUG__
206               // this should be unnecessary (it's unused) but suppresses the Purify
207               // messages about uninitialized memory read
208               logb.lbHatch = 0;
209#endif
210               break;
211       }
212
213       logb.lbColor = ms_colour;
214
215       wxMSWDash *real_dash;
216       if (M_PENDATA->m_style==wxUSER_DASH && M_PENDATA->m_nbDash && M_PENDATA->m_dash)
217       {
218           real_dash = new wxMSWDash[M_PENDATA->m_nbDash];
219           int rw = M_PENDATA->m_width > 1 ? M_PENDATA->m_width : 1;
220           for ( int i = 0; i < M_PENDATA->m_nbDash; i++ )
221               real_dash[i] = M_PENDATA->m_dash[i] * rw;
222       }
223       else
224       {
225           real_dash = (wxMSWDash*)NULL;
226       }
227
228       M_PENDATA->m_hPen =
229         (WXHPEN) ExtCreatePen( ms_style,
230                                M_PENDATA->m_width,
231                                &logb,
232                                M_PENDATA->m_style == wxUSER_DASH
233                                  ? M_PENDATA->m_nbDash
234                                  : 0,
235                                (LPDWORD)real_dash );
236
237       delete [] real_dash;
238   }
239#else // WinCE
240   M_PENDATA->m_hPen =
241     (WXHPEN) CreatePen( wx2msPenStyle(M_PENDATA->m_style),
242                         M_PENDATA->m_width,
243                         ms_colour );
244#endif // !WinCE/WinCE
245
246   return true;
247}
248
249WXHANDLE wxPen::GetResourceHandle() const
250{
251    if ( !M_PENDATA )
252        return 0;
253    else
254        return (WXHANDLE)M_PENDATA->m_hPen;
255}
256
257bool wxPen::FreeResource(bool WXUNUSED(force))
258{
259    if (M_PENDATA && (M_PENDATA->m_hPen != 0))
260    {
261        DeleteObject((HPEN) M_PENDATA->m_hPen);
262        M_PENDATA->m_hPen = 0;
263        return true;
264    }
265    else return false;
266}
267
268bool wxPen::IsFree() const
269{
270    return (M_PENDATA && M_PENDATA->m_hPen == 0);
271}
272
273void wxPen::Unshare()
274{
275    // Don't change shared data
276    if (!m_refData)
277    {
278        m_refData = new wxPenRefData();
279    }
280    else
281    {
282        wxPenRefData* ref = new wxPenRefData(*(wxPenRefData*)m_refData);
283        UnRef();
284        m_refData = ref;
285    }
286}
287
288void wxPen::SetColour(const wxColour& col)
289{
290    Unshare();
291
292    M_PENDATA->m_colour = col;
293
294    RealizeResource();
295}
296
297void wxPen::SetColour(unsigned char r, unsigned char g, unsigned char b)
298{
299    Unshare();
300
301    M_PENDATA->m_colour.Set(r, g, b);
302
303    RealizeResource();
304}
305
306void wxPen::SetWidth(int Width)
307{
308    Unshare();
309
310    M_PENDATA->m_width = Width;
311
312    RealizeResource();
313}
314
315void wxPen::SetStyle(int Style)
316{
317    Unshare();
318
319    M_PENDATA->m_style = Style;
320
321    RealizeResource();
322}
323
324void wxPen::SetStipple(const wxBitmap& Stipple)
325{
326    Unshare();
327
328    M_PENDATA->m_stipple = Stipple;
329    M_PENDATA->m_style = wxSTIPPLE;
330
331    RealizeResource();
332}
333
334void wxPen::SetDashes(int nb_dashes, const wxDash *Dash)
335{
336    Unshare();
337
338    M_PENDATA->m_nbDash = nb_dashes;
339    M_PENDATA->m_dash = (wxDash *)Dash;
340
341    RealizeResource();
342}
343
344void wxPen::SetJoin(int Join)
345{
346    Unshare();
347
348    M_PENDATA->m_join = Join;
349
350    RealizeResource();
351}
352
353void wxPen::SetCap(int Cap)
354{
355    Unshare();
356
357    M_PENDATA->m_cap = Cap;
358
359    RealizeResource();
360}
361
362int wx2msPenStyle(int wx_style)
363{
364#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
365    switch (wx_style)
366    {
367        case wxDOT:
368            return PS_DOT;
369
370        case wxDOT_DASH:
371            return PS_DASHDOT;
372
373        case wxSHORT_DASH:
374        case wxLONG_DASH:
375            return PS_DASH;
376
377        case wxTRANSPARENT:
378            return PS_NULL;
379
380        case wxUSER_DASH:
381            return PS_USERSTYLE;
382    }
383#else
384    wxUnusedVar(wx_style);
385#endif
386    return PS_SOLID;
387}
388