* Since AppKit cannot draw directly on NSBitmapImageRep, copy the data
[wxWidgets.git] / src / cocoa / dcmemory.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/dcmemory.mm
3 // Purpose:     wxMemoryDC class
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/03/16
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2002 David Elliott
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/dcmemory.h"
13 #include "wx/log.h"
14
15 #import <AppKit/NSImage.h>
16 #import <AppKit/NSAffineTransform.h>
17 #import <AppKit/NSGraphicsContext.h>
18
19 //-----------------------------------------------------------------------------
20 // wxMemoryDC
21 //-----------------------------------------------------------------------------
22
23 IMPLEMENT_DYNAMIC_CLASS(wxMemoryDC,wxDC)
24
25 wxMemoryDC::wxMemoryDC(void)
26 {
27     m_cocoaNSImage = NULL;
28     m_ok = false;
29 }
30
31 wxMemoryDC::wxMemoryDC( wxDC *WXUNUSED(dc) )
32 {
33     m_cocoaNSImage = NULL;
34     m_ok = false;
35 }
36
37 wxMemoryDC::~wxMemoryDC(void)
38 {
39     CocoaUnwindStackAndLoseFocus();
40     [m_cocoaNSImage release];
41 }
42
43 bool wxMemoryDC::CocoaLockFocus()
44 {
45     if(m_cocoaNSImage)
46     {
47         [m_cocoaNSImage lockFocus];
48         sm_cocoaDCStack.Insert(this);
49         m_cocoaFlipped = [m_cocoaNSImage isFlipped];
50         m_cocoaHeight = [m_cocoaNSImage size].height;
51         CocoaApplyTransformations();
52         return true;
53     }
54     return false;
55 }
56
57 bool wxMemoryDC::CocoaUnlockFocus()
58 {
59     [m_cocoaNSImage unlockFocus];
60     return true;
61 }
62
63 // NOTE: The AppKit is unable to draw onto an NSBitmapImageRep so we must
64 // instead copy the data to an offscreen window, then copy it back
65 void wxMemoryDC::SelectObject( const wxBitmap& bitmap )
66 {
67     if(m_selectedBitmap.Ok())
68     {
69         CocoaTakeFocus();
70         wxASSERT(m_cocoaNSImage);
71         m_selectedBitmap.SetNSBitmapImageRep(
72             [[NSBitmapImageRep alloc]
73                 initWithFocusedViewRect:NSMakeRect(0.0,0.0,
74                     m_selectedBitmap.GetWidth(),
75                     m_selectedBitmap.GetHeight())]);
76     }
77     CocoaUnwindStackAndLoseFocus();
78     [m_cocoaNSImage release];
79     m_cocoaNSImage = nil;
80     m_selectedBitmap = bitmap;
81     if(m_selectedBitmap.Ok())
82     {
83         // Create an offscreen window of the same size
84         m_cocoaNSImage = [[NSImage alloc]
85                 initWithSize:NSMakeSize(m_selectedBitmap.GetWidth(),
86                     m_selectedBitmap.GetHeight())];
87
88         // Now copy the data
89         NSImage *nsimage = [[NSImage alloc]
90                 initWithSize:NSMakeSize(m_selectedBitmap.GetWidth(),
91                     m_selectedBitmap.GetHeight())];
92         [nsimage addRepresentation: const_cast<wxBitmap&>(m_selectedBitmap).GetNSBitmapImageRep()];
93         [nsimage drawAtPoint: NSMakePoint(0,0)
94             fromRect: NSMakeRect(0.0,0.0,m_selectedBitmap.GetWidth(),m_selectedBitmap.GetHeight())
95             operation: NSCompositeCopy
96             fraction: 1.0];
97         
98         [nsimage release];
99     }
100 }
101
102 void wxMemoryDC::DoGetSize( int *width, int *height ) const
103 {
104     if(width)
105         *width = m_selectedBitmap.GetWidth();
106     if(height)
107         *height = m_selectedBitmap.GetHeight();
108 }
109
110 bool wxMemoryDC::CocoaDoBlitOnFocusedDC(wxCoord xdest, wxCoord ydest,
111     wxCoord width, wxCoord height, wxCoord xsrc, wxCoord ysrc,
112     int logicalFunc, bool useMask, wxCoord xsrcMask, wxCoord ysrcMask)
113 {
114     if(!m_selectedBitmap.Ok())
115         return false;
116
117     NSAffineTransform *transform = [NSAffineTransform transform];
118     [transform translateXBy:xdest yBy:ydest];
119
120     NSAffineTransform *flipTransform = [NSAffineTransform transform];
121     /*  x' = 1x + 0y + 0
122         y' = 0x + -1y + window's height
123     */
124     NSAffineTransformStruct matrix = {
125         1,  0
126     ,   0, -1
127     ,   0, height
128     };
129     [flipTransform setTransformStruct: matrix];
130
131     NSGraphicsContext *context = [NSGraphicsContext currentContext];
132     [context saveGraphicsState];
133     [transform concat];
134     [flipTransform concat];
135
136     wxLogDebug("[m_cocoaNSImage isFlipped]=%d", [m_cocoaNSImage isFlipped]);
137     [m_cocoaNSImage drawAtPoint: NSMakePoint(0,0)
138         fromRect: NSMakeRect(xsrc,
139             m_selectedBitmap.GetHeight()-height-ysrc,
140             width, height)
141         operation: NSCompositeCopy // FIXME: raster ops
142         fraction: 1.0];
143         
144     [context restoreGraphicsState];
145     return false;
146 }
147