libs-gui/Source/NSToolbarItem.m

1510 lines
38 KiB
Mathematica
Raw Normal View History

/*
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/NSAttributedString.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