2006-09-22 11:53:40 +00:00
|
|
|
/** <title>GSTheme</title>
|
2004-01-19 04:22:47 +00:00
|
|
|
|
|
|
|
<abstract>Useful/configurable drawing functions</abstract>
|
|
|
|
|
|
|
|
Copyright (C) 2004 Free Software Foundation, Inc.
|
|
|
|
|
|
|
|
Author: Adam Fedor <fedor@gnu.org>
|
|
|
|
Date: Jan 2004
|
|
|
|
|
|
|
|
This file is part of the GNU Objective C User interface library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-10-29 21:16:17 +00:00
|
|
|
modify it under the terms of the GNU Lesser General Public
|
2004-01-19 04:22:47 +00:00
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-10 04:01:49 +00:00
|
|
|
version 2 of the License, or (at your option) any later version.
|
2007-10-29 21:16:17 +00:00
|
|
|
|
2004-01-19 04:22:47 +00:00
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2007-10-29 21:16:17 +00:00
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, see <http://www.gnu.org/licenses/> or write to the
|
|
|
|
Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
2004-01-19 04:22:47 +00:00
|
|
|
|
2009-02-10 14:32:08 +00:00
|
|
|
#import <Foundation/NSBundle.h>
|
2010-03-24 09:18:14 +00:00
|
|
|
#import <Foundation/NSDebug.h>
|
2009-02-10 14:32:08 +00:00
|
|
|
#import <Foundation/NSDictionary.h>
|
2010-03-24 09:18:14 +00:00
|
|
|
#import <Foundation/NSException.h>
|
2009-02-10 14:32:08 +00:00
|
|
|
#import <Foundation/NSFileManager.h>
|
2009-02-11 08:32:50 +00:00
|
|
|
#import <Foundation/NSInvocation.h>
|
2009-02-10 14:32:08 +00:00
|
|
|
#import <Foundation/NSMapTable.h>
|
|
|
|
#import <Foundation/NSMethodSignature.h>
|
|
|
|
#import <Foundation/NSNotification.h>
|
|
|
|
#import <Foundation/NSNull.h>
|
|
|
|
#import <Foundation/NSPathUtilities.h>
|
|
|
|
#import <Foundation/NSSet.h>
|
|
|
|
#import <Foundation/NSUserDefaults.h>
|
2008-12-29 10:28:59 +00:00
|
|
|
#import "GNUstepGUI/GSTheme.h"
|
|
|
|
#import "AppKit/NSApplication.h"
|
2010-01-29 08:08:10 +00:00
|
|
|
#import "AppKit/NSButtonCell.h"
|
2008-12-29 10:28:59 +00:00
|
|
|
#import "AppKit/NSButton.h"
|
|
|
|
#import "AppKit/NSColor.h"
|
|
|
|
#import "AppKit/NSColorList.h"
|
|
|
|
#import "AppKit/NSGraphics.h"
|
|
|
|
#import "AppKit/NSImage.h"
|
|
|
|
#import "AppKit/NSImageView.h"
|
|
|
|
#import "AppKit/NSMatrix.h"
|
|
|
|
#import "AppKit/NSMenu.h"
|
|
|
|
#import "AppKit/NSPanel.h"
|
|
|
|
#import "AppKit/NSScrollView.h"
|
2010-01-29 08:08:10 +00:00
|
|
|
#import "AppKit/NSSegmentedControl.h"
|
2008-12-29 10:28:59 +00:00
|
|
|
#import "AppKit/NSTextContainer.h"
|
|
|
|
#import "AppKit/NSTextField.h"
|
|
|
|
#import "AppKit/NSTextView.h"
|
|
|
|
#import "AppKit/NSScrollView.h"
|
|
|
|
#import "AppKit/NSView.h"
|
|
|
|
#import "AppKit/NSWindow.h"
|
|
|
|
#import "AppKit/NSBezierPath.h"
|
|
|
|
#import "AppKit/PSOperators.h"
|
|
|
|
#import "GSThemePrivate.h"
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2013-07-04 15:46:11 +00:00
|
|
|
NSString *GSSwitch = @"GSSwitch";
|
|
|
|
NSString *GSRadio = @"GSRadio";
|
|
|
|
|
2009-01-05 09:43:25 +00:00
|
|
|
// Scroller part names
|
|
|
|
NSString *GSScrollerDownArrow = @"GSScrollerDownArrow";
|
|
|
|
NSString *GSScrollerHorizontalKnob = @"GSScrollerHorizontalKnob";
|
|
|
|
NSString *GSScrollerHorizontalSlot = @"GSScrollerHorizontalSlot";
|
|
|
|
NSString *GSScrollerLeftArrow = @"GSScrollerLeftArrow";
|
|
|
|
NSString *GSScrollerRightArrow = @"GSScrollerRightArrow";
|
|
|
|
NSString *GSScrollerUpArrow = @"GSScrollerUpArrow";
|
|
|
|
NSString *GSScrollerVerticalKnob = @"GSScrollerVerticalKnob";
|
|
|
|
NSString *GSScrollerVerticalSlot = @"GSScrollerVerticalSlot";
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2010-01-29 22:21:34 +00:00
|
|
|
// Table view part names
|
|
|
|
NSString *GSTableHeader = @"GSTableHeader";
|
|
|
|
NSString *GSTableCorner = @"GSTableCorner";
|
|
|
|
|
2010-04-19 03:14:36 +00:00
|
|
|
// Browser part names
|
|
|
|
NSString *GSBrowserHeader = @"GSBrowserHeader";
|
|
|
|
|
2010-01-30 05:00:29 +00:00
|
|
|
// Menu part names
|
|
|
|
NSString *GSMenuHorizontalBackground = @"GSMenuHorizontalBackground";
|
|
|
|
NSString *GSMenuVerticalBackground = @"GSMenuVerticalBackground";
|
2013-09-29 00:30:59 +00:00
|
|
|
NSString *GSMenuTitleBackground = @"GSMenuTitleBackground";
|
2010-01-30 05:00:29 +00:00
|
|
|
NSString *GSMenuHorizontalItem = @"GSMenuHorizontalItem";
|
|
|
|
NSString *GSMenuVerticalItem = @"GSMenuVerticalItem";
|
2011-10-28 09:40:41 +00:00
|
|
|
NSString *GSMenuSeparatorItem = @"GSMenuSeparatorItem";
|
2010-01-29 22:21:34 +00:00
|
|
|
|
2013-10-02 23:56:16 +00:00
|
|
|
// NSPopUpButton part names
|
|
|
|
NSString *GSPopUpButton = @"GSPopUpButton";
|
|
|
|
|
2010-02-01 06:20:11 +00:00
|
|
|
// Progress indicator part names
|
2013-10-14 03:31:54 +00:00
|
|
|
NSString *GSProgressIndicatorBezel = @"GSProgressIndicatorBezel";
|
2010-02-01 06:20:11 +00:00
|
|
|
NSString *GSProgressIndicatorBarDeterminate
|
|
|
|
= @"GSProgressIndicatorBarDeterminate";
|
|
|
|
|
2010-02-12 23:09:35 +00:00
|
|
|
// Color well part names
|
|
|
|
NSString *GSColorWell = @"GSColorWell";
|
2013-10-16 04:11:41 +00:00
|
|
|
NSString *GSColorWellInnerBorder = @"GSColorWellInnerBorder";
|
2010-02-12 23:09:35 +00:00
|
|
|
|
2013-10-03 04:51:10 +00:00
|
|
|
// Slider part names
|
|
|
|
NSString *GSSliderHorizontalTrack = @"GSSliderHorizontalTrack";
|
|
|
|
NSString *GSSliderVerticalTrack = @"GSSliderVerticalTrack";
|
|
|
|
|
2013-10-03 19:52:05 +00:00
|
|
|
// NSBox parts
|
|
|
|
NSString *GSBoxBorder = @"GSBoxBorder";
|
|
|
|
|
2013-10-08 08:01:23 +00:00
|
|
|
/* NSTabView parts */
|
2015-11-01 15:38:47 +00:00
|
|
|
NSString *GSTabViewSelectedTabFill
|
|
|
|
= @"GSTabViewSelectedTabFill";
|
|
|
|
NSString *GSTabViewUnSelectedTabFill
|
|
|
|
= @"GSTabViewUnSelectedTabFill";
|
|
|
|
NSString *GSTabViewBackgroundTabFill
|
|
|
|
= @"GSTabViewBackgroundTabFill";
|
|
|
|
NSString *GSTabViewBottomSelectedTabFill
|
|
|
|
= @"GSTabViewBottomSelectedTabFill";
|
|
|
|
NSString *GSTabViewBottomUnSelectedTabFill
|
|
|
|
= @"GSTabViewBottomUnSelectedTabFill";
|
|
|
|
NSString *GSTabViewBottomBackgroundTabFill
|
|
|
|
= @"GSTabViewBottomBackgroundTabFill";
|
|
|
|
NSString *GSTabViewLeftSelectedTabFill
|
|
|
|
= @"GSTabViewLeftSelectedTabFill";
|
|
|
|
NSString *GSTabViewLeftUnSelectedTabFill
|
|
|
|
= @"GSTabViewLeftUnSelectedTabFill";
|
|
|
|
NSString *GSTabViewLeftBackgroundTabFill
|
|
|
|
= @"GSTabViewLeftBackgroundTabFill";
|
|
|
|
NSString *GSTabViewRightSelectedTabFill
|
|
|
|
= @"GSTabViewRightSelectedTabFill";
|
|
|
|
NSString *GSTabViewRightUnSelectedTabFill
|
|
|
|
= @"GSTabViewRightUnSelectedTabFill";
|
|
|
|
NSString *GSTabViewRightBackgroundTabFill
|
|
|
|
= @"GSTabViewRightBackgroundTabFill";
|
2013-10-09 01:48:50 +00:00
|
|
|
|
2013-10-08 08:01:23 +00:00
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
NSString *GSThemeDidActivateNotification
|
|
|
|
= @"GSThemeDidActivateNotification";
|
|
|
|
NSString *GSThemeDidDeactivateNotification
|
|
|
|
= @"GSThemeDidDeactivateNotification";
|
2008-12-29 11:49:42 +00:00
|
|
|
NSString *GSThemeWillActivateNotification
|
|
|
|
= @"GSThemeWillActivateNotification";
|
|
|
|
NSString *GSThemeWillDeactivateNotification
|
|
|
|
= @"GSThemeWillDeactivateNotification";
|
2006-09-22 11:23:03 +00:00
|
|
|
|
2009-10-19 10:49:10 +00:00
|
|
|
NSString *
|
2009-10-19 10:34:55 +00:00
|
|
|
GSThemeStringFromFillStyle(GSThemeFillStyle s)
|
|
|
|
{
|
|
|
|
switch (s)
|
|
|
|
{
|
|
|
|
case GSThemeFillStyleNone: return @"None";
|
|
|
|
case GSThemeFillStyleScale: return @"Scale";
|
|
|
|
case GSThemeFillStyleRepeat: return @"Repeat";
|
|
|
|
case GSThemeFillStyleCenter: return @"Center";
|
|
|
|
case GSThemeFillStyleMatrix: return @"Matrix";
|
|
|
|
case GSThemeFillStyleScaleAll: return @"ScaleAll";
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2009-10-19 10:49:10 +00:00
|
|
|
GSThemeFillStyle
|
2009-10-19 10:34:55 +00:00
|
|
|
GSThemeFillStyleFromString(NSString *s)
|
|
|
|
{
|
2009-10-19 14:09:05 +00:00
|
|
|
if (s == nil || [s isEqualToString: @"None"])
|
2009-10-19 10:34:55 +00:00
|
|
|
{
|
|
|
|
return GSThemeFillStyleNone;
|
|
|
|
}
|
|
|
|
if ([s isEqualToString: @"Scale"])
|
|
|
|
{
|
|
|
|
return GSThemeFillStyleScale;
|
|
|
|
}
|
|
|
|
if ([s isEqualToString: @"Repeat"])
|
|
|
|
{
|
|
|
|
return GSThemeFillStyleRepeat;
|
|
|
|
}
|
|
|
|
if ([s isEqualToString: @"Center"])
|
|
|
|
{
|
|
|
|
return GSThemeFillStyleCenter;
|
|
|
|
}
|
|
|
|
if ([s isEqualToString: @"Matrix"])
|
|
|
|
{
|
|
|
|
return GSThemeFillStyleMatrix;
|
|
|
|
}
|
|
|
|
if ([s isEqualToString: @"ScaleAll"])
|
|
|
|
{
|
|
|
|
return GSThemeFillStyleScaleAll;
|
|
|
|
}
|
2009-10-19 14:09:05 +00:00
|
|
|
return GSThemeFillStyleNone;
|
2009-10-19 10:34:55 +00:00
|
|
|
}
|
|
|
|
|
2010-01-29 08:08:10 +00:00
|
|
|
NSString *
|
|
|
|
GSStringFromSegmentStyle(NSSegmentStyle segmentStyle)
|
|
|
|
{
|
|
|
|
switch (segmentStyle)
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
case NSSegmentStyleAutomatic:
|
|
|
|
return @"NSSegmentStyleAutomatic";
|
|
|
|
case NSSegmentStyleRounded:
|
|
|
|
return @"NSSegmentStyleRounded";
|
|
|
|
case NSSegmentStyleTexturedRounded:
|
|
|
|
return @"NSSegmentStyleTexturedRounded";
|
|
|
|
case NSSegmentStyleRoundRect:
|
|
|
|
return @"NSSegmentStyleRoundRect";
|
|
|
|
case NSSegmentStyleTexturedSquare:
|
|
|
|
return @"NSSegmentStyleTexturedSquare";
|
|
|
|
case NSSegmentStyleCapsule:
|
|
|
|
return @"NSSegmentStyleCapsule";
|
|
|
|
case NSSegmentStyleSmallSquare:
|
|
|
|
return @"NSSegmentStyleSmallSquare";
|
|
|
|
default:
|
|
|
|
return nil;
|
2010-01-29 08:08:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NSString *
|
|
|
|
GSStringFromBezelStyle(NSBezelStyle bezelStyle)
|
|
|
|
{
|
|
|
|
switch (bezelStyle)
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
case NSRoundedBezelStyle:
|
|
|
|
return @"NSRoundedBezelStyle";
|
|
|
|
case NSRegularSquareBezelStyle:
|
|
|
|
return @"NSRegularSquareBezelStyle";
|
|
|
|
case NSThickSquareBezelStyle:
|
|
|
|
return @"NSThickSquareBezelStyle";
|
|
|
|
case NSThickerSquareBezelStyle:
|
|
|
|
return @"NSThickerSquareBezelStyle";
|
|
|
|
case NSDisclosureBezelStyle:
|
|
|
|
return @"NSDisclosureBezelStyle";
|
|
|
|
case NSShadowlessSquareBezelStyle:
|
|
|
|
return @"NSShadowlessSquareBezelStyle";
|
|
|
|
case NSCircularBezelStyle:
|
|
|
|
return @"NSCircularBezelStyle";
|
|
|
|
case NSTexturedSquareBezelStyle:
|
|
|
|
return @"NSTexturedSquareBezelStyle";
|
|
|
|
case NSHelpButtonBezelStyle:
|
|
|
|
return @"NSHelpButtonBezelStyle";
|
|
|
|
case NSSmallSquareBezelStyle:
|
|
|
|
return @"NSSmallSquareBezelStyle";
|
|
|
|
case NSTexturedRoundedBezelStyle:
|
|
|
|
return @"NSTexturedRoundedBezelStyle";
|
|
|
|
case NSRoundRectBezelStyle:
|
|
|
|
return @"NSRoundRectBezelStyle";
|
|
|
|
case NSRecessedBezelStyle:
|
|
|
|
return @"NSRecessedBezelStyle";
|
|
|
|
case NSRoundedDisclosureBezelStyle:
|
|
|
|
return @"NSRoundedDisclosureBezelStyle";
|
|
|
|
case NSNeXTBezelStyle:
|
|
|
|
return @"NSNeXTBezelStyle";
|
|
|
|
case NSPushButtonBezelStyle:
|
|
|
|
return @"NSPushButtonBezelStyle";
|
|
|
|
case NSSmallIconButtonBezelStyle:
|
|
|
|
return @"NSSmallIconButtonBezelStyle";
|
|
|
|
case NSMediumIconButtonBezelStyle:
|
|
|
|
return @"NSMediumIconButtonBezelStyle";
|
|
|
|
case NSLargeIconButtonBezelStyle:
|
|
|
|
return @"NSLargeIconButtonBezelStyle";
|
|
|
|
default:
|
|
|
|
return nil;
|
2010-01-29 08:08:10 +00:00
|
|
|
}
|
|
|
|
}
|
2009-10-19 10:34:55 +00:00
|
|
|
|
2010-02-07 21:42:50 +00:00
|
|
|
NSString *
|
|
|
|
GSStringFromBorderType(NSBorderType borderType)
|
|
|
|
{
|
|
|
|
switch (borderType)
|
|
|
|
{
|
|
|
|
case NSNoBorder: return @"NSNoBorder";
|
|
|
|
case NSLineBorder: return @"NSLineBorder";
|
|
|
|
case NSBezelBorder: return @"NSBezelBorder";
|
|
|
|
case NSGrooveBorder: return @"NSGrooveBorder";
|
|
|
|
default: return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-08 08:01:23 +00:00
|
|
|
NSString *
|
|
|
|
GSStringFromTabViewType(NSTabViewType type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
case NSTopTabsBezelBorder: return @"NSTopTabsBezelBorder";
|
|
|
|
case NSBottomTabsBezelBorder: return @"NSBottomTabsBezelBorder";
|
|
|
|
case NSLeftTabsBezelBorder: return @"NSLeftTabsBezelBorder";
|
|
|
|
case NSRightTabsBezelBorder: return @"NSRightTabsBezelBorder";
|
|
|
|
case NSNoTabsBezelBorder: return @"NSNoTabsBezelBorder";
|
|
|
|
case NSNoTabsLineBorder: return @"NSNoTabsLineBorder";
|
|
|
|
case NSNoTabsNoBorder: return @"NSNoTabsNoBorder";
|
|
|
|
default: return nil;
|
2013-10-08 08:01:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-16 05:14:32 +00:00
|
|
|
NSString *
|
|
|
|
GSStringFromImageFrameStyle(NSImageFrameStyle type)
|
|
|
|
{
|
|
|
|
switch (type)
|
|
|
|
{
|
2015-11-01 15:38:47 +00:00
|
|
|
case NSImageFrameNone: return @"NSImageFrameNone";
|
|
|
|
case NSImageFramePhoto: return @"NSImageFramePhoto";
|
|
|
|
case NSImageFrameGrayBezel: return @"NSImageFrameGrayBezel";
|
|
|
|
case NSImageFrameGroove: return @"NSImageFrameGroove";
|
|
|
|
case NSImageFrameButton: return @"NSImageFrameButton";
|
|
|
|
default: return nil;
|
2013-10-16 05:14:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-14 17:55:43 +00:00
|
|
|
@interface NSImage (Private)
|
|
|
|
+ (void) _setImagePath: (NSString*)path name: (NSString*)name;
|
2013-04-06 19:30:48 +00:00
|
|
|
+ (void) _reloadCachedImages;
|
2012-01-14 17:55:43 +00:00
|
|
|
@end
|
|
|
|
|
2009-01-06 05:08:58 +00:00
|
|
|
@interface GSTheme (Private)
|
|
|
|
- (void) _revokeOwnerships;
|
|
|
|
@end
|
|
|
|
|
2009-11-20 12:55:57 +00:00
|
|
|
/* This private internal class is used to store information about a method
|
|
|
|
* in some other class which is overridden while the current theme is
|
|
|
|
* active.
|
|
|
|
*/
|
2009-11-20 12:13:10 +00:00
|
|
|
@interface GSThemeMethod : NSObject
|
|
|
|
{
|
|
|
|
@public
|
2010-03-05 05:18:39 +00:00
|
|
|
Class cls;
|
|
|
|
SEL sel;
|
2009-11-20 12:55:57 +00:00
|
|
|
IMP imp; // The new method implementation
|
|
|
|
IMP old; // The original method implementation
|
2010-03-05 05:18:39 +00:00
|
|
|
Method mth; // The method information
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation GSThemeMethod
|
|
|
|
@end
|
|
|
|
|
2006-09-22 11:53:40 +00:00
|
|
|
@implementation GSTheme
|
2004-01-19 04:22:47 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
static GSTheme *defaultTheme = nil;
|
|
|
|
static GSTheme *theTheme = nil;
|
2006-09-22 11:23:03 +00:00
|
|
|
static NSMutableDictionary *themes = nil;
|
|
|
|
static NSNull *null = nil;
|
2009-01-05 06:51:59 +00:00
|
|
|
static NSMapTable *names = 0;
|
2005-11-23 05:43:21 +00:00
|
|
|
|
2009-01-02 10:12:25 +00:00
|
|
|
typedef struct {
|
|
|
|
NSBundle *bundle;
|
|
|
|
NSColorList *colors;
|
2009-01-31 09:59:32 +00:00
|
|
|
NSColorList *extraColors[GSThemeSelectedState+1];
|
2012-01-14 17:55:43 +00:00
|
|
|
NSMutableSet *imageNames;
|
2009-01-31 09:59:32 +00:00
|
|
|
NSMutableDictionary *tiles[GSThemeSelectedState+1];
|
2009-01-06 05:08:58 +00:00
|
|
|
NSMutableSet *owned;
|
2009-01-02 10:12:25 +00:00
|
|
|
NSImage *icon;
|
|
|
|
NSString *name;
|
2009-08-25 07:46:37 +00:00
|
|
|
Class colorClass;
|
|
|
|
Class imageClass;
|
2010-03-05 05:18:39 +00:00
|
|
|
NSMutableArray *overrides;
|
2009-01-02 10:12:25 +00:00
|
|
|
} internal;
|
|
|
|
|
2009-01-05 09:43:25 +00:00
|
|
|
#define _internal ((internal*)_reserved)
|
|
|
|
#define _bundle _internal->bundle
|
|
|
|
#define _colors _internal->colors
|
2009-01-07 06:50:14 +00:00
|
|
|
#define _extraColors _internal->extraColors
|
2012-01-14 17:55:43 +00:00
|
|
|
#define _imageNames _internal->imageNames
|
2009-01-31 09:59:32 +00:00
|
|
|
#define _tiles _internal->tiles
|
2009-01-06 05:08:58 +00:00
|
|
|
#define _owned _internal->owned
|
2009-01-05 09:43:25 +00:00
|
|
|
#define _icon _internal->icon
|
|
|
|
#define _name _internal->name
|
2009-08-25 07:46:37 +00:00
|
|
|
#define _colorClass _internal->colorClass
|
|
|
|
#define _imageClass _internal->imageClass
|
2009-11-20 12:13:10 +00:00
|
|
|
#define _overrides _internal->overrides
|
2009-01-02 10:12:25 +00:00
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
+ (void) defaultsDidChange: (NSNotification*)n
|
|
|
|
{
|
|
|
|
NSUserDefaults *defs;
|
|
|
|
NSString *name;
|
2005-11-02 13:55:27 +00:00
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
name = [defs stringForKey: @"GSTheme"];
|
2012-01-14 16:10:48 +00:00
|
|
|
if (0 == [name length])
|
|
|
|
{
|
|
|
|
name = @"GNUstep";
|
|
|
|
}
|
|
|
|
else if ([[name pathExtension] isEqual: @"theme"])
|
|
|
|
{
|
|
|
|
name = [name stringByDeletingPathExtension];
|
|
|
|
}
|
|
|
|
if (NO == [[name lastPathComponent] isEqual: [theTheme name]])
|
2006-09-22 11:23:03 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
[self setTheme: [self loadThemeNamed: name]];
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) initialize
|
2005-11-02 13:55:27 +00:00
|
|
|
{
|
2006-09-22 11:23:03 +00:00
|
|
|
if (themes == nil)
|
2005-11-02 13:55:27 +00:00
|
|
|
{
|
2006-09-22 11:23:03 +00:00
|
|
|
themes = [NSMutableDictionary new];
|
|
|
|
null = RETAIN([NSNull null]);
|
2009-01-02 10:12:25 +00:00
|
|
|
defaultTheme = [[self alloc] initWithBundle: nil];
|
2006-09-22 11:23:03 +00:00
|
|
|
ASSIGN(theTheme, defaultTheme);
|
2009-01-05 06:51:59 +00:00
|
|
|
names = NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
|
|
|
NSIntMapValueCallBacks, 0);
|
2012-01-14 16:10:48 +00:00
|
|
|
/* Establish the theme specified by the user defaults (if any);
|
|
|
|
*/
|
|
|
|
[self defaultsDidChange: nil];
|
2005-11-02 13:55:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
+ (GSTheme*) loadThemeNamed: (NSString*)aName
|
2005-11-02 13:55:27 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
NSBundle *bundle;
|
|
|
|
Class cls;
|
2006-09-22 11:53:40 +00:00
|
|
|
GSTheme *instance;
|
2006-10-02 05:09:48 +00:00
|
|
|
NSString *theme;
|
2006-09-22 11:23:03 +00:00
|
|
|
|
2012-01-14 16:10:48 +00:00
|
|
|
if ([[aName pathExtension] isEqual: @"theme"])
|
|
|
|
{
|
|
|
|
aName = [aName stringByDeletingPathExtension];
|
|
|
|
}
|
|
|
|
if ([aName length] == 0 || [[aName lastPathComponent] isEqual: @"GNUstep"])
|
2006-09-22 11:23:03 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
return defaultTheme;
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
if ([aName isAbsolutePath] == YES)
|
2006-09-22 11:23:03 +00:00
|
|
|
{
|
|
|
|
theme = aName;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
aName = [aName lastPathComponent];
|
2012-01-14 16:10:48 +00:00
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2012-01-14 16:10:48 +00:00
|
|
|
/* Ensure that the theme name has the 'theme' extension.
|
|
|
|
*/
|
|
|
|
if ([[aName pathExtension] isEqualToString: @"theme"] == YES)
|
|
|
|
{
|
|
|
|
theme = aName;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
theme = [aName stringByAppendingPathExtension: @"theme"];
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bundle = [themes objectForKey: theme];
|
|
|
|
if (bundle == nil)
|
|
|
|
{
|
2009-11-02 11:48:22 +00:00
|
|
|
NSString *path = nil;
|
2006-09-22 11:23:03 +00:00
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
2006-10-02 05:09:48 +00:00
|
|
|
BOOL isDir;
|
2006-09-22 11:23:03 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
/* A theme may be either an absolute path or a filename to be located
|
|
|
|
* in the Themes subdirectory of one of the standard Library directories.
|
|
|
|
*/
|
|
|
|
if ([theme isAbsolutePath] == YES)
|
|
|
|
{
|
|
|
|
if ([mgr fileExistsAtPath: theme isDirectory: &isDir] == YES
|
|
|
|
&& isDir == YES)
|
|
|
|
{
|
|
|
|
path = theme;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSEnumerator *enumerator;
|
|
|
|
|
|
|
|
enumerator = [NSSearchPathForDirectoriesInDomains
|
|
|
|
(NSAllLibrariesDirectory, NSAllDomainsMask, YES) objectEnumerator];
|
|
|
|
while ((path = [enumerator nextObject]) != nil)
|
2006-09-22 11:23:03 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
path = [path stringByAppendingPathComponent: @"Themes"];
|
|
|
|
path = [path stringByAppendingPathComponent: theme];
|
|
|
|
if ([mgr fileExistsAtPath: path isDirectory: &isDir])
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (path == nil)
|
|
|
|
{
|
|
|
|
NSLog (@"No theme named '%@' found", aName);
|
2006-10-02 05:09:48 +00:00
|
|
|
return nil;
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bundle = [NSBundle bundleWithPath: path];
|
|
|
|
[themes setObject: bundle forKey: theme];
|
|
|
|
[bundle load]; // Ensure code is loaded.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cls = [bundle principalClass];
|
|
|
|
if (cls == 0)
|
|
|
|
{
|
|
|
|
cls = self;
|
|
|
|
}
|
|
|
|
instance = [[cls alloc] initWithBundle: bundle];
|
2006-10-02 05:09:48 +00:00
|
|
|
return AUTORELEASE(instance);
|
|
|
|
}
|
|
|
|
|
|
|
|
+ (void) orderFrontSharedThemePanel: (id)sender
|
|
|
|
{
|
|
|
|
GSThemePanel *panel;
|
|
|
|
|
|
|
|
panel = [GSThemePanel sharedThemePanel];
|
|
|
|
[panel update: self];
|
|
|
|
[panel center];
|
|
|
|
[panel orderFront: self];
|
2005-11-02 13:55:27 +00:00
|
|
|
}
|
|
|
|
|
2006-09-22 11:53:40 +00:00
|
|
|
+ (void) setTheme: (GSTheme*)theme
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2006-09-22 11:23:03 +00:00
|
|
|
if (theme == nil)
|
|
|
|
{
|
|
|
|
theme = defaultTheme;
|
|
|
|
}
|
|
|
|
if (theme != theTheme)
|
|
|
|
{
|
2011-06-09 17:51:39 +00:00
|
|
|
/*
|
|
|
|
* Remove any previous observers...
|
|
|
|
*/
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
removeObserver: self];
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
[theTheme deactivate];
|
|
|
|
ASSIGN (theTheme, theme);
|
|
|
|
[theTheme activate];
|
2011-06-09 17:51:39 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Listen to notifications...
|
|
|
|
*/
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserver: self
|
|
|
|
selector: @selector(defaultsDidChange:)
|
|
|
|
name: NSUserDefaultsDidChangeNotification
|
|
|
|
object: nil];
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2006-09-22 11:53:40 +00:00
|
|
|
+ (GSTheme*) theme
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2006-09-22 11:23:03 +00:00
|
|
|
return theTheme;
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
- (void) activate
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
NSUserDefaults *defs;
|
|
|
|
NSMutableArray *searchList;
|
2006-09-22 11:23:03 +00:00
|
|
|
NSEnumerator *enumerator;
|
2006-10-02 05:09:48 +00:00
|
|
|
NSDictionary *infoDict;
|
|
|
|
NSWindow *window;
|
2009-01-31 09:59:32 +00:00
|
|
|
GSThemeControlState state;
|
2013-04-06 19:30:30 +00:00
|
|
|
|
2009-08-27 17:13:31 +00:00
|
|
|
NSDebugMLLog(@"GSTheme", @"%@ %p", [self name], self);
|
2008-12-29 12:05:35 +00:00
|
|
|
/* Get rid of any cached colors list so that we regenerate it when needed
|
|
|
|
*/
|
|
|
|
[_colors release];
|
|
|
|
_colors = nil;
|
2009-01-31 09:59:32 +00:00
|
|
|
for (state = 0; state <= GSThemeSelectedState; state++)
|
|
|
|
{
|
|
|
|
[_extraColors[state] release];
|
|
|
|
_extraColors[state] = nil;
|
|
|
|
}
|
2008-12-29 12:05:35 +00:00
|
|
|
|
2012-01-14 17:55:43 +00:00
|
|
|
/*
|
2013-04-06 19:30:48 +00:00
|
|
|
* Reload NSImage's cache of image by name
|
2012-01-14 17:55:43 +00:00
|
|
|
*/
|
2013-04-06 19:30:48 +00:00
|
|
|
[NSImage _reloadCachedImages];
|
2012-01-14 17:55:43 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
/*
|
|
|
|
* Use the GSThemeDomain key in the info dictionary of the theme to
|
|
|
|
* set a defaults domain which will establish user defaults values
|
|
|
|
* but will not override any defaults set explicitly by the user.
|
|
|
|
* NB. For subclasses, the theme info dictionary may not be the same
|
|
|
|
* as that of the bundle, so we don't use the bundle method directly.
|
|
|
|
*/
|
|
|
|
infoDict = [self infoDictionary];
|
|
|
|
defs = [NSUserDefaults standardUserDefaults];
|
|
|
|
searchList = [[defs searchList] mutableCopy];
|
|
|
|
if ([[infoDict objectForKey: @"GSThemeDomain"] isKindOfClass:
|
|
|
|
[NSDictionary class]] == YES)
|
|
|
|
{
|
|
|
|
[defs removeVolatileDomainForName: @"GSThemeDomain"];
|
|
|
|
[defs setVolatileDomain: [infoDict objectForKey: @"GSThemeDomain"]
|
|
|
|
forName: @"GSThemeDomain"];
|
|
|
|
if ([searchList containsObject: @"GSThemeDomain"] == NO)
|
|
|
|
{
|
2011-12-17 17:16:09 +00:00
|
|
|
NSUInteger index;
|
2006-10-02 05:09:48 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Higher priority than GSConfigDomain and NSRegistrationDomain,
|
|
|
|
* but lower than NSGlobalDomain, NSArgumentDomain, and others
|
|
|
|
* set by the user to be application specific.
|
|
|
|
*/
|
|
|
|
index = [searchList indexOfObject: GSConfigDomain];
|
|
|
|
if (index == NSNotFound)
|
|
|
|
{
|
|
|
|
index = [searchList indexOfObject: NSRegistrationDomain];
|
|
|
|
if (index == NSNotFound)
|
|
|
|
{
|
|
|
|
index = [searchList count];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
[searchList insertObject: @"GSThemeDomain" atIndex: index];
|
|
|
|
[defs setSearchList: searchList];
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
[searchList removeObject: @"GSThemeDomain"];
|
|
|
|
[defs removeVolatileDomainForName: @"GSThemeDomain"];
|
|
|
|
}
|
|
|
|
RELEASE(searchList);
|
2006-09-22 11:23:03 +00:00
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
/* Install any overridden methods.
|
|
|
|
*/
|
|
|
|
if (_overrides != nil)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
NSEnumerator *e = [_overrides objectEnumerator];
|
|
|
|
GSThemeMethod *m;
|
2009-11-20 12:13:10 +00:00
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
while ((m = [e nextObject]) != nil)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
method_setImplementation(m->mth, m->imp);
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-29 11:49:42 +00:00
|
|
|
/*
|
2009-11-20 12:13:10 +00:00
|
|
|
* Tell subclass that basic activation is done and it can do its own.
|
2008-12-29 11:49:42 +00:00
|
|
|
*/
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
postNotificationName: GSThemeWillActivateNotification
|
|
|
|
object: self
|
|
|
|
userInfo: nil];
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
/*
|
|
|
|
* Tell all other classes that new theme information is present.
|
|
|
|
*/
|
2006-09-22 11:23:03 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
2008-12-29 11:49:42 +00:00
|
|
|
postNotificationName: GSThemeDidActivateNotification
|
|
|
|
object: self
|
|
|
|
userInfo: nil];
|
2006-10-02 05:09:48 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset main menu to change between styles if necessary
|
|
|
|
*/
|
|
|
|
[[NSApp mainMenu] setMain: YES];
|
|
|
|
|
|
|
|
/*
|
2009-01-25 13:47:30 +00:00
|
|
|
* Mark all windows as needing redisplaying to show the new theme.
|
2006-10-02 05:09:48 +00:00
|
|
|
*/
|
|
|
|
enumerator = [[NSApp windows] objectEnumerator];
|
|
|
|
while ((window = [enumerator nextObject]) != nil)
|
|
|
|
{
|
|
|
|
[[[window contentView] superview] setNeedsDisplay: YES];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSArray*) authors
|
|
|
|
{
|
|
|
|
return [[self infoDictionary] objectForKey: @"GSThemeAuthors"];
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
- (NSBundle*) bundle
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2006-09-22 11:23:03 +00:00
|
|
|
return _bundle;
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2009-08-25 07:46:37 +00:00
|
|
|
- (Class) colorClass
|
|
|
|
{
|
|
|
|
return [NSColorList class];
|
|
|
|
}
|
|
|
|
|
2009-11-19 20:37:43 +00:00
|
|
|
- (void) colorFlush: (NSString*)aName
|
|
|
|
state: (GSThemeControlState)elementState
|
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
int end;
|
|
|
|
|
2011-02-24 13:28:20 +00:00
|
|
|
if (elementState > GSThemeSelectedState)
|
2009-11-19 20:37:43 +00:00
|
|
|
{
|
|
|
|
pos = 0;
|
|
|
|
end = GSThemeSelectedState;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos = elementState;
|
|
|
|
end = elementState;
|
|
|
|
}
|
|
|
|
while (pos <= end)
|
|
|
|
{
|
|
|
|
if (_extraColors[pos] != nil)
|
|
|
|
{
|
|
|
|
[_extraColors[pos] release];
|
|
|
|
_extraColors[pos] = nil;
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-31 09:59:32 +00:00
|
|
|
- (NSColor*) colorNamed: (NSString*)aName
|
|
|
|
state: (GSThemeControlState)elementState
|
|
|
|
{
|
|
|
|
NSColor *c = nil;
|
|
|
|
|
|
|
|
NSAssert(elementState <= GSThemeSelectedState, NSInvalidArgumentException);
|
2009-11-19 20:37:43 +00:00
|
|
|
NSAssert(elementState >= 0, NSInvalidArgumentException);
|
2009-01-31 09:59:32 +00:00
|
|
|
|
|
|
|
if (aName != nil)
|
|
|
|
{
|
|
|
|
if (_extraColors[elementState] == nil)
|
|
|
|
{
|
|
|
|
NSString *colorsPath;
|
|
|
|
NSString *listName;
|
|
|
|
NSString *resourceName;
|
|
|
|
|
|
|
|
/* Attempt to load color list ... if the list is not found
|
|
|
|
* or the load fails, set a null marker.
|
|
|
|
*/
|
|
|
|
switch (elementState)
|
|
|
|
{
|
2009-11-02 11:48:22 +00:00
|
|
|
default:
|
2009-01-31 09:59:32 +00:00
|
|
|
case GSThemeNormalState:
|
|
|
|
listName = @"ThemeExtra";
|
|
|
|
break;
|
|
|
|
case GSThemeHighlightedState:
|
|
|
|
listName = @"ThemeExtraHighlighted";
|
|
|
|
break;
|
|
|
|
case GSThemeSelectedState:
|
|
|
|
listName = @"ThemeExtraSelected";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
resourceName = [listName stringByAppendingString: @"Colors"];
|
|
|
|
colorsPath = [_bundle pathForResource: resourceName
|
|
|
|
ofType: @"clr"];
|
|
|
|
if (colorsPath != nil)
|
|
|
|
{
|
|
|
|
_extraColors[elementState]
|
2009-08-25 07:46:37 +00:00
|
|
|
= [[_colorClass alloc] initWithName: listName
|
2009-01-31 09:59:32 +00:00
|
|
|
fromFile: colorsPath];
|
|
|
|
/* If the list is actually empty, we get rid of it to avoid
|
|
|
|
* unnecessary lookups.
|
|
|
|
*/
|
|
|
|
if ([[_extraColors[elementState] allKeys] count] == 0)
|
|
|
|
{
|
|
|
|
[_extraColors[elementState] release];
|
|
|
|
_extraColors[elementState] = nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_extraColors[elementState] == nil)
|
|
|
|
{
|
2012-01-23 14:27:58 +00:00
|
|
|
_extraColors[elementState] = (id)[null retain];
|
2009-01-31 09:59:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_extraColors[elementState] != (id)null)
|
|
|
|
{
|
|
|
|
c = [_extraColors[elementState] colorWithKey: aName];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
|
2008-12-29 11:52:36 +00:00
|
|
|
- (NSColorList*) colors
|
|
|
|
{
|
2008-12-29 12:05:35 +00:00
|
|
|
if (_colors == nil)
|
|
|
|
{
|
|
|
|
NSString *colorsPath;
|
|
|
|
|
|
|
|
colorsPath = [_bundle pathForResource: @"ThemeColors" ofType: @"clr"];
|
|
|
|
if (colorsPath == nil)
|
|
|
|
{
|
2013-01-30 09:48:54 +00:00
|
|
|
_colors = (id)[null retain];
|
2008-12-29 12:05:35 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-08-25 07:46:37 +00:00
|
|
|
_colors = [[_colorClass alloc] initWithName: @"System"
|
2008-12-29 12:05:35 +00:00
|
|
|
fromFile: colorsPath];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ((id)_colors == (id)null)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2008-12-29 11:52:36 +00:00
|
|
|
return _colors;
|
|
|
|
}
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
- (void) deactivate
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2009-08-27 17:13:31 +00:00
|
|
|
NSDebugMLLog(@"GSTheme", @"%@ %p", [self name], self);
|
|
|
|
|
2008-12-29 11:49:42 +00:00
|
|
|
/* Tell everything that we will become inactive.
|
|
|
|
*/
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
postNotificationName: GSThemeWillDeactivateNotification
|
|
|
|
object: self
|
|
|
|
userInfo: nil];
|
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
/* Remove any overridden methods.
|
|
|
|
*/
|
|
|
|
if (_overrides != nil)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
NSEnumerator *e = [_overrides objectEnumerator];
|
|
|
|
GSThemeMethod *m;
|
2009-11-20 12:13:10 +00:00
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
while ((m = [e nextObject]) != nil)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
method_setImplementation(m->mth, m->old);
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-06 05:08:58 +00:00
|
|
|
[self _revokeOwnerships];
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
/* Tell everything that we have become inactive.
|
|
|
|
*/
|
2006-09-22 11:23:03 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
2008-12-29 11:49:42 +00:00
|
|
|
postNotificationName: GSThemeDidDeactivateNotification
|
|
|
|
object: self
|
|
|
|
userInfo: nil];
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
- (void) dealloc
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2009-01-02 10:12:25 +00:00
|
|
|
if (_reserved != 0)
|
|
|
|
{
|
2009-01-31 09:59:32 +00:00
|
|
|
GSThemeControlState state;
|
|
|
|
|
|
|
|
for (state = 0; state <= GSThemeSelectedState; state++)
|
|
|
|
{
|
|
|
|
RELEASE(_extraColors[state]);
|
|
|
|
RELEASE(_tiles[state]);
|
|
|
|
}
|
2009-01-02 10:12:25 +00:00
|
|
|
RELEASE(_bundle);
|
|
|
|
RELEASE(_colors);
|
2012-01-14 17:55:43 +00:00
|
|
|
RELEASE(_imageNames);
|
2009-01-02 10:12:25 +00:00
|
|
|
RELEASE(_icon);
|
2009-01-06 05:08:58 +00:00
|
|
|
[self _revokeOwnerships];
|
2009-11-20 12:13:10 +00:00
|
|
|
RELEASE(_overrides);
|
2009-01-06 05:08:58 +00:00
|
|
|
RELEASE(_owned);
|
2009-01-02 10:12:25 +00:00
|
|
|
NSZoneFree ([self zone], _reserved);
|
|
|
|
}
|
2006-09-22 11:23:03 +00:00
|
|
|
[super dealloc];
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
- (NSImage*) icon
|
|
|
|
{
|
|
|
|
if (_icon == nil)
|
|
|
|
{
|
|
|
|
NSString *path;
|
|
|
|
|
|
|
|
path = [[self infoDictionary] objectForKey: @"GSThemeIcon"];
|
|
|
|
if (path != nil)
|
|
|
|
{
|
|
|
|
NSString *ext = [path pathExtension];
|
|
|
|
|
|
|
|
path = [path stringByDeletingPathExtension];
|
|
|
|
path = [_bundle pathForResource: path ofType: ext];
|
|
|
|
if (path != nil)
|
|
|
|
{
|
2009-08-25 07:46:37 +00:00
|
|
|
_icon = [[_imageClass alloc] initWithContentsOfFile: path];
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (_icon == nil)
|
|
|
|
{
|
2009-08-25 07:46:37 +00:00
|
|
|
_icon = RETAIN([_imageClass imageNamed: @"GNUstep"]);
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
2009-02-07 09:28:55 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
NSSize s = [_icon size];
|
|
|
|
float scale = 1.0;
|
|
|
|
|
|
|
|
if (s.height > 48.0)
|
|
|
|
scale = 48.0 / s.height;
|
|
|
|
if (48.0 / s.width < scale)
|
|
|
|
scale = 48.0 / s.width;
|
|
|
|
if (scale != 1.0)
|
|
|
|
{
|
|
|
|
[_icon setScalesWhenResized: YES];
|
|
|
|
s.height *= scale;
|
|
|
|
s.width *= scale;
|
|
|
|
[_icon setSize: s];
|
|
|
|
}
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
|
|
|
return _icon;
|
|
|
|
}
|
|
|
|
|
2009-08-25 07:46:37 +00:00
|
|
|
- (Class) imageClass
|
|
|
|
{
|
|
|
|
return [NSImage class];
|
|
|
|
}
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
- (id) initWithBundle: (NSBundle*)bundle
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2009-11-20 12:13:10 +00:00
|
|
|
Class c = [self class];
|
2010-03-05 05:18:39 +00:00
|
|
|
unsigned int count;
|
|
|
|
Method *methods;
|
2009-11-20 12:13:10 +00:00
|
|
|
GSThemeMethod *mth;
|
|
|
|
GSThemeControlState state;
|
2009-01-31 09:59:32 +00:00
|
|
|
|
2009-01-02 10:12:25 +00:00
|
|
|
_reserved = NSZoneCalloc ([self zone], 1, sizeof(internal));
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
ASSIGN(_bundle, bundle);
|
2012-01-14 17:55:43 +00:00
|
|
|
_imageNames = [NSMutableSet new];
|
2009-01-31 09:59:32 +00:00
|
|
|
for (state = 0; state <= GSThemeSelectedState; state++)
|
|
|
|
{
|
|
|
|
_tiles[state] = [NSMutableDictionary new];
|
|
|
|
}
|
2009-01-06 05:08:58 +00:00
|
|
|
_owned = [NSMutableSet new];
|
|
|
|
|
2009-01-02 10:12:25 +00:00
|
|
|
ASSIGN(_name,
|
|
|
|
[[[_bundle bundlePath] lastPathComponent] stringByDeletingPathExtension]);
|
|
|
|
|
2009-08-25 07:46:37 +00:00
|
|
|
_colorClass = [self colorClass];
|
|
|
|
_imageClass = [self imageClass];
|
2005-11-23 05:43:21 +00:00
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
/* Now we look through our methods to find those which are actually
|
|
|
|
* replacements to override methods in other classes.
|
2009-11-20 12:55:57 +00:00
|
|
|
* That's determined by method name ... any method of the form
|
|
|
|
* '_override' <classname> 'Method_' <originalmethodname>
|
|
|
|
* is used to replace the original method in the class.
|
|
|
|
* We maintain dictionaries (keyed by class) for instance and class
|
|
|
|
* methods, so we can look up the original methods at runtime if the
|
|
|
|
* replacement methods want to call them.
|
2009-11-20 12:13:10 +00:00
|
|
|
*/
|
2010-03-05 05:18:39 +00:00
|
|
|
methods = class_copyMethodList(c, &count);
|
|
|
|
if (methods != NULL)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
int counter = 0;
|
2009-11-20 12:13:10 +00:00
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
while (methods[counter] != 0)
|
|
|
|
{
|
|
|
|
Method method = methods[counter++];
|
|
|
|
const char *name = sel_getName(method_getName(method));
|
|
|
|
const char *ptr;
|
2009-11-19 20:37:43 +00:00
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
if (strncmp(name, "_override", 9) == 0
|
|
|
|
&& (ptr = strstr(name, "Method_")) > 0)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
char buf[strlen(name)];
|
|
|
|
const char *types;
|
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
mth = [[GSThemeMethod new] autorelease];
|
2010-03-05 05:18:39 +00:00
|
|
|
types = method_getTypeEncoding(method);
|
|
|
|
mth->imp = method_getImplementation(method);
|
|
|
|
memcpy(buf, name + 9, (ptr - name) + 9);
|
|
|
|
buf[(ptr - name) + 9] = '\0';
|
|
|
|
mth->cls = objc_lookUpClass(buf);
|
2009-11-20 12:13:10 +00:00
|
|
|
if (mth->cls == 0)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
NSLog(@"Unable to find class '%s' for '%s'", buf, name);
|
2009-11-20 12:13:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
memcpy(buf, ptr + 7, strlen(ptr + 7));
|
|
|
|
buf[strlen(ptr + 7)] = '\0';
|
|
|
|
mth->sel = sel_getUid(buf);
|
2009-11-20 12:13:10 +00:00
|
|
|
if (mth->sel == 0)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
NSLog(@"Unable to find selector '-%s' for '%s'", buf, name);
|
2009-11-20 12:13:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (NO == [mth->cls instancesRespondToSelector: mth->sel])
|
|
|
|
{
|
|
|
|
NSLog(@"Instances do not respond for '%s'", name);
|
|
|
|
continue;
|
|
|
|
}
|
2009-11-20 12:55:57 +00:00
|
|
|
mth->old = [mth->cls instanceMethodForSelector: mth->sel];
|
2010-03-05 05:18:39 +00:00
|
|
|
class_addMethod(mth->cls, mth->sel, mth->imp, types);
|
|
|
|
mth->mth = class_getInstanceMethod(mth->cls, mth->sel);
|
|
|
|
|
|
|
|
if (_overrides == nil)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
_overrides = [NSMutableArray new];
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
[_overrides addObject: mth];
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
free(methods);
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
methods = class_copyMethodList(object_getClass(c), &count);
|
|
|
|
if (methods != NULL)
|
|
|
|
{
|
|
|
|
int counter = 0;
|
2009-11-20 12:13:10 +00:00
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
while (methods[counter] != 0)
|
|
|
|
{
|
|
|
|
Method method = methods[counter++];
|
|
|
|
const char *name = sel_getName(method_getName(method));
|
|
|
|
const char *ptr;
|
2009-11-20 12:13:10 +00:00
|
|
|
|
|
|
|
if (strncmp(name, "_override", 9) == 0
|
|
|
|
&& (ptr = strstr(name, "Method_")) > 0)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
char buf[strlen(name)];
|
|
|
|
const char *types;
|
|
|
|
Class cls;
|
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
mth = [[GSThemeMethod new] autorelease];
|
2010-03-05 05:18:39 +00:00
|
|
|
types = method_getTypeEncoding(method);
|
|
|
|
mth->imp = method_getImplementation(method);
|
|
|
|
memcpy(buf, name + 9, (ptr - name) + 9);
|
|
|
|
buf[(ptr - name) + 9] = '\0';
|
|
|
|
cls = objc_lookUpClass(buf);
|
|
|
|
if (cls == 0)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
NSLog(@"Unable to find class '%s' for '%s'", buf, name);
|
2009-11-20 12:13:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
mth->cls = object_getClass(cls);
|
|
|
|
memcpy(buf, ptr + 7, strlen(ptr + 7));
|
|
|
|
buf[strlen(ptr + 7)] = '\0';
|
|
|
|
mth->sel = sel_getUid(buf);
|
2009-11-20 12:13:10 +00:00
|
|
|
if (mth->sel == 0)
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
NSLog(@"Unable to find selector '-%s' for '%s'", buf, name);
|
2009-11-20 12:13:10 +00:00
|
|
|
continue;
|
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
if (NO == [cls respondsToSelector: mth->sel])
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
|
|
|
NSLog(@"Class does not respond for '%s'", name);
|
|
|
|
continue;
|
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
mth->old = [cls methodForSelector: mth->sel];
|
|
|
|
class_addMethod(mth->cls, mth->sel, mth->imp, types);
|
|
|
|
mth->mth = class_getClassMethod(cls, mth->sel);
|
2009-11-20 12:13:10 +00:00
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
if (_overrides == nil)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
_overrides = [NSMutableArray new];
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
[_overrides addObject: mth];
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
free(methods);
|
2009-11-19 20:37:43 +00:00
|
|
|
}
|
2009-11-20 12:13:10 +00:00
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (NSDictionary*) infoDictionary
|
|
|
|
{
|
|
|
|
return [_bundle infoDictionary];
|
2009-11-19 20:37:43 +00:00
|
|
|
}
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
- (NSString*) name
|
|
|
|
{
|
|
|
|
if (self == defaultTheme)
|
|
|
|
{
|
2009-01-02 10:12:25 +00:00
|
|
|
_name = @"GNUstep";
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
2009-01-01 08:30:19 +00:00
|
|
|
return _name;
|
|
|
|
}
|
|
|
|
|
2009-01-05 06:51:59 +00:00
|
|
|
- (NSString*) nameForElement: (id)anObject
|
|
|
|
{
|
|
|
|
NSString *name = (NSString*)NSMapGet(names, (void*)anObject);
|
|
|
|
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
2009-11-20 12:13:10 +00:00
|
|
|
- (IMP) overriddenMethod: (SEL)selector for: (id)receiver
|
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
Class cls = object_getClass(receiver);
|
|
|
|
NSEnumerator *e = [_overrides objectEnumerator];
|
2009-11-20 12:13:10 +00:00
|
|
|
GSThemeMethod *m;
|
|
|
|
|
2010-03-05 05:18:39 +00:00
|
|
|
while ((m = [e nextObject]) != nil)
|
2009-11-20 12:13:10 +00:00
|
|
|
{
|
2010-03-05 05:18:39 +00:00
|
|
|
if (m->cls == cls && sel_isEqual(selector, m->sel))
|
|
|
|
{
|
|
|
|
return m->old;
|
|
|
|
}
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
2010-03-05 05:18:39 +00:00
|
|
|
return (IMP)0;
|
2009-11-20 12:13:10 +00:00
|
|
|
}
|
|
|
|
|
2009-01-01 08:30:19 +00:00
|
|
|
- (void) setName: (NSString*)aString
|
|
|
|
{
|
|
|
|
if (self != defaultTheme)
|
|
|
|
{
|
|
|
|
ASSIGNCOPY(_name, aString);
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
}
|
|
|
|
|
2009-01-06 05:08:58 +00:00
|
|
|
- (void) setName: (NSString*)aString
|
|
|
|
forElement: (id)anObject
|
|
|
|
temporary: (BOOL)takeOwnership
|
2009-01-05 06:51:59 +00:00
|
|
|
{
|
|
|
|
if (aString == nil)
|
|
|
|
{
|
2009-01-05 09:43:25 +00:00
|
|
|
if (anObject == nil)
|
|
|
|
{
|
|
|
|
/* Ignore this ... it's most likely a partially initialised
|
|
|
|
* control being deallocated and removing the name for a
|
|
|
|
* subsidiary item which was never allocated in the first place.
|
|
|
|
*/
|
|
|
|
return;
|
|
|
|
}
|
2009-01-05 06:51:59 +00:00
|
|
|
NSMapRemove(names, (void*)anObject);
|
2009-01-06 05:08:58 +00:00
|
|
|
[_owned removeObject: anObject];
|
2009-01-05 06:51:59 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-05 09:43:25 +00:00
|
|
|
if (anObject == nil)
|
|
|
|
{
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
format: @"[%@-%@] nil object supplied",
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
}
|
2009-01-05 06:51:59 +00:00
|
|
|
NSMapInsert(names, (void*)anObject, (void*)aString);
|
2009-01-06 05:08:58 +00:00
|
|
|
if (takeOwnership == YES)
|
|
|
|
{
|
|
|
|
[_owned addObject: anObject];
|
|
|
|
}
|
2009-02-06 15:08:14 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
[_owned removeObject: anObject];
|
|
|
|
}
|
2009-01-05 06:51:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
- (NSWindow*) themeInspector
|
|
|
|
{
|
|
|
|
return [GSThemeInspector sharedThemeInspector];
|
|
|
|
}
|
|
|
|
|
2009-11-19 20:37:43 +00:00
|
|
|
- (void) tilesFlush: (NSString*)aName
|
|
|
|
state: (GSThemeControlState)elementState
|
|
|
|
{
|
|
|
|
int pos;
|
|
|
|
int end;
|
|
|
|
|
2011-02-24 13:28:20 +00:00
|
|
|
if (elementState > GSThemeSelectedState)
|
2009-11-19 20:37:43 +00:00
|
|
|
{
|
|
|
|
pos = 0;
|
|
|
|
end = GSThemeSelectedState;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pos = elementState;
|
|
|
|
end = elementState;
|
|
|
|
}
|
|
|
|
while (pos <= end)
|
|
|
|
{
|
|
|
|
NSMutableDictionary *cache;
|
|
|
|
|
|
|
|
cache = _tiles[pos++];
|
|
|
|
if (aName == nil)
|
|
|
|
{
|
|
|
|
return [cache removeAllObjects];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[cache removeObjectForKey: aName];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-01-05 09:43:25 +00:00
|
|
|
- (GSDrawTiles*) tilesNamed: (NSString*)aName
|
|
|
|
state: (GSThemeControlState)elementState
|
2005-11-23 05:43:21 +00:00
|
|
|
{
|
2009-01-05 09:43:25 +00:00
|
|
|
GSDrawTiles *tiles;
|
|
|
|
NSMutableDictionary *cache;
|
|
|
|
|
2009-01-31 09:59:32 +00:00
|
|
|
NSAssert(elementState <= GSThemeSelectedState, NSInvalidArgumentException);
|
2009-11-19 20:37:43 +00:00
|
|
|
NSAssert(elementState >= 0, NSInvalidArgumentException);
|
2009-01-08 11:30:16 +00:00
|
|
|
if (aName == nil)
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
2009-01-31 09:59:32 +00:00
|
|
|
cache = _tiles[elementState];
|
2009-11-19 20:37:43 +00:00
|
|
|
tiles = [cache objectForKey: aName];
|
2006-09-22 11:23:03 +00:00
|
|
|
if (tiles == nil)
|
|
|
|
{
|
2006-10-02 05:09:48 +00:00
|
|
|
NSDictionary *info;
|
|
|
|
NSImage *image;
|
2009-01-05 09:43:25 +00:00
|
|
|
NSString *fullName;
|
|
|
|
|
|
|
|
switch (elementState)
|
|
|
|
{
|
2009-11-02 11:48:22 +00:00
|
|
|
default:
|
2009-01-05 09:43:25 +00:00
|
|
|
case GSThemeNormalState:
|
|
|
|
fullName = aName;
|
|
|
|
break;
|
2013-10-14 17:18:38 +00:00
|
|
|
case GSThemeFirstResponderState:
|
|
|
|
fullName = [aName stringByAppendingString: @"FirstResponder"];
|
|
|
|
break;
|
2010-02-01 08:26:40 +00:00
|
|
|
case GSThemeDisabledState:
|
|
|
|
fullName = [aName stringByAppendingString: @"Disabled"];
|
|
|
|
break;
|
2013-10-14 17:18:38 +00:00
|
|
|
case GSThemeHighlightedFirstResponderState:
|
2015-11-01 15:38:47 +00:00
|
|
|
fullName
|
|
|
|
= [aName stringByAppendingString: @"HighlightedFirstResponder"];
|
2013-10-14 17:18:38 +00:00
|
|
|
break;
|
2009-01-05 09:43:25 +00:00
|
|
|
case GSThemeHighlightedState:
|
|
|
|
fullName = [aName stringByAppendingString: @"Highlighted"];
|
|
|
|
break;
|
2013-10-14 17:18:38 +00:00
|
|
|
case GSThemeSelectedFirstResponderState:
|
2015-11-01 15:38:47 +00:00
|
|
|
fullName
|
|
|
|
= [aName stringByAppendingString: @"SelectedFirstResponder"];
|
2013-10-14 17:18:38 +00:00
|
|
|
break;
|
2009-01-05 09:43:25 +00:00
|
|
|
case GSThemeSelectedState:
|
|
|
|
fullName = [aName stringByAppendingString: @"Selected"];
|
|
|
|
break;
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
|
|
|
|
/* The GSThemeTiles entry in the info dictionary should be a
|
|
|
|
* dictionary containing information about each set of tiles.
|
|
|
|
* Keys are:
|
|
|
|
* FileName Name of the file in the ThemeTiles directory
|
|
|
|
* HorizontalDivision Where to divide the image into columns.
|
|
|
|
* VerticalDivision Where to divide the image into rows.
|
|
|
|
*/
|
|
|
|
info = [self infoDictionary];
|
2009-01-05 09:43:25 +00:00
|
|
|
info = [[info objectForKey: @"GSThemeTiles"] objectForKey: fullName];
|
2006-10-02 05:09:48 +00:00
|
|
|
if ([info isKindOfClass: [NSDictionary class]] == YES)
|
|
|
|
{
|
2009-10-18 16:23:34 +00:00
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
NSString *name;
|
|
|
|
NSString *path;
|
|
|
|
NSString *file;
|
|
|
|
NSString *ext;
|
2009-10-19 10:34:55 +00:00
|
|
|
GSThemeFillStyle style;
|
2009-10-18 16:23:34 +00:00
|
|
|
|
|
|
|
name = [info objectForKey: @"FillStyle"];
|
2009-10-19 10:34:55 +00:00
|
|
|
style = GSThemeFillStyleFromString(name);
|
|
|
|
if (style < GSThemeFillStyleNone) style = GSThemeFillStyleNone;
|
2006-10-02 05:09:48 +00:00
|
|
|
x = [[info objectForKey: @"HorizontalDivision"] floatValue];
|
|
|
|
y = [[info objectForKey: @"VerticalDivision"] floatValue];
|
|
|
|
file = [info objectForKey: @"FileName"];
|
|
|
|
ext = [file pathExtension];
|
|
|
|
file = [file stringByDeletingPathExtension];
|
|
|
|
path = [_bundle pathForResource: file
|
|
|
|
ofType: ext
|
|
|
|
inDirectory: @"ThemeTiles"];
|
|
|
|
if (path == nil)
|
|
|
|
{
|
|
|
|
NSLog(@"File %@.%@ not found in ThemeTiles", file, ext);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-08-25 07:46:37 +00:00
|
|
|
image = [[_imageClass alloc] initWithContentsOfFile: path];
|
2006-10-02 05:09:48 +00:00
|
|
|
if (image != nil)
|
|
|
|
{
|
2013-10-08 19:32:09 +00:00
|
|
|
if ([[info objectForKey: @"NinePatch"] boolValue]
|
|
|
|
|| [file hasSuffix: @".9"])
|
2009-10-19 03:19:01 +00:00
|
|
|
{
|
2009-10-19 07:44:22 +00:00
|
|
|
tiles = [[GSDrawTiles alloc]
|
|
|
|
initWithNinePatchImage: image];
|
2009-10-19 03:19:01 +00:00
|
|
|
[tiles setFillStyle: GSThemeFillStyleScaleAll];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tiles = [[GSDrawTiles alloc] initWithImage: image
|
|
|
|
horizontal: x
|
|
|
|
vertical: y];
|
|
|
|
[tiles setFillStyle: style];
|
|
|
|
}
|
2006-10-02 05:09:48 +00:00
|
|
|
RELEASE(image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-10-08 19:32:09 +00:00
|
|
|
|
|
|
|
if (tiles == nil)
|
|
|
|
{
|
|
|
|
NSString *imagePath;
|
|
|
|
|
|
|
|
// Try 9-patch first
|
|
|
|
imagePath = [_bundle pathForResource: fullName
|
|
|
|
ofType: @"9.png"
|
|
|
|
inDirectory: @"ThemeTiles"];
|
|
|
|
if (imagePath != nil)
|
|
|
|
{
|
|
|
|
image
|
|
|
|
= [[_imageClass alloc] initWithContentsOfFile: imagePath];
|
|
|
|
if (image != nil)
|
|
|
|
{
|
|
|
|
tiles = [[GSDrawTiles alloc]
|
|
|
|
initWithNinePatchImage: image];
|
|
|
|
[tiles setFillStyle: GSThemeFillStyleScaleAll];
|
|
|
|
RELEASE(image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tiles == nil)
|
2006-10-02 05:09:48 +00:00
|
|
|
{
|
|
|
|
NSArray *imageTypes;
|
|
|
|
NSString *imagePath;
|
|
|
|
unsigned count;
|
|
|
|
|
2009-08-25 07:46:37 +00:00
|
|
|
imageTypes = [_imageClass imageFileTypes];
|
2008-12-16 19:31:50 +00:00
|
|
|
for (count = 0; count < [imageTypes count]; count++)
|
2006-10-02 05:09:48 +00:00
|
|
|
{
|
|
|
|
NSString *ext = [imageTypes objectAtIndex: count];
|
|
|
|
|
2009-01-05 09:43:25 +00:00
|
|
|
imagePath = [_bundle pathForResource: fullName
|
2006-10-02 05:09:48 +00:00
|
|
|
ofType: ext
|
|
|
|
inDirectory: @"ThemeTiles"];
|
|
|
|
if (imagePath != nil)
|
|
|
|
{
|
2009-08-25 07:46:37 +00:00
|
|
|
image
|
|
|
|
= [[_imageClass alloc] initWithContentsOfFile: imagePath];
|
2006-10-02 05:09:48 +00:00
|
|
|
if (image != nil)
|
|
|
|
{
|
|
|
|
tiles = [[GSDrawTiles alloc] initWithImage: image];
|
|
|
|
RELEASE(image);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-09-22 11:23:03 +00:00
|
|
|
|
2006-10-02 05:09:48 +00:00
|
|
|
if (tiles == nil)
|
2006-09-22 11:23:03 +00:00
|
|
|
{
|
2009-01-05 09:43:25 +00:00
|
|
|
[cache setObject: null forKey: aName];
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-01-05 09:43:25 +00:00
|
|
|
[cache setObject: tiles forKey: aName];
|
2006-10-15 18:27:35 +00:00
|
|
|
RELEASE(tiles);
|
2006-09-22 11:23:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (tiles == (id)null)
|
|
|
|
{
|
|
|
|
tiles = nil;
|
|
|
|
}
|
|
|
|
return tiles;
|
2005-11-23 05:43:21 +00:00
|
|
|
}
|
|
|
|
|
2009-10-26 09:48:08 +00:00
|
|
|
- (NSString*) versionString
|
|
|
|
{
|
|
|
|
return [[self infoDictionary] objectForKey: @"GSThemeVersion"];
|
|
|
|
}
|
2009-11-19 20:37:43 +00:00
|
|
|
|
2013-07-15 13:20:41 +00:00
|
|
|
- (NSString *) license
|
|
|
|
{
|
|
|
|
return [[self infoDictionary] objectForKey: @"GSThemeLicense"];
|
|
|
|
}
|
|
|
|
|
2006-09-22 11:23:03 +00:00
|
|
|
@end
|
2006-10-02 05:09:48 +00:00
|
|
|
|
2009-01-06 05:08:58 +00:00
|
|
|
@implementation GSTheme (Private)
|
|
|
|
/* Remove all temporarily named objects from our registry, releasing them.
|
|
|
|
*/
|
|
|
|
- (void) _revokeOwnerships
|
|
|
|
{
|
|
|
|
id o;
|
|
|
|
|
|
|
|
while ((o = [_owned anyObject]) != nil)
|
|
|
|
{
|
|
|
|
[self setName: nil forElement: o temporary: YES];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|
2009-02-10 14:32:08 +00:00
|
|
|
@implementation GSThemeProxy
|
|
|
|
- (id) _resource
|
|
|
|
{
|
|
|
|
return _resource;
|
|
|
|
}
|
|
|
|
- (void) _setResource: (id)resource
|
|
|
|
{
|
|
|
|
ASSIGN(_resource, resource);
|
|
|
|
}
|
|
|
|
- (void) dealloc
|
|
|
|
{
|
|
|
|
DESTROY(_resource);
|
|
|
|
[super dealloc];
|
|
|
|
}
|
2009-10-12 09:09:59 +00:00
|
|
|
- (NSString*) description
|
|
|
|
{
|
|
|
|
return [_resource description];
|
|
|
|
}
|
2009-11-23 23:13:26 +00:00
|
|
|
- (id) forwardingTargetForSelector:(SEL)aSelector
|
|
|
|
{
|
|
|
|
return _resource;
|
|
|
|
}
|
2009-02-10 14:32:08 +00:00
|
|
|
- (void) forwardInvocation: (NSInvocation*)anInvocation
|
|
|
|
{
|
|
|
|
[anInvocation invokeWithTarget: _resource];
|
|
|
|
}
|
|
|
|
- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector
|
|
|
|
{
|
|
|
|
if (_resource != nil)
|
|
|
|
{
|
|
|
|
return [_resource methodSignatureForSelector: aSelector];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Evil hack to prevent recursion - if we are asking a remote
|
|
|
|
* object for a method signature, we can't ask it for the
|
|
|
|
* signature of methodSignatureForSelector:, so we hack in
|
|
|
|
* the signature required manually :-(
|
|
|
|
*/
|
2010-09-09 23:50:38 +00:00
|
|
|
if (sel_isEqual(aSelector, _cmd))
|
2009-02-10 14:32:08 +00:00
|
|
|
{
|
|
|
|
static NSMethodSignature *sig = nil;
|
|
|
|
|
|
|
|
if (sig == nil)
|
|
|
|
{
|
|
|
|
sig = RETAIN([NSMethodSignature signatureWithObjCTypes: "@@::"]);
|
|
|
|
}
|
|
|
|
return sig;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@end
|
|
|
|
|