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)
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.
31 #include <sys/types.h>
33 #include <gdk/gdkkeysyms.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
},
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
},
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
},
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
},
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
},
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
);
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
){
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
){
152 _sv_plot_set_crossactive(PLOT(p
->private->graph
),0);
153 _sv_panel_dirty_legend(p
);
158 static void wrap_legend(sv_panel_t
*p
, GtkWidget
*dummy
){
162 _sv_plot_toggle_legend(PLOT(p
->private->graph
));
163 _sv_panel_dirty_legend(p
);
168 static void set_grid(sv_panel_t
*p
, int mode
){
172 _sv_plot_set_grid(PLOT(p
->private->graph
),mode
);
173 _sv_panel_update_menus(p
);
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;
195 set_grid(p
,_SV_PLOT_GRID_NORMAL
);
196 redraw_if_running(p
);
197 _sv_panel_update_menus(p
);
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
){
224 _sv_plot_set_bg_invert(PLOT(p
->private->graph
),mode
);
225 _sv_panel_update_menus(p
);
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
){
260 p
->private->oversample_n
= n
;
261 p
->private->oversample_d
= d
;
262 _sv_panel_update_menus(p
);
263 recompute_if_running(p
);
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
;
274 res_set(p
,p
->private->def_oversample_n
,p
->private->def_oversample_d
);
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
,
325 gtk_print_operation_set_n_pages(op
,1);
329 static void _print_handler(GtkPrintOperation
*operation
,
330 GtkPrintContext
*context
,
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
);
357 GtkPrintOperationResult ret
= gtk_print_operation_run (op
,GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG
,
360 if (ret
== GTK_PRINT_OPERATION_RESULT_ERROR
) {
361 GtkWidget
*error_dialog
= gtk_message_dialog_new (NULL
,0,GTK_MESSAGE_ERROR
,
363 "Error printing file:\n%s",
365 g_signal_connect (error_dialog
, "response",
366 G_CALLBACK (gtk_widget_destroy
), NULL
);
367 gtk_widget_show (error_dialog
);
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
));
377 static void wrap_undo_down(sv_panel_t
*p
, GtkWidget
*dummy
){
380 static void wrap_undo_up(sv_panel_t
*p
, GtkWidget
*dummy
){
384 static void wrap_save(sv_panel_t
*p
, GtkWidget
*dummy
){
385 GtkWidget
*dialog
= gtk_file_chooser_dialog_new ("Save",
387 GTK_FILE_CHOOSER_ACTION_SAVE
,
388 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
389 GTK_STOCK_SAVE
, GTK_RESPONSE_ACCEPT
,
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
);
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",
415 GTK_FILE_CHOOSER_ACTION_OPEN
,
416 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
417 GTK_STOCK_OPEN
, GTK_RESPONSE_ACCEPT
,
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
);
434 if(errno
== -EINVAL
){
435 dialog
= gtk_message_dialog_new (NULL
,0,
438 "Error parsing file '%s'",
441 dialog
= gtk_message_dialog_new (NULL
,0,
444 "Error opening file '%s': %s",
445 _sv_filename
, strerror (errno
));
447 gtk_dialog_run (GTK_DIALOG (dialog
));
448 gtk_widget_destroy (dialog
);
454 _sv_filebase
= temp_filebase
;
455 _sv_filename
= temp_filename
;
456 _sv_dirname
= temp_dirname
;
465 gtk_widget_destroy (dialog
);
469 void _sv_panel_update_menus(sv_panel_t
*p
){
472 if(!_sv_undo_stack
||
474 gtk_widget_set_sensitive(_gtk_menu_get_item(GTK_MENU(p
->private->popmenu
),4),FALSE
);
476 gtk_widget_set_sensitive(_gtk_menu_get_item(GTK_MENU(p
->private->popmenu
),4),TRUE
);
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
);
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");
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
);
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
,
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
:
560 // we still filter, but differently
561 switch(event
->keyval
){
563 case GDK_e
:case GDK_E
:
564 case GDK_Return
:case GDK_ISO_Enter
:
569 /* non-control keypresses */
570 switch(event
->keyval
){
577 case GDK_t
:case GDK_T
:
604 case GDK_Return
:case GDK_ISO_Enter
:
626 _sv_panel_print(p
,NULL
);