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