3 * Copyright (C) 2007 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., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include <calf/ctl_led.h>
24 #include <calf/giface.h>
26 #include <calf/preset.h>
27 #include <calf/preset_gui.h>
28 #include <calf/main_win.h>
30 using namespace calf_plugins
;
33 static const char *ui_xml
=
36 " <menu action=\"HostMenuAction\">\n"
37 " <menu action=\"AddPluginMenuAction\">\n"
40 " <menuitem action=\"exit\"/>\n"
46 static void exit_action(GtkWidget
*widget
, main_window
*main
)
48 gtk_widget_destroy(GTK_WIDGET(main
->toplevel
));
51 static const GtkActionEntry actions
[] = {
52 { "HostMenuAction", "", "_Host", NULL
, "Host-related operations", NULL
},
53 { "AddPluginMenuAction", "", "_Add plugin", NULL
, "Add a plugin to the rack", NULL
},
54 { "exit", "", "_Exit", NULL
, "Exit application", (GCallback
)exit_action
},
57 main_window::main_window()
64 void main_window::add_plugin(plugin_ctl_iface
*plugin
)
68 plugin_strip
*strip
= create_strip(plugin
);
69 plugins
[plugin
] = strip
;
73 plugin_queue
.push_back(plugin
);
74 plugins
[plugin
] = NULL
;
78 void main_window::del_plugin(plugin_ctl_iface
*plugin
)
80 if (!plugins
.count(plugin
))
82 plugin_strip
*strip
= plugins
[plugin
];
84 strip
->gui_win
->close();
87 for(GList
*p
= GTK_TABLE(strips_table
)->children
; p
!= NULL
; p
= p
->next
)
89 GtkTableChild
*c
= (GtkTableChild
*)p
->data
;
90 if (c
->widget
== strip
->name
)
92 row
= c
->top_attach
- 1;
98 vector
<GtkWidget
*> to_destroy
;
99 for(GList
*p
= GTK_TABLE(strips_table
)->children
; p
!= NULL
; p
= p
->next
)
101 GtkTableChild
*c
= (GtkTableChild
*)p
->data
;
102 if (c
->top_attach
>= row
&& c
->top_attach
< row
+ 3)
103 to_destroy
.push_back(c
->widget
);
104 if (c
->top_attach
>= row
+ 3)
107 c
->bottom_attach
-= 3;
111 for (unsigned int i
= 0; i
< to_destroy
.size(); i
++)
112 gtk_container_remove(GTK_CONTAINER(strips_table
), to_destroy
[i
]);
113 //for (unsigned int i = 0; i < to_destroy.size(); i++)
114 // gtk_widget_destroy(to_destroy[i]);
116 plugins
.erase(plugin
);
117 int rows
= 0, cols
= 0;
118 g_object_get(G_OBJECT(strips_table
), "n-rows", &rows
, "n-columns", &cols
, NULL
);
119 gtk_table_resize(GTK_TABLE(strips_table
), rows
- 3, cols
);
121 // a hack to remove unneeded vertical space from the window
122 // not perfect, as it undoes user's vertical resize
123 // only needed when window is resizable though
125 gtk_window_get_size(toplevel, &width, &height);
126 gtk_window_resize(toplevel, width, 1);
130 void main_window::set_window(plugin_ctl_iface
*plugin
, plugin_gui_window
*gui_win
)
132 if (!plugins
.count(plugin
))
134 plugin_strip
*strip
= plugins
[plugin
];
137 strip
->gui_win
= gui_win
;
139 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(strip
->name
), gui_win
!= NULL
);
142 void main_window::refresh_all_presets(bool builtin_too
)
144 for (std::map
<plugin_ctl_iface
*, plugin_strip
*>::iterator i
= plugins
.begin(); i
!= plugins
.end(); i
++)
146 if (i
->second
&& i
->second
->gui_win
) {
148 i
->second
->gui_win
->fill_gui_presets(true, ch
);
149 i
->second
->gui_win
->fill_gui_presets(false, ch
);
155 gui_button_pressed(GtkWidget
*button
, main_window::plugin_strip
*strip
)
157 GtkToggleButton
*tb
= GTK_TOGGLE_BUTTON(button
);
158 if ((gtk_toggle_button_get_active(tb
) != 0) == (strip
->gui_win
!= NULL
))
160 if (strip
->gui_win
) {
161 strip
->gui_win
->close();
162 strip
->gui_win
= NULL
;
164 strip
->main_win
->open_gui(strip
->plugin
);
170 extra_button_pressed(GtkWidget
*button
, main_window::plugin_strip
*strip
)
172 strip
->main_win
->owner
->remove_plugin(strip
->plugin
);
176 main_window::plugin_strip
*main_window::create_strip(plugin_ctl_iface
*plugin
)
178 plugin_strip
*strip
= new plugin_strip
;
179 strip
->main_win
= this;
180 strip
->plugin
= plugin
;
181 strip
->gui_win
= NULL
;
183 GtkAttachOptions ao
= (GtkAttachOptions
)(GTK_EXPAND
| GTK_FILL
);
185 int row
= 0, cols
= 0;
186 g_object_get(G_OBJECT(strips_table
), "n-rows", &row
, "n-columns", &cols
, NULL
);
187 gtk_table_resize(GTK_TABLE(strips_table
), row
+ 3, cols
);
189 GtkWidget
*sep
= gtk_hseparator_new();
190 gtk_table_attach(GTK_TABLE(strips_table
), sep
, 0, 5, row
, row
+ 1, ao
, GTK_SHRINK
, 0, 0);
191 gtk_widget_show(sep
);
194 GtkWidget
*label
= gtk_toggle_button_new_with_label(plugin
->get_label());
195 gtk_table_attach(GTK_TABLE(strips_table
), label
, 0, 1, row
, row
+ 2, ao
, GTK_SHRINK
, 0, 0);
197 gtk_signal_connect(GTK_OBJECT(label
), "toggled", G_CALLBACK(gui_button_pressed
),
198 (plugin_ctl_iface
*)strip
);
199 gtk_widget_show(strip
->name
);
201 if (plugin
->get_midi())
202 label
= calf_led_new();
204 label
= gtk_label_new("");
205 gtk_table_attach(GTK_TABLE(strips_table
), label
, 1, 2, row
, row
+ 2, GTK_FILL
, GTK_SHRINK
, 0, 0);
206 strip
->midi_in
= label
;
207 gtk_widget_show(strip
->midi_in
);
209 for (int i
= 0; i
< 2; i
++)
210 strip
->audio_in
[i
] = strip
->audio_out
[i
] = NULL
;
212 if (plugin
->get_input_count() == 2) {
213 label
= calf_vumeter_new();
214 gtk_table_attach(GTK_TABLE(strips_table
), label
, 2, 3, row
, row
+ 1, ao
, GTK_SHRINK
, 0, 0);
215 strip
->audio_in
[0] = label
;
216 label
= calf_vumeter_new();
217 gtk_table_attach(GTK_TABLE(strips_table
), label
, 2, 3, row
+ 1, row
+ 2, ao
, GTK_SHRINK
, 0, 0);
218 strip
->audio_in
[1] = label
;
219 gtk_widget_show(strip
->audio_in
[0]);
220 gtk_widget_show(strip
->audio_in
[1]);
223 if (plugin
->get_output_count() == 2) {
224 label
= calf_vumeter_new();
225 gtk_table_attach(GTK_TABLE(strips_table
), label
, 3, 4, row
, row
+ 1, ao
, GTK_SHRINK
, 0, 0);
226 strip
->audio_out
[0] = label
;
227 label
= calf_vumeter_new();
228 gtk_table_attach(GTK_TABLE(strips_table
), label
, 3, 4, row
+ 1, row
+ 2, ao
, GTK_SHRINK
, 0, 0);
229 strip
->audio_out
[1] = label
;
230 gtk_widget_show(strip
->audio_out
[0]);
231 gtk_widget_show(strip
->audio_out
[1]);
233 GtkWidget
*extra
= gtk_button_new_with_label("Delete");
234 gtk_table_attach(GTK_TABLE(strips_table
), extra
, 4, 5, row
, row
+ 2, GTK_SHRINK
, GTK_SHRINK
, 0, 0);
235 strip
->extra
= extra
;
236 gtk_signal_connect(GTK_OBJECT(extra
), "clicked", G_CALLBACK(extra_button_pressed
),
237 (plugin_ctl_iface
*)strip
);
238 gtk_widget_show(strip
->extra
);
243 void main_window::update_strip(plugin_ctl_iface
*plugin
)
245 // plugin_strip *strip = plugins[plugin];
250 void main_window::open_gui(plugin_ctl_iface
*plugin
)
252 plugin_gui_window
*gui_win
= new plugin_gui_window(this);
253 gui_win
->create(plugin
, (prefix
+ plugin
->get_label()).c_str(), plugin
->get_id());
254 gtk_widget_show_all(GTK_WIDGET(gui_win
->toplevel
));
255 plugins
[plugin
]->gui_win
= gui_win
;
258 static const char *plugin_pre_xml
=
261 " <menu action=\"AddPluginMenuAction\">\n"
262 " <placeholder name=\"plugin\">\n";
264 static const char *plugin_post_xml
=
271 void main_window::add_plugin_action(GtkWidget
*src
, gpointer data
)
273 add_plugin_params
*app
= (add_plugin_params
*)data
;
274 app
->main_win
->new_plugin(app
->name
.c_str());
277 static void action_destroy_notify(gpointer data
)
279 delete (main_window::add_plugin_params
*)data
;
283 void main_window::new_plugin(const char *plugin)
285 printf("new plugin %s\n", plugin);
289 std::string
main_window::make_plugin_list(GtkActionGroup
*actions
)
291 string s
= plugin_pre_xml
;
292 std::vector
<plugin_metadata_iface
*> plugins
;
293 calf_plugins::get_all_plugins(plugins
);
294 for(unsigned int i
= 0; i
< plugins
.size(); i
++)
296 plugin_metadata_iface
*p
= plugins
[i
];
297 string action_name
= "Add" + string(p
->get_id())+"Action";
298 s
+= string("<menuitem action=\"") + action_name
+ "\" />";
299 GtkActionEntry ae
= { action_name
.c_str(), NULL
, p
->get_label(), NULL
, NULL
, (GCallback
)add_plugin_action
};
300 gtk_action_group_add_actions_full(actions
, &ae
, 1, (gpointer
)new add_plugin_params(this, p
->get_id()), action_destroy_notify
);
304 return s
+ plugin_post_xml
;
307 void main_window::create()
309 toplevel
= GTK_WINDOW(gtk_window_new (GTK_WINDOW_TOPLEVEL
));
310 gtk_window_set_default_icon_name("calf");
312 gtk_window_set_resizable(toplevel
, false);
314 all_vbox
= gtk_vbox_new(0, FALSE
);
316 ui_mgr
= gtk_ui_manager_new();
317 std_actions
= gtk_action_group_new("default");
318 gtk_action_group_add_actions(std_actions
, actions
, sizeof(actions
)/sizeof(actions
[0]), this);
319 GError
*error
= NULL
;
320 gtk_ui_manager_insert_action_group(ui_mgr
, std_actions
, 0);
321 gtk_ui_manager_add_ui_from_string(ui_mgr
, ui_xml
, -1, &error
);
322 gtk_box_pack_start(GTK_BOX(all_vbox
), gtk_ui_manager_get_widget(ui_mgr
, "/ui/menubar"), false, false, 0);
324 plugin_actions
= gtk_action_group_new("plugins");
325 string plugin_xml
= make_plugin_list(plugin_actions
);
326 gtk_ui_manager_insert_action_group(ui_mgr
, plugin_actions
, 0);
327 gtk_ui_manager_add_ui_from_string(ui_mgr
, plugin_xml
.c_str(), -1, &error
);
330 strips_table
= gtk_table_new(1, 6, FALSE
);
331 gtk_table_set_col_spacings(GTK_TABLE(strips_table
), 10);
332 gtk_table_set_row_spacings(GTK_TABLE(strips_table
), 5);
334 gtk_table_attach(GTK_TABLE(strips_table
), gtk_label_new("Module"), 0, 1, 0, 1, GTK_FILL
, GTK_SHRINK
, 0, 0);
335 gtk_table_attach(GTK_TABLE(strips_table
), gtk_label_new("MIDI In"), 1, 2, 0, 1, GTK_FILL
, GTK_SHRINK
, 0, 0);
336 gtk_table_attach(GTK_TABLE(strips_table
), gtk_label_new("Audio In"), 2, 3, 0, 1, GTK_FILL
, GTK_SHRINK
, 0, 0);
337 gtk_table_attach(GTK_TABLE(strips_table
), gtk_label_new("Audio Out"), 3, 4, 0, 1, GTK_FILL
, GTK_SHRINK
, 0, 0);
338 for(GList
*p
= GTK_TABLE(strips_table
)->children
; p
!= NULL
; p
= p
->next
)
340 GtkTableChild
*c
= (GtkTableChild
*)p
->data
;
341 if (c
->top_attach
== 0) {
342 gtk_misc_set_alignment(GTK_MISC(c
->widget
), 0.5, 0);
345 for (std::vector
<plugin_ctl_iface
*>::iterator i
= plugin_queue
.begin(); i
!= plugin_queue
.end(); i
++)
347 plugins
[*i
] = create_strip(*i
);
351 gtk_container_add(GTK_CONTAINER(all_vbox
), strips_table
);
352 gtk_container_add(GTK_CONTAINER(toplevel
), all_vbox
);
354 gtk_widget_show_all(GTK_WIDGET(toplevel
));
355 source_id
= g_timeout_add_full(G_PRIORITY_LOW
, 1000/30, on_idle
, this, NULL
); // 30 fps should be enough for everybody
358 void main_window::refresh_plugin(plugin_ctl_iface
*plugin
)
360 if (plugins
[plugin
]->gui_win
)
361 plugins
[plugin
]->gui_win
->gui
->refresh();
364 void main_window::close_guis()
366 for (std::map
<plugin_ctl_iface
*, plugin_strip
*>::iterator i
= plugins
.begin(); i
!= plugins
.end(); i
++)
368 if (i
->second
&& i
->second
->gui_win
) {
369 i
->second
->gui_win
->close();
375 void main_window::on_closed()
378 g_source_remove(source_id
);
383 static inline float LVL(float value
)
385 return sqrt(value
) * 0.75;
388 gboolean
main_window::on_idle(void *data
)
390 main_window
*self
= (main_window
*)data
;
391 for (std::map
<plugin_ctl_iface
*, plugin_strip
*>::iterator i
= self
->plugins
.begin(); i
!= self
->plugins
.end(); i
++)
395 plugin_ctl_iface
*plugin
= i
->first
;
396 plugin_strip
*strip
= i
->second
;
398 if (plugin
->get_input_count() == 2) {
399 calf_vumeter_set_value(CALF_VUMETER(strip
->audio_in
[0]), LVL(plugin
->get_level(idx
++)));
400 calf_vumeter_set_value(CALF_VUMETER(strip
->audio_in
[1]), LVL(plugin
->get_level(idx
++)));
402 if (plugin
->get_output_count() == 2) {
403 calf_vumeter_set_value(CALF_VUMETER(strip
->audio_out
[0]), LVL(plugin
->get_level(idx
++)));
404 calf_vumeter_set_value(CALF_VUMETER(strip
->audio_out
[1]), LVL(plugin
->get_level(idx
++)));
406 if (plugin
->get_midi()) {
407 calf_led_set_state (CALF_LED (strip
->midi_in
), plugin
->get_level(idx
++) > 0.f
);