Corrected wxRTTI for wxNotebook so dynamic casting to wxBookCtrlBase works
[wxWidgets.git] / src / cocoa / notebook.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        cocoa/notebook.mm
3 // Purpose:     wxNotebook
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2004/04/08
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2004 David Elliott
9 // Licence:     wxWidgets licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #if wxUSE_NOTEBOOK
15
16 #ifndef WX_PRECOMP
17     #include "wx/app.h"
18 #endif //WX_PRECOMP
19 #include "wx/notebook.h"
20 #include "wx/imaglist.h"
21
22 #include "wx/cocoa/autorelease.h"
23 #include "wx/cocoa/string.h"
24 #include "wx/cocoa/objc/objc_uniquifying.h"
25
26 #import <AppKit/NSTabView.h>
27 #import <AppKit/NSTabViewItem.h>
28 #import <AppKit/NSImage.h>
29
30 // testing:
31 #import <AppKit/NSPasteboard.h>
32 #import <Foundation/NSArray.h>
33
34 // ========================================================================
35 // WXCTabViewImageItem
36 // ========================================================================
37 @interface WXCTabViewImageItem : NSTabViewItem
38 {
39     NSImage *m_image;
40 }
41
42 - (id)init;
43 - (id)initWithIdentifier: (id)identifier;
44 - (void)dealloc;
45
46 - (NSSize)sizeOfLabel:(BOOL)shouldTruncateLabel;
47 - (void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect;
48
49 - (NSImage*)image;
50 - (void)setImage:(NSImage*)image;
51 @end // interface WXCTabViewImageItem : NSTabViewItem
52 WX_DECLARE_GET_OBJC_CLASS(WXCTabViewImageItem,NSTabViewItem)
53
54 @implementation WXCTabViewImageItem : NSTabViewItem
55 - (id)init
56 {
57     return [self initWithIdentifier:nil];
58 }
59
60 - (id)initWithIdentifier: (id)identifier;
61 {
62     m_image = nil;
63     return [super initWithIdentifier:identifier];
64 }
65
66 - (void)dealloc
67 {
68     [m_image release];
69     [super dealloc];
70 }
71
72 - (NSSize)sizeOfLabel:(BOOL)shouldTruncateLabel
73 {
74     NSSize labelSize = [super sizeOfLabel:shouldTruncateLabel];
75     if(!m_image)
76         return labelSize;
77     NSSize imageSize = [m_image size];
78     // scale image size
79     if(imageSize.height > labelSize.height)
80     {
81         imageSize.width *= labelSize.height/imageSize.height;
82         imageSize.height *= labelSize.height/imageSize.height;
83         [m_image setScalesWhenResized:YES];
84         [m_image setSize: imageSize];
85     }
86     labelSize.width += imageSize.width;
87     return labelSize;
88 }
89
90 - (void)drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect
91 {
92     if(m_image)
93     {
94         NSSize imageSize = [m_image size];
95         [m_image compositeToPoint:NSMakePoint(tabRect.origin.x,
96                 tabRect.origin.y+imageSize.height)
97             operation:NSCompositeSourceOver];
98         tabRect.size.width -= imageSize.width;
99         tabRect.origin.x += imageSize.width;
100     }
101     [super drawLabel:shouldTruncateLabel inRect:tabRect];
102 }
103
104 - (NSImage*)image
105 {
106     return m_image;
107 }
108
109 - (void)setImage:(NSImage*)image
110 {
111     [image retain];
112     [m_image release];
113     m_image = image;
114     if(!m_image)
115         return;
116     [[NSPasteboard generalPasteboard]
117         declareTypes:[NSArray arrayWithObject:NSTIFFPboardType]
118         owner:nil];
119     [[NSPasteboard generalPasteboard]
120         setData:[m_image TIFFRepresentation]
121         forType:NSTIFFPboardType];
122 }
123
124 @end // implementation WXCTabViewImageItem : NSTabViewItem
125 WX_IMPLEMENT_GET_OBJC_CLASS(WXCTabViewImageItem,NSTabViewItem)
126
127 // ========================================================================
128 // wxNotebookEvent
129 // ========================================================================
130 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED)
131 DEFINE_EVENT_TYPE(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING)
132 IMPLEMENT_DYNAMIC_CLASS(wxNotebookEvent, wxNotifyEvent)
133
134 // ========================================================================
135 // wxNotebook
136 // ========================================================================
137 IMPLEMENT_DYNAMIC_CLASS(wxNotebook, wxBookCtrlBase)
138 BEGIN_EVENT_TABLE(wxNotebook, wxNotebookBase)
139 END_EVENT_TABLE()
140 WX_IMPLEMENT_COCOA_OWNER(wxNotebook,NSTabView,NSView,NSView)
141
142 bool wxNotebook::Create(wxWindow *parent, wxWindowID winid,
143            const wxPoint& pos,
144            const wxSize& size,
145            long style,
146            const wxString& name)
147 {
148     wxAutoNSAutoreleasePool pool;
149     if(!CreateControl(parent,winid,pos,size,style,wxDefaultValidator,name))
150         return false;
151     m_cocoaNSView = NULL;
152     SetNSTabView([[NSTabView alloc] initWithFrame:MakeDefaultNSRect(size)]);
153
154     do
155     {
156         NSTabViewType tabViewType;
157         if(style & wxNB_TOP)
158             tabViewType = NSTopTabsBezelBorder;
159         else if(style & wxNB_LEFT)
160             tabViewType = NSLeftTabsBezelBorder;
161         else if(style & wxNB_RIGHT)
162             tabViewType = NSRightTabsBezelBorder;
163         else if(style & wxNB_BOTTOM)
164             tabViewType = NSBottomTabsBezelBorder;
165         else
166             break;
167         [GetNSTabView() setTabViewType:tabViewType];
168     } while(0);
169
170     if(m_parent)
171         m_parent->CocoaAddChild(this);
172     SetInitialFrameRect(pos,size);
173
174     return true;
175 }
176
177 wxNotebook::~wxNotebook()
178 {
179 }
180
181 void wxNotebook::SetPadding(const wxSize& padding)
182 {   // Can't do
183 }
184
185 void wxNotebook::SetTabSize(const wxSize& sz)
186 {   // Can't do
187 }
188
189 void wxNotebook::SetPageSize(const wxSize& size)
190 {
191 }
192
193
194 wxNotebookPage *wxNotebook::DoRemovePage(size_t nPage)
195 {
196     wxNotebookPage *page = wxNotebookBase::DoRemovePage(nPage);
197     if(!page)
198         return NULL;
199     NSTabViewItem *tvitem = [GetNSTabView() tabViewItemAtIndex: nPage];
200     wxASSERT(tvitem);
201     [tvitem retain];
202     [GetNSTabView() removeTabViewItem:tvitem];
203     // Remove the child window as a notebook page
204     wxASSERT(static_cast<NSView*>([tvitem view]) == page->GetNSViewForSuperview());
205     [tvitem setView:nil];
206     [tvitem release];
207     // Make it back into a normal child window
208     [m_cocoaNSView addSubview: page->GetNSViewForSuperview()];
209     
210     return page;
211 }
212
213 bool wxNotebook::DeletePage(size_t nPage)
214 {
215     return wxNotebookBase::DeletePage(nPage);
216 }
217
218 bool wxNotebook::InsertPage( size_t pos,
219                  wxNotebookPage *page, const wxString& title,
220                  bool bSelect, int imageId)
221 {
222     wxAutoNSAutoreleasePool pool;
223     m_pages.Insert(page,pos);
224     NSTabViewItem *tvitem = [[WX_GET_OBJC_CLASS(WXCTabViewImageItem) alloc] initWithIdentifier:nil];
225     [tvitem setLabel: wxNSStringWithWxString(title)];
226     const wxBitmap *bmp = (imageId!=-1)?m_imageList->GetBitmapPtr(imageId):NULL;
227     if(bmp)
228         [(WXCTabViewImageItem*) tvitem setImage: bmp->GetNSImage(true)];
229
230     NSView *pageNSView = page->GetNSViewForSuperview();
231     // Remove it as a normal child
232     wxASSERT(m_cocoaNSView == [pageNSView superview]);
233     [pageNSView removeFromSuperview];
234     // And make it a notebook page
235     [tvitem setView: pageNSView];
236
237     [GetNSTabView() insertTabViewItem:tvitem atIndex:pos];
238     [tvitem release];
239
240     return true;
241 }
242
243 bool wxNotebook::DeleteAllPages()
244 {
245     while(!m_pages.IsEmpty())
246         DeletePage(0);
247     return true;
248 }
249
250
251 bool wxNotebook::SetPageText(size_t nPage, const wxString& title)
252 {
253     NSTabViewItem *tvitem = [GetNSTabView() tabViewItemAtIndex: nPage];
254     if(!tvitem)
255         return false;
256     [tvitem setLabel: wxNSStringWithWxString(title)];
257     return true;
258 }
259
260 wxString wxNotebook::GetPageText(size_t nPage) const
261 {
262     return wxStringWithNSString([[GetNSTabView() tabViewItemAtIndex: nPage] label]);
263 }
264
265
266 int wxNotebook::GetPageImage(size_t nPage) const
267 {
268     // To do this we'd need to keep track of this, which we don't!
269     return -1;
270 }
271
272 bool wxNotebook::SetPageImage(size_t nPage, int nImage)
273 {
274     const wxBitmap *bmp = nImage!=-1?m_imageList->GetBitmapPtr(nImage):NULL;
275     if(!bmp)
276         return false;
277     NSTabViewItem *tvitem = [GetNSTabView() tabViewItemAtIndex: nPage];
278     if(!tvitem)
279         return false;
280     [(WXCTabViewImageItem*) tvitem setImage: bmp->GetNSImage(true)];
281     return true;
282 }
283
284 int wxNotebook::SetSelection(size_t nPage)
285 {
286     const int pageOld = GetSelection();
287
288     if ( !SendPageChangingEvent(nPage) )
289         return pageOld;
290
291     int page = ChangeSelection(nPage);
292     if ( page != wxNOT_FOUND )
293     {
294         SendPageChangedEvent(pageOld);
295     }
296
297     return page;
298 }
299
300 int wxNotebook::ChangeSelection(size_t nPage)
301 {
302     wxAutoNSAutoreleasePool pool;
303     [GetNSTabView() selectTabViewItemAtIndex:nPage];
304     return GetSelection();
305 }
306
307 int wxNotebook::GetSelection() const
308 {
309     NSTabViewItem *selectedItem = [GetNSTabView() selectedTabViewItem];
310     if(!selectedItem)
311         return -1;
312     return [GetNSTabView() indexOfTabViewItem:selectedItem];
313 }
314
315 void wxNotebook::CocoaDelegate_tabView_didSelectTabViewItem(WX_NSTabViewItem tabViewItem)
316 {
317     // FIXME: oldSel probably == newSel
318     wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, GetId(),
319         [GetNSTabView() indexOfTabViewItem:tabViewItem], GetSelection());
320     event.SetEventObject(this);
321 }
322
323 bool wxNotebook::CocoaDelegate_tabView_shouldSelectTabViewItem(WX_NSTabViewItem tabViewItem)
324 {
325     wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, GetId(),
326         [GetNSTabView() indexOfTabViewItem:tabViewItem], GetSelection());
327     event.SetEventObject(this);
328     return !HandleWindowEvent(event) || event.IsAllowed();
329 }
330
331 #endif // wxUSE_NOTEBOOK