Logo Search packages:      
Sourcecode: qasmixer version File versions  Download package

mini_mixer.cpp

//
// C++ Implementation:
//
// Description:
//
//
// Author: Sebastian Holtermann <sebholt@xwmw.org>, (C) 2010-2011
//
// Copyright: See COPYING file that comes with this distribution
//
//

#include "mini_mixer.hpp"

#include <QSettings>
#include <QEvent>
#include <QWheelEvent>
#include <QHBoxLayout>
#include <QPushButton>
#include <QStyle>

#include "config.hpp"
#include "wdg/uint_mapper.hpp"

#include <cmath>
#include <iostream>


Mini_Mixer::Mini_Mixer (
      QObject * parent_n ) :
QObject ( parent_n ),
_mx_elem ( 0 ),
_volume_permille ( 0 ),
_wheel_degrees ( 720 ),
_volume_muted ( false ),
_show_balloon ( true ),
_mixer_changes ( false )
{
      {
            const char * def_str ( 0 );
            if ( QIcon::hasThemeIcon ( "multimedia-volume-control" ) ) {
                  def_str = "multimedia-volume-control";
            } else if ( QIcon::hasThemeIcon ( "audio-volume-high" ) ) {
                  def_str = "audio-volume-high";
            }

            if ( def_str != 0 ) {
                  _icon_default = QIcon::fromTheme ( def_str );
            } else {
                  QString icon_path ( INSTALL_DIR_ICONS_SVG );
                  icon_path += "/";
                  icon_path += PROGRAM_NAME;
                  icon_path += ".svg";

                  _icon_default = QIcon ( icon_path );
            }
      }

      _icons_volume[0] = QIcon::fromTheme ( "audio-volume-low",    _icon_default );
      _icons_volume[1] = QIcon::fromTheme ( "audio-volume-medium", _icon_default );
      _icons_volume[2] = QIcon::fromTheme ( "audio-volume-high",   _icon_default );
      _icon_muted = QIcon::fromTheme ( "audio-volume-muted",       _icons_volume[0] );


      //
      // Tray icon
      //

      {
            QAction * act_show ( new QAction ( this ) );
            act_show->setText ( tr ( "&Show mixer" ) );
            act_show->setShortcut ( QKeySequence ( tr ( "Ctrl+s" ) ) );
            act_show->setIcon ( QIcon::fromTheme ( "view-fullscreen" ) );
            act_show->setIconVisibleInMenu ( true );

            QAction * act_quit ( new QAction ( this ) );
            act_quit->setText ( tr ( "&Close %1" ).arg ( PROGRAM_TITLE ) );
            act_quit->setShortcut ( QKeySequence ( QKeySequence::Quit ) );
            act_quit->setIcon ( QIcon::fromTheme ( "application-exit" ) );
            act_quit->setIconVisibleInMenu ( true );

            connect ( act_show, SIGNAL ( triggered() ),
                  this, SIGNAL ( sig_show() ) );

            connect ( act_quit, SIGNAL ( triggered() ),
                  this, SIGNAL ( sig_close() ) );

            _tray_icon_menu.addAction ( act_show );
            _tray_icon_menu.addAction ( act_quit );

            _tray_icon.setContextMenu ( &_tray_icon_menu );


            _tray_icon.installEventFilter ( this );

            connect (
                  &_tray_icon, SIGNAL ( activated ( QSystemTrayIcon::ActivationReason ) ),
                  this, SLOT ( activation ( QSystemTrayIcon::ActivationReason ) ) );
      }


      //
      // Ballon widget
      //

      _balloon_value_mask = tr ( "Volume at %1%" );

      {
            _lbl_ballon_icon = new QLabel;
            QPushButton * btn_close ( new QPushButton );
            {
                  QIcon ico;
                  ico = _balloon.style()->standardIcon ( QStyle::SP_TitleBarCloseButton );
                  btn_close->setIcon ( ico );
            }
            {
                  int btn_size ( _balloon.fontMetrics().height() );
                  btn_close->setIconSize ( QSize ( btn_size, btn_size ) );
                  btn_close->setSizePolicy ( QSizePolicy::Fixed, QSizePolicy::Fixed );
                  btn_close->setFixedSize ( btn_size, btn_size );

                  connect ( btn_close, SIGNAL ( clicked() ),
                        &_balloon, SLOT ( close() ) );
            }


            _lbl_ballon_value = new Wdg::Label_Width ( );
            _lbl_ballon_value->set_min_text ( _balloon_value_mask.arg ( 100 ) );
            _lbl_ballon_value->setText ( _balloon_value_mask.arg ( _volume_permille ) );

            int hspace ( _lbl_ballon_value->fontMetrics().averageCharWidth() * 3 / 2 );
            QHBoxLayout * lay_txt ( new QHBoxLayout );
            lay_txt->setContentsMargins ( 0, 0, 0, 0 );
            lay_txt->addWidget ( _lbl_ballon_icon );
            lay_txt->addSpacing ( hspace );
            lay_txt->addWidget ( _lbl_ballon_value );
            lay_txt->addSpacing ( hspace );
            lay_txt->addWidget ( btn_close );

            QWidget * wdg_balloon ( new QWidget );
            wdg_balloon->setLayout ( lay_txt );
            _balloon.add_widget ( wdg_balloon );
      }

      {
            unsigned int len ( _lbl_ballon_icon->fontMetrics().height() * 5 / 2 );
            _pixmap_default = _icon_default.pixmap ( len, len );
            _pixmaps_volume[0] = _icons_volume[0].pixmap ( len, len );
            _pixmaps_volume[1] = _icons_volume[1].pixmap ( len, len );
            _pixmaps_volume[2] = _icons_volume[2].pixmap ( len, len );
            _pixmap_muted = _icon_muted.pixmap ( len, len );
      }

      update_icon();
}


