1 /* Calf DSP Library
2  * GUI main window.
3  * Copyright (C) 2007-2011 Krzysztof Foltman
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  */
20 
21 #include <calf/gtk_main_win.h>
22 
23 using namespace calf_plugins;
24 using namespace std;
25 
gtk_main_window()26 gtk_main_window::gtk_main_window()
27 {
28     toplevel = NULL;
29     owner = NULL;
30     notifier = NULL;
31     is_closed = true;
32     progress_window = NULL;
33     images = image_factory();
34 }
35 
36 static const char *ui_xml =
37 "<ui>\n"
38 "  <menubar>\n"
39 "    <menu action=\"FileMenuAction\">\n"
40 "      <menuitem action=\"FileOpen\"/>\n"
41 "      <menuitem action=\"FileSave\"/>\n"
42 "      <menuitem action=\"FileSaveAs\"/>\n"
43 "      <separator/>\n"
44 "      <menuitem action=\"FileReorder\"/>\n"
45 "      <separator/>\n"
46 "      <menuitem action=\"FilePreferences\"/>\n"
47 "      <separator/>\n"
48 "      <menuitem action=\"FileQuit\"/>\n"
49 "    </menu>\n"
50 "    <menu action=\"AddPluginMenuAction\" />\n"
51 "  </menubar>\n"
52 "</ui>\n"
53 ;
54 
55 const GtkActionEntry gtk_main_window::actions[] = {
56     { "FileMenuAction", NULL, "_File", NULL, "File-related operations", NULL },
57     { "FileOpen", GTK_STOCK_OPEN, "_Open", "<Ctrl>O", "Open a rack file", (GCallback)on_open_action },
58     { "FileSave", GTK_STOCK_SAVE, "_Save", "<Ctrl>S", "Save a rack file", (GCallback)on_save_action },
59     { "FileSaveAs", GTK_STOCK_SAVE_AS, "Save _as...", NULL, "Save a rack file as", (GCallback)on_save_as_action },
60     { "HostMenuAction", NULL, "_Host", NULL, "Host-related operations", NULL },
61     { "AddPluginMenuAction", NULL, "_Add plugin", NULL, "Add a plugin to the rack", NULL },
62     { "FileReorder", NULL, "_Reorder plugins", NULL, "Reorder plugins to minimize latency (experimental)", (GCallback)on_reorder_action },
63     { "FilePreferences", GTK_STOCK_PREFERENCES, "_Preferences...", NULL, "Adjust preferences", (GCallback)on_preferences_action },
64     { "FileQuit", GTK_STOCK_QUIT, "_Quit", "<Ctrl>Q", "Exit application", (GCallback)on_exit_action },
65 };
66 
on_open_action(GtkWidget * widget,gtk_main_window * main)67 void gtk_main_window::on_open_action(GtkWidget *widget, gtk_main_window *main)
68 {
69     main->open_file();
70 }
71 
on_save_action(GtkWidget * widget,gtk_main_window * main)72 void gtk_main_window::on_save_action(GtkWidget *widget, gtk_main_window *main)
73 {
74     main->save_file();
75 }
76 
on_save_as_action(GtkWidget * widget,gtk_main_window * main)77 void gtk_main_window::on_save_as_action(GtkWidget *widget, gtk_main_window *main)
78 {
79     main->save_file_as();
80 }
81 
on_reorder_action(GtkWidget * widget,gtk_main_window * main)82 void gtk_main_window::on_reorder_action(GtkWidget *widget, gtk_main_window *main)
83 {
84     main->owner->reorder_plugins();
85 }
86 
on_preferences_action(GtkWidget * widget,gtk_main_window * main)87 void gtk_main_window::on_preferences_action(GtkWidget *widget, gtk_main_window *main)
88 {
89     GtkBuilder *prefs_builder = gtk_builder_new();
90     GError *error = NULL;
91     const gchar *objects[] = { "preferences", NULL };
92     if (!gtk_builder_add_objects_from_file(prefs_builder, PKGLIBDIR "/calf-gui.xml", (gchar **)objects, &error))
93     {
94         g_warning("Cannot load preferences dialog: %s", error->message);
95         g_error_free(error);
96         g_object_unref(G_OBJECT(prefs_builder));
97         return;
98     }
99 
100     // styles selector
101     GtkCellRenderer *cell;
102     GtkListStore *styles = main->get_styles();
103     GtkComboBox *cb = GTK_COMBO_BOX(gtk_builder_get_object(prefs_builder, "rcstyles"));
104     gtk_combo_box_set_model(cb, GTK_TREE_MODEL(styles));
105     cell = gtk_cell_renderer_text_new();
106     gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cb), cell, TRUE);
107     gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cb), cell, "text", 0, NULL);
108     GtkTreeIter iter;
109     gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(styles), &iter);
110     while (valid) {
111         GValue path = G_VALUE_INIT;
112         gtk_tree_model_get_value(GTK_TREE_MODEL(styles), &iter, 1, &path);
113         if (main->get_config()->style.compare(g_value_get_string(&path)) == 0) {
114             gtk_combo_box_set_active_iter(cb, &iter);
115             break;
116         }
117         valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(styles), &iter);
118         g_value_unset(&path);
119     }
120 
121     GtkComboBoxText *rack_float = GTK_COMBO_BOX_TEXT(gtk_builder_get_object(prefs_builder, "rack-float"));
122     gtk_combo_box_text_append_text(rack_float, "Rows");
123     gtk_combo_box_text_append_text(rack_float, "Columns");
124     gtk_combo_box_set_active(GTK_COMBO_BOX(rack_float), main->get_config()->rack_float);
125     GtkWidget *preferences_dlg = GTK_WIDGET(gtk_builder_get_object(prefs_builder, "preferences"));
126     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-rack-ears")), main->get_config()->rack_ears);
127     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "win-to-tray")), main->get_config()->win_to_tray);
128     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "win-start-hidden")), main->get_config()->win_start_hidden);
129     gtk_spin_button_set_range(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")), 1, 32);
130     gtk_spin_button_set_increments(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")), 1, 1);
131     gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")), main->get_config()->float_size);
132     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-vu-meters")), main->get_config()->vu_meters);
133     int response = gtk_dialog_run(GTK_DIALOG(preferences_dlg));
134     if (response == GTK_RESPONSE_OK)
135     {
136         GValue path_ = G_VALUE_INIT;
137         GtkTreeIter iter;
138         gtk_combo_box_get_active_iter(cb, &iter);
139         gtk_tree_model_get_value(GTK_TREE_MODEL(styles), &iter, 1, &path_);
140         main->get_config()->rack_ears = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-rack-ears")));
141         main->get_config()->win_to_tray = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "win-to-tray")));
142         main->get_config()->win_start_hidden = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "win-start-hidden")));
143         main->get_config()->rack_float = gtk_combo_box_get_active(GTK_COMBO_BOX(rack_float));
144         main->get_config()->float_size = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")));
145         main->get_config()->vu_meters = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-vu-meters")));
146         main->get_config()->style = g_value_get_string(&path_);
147         main->get_config()->save(main->get_config_db());
148         //main->load_style(g_value_get_string(&path_));
149         g_value_unset(&path_);
150     }
151     gtk_widget_destroy(preferences_dlg);
152     g_object_unref(G_OBJECT(prefs_builder));
153 }
154 
on_exit_action(GtkWidget * widget,gtk_main_window * main)155 void gtk_main_window::on_exit_action(GtkWidget *widget, gtk_main_window *main)
156 {
157     gtk_widget_destroy(GTK_WIDGET(main->toplevel));
158 }
159 
add_plugin(jack_host * plugin)160 void gtk_main_window::add_plugin(jack_host *plugin)
161 {
162     if (toplevel)
163     {
164         plugin_strip *strip = create_strip(plugin);
165         plugins[plugin] = strip;
166         update_strip(plugin);
167         sort_strips();
168     }
169     else {
170         plugin_queue.push_back(plugin);
171         //plugins[plugin] = NULL;
172     }
173 }
174 
del_plugin(plugin_ctl_iface * plugin)175 void gtk_main_window::del_plugin(plugin_ctl_iface *plugin)
176 {
177     if (!plugins.count(plugin))
178         return;
179     plugin_strip *strip = plugins[plugin];
180     if (strip->gui_win)
181         strip->gui_win->close();
182     vector<GtkWidget *> to_destroy;
183     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
184     {
185         if (i->second == strip)
186             to_destroy.push_back(i->second->strip_table);
187         else if(i->second->id > strip->id)
188             i->second->id--;
189     }
190     for (unsigned int i = 0; i < to_destroy.size(); i++)
191         gtk_container_remove(GTK_CONTAINER(strips_table), to_destroy[i]);
192     plugins.erase(plugin);
193     sort_strips();
194 }
195 
rename_plugin(plugin_ctl_iface * plugin,std::string name)196 void gtk_main_window::rename_plugin(plugin_ctl_iface *plugin, std::string name)
197 {
198     if (!plugins.count(plugin))
199         return;
200     plugin_strip *strip = plugins[plugin];
201     gtk_label_set_text(GTK_LABEL(strip->name), name.c_str());
202     if (strip->gui_win) {
203         gtk_window_set_title(GTK_WINDOW(strip->gui_win->toplevel), ("Calf - " + name).c_str());
204     }
205 }
206 
set_window(plugin_ctl_iface * plugin,plugin_gui_window * gui_win)207 void gtk_main_window::set_window(plugin_ctl_iface *plugin, plugin_gui_window *gui_win)
208 {
209     if (!plugins.count(plugin))
210         return;
211     plugin_strip *strip = plugins[plugin];
212     if (!strip)
213         return;
214     strip->gui_win = gui_win;
215     if (!is_closed)
216         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(strip->button), gui_win != NULL ? TRUE : FALSE);
217 }
218 
refresh_all_presets(bool builtin_too)219 void gtk_main_window::refresh_all_presets(bool builtin_too)
220 {
221     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
222     {
223         if (i->second && i->second->gui_win) {
224             char ch = '0';
225             i->second->gui_win->fill_gui_presets(true, ch);
226             i->second->gui_win->fill_gui_presets(false, ch);
227         }
228     }
229 }
230 
231 static gboolean
gui_button_pressed(GtkToggleButton * button,plugin_strip * strip)232 gui_button_pressed(GtkToggleButton *button, plugin_strip *strip)
233 {
234     if (gtk_toggle_button_get_active(button) == (strip->gui_win != NULL))
235         return FALSE;
236     if (strip->gui_win) {
237         strip->gui_win->close();
238         strip->gui_win = NULL;
239     } else {
240         strip->main_win->open_gui(strip->plugin);
241     }
242     return TRUE;
243 }
244 static gboolean
connect_button_pressed(GtkWidget * button,plugin_strip * strip)245 connect_button_pressed(GtkWidget *button, plugin_strip *strip)
246 {
247     if (strip->connector) {
248         strip->connector->close();
249         strip->connector = NULL;
250     } else {
251         strip->connector = new calf_connector(strip);
252     }
253     return TRUE;
254 }
255 static gboolean
extra_button_pressed(GtkWidget * button,plugin_strip * strip)256 extra_button_pressed(GtkWidget *button, plugin_strip *strip)
257 {
258     if (strip->connector)
259         strip->connector->close();
260     strip->main_win->owner->remove_plugin(strip->plugin);
261     return TRUE;
262 }
263 
show_rack_ears(bool show)264 void gtk_main_window::show_rack_ears(bool show)
265 {
266     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
267     {
268         if (show)
269         {
270             gtk_widget_show(i->second->leftBG);
271             gtk_widget_show(i->second->rightBG);
272         }
273         else
274         {
275             gtk_widget_hide(i->second->leftBG);
276             gtk_widget_hide(i->second->rightBG);
277         }
278     }
279 }
280 
show_vu_meters(bool show)281 void gtk_main_window::show_vu_meters(bool show)
282 {
283     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
284     {
285         if (show)
286         {
287             if (i->second->inBox)
288                 gtk_widget_show(i->second->inBox);
289             if (i->second->outBox)
290                 gtk_widget_show(i->second->outBox);
291         }
292         else
293         {
294             if (i->second->inBox)
295                 gtk_widget_hide(i->second->inBox);
296             if (i->second->outBox)
297                 gtk_widget_hide(i->second->outBox);
298         }
299     }
300 }
301 
on_edit_title(GtkWidget * ebox,GdkEventButton * event,plugin_strip * strip)302 void gtk_main_window::on_edit_title(GtkWidget *ebox, GdkEventButton *event, plugin_strip *strip) {
303     gtk_entry_set_text(GTK_ENTRY(strip->entry), gtk_label_get_text(GTK_LABEL(strip->name)));
304     gtk_widget_grab_focus(strip->entry);
305     gtk_widget_hide(strip->name);
306     gtk_widget_show(strip->entry);
307 }
308 
on_activate_entry(GtkWidget * entry,plugin_strip * strip)309 void gtk_main_window::on_activate_entry(GtkWidget *entry, plugin_strip *strip) {
310     const char *txt = gtk_entry_get_text(GTK_ENTRY(entry));
311     const char *old = gtk_label_get_text(GTK_LABEL(strip->name));
312     if (strcmp(old, txt) and strlen(txt))
313         strip->main_win->owner->rename_plugin(strip->plugin, txt);
314     gtk_widget_hide(strip->entry);
315     gtk_widget_show(strip->name);
316 }
on_blur_entry(GtkWidget * entry,GdkEvent * event,plugin_strip * strip)317 gboolean gtk_main_window::on_blur_entry(GtkWidget *entry, GdkEvent *event, plugin_strip *strip) {
318     gtk_widget_hide(strip->entry);
319     gtk_widget_show(strip->name);
320     return FALSE;
321 }
322 
create_vu_meter()323 GtkWidget *gtk_main_window::create_vu_meter() {
324     GtkWidget *vu = calf_vumeter_new();
325     calf_vumeter_set_falloff(CALF_VUMETER(vu), 2.5);
326     calf_vumeter_set_hold(CALF_VUMETER(vu), 1.5);
327     calf_vumeter_set_width(CALF_VUMETER(vu), 100);
328     calf_vumeter_set_height(CALF_VUMETER(vu), 12);
329     calf_vumeter_set_position(CALF_VUMETER(vu), 2);
330     return vu;
331 }
332 
create_meter_scale()333 GtkWidget *gtk_main_window::create_meter_scale() {
334     GtkWidget *vu = calf_meter_scale_new();
335     CalfMeterScale *ms = CALF_METER_SCALE(vu);
336     const unsigned long sz = 7;
337     const double cv[sz] = {0., 0.0625, 0.125, 0.25, 0.5, 0.71, 1.};
338     const vector<double> ck(cv, &cv[sz]);
339     ms->marker   = ck;
340     ms->dots     = 1;
341     ms->position = 2;
342     gtk_widget_set_name(vu, "Calf-MeterScale");
343     return vu;
344 }
345 
on_table_clicked(GtkWidget * table,GdkEvent * event)346 void gtk_main_window::on_table_clicked(GtkWidget *table, GdkEvent *event) {
347     gtk_widget_grab_focus(table);
348 }
349 
create_strip(jack_host * plugin)350 plugin_strip *gtk_main_window::create_strip(jack_host *plugin)
351 {
352     /*    0          1    2             3      4          5           6          7
353      *  0 ┌──────────┬────────────────────────────────────────────────┬──────────┐ 0
354      *    │          │                   top light                    │          │
355      *  1 │          ├────┬─────────────┬──────┬──────────┬───────────┤          │ 1
356      *    │          │    │             │      │          │           │          │
357      *    │          │ X  │    label    │ MIDI │  inputs  │  outputs  │          │
358      *    │          │    │             │      │          │           │          │
359      *  2 │   left   ├────┼─────────────┼──────┼──────────┼───────────┤   right  │ 2
360      *    │   box    │    ╎             ╎      ╎          ╎           │    box   │
361      *    │          │   buttons and params    ╎          ╎           │          │
362      *    │          │    ╎             ╎      ╎          ╎           │          │
363      *  3 │          ├────┴─────────────┴──────┴──────────┴───────────┤          │ 3
364      *    │          │                  bottom light                  │          │
365      *  4 └──────────┴────────────────────────────────────────────────┴──────────┘ 4
366      *    0          1    2             3      4          5           6          7
367      */
368 
369     plugin_strip *strip = new plugin_strip;
370     strip->main_win = this;
371     strip->plugin = plugin;
372     strip->gui_win = NULL;
373     strip->connector = NULL;
374     strip->id = plugins.size();
375 
376     const plugin_metadata_iface *metadata = plugin->get_metadata_iface();
377     GtkAttachOptions ao = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL);
378 
379     strip->strip_table = gtk_table_new(7, 4, FALSE);
380     gtk_table_set_col_spacings(GTK_TABLE(strip->strip_table), 0);
381     gtk_table_set_row_spacings(GTK_TABLE(strip->strip_table), 0);
382 
383     // images for left side
384     GtkWidget *nwImg     = gtk_image_new_from_pixbuf(images.get("side_d_nw"));
385     GtkWidget *swImg     = gtk_image_new_from_pixbuf(images.get("side_d_sw"));
386     GtkWidget *wImg      = gtk_image_new_from_pixbuf(images.get("side_d_w"));
387     gtk_widget_set_size_request(GTK_WIDGET(wImg), 56, 1);
388 
389     // images for right side
390     GtkWidget *neImg     = gtk_image_new_from_pixbuf(images.get("side_d_ne"));
391     GtkWidget *seImg     = gtk_image_new_from_pixbuf(images.get("side_d_se"));
392     GtkWidget *eImg      = gtk_image_new_from_pixbuf(images.get("side_d_e"));
393     gtk_widget_set_size_request(GTK_WIDGET(eImg), 56, 1);
394 
395     // pack left box @ 0, 0
396     GtkWidget *leftBG  = gtk_event_box_new();
397     GtkWidget *leftBox = gtk_vbox_new(FALSE, 0);
398     gtk_container_add(GTK_CONTAINER(leftBG), leftBox);
399     gtk_widget_set_name(leftBG, "CalfMainLeft");
400     gtk_box_pack_start(GTK_BOX(leftBox), GTK_WIDGET(nwImg), FALSE, FALSE, 0);
401     gtk_box_pack_end(GTK_BOX(leftBox), GTK_WIDGET(swImg), FALSE, FALSE, 0);
402     gtk_widget_show_all(GTK_WIDGET(leftBG));
403     if (!get_config()->rack_ears)
404         gtk_widget_hide(GTK_WIDGET(leftBG));
405     gtk_table_attach(GTK_TABLE(strip->strip_table), leftBG, 0, 1, 0, 4, (GtkAttachOptions)(0), ao, 0, 0);
406 
407      // pack right box
408     GtkWidget *rightBG = gtk_event_box_new();
409     GtkWidget *rightBox = gtk_vbox_new(FALSE, 0);
410     gtk_container_add(GTK_CONTAINER(rightBG), rightBox);
411     gtk_widget_set_name(rightBG, "CalfMainRight");
412     gtk_box_pack_start(GTK_BOX(rightBox), GTK_WIDGET(neImg), FALSE, FALSE, 0);
413     gtk_box_pack_end(GTK_BOX(rightBox), GTK_WIDGET(seImg), FALSE, FALSE, 0);
414     gtk_widget_show_all(GTK_WIDGET(rightBG));
415     if (!get_config()->rack_ears)
416         gtk_widget_hide(GTK_WIDGET(rightBG));
417     gtk_table_attach(GTK_TABLE(strip->strip_table), rightBG, 6, 7, 0, 4, (GtkAttachOptions)(0), ao, 0, 0);
418 
419     strip->leftBG = leftBG;
420     strip->rightBG = rightBG;
421 
422     // top light
423     GtkWidget *topImg     = gtk_image_new_from_pixbuf(images.get("light_top"));
424     gtk_widget_set_size_request(GTK_WIDGET(topImg), 1, 1);
425     gtk_table_attach(GTK_TABLE(strip->strip_table), topImg, 1, 6, 0, 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK), (GtkAttachOptions)(0), 0, 0);
426     gtk_widget_show(topImg);
427 
428     // remove buton 1, 1
429     strip->extra = calf_button_new("×");
430     g_signal_connect(GTK_OBJECT(strip->extra), "clicked", G_CALLBACK(extra_button_pressed),
431         (plugin_ctl_iface *)strip);
432     gtk_widget_show(strip->extra);
433     gtk_table_attach(GTK_TABLE(strip->strip_table), GTK_WIDGET(strip->extra), 1, 2, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 5, 5);
434 
435     // title @ 2, 1
436     strip->name = gtk_label_new(NULL);
437     gtk_widget_set_name(GTK_WIDGET(strip->name), "Calf-Rack-Title");
438     gtk_label_set_markup(GTK_LABEL(strip->name), plugin->instance_name.c_str());//metadata->get_label());
439     gtk_label_set_justify(GTK_LABEL(strip->name), GTK_JUSTIFY_RIGHT);
440 
441     GtkWidget * align = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
442     gtk_widget_set_size_request(align, 180, -1);
443 
444     GtkWidget *ebox = gtk_event_box_new ();
445     gtk_event_box_set_visible_window(GTK_EVENT_BOX(ebox), FALSE);
446     gtk_widget_set_events(ebox, GDK_BUTTON_PRESS_MASK);
447     gtk_signal_connect(GTK_OBJECT(ebox), "button_press_event", GTK_SIGNAL_FUNC(on_edit_title), strip);
448 
449     gtk_container_add(GTK_CONTAINER(align), strip->name);
450     gtk_container_add(GTK_CONTAINER(ebox), align);
451     gtk_table_attach(GTK_TABLE(strip->strip_table), ebox, 2, 3, 1, 2, (GtkAttachOptions)0, ao, 10, 0);
452     gtk_widget_show_all(ebox);
453 
454     strip->entry = gtk_entry_new();
455     gtk_entry_set_text(GTK_ENTRY(strip->entry), "Calf-Rack-Entry");
456     gtk_widget_set_name(strip->entry, "Calf-Rack-Entry");
457     gtk_widget_set_size_request(strip->entry, 180, -1);
458     gtk_table_attach(GTK_TABLE(strip->strip_table), strip->entry, 2, 3, 1, 2, (GtkAttachOptions)0, ao, 10, 0);
459     gtk_widget_show_all(strip->entry);
460     gtk_signal_connect(GTK_OBJECT(strip->entry), "activate", GTK_SIGNAL_FUNC(on_activate_entry), strip);
461     gtk_signal_connect(GTK_OBJECT(strip->entry), "focus-out-event", GTK_SIGNAL_FUNC(on_blur_entry), strip);
462     gtk_widget_hide(strip->entry);
463 
464     // open button
465     strip->button = calf_toggle_button_new("Open");
466     g_signal_connect(GTK_OBJECT(strip->button), "toggled", G_CALLBACK(gui_button_pressed),
467         (plugin_ctl_iface *)strip);
468     gtk_widget_show(strip->button);
469     //g_signal_connect (GTK_OBJECT (widget), "value-changed", G_CALLBACK (toggle_value_changed), (gpointer)this);
470 
471     // connect button
472     strip->con = calf_toggle_button_new("Connect");
473     g_signal_connect(GTK_OBJECT(strip->con), "toggled", G_CALLBACK(connect_button_pressed),
474         (plugin_ctl_iface *)strip);
475     gtk_widget_show(strip->con);
476 
477     // button box @ 1, 2
478     GtkWidget *balign = gtk_alignment_new(0, 0.8, 0, 0);
479     GtkWidget *buttonBox = gtk_hbox_new(FALSE, 5);
480     gtk_box_pack_start(GTK_BOX(buttonBox), GTK_WIDGET(strip->button), FALSE, FALSE, 0);
481     gtk_box_pack_start(GTK_BOX(buttonBox), GTK_WIDGET(strip->con), FALSE, FALSE, 0);
482     gtk_container_add(GTK_CONTAINER(balign), buttonBox);
483     gtk_table_attach(GTK_TABLE(strip->strip_table), balign, 1, 3, 2, 3, ao, ao, 5, 5);
484     gtk_widget_show_all(balign);
485 
486     // param box
487     GtkWidget *palign = gtk_alignment_new(1, 1, 0, 0);
488     plugin_gui_widget *widget = new plugin_gui_widget(this, this);
489     strip->gui_widget = widget;
490     GtkWidget *paramBox = widget->create(plugin);
491     gtk_container_add(GTK_CONTAINER(palign), paramBox);
492     gtk_table_attach(GTK_TABLE(strip->strip_table), palign, 3, 6, 2, 3, ao, (GtkAttachOptions)0, 5, 5);
493     gtk_widget_show_all(palign);
494 
495     // midi box @ 2, 1
496     if (metadata->get_midi()) {
497         GtkWidget *led = calf_led_new();
498         GtkWidget *midiBox = gtk_vbox_new(FALSE, 1);
499         gtk_box_pack_start(GTK_BOX(midiBox), GTK_WIDGET(gtk_label_new("MIDI")), FALSE, FALSE, 0);
500         gtk_box_pack_start(GTK_BOX(midiBox), GTK_WIDGET(led), FALSE, FALSE, 0);
501         gtk_box_pack_start(GTK_BOX(midiBox), gtk_label_new(""), TRUE, TRUE, 0);
502         gtk_table_attach(GTK_TABLE(strip->strip_table), midiBox, 3, 4, 1, 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 5, 3);
503         gtk_widget_set_size_request(GTK_WIDGET(led), 25, 25);
504         strip->midi_in = led;
505         gtk_widget_show_all(midiBox);
506     } else {
507         GtkWidget *led = gtk_label_new("");
508         gtk_table_attach(GTK_TABLE(strip->strip_table), led, 3, 4, 1, 2, GTK_FILL, GTK_EXPAND, 5, 3);
509         gtk_widget_set_size_request(GTK_WIDGET(led), 25, 25);
510         strip->midi_in = led;
511         gtk_widget_show(strip->midi_in);
512     }
513 
514     strip->inBox = NULL;
515     strip->outBox = NULL;
516     strip->audio_in.clear();
517     strip->audio_out.clear();
518 
519     GtkWidget *vu;
520     if (metadata->get_input_count()) {
521 
522         GtkWidget *inBox  = gtk_vbox_new(FALSE, 1);
523 
524         gtk_box_pack_start(GTK_BOX(inBox), gtk_label_new("Audio In"),FALSE, FALSE, 0);
525 
526         for (int i = 0; i < metadata->get_input_count(); i++)
527         {
528             vu = create_vu_meter();
529             gtk_box_pack_start(GTK_BOX(inBox), vu, TRUE, TRUE, 0);
530             strip->audio_in.push_back(vu);
531         }
532         vu = create_meter_scale();
533         gtk_box_pack_start(GTK_BOX(inBox), vu, TRUE, TRUE, 0);
534 
535         strip->inBox = gtk_alignment_new(0.f, 0.f, 1.f, 0.f);
536         gtk_container_add(GTK_CONTAINER(strip->inBox), inBox);
537 
538         gtk_table_attach(GTK_TABLE(strip->strip_table), strip->inBox, 4, 5, 1, 2, ao, ao, 5, 3);
539 
540         if (get_config()->vu_meters)
541             gtk_widget_show_all(strip->inBox);
542 
543         gtk_widget_set_size_request(GTK_WIDGET(strip->inBox), 180, -1);
544     } else {
545         GtkWidget *inBox = gtk_label_new("");
546         gtk_table_attach(GTK_TABLE(strip->strip_table), inBox, 4, 5, 1, 2, GTK_FILL, GTK_EXPAND, 5, 3);
547         gtk_widget_set_size_request(GTK_WIDGET(inBox), 180, -1);
548         gtk_widget_show(inBox);
549     }
550 
551     if (metadata->get_output_count()) {
552 
553         GtkWidget *outBox  = gtk_vbox_new(FALSE, 1);
554 
555         gtk_box_pack_start(GTK_BOX(outBox), gtk_label_new("Audio Out"),TRUE, TRUE, 0);
556 
557         for (int i = 0; i < metadata->get_output_count(); i++)
558         {
559             vu = create_vu_meter();
560             gtk_box_pack_start(GTK_BOX(outBox), vu, TRUE, TRUE, 0);
561             strip->audio_out.push_back(vu);
562         }
563         vu = create_meter_scale();
564         gtk_box_pack_start(GTK_BOX(outBox), vu, TRUE, TRUE, 0);
565 
566         strip->outBox = gtk_alignment_new(0.f, 0.f, 1.f, 0.f);
567         gtk_container_add(GTK_CONTAINER(strip->outBox), outBox);
568 
569         gtk_table_attach(GTK_TABLE(strip->strip_table), strip->outBox, 5, 6, 1, 2, ao, ao, 5, 3);
570 
571         if (get_config()->vu_meters)
572             gtk_widget_show_all(strip->outBox);
573 
574         gtk_widget_set_size_request(GTK_WIDGET(strip->outBox), 180, -1);
575     } else {
576         GtkWidget *outBox = gtk_label_new("");
577         gtk_table_attach(GTK_TABLE(strip->strip_table), outBox, 5, 6, 1, 2, GTK_FILL, GTK_EXPAND, 5, 3);
578         gtk_widget_set_size_request(GTK_WIDGET(outBox), 180, -1);
579         gtk_widget_show(outBox);
580     }
581 
582 
583     // bottom light
584     GtkWidget *botImg     = gtk_image_new_from_pixbuf(images.get("light_bottom"));
585     gtk_widget_set_size_request(GTK_WIDGET(botImg), 1, 1);
586     gtk_table_attach(GTK_TABLE(strip->strip_table), botImg, 1, 6, 3, 4, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK), (GtkAttachOptions)(0), 0, 0);
587     gtk_widget_show(botImg);
588 
589     gtk_widget_show(GTK_WIDGET(strip->strip_table));
590 
591     return strip;
592 }
593 
sort_strips()594 void gtk_main_window::sort_strips()
595 {
596     if(plugins.size() <= 0) return;
597     int rack_float = get_config()->rack_float; // 0=horiz, 1=vert
598     int float_size = get_config()->float_size; // amout of rows/cols before line break
599     int posx, posy;
600     gtk_table_resize(GTK_TABLE(strips_table), (int)(plugins.size() / float_size + 1), float_size);
601     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
602     {
603         switch (rack_float) {
604             case 0:
605             default:
606                 posx = i->second->id % float_size;
607                 posy = (int)(i->second->id / float_size);
608                 break;
609             case 1:
610                 posy = i->second->id % float_size;
611                 posx = (int)(i->second->id / float_size);
612                 break;
613         }
614         bool rem = false;
615         if(i->second->strip_table->parent != NULL) {
616             rem = true;
617             g_object_ref(i->second->strip_table);
618             gtk_container_remove(GTK_CONTAINER(strips_table), GTK_WIDGET(i->second->strip_table));
619         }
620         gtk_table_attach(GTK_TABLE(strips_table), i->second->strip_table, posx, posx + 1, posy, posy + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK), 0, 0);
621         if(rem) g_object_unref(i->second->strip_table);
622     }
623 }
624 
update_strip(plugin_ctl_iface * plugin)625 void gtk_main_window::update_strip(plugin_ctl_iface *plugin)
626 {
627     // plugin_strip *strip = plugins[plugin];
628     // assert(strip);
629 
630 }
631 
open_gui(plugin_ctl_iface * plugin)632 void gtk_main_window::open_gui(plugin_ctl_iface *plugin)
633 {
634     plugin_gui_window *gui_win = new plugin_gui_window(this, this);
635     std::string title = "Calf - ";
636     gui_win->create(plugin, (title + ((jack_host *)plugin)->get_instance_name()).c_str(), plugin->get_metadata_iface()->get_id()); //(owner->get_client_name() + " - " + plugin->get_metadata_iface()->get_label()).c_str(), plugin->get_metadata_iface()->get_id());
637     gtk_widget_show(GTK_WIDGET(gui_win->toplevel));
638     plugins[plugin]->gui_win = gui_win;
639 }
640 
641 static const char *plugin_pre_xml =
642 "<ui>\n"
643 "  <menubar>\n"
644 "    <menu action=\"AddPluginMenuAction\">\n"
645 "      <placeholder name=\"plugin\">\n";
646 
647 static const char *plugin_post_xml =
648 "      </placeholder>\n"
649 "    </menu>\n"
650 "  </menubar>\n"
651 "</ui>\n"
652 ;
653 #define countof(X) ( (size_t) ( sizeof(X)/sizeof*(X) ) )
register_icons()654 void gtk_main_window::register_icons()
655 {
656     const char *names[]={"Allpass", "Amplifier", "Analyser",
657                          "Bandpass", "Chorus", "Comb", "Compressor",
658                          "Constant", "Converter", "Delay", "Distortion",
659                          "Dynamics", "Envelope", "EQ", "Expander",
660                          "Filter", "Flanger", "Function", "Gate",
661                          "Generator", "Highpass", "Instrument",
662                          "Limiter", "Mixer", "Modulator", "MultiEQ",
663                          "Oscillator", "ParaEQ", "Phaser", "Pitch",
664                          "Reverb", "Simulator", "Spatial", "Spectral",
665                          "Utility", "Waveshaper"};
666     factory = gtk_icon_factory_new ();
667     for (size_t i = 0; i < countof(names); i++) {
668         char name[1024];
669         strcpy(name, "LV2-");
670         strcat(name, names[i]);
671         if (!gtk_icon_factory_lookup(factory, name)) {
672             std::string iname = std::string(PKGLIBDIR) + "icons/LV2/" + names[i] + ".svg";
673             GdkPixbuf *buf    = gdk_pixbuf_new_from_file_at_size(iname.c_str(), 64, 64, NULL);
674             GtkIconSet *icon  = gtk_icon_set_new_from_pixbuf(buf);
675             gtk_icon_factory_add (factory, name, icon);
676             gtk_icon_set_unref(icon);
677             g_object_unref(buf);
678         }
679     }
680     gtk_icon_factory_add_default(factory);
681 }
682 
add_plugin_action(GtkWidget * src,gpointer data)683 void gtk_main_window::add_plugin_action(GtkWidget *src, gpointer data)
684 {
685     add_plugin_params *app = (add_plugin_params *)data;
686     app->main_win->new_plugin(app->name.c_str());
687 }
688 
action_destroy_notify(gpointer data)689 static void action_destroy_notify(gpointer data)
690 {
691     delete (gtk_main_window::add_plugin_params *)data;
692 }
693 
make_plugin_list(GtkActionGroup * actions)694 std::string gtk_main_window::make_plugin_list(GtkActionGroup *actions)
695 {
696     string s = plugin_pre_xml;
697     const plugin_registry::plugin_vector &plugins = plugin_registry::instance().get_all();
698     std::string type   = "";
699     std::string tmp    = "";
700     std::string last   = "";
701     unsigned int count = 0;
702     unsigned int size  = plugins.size();
703 
704     const plugin_metadata_iface *p = plugins[0];
705 
706     for(unsigned int i = 0; i <= size; i++)
707     {
708         if (i < size) {
709             p = plugins[i];
710             type = (p->get_plugin_info()).plugin_type;
711             type = type.substr(0, type.length() - 6);
712         }
713         if (type != last or i >= size or !i) {
714 
715             if (i) {
716                 if (count > 1) {
717                     s += "<menu action='" + last + "'>" + tmp + "</menu>";
718                     GtkAction *a = gtk_action_new(last.c_str(), last.c_str(), NULL, ("LV2-" + last).c_str());
719                     gtk_action_group_add_action(actions, a);
720                 } else {
721                     s += tmp;
722                 }
723             }
724             tmp = "";
725             last = type;
726             count = 0;
727         }
728         if (i < size) {
729             std::string action = "Add" + string(p->get_id()) + "Action";
730             std::string stock  = "LV2-" + type;
731             // TODO:
732             // add lv2 stock icons to plug-ins and not just to menus
733             // GTK_STOCK_OPEN -> ("LV2_" + type).c_str()
734             GtkActionEntry ae  = { action.c_str(), stock.c_str(), p->get_label(), NULL, NULL, (GCallback)add_plugin_action };
735             gtk_action_group_add_actions_full(actions, &ae, 1, (gpointer)new add_plugin_params(this, p->get_id()), action_destroy_notify);
736             tmp   += string("<menuitem always-show-image=\"true\" action=\"") + action + "\" />";
737             count += 1;
738         }
739     }
740     return s + plugin_post_xml;
741 }
742 
743 
describe_window(GtkWindow * win)744 window_state describe_window (GtkWindow *win)
745 {
746     window_state state = {};
747     int x, y, width, height;
748     gtk_window_get_position(win, &x, &y);
749     gtk_window_get_size(win, &width, &height);
750     state.screen = gtk_window_get_screen(win);
751     state.x = x;
752     state.y = y;
753     state.width = width;
754     state.height = height;
755     return state;
756 }
757 
position_window(GtkWidget * win,window_state state)758 void position_window (GtkWidget *win, window_state state)
759 {
760     gdk_window_move_resize(win->window, state.x, state.y, state.width, state.height);
761     gtk_window_set_screen(GTK_WINDOW(win), state.screen);
762 }
763 
tray_activate_cb(GObject * icon,gtk_main_window * main)764 static void tray_activate_cb(GObject *icon, gtk_main_window *main)
765 {
766     GtkWidget *widget = GTK_WIDGET(main->toplevel);
767     GtkWindow *window = GTK_WINDOW(widget);
768     GtkWidget *pwid;
769     GtkWindow *pwin;
770     gboolean visible = gtk_widget_get_visible(widget);
771     if (visible) {
772         main->winstate = describe_window(window);
773         gtk_widget_hide(widget);
774         for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = main->plugins.begin(); i != main->plugins.end(); ++i) {
775             if (i->second && i->second->gui_win) {
776                 pwid = i->second->gui_win->toplevel;
777                 pwin = GTK_WINDOW(pwid);
778                 i->second->gui_win->winstate = describe_window(pwin);
779                 gtk_widget_hide(pwid);
780             }
781         }
782     } else {
783         gtk_widget_show(widget);
784         gtk_window_deiconify(window);
785         position_window(widget, main->winstate);
786         for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = main->plugins.begin(); i != main->plugins.end(); ++i) {
787             if (i->second && i->second->gui_win) {
788                 pwid = i->second->gui_win->toplevel;
789                 pwin = GTK_WINDOW(pwid);
790                 gtk_widget_show(pwid);
791                 gtk_window_deiconify(pwin);
792                 position_window(pwid, i->second->gui_win->winstate);
793             }
794         }
795     }
796 }
797 
tray_popup_cb(GtkStatusIcon * icon,guint button,guint32 time,gpointer menu)798 static void tray_popup_cb(GtkStatusIcon *icon, guint button, guint32 time, gpointer menu)
799 {
800     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, gtk_status_icon_position_menu, icon, button, time);
801 }
802 
window_delete_cb(GtkWindow * window,GdkEvent * event,gtk_main_window * main)803 static gint window_delete_cb(GtkWindow *window, GdkEvent *event, gtk_main_window *main)
804 {
805     if (main->get_config()->win_to_tray) {
806         tray_activate_cb(NULL, main);
807         return TRUE;
808     } else {
809         return FALSE;
810     }
811 }
812 
window_destroy_cb(GtkWindow * window,gtk_main_window * main)813 static void window_destroy_cb(GtkWindow *window, gtk_main_window *main)
814 {
815     main->owner->on_main_window_destroy();
816 }
817 
window_hide(gtk_main_window * main)818 static gint window_hide (gtk_main_window *main)
819 {
820     main->winstate = describe_window(main->toplevel);
821     gtk_widget_hide(GTK_WIDGET(main->toplevel));
822     return FALSE;
823 }
824 
create()825 void gtk_main_window::create()
826 {
827     register_icons();
828     toplevel = GTK_WINDOW(gtk_window_new (GTK_WINDOW_TOPLEVEL));
829     std::string title = "Calf JACK Host";
830     if (!owner->get_client_name().empty())
831         title = title + " - session: " + owner->get_client_name();
832     gtk_window_set_title(toplevel, title.c_str());
833     gtk_window_set_icon_name(toplevel, "calf");
834     gtk_window_set_role(toplevel, "calf_rack");
835     //due to https://developer.gnome.org/gtk2/stable/GtkWindow.html
836     //gtk_window_set_wmclass (). even though it says not to use this
837     //function, it is the only way to get primitive WMs like fluxbox
838     //to separate calf instances so that it can remember different positions.
839     //Unlike what is stated there gtk_window_set_role() is not
840     //interpreted correctly by fluxbox and thus wmclass call is not
841     //yet obsolete
842     gtk_window_set_wmclass(toplevel, title.c_str(), "calfjackhost");
843 
844     load_style((PKGLIBDIR "styles/" + get_config()->style).c_str());
845 
846     is_closed = false;
847     gtk_window_set_resizable(toplevel, false);
848 
849     all_vbox = gtk_vbox_new(0, FALSE);
850 
851     ui_mgr = gtk_ui_manager_new();
852     std_actions = gtk_action_group_new("default");
853     gtk_action_group_add_actions(std_actions, actions, sizeof(actions)/sizeof(actions[0]), this);
854     GError *error = NULL;
855     gtk_ui_manager_insert_action_group(ui_mgr, std_actions, 0);
856     gtk_ui_manager_add_ui_from_string(ui_mgr, ui_xml, -1, &error);
857     gtk_box_pack_start(GTK_BOX(all_vbox), gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar"), false, false, 0);
858 
859     gtk_widget_set_size_request(GTK_WIDGET(gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar")), 640, -1);
860 
861     gtk_widget_set_name(GTK_WIDGET(gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar")), "Calf-Menu");
862 
863     plugin_actions = gtk_action_group_new("plugins");
864     string plugin_xml = make_plugin_list(plugin_actions);
865     gtk_ui_manager_insert_action_group(ui_mgr, plugin_actions, 0);
866     gtk_ui_manager_add_ui_from_string(ui_mgr, plugin_xml.c_str(), -1, &error);
867 
868     strips_table = gtk_table_new(0, 1, FALSE);
869     gtk_table_set_col_spacings(GTK_TABLE(strips_table), 0);
870     gtk_table_set_row_spacings(GTK_TABLE(strips_table), 0);
871 
872     for(GList *p = GTK_TABLE(strips_table)->children; p != NULL; p = p->next)
873     {
874         GtkTableChild *c = (GtkTableChild *)p->data;
875         if (c->top_attach == 0) {
876             gtk_misc_set_alignment(GTK_MISC(c->widget), 0.5, 0);
877         }
878     }
879     for (std::vector<jack_host *>::iterator i = plugin_queue.begin(); i != plugin_queue.end(); ++i)
880     {
881         plugin_strip *st = create_strip(*i);
882         plugins[*i] = st;
883         update_strip(*i);
884     }
885     sort_strips();
886 
887     GtkWidget *evbox = gtk_event_box_new();
888     gtk_widget_set_name(evbox, "Calf-Rack");
889     gtk_container_add(GTK_CONTAINER(evbox), strips_table);
890     gtk_container_add(GTK_CONTAINER(all_vbox), evbox);
891     gtk_container_add(GTK_CONTAINER(toplevel), all_vbox);
892 
893     gtk_signal_connect(GTK_OBJECT(evbox), "button-press-event", GTK_SIGNAL_FUNC(on_table_clicked), NULL);
894     gtk_widget_set_can_focus(evbox, TRUE);
895 
896     gtk_widget_set_name(GTK_WIDGET(strips_table), "Calf-Container");
897 
898     gtk_window_add_accel_group(toplevel, gtk_ui_manager_get_accel_group(ui_mgr));
899 
900     gtk_widget_show(GTK_WIDGET(strips_table));
901     gtk_widget_show(GTK_WIDGET(evbox));
902     gtk_widget_show(GTK_WIDGET(all_vbox));
903     gtk_widget_show(GTK_WIDGET(toplevel));
904 
905     source_id = g_timeout_add_full(G_PRIORITY_DEFAULT, 1000/30, on_idle, this, NULL); // 30 fps should be enough for everybody
906 
907     notifier = get_config_db()->add_listener(this);
908     on_config_change();
909     g_signal_connect(GTK_OBJECT(toplevel), "destroy", G_CALLBACK(window_destroy_cb), this);
910     g_signal_connect(GTK_OBJECT(toplevel), "delete_event", G_CALLBACK(window_delete_cb), this);
911 
912     if (get_config()->win_start_hidden)
913         g_idle_add((GSourceFunc)window_hide, this);
914 }
915 
create_status_icon()916 void gtk_main_window::create_status_icon()
917 {
918     GtkStatusIcon *icon = gtk_status_icon_new_from_icon_name("calf");
919 
920     GtkWidget *menu = gtk_menu_new();
921     GtkWidget *view = gtk_menu_item_new_with_label ("View");
922     GtkWidget *exit = gtk_menu_item_new_with_label ("Exit");
923     g_signal_connect (G_OBJECT (view), "activate", G_CALLBACK (tray_activate_cb), this);
924     g_signal_connect (G_OBJECT (exit), "activate", G_CALLBACK (window_destroy_cb), this);
925     gtk_menu_shell_append (GTK_MENU_SHELL (menu), view);
926     gtk_menu_shell_append (GTK_MENU_SHELL (menu), exit);
927     gtk_widget_show_all (menu);
928 
929     gtk_status_icon_set_tooltip (icon, "Calf Studio Gear");
930 
931     g_signal_connect(GTK_STATUS_ICON (icon), "activate", GTK_SIGNAL_FUNC (tray_activate_cb), this);
932     g_signal_connect(GTK_STATUS_ICON (icon), "popup-menu", GTK_SIGNAL_FUNC (tray_popup_cb), menu);
933 }
934 
on_config_change()935 void gtk_main_window::on_config_change()
936 {
937     get_config()->load(get_config_db());
938     show_rack_ears(get_config()->rack_ears);
939     show_vu_meters(get_config()->vu_meters);
940     sort_strips();
941 }
942 
refresh_plugin(plugin_ctl_iface * plugin)943 void gtk_main_window::refresh_plugin(plugin_ctl_iface *plugin)
944 {
945     if (plugins.count(plugin))
946     {
947         if (plugins[plugin]->gui_win)
948             plugins[plugin]->gui_win->refresh();
949         if (plugins[plugin]->gui_widget)
950             plugins[plugin]->gui_widget->refresh();
951     }
952 }
953 
refresh_plugin_param(plugin_ctl_iface * plugin,int param_no)954 void gtk_main_window::refresh_plugin_param(plugin_ctl_iface *plugin, int param_no)
955 {
956     if (plugins.count(plugin))
957     {
958         if (plugins[plugin]->gui_win)
959             plugins[plugin]->gui_win->get_gui()->refresh(param_no);
960         if (plugins[plugin]->gui_widget)
961             plugins[plugin]->gui_widget->get_gui()->refresh(param_no);
962     }
963 }
964 
on_closed()965 void gtk_main_window::on_closed()
966 {
967     if (notifier)
968     {
969         delete notifier;
970         notifier = NULL;
971     }
972     if (source_id)
973         g_source_remove(source_id);
974     is_closed = true;
975     toplevel = NULL;
976 
977     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
978     {
979         if (i->second && i->second->gui_win) {
980             i->second->gui_win->close();
981         }
982     }
983     plugins.clear();
984 }
985 
LVL(float value)986 static inline float LVL(float value)
987 {
988     return value; //sqrt(value) * 0.75;
989 }
990 
on_idle(void * data)991 gboolean gtk_main_window::on_idle(void *data)
992 {
993     gtk_main_window *self = (gtk_main_window *)data;
994 
995     self->owner->on_idle();
996 
997     if (!self->refresh_controller.check_redraw(GTK_WIDGET(self->toplevel)))
998         return TRUE;
999 
1000     for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = self->plugins.begin(); i != self->plugins.end(); ++i)
1001     {
1002         if (i->second)
1003         {
1004             plugin_ctl_iface *plugin = i->first;
1005             plugin_strip *strip = i->second;
1006             int idx = 0;
1007             if (strip->inBox && gtk_widget_is_drawable (strip->inBox)) {
1008                 for (int i = 0; i < (int)strip->audio_in.size(); i++) {
1009                     calf_vumeter_set_value(CALF_VUMETER(strip->audio_in[i]), LVL(plugin->get_level(idx++)));
1010                 }
1011             }
1012             else
1013                 idx += strip->audio_in.size();
1014             if (strip->outBox && gtk_widget_is_drawable (strip->outBox)) {
1015                 for (int i = 0; i < (int)strip->audio_out.size(); i++) {
1016                     calf_vumeter_set_value(CALF_VUMETER(strip->audio_out[i]), LVL(plugin->get_level(idx++)));
1017                 }
1018             }
1019             else
1020                 idx += strip->audio_out.size();
1021             if (plugin->get_metadata_iface()->get_midi()) {
1022                 calf_led_set_value (CALF_LED (strip->midi_in), plugin->get_level(idx++));
1023             }
1024         }
1025     }
1026     return TRUE;
1027 }
1028 
open_file()1029 void gtk_main_window::open_file()
1030 {
1031     GtkWidget *dialog;
1032     dialog = gtk_file_chooser_dialog_new ("Open File",
1033         toplevel,
1034         GTK_FILE_CHOOSER_ACTION_OPEN,
1035         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1036         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
1037         NULL);
1038     if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1039     {
1040         char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1041         char *error = owner->open_file(filename);
1042         if (error)
1043             display_error(error, filename);
1044         else
1045             owner->set_current_filename(filename);
1046         g_free (filename);
1047         free (error);
1048     }
1049     gtk_widget_destroy (dialog);
1050 }
1051 
save_file()1052 bool gtk_main_window::save_file()
1053 {
1054     if (owner->get_current_filename().empty())
1055         return save_file_as();
1056 
1057     const char *error = owner->save_file(owner->get_current_filename().c_str());
1058     if (error)
1059     {
1060         display_error(error, owner->get_current_filename().c_str());
1061         return false;
1062     }
1063     return true;
1064 }
1065 
save_file_as()1066 bool gtk_main_window::save_file_as()
1067 {
1068     GtkWidget *dialog;
1069     bool success = false;
1070     dialog = gtk_file_chooser_dialog_new ("Save File",
1071         toplevel,
1072         GTK_FILE_CHOOSER_ACTION_SAVE,
1073         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
1074         GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
1075         NULL);
1076     if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
1077     {
1078         char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
1079         char *error = owner->save_file(filename);
1080         if (error)
1081             display_error(error, filename);
1082         else
1083         {
1084             owner->set_current_filename(filename);
1085             success = true;
1086         }
1087         g_free (filename);
1088         free(error);
1089     }
1090     gtk_widget_destroy (dialog);
1091     return success;
1092 }
1093 
display_error(const char * error,const char * filename)1094 void gtk_main_window::display_error(const char *error, const char *filename)
1095 {
1096     GtkWidget *dialog;
1097     dialog = gtk_message_dialog_new_with_markup (toplevel, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error, filename, NULL);
1098     gtk_dialog_run (GTK_DIALOG (dialog));
1099     gtk_widget_destroy (dialog);
1100 }
1101 
create_progress_window()1102 GtkWidget *gtk_main_window::create_progress_window()
1103 {
1104     GtkWidget *tlw = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
1105     gtk_window_set_type_hint (GTK_WINDOW (tlw), GDK_WINDOW_TYPE_HINT_DIALOG);
1106     GtkWidget *pbar = gtk_progress_bar_new();
1107     gtk_container_add (GTK_CONTAINER(tlw), pbar);
1108     gtk_widget_show_all (pbar);
1109     return tlw;
1110 }
1111 
report_progress(float percentage,const std::string & message)1112 void gtk_main_window::report_progress(float percentage, const std::string &message)
1113 {
1114     if (percentage < 100)
1115     {
1116         if (!progress_window) {
1117             progress_window = create_progress_window();
1118             gtk_window_set_modal (GTK_WINDOW (progress_window), TRUE);
1119             if (toplevel)
1120                 gtk_window_set_transient_for (GTK_WINDOW (progress_window), toplevel);
1121             gtk_widget_show(progress_window);
1122         }
1123         GtkWidget *pbar = gtk_bin_get_child (GTK_BIN (progress_window));
1124         if (!message.empty())
1125             gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pbar), message.c_str());
1126         gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pbar), percentage / 100.0);
1127     }
1128     else
1129     {
1130         if (progress_window) {
1131             gtk_window_set_modal (GTK_WINDOW (progress_window), FALSE);
1132             gtk_widget_destroy (progress_window);
1133             progress_window = NULL;
1134         }
1135     }
1136 
1137     while (gtk_events_pending ())
1138         gtk_main_iteration ();
1139 }
1140 
add_condition(const std::string & name)1141 void gtk_main_window::add_condition(const std::string &name)
1142 {
1143     conditions.insert(name);
1144 }
1145 
show_error(const std::string & text)1146 void gtk_main_window::show_error(const std::string &text)
1147 {
1148     GtkWidget *widget = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", text.c_str());
1149     gtk_dialog_run (GTK_DIALOG (widget));
1150     gtk_widget_destroy (widget);
1151 }
1152 
get_styles()1153 GtkListStore *gtk_main_window::get_styles()
1154 {
1155     std::vector <calf_utils::direntry> list = calf_utils::list_directory(PKGLIBDIR"styles");
1156     GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
1157     for (std::vector<calf_utils::direntry>::iterator i = list.begin(); i != list.end(); i++) {
1158         string title = i->name;
1159         std::string rcf = i->full_path + "/gtk.rc";
1160         ifstream infile(rcf.c_str());
1161         if (infile.good()) {
1162             string line;
1163             getline(infile, line);
1164             title = line.substr(1);
1165         }
1166         gtk_list_store_insert_with_values(store, NULL, -1,
1167                                   0, title.c_str(),
1168                                   1, i->name.c_str(),
1169                                   -1);
1170     }
1171     return store;
1172 }
load_style(std::string path)1173 void gtk_main_window::load_style(std::string path) {
1174     gtk_rc_parse((path + "/gtk.rc").c_str());
1175     gtk_rc_reset_styles(gtk_settings_get_for_screen(gdk_screen_get_default()));
1176     images.set_path(path);
1177 }
1178