diff --git a/gui/mdwenum.cpp b/gui/mdwenum.cpp index 96dcfadd..620f4cdc 100644 --- a/gui/mdwenum.cpp +++ b/gui/mdwenum.cpp @@ -1,191 +1,191 @@ /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 2004 Christian Esken * * 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. */ // KMix #include "mdwenum.h" #include "viewbase.h" #include "core/mixer.h" // KDE #include #include #include // Qt #include #include #include #include #include #include #include /** * Class that represents an Enum element (a select one-from-many selector) * The orientation (horizontal, vertical) is ignored */ -MDWEnum::MDWEnum(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view) - : MixDeviceWidget(md, flags, view), +MDWEnum::MDWEnum(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view, ProfControl *pctl) + : MixDeviceWidget(md, flags, view, pctl), _label(nullptr), _enumCombo(nullptr) { // create actions (on _mdwActions, see MixDeviceWidget) // KStandardAction::showMenubar() is in MixDeviceWidget now KToggleAction *action = _mdwActions->add( "hide" ); action->setText( i18n("&Hide") ); connect(action, SIGNAL(triggered(bool)), SLOT(setDisabled(bool))); QAction *c = _mdwActions->addAction( "keys" ); c->setText( i18n("C&onfigure Shortcuts...") ); connect(c, SIGNAL(triggered(bool)), SLOT(defineKeys())); // create widgets createWidgets(); } void MDWEnum::createWidgets() { QBoxLayout *_layout; if (orientation()==Qt::Vertical) { _layout = new QVBoxLayout(this); _layout->setAlignment(Qt::AlignLeft|Qt::AlignTop); } else { _layout = new QHBoxLayout(this); _layout->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); } _label = new QLabel( m_mixdevice->readableName(), this); _layout->addWidget(_label); if (orientation()==Qt::Horizontal) _layout->addSpacing(8); _enumCombo = new QComboBox(this); _enumCombo->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); // ------------ fill ComboBox start ------------ int maxEnumId= m_mixdevice->enumValues().count(); for (int i=0; iaddItem( m_mixdevice->enumValues().at(i)); } // ------------ fill ComboBox end -------------- _layout->addWidget(_enumCombo); connect( _enumCombo, SIGNAL(activated(int)), this, SLOT(setEnumId(int)) ); _enumCombo->setToolTip( m_mixdevice->readableName() ); _layout->addStretch(1); } void MDWEnum::update() { if ( m_mixdevice->isEnum() ) { //qCDebug(KMIX_LOG) << "MDWEnum::update() enumID=" << m_mixdevice->enumId(); _enumCombo->setCurrentIndex( m_mixdevice->enumId() ); } else { qCCritical(KMIX_LOG) << "MDWEnum::update() enumID=" << m_mixdevice->enumId() << " is no Enum ... skipped"; } } void MDWEnum::showContextMenu(const QPoint& pos ) { if( m_view == 0 ) return; QMenu *menu = m_view->getPopup(); menu->popup( pos ); } QSizePolicy MDWEnum::sizePolicy() const { return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed ); } /** 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 MDWEnum::nextEnumId() { if( m_mixdevice->isEnum() ) { int curEnum = enumId(); if ( curEnum < m_mixdevice->enumValues().count() ) { // next enum value setEnumId(curEnum+1); } else { // wrap around setEnumId(0); } } // isEnum } void MDWEnum::setEnumId(int value) { if ( m_mixdevice->isEnum() ) { m_mixdevice->setEnumId( value ); m_mixdevice->mixer()->commitVolumeChange( m_mixdevice ); } } int MDWEnum::enumId() { if ( m_mixdevice->isEnum() ) { return m_mixdevice->enumId(); } else { return 0; } } void MDWEnum::setDisabled( bool hide ) { emit guiVisibilityChange(this, !hide); } /** * For users of this class who would like to show multiple MDWEnum's properly aligned. * It returns the size of the control label (in the control layout direction). */ int MDWEnum::labelExtentHint() const { if (_label==nullptr) return (0); if (orientation()==Qt::Vertical) return (_label->sizeHint().height()); else return (_label->sizeHint().width()); } /** * If a label from another switch is larger than ours, then the * extent of our label is adjusted. */ void MDWEnum::setLabelExtent(int extent) { if (_label==nullptr) return; if (orientation()==Qt::Vertical) _label->setMinimumHeight(extent); else _label->setMinimumWidth(extent); } diff --git a/gui/mdwenum.h b/gui/mdwenum.h index df8e1dc9..6ac70664 100644 --- a/gui/mdwenum.h +++ b/gui/mdwenum.h @@ -1,68 +1,68 @@ //-*-C++-*- /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 2004 Chrisitan Esken * * 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. */ #ifndef MDWENUM_H #define MDWENUM_H // KMix class MixDevice; class ViewBase; // Qt class QComboBox; class QLabel; #include "gui/mixdevicewidget.h" class MDWEnum : public MixDeviceWidget { Q_OBJECT public: - MDWEnum(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view); + MDWEnum(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view, ProfControl *pctl = nullptr); virtual ~MDWEnum() = default; void addActionToPopup( QAction *action ); QSizePolicy sizePolicy() const; int labelExtentHint() const Q_DECL_OVERRIDE; void setLabelExtent(int extent) Q_DECL_OVERRIDE; public slots: // GUI hide and show void setDisabled(bool) Q_DECL_OVERRIDE; // Enum handling: next and selecting void nextEnumId(); int enumId(); void setEnumId(int value); void update() Q_DECL_OVERRIDE; void showContextMenu(const QPoint& pos = QCursor::pos()) Q_DECL_OVERRIDE; private: void createWidgets(); QLabel *_label; QComboBox *_enumCombo; }; #endif diff --git a/gui/mdwslider.cpp b/gui/mdwslider.cpp index 4b0e485f..7dc8b1f4 100644 --- a/gui/mdwslider.cpp +++ b/gui/mdwslider.cpp @@ -1,1241 +1,1241 @@ /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 1996-2007 Christian Esken * * 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 "gui/mdwslider.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "core/ControlManager.h" #include "core/mixer.h" #include "gui/guiprofile.h" #include "gui/volumeslider.h" #include "gui/viewbase.h" #include "gui/ksmallslider.h" #include "gui/verticaltext.h" #include "gui/mdwmoveaction.h" #include "gui/toggletoolbutton.h" bool MDWSlider::debugMe = false; /** * MixDeviceWidget that represents a single mix device, including PopUp, muteLED, ... * * Used in KMix main window and DockWidget and PanelApplet. * It can be configured to include or exclude the captureLED and the muteLED. * The direction (horizontal, vertical) can be configured and whether it should * be "small" (uses KSmallSlider instead of a normal slider widget). * * Due to the many options, this is the most complicated MixDeviceWidget subclass. */ -MDWSlider::MDWSlider(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view) - : MixDeviceWidget(md, flags, view), +MDWSlider::MDWSlider(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view, ProfControl *pctl) + : MixDeviceWidget(md, flags, view, pctl), m_linked(true), m_controlGrid(nullptr), m_controlIcon(nullptr), m_controlLabel(nullptr), m_muteButton(nullptr), m_captureButton(nullptr), m_mediaPlayButton(nullptr), m_controlButtonSize(QSize()), _mdwMoveActions(new KActionCollection(this)), m_moveMenu(nullptr), m_sliderInWork(false), m_waitForSoundSetComplete(0) { //qCDebug(KMIX_LOG) << "for" << m_mixdevice->readableName() << "flags" << MixDeviceWidget::flags(); createActions(); createWidgets(); createShortcutActions(); // Yes, this looks odd - monitor all events sent to myself by myself? // But it's so that wheel events over the MDWSlider background can be // handled by eventFilter() in the same way as wheel events over child // widgets. Each child widget apart from the sliders themselves also // also needs to have the event filter installed on it, because QWidget // by default ignores the wheel event and does not propagate it. installEventFilter(this); update(); } MDWSlider::~MDWSlider() { qDeleteAll(m_slidersPlayback); qDeleteAll(m_slidersCapture); } void MDWSlider::createActions() { // create actions (on _mdwActions, see MixDeviceWidget) KToggleAction *taction = _mdwActions->add( "stereo" ); taction->setText( i18n("&Split Channels") ); connect( taction, SIGNAL(triggered(bool)), SLOT(toggleStereoLinked()) ); // QAction *action; // if ( ! m_mixdevice->mixer()->isDynamic() ) { // action = _mdwActions->add( "hide" ); // action->setText( i18n("&Hide") ); // connect( action, SIGNAL(triggered(bool)), SLOT(setDisabled(bool)) ); // } if( m_mixdevice->hasMuteSwitch() ) { taction = _mdwActions->add( "mute" ); taction->setText( i18n("&Muted") ); connect( taction, SIGNAL(toggled(bool)), SLOT(toggleMuted()) ); } if( m_mixdevice->captureVolume().hasSwitch() ) { taction = _mdwActions->add( "recsrc" ); taction->setText( i18n("Captu&re") ); connect( taction, SIGNAL(toggled(bool)), SLOT(toggleRecsrc()) ); } if( m_mixdevice->isMovable() ) { m_moveMenu = new QMenu( i18n("Mo&ve"), this); connect( m_moveMenu, SIGNAL(aboutToShow()), SLOT(showMoveMenu()) ); } QAction* qaction = _mdwActions->addAction( "keys" ); qaction->setText( i18n("Channel Shortcuts...") ); connect( qaction, SIGNAL(triggered(bool)), SLOT(defineKeys()) ); } void MDWSlider::addGlobalShortcut(QAction* qaction, const QString& label, bool dynamicControl) { QString finalLabel(label); finalLabel += " - " + mixDevice()->readableName() + ", " + mixDevice()->mixer()->readableName(); qaction->setText(label); if (!dynamicControl) { // virtual / dynamic controls won't get shortcuts // #ifdef __GNUC__ // #warning GLOBAL SHORTCUTS ARE NOW ASSIGNED TO ALL CONTROLS, as enableGlobalShortcut(), has not been committed // #endif // b->enableGlobalShortcut(); // enableGlobalShortcut() is not there => use workaround KGlobalAccel::setGlobalShortcut(qaction, QKeySequence()); } } void MDWSlider::createShortcutActions() { bool dynamicControl = mixDevice()->mixer()->isDynamic(); // The following actions are for the "Configure Shortcuts" dialog /* PLEASE NOTE THAT global shortcuts are saved with the name as set with setName(), instead of their action name. This is a bug according to the thread "Global shortcuts are saved with their text-name and not their action-name - Bug?" on kcd. I work around this by using a text with setText() that is unique, but still readable to the user. */ QString actionSuffix = QString(" - %1, %2").arg( mixDevice()->readableName(), mixDevice()->mixer()->readableName() ); QAction *bi, *bd, *bm; // -1- INCREASE VOLUME SHORTCUT ----------------------------------------- bi = _mdwPopupActions->addAction( QString("Increase volume %1").arg( actionSuffix ) ); QString increaseVolumeName = i18n( "Increase Volume" ); addGlobalShortcut(bi, increaseVolumeName, dynamicControl); if ( ! dynamicControl ) connect( bi, SIGNAL(triggered(bool)), SLOT(increaseVolume()) ); // -2- DECREASE VOLUME SHORTCUT ----------------------------------------- bd = _mdwPopupActions->addAction( QString("Decrease volume %1").arg( actionSuffix ) ); QString decreaseVolumeName = i18n( "Decrease Volume" ); addGlobalShortcut(bd, decreaseVolumeName, dynamicControl); if ( ! dynamicControl ) connect(bd, SIGNAL(triggered(bool)), SLOT(decreaseVolume())); // -3- MUTE VOLUME SHORTCUT ----------------------------------------- bm = _mdwPopupActions->addAction( QString("Toggle mute %1").arg( actionSuffix ) ); QString muteVolumeName = i18n( "Toggle Mute" ); addGlobalShortcut(bm, muteVolumeName, dynamicControl); if ( ! dynamicControl ) connect( bm, SIGNAL(triggered(bool)), SLOT(toggleMuted()) ); } QSizePolicy MDWSlider::sizePolicy() const { if (orientation()==Qt::Vertical) { return QSizePolicy( QSizePolicy::Preferred, QSizePolicy::MinimumExpanding ); } else { return QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Preferred ); } } QSize MDWSlider::sizeHint() const { return QSize( 90, QWidget::sizeHint().height()); } /** * This method is a helper for users of this class who would like * to show multiple MDWSlider, and align the sliders. * It returns the "height" (if vertical) of this slider's label. * Warning: Line wraps are computed for a fixed size (100), this may be inaccurate in case, * the widgets have different sizes. */ int MDWSlider::labelExtentHint() const { if (m_controlLabel==nullptr) return (0); if (orientation()==Qt::Vertical) return (m_controlLabel->heightForWidth(m_controlLabel->minimumWidth())); else return (m_controlLabel->sizeHint().width()); } /** * If a label from another widget has more lines than this widget, then a spacer is added under the label */ void MDWSlider::setLabelExtent(int extent) { if (m_controlGrid==nullptr) return; if (orientation()==Qt::Vertical) m_controlGrid->setRowMinimumHeight(1, extent); else m_controlGrid->setColumnMinimumWidth(1, extent); } /** * Alignment helper */ bool MDWSlider::hasMuteButton() const { return (m_muteButton!=nullptr); } /** * See "hasMuteButton" */ bool MDWSlider::hasCaptureLED() const { return (m_captureButton!=nullptr); } void MDWSlider::guiAddCaptureButton(const QString &captureTooltipText) { m_captureButton = new ToggleToolButton("media-record", this); m_captureButton->setSmallSize(flags() & MixDeviceWidget::SmallSize); m_captureButton->installEventFilter(this); connect(m_captureButton, SIGNAL(clicked(bool)), this, SLOT(toggleRecsrc())); m_captureButton->setToolTip(captureTooltipText); } void MDWSlider::guiAddMuteButton(const QString &muteTooltipText) { m_muteButton = new ToggleToolButton("audio-volume-high", this); m_muteButton->setInactiveIcon("audio-volume-muted"); m_muteButton->setSmallSize(flags() & MixDeviceWidget::SmallSize); m_muteButton->installEventFilter(this); connect(m_muteButton, SIGNAL(clicked(bool)), this, SLOT(toggleMuted())); m_muteButton->setToolTip(muteTooltipText); } void MDWSlider::guiAddControlLabel(Qt::Alignment alignment, const QString &channelName) { m_controlLabel = new QLabel(channelName, this); m_controlLabel->setWordWrap(true); m_controlLabel->setAlignment(alignment); m_controlLabel->installEventFilter(this); } void MDWSlider::guiAddControlIcon(const QString &tooltipText) { m_controlIcon = new QLabel(this); ToggleToolButton::setIndicatorIcon(m_mixdevice->iconName(), m_controlIcon, (flags() & MixDeviceWidget::SmallSize)); m_controlIcon->setToolTip(tooltipText); m_controlIcon->installEventFilter(this); } QWidget *MDWSlider::guiAddButtonSpacer() { if (hasMuteButton() || hasCaptureLED()) return (nullptr); // spacer not needed QWidget *buttonSpacer = new QWidget(this); if (orientation()==Qt::Vertical) // vertical sliders { buttonSpacer->setMinimumHeight(controlButtonSize().height()); buttonSpacer->setMaximumWidth(1); } else // horizontal sliders { buttonSpacer->setMinimumWidth(controlButtonSize().width()); buttonSpacer->setMaximumHeight(1); } buttonSpacer->installEventFilter(this); return (buttonSpacer); } QSize MDWSlider::controlButtonSize() { if (!m_controlButtonSize.isValid()) // not calculated yet { auto *buttonSpacer = new QToolButton(); ToggleToolButton::setIndicatorIcon("unknown", buttonSpacer, (flags() & MixDeviceWidget::SmallSize)); m_controlButtonSize = buttonSpacer->sizeHint(); qCDebug(KMIX_LOG) << m_controlButtonSize; delete buttonSpacer; } return (m_controlButtonSize); } /** * Creates all widgets : Icon, Label, Mute-Button, Slider(s) and Capture-Button. */ void MDWSlider::createWidgets() { const bool includePlayback = profileControl()->useSubcontrolPlayback(); const bool includeCapture = profileControl()->useSubcontrolCapture(); const bool wantsPlaybackSliders = includePlayback && (mixDevice()->playbackVolume().count()>0); const bool wantsCaptureSliders = includeCapture && (mixDevice()->captureVolume().count()>0); const bool wantsCaptureLED = includeCapture && (flags() & MixDeviceWidget::ShowCapture); const bool wantsMuteButton = includePlayback && (flags() & MixDeviceWidget::ShowMute); const MediaController *mediaController = mixDevice()->getMediaController(); const bool wantsMediaControls = mediaController->hasControls(); const QString channelName = mixDevice()->readableName(); QString tooltipText = channelName; QString captureTooltipText = i18nc("%1=channel", "Capture/Uncapture %1", channelName); QString muteTooltipText = i18nc("%1=channel", "Mute/Unmute %1", channelName); if (flags() & MixDeviceWidget::ShowMixerName) { const QString mixerName = mixDevice()->mixer()->readableName(); tooltipText = i18nc("%1=device %2=channel", "%1\n%2", mixerName, tooltipText); captureTooltipText = i18nc("%1=device %2=channel", "%1\n%2", mixerName, captureTooltipText); muteTooltipText = i18nc("%1=device %2=channel", "%1\n%2", mixerName, muteTooltipText); } m_controlGrid = new QGridLayout(this); setLayout(m_controlGrid); QBoxLayout *volLayout; if (orientation()==Qt::Vertical) // vertical sliders { m_controlGrid->setContentsMargins(2, 0, 2, 0); const Qt::Alignment sliderAlign = Qt::AlignHCenter|Qt::AlignBottom; // Row 0: Control type icon guiAddControlIcon(tooltipText); m_controlGrid->addWidget(m_controlIcon, 0, 0, 1, -1, Qt::AlignHCenter|Qt::AlignTop); // Row 1: Device name label guiAddControlLabel(Qt::AlignHCenter, channelName); m_controlGrid->addWidget(m_controlLabel, 1, 0, 1, -1, Qt::AlignHCenter|Qt::AlignTop); // Row 2: Sliders int col = 0; // current column being filled int playbackCol = 0; // where these sliders ended up int captureCol = 1; // or default button column if none if (wantsPlaybackSliders) { volLayout = new QHBoxLayout(); volLayout->setAlignment(sliderAlign); addSliders(volLayout, 'p', m_mixdevice->playbackVolume(), m_slidersPlayback, tooltipText); m_controlGrid->addLayout(volLayout, 2, col); playbackCol = col; ++col; } if (wantsCaptureSliders) { volLayout = new QHBoxLayout(); volLayout->setAlignment(sliderAlign); addSliders(volLayout, 'c', m_mixdevice->captureVolume(), m_slidersCapture, tooltipText); m_controlGrid->addLayout(volLayout, 2, col); captureCol = col; ++col; } if (wantsMediaControls) { volLayout = new QHBoxLayout(); volLayout->setAlignment(sliderAlign); addMediaControls(volLayout); m_controlGrid->addLayout(volLayout, 2, col); } m_controlGrid->setRowStretch(2, 1); // sliders need the most space // Row 3: Control buttons if (wantsMuteButton && m_mixdevice->hasMuteSwitch()) { guiAddMuteButton(muteTooltipText); m_controlGrid->addWidget(m_muteButton, 3, playbackCol, Qt::AlignHCenter|Qt::AlignTop); } if (wantsCaptureLED && m_mixdevice->captureVolume().hasSwitch()) { guiAddCaptureButton(captureTooltipText); m_controlGrid->addWidget(m_captureButton, 3, captureCol, Qt::AlignHCenter|Qt::AlignTop); } // If nether a mute nor a capture button is present, then put a // dummy spacer button (in column 0, where the mute button would // normally go). This is to maintain the size of the slider // relative to others that do have one or both buttons. // // We have to do this, rather than setting a minimum height for row 3, // as in the case where it is needed row 3 will be empty and QGridLayout // ignores the minimum height set on it. QWidget *buttonSpacer = guiAddButtonSpacer(); if (buttonSpacer!=nullptr) m_controlGrid->addWidget(buttonSpacer, 3, 0); } else // horizontal sliders { const Qt::Alignment sliderAlign = Qt::AlignHCenter|Qt::AlignVCenter; // Column 0: Control type icon guiAddControlIcon(tooltipText); m_controlGrid->addWidget(m_controlIcon, 0, 0, -1, 1, Qt::AlignLeft|Qt::AlignVCenter); // Column 1: Device name label guiAddControlLabel(Qt::AlignLeft, channelName); m_controlGrid->addWidget(m_controlLabel, 0, 1, -1, 1, Qt::AlignLeft|Qt::AlignVCenter); // Column 2: Sliders int row = 0; // current row being filled int playbackRow = 0; // where these sliders ended up int captureRow = 1; // or default button row if none if (wantsPlaybackSliders) { volLayout = new QVBoxLayout(); volLayout->setAlignment(sliderAlign); addSliders(volLayout, 'p', m_mixdevice->playbackVolume(), m_slidersPlayback, tooltipText); m_controlGrid->addLayout(volLayout, row, 2); playbackRow = row; ++row; } if (wantsCaptureSliders) { volLayout = new QVBoxLayout(); volLayout->setAlignment(sliderAlign); addSliders(volLayout, 'c', m_mixdevice->captureVolume(), m_slidersCapture, tooltipText); m_controlGrid->addLayout(volLayout, row, 2); captureRow = row; ++row; } if (wantsMediaControls) { volLayout = new QVBoxLayout(); volLayout->setAlignment(sliderAlign); addMediaControls(volLayout); m_controlGrid->addLayout(volLayout, row, 2); } m_controlGrid->setColumnStretch(2, 1); // sliders need the most space // Column 3: Control buttons if (wantsMuteButton && m_mixdevice->hasMuteSwitch()) { guiAddMuteButton(muteTooltipText); m_controlGrid->addWidget(m_muteButton, playbackRow, 3, Qt::AlignRight|Qt::AlignVCenter); } if (wantsCaptureLED && m_mixdevice->captureVolume().hasSwitch()) { guiAddCaptureButton(captureTooltipText); m_controlGrid->addWidget(m_captureButton, captureRow, 3, Qt::AlignRight|Qt::AlignVCenter); } // Dummy spacer button QWidget *buttonSpacer = guiAddButtonSpacer(); if (buttonSpacer!=nullptr) m_controlGrid->addWidget(buttonSpacer, 0, 3); } const bool stereoLinked = !profileControl()->isSplit(); setStereoLinked( stereoLinked ); // Activate it explicitly in KDE3 because of PanelApplet/Kicker issues. // Not sure whether this is necessary 2 generations later. layout()->activate(); } QString MDWSlider::calculatePlaybackIcon(MediaController::PlayState playState) { QString mediaIconName; switch (playState) { case MediaController::PlayPlaying: // playing => show pause icon mediaIconName = "media-playback-pause"; break; case MediaController::PlayPaused: // stopped/paused => show play icon mediaIconName = "media-playback-start"; break; case MediaController::PlayStopped: // stopped/paused => show play icon mediaIconName = "media-playback-start"; break; default: // unknown => not good, probably result from player has not yet arrived => show a play button mediaIconName = "media-playback-start"; break; } return mediaIconName; } void MDWSlider::addMediaControls(QBoxLayout* volLayout) { MediaController* mediaController = mixDevice()->getMediaController(); QBoxLayout *mediaLayout; if (orientation()==Qt::Vertical) mediaLayout = new QVBoxLayout(); else mediaLayout = new QHBoxLayout(); // QFrame* frame1 = new QFrame(this); // frame1->setFrameShape(QFrame::StyledPanel); QWidget* frame = this; // or frame1 mediaLayout->addStretch(); if (mediaController->hasMediaPrevControl()) { QToolButton *lbl = addMediaButton("media-skip-backward", mediaLayout, frame); connect(lbl, SIGNAL(clicked(bool)), this, SLOT(mediaPrev(bool))); } if (mediaController->hasMediaPlayControl()) { MediaController::PlayState playState = mediaController->getPlayState(); QString mediaIcon = calculatePlaybackIcon(playState); m_mediaPlayButton = addMediaButton(mediaIcon, mediaLayout, frame); connect(m_mediaPlayButton, SIGNAL(clicked(bool)), this, SLOT(mediaPlay(bool))); } if (mediaController->hasMediaNextControl()) { QToolButton *lbl = addMediaButton("media-skip-forward", mediaLayout, frame); connect(lbl, SIGNAL(clicked(bool)), this, SLOT(mediaNext(bool))); } mediaLayout->addStretch(); volLayout->addLayout(mediaLayout); } QToolButton* MDWSlider::addMediaButton(QString iconName, QLayout* layout, QWidget *parent) { QToolButton *lbl = new QToolButton(parent); lbl->setIconSize(QSize(IconSize(KIconLoader::Toolbar), IconSize(KIconLoader::Toolbar))); lbl->setAutoRaise(true); lbl->setCheckable(false); ToggleToolButton::setIndicatorIcon(iconName, lbl); layout->addWidget(lbl); return lbl; } /** * Updates the icon according to the data model. */ void MDWSlider::updateMediaButton() { if (m_mediaPlayButton == 0) return; // has no media button MediaController* mediaController = mixDevice()->getMediaController(); QString mediaIconName = calculatePlaybackIcon(mediaController->getPlayState()); ToggleToolButton::setIndicatorIcon(mediaIconName, m_mediaPlayButton); } void MDWSlider::mediaPrev(bool) { mixDevice()->mediaPrev(); } void MDWSlider::mediaNext(bool) { mixDevice()->mediaNext(); } void MDWSlider::mediaPlay(bool) { mixDevice()->mediaPlay(); } static QWidget *createLabel(QWidget *parent, const QString &label, Qt::Orientation orient, bool small) { QFont qf; qf.setPointSize(8); QWidget *labelWidget; if (orient == Qt::Horizontal) { auto *ql = new QLabel(label, parent); if (small) ql->setFont(qf); labelWidget = ql; } else { auto *vt = new VerticalText(parent, label); if (small) vt->setFont(qf); labelWidget = vt; } return (labelWidget); } void MDWSlider::addSliders( QBoxLayout *volLayout, char type, Volume& vol, QList& ref_sliders, QString tooltipText) { const int minSliderSize = fontMetrics().height() * 10; long minvol = vol.minVolume(); long maxvol = vol.maxVolume(); QMap vols = vol.getVolumes(); foreach (VolumeChannel vc, vols ) { //qCDebug(KMIX_LOG) << "Add label to " << vc.chid << ": " << Volume::channelNameReadable(vc.chid); QWidget *subcontrolLabel; QString subcontrolTranslation; if ( type == 'c' ) subcontrolTranslation += i18n("Capture") + ' '; subcontrolTranslation += Volume::channelNameReadable(vc.chid); subcontrolLabel = createLabel(this, subcontrolTranslation, orientation(), true); volLayout->addWidget(subcontrolLabel); QAbstractSlider* slider; if (flags() & MixDeviceWidget::SmallSize) { slider = new KSmallSlider( minvol, maxvol, (maxvol-minvol+1) / Volume::VOLUME_PAGESTEP_DIVISOR, vol.getVolume( vc.chid ), orientation(), this ); } // small else { slider = new VolumeSlider(orientation(), this); slider->setMinimum(minvol); slider->setMaximum(maxvol); slider->setPageStep(maxvol / Volume::VOLUME_PAGESTEP_DIVISOR); slider->setValue( vol.getVolume( vc.chid ) ); volumeValues.push_back( vol.getVolume( vc.chid ) ); extraData(slider).setSubcontrolLabel(subcontrolLabel); if (orientation()==Qt::Vertical) slider->setMinimumHeight(minSliderSize); else slider->setMinimumWidth(minSliderSize); if ( !profileControl()->getBackgroundColor().isEmpty() ) { slider->setStyleSheet("QSlider { background-color: " + profileControl()->getBackgroundColor() + " }"); } } // not small extraData(slider).setChid(vc.chid); // slider->installEventFilter( this ); if ( type == 'p' ) { slider->setToolTip( tooltipText ); } else { QString captureTip( i18n( "%1 (capture)", tooltipText ) ); slider->setToolTip( captureTip ); } volLayout->addWidget( slider ); // add to layout ref_sliders.append ( slider ); // add to list //ref_slidersChids.append(vc.chid); connect( slider, SIGNAL(valueChanged(int)), SLOT(volumeChange(int)) ); connect( slider, SIGNAL(sliderPressed()), SLOT(sliderPressed()) ); connect( slider, SIGNAL(sliderReleased()), SLOT(sliderReleased()) ); } // for all channels of this device } /** * Return the VolumeSliderExtraData from either VolumeSlider or KSmallSlider. * You MUST extend this method, should you decide to add more Slider Widget classes. * * @param slider * @return */ VolumeSliderExtraData& MDWSlider::extraData(QAbstractSlider *slider) { VolumeSlider* sl = qobject_cast(slider); if ( sl ) return sl->extraData; KSmallSlider* sl2 = qobject_cast(slider); return sl2->extraData; } void MDWSlider::sliderPressed() { m_sliderInWork = true; } void MDWSlider::sliderReleased() { m_sliderInWork = false; } QString MDWSlider::iconName() { return m_mixdevice->iconName(); } void MDWSlider::toggleStereoLinked() { setStereoLinked( !isStereoLinked() ); } void MDWSlider::setStereoLinked(bool value) { m_linked = value; int overallSlidersToShow = 0; if ( ! m_slidersPlayback.isEmpty() ) overallSlidersToShow += ( m_linked ? 1 : m_slidersPlayback.count() ); if ( ! m_slidersCapture.isEmpty() ) overallSlidersToShow += ( m_linked ? 1 : m_slidersCapture.count() ); bool showSubcontrolLabels = (overallSlidersToShow >= 2); setStereoLinkedInternal(m_slidersPlayback, showSubcontrolLabels); setStereoLinkedInternal(m_slidersCapture , showSubcontrolLabels); update(); // Call update(), so that the sliders can adjust EITHER to the individual values OR the average value. } void MDWSlider::setStereoLinkedInternal(QList& ref_sliders, bool showSubcontrolLabels) { if ( ref_sliders.isEmpty()) return; bool first = true; foreach ( QAbstractSlider* slider1, ref_sliders ) { slider1->setVisible(!m_linked || first); // One slider (the 1st) is always shown extraData(slider1).getSubcontrolLabel()->setVisible(!m_linked && showSubcontrolLabels); // (*) first = false; /* (*) cesken: I have excluded the "|| first" check because the text would not be nice: * It would be "Left" or "Capture Left", while it should be "Playback" and "Capture" in the "linked" case. * * But the only affected situation is when we have playback AND capture on the same control, where we show no label. * It would be nice to put at least a "Capture" label on the capture subcontrol instead. * To achieve this we would need to exchange the Text on the first capture subcontrol dynamically. This can * be done, but I'll leave this open for now. */ } // Redo the tickmarks to last slider in the slider list. // The implementation is not obvious, so lets explain: // We ALWAYS have tickmarks on the LAST slider. Sometimes the slider is not shown, and then we just don't bother. // a) So, if the last slider has tickmarks, we can always call setTicks( true ). // b) if the last slider has NO tickmarks, there ae no tickmarks at all, and we don't need to redo the tickmarks. QSlider* slider = qobject_cast( ref_sliders.last() ); if( slider && slider->tickPosition() != QSlider::NoTicks) setTicks( true ); } void MDWSlider::setLabeled(bool value) { if ( m_controlLabel != 0) m_controlLabel->setVisible(value); layout()->activate(); } void MDWSlider::setTicks( bool value ) { if (m_slidersPlayback.count() != 0) setTicksInternal(m_slidersPlayback, value); if (m_slidersCapture.count() != 0) setTicksInternal(m_slidersCapture, value); } /** * Enables or disables tickmarks * Please note that always only the first and last slider have tickmarks. */ void MDWSlider::setTicksInternal(QList& ref_sliders, bool ticks) { VolumeSlider* slider = qobject_cast( ref_sliders[0]); if (slider == 0 ) return; // Ticks are only in VolumeSlider, but not in KSmallslider if( ticks ) { if( isStereoLinked() ) slider->setTickPosition( QSlider::TicksRight ); else { slider->setTickPosition( QSlider::NoTicks ); slider = qobject_cast(ref_sliders.last()); slider->setTickPosition( QSlider::TicksLeft ); } } else { slider->setTickPosition( QSlider::NoTicks ); slider = qobject_cast(ref_sliders.last()); slider->setTickPosition( QSlider::NoTicks ); } } void MDWSlider::setIcons(bool value) { if ( m_controlIcon != 0 ) { if ( ( !m_controlIcon->isHidden() ) !=value ) { if (value) m_controlIcon->show(); else m_controlIcon->hide(); layout()->activate(); } } // if it has an icon } void MDWSlider::setColors( QColor high, QColor low, QColor back ) { for( int i=0; i(slider); if ( smallSlider ) smallSlider->setColors( high, low, back ); } for( int i=0; i(slider); if ( smallSlider ) smallSlider->setColors( high, low, back ); } } void MDWSlider::setMutedColors( QColor high, QColor low, QColor back ) { for( int i=0; i(slider); if ( smallSlider ) smallSlider->setGrayColors( high, low, back ); } for( int i=0; i(slider); if ( smallSlider ) smallSlider->setGrayColors( high, low, back ); } } /** This slot is called, when a user has changed the volume via the KMix Slider. */ void MDWSlider::volumeChange( int ) { // if ( mixDevice()->id() == "Headphone:0" ) // { // qCDebug(KMIX_LOG) << "headphone bug"; // } if (!m_slidersPlayback.isEmpty()) { ++m_waitForSoundSetComplete; volumeValues.push_back(m_slidersPlayback.first()->value()); volumeChangeInternal(m_mixdevice->playbackVolume(), m_slidersPlayback); } if (!m_slidersCapture.isEmpty()) { volumeChangeInternal(m_mixdevice->captureVolume(), m_slidersCapture); } QSignalBlocker blocker(m_view); m_mixdevice->mixer()->commitVolumeChange(m_mixdevice); } void MDWSlider::volumeChangeInternal(Volume& vol, QList& ref_sliders) { if (isStereoLinked()) { QAbstractSlider* firstSlider = ref_sliders.first(); m_mixdevice->setMuted(false); vol.setAllVolumes(firstSlider->value()); } else { for (int i = 0; i < ref_sliders.count(); i++) { if (m_mixdevice->isMuted()) { // changing from muted state: unmute (the "if" above is actually superfluous) m_mixdevice->setMuted(false); } QAbstractSlider *sliderWidget = ref_sliders[i]; vol.setVolume(extraData(sliderWidget).getChid(), sliderWidget->value()); } // iterate over all sliders } } /** This slot is called, when a user has clicked the recsrc button. Also it is called by any other associated QAction like the context menu. */ void MDWSlider::toggleRecsrc() { setRecsrc( !m_mixdevice->isRecSource() ); } void MDWSlider::setRecsrc(bool value) { if ( m_mixdevice->captureVolume().hasSwitch() ) { m_mixdevice->setRecSource( value ); m_mixdevice->mixer()->commitVolumeChange( m_mixdevice ); } } /** This slot is called, when a user has clicked the mute button. Also it is called by any other associated QAction like the context menu. */ void MDWSlider::toggleMuted() { setMuted( !m_mixdevice->isMuted() ); } void MDWSlider::setMuted(bool value) { if ( m_mixdevice->hasMuteSwitch() ) { m_mixdevice->setMuted( value ); m_mixdevice->mixer()->commitVolumeChange(m_mixdevice); } } void MDWSlider::setDisabled( bool hide ) { emit guiVisibilityChange(this, !hide); } /** * This slot is called on a Keyboard Shortcut event, except for the XF86Audio* shortcuts which are handled by the * KMixWindow class. So for 99.9% of all users, this method is never called. */ void MDWSlider::increaseVolume() { increaseOrDecreaseVolume(false, Volume::Both); } /** * This slot is called on a Keyboard Shortcut event, except for the XF86Audio* shortcuts which hare handled by the * KMixWindow class. So for 99.9% of all users, this method is never called. */ void MDWSlider::decreaseVolume() { increaseOrDecreaseVolume(true, Volume::Both); } /** * Increase or decrease all playback and capture channels of the given control. * This method is very similar to Mixer::increaseOrDecreaseVolume(), but it will * auto-unmute on increase. * * @param mixdeviceID The control name * @param decrease true for decrease. false for increase */ void MDWSlider::increaseOrDecreaseVolume(bool decrease, Volume::VolumeTypeFlag volumeType) { m_mixdevice->increaseOrDecreaseVolume(decrease, volumeType); // I should possibly not block, as the changes that come back from the Soundcard // will be ignored (e.g. because of capture groups) // qCDebug(KMIX_LOG) << "MDWSlider is blocking signals for " << m_view->id(); // bool oldViewBlockSignalState = m_view->blockSignals(true); m_mixdevice->mixer()->commitVolumeChange(m_mixdevice); // qCDebug(KMIX_LOG) << "MDWSlider is unblocking signals for " << m_view->id(); // m_view->blockSignals(oldViewBlockSignalState); } void MDWSlider::moveStreamAutomatic() { m_mixdevice->mixer()->moveStream(m_mixdevice->id(), ""); } void MDWSlider::moveStream(QString destId) { m_mixdevice->mixer()->moveStream(m_mixdevice->id(), destId); } /** * This is called whenever there are volume updates pending from the hardware for this MDW. */ void MDWSlider::update() { // bool debugMe = (mixDevice()->id() == "PCM:0" ); // if (debugMe) qCDebug(KMIX_LOG) << "The update() PCM:0 playback state" << mixDevice()->isMuted() // << ", vol=" << mixDevice()->playbackVolume().getAvgVolumePercent(Volume::MALL); if ( m_slidersPlayback.count() != 0 || m_mixdevice->hasMuteSwitch() ) updateInternal(m_mixdevice->playbackVolume(), m_slidersPlayback, m_mixdevice->isMuted() ); if ( m_slidersCapture.count() != 0 || m_mixdevice->captureVolume().hasSwitch() ) updateInternal(m_mixdevice->captureVolume(), m_slidersCapture, m_mixdevice->isNotRecSource() ); if (m_controlLabel!=nullptr) { QLabel *l; VerticalText *v; if ((l = dynamic_cast(m_controlLabel))) l->setText(m_mixdevice->readableName()); else if ((v = dynamic_cast(m_controlLabel))) v->setText(m_mixdevice->readableName()); } updateAccesability(); } /** * * @param vol * @param ref_sliders * @param muted Future directions: passing "muted" should not be necessary any longer - due to getVolumeForGUI() */ void MDWSlider::updateInternal(Volume& vol, QList& ref_sliders, bool muted) { // bool debugMe = (mixDevice()->id() == "PCM:0" ); // if (debugMe) // { // qCDebug(KMIX_LOG) << "The updateInternal() PCM:0 playback state" << mixDevice()->isMuted() // << ", vol=" << mixDevice()->playbackVolume().getAvgVolumePercent(Volume::MALL); // } for (int i = 0; i-1 && --m_waitForSoundSetComplete<1) { m_waitForSoundSetComplete = 0; volumeValues.removeAt(volume_index); if (!m_sliderInWork) slider->setValue(useVolume); } else if (!m_sliderInWork && m_waitForSoundSetComplete<1) { slider->setValue(useVolume); } // --- Avoid feedback loops END ----------------- KSmallSlider *smallSlider = qobject_cast(slider); if (smallSlider!=nullptr) // faster than QObject::inherits() { smallSlider->setGray(m_mixdevice->isMuted()); } } // for all sliders // update mute state if (m_muteButton!=nullptr) { QSignalBlocker blocker(m_muteButton); m_muteButton->setActive(!m_mixdevice->isMuted()); } // update capture state if (m_captureButton!=nullptr) { QSignalBlocker blocker(m_captureButton); m_captureButton->setActive(m_mixdevice->isRecSource()); } } #ifndef QT_NO_ACCESSIBILITY void MDWSlider::updateAccesability() { if (m_linked) { if (!m_slidersPlayback.isEmpty()) m_slidersPlayback[0]->setAccessibleName(m_slidersPlayback[0]->toolTip()); if (!m_slidersCapture.isEmpty()) m_slidersCapture[0]->setAccessibleName(m_slidersCapture[0]->toolTip()); } else { QList vols = m_mixdevice->playbackVolume().getVolumes().values(); foreach (QAbstractSlider *slider, m_slidersPlayback) { slider->setAccessibleName(slider->toolTip()+ " (" +Volume::channelNameReadable(vols.first().chid)+')'); vols.pop_front(); } vols = m_mixdevice->captureVolume().getVolumes().values(); foreach (QAbstractSlider *slider, m_slidersCapture) { slider->setAccessibleName(slider->toolTip()+ " (" +Volume::channelNameReadable(vols.first().chid)+')'); vols.pop_front(); } } } #endif void MDWSlider::showContextMenu(const QPoint &pos) { if (m_view ==nullptr) return; QMenu *menu = m_view->getPopup(); menu->addSection( SmallIcon( "kmix" ), m_mixdevice->readableName() ); if (m_moveMenu) { MixSet *ms = m_mixdevice->getMoveDestinationMixSet(); Q_ASSERT(ms); m_moveMenu->setEnabled((ms->count() > 1)); menu->addMenu( m_moveMenu ); } if ( m_slidersPlayback.count()>1 || m_slidersCapture.count()>1) { KToggleAction *stereo = qobject_cast(_mdwActions->action("stereo")); if (stereo!=nullptr) { QSignalBlocker blocker(stereo); stereo->setChecked(!isStereoLinked()); menu->addAction( stereo ); } } if ( m_mixdevice->captureVolume().hasSwitch() ) { KToggleAction *ta = qobject_cast(_mdwActions->action("recsrc")); if (ta!=nullptr) { QSignalBlocker blocker(ta); ta->setChecked( m_mixdevice->isRecSource() ); menu->addAction( ta ); } } if ( m_mixdevice->hasMuteSwitch() ) { KToggleAction *ta = qobject_cast(_mdwActions->action("mute")); if (ta!=nullptr) { QSignalBlocker blocker(ta); ta->setChecked( m_mixdevice->isMuted() ); menu->addAction( ta ); } } // QAction *a = _mdwActions->action( "hide" ); // if ( a ) // menu->addAction( a ); QAction *b = _mdwActions->action( "keys" ); if (b!=nullptr) { menu->addSeparator(); menu->addAction(b); } menu->popup(pos); } void MDWSlider::showMoveMenu() { MixSet *ms = m_mixdevice->getMoveDestinationMixSet(); Q_ASSERT(ms); _mdwMoveActions->clear(); m_moveMenu->clear(); // Default QAction *a = new QAction(_mdwMoveActions); a->setText( i18n("Automatic According to Category") ); _mdwMoveActions->addAction( QString("moveautomatic"), a); connect(a, SIGNAL(triggered(bool)), SLOT(moveStreamAutomatic()), Qt::QueuedConnection); m_moveMenu->addAction( a ); a = new QAction(_mdwMoveActions); a->setSeparator(true); _mdwMoveActions->addAction( QString("-"), a); m_moveMenu->addAction( a ); foreach (shared_ptr md, *ms) { a = new MDWMoveAction(md, _mdwMoveActions); _mdwMoveActions->addAction( QString("moveto") + md->id(), a); connect(a, SIGNAL(moveRequest(QString)), SLOT(moveStream(QString)), Qt::QueuedConnection); m_moveMenu->addAction( a ); } } /** * An event filter for the various widgets making up this control. * * Redirect all wheel events to the main slider, so that they will be * handled consistently regardless of where the pointer actually is. */ bool MDWSlider::eventFilter(QObject *obj, QEvent *ev) { if (ev->type()!=QEvent::Wheel) return (QWidget::eventFilter(obj, ev)); // only want wheel events if (!ev->spontaneous()) return (false); // avoid recursion on slider QAbstractSlider *slider = qobject_cast(obj); if (slider!=nullptr) // event is over a slider { // Do nothing in this case. No event filter is installed // on a slider, and it will handle the wheel event itself. qCWarning(KMIX_LOG) << "unexpected wheel event on slider" << slider; return (false); } // Mouse is not over a slider. Find the principal slider (the first // playback control if there are any, otherwise the first capture // control if any) and redirect the event to that. if (!m_slidersPlayback.isEmpty()) slider = m_slidersPlayback.first(); else if (!m_slidersCapture.isEmpty()) slider = m_slidersCapture.first(); else slider = nullptr; if (slider!=nullptr) { //qCDebug(KMIX_LOG) << "identified for slider" << slider; QCoreApplication::sendEvent(slider, ev); } return (true); // wheel event handled } diff --git a/gui/mdwslider.h b/gui/mdwslider.h index a9ddedb0..6f7f3850 100644 --- a/gui/mdwslider.h +++ b/gui/mdwslider.h @@ -1,160 +1,160 @@ //-*-C++-*- /* * KMix -- KDE's full featured mini mixer * * * Copyright Chrisitan Esken * * 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. */ #ifndef MDWSLIDER_H #define MDWSLIDER_H #include #include #include "gui/volumeslider.h" #include "gui/mixdevicewidget.h" #include "core/volume.h" class QBoxLayout; class QGridLayout; class QToolButton; class QLabel; class QMenu; class MixDevice; class VerticalText; class ViewBase; class ToggleToolButton; class MDWSlider : public MixDeviceWidget { Q_OBJECT public: - MDWSlider(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view); + MDWSlider(shared_ptr md, MixDeviceWidget::MDWFlags flags, ViewBase *view, ProfControl *pctl = nullptr); virtual ~MDWSlider(); enum LabelType { LT_ALL, LT_FIRST_CAPTURE, LT_NONE }; void addActionToPopup( QAction *action ); void createActions(); void createShortcutActions(); // GUI bool isStereoLinked() const Q_DECL_OVERRIDE { return m_linked; } void setStereoLinked( bool value ) Q_DECL_OVERRIDE; void setLabeled( bool value ) Q_DECL_OVERRIDE; void setTicks( bool ticks ) Q_DECL_OVERRIDE; void setIcons( bool value ) Q_DECL_OVERRIDE; QToolButton* addMediaButton(QString iconName, QLayout* layout, QWidget *parent); void updateMediaButton(); void setColors( QColor high, QColor low, QColor back ) Q_DECL_OVERRIDE; void setMutedColors( QColor high, QColor low, QColor back ) Q_DECL_OVERRIDE; bool eventFilter(QObject *obj, QEvent *ev) Q_DECL_OVERRIDE; QString iconName(); // Layout QSizePolicy sizePolicy() const; QSize sizeHint() const Q_DECL_OVERRIDE; int labelExtentHint() const Q_DECL_OVERRIDE; void setLabelExtent(int extent) Q_DECL_OVERRIDE; bool hasMuteButton() const; bool hasCaptureLED() const; static bool debugMe; public slots: void toggleRecsrc(); void toggleMuted(); void toggleStereoLinked(); void setDisabled( bool value ) Q_DECL_OVERRIDE; void update() Q_DECL_OVERRIDE; void showMoveMenu(); void showContextMenu( const QPoint &pos = QCursor::pos() ) Q_DECL_OVERRIDE; void increaseOrDecreaseVolume(bool arg1, Volume::VolumeTypeFlag volumeType); VolumeSliderExtraData& extraData(QAbstractSlider *slider); void addMediaControls(QBoxLayout* arg1); private slots: void setRecsrc(bool value); void setMuted(bool value); void volumeChange( int ); void sliderPressed(); void sliderReleased(); void increaseVolume(); void decreaseVolume(); void moveStreamAutomatic(); void moveStream( QString destId ); void mediaPlay(bool); void mediaNext(bool); void mediaPrev(bool); private: void createWidgets(); void addSliders( QBoxLayout *volLayout, char type, Volume& vol, QList& ref_sliders, QString tooltipText ); // Methods that are called two times from a wrapper. Once for playabck, once for capture void setStereoLinkedInternal( QList< QAbstractSlider* >& ref_sliders, bool showSubcontrolLabels); void setTicksInternal( QList< QAbstractSlider* >& ref_sliders, bool ticks ); void volumeChangeInternal(Volume& vol, QList< QAbstractSlider* >& ref_sliders ); void updateInternal(Volume& vol, QList< QAbstractSlider* >& ref_sliders, bool muted); #ifndef QT_NO_ACCESSIBILITY void updateAccesability(); #endif QString calculatePlaybackIcon(MediaController::PlayState playState); QWidget *guiAddButtonSpacer(); void guiAddCaptureButton(const QString &captureTooltipText); void guiAddMuteButton(const QString &muteTooltipText); void guiAddControlIcon(const QString &tooltipText); void guiAddControlLabel(Qt::Alignment alignment, const QString &channelName); void addGlobalShortcut(QAction* action, const QString& label, bool dynamicControl); QSize controlButtonSize(); bool m_linked; QGridLayout *m_controlGrid; QLabel *m_controlIcon; QLabel *m_controlLabel; // is either QLabel or VerticalText ToggleToolButton *m_muteButton; ToggleToolButton *m_captureButton; QToolButton *m_mediaPlayButton; QSize m_controlButtonSize; KActionCollection* _mdwMoveActions; QMenu *m_moveMenu; QList m_slidersPlayback; QList m_slidersCapture; bool m_sliderInWork; int m_waitForSoundSetComplete; QList volumeValues; }; #endif diff --git a/gui/mixdevicewidget.cpp b/gui/mixdevicewidget.cpp index 999f1e69..04948ba5 100644 --- a/gui/mixdevicewidget.cpp +++ b/gui/mixdevicewidget.cpp @@ -1,107 +1,109 @@ /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 1996-2004 Christian Esken * * 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 "gui/mixdevicewidget.h" #include #include #include #include #include #include #include #include #include #include "core/mixer.h" #include "core/mixertoolbox.h" #include "viewbase.h" #include "ksmallslider.h" #include "verticaltext.h" /** * Base Class for any Widget that represents a MixDevice. * The mix device can be a real (hardware bound) MixDevice or a virtual mix device. * * The direction (horizontal, vertical) can be configured and whether it should * be "small" (uses KSmallSlider instead of a normal slider widget). The actual implementations * SHOULD honor these values - those who do not might not be suitable for placing in * the panel applet or any other smallish settings. */ -MixDeviceWidget::MixDeviceWidget(shared_ptr md, MDWFlags flags, ViewBase *view) +MixDeviceWidget::MixDeviceWidget(shared_ptr md, MDWFlags flags, ViewBase *view, ProfControl *pctl) : QWidget(view), m_mixdevice(md), m_view(view), m_flags(flags), m_shortcutsDialog(nullptr) { setContextMenuPolicy(Qt::DefaultContextMenu); - // The default control profile. - // ViewDockAreaPopup sets this later using setProfileControl(). - m_pctl = md->controlProfile(); + // The control profile. ViewSliders uses the default from the MixDevice. + // ViewDockAreaPopup sets a special one. + m_pctl = pctl; + if (m_pctl==nullptr) m_pctl = md->controlProfile(); + Q_ASSERT(m_pctl!=nullptr); _mdwActions = new KActionCollection( this ); _mdwPopupActions = new KActionCollection( this ); QString name (md->id()); /* char* whatsThisChar = whatsthis.toUtf8().data(); QString w; w = ki18n(whatsThisChar).toString(MixerToolBox::whatsthisControlLocale() ); this->setWhatsThis(w); */ QString whatsthisText = mixDevice()->mixer()->translateKernelToWhatsthis(name); if ( whatsthisText != "---") { setWhatsThis(whatsthisText); } } void MixDeviceWidget::addActionToPopup( QAction *action ) { _mdwActions->addAction( action->objectName(), action ); } void MixDeviceWidget::defineKeys() { // Dialog for *global* shortcuts of this MDW if ( m_shortcutsDialog == 0 ) { m_shortcutsDialog = new KShortcutsDialog( KShortcutsEditor::GlobalAction ); m_shortcutsDialog->addCollection(_mdwPopupActions); } m_shortcutsDialog->configure(); } void MixDeviceWidget::contextMenuEvent(QContextMenuEvent *ev) { showContextMenu(ev->globalPos()); } void MixDeviceWidget::volumeChange( int ) { /* is virtual */ } //void MixDeviceWidget::setDisabled( bool ) { /* is virtual */ } //void MixDeviceWidget::setVolume( int /*channel*/, int /*vol*/ ) { /* is virtual */ } //void MixDeviceWidget::setVolume( Volume /*vol*/ ) { /* is virtual */ } //void MixDeviceWidget::update() { /* is virtual */ } //void MixDeviceWidget::showContextMenu( const QPoint &pos ) { /* is virtual */ } void MixDeviceWidget::setColors( QColor , QColor , QColor ) { /* is virtual */ } void MixDeviceWidget::setIcons( bool ) { /* is virtual */ } void MixDeviceWidget::setLabeled( bool ) { /* is virtual */ } void MixDeviceWidget::setMutedColors( QColor , QColor , QColor ) { /* is virtual */ } diff --git a/gui/mixdevicewidget.h b/gui/mixdevicewidget.h index f4c07b78..d678405c 100644 --- a/gui/mixdevicewidget.h +++ b/gui/mixdevicewidget.h @@ -1,109 +1,108 @@ //-*-C++-*- /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 2000 Stefan Schimanski <1Stein@gmx.de> * 1996-2000 Christian Esken * Sven Fischer * * 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. */ #ifndef MIXDEVICEWIDGET_H #define MIXDEVICEWIDGET_H #include "core/mixdevice.h" #include "core/volume.h" #include "gui/viewbase.h" class KActionCollection; class KShortcutsDialog; class MixDevice; class ProfControl; class MixDeviceWidget : public QWidget { Q_OBJECT public: enum MDWFlag { SmallSize = 0x01, ShowMute = 0x02, ShowCapture = 0x04, ShowMixerName = 0x08 }; Q_DECLARE_FLAGS(MDWFlags, MDWFlag); - MixDeviceWidget(shared_ptr md, MDWFlags flags, ViewBase *view); + MixDeviceWidget(shared_ptr md, MDWFlags flags, ViewBase *view, ProfControl *pctl); virtual ~MixDeviceWidget() = default; void addActionToPopup( QAction *action ); shared_ptr mixDevice() const { return (m_mixdevice); } ProfControl *profileControl() const { return (m_pctl); } - void setProfileControl(ProfControl *pctl) { m_pctl = pctl; } virtual void setColors( QColor high, QColor low, QColor back ); virtual void setIcons( bool value ); virtual void setMutedColors( QColor high, QColor low, QColor back ); virtual bool isStereoLinked() const { return (false); } virtual void setStereoLinked(bool) {} virtual void setLabeled(bool); virtual void setTicks(bool) {} virtual int labelExtentHint() const { return (0); } virtual void setLabelExtent(int extent) { Q_UNUSED(extent); } public slots: virtual void defineKeys(); virtual void showContextMenu(const QPoint &pos = QCursor::pos()) = 0; /** * Called whenever there are volume updates pending from the hardware for this MDW. */ virtual void update() = 0; signals: void guiVisibilityChange(MixDeviceWidget* source, bool enable); protected slots: virtual void setDisabled(bool value) = 0; void volumeChange(int); protected: void contextMenuEvent(QContextMenuEvent *ev) Q_DECL_OVERRIDE; Qt::Orientation orientation() const { return (m_view->orientation()); } MixDeviceWidget::MDWFlags flags() const { return (m_flags); } protected: shared_ptr m_mixdevice; KActionCollection* _mdwActions; KActionCollection* _mdwPopupActions; ViewBase* m_view; MDWFlags m_flags; KShortcutsDialog* m_shortcutsDialog; private: ProfControl* m_pctl; }; Q_DECLARE_OPERATORS_FOR_FLAGS(MixDeviceWidget::MDWFlags); #endif diff --git a/gui/viewdockareapopup.cpp b/gui/viewdockareapopup.cpp index 3d95557a..cfcc9a60 100644 --- a/gui/viewdockareapopup.cpp +++ b/gui/viewdockareapopup.cpp @@ -1,439 +1,435 @@ /* * KMix -- KDE's full featured mini mixer * * * Copyright (C) 1996-2004 Christian Esken * * 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 "gui/viewdockareapopup.h" // Qt #include #include #include #include #include #include #include // KDE #include #include // KMix #include "apps/kmix.h" #include "core/mixer.h" #include "core/ControlManager.h" #include "gui/dialogchoosebackends.h" #include "gui/guiprofile.h" #include "gui/kmixprefdlg.h" #include "gui/mdwslider.h" #include "dialogbase.h" // Restore volume button feature is incomplete => disabling for KDE 4.10 #undef RESTORE_VOLUME_BUTTON -QString ViewDockAreaPopup::InternedString_Star = QString("*"); -QString ViewDockAreaPopup::InternedString_Subcontrols = QString("pvolume,cvolume,pswitch,cswitch"); -ProfControl* ViewDockAreaPopup::MatchAllForSoundMenu = 0; -//ProfControl(ViewDockAreaPopup::InternedString_Star, ViewDockAreaPopup::InternedString_Subcontrols); ViewDockAreaPopup::ViewDockAreaPopup(QWidget* parent, QString id, ViewBase::ViewFlags vflags, QString guiProfileId, KMixWindow *dockW) : ViewBase(parent, id, 0, vflags, guiProfileId), _kmixMainWindow(dockW) { resetRefs(); setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); /* * Bug 206724: * Following are excerpts of trying to receive key events while this popup is open. * The best I could do with lots of hacks is to get the keyboard events after a mouse-click in the popup. * But such a solution is neither intuitive nor helpful - if one clicks, then usage of keyboard makes not much sense any longer. * I finally gave up on fixing Bug 206724. */ /* releaseKeyboard(); setFocusPolicy(Qt::StrongFocus); setFocus(Qt::TabFocusReason); releaseKeyboard(); mainWindowButton->setFocusPolicy(Qt::StrongFocus); Also implemented the following "event handlers", but they do not show any signs of key presses: keyPressEvent() x11Event() eventFilter() */ foreach ( Mixer* mixer, Mixer::mixers() ) { // Adding all mixers, as we potentially want to show all master controls addMixer(mixer); // The list will be redone in initLayout() with the actual Mixer instances to use } restoreVolumeIcon = QIcon::fromTheme(QLatin1String("quickopen-file")); createDeviceWidgets(); // Register listeners for all mixers ControlManager::instance().addListener( QString(), // all mixers ControlManager::GUI|ControlManager::ControlList|ControlManager::Volume|ControlManager::MasterChanged, this, QString("ViewDockAreaPopup")); } ViewDockAreaPopup::~ViewDockAreaPopup() { ControlManager::instance().removeListener(this); delete _layoutMDW; // Hint: optionsLayout and "everything else" is deleted when "delete _layoutMDW" cascades down } void ViewDockAreaPopup::controlsChange(ControlManager::ChangeType changeType) { switch (changeType) { case ControlManager::ControlList: case ControlManager::MasterChanged: createDeviceWidgets(); break; case ControlManager::GUI: updateGuiOptions(); break; case ControlManager::Volume: refreshVolumeLevels(); break; default: ControlManager::warnUnexpectedChangeType(changeType, this); break; } } void ViewDockAreaPopup::configurationUpdate() { // TODO Do we still need configurationUpdate(). It was never implemented for ViewDockAreaPopup } // TODO Currently no right-click, as we have problems to get the ViewDockAreaPopup resized void ViewDockAreaPopup::showContextMenu() { // no right-button-menu on "dock area popup" return; } void ViewDockAreaPopup::resetRefs() { seperatorBetweenMastersAndStreams = 0; separatorBetweenMastersAndStreamsInserted = false; separatorBetweenMastersAndStreamsRequired = false; configureViewButton = 0; restoreVolumeButton1 = 0; restoreVolumeButton2 = 0; restoreVolumeButton3 = 0; restoreVolumeButton4 = 0; mainWindowButton = 0; optionsLayout = 0; _layoutMDW = 0; } void ViewDockAreaPopup::initLayout() { resetMdws(); if (optionsLayout != 0) { QLayoutItem *li2; while ((li2 = optionsLayout->takeAt(0))) delete li2; } // Hint : optionsLayout itself is deleted when "delete _layoutMDW" cascades down if (_layoutMDW != 0) { QLayoutItem *li; while ((li = _layoutMDW->takeAt(0))) delete li; } /* * Strangely enough, I cannot delete optionsLayout in a loop. I get a strange stacktrace: * Application: KMix (kmix), signal: Segmentation fault [...] #6 0x00007f9c9a282900 in QString::shared_null () from /usr/lib/x86_64-linux-gnu/libQtCore.so.4 #7 0x00007f9c9d4286b0 in ViewDockAreaPopup::initLayout (this=0x1272b60) at /home/chris/workspace/kmix-git-trunk/gui/viewdockareapopup.cpp:164 #8 0x00007f9c9d425700 in ViewBase::createDeviceWidgets (this=0x1272b60) at /home/chris/workspace/kmix-git-trunk/gui/viewbase.cpp:137 #9 0x00007f9c9d42845b in ViewDockAreaPopup::controlsChange (this=0x1272b60, changeType=2) at /home/chris/workspace/kmix-git-trunk/gui/viewdockareapopup.cpp:91 */ // if ( optionsLayout != 0 ) // { // QLayoutItem *li2; // while ( ( li2 = optionsLayout->takeAt(0) ) ) // strangely enough, it crashes here // delete li2; // } // --- Due to the strange crash, delete everything manually : START --------------- // I am a bit confused why this doesn't crash. I moved the "optionsLayout->takeAt(0) delete" loop at the beginning, // so the objects should already be deleted. ... delete configureViewButton; delete restoreVolumeButton1; delete restoreVolumeButton2; delete restoreVolumeButton3; delete restoreVolumeButton4; delete mainWindowButton; delete seperatorBetweenMastersAndStreams; // --- Due to the strange crash, delete everything manually : END --------------- resetRefs(); setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); /* * BKO 299754: Looks like I need to explicitly delete layout(). I have no idea why * "delete _layoutMDW" is not enough, as that is supposed to be the layout * of this ViewDockAreaPopup * (Hint: it might have been 0 already. Nowadays it is definitely, see #resetRefs()) */ delete layout(); // BKO 299754 _layoutMDW = new QGridLayout(this); _layoutMDW->setSpacing(DialogBase::verticalSpacing()); // Review #121166: Add some space over device icons, otherwise they may hit window border _layoutMDW->setContentsMargins(0,5,0,0); //_layoutMDW->setSizeConstraint(QLayout::SetMinimumSize); _layoutMDW->setSizeConstraint(QLayout::SetMaximumSize); _layoutMDW->setObjectName(QLatin1String("KmixPopupLayout")); setLayout(_layoutMDW); // Adding all mixers, as we potentially want to show all master controls. Due to hotplugging // we have to redo the list on each initLayout() (instead of setting it once in the Constructor) _mixers.clear(); QSet preferredMixersForSoundmenu = GlobalConfig::instance().getMixersForSoundmenu(); // qCDebug(KMIX_LOG) << "Launch with " << preferredMixersForSoundmenu; foreach ( Mixer* mixer, Mixer::mixers() ) { bool useMixer = preferredMixersForSoundmenu.isEmpty() || preferredMixersForSoundmenu.contains(mixer->id()); if (useMixer) addMixer(mixer); } // The following loop is for the case when everything gets filtered out. We "reset" to show everything then. // Hint: Filtering everything out can only be an "accident", e.g. when restarting KMix with changed hardware or // backends. if ( _mixers.isEmpty() ) { foreach ( Mixer* mixer, Mixer::mixers() ) { addMixer(mixer); } } // A loop that adds the Master control of each card foreach ( Mixer* mixer, _mixers ) { // qCDebug(KMIX_LOG) << "ADD? mixerId=" << mixer->id(); shared_ptrdockMD = mixer->getLocalMasterMD(); if ( !dockMD && mixer->size() > 0 ) { // If we have no dock device yet, we will take the first available mixer device. dockMD = (*mixer)[0]; } if ( dockMD ) { // qCDebug(KMIX_LOG) << "ADD? mixerId=" << mixer->id() << ", md=" << dockMD->id(); if ( !dockMD->isApplicationStream() && dockMD->playbackVolume().hasVolume()) { // qCDebug(KMIX_LOG) << "ADD? mixerId=" << mixer->id() << ", md=" << dockMD->id() << ": YES"; // don't add application streams here. They are handled below, so // we make sure to not add them twice _mixSet.append(dockMD); } } } // loop over all cards // Add all application streams foreach ( Mixer* mixer2 , _mixers ) { foreach ( shared_ptr md, mixer2->getMixSet() ) { if (md->isApplicationStream()) { _mixSet.append(md); } } } } QWidget* ViewDockAreaPopup::add(shared_ptr md) { const bool vertical = (orientation()==Qt::Vertical); /* QString dummyMatchAll("*"); QString matchAllPlaybackAndTheCswitch("pvolume,cvolume,pswitch,cswitch"); // Leak | relevant | pctl Each time a stream is added, a new ProfControl gets created. // It cannot be deleted in ~MixDeviceWidget, as ProfControl* ownership is not consistent. // here a new pctl is created (could be deleted), but in ViewSliders the ProcControl is taken from the // MixDevice, which in turn uses it from the GUIProfile. // Summarizing: ProfControl* is either owned by the GUIProfile or created new (ownership unclear). // Hint: dummyMatchAll and matchAllPlaybackAndTheCswitch leak together with pctl ProfControl *pctl = new ProfControl( dummyMatchAll, matchAllPlaybackAndTheCswitch); */ if ( !md->isApplicationStream() ) { separatorBetweenMastersAndStreamsRequired = true; } if ( !separatorBetweenMastersAndStreamsInserted && separatorBetweenMastersAndStreamsRequired && md->isApplicationStream() ) { // First application stream => add separator separatorBetweenMastersAndStreamsInserted = true; int sliderColumn = vertical ? _layoutMDW->columnCount() : _layoutMDW->rowCount(); int row = vertical ? 0 : sliderColumn; int col = vertical ? sliderColumn : 0; seperatorBetweenMastersAndStreams = new QFrame(this); if (vertical) seperatorBetweenMastersAndStreams->setFrameStyle(QFrame::VLine); else seperatorBetweenMastersAndStreams->setFrameStyle(QFrame::HLine); _layoutMDW->addWidget( seperatorBetweenMastersAndStreams, row, col ); //_layoutMDW->addItem( new QSpacerItem( 5, 5 ), row, col ); } - if (MatchAllForSoundMenu == 0) + static ProfControl *MatchAllForSoundMenu = nullptr; + if (MatchAllForSoundMenu==nullptr) { - // Lazy init of static member on first use - // TODO: why do the strings have to be interned? This is a once only init. - MatchAllForSoundMenu = new ProfControl(ViewDockAreaPopup::InternedString_Star, ViewDockAreaPopup::InternedString_Subcontrols); + // Lazy init of static member on first use + MatchAllForSoundMenu = new ProfControl("*", "pvolume,cvolume,pswitch,cswitch"); } MixDeviceWidget *mdw = new MDWSlider(md, MixDeviceWidget::ShowMute|MixDeviceWidget::ShowCapture|MixDeviceWidget::ShowMixerName, - this); - mdw->setProfileControl(MatchAllForSoundMenu); + this, + MatchAllForSoundMenu); mdw->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); int sliderColumn = vertical ? _layoutMDW->columnCount() : _layoutMDW->rowCount(); //if (sliderColumn == 1 ) sliderColumn =0; int row = vertical ? 0 : sliderColumn; int col = vertical ? sliderColumn : 0; _layoutMDW->addWidget( mdw, row, col ); //qCDebug(KMIX_LOG) << "ADDED " << md->id() << " at column " << sliderColumn; return mdw; } void ViewDockAreaPopup::constructionFinished() { // qCDebug(KMIX_LOG) << "ViewDockAreaPopup::constructionFinished()\n"; mainWindowButton = new QPushButton(QIcon::fromTheme("show-mixer"), "" , this); mainWindowButton->setObjectName(QLatin1String("MixerPanel")); mainWindowButton->setToolTip(i18n("Show the full mixer window")); connect(mainWindowButton, SIGNAL(clicked()), SLOT(showPanelSlot())); configureViewButton = createConfigureViewButton(); optionsLayout = new QHBoxLayout(); optionsLayout->addWidget(mainWindowButton); optionsLayout->addStretch(1); optionsLayout->addWidget(configureViewButton); #ifdef RESTORE_VOLUME_BUTTON restoreVolumeButton1 = createRestoreVolumeButton(1); optionsLayout->addWidget( restoreVolumeButton1 ); // TODO enable only if user has saved a volume profile // optionsLayout->addWidget( createRestoreVolumeButton(2) ); // optionsLayout->addWidget( createRestoreVolumeButton(3) ); // optionsLayout->addWidget( createRestoreVolumeButton(4) ); #endif int sliderRow = _layoutMDW->rowCount(); _layoutMDW->addLayout(optionsLayout, sliderRow, 0, 1, _layoutMDW->columnCount()); updateGuiOptions(); _layoutMDW->update(); _layoutMDW->activate(); //bool fnc = focusNextChild(); //qCWarning(KMIX_LOG) << "fnc=" <setToolTip(i18n("Load volume profile %1", storageSlot)); profileButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); return profileButton; } void ViewDockAreaPopup::refreshVolumeLevels() { const int num = mixDeviceCount(); for (int i = 0; i(mixDeviceAt(i)); if (mdw!=nullptr) mdw->update(); } } void ViewDockAreaPopup::configureView() { // Q_ASSERT( !pulseaudioPresent() ); // QSet currentlyActiveMixersInDockArea; // foreach ( Mixer* mixer, _mixers ) // { // currentlyActiveMixersInDockArea.insert(mixer->id()); // } KMixPrefDlg* prefDlg = KMixPrefDlg::getInstance(); //prefDlg->setActiveMixersInDock(currentlyActiveMixersInDockArea); prefDlg->switchToPage(KMixPrefDlg::PrefSoundMenu); } /** * This gets activated whne a user clicks the "Mixer" PushButton in this popup. */ void ViewDockAreaPopup::showPanelSlot() { _kmixMainWindow->setVisible(true); KWindowSystem::setOnDesktop(_kmixMainWindow->winId(), KWindowSystem::currentDesktop()); KWindowSystem::activateWindow(_kmixMainWindow->winId()); // This is only needed when the window is already visible. static_cast(parent())->hide(); } Qt::Orientation ViewDockAreaPopup::orientationSetting() const { return (GlobalConfig::instance().data.getTraypopupOrientation()); }