1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/cocoa/pen.mm
3// Purpose:     wxPen
4// Author:      David Elliott
5// Modified by:
6// Created:     2003/08/02
7// Copyright:   (c) 2003 David Elliott
8// Licence:     wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
12
13#ifndef WX_PRECOMP
14    #include "wx/pen.h"
15    #include "wx/bitmap.h"
16    #include "wx/colour.h"
17#endif //WX_PRECOMP
18
19#include "wx/cocoa/ObjcRef.h"
20
21#import <AppKit/NSColor.h>
22
23// ========================================================================
24// wxPenRefData
25// ========================================================================
26class WXDLLEXPORT wxPenRefData: public wxGDIRefData
27{
28public:
29    wxPenRefData(const wxColour& colour = wxNullColour,
30        int width = 1, int style = wxSOLID,
31        const wxBitmap& stipple = wxNullBitmap);
32    wxPenRefData(const wxPenRefData& data);
33    ~wxPenRefData() { FreeCocoaNSColor(); FreeCocoaDash(); }
34
35    void SetWidth(int Width) { m_width = Width; }
36    void SetStyle(int Style)
37    {   FreeCocoaNSColor();
38        FreeCocoaDash();
39        m_style = Style;
40    }
41    void SetJoin(int Join) { m_join = Join; }
42    void SetCap(int Cap) { m_cap = Cap; }
43    void SetColour(const wxColour& col) { FreeCocoaNSColor(); m_colour = col; }
44    void SetDashes(int nb_dashes, const wxDash *Dash)
45    {
46        FreeCocoaDash();
47        m_nbDash = nb_dashes;
48        m_dash = (wxDash *)Dash;
49    }
50    void SetStipple(const wxBitmap& Stipple)
51    {
52        FreeCocoaNSColor();
53        m_stipple = Stipple;
54        m_style = wxSTIPPLE;
55    }
56    WX_NSColor GetNSColor();
57    int GetCocoaLineDash(const CGFloat **pattern);
58protected:
59    void FreeCocoaNSColor();
60    void FreeCocoaDash();
61
62    int             m_width;
63    int             m_style;
64    int             m_join;
65    int             m_cap;
66    wxColour        m_colour;
67    int             m_nbDash;
68    wxDash         *m_dash;
69    wxBitmap        m_stipple;
70    WX_NSColor      m_cocoaNSColor;
71    CGFloat        *m_cocoaDash;
72
73    // Predefined dash patterns
74    static const int scm_countDot;
75    static const CGFloat scm_patternDot[];
76    static const int scm_countLongDash;
77    static const CGFloat scm_patternLongDash[];
78    static const int scm_countShortDash;
79    static const CGFloat scm_patternShortDash[];
80    static const int scm_countDotDash;
81    static const CGFloat scm_patternDotDash[];
82
83    friend class WXDLLIMPEXP_FWD_CORE wxPen;
84
85private:
86    // Don't allow assignment
87    wxPenRefData& operator=(const wxPenRefData& data);
88};
89
90const int wxPenRefData::scm_countDot = 1;
91const CGFloat wxPenRefData::scm_patternDot[] = {
92    1.0
93};
94const int wxPenRefData::scm_countLongDash = 1;
95const CGFloat wxPenRefData::scm_patternLongDash[] = {
96    10.0
97};
98const int wxPenRefData::scm_countShortDash = 1;
99const CGFloat wxPenRefData::scm_patternShortDash[] = {
100    5.0
101};
102const int wxPenRefData::scm_countDotDash = 4;
103const CGFloat wxPenRefData::scm_patternDotDash[] = {
104    1.0
105,   1.0
106,   5.0
107,   1.0
108};
109
110#define M_PENDATA ((wxPenRefData *)m_refData)
111
112inline wxPenRefData::wxPenRefData(const wxColour& colour,
113        int width, int style, const wxBitmap& stipple)
114{
115    m_width = width;
116    m_style = style;
117    m_join = wxJOIN_ROUND;
118    m_cap = wxCAP_ROUND;
119    m_colour = colour;
120    m_nbDash = 0;
121    m_dash = 0;
122    m_stipple = stipple;
123    m_cocoaNSColor = nil;
124    m_cocoaDash = NULL;
125}
126
127inline wxPenRefData::wxPenRefData(const wxPenRefData& data)
128{
129    m_width = data.m_width;
130    m_style = data.m_style;
131    m_join = data.m_join;
132    m_cap = data.m_cap;
133    m_colour = data.m_colour;
134    m_nbDash = data.m_nbDash;
135    m_dash = data.m_dash;
136    m_stipple = data.m_stipple;
137    m_cocoaNSColor = wxGCSafeRetain(data.m_cocoaNSColor);
138    m_cocoaDash = NULL;
139}
140
141inline void wxPenRefData::FreeCocoaNSColor()
142{
143    wxGCSafeRelease(m_cocoaNSColor);
144    m_cocoaNSColor = nil;
145}
146
147inline void wxPenRefData::FreeCocoaDash()
148{
149    delete m_cocoaDash;
150    m_cocoaDash = NULL;
151}
152
153inline WX_NSColor wxPenRefData::GetNSColor()
154{
155    if(!m_cocoaNSColor)
156    {
157        switch( m_style )
158        {
159        case wxTRANSPARENT:
160            m_cocoaNSColor = wxGCSafeRetain([NSColor clearColor]);
161            break;
162        case wxSTIPPLE:
163//  wxBitmap isn't implemented yet
164//            m_cocoaNSColor = [[NSColor colorWithPatternImage: m_stipple.GetNSImage()] retain];
165//            break;
166        // The hatch brushes are going to be tricky
167        case wxBDIAGONAL_HATCH:
168        case wxCROSSDIAG_HATCH:
169        case wxFDIAGONAL_HATCH:
170        case wxCROSS_HATCH:
171        case wxHORIZONTAL_HATCH:
172        case wxVERTICAL_HATCH:
173        default:
174        // Dot/dashed pens use solid colors
175        case wxDOT:
176        case wxLONG_DASH:
177        case wxSHORT_DASH:
178        case wxDOT_DASH:
179        case wxUSER_DASH:
180        case wxSOLID:
181            NSColor *colour_NSColor = m_colour.GetNSColor();
182            if(!colour_NSColor)
183                colour_NSColor = [NSColor clearColor];
184            m_cocoaNSColor = [colour_NSColor copyWithZone:nil];
185            [wxGCSafeRetain(m_cocoaNSColor) release]; // retain in GC. no change in RR.
186            break;
187        }
188    }
189    return m_cocoaNSColor;
190}
191
192int wxPenRefData::GetCocoaLineDash(const CGFloat **pattern)
193{
194    int count;
195    switch( m_style )
196    {
197    case wxDOT:
198        count = scm_countDot;
199        if(pattern)
200            *pattern = scm_patternDot;
201        break;
202    case wxLONG_DASH:
203        count = scm_countLongDash;
204        if(pattern)
205            *pattern = scm_patternLongDash;
206        break;
207    case wxSHORT_DASH:
208        count = scm_countShortDash;
209        if(pattern)
210            *pattern = scm_patternShortDash;
211        break;
212    case wxDOT_DASH:
213        count = scm_countDotDash;
214        if(pattern)
215            *pattern = scm_patternDotDash;
216        break;
217    case wxUSER_DASH:
218        count = m_nbDash;
219        if(pattern)
220        {
221            if(!m_cocoaDash)
222            {
223                m_cocoaDash = new CGFloat[count];
224                for(int i=0; i<count; i++)
225                    m_cocoaDash[i] = m_dash[i];
226            }
227            *pattern = m_cocoaDash;
228        }
229        break;
230    case wxTRANSPARENT:
231    case wxSTIPPLE:
232    case wxBDIAGONAL_HATCH:
233    case wxCROSSDIAG_HATCH:
234    case wxFDIAGONAL_HATCH:
235    case wxCROSS_HATCH:
236    case wxHORIZONTAL_HATCH:
237    case wxVERTICAL_HATCH:
238    case wxSOLID:
239    default:
240        count = 0;
241        if(pattern)
242            *pattern = NULL;
243    }
244    return count;
245}
246
247// ========================================================================
248// wxPen
249// ========================================================================
250IMPLEMENT_DYNAMIC_CLASS(wxPen, wxGDIObject)
251
252wxPen::wxPen()
253{
254}
255
256wxPen::~wxPen()
257{
258}
259
260// Should implement Create
261wxPen::wxPen(const wxColour& colour, int width, int style)
262{
263    m_refData = new wxPenRefData(colour,width,style);
264}
265
266wxPen::wxPen(const wxBitmap& stipple, int width)
267{
268    m_refData = new wxPenRefData(wxNullColour,width,wxSTIPPLE,stipple);
269}
270
271wxGDIRefData *wxPen::CreateGDIRefData() const
272{
273    return new wxPenRefData;
274}
275
276wxGDIRefData *wxPen::CloneGDIRefData(const wxGDIRefData *data) const
277{
278    return new wxPenRefData(*(wxPenRefData *)data);
279}
280
281void wxPen::SetWidth(int Width)
282{
283    AllocExclusive();
284    M_PENDATA->SetWidth(Width);
285}
286
287void wxPen::SetStyle(int Style)
288{
289    AllocExclusive();
290    M_PENDATA->SetStyle(Style);
291}
292
293void wxPen::SetJoin(int Join)
294{
295    AllocExclusive();
296    M_PENDATA->SetJoin(Join);
297}
298
299void wxPen::SetCap(int Cap)
300{
301    AllocExclusive();
302    M_PENDATA->SetCap(Cap);
303}
304
305void wxPen::SetColour(const wxColour& col)
306{
307    AllocExclusive();
308    M_PENDATA->SetColour(col);
309}
310
311void wxPen::SetColour(unsigned char r, unsigned char g, unsigned char b)
312{
313    AllocExclusive();
314    M_PENDATA->SetColour(wxColour(r, g, b));
315}
316
317void wxPen::SetDashes(int nb_dashes, const wxDash *Dash)
318{
319    AllocExclusive();
320    M_PENDATA->SetDashes(nb_dashes, Dash);
321}
322
323void wxPen::SetStipple(const wxBitmap& Stipple)
324{
325    AllocExclusive();
326    M_PENDATA->SetStipple(Stipple);
327}
328
329wxColour wxPen::GetColour() const
330{
331    return (M_PENDATA ? M_PENDATA->m_colour : wxNullColour);
332}
333
334int wxPen::GetWidth() const
335{
336    return (M_PENDATA ? M_PENDATA->m_width : 0);
337}
338
339int wxPen::GetStyle() const
340{
341    return (M_PENDATA ? M_PENDATA->m_style : 0);
342}
343
344int wxPen::GetJoin() const
345{
346    return (M_PENDATA ? M_PENDATA->m_join : 0);
347}
348
349int wxPen::GetCap() const
350{
351    return (M_PENDATA ? M_PENDATA->m_cap : 0);
352}
353
354int wxPen::GetDashes(wxDash **ptr) const
355{
356    *ptr = (M_PENDATA ? M_PENDATA->m_dash : (wxDash*) NULL); return (M_PENDATA ? M_PENDATA->m_nbDash : 0);
357}
358
359wxBitmap *wxPen::GetStipple() const
360{
361    return (M_PENDATA ? (& M_PENDATA->m_stipple) : (wxBitmap*) NULL);
362}
363
364WX_NSColor wxPen::GetNSColor()
365{
366    return (M_PENDATA ? M_PENDATA->GetNSColor() : nil);
367}
368
369int wxPen::GetCocoaLineDash(const CGFloat **pattern)
370{
371    if(M_PENDATA)
372        return M_PENDATA->GetCocoaLineDash(pattern);
373    if(pattern)
374        *pattern = NULL;
375    return 0;
376}
377