From 223286529bb015c350f9839b4fcdb03ea59b2c7a Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20Paul=20K=C3=BChne?= Date: Thu, 21 May 2009 22:25:37 +0200 Subject: [PATCH] macosx: merge Eric Dudiak's code from GSoC 2008 Nibs will be added later on. No user-visible change as of yet. --- NEWS | 3 + THANKS | 1 + modules/gui/macosx/controls.h | 26 ++ modules/gui/macosx/controls.m | 51 +-- modules/gui/macosx/embeddedwindow.h | 80 ++++- modules/gui/macosx/embeddedwindow.m | 468 ++++++++++++++++++++++++---- modules/gui/macosx/equalizer.h | 1 + modules/gui/macosx/equalizer.m | 3 + modules/gui/macosx/intf.h | 1 + modules/gui/macosx/intf.m | 7 + modules/gui/macosx/playlist.h | 13 +- modules/gui/macosx/playlist.m | 112 +++++++ modules/gui/macosx/sidebarview.h | 45 +++ modules/gui/macosx/sidebarview.m | 201 ++++++++++++ modules/gui/macosx/sidestatusview.h | 33 ++ modules/gui/macosx/sidestatusview.m | 107 +++++++ 16 files changed, 1061 insertions(+), 91 deletions(-) create mode 100644 modules/gui/macosx/sidebarview.h create mode 100644 modules/gui/macosx/sidebarview.m create mode 100644 modules/gui/macosx/sidestatusview.h create mode 100644 modules/gui/macosx/sidestatusview.m diff --git a/NEWS b/NEWS index 4ec556f0d3..433a682930 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,9 @@ Changes between 1.0.0-rc1 and 1.1.0-git: ---------------------------------------- +Mac OS X Interface: + * Completely reworked user interface (based upon works from GSoC 2008) + Changes between 0.9.9a and 1.0.0-rc1: ------------------------------------ diff --git a/THANKS b/THANKS index fedc8859a4..1a36daf488 100644 --- a/THANKS +++ b/THANKS @@ -93,6 +93,7 @@ Dugal Harris - DirectShow fixes and MJPEG patches Dylan Aïssi - French translation Dylan Yudaken - hotkeys patch Emmanuel Blindauer - aRts audio output +Eric Dudiak - Mac OS X Interface rework (GSoC 2008) Enrico Gueli - Brightness threshold in adjust video filter Enrique Osuna - Various bug fixes in libvlc. Major Mac OS X Framework improvements. Eren Türkay - Speex boundary checks and security fix diff --git a/modules/gui/macosx/controls.h b/modules/gui/macosx/controls.h index bd123bde20..b6c1509360 100644 --- a/modules/gui/macosx/controls.h +++ b/modules/gui/macosx/controls.h @@ -38,6 +38,8 @@ IBOutlet id o_btn_shuffle; IBOutlet id o_btn_addNode; IBOutlet id o_btn_repeat; + IBOutlet id o_btn_repeat_embed; + IBOutlet id o_btn_shuffle_embed; NSImage * o_repeat_single; NSImage * o_repeat_all; @@ -114,6 +116,30 @@ @end +/***************************************************************************** + * VLCAutoGeneratedMenuContent interface + ***************************************************************************** + * This holds our data for autogenerated menus + *****************************************************************************/ +@interface VLCAutoGeneratedMenuContent : NSObject +{ + char *psz_name; + vlc_object_t * _vlc_object; + vlc_value_t value; + int i_type; +} + +- (id)initWithVariableName: (const char *)name + ofObject: (vlc_object_t *)object + andValue: (vlc_value_t)value + ofType: (int)type; +- (const char *)name; +- (vlc_value_t)value; +- (vlc_object_t *)vlcObject; +- (int)type; + +@end + /***************************************************************************** * VLCTimeField interface ***************************************************************************** diff --git a/modules/gui/macosx/controls.m b/modules/gui/macosx/controls.m index 88a6b004ab..b0aea74328 100644 --- a/modules/gui/macosx/controls.m +++ b/modules/gui/macosx/controls.m @@ -40,30 +40,6 @@ #include #include -/***************************************************************************** - * VLCAutoGeneratedMenuContent interface - ***************************************************************************** - * This holds our data for autogenerated menus - *****************************************************************************/ -@interface VLCAutoGeneratedMenuContent : NSObject -{ - char *psz_name; - vlc_object_t * _vlc_object; - vlc_value_t value; - int i_type; -} - -- (id)initWithVariableName: (const char *)name - ofObject: (vlc_object_t *)object - andValue: (vlc_value_t)value - ofType: (int)type; -- (const char *)name; -- (vlc_value_t)value; -- (vlc_object_t *)vlcObject; -- (int)type; - -@end - #pragma mark - /***************************************************************************** * VLCControls implementation @@ -160,24 +136,24 @@ - (id)voutView { - id window; - id voutView = nil; - id embeddedViewList = [[VLCMain sharedInstance] embeddedList]; - NSEnumerator *enumerator = [[NSApp orderedWindows] objectEnumerator]; - while( !voutView && ( window = [enumerator nextObject] ) ) + id o_window; + id o_voutView = nil; + id o_embeddedViewList = [[VLCMain sharedInstance] embeddedList]; + NSEnumerator *o_enumerator = [[NSApp orderedWindows] objectEnumerator]; + while( !o_voutView && ( o_window = [o_enumerator nextObject] ) ) { /* We have an embedded vout */ - if( [embeddedViewList windowContainsEmbedded: window] ) + if( [o_embeddedViewList windowContainsEmbedded: o_window] ) { - voutView = [embeddedViewList viewForWindow: window]; + o_voutView = [o_embeddedViewList viewForWindow: o_window]; } /* We have a detached vout */ - else if( [[window className] isEqualToString: @"VLCVoutWindow"] ) + else if( [[o_window className] isEqualToString: @"VLCVoutWindow"] ) { - voutView = [window voutView]; + o_voutView = [o_window voutView]; } } - return [[voutView retain] autorelease]; + return [[o_voutView retain] autorelease]; } - (IBAction)stop:(id)sender @@ -243,16 +219,19 @@ { [o_btn_repeat setImage: o_repeat_single]; [o_btn_repeat setAlternateImage: o_repeat_all]; + [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOneOn"]]; } - (void)repeatAll { [o_btn_repeat setImage: o_repeat_all]; [o_btn_repeat setAlternateImage: o_repeat_off]; + [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeatOn"]]; } - (void)repeatOff { [o_btn_repeat setImage: o_repeat_off]; [o_btn_repeat setAlternateImage: o_repeat_single]; + [o_btn_repeat_embed setImage: [NSImage imageNamed:@"sidebarRepeat"]]; } - (void)shuffle { @@ -260,6 +239,10 @@ playlist_t *p_playlist = pl_Hold( VLCIntf ); var_Get( p_playlist, "random", &val ); [o_btn_shuffle setState: val.b_bool]; + if(val.b_bool) + [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffleOn"]]; + else + [o_btn_shuffle_embed setImage: [NSImage imageNamed:@"sidebarShuffle"]]; pl_Release( VLCIntf ); } diff --git a/modules/gui/macosx/embeddedwindow.h b/modules/gui/macosx/embeddedwindow.h index ead8618f72..1a500a67e7 100644 --- a/modules/gui/macosx/embeddedwindow.h +++ b/modules/gui/macosx/embeddedwindow.h @@ -32,10 +32,31 @@ IBOutlet id o_btn_backward; IBOutlet id o_btn_forward; IBOutlet id o_btn_fullscreen; + IBOutlet id o_btn_equalizer; + IBOutlet id o_btn_playlist; IBOutlet id o_btn_play; - IBOutlet id o_slider; + IBOutlet id o_btn_prev; + IBOutlet id o_btn_stop; + IBOutlet id o_btn_next; + IBOutlet id o_btn_volume_down; + IBOutlet id o_volumeslider; + IBOutlet id o_btn_volume_up; + IBOutlet id o_timeslider; + IBOutlet id o_main_pgbar; IBOutlet id o_time; + IBOutlet id o_scrollfield; + IBOutlet id o_horizontal_split; + IBOutlet id o_vertical_split; + IBOutlet id o_videosubview; + IBOutlet id o_sidebar_list; IBOutlet id o_view; + IBOutlet id o_background_view; + IBOutlet id o_searchfield; + IBOutlet id o_status; + IBOutlet id o_playlist; + IBOutlet id o_playlist_view; + IBOutlet id o_playlist_table; + IBOutlet id o_vlc_main; NSImage * o_img_play; NSImage * o_img_play_pressed; @@ -53,19 +74,30 @@ BOOL b_window_is_invisible; NSSize videoRatio; - int originalLevel; + NSInteger originalLevel; } - (void)controlTintChanged; - (void)setTime: (NSString *)o_arg_ime position: (float)f_position; +- (id)getPgbar; - (void)playStatusUpdated: (int)i_status; - (void)setSeekable: (BOOL)b_seekable; +- (void)setStop:(BOOL)b_input; +- (void)setPrev:(BOOL)b_input; +- (void)setNext:(BOOL)b_input; +- (void)setVolumeEnabled:(BOOL)b_input; + +- (void)setScrollString:(NSString *)o_string; + +- (void)setVolumeSlider:(float)f_level; - (void)setVideoRatio:(NSSize)ratio; - (NSView *)mainView; +- (IBAction)togglePlaylist:(id)sender; + - (BOOL)isFullscreen; - (void)lockFullscreenAnimation; @@ -83,3 +115,47 @@ - (void)setFrameOnMainThread:(NSData*)packedargs; @end +/***************************************************************************** + * embeddedbackground + *****************************************************************************/ + + +@interface embeddedbackground : NSView +{ + IBOutlet id o_window; + IBOutlet id o_timeslider; + IBOutlet id o_main_pgbar; + IBOutlet id o_time; + IBOutlet id o_scrollfield; + IBOutlet id o_searchfield; + IBOutlet id o_btn_backward; + IBOutlet id o_btn_forward; + IBOutlet id o_btn_fullscreen; + IBOutlet id o_btn_equalizer; + IBOutlet id o_btn_playlist; + IBOutlet id o_btn_play; + IBOutlet id o_btn_prev; + IBOutlet id o_btn_stop; + IBOutlet id o_btn_next; + IBOutlet id o_btn_volume_down; + IBOutlet id o_volumeslider; + IBOutlet id o_btn_volume_up; + + NSPoint dragStart; +} + +@end + +/***************************************************************************** + * statusbar + *****************************************************************************/ + + +@interface statusbar : NSView +{ + IBOutlet id o_text; + + BOOL mainwindow; +} + +@end \ No newline at end of file diff --git a/modules/gui/macosx/embeddedwindow.m b/modules/gui/macosx/embeddedwindow.m index b59ccf94b7..3392fd1f25 100644 --- a/modules/gui/macosx/embeddedwindow.m +++ b/modules/gui/macosx/embeddedwindow.m @@ -1,7 +1,7 @@ /***************************************************************************** * embeddedwindow.m: MacOS X interface module ***************************************************************************** - * Copyright (C) 2005-2009 the VideoLAN team + * Copyright (C) 2005-2008 the VideoLAN team * $Id$ * * Authors: Benjamin Pracht @@ -26,14 +26,26 @@ * Preamble *****************************************************************************/ +/* DisableScreenUpdates, SetSystemUIMode, ... */ +#import + #import "intf.h" #import "controls.h" #import "vout.h" #import "embeddedwindow.h" #import "fspanel.h" +#import "playlist.h" -/* SetSystemUIMode, ... */ -#import +/***************************************************************************** + * extension to NSWindow's interface to fix compilation warnings + * and let us access this functions properly + * this uses a private Apple-API, but works fine on all current OSX releases + * keep checking for compatiblity with future releases though + *****************************************************************************/ + +@interface NSWindow (UndocumentedWindowProperties) +- (void)setBottomCornerRounded: (BOOL)value; +@end /***************************************************************************** * VLCEmbeddedWindow Implementation @@ -41,40 +53,48 @@ @implementation VLCEmbeddedWindow -- (id)initWithContentRect:(NSRect)contentRect styleMask: (NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation -{ - BOOL b_useTextured = YES; - if( [[NSWindow class] instancesRespondToSelector:@selector(setContentBorderThickness:forEdge:)] ) - { - b_useTextured = NO; - windowStyle ^= NSTexturedBackgroundWindowMask; - } - self = [super initWithContentRect:contentRect styleMask:windowStyle backing:bufferingType defer:deferCreation]; - if(! b_useTextured ) - { - [self setContentBorderThickness:28.0 forEdge:NSMinYEdge]; - } - return self; -} - - (void)awakeFromNib { [self setDelegate: self]; + [self setBottomCornerRounded:NO]; + /* button strings */ [o_btn_backward setToolTip: _NS("Rewind")]; [o_btn_forward setToolTip: _NS("Fast Forward")]; [o_btn_fullscreen setToolTip: _NS("Fullscreen")]; [o_btn_play setToolTip: _NS("Play")]; - [o_slider setToolTip: _NS("Position")]; - - o_img_play = [NSImage imageNamed: @"play_embedded"]; - o_img_pause = [NSImage imageNamed: @"pause_embedded"]; + [o_timeslider setToolTip: _NS("Position")]; + [o_btn_prev setToolTip: _NS("Previous")]; + [o_btn_stop setToolTip: _NS("Stop")]; + [o_btn_next setToolTip: _NS("Next")]; + [o_volumeslider setToolTip: _NS("Volume")]; + [o_btn_playlist setToolTip: _NS("Playlist")]; + [self setTitle: _NS("VLC media player")]; + + if(MACOS_VERSION < 10.5f) { + o_img_play = [NSImage imageNamed: @"play"]; + o_img_pause = [NSImage imageNamed: @"pause"]; + [o_btn_play setImage: [NSImage imageNamed: @"play"]]; + } + else { + o_img_play = [NSImage imageNamed: @"play_big"]; + o_img_pause = [NSImage imageNamed: @"pause_big"]; + } [self controlTintChanged]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector( controlTintChanged ) name: NSControlTintDidChangeNotification object: nil]; + /* Set color of sidebar to Leopard's "Sidebar Blue" */ + [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedRed:0.820 + green:0.843 + blue:0.886 + alpha:1.0]]; + + [self setMinSize:NSMakeSize([o_sidebar_list convertRect:[o_sidebar_list bounds] + toView: nil].size.width + 551., 114.)]; + /* Useful to save o_view frame in fullscreen mode */ o_temp_view = [[NSView alloc] init]; [o_temp_view setAutoresizingMask:NSViewHeightSizable | NSViewWidthSizable]; @@ -86,13 +106,9 @@ [o_btn_fullscreen setState: NO]; b_fullscreen = NO; - [self setMovableByWindowBackground:YES]; - - [self setDelegate:self]; - /* Make sure setVisible: returns NO */ [self orderOut:self]; - b_window_is_invisible = YES; + //b_window_is_invisible = YES; videoRatio = NSMakeSize( 0., 0. ); } @@ -102,21 +118,29 @@ if( [o_btn_play alternateImage] == o_img_play_pressed ) b_playing = YES; - if( [NSColor currentControlTint] == NSGraphiteControlTint ) - { - o_img_play_pressed = [NSImage imageNamed: @"play_embedded_graphite"]; - o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_graphite"]; - [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_embedded_graphite"]]; - [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_embedded_graphite"]]; - [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_graphite"]]; + if (MACOS_VERSION < 10.5f) { + /* System is running Tiger and should use aqua buttons */ + [o_btn_backward setImage: [NSImage imageNamed: @"skip_previous_active"]]; + [o_btn_forward setImage: [NSImage imageNamed: @"skip_forward_active"]]; + if( [NSColor currentControlTint] == NSGraphiteControlTint ) + { + o_img_play_pressed = [NSImage imageNamed: @"play_graphite"]; + o_img_pause_pressed = [NSImage imageNamed: @"pause_graphite"]; + [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_graphite"]]; + [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_graphite"]]; + } + else + { + o_img_play_pressed = [NSImage imageNamed: @"play_blue"]; + o_img_pause_pressed = [NSImage imageNamed: @"pause_blue"]; + [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_blue"]]; + [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_blue"]]; + } } - else - { - o_img_play_pressed = [NSImage imageNamed: @"play_embedded_blue"]; - o_img_pause_pressed = [NSImage imageNamed: @"pause_embedded_blue"]; - [o_btn_backward setAlternateImage: [NSImage imageNamed: @"skip_previous_embedded_blue"]]; - [o_btn_forward setAlternateImage: [NSImage imageNamed: @"skip_forward_embedded_blue"]]; - [o_btn_fullscreen setAlternateImage: [NSImage imageNamed: @"fullscreen_blue"]]; + else{ + /* System is running Leopard or later and should use metal buttons */ + o_img_play_pressed = [NSImage imageNamed: @"play_big_down"]; + o_img_pause_pressed = [NSImage imageNamed: @"pause_big_down"]; } if( b_playing ) @@ -139,7 +163,7 @@ - (void)setTime:(NSString *)o_arg_time position:(float)f_position { [o_time setStringValue: o_arg_time]; - [o_slider setFloatValue: f_position]; + [o_timeslider setFloatValue: f_position]; } - (void)playStatusUpdated:(int)i_status @@ -162,7 +186,45 @@ { [o_btn_forward setEnabled: b_seekable]; [o_btn_backward setEnabled: b_seekable]; - [o_slider setEnabled: b_seekable]; + [o_timeslider setEnabled: b_seekable]; +} + +- (void)setScrollString:(NSString *)o_string +{ + [o_scrollfield setStringValue: o_string]; +} + +- (id)getPgbar +{ + if( o_main_pgbar ) + return o_main_pgbar; + + return nil; +} + +- (void)setStop:(BOOL)b_input +{ + [o_btn_stop setEnabled: b_input]; +} + +- (void)setNext:(BOOL)b_input +{ + [o_btn_next setEnabled: b_input]; +} + +- (void)setPrev:(BOOL)b_input +{ + [o_btn_prev setEnabled: b_input]; +} + +- (void)setVolumeEnabled:(BOOL)b_input +{ + [o_volumeslider setEnabled: b_input]; +} + +- (void)setVolumeSlider:(float)f_level +{ + [o_volumeslider setFloatValue: f_level]; } - (BOOL)windowShouldZoom:(NSWindow *)sender toFrame:(NSRect)newFrame @@ -175,7 +237,9 @@ { playlist_t * p_playlist = pl_Hold( VLCIntf ); - playlist_Stop( p_playlist ); + /* Only want to stop playback if video is playing */ + if( videoRatio.height != 0. && videoRatio.width != 0. ) + playlist_Stop( p_playlist ); pl_Release( VLCIntf ); return YES; } @@ -195,6 +259,16 @@ - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize { + NSView *playlist_area = [[o_vertical_split subviews] objectAtIndex:1]; + NSRect newList = [playlist_area frame]; + if( newList.size.height < 50 && newList.size.height > 0 ) { + [self togglePlaylist:self]; + } + + /* With no video open or with the playlist open the behavior is odd */ + if( newList.size.height > 50 ) + return proposedFrameSize; + if( videoRatio.height == 0. || videoRatio.width == 0. ) return proposedFrameSize; @@ -202,11 +276,121 @@ NSRect contentRect = [self contentRectForFrameRect:[self frame]]; float marginy = viewRect.origin.y + [self frame].size.height - contentRect.size.height; float marginx = contentRect.size.width - viewRect.size.width; + proposedFrameSize.height = (proposedFrameSize.width - marginx) * videoRatio.height / videoRatio.width + marginy; return proposedFrameSize; } +- (void)becomeMainWindow +{ + [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedRed:0.820 + green:0.843 + blue:0.886 + alpha:1.0]]; + [o_status becomeMainWindow]; + [super becomeMainWindow]; +} + +- (void)resignMainWindow +{ + [o_sidebar_list setBackgroundColor: [NSColor colorWithCalibratedWhite:0.91 alpha:1.0]]; + [o_status resignMainWindow]; + [super resignMainWindow]; +} + +- (float)splitView:(NSSplitView *) splitView constrainSplitPosition:(float) proposedPosition ofSubviewAt:(int) index +{ + if([splitView isVertical]) + return proposedPosition; + else { + float bottom = [splitView frame].size.height - [splitView dividerThickness]; + if(proposedPosition > bottom - 50) { + [o_btn_playlist setState: NSOffState]; + [o_searchfield setHidden:YES]; + [o_playlist_view setHidden:YES]; + return bottom; + } + else { + [o_btn_playlist setState: NSOnState]; + [o_searchfield setHidden:NO]; + [o_playlist_view setHidden:NO]; + [o_playlist swapPlaylists: o_playlist_table]; + [o_vlc_main togglePlaylist:self]; + return proposedPosition; + } + } +} + +- (void)splitViewWillResizeSubviews:(NSNotification *) notification +{ + +} + +- (float)splitView:(NSSplitView *) splitView constrainMinCoordinate:(float) proposedMin ofSubviewAt:(int) offset +{ + if([splitView isVertical]) + return 125.; + else + return 0.; +} + +- (float)splitView:(NSSplitView *) splitView constrainMaxCoordinate:(float) proposedMax ofSubviewAt:(int) offset +{ + if([splitView isVertical]) + return MIN([self frame].size.width - 551, 300); + else + return [splitView frame].size.height; +} + +- (BOOL)splitView:(NSSplitView *) splitView canCollapseSubview:(NSView *) subview +{ + if([splitView isVertical]) + return NO; + else + return NO; +} + +- (NSRect)splitView:(NSSplitView *)splitView effectiveRect:(NSRect)proposedEffectiveRect forDrawnRect:(NSRect)drawnRect + ofDividerAtIndex:(NSInteger)dividerIndex +{ + if([splitView isVertical]) { + drawnRect.origin.x -= 3; + drawnRect.size.width += 5; + return drawnRect; + } + else + return drawnRect; +} + +- (IBAction)togglePlaylist:(id)sender +{ + NSView *playback_area = [[o_vertical_split subviews] objectAtIndex:0]; + NSView *playlist_area = [[o_vertical_split subviews] objectAtIndex:1]; + NSRect newVid = [playback_area frame]; + NSRect newList = [playlist_area frame]; + if(newList.size.height < 50 && sender != self && sender != o_vlc_main) { + newList.size.height = newVid.size.height/2; + newVid.size.height = newVid.size.height/2; + newVid.origin.y = newVid.origin.y + newList.size.height; + [o_btn_playlist setState: NSOnState]; + [o_searchfield setHidden:NO]; + [o_playlist_view setHidden:NO]; + [o_playlist swapPlaylists: o_playlist_table]; + [o_vlc_main togglePlaylist:self]; + } + else { + newVid.size.height = newVid.size.height + newList.size.height; + newList.size.height = 0; + newVid.origin.y = 0; + [o_btn_playlist setState: NSOffState]; + [o_searchfield setHidden:YES]; + [o_playlist_view setHidden:YES]; + } + [playback_area setFrame: newVid]; + [playlist_area setFrame: newList]; +} + /***************************************************************************** * Fullscreen support */ @@ -277,9 +461,10 @@ [o_fullscreen_window setBackgroundColor: [NSColor blackColor]]; [o_fullscreen_window setCanBecomeKeyWindow: YES]; - if (![self isVisible] || [self alphaValue] == 0.0) + if (![self isVisible] || [self alphaValue] == 0.0 || MACOS_VERSION < 10.4f) { - /* We don't animate if we are not visible, instead we + /* We don't animate if we are not visible or if we are running on + * Mac OS X <10.4 which doesn't support NSAnimation, instead we * simply fade the display */ CGDisplayFadeReservationToken token; @@ -293,6 +478,8 @@ [o_temp_view setFrame:[o_view frame]]; [o_fullscreen_window setContentView:o_view]; + [o_fullscreen_window makeKeyAndOrderFront:self]; + [o_fullscreen_window makeKeyAndOrderFront:self]; [o_fullscreen_window orderFront:self animate:YES]; @@ -308,12 +495,20 @@ } /* Make sure we don't see the o_view disappearing of the screen during this operation */ - NSDisableScreenUpdates(); - [[self contentView] replaceSubview:o_view with:o_temp_view]; + DisableScreenUpdates(); + [[self contentView] replaceSubview:o_view with:o_temp_view]; [o_temp_view setFrame:[o_view frame]]; [o_fullscreen_window setContentView:o_view]; [o_fullscreen_window makeKeyAndOrderFront:self]; - NSEnableScreenUpdates(); + EnableScreenUpdates(); + } + + if (MACOS_VERSION < 10.4f) + { + /* We were already fullscreen nothing to do when NSAnimation + * is not supported */ + [self unlockFullscreenAnimation]; + return; } /* We are in fullscreen (and no animation is running) */ @@ -417,9 +612,10 @@ return; } - if (fadeout) + if (fadeout || MACOS_VERSION < 10.4f) { - /* We don't animate if we are not visible, instead we + /* We don't animate if we are not visible or if we are running on + * Mac OS X <10.4 which doesn't support NSAnimation, instead we * simply fade the display */ CGDisplayFadeReservationToken token; @@ -500,7 +696,7 @@ { /* This function is private and should be only triggered at the end of the fullscreen change animation */ /* Make sure we don't see the o_view disappearing of the screen during this operation */ - NSDisableScreenUpdates(); + DisableScreenUpdates(); [o_view retain]; [o_view removeFromSuperviewWithoutNeedingDisplay]; [[self contentView] replaceSubview:o_temp_view with:o_view]; @@ -510,7 +706,7 @@ if ([self isVisible]) [super makeKeyAndOrderFront:self]; /* our version contains a workaround */ [o_fullscreen_window orderOut: self]; - NSEnableScreenUpdates(); + EnableScreenUpdates(); [o_fullscreen_window release]; o_fullscreen_window = nil; @@ -626,3 +822,167 @@ } @end + +/***************************************************************************** + * embeddedbackground + *****************************************************************************/ + + +@implementation embeddedbackground + +- (void)dealloc +{ + [self unregisterDraggedTypes]; + [super dealloc]; +} + +- (void)awakeFromNib +{ + [self registerForDraggedTypes:[NSArray arrayWithObjects:NSTIFFPboardType, + NSFilenamesPboardType, nil]]; + [self addSubview: o_timeslider]; + [self addSubview: o_scrollfield]; + [self addSubview: o_time]; + [self addSubview: o_main_pgbar]; + [self addSubview: o_btn_backward]; + [self addSubview: o_btn_forward]; + [self addSubview: o_btn_fullscreen]; + [self addSubview: o_btn_equalizer]; + [self addSubview: o_btn_playlist]; + [self addSubview: o_btn_play]; + [self addSubview: o_btn_prev]; + [self addSubview: o_btn_stop]; + [self addSubview: o_btn_next]; + [self addSubview: o_btn_volume_down]; + [self addSubview: o_volumeslider]; + [self addSubview: o_btn_volume_up]; + [self addSubview: o_searchfield]; +} + +- (NSDragOperation)draggingEntered:(id )sender +{ + if ((NSDragOperationGeneric & [sender draggingSourceOperationMask]) + == NSDragOperationGeneric) + { + return NSDragOperationGeneric; + } + else + { + return NSDragOperationNone; + } +} + +- (BOOL)prepareForDragOperation:(id )sender +{ + return YES; +} + +- (BOOL)performDragOperation:(id )sender +{ + NSPasteboard *o_paste = [sender draggingPasteboard]; + NSArray *o_types = [NSArray arrayWithObjects: NSFilenamesPboardType, nil]; + NSString *o_desired_type = [o_paste availableTypeFromArray:o_types]; + NSData *o_carried_data = [o_paste dataForType:o_desired_type]; + BOOL b_autoplay = config_GetInt( VLCIntf, "macosx-autoplay" ); + + if( o_carried_data ) + { + if ([o_desired_type isEqualToString:NSFilenamesPboardType]) + { + int i; + NSArray *o_array = [NSArray array]; + NSArray *o_values = [[o_paste propertyListForType: NSFilenamesPboardType] + sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)]; + + for( i = 0; i < (int)[o_values count]; i++) + { + NSDictionary *o_dic; + o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"]; + o_array = [o_array arrayByAddingObject: o_dic]; + } + if( b_autoplay ) + [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:NO]; + else + [[[VLCMain sharedInstance] playlist] appendArray: o_array atPos: -1 enqueue:YES]; + return YES; + } + } + [self setNeedsDisplay:YES]; + return YES; +} + +- (void)concludeDragOperation:(id )sender +{ + [self setNeedsDisplay:YES]; +} + +- (void)drawRect:(NSRect)rect +{ + NSImage *leftImage = [NSImage imageNamed:@"display_left"]; + NSImage *middleImage = [NSImage imageNamed:@"display_middle"]; + NSImage *rightImage = [NSImage imageNamed:@"display_right"]; + [middleImage setSize:NSMakeSize(NSWidth( [self bounds] ) - 134 - [leftImage size].width - [rightImage size].width, [middleImage size].height)]; + [middleImage setScalesWhenResized:YES]; + [leftImage compositeToPoint:NSMakePoint( 122., 40. ) operation:NSCompositeSourceOver]; + [middleImage compositeToPoint:NSMakePoint( 122. + [leftImage size].width, 40. ) operation:NSCompositeSourceOver]; + [rightImage compositeToPoint:NSMakePoint( NSWidth( [self bounds] ) - 12 - [rightImage size].width, 40. ) operation:NSCompositeSourceOver]; +} + +- (void)mouseDown:(NSEvent *)event +{ + dragStart = [self convertPoint:[event locationInWindow] fromView:nil]; +} + +- (void)mouseDragged:(NSEvent *)event +{ + NSPoint dragLocation = [self convertPoint:[event locationInWindow] fromView:nil]; + NSPoint winOrigin = [o_window frame].origin; + + NSPoint newOrigin = NSMakePoint(winOrigin.x + (dragLocation.x - dragStart.x), + winOrigin.y + (dragLocation.y - dragStart.y)); + [o_window setFrameOrigin: newOrigin]; +} + +@end + +/***************************************************************************** + * statusbar + *****************************************************************************/ + + +@implementation statusbar +- (void)awakeFromNib +{ + [self addSubview: o_text]; + mainwindow = YES; +} + +- (void)resignMainWindow +{ + mainwindow = NO; + [self needsDisplay]; +} + +- (void)becomeMainWindow +{ + mainwindow = YES; + [self needsDisplay]; +} + +- (void)drawRect:(NSRect)rect +{ + if(mainwindow) + [[NSColor colorWithCalibratedRed:0.820 + green:0.843 + blue:0.886 + alpha:1.0] set]; + else + [[NSColor colorWithCalibratedWhite:0.91 alpha:1.0] set]; + NSRectFill(rect); + /*NSRect divider = rect; + divider.origin.y += divider.size.height - 1; + divider.size.height = 1; + [[NSColor colorWithCalibratedWhite:0.65 alpha:1.] set]; + NSRectFill(divider);*/ +} +@end diff --git a/modules/gui/macosx/equalizer.h b/modules/gui/macosx/equalizer.h index e736be44f4..2d5967003c 100644 --- a/modules/gui/macosx/equalizer.h +++ b/modules/gui/macosx/equalizer.h @@ -27,6 +27,7 @@ @interface VLCEqualizer : NSObject { IBOutlet id o_btn_equalizer; + IBOutlet id o_btn_equalizer_embedded; IBOutlet id o_ckb_2pass; IBOutlet id o_ckb_enable; IBOutlet id o_fld_preamp; diff --git a/modules/gui/macosx/equalizer.m b/modules/gui/macosx/equalizer.m index 4f78770d3f..367ff0b477 100644 --- a/modules/gui/macosx/equalizer.m +++ b/modules/gui/macosx/equalizer.m @@ -151,6 +151,7 @@ static bool GetFiltersStatus( intf_thread_t *p_intf, { int i; [o_btn_equalizer setToolTip: _NS("Equalizer")]; + [o_btn_equalizer_embedded setToolTip: _NS("Equalizer")]; [o_ckb_2pass setTitle: _NS("2 Pass")]; [o_ckb_2pass setToolTip: _NS("Apply the " "equalizer filter twice. The effect will be sharper.")]; @@ -342,11 +343,13 @@ static bool GetFiltersStatus( intf_thread_t *p_intf, { [o_window orderOut:sender]; [o_btn_equalizer setState:NSOffState]; + [o_btn_equalizer_embedded setState:NSOffState]; } else { [o_window makeKeyAndOrderFront:sender]; [o_btn_equalizer setState:NSOnState]; + [o_btn_equalizer_embedded setState:NSOnState]; } } diff --git a/modules/gui/macosx/intf.h b/modules/gui/macosx/intf.h index d983f822df..5c5600084b 100644 --- a/modules/gui/macosx/intf.h +++ b/modules/gui/macosx/intf.h @@ -274,6 +274,7 @@ struct intf_sys_t IBOutlet NSMenu * o_mu_window; IBOutlet NSMenuItem * o_mi_minimize; IBOutlet NSMenuItem * o_mi_close_window; + IBOutlet NSMenuItem * o_mi_player; IBOutlet NSMenuItem * o_mi_controller; IBOutlet NSMenuItem * o_mi_equalizer; IBOutlet NSMenuItem * o_mi_extended; diff --git a/modules/gui/macosx/intf.m b/modules/gui/macosx/intf.m index ef0baaa77f..3124c4805e 100644 --- a/modules/gui/macosx/intf.m +++ b/modules/gui/macosx/intf.m @@ -698,6 +698,7 @@ static VLCMain *_o_sharedMainInstance = nil; [o_mu_window setTitle: _NS("Window")]; [o_mi_minimize setTitle: _NS("Minimize Window")]; [o_mi_close_window setTitle: _NS("Close Window")]; + [o_mi_player setTitle: _NS("Player...")]; [o_mi_controller setTitle: _NS("Controller...")]; [o_mi_equalizer setTitle: _NS("Equalizer...")]; [o_mi_extended setTitle: _NS("Extended Controls...")]; @@ -1675,10 +1676,13 @@ static void manage_cleanup( void * args ) } [o_btn_stop setEnabled: b_input]; + [o_embedded_window setStop: b_input]; [o_btn_ff setEnabled: b_seekable]; [o_btn_rewind setEnabled: b_seekable]; [o_btn_prev setEnabled: (b_plmul || b_chapters)]; + [o_embedded_window setPrev: (b_plmul || b_chapters)]; [o_btn_next setEnabled: (b_plmul || b_chapters)]; + [o_embedded_window setNext: (b_plmul || b_chapters)]; [o_timeslider setFloatValue: 0.0]; [o_timeslider setEnabled: b_seekable]; @@ -1687,6 +1691,7 @@ static void manage_cleanup( void * args ) [[[self controls] fspanel] setSeekable: b_seekable]; [o_embedded_window setSeekable: b_seekable]; + [o_embedded_window setTime:@"00:00" position:0.0]; p_intf->p_sys->b_current_title_update = true; @@ -1807,6 +1812,8 @@ static void manage_cleanup( void * args ) i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" ); [o_volumeslider setFloatValue: (float)i_lastShownVolume / i_volume_step]; [o_volumeslider setEnabled: TRUE]; + [o_embedded_window setVolumeSlider: (float)i_lastShownVolume / i_volume_step]; + [o_embedded_window setVolumeEnabled: TRUE]; [[[self controls] fspanel] setVolumeLevel: (float)i_lastShownVolume / i_volume_step]; p_intf->p_sys->b_mute = ( i_lastShownVolume == 0 ); p_intf->p_sys->b_volume_update = FALSE; diff --git a/modules/gui/macosx/playlist.h b/modules/gui/macosx/playlist.h index 02f291ac79..96cee08f15 100644 --- a/modules/gui/macosx/playlist.h +++ b/modules/gui/macosx/playlist.h @@ -41,13 +41,18 @@ IBOutlet id o_tc_duration; IBOutlet id o_outline_view; + IBOutlet id o_tc_name_other; + IBOutlet id o_tc_author_other; + IBOutlet id o_tc_duration_other; + IBOutlet id o_outline_view_other; + NSMutableDictionary *o_outline_dict; } - (void)initStrings; - (playlist_item_t *)selectedPlaylistItem; - (NSOutlineView *)outlineView; - +- (void)swapPlaylists:(id)newList; @end /***************************************************************************** @@ -71,8 +76,11 @@ IBOutlet id o_btn_playlist; IBOutlet id o_playlist_view; + IBOutlet id o_sidebar; IBOutlet id o_status_field; + IBOutlet id o_status_field_embed; IBOutlet id o_search_field; + IBOutlet id o_search_field_other; IBOutlet id o_mi_save_playlist; IBOutlet id o_ctx_menu; @@ -142,6 +150,9 @@ - (IBAction)addNode:(id)sender; +- (void)playSidebarItem:(id)item; +- (id)playingItem; + - (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue; - (void)appendNodeArray:(NSArray*)o_array inNode:(playlist_item_t *)p_node atPos:(int)i_position enqueue:(BOOL)b_enqueue; diff --git a/modules/gui/macosx/playlist.m b/modules/gui/macosx/playlist.m index 269e513d5b..54f548ac9b 100644 --- a/modules/gui/macosx/playlist.m +++ b/modules/gui/macosx/playlist.m @@ -49,6 +49,7 @@ #import "controls.h" #import "vlc_osd.h" #import "misc.h" +#import "sidebarview.h" #import #import @@ -119,6 +120,11 @@ [o_outline_view setAllowsEmptySelection: NO]; [o_outline_view expandItem: [o_outline_view itemAtRow:0]]; + [o_outline_view_other setTarget: self]; + [o_outline_view_other setDelegate: self]; + [o_outline_view_other setDataSource: self]; + [o_outline_view_other setAllowsEmptySelection: NO]; + pl_Release( VLCIntf ); [self initStrings]; } @@ -128,6 +134,29 @@ [[o_tc_name headerCell] setStringValue:_NS("Name")]; [[o_tc_author headerCell] setStringValue:_NS("Author")]; [[o_tc_duration headerCell] setStringValue:_NS("Duration")]; + + [[o_tc_name_other headerCell] setStringValue:_NS("Name")]; + [[o_tc_author_other headerCell] setStringValue:_NS("Author")]; + [[o_tc_duration_other headerCell] setStringValue:_NS("Duration")]; +} + +- (void)swapPlaylists:(id)newList +{ + if(newList != o_outline_view) + { + id o_outline_view_temp = o_outline_view; + id o_tc_author_temp = o_tc_author; + id o_tc_duration_temp = o_tc_duration; + id o_tc_name_temp = o_tc_name; + o_outline_view = o_outline_view_other; + o_tc_author = o_tc_author_other; + o_tc_duration = o_tc_duration_other; + o_tc_name = o_tc_name_other; + o_outline_view_other = o_outline_view_temp; + o_tc_author_other = o_tc_author_temp; + o_tc_duration_other = o_tc_duration_temp; + o_tc_name_other = o_tc_name_temp; + } } - (NSOutlineView *)outlineView @@ -365,12 +394,18 @@ [super awakeFromNib]; [o_outline_view setDoubleAction: @selector(playItem:)]; + [o_outline_view_other setDoubleAction: @selector(playItem:)]; [o_outline_view registerForDraggedTypes: [NSArray arrayWithObjects: NSFilenamesPboardType, @"VLCPlaylistItemPboardType", nil]]; [o_outline_view setIntercellSpacing: NSMakeSize (0.0, 1.0)]; + [o_outline_view_other registerForDraggedTypes: + [NSArray arrayWithObjects: NSFilenamesPboardType, + @"VLCPlaylistItemPboardType", nil]]; + [o_outline_view_other setIntercellSpacing: NSMakeSize (0.0, 1.0)]; + /* This uses private Apple API which works fine until 10.5. * We need to keep checking in the future! * These methods are being added artificially to NSOutlineView's interface above */ @@ -448,8 +483,10 @@ [o_mi_services setTitle: _NS("Services discovery")]; [o_mm_mi_services setTitle: _NS("Services discovery")]; [o_status_field setStringValue: _NS("No items in the playlist")]; + [o_status_field_embed setStringValue: _NS("No items in the playlist")]; [o_search_field setToolTip: _NS("Search in Playlist")]; + [o_search_field_other setToolTip: _NS("Search in Playlist")]; [o_mi_addNode setTitle: _NS("Add Folder to Playlist")]; [o_save_accessory_text setStringValue: _NS("File Format:")]; @@ -458,6 +495,18 @@ [[o_save_accessory_popup itemAtIndex:2] setTitle: _NS("HTML Playlist")]; } +- (void)swapPlaylists:(id)newList +{ + if(newList != o_outline_view) + { + id o_search_field_temp = o_search_field; + o_search_field = o_search_field_other; + o_search_field_other = o_search_field_temp; + [super swapPlaylists:newList]; + [self playlistUpdated]; + } +} + - (void)playlistUpdated { /* Clear indications of any existing column sorting */ @@ -472,6 +521,7 @@ // TODO Find a way to keep the dict size to a minimum //[o_outline_dict removeAllObjects]; [o_outline_view reloadData]; + [o_sidebar updateSidebar:[self playingItem]]; [[[[VLCMain sharedInstance] wizard] playlistWizard] reloadOutlineView]; [[[[VLCMain sharedInstance] bookmarks] dataTable] reloadData]; @@ -483,13 +533,22 @@ [o_status_field setStringValue: [NSString stringWithFormat: _NS("%i items"), playlist_CurrentSize( p_playlist )]]; + [o_status_field_embed setStringValue: [NSString stringWithFormat: + _NS("%i items"), + playlist_CurrentSize( p_playlist )]]; } else { if( playlist_IsEmpty( p_playlist ) ) + { [o_status_field setStringValue: _NS("No items in the playlist")]; + [o_status_field_embed setStringValue: _NS("No items in the playlist")]; + } else + { [o_status_field setStringValue: _NS("1 item")]; + [o_status_field_embed setStringValue: _NS("1 item")]; + } } PL_UNLOCK; pl_Release( VLCIntf ); @@ -813,6 +872,40 @@ pl_Release( p_intf ); } +- (void)playSidebarItem:(id)item +{ + intf_thread_t * p_intf = VLCIntf; + playlist_t * p_playlist = pl_Hold( p_intf ); + + playlist_item_t *p_item; + playlist_item_t *p_node = NULL; + + p_item = [item pointerValue]; + + if( p_item ) + { + if( p_item->i_children == -1 ) + { + p_node = p_item->p_parent; + + } + else + { + p_node = p_item; + if( p_node->i_children > 0 && p_node->pp_children[0]->i_children == -1 ) + { + p_item = p_node->pp_children[0]; + } + else + { + p_item = NULL; + } + } + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Unlocked, p_node, p_item ); + } + pl_Release( p_intf ); +} + - (IBAction)revealItemInFinder:(id)sender { playlist_item_t * p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue]; @@ -1453,6 +1546,20 @@ pl_Release( VLCIntf ); } +- (id)playingItem +{ + playlist_t *p_playlist = pl_Hold( VLCIntf ); + + id o_playing_item; + + o_playing_item = [o_outline_dict objectForKey: + [NSString stringWithFormat:@"%p", playlist_CurrentPlayingItem( p_playlist )]]; + + pl_Release( VLCIntf ); + + return o_playing_item; +} + - (IBAction)addNode:(id)sender { playlist_t * p_playlist = pl_Hold( VLCIntf ); @@ -1482,16 +1589,21 @@ [o_status_field setStringValue: [NSString stringWithFormat: _NS("%i items"), playlist_CurrentSize( p_playlist )]]; + [o_status_field_embed setStringValue: [NSString stringWithFormat: + _NS("%i items"), + playlist_CurrentSize( p_playlist )]]; } else { if( playlist_IsEmpty( p_playlist ) ) { [o_status_field setStringValue: _NS("No items in the playlist")]; + [o_status_field_embed setStringValue: _NS("No items in the playlist")]; } else { [o_status_field setStringValue: _NS("1 item")]; + [o_status_field_embed setStringValue: _NS("1 item")]; } } PL_UNLOCK; diff --git a/modules/gui/macosx/sidebarview.h b/modules/gui/macosx/sidebarview.h new file mode 100644 index 0000000000..13c972887e --- /dev/null +++ b/modules/gui/macosx/sidebarview.h @@ -0,0 +1,45 @@ +/***************************************************************************** + * sidebarview.h: MacOS X interface module + ***************************************************************************** + * Copyright (C) 2005-2008 the VideoLAN team + * $Id$ + * + * Authors: Eric Dudiak + * Colloquy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#import + +@interface sidebarview : NSSplitView +{ + long _mainSubviewIndex; +} +@end + +/***************************************************************************** + * VLCSidebar interface + *****************************************************************************/ +@interface VLCSidebar : NSObject +{ + IBOutlet id o_outline_view; + IBOutlet id o_playlist; +} + +- (NSOutlineView *)outlineView; +- (void)updateSidebar:(id)item; + +@end \ No newline at end of file diff --git a/modules/gui/macosx/sidebarview.m b/modules/gui/macosx/sidebarview.m new file mode 100644 index 0000000000..7398cc528e --- /dev/null +++ b/modules/gui/macosx/sidebarview.m @@ -0,0 +1,201 @@ +/***************************************************************************** + * sidebarview.m: MacOS X interface module + ***************************************************************************** + * Copyright (C) 2005-2008 the VideoLAN team + * $Id$ + * + * Authors: Eric Dudiak + * Colloquy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#import "sidebarview.h" +#import "intf.h" +#import "playlist.h" + +@implementation sidebarview +- (void) resetCursorRects +{ + if( ! [self isPaneSplitter] ) + [super resetCursorRects]; +} + +- (id) initWithCoder:(NSCoder *) decoder { + if( ( self = [super initWithCoder:decoder] ) ) + _mainSubviewIndex = 1; + return self; +} + +- (float) dividerThickness +{ + return 1.0; +} + +- (BOOL) isVertical +{ + return YES; +} + +- (void) drawDividerInRect:(NSRect) rect +{ + [[NSColor colorWithCalibratedWhite:0.65 alpha:1.] set]; + NSRectFill( rect ); +} + +- (void) adjustSubviews +{ + if( _mainSubviewIndex == -1 || [[self subviews] count] != 2 ) { + [super adjustSubviews]; + return; + } + + float dividerThickness = [self dividerThickness]; + NSRect newFrame = [self frame]; + + NSView *mainView = [[self subviews] objectAtIndex:_mainSubviewIndex]; + NSView *otherView = ( _mainSubviewIndex ? [[self subviews] objectAtIndex:0] : [[self subviews] objectAtIndex:1] ); + + NSRect mainFrame = [mainView frame]; + NSRect otherFrame = [otherView frame]; + + + mainFrame.size.width = NSWidth( newFrame ) - dividerThickness - NSWidth( otherFrame ); + mainFrame.size.height = NSHeight( newFrame ); + mainFrame.origin.x = ( _mainSubviewIndex ? NSWidth( otherFrame ) + dividerThickness : 0. ); + mainFrame.origin.y = 0.; + + otherFrame.size.width = NSWidth( otherFrame ); + otherFrame.size.height = NSHeight( newFrame ); + otherFrame.origin.x = ( _mainSubviewIndex ? 0. : NSWidth( mainFrame ) + dividerThickness ); + otherFrame.origin.y = 0.; + + [mainView setFrame:mainFrame]; + [otherView setFrame:otherFrame]; + + [self setNeedsDisplay:YES]; +} +@end + +/***************************************************************************** + * VLCPlaylist implementation + *****************************************************************************/ +@implementation VLCSidebar + +- (void)awakeFromNib +{ + [o_outline_view setTarget: self]; + [o_outline_view setDelegate: self]; + [o_outline_view setDataSource: self]; + [o_outline_view setAllowsEmptySelection: NO]; +} + +- (NSOutlineView *)outlineView +{ + return o_outline_view; +} + +- (void)outlineView:(NSOutlineView *)outlineView + willDisplayCell:(id)cell + forTableColumn:(NSTableColumn *)tableColumn + item:(id)item +{ + if ( ![outlineView isExpandable:item] ) + { + [cell setFont: [NSFont systemFontOfSize: 12]]; + [cell setTextColor:[NSColor blackColor]]; + } + else + { + [cell setFont: [NSFont boldSystemFontOfSize: 10]]; + [cell setTextColor:[NSColor colorWithCalibratedWhite:0.365 alpha:1.0]]; + } +} + +- (void)updateSidebar:(id)item +{ + int i_row = -1; + [o_outline_view reloadData]; + i_row = [o_outline_view rowForItem:item]; + if( i_row > -1 ) + { + [o_outline_view selectRow:i_row byExtendingSelection: NO]; + [o_outline_view scrollRowToVisible: i_row]; + } +} + +- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item +{ + if( [outlineView isExpandable:item] ) + return 12.; + else + return 20.; +} + +- (BOOL)outlineView:(NSOutlineView *)outlineView shouldSelectItem:(id)item +{ + if( [outlineView isExpandable:item] ) + return NO; + else + { + if( ![[o_playlist playingItem] isEqual: item] ) + [o_playlist playSidebarItem:item]; + return YES; + } +} + +- (void)outlineViewItemDidExpand:(NSNotification *)notification +{ + int i_row = -1; + i_row = [o_outline_view rowForItem:[o_playlist playingItem]]; + if( i_row > -1 ) + { + [o_outline_view selectRow:i_row byExtendingSelection: NO]; + [o_outline_view scrollRowToVisible: i_row]; + } +} + +@end + +@implementation VLCSidebar (NSOutlineViewDataSource) + +/* return the number of children for Obj-C pointer item */ /* DONE */ +- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item +{ + return [o_playlist outlineView:outlineView numberOfChildrenOfItem:item]; +} + +/* return the child at index for the Obj-C pointer item */ /* DONE */ +- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item +{ + return [o_playlist outlineView:outlineView child:index ofItem:item]; +} + +/* is the item expandable */ +- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item +{ + return [o_playlist outlineView:outlineView isItemExpandable:item]; +} + +/* retrieve the string values for the cells */ +- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)o_tc byItem:(id)item +{ + if( [outlineView isExpandable:item] ) + return [[o_playlist outlineView:outlineView objectValueForTableColumn:o_tc byItem:item] uppercaseString]; + else + return [o_playlist outlineView:outlineView objectValueForTableColumn:o_tc byItem:item]; +} + +@end diff --git a/modules/gui/macosx/sidestatusview.h b/modules/gui/macosx/sidestatusview.h new file mode 100644 index 0000000000..eb330e25b9 --- /dev/null +++ b/modules/gui/macosx/sidestatusview.h @@ -0,0 +1,33 @@ +/***************************************************************************** + * sidestatusview.h: MacOS X interface module + ***************************************************************************** + * Copyright (C) 2005-2008 the VideoLAN team + * $Id$ + * + * Authors: Eric Dudiak + * Colloquy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#import + +@interface sidestatusview : NSView { + IBOutlet NSSplitView *splitView; + float _clickOffset; + BOOL _insideResizeArea; +} + +@end diff --git a/modules/gui/macosx/sidestatusview.m b/modules/gui/macosx/sidestatusview.m new file mode 100644 index 0000000000..25c96f7395 --- /dev/null +++ b/modules/gui/macosx/sidestatusview.m @@ -0,0 +1,107 @@ +/***************************************************************************** + * sidestatusview.m: MacOS X interface module + ***************************************************************************** + * Copyright (C) 2005-2008 the VideoLAN team + * $Id$ + * + * Authors: Eric Dudiak + * Colloquy + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#import "sidestatusview.h" + +@implementation sidestatusview +-(void)resetCursorRects +{ + [super resetCursorRects]; + if( ! splitView ) return; + + NSImage *resizeImage = [NSImage imageNamed:@"sidebarResizeWidget"]; + NSRect location; + location.size = [resizeImage size]; + location.origin = NSMakePoint( NSWidth( [self bounds] ) - [resizeImage size].width, 0. ); + [self addCursorRect:location cursor:[NSCursor resizeLeftRightCursor]]; +} + +- (void)drawRect:(NSRect)rect +{ + NSImage *backgroundImage = [NSImage imageNamed:@"sidebarStatusAreaBackground"]; + [backgroundImage setSize:NSMakeSize(NSWidth( [self bounds] ), [backgroundImage size].height)]; + [backgroundImage setScalesWhenResized:YES]; + [backgroundImage compositeToPoint:NSMakePoint( 0., 0. ) operation:NSCompositeCopy]; + + if( splitView ) { + NSImage *resizeImage = [NSImage imageNamed:@"sidebarResizeWidget"]; + [resizeImage compositeToPoint:NSMakePoint( NSWidth( [self bounds] ) - [resizeImage size].width, 0. ) operation:NSCompositeCopy]; + } +} + +- (void)mouseDown:(NSEvent *)event +{ + if( ! splitView ) return; + NSPoint clickLocation = [self convertPoint:[event locationInWindow] fromView:nil]; + + NSImage *resizeImage = [NSImage imageNamed:@"sidebarResizeWidget"]; + NSRect location; + location.size = [resizeImage size]; + location.origin = NSMakePoint( NSWidth( [self bounds] ) - [resizeImage size].width, 0. ); + + _insideResizeArea = ( NSPointInRect( clickLocation, location ) ); + if( ! _insideResizeArea ) return; + + clickLocation = [self convertPoint:[event locationInWindow] fromView:[self superview]]; + _clickOffset = NSWidth( [[self superview] frame] ) - clickLocation.x; +} + +- (void)mouseDragged:(NSEvent *)event +{ + if( ! splitView || ! _insideResizeArea ) return; + + [[NSNotificationCenter defaultCenter] postNotificationName:NSSplitViewWillResizeSubviewsNotification object:splitView]; + + NSPoint clickLocation = [self convertPoint:[event locationInWindow] fromView:[self superview]]; + + NSRect newFrame = [[self superview] frame]; + newFrame.size.width = clickLocation.x + _clickOffset; + + id delegate = [splitView delegate]; + if( delegate && [delegate respondsToSelector:@selector( splitView:constrainSplitPosition:ofSubviewAt: )] ) { + float new = [delegate splitView:splitView constrainSplitPosition:newFrame.size.width ofSubviewAt:0]; + newFrame.size.width = new; + } + + if( delegate && [delegate respondsToSelector:@selector( splitView:constrainMinCoordinate:ofSubviewAt: )] ) { + float min = [delegate splitView:splitView constrainMinCoordinate:0. ofSubviewAt:0]; + newFrame.size.width = MAX( min, newFrame.size.width ); + } + + if( delegate && [delegate respondsToSelector:@selector( splitView:constrainMaxCoordinate:ofSubviewAt: )] ) { + float max = [delegate splitView:splitView constrainMaxCoordinate:0. ofSubviewAt:0]; + newFrame.size.width = MIN( max, newFrame.size.width ); + } + + if( delegate ) { + [delegate setMinSize:NSMakeSize(newFrame.size.width + 551., 114.)]; + } + + [[self superview] setFrame:newFrame]; + + [splitView adjustSubviews]; + + [[NSNotificationCenter defaultCenter] postNotificationName:NSSplitViewDidResizeSubviewsNotification object:splitView]; +} +@end -- 2.39.2