From d42ee3e1c031383fe96276386a294ef87a501d0f Mon Sep 17 00:00:00 2001 From: Benjamin Schaaf Date: Tue, 20 Apr 2021 00:04:53 +1000 Subject: [PATCH] Progress on GTK4 port --- data/camera.ui | 225 ++++++++++++++--------------------------- src/main.c | 211 ++++++++++++++++++-------------------- src/main.h | 3 + src/process_pipeline.c | 9 +- 4 files changed, 182 insertions(+), 266 deletions(-) diff --git a/data/camera.ui b/data/camera.ui index 9b137f0..1feddc8 100644 --- a/data/camera.ui +++ b/data/camera.ui @@ -18,9 +18,8 @@ main - + 0 - vertical 1 @@ -28,7 +27,7 @@ 1 - + 0 0 @@ -68,38 +67,53 @@ - - + + + horizontal + 1 + end + 0 0 - - - 1 + 5 + + + horizontal + 1 + end + 0 + 5 + 5 - - 0 - /org/postmarketos/Megapixels/settings-symbolic.svg + + 1 + + + 0 + /org/postmarketos/Megapixels/settings-symbolic.svg + + + + + + + 1 + + + 0 + /org/postmarketos/Megapixels/switch-camera.svg + + - - - 1 - - - 0 - /org/postmarketos/Megapixels/switch-camera.svg - - - - - - - 48 - 48 + + + app.capture 1 + 60 0 /org/postmarketos/Megapixels/shutter-button.svg @@ -109,35 +123,46 @@ - - - 1 + + + horizontal + 1 + end + end + 0 + 5 + 5 - - 0 - /org/postmarketos/Megapixels/folder-symbolic.svg - - - - - - - 1 - - - 0 + + 1 - - 24 - 24 + 0 + /org/postmarketos/Megapixels/folder-symbolic.svg + + + + + 1 - - 24 - 24 + 0 + + + 24 + 24 + 0 + + + + + 24 + 24 + 0 + + @@ -146,7 +171,7 @@ - + 0 0 @@ -184,18 +209,15 @@ - + diff --git a/src/main.c b/src/main.c index fb3af54..faf58ff 100644 --- a/src/main.c +++ b/src/main.c @@ -51,6 +51,8 @@ static bool has_auto_focus_continuous; static bool has_auto_focus_start; static MPProcessPipelineBuffer *current_preview_buffer = NULL; +static int preview_buffer_width = -1; +static int preview_buffer_height = -1; static cairo_surface_t *status_surface = NULL; static char last_path[260] = ""; @@ -130,6 +132,9 @@ update_state(const struct mp_main_state *state) has_auto_focus_start = state->has_auto_focus_start; } + preview_buffer_width = state->image_width; + preview_buffer_height = state->image_height; + return false; } @@ -381,6 +386,12 @@ preview_draw(GtkGLArea *area, GdkGLContext *ctx, gpointer data) glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); + double ratio = preview_buffer_height / (double)preview_buffer_width; + glViewport(0, + preview_height - preview_width * ratio, + preview_width, + preview_width * ratio); + if (current_preview_buffer) { glUseProgram(blit_program); @@ -488,18 +499,18 @@ on_open_directory_clicked(GtkWidget *widget, gpointer user_data) } void -on_shutter_clicked(GtkWidget *widget, gpointer user_data) +run_capture_action(GSimpleAction *action, GVariant *param, gpointer user_data) { gtk_spinner_start(GTK_SPINNER(process_spinner)); gtk_stack_set_visible_child(GTK_STACK(open_last_stack), process_spinner); mp_io_pipeline_capture(); } -// void -// on_capture_shortcut(void) -// { -// on_shutter_clicked(NULL, NULL); -// } +void +run_quit_action(GSimpleAction *action, GVariant *param, GApplication *app) +{ + g_application_quit(app); +} // static bool // check_point_inside_bounds(int x, int y, int *bounds_x, int *bounds_y) @@ -584,69 +595,66 @@ on_shutter_clicked(GtkWidget *widget, gpointer user_data) // gtk_widget_destroy(dialog); // } -// void -// on_preview_tap(GtkWidget *widget, GdkEventButton *event, gpointer user_data) -// { -// if (event->type != GDK_BUTTON_PRESS) -// return; +void +preview_pressed(GtkGestureClick *gesture, int n_press, double x, double y) +{ + // Handle taps on the controls + // if (event->y < 32) { + // if (gtk_widget_is_visible(control_box)) { + // gtk_widget_hide(control_box); + // return; + // } else { + // gtk_widget_show(control_box); + // } -// // Handle taps on the controls -// if (event->y < 32) { -// if (gtk_widget_is_visible(control_box)) { -// gtk_widget_hide(control_box); -// return; -// } else { -// gtk_widget_show(control_box); -// } + // if (event->x < 60) { + // // ISO + // current_control = USER_CONTROL_ISO; + // gtk_label_set_text(GTK_LABEL(control_name), "ISO"); + // gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto), + // !gain_is_manual); + // gtk_adjustment_set_lower(control_slider, 0.0); + // gtk_adjustment_set_upper(control_slider, (float)gain_max); + // gtk_adjustment_set_value(control_slider, (double)gain); -// if (event->x < 60) { -// // ISO -// current_control = USER_CONTROL_ISO; -// gtk_label_set_text(GTK_LABEL(control_name), "ISO"); -// gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto), -// !gain_is_manual); -// gtk_adjustment_set_lower(control_slider, 0.0); -// gtk_adjustment_set_upper(control_slider, (float)gain_max); -// gtk_adjustment_set_value(control_slider, (double)gain); + // } else if (event->x > 60 && event->x < 120) { + // // Shutter angle + // current_control = USER_CONTROL_SHUTTER; + // gtk_label_set_text(GTK_LABEL(control_name), "Shutter"); + // gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto), + // !exposure_is_manual); + // gtk_adjustment_set_lower(control_slider, 1.0); + // gtk_adjustment_set_upper(control_slider, 360.0); + // gtk_adjustment_set_value(control_slider, (double)exposure); + // } -// } else if (event->x > 60 && event->x < 120) { -// // Shutter angle -// current_control = USER_CONTROL_SHUTTER; -// gtk_label_set_text(GTK_LABEL(control_name), "Shutter"); -// gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(control_auto), -// !exposure_is_manual); -// gtk_adjustment_set_lower(control_slider, 1.0); -// gtk_adjustment_set_upper(control_slider, 360.0); -// gtk_adjustment_set_value(control_slider, (double)exposure); -// } + // return; + // } -// return; -// } + // Tapped zbar result + // if (zbar_result) { + // // Transform the event coordinates to the image + // int width = cairo_image_surface_get_width(surface); + // int height = cairo_image_surface_get_height(surface); + // double scale = MIN(preview_width / (double)width, preview_height / (double)height); + // int x = (event->x - preview_width / 2) / scale + width / 2; + // int y = (event->y - preview_height / 2) / scale + height / 2; -// // Tapped zbar result -// if (zbar_result) { -// // Transform the event coordinates to the image -// int width = cairo_image_surface_get_width(surface); -// int height = cairo_image_surface_get_height(surface); -// double scale = MIN(preview_width / (double)width, preview_height / (double)height); -// int x = (event->x - preview_width / 2) / scale + width / 2; -// int y = (event->y - preview_height / 2) / scale + height / 2; + // for (uint8_t i = 0; i < zbar_result->size; ++i) { + // MPZBarCode *code = &zbar_result->codes[i]; -// for (uint8_t i = 0; i < zbar_result->size; ++i) { -// MPZBarCode *code = &zbar_result->codes[i]; + // if (check_point_inside_bounds(x, y, code->bounds_x, code->bounds_y)) { + // on_zbar_code_tapped(widget, code); + // return; + // } + // } + // } -// if (check_point_inside_bounds(x, y, code->bounds_x, code->bounds_y)) { -// on_zbar_code_tapped(widget, code); -// return; -// } -// } -// } - -// // Tapped preview image itself, try focussing -// if (has_auto_focus_start) { -// mp_io_pipeline_focus(); -// } -// } + // Tapped preview image itself, try focussing + if (has_auto_focus_start) { + mp_io_pipeline_focus(); + } +} void on_error_close_clicked(GtkWidget *widget, gpointer user_data) @@ -770,21 +778,9 @@ on_realize(GtkWidget *window, gpointer *data) update_io_pipeline(); } -typedef struct -{ - GtkApplication parent_instance; -} MegapixelsApp; - -typedef GtkApplicationClass MegapixelsAppClass; - -GType megapixels_app_get_type (void); -G_DEFINE_TYPE(MegapixelsApp, megapixels_app, GTK_TYPE_APPLICATION) - static void -startup(GApplication *app) +activate(GtkApplication *app, gpointer data) { - G_APPLICATION_CLASS(megapixels_app_parent_class)->startup(app); - g_object_set(gtk_settings_get_default(), "gtk-application-prefer-dark-theme", TRUE, NULL); @@ -794,7 +790,6 @@ startup(GApplication *app) "/org/postmarketos/Megapixels/camera.ui"); GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window")); - GtkWidget *shutter = GTK_WIDGET(gtk_builder_get_object(builder, "shutter")); GtkWidget *switch_btn = GTK_WIDGET(gtk_builder_get_object(builder, "switch_camera")); GtkWidget *settings_btn = @@ -820,8 +815,6 @@ startup(GApplication *app) GTK_ADJUSTMENT(gtk_builder_get_object(builder, "control_adj")); control_auto = GTK_WIDGET(gtk_builder_get_object(builder, "control_auto")); g_signal_connect(window, "realize", G_CALLBACK(on_realize), NULL); - // g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); - g_signal_connect(shutter, "clicked", G_CALLBACK(on_shutter_clicked), NULL); g_signal_connect(error_close, "clicked", G_CALLBACK(on_error_close_clicked), NULL); g_signal_connect(switch_btn, "clicked", G_CALLBACK(on_camera_switch_clicked), @@ -834,15 +827,14 @@ startup(GApplication *app) NULL); g_signal_connect(open_directory, "clicked", G_CALLBACK(on_open_directory_clicked), NULL); + g_signal_connect(preview, "realize", G_CALLBACK(preview_realize), NULL); g_signal_connect(preview, "render", G_CALLBACK(preview_draw), NULL); - g_signal_connect(preview, "resize", G_CALLBACK(preview_resize), - NULL); - // gtk_widget_set_events(preview, gtk_widget_get_events(preview) | - // GDK_BUTTON_PRESS_MASK | - // GDK_POINTER_MOTION_MASK); - // g_signal_connect(preview, "button-press-event", G_CALLBACK(on_preview_tap), - // NULL); + g_signal_connect(preview, "resize", G_CALLBACK(preview_resize), NULL); + GtkGesture *click = gtk_gesture_click_new(); + g_signal_connect(click, "pressed", G_CALLBACK(preview_pressed), NULL); + gtk_widget_add_controller(preview, GTK_EVENT_CONTROLLER(click)); + g_signal_connect(control_auto, "toggled", G_CALLBACK(on_control_auto_toggled), NULL); g_signal_connect(control_slider, "value-changed", @@ -858,46 +850,35 @@ startup(GApplication *app) gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_USER); - // GClosure* capture_shortcut = g_cclosure_new(on_capture_shortcut, 0, 0); + // Setup capture action + GSimpleAction *capture_action = g_simple_action_new("capture", NULL); + g_signal_connect(capture_action, "activate", G_CALLBACK(run_capture_action), NULL); + g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(capture_action)); - // GtkAccelGroup* accel_group = gtk_accel_group_new(); - // gtk_accel_group_connect(accel_group, - // GDK_KEY_space, - // 0, - // 0, - // capture_shortcut); + const char *capture_accels[] = { "space", NULL }; + gtk_application_set_accels_for_action(app, "app.capture", capture_accels); - // gtk_window_add_accel_group(GTK_WINDOW(window), accel_group); + // Setup quit action + GSimpleAction *quit_action = g_simple_action_new("quit", NULL); + g_signal_connect(quit_action, "activate", G_CALLBACK(run_quit_action), app); + g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(quit_action)); + + const char *quit_accels[] = { "q", "w", NULL }; + gtk_application_set_accels_for_action(app, "app.quit", quit_accels); mp_io_pipeline_start(); - gtk_application_add_window(GTK_APPLICATION(app), GTK_WINDOW(window)); + gtk_application_add_window(app, GTK_WINDOW(window)); gtk_widget_show(window); } static void -shutdown(GApplication *app) +shutdown(GApplication *app, gpointer data) { // Only do cleanup in development, let the OS clean up otherwise #ifdef DEBUG mp_io_pipeline_stop(); #endif - - G_APPLICATION_CLASS(megapixels_app_parent_class)->shutdown(app); -} - -static void -megapixels_app_init(MegapixelsApp *app) -{ -} - -static void -megapixels_app_class_init(MegapixelsAppClass *class) -{ - GApplicationClass *application_class = G_APPLICATION_CLASS(class); - - application_class->startup = startup; - application_class->shutdown = shutdown; } int @@ -924,10 +905,10 @@ main(int argc, char *argv[]) setenv("LC_NUMERIC", "C", 1); - MegapixelsApp *app = g_object_new( - megapixels_app_get_type(), - "application-id", "org.postmarketos.Megapixels", - NULL); + GtkApplication *app = gtk_application_new("org.postmarketos.Megapixels", 0); + + g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); + g_signal_connect(app, "shutdown", G_CALLBACK(shutdown), NULL); g_application_run(G_APPLICATION(app), argc, argv); diff --git a/src/main.h b/src/main.h index fe899ac..720b4c5 100644 --- a/src/main.h +++ b/src/main.h @@ -11,6 +11,9 @@ struct mp_main_state { const struct mp_camera_config *camera; MPCameraMode mode; + int image_width; + int image_height; + bool gain_is_manual; int gain; int gain_max; diff --git a/src/process_pipeline.c b/src/process_pipeline.c index e6dc53a..b9aba03 100644 --- a/src/process_pipeline.c +++ b/src/process_pipeline.c @@ -675,11 +675,14 @@ mp_process_pipeline_capture() mp_pipeline_invoke(pipeline, capture, NULL, 0); } +static int output_buffer_width = -1; +static int output_buffer_height = -1; + static void on_output_changed() { - int output_buffer_width = mode.width / 2; - int output_buffer_height = mode.height / 2; + output_buffer_width = mode.width / 2; + output_buffer_height = mode.height / 2; if (camera->rotate != 0 || camera->rotate != 180) { int tmp = output_buffer_width; @@ -730,6 +733,8 @@ update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state struct mp_main_state main_state = { .camera = camera, .mode = mode, + .image_width = output_buffer_width, + .image_height = output_buffer_height, .gain_is_manual = state->gain_is_manual, .gain = gain, .gain_max = gain_max,