ardour
panner_ui.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2004 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include <limits.h>
20 
21 #include <gtkmm2ext/utils.h>
22 
23 #include "pbd/fastlog.h"
24 
25 #include "ardour/pannable.h"
26 #include "ardour/panner.h"
27 #include "ardour/panner_shell.h"
28 #include "ardour/session.h"
29 
30 #include "ardour_ui.h"
31 #include "panner_ui.h"
32 #include "panner2d.h"
33 #include "gui_thread.h"
34 #include "stereo_panner.h"
35 #include "timers.h"
36 #include "mono_panner.h"
37 
38 #include "i18n.h"
39 
40 using namespace std;
41 using namespace ARDOUR;
42 using namespace PBD;
43 using namespace Gtkmm2ext;
44 using namespace Gtk;
45 
47  : _current_nouts (-1)
48  , _current_nins (-1)
49  , _current_uri ("")
50  , _send_mode (false)
51  , pan_automation_style_button ("")
52  , pan_automation_state_button ("")
53  , _panner_list()
54 {
55  set_session (s);
56 
57  ignore_toggle = false;
58  pan_menu = 0;
59  pan_astate_menu = 0;
60  pan_astyle_menu = 0;
61  in_pan_update = false;
62  _stereo_panner = 0;
63  _mono_panner = 0;
64  _ignore_width_change = false;
66 
67  pan_automation_style_button.set_name ("MixerAutomationModeButton");
68  pan_automation_state_button.set_name ("MixerAutomationPlaybackButton");
69 
70  ARDOUR_UI::instance()->set_tip (pan_automation_state_button, _("Pan automation mode"));
71  ARDOUR_UI::instance()->set_tip (pan_automation_style_button, _("Pan automation type"));
72 
73  //set_size_request_to_display_given_text (pan_automation_state_button, X_("O"), 2, 2);
74  //set_size_request_to_display_given_text (pan_automation_style_button, X_("0"), 2, 2);
75 
76  pan_automation_style_button.unset_flags (Gtk::CAN_FOCUS);
77  pan_automation_state_button.unset_flags (Gtk::CAN_FOCUS);
78 
79  pan_automation_style_button.signal_button_press_event().connect (sigc::mem_fun(*this, &PannerUI::pan_automation_style_button_event), false);
80  pan_automation_state_button.signal_button_press_event().connect (sigc::mem_fun(*this, &PannerUI::pan_automation_state_button_event), false);
81 
82  pan_vbox.set_spacing (2);
83  pack_start (pan_vbox, true, true);
84 
85  twod_panner = 0;
86  big_window = 0;
87 
89 }
90 
91 void
93 {
94  /* note that the panshell might not change here (i.e. ps == _panshell)
95  */
96 
98 
99  delete pan_astyle_menu;
100  pan_astyle_menu = 0;
101 
102  delete pan_astate_menu;
103  pan_astate_menu = 0;
104 
105  _panshell = ps;
106  _panner = p;
107 
108  delete twod_panner;
109  twod_panner = 0;
110 
111  delete _stereo_panner;
112  _stereo_panner = 0;
113 
114  delete _mono_panner;
115  _mono_panner = 0;
116 
117  if (!_panner) {
118  return;
119  }
120 
121  _panshell->Changed.connect (connections, invalidator (*this), boost::bind (&PannerUI::panshell_changed, this), gui_context());
122 
123  /* new panner object, force complete reset of panner GUI
124  */
125 
126  _current_nouts = 0;
127  _current_nins = 0;
128 
129  setup_pan ();
132 }
133 
134 void
136 {
137  using namespace Menu_Helpers;
138 
139  if (pan_astate_menu == 0) {
140  pan_astate_menu = new Menu;
141  pan_astate_menu->set_name ("ArdourContextMenu");
142  } else {
143  pan_astate_menu->items().clear ();
144  }
145 
149  pan_astate_menu->items().push_back (MenuElem (S_("Automation|Manual"), sigc::bind (
150  sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
151  (AutoState) ARDOUR::Off)));
152  pan_astate_menu->items().push_back (MenuElem (_("Play"), sigc::bind (
153  sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
154  (AutoState) Play)));
155  pan_astate_menu->items().push_back (MenuElem (_("Write"), sigc::bind (
156  sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
157  (AutoState) Write)));
158  pan_astate_menu->items().push_back (MenuElem (_("Touch"), sigc::bind (
159  sigc::mem_fun (_panner.get(), &Panner::set_automation_state),
160  (AutoState) Touch)));
161 
162 }
163 
164 void
166 {
167  using namespace Menu_Helpers;
168 
169  if (pan_astyle_menu == 0) {
170  pan_astyle_menu = new Menu;
171  pan_astyle_menu->set_name ("ArdourContextMenu");
172  } else {
173  pan_astyle_menu->items().clear();
174  }
175 
176  pan_astyle_menu->items().push_back (MenuElem (_("Trim")));
177  pan_astyle_menu->items().push_back (MenuElem (_("Abs")));
178 }
179 
180 void
182 {
183  HBox::on_size_allocate (a);
184 }
185 
186 void
188 {
189  _width = w;
190 }
191 
193 {
194  delete twod_panner;
195  delete big_window;
196  delete pan_menu;
197  delete pan_astyle_menu;
198  delete pan_astate_menu;
199  delete _stereo_panner;
200  delete _mono_panner;
201 }
202 
203 void
205 {
207  setup_pan ();
208 }
209 
210 void
212 {
213  int const nouts = _panner ? _panner->out().n_audio() : -1;
214  int const nins = _panner ? _panner->in().n_audio() : -1;
215 
216  if (nouts == _current_nouts
217  && nins == _current_nins
219  )
220  {
221  return;
222  }
223 
224  _current_nins = nins;
225  _current_nouts = nouts;
227 
229 
230  delete twod_panner;
231  twod_panner = 0;
232  delete _stereo_panner;
233  _stereo_panner = 0;
234  delete _mono_panner;
235  _mono_panner = 0;
236 
237  if (!_panner) {
238  delete big_window;
239  big_window = 0;
240  return;
241  }
242 
243  const float scale = std::max (1.f, ARDOUR_UI::ui_scale);
244 
245  if (_current_uri == "http://ardour.org/plugin/panner_2in2out#ui")
246  {
247  delete big_window;
248  big_window = 0;
249 
251 
253  _stereo_panner->set_size_request (-1, 5 * ceilf(7.f * scale));
255  pan_vbox.pack_start (*_stereo_panner, false, false);
256 
258 
259  ac = pannable->pan_azimuth_control;
260  _stereo_panner->StartPositionGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch),
262  _stereo_panner->StopPositionGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch),
264 
265  ac = pannable->pan_width_control;
266  _stereo_panner->StartWidthGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch),
268  _stereo_panner->StopWidthGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch),
270  _stereo_panner->signal_button_release_event().connect (sigc::mem_fun(*this, &PannerUI::pan_button_event));
271  }
272  else if (_current_uri == "http://ardour.org/plugin/panner_1in2out#ui"
273  || _current_uri == "http://ardour.org/plugin/panner_balance#ui")
274  {
275  delete big_window;
276  big_window = 0;
279 
281 
282  _mono_panner->StartGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::start_touch),
284  _mono_panner->StopGesture.connect (sigc::bind (sigc::mem_fun (*this, &PannerUI::stop_touch),
286 
287  _mono_panner->signal_button_release_event().connect (sigc::mem_fun(*this, &PannerUI::pan_button_event));
288 
289  _mono_panner->set_size_request (-1, 5 * ceilf(7.f * scale));
291 
293  pan_vbox.pack_start (*_mono_panner, false, false);
294  }
295  else if (_current_uri == "http://ardour.org/plugin/panner_vbap#ui")
296  {
297  if (!twod_panner) {
298  twod_panner = new Panner2d (_panshell, rintf(61.f * scale));
299  twod_panner->set_name ("MixerPanZone");
300  twod_panner->show ();
301  twod_panner->signal_button_press_event().connect (sigc::mem_fun(*this, &PannerUI::pan_button_event), false);
302  }
303 
305  twod_panner->reset (nins);
306  if (big_window) {
307  big_window->reset (nins);
308  }
309  twod_panner->set_size_request (-1, rintf(61.f * scale));
311 
312  /* and finally, add it to the panner frame */
313 
314  pan_vbox.pack_start (*twod_panner, false, false);
315  }
316  else
317  {
318  /* stick something into the panning viewport so that it redraws */
319  EventBox* eb = manage (new EventBox());
320  pan_vbox.pack_start (*eb, false, false);
321 
322  delete big_window;
323  big_window = 0;
324  }
325 
326  pan_vbox.show_all ();
327 }
328 
329 void
331 {
332  if (_stereo_panner) {
334  } else if (_mono_panner) {
336  } else if (twod_panner) {
338  }
339  _send_mode = onoff;
340 }
341 
342 void
344 {
345  boost::shared_ptr<AutomationControl> ac = wac.lock();
346  if (!ac) {
347  return;
348  }
349  ac->start_touch (ac->session().transport_frame());
350 }
351 
352 void
354 {
355  boost::shared_ptr<AutomationControl> ac = wac.lock();
356  if (!ac) {
357  return;
358  }
359  ac->stop_touch (false, ac->session().transport_frame());
360 }
361 
362 bool
363 PannerUI::pan_button_event (GdkEventButton* ev)
364 {
365  switch (ev->button) {
366  case 1:
367  if (twod_panner && ev->type == GDK_2BUTTON_PRESS) {
368  if (!big_window) {
370  }
371  big_window->show ();
372  return true;
373  }
374  break;
375 
376  case 3:
377  if (pan_menu == 0) {
378  pan_menu = manage (new Menu);
379  pan_menu->set_name ("ArdourContextMenu");
380  }
381  build_pan_menu ();
382  pan_menu->popup (1, ev->time);
383  return true;
384  break;
385  default:
386  return false;
387  }
388 
389  return false; // what's wrong with gcc?
390 }
391 
392 void
394 {
395  using namespace Menu_Helpers;
396  MenuList& items (pan_menu->items());
397 
398  items.clear ();
399 
400  items.push_back (CheckMenuElem (_("Bypass"), sigc::mem_fun(*this, &PannerUI::pan_bypass_toggle)));
401  bypass_menu_item = static_cast<Gtk::CheckMenuItem*> (&items.back());
402 
403  /* set state first, connect second */
404 
405  bypass_menu_item->set_active (_panshell->bypassed());
406  bypass_menu_item->signal_toggled().connect (sigc::mem_fun(*this, &PannerUI::pan_bypass_toggle));
407 
408  if (!_panshell->bypassed()) {
409  items.push_back (MenuElem (_("Reset"), sigc::mem_fun (*this, &PannerUI::pan_reset)));
410  items.push_back (MenuElem (_("Edit..."), sigc::mem_fun (*this, &PannerUI::pan_edit)));
411  }
412 
413  if (_panner_list.size() > 1 && !_panshell->bypassed()) {
414  RadioMenuItem::Group group;
415  items.push_back (SeparatorElem());
416 
418  for (std::map<std::string,std::string>::const_iterator p = _panner_list.begin(); p != _panner_list.end(); ++p) {
419  items.push_back (RadioMenuElem (group, p->second,
420  sigc::bind(sigc::mem_fun (*this, &PannerUI::pan_set_custom_type), p->first)));
421  RadioMenuItem* i = dynamic_cast<RadioMenuItem *> (&items.back ());
422  i->set_active (_panshell->current_panner_uri() == p->first);
423  }
424  _suspend_menu_callbacks = false;
425  }
426 }
427 
428 void
430 {
431  if (bypass_menu_item && (_panshell->bypassed() != bypass_menu_item->get_active())) {
433  }
434 }
435 
436 void
438 {
439  if (_panshell->bypassed()) {
440  return;
441  }
442  if (_mono_panner) {
443  _mono_panner->edit ();
444  } else if (_stereo_panner) {
445  _stereo_panner->edit ();
446  } else if (twod_panner) {
447  if (!big_window) {
449  }
450  big_window->show ();
451  }
452 }
453 
454 void
456 {
457  if (_panshell->bypassed()) {
458  return;
459  }
460  _panner->reset ();
461 }
462 
463 void
464 PannerUI::pan_set_custom_type (std::string uri) {
465  if (_suspend_menu_callbacks) return;
467 }
468 
469 void
471 {
472  if (_stereo_panner) {
473  _stereo_panner->queue_draw ();
474  } else if (_mono_panner) {
475  _mono_panner->queue_draw ();
476  } else if (twod_panner) {
477  twod_panner->queue_draw ();
478  }
479 }
480 
481 void
483 {
484  bool const sensitive = !(_panner->pannable()->automation_state() & Play);
485 
486  pan_vbox.set_sensitive (sensitive);
487 
488  if (big_window) {
489  big_window->set_sensitive (sensitive);
490  }
491 }
492 
493 gint
495 {
496  using namespace Menu_Helpers;
497 
498  if (ev->type == GDK_BUTTON_RELEASE) {
499  return TRUE;
500  }
501 
502  switch (ev->button) {
503  case 1:
504  if (pan_astate_menu == 0) {
506  }
507  pan_astate_menu->popup (1, ev->time);
508  break;
509  default:
510  break;
511  }
512 
513  return TRUE;
514 }
515 
516 gint
518 {
519  if (ev->type == GDK_BUTTON_RELEASE) {
520  return TRUE;
521  }
522 
523  switch (ev->button) {
524  case 1:
525  if (pan_astyle_menu == 0) {
527  }
528  pan_astyle_menu->popup (1, ev->time);
529  break;
530  default:
531  break;
532  }
533  return TRUE;
534 }
535 
536 void
538 {
540 
541  switch (_width) {
542  case Wide:
544  break;
545  case Narrow:
547  break;
548  }
549 }
550 
551 void
553 {
555 
556  switch (_width) {
557  case Wide:
558  pan_automation_state_button.set_label (astate_string(pannable->automation_state()));
559  break;
560  case Narrow:
561  pan_automation_state_button.set_label (short_astate_string(pannable->automation_state()));
562  break;
563  }
564 
565  bool x = (pannable->automation_state() != ARDOUR::Off);
566 
567  if (pan_automation_state_button.get_active() != x) {
568  ignore_toggle = true;
569  pan_automation_state_button.set_active (x);
570  ignore_toggle = false;
571  }
572 
574 
575  /* start watching automation so that things move */
576 
577  pan_watching.disconnect();
578 
579  if (x) {
581  }
582 }
583 
584 string
586 {
587  return _astate_string (state, false);
588 }
589 
590 string
592 {
593  return _astate_string (state, true);
594 }
595 
596 string
598 {
599  string sstr;
600 
601  switch (state) {
602  case ARDOUR::Off:
603  sstr = (shrt ? "M" : S_("Manual|M"));
604  break;
605  case Play:
606  sstr = (shrt ? "P" : S_("Play|P"));
607  break;
608  case Touch:
609  sstr = (shrt ? "T" : S_("Touch|T"));
610  break;
611  case Write:
612  sstr = (shrt ? "W" : S_("Write|W"));
613  break;
614  }
615 
616  return sstr;
617 }
618 
619 string
621 {
622  return _astyle_string (style, false);
623 }
624 
625 string
627 {
628  return _astyle_string (style, true);
629 }
630 
631 string
633 {
634  if (style & Trim) {
635  return _("Trim");
636  } else {
637  /* XXX it might different in different languages */
638 
639  return (shrt ? _("Abs") : _("Abs"));
640  }
641 }
642 
643 void
645 {
646 }
647 
648 void
650 {
651 }
652 
653 void
655 {
656 }
657 
658 void
660 {
661 }
662 
663 void
664 PannerUI::set_available_panners(std::map<std::string,std::string> p)
665 {
666  _panner_list = p;
667 }
void build_pan_menu()
Definition: panner_ui.cc:393
void pan_bypass_toggle()
Definition: panner_ui.cc:429
int _current_nouts
Definition: panner_ui.h:98
void panshell_changed()
Definition: panner_ui.cc:204
boost::shared_ptr< Pannable > pannable() const
Definition: panner.h:163
void update_pan_sensitive()
Definition: panner_ui.cc:482
void set_bypassed(bool)
sigc::connection pan_watching
Definition: panner_ui.h:153
std::string short_astyle_string(ARDOUR::AutoStyle)
Definition: panner_ui.cc:626
virtual void set_panner(boost::shared_ptr< ARDOUR::PannerShell >, boost::shared_ptr< ARDOUR::Panner >)
Definition: panner_ui.cc:92
void pan_automation_style_changed()
Definition: panner_ui.cc:537
bool bypassed() const
PannerUI(ARDOUR::Session *)
Definition: panner_ui.cc:46
void set_available_panners(std::map< std::string, std::string >)
Definition: panner_ui.cc:664
sigc::signal< void > StopGesture
Definition: mono_panner.h:48
bool _send_mode
Definition: panner_ui.h:101
std::string astate_string(ARDOUR::AutoState)
Definition: panner_ui.cc:585
MonoPanner * _mono_panner
Definition: panner_ui.h:112
Definition: ardour_ui.h:130
static ARDOUR_UI * instance()
Definition: ardour_ui.h:187
Gtk::Menu * pan_astate_menu
Definition: panner_ui.h:121
Gtk::ToggleButton pan_automation_state_button
Definition: panner_ui.h:125
std::string panner_gui_uri() const
Definition: panner_shell.h:83
void reset(uint32_t n_inputs)
Definition: panner2d.cc:103
void start_touch(boost::weak_ptr< ARDOUR::AutomationControl >)
Definition: panner_ui.cc:343
sigc::signal< void > StopPositionGesture
Definition: stereo_panner.h:49
bool _suspend_menu_callbacks
Definition: panner_ui.h:167
uint32_t n_audio() const
Definition: chan_count.h:63
tuple f
Definition: signals.py:35
void effective_pan_display()
Definition: panner_ui.cc:470
Definition: Beats.hpp:239
std::string astyle_string(ARDOUR::AutoStyle)
Definition: panner_ui.cc:620
void reset(uint32_t n_inputs)
Definition: panner2d.cc:909
Width _width
Definition: panner_ui.h:109
Gtk::CheckMenuItem * bypass_menu_item
Definition: panner_ui.h:142
void show_position()
Definition: panner_ui.cc:654
void pan_set_custom_type(std::string type)
Definition: panner_ui.cc:464
#define ENSURE_GUI_THREAD(obj, method,...)
Definition: gui_thread.h:34
#define invalidator(x)
Definition: gui_thread.h:40
virtual ChanCount in() const =0
AutoStyle
Definition: types.h:155
Gtk::VBox pan_vbox
Definition: panner_ui.h:107
#define _(Text)
Definition: i18n.h:11
AutoStyle automation_style() const
Definition: panner.cc:88
gint pan_automation_style_button_event(GdkEventButton *)
Definition: panner_ui.cc:517
virtual ChanCount out() const =0
const ARDOUR::Session & session() const
boost::shared_ptr< ARDOUR::Panner > _panner
Definition: panner_ui.h:92
void setup_pan()
Definition: panner_ui.cc:211
boost::shared_ptr< ARDOUR::PannerShell > _panshell
Definition: panner_ui.h:91
bool _ignore_width_change
Definition: panner_ui.h:114
framepos_t transport_frame() const
Definition: session.h:551
Definition: amp.h:29
#define gui_context()
Definition: gui_thread.h:36
gint pan_automation_state_button_event(GdkEventButton *)
Definition: panner_ui.cc:494
bool _ignore_position_change
Definition: panner_ui.h:115
void set_width(Width)
Definition: panner_ui.cc:187
std::string _astyle_string(ARDOUR::AutoStyle, bool)
Definition: panner_ui.cc:632
virtual void reset()=0
void pan_edit()
Definition: panner_ui.cc:437
boost::shared_ptr< AutomationControl > pan_azimuth_control
Definition: pannable.h:45
void pan_automation_state_changed()
Definition: panner_ui.cc:552
std::map< std::string, std::string > _panner_list
Definition: panner_ui.h:166
int _current_nins
Definition: panner_ui.h:99
bool pan_button_event(GdkEventButton *)
Definition: panner_ui.cc:363
T * get() const
Definition: shared_ptr.hpp:268
Gtk::Menu * pan_menu
Definition: panner_ui.h:141
void build_astate_menu()
Definition: panner_ui.cc:135
std::string _astate_string(ARDOUR::AutoState, bool)
Definition: panner_ui.cc:597
std::string _current_uri
Definition: panner_ui.h:100
sigc::signal< void > StartGesture
Definition: mono_panner.h:47
void set_tip(Gtk::Widget &w, const gchar *tip)
void stop_touch(boost::weak_ptr< ARDOUR::AutomationControl >)
Definition: panner_ui.cc:353
bool select_panner_by_uri(std::string const uri)
PBD::ScopedConnectionList connections
Definition: panner_ui.h:93
void on_size_allocate(Gtk::Allocation &)
Definition: panner_ui.cc:181
void set_send_drawing_mode(bool)
Definition: panner2d.cc:387
Panner2dWindow * big_window
Definition: panner_ui.h:104
std::string short_astate_string(ARDOUR::AutoState)
Definition: panner_ui.cc:591
boost::shared_ptr< AutomationControl > pan_width_control
Definition: pannable.h:47
PBD::Signal0< void > Changed
Definition: panner_shell.h:68
Width
Definition: enums.h:25
Gtk::Menu * pan_astyle_menu
Definition: panner_ui.h:122
void set_send_drawing_mode(bool)
StereoPanner * _stereo_panner
Definition: panner_ui.h:111
sigc::signal< void > StartWidthGesture
Definition: stereo_panner.h:50
Definition: debug.h:30
bool ignore_toggle
Definition: panner_ui.h:96
Panner2d * twod_panner
2D panner, or 0
Definition: panner_ui.h:103
sigc::signal< void > StopWidthGesture
Definition: stereo_panner.h:51
void width_adjusted()
Definition: panner_ui.cc:649
Gtk::Button pan_automation_style_button
Definition: panner_ui.h:124
void show_width()
Definition: panner_ui.cc:644
#define S_(Text)
Definition: i18n.h:18
sigc::signal< void > StartPositionGesture
Definition: stereo_panner.h:48
void position_adjusted()
Definition: panner_ui.cc:659
virtual void set_session(ARDOUR::Session *)
bool in_pan_update
Definition: panner_ui.h:97
void pan_reset()
Definition: panner_ui.cc:455
static float ui_scale
Definition: ardour_ui.h:189
Definition: enums.h:27
boost::shared_ptr< Panner > panner() const
Definition: panner_shell.h:70
sigc::connection rapid_connect(const sigc::slot< void > &slot)
Definition: timers.cc:183
std::string current_panner_uri() const
Definition: panner_shell.h:81
Definition: enums.h:26
void build_astyle_menu()
Definition: panner_ui.cc:165
LIBGTKMM2EXT_API void container_clear(Gtk::Container &)
Definition: utils.cc:511
void set_send_drawing_mode(bool)
Definition: panner_ui.cc:330
void stop_touch(bool mark, double when)
AutoState
Definition: types.h:145