fix rules for optional plugins.
[galan.git] / src / control.c
blob101621d9ff3841a491b028565a6cf85481c7ef0a
1 /* gAlan - Graphical Audio Language
2 * Copyright (C) 1999 Tony Garnock-Jones
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <math.h>
24 #include <gdk/gdk.h>
25 #include <gtk/gtk.h>
27 #include "global.h"
28 #include "generator.h"
29 #include "gui.h"
30 #include "comp.h"
31 #include "control.h"
32 #include "gtkknob.h"
33 #include "gtkslider.h"
34 #include "msgbox.h"
35 #include "sheet.h"
36 #include "galan_jack.h"
38 #define GAUGE_SIZE 32
39 #define GRANULARITY 1
41 PUBLIC GtkWidget *control_panel = NULL;
42 PRIVATE ControlPanel *global_panel = NULL;
43 PRIVATE GtkWidget *control_notebook = NULL;
44 PRIVATE GList *control_panels = NULL;
45 PRIVATE GThread *update_thread;
46 PRIVATE GAsyncQueue *update_queue;
48 PRIVATE char *pixmap_path = NULL;
50 PRIVATE void mylayout_sizerequest( GtkContainer *container, GtkRequisition *requisition ) {
52 GList *list = gtk_container_get_children( container );
53 GList *listX = list;
55 requisition->width = 0;
56 requisition->height = 0;
59 for( listX=list; listX != NULL; listX = g_list_next( listX ) ) {
61 GtkWidget *widget = listX->data;
62 gint x,y,w,h;
63 GtkRequisition req;
65 gtk_container_child_get( container, widget, "x", &x, NULL );
66 gtk_container_child_get( container, widget, "y", &y, NULL );
68 gtk_widget_size_request( widget, &req );
69 w=req.width;
70 h=req.height;
72 if( x+w > requisition->width ) requisition->width = x+w;
73 if( y+h > requisition->height ) requisition->height = y+h;
76 gtk_layout_set_size( GTK_LAYOUT( container ), requisition->width, requisition->height );
81 PUBLIC void control_panel_register_panel( ControlPanel *panel, char *name, gboolean add_fixed) {
83 panel->scrollwin = gtk_scrolled_window_new( NULL, NULL );
84 if( add_fixed ) {
85 //gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( panel->scrollwin ), panel->fixedwidget );
86 gtk_container_add( GTK_CONTAINER( panel->scrollwin ), panel->fixedwidget );
87 //gtk_layout_set_size( GTK_LAYOUT( panel->fixedwidget ), 1024, 2048 );
88 gtk_layout_set_vadjustment( GTK_LAYOUT( panel->fixedwidget ),
89 gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW( panel->scrollwin ) ) );
90 gtk_layout_set_hadjustment( GTK_LAYOUT( panel->fixedwidget ),
91 gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW( panel->scrollwin ) ) );
95 gtk_widget_show(panel->scrollwin);
97 gtk_notebook_append_page( GTK_NOTEBOOK( control_notebook ), panel->scrollwin, gtk_label_new( name ) );
98 gtk_container_check_resize( GTK_CONTAINER( panel->fixedwidget ) );
99 control_panels = g_list_append( control_panels, panel );
100 panel->visible = TRUE;
103 PUBLIC void control_panel_unregister_panel( ControlPanel *panel ) {
105 int pagenum;
107 control_panels = g_list_remove( control_panels, panel );
108 pagenum = gtk_notebook_page_num( GTK_NOTEBOOK( control_notebook ), panel->scrollwin );
109 gtk_notebook_remove_page( GTK_NOTEBOOK( control_notebook ), pagenum );
110 panel->scrollwin = NULL;
111 panel->visible = FALSE;
114 PUBLIC void update_panel_name( ControlPanel *panel ) {
115 if( panel->visible )
116 gtk_notebook_set_tab_label_text( GTK_NOTEBOOK( control_notebook ), panel->scrollwin, panel->name );
117 else
118 control_update_names( panel->sheet->panel_control );
121 PUBLIC void control_moveto(Control *c, int x, int y) {
122 x = floor((x + (GRANULARITY>>1)) / ((gdouble) GRANULARITY)) * GRANULARITY;
123 y = floor((y + (GRANULARITY>>1)) / ((gdouble) GRANULARITY)) * GRANULARITY;
125 if (x != c->x || y != c->y) {
127 ControlPanel *panel = c->panel == NULL ? global_panel : c->panel;
129 x = MAX(x, 0);
130 y = MAX(y, 0);
132 gtk_layout_move(GTK_LAYOUT(panel->fixedwidget),
133 c->whole, x, y);
135 if( c->move_callback )
136 c->move_callback( c );
138 c->x = x;
139 c->y = y;
143 PRIVATE void knob_slider_handler(GtkWidget *adj, Control *c) {
144 control_emit(c, GTK_ADJUSTMENT(adj)->value);
147 PRIVATE void toggled_handler(GtkWidget *button, Control *c) {
148 control_emit(c, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) ? 1 : 0);
151 PRIVATE void clicked_handler(GtkWidget *button, Control *c) {
152 control_emit(c, 1);
155 PRIVATE void entry_changed(GtkEntry *entry, GtkAdjustment *adj) {
156 adj->value = atof(gtk_entry_get_text(entry));
157 gtk_signal_handler_block_by_data(GTK_OBJECT(adj), entry);
158 gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
159 gtk_signal_handler_unblock_by_data(GTK_OBJECT(adj), entry);
162 PRIVATE void update_entry(GtkAdjustment *adj, GtkEntry *entry) {
163 char buf[128];
164 sprintf(buf, "%g", adj->value);
165 gtk_signal_handler_block_by_data(GTK_OBJECT(entry), adj);
166 gtk_entry_set_text(entry, buf);
167 gtk_signal_handler_unblock_by_data(GTK_OBJECT(entry), adj);
170 PRIVATE void delete_ctrl_handler(GtkWidget *widget, Control *c) {
171 control_kill_control(c, FALSE);
174 PUBLIC void control_update_bg(Control *c) {
175 GError *err = NULL;
177 if( c->desc->kind != CONTROL_KIND_PANEL )
178 return;
181 if( c->testbg_active || (c->this_panel->bg_type != CONTROL_PANEL_BG_DEFAULT) ) {
183 GdkPixbuf *pb = NULL;
184 GdkPixmap *pixmap;
185 GdkBitmap *mask;
187 if( c->testbg_active ) {
188 pb = gdk_pixbuf_new_from_file( PIXMAPDIRIFY( "galan-bg-ref.png" ), &err );
189 gdk_pixbuf_render_pixmap_and_mask( pb, &pixmap, &mask, 100 );
190 } else {
191 if( ! GTK_WIDGET_MAPPED( c->widget ) )
192 return;
193 switch( c->this_panel->bg_type ) {
194 case CONTROL_PANEL_BG_IMAGE:
195 if( c->this_panel->bg_image_name )
196 pb = gdk_pixbuf_new_from_file( c->this_panel->bg_image_name, &err );
197 if( !pb ) {
198 popup_msgbox("Error Loading Pixmap", MSGBOX_OK, 120000, MSGBOX_OK,
199 "File not found, or file format error: %s",
200 c->this_panel->bg_image_name);
201 return;
204 gdk_pixbuf_render_pixmap_and_mask( pb, &pixmap, &mask, 100 );
205 gdk_window_set_back_pixmap( GTK_LAYOUT(c->widget)->bin_window, pixmap, FALSE );
206 gtk_widget_queue_draw( c->widget );
207 break;
208 case CONTROL_PANEL_BG_GRADIENT:
210 GdkWindow *win = GTK_LAYOUT(c->widget)->bin_window;
211 gint w,h;
212 gdk_drawable_get_size( GDK_DRAWABLE( win ), &w, &h );
213 //pb = gdk_pixbuf_new( GDK_COLORSPACE_RGB, FALSE, 8, w, h );
214 pixmap = gdk_pixmap_new( GDK_DRAWABLE( win ), w, h, -1 );
215 if( gdk_drawable_get_colormap( GDK_DRAWABLE( win ) ) == NULL )
216 gdk_drawable_set_colormap( GDK_DRAWABLE( win ), gdk_colormap_get_system() );
218 cairo_t *cr = gdk_cairo_create( GDK_DRAWABLE(pixmap) );
219 if( !cr ) {
220 return;
222 //cairo_scale( cr, w, h );
223 cairo_pattern_t *pat = cairo_pattern_create_linear( 0,0,0,h );
224 cairo_pattern_add_color_stop_rgb( pat, 0,
225 c->this_panel->color1.red/65536.0,
226 c->this_panel->color1.green/65536.0,
227 c->this_panel->color1.blue/65536.0 );
228 cairo_pattern_add_color_stop_rgb( pat, 1,
229 c->this_panel->color2.red/65536.0,
230 c->this_panel->color2.green/65536.0,
231 c->this_panel->color2.blue/65536.0 );
232 cairo_set_source( cr, pat );
233 cairo_rectangle( cr, 0,0,w,h );
234 cairo_fill( cr );
235 cairo_set_source_rgba( cr,
236 c->this_panel->frame_color.red/65536.0,
237 c->this_panel->frame_color.green/65536.0,
238 c->this_panel->frame_color.blue/65536.0,
239 c->this_panel->frame_alpha/65536.0);
240 cairo_rectangle( cr, 0,0,w,h );
241 cairo_set_line_width (cr, 8.0);
242 cairo_stroke( cr );
243 cairo_pattern_destroy( pat );
244 cairo_destroy( cr );
245 gdk_window_set_back_pixmap( GTK_LAYOUT(c->widget)->bin_window, pixmap, FALSE );
246 gtk_widget_queue_draw( c->widget );
249 break;
251 case CONTROL_PANEL_BG_DEFAULT:
252 case CONTROL_PANEL_BG_COLOR:
253 break;
258 } else {
259 //gtk_style_set_background(c->widget->style, GTK_LAYOUT(c->widget)->bin_window, GTK_STATE_NORMAL);
260 gtk_style_set_background(control_panel->style, GTK_LAYOUT(c->widget)->bin_window, GTK_STATE_NORMAL);
264 PRIVATE void change_bg_handler(GtkWidget *widget, Control *c) {
265 GtkWidget *dialog, *vbox2, *color1, *color2, *filename, *framecolor; //*type;
267 dialog = gtk_dialog_new_with_buttons( "Panel Background Settings", GTK_WINDOW(control_panel), GTK_DIALOG_DESTROY_WITH_PARENT,
268 "Image", CONTROL_PANEL_BG_IMAGE, "Gradient", CONTROL_PANEL_BG_GRADIENT, "Default", CONTROL_PANEL_BG_DEFAULT, NULL );
270 vbox2 = gtk_vbox_new( FALSE, 10 );
271 color1 = g_object_new( GTK_TYPE_COLOR_BUTTON, "color", &(c->this_panel->color1), "title", "color1", "use-alpha", FALSE, NULL );
272 color2 = g_object_new( GTK_TYPE_COLOR_BUTTON, "color", &(c->this_panel->color2), "title", "color2", "use-alpha", FALSE, NULL );
273 framecolor = g_object_new( GTK_TYPE_COLOR_BUTTON,
274 "color", &(c->this_panel->frame_color), "title", "frame color", "use-alpha", TRUE, "alpha", c->this_panel->frame_alpha, NULL );
276 filename = gtk_file_chooser_button_new( "Background Image", GTK_FILE_CHOOSER_ACTION_OPEN );
279 if( c->this_panel->bg_image_name ) {
280 if( ! g_path_is_absolute( c->this_panel->bg_image_name ) ) {
281 gchar *current_dir = g_get_current_dir();
282 gchar *abspath = g_build_filename( current_dir, c->this_panel->bg_image_name, NULL );
283 g_free( c->this_panel->bg_image_name );
284 c->this_panel->bg_image_name = abspath;
285 g_free( current_dir );
288 gtk_file_chooser_set_filename( GTK_FILE_CHOOSER(filename), c->this_panel->bg_image_name );
289 } else {
290 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER(filename), pixmap_path);
293 gtk_container_add( GTK_CONTAINER( vbox2 ), color1 );
294 gtk_container_add( GTK_CONTAINER( vbox2 ), color2 );
295 gtk_container_add( GTK_CONTAINER( vbox2 ), framecolor );
296 gtk_container_add( GTK_CONTAINER( vbox2 ), filename );
298 gtk_container_add( GTK_CONTAINER( GTK_DIALOG( dialog )->vbox ), vbox2 );
299 gtk_widget_show_all( dialog );
301 gint response = gtk_dialog_run( GTK_DIALOG(dialog) );
302 if( response != GTK_RESPONSE_DELETE_EVENT ) {
303 gtk_color_button_get_color( GTK_COLOR_BUTTON(color1), &(c->this_panel->color1) );
304 gtk_color_button_get_color( GTK_COLOR_BUTTON(color2), &(c->this_panel->color2) );
305 gtk_color_button_get_color( GTK_COLOR_BUTTON(framecolor), &(c->this_panel->frame_color) );
306 c->this_panel->frame_alpha = gtk_color_button_get_alpha( GTK_COLOR_BUTTON(framecolor) );
308 if( c->this_panel->bg_image_name ) free( c->this_panel->bg_image_name );
309 c->this_panel->bg_image_name = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(filename) );
310 c->this_panel->bg_type = response;
314 gtk_widget_destroy( dialog );
316 control_update_bg( c );
324 PRIVATE GtkWidget *ctrl_rename_text_widget = NULL;
326 PRIVATE void ctrl_rename_handler(MsgBoxResponse action_taken, Control *c) {
327 if (action_taken == MSGBOX_OK) {
328 const char *newname = gtk_entry_get_text(GTK_ENTRY(ctrl_rename_text_widget));
330 if (c->name != NULL) {
331 free(c->name);
332 c->name = NULL;
335 if (newname[0] != '\0') /* nonempty string */
336 c->name = safe_string_dup(newname);
338 control_update_names(c);
342 PRIVATE void rename_ctrl_handler(GtkWidget *widget, Control *c) {
343 GtkWidget *hb = gtk_hbox_new(FALSE, 5);
344 GtkWidget *label = gtk_label_new("Rename control:");
345 GtkWidget *text = gtk_entry_new();
347 gtk_box_pack_start(GTK_BOX(hb), label, TRUE, FALSE, 0);
348 gtk_box_pack_start(GTK_BOX(hb), text, TRUE, FALSE, 0);
350 gtk_widget_show(label);
351 gtk_widget_show(text);
353 gtk_entry_set_text(GTK_ENTRY(text), c->name ? c->name : "");
355 ctrl_rename_text_widget = text;
356 popup_dialog("Rename", MSGBOX_OK | MSGBOX_CANCEL, 0, MSGBOX_OK, hb,
357 (MsgBoxResponseHandler) ctrl_rename_handler, c);
360 PRIVATE void midi_learn_handler(GtkWidget *widget, Control *c) {
361 midilearn_set_target_control( c );
364 PRIVATE void control_visible_ctrl_handler(GtkWidget *widget, Control *c) {
366 c->control_visible = !(c->control_visible);
368 if( c->control_visible )
369 gtk_widget_show( c->widget );
370 else
371 gtk_widget_hide( c->widget );
373 gtk_widget_queue_resize( c->whole );
376 PRIVATE void control_panel_test_bg_ctrl_handler(GtkWidget *widget, Control *c) {
378 c->testbg_active = !(c->testbg_active);
380 control_update_bg( c );
383 PRIVATE void entry_visible_ctrl_handler(GtkWidget *widget, Control *c) {
385 c->entry_visible = !(c->entry_visible);
387 if( c->entry_visible )
388 gtk_widget_show( c->entry );
389 else
390 gtk_widget_hide( c->entry );
392 gtk_widget_queue_resize( c->whole );
395 PRIVATE void frame_visible_ctrl_handler(GtkWidget *widget, Control *c) {
396 c->frame_visible = !(c->frame_visible);
398 if( ! c->frame_visible ){
399 gtk_frame_set_shadow_type (GTK_FRAME (c->title_frame) , GTK_SHADOW_NONE);
400 gtk_frame_set_label (GTK_FRAME (c->title_frame) , NULL);
401 }else{
402 gtk_frame_set_shadow_type (GTK_FRAME (c->title_frame) , GTK_SHADOW_ETCHED_IN);
403 gtk_label_set_text(GTK_LABEL(c->title_label),c->desc->name);
405 gtk_widget_queue_resize( c->whole );
408 PRIVATE void name_visible_ctrl_handler(GtkWidget *widget, Control *c) {
409 c->name_visible = !(c->name_visible);
411 if( ! c->name_visible ){
413 /* In order for this to work, you need the pixmap to bring up the menu...
414 * gtk_widget_hide( c->title_label );
415 * the following is a temp hack.
417 gtk_label_set_text(GTK_LABEL(c->title_label)," ");
419 }else{
420 /* In order for this to work, you need the pixmap to bring up the menu...
421 * gtk_widget_show( c->title_label );
422 * the following is a temp hack
424 control_update_names(c);
426 gtk_widget_queue_resize( c->whole );
428 PRIVATE void control_panel_sizer_visible_ctrl_handler(GtkWidget *widget, Control *c) {
430 c->this_panel->sizer_visible = !(c->this_panel->sizer_visible);
432 if( c->this_panel->sizer_visible ) {
433 gtk_widget_show( c->this_panel->sizer_image );
434 gtk_layout_move( GTK_LAYOUT(c->this_panel->fixedwidget), c->this_panel->sizer_ebox,
435 c->this_panel->sizer_x, c->this_panel->sizer_y );
438 else
440 gtk_widget_hide( c->this_panel->sizer_image );
441 gtk_layout_move( GTK_LAYOUT(c->this_panel->fixedwidget), c->this_panel->sizer_ebox,
442 c->this_panel->sizer_x + 16, c->this_panel->sizer_y + 16 );
446 PRIVATE void popup_menu(Control *c, GdkEventButton *be) {
447 static GtkWidget *old_popup_menu = NULL;
448 GtkWidget *menu;
449 GtkWidget *item;
451 if (old_popup_menu != NULL) {
452 gtk_widget_unref(old_popup_menu);
453 old_popup_menu = NULL;
456 menu = gtk_menu_new();
458 item = gtk_menu_item_new_with_label("Delete");
459 gtk_widget_show(item);
460 gtk_menu_append(GTK_MENU(menu), item);
461 gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(delete_ctrl_handler), c);
463 item = gtk_menu_item_new_with_label("Rename...");
464 gtk_widget_show(item);
465 gtk_menu_append(GTK_MENU(menu), item);
466 gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(rename_ctrl_handler), c);
469 item = gtk_check_menu_item_new_with_label( "Folded" );
470 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->folded );
471 gtk_widget_show(item);
472 gtk_menu_append(GTK_MENU(menu), item);
473 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(fold_ctrl_handler), c);
475 item = gtk_check_menu_item_new_with_label( "Discreet" );
476 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->discreet );
477 gtk_widget_show(item);
478 gtk_menu_append(GTK_MENU(menu), item);
479 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(discreet_ctrl_handler), c);
482 item = gtk_check_menu_item_new_with_label( "Frame" );
483 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->frame_visible );
484 gtk_widget_show(item);
485 gtk_menu_append(GTK_MENU(menu), item);
486 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(frame_visible_ctrl_handler), c);
488 item = gtk_check_menu_item_new_with_label( "Name" );
489 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->name_visible );
490 gtk_widget_show(item);
491 gtk_menu_append(GTK_MENU(menu), item);
492 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(name_visible_ctrl_handler), c);
494 if( c->entry ) {
495 item = gtk_check_menu_item_new_with_label( "Entry" );
496 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->entry_visible );
497 gtk_widget_show(item);
498 gtk_menu_append(GTK_MENU(menu), item);
499 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(entry_visible_ctrl_handler), c);
502 item = gtk_check_menu_item_new_with_label( "Control" );
503 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->control_visible );
504 gtk_widget_show(item);
505 gtk_menu_append(GTK_MENU(menu), item);
506 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(control_visible_ctrl_handler), c);
508 if( c->desc->kind == CONTROL_KIND_PANEL ) {
509 item = gtk_menu_item_new_with_label("Set Background");
510 gtk_widget_show(item);
511 gtk_menu_append(GTK_MENU(menu), item);
512 gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(change_bg_handler), c);
514 item = gtk_check_menu_item_new_with_label( "Reference Background" );
515 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->testbg_active );
516 gtk_widget_show(item);
517 gtk_menu_append(GTK_MENU(menu), item);
518 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(control_panel_test_bg_ctrl_handler), c);
520 item = gtk_check_menu_item_new_with_label( "Sizer" );
521 gtk_check_menu_item_set_state( GTK_CHECK_MENU_ITEM( item ), c->this_panel->sizer_visible );
522 gtk_widget_show(item);
523 gtk_menu_append(GTK_MENU(menu), item);
524 gtk_signal_connect(GTK_OBJECT(item), "toggled", GTK_SIGNAL_FUNC(control_panel_sizer_visible_ctrl_handler), c);
528 if( c->desc->kind == CONTROL_KIND_KNOB || c->desc->kind == CONTROL_KIND_SLIDER ) {
529 item = gtk_menu_item_new_with_label("MIDI Learn");
530 gtk_widget_show(item);
531 gtk_menu_append(GTK_MENU(menu), item);
532 gtk_signal_connect(GTK_OBJECT(item), "activate", GTK_SIGNAL_FUNC(midi_learn_handler), c);
535 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
536 be->button, be->time);
538 g_object_ref( menu );
539 old_popup_menu = menu;
542 PRIVATE gboolean eventbox_handler(GtkWidget *eventbox, GdkEvent *event, Control *c) {
544 switch (event->type) {
545 case GDK_BUTTON_PRESS: {
546 GdkEventButton *be = (GdkEventButton *) event;
548 switch (be->button) {
549 case 1:
550 if (!c->moving) {
551 c->moving = 1;
552 gtk_grab_add(eventbox);
553 c->saved_x = c->x - be->x_root;
554 c->saved_y = c->y - be->y_root;
556 break;
558 case 2:
559 case 3:
560 popup_menu(c, be);
561 break;
563 return TRUE;
566 case GDK_BUTTON_RELEASE: {
567 if (c->moving) {
568 c->moving = 0;
569 gtk_grab_remove(eventbox);
571 return TRUE;
574 case GDK_MOTION_NOTIFY: {
575 GdkEventMotion *me = (GdkEventMotion *) event;
577 if (c->moving) {
578 control_moveto(c,
579 c->saved_x + me->x_root,
580 c->saved_y + me->y_root);
583 gtk_widget_queue_draw( eventbox );
585 return TRUE;
588 default:
589 return FALSE;
593 PRIVATE gboolean control_map_handler(GtkWidget *eventbox, Control *c) {
595 gtk_widget_queue_resize( c->whole );
596 control_update_bg( c );
598 return FALSE;
602 PUBLIC Control *control_new_control(ControlDescriptor *desc, Generator *g, ControlPanel *panel) {
603 Control *c = safe_malloc(sizeof(Control));
604 GtkAdjustment *adj = NULL;
606 c->refcnt = 1;
607 c->desc = desc;
608 c->name = NULL;
609 c->min = desc->min;
610 c->max = desc->max;
611 c->step = desc->step;
612 c->page = desc->page;
614 c->frame_visible = TRUE;
615 c->name_visible = TRUE;
616 c->entry_visible = TRUE;
617 c->control_visible = TRUE;
618 c->testbg_active = FALSE;
620 if( panel == NULL && global_panel == NULL )
621 global_panel = control_panel_new( "Global", TRUE, NULL );
623 c->panel = panel;
625 c->moving = c->saved_x = c->saved_y = 0;
626 c->x = 0;
627 c->y = 0;
628 c->events_flow = TRUE;
629 c->kill_me = FALSE;
630 c->update_refcount = 0;
632 c->whole = NULL;
633 c->g = g;
634 c->data = NULL;
636 c->move_callback = NULL;
638 switch (desc->kind) {
639 case CONTROL_KIND_SLIDER:
640 c->widget = gtk_slider_new(NULL, c->desc->size);
641 adj = gtk_slider_get_adjustment(GTK_SLIDER(c->widget));
642 break;
644 case CONTROL_KIND_KNOB:
645 c->widget = gtk_knob_new(NULL);
646 adj = gtk_knob_get_adjustment(GTK_KNOB(c->widget));
647 break;
649 case CONTROL_KIND_TOGGLE:
650 c->widget = gtk_toggle_button_new_with_label("0/1");
651 gtk_signal_connect(GTK_OBJECT(c->widget), "toggled", GTK_SIGNAL_FUNC(toggled_handler), c);
652 break;
654 case CONTROL_KIND_BUTTON:
655 c->widget = gtk_button_new();
656 gtk_widget_set_usize(c->widget, 24, 8);
657 gtk_signal_connect(GTK_OBJECT(c->widget), "clicked", GTK_SIGNAL_FUNC(clicked_handler), c);
658 break;
660 case CONTROL_KIND_USERDEF:
661 case CONTROL_KIND_PANEL:
662 c->widget = NULL;
663 break;
665 default:
666 g_error("Unknown control kind %d (ControlDescriptor named '%s')",
667 desc->kind,
668 desc->name);
671 if (desc->initialize)
672 desc->initialize(c);
674 if (c->widget == NULL) {
675 free(c);
676 return NULL;
679 if (adj != NULL) {
680 adj->lower = c->min;
681 adj->upper = c->max;
682 adj->value = c->min;
683 adj->step_increment = c->step;
684 adj->page_increment = c->page;
686 gtk_signal_connect(GTK_OBJECT(adj), "value_changed", GTK_SIGNAL_FUNC(knob_slider_handler), c);
690 GtkWidget *eventbox;
691 GtkWidget *vbox;
693 if( desc->kind == CONTROL_KIND_PANEL )
694 c->this_panel = desc->refresh_data;
695 else
696 c->this_panel = NULL;
698 c->title_frame = gtk_frame_new(g == NULL ? c->this_panel->name : g->name);
699 gtk_widget_show(c->title_frame);
701 vbox = gtk_vbox_new(FALSE, 0);
702 gtk_container_add(GTK_CONTAINER(c->title_frame), vbox);
703 gtk_widget_show(vbox);
705 eventbox = gtk_event_box_new();
706 gtk_box_pack_start(GTK_BOX(vbox), eventbox, FALSE, FALSE, 0);
707 gtk_widget_show(eventbox);
708 gtk_signal_connect(GTK_OBJECT(eventbox), "event", GTK_SIGNAL_FUNC(eventbox_handler), c);
710 c->title_label = gtk_label_new(c->name ? c->name : desc->name);
711 gtk_container_add(GTK_CONTAINER(eventbox), c->title_label);
712 gtk_widget_show(c->title_label);
714 if( desc->kind == CONTROL_KIND_PANEL )
715 gtk_widget_reparent( c->widget, vbox );
716 else
717 gtk_box_pack_start(GTK_BOX(vbox), c->widget, FALSE, FALSE, 0);
719 gtk_widget_show(c->widget);
721 if (adj != NULL && c->desc->allow_direct_edit) {
722 c->entry = gtk_entry_new();
723 gtk_widget_set_usize(c->entry, GAUGE_SIZE, 0);
724 gtk_widget_show(c->entry);
726 gtk_box_pack_start(GTK_BOX(vbox), c->entry, FALSE, FALSE, 0);
728 gtk_signal_connect(GTK_OBJECT(c->entry), "activate",
729 GTK_SIGNAL_FUNC(entry_changed), adj);
730 gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
731 GTK_SIGNAL_FUNC(update_entry), c->entry);
732 } else {
733 c->entry = NULL;
736 c->whole = gtk_event_box_new();
738 gtk_signal_connect_after(GTK_OBJECT(c->whole), "map", GTK_SIGNAL_FUNC(control_map_handler), c);
740 g_object_ref( G_OBJECT(c->whole) );
741 g_object_set_data( G_OBJECT(c->whole), "Control", c );
742 gtk_container_add(GTK_CONTAINER(c->whole), c->title_frame );
743 gtk_widget_show( c->whole );
745 gtk_layout_put(GTK_LAYOUT(panel == NULL ? global_panel->fixedwidget : panel->fixedwidget),
746 c->whole, c->x, c->y);
748 g_object_ref( G_OBJECT( panel == NULL ? global_panel->fixedwidget : panel->fixedwidget ) );
750 if (!GTK_WIDGET_REALIZED(eventbox))
751 gtk_widget_realize(eventbox);
753 gdk_window_set_events(eventbox->window,
754 GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK );
757 if( c->desc->kind != CONTROL_KIND_PANEL ) {
758 gen_register_control(c->g, c);
759 gen_update_controls( c->g, -1 );
762 if( c->widget )
763 g_object_ref( G_OBJECT(c->widget) );
765 return c;
769 * \brief Kill a Control
771 * \param c The Control to be removed
773 * with the gdk_threads_enter/leave pair i need to assure this is a different thread.
774 * it could be safe to call check for kill Control from the update processor.
776 * i will put gdk_threads enter leave outside of this function.
777 * So make sure you hold the gdk-lock when you call this function.
780 PUBLIC void control_kill_control(Control *c, gboolean lock_taken) {
781 g_return_if_fail(c != NULL);
783 midilearn_remove_control( c );
785 if (c->g != NULL)
786 gen_deregister_control(c->g, c, lock_taken);
788 control_unref( c );
791 PRIVATE void control_dispose( Control *c )
793 if( c->widget )
794 g_object_unref( G_OBJECT( c->widget ) );
795 if( c->desc->destroy != NULL )
796 c->desc->destroy( c );
797 //gtk_widget_hide(c->whole);
798 //gtk_container_remove(GTK_CONTAINER(c->panel == NULL ? global_panel->fixedwidget : c->panel->fixedwidget), c->whole);
799 gtk_widget_destroy( c->whole );
800 g_object_unref( G_OBJECT(c->whole) );
801 g_object_unref( G_OBJECT(c->panel == NULL ? global_panel->fixedwidget : c->panel->fixedwidget) );
803 if (c->name != NULL)
804 safe_free(c->name);
807 safe_free(c);
808 // TODO: a race condition with the updater_thread. let the updater delete the control.
809 // need to add a lock for the controls list.
810 //c->kill_me = TRUE;
811 //control_update_value( c );
814 PUBLIC void control_ref( Control *c )
816 g_atomic_int_inc( &(c->refcnt) );
819 PUBLIC void control_unref( Control *c )
821 if( g_atomic_int_dec_and_test( &(c->refcnt) ) )
823 control_dispose( c );
827 PRIVATE int find_control_index(Control *c) {
828 int i;
830 for (i = 0; i < c->g->klass->numcontrols; i++)
831 if (&c->g->klass->controls[i] == c->desc)
832 return i;
834 g_error("Control index unfindable! c->desc->name is %p (%s)", c->desc->name, c->desc->name);
835 return -1;
838 PRIVATE GtkWidget *panel_fixed = NULL;
840 PRIVATE void init_panel( Control *control ) {
841 control->widget = panel_fixed;
844 PRIVATE void done_panel( Control *control ) {
846 control->this_panel->sheet->panel_control_active = FALSE;
847 control->this_panel->sheet->panel_control = NULL;
849 control_panel_register_panel( control->this_panel, control->this_panel->name, FALSE );
851 g_object_ref( G_OBJECT(control->this_panel->fixedwidget) );
852 gtk_widget_reparent( control->this_panel->fixedwidget, control->this_panel->scrollwin );
853 g_object_unref( G_OBJECT(control->this_panel->fixedwidget) );
855 gtk_layout_set_vadjustment( GTK_LAYOUT( control->this_panel->fixedwidget ),
856 gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW( control->this_panel->scrollwin ) ) );
857 gtk_layout_set_hadjustment( GTK_LAYOUT( control->this_panel->fixedwidget ),
858 gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW( control->this_panel->scrollwin ) ) );
860 gtk_widget_show( control->this_panel->fixedwidget );
861 gtk_widget_queue_resize( control->this_panel->fixedwidget );
864 PRIVATE ControlDescriptor desc =
865 { CONTROL_KIND_PANEL, "panel", 0,0,0,0, 0,FALSE, TRUE,0, init_panel, done_panel, NULL, NULL };
868 PUBLIC Control *control_unpickle(ObjectStoreItem *item) {
870 Generator *g = gen_unpickle(objectstore_item_get_object(item, "generator"));
871 int control_index = objectstore_item_get_integer(item, "desc_index", 0);
872 ObjectStoreItem *ccp = objectstore_item_get_object( item, "panel" );
873 ControlPanel *cp = ((ccp == NULL) ? NULL : control_panel_unpickle( ccp ));
874 ControlPanel *tp = control_panel_unpickle( objectstore_item_get_object( item, "this_panel" ));
875 Control *c;
876 char *name;
877 int x, y;
878 int folded, discreet;
880 if( g == NULL ) {
881 desc.refresh_data = tp;
882 panel_fixed = tp->fixedwidget;
883 c = control_new_control( &desc, NULL, cp );
884 control_panel_unregister_panel( tp );
885 } else {
886 c = control_new_control(&g->klass->controls[control_index], g, cp);
890 name = objectstore_item_get_string(item, "name", NULL);
891 c->name = name ? safe_string_dup(name) : NULL;
892 if (name)
893 control_update_names(c);
895 c->min = objectstore_item_get_double(item, "min", 0);
896 c->max = objectstore_item_get_double(item, "max", 100);
897 c->step = objectstore_item_get_double(item, "step", 1);
898 c->page = objectstore_item_get_double(item, "page", 1);
900 folded = objectstore_item_get_integer(item, "folded", 0);
901 discreet = objectstore_item_get_integer(item, "discreet", 0);
903 if( ! (c->frame_visible = objectstore_item_get_integer( item, "frame_visible", ! discreet ) ) ) {
904 gtk_frame_set_shadow_type (GTK_FRAME (c->title_frame) , GTK_SHADOW_NONE);
905 gtk_frame_set_label (GTK_FRAME (c->title_frame) , NULL);
906 //gtk_label_set_text(GTK_LABEL(c->title_label)," ");
909 if( ! (c->name_visible = objectstore_item_get_integer( item, "name_visible", c->frame_visible ) ) ) {
910 gtk_label_set_text(GTK_LABEL(c->title_label)," ");
913 if( ! (c->entry_visible = objectstore_item_get_integer( item, "entry_visible", ! discreet ) ) ) {
914 if( c->entry )
915 gtk_widget_hide( c->entry );
918 if( ! (c->control_visible = objectstore_item_get_integer( item, "control_visible", ! folded ) ) ) {
919 gtk_widget_hide( c->widget );
924 // XXX: always or default ?
925 if( c->this_panel && c->this_panel->bg_image_name ) {
928 control_update_bg( c );
931 x = objectstore_item_get_integer(item, "x_coord", 0);
932 y = objectstore_item_get_integer(item, "y_coord", 0);
933 control_moveto(c, x, y);
934 c->events_flow = TRUE;
935 c->kill_me = FALSE;
936 c->update_refcount = 0;
938 return c;
941 PUBLIC ObjectStoreItem *control_pickle(Control *c, ObjectStore *db) {
942 ObjectStoreItem *item = objectstore_new_item(db, "Control", c);
943 if( c->g != NULL ) {
944 objectstore_item_set_object(item, "generator", gen_pickle(c->g, db));
945 objectstore_item_set_integer(item, "desc_index", find_control_index(c));
948 if( c->this_panel )
949 objectstore_item_set_object(item, "this_panel", control_panel_pickle(c->this_panel, db));
951 if( c->panel )
952 objectstore_item_set_object(item, "panel", control_panel_pickle(c->panel, db));
954 if (c->name)
955 objectstore_item_set_string(item, "name", c->name);
957 objectstore_item_set_double(item, "min", c->min);
958 objectstore_item_set_double(item, "max", c->max);
959 objectstore_item_set_double(item, "step", c->step);
960 objectstore_item_set_double(item, "page", c->page);
961 objectstore_item_set_integer(item, "x_coord", c->x);
962 objectstore_item_set_integer(item, "y_coord", c->y);
963 // objectstore_item_set_integer(item, "folded", c->folded);
964 // objectstore_item_set_integer(item, "discreet", c->discreet);
965 objectstore_item_set_integer(item, "control_visible", c->control_visible);
966 objectstore_item_set_integer(item, "frame_visible", c->frame_visible);
967 objectstore_item_set_integer(item, "name_visible", c->name_visible);
968 objectstore_item_set_integer(item, "entry_visible", c->entry_visible);
971 /* don't save c->data in any form, Controls are MVC views, not models. */
972 return item;
975 Control *control_clone( Control *c, Generator *g, ControlPanel *cp ) {
977 Control *retval = control_new_control( c->desc, g, cp );
979 retval->name = c->name ? safe_string_dup(c->name) : NULL;
980 if (retval->name)
981 control_update_names(retval);
984 retval->frame_visible = c->frame_visible;
985 if( ! (c->frame_visible) ) {
986 gtk_frame_set_shadow_type (GTK_FRAME (retval->title_frame) , GTK_SHADOW_NONE);
987 gtk_frame_set_label (GTK_FRAME (retval->title_frame) , NULL);
988 gtk_label_set_text(GTK_LABEL(retval->title_label)," ");
991 retval->entry_visible = c->entry_visible;
992 if( ! (c->entry_visible) ) {
993 if( retval->entry )
994 gtk_widget_hide( retval->entry );
997 retval->control_visible = c->control_visible;
998 if( ! (c->control_visible) ) {
999 gtk_widget_hide( retval->widget );
1001 retval->min = c->min;
1002 retval->max = c->max;
1003 retval->step = c->step;
1004 retval->page = c->page;
1006 control_moveto( retval, c->x, c->y );
1008 return retval;
1011 PUBLIC void control_emit(Control *c, gdouble number) {
1012 AEvent e;
1014 if (!c->events_flow)
1015 return;
1017 gen_init_aevent(&e, AE_NUMBER, NULL, 0, c->g, c->desc->queue_number, gen_get_sampletime());
1018 e.d.number = number;
1020 if (c->desc->is_dst_gen)
1021 gen_post_aevent(&e); /* send to c->g as dest */
1022 else
1023 gen_send_events(c->g, c->desc->queue_number, -1, &e); /* send *from* c->g */
1026 PUBLIC void control_update_names(Control *c) {
1027 g_return_if_fail(c != NULL);
1029 if( c->frame_visible ) {
1031 if( c->g != NULL )
1032 gtk_frame_set_label(GTK_FRAME(c->title_frame), c->g->name);
1033 else
1034 gtk_frame_set_label(GTK_FRAME(c->title_frame), c->this_panel->name );
1037 if( c->name_visible ) {
1038 gtk_label_set_text(GTK_LABEL(c->title_label), c->name ? c->name : c->desc->name);
1042 PUBLIC void control_update_range(Control *c) {
1043 GtkAdjustment *adj = NULL;
1045 switch (c->desc->kind) {
1046 case CONTROL_KIND_SLIDER: adj = gtk_slider_get_adjustment(GTK_SLIDER(c->widget)); break;
1047 case CONTROL_KIND_KNOB: adj = gtk_knob_get_adjustment(GTK_KNOB(c->widget)); break;
1048 default:
1049 break;
1052 if (adj != NULL) {
1053 adj->lower = c->min;
1054 adj->upper = c->max;
1055 adj->step_increment = c->step;
1056 adj->page_increment = c->page;
1058 gtk_signal_emit_by_name(GTK_OBJECT(adj), "changed");
1062 PUBLIC void control_update_value(Control *c) {
1063 control_ref( c );
1064 g_async_queue_push( update_queue, c );
1067 PRIVATE void control_update_value_real(Control *c) {
1068 c->events_flow = FALSE; /* as already stated... not very elegant. */
1070 if (c->desc->refresh != NULL)
1071 c->desc->refresh(c);
1073 c->events_flow = TRUE;
1076 PRIVATE gboolean control_panel_delete_handler(GtkWidget *cp, GdkEvent *event) {
1077 hide_control_panel();
1078 return TRUE;
1082 PRIVATE gboolean sizerbox_handler(GtkWidget *eventbox, GdkEvent *event, ControlPanel *panel) {
1084 switch (event->type) {
1085 case GDK_BUTTON_PRESS:
1087 GdkEventButton *be = (GdkEventButton *) event;
1089 switch (be->button) {
1090 case 1:
1091 if (!panel->sizer_moving) {
1092 panel->sizer_moving = 1;
1093 gtk_grab_add(eventbox);
1094 panel->sizer_saved_x = panel->sizer_x - be->x_root;
1095 panel->sizer_saved_y = panel->sizer_y - be->y_root;
1097 break;
1099 return TRUE;
1102 case GDK_BUTTON_RELEASE:
1104 if (panel->sizer_moving) {
1105 panel->sizer_moving = 0;
1106 gtk_grab_remove(eventbox);
1108 return TRUE;
1111 case GDK_MOTION_NOTIFY:
1113 GdkEventMotion *me = (GdkEventMotion *) event;
1115 if (panel->sizer_moving) {
1116 gtk_layout_move( GTK_LAYOUT(panel->fixedwidget), eventbox,
1117 panel->sizer_saved_x + me->x_root,
1118 panel->sizer_saved_y + me->y_root );
1120 panel->sizer_x = panel->sizer_saved_x + me->x_root;
1121 panel->sizer_y = panel->sizer_saved_y + me->y_root;
1124 return TRUE;
1127 default:
1128 return FALSE;
1132 PRIVATE void control_invoke_move_callback( GtkWidget *control_widget, gpointer user_data ) {
1133 Control *c = g_object_get_data( G_OBJECT(control_widget), "Control" );
1134 if( c && c->move_callback )
1135 c->move_callback( c );
1138 PRIVATE void control_panel_scroll_handler( GtkAdjustment *adjustment, ControlPanel *cp ) {
1139 gtk_container_foreach( GTK_CONTAINER(cp->fixedwidget), control_invoke_move_callback, NULL );
1142 PUBLIC ControlPanel *control_panel_new( char *name, gboolean visible, Sheet *sheet ) {
1144 ControlPanel *panel = safe_malloc( sizeof( ControlPanel ) );
1145 panel->scrollwin = NULL; //gtk_scrolled_window_new(NULL, NULL);
1146 panel->name = safe_string_dup(name);
1148 panel->fixedwidget = gtk_layout_new(NULL,NULL);
1151 panel->w = 0;
1152 panel->h = 0;
1154 panel->sizer_x = 0;
1155 panel->sizer_y = 0;
1156 panel->sizer_moving = 0;
1157 panel->sizer_visible = 0;
1158 panel->bg_image_name = NULL;
1159 gdk_color_white( gdk_colormap_get_system(), &(panel->color1) );
1160 gdk_color_black( gdk_colormap_get_system(), &(panel->color2) );
1162 g_signal_connect( G_OBJECT( panel->fixedwidget ), "size_request", G_CALLBACK(mylayout_sizerequest), NULL );
1166 if( visible )
1167 control_panel_register_panel( panel, name, TRUE );
1168 else
1169 panel->visible = FALSE;
1171 g_signal_connect_after( gtk_layout_get_hadjustment( GTK_LAYOUT( panel->fixedwidget ) ),
1172 "value-changed", (GCallback) control_panel_scroll_handler, panel );
1173 g_signal_connect_after( gtk_layout_get_vadjustment( GTK_LAYOUT( panel->fixedwidget ) ),
1174 "value-changed", (GCallback) control_panel_scroll_handler, panel );
1176 panel->sheet = sheet;
1178 gtk_widget_show(panel->fixedwidget);
1180 // if (!GTK_WIDGET_REALIZED(panel->fixedwidget))
1181 // gtk_widget_realize(panel->fixedwidget);
1183 gtk_container_check_resize( GTK_CONTAINER(panel->fixedwidget) );
1184 update_panel_name( panel );
1186 // code for the sizer.
1188 panel->sizer_image = gtk_image_new_from_file( PIXMAPDIRIFY( "corner-widget.png" ) );
1189 panel->sizer_ebox = gtk_event_box_new();
1191 gtk_container_add( GTK_CONTAINER( panel->sizer_ebox ), panel->sizer_image );
1193 gtk_layout_put( GTK_LAYOUT( panel->fixedwidget ), panel->sizer_ebox, 0, 0 );
1195 gtk_widget_show( panel->sizer_ebox );
1197 gtk_signal_connect(GTK_OBJECT(panel->sizer_ebox), "event", GTK_SIGNAL_FUNC(sizerbox_handler), panel);
1200 return panel;
1203 PUBLIC ControlPanel *control_panel_unpickle(ObjectStoreItem *item) {
1205 ControlPanel *cp;
1206 if( item == NULL )
1207 return NULL;
1209 cp = objectstore_get_object( item );
1210 if( cp == NULL ) {
1211 char *name = objectstore_item_get_string(item, "name", "Panel" );
1212 ObjectStoreItem *sitem = objectstore_item_get_object( item, "sheet" );
1213 //gboolean visible = objectstore_item_get_integer( item, "visible", TRUE );
1214 cp = control_panel_new( name, TRUE, NULL );
1215 objectstore_set_object(item, cp);
1216 cp->sizer_x = objectstore_item_get_integer( item, "sizer_x", 0 );
1217 cp->sizer_y = objectstore_item_get_integer( item, "sizer_y", 0 );
1218 cp->sheet = ( sitem == NULL ? NULL : sheet_unpickle( sitem ) );
1219 cp->bg_type = CONTROL_PANEL_BG_DEFAULT;
1220 cp->bg_image_name = objectstore_item_get_string( item, "current_bg", NULL );
1221 if( cp->bg_image_name ) {
1222 if( g_file_test( cp->bg_image_name, G_FILE_TEST_EXISTS ) ) {
1223 cp->bg_image_name = safe_string_dup( cp->bg_image_name );
1224 cp->bg_type = CONTROL_PANEL_BG_IMAGE;
1225 } else {
1226 char *bg_basename = g_path_get_basename( cp->bg_image_name );
1227 char *bg_in_pixmap_dir = g_build_filename( pixmap_path, bg_basename, NULL );
1229 if( g_file_test( bg_in_pixmap_dir, G_FILE_TEST_EXISTS ) ) {
1230 cp->bg_image_name = bg_in_pixmap_dir;
1231 cp->bg_type = CONTROL_PANEL_BG_IMAGE;
1232 } else {
1233 cp->bg_image_name = NULL;
1234 g_free( bg_in_pixmap_dir );
1237 g_free( bg_basename );
1240 cp->color1.red = objectstore_item_get_integer( item, "color1_red", 65535 );
1241 cp->color1.green = objectstore_item_get_integer( item, "color1_green", 65535 );
1242 cp->color1.blue = objectstore_item_get_integer( item, "color1_blue", 65535 );
1243 cp->color2.red = objectstore_item_get_integer( item, "color2_red", 0 );
1244 cp->color2.green = objectstore_item_get_integer( item, "color2_green", 0 );
1245 cp->color2.blue = objectstore_item_get_integer( item, "color2_blue", 0 );
1246 cp->frame_color.red = objectstore_item_get_integer( item, "frame_color_red", 0 );
1247 cp->frame_color.green = objectstore_item_get_integer( item, "frame_color_green", 0 );
1248 cp->frame_color.blue = objectstore_item_get_integer( item, "frame_color_blue", 0 );
1249 cp->frame_alpha = objectstore_item_get_integer( item, "frame_alpha", 0 );
1250 cp->bg_type = objectstore_item_get_integer( item, "bg_type", cp->bg_type );
1252 gtk_layout_move( GTK_LAYOUT(cp->fixedwidget), cp->sizer_ebox,
1253 cp->sizer_x + 16, cp->sizer_y + 16 );
1256 return cp;
1259 PUBLIC ObjectStoreItem *control_panel_pickle(ControlPanel *cp, ObjectStore *db) {
1260 ObjectStoreItem *item = objectstore_get_item(db, cp);
1262 if (item == NULL) {
1263 item = objectstore_new_item(db, "ControlPanel", cp);
1264 if (cp->name)
1265 objectstore_item_set_string(item, "name", cp->name);
1266 if( cp->sheet )
1267 objectstore_item_set_object( item, "sheet", sheet_pickle( cp->sheet, db ) );
1269 if ( cp->bg_image_name )
1270 objectstore_item_set_string( item, "current_bg", cp->bg_image_name );
1271 objectstore_item_set_integer( item, "visible", cp->visible );
1272 objectstore_item_set_integer( item, "sizer_x", cp->sizer_x );
1273 objectstore_item_set_integer( item, "sizer_y", cp->sizer_y );
1275 objectstore_item_set_integer( item, "color1_red", cp->color1.red );
1276 objectstore_item_set_integer( item, "color1_green", cp->color1.green );
1277 objectstore_item_set_integer( item, "color1_blue", cp->color1.blue );
1278 objectstore_item_set_integer( item, "color2_red", cp->color2.red );
1279 objectstore_item_set_integer( item, "color2_green", cp->color2.green );
1280 objectstore_item_set_integer( item, "color2_blue", cp->color2.blue );
1281 objectstore_item_set_integer( item, "frame_color_red", cp->frame_color.red );
1282 objectstore_item_set_integer( item, "frame_color_green", cp->frame_color.green );
1283 objectstore_item_set_integer( item, "frame_color_blue", cp->frame_color.blue );
1284 objectstore_item_set_integer( item, "frame_alpha", cp->frame_alpha );
1285 objectstore_item_set_integer( item, "bg_type", cp->bg_type );
1288 return item;
1291 PRIVATE gpointer update_processor( gpointer data ) {
1292 while( 1 ) {
1293 Control *c = g_async_queue_pop( update_queue );
1294 gdk_threads_enter();
1295 control_update_value_real( c );
1296 control_unref( c );
1297 gdk_threads_leave();
1299 return NULL;
1302 PUBLIC void init_control_thread(void) {
1303 GError *err;
1304 update_thread = g_thread_create( update_processor, NULL, TRUE, &err );
1307 PUBLIC void init_control(void) {
1309 pixmap_path = getenv("GALAN_PIXMAP_PATH");
1310 if( ! pixmap_path )
1311 pixmap_path = SITE_PKGDATA_DIR G_DIR_SEPARATOR_S "pixmaps";
1313 if( ! g_path_is_absolute( pixmap_path ) ) {
1314 gchar *current_dir = g_get_current_dir();
1315 gchar *abspath = g_build_filename( current_dir, pixmap_path, NULL );
1316 //g_free( pixmap_path );
1317 pixmap_path = abspath;
1318 g_free( current_dir );
1321 update_queue = g_async_queue_new();
1323 control_panel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1324 gtk_window_set_title(GTK_WINDOW(control_panel), "gAlan Control Panel");
1325 gtk_window_position(GTK_WINDOW(control_panel), GTK_WIN_POS_CENTER);
1326 gtk_window_set_policy(GTK_WINDOW(control_panel), TRUE, TRUE, FALSE);
1327 gtk_window_set_wmclass(GTK_WINDOW(control_panel), "gAlan_controls", "gAlan");
1328 gtk_widget_set_usize(control_panel, 400, 300);
1329 gtk_widget_set_name( control_panel, "control_panel" );
1330 gtk_signal_connect(GTK_OBJECT(control_panel), "delete_event",
1331 GTK_SIGNAL_FUNC(control_panel_delete_handler), NULL);
1334 control_notebook = gtk_notebook_new();
1335 gtk_widget_show( control_notebook );
1336 gtk_container_add(GTK_CONTAINER(control_panel), control_notebook);
1339 PUBLIC void show_control_panel(void) {
1340 gtk_widget_show(control_panel);
1343 PUBLIC void hide_control_panel(void) {
1344 gtk_widget_hide(control_panel);
1347 PUBLIC void reset_control_panel(void) {
1348 /* A NOOP currently.
1349 * When I get round to figuring out a good way of making newly-created controls
1350 * appear in an empty spot, this routine may become useful. */
1353 PUBLIC void control_set_value(Control *c, gfloat value) {
1354 GtkAdjustment *adj;
1356 switch (c->desc->kind) {
1357 case CONTROL_KIND_SLIDER: adj = gtk_slider_get_adjustment(GTK_SLIDER(c->widget)); break;
1358 case CONTROL_KIND_KNOB: adj = gtk_knob_get_adjustment(GTK_KNOB(c->widget)); break;
1360 case CONTROL_KIND_TOGGLE:
1361 value = MAX(MIN(value, 1), 0);
1362 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->widget), value >= 0.5);
1363 return;
1365 default:
1366 return;
1369 if (adj != NULL) {
1370 //adj->value = value;
1371 //gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
1372 gtk_adjustment_set_value( GTK_ADJUSTMENT( adj ), value );
1376 PUBLIC void control_int32_updater(Control *c) {
1377 control_set_value(c, * (gint32 *) ((gpointer) c->g->data + (size_t) c->desc->refresh_data));
1380 PUBLIC void control_double_updater(Control *c) {
1381 control_set_value(c, * (gdouble *) ((gpointer) c->g->data + (size_t) c->desc->refresh_data));