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