summaryrefslogtreecommitdiff
path: root/src/ui/balanceknob.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/balanceknob.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/balanceknob.cpp')
-rw-r--r--src/ui/balanceknob.cpp124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/ui/balanceknob.cpp b/src/ui/balanceknob.cpp
new file mode 100644
index 0000000..1c2faa4
--- /dev/null
+++ b/src/ui/balanceknob.cpp
@@ -0,0 +1,124 @@
+#include "balanceknob.h"
+
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqimage.h>
+#include <tqevent.h>
+#include <math.h>
+
+static const double DEG2RAD = M_PI / 180.0;
+static const double TRAVEL = 135.0; // degrees each side from centre
+
+BalanceKnob::BalanceKnob( int minVal, int maxVal, int val, TQWidget *parent )
+ : TQWidget(parent),
+ m_min(minVal), m_max(maxVal), m_value(val),
+ m_dragY(0), m_dragValue(0), m_dragging(false)
+{
+ setFixedSize( 30, 30 );
+ setBackgroundMode( TQt::NoBackground );
+}
+
+void BalanceKnob::setValue( int v )
+{
+ v = v < m_min ? m_min : v > m_max ? m_max : v;
+ if ( v == m_value ) return;
+ m_value = v;
+ update();
+ emit valueChanged( v );
+}
+
+void BalanceKnob::paintEvent( TQPaintEvent * )
+{
+ // 2× supersampling for smooth edges (TQt3 has no native AA)
+ const int S = 2;
+ int W = width() * S, H = height() * S;
+ int cx = W / 2, cy = H / 2;
+ int r = ( W < H ? W : H ) / 2 - S;
+
+ TQPixmap pm( W, H );
+ pm.fill( paletteBackgroundColor() );
+ TQPainter p( &pm );
+
+ double mid = ( m_min + m_max ) / 2.0;
+ double half = ( m_max - m_min ) / 2.0;
+
+ // ---- range track arc (270° from 7:30 clockwise to 4:30) -----------------
+ p.setPen( TQPen( TQColor(90, 90, 90), S * 2 ) );
+ p.setBrush( TQt::NoBrush );
+ p.drawArc( cx - r, cy - r, 2*r, 2*r, 225*16, -270*16 );
+
+ // ---- value arc (from 12-o'clock to current position) --------------------
+ double current_qt = 90.0 - ( (m_value - mid) / half ) * TRAVEL;
+ int spanAngle = (int)( (current_qt - 90.0) * 16.0 );
+ if ( spanAngle != 0 ) {
+ p.setPen( TQPen( TQColor(90, 140, 220), S * 2 ) );
+ p.drawArc( cx - r, cy - r, 2*r, 2*r, 90*16, spanAngle );
+ }
+
+ // ---- knob body -----------------------------------------------------------
+ int kr = r - S * 3;
+ p.setPen( TQt::NoPen );
+
+ p.setBrush( TQColor(38, 38, 42) );
+ p.drawEllipse( cx - kr, cy - kr, 2*kr, 2*kr );
+
+ p.setBrush( TQColor(68, 68, 74) );
+ p.drawEllipse( cx - kr + S, cy - kr + S, 2*kr - S*3, 2*kr - S*3 );
+
+ // ---- centre rest dot ----------------------------------------------------
+ p.setPen( TQt::NoPen );
+ p.setBrush( TQColor(100, 100, 110) );
+ p.drawEllipse( cx - S, cy - kr + S*2, S*2, S*2 );
+
+ // ---- indicator line -----------------------------------------------------
+ double angle_rad = ( (m_value - mid) / half ) * TRAVEL * DEG2RAD;
+ int ix = cx + (int)( (kr - S*3) * sin( angle_rad ) );
+ int iy = cy - (int)( (kr - S*3) * cos( angle_rad ) );
+
+ p.setPen( TQPen( TQt::white, S * 2 ) );
+ p.drawLine( cx, cy, ix, iy );
+
+ p.end();
+
+ // Scale back down and blit
+ TQImage scaled = pm.convertToImage().smoothScale( width(), height() );
+ TQPainter out( this );
+ out.drawImage( 0, 0, scaled );
+}
+
+void BalanceKnob::mousePressEvent( TQMouseEvent *e )
+{
+ if ( e->button() == TQt::LeftButton ) {
+ m_dragY = e->globalPos().y();
+ m_dragValue = m_value;
+ m_dragging = true;
+ grabMouse();
+ }
+}
+
+void BalanceKnob::mouseMoveEvent( TQMouseEvent *e )
+{
+ if ( !m_dragging ) return;
+ int delta = m_dragY - e->globalPos().y(); // drag up = increase
+ setValue( m_dragValue + delta );
+}
+
+void BalanceKnob::mouseReleaseEvent( TQMouseEvent * )
+{
+ if ( m_dragging ) {
+ m_dragging = false;
+ releaseMouse();
+ }
+}
+
+void BalanceKnob::mouseDoubleClickEvent( TQMouseEvent * )
+{
+ setValue( (int)( (m_min + m_max) / 2.0 ) );
+}
+
+void BalanceKnob::wheelEvent( TQWheelEvent *e )
+{
+ setValue( m_value + ( e->delta() > 0 ? 5 : -5 ) );
+}
+
+#include "balanceknob.moc"