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

mixer_switches.cpp

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

#include "mixer_switches.hpp"

#include <QHBoxLayout>
#include <QVBoxLayout>

#include <QCoreApplication>
#include <QEvent>
#include <QKeyEvent>
#include <QContextMenuEvent>
#include <QScrollBar>

#include "wdg/fill_columns_layout.hpp"

#include <iostream>


namespace QSnd
{


Mixer_Switches::Mixer_Switches (
      QWidget * parent_n ) :
QWidget ( parent_n ),
_mixer ( 0 ),
_separation_requested ( false ),
_act_toggle_joined ( this )
{
      _switches_area.setFrameStyle ( QFrame::NoFrame );

      switches_pad()->hide();
      switches_pad()->installEventFilter ( this );

      connect ( switches_pad(), SIGNAL ( sig_focus_changed() ),
            this, SLOT ( update_focus_proxies() ) );


      // Actions
      //: "c" is an abbreviation for "channel"
      _act_toggle_joined.setShortcut ( QKeySequence ( tr ( "c" ) ) );
      _act_toggle_joined.setIcon ( QIcon::fromTheme ( "object-flip-horizontal" ) );
      _act_toggle_joined.setIconVisibleInMenu ( true );

      _act_str_toggle_joined[0] = tr ( "Split &channels" );
      _act_str_toggle_joined[1] = tr ( "Join &channels" );

      connect ( &_act_toggle_joined, SIGNAL ( triggered ( bool ) ),
            this, SLOT ( action_toggle_joined() ) );

      // Context menu
      _cmenu.addAction ( &_act_toggle_joined );


      // Center widget layout
      {
            QVBoxLayout * lay_vbox = new QVBoxLayout();
            lay_vbox->setContentsMargins ( 0, 0, 0, 0 );
            lay_vbox->addWidget ( &_switches_area );
            setLayout ( lay_vbox );
      }
}


Mixer_Switches::~Mixer_Switches ( )
{
      set_mixer_simple ( 0 );
}


QSize
Mixer_Switches::minimumSizeHint ( ) const
{
      ensurePolished();

      const Wdg::Fill_Columns_Layout * lay_cols (
            dynamic_cast < const Wdg::Fill_Columns_Layout * > ( switches_pad()->layout() ) );

      QSize res ( 0, 0 );

      {
            const unsigned int num_vis ( num_visible() );

            int min_rows ( 4 );
            if ( num_vis < 6 ) {
                  min_rows = 3;
            }
            if ( num_vis < 2 ) {
                  min_rows = 2;
            }
            res.rheight() += switches_pad()->fontMetrics().height() * min_rows;

            if ( lay_cols != 0 ) {
                  res.rheight() += lay_cols->vertical_spacing_default() * ( min_rows - 1 );
            }
      }
      if ( lay_cols != 0 ) {
            QMargins mgs ( lay_cols->contentsMargins() );
            res.rwidth() += mgs.left() + mgs.right();
            res.rheight() += mgs.top() + mgs.bottom();
      }
      {
            QSize wdg_msh ( switches_pad()->minimumSizeHint() );
            res.rwidth() += wdg_msh.width();
      }

      {
            QScrollBar * vsbar ( _switches_area.verticalScrollBar() );
            if ( vsbar != 0 ) {
                  QSize sb_msh ( vsbar->minimumSizeHint() );
                  res.rwidth() += sb_msh.width();

                  if ( res.height() < sb_msh.height() ) {
                        res.setHeight ( sb_msh.height() );
                  }
            }
      }

      // Margins
      {
            QMargins mgs ( contentsMargins() );
            res.rwidth() += mgs.left() + mgs.right();
            res.rheight() += mgs.top() + mgs.bottom();
      }

      return res;
}


QSize
Mixer_Switches::sizeHint ( ) const
{
      return minimumSizeHint();
}



void
Mixer_Switches::set_mixer_simple (
      Snd_Mixer_Simple * mixer_n  )
{
      if ( mixer_n == _mixer ) {
            return;
      }

      _cmenu.close();

      if ( _mixer != 0 ) {
            disconnect ( _mixer, 0, this, 0 );

            show_visible_proxies_sets ( false );
            clear_proxies_groups();
      }

      _mixer = mixer_n;

      if ( _mixer != 0 ) {

            create_proxies_groups();

            rebuild_visible_proxies_list();

            show_visible_proxies_sets ( true );
      }
}


void
Mixer_Switches::set_mixer_settings (
      const Simple_Mixer_Settings & cfg_n )
{
      if ( _settings != cfg_n ) {

            _cmenu.close();

            show_visible_proxies_sets ( false );

            _settings = cfg_n;

            rebuild_visible_proxies_list();

            show_visible_proxies_sets ( true );
      }
}


void
Mixer_Switches::show_visible_proxies_sets (
      bool flag_n )
{
      if ( flag_n ) {
            if ( _proxies_groups_visible.size() > 0 ) {
                  switches_pad()->set_proxies_groups ( &_proxies_groups_visible );
                  _switches_area.set_widget ( switches_pad() );

                  switches_pad()->setAutoFillBackground ( false );
                  switches_pad()->show();
            }
            updateGeometry();
      } else {
            if ( _proxies_groups_visible.size() > 0 ) {
                  switches_pad()->hide();
                  _switches_area.take_widget();
                  switches_pad()->set_proxies_groups ( 0 );
            }
      }
}


void
Mixer_Switches::clear_proxies_groups ( )
{
      for ( int ii=0; ii < _proxies_groups.size(); ++ii ) {
            delete _proxies_groups[ii];
      }
      _proxies_groups.clear();
      _proxies_groups_visible.clear();
}


void
Mixer_Switches::create_proxies_groups ( )
{
      if ( _mixer == 0 ) {
            return;
      }

      //std::cout << "Mixer_Switches::init_widgets\n";

      QString ttip;

      for ( unsigned int ii=0; ii < _mixer->num_elems(); ++ii ) {
            Snd_Mixer_Simple_Elem * qsme ( _mixer->elem ( ii ) );

            // Types means either enum or switch
            for ( unsigned int itype=0; itype < 2; ++itype ) {
                  for ( unsigned int snd_dir=0; snd_dir < 2; ++snd_dir ) {
                        if ( qsme->has_volume( snd_dir ) ) {
                              continue;
                        }

                        bool cr_enum   ( itype == 0 );
                        bool cr_switch ( itype == 1 );

                        if ( ( cr_enum && qsme->has_enum ( snd_dir ) ) ||
                              ( cr_switch && qsme->has_switch ( snd_dir ) ) )
                        {
                              Mixer_Switches_Proxies_Group * mspg (
                                    new Mixer_Switches_Proxies_Group ( this ) );
                              mspg->set_mixer_simple_elem ( qsme );
                              mspg->set_snd_dir ( snd_dir );
                              mspg->set_group_name ( qsme->display_name() );
                              mspg->set_is_enum ( cr_enum );
                              mspg->set_is_switch ( cr_switch );

                              {
                                    ttip = "<div><b>";
                                    ttip += mspg->group_name();
                                    ttip += "</b></div>\n";
                                    mspg->set_tool_tip ( ttip );
                              }

                              if ( mspg->should_be_separated() ) {
                                    setup_proxies_group_separate ( mspg );
                              } else {
                                    setup_proxies_group_joined ( mspg );
                              }

                              if ( mspg->num_proxies() > 0 ) {
                                    _proxies_groups.append ( mspg );
                              } else {
                                    delete mspg;
                              }
                        }
                  }
            }

      }

}


void
Mixer_Switches::setup_proxies_group_joined (
      Mixer_Switches_Proxies_Group * mspg_n )
{
      const Snd_Mixer_Simple_Elem * qsme ( mspg_n->mixer_simple_elem() );
      const unsigned int snd_dir ( mspg_n->snd_dir() );

      mspg_n->clear_proxies();
      mspg_n->set_is_joined ( true );

      unsigned int num_channels ( 0 );
      if ( mspg_n->is_switch() ) {
            num_channels = qsme->num_switch_channels ( snd_dir );
      } else if ( mspg_n->is_enum() ) {
            num_channels = qsme->num_enum_channels ( snd_dir );
      }
      if ( num_channels > 0 ) {
            Wdg::Switches_Pad_Proxy * msp (
                  create_proxy ( mspg_n, 0 ) );

            if ( msp != 0 ) {
                  mspg_n->append_proxy ( msp );
            }
      }

      mspg_n->update_mixer_values();
}


void
Mixer_Switches::setup_proxies_group_separate (
      Mixer_Switches_Proxies_Group * mspg_n )
{
      const Snd_Mixer_Simple_Elem * qsme ( mspg_n->mixer_simple_elem() );
      const unsigned int snd_dir ( mspg_n->snd_dir() );

      mspg_n->clear_proxies();
      mspg_n->set_is_joined ( false );

      unsigned int num_channels ( 0 );
      if ( mspg_n->is_switch() ) {
            num_channels = qsme->num_switch_channels ( snd_dir );
      } else if ( mspg_n->is_enum() ) {
            num_channels = qsme->num_enum_channels ( snd_dir );
      }

      for ( unsigned int ii=0; ii < num_channels; ++ii ) {
            Wdg::Switches_Pad_Proxy * spp ( create_proxy ( mspg_n, ii ) );
            if ( spp != 0 ) {
                  mspg_n->append_proxy ( spp );
            }
      }

      mspg_n->update_mixer_values();
}


Wdg::Switches_Pad_Proxy *
Mixer_Switches::create_proxy (
      Mixer_Switches_Proxies_Group * mspg_n,
      int channel_idx_n )
{
      Snd_Mixer_Simple_Elem * qsme ( mspg_n->mixer_simple_elem() );
      const unsigned int snd_dir ( mspg_n->snd_dir() );

      QString iname;
      if ( mspg_n->is_joined() ) {
            iname = mspg_n->group_name();
      } else {
            iname = tr ( "%1 (%2)" );
            iname = iname.arg ( QCoreApplication::translate (
                  "ALSA::Channel_Name",
                  qsme->channel_name ( snd_dir, channel_idx_n ) ) );
            iname = iname.arg ( qsme->channel ( snd_dir, channel_idx_n ) );
      }

      QString ttip;
      ttip += "<div><b>";
      ttip += mspg_n->group_name();
      ttip += "</b></div>\n";

      ttip += "<div>";
      if ( snd_dir == 0 ) {
            if ( mspg_n->is_enum() ) {
                  ttip += tr ( "Playback selection" );
            } else {
                  ttip += tr ( "Playback switch" );
            }
      } else {
            if ( mspg_n->is_enum() ) {
                  ttip += tr ( "Capture selection" );
            } else {
                  ttip += tr ( "Capture switch" );
            }
      }
      ttip += "</div>\n";

      if ( !mspg_n->is_joined() ) {
            ttip += "<div>";
            ttip += iname;
            ttip += "</div>";
      }

      Wdg::Switches_Pad_Proxy * spp ( 0 );

      if ( mspg_n->is_enum() ) {
            Mixer_Switches_Proxy_Enum * msp (
                  new Mixer_Switches_Proxy_Enum ( mspg_n ) );

            msp->set_mixer_simple_elem ( qsme );
            msp->set_snd_dir ( snd_dir );
            msp->set_is_joined ( mspg_n->is_joined() );
            msp->set_channel_idx ( channel_idx_n );
            msp->set_enum_num_items ( qsme->enum_item_names().size() );
            spp = msp;
      } else if ( mspg_n->is_switch() ) {
            Mixer_Switches_Proxy_Switch * msp (
                  new Mixer_Switches_Proxy_Switch ( mspg_n ) );

            msp->set_mixer_simple_elem ( qsme );
            msp->set_snd_dir ( snd_dir );
            msp->set_is_joined ( mspg_n->is_joined() );
            msp->set_channel_idx ( channel_idx_n );
            spp = msp;
      }


      if ( spp != 0 ) {
            spp->set_item_name ( iname );
            spp->set_tool_tip ( ttip );

            // Style info
            Wdg::Switches_Pad_Proxy_Style * sinfo (
                  new Wdg::Switches_Pad_Proxy_Style ( snd_dir ) );
            spp->set_style_info ( sinfo );
      }

      return spp;
}


bool
Mixer_Switches::should_be_visible (
      const Mixer_Switches_Proxies_Group * mspg_n ) const
{
      const Snd_Mixer_Simple_Elem * qsme ( mspg_n->mixer_simple_elem() );
      const unsigned int snd_dir ( mspg_n->snd_dir() % 2 );
      return ( qsme->is_active() && _settings.show_stream[snd_dir] );
}


void
Mixer_Switches::rebuild_visible_proxies_list ( )
{
      _proxies_groups_visible.clear();

      for ( int ii=0; ii < _proxies_groups.size(); ++ii ) {
            Mixer_Switches_Proxies_Group * mspg ( _proxies_groups[ii] );
            mspg->set_is_visible ( should_be_visible ( mspg ) );
            if ( mspg->is_visible() ) {
                  // Separate on demand
                  if ( mspg->needs_separation() ) {
                        separate_proxies_group ( mspg );
                  }
                  _proxies_groups_visible.append ( mspg );
            }
      }
}


void
Mixer_Switches::update_focus_proxies ( )
{
      _focus_proxies_group = 0;
      _focus_proxy_column = 0;
      if ( switches_pad()->focus_info().has_focus ) {
            // Find focus proxies_group
            const int idx ( switches_pad()->focus_info().group_idx );
            if ( idx < _proxies_groups_visible.size() ) {
                  _focus_proxies_group = proxies_group_visible ( idx );
                  _focus_proxy_column = switches_pad()->focus_info().column_idx;
            }
      }

      if ( _focus_proxies_group != 0 ) {
            _act_proxies_group = _focus_proxies_group;
            _act_proxy_column = _focus_proxy_column;
      }
}


void
Mixer_Switches::acquire_ui_state (
      Mixer_State & state_n )
{
      if ( _focus_proxies_group != 0 ) {
            Mixer_Switches_Proxies_Group * mspg ( _focus_proxies_group );
            state_n.focus_proxy.set_group_name ( mspg->group_name() );
            state_n.focus_proxy.set_snd_dir ( mspg->snd_dir() );
            state_n.focus_proxy.set_proxy_idx ( mspg->focus_proxy() );
      }

      if ( _act_proxies_group != 0 ) {
            Mixer_Switches_Proxies_Group * mspg ( _act_proxies_group );
            state_n.action_proxy.set_group_name ( mspg->group_name() );
            state_n.action_proxy.set_snd_dir ( mspg->snd_dir() );
            state_n.action_proxy.set_proxy_idx ( mspg->focus_proxy() );
      }
}


void
Mixer_Switches::restore_ui_state (
      const Mixer_State & state_n )
{
      {
            Mixer_Switches_Proxies_Group * mspg (
                  find_visible_proxy ( state_n.action_proxy ) );
            _act_proxies_group = mspg;
            _act_proxy_column = state_n.action_proxy.proxy_idx();
      }

      // Setting the focus may override _act_proxies_group
      // so set it afterwards
      {
            Mixer_Switches_Proxies_Group * mspg (
                  find_visible_proxy ( state_n.focus_proxy ) );
            if ( mspg != 0 ) {
                  switches_pad()->set_focus_proxy (
                        mspg->group_index(),
                        state_n.focus_proxy.proxy_idx() );
            }
      }

      if ( _cmenu.isVisible() ) {
            context_menu_update();
      }
}


Mixer_Switches_Proxies_Group *
Mixer_Switches::find_visible_proxy (
      const Mixer_State_Proxy & prox_id_n )
{
      Mixer_Switches_Proxies_Group * mspg ( 0 );

      if ( !prox_id_n.is_clear() ) {
            for ( int ii=0; ii < _proxies_groups_visible.size(); ++ii ) {
                  Mixer_Switches_Proxies_Group * mspg_cur (
                        proxies_group_visible ( ii ) );
                  if (
                        ( mspg_cur->group_name() == prox_id_n.group_name() ) &&
                        ( mspg_cur->snd_dir() == prox_id_n.snd_dir() ) )
                  {
                        mspg = mspg_cur;
                        break;
                  }
            }
      }

      return mspg;
}



void
Mixer_Switches::action_toggle_joined ( )
{
      //std::cout << "Mixer_Switches::action_toggle_joined" << "\n";

      if ( _act_proxies_group != 0 ) {
            toggle_joined_separated ( _act_proxies_group );
      }
}


void
Mixer_Switches::toggle_joined_separated (
      Mixer_Switches_Proxies_Group * mspg_n )
{
      if ( mspg_n == 0 ) {
            return;
      }

      if ( !mspg_n->can_be_separated() ) {
            return;
      }

      Mixer_State ui_state;
      acquire_ui_state ( ui_state );
      show_visible_proxies_sets ( false );

      if ( mspg_n->is_joined() ) {
            separate_proxies_group ( mspg_n );
      } else {
            join_proxies_group ( mspg_n );
      }

      show_visible_proxies_sets ( true );
      restore_ui_state ( ui_state );
}


void
Mixer_Switches::join_proxies_group (
      Mixer_Switches_Proxies_Group * mspg_n )
{
      if ( !mspg_n->is_joined() ) {
            Snd_Mixer_Simple_Elem * qsme ( mspg_n->mixer_simple_elem() );
            qsme->level_switches ( mspg_n->snd_dir() );

            setup_proxies_group_joined ( mspg_n );
            if ( _cmenu.isVisible() ) {
                  context_menu_update();
            }
      }
}


void
Mixer_Switches::separate_proxies_group (
      Mixer_Switches_Proxies_Group * mspg_n )
{
      if ( mspg_n->is_joined() && mspg_n->can_be_separated() ) {
            setup_proxies_group_separate ( mspg_n );
            if ( _cmenu.isVisible() ) {
                  context_menu_update();
            }
      }
}


void
Mixer_Switches::separate_where_requested ( )
{
      bool visible_request ( false );
      for ( int ii=0; ii < _proxies_groups_visible.size(); ++ii ) {
            Mixer_Switches_Proxies_Group * mspg ( proxies_group_visible ( ii ) );
            if ( mspg->separation_request() ) {
                  visible_request = true;
                  break;
            }
      }

      if ( visible_request ) {
            Mixer_State ui_state;
            acquire_ui_state ( ui_state );
            show_visible_proxies_sets ( false );

            for ( int ii=0; ii < _proxies_groups_visible.size(); ++ii ) {
                  Mixer_Switches_Proxies_Group * mspg ( proxies_group_visible ( ii ) );
                  if ( mspg->separation_request() ) {
                        mspg->set_separation_request ( false );
                        separate_proxies_group ( mspg );
                  }
            }

            show_visible_proxies_sets ( true );
            restore_ui_state ( ui_state );
      }
}


bool
Mixer_Switches::context_menu_start (
      const QPoint & pos_n )
{
      bool res ( false );

      if ( !_cmenu.isVisible() &&
            ( _focus_proxies_group != 0 ) &&
            ( _act_proxies_group != 0 ) )
      {
            if ( context_menu_update() > 0 ) {
                  _act_proxies_group->set_notify_value_change ( true );

                  _cmenu.setTitle ( _act_proxies_group->group_name() );
                  _cmenu.popup ( pos_n );
                  res = true;
            }
      }

      return res;
}


void
Mixer_Switches::context_menu_cleanup_behind ( )
{
      if ( _act_proxies_group != 0 ) {
            _act_proxies_group->set_notify_value_change ( false );
      }
}


unsigned int
Mixer_Switches::context_menu_update ( )
{
      unsigned int act_vis ( 0 );

      Mixer_Switches_Proxies_Group * mspg ( _act_proxies_group );

      if ( mspg == 0 ) {
            _cmenu.close();
            return act_vis;
      }

      const Snd_Mixer_Simple_Elem * qsme ( mspg->mixer_simple_elem() );

      // Split/Join and level channels
      {
            const bool vis_separate (
                  qsme->num_channels ( mspg->snd_dir() ) > 1 );

            _act_toggle_joined.setVisible ( vis_separate );
            if ( vis_separate ) {
                  ++act_vis;

                  unsigned int idx ( 0 );
                  if ( mspg->num_proxies() > 1 ) {
                        ++idx;
                  }
                  _act_toggle_joined.setText ( _act_str_toggle_joined[idx] );
            }
      }

      if ( act_vis == 0 ) {
            _cmenu.close();
      }

      return act_vis;
}


bool
Mixer_Switches::eventFilter (
      QObject * watched_n,
      QEvent * event_n )
{
      bool filtered ( false );

      if ( watched_n == switches_pad() ) {
            if ( event_n->type() == QEvent::KeyPress ) {
                  QKeyEvent * ev_key ( dynamic_cast < QKeyEvent * > ( event_n ) );
                  if ( ev_key != 0 ) {
                        filtered = true;
                        QKeySequence key_seq ( ev_key->key() );
                        if ( _act_toggle_joined.shortcut() == key_seq ) {
                              _act_toggle_joined.trigger();
                        } else {
                              filtered = false;
                        }
                  }
            } else if ( event_n->type() == QEvent::ContextMenu ) {
                  //std::cout << "Mixer_Switches::eventFilter: QContextMenuEvent\n";
                  QContextMenuEvent * ev_cmenu (
                        dynamic_cast < QContextMenuEvent * > ( event_n ) );
                  if ( ev_cmenu != 0  ) {
                        if ( context_menu_start ( ev_cmenu->globalPos() ) ) {
                              filtered = true;
                        }
                  }
            }
      }

      return filtered;
}



bool
Mixer_Switches::event (
      QEvent * event_n )
{
      bool res ( true );

      if ( event_n->type() == event_type_separation_request ) {

            if ( !_separation_requested ) {
                  _separation_requested = true;
                  QCoreApplication::postEvent (
                        this, new QEvent ( event_type_separation ) );
            }

      } else if ( event_n->type() == event_type_separation ) {

            _separation_requested = false;
            separate_where_requested();

      } else if ( event_n->type() == event_type_values_changed ) {

            context_menu_update();

      } else {

            res = QWidget::event ( event_n );

      }

      return res;
}



} // End of namespace

Generated by  Doxygen 1.6.0   Back to index