Preferences: Selector for existing gtkrc files
[calf.git] / src / gtk_main_win.cpp
blobeaaf1c8e52651b72b3dd9ab8c3d5a0aec1ca93bc
1 /* Calf DSP Library
2 * GUI main window.
3 * Copyright (C) 2007-2011 Krzysztof Foltman
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.
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.
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
21 #include <calf/ctl_led.h>
22 #include <calf/ctl_vumeter.h>
23 #include <calf/giface.h>
24 #include <calf/gui.h>
25 #include <calf/custom_ctl.h>
26 #include <calf/preset.h>
27 #include <calf/gtk_main_win.h>
28 #include <calf/jackhost.h>
29 #include <iostream>
30 #include <fstream>
32 using namespace calf_plugins;
33 using namespace std;
35 gtk_main_window::gtk_main_window()
37 toplevel = NULL;
38 owner = NULL;
39 notifier = NULL;
40 is_closed = true;
41 progress_window = NULL;
44 static const char *ui_xml =
45 "<ui>\n"
46 " <menubar>\n"
47 " <menu action=\"FileMenuAction\">\n"
48 " <menuitem action=\"FileOpen\"/>\n"
49 " <menuitem action=\"FileSave\"/>\n"
50 " <menuitem action=\"FileSaveAs\"/>\n"
51 " <separator/>\n"
52 " <menuitem action=\"FileReorder\"/>\n"
53 " <separator/>\n"
54 " <menuitem action=\"FilePreferences\"/>\n"
55 " <separator/>\n"
56 " <menuitem action=\"FileQuit\"/>\n"
57 " </menu>\n"
58 " <menu action=\"AddPluginMenuAction\" />\n"
59 " </menubar>\n"
60 "</ui>\n"
63 const GtkActionEntry gtk_main_window::actions[] = {
64 { "FileMenuAction", NULL, "_File", NULL, "File-related operations", NULL },
65 { "FileOpen", GTK_STOCK_OPEN, "_Open", "<Ctrl>O", "Open a rack file", (GCallback)on_open_action },
66 { "FileSave", GTK_STOCK_SAVE, "_Save", "<Ctrl>S", "Save a rack file", (GCallback)on_save_action },
67 { "FileSaveAs", GTK_STOCK_SAVE_AS, "Save _as...", NULL, "Save a rack file as", (GCallback)on_save_as_action },
68 { "HostMenuAction", NULL, "_Host", NULL, "Host-related operations", NULL },
69 { "AddPluginMenuAction", NULL, "_Add plugin", NULL, "Add a plugin to the rack", NULL },
70 { "FileReorder", NULL, "_Reorder plugins", NULL, "Reorder plugins to minimize latency (experimental)", (GCallback)on_reorder_action },
71 { "FilePreferences", GTK_STOCK_PREFERENCES, "_Preferences...", NULL, "Adjust preferences", (GCallback)on_preferences_action },
72 { "FileQuit", GTK_STOCK_QUIT, "_Quit", "<Ctrl>Q", "Exit application", (GCallback)on_exit_action },
75 void gtk_main_window::on_open_action(GtkWidget *widget, gtk_main_window *main)
77 main->open_file();
80 void gtk_main_window::on_save_action(GtkWidget *widget, gtk_main_window *main)
82 main->save_file();
85 void gtk_main_window::on_save_as_action(GtkWidget *widget, gtk_main_window *main)
87 main->save_file_as();
90 void gtk_main_window::on_reorder_action(GtkWidget *widget, gtk_main_window *main)
92 main->owner->reorder_plugins();
95 void gtk_main_window::on_preferences_action(GtkWidget *widget, gtk_main_window *main)
97 GtkBuilder *prefs_builder = gtk_builder_new();
98 GError *error = NULL;
99 const gchar *objects[] = { "preferences", NULL };
100 if (!gtk_builder_add_objects_from_file(prefs_builder, PKGLIBDIR "/calf-gui.xml", (gchar **)objects, &error))
102 g_warning("Cannot load preferences dialog: %s", error->message);
103 g_error_free(error);
104 g_object_unref(G_OBJECT(prefs_builder));
105 return;
108 // styles selector
109 GtkCellRenderer *cell;
110 GtkListStore *store = main->get_styles();
111 GtkComboBox *cb = GTK_COMBO_BOX(gtk_builder_get_object(prefs_builder, "rcstyles"));
112 gtk_combo_box_set_model(cb, GTK_TREE_MODEL(store));
113 cell = gtk_cell_renderer_text_new();
114 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cb), cell, TRUE);
115 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cb), cell, "text", 0, NULL);
116 //gtk_tree_model_(cb);
117 GtkTreeIter iter;
118 gboolean valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter);
119 GValue title = {0,};
120 while (valid) {
121 gtk_tree_model_get_value(GTK_TREE_MODEL(store), &iter, 0, &title);
122 if (main->get_config()->style.compare(g_value_get_string(&title)) == 0) {
123 gtk_combo_box_set_active_iter(cb, &iter);
124 break;
126 valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
127 g_value_unset(&title);
131 GtkWidget *preferences_dlg = GTK_WIDGET(gtk_builder_get_object(prefs_builder, "preferences"));
132 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-rack-ears")), main->get_config()->rack_ears);
133 gtk_spin_button_set_range(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "rack-float")), 0, 1);
134 gtk_spin_button_set_range(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")), 1, 32);
135 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "rack-float")), 1, 1);
136 gtk_spin_button_set_increments(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")), 1, 1);
137 gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "rack-float")), main->get_config()->rack_float);
138 gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")), main->get_config()->float_size);
139 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-vu-meters")), main->get_config()->vu_meters);
140 int response = gtk_dialog_run(GTK_DIALOG(preferences_dlg));
141 if (response == GTK_RESPONSE_OK)
143 main->get_config()->rack_ears = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-rack-ears")));
144 main->get_config()->rack_float = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "rack-float")));
145 main->get_config()->float_size = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(prefs_builder, "float-size")));
146 main->get_config()->vu_meters = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(prefs_builder, "show-vu-meters")));
147 main->get_config()->save(main->get_config_db());
149 gtk_widget_destroy(preferences_dlg);
150 g_object_unref(G_OBJECT(prefs_builder));
153 void gtk_main_window::on_exit_action(GtkWidget *widget, gtk_main_window *main)
155 gtk_widget_destroy(GTK_WIDGET(main->toplevel));
158 void gtk_main_window::add_plugin(jack_host *plugin)
160 if (toplevel)
162 plugin_strip *strip = create_strip(plugin);
163 plugins[plugin] = strip;
164 update_strip(plugin);
165 sort_strips();
167 else {
168 plugin_queue.push_back(plugin);
169 //plugins[plugin] = NULL;
173 void gtk_main_window::del_plugin(plugin_ctl_iface *plugin)
175 if (!plugins.count(plugin))
176 return;
177 plugin_strip *strip = plugins[plugin];
178 if (strip->gui_win)
179 strip->gui_win->close();
180 vector<GtkWidget *> to_destroy;
181 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
183 if (i->second == strip)
184 to_destroy.push_back(i->second->strip_table);
185 else if(i->second->id > strip->id)
186 i->second->id--;
188 for (unsigned int i = 0; i < to_destroy.size(); i++)
189 gtk_container_remove(GTK_CONTAINER(strips_table), to_destroy[i]);
190 plugins.erase(plugin);
191 sort_strips();
194 void gtk_main_window::set_window(plugin_ctl_iface *plugin, plugin_gui_window *gui_win)
196 if (!plugins.count(plugin))
197 return;
198 plugin_strip *strip = plugins[plugin];
199 if (!strip)
200 return;
201 strip->gui_win = gui_win;
202 if (!is_closed)
203 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(strip->button), gui_win != NULL);
206 void gtk_main_window::refresh_all_presets(bool builtin_too)
208 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
210 if (i->second && i->second->gui_win) {
211 char ch = '0';
212 i->second->gui_win->fill_gui_presets(true, ch);
213 i->second->gui_win->fill_gui_presets(false, ch);
218 static gboolean
219 gui_button_pressed(GtkWidget *button, plugin_strip *strip)
221 GtkToggleButton *tb = GTK_TOGGLE_BUTTON(button);
222 if ((gtk_toggle_button_get_active(tb) != 0) == (strip->gui_win != NULL))
223 return FALSE;
224 if (strip->gui_win) {
225 strip->gui_win->close();
226 strip->gui_win = NULL;
227 } else {
228 strip->main_win->open_gui(strip->plugin);
230 return TRUE;
232 static gboolean
233 connect_button_pressed(GtkWidget *button, plugin_strip *strip)
235 //GtkToggleButton *tb = GTK_TOGGLE_BUTTON(button);
236 if (strip->connector) {
237 strip->connector->close();
238 strip->connector = NULL;
239 } else {
240 strip->connector = new calf_connector(strip);
242 return TRUE;
244 static gboolean
245 extra_button_pressed(GtkWidget *button, plugin_strip *strip)
247 if (strip->connector)
248 strip->connector->close();
249 strip->main_win->owner->remove_plugin(strip->plugin);
250 return TRUE;
253 void gtk_main_window::show_rack_ears(bool show)
255 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
257 if (show)
259 gtk_widget_show(i->second->leftBox);
260 gtk_widget_show(i->second->rightBox);
262 else
264 gtk_widget_hide(i->second->leftBox);
265 gtk_widget_hide(i->second->rightBox);
270 void gtk_main_window::show_vu_meters(bool show)
272 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
274 if (show)
276 if (i->second->inBox)
277 gtk_widget_show(i->second->inBox);
278 if (i->second->outBox)
279 gtk_widget_show(i->second->outBox);
281 else
283 if (i->second->inBox)
284 gtk_widget_hide(i->second->inBox);
285 if (i->second->outBox)
286 gtk_widget_hide(i->second->outBox);
291 plugin_strip *gtk_main_window::create_strip(jack_host *plugin)
293 plugin_strip *strip = new plugin_strip;
294 strip->main_win = this;
295 strip->plugin = plugin;
296 strip->gui_win = NULL;
297 strip->connector = NULL;
298 strip->id = plugins.size();
300 GtkAttachOptions ao = (GtkAttachOptions)(GTK_EXPAND | GTK_FILL);
302 strip->strip_table = gtk_table_new(6, 4, FALSE);
303 gtk_table_set_col_spacings(GTK_TABLE(strip->strip_table), 0);
304 gtk_table_set_row_spacings(GTK_TABLE(strip->strip_table), 0);
306 int row = 0;
307 // g_object_get(G_OBJECT(strips_table), "n-rows", &row, "n-columns", &cols, NULL);
308 // gtk_table_resize(GTK_TABLE(strips_table), row + 4, cols);
309 // printf("%03d %03d", row, cols);
310 // images for left side
311 GtkWidget *nwImg = gtk_image_new_from_file(PKGLIBDIR "/side_d_nw.png");
312 GtkWidget *swImg = gtk_image_new_from_file(PKGLIBDIR "/side_d_sw.png");
313 GtkWidget *wImg = gtk_image_new_from_file(PKGLIBDIR "/side_d_w.png");
314 gtk_widget_set_size_request(GTK_WIDGET(wImg), 56, 1);
316 // images for right side
317 GtkWidget *neImg = gtk_image_new_from_file(PKGLIBDIR "/side_d_ne.png");
318 GtkWidget *seImg = gtk_image_new_from_file(PKGLIBDIR "/side_d_se.png");
319 GtkWidget *eImg = gtk_image_new_from_file(PKGLIBDIR "/side_d_e.png");
320 gtk_widget_set_size_request(GTK_WIDGET(eImg), 56, 1);
322 // pack left box
323 GtkWidget *leftBox = gtk_vbox_new(FALSE, 0);
324 gtk_box_pack_start(GTK_BOX(leftBox), GTK_WIDGET(nwImg), FALSE, FALSE, 0);
325 gtk_box_pack_start(GTK_BOX(leftBox), GTK_WIDGET(wImg), TRUE, TRUE, 0);
326 gtk_box_pack_end(GTK_BOX(leftBox), GTK_WIDGET(swImg), FALSE, FALSE, 0);
327 gtk_widget_show_all(GTK_WIDGET(leftBox));
328 if (!get_config()->rack_ears)
329 gtk_widget_hide(GTK_WIDGET(leftBox));
330 gtk_table_attach(GTK_TABLE(strip->strip_table), leftBox, 0, 1, row, row + 4, (GtkAttachOptions)(0), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
332 // pack right box
333 GtkWidget *rightBox = gtk_vbox_new(FALSE, 0);
334 gtk_box_pack_start(GTK_BOX(rightBox), GTK_WIDGET(neImg), FALSE, FALSE, 0);
335 gtk_box_pack_start(GTK_BOX(rightBox), GTK_WIDGET(eImg), TRUE, TRUE, 0);
336 gtk_box_pack_end(GTK_BOX(rightBox), GTK_WIDGET(seImg), FALSE, FALSE, 0);
337 gtk_widget_show_all(GTK_WIDGET(rightBox));
338 if (!get_config()->rack_ears)
339 gtk_widget_hide(GTK_WIDGET(rightBox));
340 gtk_table_attach(GTK_TABLE(strip->strip_table), rightBox, 5, 6, row, row + 4, (GtkAttachOptions)(0), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 0, 0);
342 strip->leftBox = leftBox;
343 strip->rightBox = rightBox;
346 // top light
347 GtkWidget *topImg = gtk_image_new_from_file(PKGLIBDIR "/light_top.png");
348 gtk_widget_set_size_request(GTK_WIDGET(topImg), 1, 1);
349 gtk_table_attach(GTK_TABLE(strip->strip_table), topImg, 1, 5, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK), (GtkAttachOptions)(0), 0, 0);
350 gtk_widget_show(topImg);
351 strip->name = topImg;
352 row ++;
354 // title @ 1, 1
355 const plugin_metadata_iface *metadata = plugin->get_metadata_iface();
356 GtkWidget *title = gtk_label_new(NULL);
357 gtk_widget_set_name(GTK_WIDGET(title), "Calf-Rack-Title");
358 gtk_label_set_markup(GTK_LABEL(title), metadata->get_label());
359 gtk_label_set_justify(GTK_LABEL(title), GTK_JUSTIFY_RIGHT);
360 GtkWidget * align = gtk_alignment_new(0.0, 0.5, 0.0, 0.0);
361 gtk_container_add(GTK_CONTAINER(align), title);
362 gtk_table_attach(GTK_TABLE(strip->strip_table), align, 1, 2, row, row + 1, (GtkAttachOptions)(GTK_FILL), (GtkAttachOptions)(GTK_FILL) , 10, 0);
363 gtk_widget_show_all(align);
365 // open button
366 GtkWidget *label = calf_toggle_button_new("Edit");
367 strip->button = label;
368 gtk_widget_set_size_request(GTK_WIDGET(label), 80, -1);
369 g_signal_connect(GTK_OBJECT(label), "toggled", G_CALLBACK(gui_button_pressed),
370 (plugin_ctl_iface *)strip);
371 gtk_widget_show(strip->button);
373 // connect button
374 GtkWidget *con = calf_toggle_button_new("Connect");
375 strip->con = con;
376 gtk_widget_set_size_request(GTK_WIDGET(con), -1, -1);
377 g_signal_connect(GTK_OBJECT(con), "toggled", G_CALLBACK(connect_button_pressed),
378 (plugin_ctl_iface *)strip);
379 gtk_widget_show(strip->con);
381 // delete buton
382 GtkWidget *extra = calf_button_new("Remove");
383 strip->extra = extra;
384 //gtk_widget_set_size_request(GTK_WIDGET(extra), 100, -1);
385 g_signal_connect(GTK_OBJECT(extra), "clicked", G_CALLBACK(extra_button_pressed),
386 (plugin_ctl_iface *)strip);
387 gtk_widget_show(strip->extra);
389 // button box @ 1, 2
390 GtkWidget *buttonBox = gtk_hbox_new(FALSE, 5);
391 gtk_box_pack_start(GTK_BOX(buttonBox), GTK_WIDGET(strip->button), FALSE, FALSE, 0);
392 gtk_box_pack_start(GTK_BOX(buttonBox), GTK_WIDGET(strip->con), FALSE, FALSE, 0);
393 gtk_box_pack_start(GTK_BOX(buttonBox), GTK_WIDGET(strip->extra), FALSE, FALSE, 0);
394 gtk_table_attach(GTK_TABLE(strip->strip_table), buttonBox, 1, 2, row + 1, row + 2, (GtkAttachOptions)0, (GtkAttachOptions)0, 10, 10);
395 gtk_widget_show(buttonBox);
397 // midi box
398 if (metadata->get_midi()) {
399 label = calf_led_new();
400 GtkWidget *midiBox = gtk_vbox_new(FALSE, 1);
401 gtk_box_pack_start(GTK_BOX(midiBox), GTK_WIDGET(gtk_label_new("Midi")), FALSE, FALSE, 0);
402 gtk_box_pack_start(GTK_BOX(midiBox), GTK_WIDGET(label), FALSE, FALSE, 0);
403 gtk_table_attach(GTK_TABLE(strip->strip_table), midiBox, 2, 3, row, row + 1, (GtkAttachOptions)0, (GtkAttachOptions)0, 5, 3);
404 gtk_widget_set_size_request(GTK_WIDGET(label), 25, 25);
405 strip->midi_in = label;
406 gtk_widget_show_all(midiBox);
407 } else {
408 label = gtk_label_new("");
409 gtk_table_attach(GTK_TABLE(strip->strip_table), label, 2, 3, row, row + 1, GTK_FILL, GTK_EXPAND, 5, 3);
410 gtk_widget_set_size_request(GTK_WIDGET(label), 25, 25);
411 strip->midi_in = label;
412 gtk_widget_show(strip->midi_in);
414 strip->midi_in = label;
416 strip->inBox = NULL;
417 strip->outBox = NULL;
418 strip->audio_in.clear();
419 strip->audio_out.clear();
421 if (metadata->get_input_count()) {
423 GtkWidget *inBox = gtk_vbox_new(FALSE, 1);
425 gtk_box_pack_start(GTK_BOX(inBox), gtk_label_new("Audio In"),FALSE, FALSE, 0);
427 for (int i = 0; i < metadata->get_input_count(); i++)
429 label = calf_vumeter_new();
430 calf_vumeter_set_falloff(CALF_VUMETER(label), 2.5);
431 calf_vumeter_set_hold(CALF_VUMETER(label), 1.5);
432 calf_vumeter_set_width(CALF_VUMETER(label), 100);
433 calf_vumeter_set_height(CALF_VUMETER(label), 12);
434 calf_vumeter_set_position(CALF_VUMETER(label), 2);
435 gtk_box_pack_start(GTK_BOX(inBox), label, TRUE, TRUE, 0);
436 strip->audio_in.push_back(label);
439 strip->inBox = gtk_alignment_new(0.f, 0.f, 1.f, 0.f);
440 gtk_container_add(GTK_CONTAINER(strip->inBox), inBox);
442 gtk_table_attach(GTK_TABLE(strip->strip_table), strip->inBox, 3, 4, row, row + 1, ao, ao, 5, 3);
444 if (get_config()->vu_meters)
445 gtk_widget_show_all(strip->inBox);
447 gtk_widget_set_size_request(GTK_WIDGET(strip->inBox), 120, -1);
450 if (metadata->get_output_count()) {
452 GtkWidget *outBox = gtk_vbox_new(FALSE, 1);
454 gtk_box_pack_start(GTK_BOX(outBox), gtk_label_new("Audio Out"),TRUE, TRUE, 0);
456 for (int i = 0; i < metadata->get_output_count(); i++)
458 label = calf_vumeter_new();
459 calf_vumeter_set_falloff(CALF_VUMETER(label), 2.5);
460 calf_vumeter_set_hold(CALF_VUMETER(label), 1.5);
461 calf_vumeter_set_width(CALF_VUMETER(label), 100);
462 calf_vumeter_set_height(CALF_VUMETER(label), 12);
463 calf_vumeter_set_position(CALF_VUMETER(label), 2);
464 gtk_box_pack_start(GTK_BOX(outBox), label,FALSE, FALSE, 0);
465 strip->audio_out.push_back(label);
468 strip->outBox = gtk_alignment_new(0.f, 0.f, 1.f, 0.f);
469 gtk_container_add(GTK_CONTAINER(strip->outBox), outBox);
471 gtk_table_attach(GTK_TABLE(strip->strip_table), strip->outBox, 4, 5, row, row + 1, ao, ao, 5, 3);
473 if (get_config()->vu_meters)
474 gtk_widget_show_all(strip->outBox);
476 gtk_widget_set_size_request(GTK_WIDGET(strip->outBox), 120, -1);
479 // other stuff bottom right
480 GtkWidget *paramBox = gtk_hbox_new(FALSE, 0);
482 GtkWidget *logoImg = gtk_image_new_from_file(PKGLIBDIR "/logo_button.png");
483 gtk_box_pack_end(GTK_BOX(paramBox), GTK_WIDGET(logoImg), TRUE, TRUE, 0);
485 gtk_table_attach(GTK_TABLE(strip->strip_table), paramBox, 3, 5, row + 1, row + 2, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), 10, 0);
486 gtk_widget_show_all(GTK_WIDGET(paramBox));
488 row += 2;
490 // bottom light
491 GtkWidget *botImg = gtk_image_new_from_file(PKGLIBDIR "/light_bottom.png");
492 gtk_widget_set_size_request(GTK_WIDGET(botImg), 1, 1);
493 gtk_table_attach(GTK_TABLE(strip->strip_table), botImg, 1, 5, row, row + 1, (GtkAttachOptions)(GTK_EXPAND | GTK_FILL | GTK_SHRINK), (GtkAttachOptions)(0), 0, 0);
494 gtk_widget_show(botImg);
496 gtk_widget_show(GTK_WIDGET(strip->strip_table));
498 return strip;
501 void gtk_main_window::sort_strips()
503 if(plugins.size() <= 0) return;
504 int rack_float = get_config()->rack_float; // 0=horiz, 1=vert
505 int float_size = get_config()->float_size; // amout of rows/cols before line break
506 int posx, posy;
507 gtk_table_resize(GTK_TABLE(strips_table), (int)(plugins.size() / float_size + 1), float_size);
508 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
510 switch (rack_float) {
511 case 0:
512 default:
513 posx = i->second->id % float_size;
514 posy = (int)(i->second->id / float_size);
515 break;
516 case 1:
517 posy = i->second->id % float_size;
518 posx = (int)(i->second->id / float_size);
519 break;
521 bool rem = false;
522 if(i->second->strip_table->parent != NULL) {
523 rem = true;
524 g_object_ref(i->second->strip_table);
525 gtk_container_remove(GTK_CONTAINER(strips_table), GTK_WIDGET(i->second->strip_table));
527 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);
528 if(rem) g_object_unref(i->second->strip_table);
532 void gtk_main_window::update_strip(plugin_ctl_iface *plugin)
534 // plugin_strip *strip = plugins[plugin];
535 // assert(strip);
539 void gtk_main_window::open_gui(plugin_ctl_iface *plugin)
541 plugin_gui_window *gui_win = new plugin_gui_window(this, this);
542 std::string title = "Calf - ";
543 gui_win->create(plugin, (title + plugin->get_metadata_iface()->get_label()).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());
544 gtk_widget_show(GTK_WIDGET(gui_win->toplevel));
545 plugins[plugin]->gui_win = gui_win;
548 static const char *plugin_pre_xml =
549 "<ui>\n"
550 " <menubar>\n"
551 " <menu action=\"AddPluginMenuAction\">\n"
552 " <placeholder name=\"plugin\">\n";
554 static const char *plugin_post_xml =
555 " </placeholder>\n"
556 " </menu>\n"
557 " </menubar>\n"
558 "</ui>\n"
560 #define countof(X) ( (size_t) ( sizeof(X)/sizeof*(X) ) )
561 void gtk_main_window::register_icons()
563 const char *names[]={"Allpass", "Amplifier", "Analyser",
564 "Bandpass", "Chorus", "Comb", "Compressor",
565 "Constant", "Converter", "Delay", "Distortion",
566 "Dynamics", "Envelope", "EQ", "Expander",
567 "Filter", "Flanger", "Function", "Gate",
568 "Generator", "Highpass", "Instrument",
569 "Limiter", "Mixer", "Modulator", "MultiEQ",
570 "Oscillator", "ParaEQ", "Phaser", "Pitch",
571 "Reverb", "Simulator", "Spatial", "Spectral",
572 "Utility", "Waveshaper"};
573 factory = gtk_icon_factory_new ();
574 for (size_t i = 0; i < countof(names); i++) {
575 char name[1024];
576 strcpy(name, "LV2-");
577 strcat(name, names[i]);
578 if (!gtk_icon_factory_lookup(factory, name)) {
579 std::string iname = std::string(PKGLIBDIR) + "icons/LV2/" + names[i] + ".svg";
580 GdkPixbuf *buf = gdk_pixbuf_new_from_file_at_size(iname.c_str(), 64, 64, NULL);
581 GtkIconSet *icon = gtk_icon_set_new_from_pixbuf(buf);
582 gtk_icon_factory_add (factory, name, icon);
583 gtk_icon_set_unref(icon);
584 g_object_unref(buf);
587 gtk_icon_factory_add_default(factory);
590 void gtk_main_window::add_plugin_action(GtkWidget *src, gpointer data)
592 add_plugin_params *app = (add_plugin_params *)data;
593 app->main_win->new_plugin(app->name.c_str());
596 static void action_destroy_notify(gpointer data)
598 delete (gtk_main_window::add_plugin_params *)data;
601 std::string gtk_main_window::make_plugin_list(GtkActionGroup *actions)
603 string s = plugin_pre_xml;
604 const plugin_registry::plugin_vector &plugins = plugin_registry::instance().get_all();
605 std::string type = "";
606 std::string tmp = "";
607 std::string last = "";
608 unsigned int count = 0;
609 unsigned int size = plugins.size();
611 const plugin_metadata_iface *p = plugins[0];
613 for(unsigned int i = 0; i <= size; i++)
615 if (i < size) {
616 p = plugins[i];
617 type = (p->get_plugin_info()).plugin_type;
618 type = type.substr(0, type.length() - 6);
620 if (type != last or i >= size or !i) {
622 if (i) {
623 if (count > 1) {
624 s += "<menu action='" + last + "'>" + tmp + "</menu>";
625 GtkAction *a = gtk_action_new(last.c_str(), last.c_str(), NULL, ("LV2-" + last).c_str());
626 gtk_action_group_add_action(actions, a);
627 } else {
628 s += tmp;
631 tmp = "";
632 last = type;
633 count = 0;
635 if (i < size) {
636 std::string action = "Add" + string(p->get_id()) + "Action";
637 std::string stock = "LV2-" + type;
638 // TODO:
639 // add lv2 stock icons to plug-ins and not just to menus
640 // GTK_STOCK_OPEN -> ("LV2_" + type).c_str()
641 GtkActionEntry ae = { action.c_str(), stock.c_str(), p->get_label(), NULL, NULL, (GCallback)add_plugin_action };
642 gtk_action_group_add_actions_full(actions, &ae, 1, (gpointer)new add_plugin_params(this, p->get_id()), action_destroy_notify);
643 tmp += string("<menuitem always-show-image=\"true\" action=\"") + action + "\" />";
644 count += 1;
647 return s + plugin_post_xml;
650 static void window_destroy_cb(GtkWindow *window, gpointer data)
652 ((gtk_main_window *)data)->owner->on_main_window_destroy();
655 void gtk_main_window::create()
657 register_icons();
658 toplevel = GTK_WINDOW(gtk_window_new (GTK_WINDOW_TOPLEVEL));
659 std::string title = "Calf JACK Host";
660 gtk_window_set_title(toplevel, title.c_str()); //(owner->get_client_name() + " - Calf JACK Host").c_str());
661 gtk_widget_set_name(GTK_WIDGET(toplevel), "Calf-Rack");
662 gtk_window_set_icon_name(toplevel, "calf");
663 gtk_window_set_role(toplevel, "calf_rack");
665 is_closed = false;
666 gtk_window_set_resizable(toplevel, false);
668 all_vbox = gtk_vbox_new(0, FALSE);
670 ui_mgr = gtk_ui_manager_new();
671 std_actions = gtk_action_group_new("default");
672 gtk_action_group_add_actions(std_actions, actions, sizeof(actions)/sizeof(actions[0]), this);
673 GError *error = NULL;
674 gtk_ui_manager_insert_action_group(ui_mgr, std_actions, 0);
675 gtk_ui_manager_add_ui_from_string(ui_mgr, ui_xml, -1, &error);
676 gtk_box_pack_start(GTK_BOX(all_vbox), gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar"), false, false, 0);
678 gtk_widget_set_size_request(GTK_WIDGET(gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar")), 640, -1);
680 gtk_widget_set_name(GTK_WIDGET(gtk_ui_manager_get_widget(ui_mgr, "/ui/menubar")), "Calf-Menu");
682 plugin_actions = gtk_action_group_new("plugins");
683 string plugin_xml = make_plugin_list(plugin_actions);
684 gtk_ui_manager_insert_action_group(ui_mgr, plugin_actions, 0);
685 gtk_ui_manager_add_ui_from_string(ui_mgr, plugin_xml.c_str(), -1, &error);
687 strips_table = gtk_table_new(0, 1, FALSE);
688 gtk_table_set_col_spacings(GTK_TABLE(strips_table), 0);
689 gtk_table_set_row_spacings(GTK_TABLE(strips_table), 0);
691 for(GList *p = GTK_TABLE(strips_table)->children; p != NULL; p = p->next)
693 GtkTableChild *c = (GtkTableChild *)p->data;
694 if (c->top_attach == 0) {
695 gtk_misc_set_alignment(GTK_MISC(c->widget), 0.5, 0);
698 for (std::vector<jack_host *>::iterator i = plugin_queue.begin(); i != plugin_queue.end(); ++i)
700 plugin_strip *st = create_strip(*i);
701 plugins[*i] = st;
702 update_strip(*i);
704 sort_strips();
706 gtk_container_add(GTK_CONTAINER(all_vbox), strips_table);
707 gtk_container_add(GTK_CONTAINER(toplevel), all_vbox);
709 gtk_widget_set_name(GTK_WIDGET(strips_table), "Calf-Container");
711 gtk_window_add_accel_group(toplevel, gtk_ui_manager_get_accel_group(ui_mgr));
712 gtk_widget_show_all(GTK_WIDGET(toplevel));
713 source_id = g_timeout_add_full(G_PRIORITY_DEFAULT, 1000/30, on_idle, this, NULL); // 30 fps should be enough for everybody
715 notifier = get_config_db()->add_listener(this);
716 on_config_change();
717 g_signal_connect(GTK_OBJECT(toplevel), "destroy", G_CALLBACK(window_destroy_cb), this);
720 void gtk_main_window::on_config_change()
722 get_config()->load(get_config_db());
723 show_rack_ears(get_config()->rack_ears);
724 show_vu_meters(get_config()->vu_meters);
725 sort_strips();
728 void gtk_main_window::refresh_plugin(plugin_ctl_iface *plugin)
730 if (plugins[plugin]->gui_win)
731 plugins[plugin]->gui_win->gui->refresh();
734 void gtk_main_window::on_closed()
736 if (notifier)
738 delete notifier;
739 notifier = NULL;
741 if (source_id)
742 g_source_remove(source_id);
743 is_closed = true;
744 toplevel = NULL;
746 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = plugins.begin(); i != plugins.end(); ++i)
748 if (i->second && i->second->gui_win) {
749 i->second->gui_win->close();
752 plugins.clear();
755 static inline float LVL(float value)
757 return value; //sqrt(value) * 0.75;
760 gboolean gtk_main_window::on_idle(void *data)
762 gtk_main_window *self = (gtk_main_window *)data;
764 self->owner->on_idle();
766 if (!self->refresh_controller.check_redraw(GTK_WIDGET(self->toplevel)))
767 return TRUE;
769 for (std::map<plugin_ctl_iface *, plugin_strip *>::iterator i = self->plugins.begin(); i != self->plugins.end(); ++i)
771 if (i->second)
773 plugin_ctl_iface *plugin = i->first;
774 plugin_strip *strip = i->second;
775 int idx = 0;
776 if (strip->inBox && gtk_widget_is_drawable (strip->inBox)) {
777 for (int i = 0; i < (int)strip->audio_in.size(); i++) {
778 calf_vumeter_set_value(CALF_VUMETER(strip->audio_in[i]), LVL(plugin->get_level(idx++)));
781 else
782 idx += strip->audio_in.size();
783 if (strip->outBox && gtk_widget_is_drawable (strip->outBox)) {
784 for (int i = 0; i < (int)strip->audio_out.size(); i++) {
785 calf_vumeter_set_value(CALF_VUMETER(strip->audio_out[i]), LVL(plugin->get_level(idx++)));
788 else
789 idx += strip->audio_out.size();
790 if (plugin->get_metadata_iface()->get_midi()) {
791 calf_led_set_value (CALF_LED (strip->midi_in), plugin->get_level(idx++));
795 return TRUE;
798 void gtk_main_window::open_file()
800 GtkWidget *dialog;
801 dialog = gtk_file_chooser_dialog_new ("Open File",
802 toplevel,
803 GTK_FILE_CHOOSER_ACTION_OPEN,
804 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
805 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
806 NULL);
807 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
809 char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
810 char *error = owner->open_file(filename);
811 if (error)
812 display_error(error, filename);
813 else
814 owner->set_current_filename(filename);
815 g_free (filename);
816 free (error);
818 gtk_widget_destroy (dialog);
821 bool gtk_main_window::save_file()
823 if (owner->get_current_filename().empty())
824 return save_file_as();
826 const char *error = owner->save_file(owner->get_current_filename().c_str());
827 if (error)
829 display_error(error, owner->get_current_filename().c_str());
830 return false;
832 return true;
835 bool gtk_main_window::save_file_as()
837 GtkWidget *dialog;
838 bool success = false;
839 dialog = gtk_file_chooser_dialog_new ("Save File",
840 toplevel,
841 GTK_FILE_CHOOSER_ACTION_SAVE,
842 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
843 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
844 NULL);
845 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
847 char *filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
848 char *error = owner->save_file(filename);
849 if (error)
850 display_error(error, filename);
851 else
853 owner->set_current_filename(filename);
854 success = true;
856 g_free (filename);
857 free(error);
859 gtk_widget_destroy (dialog);
860 return success;
863 void gtk_main_window::display_error(const char *error, const char *filename)
865 GtkWidget *dialog;
866 dialog = gtk_message_dialog_new_with_markup (toplevel, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error, filename, NULL);
867 gtk_dialog_run (GTK_DIALOG (dialog));
868 gtk_widget_destroy (dialog);
871 GtkWidget *gtk_main_window::create_progress_window()
873 GtkWidget *tlw = gtk_window_new ( GTK_WINDOW_TOPLEVEL );
874 gtk_window_set_type_hint (GTK_WINDOW (tlw), GDK_WINDOW_TYPE_HINT_DIALOG);
875 GtkWidget *pbar = gtk_progress_bar_new();
876 gtk_container_add (GTK_CONTAINER(tlw), pbar);
877 gtk_widget_show_all (pbar);
878 return tlw;
881 void gtk_main_window::report_progress(float percentage, const std::string &message)
883 if (percentage < 100)
885 if (!progress_window) {
886 progress_window = create_progress_window();
887 gtk_window_set_modal (GTK_WINDOW (progress_window), TRUE);
888 if (toplevel)
889 gtk_window_set_transient_for (GTK_WINDOW (progress_window), toplevel);
890 gtk_widget_show(progress_window);
892 GtkWidget *pbar = gtk_bin_get_child (GTK_BIN (progress_window));
893 if (!message.empty())
894 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (pbar), message.c_str());
895 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (pbar), percentage / 100.0);
897 else
899 if (progress_window) {
900 gtk_window_set_modal (GTK_WINDOW (progress_window), FALSE);
901 gtk_widget_destroy (progress_window);
902 progress_window = NULL;
906 while (gtk_events_pending ())
907 gtk_main_iteration ();
910 void gtk_main_window::add_condition(const std::string &name)
912 conditions.insert(name);
915 void gtk_main_window::show_error(const std::string &text)
917 GtkWidget *widget = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", text.c_str());
918 gtk_dialog_run (GTK_DIALOG (widget));
919 gtk_widget_destroy (widget);
922 GtkListStore *gtk_main_window::get_styles()
924 std::vector <calf_utils::direntry> list = calf_utils::list_directory(PKGLIBDIR);
925 GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
926 for (std::vector<calf_utils::direntry>::iterator i = list.begin(); i != list.end(); i++) {
927 if (i->name.substr(i->name.length() - 3).compare(".rc") == 0) {
928 ifstream infile(i->full_path.c_str());
929 if (infile.good()) {
930 string line;
931 getline(infile, line);
932 i->name = line.substr(1);
934 gtk_list_store_insert_with_values(store, NULL, -1,
935 0, i->name.c_str(),
936 1, i->full_path.c_str(),
937 -1);
940 return store;