Files
haiku-beta6/src/apps/bin/desklink/VolumeSlider.cpp
T

346 lines
8.6 KiB
C++
Raw Normal View History

2003-10-30 15:10:18 +00:00
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
//
// Copyright (c) 2003, OpenBeOS
//
// This software is part of the OpenBeOS distribution and is covered
// by the OpenBeOS license.
//
//
// Program: desklink
// Author: Jérôme DUVAL
// Description: VolumeControl and link items in Deskbar
// Created : October 20, 2003
// Modified by: Jérome Duval
//
// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
#include <MediaRoster.h>
#include <MediaTheme.h>
#include <MultiChannelControl.h>
#include <Screen.h>
#include <Beep.h>
#include <Box.h>
#include <stdio.h>
#include <Debug.h>
#include "VolumeSlider.h"
#include "iconfile.h"
#define VOLUME_CHANGED 'vlcg'
2003-10-31 16:42:05 +00:00
#define VOLUME_UPDATED 'vlud'
2003-10-30 15:10:18 +00:00
VolumeSlider::VolumeSlider(BRect frame)
: BWindow(frame, "VolumeSlider", B_BORDERED_WINDOW, B_ASYNCHRONOUS_CONTROLS | B_WILL_ACCEPT_FIRST_CLICK, 0),
aOutNode(NULL),
paramWeb(NULL),
mixerParam(NULL)
{
//Make sure it's not outside the screen.
const int32 kMargin = 3;
BRect windowRect=ConvertToScreen(Bounds());
BRect screenFrame(BScreen(B_MAIN_SCREEN_ID).Frame());
if (screenFrame.right < windowRect.right + kMargin)
MoveBy(- kMargin - windowRect.right + screenFrame.right, 0);
if (screenFrame.bottom < windowRect.bottom + kMargin)
MoveBy(0, - kMargin - windowRect.bottom + screenFrame.bottom);
if (screenFrame.left > windowRect.left - kMargin)
MoveBy(kMargin + screenFrame.left - windowRect.left, 0);
if (screenFrame.top > windowRect.top - kMargin)
MoveBy(0, kMargin + screenFrame.top - windowRect.top);
float value = 0.0;
2003-10-31 16:42:05 +00:00
bool retrying = false;
2003-10-30 15:10:18 +00:00
aOutNode = new media_node();
2003-10-31 16:42:05 +00:00
status_t err = B_OK; /* BMediaRoster::Roster() doesn't set it if all is ok */
const char *errString = NULL;
2003-10-30 15:10:18 +00:00
BMediaRoster* roster = BMediaRoster::Roster(&err);
2003-10-31 16:42:05 +00:00
retry:
/* here we release the BMediaRoster once if we can't access the system mixer,
* to make sure it really isn't there, and it's not BMediaRoster that is messed up.
*/
if (retrying) {
errString = NULL;
PRINT(("retrying to get a Media Roster\n"));
/* BMediaRoster looks doomed */
roster = BMediaRoster::CurrentRoster();
if (roster) {
roster->Lock();
roster->Quit();
}
snooze(10000);
roster = BMediaRoster::Roster(&err);
}
2003-10-30 15:10:18 +00:00
2003-10-31 16:42:05 +00:00
if (roster && (err==B_OK)) {
//if((err = roster->GetAudioOutput(aOutNode)) == B_OK) {
if((err = roster->GetAudioMixer(aOutNode)) == B_OK) {
2003-10-30 15:10:18 +00:00
if((err = roster->GetParameterWebFor(*aOutNode, &paramWeb)) == B_OK) {
//Finding the Mixer slider in the audio output ParameterWeb
int32 numParams = paramWeb->CountParameters();
BParameter* p = NULL;
for (int i = 0; i < numParams; i++) {
p = paramWeb->ParameterAt(i);
2003-10-31 16:42:05 +00:00
PRINT(("BParameter[%i]: %s\n", i, p->Name()));
//if (!strcmp(p->Name(), "Master")) {
if (!strcmp(p->Kind(), B_MASTER_GAIN)) {
2003-10-30 15:10:18 +00:00
for (; i < numParams; i++) {
p = paramWeb->ParameterAt(i);
if (strcmp(p->Kind(), B_MASTER_GAIN)) p=NULL;
else break;
}
break;
} else p = NULL;
}
if (p==NULL) {
2003-10-31 16:42:05 +00:00
errString = "Could not find the mixer";
2003-10-30 15:10:18 +00:00
} else if(p->Type()!=BParameter::B_CONTINUOUS_PARAMETER) {
2003-10-31 16:42:05 +00:00
errString = "Mixer is unknown";
} else {
2003-10-30 15:10:18 +00:00
2003-10-31 16:42:05 +00:00
mixerParam = dynamic_cast<BContinuousParameter*>(p);
min = mixerParam->MinValue();
max = mixerParam->MaxValue();
step = mixerParam->ValueStep();
float chanData[2];
bigtime_t lastChange;
size_t size = sizeof(chanData);
mixerParam->GetValue( &chanData, &size, &lastChange );
value = (chanData[0]-min)*100/(max-min);
}
2003-10-30 15:10:18 +00:00
} else {
2003-10-31 16:42:05 +00:00
errString = "No parameter web";
2003-10-30 15:10:18 +00:00
}
} else {
2003-10-31 16:42:05 +00:00
if (!retrying) {
retrying = true;
goto retry;
}
errString = "No Audio output";
2003-10-30 15:10:18 +00:00
}
} else {
2003-10-31 16:42:05 +00:00
if (!retrying) {
retrying = true;
goto retry;
}
errString = "No Media Roster";
2003-10-30 15:10:18 +00:00
}
if(err!=B_OK) {
delete aOutNode;
aOutNode = NULL;
}
2003-10-31 16:42:05 +00:00
if (errString)
fprintf(stderr, "VolumeSlider: %s.\n", errString);
2003-10-30 15:10:18 +00:00
BBox *box = new BBox(Bounds(), "sliderbox", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW | B_FRAME_EVENTS, B_PLAIN_BORDER);
AddChild(box);
2003-10-31 16:42:05 +00:00
hasChanged = false; /* make sure we don't beep if we don't change anything */
2003-10-30 15:10:18 +00:00
slider = new SliderView(box->Bounds().InsetByCopy(1, 1), new BMessage(VOLUME_CHANGED),
2003-10-31 16:42:05 +00:00
(errString==NULL) ? "Volume" : errString, B_FOLLOW_LEFT | B_FOLLOW_TOP, value);
2003-10-30 15:10:18 +00:00
box->AddChild(slider);
slider->SetTarget(this);
SetPulseRate(100);
}
VolumeSlider::~VolumeSlider()
{
delete paramWeb;
BMediaRoster* roster = BMediaRoster::CurrentRoster();
if(roster && aOutNode)
roster->ReleaseNode(*aOutNode);
}
void
VolumeSlider::WindowActivated(bool active)
{
2003-10-31 16:42:05 +00:00
/* don't Quit() ! thanks for FFM users */
2003-10-30 15:10:18 +00:00
}
void
VolumeSlider::MessageReceived(BMessage *msg)
{
switch (msg->what) {
2003-10-31 16:42:05 +00:00
case VOLUME_UPDATED:
PRINT(("VOLUME_UPDATED\n"));
UpdateVolume(mixerParam);
hasChanged = true;
break;
case VOLUME_CHANGED:
if (hasChanged) {
PRINT(("VOLUME_CHANGED\n"));
UpdateVolume(mixerParam);
beep();
2003-10-30 15:10:18 +00:00
}
2003-10-31 16:42:05 +00:00
Quit();
break;
default:
BWindow::MessageReceived(msg); // not a slider message, not our problem
}
}
void VolumeSlider::UpdateVolume(BContinuousParameter* param)
{
if (!param)
return;
float chanData[2];
bigtime_t lastChange;
size_t size = sizeof(chanData);
mixerParam->GetValue( &chanData, &size, &lastChange );
for( int i=0; i<2; i++) {
chanData[i] = (slider->Value() * (max - min) / 100) / step * step + min;
}
PRINT(("Min value: %f Max Value: %f\nData: %f %f\n", mixerParam->MinValue(), mixerParam->MaxValue(), chanData[0], chanData[1]));
mixerParam->SetValue(&chanData, sizeof(chanData), system_time()+1000);
2003-10-30 15:10:18 +00:00
}
#define REDZONESTART 151
SliderView::SliderView(BRect rect, BMessage *msg, const char *title, uint32 resizeFlags, int32 value)
: BControl(rect, "slider", NULL, msg, resizeFlags, B_WILL_DRAW | B_PULSE_NEEDED),
leftBitmap(BRect(0, 0, kLeftWidth - 1, kLeftHeight - 1), B_CMAP8),
rightBitmap(BRect(0, 0, kRightWidth - 1, kRightHeight - 1), B_CMAP8),
buttonBitmap(BRect(0, 0, kButtonWidth - 1, kButtonHeight - 1), B_CMAP8),
fTitle(title)
{
leftBitmap.SetBits(kLeftBits, kLeftWidth * kLeftHeight, 0, B_CMAP8);
rightBitmap.SetBits(kRightBits, kRightWidth * kRightHeight, 0, B_CMAP8);
buttonBitmap.SetBits(kButtonBits, kButtonWidth * kButtonHeight, 0, B_CMAP8);
SetTracking(true);
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
SetValue(value);
}
SliderView::~SliderView()
{
}
void
SliderView::Pulse()
{
uint32 mouseButtons;
BPoint where;
GetMouse(&where, &mouseButtons, true);
// button not pressed, exit
if (! (mouseButtons & B_PRIMARY_MOUSE_BUTTON)) {
SetTracking(false);
Invoke();
}
}
void
SliderView::Draw(BRect updateRect)
{
SetHighColor(189,186,189);
StrokeLine(BPoint(11,1), BPoint(192,1));
SetHighColor(0,0,0);
StrokeLine(BPoint(11,2), BPoint(192,2));
SetHighColor(255,255,255);
StrokeLine(BPoint(11,14), BPoint(192,14));
SetHighColor(231,227,231);
StrokeLine(BPoint(11,15), BPoint(192,15));
SetLowColor(ViewColor());
SetDrawingMode(B_OP_OVER);
DrawBitmapAsync(&leftBitmap, BPoint(5,1));
DrawBitmapAsync(&rightBitmap, BPoint(193,1));
2003-10-31 16:42:05 +00:00
float position = 11 + (192-11) * Value() / 100;
float right = (position < REDZONESTART) ? position : REDZONESTART;
2003-10-30 15:10:18 +00:00
SetHighColor(99,151,99);
FillRect(BRect(11,3,right,4));
SetHighColor(156,203,156);
FillRect(BRect(11,5,right,13));
if(right == REDZONESTART) {
SetHighColor(156,101,99);
2003-10-31 16:42:05 +00:00
FillRect(BRect(REDZONESTART,3,position,4));
2003-10-30 15:10:18 +00:00
SetHighColor(255,154,156);
2003-10-31 16:42:05 +00:00
FillRect(BRect(REDZONESTART,5,position,13));
2003-10-30 15:10:18 +00:00
}
SetHighColor(156,154,156);
2003-10-31 16:42:05 +00:00
FillRect(BRect(position,3,192,13));
2003-10-30 15:10:18 +00:00
BFont font;
float width = font.StringWidth(fTitle);
SetHighColor(49,154,49);
DrawString(fTitle, BPoint(11 + (192-11-width)/2, 12));
2003-10-31 16:42:05 +00:00
DrawBitmapAsync(&buttonBitmap, BPoint(position-5,3));
2003-10-30 15:10:18 +00:00
Sync();
SetDrawingMode(B_OP_COPY);
}
void
SliderView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
{
if (!IsTracking())
return;
uint32 mouseButtons;
BPoint where;
GetMouse(&where, &mouseButtons, true);
// button not pressed, exit
if (! (mouseButtons & B_PRIMARY_MOUSE_BUTTON)) {
Invoke();
SetTracking(false);
}
if (!Bounds().InsetBySelf(2,2).Contains(point))
return;
2003-10-31 16:42:05 +00:00
float v = MIN(MAX(point.x, 11), 192);
v = (v - 11) / (192-11) * 100;
v = MAX(MIN(v,100), 0);
SetValue(v);
2003-10-30 15:10:18 +00:00
Draw(Bounds());
Flush();
2003-10-31 16:42:05 +00:00
if (Window())
Window()->PostMessage(VOLUME_UPDATED);
2003-10-30 15:10:18 +00:00
}
void
SliderView::MouseUp(BPoint point)
{
if (!IsTracking())
return;
2003-10-31 16:42:05 +00:00
if (Bounds().InsetBySelf(2,2).Contains(point)) {
float v = MIN(MAX(point.x, 11), 192);
v = (v - 11) / (192-11) * 100;
v = MAX(MIN(v,100), 0);
SetValue(v);
}
2003-10-30 15:10:18 +00:00
Invoke();
SetTracking(false);
Draw(Bounds());
Flush();
}