summaryrefslogtreecommitdiff
path: root/src/ui/tmixpopup.cpp
diff options
context:
space:
mode:
authorCalvin Morrison <calvin@pobox.com>2026-05-15 10:10:04 -0400
committerCalvin Morrison <calvin@pobox.com>2026-05-15 10:10:04 -0400
commite776bc768cf9afca1867200e25d64d315cd72a3e (patch)
tree6745527b939c9d37147d7dc98e8664437ee433f6 /src/ui/tmixpopup.cpp
parent4e602e78cdfc210ab7781668df2a88afb923258b (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.cpp134
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"