void
Mini_Mixer::show_tray_icon (
      bool flag_n )
{
      _tray_icon.setVisible ( flag_n );
      if ( !flag_n ) {
            close_balloon();
      }
}


void
Mini_Mixer::set_ctl_address (
      const QString & addr_n )
{
      if ( addr_n != _ctl_address ) {
            _ctl_address = addr_n;
            reload_mixer();
      }
}


void
Mini_Mixer::set_elem_name (
      const QString & name_n )
{
      _mixer_changes = true;

      close_balloon();
      clear_mixer_elem();
      _mixer.set_elem_name ( name_n );
      update_mixer_elem();

      _mixer_changes = false;

      update_volume_permille();
      update_icon();
}


void
Mini_Mixer::set_wheel_degrees (
      unsigned int degrees_n )
{
      _wheel_degrees = ( degrees_n > 0 ) ? degrees_n : 1;
}


void
Mini_Mixer::set_show_balloon (
      bool flag_n )
{
      if ( _show_balloon != flag_n ) {
            _show_balloon = flag_n;
            if ( _show_balloon ) {
                  raise_balloon();
            } else {
                  close_balloon();
            }
      }
}


void
Mini_Mixer::set_balloon_lifetime (
      unsigned int ms_n )
{
      _balloon.set_duration_ms ( ms_n );
}


void
Mini_Mixer::reload_mixer ( )
{
      _mixer_changes = true;

      close_balloon();
      clear_mixer_elem();
      _mixer.close();
      _mixer.open ( _ctl_address );
      update_mixer_elem();

      _mixer_changes = false;

      update_volume_permille();
      update_icon();
}


void
Mini_Mixer::clear_mixer_elem ( )
{
      if ( _mx_elem != 0 ) {
            disconnect ( _mx_elem, 0, this, 0 );
      }
      _mx_elem = 0;
      _volume_muted = false;
      _volume_permille = 0;
}


void
Mini_Mixer::update_mixer_elem ( )
{
      for ( unsigned int ii=0; ii < _mixer.num_elems(); ++ii ) {
            if ( _mixer.elem ( ii )->has_volume ( 0 ) ) {
                  _mx_elem = _mixer.elem ( ii );
            }
      }

      if ( _mx_elem != 0 ) {
            connect ( _mx_elem, SIGNAL ( sig_values_changed() ),
                  this, SLOT ( mixer_values_changed() ) );
      }
}


void
Mini_Mixer::mixer_values_changed ( )
{
      if ( update_volume_permille() ) {
            raise_balloon();
      }
      update_icon();
}


void
Mini_Mixer::activation (
      QSystemTrayIcon::ActivationReason reason_n )
{
      //std::cout << "Mini_Mixer::activation " << reason_n << "\n";

      if ( reason_n == QSystemTrayIcon::Context ) {
            return;
      }

      if ( reason_n == QSystemTrayIcon::MiddleClick  ) {
            if ( _mx_elem != 0 ) {
                  if ( _mx_elem->has_switch ( 0 ) ) {
                        _mx_elem->invert_switches ( 0 );
                  }
            }
      } else {
            emit sig_activated();
      }
}


