Commit af691d06 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

BeOS interface: remove

This has been broken for sure since 1.0, most probably nuch earlier.
parent e4347611
......@@ -380,7 +380,6 @@ case "${host_os}" in
CXXFLAGS_save="${CXXFLAGS_save} -Wno-multichar"; CXXFLAGS="${CXXFLAGS_save}"
VLC_ADD_CXXFLAGS([beos],[])
VLC_ADD_LIBS([vlc libvlccore logger],[-lbe])
VLC_ADD_LIBS([beos],[-lbe -lmedia -ltranslation -ltracker -lgame])
VLC_ADD_LIBS([dvdnav dvdread],[-ldl])
VLC_ADD_LIBS([filesystem],[-lpoll])
LDFLAGS_save="${LDFLAGS_save} -lintl"; LDFLAGS="${LDFLAGS_save}"
......@@ -390,11 +389,6 @@ case "${host_os}" in
else
VLC_ADD_LIBS([filesystem access_ftp access_mms access_output_udp oldtelnet netsync sap libvlccore growl_udp],[-lnet])
fi
dnl Ugly check for Zeta
if test -f /boot/beos/system/lib/libzeta.so; then
VLC_ADD_LIBS([beos],[-lzeta])
fi
;;
*)
SYS="${host_os}"
......@@ -4101,12 +4095,6 @@ dnl
AC_ARG_WITH(,[Interface plugins:])
dnl special case for BeOS
if test "${SYS}" = "beos"
then
VLC_ADD_PLUGIN([beos])
fi
dnl
dnl Skins2 module
dnl
......@@ -5039,7 +5027,6 @@ AC_CONFIG_FILES([
modules/demux/mpeg/Makefile
modules/demux/playlist/Makefile
modules/gui/Makefile
modules/gui/beos/Makefile
modules/gui/macosx/Makefile
modules/gui/hildon/Makefile
modules/gui/minimal_macosx/Makefile
......
......@@ -60,7 +60,6 @@ $Id$
* ball: Augmented reality ball video filter module
* bandlimited_resampler: Bandlimited interpolation audio resampler
* bda: DVB support for Windows BDA drivers
* beos: Audio output, video output and interface module for BeOS
* blend: a picture filter that blends two pictures
* blendbench: a picture filter that test performance of blending routines
* bluescreen: Bluescreen (weather channel like) video filter
......
DIST_SUBDIRS = beos macosx hildon minimal_macosx qt4 skins2 macosx_dialog_provider
DIST_SUBDIRS = macosx hildon minimal_macosx qt4 skins2 macosx_dialog_provider
SUBDIRS =
if HAVE_BEOS
SUBDIRS += beos
endif
if HAVE_DARWIN
SUBDIRS += macosx minimal_macosx macosx_dialog_provider
endif
......
/*****************************************************************************
* AudioOutput.cpp: BeOS audio output
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Eric Petit <titer@videolan.org>
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <malloc.h>
#include <SoundPlayer.h>
#include <media/MediaDefs.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_aout.h>
extern "C"
{
#include <aout_internal.h>
}
/*****************************************************************************
* aout_sys_t: BeOS audio output method descriptor
*****************************************************************************/
typedef struct aout_sys_t
{
BSoundPlayer * p_player;
mtime_t latency;
} aout_sys_t;
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static void Play ( void * p_aout, void * p_buffer, size_t size,
const media_raw_audio_format & format );
static void DoNothing ( aout_instance_t * p_aout );
/*****************************************************************************
* OpenAudio
*****************************************************************************/
int OpenAudio ( vlc_object_t * p_this )
{
aout_instance_t * p_aout = (aout_instance_t*) p_this;
p_aout->output.p_sys = (aout_sys_t*) malloc( sizeof( aout_sys_t ) );
if( p_aout->output.p_sys == NULL )
return -1;
aout_sys_t * p_sys = p_aout->output.p_sys;
aout_VolumeSoftInit( p_aout );
int i_nb_channels = aout_FormatNbChannels( &p_aout->output.output );
/* BSoundPlayer does not support more than 2 channels AFAIK */
if( i_nb_channels > 2 )
{
i_nb_channels = 2;
p_aout->output.output.i_physical_channels
= AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT;
}
media_raw_audio_format * p_format;
p_format = (media_raw_audio_format*)
malloc( sizeof( media_raw_audio_format ) );
p_format->channel_count = i_nb_channels;
p_format->frame_rate = p_aout->output.output.i_rate;
p_format->format = media_raw_audio_format::B_AUDIO_FLOAT;
#ifdef WORDS_BIGENDIAN
p_format->byte_order = B_MEDIA_BIG_ENDIAN;
#else
p_format->byte_order = B_MEDIA_LITTLE_ENDIAN;
#endif
p_format->buffer_size = 8192;
p_aout->output.output.i_format = VLC_CODEC_FL32;
p_aout->output.i_nb_samples = 2048 / i_nb_channels;
p_aout->output.pf_play = DoNothing;
p_sys->p_player = new BSoundPlayer( p_format, "player", Play, NULL, p_aout );
if( p_sys->p_player->InitCheck() != B_OK )
{
msg_Err( p_aout, "BSoundPlayer InitCheck failed" );
delete p_sys->p_player;
free( p_sys );
return -1;
}
/* Start playing */
p_sys->latency = p_sys->p_player->Latency();
p_sys->p_player->Start();
p_sys->p_player->SetHasData( true );
return 0;
}
/*****************************************************************************
* CloseAudio
*****************************************************************************/
void CloseAudio ( vlc_object_t * p_this )
{
aout_instance_t * p_aout = (aout_instance_t *) p_this;
aout_sys_t * p_sys = (aout_sys_t *) p_aout->output.p_sys;
/* Clean up */
p_sys->p_player->Stop();
delete p_sys->p_player;
free( p_sys );
}
/*****************************************************************************
* Play
*****************************************************************************/
static void Play( void * _p_aout, void * _p_buffer, size_t i_size,
const media_raw_audio_format &format )
{
aout_instance_t * p_aout = (aout_instance_t*) _p_aout;
float * p_buffer = (float*) _p_buffer;
aout_sys_t * p_sys = (aout_sys_t*) p_aout->output.p_sys;
aout_buffer_t * p_aout_buffer;
p_aout_buffer = aout_OutputNextBuffer( p_aout,
mdate() + p_sys->latency,
false );
if( p_aout_buffer != NULL )
{
vlc_memcpy( p_buffer, p_aout_buffer->p_buffer,
MIN( i_size, p_aout_buffer->i_buffer ) );
if( p_aout_buffer->i_buffer < i_size )
{
vlc_memset( p_buffer + p_aout_buffer->i_buffer,
0, i_size - p_aout_buffer->i_buffer );
}
aout_BufferFree( p_aout_buffer );
}
else
{
vlc_memset( p_buffer, 0, i_size );
}
}
/*****************************************************************************
* DoNothing
*****************************************************************************/
static void DoNothing( aout_instance_t *p_aout )
{
return;
}
/*****************************************************************************
* beos.cpp : BeOS plugin for vlc
*****************************************************************************
* Copyright (C) 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_plugin.h>
/*****************************************************************************
* External prototypes
*****************************************************************************/
int OpenIntf ( vlc_object_t * );
void CloseIntf ( vlc_object_t * );
int OpenAudio ( vlc_object_t * );
void CloseAudio ( vlc_object_t * );
int OpenVideo ( vlc_object_t * );
void CloseVideo ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin ()
set_category( CAT_INTERFACE )
set_subcategory( SUBCAT_INTERFACE_MAIN )
add_bool( "beos-dvdmenus", false, NULL, _("Use DVD Menus"), "", true )
set_shortname( "BeOS" )
set_description( N_("BeOS standard API interface") )
set_capability( "interface", 100 )
set_callbacks( OpenIntf, CloseIntf )
add_submodule ()
set_capability( "video output", 100 )
set_callbacks( OpenVideo, CloseVideo )
add_submodule ()
set_capability( "audio output", 100 )
set_callbacks( OpenAudio, CloseAudio )
vlc_module_end ()
This source diff could not be displayed because it is too large. You can view the blob instead.
/*****************************************************************************
* DrawingTidbits.cpp
*****************************************************************************
* Copyright (C) 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tcastley@mail.powerup.com.au>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#include <math.h>
#include <Bitmap.h>
#include <Debug.h>
#include <Screen.h>
#include "DrawingTidbits.h"
// ShiftComponent
inline uchar
ShiftComponent(uchar component, float percent)
{
// change the color by <percent>, make sure we aren't rounding
// off significant bits
if (percent >= 1)
return (uchar)(component * (2 - percent));
else
return (uchar)(255 - percent * (255 - component));
}
// ShiftColor
rgb_color
ShiftColor(rgb_color color, float percent)
{
rgb_color result = {
ShiftComponent(color.red, percent),
ShiftComponent(color.green, percent),
ShiftComponent(color.blue, percent),
0
};
return result;
}
// CompareColors
static bool
CompareColors(const rgb_color a, const rgb_color b)
{
return a.red == b.red
&& a.green == b.green
&& a.blue == b.blue
&& a.alpha == b.alpha;
}
// ==
bool
operator==(const rgb_color &a, const rgb_color &b)
{
return CompareColors(a, b);
}
// !=
bool
operator!=(const rgb_color &a, const rgb_color &b)
{
return !CompareColors(a, b);
}
// ReplaceColor
void
ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to)
{
ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
BScreen screen(B_MAIN_SCREEN_ID);
uint32 fromIndex = screen.IndexForColor(from);
uint32 toIndex = screen.IndexForColor(to);
uchar *bits = (uchar *)bitmap->Bits();
int32 bitsLength = bitmap->BitsLength();
for (int32 index = 0; index < bitsLength; index++)
if (bits[index] == fromIndex)
bits[index] = toIndex;
}
// ReplaceTransparentColor
void
ReplaceTransparentColor(BBitmap *bitmap, rgb_color with)
{
ASSERT(bitmap->ColorSpace() == B_COLOR_8_BIT); // other color spaces not implemented yet
BScreen screen(B_MAIN_SCREEN_ID);
uint32 withIndex = screen.IndexForColor(with);
uchar *bits = (uchar *)bitmap->Bits();
int32 bitsLength = bitmap->BitsLength();
for (int32 index = 0; index < bitsLength; index++)
if (bits[index] == B_TRANSPARENT_8_BIT)
bits[index] = withIndex;
}
// ycrcb_to_rgb
inline void
ycbcr_to_rgb( uint8 y, uint8 cb, uint8 cr,
uint8& r, uint8& g, uint8& b)
{
r = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 1.596 * ( cr - 128 ) ) );
g = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) - 0.813 * ( cr - 128 )
- 0.391 * ( cb - 128 ) ) );
b = (uint8)max_c( 0, min_c( 255, 1.164 * ( y - 16 ) + 2.018 * ( cb - 128 ) ) );
}
// this function will not produce visually pleasing results!
// we'd have to convert to Lab colorspace, do the mixing
// and convert back to RGB - in an ideal world...
//
// mix_colors
inline void
mix_colors( uint8 ra, uint8 ga, uint8 ba,
uint8 rb, uint8 gb, uint8 bb,
uint8& r, uint8& g, uint8& b, float mixLevel )
{
float mixA = ( 1.0 - mixLevel );
float mixB = mixLevel;
r = (uint8)(mixA * ra + mixB * rb);
g = (uint8)(mixA * ga + mixB * gb);
b = (uint8)(mixA * ba + mixB * bb);
}
// the algorithm used is probably pretty slow, but it should be easy
// to understand what's going on...
//
// scale_bitmap
status_t
scale_bitmap( BBitmap* bitmap, uint32 fromWidth, uint32 fromHeight )
{
status_t status = B_BAD_VALUE;
if ( bitmap && bitmap->IsValid()
&& ( bitmap->ColorSpace() == B_RGB32 || bitmap->ColorSpace() == B_RGBA32 ) )
{
status = B_MISMATCHED_VALUES;
// we only support upscaling as of now
uint32 destWidth = bitmap->Bounds().IntegerWidth() + 1;
uint32 destHeight = bitmap->Bounds().IntegerHeight() + 1;
if ( fromWidth <= destWidth && fromHeight <= destHeight )
{
status = B_OK;
uint32 bpr = bitmap->BytesPerRow();
if ( fromWidth < destWidth )
{
// scale horizontally
uint8* src = (uint8*)bitmap->Bits();
uint8* p = new uint8[fromWidth * 4]; // temp buffer
for ( uint32 y = 0; y < fromHeight; y++ )
{
// copy valid pixels into temp buffer
memcpy( p, src, fromWidth * 4 );
for ( uint32 x = 0; x < destWidth; x++ )
{
// mix colors of left and right pixels and write it back
// into the bitmap
float xPos = ( (float)x / (float)destWidth ) * (float)fromWidth;
uint32 leftIndex = (uint32)floorf( xPos ) * 4;
uint32 rightIndex = (uint32)ceilf( xPos ) * 4;
rgb_color left;
left.red = p[leftIndex + 2];
left.green = p[leftIndex + 1];
left.blue = p[leftIndex + 0];
rgb_color right;
right.red = p[rightIndex + 2];
right.green = p[rightIndex + 1];
right.blue = p[rightIndex + 0];
rgb_color mix;
mix_colors( left.red, left.green, left.blue,
right.red, right.green, right.blue,
mix.red, mix.green, mix.blue, xPos - floorf( xPos ) );
uint32 destIndex = x * 4;
src[destIndex + 2] = mix.red;
src[destIndex + 1] = mix.green;
src[destIndex + 0] = mix.blue;
}
src += bpr;
}
delete[] p;
}
if ( fromHeight < destHeight )
{
// scale vertically
uint8* src = (uint8*)bitmap->Bits();
uint8* p = new uint8[fromHeight * 3]; // temp buffer
for ( uint32 x = 0; x < destWidth; x++ )
{
// copy valid pixels into temp buffer
for ( uint32 y = 0; y < fromHeight; y++ )
{
uint32 destIndex = y * 3;
uint32 srcIndex = x * 4 + y * bpr;
p[destIndex + 0] = src[srcIndex + 0];
p[destIndex + 1] = src[srcIndex + 1];
p[destIndex + 2] = src[srcIndex + 2];
}
// do the scaling
for ( uint32 y = 0; y < destHeight; y++ )
{
// mix colors of upper and lower pixels and write it back
// into the bitmap
float yPos = ( (float)y / (float)destHeight ) * (float)fromHeight;
uint32 upperIndex = (uint32)floorf( yPos ) * 3;
uint32 lowerIndex = (uint32)ceilf( yPos ) * 3;
rgb_color upper;
upper.red = p[upperIndex + 2];
upper.green = p[upperIndex + 1];
upper.blue = p[upperIndex + 0];
rgb_color lower;
lower.red = p[lowerIndex + 2];
lower.green = p[lowerIndex + 1];
lower.blue = p[lowerIndex + 0];
rgb_color mix;
mix_colors( upper.red, upper.green, upper.blue,
lower.red, lower.green, lower.blue,
mix.red, mix.green, mix.blue, yPos - floorf( yPos ) );
uint32 destIndex = x * 4 + y * bpr;
src[destIndex + 2] = mix.red;
src[destIndex + 1] = mix.green;
src[destIndex + 0] = mix.blue;
}
}
delete[] p;
}
}
}
return status;
}
// convert_bitmap
status_t
convert_bitmap( BBitmap* inBitmap, BBitmap* outBitmap )
{
status_t status = B_BAD_VALUE;
// see that we got valid bitmaps
if ( inBitmap && inBitmap->IsValid()
&& outBitmap && outBitmap->IsValid() )
{
status = B_MISMATCHED_VALUES;
// see that bitmaps are compatible and that we support the conversion
if ( inBitmap->Bounds().Width() <= outBitmap->Bounds().Width()
&& inBitmap->Bounds().Height() <= outBitmap->Bounds().Height()
&& ( outBitmap->ColorSpace() == B_RGB32
|| outBitmap->ColorSpace() == B_RGBA32) )
{
int32 width = inBitmap->Bounds().IntegerWidth() + 1;
int32 height = inBitmap->Bounds().IntegerHeight() + 1;
int32 srcBpr = inBitmap->BytesPerRow();
int32 dstBpr = outBitmap->BytesPerRow();
uint8* srcBits = (uint8*)inBitmap->Bits();
uint8* dstBits = (uint8*)outBitmap->Bits();
switch (inBitmap->ColorSpace())
{
case B_YCbCr422:
// Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0]
// Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
for ( int32 y = 0; y < height; y++ )
{
for ( int32 x = 0; x < width; x += 2 )
{
int32 srcOffset = x * 2;
int32 dstOffset = x * 4;
ycbcr_to_rgb( srcBits[srcOffset + 0],
srcBits[srcOffset + 1],
srcBits[srcOffset + 3],
dstBits[dstOffset + 2],
dstBits[dstOffset + 1],
dstBits[dstOffset + 0] );
ycbcr_to_rgb( srcBits[srcOffset + 2],
srcBits[srcOffset + 1],
srcBits[srcOffset + 3],
dstBits[dstOffset + 6],
dstBits[dstOffset + 5],
dstBits[dstOffset + 4] );
// take care of alpha
dstBits[x * 4 + 3] = 255;
dstBits[x * 4 + 7] = 255;
}
srcBits += srcBpr;
dstBits += dstBpr;
}
status = B_OK;
break;
case B_YCbCr420:
// Non-interlaced only!
// Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
// Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
status = B_ERROR;
break;
case B_YUV422:
// U0[7:0] Y0[7:0] V0[7:0] Y1[7:0]
// U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
status = B_ERROR;
break;
case B_RGB32:
case B_RGBA32:
memcpy( dstBits, srcBits, inBitmap->BitsLength() );
status = B_OK;
break;
case B_RGB16:
// G[2:0],B[4:0] R[4:0],G[5:3]
for ( int32 y = 0; y < height; y ++ )
{
for ( int32 x = 0; x < width; x++ )
{
int32 srcOffset = x * 2;
int32 dstOffset = x * 4;
uint8 blue = srcBits[srcOffset + 0] & 0x1f;
uint8 green = ( srcBits[srcOffset + 0] >> 5 )
| ( ( srcBits[srcOffset + 1] & 0x07 ) << 3 );
uint8 red = srcBits[srcOffset + 1] & 0xf8;
// homogeneously scale each component to 8 bit
dstBits[dstOffset + 0] = (blue << 3) | (blue >> 2);
dstBits[dstOffset + 1] = (green << 2) | (green >> 4);
dstBits[dstOffset + 2] = red | (red >> 5);
}
srcBits += srcBpr;
dstBits += dstBpr;
}
status = B_OK;
break;
default:
status = B_MISMATCHED_VALUES;
break;
}
if ( status == B_OK )
{
if ( width < outBitmap->Bounds().IntegerWidth() + 1
|| height < outBitmap->Bounds().IntegerHeight() + 1 )
{
scale_bitmap( outBitmap, width, height );
}
}
}
}
return status;
}
// clip_float
inline uint8
clip_float(float value)
{
if (value < 0)
value = 0;
if (value > 255)
value = 255;
return (uint8)value;
}
// dim_bitmap
status_t
dim_bitmap(BBitmap* bitmap, rgb_color center, float dimLevel)
{
status_t status = B_BAD_VALUE;
if (bitmap && bitmap->IsValid())
{
switch (bitmap->ColorSpace())
{
case B_CMAP8:
{
BScreen screen(B_MAIN_SCREEN_ID);
if (screen.IsValid())
{
// iterate over each pixel, get the respective
// color from the screen object, find the distance
// to the "center" color and shorten the distance
// by "dimLevel"
int32 length = bitmap->BitsLength();
uint8* bits = (uint8*)bitmap->Bits();
for (int32 i = 0; i < length; i++)
{
// preserve transparent pixels
if (bits[i] != B_TRANSPARENT_MAGIC_CMAP8)
{
// get color for this index
rgb_color c = screen.ColorForIndex(bits[i]);
// red
float dist = (c.red - center.red) * dimLevel;
c.red = clip_float(center.red + dist);
// green
dist = (c.green - center.green) * dimLevel;
c.green = clip_float(center.green + dist);
// blue
dist = (c.blue - center.blue) * dimLevel;
c.blue = clip_float(center.blue + dist);
// write correct index of the dimmed color
// back into bitmap (and hope the match is close...)
bits[i] = screen.IndexForColor(c);
}
}
status = B_OK;
}
break;
}
case B_RGB32:
case B_RGBA32:
{
// iterate over each color component, find the distance
// to the "center" color and shorten the distance
// by "dimLevel"
uint8* bits = (uint8*)bitmap->Bits();
int32 bpr = bitmap->BytesPerRow();
int32 pixels = bitmap->Bounds().IntegerWidth() + 1;
int32 lines = bitmap->Bounds().IntegerHeight() + 1;
// iterate over color components
for (int32 y = 0; y < lines; y++) {
for (int32 x = 0; x < pixels; x++) {
int32 offset = 4 * x; // four bytes per pixel
// blue
float dist = (bits[offset + 0] - center.blue) * dimLevel;
bits[offset + 0] = clip_float(center.blue + dist);
// green
dist = (bits[offset + 1] - center.green) * dimLevel;
bits[offset + 1] = clip_float(center.green + dist);
// red
dist = (bits[offset + 2] - center.red) * dimLevel;
bits[offset + 2] = clip_float(center.red + dist);
// ignore alpha channel
}
// next line
bits += bpr;
}
status = B_OK;
break;
}
default:
status = B_ERROR;
break;
}
}
return status;
}
// dimmed_color_cmap8
rgb_color
dimmed_color_cmap8(rgb_color color, rgb_color center, float dimLevel)
{
BScreen screen(B_MAIN_SCREEN_ID);
if (screen.IsValid())
{
// red
float dist = (color.red - center.red) * dimLevel;
color.red = clip_float(center.red + dist);
// green
dist = (color.green - center.green) * dimLevel;
color.green = clip_float(center.green + dist);
// blue
dist = (color.blue - center.blue) * dimLevel;
color.blue = clip_float(center.blue + dist);
// get color index for dimmed color
int32 index = screen.IndexForColor(color);
// put color at index (closest match in palette
// to dimmed result) into returned color
color = screen.ColorForIndex(index);
}
return color;
}
/*****************************************************************************
* DrawingTidbits.h
*****************************************************************************
* Copyright (C) 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tcastley@mail.powerup.com.au>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#ifndef __DRAWING_TIBITS__
#define __DRAWING_TIBITS__
#include <GraphicsDefs.h>
rgb_color ShiftColor(rgb_color , float );
bool operator==(const rgb_color &, const rgb_color &);
bool operator!=(const rgb_color &, const rgb_color &);
inline rgb_color
Color(int32 r, int32 g, int32 b, int32 alpha = 255)
{
rgb_color result;
result.red = r;
result.green = g;
result.blue = b;
result.alpha = alpha;
return result;
}
const rgb_color kWhite = { 255, 255, 255, 255};
const rgb_color kBlack = { 0, 0, 0, 255};
const float kDarkness = 1.06;
const float kDimLevel = 0.6;
void ReplaceColor(BBitmap *bitmap, rgb_color from, rgb_color to);
void ReplaceTransparentColor(BBitmap *bitmap, rgb_color with);
// function can be used to scale the upper left part of
// a bitmap to fill the entire bitmap, ie fromWidth
// and fromHeight must be smaller or equal to the bitmaps size!
// only supported colorspaces are B_RGB32 and B_RGBA32
status_t scale_bitmap( BBitmap* bitmap,
uint32 fromWidth, uint32 fromHeight );
// bitmaps need to be the same size, or this function will fail
// currently supported conversions:
// B_YCbCr422 -> B_RGB32
// B_RGB32 -> B_RGB32
// B_RGB16 -> B_RGB32
// not yet implemented conversions:
// B_YCbCr420 -> B_RGB32
// B_YUV422 -> B_RGB32
status_t convert_bitmap(BBitmap* inBitmap, BBitmap* outBitmap);
// dims bitmap (in place) by finding the distance of
// the color at each pixel to the provided "center" color
// and shortens that distance by dimLevel
// (dimLevel < 1 -> less contrast)
// (dimLevel > 1 -> more contrast)
// (dimLevel < 0 -> inverted colors)
// currently supported colorspaces:
// B_RGB32
// B_RGBA32
// B_CMAP8
status_t dim_bitmap(BBitmap* bitmap, rgb_color center,
float dimLevel);
rgb_color dimmed_color_cmap8(rgb_color color, rgb_color center,
float dimLevel);
#endif // __DRAWING_TIBITS__
/*****************************************************************************
* intf_beos.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Tony Castley <tony@castley.net>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <stippi@yellowbites.com>
* Eric Petit <titer@videolan.org>
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <InterfaceKit.h>
#include <Application.h>
#include <Message.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
#include <vlc_aout.h>
#include <aout_internal.h>
#include "InterfaceWindow.h"
#include "MsgVals.h"
/*****************************************************************************
* intf_sys_t: internal variables of the BeOS interface
*****************************************************************************/
struct intf_sys_t
{
InterfaceWindow * p_window;
};
/*****************************************************************************
* Local prototype
*****************************************************************************/
static void Run ( intf_thread_t *p_intf );
/*****************************************************************************
* intf_Open: initialize interface
*****************************************************************************/
int OpenIntf ( vlc_object_t *p_this )
{
intf_thread_t * p_intf = (intf_thread_t*) p_this;
/* Allocate instance and initialize some members */
p_intf->p_sys = (intf_sys_t*) malloc( sizeof( intf_sys_t ) );
if( !p_intf->p_sys )
return VLC_EGENERIC;
p_intf->pf_run = Run;
/* Create the interface window */
BScreen screen( B_MAIN_SCREEN_ID );
BRect rect = screen.Frame();
rect.top = rect.bottom - 100;
rect.bottom -= 50;
rect.left += 50;
rect.right = rect.left + 350;
p_intf->p_sys->p_window =
new InterfaceWindow( p_intf, rect, "VLC " VERSION );
if( !p_intf->p_sys->p_window )
{
free( p_intf->p_sys );
msg_Err( p_intf, "cannot allocate InterfaceWindow" );
return VLC_EGENERIC;
}
/* Make the be_app aware the interface has been created */
BMessage message( INTERFACE_CREATED );
message.AddPointer( "window", p_intf->p_sys->p_window );
be_app->PostMessage( &message );
return VLC_SUCCESS;
}
/*****************************************************************************
* intf_Close: destroy dummy interface
*****************************************************************************/
void CloseIntf ( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t*) p_this;
/* Destroy the interface window */
if( p_intf->p_sys->p_window->Lock() )
p_intf->p_sys->p_window->Quit();
/* Destroy structure */
free( p_intf->p_sys );
}
/*****************************************************************************
* intf_Run: event loop
*****************************************************************************/
static void Run( intf_thread_t *p_intf )
{
while( vlc_object_alive( p_intf ) )
{
p_intf->p_sys->p_window->UpdateInterface();
msleep( INTF_IDLE_SLEEP );
}
}
/*****************************************************************************
* InterfaceWindow.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Tony Castley <tony@castley.net>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <superstippi@gmx.de>
*
* 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.
*****************************************************************************/
/* System headers */
#include <kernel/OS.h>
#include <InterfaceKit.h>
#include <AppKit.h>
#include <StorageKit.h>
#include <SupportKit.h>
#include <malloc.h>
#include <scsi.h>
#include <scsiprobe_driver.h>
#include <fs_info.h>
/* VLC headers */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_aout.h>
#include <vlc_interface.h>
/* BeOS interface headers */
#include "MsgVals.h"
#include "MediaControlView.h"
#include "PlayListWindow.h"
#include "PreferencesWindow.h"
#include "MessagesWindow.h"
#include "InterfaceWindow.h"
#define INTERFACE_UPDATE_TIMEOUT 80000 // 2 frames if at 25 fps
#define INTERFACE_LOCKING_TIMEOUT 5000
// make_sure_frame_is_on_screen
bool
make_sure_frame_is_on_screen( BRect& frame )
{
BScreen screen( B_MAIN_SCREEN_ID );
if (frame.IsValid() && screen.IsValid()) {
if (!screen.Frame().Contains(frame)) {
// make sure frame fits in the screen
if (frame.Width() > screen.Frame().Width())
frame.right -= frame.Width() - screen.Frame().Width() + 10.0;
if (frame.Height() > screen.Frame().Height())
frame.bottom -= frame.Height() - screen.Frame().Height() + 30.0;
// frame is now at the most the size of the screen
if (frame.right > screen.Frame().right)
frame.OffsetBy(-(frame.right - screen.Frame().right), 0.0);
if (frame.bottom > screen.Frame().bottom)
frame.OffsetBy(0.0, -(frame.bottom - screen.Frame().bottom));
if (frame.left < screen.Frame().left)
frame.OffsetBy((screen.Frame().left - frame.left), 0.0);
if (frame.top < screen.Frame().top)
frame.OffsetBy(0.0, (screen.Frame().top - frame.top));
}
return true;
}
return false;
}
// make_sure_frame_is_within_limits
void
make_sure_frame_is_within_limits( BRect& frame, float minWidth, float minHeight,
float maxWidth, float maxHeight )
{
if ( frame.Width() < minWidth )
frame.right = frame.left + minWidth;
if ( frame.Height() < minHeight )
frame.bottom = frame.top + minHeight;
if ( frame.Width() > maxWidth )
frame.right = frame.left + maxWidth;
if ( frame.Height() > maxHeight )
frame.bottom = frame.top + maxHeight;
}
// get_volume_info
bool
get_volume_info( BVolume& volume, BString& volumeName, bool& isCDROM, BString& deviceName )
{
bool success = false;
isCDROM = false;
deviceName = "";
volumeName = "";
char name[B_FILE_NAME_LENGTH];
if ( volume.GetName( name ) >= B_OK ) // disk is currently mounted
{
volumeName = name;
dev_t dev = volume.Device();
fs_info info;
if ( fs_stat_dev( dev, &info ) == B_OK )
{
success = true;
deviceName = info.device_name;
if ( volume.IsReadOnly() )
{
int i_dev = open( info.device_name, O_RDONLY );
if ( i_dev >= 0 )
{
device_geometry g;
if ( ioctl( i_dev, B_GET_GEOMETRY, &g, sizeof( g ) ) >= 0 )
isCDROM = ( g.device_type == B_CD );
close( i_dev );
}
}
}
}
return success;
}
// collect_folder_contents
void
collect_folder_contents( BDirectory& dir, BList& list, bool& deep, bool& asked, BEntry& entry )
{
while ( dir.GetNextEntry( &entry, true ) == B_OK )
{
if ( !entry.IsDirectory() )
{
BPath path;
// since the directory will give us the entries in reverse order,
// we put them each at the same index, effectively reversing the
// items while adding them
if ( entry.GetPath( &path ) == B_OK )
{
BString* string = new BString( path.Path() );
if ( !list.AddItem( string, 0 ) )
delete string; // at least don't leak
}
}
else
{
if ( !asked )
{
// ask user if we should parse sub-folders as well
BAlert* alert = new BAlert( "sub-folders?",
_("Open files from all sub-folders as well?"),
_("Cancel"), _("Open"), NULL, B_WIDTH_AS_USUAL,
B_IDEA_ALERT );
int32 buttonIndex = alert->Go();
deep = buttonIndex == 1;
asked = true;
// never delete BAlerts!!
}
if ( deep )
{
BDirectory subDir( &entry );
if ( subDir.InitCheck() == B_OK )
collect_folder_contents( subDir, list,
deep, asked, entry );
}
}
}
}
static int PlaylistChanged( vlc_object_t *p_this, const char * psz_variable,
vlc_value_t old_val, vlc_value_t new_val,
void * param )
{
InterfaceWindow * w = (InterfaceWindow *) param;
w->UpdatePlaylist();
return VLC_SUCCESS;
}
/*****************************************************************************
* InterfaceWindow
*****************************************************************************/
InterfaceWindow::InterfaceWindow( intf_thread_t * _p_intf, BRect frame,
const char * name )
: BWindow( frame, name, B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS ),
/* Initializations */
p_intf( _p_intf ),
p_input( NULL ),
p_playlist( NULL ),
fFilePanel( NULL ),
fLastUpdateTime( system_time() ),
fSettings( new BMessage( 'sett' ) )
{
p_playlist = pl_Hold( p_intf );
var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
var_AddCallback( p_playlist, "item-change", PlaylistChanged, this );
var_AddCallback( p_playlist, "playlist-item-append", PlaylistChanged, this );
var_AddCallback( p_playlist, "playlist-item-deleted", PlaylistChanged, this );
var_AddCallback( p_playlist, "item-current", PlaylistChanged, this );
char psz_tmp[1024];
#define ADD_ELLIPSIS( a ) \
memset( psz_tmp, 0, 1024 ); \
snprintf( psz_tmp, 1024, "%s%s", a, B_UTF8_ELLIPSIS );
BScreen screen;
BRect screen_rect = screen.Frame();
BRect window_rect;
window_rect.Set( ( screen_rect.right - PREFS_WINDOW_WIDTH ) / 2,
( screen_rect.bottom - PREFS_WINDOW_HEIGHT ) / 2,
( screen_rect.right + PREFS_WINDOW_WIDTH ) / 2,
( screen_rect.bottom + PREFS_WINDOW_HEIGHT ) / 2 );
fPreferencesWindow = new PreferencesWindow( p_intf, window_rect, _("Preferences") );
window_rect.Set( screen_rect.right - 500,
screen_rect.top + 50,
screen_rect.right - 150,
screen_rect.top + 250 );
#if 0
fPlaylistWindow = new PlayListWindow( window_rect, _("Playlist"), this, p_intf );
window_rect.Set( screen_rect.right - 550,
screen_rect.top + 300,
screen_rect.right - 150,
screen_rect.top + 500 );
#endif
fMessagesWindow = new MessagesWindow( p_intf, window_rect, _("Messages") );
// the media control view
p_mediaControl = new MediaControlView( p_intf, BRect( 0.0, 0.0, 250.0, 50.0 ) );
p_mediaControl->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
float width, height;
p_mediaControl->GetPreferredSize( &width, &height );
// set up the main menu
fMenuBar = new BMenuBar( BRect(0.0, 0.0, width, 15.0), "main menu",
B_FOLLOW_NONE, B_ITEMS_IN_ROW, false );
// make menu bar resize to correct height
float menuWidth, menuHeight;
fMenuBar->GetPreferredSize( &menuWidth, &menuHeight );
fMenuBar->ResizeTo( width, menuHeight ); // don't change! it's a workarround!
// take care of proper size for ourself
height += fMenuBar->Bounds().Height();
ResizeTo( width, height );
p_mediaControl->MoveTo( fMenuBar->Bounds().LeftBottom() + BPoint(0.0, 1.0) );
AddChild( fMenuBar );
// Add the file Menu
BMenu* fileMenu = new BMenu( _("File") );
fMenuBar->AddItem( fileMenu );
ADD_ELLIPSIS( _("Open File") );
fileMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_FILE ), 'O') );
fileMenu->AddItem( new CDMenu( _("Open Disc") ) );
ADD_ELLIPSIS( _("Open Subtitles") );
fileMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( LOAD_SUBFILE ) ) );
fileMenu->AddSeparatorItem();
ADD_ELLIPSIS( _("About") );
BMenuItem* item = new BMenuItem( psz_tmp, new BMessage( B_ABOUT_REQUESTED ), 'A');
item->SetTarget( be_app );
fileMenu->AddItem( item );
fileMenu->AddItem( new BMenuItem( _("Quit"), new BMessage( B_QUIT_REQUESTED ), 'Q') );
fLanguageMenu = new LanguageMenu( p_intf, _("Language"), "audio-es" );
fSubtitlesMenu = new LanguageMenu( p_intf, _("Subtitles"), "spu-es" );
/* Add the Audio menu */
fAudioMenu = new BMenu( _("Audio") );
fMenuBar->AddItem ( fAudioMenu );
fAudioMenu->AddItem( fLanguageMenu );
fAudioMenu->AddItem( fSubtitlesMenu );
fPrevTitleMI = new BMenuItem( _("Prev Title"), new BMessage( PREV_TITLE ) );
fNextTitleMI = new BMenuItem( _("Next Title"), new BMessage( NEXT_TITLE ) );
fPrevChapterMI = new BMenuItem( _("Previous chapter"), new BMessage( PREV_CHAPTER ) );
fNextChapterMI = new BMenuItem( _("Next chapter"), new BMessage( NEXT_CHAPTER ) );
/* Add the Navigation menu */
fNavigationMenu = new BMenu( _("Navigation") );
fMenuBar->AddItem( fNavigationMenu );
fNavigationMenu->AddItem( fPrevTitleMI );
fNavigationMenu->AddItem( fNextTitleMI );
fNavigationMenu->AddItem( fTitleMenu = new TitleMenu( _("Go to Title"), p_intf ) );
fNavigationMenu->AddSeparatorItem();
fNavigationMenu->AddItem( fPrevChapterMI );
fNavigationMenu->AddItem( fNextChapterMI );
fNavigationMenu->AddItem( fChapterMenu = new ChapterMenu( _("Go to Chapter"), p_intf ) );
/* Add the Speed menu */
fSpeedMenu = new BMenu( _("Speed") );
fSpeedMenu->SetRadioMode( true );
fSpeedMenu->AddItem(
fHeighthMI = new BMenuItem( "1/8x", new BMessage( HEIGHTH_PLAY ) ) );
fSpeedMenu->AddItem(
fQuarterMI = new BMenuItem( "1/4x", new BMessage( QUARTER_PLAY ) ) );
fSpeedMenu->AddItem(
fHalfMI = new BMenuItem( "1/2x", new BMessage( HALF_PLAY ) ) );
fSpeedMenu->AddItem(
fNormalMI = new BMenuItem( "1x", new BMessage( NORMAL_PLAY ) ) );
fSpeedMenu->AddItem(
fTwiceMI = new BMenuItem( "2x", new BMessage( TWICE_PLAY ) ) );
fSpeedMenu->AddItem(
fFourMI = new BMenuItem( "4x", new BMessage( FOUR_PLAY ) ) );
fSpeedMenu->AddItem(
fHeightMI = new BMenuItem( "8x", new BMessage( HEIGHT_PLAY ) ) );
fMenuBar->AddItem( fSpeedMenu );
/* Add the Show menu */
fShowMenu = new BMenu( _("Window") );
#if 0
ADD_ELLIPSIS( _("Playlist") );
fShowMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_PLAYLIST ), 'P') );
#endif
ADD_ELLIPSIS( _("Messages") );
fShowMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_MESSAGES ), 'M' ) );
ADD_ELLIPSIS( _("Preferences") );
fShowMenu->AddItem( new BMenuItem( psz_tmp, new BMessage( OPEN_PREFERENCES ), 'S' ) );
fMenuBar->AddItem( fShowMenu );
// add the media control view after the menubar is complete
// because it will set the window size limits in AttachedToWindow()
// and the menubar needs to report the correct PreferredSize()
AddChild( p_mediaControl );
/* Prepare fow showing */
_SetMenusEnabled( false );
p_mediaControl->SetEnabled( false );
_RestoreSettings();
Show();
}
InterfaceWindow::~InterfaceWindow()
{
if( p_input )
{
vlc_object_release( p_input );
}
if( p_playlist )
{
vlc_object_release( p_playlist );
}
#if 0
if( fPlaylistWindow )
{
fPlaylistWindow->ReallyQuit();
}
#endif
if( fMessagesWindow )
{
fMessagesWindow->ReallyQuit();
}
if( fPreferencesWindow )
{
fPreferencesWindow->ReallyQuit();
}
delete fFilePanel;
delete fSettings;
}
/*****************************************************************************
* InterfaceWindow::FrameResized
*****************************************************************************/
void
InterfaceWindow::FrameResized(float width, float height)
{
BRect r(Bounds());
fMenuBar->MoveTo(r.LeftTop());
fMenuBar->ResizeTo(r.Width(), fMenuBar->Bounds().Height());
r.top += fMenuBar->Bounds().Height() + 1.0;
p_mediaControl->MoveTo(r.LeftTop());
p_mediaControl->ResizeTo(r.Width(), r.Height());
}
/*****************************************************************************
* InterfaceWindow::MessageReceived
*****************************************************************************/
void InterfaceWindow::MessageReceived( BMessage * p_message )
{
switch( p_message->what )
{
case B_ABOUT_REQUESTED:
{
BAlert * alert;
alert = new BAlert( "VLC media player" VERSION,
"VLC media player" VERSION " (BeOS interface)\n\n"
"The VideoLAN team <videolan@videolan.org>\n"
"http://www.videolan.org/", _("OK") );
alert->Go();
break;
}
case TOGGLE_ON_TOP:
break;
case OPEN_FILE:
_ShowFilePanel( B_REFS_RECEIVED, _("VLC media player: Open Media Files") );
break;
case LOAD_SUBFILE:
_ShowFilePanel( SUBFILE_RECEIVED, _("VLC media player: Open Subtitle File") );
break;
#if 0
case OPEN_PLAYLIST:
if (fPlaylistWindow->Lock())
{
if (fPlaylistWindow->IsHidden())
fPlaylistWindow->Show();
else
fPlaylistWindow->Activate();
fPlaylistWindow->Unlock();
}
break;
#endif
case OPEN_DVD:
{
const char * psz_device;
if( p_playlist &&
p_message->FindString( "device", &psz_device ) == B_OK )
{
char psz_uri[1024];
memset( psz_uri, 0, 1024 );
snprintf( psz_uri, 1024, "dvdnav:%s", psz_device );
playlist_Add( p_playlist, psz_uri, psz_device,
PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END, true );
}
UpdatePlaylist();
}
break;
case SUBFILE_RECEIVED:
{
entry_ref ref;
if( p_message->FindRef( "refs", 0, &ref ) == B_OK )
{
BPath path( &ref );
if ( path.InitCheck() == B_OK )
config_PutPsz( p_intf, "sub-file", path.Path() );
}
break;
}
case STOP_PLAYBACK:
if( p_playlist )
{
playlist_Stop( p_playlist );
}
p_mediaControl->SetStatus(-1, INPUT_RATE_DEFAULT);
break;
case START_PLAYBACK:
case PAUSE_PLAYBACK:
{
vlc_value_t val;
val.i_int = PLAYING_S;
if( p_input )
{
var_Get( p_input, "state", &val );
}
if( p_input && val.i_int != PAUSE_S )
{
val.i_int = PAUSE_S;
var_Set( p_input, "state", val );
}
else
{
playlist_Play( p_playlist );
}
break;
}
case HEIGHTH_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", .125 );
}
break;
case QUARTER_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", .25 );
}
break;
case HALF_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", .5 );
}
break;
case NORMAL_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", 1. );
}
break;
case TWICE_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", 2. );
}
break;
case FOUR_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", 4. );
}
break;
case HEIGHT_PLAY:
if( p_input )
{
var_SetFloat( p_input, "rate", 8. );
}
break;
case SEEK_PLAYBACK:
/* handled by semaphores */
break;
case VOLUME_CHG:
aout_VolumeSet( p_intf, p_mediaControl->GetVolume() );
break;
case VOLUME_MUTE:
aout_ToggleMute( p_intf, NULL );
break;
case SELECT_CHANNEL:
{
int32 channel;
if( p_input )
{
if( p_message->FindInt32( "audio-es", &channel ) == B_OK )
{
var_SetInteger( p_input, "audio-es", channel );
}
else if( p_message->FindInt32( "spu-es", &channel ) == B_OK )
{
var_SetInteger( p_input, "spu-es", channel );
}
}
break;
}
case PREV_TITLE:
if( p_input )
{
var_TriggerCallback( p_input, "prev-title" );
}
break;
case NEXT_TITLE:
if( p_input )
{
var_TriggerCallback( p_input, "next-title" );
}
break;
case TOGGLE_TITLE:
{
int32 index;
if( p_input &&
p_message->FindInt32( "index", &index ) == B_OK )
{
var_SetInteger( p_input, "title", index );
}
break;
}
case PREV_CHAPTER:
if( p_input )
{
var_TriggerCallback( p_input, "prev-chapter" );
}
break;
case NEXT_CHAPTER:
if( p_input )
{
var_TriggerCallback( p_input, "next-chapter" );
}
break;
case TOGGLE_CHAPTER:
{
int32 index;
if( p_input &&
p_message->FindInt32( "index", &index ) == B_OK )
{
var_SetInteger( p_input, "chapter", index );
}
break;
}
case PREV_FILE:
if( p_playlist )
{
playlist_Prev( p_playlist );
}
break;
case NEXT_FILE:
if( p_playlist )
{
playlist_Next( p_playlist );
}
break;
case NAVIGATE_PREV:
if( p_input )
{
vlc_value_t val;
/* First try to go to previous chapter */
if( !var_Get( p_input, "chapter", &val ) )
{
if( val.i_int > 1 )
{
var_TriggerCallback( p_input, "prev-chapter" );
break;
}
}
/* Try to go to previous title */
if( !var_Get( p_input, "title", &val ) )
{
if( val.i_int > 1 )
{
var_TriggerCallback( p_input, "prev-title" );
break;
}
}
/* Try to go to previous file */
if( p_playlist )
{
playlist_Prev( p_playlist );
}
}
break;
case NAVIGATE_NEXT:
if( p_input )
{
/* First try to go to next chapter */
if( !var_Get( p_input, "chapter", &val ) )
{
int i_chapter_count = var_CountChoices( p_input, "chapter" );
if( i_chapter_count > val.i_int )
{
var_TriggerCallback( p_input, "next-chapter" );
break;
}
}
/* Try to go to next title */
if( !var_Get( p_input, "title", &val ) )
{
int i_title_count = var_CountChoices( p_input, "title" );
if( i_title_count > val.i_int )
{
var_TriggerCallback( p_input, "next-title" );
break;
}
}
/* Try to go to next file */
if( p_playlist )
{
playlist_Next( p_playlist );
}
}
break;
// drag'n'drop and system messages
case MSG_SOUNDPLAY:
// convert soundplay drag'n'drop message (containing paths)
// to normal message (containing refs)
{
const char* path;
for ( int32 i = 0; p_message->FindString( "path", i, &path ) == B_OK; i++ )
{
entry_ref ref;
if ( get_ref_for_path( path, &ref ) == B_OK )
p_message->AddRef( "refs", &ref );
}
}
// fall through
case B_REFS_RECEIVED:
case B_SIMPLE_DATA:
{
/* file(s) opened by the File menu -> append to the playlist;
file(s) opened by drag & drop -> replace playlist;
file(s) opened by 'shift' + drag & drop -> append */
int32 count;
type_code dummy;
if( p_message->GetInfo( "refs", &dummy, &count ) != B_OK ||
count < 1 )
{
break;
}
bool b_remove = ( p_message->WasDropped() &&
!( modifiers() & B_SHIFT_KEY ) );
if( b_remove && p_playlist )
{
playlist_Clear( p_playlist, true );
}
entry_ref ref;
for( int i = 0; p_message->FindRef( "refs", i, &ref ) == B_OK; i++ )
{
BPath path( &ref );
/* TODO: find out if this is a DVD icon */
if( p_playlist )
{
playlist_Add( p_playlist, path.Path(), NULL,
PLAYLIST_APPEND | PLAYLIST_GO, PLAYLIST_END, true );
}
}
UpdatePlaylist();
break;
}
case OPEN_PREFERENCES:
{
if( fPreferencesWindow->Lock() )
{
if (fPreferencesWindow->IsHidden())
fPreferencesWindow->Show();
else
fPreferencesWindow->Activate();
fPreferencesWindow->Unlock();
}
break;
}
case OPEN_MESSAGES:
{
if( fMessagesWindow->Lock() )
{
if (fMessagesWindow->IsHidden())
fMessagesWindow->Show();
else
fMessagesWindow->Activate();
fMessagesWindow->Unlock();
}
break;
}
case MSG_UPDATE:
UpdateInterface();
break;
default:
BWindow::MessageReceived( p_message );
break;
}
}
/*****************************************************************************
* InterfaceWindow::QuitRequested
*****************************************************************************/
bool InterfaceWindow::QuitRequested()
{
if( p_playlist )
{
playlist_Stop( p_playlist );
}
p_mediaControl->SetStatus(-1, INPUT_RATE_DEFAULT);
_StoreSettings();
vlc_object_kill( p_intf );
return( true );
}
/*****************************************************************************
* InterfaceWindow::UpdateInterface
*****************************************************************************/
void InterfaceWindow::UpdateInterface()
{
if( !p_input )
{
p_input = (input_thread_t *)
vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
}
else if( p_input->b_dead )
{
vlc_object_release( p_input );
p_input = NULL;
}
/* Get ready to update the interface */
if( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) != B_OK )
{
return;
}
if( b_playlist_update )
{
#if 0
if( fPlaylistWindow->Lock() )
{
fPlaylistWindow->UpdatePlaylist( true );
fPlaylistWindow->Unlock();
b_playlist_update = false;
}
#endif
p_mediaControl->SetEnabled( !playlist_IsEmpty( p_playlist ) );
}
if( p_input )
{
vlc_value_t val;
p_mediaControl->SetEnabled( true );
bool hasTitles = !var_Get( p_input, "title", &val );
bool hasChapters = !var_Get( p_input, "chapter", &val );
p_mediaControl->SetStatus( INPUT_RATE_DEFAULT / var_GetFloat( p_input, "state" ),
INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" ) );
var_Get( p_input, "position", &val );
p_mediaControl->SetProgress( val.f_float );
_SetMenusEnabled( true, hasChapters, hasTitles );
_UpdateSpeedMenu( INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" ) );
// enable/disable skip buttons
#if 0
bool canSkipPrev;
bool canSkipNext;
p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
#endif
audio_volume_t i_volume;
aout_VolumeGet( p_intf, &i_volume );
p_mediaControl->SetAudioEnabled( true );
p_mediaControl->SetMuted( i_volume );
}
else
{
p_mediaControl->SetAudioEnabled( false );
_SetMenusEnabled( false );
if( !playlist_IsEmpty( p_playlist ) )
{
p_mediaControl->SetProgress( 0 );
#if 0
// enable/disable skip buttons
bool canSkipPrev;
bool canSkipNext;
p_wrapper->GetNavCapabilities( &canSkipPrev, &canSkipNext );
p_mediaControl->SetSkippable( canSkipPrev, canSkipNext );
#endif
}
else
{
p_mediaControl->SetEnabled( false );
}
}
Unlock();
fLastUpdateTime = system_time();
}
/*****************************************************************************
* InterfaceWindow::UpdatePlaylist
*****************************************************************************/
void
InterfaceWindow::UpdatePlaylist()
{
b_playlist_update = true;
}
/*****************************************************************************
* InterfaceWindow::IsStopped
*****************************************************************************/
bool
InterfaceWindow::IsStopped() const
{
return (system_time() - fLastUpdateTime > INTERFACE_UPDATE_TIMEOUT);
}
/*****************************************************************************
* InterfaceWindow::_SetMenusEnabled
*****************************************************************************/
void
InterfaceWindow::_SetMenusEnabled(bool hasFile, bool hasChapters, bool hasTitles)
{
if (!hasFile)
{
hasChapters = false;
hasTitles = false;
}
if ( LockWithTimeout( INTERFACE_LOCKING_TIMEOUT ) == B_OK)
{
if ( fNextChapterMI->IsEnabled() != hasChapters )
fNextChapterMI->SetEnabled( hasChapters );
if ( fPrevChapterMI->IsEnabled() != hasChapters )
fPrevChapterMI->SetEnabled( hasChapters );
if ( fChapterMenu->IsEnabled() != hasChapters )
fChapterMenu->SetEnabled( hasChapters );
if ( fNextTitleMI->IsEnabled() != hasTitles )
fNextTitleMI->SetEnabled( hasTitles );
if ( fPrevTitleMI->IsEnabled() != hasTitles )
fPrevTitleMI->SetEnabled( hasTitles );
if ( fTitleMenu->IsEnabled() != hasTitles )
fTitleMenu->SetEnabled( hasTitles );
if ( fAudioMenu->IsEnabled() != hasFile )
fAudioMenu->SetEnabled( hasFile );
if ( fNavigationMenu->IsEnabled() != hasFile )
fNavigationMenu->SetEnabled( hasFile );
if ( fLanguageMenu->IsEnabled() != hasFile )
fLanguageMenu->SetEnabled( hasFile );
if ( fSubtitlesMenu->IsEnabled() != hasFile )
fSubtitlesMenu->SetEnabled( hasFile );
if ( fSpeedMenu->IsEnabled() != hasFile )
fSpeedMenu->SetEnabled( hasFile );
Unlock();
}
}
/*****************************************************************************
* InterfaceWindow::_UpdateSpeedMenu
*****************************************************************************/
void
InterfaceWindow::_UpdateSpeedMenu( int rate )
{
BMenuItem * toMark = NULL;
switch( rate )
{
case ( INPUT_RATE_DEFAULT * 8 ):
toMark = fHeighthMI;
break;
case ( INPUT_RATE_DEFAULT * 4 ):
toMark = fQuarterMI;
break;
case ( INPUT_RATE_DEFAULT * 2 ):
toMark = fHalfMI;
break;
case ( INPUT_RATE_DEFAULT ):
toMark = fNormalMI;
break;
case ( INPUT_RATE_DEFAULT / 2 ):
toMark = fTwiceMI;
break;
case ( INPUT_RATE_DEFAULT / 4 ):
toMark = fFourMI;
break;
case ( INPUT_RATE_DEFAULT / 8 ):
toMark = fHeightMI;
break;
}
if ( toMark && !toMark->IsMarked() )
{
toMark->SetMarked( true );
}
}
/*****************************************************************************
* InterfaceWindow::_ShowFilePanel
*****************************************************************************/
void
InterfaceWindow::_ShowFilePanel( uint32 command, const char* windowTitle )
{
if( !fFilePanel )
{
fFilePanel = new BFilePanel( B_OPEN_PANEL, NULL, NULL,
B_FILE_NODE | B_DIRECTORY_NODE );
fFilePanel->SetTarget( this );
}
fFilePanel->Window()->SetTitle( windowTitle );
BMessage message( command );
fFilePanel->SetMessage( &message );
if ( !fFilePanel->IsShowing() )
{
fFilePanel->Refresh();
fFilePanel->Show();
}
}
// set_window_pos
void
set_window_pos( BWindow* window, BRect frame )
{
// sanity checks: make sure window is not too big/small
// and that it's not off-screen
float minWidth, maxWidth, minHeight, maxHeight;
window->GetSizeLimits( &minWidth, &maxWidth, &minHeight, &maxHeight );
make_sure_frame_is_within_limits( frame,
minWidth, minHeight, maxWidth, maxHeight );
if ( make_sure_frame_is_on_screen( frame ) )
{
window->MoveTo( frame.LeftTop() );
window->ResizeTo( frame.Width(), frame.Height() );
}
}
// set_window_pos
void
launch_window( BWindow* window, bool showing )
{
if ( window->Lock() )
{
if ( showing )
{
if ( window->IsHidden() )
window->Show();
}
else
{
if ( !window->IsHidden() )
window->Hide();
}
window->Unlock();
}
}
/*****************************************************************************
* InterfaceWindow::_RestoreSettings
*****************************************************************************/
void
InterfaceWindow::_RestoreSettings()
{
if ( load_settings( fSettings, "interface_settings", "VideoLAN Client" ) == B_OK )
{
BRect frame;
if ( fSettings->FindRect( "main frame", &frame ) == B_OK )
set_window_pos( this, frame );
#if 0
if (fSettings->FindRect( "playlist frame", &frame ) == B_OK )
set_window_pos( fPlaylistWindow, frame );
#endif
if (fSettings->FindRect( "messages frame", &frame ) == B_OK )
set_window_pos( fMessagesWindow, frame );
if (fSettings->FindRect( "settings frame", &frame ) == B_OK )
{
/* FIXME: Preferences resizing doesn't work correctly yet */
frame.right = frame.left + fPreferencesWindow->Frame().Width();
frame.bottom = frame.top + fPreferencesWindow->Frame().Height();
set_window_pos( fPreferencesWindow, frame );
}
bool showing;
#if 0
if ( fSettings->FindBool( "playlist showing", &showing ) == B_OK )
launch_window( fPlaylistWindow, showing );
#endif
if ( fSettings->FindBool( "messages showing", &showing ) == B_OK )
launch_window( fMessagesWindow, showing );
if ( fSettings->FindBool( "settings showing", &showing ) == B_OK )
launch_window( fPreferencesWindow, showing );
#if 0
uint32 displayMode;
if ( fSettings->FindInt32( "playlist display mode", (int32*)&displayMode ) == B_OK )
fPlaylistWindow->SetDisplayMode( displayMode );
#endif
}
}
/*****************************************************************************
* InterfaceWindow::_StoreSettings
*****************************************************************************/
void
InterfaceWindow::_StoreSettings()
{
/* Save the volume */
config_PutInt( p_intf, "volume", p_mediaControl->GetVolume() );
/* Save the windows positions */
if ( fSettings->ReplaceRect( "main frame", Frame() ) != B_OK )
fSettings->AddRect( "main frame", Frame() );
#if 0
if ( fPlaylistWindow->Lock() )
{
if (fSettings->ReplaceRect( "playlist frame", fPlaylistWindow->Frame() ) != B_OK)
fSettings->AddRect( "playlist frame", fPlaylistWindow->Frame() );
if (fSettings->ReplaceBool( "playlist showing", !fPlaylistWindow->IsHidden() ) != B_OK)
fSettings->AddBool( "playlist showing", !fPlaylistWindow->IsHidden() );
fPlaylistWindow->Unlock();
}
#endif
if ( fMessagesWindow->Lock() )
{
if (fSettings->ReplaceRect( "messages frame", fMessagesWindow->Frame() ) != B_OK)
fSettings->AddRect( "messages frame", fMessagesWindow->Frame() );
if (fSettings->ReplaceBool( "messages showing", !fMessagesWindow->IsHidden() ) != B_OK)
fSettings->AddBool( "messages showing", !fMessagesWindow->IsHidden() );
fMessagesWindow->Unlock();
}
if ( fPreferencesWindow->Lock() )
{
if (fSettings->ReplaceRect( "settings frame", fPreferencesWindow->Frame() ) != B_OK)
fSettings->AddRect( "settings frame", fPreferencesWindow->Frame() );
if (fSettings->ReplaceBool( "settings showing", !fPreferencesWindow->IsHidden() ) != B_OK)
fSettings->AddBool( "settings showing", !fPreferencesWindow->IsHidden() );
fPreferencesWindow->Unlock();
}
#if 0
uint32 displayMode = fPlaylistWindow->DisplayMode();
if (fSettings->ReplaceInt32( "playlist display mode", displayMode ) != B_OK )
fSettings->AddInt32( "playlist display mode", displayMode );
#endif
save_settings( fSettings, "interface_settings", "VideoLAN Client" );
}
/*****************************************************************************
* CDMenu::CDMenu
*****************************************************************************/
CDMenu::CDMenu(const char *name)
: BMenu(name)
{
}
/*****************************************************************************
* CDMenu::~CDMenu
*****************************************************************************/
CDMenu::~CDMenu()
{
}
/*****************************************************************************
* CDMenu::AttachedToWindow
*****************************************************************************/
void CDMenu::AttachedToWindow(void)
{
// remove all items
while ( BMenuItem* item = RemoveItem( 0L ) )
delete item;
GetCD( "/dev/disk" );
BMenu::AttachedToWindow();
}
/*****************************************************************************
* CDMenu::GetCD
*****************************************************************************/
int CDMenu::GetCD( const char *directory )
{
BVolumeRoster volRoster;
BVolume vol;
BDirectory dir;
status_t status = volRoster.GetNextVolume( &vol );
while ( status == B_NO_ERROR )
{
BString deviceName;
BString volumeName;
bool isCDROM;
if ( get_volume_info( vol, volumeName, isCDROM, deviceName )
&& isCDROM )
{
BMessage* msg = new BMessage( OPEN_DVD );
msg->AddString( "device", deviceName.String() );
BMenuItem* item = new BMenuItem( volumeName.String(), msg );
AddItem( item );
}
vol.Unset();
status = volRoster.GetNextVolume( &vol );
}
return 0;
}
/*****************************************************************************
* LanguageMenu::LanguageMenu
*****************************************************************************/
LanguageMenu::LanguageMenu( intf_thread_t * _p_intf, const char * psz_name,
char * _psz_variable )
: BMenu( psz_name )
{
p_intf = _p_intf;
psz_variable = strdup( _psz_variable );
}
/*****************************************************************************
* LanguageMenu::~LanguageMenu
*****************************************************************************/
LanguageMenu::~LanguageMenu()
{
free( psz_variable );
}
/*****************************************************************************
* LanguageMenu::AttachedToWindow
*****************************************************************************/
void LanguageMenu::AttachedToWindow()
{
BMenuItem * item;
// remove all items
while( ( item = RemoveItem( 0L ) ) )
{
delete item;
}
SetRadioMode( true );
input_thread_t * p_input = (input_thread_t *)
vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
if( !p_input )
{
return;
}
vlc_value_t val_list, text_list;
BMessage * message;
int i_current;
i_current = var_GetInteger( p_input, psz_variable );
var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list );
for( int i = 0; i < val_list.p_list->i_count; i++ )
{
message = new BMessage( SELECT_CHANNEL );
message->AddInt32( psz_variable, val_list.p_list->p_values[i].i_int );
item = new BMenuItem( text_list.p_list->p_values[i].psz_string, message );
if( val_list.p_list->p_values[i].i_int == i_current )
{
item->SetMarked( true );
}
AddItem( item );
}
var_FreeList( &val_list, &text_list );
vlc_object_release( p_input );
BMenu::AttachedToWindow();
}
/*****************************************************************************
* TitleMenu::TitleMenu
*****************************************************************************/
TitleMenu::TitleMenu( const char *name, intf_thread_t *p_interface )
: BMenu(name),
p_intf( p_interface )
{
}
/*****************************************************************************
* TitleMenu::~TitleMenu
*****************************************************************************/
TitleMenu::~TitleMenu()
{
}
/*****************************************************************************
* TitleMenu::AttachedToWindow
*****************************************************************************/
void TitleMenu::AttachedToWindow()
{
BMenuItem * item;
while( ( item = RemoveItem( 0L ) ) )
{
delete item;
}
input_thread_t * p_input;
p_input = (input_thread_t *)
vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
if( !p_input )
{
return;
}
vlc_value_t val;
BMessage * message;
if( !var_Get( p_input, "title", &val ) )
{
vlc_value_t val_list, text_list;
var_Change( p_input, "title", VLC_VAR_GETCHOICES,
&val_list, &text_list );
for( int i = 0; i < val_list.p_list->i_count; i++ )
{
message = new BMessage( TOGGLE_TITLE );
message->AddInt32( "index", val_list.p_list->p_values[i].i_int );
item = new BMenuItem( text_list.p_list->p_values[i].psz_string,
message );
if( val_list.p_list->p_values[i].i_int == val.i_int )
{
item->SetMarked( true );
}
AddItem( item );
}
var_FreeList( &val_list, &text_list );
}
vlc_object_release( p_input );
BMenu::AttachedToWindow();
}
/*****************************************************************************
* ChapterMenu::ChapterMenu
*****************************************************************************/
ChapterMenu::ChapterMenu( const char *name, intf_thread_t *p_interface )
: BMenu(name),
p_intf( p_interface )
{
}
/*****************************************************************************
* ChapterMenu::~ChapterMenu
*****************************************************************************/
ChapterMenu::~ChapterMenu()
{
}
/*****************************************************************************
* ChapterMenu::AttachedToWindow
*****************************************************************************/
void ChapterMenu::AttachedToWindow()
{
BMenuItem * item;
while( ( item = RemoveItem( 0L ) ) )
{
delete item;
}
input_thread_t * p_input;
p_input = (input_thread_t *)
vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
if( !p_input )
{
return;
}
vlc_value_t val;
BMessage * message;
if( !var_Get( p_input, "chapter", &val ) )
{
vlc_value_t val_list, text_list;
var_Change( p_input, "chapter", VLC_VAR_GETCHOICES,
&val_list, &text_list );
for( int i = 0; i < val_list.p_list->i_count; i++ )
{
message = new BMessage( TOGGLE_CHAPTER );
message->AddInt32( "index", val_list.p_list->p_values[i].i_int );
item = new BMenuItem( text_list.p_list->p_values[i].psz_string,
message );
if( val_list.p_list->p_values[i].i_int == val.i_int )
{
item->SetMarked( true );
}
AddItem( item );
}
var_FreeList( &val_list, &text_list );
}
vlc_object_release( p_input );
BMenu::AttachedToWindow();
}
/*****************************************************************************
* load_settings
*****************************************************************************/
status_t
load_settings( BMessage* message, const char* fileName, const char* folder )
{
status_t ret = B_BAD_VALUE;
if ( message )
{
BPath path;
if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
{
// passing folder is optional
if ( folder )
ret = path.Append( folder );
if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
{
BFile file( path.Path(), B_READ_ONLY );
if ( ( ret = file.InitCheck() ) == B_OK )
{
ret = message->Unflatten( &file );
file.Unset();
}
}
}
}
return ret;
}
/*****************************************************************************
* save_settings
*****************************************************************************/
status_t
save_settings( BMessage* message, const char* fileName, const char* folder )
{
status_t ret = B_BAD_VALUE;
if ( message )
{
BPath path;
if ( ( ret = find_directory( B_USER_SETTINGS_DIRECTORY, &path ) ) == B_OK )
{
// passing folder is optional
if ( folder && ( ret = path.Append( folder ) ) == B_OK )
ret = create_directory( path.Path(), 0777 );
if ( ret == B_OK && ( ret = path.Append( fileName ) ) == B_OK )
{
BFile file( path.Path(), B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );
if ( ( ret = file.InitCheck() ) == B_OK )
{
ret = message->Flatten( &file );
file.Unset();
}
}
}
}
return ret;
}
/*****************************************************************************
* InterfaceWindow.h: BeOS interface window class prototype
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Tony Castley <tcastley@mail.powerup.com.au>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#ifndef BEOS_INTERFACE_WINDOW_H
#define BEOS_INTERFACE_WINDOW_H
#include <Menu.h>
#include <Window.h>
class BMenuBar;
class MediaControlView;
#if 0
class PlayListWindow;
#endif
class BFilePanel;
class PreferencesWindow;
class MessagesWindow;
class CDMenu : public BMenu
{
public:
CDMenu( const char* name );
virtual ~CDMenu();
virtual void AttachedToWindow();
private:
int GetCD( const char* directory );
};
class LanguageMenu : public BMenu
{
public:
LanguageMenu( intf_thread_t * p_intf,
const char * psz_name,
char * psz_variable );
virtual ~LanguageMenu();
virtual void AttachedToWindow();
private:
intf_thread_t * p_intf;
char * psz_variable;
};
class TitleMenu : public BMenu
{
public:
TitleMenu( const char* name, intf_thread_t *p_interface );
virtual ~TitleMenu();
virtual void AttachedToWindow();
intf_thread_t *p_intf;
};
class ChapterMenu : public BMenu
{
public:
ChapterMenu( const char* name, intf_thread_t *p_interface );
virtual ~ChapterMenu();
virtual void AttachedToWindow();
intf_thread_t *p_intf;
};
class InterfaceWindow : public BWindow
{
public:
InterfaceWindow( intf_thread_t * p_intf,
BRect frame,
const char * name );
virtual ~InterfaceWindow();
// BWindow
virtual void FrameResized( float width, float height );
virtual void MessageReceived( BMessage* message );
virtual bool QuitRequested();
// InterfaceWindow
void UpdateInterface();
void UpdatePlaylist();
bool IsStopped() const;
MediaControlView* p_mediaControl;
MessagesWindow* fMessagesWindow;
private:
void _SetMenusEnabled( bool hasFile,
bool hasChapters = false,
bool hasTitles = false );
void _UpdateSpeedMenu( int rate );
void _ShowFilePanel( uint32 command,
const char* windowTitle );
void _RestoreSettings();
void _StoreSettings();
intf_thread_t * p_intf;
input_thread_t * p_input;
playlist_t * p_playlist;
es_descriptor_t * p_spu_es;
bool b_playlist_update;
BFilePanel* fFilePanel;
#if 0
PlayListWindow* fPlaylistWindow;
#endif
PreferencesWindow* fPreferencesWindow;
BMenuBar* fMenuBar;
BMenuItem* fGotoMenuMI;
BMenuItem* fNextTitleMI;
BMenuItem* fPrevTitleMI;
BMenuItem* fNextChapterMI;
BMenuItem* fPrevChapterMI;
BMenuItem* fOnTopMI;
BMenuItem* fHeighthMI;
BMenuItem* fQuarterMI;
BMenuItem* fHalfMI;
BMenuItem* fNormalMI;
BMenuItem* fTwiceMI;
BMenuItem* fFourMI;
BMenuItem* fHeightMI;
BMenu* fAudioMenu;
BMenu* fNavigationMenu;
BMenu* fTitleMenu;
BMenu* fChapterMenu;
BMenu* fLanguageMenu;
BMenu* fSubtitlesMenu;
BMenu* fSpeedMenu;
BMenu* fShowMenu;
bigtime_t fLastUpdateTime;
BMessage* fSettings; // we keep the message arround
// for forward compatibility
};
// some global support functions
status_t load_settings( BMessage* message,
const char* fileName,
const char* folder = NULL );
status_t save_settings( BMessage* message,
const char* fileName,
const char* folder = NULL );
#endif // BEOS_INTERFACE_WINDOW_H
/*****************************************************************************
* ListViews.h: BeOS interface list view class implementation
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#if 0
#include <malloc.h>
#include <Bitmap.h>
#include <Entry.h>
#include <String.h>
/* VLC headers */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
#include "InterfaceWindow.h"
#include "ListViews.h"
#include "MsgVals.h"
#define MAX_DRAG_HEIGHT 200.0
#define ALPHA 170
#define TEXT_OFFSET 20.0
/*****************************************************************************
* PlaylistItem class
*****************************************************************************/
PlaylistItem::PlaylistItem( const char *name )
: BStringItem( name ),
fName( "" )
{
entry_ref ref;
if ( get_ref_for_path( name, &ref) == B_OK )
fName.SetTo( ref.name );
}
PlaylistItem::~PlaylistItem()
{
}
/*****************************************************************************
* PlaylistItem::DrawItem
*****************************************************************************/
void
PlaylistItem::Draw( BView *owner, BRect frame, bool tintedLine,
uint32 mode, bool active, bool playing )
{
rgb_color color = (rgb_color){ 255, 255, 255, 255 };
if ( tintedLine )
color = tint_color( color, 1.04 );
// background
if ( IsSelected() )
color = tint_color( color, B_DARKEN_2_TINT );
owner->SetLowColor( color );
owner->FillRect( frame, B_SOLID_LOW );
// label
owner->SetHighColor( 0, 0, 0, 255 );
font_height fh;
owner->GetFontHeight( &fh );
const char* text = Text();
switch ( mode )
{
case DISPLAY_NAME:
if ( fName.CountChars() > 0 )
text = fName.String();
break;
case DISPLAY_PATH:
default:
break;
}
BString truncatedString( text );
owner->TruncateString( &truncatedString, B_TRUNCATE_MIDDLE,
frame.Width() - TEXT_OFFSET - 4.0 );
owner->DrawString( truncatedString.String(),
BPoint( frame.left + TEXT_OFFSET,
frame.top + fh.ascent + 1.0 ) );
// playmark
if ( active )
{
rgb_color black = (rgb_color){ 0, 0, 0, 255 };
rgb_color green = (rgb_color){ 0, 255, 0, 255 };
BRect r( 0.0, 0.0, 10.0, 10.0 );
r.OffsetTo( frame.left + 4.0,
ceilf( ( frame.top + frame.bottom ) / 2.0 ) - 5.0 );
if ( !playing )
green = tint_color( color, B_DARKEN_1_TINT );
rgb_color lightGreen = tint_color( green, B_LIGHTEN_2_TINT );
rgb_color darkGreen = tint_color( green, B_DARKEN_2_TINT );
BPoint arrow[3];
arrow[0] = r.LeftTop();
arrow[1] = r.LeftBottom();
arrow[2].x = r.right;
arrow[2].y = ( r.top + r.bottom ) / 2.0;
owner->BeginLineArray( 6 );
// black outline
owner->AddLine( arrow[0], arrow[1], black );
owner->AddLine( BPoint( arrow[1].x + 1.0, arrow[1].y - 1.0 ),
arrow[2], black );
owner->AddLine( arrow[0], arrow[2], black );
// inset arrow
arrow[0].x += 1.0;
arrow[0].y += 2.0;
arrow[1].x += 1.0;
arrow[1].y -= 2.0;
arrow[2].x -= 2.0;
// highlights and shadow
owner->AddLine( arrow[1], arrow[2], darkGreen );
owner->AddLine( arrow[0], arrow[2], lightGreen );
owner->AddLine( arrow[0], arrow[1], lightGreen );
owner->EndLineArray();
// fill green
arrow[0].x += 1.0;
arrow[0].y += 1.0;
arrow[1].x += 1.0;
arrow[1].y -= 1.0;
arrow[2].x -= 2.0;
owner->SetHighColor( green );
owner->FillPolygon( arrow, 3 );
}
}
/*****************************************************************************
* DragSortableListView class
*****************************************************************************/
DragSortableListView::DragSortableListView( BRect frame, const char* name,
list_view_type type, uint32 resizingMode,
uint32 flags )
: BListView( frame, name, type, resizingMode, flags ),
fDropRect( 0.0, 0.0, -1.0, -1.0 ),
fDropIndex( -1 )
{
SetViewColor( B_TRANSPARENT_32_BIT );
}
DragSortableListView::~DragSortableListView()
{
}
/*****************************************************************************
* DragSortableListView::Draw
*****************************************************************************/
void
DragSortableListView::Draw( BRect updateRect )
{
int32 firstIndex = IndexOf( updateRect.LeftTop() );
int32 lastIndex = IndexOf( updateRect.RightBottom() );
if ( firstIndex >= 0 )
{
if ( lastIndex < firstIndex )
lastIndex = CountItems() - 1;
// update rect contains items
BRect r( updateRect );
for ( int32 i = firstIndex; i <= lastIndex; i++)
{
r = ItemFrame( i );
DrawListItem( this, i, r );
}
updateRect.top = r.bottom + 1.0;
if ( updateRect.IsValid() )
{
SetLowColor( 255, 255, 255, 255 );
FillRect( updateRect, B_SOLID_LOW );
}
}
else
{
SetLowColor( 255, 255, 255, 255 );
FillRect( updateRect, B_SOLID_LOW );
}
// drop anticipation indication
if ( fDropRect.IsValid() )
{
SetHighColor( 255, 0, 0, 255 );
StrokeRect( fDropRect );
}
}
/*****************************************************************************
* DragSortableListView::InitiateDrag
*****************************************************************************/
bool
DragSortableListView::InitiateDrag( BPoint point, int32 index, bool )
{
bool success = false;
BListItem* item = ItemAt( CurrentSelection( 0 ) );
if ( !item )
{
// workarround a timing problem
Select( index );
item = ItemAt( index );
}
if ( item )
{
// create drag message
BMessage msg( B_SIMPLE_DATA );
MakeDragMessage( &msg );
// figure out drag rect
float width = Bounds().Width();
BRect dragRect(0.0, 0.0, width, -1.0);
// figure out, how many items fit into our bitmap
int32 numItems;
bool fade = false;
for (numItems = 0; BListItem* item = ItemAt( CurrentSelection( numItems ) ); numItems++) {
dragRect.bottom += ceilf( item->Height() ) + 1.0;
if ( dragRect.Height() > MAX_DRAG_HEIGHT ) {
fade = true;
dragRect.bottom = MAX_DRAG_HEIGHT;
numItems++;
break;
}
}
BBitmap* dragBitmap = new BBitmap( dragRect, B_RGB32, true );
if ( dragBitmap && dragBitmap->IsValid() ) {
if ( BView *v = new BView( dragBitmap->Bounds(), "helper", B_FOLLOW_NONE, B_WILL_DRAW ) ) {
dragBitmap->AddChild( v );
dragBitmap->Lock();
BRect itemBounds( dragRect) ;
itemBounds.bottom = 0.0;
// let all selected items, that fit into our drag_bitmap, draw
for ( int32 i = 0; i < numItems; i++ ) {
int32 index = CurrentSelection( i );
BListItem* item = ItemAt( index );
itemBounds.bottom = itemBounds.top + ceilf( item->Height() );
if ( itemBounds.bottom > dragRect.bottom )
itemBounds.bottom = dragRect.bottom;
DrawListItem( v, index, itemBounds );
itemBounds.top = itemBounds.bottom + 1.0;
}
// make a black frame arround the edge
v->SetHighColor( 0, 0, 0, 255 );
v->StrokeRect( v->Bounds() );
v->Sync();
uint8 *bits = (uint8 *)dragBitmap->Bits();
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
int32 bpr = dragBitmap->BytesPerRow();
if (fade) {
for ( int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr ) {
uint8 *line = bits + 3;
for (uint8 *end = line + 4 * width; line < end; line += 4)
*line = ALPHA;
}
for ( int32 y = height - ALPHA / 2; y < height; y++, bits += bpr ) {
uint8 *line = bits + 3;
for (uint8 *end = line + 4 * width; line < end; line += 4)
*line = (height - y) << 1;
}
} else {
for ( int32 y = 0; y < height; y++, bits += bpr ) {
uint8 *line = bits + 3;
for (uint8 *end = line + 4 * width; line < end; line += 4)
*line = ALPHA;
}
}
dragBitmap->Unlock();
success = true;
}
}
if (success)
DragMessage( &msg, dragBitmap, B_OP_ALPHA, BPoint( 0.0, 0.0 ) );
else {
delete dragBitmap;
DragMessage( &msg, dragRect.OffsetToCopy( point ), this );
}
}
return success;
}
/*****************************************************************************
* DragSortableListView::WindowActivated
*****************************************************************************/
void
DragSortableListView::WindowActivated( bool active )
{
// workarround for buggy focus indication of BScrollView
if ( BView* view = Parent() )
view->Invalidate();
}
/*****************************************************************************
* DragSortableListView::MessageReceived
*****************************************************************************/
void
DragSortableListView::MessageReceived(BMessage* message)
{
switch ( message->what )
{
case B_MODIFIERS_CHANGED:
ModifiersChanged();
break;
case B_SIMPLE_DATA:
{
DragSortableListView *list = NULL;
if ( message->FindPointer( "list", (void **)&list ) == B_OK
&& list == this )
{
int32 count = CountItems();
if ( fDropIndex < 0 || fDropIndex > count )
fDropIndex = count;
BList items;
int32 index;
for ( int32 i = 0; message->FindInt32( "index", i, &index ) == B_OK; i++ )
if ( BListItem* item = ItemAt(index) )
items.AddItem( (void*)item );
if ( items.CountItems() > 0 )
{
if ( modifiers() & B_SHIFT_KEY )
CopyItems( items, fDropIndex );
else
MoveItems( items, fDropIndex );
}
fDropIndex = -1;
}
break;
}
default:
BListView::MessageReceived( message );
break;
}
}
/*****************************************************************************
* DragSortableListView::MouseMoved
*****************************************************************************/
void
DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage *msg)
{
if ( msg && ( msg->what == B_SIMPLE_DATA || msg->what == MSG_SOUNDPLAY ) )
{
bool replaceAll = !msg->HasPointer("list") && !(modifiers() & B_SHIFT_KEY);
switch ( transit )
{
case B_ENTERED_VIEW:
// remember drag message
// this is needed to react on modifier changes
fDragMessageCopy = *msg;
case B_INSIDE_VIEW:
{
if ( replaceAll )
{
BRect r( Bounds() );
r.bottom--; // compensate for scrollbar offset
_SetDropAnticipationRect( r );
fDropIndex = -1;
}
else
{
// offset where by half of item height
BRect r( ItemFrame( 0 ) );
where.y += r.Height() / 2.0;
int32 index = IndexOf( where );
if ( index < 0 )
index = CountItems();
_SetDropIndex( index );
}
break;
}
case B_EXITED_VIEW:
// forget drag message
fDragMessageCopy.what = 0;
case B_OUTSIDE_VIEW:
_RemoveDropAnticipationRect();
break;
}
}
else
{
_RemoveDropAnticipationRect();
BListView::MouseMoved(where, transit, msg);
fDragMessageCopy.what = 0;
}
}
/*****************************************************************************
* DragSortableListView::MouseUp
*****************************************************************************/
void
DragSortableListView::MouseUp( BPoint where )
{
// remove drop mark
_SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
// be sure to forget drag message
fDragMessageCopy.what = 0;
BListView::MouseUp( where );
}
/*****************************************************************************
* DragSortableListView::DrawItem
*****************************************************************************/
void
DragSortableListView::DrawItem( BListItem *item, BRect itemFrame, bool complete )
{
DrawListItem( this, IndexOf( item ), itemFrame );
}
/*****************************************************************************
* DragSortableListView::ModifiersChaned
*****************************************************************************/
void
DragSortableListView::ModifiersChanged()
{
BPoint where;
uint32 buttons;
GetMouse( &where, &buttons, false );
uint32 transit = Bounds().Contains( where ) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
MouseMoved( where, transit, &fDragMessageCopy );
}
/*****************************************************************************
* DragSortableListView::MoveItems
*****************************************************************************/
void
DragSortableListView::MoveItems( BList& items, int32 index )
{
DeselectAll();
// we remove the items while we look at them, the insertion index is decreased
// when the items index is lower, so that we insert at the right spot after
// removal
BList removedItems;
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
BListItem* item = (BListItem*)items.ItemAt( i );
int32 removeIndex = IndexOf( item );
if ( RemoveItem( item ) && removedItems.AddItem( (void*)item ) )
{
if ( removeIndex < index )
index--;
}
// else ??? -> blow up
}
for ( int32 i = 0; BListItem* item = (BListItem*)removedItems.ItemAt( i ); i++ )
{
if ( AddItem( item, index ) )
{
// after we're done, the newly inserted items will be selected
Select( index, true );
// next items will be inserted after this one
index++;
}
else
delete item;
}
}
/*****************************************************************************
* DragSortableListView::CopyItems
*****************************************************************************/
void
DragSortableListView::CopyItems( BList& items, int32 index )
{
DeselectAll();
// by inserting the items after we copied all items first, we avoid
// cloning an item we already inserted and messing everything up
// in other words, don't touch the list before we know which items
// need to be cloned
BList clonedItems;
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
BListItem* item = CloneItem( IndexOf( (BListItem*)items.ItemAt( i ) ) );
if ( item && !clonedItems.AddItem( (void*)item ) )
delete item;
}
for ( int32 i = 0; BListItem* item = (BListItem*)clonedItems.ItemAt( i ); i++ )
{
if ( AddItem( item, index ) )
{
// after we're done, the newly inserted items will be selected
Select( index, true );
// next items will be inserted after this one
index++;
}
else
delete item;
}
}
/*****************************************************************************
* DragSortableListView::RemoveItemList
*****************************************************************************/
void
DragSortableListView::RemoveItemList( BList& items )
{
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
BListItem* item = (BListItem*)items.ItemAt( i );
if ( RemoveItem( item ) )
delete item;
}
}
/*****************************************************************************
* DragSortableListView::RemoveSelected
*****************************************************************************/
void
DragSortableListView::RemoveSelected()
{
BList items;
for ( int32 i = 0; BListItem* item = ItemAt( CurrentSelection( i ) ); i++ )
items.AddItem( (void*)item );
RemoveItemList( items );
}
/*****************************************************************************
* DragSortableListView::CountSelectedItems
*****************************************************************************/
int32
DragSortableListView::CountSelectedItems() const
{
int32 count = 0;
while ( CurrentSelection( count ) >= 0 )
count++;
return count;
}
/*****************************************************************************
* DragSortableListView::_SetDropAnticipationRect
*****************************************************************************/
void
DragSortableListView::_SetDropAnticipationRect( BRect r )
{
if ( fDropRect != r )
{
if ( fDropRect.IsValid() )
Invalidate( fDropRect );
fDropRect = r;
if ( fDropRect.IsValid() )
Invalidate( fDropRect );
}
}
/*****************************************************************************
* DragSortableListView::_SetDropAnticipationRect
*****************************************************************************/
void
DragSortableListView::_SetDropIndex( int32 index )
{
if ( fDropIndex != index )
{
fDropIndex = index;
if ( fDropIndex == -1 )
_SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
else
{
int32 count = CountItems();
if ( fDropIndex == count )
{
BRect r;
if ( BListItem* item = ItemAt( count - 1 ) )
{
r = ItemFrame( count - 1 );
r.top = r.bottom + 1.0;
r.bottom = r.top + 1.0;
}
else
{
r = Bounds();
r.bottom--; // compensate for scrollbars moved slightly out of window
}
_SetDropAnticipationRect( r );
}
else
{
BRect r = ItemFrame( fDropIndex );
r.bottom = r.top + 1.0;
_SetDropAnticipationRect( r );
}
}
}
}
/*****************************************************************************
* DragSortableListView::_RemoveDropAnticipationRect
*****************************************************************************/
void
DragSortableListView::_RemoveDropAnticipationRect()
{
_SetDropAnticipationRect( BRect( 0.0, 0.0, -1.0, -1.0 ) );
_SetDropIndex( -1 );
}
/*****************************************************************************
* PlaylistView class
*****************************************************************************/
PlaylistView::PlaylistView( intf_thread_t * _p_intf,
BRect frame, InterfaceWindow* mainWindow,
BMessage* selectionChangeMessage )
: DragSortableListView( frame, "playlist listview",
B_MULTIPLE_SELECTION_LIST, B_FOLLOW_ALL_SIDES,
B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED
| B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE ),
p_intf( _p_intf ),
fCurrentIndex( -1 ),
fPlaying( false ),
fDisplayMode( DISPLAY_PATH ),
fMainWindow( mainWindow ),
fSelectionChangeMessage( selectionChangeMessage ),
fLastClickedItem( NULL )
{
}
PlaylistView::~PlaylistView()
{
delete fSelectionChangeMessage;
}
/*****************************************************************************
* PlaylistView::AttachedToWindow
*****************************************************************************/
void
PlaylistView::AttachedToWindow()
{
// get pulse message every two frames
Window()->SetPulseRate( 80000 );
}
/*****************************************************************************
* PlaylistView::MessageReceived
*****************************************************************************/
void
PlaylistView::MessageReceived( BMessage* message)
{
switch ( message->what )
{
case MSG_SOUNDPLAY:
case B_SIMPLE_DATA:
if ( message->HasPointer( "list" ) )
{
// message comes from ourself
DragSortableListView::MessageReceived( message );
}
else
{
// message comes from another app (for example Tracker)
message->AddInt32( "drop index", fDropIndex );
fMainWindow->PostMessage( message, fMainWindow );
}
break;
default:
DragSortableListView::MessageReceived( message );
break;
}
}
/*****************************************************************************
* PlaylistView::MouseDown
*****************************************************************************/
void
PlaylistView::MouseDown( BPoint where )
{
int32 clicks = 1;
Window()->CurrentMessage()->FindInt32( "clicks", &clicks );
bool handled = false;
for ( int32 i = 0; PlaylistItem* item = (PlaylistItem*)ItemAt( i ); i++ )
{
BRect r = ItemFrame( i );
if ( r.Contains( where ) )
{
if ( clicks == 2 )
{
// only do something if user clicked the same item twice
if ( fLastClickedItem == item )
{
playlist_t * p_playlist = pl_Hold( p_intf );
if( p_playlist )
{
playlist_Goto( p_playlist, i );
pl_Release( p_intf );
}
handled = true;
}
}
else
{
// remember last clicked item
fLastClickedItem = item;
if ( i == fCurrentIndex )
{
r.right = r.left + TEXT_OFFSET;
if ( r.Contains ( where ) )
{
fMainWindow->PostMessage( PAUSE_PLAYBACK );
InvalidateItem( i );
handled = true;
}
}
}
break;
}
}
if ( !handled )
DragSortableListView::MouseDown(where);
}
/*****************************************************************************
* PlaylistView::KeyDown
*****************************************************************************/
void
PlaylistView::KeyDown( const char* bytes, int32 numBytes )
{
if ( numBytes < 1 )
return;
if ( ( bytes[0] == B_BACKSPACE ) || ( bytes[0] == B_DELETE ) )
{
RemoveSelected();
}
DragSortableListView::KeyDown( bytes, numBytes );
}
/*****************************************************************************
* PlaylistView::Pulse
*****************************************************************************/
void
PlaylistView::Pulse()
{
if ( fMainWindow->IsStopped() )
SetPlaying( false );
}
/*****************************************************************************
* PlaylistView::SelectionChanged
*****************************************************************************/
void
PlaylistView::SelectionChanged()
{
BLooper* looper = Looper();
if ( fSelectionChangeMessage && looper )
{
BMessage message( *fSelectionChangeMessage );
looper->PostMessage( &message );
}
}
/*****************************************************************************
* PlaylistView::MoveItems
*****************************************************************************/
void
PlaylistView::MoveItems( BList& items, int32 index )
{
#if 0
DeselectAll();
// we remove the items while we look at them, the insertion index is decreased
// when the items index is lower, so that we insert at the right spot after
// removal
if ( fVlcWrapper->PlaylistLock() )
{
BList removedItems;
BList removeItems;
int32 count = items.CountItems();
int32 indexOriginal = index;
// remember currently playing item
BListItem* playingItem = _PlayingItem();
// collect item pointers for removal by index
for ( int32 i = 0; i < count; i++ )
{
int32 removeIndex = IndexOf( (BListItem*)items.ItemAt( i ) );
void* item = fVlcWrapper->PlaylistItemAt( removeIndex );
if ( item && removeItems.AddItem( item ) )
{
if ( removeIndex < index )
index--;
}
// else ??? -> blow up
}
// actually remove items using pointers
for ( int32 i = 0; i < count; i++ )
{
void* item = fVlcWrapper->PlaylistRemoveItem( removeItems.ItemAt( i ) );
if ( item && !removedItems.AddItem( item ) )
free( item );
}
// add items at index
for ( int32 i = 0; void* item = removedItems.ItemAt( i ); i++ )
{
if ( fVlcWrapper->PlaylistAddItem( item, index ) )
// next items will be inserted after this one
index++;
else
free( item );
}
// update GUI
DragSortableListView::MoveItems( items, indexOriginal );
// restore currently playing item
_SetPlayingIndex( playingItem );
// update interface (in case it isn't playing,
// there is a chance that it needs to update)
fMainWindow->PostMessage( MSG_UPDATE );
fVlcWrapper->PlaylistUnlock();
}
#endif
}
/*****************************************************************************
* PlaylistView::CopyItems
*****************************************************************************/
void
PlaylistView::CopyItems( BList& items, int32 toIndex )
{
#if 0
DeselectAll();
// we remove the items while we look at them, the insertion index is decreased
// when the items index is lower, so that we insert at the right spot after
// removal
if ( fVlcWrapper->PlaylistLock() )
{
BList clonedItems;
int32 count = items.CountItems();
// remember currently playing item
BListItem* playingItem = _PlayingItem();
// collect cloned item pointers
for ( int32 i = 0; i < count; i++ )
{
int32 index = IndexOf( (BListItem*)items.ItemAt( i ) );
void* item = fVlcWrapper->PlaylistItemAt( index );
void* cloned = fVlcWrapper->PlaylistCloneItem( item );
if ( cloned && !clonedItems.AddItem( cloned ) )
free( cloned );
}
// add cloned items at index
int32 index = toIndex;
for ( int32 i = 0; void* item = clonedItems.ItemAt( i ); i++ )
{
if ( fVlcWrapper->PlaylistAddItem( item, index ) )
// next items will be inserted after this one
index++;
else
free( item );
}
// update GUI
DragSortableListView::CopyItems( items, toIndex );
// restore currently playing item
_SetPlayingIndex( playingItem );
// update interface (in case it isn't playing,
// there is a chance that it needs to update)
fMainWindow->PostMessage( MSG_UPDATE );
fVlcWrapper->PlaylistUnlock();
}
#endif
}
/*****************************************************************************
* PlaylistView::RemoveItemList
*****************************************************************************/
void
PlaylistView::RemoveItemList( BList& items )
{
#if 0
if ( fVlcWrapper->PlaylistLock() )
{
// remember currently playing item
BListItem* playingItem = _PlayingItem();
// collect item pointers for removal
BList removeItems;
int32 count = items.CountItems();
for ( int32 i = 0; i < count; i++ )
{
int32 index = IndexOf( (BListItem*)items.ItemAt( i ) );
void* item = fVlcWrapper->PlaylistItemAt( index );
if ( item && !removeItems.AddItem( item ) )
free( item );
}
// remove items from playlist
count = removeItems.CountItems();
for ( int32 i = 0; void* item = removeItems.ItemAt( i ); i++ )
{
fVlcWrapper->PlaylistRemoveItem( item );
}
// update GUI
DragSortableListView::RemoveItemList( items );
// restore currently playing item
_SetPlayingIndex( playingItem );
// update interface (in case it isn't playing,
// there is a chance that it needs to update)
fMainWindow->PostMessage( MSG_UPDATE );
fVlcWrapper->PlaylistUnlock();
}
#endif
}
/*****************************************************************************
* PlaylistView::CloneItem
*****************************************************************************/
BListItem*
PlaylistView::CloneItem( int32 atIndex ) const
{
BListItem* clone = NULL;
if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( atIndex ) ) )
clone = new PlaylistItem( item->Text() );
return clone;
}
/*****************************************************************************
* PlaylistView::DrawListItem
*****************************************************************************/
void
PlaylistView::DrawListItem( BView* owner, int32 index, BRect frame ) const
{
if ( PlaylistItem* item = dynamic_cast<PlaylistItem*>( ItemAt( index ) ) )
item->Draw( owner, frame, index % 2,
fDisplayMode, index == fCurrentIndex, fPlaying );
}
/*****************************************************************************
* PlaylistView::MakeDragMessage
*****************************************************************************/
void
PlaylistView::MakeDragMessage( BMessage* message ) const
{
if ( message )
{
message->AddPointer( "list", (void*)this );
int32 index;
for ( int32 i = 0; ( index = CurrentSelection( i ) ) >= 0; i++ )
{
message->AddInt32( "index", index );
// add refs to message (inter application communication)
if ( BStringItem* item = dynamic_cast<BStringItem*>( ItemAt( index ) ) )
{
entry_ref ref;
if ( get_ref_for_path( item->Text(), &ref ) == B_OK )
message->AddRef( "refs", &ref );
}
}
}
}
/*****************************************************************************
* PlaylistView::SetCurrent
*****************************************************************************/
void
PlaylistView::SetCurrent( int32 index )
{
if ( fCurrentIndex != index )
{
InvalidateItem( fCurrentIndex );
fCurrentIndex = index;
InvalidateItem( fCurrentIndex );
}
}
/*****************************************************************************
* PlaylistView::SetPlaying
*****************************************************************************/
void
PlaylistView::SetPlaying( bool playing )
{
if ( fPlaying != playing )
{
fPlaying = playing;
InvalidateItem( fCurrentIndex );
}
}
/*****************************************************************************
* PlaylistView::SetPlaying
*****************************************************************************/
void
PlaylistView::RebuildList()
{
playlist_t * p_playlist = pl_Hold( p_intf );
// remove all items
BListItem * item;
int32 count = CountItems();
while( ( item = RemoveItem( --count ) ) )
delete item;
// rebuild listview from VLC's playlist
PL_LOCK;
FOREACH_ARRAY( playlist_item_t *p_item, p_playlist->items )
AddItem( new PlaylistItem( p_item->p_input->psz_name ) );
FOREACH_END();
PL_UNLOCK;
vlc_object_release( p_playlist );
}
/*****************************************************************************
* PlaylistView::SortReverse
*****************************************************************************/
void
PlaylistView::SortReverse()
{
#if 0
if ( int32 count = CountSelectedItems() )
{
int32 last = count - 1;
// remember currently playing item
BListItem* playingItem = _PlayingItem();
for ( int32 first = 0; first < count / 2; first++, last-- )
{
int32 index1 = CurrentSelection( first);
int32 index2 = CurrentSelection( last);
if ( SwapItems( index1, index2 ) )
{
// index2 > index1, so the list won't get messed up
// if we remove the items in that order
// TODO: Error checking + handling!
void* item2 = fVlcWrapper->PlaylistRemoveItem( index2 );
void* item1 = fVlcWrapper->PlaylistRemoveItem( index1 );
fVlcWrapper->PlaylistAddItem( item2, index1 );
fVlcWrapper->PlaylistAddItem( item1, index2 );
}
}
// restore currently playing item
_SetPlayingIndex( playingItem );
}
#endif
}
/*****************************************************************************
* PlaylistView::SortByPath
*****************************************************************************/
void
PlaylistView::SortByPath()
{
}
/*****************************************************************************
* PlaylistView::SortByName
*****************************************************************************/
void
PlaylistView::SortByName()
{
}
/*****************************************************************************
* PlaylistView::SetDisplayMode
*****************************************************************************/
void
PlaylistView::SetDisplayMode( uint32 mode )
{
if ( mode != fDisplayMode )
{
fDisplayMode = mode;
Invalidate();
}
}
/*****************************************************************************
* PlaylistView::_PlayingItem
*****************************************************************************/
BListItem*
PlaylistView::_PlayingItem() const
{
playlist_t * p_playlist = pl_Hold( p_intf );
if( !p_playlist )
{
return NULL;
}
BListItem * item = ItemAt( p_playlist->i_index );
pl_Release( p_intf );
return item;
}
/*****************************************************************************
* PlaylistView::_SetPlayingIndex
*****************************************************************************/
void
PlaylistView::_SetPlayingIndex( BListItem* playingItem )
{
for ( int32 i = 0; BListItem* item = ItemAt( i ); i++ )
{
if ( item == playingItem )
{
playlist_t * p_playlist = pl_Hold( p_intf );
if( !p_playlist )
{
return;
}
playlist_Goto( p_playlist, i );
SetCurrent( i );
pl_Release( p_intf );
break;
}
}
}
#endif
/*****************************************************************************
* ListViews.h: BeOS interface list view class prototype
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#ifndef LIST_VIEWS_H
#define LIST_VIEWS_H
#include <ListItem.h>
#include <ListView.h>
#include <String.h>
enum
{
DISPLAY_PATH = 0,
DISPLAY_NAME,
};
class InterfaceWindow;
// PlaylistItem
class PlaylistItem : public BStringItem
{
public:
PlaylistItem( const char* name );
virtual ~PlaylistItem();
virtual void Draw( BView* owner, BRect frame,
bool tintedLine,
uint32 mode,
bool active = false,
bool playing = false );
private:
BString fName; // additional to BStringItem::Text()
};
// DragSortableListView
class DragSortableListView : public BListView
{
public:
DragSortableListView( BRect frame,
const char* name,
list_view_type type
= B_SINGLE_SELECTION_LIST,
uint32 resizingMode
= B_FOLLOW_LEFT
| B_FOLLOW_TOP,
uint32 flags
= B_WILL_DRAW
| B_NAVIGABLE
| B_FRAME_EVENTS );
virtual ~DragSortableListView();
// BListView
virtual void Draw( BRect updateRect );
virtual bool InitiateDrag( BPoint point, int32 index,
bool wasSelected );
virtual void MessageReceived( BMessage* message );
virtual void MouseMoved( BPoint where, uint32 transit,
const BMessage* dragMessage );
virtual void MouseUp( BPoint where );
virtual void WindowActivated( bool active );
virtual void DrawItem( BListItem *item, BRect itemFrame,
bool complete = false);
// DragSortableListView
virtual void ModifiersChanged(); // called by window
virtual void MoveItems( BList& items, int32 toIndex );
virtual void CopyItems( BList& items, int32 toIndex );
virtual void RemoveItemList( BList& indices );
void RemoveSelected(); // uses RemoveItemList()
int32 CountSelectedItems() const;
virtual BListItem* CloneItem( int32 atIndex ) const = 0;
virtual void DrawListItem( BView* owner, int32 index,
BRect itemFrame ) const = 0;
virtual void MakeDragMessage( BMessage* message ) const = 0;
private:
void _SetDropAnticipationRect( BRect r );
void _SetDropIndex( int32 index );
void _RemoveDropAnticipationRect();
BRect fDropRect;
BMessage fDragMessageCopy;
protected:
int32 fDropIndex;
};
// PlaylistView
class PlaylistView : public DragSortableListView
{
public:
PlaylistView( intf_thread_t * p_intf,
BRect frame,
InterfaceWindow* mainWindow,
BMessage* selectionChangeMessage = NULL );
~PlaylistView();
// BListView
virtual void AttachedToWindow();
virtual void MessageReceived( BMessage* message );
virtual void MouseDown( BPoint where );
virtual void KeyDown( const char* bytes, int32 numBytes );
virtual void Pulse();
virtual void SelectionChanged();
// DragSortableListView
virtual void MoveItems( BList& items, int32 toIndex );
virtual void CopyItems( BList& items, int32 toIndex );
virtual void RemoveItemList( BList& indices );
virtual BListItem* CloneItem( int32 atIndex ) const;
virtual void DrawListItem( BView* owner, int32 index,
BRect itemFrame ) const;
virtual void MakeDragMessage( BMessage* message ) const;
// PlaylistView
void SetCurrent( int32 index );
void SetPlaying( bool playing );
void RebuildList();
void SortReverse();
void SortByPath();
void SortByName();
void SetDisplayMode( uint32 mode );
uint32 DisplayMode() const
{ return fDisplayMode; }
private:
BListItem* _PlayingItem() const;
void _SetPlayingIndex( BListItem* item );
intf_thread_t * p_intf;
int32 fCurrentIndex;
bool fPlaying;
uint32 fDisplayMode;
InterfaceWindow* fMainWindow;
BMessage* fSelectionChangeMessage;
PlaylistItem* fLastClickedItem;
};
#endif // LIST_VIEWS_H
/*****************************************************************************
* MediaControlView.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tony@castley.net>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
/* System headers */
#include <InterfaceKit.h>
#include <AppKit.h>
#include <String.h>
/* VLC headers */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
extern "C"
{
#include <audio_output.h>
}
/* BeOS interface headers */
#include "Bitmaps.h"
#include "DrawingTidbits.h"
#include "InterfaceWindow.h"
#include "MsgVals.h"
#include "TransportButton.h"
#include "ListViews.h"
#include "MediaControlView.h"
#define BORDER_INSET 6.0
#define MIN_SPACE 4.0
#define SPEAKER_SLIDER_DIST 6.0
#define VOLUME_MIN_WIDTH 70.0
#define DIM_LEVEL 0.4
#define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
#define SEEK_SLIDER_KNOB_WIDTH 8.0
// slider colors are hardcoded here, because that's just
// what they currently are within those bitmaps
const rgb_color kGreen = (rgb_color){ 152, 203, 152, 255 };
const rgb_color kGreenShadow = (rgb_color){ 102, 152, 102, 255 };
const rgb_color kBackground = (rgb_color){ 216, 216, 216, 255 };
const rgb_color kSeekGreen = (rgb_color){ 171, 221, 161, 255 };
const rgb_color kSeekGreenShadow = (rgb_color){ 144, 186, 136, 255 };
const rgb_color kSeekRed = (rgb_color){ 255, 0, 0, 255 };
const rgb_color kSeekRedLight = (rgb_color){ 255, 152, 152, 255 };
const rgb_color kSeekRedShadow = (rgb_color){ 178, 0, 0, 255 };
#define DISABLED_SEEK_MESSAGE _("Drop files to play")
#define SEEKSLIDER_RANGE 2048
enum
{
MSG_REWIND = 'rwnd',
MSG_FORWARD = 'frwd',
MSG_SKIP_BACKWARDS = 'skpb',
MSG_SKIP_FORWARD = 'skpf',
};
// constructor
MediaControlView::MediaControlView( intf_thread_t * _p_intf, BRect frame)
: BBox(frame, NULL, B_FOLLOW_NONE, B_WILL_DRAW | B_FRAME_EVENTS | B_PULSE_NEEDED,
B_PLAIN_BORDER),
p_intf( _p_intf ),
fCurrentRate(INPUT_RATE_DEFAULT),
fCurrentStatus(-1),
fBottomControlHeight(0.0),
fIsEnabled( true )
{
BRect frame(0.0, 0.0, 10.0, 10.0);
// Seek Slider
fSeekSlider = new SeekSlider( p_intf, frame, "seek slider", this );
fSeekSlider->SetValue(0);
fSeekSlider->ResizeToPreferred();
AddChild( fSeekSlider );
// Buttons
// Skip Back
frame.SetRightBottom(kSkipButtonSize);
fBottomControlHeight = kRewindBitmapHeight - 1.0;
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
kSkipBackBitmapBits,
kPressedSkipBackBitmapBits,
kDisabledSkipBackBitmapBits,
new BMessage(MSG_SKIP_BACKWARDS));
AddChild( fSkipBack );
// Play Pause
frame.SetRightBottom(kPlayButtonSize);
if (fBottomControlHeight < kPlayPauseBitmapHeight - 1.0)
fBottomControlHeight = kPlayPauseBitmapHeight - 1.0;
fPlayPause = new PlayPauseButton(frame, B_EMPTY_STRING,
kPlayButtonBitmapBits,
kPressedPlayButtonBitmapBits,
kDisabledPlayButtonBitmapBits,
kPlayingPlayButtonBitmapBits,
kPressedPlayingPlayButtonBitmapBits,
kPausedPlayButtonBitmapBits,
kPressedPausedPlayButtonBitmapBits,
new BMessage(START_PLAYBACK));
AddChild( fPlayPause );
// Skip Foward
frame.SetRightBottom(kSkipButtonSize);
fSkipForward = new TransportButton(frame, B_EMPTY_STRING,
kSkipForwardBitmapBits,
kPressedSkipForwardBitmapBits,
kDisabledSkipForwardBitmapBits,
new BMessage(MSG_SKIP_FORWARD));
AddChild( fSkipForward );
// Forward
fForward = new TransportButton(frame, B_EMPTY_STRING,
kForwardBitmapBits,
kPressedForwardBitmapBits,
kDisabledForwardBitmapBits,
new BMessage(MSG_FORWARD));
// AddChild( fForward );
// Rewind
fRewind = new TransportButton(frame, B_EMPTY_STRING,
kRewindBitmapBits,
kPressedRewindBitmapBits,
kDisabledRewindBitmapBits,
new BMessage(MSG_REWIND));
// AddChild( fRewind );
// Stop
frame.SetRightBottom(kStopButtonSize);
if (fBottomControlHeight < kStopBitmapHeight - 1.0)
fBottomControlHeight = kStopBitmapHeight - 1.0;
fStop = new TransportButton(frame, B_EMPTY_STRING,
kStopButtonBitmapBits,
kPressedStopButtonBitmapBits,
kDisabledStopButtonBitmapBits,
new BMessage(STOP_PLAYBACK));
AddChild( fStop );
// Mute
frame.SetRightBottom(kSpeakerButtonSize);
if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
fMute = new TransportButton(frame, B_EMPTY_STRING,
kSpeakerIconBits,
kPressedSpeakerIconBits,
kSpeakerIconBits,
new BMessage(VOLUME_MUTE));
AddChild( fMute );
// Volume Slider
fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
kVolumeSliderBitmapHeight - 1.0),
"volume slider", 1, AOUT_VOLUME_MAX,
new BMessage(VOLUME_CHG));
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
MediaControlView::~MediaControlView()
{
}
// AttachedToWindow
void
MediaControlView::AttachedToWindow()
{
// we are now a valid BHandler
fRewind->SetTarget(this);
fForward->SetTarget(this);
fSkipBack->SetTarget(this);
fSkipForward->SetTarget(this);
fVolumeSlider->SetTarget(Window());
BRect r(_MinFrame());
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
width -= r.Width();
if (width > 0.0)
r.right += width;
}
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
FrameResized(Bounds().Width(), Bounds().Height());
// get pulse message every two frames
Window()->SetPulseRate(80000);
}
// FrameResized
void
MediaControlView::FrameResized(float width, float height)
{
BRect r(Bounds());
// make sure we don't leave dirty pixels
// (B_FULL_UPDATE_ON_RESIZE == annoying flicker -> this is smarter)
if (fOldBounds.Width() < r.Width())
Invalidate(BRect(fOldBounds.right, fOldBounds.top + 1.0,
fOldBounds.right, fOldBounds.bottom - 1.0));
else
Invalidate(BRect(r.right, r.top + 1.0,
r.right, r.bottom - 1.0));
if (fOldBounds.Height() < r.Height())
Invalidate(BRect(fOldBounds.left + 1.0, fOldBounds.bottom,
fOldBounds.right - 1.0, fOldBounds.bottom));
else
Invalidate(BRect(r.left + 1.0, r.bottom,
r.right - 1.0, r.bottom));
// remember for next time
fOldBounds = r;
// layout controls
r.InsetBy(BORDER_INSET, BORDER_INSET);
_LayoutControls(r);
}
// GetPreferredSize
void
MediaControlView::GetPreferredSize(float* width, float* height)
{
if (width && height)
{
BRect r(_MinFrame());
*width = r.Width();
*height = r.Height();
}
}
// MessageReceived
void
MediaControlView::MessageReceived(BMessage* message)
{
switch (message->what)
{
case MSG_REWIND:
break;
case MSG_FORWARD:
break;
case MSG_SKIP_BACKWARDS:
Window()->PostMessage(NAVIGATE_PREV);
break;
case MSG_SKIP_FORWARD:
Window()->PostMessage(NAVIGATE_NEXT);
break;
default:
BBox::MessageReceived(message);
break;
}
}
// Pulse
void
MediaControlView::Pulse()
{
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( float position )
{
fSeekSlider->SetPosition( position );
}
// SetStatus
void
MediaControlView::SetStatus(int status, int rate)
{
// we need to set the button status periodically
// (even if it is the same) to get a blinking button
fCurrentStatus = status;
switch( status )
{
case PLAYING_S:
case OPENNING_S:
fPlayPause->SetPlaying();
break;
case PAUSE_S:
fPlayPause->SetPaused();
break;
default:
fPlayPause->SetStopped();
break;
}
if (rate != fCurrentRate)
{
fCurrentRate = rate;
if ( rate < INPUT_RATE_DEFAULT )
{
// TODO: ...
}
}
}
// SetEnabled
void
MediaControlView::SetEnabled(bool 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
void
MediaControlView::SetAudioEnabled(bool enabled)
{
fMute->SetEnabled(enabled);
fVolumeSlider->SetEnabled(enabled);
}
// GetVolume
uint32
MediaControlView::GetVolume() const
{
return fVolumeSlider->Value();
}
// SetSkippable
void
MediaControlView::SetSkippable(bool backward, bool forward)
{
fSkipBack->SetEnabled(backward);
fSkipForward->SetEnabled(forward);
}
// SetMuted
void
MediaControlView::SetMuted(bool mute)
{
fVolumeSlider->SetMuted(mute);
}
// _LayoutControls
void
MediaControlView::_LayoutControls(BRect frame) const
{
// seek slider
BRect r(frame);
// calculate absolutly minimal width
float minWidth = fSkipBack->Bounds().Width();
// minWidth += fRewind->Bounds().Width();
minWidth += fStop->Bounds().Width();
minWidth += fPlayPause->Bounds().Width();
// minWidth += fForward->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
r.right = r.left + fSkipBack->Bounds().Width();
_LayoutControl(fSkipBack, r);
// rewind
// r.left = r.right + space;
// r.right = r.left + fRewind->Bounds().Width();
// _LayoutControl(fRewind, r);
// stop
r.left = r.right + space;
r.right = r.left + fStop->Bounds().Width();
_LayoutControl(fStop, r);
// play/pause
r.left = r.right + space;
r.right = r.left + fPlayPause->Bounds().Width();
_LayoutControl(fPlayPause, r);
// forward
// r.left = r.right + space;
// r.right = r.left + fForward->Bounds().Width();
// _LayoutControl(fForward, r);
// skip forward
r.left = r.right + space;
r.right = r.left + fSkipForward->Bounds().Width();
_LayoutControl(fSkipForward, r);
// speaker icon
r.left = r.right + space + space;
r.right = r.left + fMute->Bounds().Width();
_LayoutControl(fMute, r);
// volume slider
r.left = r.right + SPEAKER_SLIDER_DIST; // keep speaker icon and volume slider attached
r.right = frame.right;
_LayoutControl(fVolumeSlider, r, true);
}
// _MinFrame
BRect
MediaControlView::_MinFrame() const
{
// add up width of controls along bottom (seek slider will likely adopt)
float minWidth = 2 * BORDER_INSET;
minWidth += fSkipBack->Bounds().Width() + MIN_SPACE;
// minWidth += fRewind->Bounds().Width() + MIN_SPACE;
minWidth += fStop->Bounds().Width() + MIN_SPACE;
minWidth += fPlayPause->Bounds().Width() + MIN_SPACE;
// minWidth += fForward->Bounds().Width() + MIN_SPACE;
minWidth += fSkipForward->Bounds().Width() + MIN_SPACE + MIN_SPACE;
minWidth += fMute->Bounds().Width() + SPEAKER_SLIDER_DIST;
minWidth += VOLUME_MIN_WIDTH;
// add up height of seek slider and heighest control on bottom
float minHeight = 2 * BORDER_INSET;
minHeight += fSeekSlider->Bounds().Height() + MIN_SPACE + MIN_SPACE / 2.0;
minHeight += fBottomControlHeight;
return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
}
// _LayoutControl
void
MediaControlView::_LayoutControl(BView* view, BRect frame,
bool resizeWidth, bool resizeHeight) const
{
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());
float width = resizeWidth ? frame.Width() : view->Bounds().Width();
float height = resizeHeight ? frame.Height() : view->Bounds().Height();
if (resizeWidth || resizeHeight)
view->ResizeTo(width, height);
}
/*****************************************************************************
* SeekSlider
*****************************************************************************/
SeekSlider::SeekSlider( intf_thread_t * _p_intf,
BRect frame, const char* name, MediaControlView *owner )
: BControl(frame, name, NULL, NULL, B_FOLLOW_NONE,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
p_intf(_p_intf),
fOwner(owner),
fTracking(false)
{
BFont font(be_plain_font);
font.SetSize(9.0);
SetFont(&font);
}
SeekSlider::~SeekSlider()
{
}
/*****************************************************************************
* VolumeSlider::AttachedToWindow
*****************************************************************************/
void
SeekSlider::AttachedToWindow()
{
BControl::AttachedToWindow();
SetViewColor(B_TRANSPARENT_32_BIT);
}
/*****************************************************************************
* VolumeSlider::Draw
*****************************************************************************/
void
SeekSlider::Draw(BRect updateRect)
{
BRect r(Bounds());
float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
float sliderStart = (r.left + knobWidth2);
float sliderEnd = (r.right - knobWidth2);
float knobPos = sliderStart
+ floorf((sliderEnd - sliderStart - 1.0) * Value()
/ SEEKSLIDER_RANGE);
// draw both sides (the original from Be doesn't seem
// to make a difference for enabled/disabled state)
// DrawBitmapAsync(fLeftSideBits, r.LeftTop());
// DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
// colors for the slider area between the two bitmaps
rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
rgb_color green = kSeekGreen;
rgb_color greenShadow = kSeekGreenShadow;
rgb_color black = kBlack;
rgb_color dotGrey = midShadow;
rgb_color dotGreen = greenShadow;
// draw frame
_StrokeFrame(r, softShadow, softShadow, softLight, softLight);
r.InsetBy(1.0, 1.0);
_StrokeFrame(r, black, black, light, light);
if (IsEnabled())
{
r.InsetBy(1.0, 1.0);
// inner shadow
_StrokeFrame(r, greenShadow, greenShadow, green, green);
r.top++;
r.left++;
_StrokeFrame(r, greenShadow, greenShadow, green, green);
// inside area
r.InsetBy(1.0, 1.0);
SetHighColor(green);
FillRect(r);
// dots
int32 dotCount = (int32)(r.Width() / 6.0);
BPoint dotPos;
dotPos.y = r.top + 2.0;
SetHighColor(dotGreen);
for (int32 i = 0; i < dotCount; i++)
{
dotPos.x = sliderStart + i * 6.0 + 5.0;
StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 6.0));
}
// slider handle
r.top -= 4.0;
r.bottom += 3.0;
r.left = knobPos - knobWidth2;
r.right = knobPos + knobWidth2;
// black outline
float handleBottomSize = 2.0;
float handleArrowSize = 6.0;
BeginLineArray(10);
// upper handle
AddLine(BPoint(r.left, r.top + handleBottomSize),
BPoint(r.left, r.top), black);
AddLine(BPoint(r.left + 1.0, r.top),
BPoint(r.right, r.top), black);
AddLine(BPoint(r.right, r.top + 1.0),
BPoint(r.right, r.top + handleBottomSize), black);
AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
BPoint(knobPos, r.top + handleArrowSize), black);
AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), black);
// lower handle
AddLine(BPoint(r.left, r.bottom),
BPoint(r.left, r.bottom - handleBottomSize), black);
AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
BPoint(knobPos, r.bottom - handleArrowSize), black);
AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
BPoint(r.right, r.bottom - handleBottomSize), black);
AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
BPoint(r.right, r.bottom), black);
AddLine(BPoint(r.right - 1.0, r.bottom),
BPoint(r.left + 1.0, r.bottom), black);
EndLineArray();
// inner red light and shadow lines
r.InsetBy(1.0, 1.0);
handleBottomSize--;
handleArrowSize -= 2.0;
BeginLineArray(10);
// upper handle
AddLine(BPoint(r.left, r.top + handleBottomSize),
BPoint(r.left, r.top), kSeekRedLight);
AddLine(BPoint(r.left + 1.0, r.top),
BPoint(r.right, r.top), kSeekRedLight);
AddLine(BPoint(r.right, r.top + 1.0),
BPoint(r.right, r.top + handleBottomSize), kSeekRedShadow);
AddLine(BPoint(r.right - 1.0, r.top + handleBottomSize + 1.0),
BPoint(knobPos, r.top + handleArrowSize), kSeekRedShadow);
AddLine(BPoint(knobPos - 1.0, r.top + handleArrowSize - 1.0),
BPoint(r.left + 1.0, r.top + handleBottomSize + 1.0), kSeekRedLight);
// lower handle
AddLine(BPoint(r.left, r.bottom),
BPoint(r.left, r.bottom - handleBottomSize), kSeekRedLight);
AddLine(BPoint(r.left + 1.0, r.bottom - handleBottomSize - 1.0),
BPoint(knobPos, r.bottom - handleArrowSize), kSeekRedLight);
AddLine(BPoint(knobPos + 1.0, r.bottom - handleArrowSize + 1.0),
BPoint(r.right, r.bottom - handleBottomSize), kSeekRedShadow);
AddLine(BPoint(r.right, r.bottom - handleBottomSize + 1.0),
BPoint(r.right, r.bottom), kSeekRedShadow);
AddLine(BPoint(r.right - 1.0, r.bottom),
BPoint(r.left + 1.0, r.bottom), kSeekRedShadow);
EndLineArray();
// fill rest of handles with red
SetHighColor(kSeekRed);
r.InsetBy(1.0, 1.0);
handleArrowSize -= 2.0;
BPoint arrow[3];
// upper handle arrow
arrow[0].x = r.left;
arrow[0].y = r.top;
arrow[1].x = r.right;
arrow[1].y = r.top;
arrow[2].x = knobPos;
arrow[2].y = r.top + handleArrowSize;
FillPolygon(arrow, 3);
// lower handle arrow
arrow[0].x = r.left;
arrow[0].y = r.bottom;
arrow[1].x = r.right;
arrow[1].y = r.bottom;
arrow[2].x = knobPos;
arrow[2].y = r.bottom - handleArrowSize;
FillPolygon(arrow, 3);
}
else
{
r.InsetBy(1.0, 1.0);
_StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
r.InsetBy(1.0, 1.0);
_StrokeFrame(r, darkShadow, darkShadow, darkShadow, darkShadow);
r.InsetBy(1.0, 1.0);
SetHighColor(darkShadow);
SetLowColor(shadow);
// stripes
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 }};
BRect stripesRect(r);
stripesRect.right = textPos - 5.0;
FillRect(stripesRect, stripes);
stripesRect.left = textPos + width + 3.0;
stripesRect.right = r.right;
FillRect(stripesRect, stripes);
// info text
r.left = textPos - 4.0;
r.right = textPos + width + 2.0;
FillRect(r);
SetHighColor(shadow);
SetLowColor(darkShadow);
font_height fh;
GetFontHeight(&fh);
DrawString(DISABLED_SEEK_MESSAGE, BPoint(textPos, r.top + ceilf(fh.ascent) - 1.0));
}
}
/*****************************************************************************
* SeekSlider::MouseDown
*****************************************************************************/
void
SeekSlider::MouseDown(BPoint where)
{
if (IsEnabled() && Bounds().Contains(where))
{
SetValue(_ValueFor(where.x));
fTracking = true;
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
}
}
/*****************************************************************************
* SeekSlider::MouseMoved
*****************************************************************************/
void
SeekSlider::MouseMoved(BPoint where, uint32 code, const BMessage* dragMessage)
{
if (fTracking)
{
SetValue(_ValueFor(where.x));
}
}
/*****************************************************************************
* SeekSlider::MouseUp
*****************************************************************************/
void
SeekSlider::MouseUp(BPoint where)
{
if (fTracking)
{
fTracking = false;
input_thread_t * p_input;
p_input = (input_thread_t *)
vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
if( p_input )
{
var_SetFloat( p_input, "position",
(float) Value() / SEEKSLIDER_RANGE );
vlc_object_release( p_input );
}
}
}
/*****************************************************************************
* SeekSlider::ResizeToPreferred
*****************************************************************************/
void
SeekSlider::ResizeToPreferred()
{
float width = 15.0 + StringWidth(DISABLED_SEEK_MESSAGE) + 15.0;
ResizeTo(width, 17.0);
}
/*****************************************************************************
* SeekSlider::SetPosition
*****************************************************************************/
void
SeekSlider::SetPosition(float position)
{
if ( LockLooper() )
{
if( !fTracking )
{
SetValue( SEEKSLIDER_RANGE * position );
}
UnlockLooper();
}
}
/*****************************************************************************
* SeekSlider::_ValueFor
*****************************************************************************/
int32
SeekSlider::_ValueFor(float xPos) const
{
BRect r(Bounds());
float knobWidth2 = SEEK_SLIDER_KNOB_WIDTH / 2.0;
float sliderStart = (r.left + knobWidth2);
float sliderEnd = (r.right - knobWidth2);
int32 value = (int32)(((xPos - sliderStart) * SEEKSLIDER_RANGE)
/ (sliderEnd - sliderStart - 1.0));
if (value < 0)
value = 0;
if (value > SEEKSLIDER_RANGE)
value = SEEKSLIDER_RANGE;
return value;
}
/*****************************************************************************
* SeekSlider::_StrokeFrame
*****************************************************************************/
void
SeekSlider::_StrokeFrame(BRect r, rgb_color left, rgb_color top,
rgb_color right, rgb_color bottom)
{
BeginLineArray(4);
AddLine(BPoint(r.left, r.bottom), BPoint(r.left, r.top), left);
AddLine(BPoint(r.left + 1.0, r.top), BPoint(r.right, r.top), top);
AddLine(BPoint(r.right, r.top + 1.0), BPoint(r.right, r.bottom), right);
AddLine(BPoint(r.right - 1.0, r.bottom), BPoint(r.left + 1.0, r.bottom), bottom);
EndLineArray();
}
/*****************************************************************************
* VolumeSlider
*****************************************************************************/
VolumeSlider::VolumeSlider(BRect frame, const char* name, int32 minValue, int32 maxValue,
BMessage* message, BHandler* target)
: BControl(frame, name, NULL, message, B_FOLLOW_NONE,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE),
fLeftSideBits(NULL),
fRightSideBits(NULL),
fKnobBits(NULL),
fTracking(false),
fMuted(false),
fMinValue(minValue),
fMaxValue(maxValue)
{
SetTarget(target);
// create bitmaps
BRect r(BPoint(0.0, 0.0), kVolumeSliderBitmapSize);
fLeftSideBits = new BBitmap(r, B_CMAP8);
fRightSideBits = new BBitmap(r, B_CMAP8);
r.Set(0.0, 0.0, kVolumeSliderKnobBitmapSize.x, kVolumeSliderKnobBitmapSize.y);
fKnobBits = new BBitmap(r, B_CMAP8);
_MakeBitmaps();
}
/*****************************************************************************
* VolumeSlider destructor
*****************************************************************************/
VolumeSlider::~VolumeSlider()
{
delete fLeftSideBits;
delete fRightSideBits;
delete fKnobBits;
}
/*****************************************************************************
* VolumeSlider::AttachedToWindow
*****************************************************************************/
void
VolumeSlider::AttachedToWindow()
{
BControl::AttachedToWindow();
SetViewColor(B_TRANSPARENT_32_BIT);
}
/*****************************************************************************
* VolumeSlider::SetValue
*****************************************************************************/
void
VolumeSlider::SetValue(int32 value)
{
if (value != Value())
{
BControl::SetValue(value);
Invoke();
}
}
/*****************************************************************************
* VolumeSlider::SetEnabled
*****************************************************************************/
void
VolumeSlider::SetEnabled(bool enable)
{
if (enable != IsEnabled())
{
BControl::SetEnabled(enable);
_MakeBitmaps();
Invalidate();
}
}
/*****************************************************************************
* VolumeSlider::Draw
*****************************************************************************/
void
VolumeSlider::Draw(BRect updateRect)
{
if (IsValid())
{
BRect r(Bounds());
float sliderSideWidth = kVolumeSliderBitmapWidth;
float sliderStart = (r.left + sliderSideWidth);
float sliderEnd = (r.right - sliderSideWidth);
float knobPos = sliderStart
+ (sliderEnd - sliderStart - 1.0) * (Value() - fMinValue)
/ (fMaxValue - fMinValue);
// draw both sides (the original from Be doesn't seem
// to make a difference for enabled/disabled state)
DrawBitmapAsync(fLeftSideBits, r.LeftTop());
DrawBitmapAsync(fRightSideBits, BPoint(sliderEnd + 1.0, r.top));
// colors for the slider area between the two bitmaps
rgb_color background = kBackground;//ui_color(B_PANEL_BACKGROUND_COLOR);
rgb_color shadow = tint_color(background, B_DARKEN_2_TINT);
rgb_color softShadow = tint_color(background, B_DARKEN_1_TINT);
rgb_color darkShadow = tint_color(background, B_DARKEN_4_TINT);
rgb_color midShadow = tint_color(background, B_DARKEN_3_TINT);
rgb_color light = tint_color(background, B_LIGHTEN_MAX_TINT);
rgb_color softLight = tint_color(background, B_LIGHTEN_1_TINT);
rgb_color green = kGreen;
rgb_color greenShadow = kGreenShadow;
rgb_color black = kBlack;
rgb_color dotGrey = midShadow;
rgb_color dotGreen = greenShadow;
// make dimmed version of colors if we're disabled
if (!IsEnabled())
{
shadow = (rgb_color){ 200, 200, 200, 255 };
softShadow = dimmed_color_cmap8(softShadow, background, DIM_LEVEL);
darkShadow = dimmed_color_cmap8(darkShadow, background, DIM_LEVEL);
midShadow = shadow;
light = dimmed_color_cmap8(light, background, DIM_LEVEL);
softLight = dimmed_color_cmap8(softLight, background, DIM_LEVEL);
green = dimmed_color_cmap8(green, background, DIM_LEVEL);
greenShadow = dimmed_color_cmap8(greenShadow, background, DIM_LEVEL);
black = dimmed_color_cmap8(black, background, DIM_LEVEL);
dotGreen = dotGrey;
}
else if (fMuted)
{
green = tint_color(kBackground, B_DARKEN_3_TINT);
greenShadow = tint_color(kBackground, B_DARKEN_4_TINT);
dotGreen = greenShadow;
}
// draw slider edges between bitmaps
BeginLineArray(7);
AddLine(BPoint(sliderStart, r.top),
BPoint(sliderEnd, r.top), softShadow);
AddLine(BPoint(sliderStart, r.bottom),
BPoint(sliderEnd, r.bottom), softLight);
r.InsetBy(0.0, 1.0);
AddLine(BPoint(sliderStart, r.top),
BPoint(sliderEnd, r.top), black);
AddLine(BPoint(sliderStart, r.bottom),
BPoint(sliderEnd, r.bottom), light);
r.top++;
AddLine(BPoint(sliderStart, r.top),
BPoint(knobPos, r.top), greenShadow);
AddLine(BPoint(knobPos, r.top),
BPoint(sliderEnd, r.top), midShadow);
r.top++;
AddLine(BPoint(sliderStart, r.top),
BPoint(knobPos, r.top), greenShadow);
EndLineArray();
// fill rest inside of slider
r.InsetBy(0.0, 1.0);
r.left = sliderStart;
r.right = knobPos;
SetHighColor(green);
FillRect(r, B_SOLID_HIGH);
r.left = knobPos + 1.0;
r.right = sliderEnd;
r.top -= 1.0;
SetHighColor(shadow);
FillRect(r, B_SOLID_HIGH);
// draw little dots inside
int32 dotCount = (int32)((sliderEnd - sliderStart) / 5.0);
BPoint dotPos;
dotPos.y = r.top + 4.0;
for (int32 i = 0; i < dotCount; i++)
{
dotPos.x = sliderStart + i * 5.0 + 4.0;
SetHighColor(dotPos.x < knobPos ? dotGreen : dotGrey);
StrokeLine(dotPos, BPoint(dotPos.x, dotPos.y + 1.0));
}
// draw knob
r.top -= 1.0;
SetDrawingMode(B_OP_OVER); // part of knob is transparent
DrawBitmapAsync(fKnobBits, BPoint(knobPos - kVolumeSliderKnobWidth / 2, r.top));
}
}
/*****************************************************************************
* VolumeSlider::MouseDown
*****************************************************************************/
void
VolumeSlider::MouseDown(BPoint where)
{
if (Bounds().Contains(where) && IsEnabled())
{
fTracking = true;
SetValue(_ValueFor(where.x));
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
}
}
/*****************************************************************************
* VolumeSlider::MouseMoved
*****************************************************************************/
void
VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
{
if (fTracking)
SetValue(_ValueFor(where.x));
}
/*****************************************************************************
* VolumeSlider::MouseUp
*****************************************************************************/
void
VolumeSlider::MouseUp(BPoint where)
{
fTracking = false;
}
/*****************************************************************************
* VolumeSlider::IsValid
*****************************************************************************/
bool
VolumeSlider::IsValid() const
{
return (fLeftSideBits && fLeftSideBits->IsValid()
&& fRightSideBits && fRightSideBits->IsValid()
&& fKnobBits && fKnobBits->IsValid());
}
/*****************************************************************************
* VolumeSlider::SetMuted
*****************************************************************************/
void
VolumeSlider::SetMuted(bool mute)
{
if (mute != fMuted)
{
fMuted = mute;
_MakeBitmaps();
Invalidate();
}
}
/*****************************************************************************
* VolumeSlider::_MakeBitmaps
*****************************************************************************/
void
VolumeSlider::_MakeBitmaps()
{
if (IsValid())
{
// left side of slider
memcpy(fLeftSideBits->Bits(), kVolumeSliderLeftBitmapBits,
fLeftSideBits->BitsLength());
// right side of slider
memcpy(fRightSideBits->Bits(), kVolumeSliderRightBits,
fRightSideBits->BitsLength());
// slider knob
int32 length = fKnobBits->BitsLength();
memcpy(fKnobBits->Bits(), kVolumeSliderKnobBits, length);
uint8* bits = (uint8*)fKnobBits->Bits();
// black was used in the knob to represent transparency
// use screen to get index for the "transarent" color used in the bitmap
BScreen screen(B_MAIN_SCREEN_ID);
uint8 blackIndex = screen.IndexForColor(kBlack);
// replace black index with transparent index
for (int32 i = 0; i < length; i++)
if (bits[i] == blackIndex)
bits[i] = B_TRANSPARENT_MAGIC_CMAP8;
if (!IsEnabled())
{
// make ghosted versions of the bitmaps
dim_bitmap(fLeftSideBits, kBackground, DIM_LEVEL);
dim_bitmap(fRightSideBits, kBackground, DIM_LEVEL);
dim_bitmap(fKnobBits, kBackground, DIM_LEVEL);
}
else if (fMuted)
{
// replace green color (and shadow) in left slider side
bits = (uint8*)fLeftSideBits->Bits();
length = fLeftSideBits->BitsLength();
uint8 greenIndex = screen.IndexForColor(kGreen);
uint8 greenShadowIndex = screen.IndexForColor(kGreenShadow);
rgb_color shadow = tint_color(kBackground, B_DARKEN_3_TINT);
rgb_color midShadow = tint_color(kBackground, B_DARKEN_4_TINT);
uint8 replaceIndex = screen.IndexForColor(shadow);
uint8 replaceShadowIndex = screen.IndexForColor(midShadow);
for (int32 i = 0; i < length; i++)
{
if (bits[i] == greenIndex)
bits[i] = replaceIndex;
else if (bits[i] == greenShadowIndex)
bits[i] = replaceShadowIndex;
}
}
}
}
/*****************************************************************************
* VolumeSlider::_ValueFor
*****************************************************************************/
int32
VolumeSlider::_ValueFor(float xPos) const
{
BRect r(Bounds());
float sliderStart = (r.left + kVolumeSliderBitmapWidth);
float sliderEnd = (r.right - kVolumeSliderBitmapWidth);
int32 value = fMinValue + (int32)(((xPos - sliderStart) * (fMaxValue - fMinValue))
/ (sliderEnd - sliderStart - 1.0));
if (value < fMinValue)
value = fMinValue;
if (value > fMaxValue)
value = fMaxValue;
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 )
{
#if 0
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;
#endif
}
}
/*****************************************************************************
* 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 << "-";
}
/*****************************************************************************
* MediaControlView.h: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tony@castley.net>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#ifndef BEOS_MEDIA_CONTROL_VIEW_H
#define BEOS_MEDIA_CONTROL_VIEW_H
#include <Box.h>
#include <Control.h>
class BBitmap;
class PlayPauseButton;
class PositionInfoView;
class SeekSlider;
class TransportButton;
class VolumeSlider;
class MediaControlView : public BBox
{
public:
MediaControlView( intf_thread_t * p_intf, BRect frame );
virtual ~MediaControlView();
// BBox
virtual void AttachedToWindow();
virtual void FrameResized(float width, float height);
virtual void GetPreferredSize(float* width, float* height);
virtual void MessageReceived(BMessage* message);
virtual void Pulse(); // detect stopped stream
// MediaControlView
void SetProgress( float position );
void SetStatus(int status, int rate);
void SetEnabled(bool enable);
void SetAudioEnabled(bool enable);
uint32 GetVolume() const;
void SetSkippable(bool backward,
bool forward);
void SetMuted(bool mute);
private:
void _LayoutControls(BRect frame) const;
BRect _MinFrame() const;
void _LayoutControl(BView* view,
BRect frame,
bool resizeWidth = false,
bool resizeHeight = false) const;
intf_thread_t * p_intf;
VolumeSlider* fVolumeSlider;
SeekSlider* fSeekSlider;
TransportButton* fSkipBack;
TransportButton* fSkipForward;
TransportButton* fRewind;
TransportButton* fForward;
PlayPauseButton* fPlayPause;
TransportButton* fStop;
TransportButton* fMute;
PositionInfoView* fPositionInfo;
int fCurrentRate;
int fCurrentStatus;
float fBottomControlHeight;
BRect fOldBounds;
bool fIsEnabled;
};
class SeekSlider : public BControl
{
public:
SeekSlider(intf_thread_t * p_intf,
BRect frame,
const char* name,
MediaControlView* owner );
virtual ~SeekSlider();
// BControl
virtual void AttachedToWindow();
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void MouseUp(BPoint where);
virtual void ResizeToPreferred();
// SeekSlider
void SetPosition(float position);
private:
int32 _ValueFor(float x) const;
void _StrokeFrame(BRect frame,
rgb_color left,
rgb_color top,
rgb_color right,
rgb_color bottom);
intf_thread_t * p_intf;
MediaControlView* fOwner;
bool fTracking;
};
class VolumeSlider : public BControl
{
public:
VolumeSlider(BRect frame,
const char* name,
int32 minValue,
int32 maxValue,
BMessage* message = NULL,
BHandler* target = NULL);
virtual ~VolumeSlider();
// BControl
virtual void AttachedToWindow();
virtual void SetValue(int32 value);
virtual void SetEnabled(bool enable);
virtual void Draw(BRect updateRect);
virtual void MouseDown(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void MouseUp(BPoint where);
// VolumeSlider
bool IsValid() const;
void SetMuted(bool mute);
private:
void _MakeBitmaps();
void _DimBitmap(BBitmap* bitmap);
int32 _ValueFor(float xPos) const;
BBitmap* fLeftSideBits;
BBitmap* fRightSideBits;
BBitmap* fKnobBits;
bool fTracking;
bool fMuted;
int32 fMinValue;
int32 fMaxValue;
};
class PositionInfoView : public BView
{
public:
PositionInfoView( BRect frame,
const char* name,
intf_thread_t *p_intf );
virtual ~PositionInfoView();
// BView
virtual void Draw( BRect updateRect );
virtual void ResizeToPreferred();
virtual void GetPreferredSize( float* width,
float* height );
virtual void Pulse();
// PositionInfoView
enum
{
MODE_SMALL,
MODE_BIG,
};
void SetMode( uint32 mode );
void GetBigPreferredSize( float* width,
float* height );
void SetFile( int32 index, int32 size );
void SetTitle( int32 index, int32 size );
void SetChapter( int32 index, int32 size );
void SetTime( int32 seconds );
void SetTime( const char* string );
private:
void _InvalidateContents( uint32 which = 0 );
void _MakeString( BString& into,
int32 index,
int32 maxIndex ) const;
// void _DrawAlignedString( const char* string,
// BRect frame,
// alignment mode = B_ALIGN_LEFT );
uint32 fMode;
int32 fCurrentFileIndex;
int32 fCurrentFileSize;
int32 fCurrentTitleIndex;
int32 fCurrentTitleSize;
int32 fCurrentChapterIndex;
int32 fCurrentChapterSize;
int32 fSeconds;
BString fTimeString;
bigtime_t fLastPulseUpdate;
float fStackedWidthCache;
float fStackedHeightCache;
intf_thread_t * p_intf;
};
#endif // BEOS_MEDIA_CONTROL_VIEW_H
/*****************************************************************************
* MessagesWindow.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Eric Petit <titer@videolan.org>
*
* 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.
*****************************************************************************/
/* BeOS headers */
#include <InterfaceKit.h>
#include <SupportKit.h>
/* VLC headers */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
/* BeOS module headers */
#include "InterfaceWindow.h"
#include "MessagesWindow.h"
/*****************************************************************************
* MessagesView::Pulse
*****************************************************************************/
void MessagesView::Pulse()
{
bool isScrolling = false;
if( fScrollBar->LockLooper() )
{
float min, max;
fScrollBar->GetRange( &min, &max );
if( fScrollBar->Value() != max )
isScrolling = true;
fScrollBar->UnlockLooper();
}
int i_start, oldLength;
const char * psz_module_type = NULL;
rgb_color red = { 200, 0, 0 };
rgb_color gray = { 150, 150, 150 };
rgb_color green = { 0, 150, 0 };
rgb_color orange = { 230, 180, 00 };
rgb_color color;
vlc_mutex_lock( p_sub->p_lock );
int i_stop = *p_sub->pi_stop;
vlc_mutex_unlock( p_sub->p_lock );
if( p_sub->i_start != i_stop )
{
for( i_start = p_sub->i_start;
i_start != i_stop;
i_start = (i_start+1) % VLC_MSG_QSIZE )
{
/* Add message */
switch( p_sub->p_msg[i_start].i_type )
{
case VLC_MSG_INFO: color = green; break;
case VLC_MSG_WARN: color = orange; break;
case VLC_MSG_ERR: color = red; break;
case VLC_MSG_DBG: color = gray; break;
}
psz_module_type = p_sub->p_msg[i_start].psz_object_type;
if( LockLooper() )
{
oldLength = TextLength();
BString string;
string << p_sub->p_msg[i_start].psz_module
<< " " << psz_module_type << " : "
<< p_sub->p_msg[i_start].psz_msg << "\n";
Insert( TextLength(), string.String(), strlen( string.String() ) );
SetFontAndColor( oldLength, TextLength(), NULL, 0, &color );
Draw( Bounds() );
UnlockLooper();
}
}
vlc_mutex_lock( p_sub->p_lock );
p_sub->i_start = i_start;
vlc_mutex_unlock( p_sub->p_lock );
}
/* Scroll at the end unless the is user is scrolling or selecting something */
int32 start, end;
GetSelection( &start, &end );
if( !isScrolling && start == end && fScrollBar->LockLooper() )
{
float min, max;
fScrollBar->GetRange( &min, &max );
fScrollBar->SetValue( max );
fScrollBar->UnlockLooper();
}
BTextView::Pulse();
}
/*****************************************************************************
* MessagesWindow::MessagesWindow
*****************************************************************************/
MessagesWindow::MessagesWindow( intf_thread_t * _p_intf,
BRect frame, const char * name )
: BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_NOT_ZOOMABLE ),
p_intf(_p_intf)
{
SetSizeLimits( 400, 2000, 200, 2000 );
p_sub = msg_Subscribe( p_intf );
BRect rect, textRect;
rect = Bounds();
rect.right -= B_V_SCROLL_BAR_WIDTH;
textRect = rect;
textRect.InsetBy( 5, 5 );
fMessagesView = new MessagesView( p_sub,
rect, "messages", textRect,
B_FOLLOW_ALL, B_WILL_DRAW );
fMessagesView->MakeEditable( false );
fMessagesView->SetStylable( true );
fScrollView = new BScrollView( "scrollview", fMessagesView, B_WILL_DRAW,
B_FOLLOW_ALL, false, true );
fMessagesView->fScrollBar = fScrollView->ScrollBar( B_VERTICAL );
AddChild( fScrollView );
/* start window thread in hidden state */
Hide();
Show();
}
/*****************************************************************************
* MessagesWindow::~MessagesWindow
*****************************************************************************/
MessagesWindow::~MessagesWindow()
{
msg_Unsubscribe( p_intf, p_sub );
}
/*****************************************************************************
* MessagesWindow::FrameResized
*****************************************************************************/
void MessagesWindow::FrameResized( float width, float height )
{
BWindow::FrameResized( width, height );
BRect rect = fMessagesView->Bounds();
rect.InsetBy( 5, 5 );
fMessagesView->SetTextRect( rect );
}
/*****************************************************************************
* MessagesWindow::QuitRequested
*****************************************************************************/
bool MessagesWindow::QuitRequested()
{
Hide();
return false;
}
/*****************************************************************************
* MessagesWindow::ReallyQuit
*****************************************************************************/
void MessagesWindow::ReallyQuit()
{
Lock();
Hide();
Quit();
}
/*****************************************************************************
* MessagesWindow.h
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Eric Petit <titer@videolan.org>
*
* 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.
*****************************************************************************/
#ifndef BEOS_MESSAGES_WINDOW_H
#define BEOS_MESSAGES_WINDOW_H
#include <Window.h>
class MessagesView : public BTextView
{
public:
MessagesView( msg_subscription_t * _p_sub,
BRect rect, char * name, BRect textRect,
uint32 resizingMode, uint32 flags )
: BTextView( rect, name, textRect,
resizingMode, flags ),
p_sub(_p_sub)
{
}
virtual void Pulse();
msg_subscription_t * p_sub;
BScrollBar * fScrollBar;
};
class MessagesWindow : public BWindow
{
public:
MessagesWindow( intf_thread_t * p_intf,
BRect frame, const char * name );
virtual ~MessagesWindow();
virtual void FrameResized( float, float );
virtual bool QuitRequested();
void ReallyQuit();
intf_thread_t * p_intf;
msg_subscription_t * p_sub;
BView * fBackgroundView;
MessagesView * fMessagesView;
BScrollView * fScrollView;
};
#endif // BEOS_PREFERENCES_WINDOW_H
SOURCES_beos = \
BeOS.cpp \
AudioOutput.cpp \
VideoOutput.cpp \
Interface.cpp \
InterfaceWindow.cpp \
InterfaceWindow.h \
ListViews.cpp \
ListViews.h \
DrawingTidbits.cpp \
DrawingTidbits.h \
TransportButton.cpp \
TransportButton.h \
PlayListWindow.cpp \
PlayListWindow.h \
PreferencesWindow.cpp \
PreferencesWindow.h \
MessagesWindow.cpp \
MessagesWindow.h \
MediaControlView.cpp \
MediaControlView.h \
Bitmaps.h \
MsgVals.h \
VideoWindow.h \
$(NULL)
/*****************************************************************************
* MsgVals.h
*****************************************************************************
* Copyright (C) 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tcastley@mail.powerup.com.au>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#ifndef BEOS_MESSAGE_VALUES_H
#define BEOS_MESSAGE_VALUES_H
#define PLAYING 0
#define PAUSED 1
#define OPEN_FILE 'opfl'
#define OPEN_DVD 'opdv'
#define LOAD_SUBFILE 'losu'
#define SUBFILE_RECEIVED 'sure'
#define OPEN_PLAYLIST 'oppl'
#define STOP_PLAYBACK 'stpl'
#define START_PLAYBACK 'play'
#define PAUSE_PLAYBACK 'papl'
#define HEIGHTH_PLAY 'hhpl'
#define QUARTER_PLAY 'qupl'
#define HALF_PLAY 'hapl'
#define NORMAL_PLAY 'nrpl'
#define TWICE_PLAY 'twpl'
#define FOUR_PLAY 'fopl'
#define HEIGHT_PLAY 'hepl'
#define SEEK_PLAYBACK 'seek'
#define VOLUME_CHG 'voch'
#define VOLUME_MUTE 'mute'
#define SELECT_CHANNEL 'chan'
#define SELECT_SUBTITLE 'subt'
#define PREV_TITLE 'prti'
#define NEXT_TITLE 'nxti'
#define TOGGLE_TITLE 'tgti'
#define PREV_CHAPTER 'prch'
#define NEXT_CHAPTER 'nxch'
#define TOGGLE_CHAPTER 'tgch'
#define PREV_FILE 'prfl'
#define NEXT_FILE 'nxfl'
#define NAVIGATE_PREV 'navp' // could be chapter, title or file
#define NAVIGATE_NEXT 'navn' // could be chapter, title or file
#define OPEN_PREFERENCES 'pref'
#define OPEN_MESSAGES 'mess'
#define TOGGLE_ON_TOP 'ontp'
#define SHOW_INTERFACE 'shin'
#define TOGGLE_FULL_SCREEN 'tgfs'
#define RESIZE_50 'rshl'
#define RESIZE_100 'rsor'
#define RESIZE_200 'rsdb'
#define RESIZE_TRUE 'rstr'
#define ASPECT_CORRECT 'asco'
#define VERT_SYNC 'vsyn'
#define WINDOW_FEEL 'wfel'
#define SCREEN_SHOT 'scrn'
#define MSG_UPDATE 'updt'
#define MSG_SOUNDPLAY 'move' // drag'n'drop from soundplay playlist
#define INTERFACE_CREATED 'ifcr' /* see VlcApplication::MessageReceived()
* in src/misc/beos_specific.cpp */
#define SHORTCUT 'shcu'
#endif // BEOS_MESSAGE_VALUES_H
/*****************************************************************************
* PlayListWindow.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Tony Castley <tony@castley.net>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#if 0
/* System headers */
#include <InterfaceKit.h>
#include <StorageKit.h>
/* VLC headers */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
/* BeOS interface headers */
#include "InterfaceWindow.h"
#include "ListViews.h"
#include "MsgVals.h"
#include "PlayListWindow.h"
enum
{
MSG_SELECT_ALL = 'sall',
MSG_SELECT_NONE = 'none',
MSG_RANDOMIZE = 'rndm',
MSG_SORT_REVERSE = 'srtr',
MSG_SORT_NAME = 'srtn',
MSG_SORT_PATH = 'srtp',
MSG_REMOVE = 'rmov',
MSG_REMOVE_ALL = 'rmal',
MSG_SELECTION_CHANGED = 'slch',
MSG_SET_DISPLAY = 'stds',
};
/*****************************************************************************
* PlayListWindow::PlayListWindow
*****************************************************************************/
PlayListWindow::PlayListWindow( BRect frame, const char* name,
InterfaceWindow* mainWindow,
intf_thread_t *p_interface )
: BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_WILL_ACCEPT_FIRST_CLICK | B_ASYNCHRONOUS_CONTROLS ),
fMainWindow( mainWindow )
{
char psz_tmp[1024];
#define ADD_ELLIPSIS( a ) \
memset( psz_tmp, 0, 1024 ); \
snprintf( psz_tmp, 1024, "%s%s", a, B_UTF8_ELLIPSIS );
p_intf = p_interface;
SetName( _("playlist") );
// set up the main menu bar
fMenuBar = new BMenuBar( BRect(0.0, 0.0, frame.Width(), 15.0), "main menu",
B_FOLLOW_NONE, B_ITEMS_IN_ROW, false );
AddChild( fMenuBar );
// Add the File menu
BMenu *fileMenu = new BMenu( _("File") );
fMenuBar->AddItem( fileMenu );
ADD_ELLIPSIS( _("Open File") );
BMenuItem* item = new BMenuItem( psz_tmp, new BMessage( OPEN_FILE ), 'O' );
item->SetTarget( fMainWindow );
fileMenu->AddItem( item );
CDMenu* cd_menu = new CDMenu( _("Open Disc") );
fileMenu->AddItem( cd_menu );
fileMenu->AddSeparatorItem();
item = new BMenuItem( _("Close"),
new BMessage( B_QUIT_REQUESTED ), 'W' );
fileMenu->AddItem( item );
// Add the Edit menu
BMenu *editMenu = new BMenu( _("Edit") );
fMenuBar->AddItem( editMenu );
fSelectAllMI = new BMenuItem( _("Select All"),
new BMessage( MSG_SELECT_ALL ), 'A' );
editMenu->AddItem( fSelectAllMI );
fSelectNoneMI = new BMenuItem( _("Select None"),
new BMessage( MSG_SELECT_NONE ), 'A', B_SHIFT_KEY );
editMenu->AddItem( fSelectNoneMI );
editMenu->AddSeparatorItem();
fSortReverseMI = new BMenuItem( _("Sort Reverse"),
new BMessage( MSG_SORT_REVERSE ), 'F' );
editMenu->AddItem( fSortReverseMI );
fSortNameMI = new BMenuItem( _("Sort by Name"),
new BMessage( MSG_SORT_NAME ), 'N' );
fSortNameMI->SetEnabled( false );
editMenu->AddItem( fSortNameMI );
fSortPathMI = new BMenuItem( _("Sort by Path"),
new BMessage( MSG_SORT_PATH ), 'P' );
fSortPathMI->SetEnabled( false );
editMenu->AddItem( fSortPathMI );
fRandomizeMI = new BMenuItem( _("Randomize"),
new BMessage( MSG_RANDOMIZE ), 'R' );
fRandomizeMI->SetEnabled( false );
editMenu->AddItem( fRandomizeMI );
editMenu->AddSeparatorItem();
fRemoveMI = new BMenuItem( _("Remove"),
new BMessage( MSG_REMOVE ) );
editMenu->AddItem( fRemoveMI );
fRemoveAllMI = new BMenuItem( _("Remove All"),
new BMessage( MSG_REMOVE_ALL ) );
editMenu->AddItem( fRemoveAllMI );
// Add View menu
fViewMenu = new BMenu( _("View") );
fMenuBar->AddItem( fViewMenu );
fViewMenu->SetRadioMode( true );
BMessage* message = new BMessage( MSG_SET_DISPLAY );
message->AddInt32( "mode", DISPLAY_PATH );
item = new BMenuItem( _("Path"), message );
item->SetMarked( true );
fViewMenu->AddItem( item );
message = new BMessage( MSG_SET_DISPLAY );
message->AddInt32( "mode", DISPLAY_NAME );
item = new BMenuItem( _("Name"), message );
fViewMenu->AddItem( item );
// make menu bar resize to correct height
float menuWidth, menuHeight;
fMenuBar->GetPreferredSize( &menuWidth, &menuHeight );
// don't change next line! it's a workarround!
fMenuBar->ResizeTo( frame.Width(), menuHeight );
frame = Bounds();
frame.top += fMenuBar->Bounds().IntegerHeight() + 1;
frame.right -= B_V_SCROLL_BAR_WIDTH;
fListView = new PlaylistView( p_intf, frame, fMainWindow,
new BMessage( MSG_SELECTION_CHANGED ) );
fBackgroundView = new BScrollView( "playlist scrollview",
fListView, B_FOLLOW_ALL_SIDES,
0, false, true,
B_NO_BORDER );
AddChild( fBackgroundView );
// be up to date
UpdatePlaylist();
FrameResized( Bounds().Width(), Bounds().Height() );
SetSizeLimits( menuWidth * 1.5, menuWidth * 8.0,
menuHeight * 5.0, menuHeight * 50.0 );
UpdatePlaylist( true );
// start window thread in hidden state
Hide();
Show();
}
/*****************************************************************************
* PlayListWindow::~PlayListWindow
*****************************************************************************/
PlayListWindow::~PlayListWindow()
{
}
/*****************************************************************************
* PlayListWindow::QuitRequested
*****************************************************************************/
bool
PlayListWindow::QuitRequested()
{
Hide();
return false;
}
/*****************************************************************************
* PlayListWindow::MessageReceived
*****************************************************************************/
void
PlayListWindow::MessageReceived( BMessage * p_message )
{
switch ( p_message->what )
{
case OPEN_DVD:
case B_REFS_RECEIVED:
case B_SIMPLE_DATA:
// forward to interface window
fMainWindow->PostMessage( p_message );
break;
case MSG_SELECT_ALL:
fListView->Select( 0, fListView->CountItems() - 1 );
break;
case MSG_SELECT_NONE:
fListView->DeselectAll();
break;
case MSG_RANDOMIZE:
break;
case MSG_SORT_REVERSE:
fListView->SortReverse();
break;
case MSG_SORT_NAME:
break;
case MSG_SORT_PATH:
break;
case MSG_REMOVE:
fListView->RemoveSelected();
break;
case MSG_REMOVE_ALL:
fListView->Select( 0, fListView->CountItems() - 1 );
fListView->RemoveSelected();
break;
case MSG_SELECTION_CHANGED:
_CheckItemsEnableState();
break;
case MSG_SET_DISPLAY:
{
uint32 mode;
if ( p_message->FindInt32( "mode", (int32*)&mode ) == B_OK )
SetDisplayMode( mode );
break;
}
case B_MODIFIERS_CHANGED:
fListView->ModifiersChanged();
break;
default:
BWindow::MessageReceived( p_message );
break;
}
}
/*****************************************************************************
* PlayListWindow::FrameResized
*****************************************************************************/
void
PlayListWindow::FrameResized(float width, float height)
{
BRect r(Bounds());
fMenuBar->MoveTo(r.LeftTop());
fMenuBar->ResizeTo(r.Width(), fMenuBar->Bounds().Height());
r.top += fMenuBar->Bounds().Height() + 1.0;
fBackgroundView->MoveTo(r.LeftTop());
// the "+ 1.0" is to make the scrollbar
// be partly covered by the window border
fBackgroundView->ResizeTo(r.Width() + 1.0, r.Height() + 1.0);
}
/*****************************************************************************
* PlayListWindow::ReallyQuit
*****************************************************************************/
void
PlayListWindow::ReallyQuit()
{
Lock();
Hide();
Quit();
}
/*****************************************************************************
* PlayListWindow::UpdatePlaylist
*****************************************************************************/
void
PlayListWindow::UpdatePlaylist( bool rebuild )
{
playlist_t * p_playlist;
if( rebuild )
fListView->RebuildList();
p_playlist = pl_Hold( p_intf );
fListView->SetCurrent( p_playlist->i_index );
fListView->SetPlaying( p_playlist->status.i_status == PLAYLIST_RUNNING );
pl_Release( p_intf );
_CheckItemsEnableState();
}
/*****************************************************************************
* PlayListWindow::SetDisplayMode
*****************************************************************************/
void
PlayListWindow::SetDisplayMode( uint32 mode )
{
if ( Lock() )
{
// propagate to list view
fListView->SetDisplayMode( mode );
// mark correct menu item
for ( int32 i = 0; BMenuItem* item = fViewMenu->ItemAt( i ); i++ )
{
BMessage* message = item->Message();
uint32 itemMode;
if ( message
&& message->FindInt32( "mode", (int32*)&itemMode ) == B_OK
&& itemMode == mode )
{
item->SetMarked( true );
break;
}
}
Unlock();
}
}
/*****************************************************************************
* PlayListWindow::DisplayMode
*****************************************************************************/
uint32
PlayListWindow::DisplayMode() const
{
return fListView->DisplayMode();
}
/*****************************************************************************
* PlayListWindow::_CheckItemsEnableState
*****************************************************************************/
void
PlayListWindow::_CheckItemsEnableState() const
{
// check if one item selected
int32 test = fListView->CurrentSelection( 0 );
bool enable1 = test >= 0;
// check if at least two items selected
test = fListView->CurrentSelection( 1 );
bool enable2 = test >= 0;
bool notEmpty = fListView->CountItems() > 0;
_SetMenuItemEnabled( fSelectAllMI, notEmpty );
_SetMenuItemEnabled( fSelectNoneMI, enable1 );
_SetMenuItemEnabled( fSortReverseMI, enable2 );
// _SetMenuItemEnabled( fSortNameMI, enable2 );
// _SetMenuItemEnabled( fSortPathMI, enable2 );
// _SetMenuItemEnabled( fRandomizeMI, enable2 );
_SetMenuItemEnabled( fRemoveMI, enable1 );
_SetMenuItemEnabled( fRemoveAllMI, notEmpty );
}
/*****************************************************************************
* PlayListWindow::_SetMenuItemEnabled
*****************************************************************************/
void
PlayListWindow::_SetMenuItemEnabled( BMenuItem* item, bool enabled ) const
{
// this check should actally be done in BMenuItem::SetEnabled(), but it is not...
if ( item->IsEnabled() != enabled )
item->SetEnabled( enabled );
}
#endif
/*****************************************************************************
* PlayListWindow.h: BeOS interface window class prototype
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Tony Castley <tcastley@mail.powerup.com.au>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#if 0
#ifndef BEOS_PLAY_LIST_WINDOW_H
#define BEOS_PLAY_LIST_WINDOW_H
#include <Window.h>
class BMenuItem;
class InterfaceWindow;
class PlaylistView;
class PlayListWindow : public BWindow
{
public:
PlayListWindow(BRect frame,
const char* name,
InterfaceWindow* mainWindow,
intf_thread_t *p_interface );
virtual ~PlayListWindow();
// BWindow
virtual bool QuitRequested();
virtual void MessageReceived(BMessage *message);
virtual void FrameResized(float width, float height);
// PlayListWindow
void ReallyQuit();
void UpdatePlaylist( bool rebuild = false );
void SetDisplayMode( uint32 mode );
uint32 DisplayMode() const;
private:
void _CheckItemsEnableState() const;
void _SetMenuItemEnabled( BMenuItem* item,
bool enabled ) const;
PlaylistView * fListView;
BView * fBackgroundView;
BMenuBar * fMenuBar;
InterfaceWindow * fMainWindow;
BMenuItem* fSelectAllMI;
BMenuItem* fSelectNoneMI;
BMenuItem* fSortReverseMI;
BMenuItem* fSortNameMI;
BMenuItem* fSortPathMI;
BMenuItem* fRandomizeMI;
BMenuItem* fRemoveMI;
BMenuItem* fRemoveAllMI;
BMenu* fViewMenu;
intf_thread_t * p_intf;
};
#endif // BEOS_PLAY_LIST_WINDOW_H
#endif
/*****************************************************************************
* PreferencesWindow.cpp: beos interface
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Eric Petit <titer@m0k.org>
*
* 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.
*****************************************************************************/
#include <String.h>
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
#include <vlc_keys.h>
#include <vlc_config_cat.h>
#include "PreferencesWindow.h"
#define TYPE_CATEGORY 0
#define TYPE_SUBCATEGORY 2
#define TYPE_MODULE 3
/*****************************************************************************
* PreferencesWindow::PreferencesWindow
*****************************************************************************/
PreferencesWindow::PreferencesWindow( intf_thread_t * _p_intf,
BRect frame, const char * name )
: BWindow( frame, name, B_FLOATING_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
B_NOT_ZOOMABLE )
{
p_intf = _p_intf;
fCurrent = NULL;
BRect rect;
SetSizeLimits( PREFS_WINDOW_WIDTH, 2000, PREFS_WINDOW_HEIGHT, 2000 );
/* The "background" view */
fPrefsView = new BView( Bounds(), NULL, B_FOLLOW_ALL, B_WILL_DRAW );
fPrefsView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
AddChild( fPrefsView );
/* Create a scrollable outline view for the preferences tree */
rect = Bounds();
rect.InsetBy( 10, 10 );
rect.right = rect.left + 150;
fOutline = new BOutlineListView( rect, "preferences tree",
B_SINGLE_SELECTION_LIST,
B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM );
BScrollView * scrollview =
new BScrollView( "scrollview", fOutline,
B_FOLLOW_LEFT | B_FOLLOW_TOP_BOTTOM,
0, false, true );
fPrefsView->AddChild( scrollview );
/* We need to be informed if the user selects an item */
fOutline->SetSelectionMessage( new BMessage( PREFS_ITEM_SELECTED ) );
/* Create a dummy, empty view so we can correctly place the real
config views later */
rect.bottom -= 40;
rect.left = rect.right + 15 + B_V_SCROLL_BAR_WIDTH;
rect.right = Bounds().right - 15;
fDummyView = new BView( rect, "", B_FOLLOW_ALL_SIDES, B_WILL_DRAW );
fDummyView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
fPrefsView->AddChild( fDummyView );
/* Fill the tree */
vlc_list_t * p_list;
p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE, FIND_ANYWHERE );
if( !p_list )
{
msg_Warn( p_intf, "couldn't find any module !" );
return;
}
/* Find the main module */
module_t * p_module = NULL;
module_config_t * p_item = NULL;
for( int i = 0; i < p_list->i_count; i++ )
{
p_module = (module_t*) p_list->p_values[i].p_object;
if( !strcmp( p_module->psz_object_name, "main" ) &&
( p_item = p_module->p_config ) )
break;
else
p_module = NULL;
}
ConfigItem * catItem = NULL, * subcatItem, * otherItem;
if( p_module )
{
/* We found the main module, build the category tree */
for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
{
switch( p_item->i_type )
{
case CONFIG_CATEGORY:
catItem = new ConfigItem( p_intf,
config_CategoryNameGet( p_item->i_value ),
false,
p_item->i_value,
TYPE_CATEGORY,
config_CategoryHelpGet( p_item->i_value ) );
fOutline->AddItem( catItem );
break;
case CONFIG_SUBCATEGORY:
if( catItem )
{
subcatItem = new ConfigItem( p_intf,
config_CategoryNameGet( p_item->i_value ),
false,
p_item->i_value,
TYPE_SUBCATEGORY,
config_CategoryHelpGet( p_item->i_value ) );
fOutline->AddUnder( subcatItem, catItem );
}
else
{
msg_Warn( p_intf, "subcategory without a category" );
}
break;
}
}
}
/* Now parse all others modules */
int category, subcategory, options;
for( int i = 0; i < p_list->i_count; i++ )
{
category = -1;
subcategory = -1;
options = 0;
p_module = (module_t*) p_list->p_values[i].p_object;
if( !strcmp( p_module->psz_object_name, "main" ) )
continue;
if( p_module->b_submodule ||
!( p_item = p_module->p_config ) )
continue;
for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
{
switch( p_item->i_type )
{
case CONFIG_CATEGORY:
category = p_item->i_value;
break;
case CONFIG_SUBCATEGORY:
subcategory = p_item->i_value;
break;
default:
if( p_item->i_type & CONFIG_ITEM )
options++;
}
if( options > 0 && category >= 0 && subcategory >= 0 )
{
break;
}
}
if( options < 1 || category < 0 || subcategory < 0 )
continue;
catItem = NULL;
for( int j = 0; j < fOutline->CountItemsUnder( NULL, true ); j++ )
{
catItem = (ConfigItem*)
fOutline->ItemUnderAt( NULL, true, j );
if( catItem->ObjectId() == category )
break;
else
catItem = NULL;
}
if( !catItem )
continue;
subcatItem = NULL;
for( int j = 0; j < fOutline->CountItemsUnder( catItem, true ); j++ )
{
subcatItem = (ConfigItem*)
fOutline->ItemUnderAt( catItem, true, j );
if( subcatItem->ObjectId() == subcategory )
break;
else
subcatItem = NULL;
}
if( !subcatItem )
subcatItem = catItem;
otherItem = new ConfigItem( p_intf,
p_module->psz_shortname ?
p_module->psz_shortname : p_module->psz_object_name,
p_module->b_submodule,
p_module->b_submodule ?
((module_t *)p_module->p_parent)->i_object_id :
p_module->i_object_id,
TYPE_MODULE,
NULL );
fOutline->AddUnder( otherItem, subcatItem );
}
vlc_list_release( p_list );
/* Collapse the whole tree */
for( int i = 0; i < fOutline->FullListCountItems(); i++ )
{
otherItem = (ConfigItem *) fOutline->FullListItemAt( i );
fOutline->Collapse( otherItem );
}
/* Set the correct values */
Apply( false );
/* Select the first item */
fOutline->Select( 0 );
/* Add the buttons */
BButton * button;
rect = Bounds();
rect.InsetBy( 10, 10 );
rect.left = rect.right - 80;
rect.top = rect.bottom - 25;
button = new BButton( rect, "", _("Apply"), new BMessage( PREFS_APPLY ),
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
button->MakeDefault( true );
fPrefsView->AddChild( button );
rect.OffsetBy( -90, 0 );
button = new BButton( rect, "", _("Save"), new BMessage( PREFS_SAVE ),
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
fPrefsView->AddChild( button );
rect.OffsetBy( -90, 0 );
button = new BButton( rect, "", _("Defaults"),
new BMessage( PREFS_DEFAULTS ),
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM );
fPrefsView->AddChild( button );
Hide();
Show();
}
/*****************************************************************************
* PreferencesWindow::~PreferencesWindow
*****************************************************************************/
PreferencesWindow::~PreferencesWindow()
{
}
/*****************************************************************************
* PreferencesWindow::QuitRequested
*****************************************************************************/
bool PreferencesWindow::QuitRequested()
{
if( !IsHidden() )
{
Hide();
}
return false;
}
/*****************************************************************************
* PreferencesWindow::MessageReceived
*****************************************************************************/
void PreferencesWindow::MessageReceived( BMessage * message )
{
switch( message->what )
{
case PREFS_ITEM_SELECTED:
Update();
break;
case PREFS_DEFAULTS:
config_ResetAll( p_intf );
config_SaveConfigFile( p_intf, NULL );
Apply( false );
break;
case PREFS_APPLY:
Apply( true );
break;
case PREFS_SAVE:
Apply( true );
config_SaveConfigFile( p_intf, NULL );
break;
default:
BWindow::MessageReceived( message );
}
}
/*****************************************************************************
* PreferencesWindow::FrameResized
*****************************************************************************/
void PreferencesWindow::FrameResized( float width, float height )
{
BWindow::FrameResized( width, height );
fCurrent->UpdateScrollBar();
}
/*****************************************************************************
* PreferencesWindow::Update
*****************************************************************************/
void PreferencesWindow::Update()
{
/* Get the selected item, if any */
if( fOutline->CurrentSelection() < 0 )
return;
/* Detach the old box if any */
if( fCurrent )
{
fCurrent->ResetScroll();
fDummyView->RemoveChild( fCurrent->Box() );
}
/* Add the new one... */
fCurrent = (ConfigItem *)
fOutline->ItemAt( fOutline->CurrentSelection() );
fDummyView->AddChild( fCurrent->Box() );
/* ...then resize it (we must resize it after it's attached or the
children don't get adjusted) */
fCurrent->Box()->ResizeTo( fDummyView->Bounds().Width(),
fDummyView->Bounds().Height() );
fCurrent->UpdateScrollBar();
}
/*****************************************************************************
* PreferencesWindow::Apply
* Apply changes if doIt is true, revert them otherwise
*****************************************************************************/
void PreferencesWindow::Apply( bool doIt )
{
ConfigItem * item;
for( int i = 0; i < fOutline->FullListCountItems(); i++ )
{
item = (ConfigItem*) fOutline->FullListItemAt( i );
item->Apply( doIt );
}
}
/*****************************************************************************
* PreferencesWindow::ReallyQuit
*****************************************************************************/
void PreferencesWindow::ReallyQuit()
{
Lock();
Hide();
Quit();
}
/***********************************************************************
* ConfigItem::ConfigItem
***********************************************************************
*
**********************************************************************/
ConfigItem::ConfigItem( intf_thread_t * _p_intf, char * name,
bool subModule, int objectId,
int type, char * help )
: BStringItem( name )
{
p_intf = _p_intf;
fSubModule = subModule;
fObjectId = objectId;
fType = type;
fHelp = strdup( help );
BRect r;
r = BRect( 0, 0, 100, 100 );
fBox = new BBox( r, NULL, B_FOLLOW_ALL );
fBox->SetLabel( name );
fTextView = NULL;
fScroll = NULL;
fView = NULL;
if( fType == TYPE_CATEGORY )
{
/* Category: we just show the help text */
r = fBox->Bounds();
r.InsetBy( 10, 10 );
r.top += 5;
fTextView = new VTextView( r, NULL, B_FOLLOW_ALL, B_WILL_DRAW);
fTextView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
fTextView->MakeEditable( false );
fTextView->MakeSelectable( false );
fTextView->Insert( fHelp );
fBox->AddChild( fTextView );
return;
}
vlc_list_t * p_list = NULL;
module_t * p_module = NULL;
if( fType == TYPE_MODULE )
{
p_module = (module_t *) vlc_object_get( fObjectId );
}
else
{
if( !( p_list = vlc_list_find( p_intf, VLC_OBJECT_MODULE,
FIND_ANYWHERE ) ) )
{
return;
}
for( int i = 0; i < p_list->i_count; i++ )
{
p_module = (module_t*) p_list->p_values[i].p_object;
if( !strcmp( p_module->psz_object_name, "main" ) )
break;
else
p_module = NULL;
}
}
if( !p_module )
/* Shouldn't happen */
return;
module_config_t * p_item;
p_item = fSubModule ? ((module_t *)p_module->p_parent)->p_config :
p_module->p_config;
if( fType == TYPE_SUBCATEGORY )
{
for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
{
if( p_item->i_type == CONFIG_SUBCATEGORY &&
p_item->i_value == fObjectId )
{
break;
}
}
}
r = fBox->Bounds();
r = BRect( 10,20,fBox->Bounds().right-B_V_SCROLL_BAR_WIDTH-10,
fBox->Bounds().bottom-10 );
fView = new BView( r, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE );
fView->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
r = fView->Bounds();
r.InsetBy( 10,10 );
ConfigWidget * widget;
for( ; p_item->i_type != CONFIG_HINT_END; p_item++ )
{
if( ( p_item->i_type == CONFIG_CATEGORY ||
p_item->i_type == CONFIG_SUBCATEGORY ) &&
fType == TYPE_SUBCATEGORY &&
p_item->i_value != fObjectId )
{
break;
}
widget = new ConfigWidget( p_intf, r, p_item );
if( !widget->InitCheck() )
{
delete widget;
continue;
}
fView->AddChild( widget );
r.top += widget->Bounds().Height();
}
if( fType == TYPE_MODULE )
{
vlc_object_release( p_module );
}
else
{
vlc_list_release( p_list );
}
/* Create a scroll view around our fView */
fScroll = new BScrollView( NULL, fView, B_FOLLOW_ALL, 0, false,
true, B_FANCY_BORDER );
fScroll->SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
fBox->AddChild( fScroll );
/* Adjust fView's height to the size it actually needs (we do this
only now so the BScrollView fits the BBox) */
fView->ResizeTo( fView->Bounds().Width(), r.top + 10 );
}
/***********************************************************************
* ConfigItem::~ConfigItem
***********************************************************************
*
**********************************************************************/
ConfigItem::~ConfigItem()
{
if( fHelp )
{
free( fHelp );
}
}
/*****************************************************************************
* ConfigItem::UpdateScrollBar
*****************************************************************************/
void ConfigItem::UpdateScrollBar()
{
/* We have to fix the scrollbar manually because it doesn't handle
correctly simple BViews */
if( !fScroll )
{
return;
}
/* Get the available BRect for display */
BRect display = fScroll->Bounds();
display.right -= B_V_SCROLL_BAR_WIDTH;
/* Fix the scrollbar */
BScrollBar * scrollBar;
BRect visible = display & fView->Bounds();
BRect total = display | fView->Bounds();
scrollBar = fScroll->ScrollBar( B_VERTICAL );
long max = (long)( fView->Bounds().Height() - visible.Height() );
if( max < 0 ) max = 0;
scrollBar->SetRange( 0, max );
scrollBar->SetProportion( visible.Height() / total.Height() );
scrollBar->SetSteps( 10, 100 );
/* We have to force redraw to avoid visual bugs when resizing
(BeOS bug?) */
fScroll->Invalidate();
fView->Invalidate();
}
/*****************************************************************************
* ConfigItem::ResetScroll
*****************************************************************************/
void ConfigItem::ResetScroll()
{
if( !fScroll )
{
return;
}
fView->ScrollTo( 0, 0 );
}
/***********************************************************************
* ConfigItem::Apply
***********************************************************************
*
**********************************************************************/
void ConfigItem::Apply( bool doIt )
{
if( !fScroll )
{
return;
}
/* Call ConfigWidget::Apply for every child of your fView */
ConfigWidget * widget;
for( int i = 0; i < fView->CountChildren(); i++ )
{
widget = (ConfigWidget*) fView->ChildAt( i );
widget->Apply( doIt );
}
}
/***********************************************************************
* ConfigWidget::ConfigWidget
***********************************************************************
* Builds a view with the right controls for the given config variable.
* rect: the BRect where we place ourselves. All we care is its width
* and its top coordinate, since we adapt our height to take only
* the place we need
**********************************************************************/
ConfigWidget::ConfigWidget( intf_thread_t * _p_intf, BRect rect,
module_config_t * p_item )
: BView( rect, NULL, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
B_WILL_DRAW )
{
p_intf = _p_intf;
SetViewColor( ui_color( B_PANEL_BACKGROUND_COLOR ) );
BRect r;
BMenuItem * menuItem;
fInitOK = true;
fType = p_item->i_type;
fName = strdup( p_item->psz_name );
switch( fType )
{
case CONFIG_ITEM_MODULE:
case CONFIG_ITEM_MODULE_CAT:
case CONFIG_ITEM_MODULE_LIST_CAT:
case CONFIG_ITEM_STRING:
case CONFIG_ITEM_FILE:
case CONFIG_ITEM_DIRECTORY:
case CONFIG_ITEM_INTEGER:
case CONFIG_ITEM_FLOAT:
ResizeTo( Bounds().Width(), 25 );
fTextControl = new VTextControl( Bounds(), NULL,
p_item->psz_text, NULL, new BMessage(),
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
AddChild( fTextControl );
break;
case CONFIG_ITEM_KEY:
ResizeTo( Bounds().Width(), 25 );
r = Bounds();
r.left = r.right - 100;
fPopUpMenu = new BPopUpMenu( "" );
fMenuField = new BMenuField( r, NULL, NULL, fPopUpMenu,
B_FOLLOW_RIGHT | B_FOLLOW_TOP );
for( unsigned i = 0;
i < sizeof( vlc_keys ) / sizeof( key_descriptor_t );
i++ )
{
menuItem = new BMenuItem( vlc_keys[i].psz_key_string, NULL );
fPopUpMenu->AddItem( menuItem );
}
r.right = r.left - 10; r.left = r.left - 60;
fShiftCheck = new BCheckBox( r, NULL, "Shift",
new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
r.right = r.left - 10; r.left = r.left - 60;
fCtrlCheck = new BCheckBox( r, NULL, "Ctrl",
new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
r.right = r.left - 10; r.left = r.left - 60;
fAltCheck = new BCheckBox( r, NULL, "Alt",
new BMessage(), B_FOLLOW_RIGHT | B_FOLLOW_TOP );
r.right = r.left - 10; r.left = 0; r.bottom -= 10;
fStringView = new BStringView( r, NULL, p_item->psz_text,
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
AddChild( fStringView );
AddChild( fAltCheck );
AddChild( fCtrlCheck );
AddChild( fShiftCheck );
AddChild( fMenuField );
break;
case CONFIG_ITEM_BOOL:
ResizeTo( Bounds().Width(), 25 );
fCheckBox = new BCheckBox( Bounds(), NULL, p_item->psz_text,
new BMessage(), B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP );
AddChild( fCheckBox );
break;
case CONFIG_SECTION:
fInitOK = false;
break;
default:
fInitOK = false;
}
}
ConfigWidget::~ConfigWidget()
{
free( fName );
}
/***********************************************************************
* ConfigWidget::Apply
***********************************************************************
*
**********************************************************************/
void ConfigWidget::Apply( bool doIt )
{
BMenuItem * menuItem;
char string[256];
vlc_value_t val;
switch( fType )
{
case CONFIG_ITEM_STRING:
case CONFIG_ITEM_FILE:
case CONFIG_ITEM_MODULE:
case CONFIG_ITEM_MODULE_CAT:
case CONFIG_ITEM_MODULE_LIST_CAT:
case CONFIG_ITEM_DIRECTORY:
if( doIt )
{
config_PutPsz( p_intf, fName, fTextControl->Text() );
}
else
{
fTextControl->SetText( config_GetPsz( p_intf, fName ) );
}
break;
case CONFIG_ITEM_INTEGER:
if( doIt )
{
config_PutInt( p_intf, fName, atoi( fTextControl->Text() ) );
}
else
{
snprintf( string, 256, "%d", config_GetInt( p_intf, fName ) );
fTextControl->SetText( string );
}
break;
case CONFIG_ITEM_FLOAT:
if( doIt )
{
config_PutFloat( p_intf, fName, atof( fTextControl->Text() ) );
}
else
{
snprintf( string, 256, "%f", config_GetFloat( p_intf, fName ) );
fTextControl->SetText( string );
}
break;
case CONFIG_ITEM_KEY:
if( doIt )
{
menuItem = fPopUpMenu->FindMarked();
if( menuItem )
{
val.i_int = vlc_keys[fPopUpMenu->IndexOf( menuItem )].i_key_code;
if( fAltCheck->Value() )
{
val.i_int |= KEY_MODIFIER_ALT;
}
if( fCtrlCheck->Value() )
{
val.i_int |= KEY_MODIFIER_CTRL;
}
if( fShiftCheck->Value() )
{
val.i_int |= KEY_MODIFIER_SHIFT;
}
var_Set( p_intf->p_libvlc, fName, val );
}
}
else
{
val.i_int = config_GetInt( p_intf, fName );
fAltCheck->SetValue( val.i_int & KEY_MODIFIER_ALT );
fCtrlCheck->SetValue( val.i_int & KEY_MODIFIER_CTRL );
fShiftCheck->SetValue( val.i_int & KEY_MODIFIER_SHIFT );
for( unsigned i = 0;
i < sizeof( vlc_keys ) / sizeof( key_descriptor_t ); i++ )
{
if( (unsigned) vlc_keys[i].i_key_code ==
( val.i_int & ~KEY_MODIFIER ) )
{
menuItem = fPopUpMenu->ItemAt( i );
menuItem->SetMarked( true );
break;
}
}
}
break;
case CONFIG_ITEM_BOOL:
if( doIt )
{
config_PutInt( p_intf, fName, fCheckBox->Value() );
}
else
{
fCheckBox->SetValue( config_GetInt( p_intf, fName ) );
}
break;
default:
break;
}
}
VTextView::VTextView( BRect frame, const char *name,
uint32 resizingMode, uint32 flags )
: BTextView( frame, name, BRect( 10,10,10,10 ), resizingMode, flags )
{
FrameResized( Bounds().Width(), Bounds().Height() );
}
void VTextView::FrameResized( float width, float height )
{
BTextView::FrameResized( width, height );
SetTextRect( BRect( 10,10, width-11, height-11 ) );
}
VTextControl::VTextControl( BRect frame, const char *name,
const char *label, const char *text,
BMessage * message, uint32 resizingMode )
: BTextControl( frame, name, label, text, message, resizingMode )
{
FrameResized( Bounds().Width(), Bounds().Height() );
}
void VTextControl::FrameResized( float width, float height )
{
BTextControl::FrameResized( width, height );
SetDivider( width / 2 );
}
/*****************************************************************************
* PreferencesWindow.h
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Eric Petit <titer@m0k.org>
*
* 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.
*****************************************************************************/
#ifndef BEOS_PREFERENCES_WINDOW_H
#define BEOS_PREFERENCES_WINDOW_H
#include <InterfaceKit.h>
#define PREFS_WINDOW_WIDTH 700
#define PREFS_WINDOW_HEIGHT 400
#define PREFS_ITEM_SELECTED 'pris'
#define PREFS_DEFAULTS 'prde'
#define PREFS_APPLY 'prap'
#define PREFS_SAVE 'prsa'
class VTextView : public BTextView
{
public:
VTextView( BRect frame, const char *name,
uint32 resizingMode, uint32 flags );
void FrameResized( float width, float height );
};
class VTextControl : public BTextControl
{
public:
VTextControl( BRect frame, const char *name,
const char *label, const char *text,
BMessage * message, uint32 resizingMode );
void FrameResized( float width, float height );
};
class ConfigWidget : public BView
{
public:
ConfigWidget( intf_thread_t * p_intf, BRect rect,
module_config_t * p_item );
~ConfigWidget();
bool InitCheck() { return fInitOK; }
void Apply( bool doIt );
private:
intf_thread_t * p_intf;
bool fInitOK;
int fType;
char * fName;
VTextControl * fTextControl;
BCheckBox * fCheckBox;
BPopUpMenu * fPopUpMenu;
BMenuField * fMenuField;
BSlider * fSlider;
BStringView * fStringView;
BCheckBox * fAltCheck;
BCheckBox * fCtrlCheck;
BCheckBox * fShiftCheck;
};
class ConfigItem : public BStringItem
{
public:
ConfigItem( intf_thread_t * p_intf,
char * name, bool subModule,
int objectId, int type, char * help );
~ConfigItem();
int ObjectId() { return fObjectId; }
BBox * Box() { return fBox; }
void UpdateScrollBar();
void ResetScroll();
void Apply( bool doIt );
private:
intf_thread_t * p_intf;
bool fSubModule;
int fObjectId;
int fType;
char * fHelp;
BBox * fBox;
VTextView * fTextView;
BScrollView * fScroll;
BView * fView;
};
class PreferencesWindow : public BWindow
{
public:
PreferencesWindow( intf_thread_t * p_intf,
BRect frame,
const char * name );
virtual ~PreferencesWindow();
virtual bool QuitRequested();
virtual void MessageReceived(BMessage* message);
virtual void FrameResized( float, float );
void Update();
void Apply( bool doIt );
void ReallyQuit();
private:
void BuildConfigView( ConfigItem * stringItem,
module_config_t ** pp_item,
bool stop_after_category );
BView * fPrefsView;
BOutlineListView * fOutline;
BView * fDummyView;
ConfigItem * fCurrent;
intf_thread_t * p_intf;
};
#endif // BEOS_PREFERENCES_WINDOW_H
/*****************************************************************************
* TransportButton.cpp
*****************************************************************************
* Copyright (C) 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tcastley@mail.powerup.com.au>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#include <Bitmap.h>
#include <Debug.h>
#include <MessageFilter.h>
#include <Screen.h>
#include <Window.h>
#include <map>
#include "TransportButton.h"
#include "DrawingTidbits.h"
class BitmapStash {
// Bitmap stash is a simple class to hold all the lazily-allocated
// bitmaps that the TransportButton needs when rendering itself.
// signature is a combination of the different enabled, pressed, playing, etc.
// flavors of a bitmap. If the stash does not have a particular bitmap,
// it turns around to ask the button to create one and stores it for next time.
public:
BitmapStash(TransportButton *);
~BitmapStash();
BBitmap *GetBitmap(uint32 signature);
private:
TransportButton *owner;
map<uint32, BBitmap *> stash;
};
BitmapStash::BitmapStash(TransportButton *owner)
: owner(owner)
{
}
BBitmap *
BitmapStash::GetBitmap(uint32 signature)
{
if (stash.find(signature) == stash.end()) {
BBitmap *newBits = owner->MakeBitmap(signature);
ASSERT(newBits);
stash[signature] = newBits;
}
return stash[signature];
}
BitmapStash::~BitmapStash()
{
// delete all the bitmaps
for (map<uint32, BBitmap *>::iterator i = stash.begin(); i != stash.end(); i++)
delete (*i).second;
}
class PeriodicMessageSender {
// used to send a specified message repeatedly when holding down a button
public:
static PeriodicMessageSender *Launch(BMessenger target,
const BMessage *message, bigtime_t period);
void Quit();
private:
PeriodicMessageSender(BMessenger target, const BMessage *message,
bigtime_t period);
~PeriodicMessageSender() {}
// use quit
static status_t TrackBinder(void *);
void Run();
BMessenger target;
BMessage message;
bigtime_t period;
bool requestToQuit;
};
PeriodicMessageSender::PeriodicMessageSender(BMessenger target,
const BMessage *message, bigtime_t period)
: target(target),
message(*message),
period(period),
requestToQuit(false)
{
}
PeriodicMessageSender *
PeriodicMessageSender::Launch(BMessenger target, const BMessage *message,
bigtime_t period)
{
PeriodicMessageSender *result = new PeriodicMessageSender(target, message, period);
thread_id thread = spawn_thread(&PeriodicMessageSender::TrackBinder,
"ButtonRepeatingThread", B_NORMAL_PRIORITY, result);
if (thread <= 0 || resume_thread(thread) != B_OK) {
// didn't start, don't leak self
delete result;
result = 0;
}
return result;
}
void
PeriodicMessageSender::Quit()
{
requestToQuit = true;
}
status_t
PeriodicMessageSender::TrackBinder(void *castToThis)
{
((PeriodicMessageSender *)castToThis)->Run();
return 0;
}
void
PeriodicMessageSender::Run()
{
for (;;) {
snooze(period);
if (requestToQuit)
break;
target.SendMessage(&message);
}
delete this;
}
class SkipButtonKeypressFilter : public BMessageFilter {
public:
SkipButtonKeypressFilter(uint32 shortcutKey, uint32 shortcutModifier,
TransportButton *target);
protected:
filter_result Filter(BMessage *message, BHandler **handler);
private:
uint32 shortcutKey;
uint32 shortcutModifier;
TransportButton *target;
};
SkipButtonKeypressFilter::SkipButtonKeypressFilter(uint32 shortcutKey,
uint32 shortcutModifier, TransportButton *target)
: BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
shortcutKey(shortcutKey),
shortcutModifier(shortcutModifier),
target(target)
{
}
filter_result
SkipButtonKeypressFilter::Filter(BMessage *message, BHandler **handler)
{
if (target->IsEnabled()
&& (message->what == B_KEY_DOWN || message->what == B_KEY_UP)) {
uint32 modifiers;
uint32 rawKeyChar = 0;
uint8 byte = 0;
int32 key = 0;
if (message->FindInt32("modifiers", (int32 *)&modifiers) != B_OK
|| message->FindInt32("raw_char", (int32 *)&rawKeyChar) != B_OK
|| message->FindInt8("byte", (int8 *)&byte) != B_OK
|| message->FindInt32("key", &key) != B_OK)
return B_DISPATCH_MESSAGE;
modifiers &= B_SHIFT_KEY | B_COMMAND_KEY | B_CONTROL_KEY
| B_OPTION_KEY | B_MENU_KEY;
// strip caps lock, etc.
if (modifiers == shortcutModifier && rawKeyChar == shortcutKey) {
if (message->what == B_KEY_DOWN)
target->ShortcutKeyDown();
else
target->ShortcutKeyUp();
return B_SKIP_MESSAGE;
}
}
// let others deal with this
return B_DISPATCH_MESSAGE;
}
TransportButton::TransportButton(BRect frame, const char *name,
const unsigned char *normalBits,
const unsigned char *pressedBits,
const unsigned char *disabledBits,
BMessage *invokeMessage, BMessage *startPressingMessage,
BMessage *pressingMessage, BMessage *donePressingMessage, bigtime_t period,
uint32 key, uint32 modifiers, uint32 resizeFlags)
: BControl(frame, name, "", invokeMessage, resizeFlags, B_WILL_DRAW | B_NAVIGABLE),
bitmaps(new BitmapStash(this)),
normalBits(normalBits),
pressedBits(pressedBits),
disabledBits(disabledBits),
startPressingMessage(startPressingMessage),
pressingMessage(pressingMessage),
donePressingMessage(donePressingMessage),
pressingPeriod(period),
mouseDown(false),
keyDown(false),
messageSender(0),
keyPressFilter(0)
{
if (key)
keyPressFilter = new SkipButtonKeypressFilter(key, modifiers, this);
}
void
TransportButton::AttachedToWindow()
{
_inherited::AttachedToWindow();
if (keyPressFilter)
Window()->AddCommonFilter(keyPressFilter);
// transparent to reduce flicker
SetViewColor(B_TRANSPARENT_COLOR);
}
void
TransportButton::DetachedFromWindow()
{
if (keyPressFilter)
Window()->RemoveCommonFilter(keyPressFilter);
_inherited::DetachedFromWindow();
}
TransportButton::~TransportButton()
{
delete startPressingMessage;
delete pressingMessage;
delete donePressingMessage;
delete bitmaps;
delete keyPressFilter;
}
void
TransportButton::WindowActivated(bool state)
{
if (!state)
ShortcutKeyUp();
_inherited::WindowActivated(state);
}
void
TransportButton::SetEnabled(bool on)
{
if (on != IsEnabled()) {
_inherited::SetEnabled(on);
if (!on)
ShortcutKeyUp();
}
}
const unsigned char *
TransportButton::BitsForMask(uint32 mask) const
{
switch (mask) {
case 0:
return normalBits;
case kDisabledMask:
return disabledBits;
case kPressedMask:
return pressedBits;
default:
break;
}
TRESPASS();
return 0;
}
BBitmap *
TransportButton::MakeBitmap(uint32 mask)
{
BRect r(Bounds());
BBitmap *result = new BBitmap(r, B_CMAP8);
uint8* src = (uint8*)BitsForMask(mask);
if (src && result && result->IsValid()) {
// int32 width = r.IntegerWidth() + 1;
int32 height = r.IntegerHeight() + 1;
int32 bpr = result->BytesPerRow();
uint8* dst = (uint8*)result->Bits();
// copy source bits into bitmap line by line,
// taking possible alignment into account
// since the source data has been generated
// by QuickRes, it still contains aligment too
// (hence skipping bpr and not width bytes)
for (int32 y = 0; y < height; y++) {
memcpy(dst, src, bpr);
src += bpr;
dst += bpr;
}
ReplaceTransparentColor(result, Parent()->ViewColor());
} else {
delete result;
result = NULL;
}
return result;
}
uint32
TransportButton::ModeMask() const
{
return (IsEnabled() ? 0 : kDisabledMask)
| (Value() ? kPressedMask : 0);
}
void
TransportButton::Draw(BRect)
{
DrawBitmapAsync(bitmaps->GetBitmap(ModeMask()));
}
void
TransportButton::StartPressing()
{
SetValue(1);
if (startPressingMessage)
Invoke(startPressingMessage);
if (pressingMessage) {
ASSERT(pressingMessage);
messageSender = PeriodicMessageSender::Launch(Messenger(),
pressingMessage, pressingPeriod);
}
}
void
TransportButton::MouseCancelPressing()
{
if (!mouseDown || keyDown)
return;
mouseDown = false;
if (pressingMessage) {
ASSERT(messageSender);
PeriodicMessageSender *sender = messageSender;
messageSender = 0;
sender->Quit();
}
if (donePressingMessage)
Invoke(donePressingMessage);
SetValue(0);
}
void
TransportButton::DonePressing()
{
if (pressingMessage) {
ASSERT(messageSender);
PeriodicMessageSender *sender = messageSender;
messageSender = 0;
sender->Quit();
}
Invoke();
SetValue(0);
}
void
TransportButton::MouseStartPressing()
{
if (mouseDown)
return;
mouseDown = true;
if (!keyDown)
StartPressing();
}
void
TransportButton::MouseDonePressing()
{
if (!mouseDown)
return;
mouseDown = false;
if (!keyDown)
DonePressing();
}
void
TransportButton::ShortcutKeyDown()
{
if (!IsEnabled())
return;
if (keyDown)
return;
keyDown = true;
if (!mouseDown)
StartPressing();
}
void
TransportButton::ShortcutKeyUp()
{
if (!keyDown)
return;
keyDown = false;
if (!mouseDown)
DonePressing();
}
void
TransportButton::MouseDown(BPoint)
{
if (!IsEnabled())
return;
ASSERT(Window()->Flags() & B_ASYNCHRONOUS_CONTROLS);
SetTracking(true);
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
MouseStartPressing();
}
void
TransportButton::MouseMoved(BPoint point, uint32 code, const BMessage *)
{
if (IsTracking() && Bounds().Contains(point) != Value()) {
if (!Value())
MouseStartPressing();
else
MouseCancelPressing();
}
}
void
TransportButton::MouseUp(BPoint point)
{
if (IsTracking()) {
if (Bounds().Contains(point))
MouseDonePressing();
else
MouseCancelPressing();
SetTracking(false);
}
}
void
TransportButton::SetStartPressingMessage(BMessage *message)
{
delete startPressingMessage;
startPressingMessage = message;
}
void
TransportButton::SetPressingMessage(BMessage *message)
{
delete pressingMessage;
pressingMessage = message;
}
void
TransportButton::SetDonePressingMessage(BMessage *message)
{
delete donePressingMessage;
donePressingMessage = message;
}
void
TransportButton::SetPressingPeriod(bigtime_t newTime)
{
pressingPeriod = newTime;
}
PlayPauseButton::PlayPauseButton(BRect frame, const char *name,
const unsigned char *normalBits, const unsigned char *pressedBits,
const unsigned char *disabledBits, const unsigned char *normalPlayingBits,
const unsigned char *pressedPlayingBits, const unsigned char *normalPausedBits,
const unsigned char *pressedPausedBits,
BMessage *invokeMessage, uint32 key, uint32 modifiers, uint32 resizeFlags)
: TransportButton(frame, name, normalBits, pressedBits,
disabledBits, invokeMessage, 0,
0, 0, 0, key, modifiers, resizeFlags),
normalPlayingBits(normalPlayingBits),
pressedPlayingBits(pressedPlayingBits),
normalPausedBits(normalPausedBits),
pressedPausedBits(pressedPausedBits),
state(PlayPauseButton::kStopped),
lastPauseBlinkTime(0),
lastModeMask(0)
{
}
void
PlayPauseButton::SetStopped()
{
if (state == kStopped || state == kAboutToPlay)
return;
state = kStopped;
Invalidate();
}
void
PlayPauseButton::SetPlaying()
{
if (state == kPlaying || state == kAboutToPause)
return;
state = kPlaying;
Invalidate();
}
const bigtime_t kPauseBlinkPeriod = 600000;
void
PlayPauseButton::SetPaused()
{
if (state == kAboutToPlay)
return;
// in paused state blink the LED on and off
bigtime_t now = system_time();
if (state == kPausedLedOn || state == kPausedLedOff) {
if (now - lastPauseBlinkTime < kPauseBlinkPeriod)
return;
if (state == kPausedLedOn)
state = kPausedLedOff;
else
state = kPausedLedOn;
} else
state = kPausedLedOn;
lastPauseBlinkTime = now;
Invalidate();
}
uint32
PlayPauseButton::ModeMask() const
{
if (!IsEnabled())
return kDisabledMask;
uint32 result = 0;
if (Value())
result = kPressedMask;
if (state == kPlaying || state == kAboutToPlay)
result |= kPlayingMask;
else if (state == kAboutToPause || state == kPausedLedOn)
result |= kPausedMask;
return result;
}
const unsigned char *
PlayPauseButton::BitsForMask(uint32 mask) const
{
switch (mask) {
case kPlayingMask:
return normalPlayingBits;
case kPlayingMask | kPressedMask:
return pressedPlayingBits;
case kPausedMask:
return normalPausedBits;
case kPausedMask | kPressedMask:
return pressedPausedBits;
default:
return _inherited::BitsForMask(mask);
}
TRESPASS();
return 0;
}
void
PlayPauseButton::StartPressing()
{
if (state == kPlaying)
state = kAboutToPause;
else
state = kAboutToPlay;
_inherited::StartPressing();
}
void
PlayPauseButton::MouseCancelPressing()
{
if (state == kAboutToPause)
state = kPlaying;
else
state = kStopped;
_inherited::MouseCancelPressing();
}
void
PlayPauseButton::DonePressing()
{
if (state == kAboutToPause) {
state = kPausedLedOn;
lastPauseBlinkTime = system_time();
} else if (state == kAboutToPlay)
state = kPlaying;
_inherited::DonePressing();
}
/*****************************************************************************
* TransportButton.h
*****************************************************************************
* Copyright (C) 2001 the VideoLAN team
* $Id$
*
* Authors: Tony Castley <tcastley@mail.powerup.com.au>
*
* 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.
*****************************************************************************/
#ifndef __MEDIA_BUTTON__
#define __MEDIA_BUTTON__
#include <Control.h>
class BMessage;
class BBitmap;
class PeriodicMessageSender;
class BitmapStash;
// TransportButton must be installed into a window with B_ASYNCHRONOUS_CONTROLS on
// currently no button focus drawing
class TransportButton : public BControl {
public:
TransportButton(BRect frame, const char *name,
const unsigned char *normalBits,
const unsigned char *pressedBits,
const unsigned char *disabledBits,
BMessage *invokeMessage, // done pressing over button
BMessage *startPressingMessage = 0, // just clicked button
BMessage *pressingMessage = 0, // periodical still pressing
BMessage *donePressing = 0, // tracked out of button/didn't invoke
bigtime_t period = 0, // pressing message period
uint32 key = 0, // optional shortcut key
uint32 modifiers = 0, // optional shortcut key modifier
uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP);
virtual ~TransportButton();
void SetStartPressingMessage(BMessage *);
void SetPressingMessage(BMessage *);
void SetDonePressingMessage(BMessage *);
void SetPressingPeriod(bigtime_t);
virtual void SetEnabled(bool);
protected:
enum {
kDisabledMask = 0x1,
kPressedMask = 0x2
};
virtual void AttachedToWindow();
virtual void DetachedFromWindow();
virtual void Draw(BRect);
virtual void MouseDown(BPoint);
virtual void MouseMoved(BPoint, uint32 code, const BMessage *);
virtual void MouseUp(BPoint);
virtual void WindowActivated(bool);
virtual BBitmap *MakeBitmap(uint32);
// lazy bitmap builder
virtual uint32 ModeMask() const;
// mode mask corresponding to the current button state
// - determines which bitmap will be used
virtual const unsigned char *BitsForMask(uint32) const;
// pick the right bits based on a mode mask
// overriding class can add swapping between two pairs of bitmaps, etc.
virtual void StartPressing();
virtual void MouseCancelPressing();
virtual void DonePressing();
private:
void ShortcutKeyDown();
void ShortcutKeyUp();
void MouseStartPressing();
void MouseDonePressing();
BitmapStash *bitmaps;
// using BitmapStash * here instead of a direct member so that the class can be private in
// the .cpp file
// bitmap bits used to build bitmaps for the different states
const unsigned char *normalBits;
const unsigned char *pressedBits;
const unsigned char *disabledBits;
BMessage *startPressingMessage;
BMessage *pressingMessage;
BMessage *donePressingMessage;
bigtime_t pressingPeriod;
bool mouseDown;
bool keyDown;
PeriodicMessageSender *messageSender;
BMessageFilter *keyPressFilter;
typedef BControl _inherited;
friend class SkipButtonKeypressFilter;
friend class BitmapStash;
};
class PlayPauseButton : public TransportButton {
// Knows about playing and paused states, blinks
// the pause LED during paused state
public:
PlayPauseButton(BRect frame, const char *name,
const unsigned char *normalBits,
const unsigned char *pressedBits,
const unsigned char *disabledBits,
const unsigned char *normalPlayingBits,
const unsigned char *pressedPlayingBits,
const unsigned char *normalPausedBits,
const unsigned char *pressedPausedBits,
BMessage *invokeMessage, // done pressing over button
uint32 key = 0, // optional shortcut key
uint32 modifiers = 0, // optional shortcut key modifier
uint32 resizeFlags = B_FOLLOW_LEFT | B_FOLLOW_TOP);
// These need get called periodically to update the button state
// OK to call them over and over - once the state is correct, the call
// is very low overhead
void SetStopped();
void SetPlaying();
void SetPaused();
protected:
virtual uint32 ModeMask() const;
virtual const unsigned char *BitsForMask(uint32) const;
virtual void StartPressing();
virtual void MouseCancelPressing();
virtual void DonePressing();
private:
const unsigned char *normalPlayingBits;
const unsigned char *pressedPlayingBits;
const unsigned char *normalPausedBits;
const unsigned char *pressedPausedBits;
enum PlayState {
kStopped,
kAboutToPlay,
kPlaying,
kAboutToPause,
kPausedLedOn,
kPausedLedOff
};
enum {
kPlayingMask = 0x4,
kPausedMask = 0x8
};
PlayState state;
bigtime_t lastPauseBlinkTime;
uint32 lastModeMask;
typedef TransportButton _inherited;
};
#endif // __MEDIA_BUTTON__
/*****************************************************************************
* vout_beos.cpp: beos video output display method
*****************************************************************************
* Copyright (C) 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Tony Castley <tcastley@mail.powerup.com.au>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <Application.h>
#include <BitmapStream.h>
#include <Bitmap.h>
#include <Directory.h>
#include <DirectWindow.h>
#include <File.h>
#include <InterfaceKit.h>
#include <NodeInfo.h>
#include <String.h>
#include <TranslatorRoster.h>
#include <WindowScreen.h>
/* VLC headers */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_interface.h>
#include <vlc_vout.h>
#include <vlc_keys.h>
#include "InterfaceWindow.h" // for load/save_settings()
#include "DrawingTidbits.h"
#include "MsgVals.h"
#include "VideoWindow.h"
/*****************************************************************************
* vout_sys_t: BeOS video output method descriptor
*****************************************************************************
* This structure is part of the video output thread descriptor.
* It describes the BeOS specific properties of an output thread.
*****************************************************************************/
struct vout_sys_t
{
VideoWindow * p_window;
int32_t i_width;
int32_t i_height;
// uint8_t *pp_buffer[3];
uint32_t source_chroma;
int i_index;
};
#define MIN_AUTO_VSYNC_REFRESH 61 // Hz
/*****************************************************************************
* beos_GetAppWindow : retrieve a BWindow pointer from the window name
*****************************************************************************/
BWindow*
beos_GetAppWindow(char *name)
{
int32_t index;
BWindow *window;
for (index = 0 ; ; index++)
{
window = be_app->WindowAt(index);
if (window == NULL)
break;
if (window->LockWithTimeout(20000) == B_OK)
{
if (strcmp(window->Name(), name) == 0)
{
window->Unlock();
break;
}
window->Unlock();
}
}
return window;
}
static const int beos_keys[][2] =
{
{ B_LEFT_ARROW, KEY_LEFT },
{ B_RIGHT_ARROW, KEY_RIGHT },
{ B_UP_ARROW, KEY_UP },
{ B_DOWN_ARROW, KEY_DOWN },
{ B_SPACE, ' ' },
{ B_ENTER, KEY_ENTER },
{ B_F1_KEY, KEY_F1 },
{ B_F2_KEY, KEY_F2 },
{ B_F3_KEY, KEY_F3 },
{ B_F4_KEY, KEY_F4 },
{ B_F5_KEY, KEY_F5 },
{ B_F6_KEY, KEY_F6 },
{ B_F7_KEY, KEY_F7 },
{ B_F8_KEY, KEY_F8 },
{ B_F9_KEY, KEY_F9 },
{ B_F10_KEY, KEY_F10 },
{ B_F11_KEY, KEY_F11 },
{ B_F12_KEY, KEY_F12 },
{ B_HOME, KEY_HOME },
{ B_END, KEY_END },
{ B_ESCAPE, KEY_ESC },
{ B_PAGE_UP, KEY_PAGEUP },
{ B_PAGE_DOWN, KEY_PAGEDOWN },
{ B_TAB, KEY_TAB },
{ B_BACKSPACE, KEY_BACKSPACE }
};
static int ConvertKeyFromVLC( int key )
{
for( unsigned i = 0; i < sizeof( beos_keys ) / sizeof( int ) / 2; i++ )
{
if( beos_keys[i][1] == key )
{
return beos_keys[i][0];
}
}
return key;
}
static int ConvertKeyToVLC( int key )
{
for( unsigned i = 0; i < sizeof( beos_keys ) / sizeof( int ) / 2; i++ )
{
if( beos_keys[i][0] == key )
{
return beos_keys[i][1];
}
}
return key;
}
/*****************************************************************************
* get_interface_window
*****************************************************************************/
BWindow*
get_interface_window()
{
return beos_GetAppWindow( "VLC " PACKAGE_VERSION );
}
class BackgroundView : public BView
{
public:
BackgroundView(BRect frame, VLCView* view)
: BView(frame, "background",
B_FOLLOW_ALL, B_FULL_UPDATE_ON_RESIZE),
fVideoView(view)
{
SetViewColor(kBlack);
}
virtual ~BackgroundView() {}
virtual void MouseDown(BPoint where)
{
// convert coordinates
where = fVideoView->ConvertFromParent(where);
// let him handle it
fVideoView->MouseDown(where);
}
virtual void MouseMoved(BPoint where, uint32_t transit,
const BMessage* dragMessage)
{
// convert coordinates
where = fVideoView->ConvertFromParent(where);
// let him handle it
fVideoView->MouseMoved(where, transit, dragMessage);
// notice: It might look like transit should be
// B_OUTSIDE_VIEW regardless, but leave it like this,
// otherwise, unwanted things will happen!
}
private:
VLCView* fVideoView;
};
/*****************************************************************************
* VideoSettings constructor and destructor
*****************************************************************************/
VideoSettings::VideoSettings()
: fVideoSize( SIZE_100 ),
fFlags( FLAG_CORRECT_RATIO ),
fSettings( new BMessage( 'sett' ) )
{
// read settings from disk
status_t ret = load_settings( fSettings, "video_settings", "VideoLAN Client" );
if ( ret == B_OK )
{
uint32_t flags;
if ( fSettings->FindInt32( "flags", (int32*)&flags ) == B_OK )
SetFlags( flags );
uint32_t size;
if ( fSettings->FindInt32( "video size", (int32*)&size ) == B_OK )
SetVideoSize( size );
}
else
{
// figure out if we should use vertical sync by default
BScreen screen(B_MAIN_SCREEN_ID);
if (screen.IsValid())
{
display_mode mode;
screen.GetMode(&mode);
float refresh = (mode.timing.pixel_clock * 1000)
/ ((mode.timing.h_total)* (mode.timing.v_total));
if (refresh < MIN_AUTO_VSYNC_REFRESH)
AddFlags(FLAG_SYNC_RETRACE);
}
}
}
VideoSettings::VideoSettings( const VideoSettings& clone )
: fVideoSize( clone.VideoSize() ),
fFlags( clone.Flags() ),
fSettings( NULL )
{
}
VideoSettings::~VideoSettings()
{
if ( fSettings )
{
// we are the default settings
// and write our settings to disk
if (fSettings->ReplaceInt32( "video size", VideoSize() ) != B_OK)
fSettings->AddInt32( "video size", VideoSize() );
if (fSettings->ReplaceInt32( "flags", Flags() ) != B_OK)
fSettings->AddInt32( "flags", Flags() );
save_settings( fSettings, "video_settings", "VideoLAN Client" );
delete fSettings;
}
else
{
// we are just a clone of the default settings
fDefaultSettings.SetVideoSize( VideoSize() );
fDefaultSettings.SetFlags( Flags() );
}
}
/*****************************************************************************
* VideoSettings::DefaultSettings
*****************************************************************************/
VideoSettings*
VideoSettings::DefaultSettings()
{
return &fDefaultSettings;
}
/*****************************************************************************
* VideoSettings::SetVideoSize
*****************************************************************************/
void
VideoSettings::SetVideoSize( uint32_t mode )
{
fVideoSize = mode;
}
// static variable initialization
VideoSettings
VideoSettings::fDefaultSettings;
/*****************************************************************************
* VideoWindow constructor and destructor
*****************************************************************************/
VideoWindow::VideoWindow(int v_width, int v_height, BRect frame,
vout_thread_t *p_videoout)
: BWindow(frame, NULL, B_TITLED_WINDOW, B_NOT_CLOSABLE | B_NOT_MINIMIZABLE),
i_width(frame.IntegerWidth()),
i_height(frame.IntegerHeight()),
winSize(frame),
i_buffer(0),
teardownwindow(false),
fTrueWidth(v_width),
fTrueHeight(v_height),
fCachedFeel(B_NORMAL_WINDOW_FEEL),
fInterfaceShowing(false),
fInitStatus(B_ERROR),
fSettings(new VideoSettings(*VideoSettings::DefaultSettings()))
{
p_vout = p_videoout;
// create the view to do the display
view = new VLCView( Bounds(), p_vout );
// create background view
BView *mainView = new BackgroundView( Bounds(), view );
AddChild(mainView);
mainView->AddChild(view);
// allocate bitmap buffers
for (int32_t i = 0; i < 3; i++)
bitmap[i] = NULL;
fInitStatus = _AllocateBuffers(v_width, v_height, &mode);
// make sure we layout the view correctly
FrameResized(i_width, i_height);
if (fInitStatus >= B_OK && mode == OVERLAY)
{
overlay_restrictions r;
bitmap[0]->GetOverlayRestrictions(&r);
SetSizeLimits((i_width * r.min_width_scale), i_width * r.max_width_scale,
(i_height * r.min_height_scale), i_height * r.max_height_scale);
}
// vlc settings override settings from disk
if (config_GetInt(p_vout, "fullscreen"))
fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
_SetToSettings();
}
VideoWindow::~VideoWindow()
{
int32 result;
teardownwindow = true;
wait_for_thread(fDrawThreadID, &result);
_FreeBuffers();
delete fSettings;
}
/*****************************************************************************
* VideoWindow::MessageReceived
*****************************************************************************/
void
VideoWindow::MessageReceived( BMessage *p_message )
{
switch( p_message->what )
{
case SHOW_INTERFACE:
SetInterfaceShowing( true );
break;
case TOGGLE_FULL_SCREEN:
BWindow::Zoom();
break;
case RESIZE_50:
case RESIZE_100:
case RESIZE_200:
if (IsFullScreen())
BWindow::Zoom();
_SetVideoSize(p_message->what);
break;
case VERT_SYNC:
SetSyncToRetrace(!IsSyncedToRetrace());
break;
case WINDOW_FEEL:
{
window_feel winFeel;
if (p_message->FindInt32("WinFeel", (int32*)&winFeel) == B_OK)
{
SetFeel(winFeel);
fCachedFeel = winFeel;
if (winFeel == B_FLOATING_ALL_WINDOW_FEEL)
fSettings->AddFlags(VideoSettings::FLAG_ON_TOP_ALL);
else
fSettings->ClearFlags(VideoSettings::FLAG_ON_TOP_ALL);
}
}
break;
case ASPECT_CORRECT:
SetCorrectAspectRatio(!CorrectAspectRatio());
break;
case B_KEY_DOWN:
case B_UNMAPPED_KEY_DOWN:
case B_KEY_UP:
case B_UNMAPPED_KEY_UP:
{
key_map * keys;
char * chars;
int32 key, modifiers;
if( p_message->FindInt32( "key", &key ) != B_OK ||
p_message->FindInt32( "modifiers", &modifiers ) != B_OK )
{
/* Shouldn't happen */
break;
}
if( ( p_message->what == B_KEY_UP ||
p_message->what == B_UNMAPPED_KEY_UP ) &&
!( modifiers & B_COMMAND_KEY ) )
{
/* We only use the KEY_UP messages to detect Alt+X
shortcuts (because the KEY_DOWN messages aren't
sent when Alt is pressed) */
break;
}
/* Special case for Alt+1, Alt+2 and Alt+3 shortcuts: since
the character depends on the keymap, we use the key codes
directly (18, 19, 20) */
if( ( modifiers & B_COMMAND_KEY ) &&
key >= 18 && key <= 20 )
{
if( key == 18 )
PostMessage( RESIZE_50 );
else if( key == 19 )
PostMessage( RESIZE_100 );
else
PostMessage( RESIZE_200 );
break;
}
/* Get the current keymap */
get_key_map( &keys, &chars );
if( key >= 128 || chars[keys->normal_map[key]] != 1 )
{
/* Weird key or Unicode character */
free( keys );
free( chars );
break;
}
vlc_value_t val;
val.i_int = ConvertKeyToVLC( chars[keys->normal_map[key]+1] );
if( modifiers & B_COMMAND_KEY )
{
val.i_int |= KEY_MODIFIER_ALT;
}
if( modifiers & B_SHIFT_KEY )
{
val.i_int |= KEY_MODIFIER_SHIFT;
}
if( modifiers & B_CONTROL_KEY )
{
val.i_int |= KEY_MODIFIER_CTRL;
}
var_Set( p_vout->p_libvlc, "key-pressed", val );
free( keys );
free( chars );
break;
}
default:
BWindow::MessageReceived( p_message );
break;
}
}
/*****************************************************************************
* VideoWindow::Zoom
*****************************************************************************/
void
VideoWindow::Zoom(BPoint origin, float width, float height )
{
ToggleFullScreen();
}
/*****************************************************************************
* VideoWindow::FrameMoved
*****************************************************************************/
void
VideoWindow::FrameMoved(BPoint origin)
{
if (IsFullScreen())
return ;
winSize = Frame();
}
/*****************************************************************************
* VideoWindow::FrameResized
*****************************************************************************/
void
VideoWindow::FrameResized( float width, float height )
{
int32_t useWidth = CorrectAspectRatio() ? i_width : fTrueWidth;
int32_t useHeight = CorrectAspectRatio() ? i_height : fTrueHeight;
float out_width, out_height;
float out_left, out_top;
float width_scale = width / useWidth;
float height_scale = height / useHeight;
if (width_scale <= height_scale)
{
out_width = (useWidth * width_scale);
out_height = (useHeight * width_scale);
out_left = 0;
out_top = (height - out_height) / 2;
}
else /* if the height is proportionally smaller */
{
out_width = (useWidth * height_scale);
out_height = (useHeight * height_scale);
out_top = 0;
out_left = (width - out_width) / 2;
}
view->MoveTo(out_left,out_top);
view->ResizeTo(out_width, out_height);
if (!IsFullScreen())
winSize = Frame();
}
/*****************************************************************************
* VideoWindow::ScreenChanged
*****************************************************************************/
void
VideoWindow::ScreenChanged(BRect frame, color_space format)
{
BScreen screen(this);
display_mode mode;
screen.GetMode(&mode);
float refresh = (mode.timing.pixel_clock * 1000)
/ ((mode.timing.h_total) * (mode.timing.v_total));
SetSyncToRetrace(refresh < MIN_AUTO_VSYNC_REFRESH);
}
/*****************************************************************************
* VideoWindow::Activate
*****************************************************************************/
void
VideoWindow::WindowActivated(bool active)
{
}
/*****************************************************************************
* VideoWindow::drawBuffer
*****************************************************************************/
void
VideoWindow::drawBuffer(int bufferIndex)
{
i_buffer = bufferIndex;
// sync to the screen if required
if (IsSyncedToRetrace())
{
BScreen screen(this);
screen.WaitForRetrace(22000);
}
if (fInitStatus >= B_OK && LockLooper())
{
// switch the overlay bitmap
if (mode == OVERLAY)
{
rgb_color key;
view->SetViewOverlay(bitmap[i_buffer],
bitmap[i_buffer]->Bounds() ,
view->Bounds(),
&key, B_FOLLOW_ALL,
B_OVERLAY_FILTER_HORIZONTAL|B_OVERLAY_FILTER_VERTICAL|
B_OVERLAY_TRANSFER_CHANNEL);
view->SetViewColor(key);
}
else
{
// switch the bitmap
view->DrawBitmap(bitmap[i_buffer], view->Bounds() );
}
UnlockLooper();
}
}
/*****************************************************************************
* VideoWindow::SetInterfaceShowing
*****************************************************************************/
void
VideoWindow::ToggleInterfaceShowing()
{
SetInterfaceShowing(!fInterfaceShowing);
}
/*****************************************************************************
* VideoWindow::SetInterfaceShowing
*****************************************************************************/
void
VideoWindow::SetInterfaceShowing(bool showIt)
{
BWindow* window = get_interface_window();
if (window)
{
if (showIt)
{
if (fCachedFeel != B_NORMAL_WINDOW_FEEL)
SetFeel(B_NORMAL_WINDOW_FEEL);
window->Activate(true);
SendBehind(window);
}
else
{
SetFeel(fCachedFeel);
Activate(true);
window->SendBehind(this);
}
fInterfaceShowing = showIt;
}
}
/*****************************************************************************
* VideoWindow::SetCorrectAspectRatio
*****************************************************************************/
void
VideoWindow::SetCorrectAspectRatio(bool doIt)
{
if (CorrectAspectRatio() != doIt)
{
if (doIt)
fSettings->AddFlags(VideoSettings::FLAG_CORRECT_RATIO);
else
fSettings->ClearFlags(VideoSettings::FLAG_CORRECT_RATIO);
FrameResized(Bounds().Width(), Bounds().Height());
}
}
/*****************************************************************************
* VideoWindow::CorrectAspectRatio
*****************************************************************************/
bool
VideoWindow::CorrectAspectRatio() const
{
return fSettings->HasFlags(VideoSettings::FLAG_CORRECT_RATIO);
}
/*****************************************************************************
* VideoWindow::ToggleFullScreen
*****************************************************************************/
void
VideoWindow::ToggleFullScreen()
{
SetFullScreen(!IsFullScreen());
}
/*****************************************************************************
* VideoWindow::SetFullScreen
*****************************************************************************/
void
VideoWindow::SetFullScreen(bool doIt)
{
if (doIt)
{
SetLook( B_NO_BORDER_WINDOW_LOOK );
BScreen screen( this );
BRect rect = screen.Frame();
Activate();
MoveTo(0.0, 0.0);
ResizeTo(rect.IntegerWidth(), rect.IntegerHeight());
be_app->ObscureCursor();
fInterfaceShowing = false;
fSettings->AddFlags(VideoSettings::FLAG_FULL_SCREEN);
}
else
{
SetLook( B_TITLED_WINDOW_LOOK );
MoveTo(winSize.left, winSize.top);
ResizeTo(winSize.IntegerWidth(), winSize.IntegerHeight());
be_app->ShowCursor();
fInterfaceShowing = true;
fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
}
}
/*****************************************************************************
* VideoWindow::IsFullScreen
*****************************************************************************/
bool
VideoWindow::IsFullScreen() const
{
return fSettings->HasFlags(VideoSettings::FLAG_FULL_SCREEN);
}
/*****************************************************************************
* VideoWindow::SetSyncToRetrace
*****************************************************************************/
void
VideoWindow::SetSyncToRetrace(bool doIt)
{
if (doIt)
fSettings->AddFlags(VideoSettings::FLAG_SYNC_RETRACE);
else
fSettings->ClearFlags(VideoSettings::FLAG_SYNC_RETRACE);
}
/*****************************************************************************
* VideoWindow::IsSyncedToRetrace
*****************************************************************************/
bool
VideoWindow::IsSyncedToRetrace() const
{
return fSettings->HasFlags(VideoSettings::FLAG_SYNC_RETRACE);
}
/*****************************************************************************
* VideoWindow::_AllocateBuffers
*****************************************************************************/
status_t
VideoWindow::_AllocateBuffers(int width, int height, int* mode)
{
// clear any old buffers
_FreeBuffers();
// set default mode
*mode = BITMAP;
bitmap_count = 3;
BRect bitmapFrame( 0, 0, width, height );
// read from config, if we are supposed to use overlay at all
int noOverlay = !config_GetInt( p_vout, "overlay" );
/* Test for overlay capability: for every chroma in colspace,
we try to do double-buffered overlay, single-buffered overlay
or basic overlay. If nothing worked, we then have to work with
a non-overlay BBitmap. */
for( int i = 0; i < COLOR_COUNT; i++ )
{
if( noOverlay )
break;
bitmap[0] = new BBitmap( bitmapFrame,
B_BITMAP_WILL_OVERLAY |
B_BITMAP_RESERVE_OVERLAY_CHANNEL,
colspace[i].colspace );
if( bitmap[0] && bitmap[0]->InitCheck() == B_OK )
{
colspace_index = i;
*mode = OVERLAY;
rgb_color key;
view->SetViewOverlay( bitmap[0], bitmap[0]->Bounds(),
view->Bounds(), &key, B_FOLLOW_ALL,
B_OVERLAY_FILTER_HORIZONTAL |
B_OVERLAY_FILTER_VERTICAL );
view->SetViewColor( key );
SetTitle( "VLC " PACKAGE_VERSION " (Overlay)" );
bitmap[1] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
colspace[colspace_index].colspace);
if( bitmap[1] && bitmap[1]->InitCheck() == B_OK )
{
bitmap[2] = new BBitmap( bitmapFrame, B_BITMAP_WILL_OVERLAY,
colspace[colspace_index].colspace);
if( bitmap[2] && bitmap[2]->InitCheck() == B_OK )
{
msg_Dbg( p_vout, "using double-buffered overlay" );
}
else
{
msg_Dbg( p_vout, "using single-buffered overlay" );
bitmap_count = 2;
delete bitmap[2]; bitmap[2] = NULL;
}
}
else
{
msg_Dbg( p_vout, "using simple overlay" );
bitmap_count = 1;
delete bitmap[1]; bitmap[1] = NULL;
}
break;
}
else
{
delete bitmap[0]; bitmap[0] = NULL;
}
}
if (*mode == BITMAP)
{
msg_Warn( p_vout, "no possible overlay" );
// fallback to RGB
colspace_index = DEFAULT_COL; // B_RGB32
bitmap[0] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
bitmap[1] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
bitmap[2] = new BBitmap( bitmapFrame, colspace[colspace_index].colspace );
SetTitle( "VLC " PACKAGE_VERSION " (Bitmap)" );
}
// see if everything went well
status_t status = B_ERROR;
for (int32_t i = 0; i < bitmap_count; i++)
{
if (bitmap[i])
status = bitmap[i]->InitCheck();
if (status < B_OK)
break;
}
if (status >= B_OK)
{
// clear bitmaps to black
for (int32_t i = 0; i < bitmap_count; i++)
_BlankBitmap(bitmap[i]);
}
return status;
}
/*****************************************************************************
* VideoWindow::_FreeBuffers
*****************************************************************************/
void
VideoWindow::_FreeBuffers()
{
delete bitmap[0]; bitmap[0] = NULL;
delete bitmap[1]; bitmap[1] = NULL;
delete bitmap[2]; bitmap[2] = NULL;
fInitStatus = B_ERROR;
}
/*****************************************************************************
* VideoWindow::_BlankBitmap
*****************************************************************************/
void
VideoWindow::_BlankBitmap(BBitmap* bitmap) const
{
// no error checking (we do that earlier on and since it's a private function...
// YCbCr:
// Loss/Saturation points are Y 16-235 (absoulte); Cb/Cr 16-240 (center 128)
// YUV:
// Extrema points are Y 0 - 207 (absolute) U -91 - 91 (offset 128) V -127 - 127 (offset 128)
// we only handle weird colorspaces with special care
switch (bitmap->ColorSpace()) {
case B_YCbCr422: {
// Y0[7:0] Cb0[7:0] Y1[7:0] Cr0[7:0] Y2[7:0] Cb2[7:0] Y3[7:0] Cr2[7:0]
int32_t height = bitmap->Bounds().IntegerHeight() + 1;
uint8_t* bits = (uint8_t*)bitmap->Bits();
int32_t bpr = bitmap->BytesPerRow();
for (int32_t y = 0; y < height; y++) {
// handle 2 bytes at a time
for (int32_t i = 0; i < bpr; i += 2) {
// offset into line
bits[i] = 16;
bits[i + 1] = 128;
}
// next line
bits += bpr;
}
break;
}
case B_YCbCr420: {
// TODO: untested!!
// Non-interlaced only, Cb0 Y0 Y1 Cb2 Y2 Y3 on even scan lines ...
// Cr0 Y0 Y1 Cr2 Y2 Y3 on odd scan lines
int32_t height = bitmap->Bounds().IntegerHeight() + 1;
uint8_t* bits = (uint8_t*)bitmap->Bits();
int32_t bpr = bitmap->BytesPerRow();
for (int32_t y = 0; y < height; y += 1) {
// handle 3 bytes at a time
for (int32_t i = 0; i < bpr; i += 3) {
// offset into line
bits[i] = 128;
bits[i + 1] = 16;
bits[i + 2] = 16;
}
// next line
bits += bpr;
}
break;
}
case B_YUV422: {
// TODO: untested!!
// U0[7:0] Y0[7:0] V0[7:0] Y1[7:0] U2[7:0] Y2[7:0] V2[7:0] Y3[7:0]
int32_t height = bitmap->Bounds().IntegerHeight() + 1;
uint8_t* bits = (uint8_t*)bitmap->Bits();
int32_t bpr = bitmap->BytesPerRow();
for (int32_t y = 0; y < height; y += 1) {
// handle 2 bytes at a time
for (int32_t i = 0; i < bpr; i += 2) {
// offset into line
bits[i] = 128;
bits[i + 1] = 0;
}
// next line
bits += bpr;
}
break;
}
default:
memset(bitmap->Bits(), 0, bitmap->BitsLength());
break;
}
}
/*****************************************************************************
* VideoWindow::_SetVideoSize
*****************************************************************************/
void
VideoWindow::_SetVideoSize(uint32_t mode)
{
// let size depend on aspect correction
int32_t width = CorrectAspectRatio() ? i_width : fTrueWidth;
int32_t height = CorrectAspectRatio() ? i_height : fTrueHeight;
switch (mode)
{
case RESIZE_50:
width /= 2;
height /= 2;
break;
case RESIZE_200:
width *= 2;
height *= 2;
break;
case RESIZE_100:
default:
break;
}
fSettings->ClearFlags(VideoSettings::FLAG_FULL_SCREEN);
ResizeTo(width, height);
}
/*****************************************************************************
* VideoWindow::_SetToSettings
*****************************************************************************/
void
VideoWindow::_SetToSettings()
{
// adjust dimensions
uint32_t mode = RESIZE_100;
switch (fSettings->VideoSize())
{
case VideoSettings::SIZE_50:
mode = RESIZE_50;
break;
case VideoSettings::SIZE_200:
mode = RESIZE_200;
break;
case VideoSettings::SIZE_100:
case VideoSettings::SIZE_OTHER:
default:
break;
}
bool fullscreen = IsFullScreen(); // remember settings
_SetVideoSize(mode); // because this will reset settings
// the fullscreen status is reflected in the settings,
// but not yet in the windows state
if (fullscreen)
SetFullScreen(true);
if (fSettings->HasFlags(VideoSettings::FLAG_ON_TOP_ALL))
fCachedFeel = B_FLOATING_ALL_WINDOW_FEEL;
else
fCachedFeel = B_NORMAL_WINDOW_FEEL;
SetFeel(fCachedFeel);
}
/*****************************************************************************
* VLCView::VLCView
*****************************************************************************/
VLCView::VLCView(BRect bounds, vout_thread_t *p_vout_instance )
: BView(bounds, "video view", B_FOLLOW_NONE, B_WILL_DRAW | B_PULSE_NEEDED),
fLastMouseMovedTime(mdate()),
fCursorHidden(false),
fCursorInside(false),
fIgnoreDoubleClick(false)
{
p_vout = p_vout_instance;
fMouseHideTimeout = var_GetInteger(p_vout, "mouse-hide-timeout") * 1000;
SetViewColor(B_TRANSPARENT_32_BIT);
}
/*****************************************************************************
* VLCView::~VLCView
*****************************************************************************/
VLCView::~VLCView()
{
}
/*****************************************************************************
* VLCVIew::AttachedToWindow
*****************************************************************************/
void
VLCView::AttachedToWindow()
{
// periodically check if we want to hide the pointer
Window()->SetPulseRate(1000000);
}
/*****************************************************************************
* VLCVIew::MouseDown
*****************************************************************************/
void
VLCView::MouseDown(BPoint where)
{
VideoWindow* videoWindow = dynamic_cast<VideoWindow*>(Window());
BMessage* msg = Window()->CurrentMessage();
int32 clicks;
uint32_t buttons;
msg->FindInt32("clicks", &clicks);
msg->FindInt32("buttons", (int32*)&buttons);
if (videoWindow)
{
if (buttons & B_PRIMARY_MOUSE_BUTTON)
{
if (clicks == 2 && !fIgnoreDoubleClick)
Window()->Zoom();
/* else
videoWindow->ToggleInterfaceShowing(); */
fIgnoreDoubleClick = false;
}
else
{
if (buttons & B_SECONDARY_MOUSE_BUTTON)
{
// clicks will be 2 next time (if interval short enough)
// even if the first click and the second
// have not been made with the same mouse button
fIgnoreDoubleClick = true;
// launch popup menu
BPopUpMenu *menu = new BPopUpMenu("context menu");
menu->SetRadioMode(false);
// In full screen, add an item to show/hide the interface
if( videoWindow->IsFullScreen() )
{
BMenuItem *intfItem =
new BMenuItem( _("Show Interface"), new BMessage(SHOW_INTERFACE) );
menu->AddItem( intfItem );
}
// Resize to 50%
BMenuItem *halfItem = new BMenuItem(_("50%"), new BMessage(RESIZE_50));
menu->AddItem(halfItem);
// Resize to 100%
BMenuItem *origItem = new BMenuItem(_("100%"), new BMessage(RESIZE_100));
menu->AddItem(origItem);
// Resize to 200%
BMenuItem *doubleItem = new BMenuItem(_("200%"), new BMessage(RESIZE_200));
menu->AddItem(doubleItem);
// Toggle FullScreen
BMenuItem *zoomItem = new BMenuItem(_("Fullscreen"), new BMessage(TOGGLE_FULL_SCREEN));
zoomItem->SetMarked(videoWindow->IsFullScreen());
menu->AddItem(zoomItem);
menu->AddSeparatorItem();
// Toggle vSync
BMenuItem *vsyncItem = new BMenuItem(_("Vertical Sync"), new BMessage(VERT_SYNC));
vsyncItem->SetMarked(videoWindow->IsSyncedToRetrace());
menu->AddItem(vsyncItem);
// Correct Aspect Ratio
BMenuItem *aspectItem = new BMenuItem(_("Correct Aspect Ratio"), new BMessage(ASPECT_CORRECT));
aspectItem->SetMarked(videoWindow->CorrectAspectRatio());
menu->AddItem(aspectItem);
menu->AddSeparatorItem();
// Window Feel Items
/* BMessage *winNormFeel = new BMessage(WINDOW_FEEL);
winNormFeel->AddInt32("WinFeel", (int32_t)B_NORMAL_WINDOW_FEEL);
BMenuItem *normWindItem = new BMenuItem("Normal Window", winNormFeel);
normWindItem->SetMarked(videoWindow->Feel() == B_NORMAL_WINDOW_FEEL);
menu->AddItem(normWindItem);
BMessage *winFloatFeel = new BMessage(WINDOW_FEEL);
winFloatFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_APP_WINDOW_FEEL);
BMenuItem *onTopWindItem = new BMenuItem("App Top", winFloatFeel);
onTopWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_APP_WINDOW_FEEL);
menu->AddItem(onTopWindItem);
BMessage *winAllFeel = new BMessage(WINDOW_FEEL);
winAllFeel->AddInt32("WinFeel", (int32_t)B_FLOATING_ALL_WINDOW_FEEL);
BMenuItem *allSpacesWindItem = new BMenuItem("On Top All Workspaces", winAllFeel);
allSpacesWindItem->SetMarked(videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL);
menu->AddItem(allSpacesWindItem);*/
BMessage *windowFeelMsg = new BMessage( WINDOW_FEEL );
bool onTop = videoWindow->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
window_feel feel = onTop ? B_NORMAL_WINDOW_FEEL : B_FLOATING_ALL_WINDOW_FEEL;
windowFeelMsg->AddInt32( "WinFeel", (int32_t)feel );
BMenuItem *windowFeelItem = new BMenuItem( _("Stay On Top"), windowFeelMsg );
windowFeelItem->SetMarked( onTop );
menu->AddItem( windowFeelItem );
menu->AddSeparatorItem();
BMenuItem* screenShotItem = new BMenuItem( _("Take Screen Shot"),
new BMessage( SCREEN_SHOT ) );
menu->AddItem( screenShotItem );
menu->SetTargetForItems( this );
ConvertToScreen( &where );
BRect mouseRect( where.x - 5, where.y - 5,
where.x + 5, where.y + 5 );
menu->Go( where, true, false, mouseRect, true );
}
}
}
fLastMouseMovedTime = mdate();
fCursorHidden = false;
}
/*****************************************************************************
* VLCVIew::MouseUp
*****************************************************************************/
void
VLCView::MouseUp( BPoint where )
{
var_SetBool( p_vout, "mouse-clicked", true );
}
/*****************************************************************************
* VLCVIew::MouseMoved
*****************************************************************************/
void
VLCView::MouseMoved(BPoint point, uint32 transit, const BMessage* dragMessage)
{
fLastMouseMovedTime = mdate();
fCursorHidden = false;
fCursorInside = ( transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW );
if( !fCursorInside )
{
return;
}
vlc_value_t val;
unsigned int i_width, i_height, i_x, i_y;
vout_PlacePicture( p_vout, (unsigned int)Bounds().Width(),
(unsigned int)Bounds().Height(),
&i_x, &i_y, &i_width, &i_height );
val.i_int = ( (int)point.x - i_x ) * p_vout->render.i_width / i_width;
var_Set( p_vout, "mouse-x", val );
val.i_int = ( (int)point.y - i_y ) * p_vout->render.i_height / i_height;
var_Set( p_vout, "mouse-y", val );
val.b_bool = true;
var_Set( p_vout, "mouse-moved", val );
}
/*****************************************************************************
* VLCVIew::Pulse
*****************************************************************************/
void
VLCView::Pulse()
{
// We are getting the pulse messages no matter if the mouse is over
// this view. If we are in full screen mode, we want to hide the cursor
// even if it is not.
VideoWindow *videoWindow = dynamic_cast<VideoWindow*>(Window());
if (!fCursorHidden)
{
if (fCursorInside
&& mdate() - fLastMouseMovedTime > fMouseHideTimeout)
{
be_app->ObscureCursor();
fCursorHidden = true;
// hide the interface window as well if full screen
if (videoWindow && videoWindow->IsFullScreen())
videoWindow->SetInterfaceShowing(false);
}
}
// Workaround to disable the screensaver in full screen:
// we simulate an activity every 29 seconds
if( videoWindow && videoWindow->IsFullScreen() &&
mdate() - fLastMouseMovedTime > 29000000 )
{
BPoint where;
uint32 buttons;
GetMouse(&where, &buttons, false);
ConvertToScreen(&where);
set_mouse_position((int32_t) where.x, (int32_t) where.y);
}
}
/*****************************************************************************
* VLCVIew::Draw
*****************************************************************************/
void
VLCView::Draw(BRect updateRect)
{
VideoWindow* window = dynamic_cast<VideoWindow*>( Window() );
if ( window && window->mode == BITMAP )
FillRect( updateRect );
}
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Init ( vout_thread_t * );
static void End ( vout_thread_t * );
static int Manage ( vout_thread_t * );
static void Display ( vout_thread_t *, picture_t * );
static int Control ( vout_thread_t *, int, va_list );
static int BeosOpenDisplay ( vout_thread_t *p_vout );
static void BeosCloseDisplay( vout_thread_t *p_vout );
/*****************************************************************************
* OpenVideo: allocates BeOS video thread output method
*****************************************************************************
* This function allocates and initializes a BeOS vout method.
*****************************************************************************/
int OpenVideo ( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
/* Allocate structure */
p_vout->p_sys = (vout_sys_t*) malloc( sizeof( vout_sys_t ) );
if( p_vout->p_sys == NULL )
return 1;
p_vout->p_sys->i_width = p_vout->render.i_width;
p_vout->p_sys->i_height = p_vout->render.i_height;
p_vout->p_sys->source_chroma = p_vout->render.i_chroma;
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = Manage;
p_vout->pf_render = NULL;
p_vout->pf_display = Display;
p_vout->pf_control = Control;
return( 0 );
}
/*****************************************************************************
* Init: initialize BeOS video thread output method
*****************************************************************************/
int Init( vout_thread_t *p_vout )
{
int i_index;
picture_t *p_pic;
I_OUTPUTPICTURES = 0;
/* Open and initialize device */
if( BeosOpenDisplay( p_vout ) )
{
msg_Err(p_vout, "vout error: can't open display");
return 0;
}
p_vout->output.i_width = p_vout->render.i_width;
p_vout->output.i_height = p_vout->render.i_height;
/* Assume we have square pixels */
p_vout->output.i_aspect = p_vout->p_sys->i_width
* VOUT_ASPECT_FACTOR / p_vout->p_sys->i_height;
p_vout->output.i_chroma = colspace[p_vout->p_sys->p_window->colspace_index].chroma;
p_vout->p_sys->i_index = 0;
p_vout->output.i_rmask = 0x00ff0000;
p_vout->output.i_gmask = 0x0000ff00;
p_vout->output.i_bmask = 0x000000ff;
for( int buffer_index = 0 ;
buffer_index < p_vout->p_sys->p_window->bitmap_count;
buffer_index++ )
{
p_pic = NULL;
/* Find an empty picture slot */
for( i_index = 0 ; i_index < VOUT_MAX_PICTURES ; i_index++ )
{
p_pic = NULL;
if( p_vout->p_picture[ i_index ].i_status == FREE_PICTURE )
{
p_pic = p_vout->p_picture + i_index;
break;
}
}
if( p_pic == NULL )
{
return 0;
}
p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[buffer_index]->Bits();
p_pic->p->i_lines = p_vout->p_sys->i_height;
p_pic->p->i_visible_lines = p_vout->p_sys->i_height;
p_pic->p->i_pixel_pitch = colspace[p_vout->p_sys->p_window->colspace_index].pixel_bytes;
p_pic->i_planes = colspace[p_vout->p_sys->p_window->colspace_index].planes;
p_pic->p->i_pitch = p_vout->p_sys->p_window->bitmap[buffer_index]->BytesPerRow();
p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * ( p_vout->p_sys->p_window->bitmap[buffer_index]->Bounds().IntegerWidth() + 1 );
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_type = DIRECT_PICTURE;
PP_OUTPUTPICTURE[ I_OUTPUTPICTURES ] = p_pic;
I_OUTPUTPICTURES++;
}
return( 0 );
}
/*****************************************************************************
* End: terminate BeOS video thread output method
*****************************************************************************/
void End( vout_thread_t *p_vout )
{
BeosCloseDisplay( p_vout );
}
/*****************************************************************************
* Manage
*****************************************************************************/
static int Manage( vout_thread_t * p_vout )
{
if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE )
{
p_vout->p_sys->p_window->PostMessage( TOGGLE_FULL_SCREEN );
p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE;
}
return 0;
}
/*****************************************************************************
* CloseVideo: destroy BeOS video thread output method
*****************************************************************************
* Terminate an output method created by DummyCreateOutputMethod
*****************************************************************************/
void CloseVideo ( vlc_object_t *p_this )
{
vout_thread_t * p_vout = (vout_thread_t *)p_this;
free( p_vout->p_sys );
}
/*****************************************************************************
* Display: displays previously rendered output
*****************************************************************************
* This function send the currently rendered image to BeOS image, waits until
* it is displayed and switch the two rendering buffers, preparing next frame.
*****************************************************************************/
void Display( vout_thread_t *p_vout, picture_t *p_pic )
{
VideoWindow * p_win = p_vout->p_sys->p_window;
/* draw buffer if required */
if (!p_win->teardownwindow)
{
p_win->drawBuffer(p_vout->p_sys->i_index);
}
/* change buffer */
p_vout->p_sys->i_index = ++p_vout->p_sys->i_index %
p_vout->p_sys->p_window->bitmap_count;
p_pic->p->p_pixels = (uint8_t*)p_vout->p_sys->p_window->bitmap[p_vout->p_sys->i_index]->Bits();
}
static int Control( vout_thread_t * p_vout, int i_query, va_list args )
{
return VLC_EGENERIC;
}
/* following functions are local */
/*****************************************************************************
* BeosOpenDisplay: open and initialize BeOS device
*****************************************************************************/
static int BeosOpenDisplay( vout_thread_t *p_vout )
{
p_vout->p_sys->p_window = new VideoWindow( p_vout->p_sys->i_width - 1,
p_vout->p_sys->i_height - 1,
BRect( 20, 50,
20 + p_vout->i_window_width - 1,
50 + p_vout->i_window_height - 1 ),
p_vout );
if( p_vout->p_sys->p_window == NULL )
{
msg_Err( p_vout, "cannot allocate VideoWindow" );
return( 1 );
}
else
{
p_vout->p_sys->p_window->Show();
}
return( 0 );
}
/*****************************************************************************
* BeosDisplay: close and reset BeOS device
*****************************************************************************
* Returns all resources allocated by BeosOpenDisplay and restore the original
* state of the device.
*****************************************************************************/
static void BeosCloseDisplay( vout_thread_t *p_vout )
{
VideoWindow * p_win = p_vout->p_sys->p_window;
/* Destroy the video window */
if( p_win != NULL && !p_win->teardownwindow)
{
p_win->Lock();
p_win->teardownwindow = true;
p_win->Hide();
p_win->Quit();
}
p_win = NULL;
}
/*****************************************************************************
* VideoWindow.h: BeOS video window class prototype
*****************************************************************************
* Copyright (C) 1999, 2000, 2001 the VideoLAN team
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Tony Castley <tcastley@mail.powerup.com.au>
* Richard Shepherd <richard@rshepherd.demon.co.uk>
* Stephan Aßmus <stippi@yellowbites.com>
*
* 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.
*****************************************************************************/
#ifndef BEOS_VIDEO_WINDOW_H
#define BEOS_VIDEO_WINDOW_H
#include <View.h>
#include <Window.h>
#define BITMAP 0
#define OVERLAY 1
#define OPENGL 2
typedef struct colorcombo
{
color_space colspace;
const char *name;
uint32_t chroma;
int planes;
int pixel_bytes;
} colorcombo;
colorcombo colspace[]=
{
{B_YCbCr420, "B_YCbCr420", VLC_CODEC_I420, 3, 2},
{B_YUV422, "B_YUV422", VLC_FOURCC('Y','4','2','2'), 3, 2},
{B_YCbCr422, "B_YCbCr422", VLC_CODEC_YUYV, 3, 2},
{B_RGB32, "B_RGB32", VLC_CODEC_RGB32, 1, 4},
{B_RGB16, "B_RGB16", VLC_CODEC_RGB16, 1, 2}
};
#define COLOR_COUNT 5
#define DEFAULT_COL 3
class VideoSettings
{
public:
VideoSettings( const VideoSettings& clone );
virtual ~VideoSettings();
static VideoSettings* DefaultSettings();
enum
{
SIZE_OTHER = 0,
SIZE_50 = 1,
SIZE_100 = 2,
SIZE_200 = 3,
};
void SetVideoSize( uint32_t mode );
inline uint32_t VideoSize() const
{ return fVideoSize; }
enum
{
FLAG_CORRECT_RATIO = 0x0001,
FLAG_SYNC_RETRACE = 0x0002,
FLAG_ON_TOP_ALL = 0x0004,
FLAG_FULL_SCREEN = 0x0008,
};
inline void SetFlags( uint32_t flags )
{ fFlags = flags; }
inline void AddFlags( uint32_t flags )
{ fFlags |= flags; }
inline void ClearFlags( uint32_t flags )
{ fFlags &= ~flags; }
inline bool HasFlags( uint32_t flags ) const
{ return fFlags & flags; }
inline uint32_t Flags() const
{ return fFlags; }
private:
VideoSettings(); // reserved for default settings
static VideoSettings fDefaultSettings;
uint32_t fVideoSize;
uint32_t fFlags;
BMessage* fSettings;
};
class VLCView : public BView
{
public:
VLCView( BRect bounds, vout_thread_t *p_vout );
virtual ~VLCView();
virtual void AttachedToWindow();
virtual void MouseDown(BPoint where);
virtual void MouseUp(BPoint where);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void Pulse();
virtual void Draw(BRect updateRect);
private:
vout_thread_t *p_vout;
bigtime_t fLastMouseMovedTime;
int fMouseHideTimeout;
bool fCursorHidden;
bool fCursorInside;
bool fIgnoreDoubleClick;
};
class VideoWindow : public BWindow
{
public:
VideoWindow(int v_width,
int v_height,
BRect frame,
vout_thread_t *p_vout);
virtual ~VideoWindow();
// BWindow
virtual void MessageReceived(BMessage* message);
virtual void Zoom(BPoint origin,
float width, float height);
virtual void FrameResized(float width, float height);
virtual void FrameMoved(BPoint origin);
virtual void ScreenChanged(BRect frame,
color_space mode);
virtual void WindowActivated(bool active);
// VideoWindow
void drawBuffer(int bufferIndex);
void ToggleInterfaceShowing();
void SetInterfaceShowing(bool showIt);
void SetCorrectAspectRatio(bool doIt);
bool CorrectAspectRatio() const;
void ToggleFullScreen();
void SetFullScreen(bool doIt);
bool IsFullScreen() const;
void SetOnTop(bool doIt);
bool IsOnTop() const;
void SetSyncToRetrace(bool doIt);
bool IsSyncedToRetrace() const;
inline status_t InitCheck() const
{ return fInitStatus; }
// this is the hook controling direct screen connection
int32_t i_width; // aspect corrected bitmap size
int32_t i_height;
BRect winSize; // current window size
BBitmap *bitmap[3];
// BBitmap *overlaybitmap;
VLCView *view;
int i_buffer;
volatile bool teardownwindow;
thread_id fDrawThreadID;
int mode;
int bitmap_count;
int colspace_index;
private:
status_t _AllocateBuffers(int width,
int height,
int* mode);
void _FreeBuffers();
void _BlankBitmap(BBitmap* bitmap) const;
void _SetVideoSize(uint32_t mode);
void _SetToSettings();
vout_thread_t *p_vout;
int32_t fTrueWidth; // incomming bitmap size
int32_t fTrueHeight;
window_feel fCachedFeel;
bool fInterfaceShowing;
status_t fInitStatus;
VideoSettings* fSettings;
};
#endif // BEOS_VIDEO_WINDOW_H
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment