Applied patch #881258: Add wxT() to debug messages and a few others
[wxWidgets.git] / src / cocoa / toolbar.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/cocoa/toolbar.mm
3 // Purpose:     wxToolBar
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/08/17
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #if wxUSE_TOOLBAR_NATIVE
24 #ifndef WX_PRECOMP
25     #include "wx/toolbar.h"
26     #include "wx/frame.h"
27     #include "wx/log.h"
28 #endif // WX_PRECOMP
29
30 #include "wx/cocoa/string.h"
31 #include "wx/cocoa/autorelease.h"
32
33 #import <AppKit/NSView.h>
34 #import <AppKit/NSButtonCell.h>
35 #import <AppKit/NSMatrix.h>
36 #import <AppKit/NSImage.h>
37 #import <AppKit/NSEvent.h>
38 #import <AppKit/NSColor.h>
39 #import <AppKit/NSAttributedString.h>
40 #import <AppKit/NSFont.h>
41
42 #include <math.h>
43
44 DECLARE_WXCOCOA_OBJC_CLASS(NSActionCell);
45
46 // ========================================================================
47 // wxCocoaNSActionCell
48 // ========================================================================
49 WX_DECLARE_OBJC_HASHMAP(NSActionCell);
50
51 class wxCocoaNSActionCell
52 {
53     WX_DECLARE_OBJC_INTERFACE(NSActionCell)
54 public:
55     virtual void CocoaTarget_wxNSActionCellAction() {}
56 protected:
57     static struct objc_object *sm_cocoaTarget;
58 };
59
60 // ============================================================================
61 // @class wxNSActionCellTarget
62 // ============================================================================
63 @interface wxNSActionCellTarget : NSObject
64 {
65 }
66
67 - (void)wxNSActionCellAction: (id)sender;
68 @end //interface wxNSActionCellTarget
69
70 @implementation wxNSActionCellTarget : NSObject
71
72 - (void)wxNSActionCellAction: (id)sender
73 {
74     wxLogDebug(wxT("wxNSActionCellAction"));
75     wxCocoaNSActionCell *wxcontrol = wxCocoaNSActionCell::GetFromCocoa(sender);
76     wxCHECK_RET(wxcontrol,wxT("wxNSActionCellAction received but no wxCocoaNSActionCell exists!"));
77     wxcontrol->CocoaTarget_wxNSActionCellAction();
78 }
79
80 @end //implementation wxNSActionCellTarget
81
82 // ========================================================================
83 // wxCocoaNSActionCell
84 // ========================================================================
85 struct objc_object *wxCocoaNSActionCell::sm_cocoaTarget = [[wxNSActionCellTarget alloc] init];
86 WX_IMPLEMENT_OBJC_INTERFACE(NSActionCell)
87
88 // ========================================================================
89 // wxToolBarTool
90 // ========================================================================
91 class wxToolBarTool : public wxToolBarToolBase, protected wxCocoaNSActionCell
92 {
93 public:
94     wxToolBarTool(wxToolBar *tbar, int toolid, const wxString& label,
95             const wxBitmap& bitmap1, const wxBitmap& bitmap2,
96             wxItemKind kind, wxObject *clientData,
97             const wxString& shortHelpString, const wxString& longHelpString)
98     :   wxToolBarToolBase(tbar, toolid, label, bitmap1, bitmap2, kind,
99             clientData, shortHelpString, longHelpString)
100     {
101         Init();
102         CreateButtonCell();
103     }
104
105     wxToolBarTool(wxToolBar *tbar, wxControl *control)
106         : wxToolBarToolBase(tbar, control)
107     {
108         Init();
109     }
110     ~wxToolBarTool();
111
112     bool CreateButtonCell();
113
114     // is this a radio button?
115     //
116     // unlike GetKind(), can be called for any kind of tools, not just buttons
117     bool IsRadio() const { return IsButton() && GetKind() == wxITEM_RADIO; }
118
119     NSRect GetFrameRect()
120     {   return m_frameRect; }
121     void SetFrameRect(NSRect frameRect)
122     {   m_frameRect = frameRect; }
123     void DrawTool(NSView *nsview);
124
125     NSButtonCell *GetNSButtonCell()
126     {   return m_cocoaNSButtonCell; }
127 protected:
128     void Init();
129     NSButtonCell *m_cocoaNSButtonCell;
130     NSRect m_frameRect;
131 };
132
133 // ========================================================================
134 // wxToolBarTool
135 // ========================================================================
136 void wxToolBarTool::Init()
137 {
138     m_cocoaNSButtonCell = NULL;
139     m_frameRect = NSZeroRect;
140 }
141
142 wxToolBarTool::~wxToolBarTool()
143 {
144     DisassociateNSActionCell(m_cocoaNSButtonCell);
145     [m_cocoaNSButtonCell release];
146 }
147
148 bool wxToolBarTool::CreateButtonCell()
149 {
150     wxAutoNSAutoreleasePool pool;
151
152     NSImage *nsimage = [m_bmpNormal.GetNSImage(true) retain];
153     m_cocoaNSButtonCell = [[NSButtonCell alloc] initTextCell:nil];
154     [m_cocoaNSButtonCell setImage:nsimage];
155     NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:wxNSStringWithWxString(m_label) attributes:[NSDictionary dictionaryWithObject:[NSFont labelFontOfSize:0.0] forKey:NSFontAttributeName]];
156 //    [m_cocoaNSButtonCell setTitle:wxNSStringWithWxString(m_label)];
157     [m_cocoaNSButtonCell setAttributedTitle:[attributedTitle autorelease]];
158
159     // Create an alternate image in the style of NSToolBar
160     if(nsimage)
161     {
162         NSImage *alternateImage = [[NSImage alloc] initWithSize:[nsimage size]];
163         [alternateImage lockFocus];
164         // Paint the entire image with solid black at 50% transparency
165         NSRect imageRect = NSZeroRect;
166         imageRect.size = [alternateImage size];
167         [[NSColor colorWithCalibratedWhite:0.0 alpha:0.5] set];
168         NSRectFill(imageRect);
169         // Composite the original image with the alternate image
170         [nsimage compositeToPoint:NSZeroPoint operation:NSCompositeDestinationAtop];
171         [alternateImage unlockFocus];
172         [m_cocoaNSButtonCell setAlternateImage:alternateImage];
173         [alternateImage release];
174     }
175     [nsimage release];
176
177     NSMutableAttributedString *alternateTitle = [[NSMutableAttributedString alloc] initWithAttributedString:[m_cocoaNSButtonCell attributedTitle]];
178     [alternateTitle applyFontTraits:NSBoldFontMask range:NSMakeRange(0,[alternateTitle length])];
179     [m_cocoaNSButtonCell setAttributedAlternateTitle:alternateTitle];
180     [alternateTitle release];
181
182     // ----
183     [m_cocoaNSButtonCell setImagePosition:NSImageBelow];
184 //    [m_cocoaNSButtonCell setBezeled:NO];
185     [m_cocoaNSButtonCell setButtonType:NSMomentaryChangeButton];
186     [m_cocoaNSButtonCell setBordered:NO];
187 //    [m_cocoaNSButtonCell setHighlightsBy:NSContentsCellMask|NSPushInCellMask];
188 //    [m_cocoaNSButtonCell setShowsStateBy:NSContentsCellMask|NSPushInCellMask];
189     AssociateNSActionCell(m_cocoaNSButtonCell);
190     return true;
191 }
192
193 void wxToolBarTool::DrawTool(NSView *nsview)
194 {
195     [m_cocoaNSButtonCell drawWithFrame:m_frameRect inView:nsview];
196 }
197
198 // ========================================================================
199 // wxToolBar
200 // ========================================================================
201 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
202
203 //-----------------------------------------------------------------------------
204 // wxToolBar construction
205 //-----------------------------------------------------------------------------
206
207 void wxToolBar::Init()
208 {
209     m_owningFrame = NULL;
210     m_mouseDownTool = NULL;
211 }
212
213 wxToolBar::~wxToolBar()
214 {
215 }
216
217 bool wxToolBar::Create( wxWindow *parent,
218                         wxWindowID winid,
219                         const wxPoint& pos,
220                         const wxSize& size,
221                         long style,
222                         const wxString& name )
223 {
224     // Call wxControl::Create so we get a wxNonControlNSControl
225     return wxToolBarBase::Create(parent,winid,pos,size,style,wxDefaultValidator,name);
226 }
227
228 wxToolBarToolBase *wxToolBar::CreateTool(int toolid,
229                                          const wxString& text,
230                                          const wxBitmap& bitmap1,
231                                          const wxBitmap& bitmap2,
232                                          wxItemKind kind,
233                                          wxObject *clientData,
234                                          const wxString& shortHelpString,
235                                          const wxString& longHelpString)
236 {
237     return new wxToolBarTool(this, toolid, text, bitmap1, bitmap2, kind,
238                              clientData, shortHelpString, longHelpString);
239 }
240
241 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
242 {
243     return new wxToolBarTool(this, control);
244 }
245
246 void wxToolBar::SetWindowStyleFlag( long style )
247 {
248     wxToolBarBase::SetWindowStyleFlag(style);
249 }
250
251 bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
252 {
253     return true;
254 }
255
256 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
257 {
258     Realize();
259     return true;
260 }
261
262 bool wxToolBar::Cocoa_drawRect(const NSRect &rect)
263 {
264     wxToolBarToolsList::compatibility_iterator node;
265     for(node = m_tools.GetFirst(); node; node = node->GetNext())
266     {
267         wxToolBarTool *tool = static_cast<wxToolBarTool*>(node->GetData());
268         tool->DrawTool(m_cocoaNSView);
269     }
270     return wxToolBarBase::Cocoa_drawRect(rect);
271 }
272
273 static const NSSize toolPadding = { 4.0, 4.0 };
274
275 static NSRect AddToolPadding(NSRect toolRect)
276 {
277         toolRect.origin.x -= toolPadding.width;
278         toolRect.size.width += 2.0*toolPadding.width;
279         toolRect.origin.y -= toolPadding.height;
280         toolRect.size.height += 2.0*toolPadding.height;
281         return toolRect;
282 }
283
284 bool wxToolBar::Cocoa_mouseDragged(WX_NSEvent theEvent)
285 {
286     if(m_mouseDownTool && [m_cocoaNSView
287             mouse:[m_cocoaNSView convertPoint:[theEvent locationInWindow]
288                 fromView:nil]
289             inRect:AddToolPadding(m_mouseDownTool->GetFrameRect())])
290     {
291         NSButtonCell *buttonCell = m_mouseDownTool->GetNSButtonCell();
292         if(buttonCell)
293         {
294             [buttonCell setHighlighted: YES];
295             if([buttonCell trackMouse: theEvent
296                 inRect:AddToolPadding(m_mouseDownTool->GetFrameRect()) ofView:m_cocoaNSView
297                 untilMouseUp:NO])
298             {
299                 m_mouseDownTool = NULL;
300                 wxLogDebug(wxT("Button was clicked after drag!"));
301             }
302             [buttonCell setHighlighted: NO];
303         }
304     }
305     return wxToolBarBase::Cocoa_mouseDragged(theEvent);
306 }
307
308 bool wxToolBar::Cocoa_mouseDown(WX_NSEvent theEvent)
309 {
310     wxToolBarTool *tool = CocoaFindToolForPosition([m_cocoaNSView convertPoint:[theEvent locationInWindow] fromView:nil]);
311     if(tool)
312     {
313         NSButtonCell *buttonCell = tool->GetNSButtonCell();
314         if(buttonCell)
315         {
316             m_mouseDownTool = tool;
317             [buttonCell setHighlighted: YES];
318             if([buttonCell trackMouse: theEvent
319                 inRect:AddToolPadding(tool->GetFrameRect()) ofView:m_cocoaNSView
320                 untilMouseUp:NO])
321             {
322                 m_mouseDownTool = NULL;
323                 wxLogDebug(wxT("Button was clicked!"));
324             }
325             [buttonCell setHighlighted: NO];
326         }
327     }
328     return wxToolBarBase::Cocoa_mouseDown(theEvent);
329 }
330
331 bool wxToolBar::Realize()
332 {
333     wxAutoNSAutoreleasePool pool;
334
335     wxToolBarToolsList::compatibility_iterator node;
336     NSSize totalSize = NSZeroSize;
337     // This is for horizontal, TODO: vertical
338     for(node = m_tools.GetFirst(); node; node = node->GetNext())
339     {
340         wxToolBarTool *tool = static_cast<wxToolBarTool*>(node->GetData());
341         if(tool->IsControl())
342         {
343             totalSize.width = ceil(totalSize.width);
344             wxControl *control = tool->GetControl();
345             wxSize controlSize = control->GetSize();
346             control->SetPosition(wxPoint((wxCoord)totalSize.width,0));
347             totalSize.width += controlSize.x;
348             if(controlSize.y > totalSize.height)
349                 totalSize.height = controlSize.y;
350         }
351         else if(tool->IsSeparator())
352         {
353             totalSize.width += 2.0;
354         }
355         else
356         {
357             NSButtonCell *buttonCell = tool->GetNSButtonCell();
358             NSSize toolSize = [buttonCell cellSize];
359             tool->SetFrameRect(NSMakeRect(totalSize.width+toolPadding.width,toolPadding.height,toolSize.width,toolSize.height));
360             toolSize.width += 2.0*toolPadding.width;
361             toolSize.height += 2.0*toolPadding.height;
362             totalSize.width += toolSize.width;
363             if(toolSize.height > totalSize.height)
364                 totalSize.height = toolSize.height;
365         }
366     }
367     m_bestSize = wxSize((wxCoord)ceil(totalSize.width),(wxCoord)ceil(totalSize.height));
368     if(m_owningFrame)
369         m_owningFrame->UpdateFrameNSView();
370     return true;
371 }
372
373 wxSize wxToolBar::DoGetBestSize() const
374 {
375     return m_bestSize;
376 }
377
378 // ----------------------------------------------------------------------------
379 // wxToolBar tools state
380 // ----------------------------------------------------------------------------
381
382 void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
383 {
384 }
385
386 void wxToolBar::DoToggleTool( wxToolBarToolBase *toolBase, bool toggle )
387 {
388 }
389
390 void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
391                             bool WXUNUSED(toggle))
392 {
393 }
394
395 // ----------------------------------------------------------------------------
396 // wxToolBar geometry
397 // ----------------------------------------------------------------------------
398
399 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
400 {
401     return NULL;
402 }
403
404 wxToolBarTool *wxToolBar::CocoaFindToolForPosition(const NSPoint& pos) const
405 {
406     wxToolBarToolsList::compatibility_iterator node;
407     for(node = m_tools.GetFirst(); node; node = node->GetNext())
408     {
409         wxToolBarTool *tool = static_cast<wxToolBarTool*>(node->GetData());
410         if(tool->IsControl())
411         {
412             // TODO
413         }
414         else if(tool->IsSeparator())
415         {   // Do nothing
416         }
417         else
418         {
419             if([m_cocoaNSView mouse:pos inRect:AddToolPadding(tool->GetFrameRect())])
420                 return tool;
421         }
422     }
423     return NULL;
424 }
425
426 void wxToolBar::SetMargins( int x, int y )
427 {
428 }
429
430 void wxToolBar::SetToolSeparation( int separation )
431 {
432     m_toolSeparation = separation;
433 }
434
435 void wxToolBar::SetToolShortHelp( int id, const wxString& helpString )
436 {
437 }
438
439 // ----------------------------------------------------------------------------
440 // wxToolBar idle handling
441 // ----------------------------------------------------------------------------
442
443 void wxToolBar::OnInternalIdle()
444 {
445 }
446
447 #endif // wxUSE_TOOLBAR_NATIVE