* added GUI classes for the transport control panel implementation
* as noted by the headers, these originate from Be Sample Code or code that was written by myself alone for VLC (they have been updated in the meantime though) * seek slider is missing yet as well playback position info view (could be taken from VLC as well, I still have the implementation that contains only my own code) * fixed application quitting when only one of multiple player windows is closed (not it quits when the last player is closed or MediaPlayer->Quit is selected from the menu) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17222 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -24,10 +24,9 @@
|
||||
#include "ControllerView.h"
|
||||
|
||||
ControllerView::ControllerView(BRect frame, Controller *ctrl)
|
||||
: BView(frame, "controller", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE)
|
||||
: TransportControlGroup(frame)
|
||||
, fController(ctrl)
|
||||
{
|
||||
SetViewColor(128,0,0);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,23 +35,17 @@ ControllerView::~ControllerView()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::ResizeToPreferred()
|
||||
{
|
||||
ResizeTo(300 - 1, 60 - 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::AttachedToWindow()
|
||||
{
|
||||
}
|
||||
TransportControlGroup::AttachedToWindow();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::Draw(BRect updateRect)
|
||||
{
|
||||
BView::Draw(updateRect);
|
||||
TransportControlGroup::Draw(updateRect);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +54,74 @@ ControllerView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
TransportControlGroup::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
uint32
|
||||
ControllerView::EnabledButtons()
|
||||
{
|
||||
return 0xffffffff;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::TogglePlaying()
|
||||
{
|
||||
printf("ControllerView::TogglePlaying()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::Stop()
|
||||
{
|
||||
printf("ControllerView::Stop()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::Rewind()
|
||||
{
|
||||
// TODO: make it so this function is called repeatedly
|
||||
printf("ControllerView::Rewind()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::Forward()
|
||||
{
|
||||
// TODO: make it so this function is called repeatedly
|
||||
printf("ControllerView::Forward()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::SkipBackward()
|
||||
{
|
||||
printf("ControllerView::SkipBackward()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::SkipForward()
|
||||
{
|
||||
printf("ControllerView::SkipForward()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::SetVolume(float value)
|
||||
{
|
||||
printf("ControllerView::SetVolume(%.2f)\n", value);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ControllerView::ToggleMute()
|
||||
{
|
||||
printf("ControllerView::ToggleMute()\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -21,23 +21,32 @@
|
||||
#ifndef __CONTROLLER_VIEW_H
|
||||
#define __CONTROLLER_VIEW_H
|
||||
|
||||
#include <View.h>
|
||||
#include "TransportControlGroup.h"
|
||||
|
||||
|
||||
class Controller;
|
||||
|
||||
class ControllerView : public BView
|
||||
class ControllerView : public TransportControlGroup
|
||||
{
|
||||
public:
|
||||
ControllerView(BRect frame, Controller *ctrl);
|
||||
~ControllerView();
|
||||
|
||||
void ResizeToPreferred();
|
||||
|
||||
private:
|
||||
void AttachedToWindow();
|
||||
void MessageReceived(BMessage *msg);
|
||||
void Draw(BRect updateRect);
|
||||
|
||||
// TransportControlGroup interface
|
||||
virtual uint32 EnabledButtons();
|
||||
virtual void TogglePlaying();
|
||||
virtual void Stop();
|
||||
virtual void Rewind();
|
||||
virtual void Forward();
|
||||
virtual void SkipBackward();
|
||||
virtual void SkipForward();
|
||||
virtual void SetVolume(float value);
|
||||
virtual void ToggleMute();
|
||||
|
||||
private:
|
||||
Controller * fController;
|
||||
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// TODO: remove this file again.... It originates from Be Sample code,
|
||||
// but was added to the VLC Media Player BeOS interface, I added some stuff
|
||||
// during my work on VLC, but I am not sure anymore if this file still
|
||||
// contains work done by Tony Castley, which would be GPL!
|
||||
|
||||
#include "DrawingTidbits.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Debug.h>
|
||||
#include <Screen.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;
|
||||
}
|
||||
|
||||
// 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:
|
||||
//printf("unkown colorspace: %ld\n", inBitmap->ColorSpace());
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// TODO: remove this file again.... It originates from Be Sample code,
|
||||
// but was added to the VLC Media Player BeOS interface, I added some stuff
|
||||
// during my work on VLC, but I am not sure anymore if this file still
|
||||
// contains work done by Tony Castley, which would be GPL!
|
||||
|
||||
#ifndef __DRAWING_TIBITS__
|
||||
#define __DRAWING_TIBITS__
|
||||
|
||||
#include <GraphicsDefs.h>
|
||||
|
||||
class BBitmap;
|
||||
|
||||
const rgb_color kBlack = { 0, 0, 0, 255 };
|
||||
const rgb_color kWhite = { 255, 255, 255, 255 };
|
||||
|
||||
rgb_color ShiftColor(rgb_color , float );
|
||||
|
||||
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 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__
|
||||
@@ -2,14 +2,24 @@ SubDir HAIKU_TOP src apps mediaplayer ;
|
||||
|
||||
SetSubDirSupportedPlatformsBeOSCompatible ;
|
||||
|
||||
AddSubDirSupportedPlatforms libbe_test ;
|
||||
|
||||
Application MediaPlayer :
|
||||
Controller.cpp
|
||||
ControllerView.cpp
|
||||
DrawingTidbits.cpp
|
||||
MainApp.cpp
|
||||
MainWin.cpp
|
||||
TransportButton.cpp
|
||||
TransportControlGroup.cpp
|
||||
VideoNode.cpp
|
||||
VideoView.cpp
|
||||
VolumeSlider.cpp
|
||||
: be media tracker
|
||||
: MediaPlayer.rdef
|
||||
;
|
||||
|
||||
if $(TARGET_PLATFORM) = libbe_test {
|
||||
HaikuInstall install-test-apps : $(HAIKU_APP_TEST_DIR) : MediaPlayer
|
||||
: tests!apps ;
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <Path.h>
|
||||
#include <Entry.h>
|
||||
#include <Alert.h>
|
||||
#include <Autolock.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -30,6 +31,7 @@ MainApp *gMainApp;
|
||||
MainApp::MainApp()
|
||||
: BApplication("application/x-vnd.Haiku.MediaPlayer")
|
||||
, fFirstWindow(NewWindow())
|
||||
, fPlayerCount(1)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,6 +44,8 @@ MainApp::~MainApp()
|
||||
BWindow *
|
||||
MainApp::NewWindow()
|
||||
{
|
||||
BAutolock _(this);
|
||||
fPlayerCount++;
|
||||
return new MainWin();
|
||||
}
|
||||
|
||||
@@ -101,6 +105,23 @@ MainApp::ArgvReceived(int32 argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainApp::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case M_PLAYER_QUIT:
|
||||
fPlayerCount--;
|
||||
if (fPlayerCount == 0)
|
||||
PostMessage(B_QUIT_REQUESTED);
|
||||
break;
|
||||
|
||||
default:
|
||||
BApplication::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main()
|
||||
{
|
||||
|
||||
@@ -23,6 +23,11 @@
|
||||
#include <Application.h>
|
||||
#include "MainWin.h"
|
||||
|
||||
enum
|
||||
{
|
||||
M_PLAYER_QUIT = 'plqt',
|
||||
};
|
||||
|
||||
class MainApp : public BApplication
|
||||
{
|
||||
public:
|
||||
@@ -34,9 +39,11 @@ public:
|
||||
private:
|
||||
void RefsReceived(BMessage *msg);
|
||||
void ArgvReceived(int32 argc, char **argv);
|
||||
void MessageReceived(BMessage *msg);
|
||||
|
||||
private:
|
||||
BWindow * fFirstWindow;
|
||||
int32 fPlayerCount;
|
||||
};
|
||||
|
||||
extern MainApp *gMainApp;
|
||||
|
||||
@@ -342,7 +342,7 @@ MainWin::SetupTrackMenus()
|
||||
bool
|
||||
MainWin::QuitRequested()
|
||||
{
|
||||
be_app->PostMessage(B_QUIT_REQUESTED);
|
||||
be_app->PostMessage(M_PLAYER_QUIT);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,3 +17,57 @@ resource file_types message {
|
||||
"types" = "video/quicktime",
|
||||
"types" = "video/x-msvideo"
|
||||
};
|
||||
|
||||
resource large_icon {
|
||||
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFFFF001B1C000000000000FFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF003F1B1C1B1C0B0A1C1C0000FFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00153F3F1B1C1B1C0B0A1C190000FFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF001515153F3F1B1C1B1C0B0A1A190000FFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF0015151516153F3F1B1C1B1C0B0A1A1900FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00150B15151516153F3F1B1C1B1A0B0A00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00150B0A0B15151615153F3F1B1C1B1100FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00150B86860B0B15151516153F1B0F0F00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00150A868686860C0A151615150F0F0F00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00150B8686868686860D0D15160E0F0F00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00150B86868686868686863F150F0F0E00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00160A86868686868686863F150F0F0E00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00160A86868686868686863F150F0F0E00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00160A3F868686868686863F150F0F0E00FFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF001615153F3F86868686863F150F0F0E00111111FFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFFFF000A1516153F3F8686863F150F0F0E0011111111FFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF003F3F0A0B1515163F3F863F150F0F0E0000111111FFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF0015153F3F0A0B1515163F3F150F0F0E0B0B001111FFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF00151515163F3F0A0B15202A150F0F0E0B0F001111FFFF"
|
||||
$"FFFFFFFFFFFFFFFFFF001515150B0B153F3F0A0B15150F0F0B0F0E001111FFFF"
|
||||
$"FFFFFFFFFFFFFFFFFFFF00001515150B0B153F3F0A0B0A0B0F0F0F001111FFFF"
|
||||
$"FFFFFF000000FFFFFFFFFFFF00001515150B15153F3F0E0F0F0F001111FFFFFF"
|
||||
$"FFFF000A0B0A0000FFFFFFFFFFFF00001515152D16150F0F0E001111FFFFFFFF"
|
||||
$"FF000A07060B0A0B0000FFFFFFFFFFFF0000151515160E0F001111FFFFFFFFFF"
|
||||
$"FF000A0B0AFA060B0A0700FFFFFFFFFFFFFF000015150F001111FFFFFFFFFFFF"
|
||||
$"FF0013130A0B0B0A070600FFFFFFFFFFFFFFFFFF0000001111FFFFFFFFFFFFFF"
|
||||
$"FFFF000013130A070600FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFF0000130600FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
};
|
||||
|
||||
resource mini_icon {
|
||||
$"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFF0B0B0C0FFFFFFFFFFFFFFFFF"
|
||||
$"FFFFFFFF011B3F120B0A07FFFFFFFFFF"
|
||||
$"FFFFFFFF010F1C3F3F1A0F0709FFFFFF"
|
||||
$"FFFFFFFF00100C89193F3F1D00FFFFFF"
|
||||
$"FFFFFFFF011186AE0C89191602FFFFFF"
|
||||
$"FFFFFFFF0011861786AE180D03FFFFFF"
|
||||
$"FFFFFFFF0111868686861E0E03FFFFFF"
|
||||
$"FFFFFF05000E3F6086ACFE0E040EFFFF"
|
||||
$"FFFFFF0012140F0E3F1A1D0F03060EFF"
|
||||
$"FFFFFF0512161E130F0E1A0F06020EFF"
|
||||
$"FFFFFFFF04020C1419160E0612040EFF"
|
||||
$"FF06000EFFFF04050BEB3F110606FFFF"
|
||||
$"0A00120600FFFFFF0404040305FFFFFF"
|
||||
$"0D030D0C000DFFFFFFFFFFFFFFFFFFFF"
|
||||
$"FFFF0D000DFFFFFFFFFFFFFFFFFFFFFF"
|
||||
};
|
||||
|
||||
@@ -0,0 +1,633 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// NOTE: this file originates from the Be Sample Code. This file was used
|
||||
// in the VLC Media Player. I took the version from when I worked on VLC
|
||||
// during the 0.4.4 - 0.4.6 times. I remember I did some minor work in it,
|
||||
// I think I even compared it with the original Be Sample Code version,
|
||||
// but there were virtually no changes. -Stephan Aßmus
|
||||
|
||||
#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;
|
||||
|
||||
volatile 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 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();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// NOTE: this file originates from the Be Sample Code. See .cpp.
|
||||
|
||||
#ifndef TRANSPORT_BUTTON_H
|
||||
#define TRANSPORT_BUTTON_H
|
||||
|
||||
#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 uchar* normalBits,
|
||||
const uchar* pressedBits,
|
||||
const uchar* 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* message);
|
||||
void SetPressingMessage(BMessage* message);
|
||||
void SetDonePressingMessage(BMessage* message);
|
||||
void SetPressingPeriod(bigtime_t);
|
||||
|
||||
virtual void SetEnabled(bool enabled);
|
||||
|
||||
protected:
|
||||
|
||||
enum {
|
||||
kDisabledMask = 0x1,
|
||||
kPressedMask = 0x2
|
||||
};
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
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 WindowActivated(bool active);
|
||||
|
||||
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 uchar* BitsForMask(uint32 mask) 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 uchar* normalBits;
|
||||
const uchar* pressedBits;
|
||||
const uchar* 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 uchar* normalBits,
|
||||
const uchar* pressedBits,
|
||||
const uchar* disabledBits,
|
||||
const uchar* normalPlayingBits,
|
||||
const uchar* pressedPlayingBits,
|
||||
const uchar* normalPausedBits,
|
||||
const uchar* 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 uchar* BitsForMask(uint32) const;
|
||||
|
||||
virtual void StartPressing();
|
||||
virtual void MouseCancelPressing();
|
||||
virtual void DonePressing();
|
||||
|
||||
private:
|
||||
const uchar* normalPlayingBits;
|
||||
const uchar* pressedPlayingBits;
|
||||
const uchar* normalPausedBits;
|
||||
const uchar* 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 // TRANSPORT_BUTTON_H
|
||||
@@ -0,0 +1,458 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me
|
||||
// removed. -Stephan Aßmus
|
||||
|
||||
#include "TransportControlGroup.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "ButtonBitmaps.h"
|
||||
#include "TransportButton.h"
|
||||
#include "VolumeSlider.h"
|
||||
|
||||
enum {
|
||||
MSG_PLAY = 'play',
|
||||
MSG_STOP = 'stop',
|
||||
MSG_REWIND = 'rwnd',
|
||||
MSG_FORWARD = 'frwd',
|
||||
MSG_SKIP_BACKWARDS = 'skpb',
|
||||
MSG_SKIP_FORWARD = 'skpf',
|
||||
MSG_SET_VOLUME = 'stvl',
|
||||
MSG_SET_MUTE = 'stmt',
|
||||
};
|
||||
|
||||
#define BORDER_INSET 6.0
|
||||
#define MIN_SPACE 4.0
|
||||
#define SPEAKER_SLIDER_DIST 6.0
|
||||
#define VOLUME_MIN_WIDTH 70.0
|
||||
#define VOLUME_SLIDER_LAYOUT_WEIGHT 2.0
|
||||
|
||||
// constructor
|
||||
TransportControlGroup::TransportControlGroup(BRect frame)
|
||||
: BView(frame, "transport control group",
|
||||
B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
|
||||
B_WILL_DRAW | B_FRAME_EVENTS),
|
||||
fBottomControlHeight(0.0)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
BRect frame(0.0, 0.0, 10.0, 10.0);
|
||||
|
||||
// Buttons
|
||||
// Skip Back
|
||||
frame.right = kRewindBitmapWidth - 1;
|
||||
frame.bottom = kRewindBitmapHeight - 1;
|
||||
fBottomControlHeight = kRewindBitmapHeight - 1.0;
|
||||
fSkipBack = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSkipBackBitmapBits,
|
||||
kPressedSkipBackBitmapBits,
|
||||
kDisabledSkipBackBitmapBits,
|
||||
new BMessage(MSG_SKIP_BACKWARDS));
|
||||
AddChild(fSkipBack);
|
||||
|
||||
// Skip Foward
|
||||
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);
|
||||
|
||||
// Play Pause
|
||||
frame.right = kPlayPauseBitmapWidth - 1;
|
||||
frame.bottom = kPlayPauseBitmapHeight - 1;
|
||||
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(MSG_PLAY));
|
||||
|
||||
AddChild(fPlayPause);
|
||||
|
||||
// Stop
|
||||
frame.right = kStopBitmapWidth - 1;
|
||||
frame.bottom = kStopBitmapHeight - 1;
|
||||
if (fBottomControlHeight < kStopBitmapHeight - 1.0)
|
||||
fBottomControlHeight = kStopBitmapHeight - 1.0;
|
||||
fStop = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kStopButtonBitmapBits,
|
||||
kPressedStopButtonBitmapBits,
|
||||
kDisabledStopButtonBitmapBits,
|
||||
new BMessage(MSG_STOP));
|
||||
AddChild(fStop);
|
||||
|
||||
// Mute
|
||||
frame.right = kSpeakerIconBitmapWidth - 1;
|
||||
frame.bottom = kSpeakerIconBitmapHeight - 1;
|
||||
if (fBottomControlHeight < kSpeakerIconBitmapHeight - 1.0)
|
||||
fBottomControlHeight = kSpeakerIconBitmapHeight - 1.0;
|
||||
fMute = new TransportButton(frame, B_EMPTY_STRING,
|
||||
kSpeakerIconBits,
|
||||
kPressedSpeakerIconBits,
|
||||
kSpeakerIconBits,
|
||||
new BMessage(MSG_SET_MUTE));
|
||||
|
||||
AddChild(fMute);
|
||||
|
||||
// Volume Slider
|
||||
fVolumeSlider = new VolumeSlider(BRect(0.0, 0.0, VOLUME_MIN_WIDTH,
|
||||
kVolumeSliderBitmapHeight - 1.0),
|
||||
"volume slider", 0, 255,
|
||||
new BMessage(MSG_SET_VOLUME));
|
||||
fVolumeSlider->SetValue(128);
|
||||
AddChild(fVolumeSlider);
|
||||
}
|
||||
|
||||
// destructor
|
||||
TransportControlGroup::~TransportControlGroup()
|
||||
{
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
TransportControlGroup::AttachedToWindow()
|
||||
{
|
||||
SetEnabled(EnabledButtons());
|
||||
|
||||
// we are now a valid BHandler
|
||||
fVolumeSlider->SetTarget(this);
|
||||
fSkipBack->SetTarget(this);
|
||||
fSkipForward->SetTarget(this);
|
||||
fRewind->SetTarget(this);
|
||||
fForward->SetTarget(this);
|
||||
fPlayPause->SetTarget(this);
|
||||
fStop->SetTarget(this);
|
||||
fMute->SetTarget(this);
|
||||
|
||||
FrameResized(Bounds().Width(), Bounds().Height());
|
||||
}
|
||||
|
||||
// FrameResized
|
||||
void
|
||||
TransportControlGroup::FrameResized(float width, float height)
|
||||
{
|
||||
// layout controls
|
||||
BRect r(Bounds());
|
||||
r.InsetBy(BORDER_INSET, BORDER_INSET);
|
||||
_LayoutControls(r);
|
||||
}
|
||||
|
||||
// GetPreferredSize
|
||||
void
|
||||
TransportControlGroup::GetPreferredSize(float* width, float* height)
|
||||
{
|
||||
BRect r(_MinFrame());
|
||||
|
||||
if (width)
|
||||
*width = r.Width();
|
||||
if (height)
|
||||
*height = r.Height();
|
||||
}
|
||||
|
||||
// MessageReceived
|
||||
void
|
||||
TransportControlGroup::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch (message->what) {
|
||||
case MSG_PLAY:
|
||||
_TogglePlaying();
|
||||
break;
|
||||
case MSG_STOP:
|
||||
_Stop();
|
||||
break;
|
||||
|
||||
case MSG_REWIND:
|
||||
_Rewind();
|
||||
break;
|
||||
case MSG_FORWARD:
|
||||
_Forward();
|
||||
break;
|
||||
|
||||
case MSG_SKIP_BACKWARDS:
|
||||
_SkipBackward();
|
||||
break;
|
||||
case MSG_SKIP_FORWARD:
|
||||
_SkipForward();
|
||||
break;
|
||||
|
||||
case MSG_SET_VOLUME:
|
||||
_SetVolume();
|
||||
break;
|
||||
case MSG_SET_MUTE:
|
||||
_ToggleMute();
|
||||
break;
|
||||
|
||||
default:
|
||||
BView::MessageReceived(message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// default implementation for the virtuals
|
||||
uint32 TransportControlGroup::EnabledButtons() { return 0; }
|
||||
void TransportControlGroup::TogglePlaying() {}
|
||||
void TransportControlGroup::Stop() {}
|
||||
void TransportControlGroup::Rewind() {}
|
||||
void TransportControlGroup::Forward() {}
|
||||
void TransportControlGroup::SkipBackward() {}
|
||||
void TransportControlGroup::SkipForward() {}
|
||||
void TransportControlGroup::SetVolume(float value) {}
|
||||
void TransportControlGroup::ToggleMute() {}
|
||||
|
||||
// SetEnabled
|
||||
void
|
||||
TransportControlGroup::SetEnabled(uint32 buttons)
|
||||
{
|
||||
fVolumeSlider->SetEnabled(buttons & VOLUME_ENABLED);
|
||||
fMute->SetEnabled(buttons & VOLUME_ENABLED);
|
||||
|
||||
fSkipBack->SetEnabled(buttons & SKIP_BACK_ENABLED);
|
||||
fSkipForward->SetEnabled(buttons & SKIP_FORWARD_ENABLED);
|
||||
fRewind->SetEnabled(buttons & SEEK_BACK_ENABLED);
|
||||
fForward->SetEnabled(buttons & SEEK_FORWARD_ENABLED);
|
||||
|
||||
fPlayPause->SetEnabled(buttons & PLAYBACK_ENABLED);
|
||||
fStop->SetEnabled(buttons & PLAYBACK_ENABLED);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetPlaybackState
|
||||
void
|
||||
TransportControlGroup::SetPlaybackState(uint32 state)
|
||||
{
|
||||
switch (state) {
|
||||
case PLAYBACK_STATE_PLAYING:
|
||||
fPlayPause->SetPlaying();
|
||||
break;
|
||||
case PLAYBACK_STATE_PAUSED:
|
||||
fPlayPause->SetPaused();
|
||||
break;
|
||||
case PLAYBACK_STATE_STOPPED:
|
||||
fPlayPause->SetStopped();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// SetSkippable
|
||||
void
|
||||
TransportControlGroup::SetSkippable(bool backward, bool forward)
|
||||
{
|
||||
fSkipBack->SetEnabled(backward);
|
||||
fSkipForward->SetEnabled(forward);
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// SetAudioEnabled
|
||||
void
|
||||
TransportControlGroup::SetAudioEnabled(bool enabled)
|
||||
{
|
||||
fMute->SetEnabled(enabled);
|
||||
fVolumeSlider->SetEnabled(enabled);
|
||||
}
|
||||
|
||||
// SetMuted
|
||||
void
|
||||
TransportControlGroup::SetMuted(bool mute)
|
||||
{
|
||||
fVolumeSlider->SetMuted(mute);
|
||||
}
|
||||
|
||||
// Volume
|
||||
uint32
|
||||
TransportControlGroup::Volume() const
|
||||
{
|
||||
return fVolumeSlider->Value();
|
||||
}
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
// _LayoutControls
|
||||
void
|
||||
TransportControlGroup::_LayoutControls(BRect frame) const
|
||||
{
|
||||
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;
|
||||
|
||||
float currentWidth = frame.Width();
|
||||
float space = (currentWidth - minWidth) / 6.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.top + MIN_SPACE;
|
||||
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
|
||||
TransportControlGroup::_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 += fBottomControlHeight;
|
||||
return BRect(0.0, 0.0, minWidth - 1.0, minHeight - 1.0);
|
||||
}
|
||||
|
||||
// _LayoutControl
|
||||
void
|
||||
TransportControlGroup::_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);
|
||||
}
|
||||
|
||||
// _TogglePlaying
|
||||
void
|
||||
TransportControlGroup::_TogglePlaying()
|
||||
{
|
||||
TogglePlaying();
|
||||
}
|
||||
|
||||
// _Stop
|
||||
void
|
||||
TransportControlGroup::_Stop()
|
||||
{
|
||||
fPlayPause->SetStopped();
|
||||
Stop();
|
||||
}
|
||||
|
||||
// _Rewind
|
||||
void
|
||||
TransportControlGroup::_Rewind()
|
||||
{
|
||||
Rewind();
|
||||
}
|
||||
|
||||
// _Forward
|
||||
void
|
||||
TransportControlGroup::_Forward()
|
||||
{
|
||||
Forward();
|
||||
}
|
||||
|
||||
// _SkipBackward
|
||||
void
|
||||
TransportControlGroup::_SkipBackward()
|
||||
{
|
||||
SkipBackward();
|
||||
}
|
||||
|
||||
// _SkipForward
|
||||
void
|
||||
TransportControlGroup::_SkipForward()
|
||||
{
|
||||
SkipForward();
|
||||
}
|
||||
|
||||
// _SetVolume
|
||||
void
|
||||
TransportControlGroup::_SetVolume()
|
||||
{
|
||||
SetVolume((float)(fVolumeSlider->Value() / 255.0));
|
||||
}
|
||||
|
||||
// _ToggleMute
|
||||
void
|
||||
TransportControlGroup::_ToggleMute()
|
||||
{
|
||||
fVolumeSlider->SetMuted(!fVolumeSlider->IsMuted());
|
||||
ToggleMute();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me
|
||||
// removed. -Stephan Aßmus
|
||||
|
||||
#ifndef TRANSPORT_CONTROL_GROUP_H
|
||||
#define TRANSPORT_CONTROL_GROUP_H
|
||||
|
||||
#include <View.h>
|
||||
|
||||
class PlayPauseButton;
|
||||
class TransportButton;
|
||||
class VolumeSlider;
|
||||
|
||||
enum {
|
||||
PLAYBACK_STATE_PLAYING = 0,
|
||||
PLAYBACK_STATE_PAUSED,
|
||||
PLAYBACK_STATE_STOPPED,
|
||||
};
|
||||
|
||||
enum {
|
||||
SKIP_BACK_ENABLED = 1 << 0,
|
||||
SEEK_BACK_ENABLED = 1 << 1,
|
||||
PLAYBACK_ENABLED = 1 << 2,
|
||||
SEEK_FORWARD_ENABLED = 1 << 3,
|
||||
SKIP_FORWARD_ENABLED = 1 << 4,
|
||||
VOLUME_ENABLED = 1 << 5,
|
||||
};
|
||||
|
||||
class TransportControlGroup : public BView {
|
||||
public:
|
||||
TransportControlGroup(BRect frame);
|
||||
virtual ~TransportControlGroup();
|
||||
|
||||
// BView interface
|
||||
virtual void AttachedToWindow();
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void GetPreferredSize(float* width, float* height);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
// TransportControlGroup
|
||||
virtual uint32 EnabledButtons();
|
||||
virtual void TogglePlaying();
|
||||
virtual void Stop();
|
||||
virtual void Rewind();
|
||||
virtual void Forward();
|
||||
virtual void SkipBackward();
|
||||
virtual void SkipForward();
|
||||
virtual void SetVolume(float value);
|
||||
virtual void ToggleMute();
|
||||
|
||||
void SetEnabled(uint32 whichButtons);
|
||||
|
||||
void SetPlaybackState(uint32 state);
|
||||
void SetSkippable(bool backward,
|
||||
bool forward);
|
||||
|
||||
void SetAudioEnabled(bool enable);
|
||||
void SetMuted(bool mute);
|
||||
uint32 Volume() const;
|
||||
|
||||
private:
|
||||
void _LayoutControls(BRect frame) const;
|
||||
BRect _MinFrame() const;
|
||||
void _LayoutControl(BView* view,
|
||||
BRect frame,
|
||||
bool resizeWidth = false,
|
||||
bool resizeHeight = false) const;
|
||||
|
||||
void _TogglePlaying();
|
||||
void _Stop();
|
||||
void _Rewind();
|
||||
void _Forward();
|
||||
void _SkipBackward();
|
||||
void _SkipForward();
|
||||
void _SetVolume();
|
||||
void _ToggleMute();
|
||||
|
||||
|
||||
VolumeSlider* fVolumeSlider;
|
||||
|
||||
TransportButton* fSkipBack;
|
||||
TransportButton* fSkipForward;
|
||||
TransportButton* fRewind;
|
||||
TransportButton* fForward;
|
||||
PlayPauseButton* fPlayPause;
|
||||
TransportButton* fStop;
|
||||
TransportButton* fMute;
|
||||
|
||||
int fCurrentStatus;
|
||||
float fBottomControlHeight;
|
||||
};
|
||||
|
||||
#endif // TRANSPORT_CONTROL_GROUP_H
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
// NOTE: Based on my code in the BeOS interface for the VLC media player
|
||||
// that I did during the VLC 0.4.3 - 0.4.6 times. Code not done by me
|
||||
// removed. -Stephan Aßmus
|
||||
|
||||
#include "VolumeSlider.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Bitmap.h>
|
||||
#include <Screen.h>
|
||||
|
||||
#include "ButtonBitmaps.h"
|
||||
#include "DrawingTidbits.h"
|
||||
|
||||
// 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 DIM_LEVEL 0.4
|
||||
|
||||
// constructor
|
||||
VolumeSlider::VolumeSlider(BRect frame, const char* name,
|
||||
int32 minValue, int32 maxValue,
|
||||
BMessage* message, BHandler* target)
|
||||
: BControl(frame, name, NULL, message, B_FOLLOW_LEFT | B_FOLLOW_TOP,
|
||||
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(0.0, 0.0,
|
||||
kVolumeSliderBitmapWidth - 1, kVolumeSliderBitmapHeight - 1);
|
||||
fLeftSideBits = new BBitmap(r, B_CMAP8);
|
||||
fRightSideBits = new BBitmap(r, B_CMAP8);
|
||||
r.Set(0.0, 0.0,
|
||||
kVolumeSliderKnobWidth - 1, kVolumeSliderKnobHeight - 1);
|
||||
fKnobBits = new BBitmap(r, B_CMAP8);
|
||||
|
||||
_MakeBitmaps();
|
||||
}
|
||||
|
||||
// destructor
|
||||
VolumeSlider::~VolumeSlider()
|
||||
{
|
||||
delete fLeftSideBits;
|
||||
delete fRightSideBits;
|
||||
delete fKnobBits;
|
||||
}
|
||||
|
||||
// AttachedToWindow
|
||||
void
|
||||
VolumeSlider::AttachedToWindow()
|
||||
{
|
||||
BControl::AttachedToWindow();
|
||||
SetViewColor(B_TRANSPARENT_COLOR);
|
||||
}
|
||||
|
||||
// SetValue
|
||||
void
|
||||
VolumeSlider::SetValue(int32 value)
|
||||
{
|
||||
if (value == Value())
|
||||
return;
|
||||
|
||||
BControl::SetValue(value);
|
||||
Invoke();
|
||||
}
|
||||
|
||||
// SetEnabled
|
||||
void
|
||||
VolumeSlider::SetEnabled(bool enable)
|
||||
{
|
||||
if (enable == IsEnabled())
|
||||
return;
|
||||
|
||||
BControl::SetEnabled(enable);
|
||||
|
||||
_MakeBitmaps();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// Draw
|
||||
void
|
||||
VolumeSlider::Draw(BRect updateRect)
|
||||
{
|
||||
if (!IsValid()) {
|
||||
fprintf(stderr, "VolumeSlider::Draw() - Error: no valid bitmaps!");
|
||||
SetHighColor(255, 0, 0);
|
||||
FillRect(updateRect);
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// MouseMoved
|
||||
void
|
||||
VolumeSlider::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
|
||||
{
|
||||
if (fTracking)
|
||||
SetValue(_ValueFor(where.x));
|
||||
}
|
||||
|
||||
// MouseUp
|
||||
void
|
||||
VolumeSlider::MouseUp(BPoint where)
|
||||
{
|
||||
fTracking = false;
|
||||
}
|
||||
|
||||
// IsValid
|
||||
bool
|
||||
VolumeSlider::IsValid() const
|
||||
{
|
||||
return (fLeftSideBits && fLeftSideBits->IsValid()
|
||||
&& fRightSideBits && fRightSideBits->IsValid()
|
||||
&& fKnobBits && fKnobBits->IsValid());
|
||||
}
|
||||
|
||||
// SetMuted
|
||||
void
|
||||
VolumeSlider::SetMuted(bool mute)
|
||||
{
|
||||
if (mute == fMuted)
|
||||
return;
|
||||
|
||||
fMuted = mute;
|
||||
_MakeBitmaps();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
// _MakeBitmaps
|
||||
void
|
||||
VolumeSlider::_MakeBitmaps()
|
||||
{
|
||||
if (!IsValid())
|
||||
return;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// _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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2006, Haiku.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*
|
||||
* Authors:
|
||||
* Stephan Aßmus <superstippi@gmx.de>
|
||||
*/
|
||||
|
||||
#ifndef VOLUME_SLIDER_H
|
||||
#define VOLUME_SLIDER_H
|
||||
|
||||
#include <Control.h>
|
||||
|
||||
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);
|
||||
bool IsMuted() const
|
||||
{ return fMuted; }
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
#endif // VOLUME_SLIDER_H
|
||||
Reference in New Issue
Block a user