1 /////////////////////////////////////////////////////////////////////////////
 
   2 // Name:        src/cocoa/toolbar.mm
 
   4 // Author:      David Elliott
 
   8 // Copyright:   (c) 2003 David Elliott
 
   9 // Licence:     wxWidgets licence
 
  10 /////////////////////////////////////////////////////////////////////////////
 
  12 // ============================================================================
 
  14 // ============================================================================
 
  16 // ----------------------------------------------------------------------------
 
  18 // ----------------------------------------------------------------------------
 
  20 // For compilers that support precompilation, includes "wx.h".
 
  21 #include "wx/wxprec.h"
 
  23 #if wxUSE_TOOLBAR_NATIVE
 
  25     #include "wx/toolbar.h"
 
  30 #include "wx/cocoa/string.h"
 
  31 #include "wx/cocoa/autorelease.h"
 
  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>
 
  44 DECLARE_WXCOCOA_OBJC_CLASS(NSActionCell);
 
  46 // ========================================================================
 
  47 // wxCocoaNSActionCell
 
  48 // ========================================================================
 
  49 WX_DECLARE_OBJC_HASHMAP(NSActionCell);
 
  51 class wxCocoaNSActionCell
 
  53     WX_DECLARE_OBJC_INTERFACE(NSActionCell)
 
  55     virtual void CocoaTarget_wxNSActionCellAction() {}
 
  57     static struct objc_object *sm_cocoaTarget;
 
  60 // ============================================================================
 
  61 // @class wxNSActionCellTarget
 
  62 // ============================================================================
 
  63 @interface wxNSActionCellTarget : NSObject
 
  67 - (void)wxNSActionCellAction: (id)sender;
 
  68 @end //interface wxNSActionCellTarget
 
  70 @implementation wxNSActionCellTarget : NSObject
 
  72 - (void)wxNSActionCellAction: (id)sender
 
  74     wxLogTrace(wxTRACE_COCOA,wxT("wxNSActionCellAction"));
 
  75     wxCocoaNSActionCell *wxcontrol = wxCocoaNSActionCell::GetFromCocoa(sender);
 
  76     wxCHECK_RET(wxcontrol,wxT("wxNSActionCellAction received but no wxCocoaNSActionCell exists!"));
 
  77     wxcontrol->CocoaTarget_wxNSActionCellAction();
 
  80 @end //implementation wxNSActionCellTarget
 
  82 // ========================================================================
 
  83 // wxCocoaNSActionCell
 
  84 // ========================================================================
 
  85 struct objc_object *wxCocoaNSActionCell::sm_cocoaTarget = [[wxNSActionCellTarget alloc] init];
 
  86 WX_IMPLEMENT_OBJC_INTERFACE(NSActionCell)
 
  88 // ========================================================================
 
  90 // ========================================================================
 
  91 class wxToolBarTool : public wxToolBarToolBase, protected wxCocoaNSActionCell
 
  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)
 
 105     wxToolBarTool(wxToolBar *tbar, wxControl *control)
 
 106         : wxToolBarToolBase(tbar, control)
 
 112     bool CreateButtonCell();
 
 114     // is this a radio button?
 
 116     // unlike GetKind(), can be called for any kind of tools, not just buttons
 
 117     bool IsRadio() const { return IsButton() && GetKind() == wxITEM_RADIO; }
 
 119     NSRect GetFrameRect()
 
 120     {   return m_frameRect; }
 
 121     void SetFrameRect(NSRect frameRect)
 
 122     {   m_frameRect = frameRect; }
 
 123     void DrawTool(NSView *nsview);
 
 125     NSButtonCell *GetNSButtonCell()
 
 126     {   return m_cocoaNSButtonCell; }
 
 129     NSButtonCell *m_cocoaNSButtonCell;
 
 133 // ========================================================================
 
 135 // ========================================================================
 
 136 void wxToolBarTool::Init()
 
 138     m_cocoaNSButtonCell = NULL;
 
 139     m_frameRect = NSZeroRect;
 
 142 wxToolBarTool::~wxToolBarTool()
 
 144     DisassociateNSActionCell(m_cocoaNSButtonCell);
 
 145     [m_cocoaNSButtonCell release];
 
 148 bool wxToolBarTool::CreateButtonCell()
 
 150     wxAutoNSAutoreleasePool pool;
 
 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]];
 
 159     // Create an alternate image in the style of NSToolBar
 
 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];
 
 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];
 
 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);
 
 193 void wxToolBarTool::DrawTool(NSView *nsview)
 
 195     [m_cocoaNSButtonCell drawWithFrame:m_frameRect inView:nsview];
 
 198 // ========================================================================
 
 200 // ========================================================================
 
 201 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
 
 203 //-----------------------------------------------------------------------------
 
 204 // wxToolBar construction
 
 205 //-----------------------------------------------------------------------------
 
 207 void wxToolBar::Init()
 
 209     m_owningFrame = NULL;
 
 210     m_mouseDownTool = NULL;
 
 213 wxToolBar::~wxToolBar()
 
 217 bool wxToolBar::Create( wxWindow *parent,
 
 222                         const wxString& name )
 
 224     // Call wxControl::Create so we get a wxNonControlNSControl
 
 225     return wxToolBarBase::Create(parent,winid,pos,size,style,wxDefaultValidator,name);
 
 228 wxToolBarToolBase *wxToolBar::CreateTool(int toolid,
 
 229                                          const wxString& text,
 
 230                                          const wxBitmap& bitmap1,
 
 231                                          const wxBitmap& bitmap2,
 
 233                                          wxObject *clientData,
 
 234                                          const wxString& shortHelpString,
 
 235                                          const wxString& longHelpString)
 
 237     return new wxToolBarTool(this, toolid, text, bitmap1, bitmap2, kind,
 
 238                              clientData, shortHelpString, longHelpString);
 
 241 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
 
 243     return new wxToolBarTool(this, control);
 
 246 void wxToolBar::SetWindowStyleFlag( long style )
 
 248     wxToolBarBase::SetWindowStyleFlag(style);
 
 251 bool wxToolBar::DoInsertTool(size_t pos, wxToolBarToolBase *toolBase)
 
 256 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *toolBase)
 
 262 bool wxToolBar::Cocoa_drawRect(const NSRect &rect)
 
 264     wxToolBarToolsList::compatibility_iterator node;
 
 265     for(node = m_tools.GetFirst(); node; node = node->GetNext())
 
 267         wxToolBarTool *tool = static_cast<wxToolBarTool*>(node->GetData());
 
 268         tool->DrawTool(m_cocoaNSView);
 
 270     return wxToolBarBase::Cocoa_drawRect(rect);
 
 273 static const NSSize toolPadding = { 4.0, 4.0 };
 
 275 static NSRect AddToolPadding(NSRect toolRect)
 
 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;
 
 284 bool wxToolBar::Cocoa_mouseDragged(WX_NSEvent theEvent)
 
 286     if(m_mouseDownTool && [m_cocoaNSView
 
 287             mouse:[m_cocoaNSView convertPoint:[theEvent locationInWindow]
 
 289             inRect:AddToolPadding(m_mouseDownTool->GetFrameRect())])
 
 291         NSButtonCell *buttonCell = m_mouseDownTool->GetNSButtonCell();
 
 294             [buttonCell setHighlighted: YES];
 
 295             if([buttonCell trackMouse: theEvent
 
 296                 inRect:AddToolPadding(m_mouseDownTool->GetFrameRect()) ofView:m_cocoaNSView
 
 299                 m_mouseDownTool = NULL;
 
 300                 wxLogTrace(wxTRACE_COCOA,wxT("Button was clicked after drag!"));
 
 302             [buttonCell setHighlighted: NO];
 
 305     return wxToolBarBase::Cocoa_mouseDragged(theEvent);
 
 308 bool wxToolBar::Cocoa_mouseDown(WX_NSEvent theEvent)
 
 310     wxToolBarTool *tool = CocoaFindToolForPosition([m_cocoaNSView convertPoint:[theEvent locationInWindow] fromView:nil]);
 
 313         NSButtonCell *buttonCell = tool->GetNSButtonCell();
 
 316             m_mouseDownTool = tool;
 
 317             [buttonCell setHighlighted: YES];
 
 318             if([buttonCell trackMouse: theEvent
 
 319                 inRect:AddToolPadding(tool->GetFrameRect()) ofView:m_cocoaNSView
 
 322                 m_mouseDownTool = NULL;
 
 323                 wxLogTrace(wxTRACE_COCOA,wxT("Button was clicked!"));
 
 325             [buttonCell setHighlighted: NO];
 
 328     return wxToolBarBase::Cocoa_mouseDown(theEvent);
 
 331 bool wxToolBar::Realize()
 
 333     wxAutoNSAutoreleasePool pool;
 
 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())
 
 340         wxToolBarTool *tool = static_cast<wxToolBarTool*>(node->GetData());
 
 341         if(tool->IsControl())
 
 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;
 
 351         else if(tool->IsSeparator())
 
 353             totalSize.width += 2.0;
 
 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;
 
 367     m_bestSize = wxSize((wxCoord)ceil(totalSize.width),(wxCoord)ceil(totalSize.height));
 
 369         m_owningFrame->UpdateFrameNSView();
 
 373 wxSize wxToolBar::DoGetBestSize() const
 
 378 // ----------------------------------------------------------------------------
 
 379 // wxToolBar tools state
 
 380 // ----------------------------------------------------------------------------
 
 382 void wxToolBar::DoEnableTool(wxToolBarToolBase *toolBase, bool enable)
 
 386 void wxToolBar::DoToggleTool( wxToolBarToolBase *toolBase, bool toggle )
 
 390 void wxToolBar::DoSetToggle(wxToolBarToolBase * WXUNUSED(tool),
 
 391                             bool WXUNUSED(toggle))
 
 395 // ----------------------------------------------------------------------------
 
 396 // wxToolBar geometry
 
 397 // ----------------------------------------------------------------------------
 
 399 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
 
 404 wxToolBarTool *wxToolBar::CocoaFindToolForPosition(const NSPoint& pos) const
 
 406     wxToolBarToolsList::compatibility_iterator node;
 
 407     for(node = m_tools.GetFirst(); node; node = node->GetNext())
 
 409         wxToolBarTool *tool = static_cast<wxToolBarTool*>(node->GetData());
 
 410         if(tool->IsControl())
 
 414         else if(tool->IsSeparator())
 
 419             if([m_cocoaNSView mouse:pos inRect:AddToolPadding(tool->GetFrameRect())])
 
 426 void wxToolBar::SetMargins( int x, int y )
 
 430 void wxToolBar::SetToolSeparation( int separation )
 
 432     m_toolSeparation = separation;
 
 435 void wxToolBar::SetToolShortHelp( int id, const wxString& helpString )
 
 439 // ----------------------------------------------------------------------------
 
 440 // wxToolBar idle handling
 
 441 // ----------------------------------------------------------------------------
 
 443 void wxToolBar::OnInternalIdle()
 
 447 #endif // wxUSE_TOOLBAR_NATIVE