libs-gui/Source/NSToolbarItem.m
Fred Kiefer e344345023 Add MaxOS 10.4 methods and required ivars to NSButtonCell, implemented
then and use this methods. Also adjusted subclasses tothis changes.
Split off theming code for buttons into two methods.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@24400 72102866-910b-0410-8b05-ffd578937521
2007-01-23 14:17:02 +00:00

1508 lines
38 KiB
Objective-C

/*
NSToolbarItem.m
The Toolbar item class.
Copyright (C) 2002 Free Software Foundation, Inc.
Author: Gregory John Casamento <greg_casamento@yahoo.com>,
Fabien Vallon <fabien.vallon@fr.alcove.com>,
Quentin Mathe <qmathe@club-internet.fr>
Date: May 2002
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; see the file COPYING.LIB.
If not, write to the Free Software Foundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <Foundation/NSObject.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSDebug.h>
#include <Foundation/NSDictionary.h>
#include <Foundation/NSException.h>
#include <Foundation/NSString.h>
#include "AppKit/NSApplication.h"
#include "AppKit/NSButton.h"
#include "AppKit/NSButtonCell.h"
#include "AppKit/NSDragging.h"
#include "AppKit/NSEvent.h"
#include "AppKit/NSFont.h"
#include "AppKit/NSImage.h"
#include "AppKit/NSMenu.h"
#include "AppKit/NSMenuItem.h"
#include "AppKit/NSParagraphStyle.h"
#include "AppKit/NSPasteboard.h"
#include "AppKit/NSView.h"
#include "GNUstepGUI/GSToolbar.h"
#include "GNUstepGUI/GSToolbarView.h"
#include "AppKit/NSToolbarItem.h"
/*
* Each NSToolbarItem object are coupled with a backView which is their
* representation on the screen.
* backView for the standard toolbar item (without custom view) are NSButton
* subclass called GSToolbarButton.
* backView for the toolbar item with a custom view are NSView subclass called
* GSToolbarBackView.
* GSToolbarButton and GSToolbarBackView are adjusted according to their content
* and their title when the method layout is called.
* The predefined GNUstep toolbar items are implemented with a class cluster
* pattern: initWithToolbarItemIdentifier: returns differents concrete subclass
* in accordance with the item identifier.
*/
typedef enum {
ItemBackViewDefaultHeight = 60,
ItemBackViewRegularHeight = 60,
ItemBackViewSmallHeight = 50
} ItemBackViewHeight;
typedef enum {
ItemBackViewDefaultWidth = 60,
ItemBackViewRegularWidth = 60,
ItemBackViewSmallWidth = 50
} ItemBackViewWidth;
static const int ItemBackViewX = 0;
static const int ItemBackViewY = 0;
static const int InsetItemViewX = 10;
static const int InsetItemViewY = 26;
static const int InsetItemTextX = 3;
static const int InsetItemTextY = 4;
static NSFont *NormalFont = nil; // See NSToolbarItem -initialize method
// [NSFont smallSystemFontSize] or better should be NSControlContentFontSize
static NSFont *SmallFont = nil;
NSString *GSMovableToolbarItemPboardType = @"GSMovableToolbarItemPboardType";
@interface GSToolbar (GNUstepPrivate)
- (GSToolbarView *) _toolbarView;
- (int) _indexOfItem: (NSToolbarItem *)item; // Used by drag setup
- (void) _performRemoveItem: (NSToolbarItem *)item; // Used by drag setup
@end
@interface NSToolbarItem (GNUstepPrivate)
- (void) _layout;
// ---
- (NSView *) _backView;
- (NSMenuItem *) _defaultMenuFormRepresentation;
- (BOOL) _isFlexibleSpace;
- (BOOL) _isModified;
- (BOOL) _selectable;
- (GSToolbar *) _toolbar;
- (void) _setSelectable: (BOOL)selectable;
- (BOOL) _selected;
- (void) _setSelected: (BOOL)selected;
- (void) _setToolbar: (GSToolbar *)toolbar;
@end
@interface GSToolbarView (GNUstepPrivate)
- (void) _reload;
@end
/*
* NSButton subclass is the toolbar buttons _backView
*/
@interface GSToolbarButton : NSButton
{
NSToolbarItem *_toolbarItem;
SEL _toolbarItemAction;
}
- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem;
- (void) layout;
// Accessors
- (NSToolbarItem *) toolbarItem;
- (SEL) toolbarItemAction;
- (void) setToolbarItemAction: (SEL)action;
@end
@interface GSToolbarButtonCell : NSButtonCell
{
NSRect titleRect;
NSRect imageRect;
}
@end
// ---
@implementation GSToolbarButton
+ (Class) cellClass
{
return [GSToolbarButtonCell class];
}
- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem
{
self = [super initWithFrame: NSMakeRect(ItemBackViewX, ItemBackViewY,
ItemBackViewDefaultWidth, ItemBackViewDefaultHeight)];
// Frame will be reset by the layout method
if (self != nil)
{
// Don't do an ASSIGN here, the toolbar item itself retains us.
_toolbarItem = toolbarItem;
//[self setCell: [[GSToolbarButtonCell alloc] init]];
}
return self;
}
- (void) dealloc
{
// Nothing to do currently
[super dealloc];
}
- (void) layout
{
float textWidth, layoutedWidth = -1, layoutedHeight = -1;
NSAttributedString *attrStr;
NSDictionary *attr;
NSFont *font;
unsigned int borderMask = [[[_toolbarItem toolbar] _toolbarView] borderMask];
NSString *label = [_toolbarItem label];
// Adjust the layout in accordance with NSToolbarSizeMode
font = NormalFont;
switch ([[_toolbarItem toolbar] sizeMode])
{
case NSToolbarSizeModeDefault:
layoutedWidth = ItemBackViewDefaultWidth;
layoutedHeight = ItemBackViewDefaultHeight;
[[_toolbarItem image] setSize: NSMakeSize(32, 32)];
break;
case NSToolbarSizeModeRegular:
layoutedWidth = ItemBackViewRegularWidth;
layoutedHeight = ItemBackViewRegularHeight;
[[_toolbarItem image] setSize: NSMakeSize(32, 32)];
break;
case NSToolbarSizeModeSmall:
layoutedWidth = ItemBackViewSmallWidth;
layoutedHeight = ItemBackViewSmallHeight;
[[_toolbarItem image] setSize: NSMakeSize(24, 24)];
/* Not use [self image] here because it can return nil, when image
position is set to NSNoImage. Even if NSToolbarDisplayModeTextOnly
is not true anymore -setImagePosition: is only called below, then
[self image] can still returns nil. */
font = SmallFont;
break;
default:
; // Invalid
}
[[self cell] setFont: font];
// Adjust the layout in accordance with the border
if (!(borderMask & GSToolbarViewBottomBorder))
{
layoutedHeight++;
layoutedWidth++;
}
if (!(borderMask & GSToolbarViewTopBorder))
{
layoutedHeight++;
layoutedWidth++;
}
// Adjust the layout in accordance with the label
attr = [NSDictionary dictionaryWithObject: font forKey: NSFontAttributeName];
if (label == nil || [label isEqualToString: @""])
label = @"Dummy";
attrStr = [[NSAttributedString alloc] initWithString: label attributes: attr];
textWidth = [attrStr size].width + 2 * InsetItemTextX;
if ([[_toolbarItem toolbar] displayMode] != NSToolbarDisplayModeIconOnly
&& layoutedWidth != -1 && textWidth > layoutedWidth)
layoutedWidth = textWidth;
// Adjust the layout in accordance with NSToolbarDisplayMode
switch ([[_toolbarItem toolbar] displayMode])
{
case NSToolbarDisplayModeDefault:
[self setImagePosition: NSImageAbove];
break;
case NSToolbarDisplayModeIconAndLabel:
[self setImagePosition: NSImageAbove];
break;
case NSToolbarDisplayModeIconOnly:
[self setImagePosition: NSImageOnly];
layoutedHeight -= [attrStr size].height + InsetItemTextY;
break;
case NSToolbarDisplayModeLabelOnly:
[self setImagePosition: NSNoImage];
layoutedHeight = [attrStr size].height + InsetItemTextY * 2;
break;
default:
; // Invalid
}
DESTROY(attrStr);
// Set the frame size to use the new layout
[self setFrameSize: NSMakeSize(layoutedWidth, layoutedHeight)];
}
/*
* The code below should be kept in sync with GSToolbarBackView methods which
* have identical names.
*/
- (void) mouseDown: (NSEvent *)event
{
GSToolbar *toolbar = [_toolbarItem toolbar];
if ([event modifierFlags] == NSCommandKeyMask
&& [toolbar allowsUserCustomization])
{
NSSize viewSize = [self frame].size;
NSImage *image = [[NSImage alloc] initWithSize: viewSize];
NSCell *cell = [self cell];
NSPasteboard *pboard;
int index;
AUTORELEASE(image);
// Prepare the drag
RETAIN(self);
/* We need to keep this view (aka self) to be able to draw the drag
image. */
// Draw the drag content in an image
/* The code below is only partially supported by GNUstep, then NSImage
needs to be improved. */
[image lockFocus];
[cell setShowsFirstResponder: NO]; // To remove the dotted rect
[cell drawWithFrame:
NSMakeRect(0, 0, viewSize.width, viewSize.height) inView: nil];
[cell setShowsFirstResponder: YES];
[image unlockFocus];
pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
[pboard declareTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType]
owner: nil];
index = [toolbar _indexOfItem: _toolbarItem];
[pboard setString: [NSString stringWithFormat:@"%d", index]
forType: GSMovableToolbarItemPboardType];
[self dragImage: image
at: NSMakePoint(0.0, 0.0)
offset: NSMakeSize(0.0, 0.0)
event: event
pasteboard: pboard
source: self
slideBack: NO];
}
else if ([event modifierFlags] != NSCommandKeyMask)
{
[super mouseDown: event];
}
}
- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location
{
GSToolbar *toolbar = [_toolbarItem toolbar];
RETAIN(_toolbarItem);
/* We retain the toolbar item to be able to have have it reinsered later by
the dragging destination. */
[toolbar _performRemoveItem: _toolbarItem];
}
- (void) draggedImage: (NSImage *)dragImage
endedAt: (NSPoint)location
operation: (NSDragOperation)operation
{
RELEASE(self); // The view is no more needed : no more drawing to do with it.
}
- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)isLocal
{
return isLocal ? NSDragOperationGeneric : NSDragOperationNone;
}
/*
* End of the code to keep in sync
*/
- (BOOL) sendAction: (SEL)action to: (id)target
{
if ([_toolbarItem _selectable])
{
[[_toolbarItem toolbar]
setSelectedItemIdentifier: [_toolbarItem itemIdentifier]];
}
if (_toolbarItemAction)
{
return [NSApp sendAction: _toolbarItemAction
to: target
from: _toolbarItem];
}
else
{
return NO;
}
}
- (NSToolbarItem *) toolbarItem
{
return _toolbarItem;
}
- (void) setToolbarItemAction: (SEL) action
{
_toolbarItemAction = action;
}
- (SEL) toolbarItemAction
{
return _toolbarItemAction;
}
@end
@implementation GSToolbarButtonCell
/* Overriden NSButtonCell method to handle cell type in a basic way which avoids
to lose image or empty title on new image position (when this involves a cell
type switch) and the need to reset it. That would happen in GSToolbarButton
-layout method (on toolbar display mode switch).
Note that empty title are used with space or separator toolbar items. */
- (void) setImagePosition: (NSCellImagePosition)aPosition
{
_cell.image_position = aPosition;
if (_cell.image_position == NSNoImage)
{
_cell.type = NSTextCellType;
}
else
{
_cell.type = NSImageCellType;
}
}
// Overriden NSButtonCell method
- (void) drawInteriorWithFrame: (NSRect)cellFrame inView: (NSView*)controlView
{
NSSize titleSize = [[self attributedTitle] size];
// We ignore alternateAttributedTitle, it is not needed
/* We store the values we need to customize the drawing into titleRect and
imageRect. */
titleRect.origin.x = cellFrame.origin.x;
titleRect.origin.y = cellFrame.origin.y + InsetItemTextY;
titleRect.size.width = cellFrame.size.width;
titleRect.size.height = titleSize.height;
imageRect.origin.x = cellFrame.origin.x;
imageRect.origin.y = cellFrame.origin.y;
if ([self imagePosition] != NSImageOnly)
imageRect.origin.y += titleRect.size.height;
imageRect.size.width = cellFrame.size.width;
imageRect.size.height = cellFrame.size.height;
if ([self imagePosition] != NSImageOnly)
imageRect.size.height -= titleRect.size.height;
[super drawInteriorWithFrame: cellFrame inView: controlView];
}
// Overriden NSCell method
- (void) _drawAttributedText: (NSAttributedString*)aString
inFrame: (NSRect)aRect
{
if (aString == nil)
return;
/* Important: text should always be vertically centered without considering
descender (as if descender did not exist). This is particularly important
for single line texts.Please make sure the output remains always
correct. */
[aString drawInRect: titleRect]; // We ignore aRect value
}
// Overriden NSButtonCell method
- (void) drawImage: (NSImage *)anImage withFrame: (NSRect)aRect inView: (NSView*)controlView
{
// We ignore aRect value
[super drawImage: anImage withFrame: imageRect inView: controlView];
}
@end
/*
* Back view used to enclose toolbar item's custom view
*/
@interface GSToolbarBackView : NSView
{
NSToolbarItem *_toolbarItem;
NSFont *_font;
BOOL _enabled;
BOOL _showLabel;
}
- (id) initWithToolbarItem: (NSToolbarItem *)toolbarItem;
- (NSToolbarItem *) toolbarItem;
- (BOOL) enabled;
- (void) setEnabled: (BOOL)enabled;
@end
@implementation GSToolbarBackView
- (id)initWithToolbarItem: (NSToolbarItem *)toolbarItem
{
self = [super initWithFrame: NSMakeRect(ItemBackViewX, ItemBackViewY,
ItemBackViewDefaultWidth, ItemBackViewDefaultHeight)];
// Frame will be reset by the layout method
if (self != nil)
{
// Don't do an ASSIGN here, the toolbar item itself retains us.
_toolbarItem = toolbarItem;
}
return self;
}
- (void) dealloc
{
/* _font is pointing on a static variable then we do own it and don't need
to release it. */
[super dealloc];
}
- (void) drawRect: (NSRect)rect
{
[super drawRect: rect]; // We draw _view which is a subview
if (_showLabel)
{
NSAttributedString *attrString;
NSDictionary *attr;
NSColor *color;
NSMutableParagraphStyle *pStyle;
NSRect titleRect;
NSRect viewBounds = [self bounds];
if (_enabled)
{
color = [NSColor blackColor];
}
else
{
color = [NSColor disabledControlTextColor];
}
pStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[pStyle setAlignment: NSCenterTextAlignment];
// We draw the label
attr = [NSDictionary dictionaryWithObjectsAndKeys: _font,
NSFontAttributeName, color, NSForegroundColorAttributeName, pStyle,
NSParagraphStyleAttributeName, nil];
RELEASE(pStyle);
attrString = [[NSAttributedString alloc]
initWithString: [_toolbarItem label] attributes: attr];
titleRect.origin.x = viewBounds.origin.x;
titleRect.origin.y = viewBounds.origin.y + InsetItemTextY;
titleRect.size.width = viewBounds.size.width;
titleRect.size.height = [attrString size].height;
[attrString drawInRect: titleRect];
DESTROY(attrString);
}
}
- (void) layout
{
NSView *view = [_toolbarItem view];
float insetItemViewY;
float textWidth, layoutedWidth = -1, layoutedHeight = -1;
NSAttributedString *attrStr;
NSDictionary *attr;
unsigned int borderMask = [[[_toolbarItem toolbar] _toolbarView] borderMask];
NSString *label = [_toolbarItem label];
_font = NormalFont;
if ([view superview] == nil) // Show the view to eventually hide it later
[self addSubview: view];
// Adjust the layout in accordance with NSToolbarSizeMode
switch ([[_toolbarItem toolbar] sizeMode])
{
case NSToolbarSizeModeDefault:
layoutedWidth = ItemBackViewDefaultWidth;
layoutedHeight = ItemBackViewDefaultHeight;
if ([view frame].size.height > 32)
[view removeFromSuperview];
break;
case NSToolbarSizeModeRegular:
layoutedWidth = ItemBackViewRegularWidth;
layoutedHeight = ItemBackViewRegularHeight;
if ([view frame].size.height > 32)
[view removeFromSuperview];
break;
case NSToolbarSizeModeSmall:
layoutedWidth = ItemBackViewSmallWidth;
layoutedHeight = ItemBackViewSmallHeight;
_font = SmallFont;
if ([view frame].size.height > 24)
[view removeFromSuperview];
break;
default:
NSLog(@"Invalid NSToolbarSizeMode"); // Invalid
}
// Adjust the layout in accordance with the border
if (!(borderMask & GSToolbarViewBottomBorder))
{
layoutedHeight++;
layoutedWidth++;
}
if (!(borderMask & GSToolbarViewTopBorder))
{
layoutedHeight++;
layoutedWidth++;
}
// Adjust the layout in accordance with the label
attr = [NSDictionary dictionaryWithObject: _font forKey: NSFontAttributeName];
if (label == nil || [label isEqualToString: @""])
label = @"Dummy";
attrStr = [[NSAttributedString alloc] initWithString: label attributes: attr];
textWidth = [attrStr size].width + 2 * InsetItemTextX;
if (textWidth > layoutedWidth)
layoutedWidth = textWidth;
// Adjust the layout in accordance with NSToolbarDisplayMode
_enabled = YES;
_showLabel = YES;
/* This boolean variable is used to known when it's needed to draw the label
in the -drawRect: method. */
switch ([[_toolbarItem toolbar] displayMode])
{
case NSToolbarDisplayModeDefault:
break; // Nothing to do
case NSToolbarDisplayModeIconAndLabel:
break; // Nothing to do
case NSToolbarDisplayModeIconOnly:
_showLabel = NO;
layoutedHeight -= [attrStr size].height + InsetItemTextY;
break;
case NSToolbarDisplayModeLabelOnly:
_enabled = NO;
layoutedHeight = [attrStr size].height + InsetItemTextY * 2;
if ([view superview] != nil)
[view removeFromSuperview];
break;
default:
; // Invalid
}
/* If the view is visible...
Adjust the layout in accordance with the view width in the case it is
needed. */
if ([view superview] != nil)
{
if (layoutedWidth < [view frame].size.width + 2 * InsetItemViewX)
layoutedWidth = [view frame].size.width + 2 * InsetItemViewX;
}
// Set the frame size to use the new layout
[self setFrameSize: NSMakeSize(layoutedWidth, layoutedHeight)];
/* If the view is visible...
Adjust the view position in accordance with the new layout. */
if ([view superview] != nil)
{
if (_showLabel)
{
insetItemViewY = ([self frame].size.height - [view frame].size.height
- [attrStr size].height - InsetItemTextX) / 2
+ [attrStr size].height + InsetItemTextX;
}
else
{
insetItemViewY = ([self frame].size.height
- [view frame].size.height) / 2;
}
[view setFrameOrigin: NSMakePoint((layoutedWidth
- [view frame].size.width) / 2, insetItemViewY)];
}
DESTROY(attrStr);
}
- (NSView *) hitTest: (NSPoint)point
{
NSEvent *event = [NSApp currentEvent];
if ([self mouse: point inRect: [self frame]]
&& [event modifierFlags] == NSCommandKeyMask
&& [event type] == NSLeftMouseDown)
{
return self;
}
else
{
return [super hitTest: point];
}
}
/*
* The code below should be kept in sync with GSToolbarButton methods which
* have identical names.
*/
- (void) mouseDown: (NSEvent *)event
{
GSToolbar *toolbar = [_toolbarItem toolbar];
if ([event modifierFlags] == NSCommandKeyMask
&& [toolbar allowsUserCustomization])
{
NSSize viewSize = [self frame].size;
NSImage *image = [[NSImage alloc] initWithSize: viewSize];
NSPasteboard *pboard;
int index;
AUTORELEASE(image);
// Prepare the drag
RETAIN(self);
/* We need to keep this view (aka self) to be able to draw the drag
image. */
// Draw the drag content in an image
/* The code below is only partially supported by GNUstep, then NSImage
needs to be improved. */
[image lockFocus];
[self drawRect:
NSMakeRect(0, 0, viewSize.width, viewSize.height)];
[image unlockFocus];
pboard = [NSPasteboard pasteboardWithName: NSDragPboard];
[pboard declareTypes: [NSArray arrayWithObject: GSMovableToolbarItemPboardType]
owner: nil];
index = [toolbar _indexOfItem: _toolbarItem];
[pboard setString: [NSString stringWithFormat:@"%d", index]
forType: GSMovableToolbarItemPboardType];
[self dragImage: image
at: NSMakePoint(0.0, 0.0)
offset: NSMakeSize(0.0, 0.0)
event: event
pasteboard: pboard
source: self
slideBack: NO];
}
else if ([event modifierFlags] != NSCommandKeyMask)
{
[super mouseDown: event];
}
}
- (void) draggedImage: (NSImage *)dragImage beganAt: (NSPoint)location
{
GSToolbar *toolbar = [_toolbarItem toolbar];
RETAIN(_toolbarItem);
/* We retain the toolbar item to be able to have have it reinsered later by
the dragging destination. */
[toolbar _performRemoveItem: _toolbarItem];
}
- (void) draggedImage: (NSImage *)dragImage
endedAt: (NSPoint)location
operation: (NSDragOperation)operation
{
RELEASE(self); // The view is no more needed : no more drawing to do with it.
}
- (unsigned int) draggingSourceOperationMaskForLocal: (BOOL)isLocal
{
return isLocal ? NSDragOperationGeneric : NSDragOperationNone;
}
/*
* End of the code to keep in sync
*/
- (NSToolbarItem *)toolbarItem
{
return _toolbarItem;
}
- (BOOL) enabled
{
id view = [_toolbarItem view];
if ([view respondsToSelector: @selector(setEnabled:)])
{
return [view enabled];
}
return _enabled;
}
- (void) setEnabled: (BOOL)enabled
{
id view = [_toolbarItem view];
_enabled = enabled;
if ([view respondsToSelector: @selector(setEnabled:)])
{
[view setEnabled: enabled];
}
}
@end
/*
* Standard toolbar items.
*/
// ---- NSToolbarSeparatorItemIdentifier
@interface GSToolbarSeparatorItem : NSToolbarItem
{
}
@end
@implementation GSToolbarSeparatorItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
NSImage *image = [NSImage imageNamed: @"common_ToolbarSeparatorItem"];
self = [super initWithItemIdentifier: itemIdentifier];
[(NSButton *)[self _backView] setImagePosition: NSImageOnly];
[(NSButton *)[self _backView] setImage: image];
/* We bypass the toolbar item accessor to set the image in order to have it
(48 * 48) not resized. */
[[self _backView] setFrameSize: NSMakeSize(30, ItemBackViewDefaultHeight)];
return self;
}
- (NSMenuItem *) _defaultMenuFormRepresentation
{
return nil; // Override the default implementation in order to do nothing
}
- (void) _layout
{
NSView *backView = [self _backView];
// Override the default implementation
[(id)backView layout];
[backView setFrameSize: NSMakeSize(30, [backView frame].size.height)];
}
@end
// ---- NSToolbarSpaceItemIdentifier
@interface GSToolbarSpaceItem : NSToolbarItem
{
}
@end
@implementation GSToolbarSpaceItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
self = [super initWithItemIdentifier: itemIdentifier];
[self setLabel: @""];
return self;
}
- (NSMenuItem *) _defaultMenuFormRepresentation
{
return nil; // Override the default implementation in order to do nothing
}
@end
// ---- NSToolbarFlexibleSpaceItemIdentifier
@interface GSToolbarFlexibleSpaceItem : NSToolbarItem
{
}
@end
@implementation GSToolbarFlexibleSpaceItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
self = [super initWithItemIdentifier: itemIdentifier];
[self setLabel: @""];
[self _layout];
return self;
}
- (NSMenuItem *) _defaultMenuFormRepresentation
{
return nil; // Override the default implementation in order to do nothing
}
- (void) _layout
{
NSView *backView = [self _backView];
[(id)backView layout];
[backView setFrameSize: NSMakeSize(0, [backView frame].size.height)];
// Override the default implementation in order to reset the _backView to a zero width
}
@end
// ---- NSToolbarShowColorsItemIdentifier
@interface GSToolbarShowColorsItem : NSToolbarItem
{
}
@end
@implementation GSToolbarShowColorsItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
NSImage *image = [NSImage imageNamed: @"common_ToolbarShowColorsItem"];
self = [super initWithItemIdentifier: itemIdentifier];
[self setImage: image];
[self setLabel: @"Colors"]; // FIX ME: localize
// Set action...
[self setTarget: nil]; // Goes to first responder..
[self setAction: @selector(orderFrontColorPanel:)];
return self;
}
@end
// ---- NSToolbarShowFontsItemIdentifier
@interface GSToolbarShowFontsItem : NSToolbarItem
{
}
@end
@implementation GSToolbarShowFontsItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
NSImage *image = [NSImage imageNamed: @"common_ToolbarShowFontsItem"];
self = [super initWithItemIdentifier: itemIdentifier];
[self setImage: image];
[self setLabel: @"Fonts"]; // FIX ME: localize
// Set action...
[self setTarget: nil]; // Goes to first responder..
[self setAction: @selector(orderFrontFontPanel:)];
return self;
}
@end
// ---- NSToolbarCustomizeToolbarItemIdentifier
@interface GSToolbarCustomizeToolbarItem : NSToolbarItem
{
}
@end
@implementation GSToolbarCustomizeToolbarItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
NSImage *image = [NSImage imageNamed: @"common_ToolbarCustomizeToolbarItem"];
self = [super initWithItemIdentifier: itemIdentifier];
[self setImage: image];
[self setLabel: @"Customize"]; // FIX ME: localize
// Set action...
[self setTarget: nil]; // Goes to first responder..
[self setAction: @selector(runCustomizationPalette:)];
return self;
}
@end
// ---- NSToolbarPrintItemIdentifier
@interface GSToolbarPrintItem : NSToolbarItem
{
}
@end
@implementation GSToolbarPrintItem
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
NSImage *image = [NSImage imageNamed: @"common_Printer"];
self = [super initWithItemIdentifier: itemIdentifier];
[self setImage: image];
[self setLabel: @"Print..."]; // FIX ME: localize
// Set action...
[self setTarget: nil]; // goes to first responder..
[self setAction: @selector(print:)];
return self;
}
@end
@implementation NSToolbarItem
+ (void) initialize
{
NormalFont = RETAIN([NSFont systemFontOfSize: 11]);
// [NSFont smallSystemFontSize] or better should be NSControlContentFontSize
SmallFont = RETAIN([NSFont systemFontOfSize: 9]);
}
- (id) initWithItemIdentifier: (NSString *)itemIdentifier
{
GSToolbarButton *button;
NSButtonCell *cell;
if ((self = [super init]) != nil)
{
// GNUstep predefined toolbar items
if ([itemIdentifier isEqualToString: @"NSToolbarSeparatorItemIdentifier"]
&& [self isKindOfClass:[GSToolbarSeparatorItem class]] == NO)
{
[self release];
self = [[GSToolbarSeparatorItem alloc]
initWithItemIdentifier: itemIdentifier];
}
else if ([itemIdentifier isEqualToString: @"NSToolbarSpaceItemIdentifier"]
&& [self isKindOfClass:[GSToolbarSpaceItem class]] == NO)
{
[self release];
self = [[GSToolbarSpaceItem alloc]
initWithItemIdentifier: itemIdentifier];
}
else if ([itemIdentifier
isEqualToString: @"NSToolbarFlexibleSpaceItemIdentifier"]
&& [self isKindOfClass:[GSToolbarFlexibleSpaceItem class]] == NO)
{
[self release];
self = [[GSToolbarFlexibleSpaceItem alloc]
initWithItemIdentifier: itemIdentifier];
}
else if ([itemIdentifier
isEqualToString: @"NSToolbarShowColorsItemIdentifier"]
&& [self isKindOfClass:[GSToolbarShowColorsItem class]] == NO)
{
[self release];
self = [[GSToolbarShowColorsItem alloc]
initWithItemIdentifier: itemIdentifier];
}
else if ([itemIdentifier
isEqualToString: @"NSToolbarShowFontsItemIdentifier"]
&& [self isKindOfClass:[GSToolbarShowFontsItem class]] == NO)
{
[self release];
self = [[GSToolbarShowFontsItem alloc]
initWithItemIdentifier: itemIdentifier];
}
else if ([itemIdentifier
isEqualToString: @"NSToolbarCustomizeToolbarItemIdentifier"]
&& [self isKindOfClass:[GSToolbarCustomizeToolbarItem class]] == NO)
{
[self release];
self = [[GSToolbarCustomizeToolbarItem alloc]
initWithItemIdentifier: itemIdentifier];
}
else if ([itemIdentifier isEqualToString: @"NSToolbarPrintItemIdentifier"]
&& [self isKindOfClass:[GSToolbarPrintItem class]] == NO)
{
[self release];
self = [[GSToolbarPrintItem alloc]
initWithItemIdentifier: itemIdentifier];
}
// Normal toolbar items
else
{
ASSIGN(_itemIdentifier, itemIdentifier);
button = [[GSToolbarButton alloc] initWithToolbarItem: self];
cell = [button cell];
[button setTitle: @""];
[button setEnabled: NO];
[button setBordered: NO];
[button setImagePosition: NSImageAbove];
[cell setBezeled: YES];
[cell setHighlightsBy:
NSChangeGrayCellMask | NSChangeBackgroundCellMask];
[cell setFont: [NSFont systemFontOfSize: 11]];
/* [NSFont smallSystemFontSize] or better should be
controlContentFontSize. */
[_backView release];
_backView = button;
}
// gets
_flags._isEnabled = [_backView respondsToSelector: @selector(isEnabled)];
_flags._tag = YES;
_flags._action =
[_backView respondsToSelector: @selector(toolbarItemAction)];
_flags._target = [_backView respondsToSelector: @selector(target)];
_flags._image = [_backView respondsToSelector: @selector(image)];
// sets
_flags._setEnabled =
[_backView respondsToSelector: @selector(setEnabled:)];
_flags._setTag = YES;
_flags._setAction =
[_backView respondsToSelector: @selector(setToolbarItemAction:)];
_flags._setTarget =
[_backView respondsToSelector: @selector(setTarget:)];
_flags._setImage = [_backView respondsToSelector: @selector(setImage:)];
}
return self;
}
- (void) dealloc
{
RELEASE(_itemIdentifier);
RELEASE(_label);
RELEASE(_image);
RELEASE(_menuFormRepresentation);
RELEASE(_paletteLabel);
RELEASE(_toolTip);
RELEASE(_view);
RELEASE(_backView);
[super dealloc];
}
- (BOOL) allowsDuplicatesInToolbar
{
return _allowsDuplicatesInToolbar;
}
- (BOOL) isEnabled
{
if (_flags._isEnabled)
{
return [(id)_backView isEnabled];
}
return NO;
}
- (NSImage *)image
{
if (_flags._image)
{
return _image;
}
return nil;
}
- (NSString *) itemIdentifier
{
return _itemIdentifier;
}
- (NSString *) label
{
NSMenuItem *menuItem = [self menuFormRepresentation];
if ([[self toolbar] displayMode] == NSToolbarDisplayModeLabelOnly
&& menuItem != nil)
{
return [menuItem title];
}
else
{
return _label;
}
}
- (NSSize) maxSize
{
return _maxSize;
}
- (NSMenuItem *) menuFormRepresentation
{
return _menuFormRepresentation;
}
- (NSSize) minSize
{
return _minSize;
}
- (NSString *) paletteLabel
{
return _paletteLabel;
}
- (void) setAction: (SEL)action
{
if (_flags._setAction)
{
if ([_backView isKindOfClass: [GSToolbarButton class]])
[(GSToolbarButton *)_backView setToolbarItemAction: action];
if (action != NULL)
{
[self setEnabled: YES];
}
else
{
[self setEnabled: NO];
}
}
}
- (void) setEnabled: (BOOL)enabled
{
if (_flags._setEnabled)
[(id)_backView setEnabled: enabled];
}
- (void) setImage: (NSImage *)image
{
if (_flags._setImage)
{
ASSIGN(_image, image);
[_image setScalesWhenResized: YES];
//[_image setSize: NSMakeSize(32, 32)];
if ([_backView isKindOfClass: [NSButton class]])
[(NSButton *)_backView setImage: _image];
}
}
- (void) setLabel: (NSString *)label
{
ASSIGN(_label, label);
if ([_backView isKindOfClass: [NSButton class]])
[(NSButton *)_backView setTitle:_label];
_modified = YES;
if (_toolbar != nil)
[[_toolbar _toolbarView] _reload];
}
- (void) setMaxSize: (NSSize)maxSize
{
_maxSize = maxSize;
}
- (void) setMenuFormRepresentation: (NSMenuItem *)menuItem
{
ASSIGN(_menuFormRepresentation, menuItem);
}
- (void) setMinSize: (NSSize)minSize
{
_minSize = minSize;
}
- (void) setPaletteLabel: (NSString *)paletteLabel
{
ASSIGN(_paletteLabel, paletteLabel);
}
- (void) setTag: (int)tag
{
if (_flags._tag)
_tag = tag;
}
- (void) setTarget: (id)target
{
if (_flags._target)
{
if ([_backView isKindOfClass: [NSButton class]])
[(NSButton *)_backView setTarget: target];
}
}
- (void) setToolTip: (NSString *)toolTip
{
ASSIGN(_toolTip, toolTip);
[_view setToolTip: _toolTip];
}
- (void) setView: (NSView *)view
{
ASSIGN(_view, view);
if (_view == nil)
{
// gets
_flags._isEnabled = [_backView respondsToSelector: @selector(isEnabled)];
_flags._action =
[_backView respondsToSelector: @selector(toolbarItemAction)];
_flags._target = [_backView respondsToSelector: @selector(target)];
_flags._image = [_backView respondsToSelector: @selector(image)];
// sets
_flags._setEnabled =
[_backView respondsToSelector: @selector(setEnabled:)];
_flags._setAction =
[_backView respondsToSelector: @selector(setToolbarItemAction:)];
_flags._setTarget =
[_backView respondsToSelector: @selector(setTarget:)];
_flags._setImage = [_backView respondsToSelector: @selector(setImage:)];
}
else
{
// gets
_flags._isEnabled = [_view respondsToSelector: @selector(isEnabled)];
_flags._action = [_view respondsToSelector: @selector(action)];
_flags._target = [_view respondsToSelector: @selector(target)];
_flags._image = [_backView respondsToSelector: @selector(image)];
// sets
_flags._setEnabled = [_view respondsToSelector: @selector(setEnabled:)];
_flags._setAction = [_view respondsToSelector: @selector(setAction:)];
_flags._setTarget = [_view respondsToSelector: @selector(setTarget:)];
_flags._setImage = [_backView respondsToSelector: @selector(setImage:)];
[_view setToolTip: _toolTip];
}
[_backView release];
_backView = [[GSToolbarBackView alloc] initWithToolbarItem: self];
}
- (int) tag
{
if (_flags._tag)
return _tag;
return 0;
}
- (NSString *) toolTip
{
return _toolTip;
}
- (GSToolbar *) toolbar
{
return _toolbar;
}
- (void) validate
{
/* Validate by default, we know that all of the
"standard" items are correct. */
NSMenuItem *menuItem = [self menuFormRepresentation];
id target = [self target];
if ([[self toolbar] displayMode] == NSToolbarDisplayModeLabelOnly
&& menuItem != nil)
{
if ([target respondsToSelector: @selector(validateMenuItem:)])
[self setEnabled: [target validateMenuItem: menuItem]];
}
else
{
if ([target respondsToSelector: @selector(validateToolbarItem:)])
[self setEnabled: [target validateToolbarItem: self]];
}
// We can get a crash here when the target is pointing garbage memory...
}
- (NSView *) view
{
return _view;
}
// Private or package like visibility methods
- (NSView *) _backView
{
return _backView;
}
- (NSMenuItem *) _defaultMenuFormRepresentation
{
NSMenuItem *menuItem;
menuItem = [[NSMenuItem alloc] initWithTitle: [self label]
action: [self action]
keyEquivalent: @""];
[menuItem setTarget: [self target]];
AUTORELEASE(menuItem);
return menuItem;
}
- (void) _layout
{
[(id)_backView layout];
}
- (BOOL) _isModified
{
return _modified;
}
- (BOOL) _isFlexibleSpace
{
return [self isKindOfClass: [GSToolbarFlexibleSpaceItem class]];
}
- (BOOL) _selectable
{
return _selectable;
}
- (BOOL) _selected
{
return [(GSToolbarButton *)_backView state];
}
- (GSToolbar *) _toolbar
{
return _toolbar;
}
- (void) _setSelected: (BOOL)selected
{
if (_selectable && [self _selected] == NO && selected)
{
[(GSToolbarButton *)_backView performClick:self];
}
else if (selected == NO)
{
[(GSToolbarButton *)_backView setState: NO];
}
else if (_selectable == NO)
{
NSLog(@"The toolbar item %@ is not selectable", self);
}
}
- (void) _setSelectable: (BOOL)selectable
{
if ([_backView isKindOfClass: [GSToolbarButton class]])
{
_selectable = selectable;
[(GSToolbarButton *)_backView setButtonType: NSOnOffButton];
}
else
{
NSLog(@"The toolbar item %@ is not selectable", self);
}
}
- (void) _setToolbar: (GSToolbar *)toolbar
{
// Don't do an ASSIGN here, the toolbar itself retains us.
_toolbar = toolbar;
}
// NSValidatedUserInterfaceItem protocol
- (SEL) action
{
if (_flags._action)
{
if ([_backView isKindOfClass: [GSToolbarButton class]])
return [(GSToolbarButton *)_backView toolbarItemAction];
}
return 0;
}
- (id) target
{
if (_flags._target)
{
if ([_backView isKindOfClass: [NSButton class]])
return [(NSButton *)_backView target];
}
return nil;
}
// NSCopying protocol
- (id) copyWithZone: (NSZone *)zone
{
NSToolbarItem *new = [[NSToolbarItem allocWithZone: zone]
initWithItemIdentifier: _itemIdentifier];
// Copy all items individually...
[new setTarget: [self target]];
[new setAction: [self action]];
[new setView: [self view]];
[new setToolTip: [[self toolTip] copyWithZone: zone]];
[new setTag: [self tag]];
[new setImage: [[self image] copyWithZone: zone]];
[new setEnabled: [self isEnabled]];
[new setPaletteLabel: [[self paletteLabel] copyWithZone: zone]];
[new setMinSize: NSMakeSize(_minSize.width, _minSize.height)];
[new setMaxSize: NSMakeSize(_maxSize.width, _maxSize.height)];
return new;
}
@end