diff options
| author | Calvin Morrison <calvin@pobox.com> | 2026-05-15 10:10:04 -0400 |
|---|---|---|
| committer | Calvin Morrison <calvin@pobox.com> | 2026-05-15 10:10:04 -0400 |
| commit | e776bc768cf9afca1867200e25d64d315cd72a3e (patch) | |
| tree | 6745527b939c9d37147d7dc98e8664437ee433f6 /src/ui/tmixpopup.cpp | |
| parent | 4e602e78cdfc210ab7781668df2a88afb923258b (diff) | |
Full mixer implementation — tray, popup, prefs, devices tab with port indicators
Adds the complete tmix feature set built since the initial skeleton:
balance knob, level meters, KLed mute button, system tray with scroll-wheel
volume and recording indicator, tray popup, preferences dialog, right-click
context menus, single-instance enforcement, scroll area, window geometry
persistence, and Devices tab with PA card profile switcher and live port
availability indicators (2-column layout, in-place updates on plug/unplug).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/ui/tmixpopup.cpp')
| -rw-r--r-- | src/ui/tmixpopup.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/ui/tmixpopup.cpp b/src/ui/tmixpopup.cpp new file mode 100644 index 0000000..068c66e --- /dev/null +++ b/src/ui/tmixpopup.cpp @@ -0,0 +1,134 @@ +#include "tmixpopup.h" +#include "devicewidget.h" +#include "../model/audiodevice.h" +#include "../model/pulsemodel.h" + +#include <tqlayout.h> +#include <tqframe.h> +#include <tqlabel.h> +#include <tqpushbutton.h> +#include <tqapplication.h> +#include <tqdesktopwidget.h> +#include <tdelocale.h> +#include <tdeconfig.h> +#include <tdeglobal.h> +#include <twin.h> + +TmixPopup::TmixPopup( PulseModel *model, TQWidget *parent ) + : TQWidget( parent, "TmixPopup", + WStyle_Customize | WType_Popup | WStyle_DialogBorder ), + m_model(model), m_devWidget(0) +{ + // Single frame fills the popup — header and content share the same border + TQVBoxLayout *outer = new TQVBoxLayout( this, 0, 0 ); + + TQFrame *frame = new TQFrame( this ); + frame->setFrameStyle( TQFrame::NoFrame ); + outer->addWidget( frame ); + + m_layout = new TQVBoxLayout( frame, 0, 0 ); + + // Thin title strip — inside the frame, so edges line up exactly + TQLabel *header = new TQLabel( i18n("Volume"), frame ); + header->setAlignment( TQt::AlignCenter ); + header->setFixedHeight( 23 ); + header->setPaletteBackgroundColor( palette().active().mid() ); + header->setPaletteForegroundColor( palette().active().text() ); + m_layout->addWidget( header ); + + // Spacer between header and device widget + m_layout->addSpacing( 4 ); + + // device widget inserted at index 0 by setDevice() + + m_layout->addSpacing( 4 ); + + // "Mixer" button — flat, compact + TQPushButton *btn = new TQPushButton( i18n("Mixer"), frame ); + btn->setFlat( true ); + btn->setFixedWidth( 70 ); + m_layout->addWidget( btn, 0, TQt::AlignHCenter ); + m_layout->addSpacing( 4 ); + connect( btn, TQ_SIGNAL(clicked()), this, TQ_SIGNAL(showMixerRequested()) ); + + connect( model, TQ_SIGNAL(defaultOutputChanged(AudioDevice*)), + this, TQ_SLOT(onDefaultOutputChanged(AudioDevice*)) ); + + setDevice( model->defaultOutput() ); +} + +void TmixPopup::setDevice( AudioDevice *dev ) +{ + if ( m_devWidget ) { + m_layout->remove( m_devWidget ); + delete m_devWidget; + m_devWidget = 0; + } + if ( !dev ) return; + + m_devWidget = new DeviceWidget( dev, m_model, + static_cast<TQWidget*>( m_layout->parent() ) ); + m_devWidget->setSeparatorVisible( false ); + m_layout->insertWidget( 2, m_devWidget ); + m_devWidget->show(); + adjustSize(); +} + +void TmixPopup::onDefaultOutputChanged( AudioDevice *dev ) +{ + setDevice( dev ); +} + +void TmixPopup::toggleAt( const TQPoint &trayPos, const TQSize &traySize ) +{ + if ( isVisible() ) { + hide(); + return; + } + + adjustSize(); + + TQRect screen = TQApplication::desktop()->screenGeometry( trayPos ); + + int x = trayPos.x() + traySize.width() / 2 - width() / 2; + int y = trayPos.y() - height(); + + if ( y < screen.top() ) + y = trayPos.y() + traySize.height(); + + if ( x + width() > screen.right() ) + x = screen.right() - width(); + if ( x < screen.left() ) + x = screen.left(); + + move( x, y ); + show(); + + KWin::setState( winId(), NET::KeepAbove | NET::SkipTaskbar | NET::SkipPager ); + KWin::setOnAllDesktops( winId(), true ); +} + +bool TmixPopup::justHidden() const +{ + return m_hideTime.isValid() && m_hideTime.elapsed() < 300; +} + +void TmixPopup::hideEvent( TQHideEvent *e ) +{ + TQWidget::hideEvent( e ); + m_hideTime.start(); +} + +void TmixPopup::wheelEvent( TQWheelEvent *e ) +{ + AudioDevice *dev = m_model->defaultOutput(); + if ( !dev ) return; + TDEConfig *cfg = TDEGlobal::config(); + cfg->setGroup("General"); + int step = cfg->readNumEntry("ScrollStep", 5); + int delta = e->delta() > 0 ? step : -step; + int vol = TQMAX( 0, TQMIN( 100, dev->volume() + delta ) ); + dev->setVolume( vol ); +} + +#include "tmixpopup.moc" |
