Guitarix
rack.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, 2010 Hermann Meyer, James Warden
3  * Copyright (C) 2011 Pete Shorthose
4  * Copyright (C) 2012 Andreas Degert
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  * ---------------------------------------------------------------------------
20  *
21  * ----------------------------------------------------------------------------
22  */
23 
24 #include <guitarix.h>
25 
26 /****************************************************************
27  ** class PluginUI
28  **
29  ** This class represents a rack unit. It refers to an engine
30  ** plugin. The user interface in the rack is loaded on demand.
31  **
32  ** It is responsible for reflecting any changes done to display
33  ** parameter variables (box_visible, flat/expanded format, ordering).
34  **
35  ** Registering with an GxUI is done in PluginDict.
36  **
37  ** When a preset load is in progress re-ordering is blocked.
38  ** MainWindow connects RackContainer::check_order() to
39  ** GxSettings::signal_selection_changed so that ordering will be done
40  ** when the load is finished.
41  **
42  */
43 
44 PluginUI::PluginUI(MainWindow& main_, const char *name,
45  const Glib::ustring& tooltip_)
46  : merge_id(0),
47  action(),
48  plugin(main_.get_machine().pluginlist_lookup_plugin(name)),
49  tooltip(tooltip_),
50  shortname(),
51  icon(),
52  group(),
53  toolitem(),
54  main(main_),
55  rackbox(),
56  hidden(false),
57  hidden_by_move(false) {
58  if (plugin->get_pdef()->description && tooltip.empty()) {
60  }
62 }
63 
65  delete rackbox;
66  if (toolitem) {
67  if (group) {
68  group->remove(*toolitem);
69  }
70  delete toolitem;
71  }
73 }
74 
75 void PluginUI::unset_ui_merge_id(Glib::RefPtr<Gtk::UIManager> uimanager) {
76  if (merge_id) {
77  uimanager->remove_ui(merge_id);
78  merge_id = 0;
79  }
80 }
81 
84 }
85 
88 }
89 
90 void PluginUI::compress(bool state) {
91  plugin->set_plug_visible(state);
92  if (rackbox) {
93  if (rackbox->can_compress()) {
94  rackbox->swtch(state);
95  }
96  }
97 }
98 
99 void PluginUI::set_action(Glib::RefPtr<Gtk::ToggleAction>& act)
100 {
101  action = act;
102  action->signal_toggled().connect(sigc::mem_fun(*this, &PluginUI::on_action_toggled));
103 }
104 
105 void PluginUI::on_action_toggled() {
106  if (rackbox && action->get_active() == rackbox->get_box_visible()) {
107  return;
108  }
109  if (action->get_active()) {
110  display_new();
111  } else {
112  display(false, true);
113  }
114 }
115 
116 void PluginUI::hide(bool animate) {
117  plugin->set_on_off(false);
118  if (rackbox) {
119  rackbox->display(false, animate);
120  main.add_icon(get_id());
121  }
122 }
123 
124 void PluginUI::show(bool animate) {
125  if (!rackbox) {
126  rackbox = main.add_rackbox(*this, plugin->get_plug_visible(), -1, animate);
127  set_active(true);
128  } else {
129  rackbox->display(true, animate);
130  }
131  if (hidden) {
132  rackbox->hide();
133  }
135 }
136 
137 void PluginUI::display(bool v, bool animate) {
138  // this function hides the rackbox. It could also destroy it (or
139  // some other function could do it, e.g. when unloading a module),
140  // but currently there are too many memory leaks in the stack based
141  // builder.
143  if (v) {
145  hidden = false;
146  show(animate);
147  } else {
149  hide(animate);
150  }
151 }
152 
153 void PluginUI::display_new(bool unordered) {
154  plugin->set_plug_visible(false);
155  if (rackbox) {
156  rackbox->swtch(false);
157  }
158  display(true, true);
159  if (!unordered) {
160  rackbox->get_parent()->reorder(get_id(), -1);
161  }
162 }
163 
165  if (!rackbox) {
166  return;
167  }
168  if (plugin->get_box_visible()) {
170  int n = 0;
171  for (RackContainer::rackbox_list::iterator i = l.begin(); i != l.end(); ++i, ++n)
172  if (*i == rackbox) {
173  break;
174  }
175  display(false,false);
176  delete rackbox;
177  rackbox = 0;
178  display(true,false);
179  //rackbox = main.add_rackbox(*this, plugin->get_plug_visible(), n, false);
180  } else {
181  delete rackbox;
182  rackbox = 0;
183  }
184 }
185 
187  int res = a->get_type() - b->get_type();
188  if (res == 0) {
189  gchar *an = g_utf8_casefold(a->get_shortname(), 1);
190  gchar *bn = g_utf8_casefold(b->get_shortname(), 1);
191  res = g_utf8_collate(an, bn);
192  g_free(an);
193  g_free(bn);
194  }
195  return res < 0;
196 }
197 
198 
199 /****************************************************************
200  ** class PluginDict
201  */
202 
204  insert(pair<std::string, PluginUI*>(p->get_id(), p));
205 }
206 
208  std::map<std::string, PluginUI*>::iterator i = find(p->get_id());
209  assert(i != end());
210  erase(i);
211 }
212 
214  for (std::map<std::string, PluginUI*>::iterator i = begin(); i != end(); ++i) {
215  delete i->second;
216  }
217  clear();
218 }
219 
221  cleanup();
222 }
223 
224 void PluginDict::compress(bool state) {
225  for (std::map<std::string, PluginUI*>::iterator i = begin(); i != end(); ++i) {
226  i->second->compress(state);
227  }
228 }
229 
230 
231 /****************************************************************
232  ** class DragIcon
233  */
234 
235 inline guint8 convert_color_channel (guint8 src, guint8 alpha) {
236  return alpha ? ((guint (src) << 8) - src) / alpha : 0;
237 }
238 
239 void convert_bgra_to_rgba (guint8 const* src, guint8* dst, int width, int height) {
240  guint8 const* src_pixel = src;
241  guint8* dst_pixel = dst;
242 
243  for (int i = 0; i < height*width; ++i) {
244  dst_pixel[0] = convert_color_channel(src_pixel[2], src_pixel[3]);
245  dst_pixel[1] = convert_color_channel(src_pixel[1], src_pixel[3]);
246  dst_pixel[2] = convert_color_channel(src_pixel[0], src_pixel[3]);
247  dst_pixel[3] = src_pixel[3];
248 
249  dst_pixel += 4;
250  src_pixel += 4;
251  }
252 }
253 
254 DragIcon::DragIcon(const PluginUI& plugin, Glib::RefPtr<Gdk::DragContext> context, gx_system::CmdlineOptions& options, int xoff)
255  : window(), drag_icon_pixbuf() {
256  Glib::RefPtr<Gdk::Screen> screen = context->get_source_window()->get_screen();
257  Glib::RefPtr<Gdk::Colormap> rgba = screen->get_rgba_colormap();
258  if (screen->is_composited()) {
259  window = new Gtk::Window(Gtk::WINDOW_POPUP);
260  if (rgba) { // else will look ugly..
261  window->set_colormap(rgba);
262  }
263  }
264  create_drag_icon_pixbuf(plugin, rgba, options);
265  int w = drag_icon_pixbuf->get_width();
266  int h = drag_icon_pixbuf->get_height();
267  int h2 = (h/2)-2;
268  int w2 = std::min(std::max(0, xoff), w-gradient_length/2) - 4;
269  if (window) {
270  window->set_size_request(w, h);
271  window->signal_expose_event().connect(sigc::mem_fun(*this, &DragIcon::icon_expose_event));
272  //context->set_icon_widget(window, w2, h2);
273  gtk_drag_set_icon_widget(context->gobj(), GTK_WIDGET(window->gobj()), w2, h2);
274  } else {
275  context->set_icon(drag_icon_pixbuf, w2, h2);
276  }
277 }
278 
280  delete window;
281 }
282 
283 bool DragIcon::icon_expose_event(GdkEventExpose *ev) {
284  Cairo::RefPtr<Cairo::Context> cr = Glib::wrap(ev->window, true)->create_cairo_context();
285  gdk_cairo_region(cr->cobj(), ev->region);
286  cr->set_operator(Cairo::OPERATOR_SOURCE);
287  cr->clip();
288  Gdk::Cairo::set_source_pixbuf(cr, drag_icon_pixbuf, 0, 0);
289  cr->paint();
290  return true;
291 }
292 
293 void DragIcon::create_drag_icon_pixbuf(const PluginUI& plugin, Glib::RefPtr<Gdk::Colormap> rgba, gx_system::CmdlineOptions& options) {
294  Gtk::OffscreenWindow w;
295  w.signal_expose_event().connect(sigc::bind(sigc::mem_fun(*this, &DragIcon::window_expose_event), sigc::ref(w)));
296  if (rgba) {
297  w.set_colormap(rgba);
298  }
299  Gtk::Widget *r = RackBox::create_drag_widget(plugin, options);
300  w.add(*r);
301  w.show_all();
302  w.get_window()->process_updates(true);
303 }
304 
305 static void destroy_data(const guint8 *data) {
306  delete[] data;
307 }
308 
309 bool DragIcon::window_expose_event(GdkEventExpose *event, Gtk::OffscreenWindow& widget) {
310  Cairo::RefPtr<Cairo::Context> cr = widget.get_window()->create_cairo_context();
311  cr->set_operator(Cairo::OPERATOR_SOURCE);
312  cr->set_source_rgba(0,0,0,0);
313  cr->paint();
314  Gtk::Widget *child = widget.get_child();
315  if (child) {
316  widget.propagate_expose(*child, event);
317  }
318  Cairo::RefPtr<Cairo::Surface> x_surf = cr->get_target();
319  //int w = gdk_window_get_width(event->window); gtk 2.24
320  //int h = gdk_window_get_height(event->window);
321  int w, h;
322  gdk_drawable_get_size(event->window, &w, &h);
323  Cairo::RefPtr<Cairo::LinearGradient> grad = Cairo::LinearGradient::create(w, 0, w-gradient_length, 0);
324  grad->add_color_stop_rgba(0, 1, 1, 1, 1);
325  grad->add_color_stop_rgba(1, 1, 1, 1, 0);
326  cr->rectangle(w-gradient_length, 0, gradient_length, h);
327  cr->mask(grad);
328  Cairo::RefPtr<Cairo::ImageSurface> i_surf = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, w, h);
329  Cairo::RefPtr<Cairo::Context> crt = Cairo::Context::create(i_surf);
330  crt->set_operator(Cairo::OPERATOR_SOURCE);
331  crt->set_source(x_surf, 0, 0);
332  crt->paint();
333  guint8 *data = new guint8[w*h*4];
334  convert_bgra_to_rgba(i_surf->get_data(), data, w, h);
335  drag_icon_pixbuf = Gdk::Pixbuf::create_from_data(data, Gdk::COLORSPACE_RGB, true, 8, w, h, i_surf->get_stride(), sigc::ptr_fun(destroy_data));
336  return true;
337 }
338 
339 
340 /****************************************************************
341  ** class MiniRackBox
342  */
343 
344 Glib::RefPtr<Gtk::SizeGroup> MiniRackBox::szg_label;
345 
346 Gtk::Widget *MiniRackBox::make_delete_button(RackBox& rb) {
347  Gtk::Widget *w;
348  if (rb.has_delete()) {
349  Gtk::Label *l = new Gtk::Label("\u2a2f");
350  l->show();
351  Gtk::Button *b = new Gtk::Button();
352  b->set_focus_on_click(false);
353  b->add(*manage(l));
354  b->signal_clicked().connect(sigc::bind(sigc::mem_fun(rb.plugin, &PluginUI::display), false, true));
355  w = b;
356  } else {
357  w = new Gtk::Alignment();
358  }
359  w->set_size_request(20, 15);
360  return w;
361 }
362 
363 bool MiniRackBox::on_my_leave_out(GdkEventCrossing *focus) {
364  if (!mconbox.get_visible()) {
365  Glib::RefPtr<Gdk::Window> window = this->get_window();
366  window->set_cursor();
367  }
368  return true;
369 }
370 
371 bool MiniRackBox::on_my_enter_in(GdkEventCrossing *focus) {
372  if (!mconbox.get_visible()) {
373  Glib::RefPtr<Gdk::Window> window = this->get_window();
374  Gdk::Cursor cursor(Gdk::HAND1);
375  window->set_cursor(cursor);
376  }
377  return true;
378 }
379 
381  : Gtk::HBox(),
382  evbox(),
383  mconbox(false, 4),
384  mb_expand_button(),
385  mb_delete_button(),
386  preset_button(),
387  on_off_switch("switchit"),
388  toggle_on_off(rb.main.get_machine(), &on_off_switch, rb.plugin.plugin->id_on_off()) {
389  if (strcmp(rb.plugin.get_id(), "ampstack") != 0) { // FIXME
390  gx_gui::connect_midi_controller(&on_off_switch, rb.plugin.plugin->id_on_off().c_str(), rb.main.get_machine());
391 
392  if (!szg_label) {
393  szg_label = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
394  }
395  evbox.set_visible_window(false);
396  evbox.signal_leave_notify_event().connect(sigc::mem_fun(*this, &MiniRackBox::on_my_leave_out));
397  evbox.signal_enter_notify_event().connect(sigc::mem_fun(*this, &MiniRackBox::on_my_enter_in));
398  add(evbox);
399 
400  Gtk::Alignment *al = new Gtk::Alignment();
401  al->set_padding(0, 4, 0, 0);
402  al->set_border_width(0);
403 
404  evbox.add(*manage(al));
405 
406  Gtk::HBox *box = new Gtk::HBox();
407  Gtk::HBox *top = new Gtk::HBox();
408  al->add(*manage(box));
409 
410  this->set_spacing(0);
411  this->set_border_width(0);
412 
413  box->set_spacing(0);
414  box->set_border_width(0);
415 
416  top->set_spacing(4);
417  top->set_border_width(0);
418  top->set_name("rack_unit_title_bar");
419 
420  box->pack_start(*manage(rb.wrap_bar()), Gtk::PACK_SHRINK);
421  box->pack_start(*manage(top));
422  box->pack_start(*manage(rb.wrap_bar()), Gtk::PACK_SHRINK);
423 
424  top->pack_start(on_off_switch, Gtk::PACK_SHRINK);
425  on_off_switch.set_name("effect_on_off");
426  Gtk::Widget *effect_label = RackBox::make_label(rb.plugin, options);
427  szg_label->add_widget(*manage(effect_label));
428  top->pack_start(*manage(effect_label), Gtk::PACK_SHRINK);
429 
430  top->pack_start(mconbox, Gtk::PACK_EXPAND_WIDGET);
431 
432  mb_expand_button = rb.make_expand_button(true);
433  top->pack_end(*manage(mb_expand_button), Gtk::PACK_SHRINK);
434  if (!(rb.plugin.plugin->get_pdef()->flags & PGN_NO_PRESETS)) {
435  preset_button = rb.make_preset_button();
436  top->pack_end(*manage(preset_button), Gtk::PACK_SHRINK);
437  }
438  mb_delete_button = make_delete_button(rb);
439  mb_delete_button->set_no_show_all(true);
440  top->pack_end(*manage(mb_delete_button), Gtk::PACK_SHRINK);
441 #ifdef USE_SZG
442  RackBox::szg->add_widget(*al);
443 #else
444  al->set_size_request(32, -1);
445 #endif
446  } else { // special minibox for main amp in config mode
447  if (!szg_label) {
448  szg_label = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
449  }
450  evbox.set_visible_window(false);
451  evbox.signal_leave_notify_event().connect(sigc::mem_fun(*this, &MiniRackBox::on_my_leave_out));
452  evbox.signal_enter_notify_event().connect(sigc::mem_fun(*this, &MiniRackBox::on_my_enter_in));
453  add(evbox);
454 
455  Gtk::Alignment *al = new Gtk::Alignment();
456  al->set_padding(0, 4, 0, 0);
457  al->set_border_width(0);
458 
459  Gtk::HBox *box = new Gtk::HBox();
460  Gtk::HBox *top = new Gtk::HBox();
461  evbox.add(*manage(box));
462 
463  top->set_name("rack_unit_title_bar");
464  Gtk::Widget *effect_label = RackBox::make_label(rb.plugin, options);
465  szg_label->add_widget(*manage(effect_label));
466  top->pack_start(*manage(effect_label), Gtk::PACK_SHRINK);
467  top->pack_start(mconbox, Gtk::PACK_EXPAND_WIDGET);
468  box->pack_start(*manage(al), Gtk::PACK_SHRINK);
469  box->pack_start(*manage(top));
470 #ifdef USE_SZG
471  RackBox::szg->add_widget(*al);
472 #else
473  al->set_size_request(64, 32);
474 #endif
475  }
476  show_all();
477 }
478 
479 void MiniRackBox::pack(Gtk::Widget *w) {
480  if (w) {
481  mconbox.pack_start(*manage(w), Gtk::PACK_SHRINK, 4);
482  }
483 }
484 
486  evbox.set_above_child(mode);
487  if (mode) {
488  mconbox.hide();
489  if (preset_button) {
490  preset_button->hide();
491  }
492  if (mb_expand_button) {
493  mb_expand_button->hide();
494  }
495  if (mb_delete_button) {
496  mb_delete_button->show();
497  }
498  } else {
499  mconbox.show();
500  if (preset_button) {
501  preset_button->show();
502  }
503  if (mb_expand_button) {
504  mb_expand_button->show();
505  }
506  if (mb_delete_button) {
507  mb_delete_button->hide();
508  }
509  }
510 }
511 
512 
513 /****************************************************************
514  ** class PluginPresetPopup
515  */
516 
517 /*
518 ** InputWindow
519 */
520 
521 class InputWindow: public Gtk::Window {
522 private:
523  Glib::ustring name;
524  void on_cancel();
525  void on_ok(Gtk::Entry *e);
526  virtual bool on_key_press_event(GdkEventKey *event);
527  static InputWindow* create_from_builder(
528  BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld, const Glib::ustring& save_name_default);
529  InputWindow(BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld, const Glib::ustring& save_name_default);
530 public:
531  ~InputWindow();
532  static InputWindow *create(const gx_system::CmdlineOptions& options, const Glib::ustring& save_name_default);
533  void run();
534  Glib::ustring& get_name() { return name; }
535 };
536 
537 InputWindow *InputWindow::create_from_builder(BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld,
538  const Glib::ustring& save_name_default) {
539  return new InputWindow(cobject, bld, save_name_default);
540 }
541 
543 }
544 
545 InputWindow *InputWindow::create(const gx_system::CmdlineOptions& options, const Glib::ustring& save_name_default) {
546  Glib::RefPtr<gx_gui::GxBuilder> bld = gx_gui::GxBuilder::create_from_file(options.get_builder_filepath("pluginpreset_inputwindow.glade"));
547  InputWindow *w;
548  bld->get_toplevel_derived(
549  "PluginPresetInputWindow", w,
550  sigc::bind(sigc::ptr_fun(InputWindow::create_from_builder), bld, save_name_default));
551  return w;
552 }
553 
554 bool InputWindow::on_key_press_event(GdkEventKey *event) {
555  if (event->keyval == GDK_KEY_Escape && (event->state & Gtk::AccelGroup::get_default_mod_mask()) == 0) {
556  hide();
557  return true;
558  }
559  return Gtk::Window::on_key_press_event(event);
560 }
561 
562 void InputWindow::on_ok(Gtk::Entry *e) {
563  name = e->get_text();
564  hide();
565 }
566 
567 InputWindow::InputWindow(BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld,
568  const Glib::ustring& save_name_default)
569  : Gtk::Window(cobject), name() {
570  Gtk::Button *b;
571  bld->find_widget("cancelbutton", b);
572  b->signal_clicked().connect(
573  sigc::mem_fun(*this, &InputWindow::hide));
574  bld->find_widget("okbutton", b);
575  Gtk::Entry *e;
576  bld->find_widget("entry", e);
577  e->set_text(save_name_default);
578  e->select_region(0, -1);
579  b->signal_clicked().connect(
580  sigc::bind(sigc::mem_fun(*this, &InputWindow::on_ok), e));
581 }
582 
584  Gtk::Main::run(*this);
585 }
586 
587 /*
588 ** PluginPresetListWindow
589 */
590 
591 class TextListStore: public Gtk::ListStore {
592 public:
593  class TextListColumns : public Gtk::TreeModel::ColumnRecord {
594  public:
595  Gtk::TreeModelColumn<Glib::ustring> name;
596  TextListColumns() { add(name); }
597  } col;
598 private:
599  TextListStore(): Gtk::ListStore(), col() {
600  set_column_types(col);
601  }
602 public:
603  static Glib::RefPtr<TextListStore> create() { return Glib::RefPtr<TextListStore>(new TextListStore); }
604 };
605 
606 class PluginPresetListWindow: public Gtk::Window {
607 private:
608  Glib::RefPtr<TextListStore> textliststore;
609  PluginPresetPopup& presetlist;
610  //
611  Gtk::TreeView *treeview;
612  Gtk::Button *removebutton;
613  using Gtk::Window::on_remove;
614  void on_remove();
615  void on_selection_changed();
616  virtual bool on_key_press_event(GdkEventKey *event);
617  static PluginPresetListWindow* create_from_builder(
618  BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld, PluginPresetPopup& p);
619  PluginPresetListWindow(BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld, PluginPresetPopup& p);
620 public:
622  static PluginPresetListWindow *create(const gx_system::CmdlineOptions& options, PluginPresetPopup& p);
623  void run();
624 };
625 
626 PluginPresetListWindow *PluginPresetListWindow::create_from_builder(
627  BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld, PluginPresetPopup& p) {
628  return new PluginPresetListWindow(cobject, bld, p);
629 }
630 
632 }
633 
635  const gx_system::CmdlineOptions& options, PluginPresetPopup& p) {
636  Glib::RefPtr<gx_gui::GxBuilder> bld = gx_gui::GxBuilder::create_from_file(
637  options.get_builder_filepath("pluginpreset_listwindow.glade"));
639  bld->get_toplevel_derived(
640  "PluginPresetListWindow", w,
641  sigc::bind(sigc::ptr_fun(PluginPresetListWindow::create_from_builder), bld, sigc::ref(p)));
642  return w;
643 }
644 
645 bool PluginPresetListWindow::on_key_press_event(GdkEventKey *event) {
646  if (event->keyval == GDK_KEY_Escape && (event->state & Gtk::AccelGroup::get_default_mod_mask()) == 0) {
647  hide();
648  return true;
649  }
650  return Gtk::Window::on_key_press_event(event);
651 }
652 
653 void PluginPresetListWindow::on_remove() {
654  Gtk::TreeIter it = treeview->get_selection()->get_selected();
655  if (it) {
656  presetlist.get_machine().plugin_preset_list_remove(
657  presetlist.get_pdef(), it->get_value(textliststore->col.name));
658  textliststore->erase(it);
659  }
660 }
661 
662 PluginPresetListWindow::PluginPresetListWindow(
663  BaseObjectType* cobject, Glib::RefPtr<gx_gui::GxBuilder> bld, PluginPresetPopup& p)
664  : Gtk::Window(cobject),
665  textliststore(TextListStore::create()),
666  presetlist(p) {
667  Gtk::Button *b;
668  bld->find_widget("closebutton", b);
669  b->signal_clicked().connect(
670  sigc::mem_fun(*this, &PluginPresetListWindow::hide));
671  bld->find_widget("removebutton", removebutton);
672  removebutton->signal_clicked().connect(
673  sigc::mem_fun0(*this, &PluginPresetListWindow::on_remove));
674  bld->find_widget("treeview", treeview);
675  for (gx_preset::UnitPresetList::const_iterator i = presetlist.begin(); i != presetlist.end(); ++i) {
676  if (i->name.empty()) {
677  break;
678  }
679  textliststore->append()->set_value(textliststore->col.name, i->name);
680  }
681  treeview->set_model(textliststore);
682  removebutton->set_sensitive(false);
683  Glib::RefPtr<Gtk::TreeSelection> sel = treeview->get_selection();
684  sel->signal_changed().connect(
685  sigc::mem_fun(*this, &PluginPresetListWindow::on_selection_changed));
686 }
687 
688 void PluginPresetListWindow::on_selection_changed() {
689  removebutton->set_sensitive(treeview->get_selection()->get_selected());
690 }
691 
693  Gtk::Main::run(*this);
694 }
695 
696 /*
697 ** PluginPresetPopup
698 */
699 
700 void PluginPresetPopup::set_plugin_preset(bool factory, const Glib::ustring& name) {
701  if(strcmp(pdef->id,"seq")==0) {
702  machine.plugin_preset_list_sync_set(pdef, factory, name);
703  } else {
704  machine.plugin_preset_list_set(pdef, factory, name);
705  }
706 }
707 
708 void PluginPresetPopup::set_plugin_std_preset() {
709  machine.reset_unit(pdef);
710 }
711 
712 void PluginPresetPopup::save_plugin_preset() {
713  InputWindow *w = InputWindow::create(machine.get_options(), save_name_default);
714  w->run();
715  if (!w->get_name().empty()) {
716  // save loop file to plugin preset name
717  if(strcmp(pdef->id,"dubber")==0) {
718  Glib::ustring name = "";
719  machine.set_parameter_value("dubber.filename", name);
720  machine.set_parameter_value("dubber.savefile", true);
721  machine.set_parameter_value("dubber.filename", w->get_name());
722  }
723  machine.plugin_preset_list_save(pdef, w->get_name());
724  if(strcmp(pdef->id,"seq")==0) {
725  Glib::ustring id = "seq." + w->get_name();
726  if (!machine.parameter_hasId(id)) {
727  machine.insert_param("seq", w->get_name());
728  }
729  }
730  }
731  delete w;
732 }
733 
734 void PluginPresetPopup::remove_plugin_preset() {
735  PluginPresetListWindow *w = PluginPresetListWindow::create(machine.get_options(), *this);
736  w->run();
737  delete w;
738 }
739 
740 bool PluginPresetPopup::add_plugin_preset_list(bool *found) {
741  *found = false;
742  bool found_presets = false;
743  bool factory = false;
744  for (gx_preset::UnitPresetList::iterator i = presetnames.begin(); i != presetnames.end(); ++i) {
745  if (i->name.empty()) {
746  factory = true;
747  if (found_presets) {
748  append(*manage(new Gtk::SeparatorMenuItem()));
749  *found = true;
750  found_presets = false;
751  }
752  continue;
753  } else {
754  found_presets = true;
755  }
756  Gtk::CheckMenuItem *c = new Gtk::CheckMenuItem(i->name);
757  if (i->is_set) {
758  c->set_active(true);
759  }
760  c->signal_activate().connect(
761  sigc::bind(sigc::mem_fun(this, &PluginPresetPopup::set_plugin_preset), factory, i->name));
762  append(*manage(c));
763  }
764  return found_presets;
765 }
766 
767 static bool delete_plugin_preset_popup(PluginPresetPopup *p) {
768  delete p;
769  return false;
770 }
771 
773  Glib::signal_idle().connect(
774  sigc::bind(
775  sigc::ptr_fun(delete_plugin_preset_popup),
776  this));
777 }
778 
780  const Glib::ustring& save_name_default_)
781  : Gtk::Menu(),
782  pdef(pdef_),
783  machine(machine_),
784  save_name_default(save_name_default_),
785  presetnames() {
786  machine.plugin_preset_list_load(pdef, presetnames);
787  bool found_presets;
788  if (!add_plugin_preset_list(&found_presets)) {
789  Gtk::CheckMenuItem *c = new Gtk::CheckMenuItem(_("standard"));
790  if (machine.parameter_unit_has_std_values(pdef)) {
791  c->set_active(true);
792  }
793  c->signal_activate().connect(
794  sigc::mem_fun(this, &PluginPresetPopup::set_plugin_std_preset));
795  append(*manage(c));
796  }
797  append(*manage(new Gtk::SeparatorMenuItem()));
798  Gtk::MenuItem *mi = new Gtk::MenuItem(_("save..."));
799  append(*manage(mi));
800  mi->signal_activate().connect(
801  sigc::mem_fun(this, &PluginPresetPopup::save_plugin_preset));
802  if (found_presets) {
803  mi = new Gtk::MenuItem(_("remove..."));
804  append(*manage(mi));
805  mi->signal_activate().connect(
806  sigc::mem_fun(this, &PluginPresetPopup::remove_plugin_preset));
807  }
808  show_all();
809  popup(1, gtk_get_current_event_time());
810 }
811 
812 
813 /****************************************************************
814  ** class RackBox
815  */
816 
817 #ifdef USE_SZG
818 Glib::RefPtr<Gtk::SizeGroup> RackBox::szg;
819 #endif
820 
821 void RackBox::set_paintbox_unit_shrink(Gxw::PaintBox& pb, PluginType tp) {
822  pb.set_name("rackbox");
823  pb.property_paint_func().set_value("gx_rack_unit_shrink_expose");
824  pb.set_border_width(4);
825 }
826 
827 void RackBox::set_paintbox_unit(Gxw::PaintBox& pb, const PluginUI& plugin) {
828  pb.set_name("rackbox");
829  pb.property_paint_func().set_value("gx_rack_unit_expose");
830  pb.set_border_width(4);
831  // FIXME set special background for LV2 plugins
832  // if (plugin.plugin->get_pdef()->flags & gx_engine::PGNI_IS_LV2)
833  // fprintf(stderr,"LV2 Plugin Load for %s %i\n",plugin.plugin->get_pdef()->name, plugin.plugin->get_pdef()->flags & gx_engine::PGNI_IS_LV2);
834  // else if (plugin.plugin->get_pdef()->flags & gx_engine::PGNI_IS_LADSPA)
835  // fprintf(stderr,"LADSPA Plugin Load for %s %i\n",plugin.plugin->get_pdef()->name, plugin.plugin->get_pdef()->flags & gx_engine::PGNI_IS_LV2);
836 
837 }
838 
839 void RackBox::set_paintbox(Gxw::PaintBox& pb, PluginType tp) {
840  pb.set_name("rackbox");
841  // pb.property_paint_func().set_value("rectangle_skin_color_expose");
842  pb.set_border_width(4);
843 }
844 
845 Gtk::Widget *RackBox::make_label(const PluginUI& plugin, gx_system::CmdlineOptions& options, bool useshort) {
846  const char *effect_name = useshort ? plugin.get_shortname() : plugin.get_name();
847  Gtk::Label *effect_label = new Gtk::Label(effect_name);
848  effect_label->set_alignment(0.0, 0.5);
849  effect_label->set_name("effect_title");
850  if (plugin.get_type() == PLUGIN_TYPE_STEREO) {
851  effect_label->set_markup("◗◖ " + effect_label->get_label()); //♾⚮⦅◗◖⦆⚭ ⧓ Ꝏꝏ ⦅◉⦆● ▷◁ ▶◀
852  }
853  return effect_label;
854 }
855 
856 Gtk::Widget *RackBox::make_bar(int left, int right, bool sens) {
857  Gtk::Alignment *al = new Gtk::Alignment(0, 0, 1.0, 1.0);
858  //al->set_padding(4, 4, left, right);
859  Gtk::Button *button = new Gtk::Button();
860  button->set_size_request(32,-1);
861  //button->set_name("effect_reset");
862  button->set_tooltip_text(_("Drag'n' Drop Handle"));
863  button->set_relief(Gtk::RELIEF_NONE);
864  button->set_sensitive(sens);
865  al->add(*manage(button));
866  return al;
867 }
868 
869 bool RackBox::on_my_leave_out(GdkEventCrossing *focus) {
870  Glib::RefPtr<Gdk::Window> window = this->get_window();
871  window->set_cursor();
872  return true;
873 }
874 
875 bool RackBox::on_my_enter_in(GdkEventCrossing *focus) {
876  Glib::RefPtr<Gdk::Window> window = this->get_window();
877  Gdk::Cursor cursor(Gdk::HAND1);
878  window->set_cursor(cursor);
879  return true;
880 }
881 
882 bool RackBox::on_my_button_press(GdkEventButton* ev) {
883  if (ev->type == GDK_2BUTTON_PRESS && ev->button == 1) {
884  plugin.display(false, true);
885  }
886  return true;
887 }
888 
889 
890 Gtk::Widget *RackBox::wrap_bar(int left, int right, bool sens) {
891  Gtk::EventBox *ev = new Gtk::EventBox;
892  ev->set_visible_window(false);
893  ev->set_above_child(true);
894  ev->add(*manage(make_bar(left, right, sens)));
895  ev->signal_leave_notify_event().connect(sigc::mem_fun(*this, &RackBox::on_my_leave_out));
896  ev->signal_enter_notify_event().connect(sigc::mem_fun(*this, &RackBox::on_my_enter_in));
897  ev->signal_button_press_event().connect(sigc::mem_fun(*this, &RackBox::on_my_button_press));
898  ev->signal_drag_begin().connect(sigc::mem_fun(*this, &RackBox::on_my_drag_begin));
899  ev->signal_drag_end().connect(sigc::mem_fun(*this, &RackBox::on_my_drag_end));
900  ev->signal_drag_data_get().connect(sigc::mem_fun(*this, &RackBox::on_my_drag_data_get));
901  std::vector<Gtk::TargetEntry> listTargets;
902  listTargets.push_back(Gtk::TargetEntry(target, Gtk::TARGET_SAME_APP, 0));
903  ev->drag_source_set(listTargets, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE);
904  return ev;
905 }
906 
907 Gtk::Widget *RackBox::create_icon_widget(const PluginUI& plugin, gx_system::CmdlineOptions& options) {
908  Gxw::PaintBox *pb = new Gxw::PaintBox(Gtk::ORIENTATION_HORIZONTAL);
909  RackBox::set_paintbox(*pb, plugin.get_type());
910  Gtk::Widget *effect_label = RackBox::make_label(plugin, options);
911  Gtk::Alignment *al = new Gtk::Alignment(0.0, 0.0, 1.0, 1.0);
912  al->set_padding(0,2,2,0);
913  al->add(*manage(effect_label));
914  pb->pack_start(*manage(al), Gtk::PACK_SHRINK);
915  pb->show_all();
916  return pb;
917 }
918 
919 Gtk::Widget *RackBox::create_drag_widget(const PluginUI& plugin, gx_system::CmdlineOptions& options) {
920  Gxw::PaintBox *pb = new Gxw::PaintBox(Gtk::ORIENTATION_HORIZONTAL);
921  RackBox::set_paintbox_unit_shrink(*pb, plugin.get_type());
922  pb->set_name("drag_widget");
923  if (strcmp(plugin.get_id(), "ampstack") == 0) { // FIXME
924  pb->property_paint_func().set_value("gx_rack_amp_expose");
925  }
926  //Gxw::Switch *swtch = new Gxw::Switch("switchit");
927  //swtch->set_active(plugin.plugin->get_on_off());
928 #ifdef USE_SZG
929  //RackBox::szg->add_widget(*swtch);
930 #else
931  //swtch->set_size_request(35, -1);
932 #endif
933  Gtk::Widget *effect_label = RackBox::make_label(plugin, options);
934  Gtk::Alignment *al = new Gtk::Alignment(0.0, 0.0, 0.0, 0.0);
935  al->set_padding(0,0,4,20);
936  al->add(*manage(RackBox::make_bar(4, 4, true))); // FIXME: fix style and remove sens parameter
937  pb->pack_start(*manage(al), Gtk::PACK_SHRINK);
938  //pb->pack_start(*manage(swtch), Gtk::PACK_SHRINK);
939  pb->pack_start(*manage(effect_label), Gtk::PACK_SHRINK);
940  al = new Gtk::Alignment(0.0, 0.0, 0.0, 0.0);
941  al->set_size_request(70,30);
942  pb->pack_start(*manage(al), Gtk::PACK_SHRINK);
943  pb->show_all();
944  return pb;
945 }
946 
947 void RackBox::display(bool v, bool animate) {
948  assert(box_visible != v);
949  box_visible = v;
950  plugin.set_active(v);
951  if (v) {
952  if (animate) {
953  animate_insert();
954  } else {
955  show();
956  }
957  get_parent()->increment();
958  plugin.hidden_by_move = false;
959  plugin.toolitem->hide();
960  } else {
961  if (animate) {
962  animate_remove();
963  } else {
964  hide();
965  }
966  get_parent()->decrement();
967  plugin.hidden_by_move = true;
968  }
969 }
970 
971 RackBox::RackBox(PluginUI& plugin_, MainWindow& tl, Gtk::Widget* bare)
972  : Gtk::VBox(), plugin(plugin_), main(tl), config_mode(false), anim_tag(),
973  compress(true), delete_button(true), mbox(Gtk::ORIENTATION_HORIZONTAL), minibox(0),
974  fbox(0), target(), anim_height(0), anim_step(), drag_icon(), target_height(0),
975  box(Gtk::ORIENTATION_HORIZONTAL, 2), box_visible(true), on_off_switch("switchit"),
976  toggle_on_off(tl.get_machine(), &on_off_switch, plugin.plugin->id_on_off()) {
977  if (strcmp(plugin.get_id(), "ampstack") != 0) { // FIXME
978  gx_gui::connect_midi_controller(&on_off_switch, plugin.plugin->id_on_off().c_str(), main.get_machine());
979  }
980 #ifdef USE_SZG
981  if (!szg) {
982  szg = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
983  }
984 #endif
985  if (bare) {
986  compress = false;
987  delete_button = false;
988  }
989  set_paintbox_unit_shrink(mbox, plugin.get_type());
990  init_dnd();
991  minibox = new MiniRackBox(*this, tl.get_options());
992  mbox.pack_start(*manage(minibox));
993  pack_start(mbox, Gtk::PACK_SHRINK);
994  if (bare) {
995  add(*manage(bare));
996  fbox = bare;
997  mbox.property_paint_func().set_value("gx_rack_amp_expose");
998  } else {
999  Gxw::PaintBox *pb = new Gxw::PaintBox(Gtk::ORIENTATION_HORIZONTAL);
1000  pb->show();
1001  set_paintbox_unit(*pb, plugin);
1002  pb->pack_start(*manage(make_full_box(tl.get_options())));
1003  pack_start(*manage(pb), Gtk::PACK_SHRINK);
1004  fbox = pb;
1005  }
1006  show();
1007 }
1008 
1009 void RackBox::init_dnd() {
1010  target = "application/x-guitarix-";
1011  if (plugin.get_type() == PLUGIN_TYPE_MONO) {
1012  target += "mono";
1013  } else {
1014  target += "stereo";
1015  }
1016  if (!delete_button) {
1017  target += "-s";
1018  }
1019  mbox.signal_drag_begin().connect(sigc::mem_fun(*this, &RackBox::on_my_drag_begin));
1020  mbox.signal_drag_end().connect(sigc::mem_fun(*this, &RackBox::on_my_drag_end));
1021  mbox.signal_drag_data_get().connect(sigc::mem_fun(*this, &RackBox::on_my_drag_data_get));
1022 }
1023 
1024 void RackBox::enable_drag(bool v) {
1025  if (v) {
1026  std::vector<Gtk::TargetEntry> listTargets;
1027  listTargets.push_back(Gtk::TargetEntry(target, Gtk::TARGET_SAME_APP, 0));
1028  mbox.drag_source_set(listTargets, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE);
1029  } else {
1030  mbox.drag_source_unset();
1031  }
1032 }
1033 
1034 bool RackBox::animate_vanish() {
1035  anim_height -= anim_step;
1036  if (anim_height <= 0) {
1037  hide();
1038  set_visibility(true);
1039  set_size_request(-1,-1);
1041  return false;
1042  } else {
1043  set_size_request(-1, anim_height);
1044  return true;
1045  }
1046 }
1047 
1048 void RackBox::animate_remove() {
1049  if (!get_parent()->check_if_animate(*this)) {
1050  hide();
1051  } else {
1052  if (anim_tag.connected()) {
1053  //Glib::source_remove(anim_tag);
1054  anim_tag.disconnect();
1055  set_size_request(-1,-1);
1056  show();
1057  }
1058  anim_height = size_request().height;
1059  set_size_request(-1, anim_height);
1060  set_visibility(false);
1061  anim_step = anim_height / 5;
1062  anim_tag = Glib::signal_timeout().connect(sigc::mem_fun(*this, &RackBox::animate_vanish), 20);
1063  }
1064 }
1065 
1067  return dynamic_cast<RackContainer*>(Gtk::VBox::get_parent());
1068 }
1069 
1070 void RackBox::on_my_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context) {
1071  int x, y;
1072  get_pointer(x, y);
1073  drag_icon = new DragIcon(plugin, context, main.get_options(), x);
1074  animate_remove();
1075 }
1076 
1077 bool RackBox::animate_create() {
1078  bool ret = true;
1079  anim_height += anim_step;
1080  if (anim_height >= target_height) {
1081  set_visibility(true);
1082  set_size_request(-1,-1);
1083  ret = false;
1084  } else {
1085  set_size_request(-1, anim_height);
1086  }
1087  get_parent()->ensure_visible(*this);
1088  return ret;
1089 }
1090 
1092  if (!get_parent()->check_if_animate(*this)) {
1093  show();
1094  get_parent()->ensure_visible(*this);
1095  } else {
1096  if (anim_tag.connected()) {
1097  hide();
1098  anim_tag.disconnect();
1099  set_size_request(-1,-1);
1100  }
1101  target_height = size_request().height;
1102  set_size_request(-1,0);
1103  set_visibility(false);
1104  show();
1105  anim_height = 0;
1106  anim_step = target_height / 5;
1107  anim_tag = Glib::signal_timeout().connect(mem_fun(*this, &RackBox::animate_create), 20);
1108  }
1109 }
1110 
1111 void RackBox::on_my_drag_end(const Glib::RefPtr<Gdk::DragContext>& context) {
1112  if (drag_icon) {
1113  delete drag_icon;
1114  drag_icon = 0;
1115  }
1116  if (plugin.plugin->get_box_visible()) {
1117  animate_insert();
1118  }
1119 }
1120 
1121 void RackBox::on_my_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection, int info, int timestamp) {
1122  selection.set(target, plugin.get_id());
1123 }
1124 
1125 void RackBox::vis_switch(Gtk::Widget& a, Gtk::Widget& b) {
1126  a.hide();
1127  b.show();
1128 }
1129 
1130 void RackBox::set_visibility(bool v) {
1131  if (config_mode || get_plug_visible()) {
1132  minibox->set_config_mode(false);
1133  mbox.set_visible(v);
1134  minibox->set_config_mode(config_mode);
1135  } else {
1136  fbox->set_visible(v);
1137  }
1138 }
1139 
1140 void RackBox::swtch(bool mini) {
1141  plugin.plugin->set_plug_visible(mini);
1142  if (!config_mode) {
1143  if (mini) {
1144  vis_switch(*fbox, mbox);
1145  } else {
1146  vis_switch(mbox, *fbox);
1147  }
1148  }
1149 }
1150 
1151 void RackBox::set_config_mode(bool mode) {
1152  config_mode = mode;
1153  if (!can_compress() || !get_plug_visible()) {
1154  if (mode) {
1155  vis_switch(*fbox, mbox);
1156  if (strcmp(plugin.get_id(), "ampstack") == 0) { // FIXME
1157  return;
1158  }
1159  } else {
1160  vis_switch(mbox, *fbox);
1161  }
1162  }
1163  minibox->set_config_mode(mode);
1164  enable_drag(mode);
1165 }
1166 
1167 void RackBox::setOrder(int pos, int post_pre) {
1168  plugin.plugin->set_position(pos);
1169  if (plugin.get_type() == PLUGIN_TYPE_MONO) {
1170  plugin.plugin->set_effect_post_pre(post_pre);
1171  }
1172 }
1173 
1174 void RackBox::do_expand() {
1175  swtch(false);
1176  Glib::signal_idle().connect_once(
1177  sigc::bind(
1178  sigc::mem_fun(get_parent(), &RackContainer::ensure_visible),
1179  sigc::ref(*this)));
1180 }
1181 
1182 Gtk::Button *RackBox::make_expand_button(bool expand) {
1183  const gchar *t;
1184  Gtk::Button *b = new Gtk::Button();
1185  //b->set_relief(Gtk::RELIEF_NONE);
1186  if (expand) {
1187  t = "rack_expand";
1188  b->set_tooltip_text(_("expand effect unit"));
1189  } else {
1190  t = "rack_shrink";
1191  b->set_tooltip_text(_("shrink effect unit"));
1192  }
1193  GtkWidget *l = gtk_image_new_from_stock(t, (GtkIconSize)-1);
1194  b->set_focus_on_click(false);
1195  b->add(*manage(Glib::wrap(l)));
1196  b->set_name("effect_on_off");
1197  if (expand) {
1198  b->signal_clicked().connect(
1199  sigc::mem_fun(*this, &RackBox::do_expand));
1200  } else {
1201  b->signal_clicked().connect(
1202  sigc::bind(sigc::mem_fun(*this, &RackBox::swtch), true));
1203  }
1204  return b;
1205 }
1206 
1207 Gtk::Button *RackBox::make_preset_button() {
1208  Gtk::Button *p = new Gtk::Button();
1209  //p->set_relief(Gtk::RELIEF_NONE);
1210  GtkWidget *l = gtk_image_new_from_stock("rack_preset", (GtkIconSize)-1);
1211  p->add(*manage(Glib::wrap(l)));
1212  p->set_can_default(false);
1213  p->set_can_focus(false);
1214  p->set_tooltip_text(_("manage effect unit presets"));
1215  p->set_name("effect_on_off");
1216  p->signal_clicked().connect(
1217  sigc::mem_fun(plugin, &PluginUI::on_plugin_preset_popup));
1218  return p;
1219 }
1220 
1221 void RackBox::pack(Gtk::Widget *main, Gtk::Widget *mini, const Glib::RefPtr<Gtk::SizeGroup>& szg) {
1222  if (!main) {
1223  return;
1224  }
1225  box.pack_start(*manage(main));
1226  minibox->pack(mini);
1227  szg->add_widget(*fbox);
1228  szg->add_widget(mbox);
1229 }
1230 
1231 Gtk::HBox *RackBox::make_full_box(gx_system::CmdlineOptions& options) {
1232  Gtk::HBox *bx = new Gtk::HBox();
1233  Gtk::Widget *effect_label = make_label(plugin, options, false);
1234 
1235  // overall hbox: drag-button - center vbox - drag button
1236  Gtk::HBox *main = new Gtk::HBox();
1237  // center vbox containing title bar and widgets
1238  Gtk::VBox *center = new Gtk::VBox();
1239  // title vbox on top
1240  Gtk::HBox *top = new Gtk::HBox();
1241 
1242  // spacing for bottom shadow
1243  Gtk::Alignment *al = new Gtk::Alignment();
1244  al->set_padding(0, 4, 0, 0);
1245  al->add(*manage(main));
1246 
1247  main->set_spacing(0);
1248 
1249  center->set_name("rack_unit_center");
1250  center->set_border_width(0);
1251  center->set_spacing(4);
1252  center->pack_start(*manage(top), Gtk::PACK_SHRINK);
1253  center->pack_start(box, Gtk::PACK_EXPAND_WIDGET);
1254 
1255  top->set_spacing(4);
1256  top->set_name("rack_unit_title_bar");
1257 
1258  top->pack_start(on_off_switch, Gtk::PACK_SHRINK);
1259  on_off_switch.set_name("effect_on_off");
1260  top->pack_start(*manage(effect_label), Gtk::PACK_SHRINK);
1261  top->pack_end(*manage(make_expand_button(false)), Gtk::PACK_SHRINK);
1262  if (!(plugin.plugin->get_pdef()->flags & PGN_NO_PRESETS))
1263  top->pack_end(*manage(make_preset_button()), Gtk::PACK_SHRINK);
1264 
1265  main->pack_start(*manage(wrap_bar()), Gtk::PACK_SHRINK);
1266  main->pack_start(*manage(center), Gtk::PACK_EXPAND_WIDGET);
1267  main->pack_end(*manage(wrap_bar()), Gtk::PACK_SHRINK);
1268 
1269  main->set_name(plugin.get_id());
1270  bx->pack_start(*manage(al), Gtk::PACK_EXPAND_WIDGET);
1271  //al->show_all();
1272  bx->show_all();
1273  return bx;
1274 }
1275 
1276 Gtk::VBox *RackBox::switcher_vbox(gx_system::CmdlineOptions& options) {
1277  Gtk::VBox *vbox = new Gtk::VBox();
1278 
1279  Gtk::HBox *hbox = new Gtk::HBox();
1280  vbox->pack_start(*manage(hbox));
1281  Gtk::HBox *hbox2 = new Gtk::HBox();
1282  hbox->pack_start(*manage(hbox2), Gtk::PACK_SHRINK);
1283  Gtk::VBox *vbox2 = new Gtk::VBox();
1284  hbox2->pack_start(*manage(vbox2));
1285  hbox2->pack_start(*manage(wrap_bar(4,4)), Gtk::PACK_SHRINK);
1286 #ifdef USE_SZG
1287  szg->add_widget(&on_off_switch);
1288 #endif
1289  Gtk::Alignment *al = new Gtk::Alignment(0.5, 0.5, 0.0, 0.0);
1290  al->add(on_off_switch);
1291  vbox2->pack_start(*manage(al));
1292  return vbox;
1293 }
1294 
1295 
1296 /****************************************************************
1297  ** class RackContainer
1298  */
1299 
1300 static const int min_containersize = 40;
1301 
1303  : Gtk::VBox(),
1304  tp(tp_),
1305  main(main_),
1306  config_mode(false),
1307  in_drag(-2),
1308  child_count(0),
1309  targets(),
1310  othertargets(),
1311  highlight_connection(),
1312  autoscroll_connection() {
1313  std::vector<std::string> *pm, *ps;
1314  if (tp == PLUGIN_TYPE_MONO) {
1315  pm = &targets;
1316  ps = &othertargets;
1317  } else {
1318  ps = &targets;
1319  pm = &othertargets;
1320  }
1321  pm->push_back("application/x-guitarix-mono");
1322  pm->push_back("application/x-guitarix-mono-s");
1323  pm->push_back("application/x-gtk-tool-palette-item-mono");
1324  ps->push_back("application/x-guitarix-stereo");
1325  ps->push_back("application/x-guitarix-stereo-s");
1326  ps->push_back("application/x-gtk-tool-palette-item-stereo");
1327  std::vector<Gtk::TargetEntry> listTargets;
1328  listTargets.push_back(Gtk::TargetEntry("application/x-guitarix-mono", Gtk::TARGET_SAME_APP, 0));
1329  listTargets.push_back(Gtk::TargetEntry("application/x-guitarix-mono-s", Gtk::TARGET_SAME_APP, 1));
1330  listTargets.push_back(Gtk::TargetEntry("application/x-gtk-tool-palette-item-mono", Gtk::TARGET_SAME_APP, 2));
1331  listTargets.push_back(Gtk::TargetEntry("application/x-guitarix-stereo", Gtk::TARGET_SAME_APP, 3));
1332  listTargets.push_back(Gtk::TargetEntry("application/x-guitarix-stereo-s", Gtk::TARGET_SAME_APP, 4));
1333  listTargets.push_back(Gtk::TargetEntry("application/x-gtk-tool-palette-item-stereo", Gtk::TARGET_SAME_APP, 5));
1334  drag_dest_set(listTargets, Gtk::DEST_DEFAULT_DROP, Gdk::ACTION_MOVE);
1336  sigc::mem_fun(this, &RackContainer::unit_order_changed));
1337  signal_remove().connect(sigc::mem_fun(*this, &RackContainer::on_my_remove));
1338  set_size_request(-1, min_containersize);
1339  show_all();
1340 }
1341 
1342 void RackContainer::unit_order_changed(bool stereo) {
1343  if (stereo == (tp == PLUGIN_TYPE_STEREO)) {
1344  check_order();
1345  }
1346 }
1347 
1348 bool RackContainer::drag_highlight_expose(GdkEventExpose *event, int y0) {
1349  if (!is_drawable()) {
1350  return false;
1351  }
1352  Cairo::RefPtr<Cairo::Context> cr = Glib::wrap(event->window, true)->create_cairo_context();
1353  int x, y, width, height;
1354  if (!get_has_window()) {
1355  Gtk::Allocation a = get_allocation();
1356  x = a.get_x();
1357  y = a.get_y();
1358  width = a.get_width();
1359  height = a.get_height();
1360  } else {
1361  int depth;
1362  get_window()->get_geometry(x, y, width, height, depth);
1363  x = 0;
1364  y = 0;
1365  }
1366  GdkPixbuf * pb_ = gtk_widget_render_icon(GTK_WIDGET(this->gobj()), "insert", (GtkIconSize)-1, NULL);
1367  if (pb_) {
1368  cairo_t *cr_ = gdk_cairo_create(unwrap(get_window()));
1369  gdk_cairo_set_source_pixbuf(cr_, pb_, x, y);
1370  cairo_pattern_set_extend(cairo_get_source(cr_), CAIRO_EXTEND_REPEAT);
1371  if (y0 < 0) {
1372  cairo_set_line_width(cr_, 4.0);
1373  cairo_rectangle(cr_, x, max(0, y), width, height);
1374  cairo_stroke(cr_);
1375  } else {
1376  cairo_rectangle(cr_, x, max(y, y0 - 3), width, 2);
1377  cairo_fill(cr_);
1378  }
1379  cairo_destroy(cr_);
1380  g_object_unref(pb_);
1381  }
1382  return false;
1383 }
1384 
1385 struct childpos {
1386  int y0, y1, pos;
1387  childpos(int y0_, int y1_, int pos_): y0(y0_), y1(y1_), pos(pos_) {}
1388  bool operator<(const childpos& p) { return y0 < p.y0; }
1389 };
1390 
1391 void RackContainer::find_index(int x, int y, int* len, int *ypos) {
1392  std::list<childpos> l;
1393  std::vector<RackBox*> children = get_children();
1394  int mpos = -1;
1395  for (std::vector<RackBox*>::iterator ch = children.begin(); ch != children.end(); ++ch) {
1396  ++mpos;
1397  if (!(*ch)->get_visible()) {
1398  continue;
1399  }
1400  Gtk::Allocation a = (*ch)->get_allocation();
1401  l.push_back(childpos(a.get_y(), a.get_y()+a.get_height(), mpos));
1402  }
1403  if (l.empty()) {
1404  *len = -1;
1405  *ypos = -1;
1406  return;
1407  }
1408  Gtk::Allocation a0 = get_allocation();
1409  y += a0.get_y();
1410  int sy = l.begin()->y0;
1411  for (std::list<childpos>::iterator cp = l.begin(); cp != l.end(); ++cp) {
1412  if (y < (cp->y0 + cp->y1) / 2) {
1413  *len = cp->pos;
1414  *ypos = (cp->y0+sy)/2;
1415  return;
1416  }
1417  sy = cp->y1;
1418  }
1419  *len = mpos+1;
1420  *ypos = sy;
1421 }
1422 
1423 void RackContainer::on_my_remove(Gtk::Widget *ch) {
1424  decrement();
1425  renumber();
1426 }
1427 
1428 bool RackContainer::check_targets(const std::vector<std::string>& tgts1, const std::vector<std::string>& tgts2) {
1429  for (std::vector<std::string>::const_iterator t1 = tgts1.begin(); t1 != tgts1.end(); ++t1) {
1430  for (std::vector<std::string>::const_iterator t2 = tgts2.begin(); t2 != tgts2.end(); ++t2) {
1431  if (*t1 == *t2) {
1432  return true;
1433  }
1434  }
1435  }
1436  return false;
1437 }
1438 
1439 bool RackContainer::on_drag_motion(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, guint timestamp) {
1440  const std::vector<std::string>& tg = context->get_targets();
1441  if (!check_targets(tg, targets)) {
1442  if (check_targets(tg, othertargets)) {
1443  if (!autoscroll_connection.connected()) {
1444  autoscroll_connection = Glib::signal_timeout().connect(
1445  sigc::mem_fun(*this, &RackContainer::scrollother_timeout), 50);
1446  }
1447  context->drag_status(Gdk::DragAction(0), timestamp);
1448  return true;
1449  }
1450  return false;
1451  }
1452  context->drag_status(Gdk::ACTION_MOVE, timestamp);
1453  int i, ind;
1454  find_index(x, y, &i, &ind);
1455  if (in_drag == ind) {
1456  return true;
1457  }
1458  if (in_drag > -2) {
1459  highlight_connection.disconnect();
1460  }
1461  highlight_connection = signal_expose_event().connect(sigc::bind(sigc::mem_fun(*this, &RackContainer::drag_highlight_expose), ind), true);
1462  queue_draw();
1463  in_drag = ind;
1464  if (!autoscroll_connection.connected()) {
1465  autoscroll_connection = Glib::signal_timeout().connect(sigc::mem_fun(*this, &RackContainer::scroll_timeout), 50);
1466  }
1467  return true;
1468 }
1469 
1471  Gtk::Allocation alloc = child.get_allocation();
1472  Gtk::Viewport *p = dynamic_cast<Gtk::Viewport*>(get_ancestor(GTK_TYPE_VIEWPORT));
1473  p->get_vadjustment()->clamp_page(alloc.get_y(), alloc.get_y()+alloc.get_height());
1474 }
1475 
1476 static const double scroll_edge_size = 60.0;
1477 static const int step_size = 20;
1478 
1479 bool RackContainer::scrollother_timeout() {
1480  Gtk::Viewport *p = dynamic_cast<Gtk::Viewport*>(get_ancestor(GTK_TYPE_VIEWPORT));
1481  Gtk::Adjustment *a = p->get_vadjustment();
1482  double off = a->get_value();
1483  Gtk::Allocation alloc = get_allocation();
1484  int x, y;
1485  get_pointer(x, y);
1486  y -= alloc.get_height();
1487  double step;
1488  if (y < -scroll_edge_size) {
1489  step = step_size;
1490  } else {
1491  step = step_size * exp(-(y+scroll_edge_size)/(1.0*scroll_edge_size));
1492  if (step < 1.5) {
1493  return false;
1494  }
1495  }
1496  if (tp == PLUGIN_TYPE_MONO) {
1497  off = main.stop_at_stereo_bottom(off, step_size, a->get_page_size());
1498  } else {
1499  off = main.stop_at_mono_top(off, step_size);
1500  }
1501  if (off < a->get_lower()) {
1502  off = a->get_lower();
1503  }
1504  if (off > a->get_upper() - a->get_page_size()) {
1505  off = a->get_upper() - a->get_page_size();
1506  }
1507  a->set_value(off);
1508  return true;
1509 }
1510 
1511 bool RackContainer::scroll_timeout() {
1512  Gtk::Viewport *p = dynamic_cast<Gtk::Viewport*>(get_ancestor(GTK_TYPE_VIEWPORT));
1513  Gtk::Adjustment *a = p->get_vadjustment();
1514  double off = a->get_value();
1515  Gtk::Allocation alloc = get_allocation();
1516  int x, y;
1517  get_pointer(x, y);
1518  double sez = scroll_edge_size;
1519  if (sez > a->get_page_size() / 3) {
1520  sez = a->get_page_size() / 3;
1521  }
1522  double yw = y + alloc.get_y() - off;
1523  double step;
1524  if (yw <= sez) {
1525  step = step_size * (sez-yw) / sez;
1526  off = max(double(alloc.get_y()), off-step);
1527  } else {
1528  yw = a->get_page_size() - yw;
1529  if (yw <= sez) {
1530  step = step_size * (sez-yw) / sez;
1531  off = min(alloc.get_y()+alloc.get_height()-a->get_page_size(), off+step);
1532  } else {
1533  return true;
1534  }
1535  }
1536  if (off < a->get_lower()) {
1537  off = a->get_lower();
1538  }
1539  if (off > a->get_upper() - a->get_page_size()) {
1540  off = a->get_upper() - a->get_page_size();
1541  }
1542  a->set_value(off);
1543  return true;
1544 }
1545 
1546 void RackContainer::on_drag_leave(const Glib::RefPtr<Gdk::DragContext>& context, guint timestamp) {
1547  if (in_drag > -2) {
1548  highlight_connection.disconnect();
1549  queue_draw();
1550  in_drag = -2;
1551  }
1552  autoscroll_connection.disconnect();
1553 }
1554 
1555 void RackContainer::on_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, guint info, guint timestamp) {
1556  int i, ind;
1557  find_index(x, y, &i, &ind);
1558  std::string dtype = data.get_data_type();
1559  if (dtype == "application/x-gtk-tool-palette-item-mono" || dtype == "application/x-gtk-tool-palette-item-stereo") {
1560  main.get_plugin(data.get_data_as_string())->display_new(true);
1561  }
1562  reorder(data.get_data_as_string(), i);
1563 }
1564 
1566  for (PluginDict::iterator i = main.plugins_begin(); i != main.plugins_end(); ++i) {
1567  i->second->hidden = false;
1568  if (!i->second->hidden_by_move) {
1569  RackBox *r = i->second->rackbox;
1570  if (r) {
1571  r->show();
1572  }
1573  }
1574  }
1575 }
1576 
1578  for (PluginDict::iterator i = main.plugins_begin(); i != main.plugins_end(); ++i) {
1579  i->second->hidden = true;
1580  RackBox *r = i->second->rackbox;
1581  if (r) {
1582  if (r->can_compress()) {
1583  r->hide();
1584  }
1585  }
1586  }
1587 }
1588 
1589 void RackContainer::reorder(const std::string& name, unsigned int pos) {
1590  std::vector<RackBox*> l = get_children();
1591  main.get_machine().insert_rack_unit(name, ((pos >= l.size()) ? "" : l[pos]->get_id()), tp);
1592  check_order();
1593 }
1594 
1595 void RackContainer::on_add(Widget *ch) {
1596  add(*dynamic_cast<RackBox*>(ch));
1597 }
1598 
1599 void RackContainer::add(RackBox& r, int pos) {
1600  pack_start(r, Gtk::PACK_SHRINK);
1601  increment();
1602  if (config_mode) {
1603  r.set_config_mode(true);
1604  }
1605  reorder_child(r, pos);
1606  renumber();
1607 }
1608 
1610  ++child_count;
1611  if (child_count == 1) {
1612  set_size_request(-1, -1);
1613  }
1614 }
1615 
1617  --child_count;
1618  assert(child_count >= 0);
1619  if (child_count == 0) {
1620  set_size_request(-1, min_containersize);
1621  }
1622 }
1623 
1625  config_mode = mode;
1626  std::vector<RackBox*> l = get_children();
1627  for (std::vector<RackBox*>::iterator c = l.begin(); c != l.end(); ++c) {
1628  (*c)->set_config_mode(mode);
1629  }
1630 }
1631 
1633  const std::vector<std::string>& ol = main.get_machine().get_rack_unit_order(tp);
1634  bool in_order = true;
1635  std::set<std::string> unit_set(ol.begin(), ol.end());
1636  rackbox_list l = get_children();
1637  std::vector<std::string>::const_iterator oi = ol.begin();
1638  for (rackbox_list::iterator c = l.begin(); c != l.end(); ++c) {
1639  if (!(*c)->get_box_visible()) {
1640  continue;
1641  }
1642  if (unit_set.find((*c)->get_id()) == unit_set.end()) {
1643  main.get_plugin((*c)->get_id())->hide(false);
1644  continue;
1645  }
1646  if (!in_order) {
1647  continue;
1648  }
1649  if (oi == ol.end()) {
1650  in_order = false;
1651  continue;
1652  }
1653  if (*oi != (*c)->get_id()) {
1654  in_order = false;
1655  }
1656  ++oi;
1657  }
1658  if (oi != ol.end()) {
1659  in_order = false;
1660  }
1661  if (in_order) {
1662  return;
1663  }
1664  int n = 0;
1665  for (std::vector<std::string>::const_iterator oi = ol.begin(); oi != ol.end(); ++oi) {
1666  PluginUI *p = main.get_plugin(*oi);
1667  if (!p->rackbox) {
1668  p->show(false);
1669  } else {
1670  if (!p->rackbox->get_box_visible()) {
1671  p->rackbox->display(true, false);
1672  if (p->hidden) {
1673  p->rackbox->hide();
1674  }
1675  }
1676  }
1677  reorder_child(*p->rackbox, n++);
1678  }
1679  renumber();
1680 }
1681 
1682 void RackContainer::renumber() {
1683  rackbox_list l = get_children();
1684  int pos = 0;
1685  unsigned int post_pre = 1;
1686  for (rackbox_list::iterator c = l.begin(); c != l.end(); ++c, ++pos) {
1687  if (strcmp((*c)->get_id(), "ampstack") == 0) { // FIXME
1688  pos = 0;
1689  post_pre = 0;
1690  continue;
1691  }
1692  (*c)->setOrder(pos, post_pre);
1693  }
1694 }
MiniRackBox(RackBox &rb, gx_system::CmdlineOptions &options)
Definition: rack.cpp:380
CmdConnection::msg_type end
Definition: jsonrpc.cpp:258
void convert_bgra_to_rgba(guint8 const *src, guint8 *dst, int width, int height)
Definition: rack.cpp:239
bool can_compress()
Gtk::TreeModelColumn< Glib::ustring > name
Definition: rack.cpp:595
void run()
Definition: rack.cpp:583
void check_order()
Definition: rack.cpp:1632
void cleanup()
Definition: rack.cpp:213
void add(RackBox &r, int pos=-1)
Definition: rack.cpp:1599
#define GDK_KEY_Escape
Definition: guitarix.h:53
PluginDef * get_pdef()
static Glib::RefPtr< TextListStore > create()
Definition: rack.cpp:603
gx_engine::GxMachineBase & get_machine()
void add_icon(const std::string &name)
static InputWindow * create(const gx_system::CmdlineOptions &options, const Glib::ustring &save_name_default)
Definition: rack.cpp:545
void ensure_visible(RackBox &child)
Definition: rack.cpp:1470
virtual void on_selection_done()
Definition: rack.cpp:772
const char * get_shortname() const
std::string get_builder_filepath(const std::string &basename) const
Definition: gx_system.h:373
const std::string & id_on_off() const
~PluginDict()
Definition: rack.cpp:220
const char * get_name() const
bool get_plug_visible() const
void display(bool v, bool animate)
Definition: rack.cpp:137
bool get_plug_visible()
bool get_box_visible()
Glib::ustring tooltip
RackContainer(PluginType tp, MainWindow &main)
Definition: rack.cpp:1302
void set_config_mode(bool mode)
Definition: rack.cpp:1624
DragIcon(const PluginUI &plugin, Glib::RefPtr< Gdk::DragContext > context, gx_system::CmdlineOptions &options, int xoff=0)
Definition: rack.cpp:254
static bool is_registered(gx_engine::GxMachineBase &m, const char *name)
Definition: rack.cpp:86
void plugin_preset_popup(const PluginDef *pdef)
void set_config_mode(bool mode)
Definition: rack.cpp:1151
Glib::ustring & get_name()
Definition: rack.cpp:534
bool hidden_by_move
~DragIcon()
Definition: rack.cpp:279
const char * description
Definition: gx_plugin.h:191
RackBox(PluginUI &plugin, MainWindow &main, Gtk::Widget *bare=0)
Definition: rack.cpp:971
bool get_box_visible() const
void hide(bool animate)
Definition: rack.cpp:116
void hide_effect(const std::string &name)
void display(bool v, bool animate)
Definition: rack.cpp:947
virtual bool parameter_unit_has_std_values(const PluginDef *pdef) const =0
childpos(int y0_, int y1_, int pos_)
Definition: rack.cpp:1387
virtual void on_plugin_preset_popup()
Definition: rack.cpp:82
PluginType
Definition: machine.h:34
PluginPresetPopup(const PluginDef *pdef, gx_engine::GxMachineBase &machine, const Glib::ustring &save_name_default="")
Definition: rack.cpp:779
void pack(Gtk::Widget *mainbox, Gtk::Widget *minibox, const Glib::RefPtr< Gtk::SizeGroup > &szg)
Definition: rack.cpp:1221
void decrement()
Definition: rack.cpp:1616
static Gtk::Widget * create_icon_widget(const PluginUI &plugin, gx_system::CmdlineOptions &options)
Definition: rack.cpp:907
void show(bool animate)
Definition: rack.cpp:124
Gtk::ToolItemGroup * group
gx_engine::Plugin * plugin
void pack(Gtk::Widget *w)
Definition: rack.cpp:479
friend class MiniRackBox
bool operator<(const childpos &p)
Definition: rack.cpp:1388
gx_system::CmdlineOptions & get_options()
void increment()
Definition: rack.cpp:1609
void show_entries()
Definition: rack.cpp:1565
#define min(x, y)
void animate_insert()
Definition: rack.cpp:1091
virtual sigc::signal< void, bool > & signal_rack_unit_order_changed()=0
int y1
Definition: rack.cpp:1386
#define max(x, y)
RackBox * add_rackbox(PluginUI &pl, bool mini=false, int pos=-1, bool animate=false)
static PluginPresetListWindow * create(const gx_system::CmdlineOptions &options, PluginPresetPopup &p)
Definition: rack.cpp:634
PluginType get_type() const
void hide_entries()
Definition: rack.cpp:1577
int flags
Definition: gx_plugin.h:185
void set_active(bool v)
void set_action(Glib::RefPtr< Gtk::ToggleAction > &act)
Definition: rack.cpp:99
MainWindow & main
virtual void plugin_preset_list_load(const PluginDef *pdef, gx_preset::UnitPresetList &presetnames)=0
void connect_midi_controller(Gtk::Widget *w, const std::string &id, gx_engine::GxMachineBase &machine)
void set_config_mode(bool mode)
Definition: rack.cpp:485
virtual void remove_rack_unit(const std::string &unit, PluginType type)=0
rackbox_list get_children()
Gtk::ToolItem * toolitem
void set_effect_post_pre(int v) const
void set_position(int v) const
guint8 convert_color_channel(guint8 src, guint8 alpha)
Definition: rack.cpp:235
void unset_ui_merge_id(Glib::RefPtr< Gtk::UIManager > uimanager)
Definition: rack.cpp:75
RackContainer * get_parent()
Definition: rack.cpp:1066
void update_rackbox()
Definition: rack.cpp:164
gx_engine::GxMachineBase & get_machine()
void resize_finished()
int y0
Definition: rack.cpp:1386
int main(int argc, char *argv[])
Definition: gxw_demo.cc:62
void swtch(bool mini)
Definition: rack.cpp:1140
void add(PluginUI *p)
Definition: rack.cpp:203
void set_plug_visible(bool v) const
void compress(bool state)
Definition: rack.cpp:90
const char * get_id() const
void remove(PluginUI *p)
Definition: rack.cpp:207
Gxw::BigKnob * wrap(GxBigKnob *object, bool take_copy)
Definition: bigknob.cc:44
PluginUI(MainWindow &main, const char *id_, const Glib::ustring &tooltip_="")
Definition: rack.cpp:44
void display_new(bool unordered=false)
Definition: rack.cpp:153
void reorder(const std::string &name, unsigned int pos)
Definition: rack.cpp:1589
virtual Plugin * pluginlist_lookup_plugin(const std::string &id) const =0
virtual ~PluginUI()
Definition: rack.cpp:64
void set_box_visible(bool v) const
~InputWindow()
Definition: rack.cpp:542
void setOrder(int pos, int post_pre)
Definition: rack.cpp:1167
void set_on_off(bool v) const
virtual void insert_rack_unit(const std::string &unit, const std::string &before, PluginType type)=0
friend bool plugins_by_name_less(PluginUI *a, PluginUI *b)
Definition: rack.cpp:186
std::map< std::string, PluginUI * >::iterator iterator
RackBox * rackbox
Glib::ListHandle< RackBox * > rackbox_list
void compress(bool state)
Definition: rack.cpp:224
static Gtk::Widget * create_drag_widget(const PluginUI &plugin, gx_system::CmdlineOptions &options)
Definition: rack.cpp:919