diff --git a/Application/MiniWindow.h b/Application/MiniWindow.h new file mode 100644 index 000000000..ea26322fa --- /dev/null +++ b/Application/MiniWindow.h @@ -0,0 +1,16 @@ +// +// MiniWindow.h +// Cog +// +// Created by Vincent Spader on 2/22/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import +#import "DualWindow.h" + +@interface MiniWindow : DualWindow { + +} + +@end diff --git a/Application/MiniWindow.m b/Application/MiniWindow.m new file mode 100644 index 000000000..5f85886fa --- /dev/null +++ b/Application/MiniWindow.m @@ -0,0 +1,44 @@ +// +// MiniWindow.m +// Cog +// +// Created by Vincent Spader on 2/22/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "MiniWindow.h" + + +@implementation MiniWindow + +- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation +{ + self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; + if (self) + { + [self setShowsResizeIndicator:NO]; + [self setExcludedFromWindowsMenu:YES]; + [self setContentBorderThickness:24.0 forEdge:NSMinYEdge]; + } + + return self; +} + +- (void)awakeFromNib +{ + if ([self hiddenDefaultsKey]) { + // Hide the mini window by default. + [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:[self hiddenDefaultsKey]]]; + } + + [super awakeFromNib]; +} + +- (NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)proposedFrameSize { + // Do not allow height to change + proposedFrameSize.height = [self frame].size.height; + + return proposedFrameSize; +} + +@end diff --git a/Application/PlaybackController.h b/Application/PlaybackController.h index 08be6fc38..0c43bca48 100644 --- a/Application/PlaybackController.h +++ b/Application/PlaybackController.h @@ -19,9 +19,7 @@ IBOutlet PlaylistController *playlistController; IBOutlet PlaylistView *playlistView; - IBOutlet TrackingSlider *positionSlider; IBOutlet NSSlider *volumeSlider; - IBOutlet NSTextField *timeField; IBOutlet NSSegmentedControl *playbackButtons; @@ -32,10 +30,13 @@ AudioPlayer *audioPlayer; int playbackStatus; + double position; + BOOL seekable; BOOL showTimeRemaining; AudioScrobbler *scrobbler; + } @property int playbackStatus; @@ -69,9 +70,15 @@ - (void)audioFadeDown:(NSTimer *)audioTimer; - (void)audioFadeUp:(NSTimer *)audioTimer; -- (void)updateTimeField:(double)pos; - - (void)playEntryAtIndex:(int)i; - (void)playEntry:(PlaylistEntry *)pe; +// For bindings + +- (void)setPosition:(double)p; +- (double)position; + +- (void)setSeekable:(BOOL)s; +- (BOOL)seekable; + @end diff --git a/Application/PlaybackController.m b/Application/PlaybackController.m index 5e8bc5a9f..da5af417c 100644 --- a/Application/PlaybackController.m +++ b/Application/PlaybackController.m @@ -13,6 +13,11 @@ @synthesize playbackStatus; ++ (NSSet *)keyPathsForValuesAffectingSeekable +{ + return [NSSet setWithObjects:@"playlistController.currentEntry",@"playlistController.currentEntry.seekable",nil]; +} + - (id)init { self = [super init]; @@ -60,8 +65,8 @@ [volumeSlider setDoubleValue:logarithmicToLinear(100.0)]; [audioPlayer setVolume: 100]; - - [positionSlider setEnabled:NO]; + + [self setSeekable:NO]; } - (IBAction)playPauseResume:(id)sender @@ -158,8 +163,7 @@ NSLog(@"PLAYLIST CONTROLLER: %@", [playlistController class]); [playlistController setCurrentEntry:pe]; - [positionSlider setDoubleValue:0.0]; - [self updateTimeField:0.0f]; + [self setPosition:0.0]; if (pe == nil) return; @@ -195,15 +199,19 @@ [self playEntry:[playlistController currentEntry]]; } +- (void)updatePosition:(id)sender +{ + double pos = [audioPlayer amountPlayed]; + + [self setPosition:pos]; +} + - (IBAction)seek:(id)sender { - double time; - time = [positionSlider doubleValue]; + double time = [sender doubleValue]; - if ([sender tracking] == NO) // check if user stopped sliding before playing audio - [audioPlayer seekToTime:time]; + [audioPlayer seekToTime:time]; - [self updateTimeField:time]; } - (IBAction)eventSeekForward:(id)sender @@ -215,15 +223,14 @@ { double seekTo = [audioPlayer amountPlayed] + amount; - if (seekTo > (int)[positionSlider maxValue]) + if (seekTo > [[[playlistController currentEntry] length] doubleValue]) { [self next:self]; } else { [audioPlayer seekToTime:seekTo]; - [self updateTimeField:seekTo]; - [positionSlider setDoubleValue:seekTo]; + [self setPosition:seekTo]; } } @@ -240,8 +247,7 @@ seekTo = 0; [audioPlayer seekToTime:seekTo]; - [self updateTimeField:seekTo]; - [positionSlider setDoubleValue:seekTo]; + [self setPosition:seekTo]; } - (void)changePlayButtonImage:(NSString *)name @@ -459,7 +465,7 @@ } - +/* - (void)updateTimeField:(double)pos { NSString *text; @@ -470,19 +476,19 @@ } else { - int sec = (int)(([positionSlider maxValue] - pos)); + int sec = (int)(([[[playlistController currentEntry] length] doubleValue] - pos)); if (sec < 0) sec = 0; text = [NSString stringWithFormat:NSLocalizedString(@"TimeRemaining", @""), sec/60, sec%60]; } [timeField setStringValue:text]; } - +*/ - (IBAction)toggleShowTimeRemaining:(id)sender { showTimeRemaining = !showTimeRemaining; - [self updateTimeField:[positionSlider doubleValue]]; + // [self updateTimeField:position]; } - (void)audioPlayer:(AudioPlayer *)player requestNextStream:(id)userInfo @@ -504,10 +510,8 @@ [playlistController setCurrentEntry:pe]; - [positionSlider setDoubleValue:0.0f]; + [self setPosition:0]; - [self updateTimeField:0.0f]; - if([[NSUserDefaults standardUserDefaults] boolForKey:@"enableAudioScrobbler"]) { [scrobbler start:pe]; } @@ -521,18 +525,6 @@ clickContext:nil]; } -- (void)updatePosition:(id)sender -{ - double pos = [audioPlayer amountPlayed]; - - if ([positionSlider tracking] == NO) - { - [positionSlider setDoubleValue:pos]; - [self updateTimeField:pos]; - } - -} - - (void)audioPlayer:(AudioPlayer *)player statusChanged:(id)s { int status = [s intValue]; @@ -543,11 +535,11 @@ [positionTimer invalidate]; positionTimer = NULL; } + if (status == kCogStatusStopped) { - [positionSlider setDoubleValue:0.0f]; - [positionSlider setEnabled:NO]; // the player stopped, disable the slider - [self updateTimeField:0.0f]; + [self setPosition:0]; + [self setSeekable:NO]; // the player stopped, disable the slider } //Show play image @@ -559,7 +551,7 @@ positionTimer = [NSTimer timerWithTimeInterval:1.00 target:self selector:@selector(updatePosition:) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:positionTimer forMode:NSRunLoopCommonModes]; } - + //Show pause [self changePlayButtonImage:@"pause"]; } @@ -567,15 +559,35 @@ if (status == kCogStatusStopped) { NSLog(@"DONE!"); [playlistController setCurrentEntry:nil]; - [positionSlider setEnabled:NO]; // the player stopped, disable the slider + [self setSeekable:NO]; // the player stopped, disable the slider } else { NSLog(@"PLAYING!"); + [self setSeekable:YES]; } playbackStatus = status; } +- (void)setPosition:(double)p +{ + position = p; +} + +- (double)position +{ + return position; +} + +- (void)setSeekable:(BOOL)s +{ + seekable = s; +} + +- (BOOL)seekable +{ + return seekable && [[playlistController currentEntry] seekable]; +} @end diff --git a/Application/PositionSlider.h b/Application/PositionSlider.h new file mode 100644 index 000000000..a1c692646 --- /dev/null +++ b/Application/PositionSlider.h @@ -0,0 +1,18 @@ +// +// PositionSlider.h +// Cog +// +// Created by Vincent Spader on 2/22/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import +#import "TrackingSlider.h" + +@class TimeField; + +@interface PositionSlider : TrackingSlider { + IBOutlet TimeField *positionTextField; +} + +@end diff --git a/Application/PositionSlider.m b/Application/PositionSlider.m new file mode 100644 index 000000000..a14e9be0b --- /dev/null +++ b/Application/PositionSlider.m @@ -0,0 +1,33 @@ +// +// PositionSlider.m +// Cog +// +// Created by Vincent Spader on 2/22/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "PositionSlider.h" +#import "TimeField.h" + +@implementation PositionSlider + +- (void)setDoubleValue:(double)value +{ + [positionTextField setDoubleValue:value]; + + [super setDoubleValue:value]; +} + +- (void)setMaxValue:(double)value +{ + [positionTextField setMaxDoubleValue:value]; +} + +- (void)mouseDragged:(NSEvent *)theEvent +{ + [positionTextField setDoubleValue:[self doubleValue]]; + + [super mouseDragged:theEvent]; +} + +@end diff --git a/Application/TimeField.h b/Application/TimeField.h new file mode 100644 index 000000000..72973c8dc --- /dev/null +++ b/Application/TimeField.h @@ -0,0 +1,22 @@ +// +// TimeField.h +// Cog +// +// Created by Vincent Spader on 2/22/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import + + +@interface TimeField : NSTextField { + BOOL showTimeRemaining; + + double value; + double maxValue; +} + +- (void)setMaxDoubleValue:(double)v; +- (void)setDoubleValue:(double)v; + +@end diff --git a/Application/TimeField.m b/Application/TimeField.m new file mode 100644 index 000000000..8c5b9084d --- /dev/null +++ b/Application/TimeField.m @@ -0,0 +1,49 @@ +// +// TimeField.m +// Cog +// +// Created by Vincent Spader on 2/22/09. +// Copyright 2009 __MyCompanyName__. All rights reserved. +// + +#import "TimeField.h" + + +@implementation TimeField + +- (void)update +{ + NSString *text; + if (showTimeRemaining == NO) + { + int sec = value; + text = [NSString stringWithFormat:NSLocalizedString(@"TimeElapsed", @""), sec/60, sec%60]; + } + else + { + int sec = maxValue - value; + if (sec < 0) + sec = 0; + text = [NSString stringWithFormat:NSLocalizedString(@"TimeRemaining", @""), sec/60, sec%60]; + } + [self setStringValue:text]; +} + +- (void)mouseDown:(NSEvent *)theEvent +{ + showTimeRemaining = !showTimeRemaining; + [self update]; +} + +- (void)setMaxDoubleValue:(double)v +{ + maxValue = v; +} + +- (void)setDoubleValue:(double)v +{ + value = v; + [self update]; +} + +@end diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index 9cb22ee3d..39932c79e 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -42,7 +42,6 @@ 177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF870B8BC2A70000BC8C /* ImageTextCell.m */; }; 177EBFAB0B8BC2A70000BC8C /* NDHotKeyControl.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF8D0B8BC2A70000BC8C /* NDHotKeyControl.m */; }; 177EBFAD0B8BC2A70000BC8C /* NDHotKeyEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EBF8F0B8BC2A70000BC8C /* NDHotKeyEvent.m */; }; - 177EC01F0B8BC2CF0000BC8C /* ClickField.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0130B8BC2CF0000BC8C /* ClickField.m */; }; 177EC0210B8BC2CF0000BC8C /* DBLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0150B8BC2CF0000BC8C /* DBLog.m */; }; 177EC0230B8BC2CF0000BC8C /* DragScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC0170B8BC2CF0000BC8C /* DragScrollView.m */; }; 177EC0270B8BC2CF0000BC8C /* TrackingCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 177EC01B0B8BC2CF0000BC8C /* TrackingCell.m */; }; @@ -120,6 +119,8 @@ 17D1B2810CF8B2830028F5B5 /* song.icns in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B27A0CF8B2830028F5B5 /* song.icns */; }; 17D1B2820CF8B2830028F5B5 /* vg.icns in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B27B0CF8B2830028F5B5 /* vg.icns */; }; 17D1B2830CF8B2830028F5B5 /* xm.icns in Resources */ = {isa = PBXBuildFile; fileRef = 17D1B27C0CF8B2830028F5B5 /* xm.icns */; }; + 17E0D4CA0F51FF78005B6FED /* PositionSlider.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E0D4C90F51FF78005B6FED /* PositionSlider.m */; }; + 17E0D55B0F520636005B6FED /* TimeField.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E0D55A0F520636005B6FED /* TimeField.m */; }; 17E41E070C130DFF00AC744D /* Credits.html in Resources */ = {isa = PBXBuildFile; fileRef = 17E41E060C130DFF00AC744D /* Credits.html */; }; 17E41E230C130EE200AC744D /* Help in Resources */ = {isa = PBXBuildFile; fileRef = 17E41E220C130EE200AC744D /* Help */; }; 17E78CB10D68D46F005C5A59 /* StringToURLTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E78CB00D68D46F005C5A59 /* StringToURLTransformer.m */; }; @@ -560,8 +561,6 @@ 177EBF8D0B8BC2A70000BC8C /* NDHotKeyControl.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NDHotKeyControl.m; sourceTree = ""; }; 177EBF8E0B8BC2A70000BC8C /* NDHotKeyEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NDHotKeyEvent.h; sourceTree = ""; }; 177EBF8F0B8BC2A70000BC8C /* NDHotKeyEvent.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NDHotKeyEvent.m; sourceTree = ""; }; - 177EC0120B8BC2CF0000BC8C /* ClickField.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ClickField.h; sourceTree = ""; }; - 177EC0130B8BC2CF0000BC8C /* ClickField.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = ClickField.m; sourceTree = ""; }; 177EC0140B8BC2CF0000BC8C /* DBLog.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DBLog.h; sourceTree = ""; }; 177EC0150B8BC2CF0000BC8C /* DBLog.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DBLog.m; sourceTree = ""; }; 177EC0160B8BC2CF0000BC8C /* DragScrollView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DragScrollView.h; sourceTree = ""; }; @@ -665,6 +664,10 @@ 17D1B27A0CF8B2830028F5B5 /* song.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = song.icns; sourceTree = ""; }; 17D1B27B0CF8B2830028F5B5 /* vg.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = vg.icns; sourceTree = ""; }; 17D1B27C0CF8B2830028F5B5 /* xm.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = xm.icns; sourceTree = ""; }; + 17E0D4C80F51FF78005B6FED /* PositionSlider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PositionSlider.h; sourceTree = ""; }; + 17E0D4C90F51FF78005B6FED /* PositionSlider.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PositionSlider.m; sourceTree = ""; }; + 17E0D5590F520636005B6FED /* TimeField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TimeField.h; sourceTree = ""; }; + 17E0D55A0F520636005B6FED /* TimeField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TimeField.m; sourceTree = ""; }; 17E78CAF0D68D46F005C5A59 /* StringToURLTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringToURLTransformer.h; sourceTree = ""; }; 17E78CB00D68D46F005C5A59 /* StringToURLTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StringToURLTransformer.m; sourceTree = ""; }; 17F3BB830CBC565100864489 /* CueSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CueSheet.xcodeproj; path = Plugins/CueSheet/CueSheet.xcodeproj; sourceTree = ""; }; @@ -840,6 +843,10 @@ 179571580F51DF4100E4168D /* MiniWindow.m */, 179571710F51E21400E4168D /* MainWindow.h */, 179571720F51E21400E4168D /* MainWindow.m */, + 17E0D4C80F51FF78005B6FED /* PositionSlider.h */, + 17E0D4C90F51FF78005B6FED /* PositionSlider.m */, + 17E0D5590F520636005B6FED /* TimeField.h */, + 17E0D55A0F520636005B6FED /* TimeField.m */, ); path = Application; sourceTree = ""; @@ -889,8 +896,6 @@ 177EC0110B8BC2CF0000BC8C /* Utils */ = { isa = PBXGroup; children = ( - 177EC0120B8BC2CF0000BC8C /* ClickField.h */, - 177EC0130B8BC2CF0000BC8C /* ClickField.m */, 177EC0140B8BC2CF0000BC8C /* DBLog.h */, 177EC0150B8BC2CF0000BC8C /* DBLog.m */, 177EC0160B8BC2CF0000BC8C /* DragScrollView.h */, @@ -1775,7 +1780,6 @@ 177EBFA70B8BC2A70000BC8C /* ImageTextCell.m in Sources */, 177EBFAB0B8BC2A70000BC8C /* NDHotKeyControl.m in Sources */, 177EBFAD0B8BC2A70000BC8C /* NDHotKeyEvent.m in Sources */, - 177EC01F0B8BC2CF0000BC8C /* ClickField.m in Sources */, 177EC0210B8BC2CF0000BC8C /* DBLog.m in Sources */, 177EC0230B8BC2CF0000BC8C /* DragScrollView.m in Sources */, 177EC0270B8BC2CF0000BC8C /* TrackingCell.m in Sources */, @@ -1832,6 +1836,8 @@ 1752C6B00F3FE3CC00FC3235 /* VolumeSlider.m in Sources */, 179571590F51DF4100E4168D /* MiniWindow.m in Sources */, 179571730F51E21400E4168D /* MainWindow.m in Sources */, + 17E0D4CA0F51FF78005B6FED /* PositionSlider.m in Sources */, + 17E0D55B0F520636005B6FED /* TimeField.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/English.lproj/MainMenu.xib b/English.lproj/MainMenu.xib index 2b28d8f7e..0b8e550cd 100644 --- a/English.lproj/MainMenu.xib +++ b/English.lproj/MainMenu.xib @@ -8,9 +8,9 @@ 353.00 YES - - + + YES @@ -186,7 +186,7 @@ {{0, 14}, {96, 15}} YES - 604372736 + 604110336 131072 @@ -5046,22 +5046,6 @@ OQA 1597 - - - timeField - - - - 1598 - - - - toggleShowTimeRemaining: - - - - 1599 - playbackButtons @@ -5683,42 +5667,6 @@ OQA 1903 - - - maxValue: content.length - - - - - - maxValue: content.length - maxValue - content.length - - NSRaisesForNotApplicableKeys - - - 2 - - - 1905 - - - - enabled: content.seekable - - - - - - enabled: content.seekable - enabled - content.seekable - 2 - - - 1908 - fontSize: values.fontSize @@ -6710,6 +6658,124 @@ OQA 2374 + + + enabled: seekable + + + + + + enabled: seekable + enabled + seekable + 2 + + + 2376 + + + + maxValue: content.length + + + + + + maxValue: content.length + maxValue + content.length + + NSRaisesForNotApplicableKeys + + + 2 + + + 2377 + + + + value: position + + + + + + value: position + value + position + + 2 + + + 2378 + + + + maxValue: content.length + + + + + + maxValue: content.length + maxValue + content.length + 2 + + + 2381 + + + + value: position + + + + + + value: position + value + position + + 2 + + + 2382 + + + + enabled: seekable + + + + + + enabled: seekable + enabled + seekable + 2 + + + 2384 + + + + positionTextField + + + + 2385 + + + + positionTextField + + + + 2386 + @@ -9834,7 +9900,7 @@ OQA com.apple.InterfaceBuilder.CocoaPlugin - TrackingSlider + PositionSlider com.apple.InterfaceBuilder.CocoaPlugin TrackingCell @@ -9845,7 +9911,7 @@ OQA com.apple.InterfaceBuilder.CocoaPlugin - ClickField + TimeField com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -9997,7 +10063,7 @@ OQA {{334, 92}, {691, 397}} {{334, 92}, {691, 397}} - + {{25, 14}, {683, 396}} {3.40282e+38, 3.40282e+38} @@ -10079,12 +10145,12 @@ OQA com.apple.InterfaceBuilder.CocoaPlugin - ClickField + TimeField com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - TrackingSlider + PositionSlider com.apple.InterfaceBuilder.CocoaPlugin TrackingCell @@ -10285,7 +10351,7 @@ OQA - 2374 + 2386 @@ -10397,22 +10463,6 @@ OQA - - ClickField - NSTextField - - IBProjectSource - Utils/ClickField.h - - - - ClickField - NSTextField - - IBUserSource - - - DNDArrayController NSArrayController @@ -10655,8 +10705,6 @@ OQA playbackButtons playlistController playlistView - positionSlider - timeField volumeSlider @@ -10665,8 +10713,6 @@ OQA NSSegmentedControl PlaylistController PlaylistView - TrackingSlider - NSTextField NSSlider @@ -10846,6 +10892,18 @@ OQA ThirdParty/GCWindowMenu/PopupButton.h + + PositionSlider + TrackingSlider + + positionTextField + TimeField + + + IBProjectSource + Application/PositionSlider.h + + PreferencesController NSObject @@ -10995,6 +11053,14 @@ OQA TagEditor/TagEditorController.h + + TimeField + NSTextField + + IBProjectSource + Application/TimeField.h + + TrackingCell NSSliderCell diff --git a/Utils/ClickField.h b/Utils/ClickField.h deleted file mode 100644 index b9c36227c..000000000 --- a/Utils/ClickField.h +++ /dev/null @@ -1,9 +0,0 @@ -/* ClickField */ - -#import - -@interface ClickField : NSTextField -{ - -} -@end diff --git a/Utils/ClickField.m b/Utils/ClickField.m deleted file mode 100644 index 19005df37..000000000 --- a/Utils/ClickField.m +++ /dev/null @@ -1,17 +0,0 @@ -#import "ClickField.h" - -@implementation ClickField - -- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent { - return YES; -} - -- (void)mouseDown:(NSEvent *)theEvent -{ - if([theEvent type] == NSLeftMouseDown) - { - [self sendAction:[self action] to:[self target]]; - } -} - -@end diff --git a/Utils/TrackingCell.h b/Utils/TrackingCell.h index d385c21c0..67b86b167 100644 --- a/Utils/TrackingCell.h +++ b/Utils/TrackingCell.h @@ -9,6 +9,7 @@ - (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView; - (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flags; -- (BOOL)tracking; + +- (BOOL)isTracking; @end diff --git a/Utils/TrackingCell.m b/Utils/TrackingCell.m index 40de67375..7fc51b74b 100644 --- a/Utils/TrackingCell.m +++ b/Utils/TrackingCell.m @@ -9,6 +9,16 @@ } + +- (BOOL)continueTracking:(NSPoint)lastPoint at:(NSPoint)currentPoint inView:(NSView *)controlView +{ + NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDragged location:currentPoint modifierFlags:NSLeftMouseDown timestamp:0 windowNumber:[[controlView window] windowNumber] context:nil eventNumber:0 clickCount:0 pressure:0]; + + [controlView mouseDragged:event]; + + return [super continueTracking:lastPoint at:currentPoint inView:controlView]; +} + - (void)stopTracking:(NSPoint)lastPoint at:(NSPoint)stopPoint inView:(NSView *)controlView mouseIsUp:(BOOL)flag { tracking = NO; @@ -16,10 +26,9 @@ [super stopTracking:lastPoint at:stopPoint inView:controlView mouseIsUp:flag]; } -- (BOOL)tracking +- (BOOL)isTracking { return tracking; } - @end diff --git a/Utils/TrackingSlider.h b/Utils/TrackingSlider.h index 6fe0e2cd7..8515c256a 100644 --- a/Utils/TrackingSlider.h +++ b/Utils/TrackingSlider.h @@ -13,7 +13,9 @@ @interface TrackingSlider : NSSlider { + NSMutableDictionary *bindingInfo; } --(BOOL)tracking; + +- (BOOL)isTracking; @end diff --git a/Utils/TrackingSlider.m b/Utils/TrackingSlider.m index b6d2a63fc..27dd6edac 100644 --- a/Utils/TrackingSlider.m +++ b/Utils/TrackingSlider.m @@ -3,9 +3,88 @@ @implementation TrackingSlider --(BOOL)tracking + +static NSString *TrackingSliderValueObservationContext = @"TrackingSliderValueObservationContext"; + +- (id)initWithFrame:(NSRect)frameRect { - return [[self cell] tracking]; + self = [super initWithFrame:frameRect]; + if (self) + { + bindingInfo = [[NSMutableDictionary alloc] init]; + } + + return self; } +- (id)initWithCoder:(NSCoder *)decoder +{ + self = [super initWithCoder:decoder]; + if (self) + { + bindingInfo = [[NSMutableDictionary alloc] init]; + } + + return self; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context +{ + if ([TrackingSliderValueObservationContext isEqual:context]) + { + if (![self isTracking]) + { + id value = [change objectForKey:NSKeyValueChangeNewKey]; + [self setDoubleValue:[value doubleValue]]; + } + } + else + { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +- (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options +{ + if ([binding isEqualToString:@"value"]) + { + [observableController addObserver:self forKeyPath:keyPath options:(NSKeyValueObservingOptionNew) context:TrackingSliderValueObservationContext]; + + NSDictionary *bindingsData = [NSDictionary dictionaryWithObjectsAndKeys: + observableController, NSObservedObjectKey, + [keyPath copy], NSObservedKeyPathKey, + [options copy], NSOptionsKey, nil]; + + [bindingInfo setObject:bindingsData forKey:binding]; + } + else + { + [super bind:binding toObject:observableController withKeyPath:keyPath options:options]; + } +} + +- (void)unbind:(NSString *)binding +{ + if ([binding isEqualToString:@"value"]) + { + NSDictionary *info = [bindingInfo objectForKey:binding]; + + NSString *keyPath = [info objectForKey:NSObservedKeyPathKey]; + id observedObject = [info objectForKey:NSObservedObjectKey]; + + [observedObject removeObserver:self forKeyPath:keyPath]; + } + else + { + [super unbind:binding]; + } +} + +- (BOOL)isTracking +{ + return [[self cell] isTracking]; +} + + + @end