From 0ebea86cdb7cd6fa2cfc67d0c84d6a57b44e2203 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Fri, 12 Feb 2021 15:46:07 -0800 Subject: [PATCH 1/6] Add code for boolean config file options --- src/config.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/config.c b/src/config.c index 18d1ee9..220b294 100644 --- a/src/config.c +++ b/src/config.c @@ -44,6 +44,8 @@ g_key_file_save_to_file (GKeyFile *key_file, #define g_key_file_get_int g_key_file_get_integer #define g_key_file_set_int g_key_file_set_integer // the devil may take glib +#define g_key_file_get_bool g_key_file_get_boolean +#define g_key_file_set_bool g_key_file_set_boolean void load_config(struct main_window *w) { From 13269eea89a18ab48161333039f855a0e7b7690d Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 18 Feb 2021 00:26:20 -0800 Subject: [PATCH 2/6] Create utilities for menu items Create some utilities for creating menu items so there isn't so much copy and paste of the code. --- src/interface.c | 55 +++++++++++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/interface.c b/src/interface.c index 7c1d3ca..707c766 100644 --- a/src/interface.c +++ b/src/interface.c @@ -694,6 +694,29 @@ static void load(GtkMenuItem *m, struct main_window *w) gtk_widget_destroy(dialog); } +/* Add a checkbox with name to the given menu, with initial state active and + * attach the supplied callback and parameter to the toggled signal. Set is set + * before attaching the signal, so the callback is not called when created. */ +static GtkWidget* add_checkbox(GtkWidget* menu, const char* name, bool active, GCallback callback, void* param) +{ + GtkWidget *checkbox = gtk_check_menu_item_new_with_label(name); + gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(checkbox), active); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), checkbox); + g_signal_connect(checkbox, "toggled", callback, param); + return checkbox; +} + +/* Add a menu item with given label to the given menu, with the supplied initial +* sensitivity, callback, and callback parameter. */ +static GtkWidget* add_menu_item(GtkWidget* menu, const char* label, bool sensitive, GCallback callback, void* param) +{ + GtkWidget *item = gtk_menu_item_new_with_label(label); + gtk_menu_shell_append(GTK_MENU_SHELL(menu), item); + gtk_widget_set_sensitive(item, sensitive); + g_signal_connect(item, "activate", callback, param); + return item; +} + /* Set up the main window and populate with widgets */ static void init_main_window(struct main_window *w) { @@ -800,47 +823,29 @@ static void init_main_window(struct main_window *w) gtk_box_pack_end(GTK_BOX(hbox), command_menu_button, FALSE, FALSE, 0); // ... Open - GtkWidget *open_item = gtk_menu_item_new_with_label("Open"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), open_item); - g_signal_connect(open_item, "activate", G_CALLBACK(load), w); + add_menu_item(command_menu, "Open", true, G_CALLBACK(load), w); // ... Save - w->save_item = gtk_menu_item_new_with_label("Save current display"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), w->save_item); - g_signal_connect(w->save_item, "activate", G_CALLBACK(save_current), w); - gtk_widget_set_sensitive(w->save_item, FALSE); + w->save_item = add_menu_item(command_menu, "Save current display", false, G_CALLBACK(save_current), w); // ... Save all - w->save_all_item = gtk_menu_item_new_with_label("Save all snapshots"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), w->save_all_item); - g_signal_connect(w->save_all_item, "activate", G_CALLBACK(save_all), w); - gtk_widget_set_sensitive(w->save_all_item, FALSE); + w->save_all_item = add_menu_item(command_menu, "Save all snapshots", false, G_CALLBACK(save_all), w); gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), gtk_separator_menu_item_new()); // ... Light checkbox - GtkWidget *light_checkbox = gtk_check_menu_item_new_with_label("Light algorithm"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), light_checkbox); - g_signal_connect(light_checkbox, "toggled", G_CALLBACK(handle_light), w); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(light_checkbox), w->is_light); + add_checkbox(command_menu, "Light algorithm", w->is_light, G_CALLBACK(handle_light), w); // ... Calibrate checkbox - w->cal_button = gtk_check_menu_item_new_with_label("Calibrate"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), w->cal_button); - g_signal_connect(w->cal_button, "toggled", G_CALLBACK(handle_calibrate), w); + w->cal_button = add_checkbox(command_menu, "Calibrate", false, G_CALLBACK(handle_calibrate), w); gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), gtk_separator_menu_item_new()); // ... Close all - w->close_all_item = gtk_menu_item_new_with_label("Close all snapshots"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), w->close_all_item); - g_signal_connect(w->close_all_item, "activate", G_CALLBACK(close_all), w); - gtk_widget_set_sensitive(w->close_all_item, FALSE); + w->close_all_item = add_menu_item(command_menu, "Close all snapshots", false, G_CALLBACK(close_all), w); // ... Quit - GtkWidget *quit_item = gtk_menu_item_new_with_label("Quit"); - gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), quit_item); - g_signal_connect(quit_item, "activate", G_CALLBACK(handle_quit), w); + add_menu_item(command_menu, "Quit", true, G_CALLBACK(handle_quit), w); gtk_widget_show_all(command_menu); From 41ee57a03c5c03be6317eda01e4b876e8525384e Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 18 Feb 2021 00:38:17 -0800 Subject: [PATCH 3/6] Break up the output panel GUI creation function It's quite large. Split it into new -functions that create the various parts of the output panel. The waveforms (tic, toc, period, debug), the paper strip chart and its controls, and the window under the output display that contains them, each get their own function. There is some minimal support for a vertical vs horizontal paperstrip chart, but it's not used yet. --- src/output_panel.c | 121 ++++++++++++++++++++++++++++++--------------- src/tg.h | 3 ++ 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/src/output_panel.c b/src/output_panel.c index 0e7fc8b..81b567e 100644 --- a/src/output_panel.c +++ b/src/output_panel.c @@ -782,89 +782,130 @@ void op_destroy(struct output_panel *op) free(op); } -struct output_panel *init_output_panel(struct computer *comp, struct snapshot *snst, int border) +/* Creates the paperstrip, with buttons. Returns top level Widget that contains + * them. Vertical controls orientation of paper strip. */ +static GtkWidget* create_paperstrip(struct output_panel *op, bool vertical) { - struct output_panel *op = malloc(sizeof(struct output_panel)); - - op->computer = comp; - op->snst = snst; - - op->panel = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_container_set_border_width(GTK_CONTAINER(op->panel), border); - - // Info area on top - op->output_drawing_area = gtk_drawing_area_new(); - gtk_widget_set_size_request(op->output_drawing_area, 0, OUTPUT_WINDOW_HEIGHT); - gtk_box_pack_start(GTK_BOX(op->panel),op->output_drawing_area, FALSE, TRUE, 0); - g_signal_connect (op->output_drawing_area, "draw", G_CALLBACK(output_draw_event), op); - gtk_widget_set_events(op->output_drawing_area, GDK_EXPOSURE_MASK); - - GtkWidget *hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_pack_start(GTK_BOX(op->panel), hbox2, TRUE, TRUE, 0); - - GtkWidget *vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_box_pack_start(GTK_BOX(hbox2), vbox2, FALSE, TRUE, 0); + GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); // Paperstrip op->paperstrip_drawing_area = gtk_drawing_area_new(); gtk_widget_set_size_request(op->paperstrip_drawing_area, 300, 0); - gtk_box_pack_start(GTK_BOX(vbox2), op->paperstrip_drawing_area, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), op->paperstrip_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->paperstrip_drawing_area, "draw", G_CALLBACK(paperstrip_draw_event), op); gtk_widget_set_events(op->paperstrip_drawing_area, GDK_EXPOSURE_MASK); - GtkWidget *hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_pack_start(GTK_BOX(vbox2), hbox3, FALSE, TRUE, 0); + // Buttons + GtkWidget *hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); // < button - GtkWidget *left_button = gtk_button_new_with_label("<"); - gtk_box_pack_start(GTK_BOX(hbox3), left_button, TRUE, TRUE, 0); - g_signal_connect (left_button, "clicked", G_CALLBACK(handle_left), op); + op->left_button = gtk_button_new_from_icon_name( + vertical ? "pan-start-symbolic" : "pan-up-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start(GTK_BOX(hbox), op->left_button, TRUE, TRUE, 0); + g_signal_connect (op->left_button, "clicked", G_CALLBACK(handle_left), op); // CLEAR button - if(comp) { + if(op->computer) { op->clear_button = gtk_button_new_with_label("Clear"); - gtk_box_pack_start(GTK_BOX(hbox3), op->clear_button, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), op->clear_button, TRUE, TRUE, 0); g_signal_connect (op->clear_button, "clicked", G_CALLBACK(handle_clear_trace), op); - gtk_widget_set_sensitive(op->clear_button, !snst->calibrate); + gtk_widget_set_sensitive(op->clear_button, !op->snst->calibrate); } // CENTER button GtkWidget *center_button = gtk_button_new_with_label("Center"); - gtk_box_pack_start(GTK_BOX(hbox3), center_button, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), center_button, TRUE, TRUE, 0); g_signal_connect (center_button, "clicked", G_CALLBACK(handle_center_trace), op); // > button - GtkWidget *right_button = gtk_button_new_with_label(">"); - gtk_box_pack_start(GTK_BOX(hbox3), right_button, TRUE, TRUE, 0); - g_signal_connect (right_button, "clicked", G_CALLBACK(handle_right), op); + op->right_button = gtk_button_new_from_icon_name( + vertical ? "pan-end-symbolic" : "pan-down-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_start(GTK_BOX(hbox), op->right_button, TRUE, TRUE, 0); + g_signal_connect (op->right_button, "clicked", G_CALLBACK(handle_right), op); + + return vbox; +} - GtkWidget *vbox3 = gtk_box_new(GTK_ORIENTATION_VERTICAL,10); - gtk_box_pack_start(GTK_BOX(hbox2), vbox3, TRUE, TRUE, 0); +/* Create the tic, toc, and period waveforms. Returns the GtkBox that contains + * them. Vertical controls how the waves are stacked. */ +static GtkWidget* create_waveforms(struct output_panel *op, bool vertical) +{ + GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); // Tic waveform area op->tic_drawing_area = gtk_drawing_area_new(); - gtk_box_pack_start(GTK_BOX(vbox3), op->tic_drawing_area, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), op->tic_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->tic_drawing_area, "draw", G_CALLBACK(tic_draw_event), op); gtk_widget_set_events(op->tic_drawing_area, GDK_EXPOSURE_MASK); // Toc waveform area op->toc_drawing_area = gtk_drawing_area_new(); - gtk_box_pack_start(GTK_BOX(vbox3), op->toc_drawing_area, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), op->toc_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->toc_drawing_area, "draw", G_CALLBACK(toc_draw_event), op); gtk_widget_set_events(op->toc_drawing_area, GDK_EXPOSURE_MASK); // Period waveform area op->period_drawing_area = gtk_drawing_area_new(); - gtk_box_pack_start(GTK_BOX(vbox3), op->period_drawing_area, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), op->period_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->period_drawing_area, "draw", G_CALLBACK(period_draw_event), op); gtk_widget_set_events(op->period_drawing_area, GDK_EXPOSURE_MASK); #ifdef DEBUG op->debug_drawing_area = gtk_drawing_area_new(); - gtk_box_pack_start(GTK_BOX(vbox3), op->debug_drawing_area, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(box), op->debug_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->debug_drawing_area, "draw", G_CALLBACK(debug_draw_event), op); gtk_widget_set_events(op->debug_drawing_area, GDK_EXPOSURE_MASK); #endif + return box; +} + +/* Create container and place paperstrip and waveforms in either vertical or + * horizontal paperstrip orientation. Puts container in the panel and shows it. */ +static void place_displays(struct output_panel *op, GtkWidget *paperstrip, GtkWidget *waveforms, bool vertical) +{ + op->displays = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); + gtk_box_pack_start(GTK_BOX(op->displays), paperstrip, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(op->displays), waveforms, TRUE, TRUE, 0); + + gtk_box_pack_end(GTK_BOX(op->panel), op->displays, TRUE, TRUE, 0); + gtk_widget_show(op->displays); +} + +/* Create the paperstrip and waveforms, a container for them, and place it into + * the panel. Returns containing Widget. Vertical controls paperstrip + * orientation. */ +static GtkWidget *create_displays(struct output_panel *op, bool vertical) +{ + // The paperstrip and buttons + GtkWidget *paperstrip = create_paperstrip(op, vertical); + // Tic/toc/period waveform area + GtkWidget *waveforms = create_waveforms(op, vertical); + + place_displays(op, paperstrip, waveforms, vertical); + + return op->displays; +} + +struct output_panel *init_output_panel(struct computer *comp, struct snapshot *snst, int border) +{ + struct output_panel *op = malloc(sizeof(struct output_panel)); + + op->computer = comp; + op->snst = snst; + + op->panel = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); + gtk_container_set_border_width(GTK_CONTAINER(op->panel), border); + + // Info area on top + op->output_drawing_area = gtk_drawing_area_new(); + gtk_widget_set_size_request(op->output_drawing_area, 0, OUTPUT_WINDOW_HEIGHT); + gtk_box_pack_start(GTK_BOX(op->panel),op->output_drawing_area, FALSE, TRUE, 0); + g_signal_connect (op->output_drawing_area, "draw", G_CALLBACK(output_draw_event), op); + gtk_widget_set_events(op->output_drawing_area, GDK_EXPOSURE_MASK); + + create_displays(op, true); + return op; } diff --git a/src/tg.h b/src/tg.h index 789f66c..86785d4 100644 --- a/src/tg.h +++ b/src/tg.h @@ -200,11 +200,14 @@ struct output_panel { GtkWidget *panel; GtkWidget *output_drawing_area; + GtkWidget *displays; GtkWidget *tic_drawing_area; GtkWidget *toc_drawing_area; GtkWidget *period_drawing_area; GtkWidget *paperstrip_drawing_area; GtkWidget *clear_button; + GtkWidget *left_button; + GtkWidget *right_button; #ifdef DEBUG GtkWidget *debug_drawing_area; #endif From 4e68612842def7dc3eacfde613e62d7e0abadc52 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 18 Feb 2021 01:47:15 -0800 Subject: [PATCH 4/6] Use resizble paned widget for paperstrip and waveforms This lets the size of the paperstrip vs the waveforms be adjusted by sliding the pane between them. To get the layout right, we need to give the waveforms a minimum size. 300x150 seems about the minimum. It should look basically the same as it did before. Each snapshot has its own unique pane position. Adjusting one tab in the notebook doesn't adjust the other tabs. It might be nice if that weren't the case and they were all synced. --- src/output_panel.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/output_panel.c b/src/output_panel.c index 81b567e..095d31b 100644 --- a/src/output_panel.c +++ b/src/output_panel.c @@ -835,18 +835,21 @@ static GtkWidget* create_waveforms(struct output_panel *op, bool vertical) // Tic waveform area op->tic_drawing_area = gtk_drawing_area_new(); + gtk_widget_set_size_request(op->tic_drawing_area, 300, 150); gtk_box_pack_start(GTK_BOX(box), op->tic_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->tic_drawing_area, "draw", G_CALLBACK(tic_draw_event), op); gtk_widget_set_events(op->tic_drawing_area, GDK_EXPOSURE_MASK); // Toc waveform area op->toc_drawing_area = gtk_drawing_area_new(); + gtk_widget_set_size_request(op->toc_drawing_area, 300, 150); gtk_box_pack_start(GTK_BOX(box), op->toc_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->toc_drawing_area, "draw", G_CALLBACK(toc_draw_event), op); gtk_widget_set_events(op->toc_drawing_area, GDK_EXPOSURE_MASK); // Period waveform area op->period_drawing_area = gtk_drawing_area_new(); + gtk_widget_set_size_request(op->period_drawing_area, 300, 150); gtk_box_pack_start(GTK_BOX(box), op->period_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->period_drawing_area, "draw", G_CALLBACK(period_draw_event), op); gtk_widget_set_events(op->period_drawing_area, GDK_EXPOSURE_MASK); @@ -865,9 +868,10 @@ static GtkWidget* create_waveforms(struct output_panel *op, bool vertical) * horizontal paperstrip orientation. Puts container in the panel and shows it. */ static void place_displays(struct output_panel *op, GtkWidget *paperstrip, GtkWidget *waveforms, bool vertical) { - op->displays = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 10); - gtk_box_pack_start(GTK_BOX(op->displays), paperstrip, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(op->displays), waveforms, TRUE, TRUE, 0); + op->displays = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + gtk_paned_set_wide_handle(GTK_PANED(op->displays), TRUE); + gtk_paned_pack1(GTK_PANED(op->displays), paperstrip, FALSE, FALSE); + gtk_paned_pack2(GTK_PANED(op->displays), waveforms, TRUE, FALSE); gtk_box_pack_end(GTK_BOX(op->panel), op->displays, TRUE, TRUE, 0); gtk_widget_show(op->displays); From 05e85bc3ccf2f4b745e8e64275e2e208ba0e9dff Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Thu, 18 Feb 2021 02:23:26 -0800 Subject: [PATCH 5/6] Add vertical/horizontal paperstrip option This allow changing the layout so the paperstrip is horizontal, scrolling to the left, with the three waveforms arraigned horizontally below the paperstrip. The effect is to make the paperstrip longer and give it more space. For many tasks the paper strip is much more useful than the waveform displays. This allows adjusting the layout to be more useful in those cases. A new checkbox in the menu is added to control this. It can be changed on the fly and the widgets will be re-arraigned. A config file option, "vertical_paperstrip", is added to remember the current setting. Default vertical layout to true if not present in config file. If multiple snapshots are present, the change of orientation will affect all of them, rather that just the current viewed one. It would be possible to change this. --- src/interface.c | 24 ++++++++++++++-- src/output_panel.c | 70 ++++++++++++++++++++++++++++++++++++++-------- src/tg.h | 13 +++++++-- 3 files changed, 92 insertions(+), 15 deletions(-) diff --git a/src/interface.c b/src/interface.c index 707c766..9ae4cb7 100644 --- a/src/interface.c +++ b/src/interface.c @@ -422,7 +422,7 @@ static GtkWidget *make_tab_label(char *name, struct output_panel *panel_to_close static void add_new_tab(struct snapshot *s, char *name, struct main_window *w) { - struct output_panel *op = init_output_panel(NULL, s, 5); + struct output_panel *op = init_output_panel(NULL, s, 5, w->vertical_layout); GtkWidget *label = make_tab_label(name, op); gtk_widget_show_all(op->panel); @@ -694,6 +694,22 @@ static void load(GtkMenuItem *m, struct main_window *w) gtk_widget_destroy(dialog); } +static void handle_layout(GtkCheckMenuItem *b, struct main_window *w) +{ + const bool vertical = gtk_check_menu_item_get_active(b) == TRUE; + + w->vertical_layout = vertical; + set_panel_layout(w->active_panel, vertical); + + int n = 0; + GtkWidget *panel; + while ((panel = gtk_notebook_get_nth_page(GTK_NOTEBOOK(w->notebook), n++))) { + struct output_panel *op = g_object_get_data(G_OBJECT(panel), "op-pointer"); + if(op) + set_panel_layout(op, vertical); + } +} + /* Add a checkbox with name to the given menu, with initial state active and * attach the supplied callback and parameter to the toggled signal. Set is set * before attaching the signal, so the callback is not called when created. */ @@ -839,6 +855,9 @@ static void init_main_window(struct main_window *w) // ... Calibrate checkbox w->cal_button = add_checkbox(command_menu, "Calibrate", false, G_CALLBACK(handle_calibrate), w); + // Layout checkbox + add_checkbox(command_menu, "Vertical", w->vertical_layout, G_CALLBACK(handle_layout), w); + gtk_menu_shell_append(GTK_MENU_SHELL(command_menu), gtk_separator_menu_item_new()); // ... Close all @@ -936,6 +955,7 @@ static void start_interface(GApplication* app, void *p) w->la = DEFAULT_LA; w->calibrate = 0; w->is_light = 0; + w->vertical_layout = true; load_config(w); @@ -959,7 +979,7 @@ static void start_interface(GApplication* app, void *p) w->computer->curr = NULL; compute_results(w->active_snapshot); - w->active_panel = init_output_panel(w->computer, w->active_snapshot, 0); + w->active_panel = init_output_panel(w->computer, w->active_snapshot, 0, w->vertical_layout); init_main_window(w); diff --git a/src/output_panel.c b/src/output_panel.c index 095d31b..97b00cf 100644 --- a/src/output_panel.c +++ b/src/output_panel.c @@ -549,9 +549,19 @@ static gboolean paperstrip_draw_event(GtkWidget *widget, cairo_t *c, struct outp GtkAllocation temp; gtk_widget_get_allocation (op->paperstrip_drawing_area, &temp); + int width, height; - int width = temp.width; - int height = temp.height; + /* The paperstrip is coded to be vertical; horizontal uses cairo to rotate it. */ + if(op->vertical_layout) { + width = temp.width; + height = temp.height; + } else { + width = temp.height; + height = temp.width; + + cairo_translate(c, height, 0); + cairo_rotate(c, M_PI/2); + } int stopped = 0; if( snst->events_count && @@ -790,7 +800,7 @@ static GtkWidget* create_paperstrip(struct output_panel *op, bool vertical) // Paperstrip op->paperstrip_drawing_area = gtk_drawing_area_new(); - gtk_widget_set_size_request(op->paperstrip_drawing_area, 300, 0); + gtk_widget_set_size_request(op->paperstrip_drawing_area, 150, 150); gtk_box_pack_start(GTK_BOX(vbox), op->paperstrip_drawing_area, TRUE, TRUE, 0); g_signal_connect (op->paperstrip_drawing_area, "draw", G_CALLBACK(paperstrip_draw_event), op); gtk_widget_set_events(op->paperstrip_drawing_area, GDK_EXPOSURE_MASK); @@ -831,7 +841,7 @@ static GtkWidget* create_paperstrip(struct output_panel *op, bool vertical) * them. Vertical controls how the waves are stacked. */ static GtkWidget* create_waveforms(struct output_panel *op, bool vertical) { - GtkWidget *box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); + GtkWidget *box = gtk_box_new(vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL, 10); // Tic waveform area op->tic_drawing_area = gtk_drawing_area_new(); @@ -868,11 +878,24 @@ static GtkWidget* create_waveforms(struct output_panel *op, bool vertical) * horizontal paperstrip orientation. Puts container in the panel and shows it. */ static void place_displays(struct output_panel *op, GtkWidget *paperstrip, GtkWidget *waveforms, bool vertical) { - op->displays = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + op->vertical_layout = vertical; + + op->displays = gtk_paned_new(vertical ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); gtk_paned_set_wide_handle(GTK_PANED(op->displays), TRUE); - gtk_paned_pack1(GTK_PANED(op->displays), paperstrip, FALSE, FALSE); + + gtk_paned_pack1(GTK_PANED(op->displays), paperstrip, vertical ? FALSE : TRUE, FALSE); + + gtk_orientable_set_orientation(GTK_ORIENTABLE(waveforms), vertical ? GTK_ORIENTATION_VERTICAL : GTK_ORIENTATION_HORIZONTAL); gtk_paned_pack2(GTK_PANED(op->displays), waveforms, TRUE, FALSE); + /* Make paperstrip arrows buttons point correct way */ + GtkWidget *left_arrow = gtk_button_get_image(GTK_BUTTON(op->left_button)); + gtk_image_set_from_icon_name(GTK_IMAGE(left_arrow), + vertical ? "pan-start-symbolic" : "pan-up-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); + GtkWidget *right_arrow = gtk_button_get_image(GTK_BUTTON(op->right_button)); + gtk_image_set_from_icon_name(GTK_IMAGE(right_arrow), + vertical ? "pan-end-symbolic" : "pan-down-symbolic", GTK_ICON_SIZE_LARGE_TOOLBAR); + gtk_box_pack_end(GTK_BOX(op->panel), op->displays, TRUE, TRUE, 0); gtk_widget_show(op->displays); } @@ -883,16 +906,41 @@ static void place_displays(struct output_panel *op, GtkWidget *paperstrip, GtkWi static GtkWidget *create_displays(struct output_panel *op, bool vertical) { // The paperstrip and buttons - GtkWidget *paperstrip = create_paperstrip(op, vertical); + op->paperstrip_box = create_paperstrip(op, vertical); // Tic/toc/period waveform area - GtkWidget *waveforms = create_waveforms(op, vertical); + op->waveforms_box = create_waveforms(op, vertical); - place_displays(op, paperstrip, waveforms, vertical); + place_displays(op, op->paperstrip_box, op->waveforms_box, vertical); return op->displays; } -struct output_panel *init_output_panel(struct computer *comp, struct snapshot *snst, int border) +/* Change orientation of existing output panel. Is a no-op if orientation is + * not changed. */ +void set_panel_layout(struct output_panel *op, bool vertical) +{ + if (op->vertical_layout == vertical) + return; + + /* Remove waveforms and paperstrip containers from displays container, + * then use place_displays() to put them into a new displays container. + * The need to be refed so they are not deleted when removed from the + * container. */ + g_object_ref(op->waveforms_box); + gtk_container_remove(GTK_CONTAINER(op->displays), op->waveforms_box); + + g_object_ref(op->paperstrip_box); + gtk_container_remove(GTK_CONTAINER(op->displays), op->paperstrip_box); + + gtk_widget_destroy(op->displays); op->displays = NULL; + place_displays(op, op->paperstrip_box, op->waveforms_box, vertical); + + /* They are now refed by op->displays so we don't need our refs anymore */ + g_object_unref(op->paperstrip_box); + g_object_unref(op->waveforms_box); +} + +struct output_panel *init_output_panel(struct computer *comp, struct snapshot *snst, int border, bool vertical) { struct output_panel *op = malloc(sizeof(struct output_panel)); @@ -909,7 +957,7 @@ struct output_panel *init_output_panel(struct computer *comp, struct snapshot *s g_signal_connect (op->output_drawing_area, "draw", G_CALLBACK(output_draw_event), op); gtk_widget_set_events(op->output_drawing_area, GDK_EXPOSURE_MASK); - create_displays(op, true); + create_displays(op, vertical); return op; } diff --git a/src/tg.h b/src/tg.h index 86785d4..f92d640 100644 --- a/src/tg.h +++ b/src/tg.h @@ -201,22 +201,28 @@ struct output_panel { GtkWidget *output_drawing_area; GtkWidget *displays; + GtkWidget *waveforms_box; GtkWidget *tic_drawing_area; GtkWidget *toc_drawing_area; GtkWidget *period_drawing_area; + GtkWidget *paperstrip_box; GtkWidget *paperstrip_drawing_area; GtkWidget *clear_button; GtkWidget *left_button; GtkWidget *right_button; + GtkWidget *zoom_button; #ifdef DEBUG GtkWidget *debug_drawing_area; #endif + bool vertical_layout; + struct computer *computer; struct snapshot *snst; }; void initialize_palette(); -struct output_panel *init_output_panel(struct computer *comp, struct snapshot *snst, int border); +struct output_panel *init_output_panel(struct computer *comp, struct snapshot *snst, int border, bool vertical_layout); +void set_panel_layout(struct output_panel *op, bool vertical); void redraw_op(struct output_panel *op); void op_set_snapshot(struct output_panel *op, struct snapshot *snst); void op_set_border(struct output_panel *op, int i); @@ -253,6 +259,8 @@ struct main_window { int cal; // 0.1 s/d int nominal_sr; + bool vertical_layout; + GKeyFile *config_file; gchar *config_file_name; struct conf_data *conf_data; @@ -275,7 +283,8 @@ void error(char *format,...); OP(bph, bph, int) \ OP(lift_angle, la, double) \ OP(calibration, cal, int) \ - OP(light_algorithm, is_light, int) + OP(light_algorithm, is_light, int) \ + OP(vertical_paperstrip, vertical_layout, bool) struct conf_data { #define DEF(NAME,PLACE,TYPE) TYPE PLACE; From 6f088c01f695ad80e814ba7116d42fa3878522ff Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Sun, 7 Mar 2021 21:43:36 -0800 Subject: [PATCH 6/6] Scale font using paperstrip/waveform window size Using the size of the main app window, what was done, doesn't work so well now that the space allocation between the paperstrip and waveforms can be changed. This way making the waveforms (or paperstrip) smaller will give a smaller font that fits in the smaller space better. --- src/output_panel.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/output_panel.c b/src/output_panel.c index 97b00cf..c34b597 100644 --- a/src/output_panel.c +++ b/src/output_panel.c @@ -322,10 +322,9 @@ static void expose_waveform( int width = temp.width; int height = temp.height; - gtk_widget_get_allocation(gtk_widget_get_toplevel(da), &temp); - int font = temp.width / 90; - if(font < 12) - font = 12; + int font = width / 25; + font = font < 12 ? 12 : font > 24 ? 24 : font; + int i; cairo_set_font_size(c,font); @@ -670,18 +669,14 @@ static gboolean paperstrip_draw_event(GtkWidget *widget, cairo_t *c, struct outp cairo_line_to(c, right_margin + .5, height - 20.5); cairo_fill(c); - char s[100]; - cairo_text_extents_t extents; + int font = width / 25; + cairo_set_font_size(c, font < 12 ? 12 : font > 24 ? 24 : font); - gtk_widget_get_allocation(gtk_widget_get_toplevel(widget), &temp); - int font = temp.width / 90; - if(font < 12) - font = 12; - cairo_set_font_size(c,font); - - sprintf(s, "%.1f ms", snst->calibrate ? + char s[32]; + snprintf(s, sizeof(s), "%.1f ms", snst->calibrate ? 1000. / zoom_factor : 3600000. / (snst->guessed_bph * zoom_factor)); + cairo_text_extents_t extents; cairo_text_extents(c,s,&extents); cairo_move_to(c, (width - extents.x_advance)/2, height - 30); cairo_show_text(c,s);