* MediaControlView.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 VideoLAN
- * $Id: MediaControlView.cpp,v 1.4 2002/10/14 20:09:17 titer Exp $
+ * $Id$
*
* Authors: Tony Castley <tony@castley.net>
* Stephan Aßmus <stippi@yellowbites.com>
/* System headers */
#include <InterfaceKit.h>
#include <AppKit.h>
+#include <String.h>
#include <string.h>
/* VLC headers */
#include <vlc/vlc.h>
#include <vlc/intf.h>
+extern "C"
+{
+ #include <audio_output.h>
+}
/* BeOS interface headers */
#include "VlcWrapper.h"
const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
-const char* kDisabledSeekMessage = "Drop files to play";
+#define DISABLED_SEEK_MESSAGE _("Drop files to play")
enum
{
};
// constructor
-MediaControlView::MediaControlView(BRect frame)
+MediaControlView::MediaControlView(BRect frame, intf_thread_t *p_interface)
: BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
B_PLAIN_BORDER),
fScrubSem(B_ERROR),
fCurrentRate(DEFAULT_RATE),
fCurrentStatus(UNDEF_S),
- fBottomControlHeight(0.0)
+ fBottomControlHeight(0.0),
+ fIsEnabled( true )
{
+ p_intf = p_interface;
+
BRect frame(0.0, 0.0, 10.0, 10.0);
// Seek Slider
- fSeekSlider = new SeekSlider(frame, "seek slider", this,
- 0, SEEKSLIDER_RANGE - 1);
+ fSeekSlider = new SeekSlider( frame, "seek slider", this,
+ 0, SEEKSLIDER_RANGE );
fSeekSlider->SetValue(0);
fSeekSlider->ResizeToPreferred();
AddChild( fSeekSlider );
kVolumeSliderBitmapHeight - 1.0),
"volume slider", 1, AOUT_VOLUME_MAX,
new BMessage(VOLUME_CHG));
- fVolumeSlider->SetValue(AOUT_VOLUME_DEFAULT);
+ fVolumeSlider->SetValue( config_GetInt( p_intf, "volume" ) );
AddChild( fVolumeSlider );
+
+ // Position Info View
+ fPositionInfo = new PositionInfoView(BRect(0.0, 0.0, 10.0, 10.0), "led",
+ p_intf);
+ fPositionInfo->ResizeToPreferred();
+ AddChild( fPositionInfo );
}
// destructor
fVolumeSlider->SetTarget(Window());
BRect r(_MinFrame());
- if (BMenuBar* menuBar = Window()->KeyMenuBar())
- r.bottom += menuBar->Bounds().Height();
+ if (BMenuBar* menuBar = Window()->KeyMenuBar()) {
+ float width, height;
+ menuBar->GetPreferredSize(&width, &height);
+// r.bottom += menuBar->Bounds().Height();
+ r.bottom += height;
+ // see that our calculated minimal width is not smaller than what
+ // the menubar can be
+printf("preferred: width: %f, height: %f - width: %f\n", width, height, r.Width());
+ width -= r.Width();
+ if (width > 0.0)
+ r.right += width;
+ }
- Window()->SetSizeLimits(r.Width(), r.Width() * 2.0, r.Height(), r.Height() * 2.0);
+ Window()->SetSizeLimits(r.Width(), r.Width() * 1.8, r.Height(), r.Height() * 1.3);
if (!Window()->Bounds().Contains(r))
Window()->ResizeTo(r.Width(), r.Height());
else
InterfaceWindow* window = dynamic_cast<InterfaceWindow*>(Window());
if (window && window->IsStopped())
fPlayPause->SetStopped();
+
+ unsigned short i_volume;
+ aout_VolumeGet( p_intf, (audio_volume_t*)&i_volume );
+ fVolumeSlider->SetValue( i_volume );
}
// SetProgress
void
-MediaControlView::SetProgress(uint64 seek, uint64 size)
+MediaControlView::SetProgress( float position )
{
- fSeekSlider->SetPosition((float)seek / (float)size);
+ fSeekSlider->SetPosition( position );
}
// SetStatus
case PLAYING_S:
case FORWARD_S:
case BACKWARD_S:
- case START_S:
fPlayPause->SetPlaying();
break;
case PAUSE_S:
fPlayPause->SetPaused();
break;
case UNDEF_S:
- case NOT_STARTED_S:
default:
fPlayPause->SetStopped();
break;
void
MediaControlView::SetEnabled(bool enabled)
{
- fSkipBack->SetEnabled(enabled);
- fPlayPause->SetEnabled(enabled);
- fSkipForward->SetEnabled(enabled);
- fStop->SetEnabled(enabled);
- fMute->SetEnabled(enabled);
- fVolumeSlider->SetEnabled(enabled);
- fSeekSlider->SetEnabled(enabled);
- fRewind->SetEnabled(enabled);
- fForward->SetEnabled(enabled);
+ if( ( enabled && fIsEnabled ) ||
+ ( !enabled && !fIsEnabled ) )
+ {
+ /* do not redraw if it is not necessary */
+ return;
+ }
+
+ if( LockLooper() )
+ {
+ fSkipBack->SetEnabled( enabled );
+ fPlayPause->SetEnabled( enabled );
+ fSkipForward->SetEnabled( enabled );
+ fStop->SetEnabled( enabled );
+ fMute->SetEnabled( enabled );
+ fVolumeSlider->SetEnabled( enabled );
+ fSeekSlider->SetEnabled( enabled );
+ fRewind->SetEnabled( enabled );
+ fForward->SetEnabled( enabled );
+ UnlockLooper();
+ fIsEnabled = enabled;
+ }
}
// SetAudioEnabled
{
// seek slider
BRect r(frame);
- r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
- _LayoutControl(fSeekSlider, r, true);
// calculate absolutly minimal width
float minWidth = fSkipBack->Bounds().Width();
// minWidth += fRewind->Bounds().Width();
minWidth += fSkipForward->Bounds().Width();
minWidth += fMute->Bounds().Width();
minWidth += VOLUME_MIN_WIDTH;
+
+ // layout time slider and info view
+ float width, height;
+ fPositionInfo->GetBigPreferredSize( &width, &height );
+ float ratio = width / height;
+ width = r.Height() * ratio;
+ if (frame.Width() - minWidth - MIN_SPACE >= width
+ && frame.Height() >= height)
+ {
+ r.right = r.left + width;
+ fPositionInfo->SetMode(PositionInfoView::MODE_BIG);
+ _LayoutControl(fPositionInfo, r, true, true);
+ frame.left = r.right + MIN_SPACE;
+ r.left = frame.left;
+ r.right = frame.right;
+ // r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
+ r.bottom = r.top + fSeekSlider->Bounds().Height();
+ _LayoutControl(fSeekSlider, r, true);
+ }
+ else
+ {
+ fPositionInfo->GetPreferredSize( &width, &height );
+ fPositionInfo->SetMode(PositionInfoView::MODE_SMALL);
+ fPositionInfo->ResizeTo(width, height);
+ r.bottom = r.top + r.Height() / 2.0 - MIN_SPACE / 2.0;
+ r.right = r.left + fPositionInfo->Bounds().Width();
+ _LayoutControl(fPositionInfo, r, true );
+ r.left = r.right + MIN_SPACE;
+ r.right = frame.right;
+ _LayoutControl(fSeekSlider, r, true);
+ }
float currentWidth = frame.Width();
float space = (currentWidth - minWidth) / 6.0;//8.0;
// apply weighting
space = MIN_SPACE + (space - MIN_SPACE) / VOLUME_SLIDER_LAYOUT_WEIGHT;
// layout controls with "space" inbetween
+ r.left = frame.left;
r.top = r.bottom + MIN_SPACE + 1.0;
r.bottom = frame.bottom;
// skip back
// _LayoutControl
void
-MediaControlView::_LayoutControl(BView* view, BRect frame, bool resize) const
+MediaControlView::_LayoutControl(BView* view, BRect frame,
+ bool resizeWidth, bool resizeHeight) const
{
- // center vertically
- frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
- if (!resize)
+ if (!resizeHeight)
+ // center vertically
+ frame.top = (frame.top + frame.bottom) / 2.0 - view->Bounds().Height() / 2.0;
+ if (!resizeWidth)
+ //center horizontally
frame.left = (frame.left + frame.right) / 2.0 - view->Bounds().Width() / 2.0;
view->MoveTo(frame.LeftTop());
- if (resize)
- view->ResizeTo(frame.Width(), view->Bounds().Height());
+ float width = resizeWidth ? frame.Width() : view->Bounds().Width();
+ float height = resizeHeight ? frame.Height() : view->Bounds().Height();
+ if (resizeWidth || resizeHeight)
+ view->ResizeTo(width, height);
}
SetHighColor(darkShadow);
SetLowColor(shadow);
// stripes
- float width = floorf(StringWidth(kDisabledSeekMessage));
+ float width = floorf(StringWidth(DISABLED_SEEK_MESSAGE));
float textPos = r.left + r.Width() / 2.0 - width / 2.0;
- pattern stripes = { 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 };
+ pattern stripes = {{ 0xc7, 0x8f, 0x1f, 0x3e, 0x7c, 0xf8, 0xf1, 0xe3 }};
BRect stripesRect(r);
stripesRect.right = textPos - 5.0;
FillRect(stripesRect, stripes);
SetLowColor(darkShadow);
font_height fh;
GetFontHeight(&fh);
- DrawString(kDisabledSeekMessage, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
+ DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
}
}
void
SeekSlider::ResizeToPreferred()
{
- float width = 15.0 + StringWidth(kDisabledSeekMessage) + 15.0;
+ float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
ResizeTo(width, 17.0);
}
void
SeekSlider::SetPosition(float position)
{
- SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
+ if ( LockLooper() )
+ {
+ SetValue(fMinValue + (int32)floorf((fMaxValue - fMinValue) * position + 0.5));
+ UnlockLooper();
+ }
}
/*****************************************************************************
SetDrawingMode(B_OP_OVER); // part of knob is transparent
DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
}
- else
- fprintf(stderr, "VolumeSlider::Draw() - Error: no valid bitmaps!");
}
/*****************************************************************************
return value;
}
+/*****************************************************************************
+ * PositionInfoView::PositionInfoView
+ *****************************************************************************/
+PositionInfoView::PositionInfoView( BRect frame, const char* name,
+ intf_thread_t * p_interface )
+ : BView( frame, name, B_FOLLOW_NONE,
+ B_WILL_DRAW | B_PULSE_NEEDED | B_FULL_UPDATE_ON_RESIZE ),
+ fMode( MODE_SMALL ),
+ fCurrentFileIndex( -1 ),
+ fCurrentFileSize( -1 ),
+ fCurrentTitleIndex( -1 ),
+ fCurrentTitleSize( -1 ),
+ fCurrentChapterIndex( -1 ),
+ fCurrentChapterSize( -1 ),
+ fSeconds( -1 ),
+ fTimeString( "-:--:--" ),
+ fLastPulseUpdate( system_time() ),
+ fStackedWidthCache( 0.0 ),
+ fStackedHeightCache( 0.0 )
+{
+ p_intf = p_interface;
+
+ SetViewColor( B_TRANSPARENT_32_BIT );
+ SetLowColor( kBlack );
+ SetHighColor( 0, 255, 0, 255 );
+ SetFontSize( 11.0 );
+}
+
+/*****************************************************************************
+ * PositionInfoView::~PositionInfoView
+ *****************************************************************************/
+PositionInfoView::~PositionInfoView()
+{
+}
+
+/*****************************************************************************
+ * PositionInfoView::Draw
+ *****************************************************************************/
+void
+PositionInfoView::Draw( BRect updateRect )
+{
+ rgb_color background = ui_color( B_PANEL_BACKGROUND_COLOR );
+ rgb_color shadow = tint_color( background, B_DARKEN_1_TINT );
+ rgb_color darkShadow = tint_color( background, B_DARKEN_4_TINT );
+ rgb_color light = tint_color( background, B_LIGHTEN_MAX_TINT );
+ rgb_color softLight = tint_color( background, B_LIGHTEN_1_TINT );
+ // frame
+ BRect r( Bounds() );
+ BeginLineArray( 8 );
+ AddLine( BPoint( r.left, r.bottom ),
+ BPoint( r.left, r.top ), shadow );
+ AddLine( BPoint( r.left + 1.0, r.top ),
+ BPoint( r.right, r.top ), shadow );
+ AddLine( BPoint( r.right, r.top + 1.0 ),
+ BPoint( r.right, r.bottom ), softLight );
+ AddLine( BPoint( r.right - 1.0, r.bottom ),
+ BPoint( r.left + 1.0, r.bottom ), softLight );
+ r.InsetBy( 1.0, 1.0 );
+ AddLine( BPoint( r.left, r.bottom ),
+ BPoint( r.left, r.top ), darkShadow );
+ AddLine( BPoint( r.left + 1.0, r.top ),
+ BPoint( r.right, r.top ), darkShadow );
+ AddLine( BPoint( r.right, r.top + 1.0 ),
+ BPoint( r.right, r.bottom ), light );
+ AddLine( BPoint( r.right - 1.0, r.bottom ),
+ BPoint( r.left + 1.0, r.bottom ), light );
+ EndLineArray();
+ // background
+ r.InsetBy( 1.0, 1.0 );
+ FillRect( r, B_SOLID_LOW );
+ // contents
+ font_height fh;
+ GetFontHeight( &fh );
+ switch ( fMode )
+ {
+ case MODE_SMALL:
+ {
+ float width = StringWidth( fTimeString.String() );
+ DrawString( fTimeString.String(),
+ BPoint( r.left + r.Width() / 2.0 - width / 2.0,
+ r.top + r.Height() / 2.0 + fh.ascent / 2.0 - 1.0 ) );
+ break;
+ }
+ case MODE_BIG:
+ {
+ BFont font;
+ GetFont( &font );
+ BFont smallFont = font;
+ BFont bigFont = font;
+ BFont tinyFont = font;
+ smallFont.SetSize( r.Height() / 5.0 );
+ bigFont.SetSize( r.Height() / 3.0 );
+ tinyFont.SetSize( r.Height() / 7.0 );
+ float timeHeight = r.Height() / 2.5;
+ float height = ( r.Height() - timeHeight ) / 3.0;
+ SetFont( &tinyFont );
+ SetHighColor( 0, 180, 0, 255 );
+ DrawString( _("File"), BPoint( r.left + 3.0, r.top + height ) );
+ DrawString( _("Title"), BPoint( r.left + 3.0, r.top + 2.0 * height ) );
+ DrawString( _("Chapter"), BPoint( r.left + 3.0, r.top + 3.0 * height ) );
+ SetFont( &smallFont );
+ BString helper;
+ SetHighColor( 0, 255, 0, 255 );
+ // file
+ _MakeString( helper, fCurrentFileIndex, fCurrentFileSize );
+ float width = StringWidth( helper.String() );
+ DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + height ) );
+ // title
+ _MakeString( helper, fCurrentTitleIndex, fCurrentTitleSize );
+ width = StringWidth( helper.String() );
+ DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 2.0 * height ) );
+ // chapter
+ _MakeString( helper, fCurrentChapterIndex, fCurrentChapterSize );
+ width = StringWidth( helper.String() );
+ DrawString( helper.String(), BPoint( r.right - 3.0 - width, r.top + 3.0 * height ) );
+ // time
+ SetFont( &bigFont );
+ width = StringWidth( fTimeString.String() );
+ DrawString( fTimeString.String(),
+ BPoint( r.left + r.Width() / 2.0 - width / 2.0,
+ r.bottom - 3.0 ) );
+ break;
+ }
+ }
+}
+/*****************************************************************************
+ * PositionInfoView::ResizeToPreferred
+ *****************************************************************************/
+void
+PositionInfoView::ResizeToPreferred()
+{
+ float width, height;
+ GetPreferredSize( &width, &height );
+ ResizeTo( width, height );
+}
+/*****************************************************************************
+ * PositionInfoView::GetPreferredSize
+ *****************************************************************************/
+void
+PositionInfoView::GetPreferredSize( float* width, float* height )
+{
+ if ( width && height )
+ {
+ *width = 5.0 + ceilf( StringWidth( "0:00:00" ) ) + 5.0;
+ font_height fh;
+ GetFontHeight( &fh );
+ *height = 3.0 + ceilf( fh.ascent ) + 3.0;
+ fStackedWidthCache = *width * 1.2;
+ fStackedHeightCache = *height * 2.7;
+ }
+}
+/*****************************************************************************
+ * PositionInfoView::Pulse
+ *****************************************************************************/
+void
+PositionInfoView::Pulse()
+{
+ // allow for Pulse frequency to be higher, MediaControlView needs it
+ bigtime_t now = system_time();
+ if ( now - fLastPulseUpdate > 900000 )
+ {
+ int32 index, size;
+ p_intf->p_sys->p_wrapper->GetPlaylistInfo( index, size );
+ SetFile( index + 1, size );
+ p_intf->p_sys->p_wrapper->TitleInfo( index, size );
+ SetTitle( index, size );
+ p_intf->p_sys->p_wrapper->ChapterInfo( index, size );
+ SetChapter( index, size );
+ SetTime( p_intf->p_sys->p_wrapper->GetTimeAsString() );
+ fLastPulseUpdate = now;
+ }
+}
+/*****************************************************************************
+ * PositionInfoView::GetBigPreferredSize
+ *****************************************************************************/
+void
+PositionInfoView::GetBigPreferredSize( float* width, float* height )
+{
+ if ( width && height )
+ {
+ *width = fStackedWidthCache;
+ *height = fStackedHeightCache;
+ }
+}
+
+/*****************************************************************************
+ * PositionInfoView::SetMode
+ *****************************************************************************/
+void
+PositionInfoView::SetMode( uint32 mode )
+{
+ if ( fMode != mode )
+ {
+ fMode = mode;
+ _InvalidateContents();
+ }
+}
+
+/*****************************************************************************
+ * PositionInfoView::SetFile
+ *****************************************************************************/
+void
+PositionInfoView::SetFile( int32 index, int32 size )
+{
+ if ( fCurrentFileIndex != index || fCurrentFileSize != size )
+ {
+ fCurrentFileIndex = index;
+ fCurrentFileSize = size;
+ _InvalidateContents();
+ }
+}
+
+/*****************************************************************************
+ * PositionInfoView::SetTitle
+ *****************************************************************************/
+void
+PositionInfoView::SetTitle( int32 index, int32 size )
+{
+ if ( fCurrentTitleIndex != index || fCurrentFileSize != size )
+ {
+ fCurrentTitleIndex = index;
+ fCurrentTitleSize = size;
+ _InvalidateContents();
+ }
+}
+
+/*****************************************************************************
+ * PositionInfoView::SetChapter
+ *****************************************************************************/
+void
+PositionInfoView::SetChapter( int32 index, int32 size )
+{
+ if ( fCurrentChapterIndex != index || fCurrentFileSize != size )
+ {
+ fCurrentChapterIndex = index;
+ fCurrentChapterSize = size;
+ _InvalidateContents();
+ }
+}
+
+/*****************************************************************************
+ * PositionInfoView::SetTime
+ *****************************************************************************/
+void
+PositionInfoView::SetTime( int32 seconds )
+{
+ if ( fSeconds != seconds )
+ {
+ if ( seconds >= 0 )
+ {
+ int32 minutes = seconds / 60;
+ int32 hours = minutes / 60;
+ seconds -= minutes * 60 - hours * 60 * 60;
+ minutes -= hours * 60;
+ fTimeString.SetTo( "" );
+ fTimeString << hours << ":" << minutes << ":" << seconds;
+ }
+ else
+ fTimeString.SetTo( "-:--:--" );
+
+ fSeconds = seconds;
+ _InvalidateContents();
+ }
+}
+
+/*****************************************************************************
+ * PositionInfoView::SetTime
+ *****************************************************************************/
+void
+PositionInfoView::SetTime( const char* string )
+{
+ fTimeString.SetTo( string );
+ _InvalidateContents();
+}
+
+/*****************************************************************************
+ * PositionInfoView::_InvalidateContents
+ *****************************************************************************/
+void
+PositionInfoView::_InvalidateContents( uint32 which )
+{
+ BRect r( Bounds() );
+ r.InsetBy( 2.0, 2.0 );
+ Invalidate( r );
+}
+
+/*****************************************************************************
+ * PositionInfoView::_InvalidateContents
+ *****************************************************************************/
+void
+PositionInfoView::_MakeString( BString& into, int32 index, int32 maxIndex ) const
+{
+ into = "";
+ if ( index >= 0 && maxIndex >= 0 )
+ into << index;
+ else
+ into << "-";
+ into << "/";
+ if ( maxIndex >= 0 )
+ into << maxIndex;
+ else
+ into << "-";
+}