From 81ec22a19551c93c5bb9fb6df400ff51b7377dfd Mon Sep 17 00:00:00 2001 From: Tom Greig <tg8g16@soton.ac.uk> Date: Mon, 3 Apr 2023 10:09:05 +0100 Subject: [PATCH] Add scale bars and rework UI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There were too many things in the column view. Input title fonts, frame rates and scales are now below and pertain to which ever input is selected. There are now nice handy ‘copy to all inputs’ buttons so you don't have to enter the same information six times or whatever. Also, this fixes a bug where ffmpeg would complain if an input's title was empty (we just make the title a single space in this case!) And yeah, scale bars. --- inc/input.h | 5 +- inc/util.h | 2 +- src/input.c | 69 ++++--- src/main.c | 573 +++++++++++++++++++++++++++++++++++++++++++++------ src/output.c | 2 +- 5 files changed, 563 insertions(+), 88 deletions(-) diff --git a/inc/input.h b/inc/input.h index d1c3f95..a2b3ce3 100644 --- a/inc/input.h +++ b/inc/input.h @@ -40,7 +40,10 @@ struct input { struct input_source* source; char* title; - struct font font; + struct font title_font; + double scale_length; + char* scale_label; + struct font scale_font; unsigned int row; unsigned int column; double frame_rate; diff --git a/inc/util.h b/inc/util.h index 4bff422..06aee53 100644 --- a/inc/util.h +++ b/inc/util.h @@ -2,7 +2,7 @@ #define __TIMELAPSE_EDITOR_UTIL_H__ struct font { - const char* font_path; + char* font_name; unsigned int font_size; unsigned char font_colour[3]; }; diff --git a/src/input.c b/src/input.c index 4559151..e5c7958 100644 --- a/src/input.c +++ b/src/input.c @@ -145,37 +145,60 @@ struct input_context* input_context_create( char* filter_description = strdup( "" ); - if ( '\0' != input->title[0] ) { + const char* title; + if ( 0 == strlen( input->title ) ) { + title = " "; + } else { + title = input->title; + } - char* title_text; - switch ( input->rate_unit ) { + char* title_text; + switch ( input->rate_unit ) { - case INPUT_RATE_FPS: - title_text = format_title( input->title, - input->frame_rate, 1 ); - break; + case INPUT_RATE_FPS: + title_text = format_title( title, + input->frame_rate, 1 ); + break; - case INPUT_RATE_SPF: - title_text = format_title( input->title, - 1, input->frame_rate ); - break; + case INPUT_RATE_SPF: + title_text = format_title( title, + 1, input->frame_rate ); + break; - case INPUT_RATE_MPF: - title_text = format_title( input->title, - 1, 60 * input->frame_rate ); - break; + case INPUT_RATE_MPF: + title_text = format_title( title, + 1, 60 * input->frame_rate ); + break; - } + } - filter_description = sappendf( filter_description, - "drawtext=text=%s:fontsize=%d:x=10:y=h-th-10:" - "fontcolor=#%02X%02X%02X:fontfile=%s", - title_text, input->font.font_size, - input->font.font_colour[0], input->font.font_colour[1], - input->font.font_colour[2], input->font.font_path ); + filter_description = sappendf( filter_description, + "drawtext=text=%s:fontsize=%d:x=10:y=h-th-10:" + "fontcolor=#%02X%02X%02X:font=%s", + title_text, input->title_font.font_size, + input->title_font.font_colour[0], + input->title_font.font_colour[1], + input->title_font.font_colour[2], + input->title_font.font_name ); - free( title_text ); + free( title_text ); + if ( 0 < input->scale_length ) { + filter_description = sappendf( filter_description, + ",drawbox=t=fill:c=white:x=iw-10-%lf:y=ih-13:w=%lf:h=3", + input->scale_length, input->scale_length ); + } + + if ( 0 < strlen( input->scale_label ) ) { + filter_description = sappendf( filter_description, + ",drawtext=text=%s:fontsize=%d:x=w-10-%lf/2-tw/2:y=h-th-14:" + "fontcolor=#%02X%02X%02X:font=%s", + input->scale_label, input->scale_font.font_size, + input->scale_length, + input->scale_font.font_colour[0], + input->scale_font.font_colour[1], + input->scale_font.font_colour[2], + input->scale_font.font_name ); } AVFilterInOut* outputs = avfilter_inout_alloc(); diff --git a/src/main.c b/src/main.c index 5561eeb..a1d0cbb 100644 --- a/src/main.c +++ b/src/main.c @@ -25,6 +25,19 @@ struct app { GListStore* input_store; struct input_source* input_sources; + GtkWidget* input_title_font; + GtkWidget* input_frame_rate_spin; + GtkWidget* input_frame_rate_mode; + GtkWidget* input_scale_label; + GtkWidget* input_scale_mu; + GtkWidget* input_scale_length; + GtkWidget* input_scale_font; + + GtkWidget* input_title_font_copy; + GtkWidget* input_frame_rate_copy; + GtkWidget* input_scale_copy; + GtkWidget* input_scale_font_copy; + GThread* render_thread; GtkWidget* progress_dialogue; GtkWidget* progress_text; @@ -45,6 +58,20 @@ static void input_class_init( InputClass* class ) { (void) class; } /* Funk! */ +static struct input* get_selected_input( struct app* app ) { + + unsigned int selected_index = gtk_single_selection_get_selected( + app->input_selection ); + Input* selected_item = INPUT_INPUT( g_list_model_get_item( + G_LIST_MODEL( app->input_store ), selected_index ) ); + if ( NULL != selected_item ) { + return selected_item->input; + } else { + return NULL; + } + +} + static void update_export_sensitivity( struct app* app ) { gtk_widget_set_sensitive( app->export_all_button, @@ -55,6 +82,61 @@ static void update_export_sensitivity( struct app* app ) { GTK_INVALID_LIST_POSITION != gtk_single_selection_get_selected( app->input_selection ) ); + struct input* input = get_selected_input( app ); + if ( NULL == input ) { + + gtk_widget_set_sensitive( app->input_title_font, false ); + gtk_widget_set_sensitive( app->input_frame_rate_spin, false ); + gtk_widget_set_sensitive( app->input_frame_rate_mode, false ); + gtk_widget_set_sensitive( app->input_scale_label, false ); + gtk_widget_set_sensitive( app->input_scale_mu, false ); + gtk_widget_set_sensitive( app->input_scale_length, false ); + gtk_widget_set_sensitive( app->input_scale_font, false ); + + gtk_widget_set_sensitive( app->input_title_font_copy, false ); + gtk_widget_set_sensitive( app->input_frame_rate_copy, false ); + gtk_widget_set_sensitive( app->input_scale_copy, false ); + gtk_widget_set_sensitive( app->input_scale_font_copy, false ); + + } else { + + gtk_widget_set_sensitive( app->input_title_font, true ); + gtk_widget_set_sensitive( app->input_frame_rate_spin, true ); + gtk_widget_set_sensitive( app->input_frame_rate_mode, true ); + gtk_widget_set_sensitive( app->input_scale_label, true ); + gtk_widget_set_sensitive( app->input_scale_mu, true ); + gtk_widget_set_sensitive( app->input_scale_length, true ); + gtk_widget_set_sensitive( app->input_scale_font, true ); + + gtk_widget_set_sensitive( app->input_title_font_copy, true ); + gtk_widget_set_sensitive( app->input_frame_rate_copy, true ); + gtk_widget_set_sensitive( app->input_scale_copy, true ); + gtk_widget_set_sensitive( app->input_scale_font_copy, true ); + + char font[1024]; + snprintf( font, 1024, "%s %d", input->title_font.font_name, + input->title_font.font_size ); + gtk_font_chooser_set_font( + GTK_FONT_CHOOSER( app->input_title_font ), font ); + gtk_spin_button_set_value( + GTK_SPIN_BUTTON( app->input_frame_rate_spin ), + input->frame_rate ); + gtk_drop_down_set_selected( + GTK_DROP_DOWN( app->input_frame_rate_mode ), + input->rate_unit ); + gtk_entry_buffer_set_text( + gtk_entry_get_buffer( GTK_ENTRY( app->input_scale_label ) ), + input->scale_label, -1 ); + gtk_spin_button_set_value( + GTK_SPIN_BUTTON( app->input_scale_length ), + input->scale_length ); + snprintf( font, 1024, "%s %d", input->scale_font.font_name, + input->scale_font.font_size ); + gtk_font_chooser_set_font( + GTK_FONT_CHOOSER( app->input_scale_font ), font ); + + } + } static int get_font( PangoFontDescription* description, @@ -66,9 +148,12 @@ static int get_font( PangoFontDescription* description, return -1; } - result->font_path = - pango_font_description_get_family( description ); - if ( NULL == result->font_path ) { + if ( NULL != result->font_name ) { + free( result->font_name ); + } + result->font_name = strdup( + pango_font_description_get_family( description ) ); + if ( NULL == result->font_name ) { *error = write_error( __FILE__, __LINE__ - 2, "Couldn't get font name" ); return -1; @@ -129,13 +214,20 @@ static void open_input_callback( NULL != input; input = input->next ) { - input->font.font_path = "/home/tom/.local/share/fonts/" - "Open Sans/OpenSans-Regular.ttf"; - input->font.font_size = 24; - input->font.font_colour[0] = 0xFF; - input->font.font_colour[1] = 0xFF; - input->font.font_colour[2] = 0xFF; + input->title_font.font_name = strdup( "Sans" ); + input->title_font.font_size = 12; + input->title_font.font_colour[0] = 0xFF; + input->title_font.font_colour[1] = 0xFF; + input->title_font.font_colour[2] = 0xFF; + + input->title = strdup( "" ); + input->scale_label = strdup( "" ); + input->scale_font.font_name = strdup( "Sans" ); + input->scale_font.font_size = 12; + input->scale_font.font_colour[0] = 0xFF; + input->scale_font.font_colour[1] = 0xFF; + input->scale_font.font_colour[2] = 0xFF; Input* new_input = INPUT_INPUT( g_object_new( INPUT_TYPE_INPUT, NULL ) ); @@ -385,7 +477,7 @@ static void export_all_file_callback( } fprintf( stderr, "Got %s as font file\n", - config->title_font.font_path ); + config->title_font.font_name ); if ( 0 == gtk_drop_down_get_selected( GTK_DROP_DOWN( app->speed_mode ) ) ) { @@ -456,11 +548,7 @@ static void export_selected_file_callback( GTK_FILE_CHOOSER( file_dialogue ) ); char* file_path = g_file_get_path( file ); - unsigned int selected_index = gtk_single_selection_get_selected( - app->input_selection ); - Input* selected_item = INPUT_INPUT( g_list_model_get_item( - G_LIST_MODEL( app->input_store ), selected_index ) ); - struct input* input = selected_item->input; + struct input* input = get_selected_input( app ); struct output_config* config = calloc( 1, sizeof (struct output_config) ); @@ -622,6 +710,18 @@ static void build_general_settings( } +static void input_selection_changed( GtkSelectionModel* selection, + unsigned int position, unsigned int n_items, void* data ) { + + (void) selection; + (void) position; + (void) n_items; + + struct app* app = (struct app*) data; + update_export_sensitivity( app ); + +} + static void file_factory_setup_callback( GtkListItemFactory* factory, GtkListItem* list_item ) { @@ -767,33 +867,78 @@ static void column_factory_bind_callback( } -static void frame_rate_factory_setup_callback( - GtkListItemFactory* factory, GtkListItem* list_item ) { +static void input_title_font_set( GtkFontChooser* font_button, + void* data ) { - (void) factory; + struct app* app = (struct app*) data; - GtkWidget* grid = gtk_grid_new(); + struct input* input = get_selected_input( app ); - GtkWidget* frame_rate_spin = gtk_spin_button_new( - gtk_adjustment_new( 1, 0, 1E30, 1, 10, 10 ), 1, 0 ); - gtk_grid_attach( GTK_GRID( grid ), frame_rate_spin, 0, 0, 1, 1 ); + char* error; + if ( 0 > get_font( gtk_font_chooser_get_font_desc( + GTK_FONT_CHOOSER( font_button ) ), + &( input->title_font ), &error ) ) { + assert( NULL != error ); + GtkWidget* message = gtk_message_dialog_new( + GTK_WINDOW( app->top_level_window ), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "%s", error ); + g_signal_connect( message, "response", + G_CALLBACK( gtk_window_destroy ), NULL ); - static const char* rate_modes[] = { - [INPUT_RATE_FPS] = "FPS", - [INPUT_RATE_SPF] = "secs / frame", - [INPUT_RATE_MPF] = "mins / frame", - NULL, - }; - GtkWidget* rate_mode = gtk_drop_down_new_from_strings( rate_modes ); - gtk_grid_attach( GTK_GRID( grid ), rate_mode, 1, 0, 1, 1 ); + gtk_window_present( GTK_WINDOW( message ) ); + } + +} - gtk_list_item_set_child( list_item, grid ); +static void input_title_font_copy( GtkButton* button, void* data ) { + + (void) button; + + struct app* app = (struct app*) data; + + struct input* selected_input = get_selected_input( app ); + + size_t n = g_list_model_get_n_items( + G_LIST_MODEL( app->input_store ) ); + + for ( size_t i = 0; i < n; i++ ) { + + Input* Input = INPUT_INPUT( g_list_model_get_item( + G_LIST_MODEL( app->input_store ), i ) ); + struct input* input = Input->input; + + if ( input == selected_input ) { + continue; + } + + if ( NULL != input->title_font.font_name ) { + free( input->title_font.font_name ); + } + input->title_font.font_name = strdup( + selected_input->title_font.font_name ); + + input->title_font.font_size = + selected_input->title_font.font_size; + + input->title_font.font_colour[0] = + selected_input->title_font.font_colour[0]; + input->title_font.font_colour[1] = + selected_input->title_font.font_colour[1]; + input->title_font.font_colour[2] = + selected_input->title_font.font_colour[2]; + + } } static void input_frame_rate_changed( GtkAdjustment* adj, void* data ) { - struct input* input = (struct input*) data; + struct app* app = (struct app*) data; + + struct input* input = get_selected_input( app ); + input->frame_rate = gtk_adjustment_get_value( adj ); } @@ -803,34 +948,190 @@ static void input_rate_mode_changed( GObject* drop_down, (void) param_spec; - struct input* input = (struct input*) data; + struct app* app = (struct app*) data; + + struct input* input = get_selected_input( app ); + input->rate_unit = gtk_drop_down_get_selected( GTK_DROP_DOWN( drop_down ) ); } -static void frame_rate_factory_bind_callback( - GtkListItemFactory* factory, GtkListItem* list_item ) { +static void input_frame_rate_copy( GtkButton* button, void* data ) { - (void) factory; + (void) button; - GtkWidget* grid = gtk_list_item_get_child( list_item ); - Input* input = gtk_list_item_get_item( list_item ); - GtkWidget* frame_rate_spin = gtk_grid_get_child_at( - GTK_GRID( grid ), 0, 0 ); - GtkWidget* rate_mode = gtk_grid_get_child_at( - GTK_GRID( grid ), 1, 0 ); + struct app* app = (struct app*) data; - gtk_spin_button_set_value( GTK_SPIN_BUTTON( frame_rate_spin ), - input->input->frame_rate ); - g_signal_connect( gtk_spin_button_get_adjustment( - GTK_SPIN_BUTTON( frame_rate_spin ) ), "value-changed", - G_CALLBACK( input_frame_rate_changed ), input->input ); + struct input* selected_input = get_selected_input( app ); + + size_t n = g_list_model_get_n_items( + G_LIST_MODEL( app->input_store ) ); + + for ( size_t i = 0; i < n; i++ ) { + + Input* Input = INPUT_INPUT( g_list_model_get_item( + G_LIST_MODEL( app->input_store ), i ) ); + struct input* input = Input->input; + + if ( input == selected_input ) { + continue; + } - gtk_drop_down_set_selected( GTK_DROP_DOWN( rate_mode ), - input->input->rate_unit ); - g_signal_connect( rate_mode, "notify::selected", - G_CALLBACK( input_rate_mode_changed ), input->input ); + input->frame_rate = selected_input->frame_rate; + input->rate_unit = selected_input->rate_unit; + + } + +} + +static void input_scale_label_deleted( GtkEntryBuffer* buffer, + unsigned int position, unsigned int n_chars, void* data ) { + + (void) position; + (void) n_chars; + + struct app* app = (struct app*) data; + + struct input* input = get_selected_input( app ); + + strcpy( input->scale_label, gtk_entry_buffer_get_text( buffer ) ); + +} + +static void input_scale_label_inserted( GtkEntryBuffer* buffer, + unsigned int position, char* chars, + unsigned int n_chars, void* data ) { + + (void) position; + (void) chars; + (void) n_chars; + + struct app* app = (struct app*) data; + + struct input* input = get_selected_input( app ); + + free( input->scale_label ); + input->scale_label = strdup( gtk_entry_buffer_get_text( buffer ) ); + +} + +static void mu_button_clicked( GtkButton* button, void* data ) { + + (void) button; + + GtkEntry* entry = (GtkEntry*) data; + GtkEntryBuffer* buffer = gtk_entry_get_buffer( entry ); + + gtk_entry_buffer_insert_text( buffer, + gtk_entry_buffer_get_length( buffer), "µ", -1 ); + +} + +static void input_scale_len_changed( GtkAdjustment* adj, void* data ) { + + struct app* app = (struct app*) data; + + struct input* input = get_selected_input( app ); + + input->scale_length = gtk_adjustment_get_value( adj ); + +} + +static void input_scale_copy( GtkButton* button, void* data ) { + + (void) button; + + struct app* app = (struct app*) data; + + struct input* selected_input = get_selected_input( app ); + + size_t n = g_list_model_get_n_items( + G_LIST_MODEL( app->input_store ) ); + + for ( size_t i = 0; i < n; i++ ) { + + Input* Input = INPUT_INPUT( g_list_model_get_item( + G_LIST_MODEL( app->input_store ), i ) ); + struct input* input = Input->input; + + if ( input == selected_input ) { + continue; + } + + input->scale_length = selected_input->scale_length; + if ( NULL != input->scale_label ) { + free( input->scale_label ); + } + input->scale_label = strdup( selected_input->scale_label ); + + } + +} + +static void input_scale_font_set( GtkFontChooser* font_button, + void* data ) { + + struct app* app = (struct app*) data; + + struct input* input = get_selected_input( app ); + + char* error; + if ( 0 > get_font( gtk_font_chooser_get_font_desc( + GTK_FONT_CHOOSER( font_button ) ), + &( input->scale_font ), &error ) ) { + assert( NULL != error ); + GtkWidget* message = gtk_message_dialog_new( + GTK_WINDOW( app->top_level_window ), + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, + "%s", error ); + g_signal_connect( message, "response", + G_CALLBACK( gtk_window_destroy ), NULL ); + + gtk_window_present( GTK_WINDOW( message ) ); + } + +} + +static void input_scale_font_copy( GtkButton* button, void* data ) { + + (void) button; + + struct app* app = (struct app*) data; + + struct input* selected_input = get_selected_input( app ); + + size_t n = g_list_model_get_n_items( + G_LIST_MODEL( app->input_store ) ); + + for ( size_t i = 0; i < n; i++ ) { + + Input* Input = INPUT_INPUT( g_list_model_get_item( + G_LIST_MODEL( app->input_store ), i ) ); + struct input* input = Input->input; + + if ( input == selected_input ) { + continue; + } + + if ( NULL != input->scale_font.font_name ) { + free( input->scale_font.font_name ); + } + input->scale_font.font_name = strdup( + selected_input->scale_font.font_name ); + + input->scale_font.font_size = + selected_input->scale_font.font_size; + + input->scale_font.font_colour[0] = + selected_input->scale_font.font_colour[0]; + input->scale_font.font_colour[1] = + selected_input->scale_font.font_colour[1]; + input->scale_font.font_colour[2] = + selected_input->scale_font.font_colour[2]; + + } } @@ -846,10 +1147,19 @@ static void build_input_settings( struct app* app, GtkBox* container ) { app->input_store = g_list_store_new( INPUT_TYPE_INPUT ); GtkSingleSelection* selection = gtk_single_selection_new( G_LIST_MODEL( app->input_store ) ); + g_signal_connect( G_OBJECT( selection ), "selection-changed", + G_CALLBACK( input_selection_changed ), app ); + + GtkWidget* input_list_scroll = gtk_scrolled_window_new(); + gtk_widget_set_vexpand( input_list_scroll, true ); GtkWidget* input_list = gtk_column_view_new( GTK_SELECTION_MODEL( selection ) ); gtk_widget_set_hexpand( input_list, true ); + gtk_column_view_set_reorderable( + GTK_COLUMN_VIEW( input_list ), false ); + gtk_column_view_set_show_column_separators( + GTK_COLUMN_VIEW( input_list ), false ); GtkListItemFactory* file_item_factory = gtk_signal_list_item_factory_new(); @@ -859,6 +1169,8 @@ static void build_input_settings( struct app* app, GtkBox* container ) { G_CALLBACK( file_factory_bind_callback ), NULL ); GtkColumnViewColumn* file_column = gtk_column_view_column_new( "File", file_item_factory ); + gtk_column_view_column_set_resizable( file_column, true ); + gtk_column_view_column_set_expand( file_column, true ); gtk_column_view_append_column( GTK_COLUMN_VIEW( input_list ), file_column ); @@ -870,6 +1182,8 @@ static void build_input_settings( struct app* app, GtkBox* container ) { G_CALLBACK( title_factory_bind_callback ), NULL ); GtkColumnViewColumn* title_column = gtk_column_view_column_new( "Title", title_item_factory ); + gtk_column_view_column_set_resizable( title_column, true ); + gtk_column_view_column_set_expand( title_column, true ); gtk_column_view_append_column( GTK_COLUMN_VIEW( input_list ), title_column ); @@ -881,6 +1195,8 @@ static void build_input_settings( struct app* app, GtkBox* container ) { G_CALLBACK( row_factory_bind_callback ), NULL ); GtkColumnViewColumn* row_column = gtk_column_view_column_new( "Row", row_item_factory ); + gtk_column_view_column_set_resizable( row_column, true ); + gtk_column_view_column_set_expand( row_column, true ); gtk_column_view_append_column( GTK_COLUMN_VIEW( input_list ), row_column ); @@ -892,26 +1208,157 @@ static void build_input_settings( struct app* app, GtkBox* container ) { G_CALLBACK( column_factory_bind_callback ), NULL ); GtkColumnViewColumn* column_column = gtk_column_view_column_new( "Column", column_item_factory ); + gtk_column_view_column_set_resizable( column_column, true ); + gtk_column_view_column_set_expand( column_column, true ); gtk_column_view_append_column( GTK_COLUMN_VIEW( input_list ), column_column ); - GtkListItemFactory* frame_rate_item_factory = - gtk_signal_list_item_factory_new(); - g_signal_connect( frame_rate_item_factory, "setup", - G_CALLBACK( frame_rate_factory_setup_callback ), NULL ); - g_signal_connect( frame_rate_item_factory, "bind", - G_CALLBACK( frame_rate_factory_bind_callback ), NULL ); - GtkColumnViewColumn* frame_rate_column = gtk_column_view_column_new( - "Frame Rate", frame_rate_item_factory ); - gtk_column_view_append_column( GTK_COLUMN_VIEW( input_list ), - frame_rate_column ); + gtk_scrolled_window_set_child( + GTK_SCROLLED_WINDOW( input_list_scroll ), input_list ); - gtk_box_append( GTK_BOX( box ), input_list ); + gtk_box_append( GTK_BOX( box ), input_list_scroll ); app->input_selection = selection; + GtkWidget* options_grid = gtk_grid_new(); + + GtkWidget* title_font_label = gtk_label_new( "Title Font" ); + gtk_grid_attach( GTK_GRID( options_grid ), title_font_label, + 0, 0, 1, 1 ); + + GtkWidget* title_font_button = gtk_font_button_new(); + g_signal_connect( G_OBJECT( title_font_button ), "font-set", + G_CALLBACK( input_title_font_set ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), title_font_button, + 1, 0, 1, 1 ); + + GtkWidget* title_font_copy_button = + gtk_button_new_from_icon_name( "edit-copy" ); + gtk_widget_set_tooltip_text( + title_font_copy_button, "Copy to all" ); + g_signal_connect( G_OBJECT( title_font_copy_button ), "clicked", + G_CALLBACK( input_title_font_copy ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), title_font_copy_button, + 2, 0, 1, 1 ); + + GtkWidget* frame_rate_label = gtk_label_new( "Frame Rate" ); + gtk_grid_attach( GTK_GRID( options_grid ), frame_rate_label, + 0, 1, 1, 1 ); + + GtkWidget* frame_rate_box = gtk_box_new( + GTK_ORIENTATION_HORIZONTAL, 0 ); + + GtkWidget* frame_rate_spin = gtk_spin_button_new( + gtk_adjustment_new( 1, 0, 1E30, 1, 10, 10 ), 1, 0 ); + g_signal_connect( gtk_spin_button_get_adjustment( + GTK_SPIN_BUTTON( frame_rate_spin ) ), "value-changed", + G_CALLBACK( input_frame_rate_changed ), app ); + gtk_box_append( GTK_BOX( frame_rate_box ), frame_rate_spin ); + + static const char* rate_modes[] = { + [INPUT_RATE_FPS] = "FPS", + [INPUT_RATE_SPF] = "secs / frame", + [INPUT_RATE_MPF] = "mins / frame", + NULL, + }; + GtkWidget* frame_rate_mode = gtk_drop_down_new_from_strings( + rate_modes ); + g_signal_connect( frame_rate_mode, "notify::selected", + G_CALLBACK( input_rate_mode_changed ), app ); + gtk_box_append( GTK_BOX( frame_rate_box ), frame_rate_mode ); + gtk_grid_attach( GTK_GRID( options_grid ), frame_rate_box, + 1, 1, 1, 1 ); + + GtkWidget* frame_rate_copy_button = + gtk_button_new_from_icon_name( "edit-copy" ); + gtk_widget_set_tooltip_text( + frame_rate_copy_button, "Copy to all" ); + g_signal_connect( G_OBJECT( frame_rate_copy_button ), "clicked", + G_CALLBACK( input_frame_rate_copy ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), frame_rate_copy_button, + 2, 1, 1, 1 ); + + GtkWidget* scale_label_label = gtk_label_new( "Scale Label" ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_label_label, + 0, 2, 1, 1 ); + + GtkWidget* scale_label_box = gtk_box_new( + GTK_ORIENTATION_HORIZONTAL, 0 ); + + GtkWidget* scale_label_entry = gtk_entry_new(); + g_signal_connect( gtk_entry_get_buffer( + GTK_ENTRY( scale_label_entry) ), "inserted-text", + G_CALLBACK( input_scale_label_inserted ), app ); + g_signal_connect( gtk_entry_get_buffer( + GTK_ENTRY( scale_label_entry ) ), "deleted-text", + G_CALLBACK( input_scale_label_deleted ), app ); + gtk_box_append( GTK_BOX( scale_label_box ), scale_label_entry ); + + GtkWidget* scale_mu_button = gtk_button_new_with_label( "µ" ); + g_signal_connect( G_OBJECT( scale_mu_button ), "clicked", + G_CALLBACK( mu_button_clicked ), scale_label_entry ); + gtk_box_append( GTK_BOX( scale_label_box ), scale_mu_button ); + + gtk_grid_attach( GTK_GRID( options_grid ), scale_label_box, + 1, 2, 1, 1 ); + + GtkWidget* scale_len_label = gtk_label_new( "Scale Length (px)" ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_len_label, + 0, 3, 1, 1 ); + + GtkWidget* scale_len_spin = gtk_spin_button_new( + gtk_adjustment_new( 0, 0, 1E5, 1, 10, 10 ), 1, 3 ); + g_signal_connect( gtk_spin_button_get_adjustment( + GTK_SPIN_BUTTON( scale_len_spin ) ), "value-changed", + G_CALLBACK( input_scale_len_changed ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_len_spin, + 1, 3, 1, 1 ); + + GtkWidget* scale_copy_button = + gtk_button_new_from_icon_name( "edit-copy" ); + gtk_widget_set_tooltip_text( + scale_copy_button, "Copy to all" ); + g_signal_connect( G_OBJECT( scale_copy_button ), "clicked", + G_CALLBACK( input_scale_copy ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_copy_button, + 2, 2, 1, 2 ); + + GtkWidget* scale_font_label = gtk_label_new( "Scale Label Font" ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_font_label, + 0, 4, 1, 1 ); + + GtkWidget* scale_font_button = gtk_font_button_new(); + g_signal_connect( G_OBJECT( scale_font_button ), "font-set", + G_CALLBACK( input_scale_font_set ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_font_button, + 1, 4, 1, 1 ); + + GtkWidget* scale_font_copy_button = + gtk_button_new_from_icon_name( "edit-copy" ); + gtk_widget_set_tooltip_text( + scale_font_copy_button, "Copy to all" ); + g_signal_connect( G_OBJECT( scale_font_copy_button ), "clicked", + G_CALLBACK( input_scale_font_copy ), app ); + gtk_grid_attach( GTK_GRID( options_grid ), scale_font_copy_button, + 2, 4, 1, 1 ); + + gtk_box_append( GTK_BOX( box ), options_grid ); + gtk_box_append( container, frame ); + app->input_title_font = title_font_button; + app->input_frame_rate_spin = frame_rate_spin; + app->input_frame_rate_mode = frame_rate_mode; + app->input_scale_label = scale_label_entry; + app->input_scale_mu = scale_mu_button; + app->input_scale_length = scale_len_spin; + app->input_scale_font = scale_font_button; + + app->input_title_font_copy = title_font_copy_button; + app->input_frame_rate_copy = frame_rate_copy_button; + app->input_scale_copy = scale_copy_button; + app->input_scale_font_copy = scale_font_copy_button; + } static void application_callback( @@ -937,6 +1384,8 @@ static void application_callback( gtk_box_append( GTK_BOX( vbox ), hbox ); + update_export_sensitivity( app ); + gtk_window_present( (GtkWindow*) app->top_level_window ); } diff --git a/src/output.c b/src/output.c index e7e9fb5..6037be9 100644 --- a/src/output.c +++ b/src/output.c @@ -457,7 +457,7 @@ void* output_all( void* data ) { config->title_font.font_colour[0], config->title_font.font_colour[1], config->title_font.font_colour[2], - config->title_font.font_path ); + config->title_font.font_name ); free( title_text ); -- GitLab