It appears Solaris's cc is ignoring the signedness of bitfield types.
[xiph/unicode.git] / sushivision / panelmenu.c
blobc691b49204033bf8c06c90c3dc0477ea95605c3e
1 /*
3 * sushivision copyright (C) 2006-2007 Monty <monty@xiph.org>
5 * sushivision is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * sushivision 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
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with sushivision; see the file COPYING. If not, write to the
17 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define _GNU_SOURCE
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <pthread.h>
27 #include <errno.h>
28 #include <math.h>
29 #include <signal.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <gtk/gtk.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <cairo-ft.h>
35 #include "internal.h"
37 static void wrap_exit(sv_panel_t *dummy, GtkWidget *dummyw);
38 static void wrap_bg(sv_panel_t *p, GtkWidget *w);
39 static void wrap_grid(sv_panel_t *p, GtkWidget *w);
40 static void wrap_text(sv_panel_t *p, GtkWidget *w);
41 static void wrap_res(sv_panel_t *p, GtkWidget *w);
42 static void wrap_load(sv_panel_t *p, GtkWidget *dummy);
43 static void wrap_save(sv_panel_t *p, GtkWidget *dummy);
44 static void wrap_print(sv_panel_t *p, GtkWidget *dummy);
45 static void wrap_undo_up(sv_panel_t *p, GtkWidget *dummy);
46 static void wrap_undo_down(sv_panel_t *p, GtkWidget *dummy);
47 static void wrap_legend(sv_panel_t *p, GtkWidget *dummy);
48 static void wrap_escape(sv_panel_t *p, GtkWidget *dummy);
49 static void wrap_enter(sv_panel_t *p, GtkWidget *dummy);
51 static sv_propmap_t *bgmap[]={
52 &(sv_propmap_t){"white","#ffffff", "[<i>b</i>]",NULL,wrap_bg},
53 &(sv_propmap_t){"gray","#a0a0a0", "[<i>b</i>]",NULL,wrap_bg},
54 &(sv_propmap_t){"blue","#000060", "[<i>b</i>]",NULL,wrap_bg},
55 &(sv_propmap_t){"black","#000000", "[<i>b</i>]",NULL,wrap_bg},
56 &(sv_propmap_t){"checks","checks", "[<i>b</i>]",NULL,wrap_bg},
57 NULL
60 static sv_propmap_t *gridmap[]={
61 &(sv_propmap_t){"light","#e6e6e6", "[<i>g</i>]",NULL,wrap_grid},
62 &(sv_propmap_t){"normal","#b4b4b4", "[<i>g</i>]",NULL,wrap_grid},
63 &(sv_propmap_t){"dark","#181818", "[<i>g</i>]",NULL,wrap_grid},
64 &(sv_propmap_t){"tics","tics", "[<i>g</i>]",NULL,wrap_grid},
65 &(sv_propmap_t){"none","none", "[<i>g</i>]",NULL,wrap_grid},
66 NULL
69 static _sv_propmap_t *textmap[]={
70 &(sv_propmap_t){"dark","#000000", "[<i>t</i>]",NULL,wrap_text},
71 &(sv_propmap_t){"light","#ffffff", "[<i>t</i>]",NULL,wrap_text},
72 NULL
75 static _sv_propmap_t *legendmap[]={
76 &(_sv_propmap_t){"none","none", NULL,NULL,NULL},
77 &(_sv_propmap_t){"shadowed","shadowed", NULL,NULL,NULL},
78 &(_sv_propmap_t){"boxed","boxed", NULL,NULL,NULL},
79 NULL
82 static _sv_propmap_t *menu[]={
83 &(_sv_propmap_t){"Open",0,"[<i>o</i>]",NULL,wrap_load},
84 &(_sv_propmap_t){"Save",0,"[<i>s</i>]",NULL,wrap_save},
85 &(_sv_propmap_t){"Print/Export",0,"[<i>p</i>]",NULL,wrap_print},
87 &(_sv_propmap_t){"",0,NULL,NULL,NULL},
89 &(_sv_propmap_t){"Undo",0,"[<i>bksp</i>]",NULL,wrap_undo_down},
90 &(_sv_propmap_t){"Redo",0,"[<i>space</i>]",NULL,wrap_undo_up},
91 &(_sv_propmap_t){"Start zoom box",0,"[<i>enter</i>]",NULL,wrap_enter},
92 &(_sv_propmap_t){"Clear selection",0,"[<i>escape</i>]",NULL,wrap_escape},
93 &(_sv_propmap_t){"Toggle Legend",0,"[<i>l</i>]",NULL,wrap_legend},
95 &(_sv_propmap_t){"",9,NULL,NULL,NULL},
97 &(_sv_propmap_t){"Background",0,"...",bgmap,NULL},
98 &(_sv_propmap_t){"Text color",0,"...",textmap,NULL},
99 &(_sv_propmap_t){"Grid mode",0,"...",gridmap,NULL},
100 &(_sv_propmap_t){"Sampling",0,"...",resmap,NULL},
102 &(_sv_propmap_t){"",0,NULL,NULL,NULL},
104 &(_sv_propmap_t){"Quit",0,"[<i>q</i>]",NULL,wrap_exit},
106 NULL
109 static void decide_text_inv(sv_panel_t *p){
110 if(p->private->graph){
111 _sv_plot_t *plot = PLOT(p->private->graph);
112 if(p->private->bg_type == SV_BG_WHITE)
113 _sv_plot_set_bg_invert(plot,_SV_PLOT_TEXT_DARK);
114 else
115 _sv_plot_set_bg_invert(plot,_SV_PLOT_TEXT_LIGHT);
119 static void recompute_if_running(sv_panel_t *p){
120 if(p->private->realized && p->private->graph)
121 _sv_panel_recompute(p);
124 static void redraw_if_running(sv_panel_t *p){
125 if(p->private->realized && p->private->graph){
126 _sv_plot_draw_scales(PLOT(p->private->graph));
127 _sv_panel_dirty_map(p);
128 _sv_panel_dirty_legend(p);
132 static void refg_if_running(sv_panel_t *p){
133 if(p->private->realized && p->private->graph){
134 _sv_plot_draw_scales(PLOT(p->private->graph));
135 _sv_panel_dirty_legend(p);
139 static void wrap_exit(sv_panel_t *dummy, GtkWidget *dummyw){
140 _sv_clean_exit();
143 // precipitated actions perform undo push
144 static void wrap_enter(sv_panel_t *p, GtkWidget *dummy){
145 _sv_plot_do_enter(PLOT(p->private->graph));
148 static void wrap_escape(sv_panel_t *p, GtkWidget *dummy){
149 _sv_undo_push();
150 _sv_undo_suspend();
152 _sv_plot_set_crossactive(PLOT(p->private->graph),0);
153 _sv_panel_dirty_legend(p);
155 _sv_undo_resume();
158 static void wrap_legend(sv_panel_t *p, GtkWidget *dummy){
159 _sv_undo_push();
160 _sv_undo_suspend();
162 _sv_plot_toggle_legend(PLOT(p->private->graph));
163 _sv_panel_dirty_legend(p);
165 _sv_undo_resume();
168 static void set_grid(sv_panel_t *p, int mode){
169 _sv_undo_push();
170 _sv_undo_suspend();
172 _sv_plot_set_grid(PLOT(p->private->graph),mode);
173 _sv_panel_update_menus(p);
174 refg_if_running(p);
176 _sv_undo_resume();
179 static void wrap_grid(sv_panel_t *p, GtkWidget *w){
180 int pos = _gtk_menu_item_position(w);
181 set_grid(p, gridmap[pos]->value);
184 static int set_background(sv_panel_t *p,
185 enum sv_background bg){
187 sv_panel_internal_t *pi = p->private;
189 _sv_undo_push();
190 _sv_undo_suspend();
192 pi->bg_type = bg;
194 decide_text_inv(p);
195 set_grid(p,_SV_PLOT_GRID_NORMAL);
196 redraw_if_running(p);
197 _sv_panel_update_menus(p);
199 _sv_undo_resume();
200 return 0;
203 static void wrap_bg(sv_panel_t *p, GtkWidget *w){
204 int pos = _gtk_menu_item_position(w);
205 set_background(p, bgmap[pos]->value);
208 static void cycle_bg(sv_panel_t *p){
209 int menupos = _sv_propmap_pos(bgmap, p->private->bg_type) + 1;
210 if(bgmap[menupos] == NULL) menupos = 0;
211 set_background(p, bgmap[menupos]->value);
214 static void cycleB_bg(sv_panel_t *p){
215 int menupos = _sv_propmap_pos(bgmap, p->private->bg_type) - 1;
216 if(menupos<0) menupos = _sv_propmap_last(bgmap);
217 set_background(p, bgmap[menupos]->value);
220 static void set_text(sv_panel_t *p, int mode){
221 _sv_undo_push();
222 _sv_undo_suspend();
224 _sv_plot_set_bg_invert(PLOT(p->private->graph),mode);
225 _sv_panel_update_menus(p);
226 refg_if_running(p);
228 _sv_undo_resume();
231 static void wrap_text(sv_panel_t *p, GtkWidget *w){
232 int pos = _gtk_menu_item_position(w);
233 set_text(p, textmap[pos]->value);
236 static void cycle_text(sv_panel_t *p){
237 int menupos = _sv_propmap_pos(textmap, PLOT(p->private->graph)->bg_inv) + 1;
238 if(textmap[menupos] == NULL) menupos = 0;
239 set_text(p, textmap[menupos]->value);
242 static void cycle_grid(sv_panel_t *p){
243 int menupos = _sv_propmap_pos(gridmap, PLOT(p->private->graph)->grid_mode) + 1;
244 if(gridmap[menupos] == NULL) menupos = 0;
245 set_grid(p, gridmap[menupos]->value);
247 static void cycleB_grid(sv_panel_t *p){
248 int menupos = _sv_propmap_pos(gridmap, PLOT(p->private->graph)->grid_mode) - 1;
249 if(menupos<0) menupos = _sv_propmap_last(gridmap);
250 set_grid(p, gridmap[menupos]->value);
253 static void res_set(sv_panel_t *p, int n, int d){
254 if(n != p->private->oversample_n ||
255 d != p->private->oversample_d){
257 _sv_undo_push();
258 _sv_undo_suspend();
260 p->private->oversample_n = n;
261 p->private->oversample_d = d;
262 _sv_panel_update_menus(p);
263 recompute_if_running(p);
265 _sv_undo_resume();
269 // a little different; the menu value is not the internal setting
270 static void res_set_pos(sv_panel_t *p, int pos){
271 p->private->menu_cursamp = pos;
272 switch(pos){
273 case RES_DEF:
274 res_set(p,p->private->def_oversample_n,p->private->def_oversample_d);
275 break;
276 case RES_1_32:
277 res_set(p,1,32);
278 break;
279 case RES_1_16:
280 res_set(p,1,16);
281 break;
282 case RES_1_8:
283 res_set(p,1,8);
284 break;
285 case RES_1_4:
286 res_set(p,1,4);
287 break;
288 case RES_1_2:
289 res_set(p,1,2);
290 break;
291 case RES_1_1:
292 res_set(p,1,1);
293 break;
294 case RES_2_1:
295 res_set(p,2,1);
296 break;
297 case RES_4_1:
298 res_set(p,4,1);
299 break;
303 static void wrap_res(sv_panel_t *p, GtkWidget *w){
304 int pos = _gtk_menu_item_position(w);
305 res_set_pos(p, resmap[pos]->value);
308 static void cycle_res(sv_panel_t *p){
309 int menupos = _sv_propmap_pos(resmap, p->private->menu_cursamp) + 1;
310 if(resmap[menupos] == NULL) menupos = 0;
311 res_set_pos(p, resmap[menupos]->value);
314 static void cycleB_res(sv_panel_t *p){
315 int menupos = _sv_propmap_pos(resmap, p->private->menu_cursamp) - 1;
316 if(menupos<0) menupos = _sv_propmap_last(resmap);
317 res_set_pos(p, resmap[menupos]->value);
320 static GtkPrintSettings *printset=NULL;
321 static void _begin_print_handler (GtkPrintOperation *op,
322 GtkPrintContext *context,
323 gpointer dummy){
325 gtk_print_operation_set_n_pages(op,1);
329 static void _print_handler(GtkPrintOperation *operation,
330 GtkPrintContext *context,
331 gint page_nr,
332 gpointer user_data){
334 cairo_t *c;
335 gdouble w, h;
336 sv_panel_t *p = (sv_panel_t *)user_data;
338 c = gtk_print_context_get_cairo_context (context);
339 w = gtk_print_context_get_width (context);
340 h = gtk_print_context_get_height (context);
342 p->private->print_action(p,c,w,h);
345 static void _sv_panel_print(sv_panel_t *p, GtkWidget *dummy){
346 GtkPrintOperation *op = gtk_print_operation_new ();
348 if (printset != NULL)
349 gtk_print_operation_set_print_settings (op, printset);
351 g_signal_connect (op, "begin-print",
352 G_CALLBACK (_begin_print_handler), p);
353 g_signal_connect (op, "draw-page",
354 G_CALLBACK (_print_handler), p);
356 GError *err;
357 GtkPrintOperationResult ret = gtk_print_operation_run (op,GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
358 NULL,&err);
360 if (ret == GTK_PRINT_OPERATION_RESULT_ERROR) {
361 GtkWidget *error_dialog = gtk_message_dialog_new (NULL,0,GTK_MESSAGE_ERROR,
362 GTK_BUTTONS_CLOSE,
363 "Error printing file:\n%s",
364 err->message);
365 g_signal_connect (error_dialog, "response",
366 G_CALLBACK (gtk_widget_destroy), NULL);
367 gtk_widget_show (error_dialog);
368 g_error_free (err);
369 }else if (ret == GTK_PRINT_OPERATION_RESULT_APPLY){
370 if (printset != NULL)
371 g_object_unref (printset);
372 printset = g_object_ref (gtk_print_operation_get_print_settings (op));
374 g_object_unref (op);
377 static void wrap_undo_down(sv_panel_t *p, GtkWidget *dummy){
378 _sv_undo_down();
380 static void wrap_undo_up(sv_panel_t *p, GtkWidget *dummy){
381 _sv_undo_up();
384 static void wrap_save(sv_panel_t *p, GtkWidget *dummy){
385 GtkWidget *dialog = gtk_file_chooser_dialog_new ("Save",
386 NULL,
387 GTK_FILE_CHOOSER_ACTION_SAVE,
388 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
389 GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
390 NULL);
392 gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
393 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), _sv_cwdname, NULL);
394 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), _sv_dirname);
395 gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), _sv_filebase);
397 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT){
398 if(_sv_filebase)free(_sv_filebase);
399 if(_sv_filename)free(_sv_filename);
400 if(_sv_dirname)free(_sv_dirname);
402 _sv_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
403 _sv_dirname = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
404 _sv_filebase = g_path_get_basename(_sv_filename);
405 _sv_main_save();
408 gtk_widget_destroy (dialog);
412 static void wrap_load(sv_panel_t *p, GtkWidget *dummy){
413 GtkWidget *dialog = gtk_file_chooser_dialog_new ("Open",
414 NULL,
415 GTK_FILE_CHOOSER_ACTION_OPEN,
416 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
417 GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
418 NULL);
420 gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog), _sv_cwdname, NULL);
421 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), _sv_dirname);
423 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT){
424 char *temp_filebase = _sv_filebase;
425 char *temp_filename = _sv_filename;
426 char *temp_dirname = _sv_dirname;
427 _sv_filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
428 _sv_dirname = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog));
429 _sv_filebase = g_path_get_basename(_sv_filename);
431 if(_sv_main_load()){
432 // error
433 GtkWidget *dialog;
434 if(errno == -EINVAL){
435 dialog = gtk_message_dialog_new (NULL,0,
436 GTK_MESSAGE_ERROR,
437 GTK_BUTTONS_CLOSE,
438 "Error parsing file '%s'",
439 _sv_filename);
440 }else{
441 dialog = gtk_message_dialog_new (NULL,0,
442 GTK_MESSAGE_ERROR,
443 GTK_BUTTONS_CLOSE,
444 "Error opening file '%s': %s",
445 _sv_filename, strerror (errno));
447 gtk_dialog_run (GTK_DIALOG (dialog));
448 gtk_widget_destroy (dialog);
450 free(_sv_filebase);
451 free(_sv_filename);
452 free(_sv_dirname);
454 _sv_filebase = temp_filebase;
455 _sv_filename = temp_filename;
456 _sv_dirname = temp_dirname;
458 }else{
459 free(temp_filebase);
460 free(temp_filename);
461 free(temp_dirname);
465 gtk_widget_destroy (dialog);
469 void _sv_panel_update_menus(sv_panel_t *p){
471 // is undo active?
472 if(!_sv_undo_stack ||
473 !_sv_undo_level){
474 gtk_widget_set_sensitive(_gtk_menu_get_item(GTK_MENU(p->private->popmenu),4),FALSE);
475 }else{
476 gtk_widget_set_sensitive(_gtk_menu_get_item(GTK_MENU(p->private->popmenu),4),TRUE);
479 // is redo active?
480 if(!_sv_undo_stack ||
481 !_sv_undo_stack[_sv_undo_level] ||
482 !_sv_undo_stack[_sv_undo_level+1]){
483 gtk_widget_set_sensitive(_gtk_menu_get_item(GTK_MENU(p->private->popmenu),5),FALSE);
484 }else{
485 gtk_widget_set_sensitive(_gtk_menu_get_item(GTK_MENU(p->private->popmenu),5),TRUE);
488 // are we starting or enacting a zoom box?
489 if(p->private->oldbox_active){
490 _gtk_menu_alter_item_label(GTK_MENU(p->private->popmenu),6,"Zoom to box");
491 }else{
492 _gtk_menu_alter_item_label(GTK_MENU(p->private->popmenu),6,"Start zoom box");
495 // make sure menu reflects plot configuration
496 _gtk_menu_alter_item_right(GTK_MENU(p->private->popmenu),
497 _sv_propmap_label_pos(menu,"Background"),
498 bgmap[_sv_propmap_pos(bgmap,p->private->bg_type)]->left);
500 _gtk_menu_alter_item_right(GTK_MENU(p->private->popmenu),
501 _sv_propmap_label_pos(menu,"Text color"),
502 textmap[_sv_propmap_pos(textmap,PLOT(p->private->graph)->bg_inv)]->left);
504 _gtk_menu_alter_item_right(GTK_MENU(p->private->popmenu),
505 _sv_propmap_label_pos(menu,"Grid mode"),
506 gridmap[_sv_propmap_pos(gridmap,PLOT(p->private->graph)->grid_mode)]->left);
508 char buffer[80];
509 snprintf(buffer,60,"%d:%d",p->private->oversample_n,p->private->oversample_d);
510 if(p->private->def_oversample_n == p->private->oversample_n &&
511 p->private->def_oversample_d == p->private->oversample_d)
512 strcat(buffer," (default)");
513 _gtk_menu_alter_item_right(GTK_MENU(p->private->popmenu),
514 _sv_propmap_label_pos(menu,"Sampling"),buffer);
518 static gboolean panel_keypress(GtkWidget *widget,
519 GdkEventKey *event,
520 gpointer in){
521 sv_panel_t *p = (sv_panel_t *)in;
522 // sv_panel2d_t *p2 = (sv_panel2d_t *)p->internal;
524 // check if the widget with focus is an Entry
525 GtkWidget *focused = gtk_window_get_focus(GTK_WINDOW(widget));
526 int entryp = (focused?GTK_IS_ENTRY(focused):0);
528 // don't swallow modified keypresses
529 if(event->state&GDK_MOD1_MASK) return FALSE;
530 if(event->state&GDK_CONTROL_MASK)return FALSE;
532 switch(event->keyval){
533 case GDK_Home:case GDK_KP_Begin:
534 case GDK_End:case GDK_KP_End:
535 case GDK_Up:case GDK_KP_Up:
536 case GDK_Down:case GDK_KP_Down:
537 case GDK_Left:case GDK_KP_Left:
538 case GDK_Right:case GDK_KP_Right:
539 case GDK_minus:case GDK_KP_Subtract:
540 case GDK_plus:case GDK_KP_Add:
541 case GDK_period:case GDK_KP_Decimal:
542 case GDK_0:case GDK_KP_0:
543 case GDK_1:case GDK_KP_1:
544 case GDK_2:case GDK_KP_2:
545 case GDK_3:case GDK_KP_3:
546 case GDK_4:case GDK_KP_4:
547 case GDK_5:case GDK_KP_5:
548 case GDK_6:case GDK_KP_6:
549 case GDK_7:case GDK_KP_7:
550 case GDK_8:case GDK_KP_8:
551 case GDK_9:case GDK_KP_9:
552 case GDK_Tab:case GDK_KP_Tab:
553 case GDK_ISO_Left_Tab:
554 case GDK_Delete:case GDK_KP_Delete:
555 case GDK_Insert:case GDK_KP_Insert:
556 return FALSE;
559 if(entryp){
560 // we still filter, but differently
561 switch(event->keyval){
562 case GDK_BackSpace:
563 case GDK_e:case GDK_E:
564 case GDK_Return:case GDK_ISO_Enter:
565 return FALSE;
569 /* non-control keypresses */
570 switch(event->keyval){
571 case GDK_b:
572 cycle_bg(p);
573 return TRUE;
574 case GDK_B:
575 cycleB_bg(p);
576 return TRUE;
577 case GDK_t:case GDK_T:
578 cycle_text(p);
579 return TRUE;
580 case GDK_g:
581 cycle_grid(p);
582 return TRUE;
583 case GDK_G:
584 cycleB_grid(p);
585 return TRUE;
586 case GDK_m:
587 cycle_res(p);
588 return TRUE;
589 case GDK_M:
590 cycleB_res(p);
591 return TRUE;
593 case GDK_s:
594 wrap_save(p,NULL);
595 return TRUE;
596 case GDK_o:
597 wrap_load(p,NULL);
598 return TRUE;
600 case GDK_Escape:
601 wrap_escape(p,NULL);
602 return TRUE;
604 case GDK_Return:case GDK_ISO_Enter:
605 wrap_enter(p,NULL);
606 return TRUE;
608 case GDK_Q:
609 case GDK_q:
610 // quit
611 _sv_clean_exit();
612 return TRUE;
614 case GDK_BackSpace:
615 // undo
616 _sv_undo_down();
617 return TRUE;
619 case GDK_r:
620 case GDK_space:
621 // redo/forward
622 _sv_undo_up();
623 return TRUE;
625 case GDK_p:
626 _sv_panel_print(p,NULL);
627 return TRUE;
629 case GDK_l:
630 wrap_legend(p,NULL);
631 return TRUE;
634 return FALSE;