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 02111-1307, USA.
30 #include "gui_config.h"
33 namespace calf_plugins
{
35 class window_update_controller
39 window_update_controller() : refresh_counter() {}
40 bool check_redraw(GtkWidget
*toplevel
);
49 typedef std::map
<std::string
, std::string
> xml_attribute_map
;
52 std::string control_name
;
53 xml_attribute_map attribs
;
56 void require_attribute(const char *name
);
57 void require_int_attribute(const char *name
);
58 int get_int(const char *name
, int def_value
= 0);
59 float get_float(const char *name
, float def_value
= 0.f
);
60 std::vector
<double> get_vector(const char *name
, std::string
&value
);
63 virtual GtkWidget
*create(plugin_gui
*_gui
) { return NULL
; }
64 virtual bool is_container() { return GTK_IS_CONTAINER(widget
); };
65 virtual void set_visibilty(bool state
);
66 virtual void add(control_base
*ctl
) { gtk_container_add(GTK_CONTAINER(widget
), ctl
->widget
); }
67 /// called from created() to set all the properties
68 virtual void set_std_properties();
69 /// called after the control is created
70 virtual void created();
71 virtual ~control_base() {}
74 #define _GUARD_CHANGE_ if (in_change) return; guard_change __gc__(this);
76 class param_control
: public control_base
82 std::string param_variable
;
85 float old_displayed_value
;
89 guard_change(param_control
*_pc
) : pc(_pc
) { pc
->in_change
++; }
90 ~guard_change() { pc
->in_change
--; }
94 inline const parameter_properties
&get_props();
96 virtual GtkWidget
*create(plugin_gui
*_gui
);
97 /// called to create a widget for a control
98 virtual GtkWidget
*create(plugin_gui
*_gui
, int _param_no
)=0;
99 /// called to transfer the value from control to parameter(s)
100 virtual void get()=0;
101 /// called to transfer the value from parameter(s) to control
102 virtual void set()=0;
103 /// called after the control is created
104 virtual void created();
105 /// called on DSSI configure()
106 virtual void configure(const char *key
, const char *value
) {}
107 /// called from created() to add hooks for parameters
108 virtual void hook_params();
109 /// called from created() to add context menu handlers
110 virtual void add_context_menu_handler();
111 virtual void on_idle() {}
112 virtual ~param_control();
113 virtual void do_popup_menu();
114 static gboolean
on_button_press_event(GtkWidget
*widget
, GdkEventButton
*event
, void *user_data
);
115 static gboolean
on_popup_menu(GtkWidget
*widget
, void *user_data
);
116 virtual void create_value_entry(GtkWidget
*widget
, int x
, int y
);
117 virtual void destroy_value_entry();
118 static gboolean
value_entry_action(GtkEntry
*widget
, GdkEvent
*event
, void *user_data
);
119 static gboolean
value_entry_unfocus(GtkWidget
*widget
, GdkEventFocus
*event
, void *user_data
);
120 static gboolean
value_entry_click(GtkWidget
*widget
, GdkEventButton
*event
, void *user_data
);
124 class plugin_gui_window
;
126 class plugin_gui
: public send_configure_iface
, public send_updates_iface
130 std::multimap
<int, param_control
*> par2ctl
;
132 control_base
*top_container
;
133 std::map
<std::string
, int> param_name_map
;
135 int last_status_serial_no
;
136 std::map
<int, GSList
*> param_radio_groups
;
137 GtkWidget
*leftBox
, *rightBox
;
138 int context_menu_param_no
;
139 uint32_t context_menu_last_designator
;
140 std::vector
<control_base
*> stack
;
142 struct automation_menu_entry
{
145 automation_menu_entry(plugin_gui
*_gui
, int _source
)
146 : gui(_gui
), source(_source
) {}
148 std::vector
<automation_menu_entry
*> automation_menu_callback_data
;
150 static void on_automation_add(GtkWidget
*widget
, void *user_data
);
151 static void on_automation_delete(GtkWidget
*widget
, void *user_data
);
152 static void on_automation_set_lower(GtkWidget
*widget
, void *user_data
);
153 static void on_automation_set_upper(GtkWidget
*widget
, void *user_data
);
154 void on_automation_set_lower_or_upper(automation_menu_entry
*ame
, bool is_upper
);
156 plugin_gui_window
*window
;
157 GtkWidget
*container
;
158 const char *effect_name
;
159 plugin_ctl_iface
*plugin
;
160 preset_access_iface
*preset_access
;
161 std::vector
<param_control
*> params
;
162 std::vector
<int> read_serials
;
164 /* For optional lv2ui:show interface. */
166 GtkWidget
* optwidget
;
167 GtkWidget
* optwindow
;
168 const char* opttitle
;
170 plugin_gui(plugin_gui_window
*_window
);
171 GtkWidget
*create_from_xml(plugin_ctl_iface
*_plugin
, const char *xml
);
172 control_base
*create_widget_from_xml(const char *element
, const char *attributes
[]);
174 void add_param_ctl(int param
, param_control
*ctl
) { par2ctl
.insert(std::pair
<int, param_control
*>(param
, ctl
)); }
175 void remove_param_ctl(int param
, param_control
*ctl
);
177 void refresh(int param_no
, param_control
*originator
= NULL
);
178 int get_param_no_by_name(std::string param_name
);
179 void xml_element_start(const char *element
, const char *attributes
[]);
180 void set_param_value(int param_no
, float value
, param_control
*originator
= NULL
);
181 /// Called on change of configure variable
182 void send_configure(const char *key
, const char *value
);
183 /// Called on change of status variable
184 void send_status(const char *key
, const char *value
);
186 /// Get a radio button group (if it exists) for a parameter
187 GSList
*get_radio_group(int param
);
188 /// Set a radio button group for a parameter
189 void set_radio_group(int param
, GSList
*group
);
190 /// Show rack ear widgets
191 void show_rack_ears(bool show
);
192 /// Pop-up a context menu for a control
193 void on_control_popup(param_control
*ctl
, int param_no
);
194 /// Clean up callback data allocated for the automation pop-up menu
195 void cleanup_automation_entries();
196 /// Destroy all the widgets in the container
197 void destroy_child_widgets(GtkWidget
*parent
);
199 static void xml_element_start(void *data
, const char *element
, const char *attributes
[]);
200 static void xml_element_end(void *data
, const char *element
);
203 class main_window_iface
;
204 class main_window_owner_iface
;
206 /// A class used to inform the plugin GUIs about the environment they run in
207 /// (currently: what plugin features are accessible)
208 struct gui_environment_iface
210 virtual bool check_condition(const char *name
) = 0;
211 virtual calf_utils::config_db_iface
*get_config_db() = 0;
212 virtual calf_utils::gui_config
*get_config() = 0;
213 virtual ~gui_environment_iface() {}
216 /// An interface that wraps UI-dependent elements of the session
217 struct session_environment_iface
219 /// Called to initialise the UI libraries
220 virtual void init_gui(int &argc
, char **&argv
) = 0;
221 /// Create an appropriate version of the main window
222 virtual main_window_iface
*create_main_window() = 0;
223 /// Called to start the UI loop
224 virtual void start_gui_loop() = 0;
225 /// Called from within event handlers to finish the UI loop
226 virtual void quit_gui_loop() = 0;
227 virtual ~session_environment_iface() {}
230 /// Trivial implementation of gui_environment_iface
231 class gui_environment
: public gui_environment_iface
235 calf_utils::config_db_iface
*config_db
;
236 calf_utils::gui_config gui_config
;
239 std::set
<std::string
> conditions
;
243 virtual bool check_condition(const char *name
) { return conditions
.count(name
) != 0; }
244 virtual calf_utils::config_db_iface
*get_config_db() { return config_db
; }
245 virtual calf_utils::gui_config
*get_config() { return &gui_config
; }
249 /// Interface used by the plugin to communicate with the main hosting window
250 struct main_window_iface
: public progress_report_iface
252 /// Set owner pointer
253 virtual void set_owner(main_window_owner_iface
*owner
) = 0;
254 /// Add a condition to the list of conditions supported by the host
255 virtual void add_condition(const std::string
&name
) = 0;
256 /// Create the actual window associated with this interface
257 virtual void create() = 0;
258 /// Add the plugin to the window
259 virtual void add_plugin(jack_host
*plugin
) = 0;
260 /// Remove the plugin from the window
261 virtual void del_plugin(plugin_ctl_iface
*plugin
) = 0;
262 /// Refresh the plugin UI
263 virtual void refresh_plugin(plugin_ctl_iface
*plugin
) = 0;
264 /// Bind the plugin window to the plugin
265 virtual void set_window(plugin_ctl_iface
*plugin
, plugin_gui_window
*window
) = 0;
266 /// Refresh preset lists on all windows (if, for example, a new preset has been created)
267 virtual void refresh_all_presets(bool builtin_too
) = 0;
268 /// Default open file operation
269 virtual void open_file() = 0;
270 /// Default save file operation
271 virtual bool save_file() = 0;
272 /// Called to clean up when host quits
273 virtual void on_closed() = 0;
274 /// Show an error message
275 virtual void show_error(const std::string
&text
) = 0;
278 virtual ~main_window_iface() {}
281 struct main_window_owner_iface
283 virtual void new_plugin(const char *name
) = 0;
284 virtual void remove_plugin(plugin_ctl_iface
*plugin
) = 0;
285 virtual char *open_file(const char *name
) = 0;
286 virtual char *save_file(const char *name
) = 0;
287 virtual void reorder_plugins() = 0;
288 /// Return JACK client name (or its counterpart) to put in window title bars
289 virtual std::string
get_client_name() const = 0;
290 /// Called on 'destroy' event of the main window
291 virtual void on_main_window_destroy() = 0;
292 /// Called from idle handler
293 virtual void on_idle() = 0;
294 /// Get the file name of the current rack
295 virtual std::string
get_current_filename() const = 0;
296 /// Set the file name of the current rack
297 virtual void set_current_filename(const std::string
&name
) = 0;
298 virtual ~main_window_owner_iface() {}
301 class plugin_gui_window
: public calf_utils::config_listener_iface
305 window_update_controller refresh_controller
;
309 GtkUIManager
*ui_mgr
;
310 GtkActionGroup
*std_actions
, *builtin_preset_actions
, *user_preset_actions
, *command_actions
;
311 gui_environment_iface
*environment
;
312 main_window_iface
*main
;
314 calf_utils::config_notifier_iface
*notifier
;
316 plugin_gui_window(gui_environment_iface
*_env
, main_window_iface
*_main
);
317 std::string
make_gui_preset_list(GtkActionGroup
*grp
, bool builtin
, char &ch
);
318 std::string
make_gui_command_list(GtkActionGroup
*grp
, const plugin_metadata_iface
*metadata
);
319 void fill_gui_presets(bool builtin
, char &ch
);
320 void create(plugin_ctl_iface
*_plugin
, const char *title
, const char *effect
);
322 virtual void on_config_change();
323 static gboolean
on_idle(void *data
);
324 static void on_window_destroyed(GtkWidget
*window
, gpointer data
);
325 ~plugin_gui_window();
329 inline const parameter_properties
¶m_control::get_props()
331 return *gui
->plugin
->get_metadata_iface()->get_param_props(param_no
);
334 class null_audio_module
;
336 struct activate_command_params
338 typedef void (*CommandFunc
)(null_audio_module
*);
342 activate_command_params(plugin_gui
*_gui
, int _idx
)
343 : gui(_gui
), function_idx(_idx
)
348 void activate_command(GtkAction
*action
, activate_command_params
*params
);
350 class cairo_impl
: public calf_plugins::cairo_iface
354 virtual void set_source_rgba(float r
, float g
, float b
, float a
= 1.f
) { cairo_set_source_rgba(context
, r
, g
, b
, a
); }
355 virtual void set_line_width(float width
) { cairo_set_line_width(context
, width
); }
356 virtual void set_dash(const double *dash
, int length
) { cairo_set_dash(context
, dash
, length
, 0); }
357 virtual void draw_label(const char *label
, float x
, float y
, int pos
, float margin
, float align
) {
358 cairo_text_extents_t extents
;
359 cairo_text_extents(context
, label
, &extents
);
364 cairo_move_to(context
, x
- extents
.width
/ 2, y
- margin
);
368 cairo_move_to(context
, x
+ margin
, y
+ 2);
372 cairo_move_to(context
, x
- extents
.width
/ 2, y
+ margin
+ extents
.height
);
376 cairo_move_to(context
, x
- margin
- extents
.width
, y
+ 2);
379 cairo_show_text(context
, label
);