|
|
|
/*
|
|
|
|
* KMix -- KDE's full featured mini mixer
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* Copyright (C) 1996-2004 Christian Esken <esken@kde.org>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library 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
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library 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 <klocale.h>
|
|
|
|
#include <kled.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kaction.h>
|
|
|
|
#include <kpopupmenu.h>
|
|
|
|
#include <kglobalaccel.h>
|
|
|
|
#include <kkeydialog.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
#include <qobject.h>
|
|
|
|
#include <qcursor.h>
|
|
|
|
#include <qslider.h>
|
|
|
|
#include <qlabel.h>
|
|
|
|
#include <qlayout.h>
|
|
|
|
#include <qpixmap.h>
|
|
|
|
#include <qtooltip.h>
|
|
|
|
#include <qwmatrix.h>
|
|
|
|
|
|
|
|
#include "mdwslider.h"
|
|
|
|
#include "mixer.h"
|
|
|
|
#include "viewbase.h"
|
|
|
|
#include "kledbutton.h"
|
|
|
|
#include "ksmallslider.h"
|
|
|
|
#include "verticaltext.h"
|
|
|
|
|
|
|
|
/**
|
|
|
|
* MixDeviceWidget that represents a single mix device, inlcuding PopUp, muteLED, ...
|
|
|
|
*
|
|
|
|
* Used in KMix main window and DockWidget and PanelApplet.
|
|
|
|
* It can be configured to include or exclude the recordLED and the muteLED.
|
|
|
|
* The direction (horizontal, vertical) can be configured and whether it should
|
|
|
|
* be "small" (uses KSmallSlider instead of QSlider then).
|
|
|
|
*
|
|
|
|
* Due to the many options, this is the most complicated MixDeviceWidget subclass.
|
|
|
|
*/
|
|
|
|
MDWSlider::MDWSlider(Mixer *mixer, MixDevice* md,
|
|
|
|
bool showMuteLED, bool showRecordLED,
|
|
|
|
bool small, Qt::Orientation orientation,
|
|
|
|
QWidget* parent, ViewBase* mw, const char* name) :
|
|
|
|
MixDeviceWidget(mixer,md,small,orientation,parent,mw,name),
|
|
|
|
m_linked(true), m_valueStyle( NNONE), m_iconLabel( 0 ), m_muteLED( 0 ), m_recordLED( 0 ), m_label( 0 ), _layout(0)
|
|
|
|
{
|
|
|
|
// create actions (on _mdwActions, see MixDeviceWidget)
|
|
|
|
|
|
|
|
new KToggleAction( i18n("&Split Channels"), 0, this, SLOT(toggleStereoLinked()),
|
|
|
|
_mdwActions, "stereo" );
|
|
|
|
new KToggleAction( i18n("&Hide"), 0, this, SLOT(setDisabled()), _mdwActions, "hide" );
|
|
|
|
|
|
|
|
KToggleAction *a = new KToggleAction(i18n("&Muted"), 0, 0, 0, _mdwActions, "mute" );
|
|
|
|
connect( a, SIGNAL(toggled(bool)), SLOT(toggleMuted()) );
|
|
|
|
|
|
|
|
if( m_mixdevice->isRecordable() ) {
|
|
|
|
a = new KToggleAction( i18n("Set &Record Source"), 0, 0, 0, _mdwActions, "recsrc" );
|
|
|
|
connect( a, SIGNAL(toggled(bool)), SLOT( toggleRecsrc()) );
|
|
|
|
}
|
|
|
|
|
|
|
|
new KAction( i18n("C&onfigure Global Shortcuts..."), 0, this, SLOT(defineKeys()), _mdwActions, "keys" );
|
|
|
|
|
|
|
|
// create widgets
|
|
|
|
createWidgets( showMuteLED, showRecordLED );
|
|
|
|
|
|
|
|
m_keys->insert( "Increase volume", i18n( "Increase Volume of '%1'" ).arg(m_mixdevice->name().utf8().data()), QString::null,
|
|
|
|
KShortcut(), KShortcut(), this, SLOT( increaseVolume() ) );
|
|
|
|
m_keys->insert( "Decrease volume", i18n( "Decrease Volume of '%1'" ).arg(m_mixdevice->name().utf8().data()), QString::null,
|
|
|
|
KShortcut(), KShortcut(), this, SLOT( decreaseVolume() ) );
|
|
|
|
m_keys->insert( "Toggle mute", i18n( "Toggle Mute of '%1'" ).arg(m_mixdevice->name().utf8().data()), QString::null,
|
|
|
|
KShortcut(), KShortcut(), this, SLOT( toggleMuted() ) );
|
|
|
|
|
|
|
|
installEventFilter( this ); // filter for popup
|
|
|
|
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QSizePolicy MDWSlider::sizePolicy() const
|
|
|
|
{
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
return QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates up to 4 widgets - Icon, Mute-Button, Slider and Record-Button.
|
|
|
|
*
|
|
|
|
* Those widgets are placed into
|
|
|
|
|
|
|
|
*/
|
|
|
|
void MDWSlider::createWidgets( bool showMuteLED, bool showRecordLED )
|
|
|
|
{
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
_layout = new QVBoxLayout( this );
|
|
|
|
_layout->setAlignment(Qt::AlignCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
_layout = new QHBoxLayout( this );
|
|
|
|
_layout->setAlignment(Qt::AlignCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -- MAIN SLIDERS LAYOUT ---
|
|
|
|
QBoxLayout *slidersLayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
slidersLayout = new QHBoxLayout( _layout );
|
|
|
|
slidersLayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
slidersLayout = new QVBoxLayout( _layout );
|
|
|
|
slidersLayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cesken: This is inconsistent. Why should vertical and horizontal layout differ?
|
|
|
|
* Also it eats too much space - especially when you don't show sliders at all.
|
|
|
|
* Even more on the vertical panel applet (see Bug #97667)
|
|
|
|
if ( _orientation == Qt::Horizontal )
|
|
|
|
slidersLayout->addSpacing( 10 );
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// -- LABEL LAYOUT TO POSITION
|
|
|
|
QBoxLayout *labelLayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
labelLayout = new QVBoxLayout( slidersLayout );
|
|
|
|
labelLayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
labelLayout = new QHBoxLayout( slidersLayout );
|
|
|
|
labelLayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
m_label = new VerticalText( this, m_mixdevice->name().utf8().data() );
|
|
|
|
QToolTip::add( m_label, m_mixdevice->name() );
|
|
|
|
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_label = new QLabel(this);
|
|
|
|
static_cast<QLabel*>(m_label) ->setText(m_mixdevice->name());
|
|
|
|
QToolTip::add( m_label, m_mixdevice->name() );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_label->hide();
|
|
|
|
|
|
|
|
/* This addSpacing() looks VERY bizarre => removing it (cesken, 21.2.2006).
|
|
|
|
Also horizontal and vertical spacing differs. This doesn't look sensible.
|
|
|
|
if ( _orientation == Qt::Horizontal )
|
|
|
|
labelLayout->addSpacing( 36 );
|
|
|
|
*/
|
|
|
|
labelLayout->addWidget( m_label );
|
|
|
|
m_label->installEventFilter( this );
|
|
|
|
|
|
|
|
/* This addSpacing() looks VERY bizarre => removing it (cesken, 21.2.2006)
|
|
|
|
Also horizontal and vertical spacing differs. This doesn't look sensible.
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
labelLayout->addSpacing( 18 );
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
// -- SLIDERS, LEDS AND ICON
|
|
|
|
QBoxLayout *sliLayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
sliLayout = new QVBoxLayout( slidersLayout );
|
|
|
|
sliLayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sliLayout = new QHBoxLayout( slidersLayout );
|
|
|
|
sliLayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- ICON ----------------------------
|
|
|
|
QBoxLayout *iconLayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
iconLayout = new QHBoxLayout( sliLayout );
|
|
|
|
iconLayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
iconLayout = new QVBoxLayout( sliLayout );
|
|
|
|
iconLayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_iconLabel = 0L;
|
|
|
|
setIcon( m_mixdevice->type() );
|
|
|
|
iconLayout->addStretch();
|
|
|
|
iconLayout->addWidget( m_iconLabel );
|
|
|
|
iconLayout->addStretch();
|
|
|
|
m_iconLabel->installEventFilter( this );
|
|
|
|
|
|
|
|
sliLayout->addSpacing( 5 );
|
|
|
|
|
|
|
|
|
|
|
|
// --- MUTE LED
|
|
|
|
if ( showMuteLED ) {
|
|
|
|
QBoxLayout *ledlayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
ledlayout = new QHBoxLayout( sliLayout );
|
|
|
|
ledlayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ledlayout = new QVBoxLayout( sliLayout );
|
|
|
|
ledlayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_mixdevice->hasMute() )
|
|
|
|
{
|
|
|
|
ledlayout->addStretch();
|
|
|
|
// create mute LED
|
|
|
|
m_muteLED = new KLedButton( Qt::green, KLed::On, KLed::Sunken,
|
|
|
|
KLed::Circular, this, "MuteLED" );
|
|
|
|
m_muteLED->setFixedSize( QSize(16, 16) );
|
|
|
|
m_muteLED->resize( QSize(16, 16) );
|
|
|
|
ledlayout->addWidget( m_muteLED );
|
|
|
|
QToolTip::add( m_muteLED, i18n( "Mute" ) );
|
|
|
|
connect( m_muteLED, SIGNAL(stateChanged(bool)), this, SLOT(toggleMuted()) );
|
|
|
|
m_muteLED->installEventFilter( this );
|
|
|
|
ledlayout->addStretch();
|
|
|
|
} // has Mute LED
|
|
|
|
else {
|
|
|
|
// we don't have a MUTE LED. We create a dummy widget
|
|
|
|
// !! possibly not neccesary any more (we are layouted)
|
|
|
|
QWidget *qw = new QWidget(this, "Spacer");
|
|
|
|
qw->setFixedSize( QSize(16, 16) );
|
|
|
|
ledlayout->addWidget(qw);
|
|
|
|
qw->installEventFilter( this );
|
|
|
|
} // has no Mute LED
|
|
|
|
|
|
|
|
sliLayout->addSpacing( 3 );
|
|
|
|
} // showMuteLED
|
|
|
|
|
|
|
|
// --- SLIDERS ---------------------------
|
|
|
|
QBoxLayout *volLayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
volLayout = new QHBoxLayout( sliLayout );
|
|
|
|
volLayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
volLayout = new QVBoxLayout( sliLayout );
|
|
|
|
volLayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sliders and volume number indication
|
|
|
|
QBoxLayout *slinumLayout;
|
|
|
|
for( int i = 0; i < m_mixdevice->getVolume().count(); i++ )
|
|
|
|
{
|
|
|
|
Volume::ChannelID chid = Volume::ChannelID(i);
|
|
|
|
// @todo !! Normally the mixdevicewidget SHOULD know, which slider represents which channel.
|
|
|
|
// We should look up the mapping here, but for now, we simply assume "chid == i".
|
|
|
|
|
|
|
|
int maxvol = m_mixdevice->getVolume().maxVolume();
|
|
|
|
int minvol = m_mixdevice->getVolume().minVolume();
|
|
|
|
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
slinumLayout = new QVBoxLayout( volLayout );
|
|
|
|
slinumLayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
slinumLayout = new QHBoxLayout( volLayout );
|
|
|
|
slinumLayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// create labels to hold volume values (taken from qamix/kamix)
|
|
|
|
QLabel *number = new QLabel( "100", this );
|
|
|
|
slinumLayout->addWidget( number );
|
|
|
|
number->setFrameStyle( QFrame::Panel | QFrame::Sunken );
|
|
|
|
number->setLineWidth( 2 );
|
|
|
|
number->setMinimumWidth( number->sizeHint().width() );
|
|
|
|
number->setPaletteBackgroundColor( QColor(190, 250, 190) );
|
|
|
|
// don't show the value by default
|
|
|
|
number->hide();
|
|
|
|
updateValue( number, chid );
|
|
|
|
_numbers.append( number );
|
|
|
|
|
|
|
|
QWidget* slider;
|
|
|
|
if ( m_small ) {
|
|
|
|
slider = new KSmallSlider( minvol, maxvol, maxvol/10,
|
|
|
|
m_mixdevice->getVolume( chid ), _orientation,
|
|
|
|
this, m_mixdevice->name().ascii() );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
slider = new QSlider( 0, maxvol, maxvol/10,
|
|
|
|
maxvol - m_mixdevice->getVolume( chid ), _orientation,
|
|
|
|
this, m_mixdevice->name().ascii() );
|
|
|
|
slider->setMinimumSize( slider->sizeHint() );
|
|
|
|
}
|
|
|
|
|
|
|
|
slider->setBackgroundOrigin(AncestorOrigin);
|
|
|
|
slider->installEventFilter( this );
|
|
|
|
QToolTip::add( slider, m_mixdevice->name() );
|
|
|
|
|
|
|
|
if( i>0 && isStereoLinked() ) {
|
|
|
|
// show only one (the first) slider, when the user wants it so
|
|
|
|
slider->hide();
|
|
|
|
number->hide();
|
|
|
|
}
|
|
|
|
slinumLayout->addWidget( slider ); // add to layout
|
|
|
|
m_sliders.append ( slider ); // add to list
|
|
|
|
_slidersChids.append(chid); // Remember slider-chid association
|
|
|
|
connect( slider, SIGNAL(valueChanged(int)), SLOT(volumeChange(int)) );
|
|
|
|
} // for all channels of this device
|
|
|
|
|
|
|
|
|
|
|
|
// --- RECORD SOURCE LED --------------------------
|
|
|
|
if ( showRecordLED )
|
|
|
|
{
|
|
|
|
sliLayout->addSpacing( 5 );
|
|
|
|
|
|
|
|
// --- LED LAYOUT TO CENTER ---
|
|
|
|
QBoxLayout *reclayout;
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
reclayout = new QHBoxLayout( sliLayout );
|
|
|
|
reclayout->setAlignment(Qt::AlignVCenter);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
reclayout = new QVBoxLayout( sliLayout );
|
|
|
|
reclayout->setAlignment(Qt::AlignHCenter);
|
|
|
|
}
|
|
|
|
|
|
|
|
if( m_mixdevice->isRecordable() ) {
|
|
|
|
reclayout->addStretch();
|
|
|
|
m_recordLED = new KLedButton( Qt::red,
|
|
|
|
m_mixdevice->isRecSource()?KLed::On:KLed::Off,
|
|
|
|
KLed::Sunken, KLed::Circular, this, "RecordLED" );
|
|
|
|
m_recordLED->setFixedSize( QSize(16, 16) );
|
|
|
|
reclayout->addWidget( m_recordLED );
|
|
|
|
connect(m_recordLED, SIGNAL(stateChanged(bool)), this, SLOT(setRecsrc(bool)));
|
|
|
|
m_recordLED->installEventFilter( this );
|
|
|
|
QToolTip::add( m_recordLED, i18n( "Record" ) );
|
|
|
|
reclayout->addStretch();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// we don't have a RECORD LED. We create a dummy widget
|
|
|
|
// !! possibly not neccesary any more (we are layouted)
|
|
|
|
QWidget *qw = new QWidget(this, "Spacer");
|
|
|
|
qw->setFixedSize( QSize(16, 16) );
|
|
|
|
reclayout->addWidget(qw);
|
|
|
|
qw->installEventFilter( this );
|
|
|
|
} // has no Record LED
|
|
|
|
} // showRecordLED
|
|
|
|
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPixmap
|
|
|
|
MDWSlider::icon( int icontype )
|
|
|
|
{
|
|
|
|
QPixmap miniDevPM;
|
|
|
|
switch (icontype) {
|
|
|
|
case MixDevice::AUDIO:
|
|
|
|
miniDevPM = UserIcon("mix_audio"); break;
|
|
|
|
case MixDevice::BASS:
|
|
|
|
case MixDevice::SURROUND_LFE: // "LFE" SHOULD have an own icon
|
|
|
|
miniDevPM = UserIcon("mix_bass"); break;
|
|
|
|
case MixDevice::CD:
|
|
|
|
miniDevPM = UserIcon("mix_cd"); break;
|
|
|
|
case MixDevice::EXTERNAL:
|
|
|
|
miniDevPM = UserIcon("mix_ext"); break;
|
|
|
|
case MixDevice::MICROPHONE:
|
|
|
|
miniDevPM = UserIcon("mix_microphone");break;
|
|
|
|
case MixDevice::MIDI:
|
|
|
|
miniDevPM = UserIcon("mix_midi"); break;
|
|
|
|
case MixDevice::RECMONITOR:
|
|
|
|
miniDevPM = UserIcon("mix_recmon"); break;
|
|
|
|
case MixDevice::TREBLE:
|
|
|
|
miniDevPM = UserIcon("mix_treble"); break;
|
|
|
|
case MixDevice::UNKNOWN:
|
|
|
|
miniDevPM = UserIcon("mix_unknown"); break;
|
|
|
|
case MixDevice::VOLUME:
|
|
|
|
miniDevPM = UserIcon("mix_volume"); break;
|
|
|
|
case MixDevice::VIDEO:
|
|
|
|
miniDevPM = UserIcon("mix_video"); break;
|
|
|
|
case MixDevice::SURROUND:
|
|
|
|
case MixDevice::SURROUND_BACK:
|
|
|
|
case MixDevice::SURROUND_CENTERFRONT:
|
|
|
|
case MixDevice::SURROUND_CENTERBACK:
|
|
|
|
miniDevPM = UserIcon("mix_surround"); break;
|
|
|
|
case MixDevice::HEADPHONE:
|
|
|
|
miniDevPM = UserIcon( "mix_headphone" ); break;
|
|
|
|
case MixDevice::DIGITAL:
|
|
|
|
miniDevPM = UserIcon( "mix_digital" ); break;
|
|
|
|
case MixDevice::AC97:
|
|
|
|
miniDevPM = UserIcon( "mix_ac97" ); break;
|
|
|
|
default:
|
|
|
|
miniDevPM = UserIcon("mix_unknown"); break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return miniDevPM;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setIcon( int icontype )
|
|
|
|
{
|
|
|
|
if( !m_iconLabel )
|
|
|
|
{
|
|
|
|
m_iconLabel = new QLabel(this);
|
|
|
|
m_iconLabel->setBackgroundOrigin(AncestorOrigin);
|
|
|
|
installEventFilter( m_iconLabel );
|
|
|
|
}
|
|
|
|
|
|
|
|
QPixmap miniDevPM = icon( icontype );
|
|
|
|
if ( !miniDevPM.isNull() )
|
|
|
|
{
|
|
|
|
if ( m_small )
|
|
|
|
{
|
|
|
|
// scale icon
|
|
|
|
QWMatrix t;
|
|
|
|
t = t.scale( 10.0/miniDevPM.width(), 10.0/miniDevPM.height() );
|
|
|
|
m_iconLabel->setPixmap( miniDevPM.xForm( t ) );
|
|
|
|
m_iconLabel->resize( 10, 10 );
|
|
|
|
} else
|
|
|
|
m_iconLabel->setPixmap( miniDevPM );
|
|
|
|
m_iconLabel->setAlignment( Qt::AlignCenter );
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
kdError(67100) << "Pixmap missing." << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
MDWSlider::isLabeled() const
|
|
|
|
{
|
|
|
|
if ( m_label == 0 )
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return !m_label->isHidden();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::toggleStereoLinked()
|
|
|
|
{
|
|
|
|
setStereoLinked( !isStereoLinked() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setStereoLinked(bool value)
|
|
|
|
{
|
|
|
|
m_linked = value;
|
|
|
|
|
|
|
|
QWidget *slider = m_sliders.first();
|
|
|
|
QLabel *number = _numbers.first();
|
|
|
|
QString qs = number->text();
|
|
|
|
|
|
|
|
/***********************************************************
|
|
|
|
Remember value of first slider, so that it can be copied
|
|
|
|
to the other sliders.
|
|
|
|
***********************************************************/
|
|
|
|
int firstSliderValue = 0;
|
|
|
|
bool firstSliderValueValid = false;
|
|
|
|
if (slider->isA("QSlider") ) {
|
|
|
|
QSlider *sld = static_cast<QSlider*>(slider);
|
|
|
|
firstSliderValue = sld->value();
|
|
|
|
firstSliderValueValid = true;
|
|
|
|
}
|
|
|
|
else if ( slider->isA("KSmallSlider") ) {
|
|
|
|
KSmallSlider *sld = static_cast<KSmallSlider*>(slider);
|
|
|
|
firstSliderValue = sld->value();
|
|
|
|
firstSliderValueValid = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for( slider=m_sliders.next(), number=_numbers.next(); slider!=0 && number!=0; slider=m_sliders.next(), number=_numbers.next() ) {
|
|
|
|
if ( m_linked ) {
|
|
|
|
slider->hide();
|
|
|
|
number->hide();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// When splitting, make the next sliders show the same value as the first.
|
|
|
|
// This might not be entirely true, but better than showing the random value
|
|
|
|
// that was used to be shown before hot-fixing this. !! must be revised
|
|
|
|
if ( firstSliderValueValid ) {
|
|
|
|
// Remark: firstSlider== 0 could happen, if the static_cast<QRangeControl*> above fails.
|
|
|
|
// It's a safety measure, if we got other Slider types in the future.
|
|
|
|
if (slider->isA("QSlider") ) {
|
|
|
|
QSlider *sld = static_cast<QSlider*>(slider);
|
|
|
|
sld->setValue( firstSliderValue );
|
|
|
|
}
|
|
|
|
if (slider->isA("KSmallSlider") ) {
|
|
|
|
KSmallSlider *sld = static_cast<KSmallSlider*>(slider);
|
|
|
|
sld->setValue( firstSliderValue );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
slider->show();
|
|
|
|
number->setText(qs);
|
|
|
|
if (m_valueStyle != NNONE)
|
|
|
|
number->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
slider = m_sliders.last();
|
|
|
|
if( slider && static_cast<QSlider *>(slider)->tickmarks() )
|
|
|
|
setTicks( true );
|
|
|
|
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setLabeled(bool value)
|
|
|
|
{
|
|
|
|
if ( m_label == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (value )
|
|
|
|
m_label->show();
|
|
|
|
else
|
|
|
|
m_label->hide();
|
|
|
|
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setTicks( bool ticks )
|
|
|
|
{
|
|
|
|
QWidget* slider;
|
|
|
|
|
|
|
|
slider = m_sliders.first();
|
|
|
|
|
|
|
|
if ( slider->inherits( "QSlider" ) )
|
|
|
|
{
|
|
|
|
if( ticks )
|
|
|
|
if( isStereoLinked() )
|
|
|
|
static_cast<QSlider *>(slider)->setTickmarks( QSlider::Right );
|
|
|
|
else
|
|
|
|
{
|
|
|
|
static_cast<QSlider *>(slider)->setTickmarks( QSlider::NoMarks );
|
|
|
|
slider = m_sliders.last();
|
|
|
|
static_cast<QSlider *>(slider)->setTickmarks( QSlider::Left );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
static_cast<QSlider *>(slider)->setTickmarks( QSlider::NoMarks );
|
|
|
|
slider = m_sliders.last();
|
|
|
|
static_cast<QSlider *>(slider)->setTickmarks( QSlider::NoMarks );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setValueStyle( ValueStyle valueStyle )
|
|
|
|
{
|
|
|
|
m_valueStyle = valueStyle;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
|
|
|
|
for(QLabel *number = _numbers.first(); number!=0; number = _numbers.next(), ++i, ++it) {
|
|
|
|
Volume::ChannelID chid = *it;
|
|
|
|
switch ( m_valueStyle ) {
|
|
|
|
case NNONE: number->hide(); break;
|
|
|
|
default:
|
|
|
|
if ( !isStereoLinked() || (i == 0)) {
|
|
|
|
updateValue( number, chid );
|
|
|
|
number->show();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setIcons(bool value)
|
|
|
|
{
|
|
|
|
if ( m_iconLabel != 0 ) {
|
|
|
|
if ( ( !m_iconLabel->isHidden()) !=value ) {
|
|
|
|
if (value)
|
|
|
|
m_iconLabel->show();
|
|
|
|
else
|
|
|
|
m_iconLabel->hide();
|
|
|
|
|
|
|
|
layout()->activate();
|
|
|
|
}
|
|
|
|
} // if it has an icon
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setColors( QColor high, QColor low, QColor back )
|
|
|
|
{
|
|
|
|
for( QWidget *slider=m_sliders.first(); slider!=0; slider=m_sliders.next() ) {
|
|
|
|
KSmallSlider *smallSlider = dynamic_cast<KSmallSlider*>(slider);
|
|
|
|
if ( smallSlider ) smallSlider->setColors( high, low, back );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::setMutedColors( QColor high, QColor low, QColor back )
|
|
|
|
{
|
|
|
|
for( QWidget *slider=m_sliders.first(); slider!=0; slider=m_sliders.next() ) {
|
|
|
|
KSmallSlider *smallSlider = dynamic_cast<KSmallSlider*>(slider);
|
|
|
|
if ( smallSlider ) smallSlider->setGrayColors( high, low, back );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
MDWSlider::updateValue( QLabel *value, Volume::ChannelID chid ) {
|
|
|
|
QString qs;
|
|
|
|
Volume& vol = m_mixdevice->getVolume();
|
|
|
|
|
|
|
|
if (m_valueStyle == NABSOLUTE )
|
|
|
|
qs.sprintf("%3d", (int) vol.getVolume( chid ) );
|
|
|
|
else
|
|
|
|
qs.sprintf("%3d", (int)( vol.getVolume( chid ) / (double)vol.maxVolume() * 100 ) );
|
|
|
|
value->setText(qs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** This slot is called, when a user has changed the volume via the KMix Slider */
|
|
|
|
void MDWSlider::volumeChange( int )
|
|
|
|
{
|
|
|
|
// --- Step 1: Get a REFERENCE of the volume Object ---
|
|
|
|
Volume& vol = m_mixdevice->getVolume();
|
|
|
|
|
|
|
|
// --- Step 2: Change the volumes directly in the Volume object to reflect the Sliders ---
|
|
|
|
if ( isStereoLinked() )
|
|
|
|
{
|
|
|
|
QWidget *slider = m_sliders.first();
|
|
|
|
Volume::ChannelID chid = _slidersChids.first();
|
|
|
|
|
|
|
|
int sliderValue = 0;
|
|
|
|
if ( slider->inherits( "KSmallSlider" ) )
|
|
|
|
{
|
|
|
|
KSmallSlider *slider = dynamic_cast<KSmallSlider *>(m_sliders.first());
|
|
|
|
if (slider) {
|
|
|
|
sliderValue= slider->value();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
QSlider *slider = dynamic_cast<QSlider *>(m_sliders.first());
|
|
|
|
if (slider) {
|
|
|
|
if ( _orientation == Qt::Vertical )
|
|
|
|
sliderValue= slider->maxValue() - slider->value();
|
|
|
|
else
|
|
|
|
sliderValue= slider->value();
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// With balance proper working, we must change relative volumes,
|
|
|
|
// not absolute, which leads a make some difference calc related
|
|
|
|
// to new sliders position against the top volume on channels
|
|
|
|
long volumeDif = sliderValue - vol.getTopStereoVolume( Volume::MMAIN );
|
|
|
|
|
|
|
|
if ( chid == Volume::LEFT ) {
|
|
|
|
vol.setVolume( Volume::LEFT , vol.getVolume( Volume::LEFT ) + volumeDif );
|
|
|
|
vol.setVolume( Volume::RIGHT, vol.getVolume( Volume::RIGHT ) + volumeDif );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
kdDebug(67100) << "MDWSlider::volumeChange(), unknown chid " << chid << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
updateValue( _numbers.first(), Volume::LEFT );
|
|
|
|
} // joined
|
|
|
|
else {
|
|
|
|
int n = 0;
|
|
|
|
QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
|
|
|
|
QLabel *number = _numbers.first();
|
|
|
|
for( QWidget *slider=m_sliders.first(); slider!=0 && number!=0; slider=m_sliders.next(), number=_numbers.next(), ++it )
|
|
|
|
{
|
|
|
|
Volume::ChannelID chid = *it;
|
|
|
|
if ( slider->inherits( "KSmallSlider" ) )
|
|
|
|
{
|
|
|
|
KSmallSlider *smallSlider = dynamic_cast<KSmallSlider *>(slider);
|
|
|
|
if (smallSlider)
|
|
|
|
vol.setVolume( chid, smallSlider->value() );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QSlider *bigSlider = dynamic_cast<QSlider *>(slider);
|
|
|
|
if (bigSlider)
|
|
|
|
if ( _orientation == Qt::Vertical )
|
|
|
|
vol.setVolume( chid, bigSlider->maxValue() - bigSlider->value() );
|
|
|
|
else
|
|
|
|
vol.setVolume( chid, bigSlider->value() );
|
|
|
|
}
|
|
|
|
updateValue( number, chid );
|
|
|
|
n++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// --- Step 3: Write back the new volumes to the HW ---
|
|
|
|
m_mixer->commitVolumeChange(m_mixdevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
This slot is called, when a user has clicked the recsrc button. Also it is called by any other
|
|
|
|
associated KAction like the context menu.
|
|
|
|
*/
|
|
|
|
void MDWSlider::toggleRecsrc() {
|
|
|
|
setRecsrc( !m_mixdevice->isRecSource() );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MDWSlider::setRecsrc(bool value )
|
|
|
|
{
|
|
|
|
if ( m_mixdevice->isRecordable() ) {
|
|
|
|
m_mixer->setRecordSource( m_mixdevice->num(), value );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
This slot is called, when a user has clicked the mute button. Also it is called by any other
|
|
|
|
associated KAction like the context menu.
|
|
|
|
*/
|
|
|
|
void MDWSlider::toggleMuted() {
|
|
|
|
setMuted( !m_mixdevice->isMuted() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void MDWSlider::setMuted(bool value)
|
|
|
|
{
|
|
|
|
if ( m_mixdevice->hasMute() ) {
|
|
|
|
m_mixdevice->setMuted( value );
|
|
|
|
m_mixer->commitVolumeChange(m_mixdevice);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MDWSlider::setDisabled()
|
|
|
|
{
|
|
|
|
setDisabled( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
void MDWSlider::setDisabled( bool value )
|
|
|
|
{
|
|
|
|
if ( m_disabled!=value) {
|
|
|
|
value ? hide() : show();
|
|
|
|
m_disabled = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
This slot is called on a MouseWheel event. Also it is called by any other
|
|
|
|
associated KAction like the context menu.
|
|
|
|
*/
|
|
|
|
void MDWSlider::increaseVolume()
|
|
|
|
{
|
|
|
|
Volume vol = m_mixdevice->getVolume();
|
|
|
|
long inc = vol.maxVolume() / 20;
|
|
|
|
if ( inc == 0 )
|
|
|
|
inc = 1;
|
|
|
|
for ( int i = 0; i < vol.count(); i++ ) {
|
|
|
|
long newVal = (vol[i]) + inc;
|
|
|
|
m_mixdevice->setVolume( i, newVal < vol.maxVolume() ? newVal : vol.maxVolume() );
|
|
|
|
}
|
|
|
|
m_mixer->commitVolumeChange(m_mixdevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
This slot is called on a MouseWheel event. Also it is called by any other
|
|
|
|
associated KAction like the context menu.
|
|
|
|
*/
|
|
|
|
void MDWSlider::decreaseVolume()
|
|
|
|
{
|
|
|
|
Volume vol = m_mixdevice->getVolume();
|
|
|
|
long inc = vol.maxVolume() / 20;
|
|
|
|
if ( inc == 0 )
|
|
|
|
inc = 1;
|
|
|
|
for ( int i = 0; i < vol.count(); i++ ) {
|
|
|
|
long newVal = (vol[i]) - inc;
|
|
|
|
m_mixdevice->setVolume( i, newVal > 0 ? newVal : 0 );
|
|
|
|
}
|
|
|
|
m_mixer->commitVolumeChange(m_mixdevice);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
This is called whenever there are volume updates pending from the hardware for this MDW.
|
|
|
|
At the moment it is called regulary via a QTimer (implicitely).
|
|
|
|
*/
|
|
|
|
void MDWSlider::update()
|
|
|
|
{
|
|
|
|
// update volumes
|
|
|
|
Volume vol = m_mixdevice->getVolume();
|
|
|
|
if( isStereoLinked() )
|
|
|
|
{
|
|
|
|
QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
|
|
|
|
|
|
|
|
long avgVol = vol.getAvgVolume( Volume::MMAIN );
|
|
|
|
|
|
|
|
QWidget *slider = m_sliders.first();
|
|
|
|
if ( slider == 0 ) {
|
|
|
|
return; // !!! Development version, check this !!!
|
|
|
|
}
|
|
|
|
slider->blockSignals( true );
|
|
|
|
if ( slider->inherits( "KSmallSlider" ) )
|
|
|
|
{
|
|
|
|
KSmallSlider *smallSlider = dynamic_cast<KSmallSlider *>(slider);
|
|
|
|
if (smallSlider) {
|
|
|
|
smallSlider->setValue( avgVol ); // !! inverted ?!?
|
|
|
|
smallSlider->setGray( m_mixdevice->isMuted() );
|
|
|
|
}
|
|
|
|
} // small slider
|
|
|
|
else {
|
|
|
|
QSlider *bigSlider = dynamic_cast<QSlider *>(slider);
|
|
|
|
if (bigSlider)
|
|
|
|
{
|
|
|
|
// In case of stereo linked and single slider, slider must
|
|
|
|
// show the top of both volumes, and not strangely low down
|
|
|
|
// the main volume by half
|
|
|
|
|
|
|
|
if ( _orientation == Qt::Vertical )
|
|
|
|
bigSlider->setValue( vol.maxVolume() - vol.getTopStereoVolume( Volume::MMAIN ) );
|
|
|
|
else
|
|
|
|
bigSlider->setValue( vol.getTopStereoVolume( Volume::MMAIN ) );
|
|
|
|
}
|
|
|
|
} // big slider
|
|
|
|
|
|
|
|
updateValue( _numbers.first(), Volume::LEFT );
|
|
|
|
slider->blockSignals( false );
|
|
|
|
} // only 1 slider (stereo-linked)
|
|
|
|
else {
|
|
|
|
QValueList<Volume::ChannelID>::Iterator it = _slidersChids.begin();
|
|
|
|
for( int i=0; i<vol.count(); i++, ++it ) {
|
|
|
|
QWidget *slider = m_sliders.at( i );
|
|
|
|
Volume::ChannelID chid = *it;
|
|
|
|
if (slider == 0) {
|
|
|
|
// !!! not implemented !!!
|
|
|
|
// not implemented: happens if there are record and playback
|
|
|
|
// sliders in the same device. Or if you only show
|
|
|
|
// the right slider (or any other fancy occasion)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
slider->blockSignals( true );
|
|
|
|
|
|
|
|
if ( slider->inherits( "KSmallSlider" ) )
|
|
|
|
{
|
|
|
|
KSmallSlider *smallSlider = dynamic_cast<KSmallSlider *>(slider);
|
|
|
|
if (smallSlider) {
|
|
|
|
smallSlider->setValue( vol[chid] );
|
|
|
|
smallSlider->setGray( m_mixdevice->isMuted() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QSlider *bigSlider = dynamic_cast<QSlider *>(slider);
|
|
|
|
if (bigSlider)
|
|
|
|
if ( _orientation == Qt::Vertical ) {
|
|
|
|
bigSlider->setValue( vol.maxVolume() - vol[i] );
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bigSlider->setValue( vol[i] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateValue( _numbers.at ( i ), chid );
|
|
|
|
|
|
|
|
slider->blockSignals( false );
|
|
|
|
} // for all sliders
|
|
|
|
} // more than 1 slider
|
|
|
|
|
|
|
|
// update mute led
|
|
|
|
if ( m_muteLED ) {
|
|
|
|
m_muteLED->blockSignals( true );
|
|
|
|
m_muteLED->setState( m_mixdevice->isMuted() ? KLed::Off : KLed::On );
|
|
|
|
m_muteLED->blockSignals( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
// update recsrc
|
|
|
|
if( m_recordLED ) {
|
|
|
|
m_recordLED->blockSignals( true );
|
|
|
|
m_recordLED->setState( m_mixdevice->isRecSource() ? KLed::On : KLed::Off );
|
|
|
|
m_recordLED->blockSignals( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MDWSlider::showContextMenu()
|
|
|
|
{
|
|
|
|
if( m_mixerwidget == NULL )
|
|
|
|
return;
|
|
|
|
|
|
|
|
KPopupMenu *menu = m_mixerwidget->getPopup();
|
|
|
|
menu->insertTitle( SmallIcon( "kmix" ), m_mixdevice->name() );
|
|
|
|
|
|
|
|
if ( m_sliders.count()>1 ) {
|
|
|
|
KToggleAction *stereo = (KToggleAction *)_mdwActions->action( "stereo" );
|
|
|
|
if ( stereo ) {
|
|
|
|
stereo->setChecked( !isStereoLinked() );
|
|
|
|
stereo->plug( menu );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KToggleAction *ta = (KToggleAction *)_mdwActions->action( "recsrc" );
|
|
|
|
if ( ta ) {
|
|
|
|
ta->setChecked( m_mixdevice->isRecSource() );
|
|
|
|
ta->plug( menu );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( m_mixdevice->hasMute() ) {
|
|
|
|
ta = ( KToggleAction* )_mdwActions->action( "mute" );
|
|
|
|
if ( ta ) {
|
|
|
|
ta->setChecked( m_mixdevice->isMuted() );
|
|
|
|
ta->plug( menu );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KAction *a = _mdwActions->action( "hide" );
|
|
|
|
if ( a )
|
|
|
|
a->plug( menu );
|
|
|
|
|
|
|
|
a = _mdwActions->action( "keys" );
|
|
|
|
if ( a && m_keys ) {
|
|
|
|
KActionSeparator sep( this );
|
|
|
|
sep.plug( menu );
|
|
|
|
a->plug( menu );
|
|
|
|
}
|
|
|
|
|
|
|
|
QPoint pos = QCursor::pos();
|
|
|
|
menu->popup( pos );
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize MDWSlider::sizeHint() const {
|
|
|
|
if ( _layout != 0 ) {
|
|
|
|
return _layout->sizeHint();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// layout not (yet) created
|
|
|
|
return QWidget::sizeHint();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* An event filter for the various QWidgets. We watch for Mouse press Events, so
|
|
|
|
* that we can popup the context menu.
|
|
|
|
*/
|
|
|
|
bool MDWSlider::eventFilter( QObject* obj, QEvent* e )
|
|
|
|
{
|
|
|
|
if (e->type() == QEvent::MouseButtonPress) {
|
|
|
|
QMouseEvent *qme = static_cast<QMouseEvent*>(e);
|
|
|
|
if (qme->button() == Qt::RightButton) {
|
|
|
|
showContextMenu();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Attention: We don't filter WheelEvents for KSmallSlider, because it handles WheelEvents itself
|
|
|
|
else if ( (e->type() == QEvent::Wheel) && !obj->isA("KSmallSlider") ) {
|
|
|
|
QWheelEvent *qwe = static_cast<QWheelEvent*>(e);
|
|
|
|
if (qwe->delta() > 0) {
|
|
|
|
increaseVolume();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
decreaseVolume();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return QWidget::eventFilter(obj,e);
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "mdwslider.moc"
|