bool
Mini_Mixer::update_volume_permille ( )
{
      bool res ( false );

      bool muted ( _volume_muted );
      unsigned int perm ( _volume_permille );

      if ( !_mixer_changes && ( _mx_elem != 0 ) ) {
            unsigned long dist_current ( Wdg::integer_distance (
                  _mx_elem->volume_min ( 0 ), _mx_elem->volume ( 0, 0 ) ) );

            unsigned long dist_total ( Wdg::integer_distance (
                  _mx_elem->volume_min ( 0 ), _mx_elem->volume_max ( 0 ) ) );

            perm = Wdg::permille ( dist_current, dist_total );

            if ( _mx_elem->has_switch ( 0 ) ) {
                  muted = !_mx_elem->switch_state ( 0, 0 );
            }
      }

      if ( ( perm != _volume_permille ) || ( muted != _volume_muted ) ) {
            _volume_muted = muted;
            _volume_permille = perm;
            res = true;
      }

      return res;
}


void
Mini_Mixer::update_icon ( )
{
      QIcon * ico ( 0 );
      QPixmap * pxmap ( 0 );

      if ( _mx_elem != 0 ) {
            if ( _volume_muted ) {
                  ico = &_icon_muted;
                  pxmap = &_pixmap_muted;
            }

            if ( ( ico == 0 ) && ( _mx_elem->has_volume ( 0 ) ) ) {
                  if ( _volume_permille < 333 ) {
                        ico = &_icons_volume[0];
                        pxmap = &_pixmaps_volume[0];
                  } else if ( _volume_permille < 750 ) {
                        ico = &_icons_volume[1];
                        pxmap = &_pixmaps_volume[1];
                  } else {
                        ico = &_icons_volume[2];
                        pxmap = &_pixmaps_volume[2];
                  }
            }
      }

      if ( ico == 0 ) {
            ico = &_icon_default;
            pxmap = &_pixmap_default;
      }

      _lbl_ballon_icon->setPixmap ( *pxmap );
      _tray_icon.setIcon ( *ico );
}


void
Mini_Mixer::raise_balloon ( )
{
      if ( _tray_icon.isVisible() &&
            _tray_icon.isSystemTrayAvailable() &&
            _show_balloon )
      {
            _lbl_ballon_value->setText ( _balloon_value_mask.arg ( _volume_permille / 10 ) );
            _balloon.set_tray_icon_geometry ( _tray_icon.geometry() );
            _balloon.start_show();
      }
}


void
Mini_Mixer::close_balloon ( )
{
      _balloon.close();
}


void
Mini_Mixer::wheel_delta (
      int wheel_delta_n )
{
      if ( _mixer_changes || ( _mixer.num_elems() == 0 ) ) {
            return;
      }

      QSnd::Snd_Mixer_Simple_Elem * mx_elem ( _mixer.elem ( 0 ) );
      if ( !mx_elem->has_volume ( 0 ) ) {
            return;
      }

      const long vol_min ( mx_elem->volume_min ( 0 ) );
      const long vol_max ( mx_elem->volume_max ( 0 ) );
      long vol_old ( mx_elem->volume ( 0, 0 ) );

      long delta;
      {
            const double range ( double ( vol_max ) - double ( vol_min ) );
            double amount ( range / double ( _wheel_degrees ) );
            amount *= ( wheel_delta_n / 8.0 );
            if ( amount > 0 ) {
                  delta = std::ceil ( amount );
            } else {
                  delta = std::floor ( amount );
            }
      }
      if ( delta == 0 ) {
            if ( wheel_delta_n > 0 ) {
                  delta = 1;
            } else {
                  delta = -1;
            }
      }

      long vol ( vol_old );
      if ( delta > 0 ) {
            if ( ( vol_max - vol ) > delta ) {
                  vol += delta;
            } else {
                  vol = vol_max;
            }
      } else {
            if ( ( vol_min - vol ) < delta ) {
                  vol += delta;
            } else {
                  vol = vol_min;
            }
      }

      if ( vol != vol_old ) {
            mx_elem->set_volume_all ( 0, vol );
      }
}


bool
Mini_Mixer::eventFilter (
      QObject * watched_n,
      QEvent * event_n )
{
      bool res ( false );

      if ( watched_n == &_tray_icon ) {
            if ( event_n->type() == QEvent::Wheel ) {
                  QWheelEvent * wev ( dynamic_cast < QWheelEvent * > ( event_n ) );
                  if ( wev != 0 ) {
                        wheel_delta ( wev->delta() );
                  }
            }
      }

      return res;
}

Generated by  Doxygen 1.6.0   Back to index