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