Browse Source

Progress on controls

opengl
Benjamin Schaaf 1 year ago
parent
commit
f9e6576266
  1. 231
      data/camera.ui
  2. 42
      data/controls-popover.ui
  3. 2
      data/org.postmarketos.Megapixels.gresource.xml
  4. 32
      data/shutter-symbolic.svg
  5. 199
      src/main.c

231
data/camera.ui

@ -1,11 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkAdjustment" id="control_adj">
<property name="upper">100</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkWindow" id="window">
<property name="can-focus">0</property>
<property name="default-width">360</property>
@ -18,7 +13,7 @@
<object class="GtkStackPage">
<property name="name">main</property>
<property name="child">
<object class="GtkOverlay" id="page_main">
<object class="GtkOverlay">
<property name="can-focus">0</property>
<child>
<object class="GtkGLArea" id="preview">
@ -28,100 +23,65 @@
</object>
</child>
<child type="overlay">
<object class="GtkBox" id="control_box">
<property name="visible">0</property>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="vexpand">1</property>
<property name="hexpand">1</property>
<property name="spacing">5</property>
<property name="can-focus">0</property>
<property name="margin-start">5</property>
<property name="margin-end">5</property>
<property name="margin-bottom">5</property>
<property name="margin-top">5</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="valign">start</property>
<property name="can-focus">0</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel" id="control_name">
<property name="can-focus">0</property>
<property name="margin-end">10</property>
<property name="label" translatable="yes">ISO</property>
</object>
</child>
<property name="spacing">5</property>
<child>
<object class="GtkScale" id="control_slider">
<property name="hexpand">1</property>
<property name="adjustment">control_adj</property>
<property name="round-digits">1</property>
<object class="GtkButton" id="iso-controls-button">
<property name="valign">start</property>
<property name="label">ISO</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
<child>
<object class="GtkToggleButton" id="control_auto">
<property name="label" translatable="yes">Auto</property>
<property name="receives-default">1</property>
<property name="margin-start">10</property>
<object class="GtkButton" id="shutter-controls-button">
<property name="valign">start</property>
<property name="icon-name">shutter-symbolic</property>
<style>
<class name="circular"/>
</style>
</object>
</child>
</object>
</child>
<style>
<class name="controlbox"/>
</style>
</object>
</child>
<child type="overlay">
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="valign">end</property>
<property name="homogeneous">0</property>
<property name="can-focus">0</property>
<property name="margin-bottom">5</property>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="valign">end</property>
<property name="can-focus">0</property>
<property name="margin-start">5</property>
<property name="spacing">5</property>
<object class="GtkButton">
<property name="visible">0</property>
<property name="halign">start</property>
<child>
<object class="GtkButton">
<property name="action-name">app.open-settings</property>
<property name="receives-default">1</property>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="spacing">10</property>
<child>
<object class="GtkImage">
<property name="can-focus">0</property>
<property name="icon-name">settings-symbolic</property>
<object class="GtkLabel">
<property name="label">Error</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">app.switch-camera</property>
<property name="receives-default">1</property>
<child>
<object class="GtkImage">
<property name="can-focus">0</property>
<property name="icon-name">switch-camera-symbolic</property>
<property name="icon-name">dialog-warning-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">app.capture</property>
<property name="receives-default">1</property>
<child>
<object class="GtkImage">
<property name="pixel-size">60</property>
<property name="can-focus">0</property>
<property name="icon-name">shutter-button-symbolic</property>
</object>
</child>
<style>
<class name="circular"/>
<class name="destructive-action"/>
</style>
</object>
</child>
@ -129,86 +89,89 @@
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="halign">end</property>
<property name="vexpand">1</property>
<property name="valign">end</property>
<property name="can-focus">0</property>
<property name="margin-end">5</property>
<property name="spacing">5</property>
<child>
<object class="GtkButton">
<property name="action-name">app.open-last</property>
<property name="receives-default">1</property>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="valign">end</property>
<property name="can-focus">0</property>
<property name="spacing">5</property>
<child>
<object class="GtkStack" id="open_last_stack">
<property name="can-focus">0</property>
<child>
<object class="GtkImage" id="thumb_last">
<property name="width-request">24</property>
<property name="height-request">24</property>
<property name="can-focus">0</property>
</object>
</child>
<child>
<object class="GtkSpinner" id="process_spinner">
<property name="width-request">24</property>
<property name="height-request">24</property>
<property name="can-focus">0</property>
</object>
</child>
<object class="GtkButton">
<property name="action-name">app.open-settings</property>
<property name="icon-name">settings-symbolic</property>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">app.switch-camera</property>
<property name="icon-name">switch-camera-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">app.open-photos</property>
<property name="receives-default">1</property>
<property name="action-name">app.capture</property>
<child>
<object class="GtkImage">
<property name="pixel-size">60</property>
<property name="can-focus">0</property>
<property name="icon-name">folder-symbolic</property>
<property name="icon-name">shutter-button-symbolic</property>
</object>
</child>
<style>
<class name="circular"/>
</style>
</object>
</child>
</object>
</child>
<style>
<class name="button-overlay"/>
</style>
</object>
</child>
<child type="overlay">
<object class="GtkBox" id="error_box">
<property name="visible">0</property>
<property name="can-focus">0</property>
<child>
<object class="GtkBox">
<property name="hexpand">1</property>
<property name="can-focus">0</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="spacing">10</property>
<child>
<object class="GtkLabel" id="error_message">
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="halign">end</property>
<property name="valign">end</property>
<property name="can-focus">0</property>
<property name="halign">start</property>
<property name="label" translatable="yes">No error</property>
</object>
</child>
<child>
<object class="GtkButton" id="error_close">
<property name="label">gtk-close</property>
<property name="receives-default">1</property>
<property name="spacing">5</property>
<child>
<object class="GtkButton">
<property name="action-name">app.open-last</property>
<child>
<object class="GtkStack" id="open_last_stack">
<property name="can-focus">0</property>
<child>
<object class="GtkImage" id="thumb_last">
<property name="width-request">24</property>
<property name="height-request">24</property>
<property name="can-focus">0</property>
</object>
</child>
<child>
<object class="GtkSpinner" id="process_spinner">
<property name="width-request">24</property>
<property name="height-request">24</property>
<property name="can-focus">0</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">app.open-photos</property>
<property name="icon-name">folder-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<style>
<class name="errorbox"/>
<class name="button-overlay"/>
</style>
</object>
</child>
@ -221,7 +184,7 @@
<property name="name">settings</property>
<property name="title" translatable="yes">page1</property>
<property name="child">
<object class="GtkScrolledWindow" id="page_settings">
<object class="GtkScrolledWindow">
<property name="child">
<object class="GtkViewport">
<property name="can-focus">0</property>
@ -238,11 +201,11 @@
<object class="GtkBox">
<property name="can-focus">0</property>
<child>
<object class="GtkButton" id="settings_back">
<object class="GtkButton">
<property name="label" translatable="yes">Back</property>
<property name="receives-default">1</property>
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="action-name">app.close-settings</property>
<style>
<class name="suggested-action"/>
</style>
@ -251,7 +214,7 @@
<child>
<object class="GtkLabel">
<property name="can-focus">0</property>
<property name="label" translatable="yes">Settings aren&apos;t functional yet</property>
<property name="label" translatable="yes">Settings aren't functional yet</property>
</object>
</child>
</object>

42
data/controls-popover.ui

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
<object class="GtkPopover" id="controls">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel" id="title">
</object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="hexpand">1</property>
<property name="spacing">5</property>
<child>
<object class="GtkScale" id="scale">
<property name="orientation">horizontal</property>
<property name="draw-value">0</property>
<property name="width-request">150</property>
</object>
</child>
<child>
<object class="GtkLabel" id="value-label">
</object>
</child>
<child>
<object class="GtkToggleButton" id="auto-button">
<property name="valign">center</property>
<property name="label">auto</property>
<property name="margin-start">5</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>

2
data/org.postmarketos.Megapixels.gresource.xml

@ -2,11 +2,13 @@
<gresources>
<gresource prefix="/org/postmarketos/Megapixels">
<file preprocess="xml-stripblanks">camera.ui</file>
<file preprocess="xml-stripblanks">controls-popover.ui</file>
<file>camera.css</file>
<file preprocess="xml-stripblanks">switch-camera-symbolic.svg</file>
<file preprocess="xml-stripblanks">shutter-button-symbolic.svg</file>
<file preprocess="xml-stripblanks">folder-symbolic.svg</file>
<file preprocess="xml-stripblanks">settings-symbolic.svg</file>
<file preprocess="xml-stripblanks">shutter-symbolic.svg</file>
<file>blit.vert</file>
<file>blit.frag</file>
<file>debayer.vert</file>

32
data/shutter-symbolic.svg

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 8.4666665 8.466667"
version="1.1"
id="svg8">
<defs
id="defs2" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<path
style="fill:#bebebe;fill-opacity:1;stroke-width:1"
d="M 16 0 A 16.000001 16.000001 0 0 0 8.5097656 1.8730469 L 11.611328 13.443359 L 19.189453 0.3203125 A 16.000001 16.000001 0 0 0 16 0 z M 20.699219 0.70703125 L 14.705078 11.087891 L 29.330078 7.1679688 A 16.000001 16.000001 0 0 0 20.699219 0.70703125 z M 7.1679688 2.6699219 A 16.000001 16.000001 0 0 0 0.70703125 11.300781 L 11.087891 17.294922 L 7.1679688 2.6699219 z M 30.126953 8.5117188 L 18.558594 11.611328 L 31.679688 19.189453 A 16.000001 16.000001 0 0 0 32 16 A 16.000001 16.000001 0 0 0 30.126953 8.5117188 z M 0.3203125 12.810547 A 16.000001 16.000001 0 0 0 0 16 A 16.000001 16.000001 0 0 0 1.8730469 23.490234 L 13.443359 20.388672 L 0.3203125 12.810547 z M 20.912109 14.705078 L 24.832031 29.330078 A 16.000001 16.000001 0 0 0 31.292969 20.699219 L 20.912109 14.705078 z M 20.388672 18.558594 L 12.8125 31.679688 A 16.000001 16.000001 0 0 0 16 32 A 16.000001 16.000001 0 0 0 23.490234 30.126953 L 20.388672 18.558594 z M 17.294922 20.912109 L 2.6699219 24.832031 A 16.000001 16.000001 0 0 0 11.300781 31.292969 L 17.294922 20.912109 z "
transform="scale(0.26458334)"
id="path4537" />
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

199
src/main.c

@ -61,12 +61,8 @@ static MPZBarScanResult *zbar_result = NULL;
static int burst_length = 3;
static enum user_control current_control;
// Widgets
GtkWidget *preview;
GtkWidget *error_box;
GtkWidget *error_message;
GtkWidget *main_stack;
GtkWidget *open_last_stack;
GtkWidget *thumb_last;
@ -598,39 +594,6 @@ run_quit_action(GSimpleAction *action, GVariant *param, GApplication *app)
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);
// }
// 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);
// }
// return;
// }
// Tapped zbar result
// if (zbar_result) {
// // Transform the event coordinates to the image
@ -656,13 +619,7 @@ preview_pressed(GtkGestureClick *gesture, int n_press, double x, double y)
}
}
void
on_error_close_clicked(GtkWidget *widget, gpointer user_data)
{
gtk_widget_hide(error_box);
}
void
static void
run_camera_switch_action(GSimpleAction *action, GVariant *param, gpointer user_data)
{
size_t next_index = camera->index + 1;
@ -678,19 +635,132 @@ run_camera_switch_action(GSimpleAction *action, GVariant *param, gpointer user_d
update_io_pipeline();
}
void
static void
run_open_settings_action(GSimpleAction *action, GVariant *param, gpointer user_data)
{
gtk_stack_set_visible_child_name(GTK_STACK(main_stack), "settings");
}
void
on_back_clicked(GtkWidget *widget, gpointer user_data)
static void
run_close_settings_action(GSimpleAction *action, GVariant *param, gpointer user_data)
{
gtk_stack_set_visible_child_name(GTK_STACK(main_stack), "main");
}
void
static void
on_controls_scale_changed(GtkAdjustment *adjustment, void (*set_fn)(double))
{
set_fn(gtk_adjustment_get_value(adjustment));
}
static void
update_value(GtkAdjustment *adjustment, GtkLabel *label)
{
char buf[12];
snprintf(buf, 12, "%.0f", gtk_adjustment_get_value(adjustment));
gtk_label_set_label(label, buf);
}
static void
on_auto_controls_toggled(GtkToggleButton *button, void (*set_auto_fn)(bool))
{
set_auto_fn(gtk_toggle_button_get_active(button));
}
static void
update_scale(GtkToggleButton *button, GtkScale *scale)
{
gtk_widget_set_sensitive(GTK_WIDGET(scale), !gtk_toggle_button_get_active(button));
}
static void
open_controls(GtkWidget *parent, const char *title_name,
double min_value, double max_value, double current,
bool auto_enabled,
void (*set_fn)(double),
void (*set_auto_fn)(bool))
{
GtkBuilder *builder = gtk_builder_new_from_resource(
"/org/postmarketos/Megapixels/controls-popover.ui");
GtkPopover *popover = GTK_POPOVER(gtk_builder_get_object(builder, "controls"));
GtkScale *scale = GTK_SCALE(gtk_builder_get_object(builder, "scale"));
GtkLabel *title = GTK_LABEL(gtk_builder_get_object(builder, "title"));
GtkLabel *value_label = GTK_LABEL(gtk_builder_get_object(builder, "value-label"));
GtkToggleButton *auto_button = GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "auto-button"));
gtk_label_set_label(title, title_name);
GtkAdjustment *adjustment = gtk_range_get_adjustment(GTK_RANGE(scale));
gtk_adjustment_set_lower(adjustment, min_value);
gtk_adjustment_set_upper(adjustment, max_value);
gtk_adjustment_set_value(adjustment, current);
update_value(adjustment, value_label);
gtk_toggle_button_set_active(auto_button, auto_enabled);
update_scale(auto_button, scale);
g_signal_connect(adjustment, "value-changed", G_CALLBACK(on_controls_scale_changed), set_fn);
g_signal_connect(adjustment, "value-changed", G_CALLBACK(update_value), value_label);
g_signal_connect(auto_button, "toggled", G_CALLBACK(on_auto_controls_toggled), set_auto_fn);
g_signal_connect(auto_button, "toggled", G_CALLBACK(update_scale), scale);
gtk_widget_set_parent(GTK_WIDGET(popover), parent);
gtk_popover_popup(popover);
// g_object_unref(popover);
}
static void
set_gain(double value)
{
if (gain != (int)value) {
gain = value;
update_io_pipeline();
}
}
static void
set_gain_auto(bool is_auto)
{
if (gain_is_manual != !is_auto) {
gain_is_manual = !is_auto;
update_io_pipeline();
}
}
static void
open_iso_controls(GtkWidget *button, gpointer user_data)
{
open_controls(button, "ISO", 0, gain_max, gain, !gain_is_manual, set_gain, set_gain_auto);
}
static void
set_shutter(double value)
{
int new_exposure =
(int)(value / 360.0 * camera->capture_mode.height);
if (new_exposure != exposure) {
exposure = new_exposure;
update_io_pipeline();
}
}
static void
set_shutter_auto(bool is_auto)
{
if (exposure_is_manual != !is_auto) {
exposure_is_manual = !is_auto;
update_io_pipeline();
}
}
static void
open_shutter_controls(GtkWidget *button, gpointer user_data)
{
open_controls(button, "Shutter", 1.0, 360.0, exposure, !exposure_is_manual, set_shutter, set_shutter_auto);
}
/*
static void
on_control_auto_toggled(GtkToggleButton *widget, gpointer user_data)
{
bool is_manual = gtk_toggle_button_get_active(widget) ? false : true;
@ -737,7 +807,7 @@ on_control_auto_toggled(GtkToggleButton *widget, gpointer user_data)
}
}
void
static void
on_control_slider_changed(GtkAdjustment *widget, gpointer user_data)
{
double value = gtk_adjustment_get_value(widget);
@ -767,6 +837,7 @@ on_control_slider_changed(GtkAdjustment *widget, gpointer user_data)
draw_controls();
}
}
*/
static void
on_realize(GtkWidget *window, gpointer *data)
@ -778,10 +849,11 @@ on_realize(GtkWidget *window, gpointer *data)
update_io_pipeline();
}
static GSimpleAction *create_simple_action(GtkApplication *app, const char *name, GCallback callback)
static GSimpleAction *
create_simple_action(GtkApplication *app, const char *name, GCallback callback)
{
GSimpleAction *action = g_simple_action_new(name, NULL);
g_signal_connect(action, "activate", callback, NULL);
g_signal_connect(action, "activate", callback, app);
g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(action));
return action;
}
@ -807,27 +879,15 @@ activate(GtkApplication *app, gpointer data)
"/org/postmarketos/Megapixels/camera.ui");
GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
GtkWidget *settings_back =
GTK_WIDGET(gtk_builder_get_object(builder, "settings_back"));
GtkWidget *error_close =
GTK_WIDGET(gtk_builder_get_object(builder, "error_close"));
GtkWidget *iso_button = GTK_WIDGET(gtk_builder_get_object(builder, "iso-controls-button"));
GtkWidget *shutter_button = GTK_WIDGET(gtk_builder_get_object(builder, "shutter-controls-button"));
preview = GTK_WIDGET(gtk_builder_get_object(builder, "preview"));
error_box = GTK_WIDGET(gtk_builder_get_object(builder, "error_box"));
error_message = GTK_WIDGET(gtk_builder_get_object(builder, "error_message"));
main_stack = GTK_WIDGET(gtk_builder_get_object(builder, "main_stack"));
open_last_stack = GTK_WIDGET(gtk_builder_get_object(builder, "open_last_stack"));
thumb_last = GTK_WIDGET(gtk_builder_get_object(builder, "thumb_last"));
process_spinner = GTK_WIDGET(gtk_builder_get_object(builder, "process_spinner"));
control_box = GTK_WIDGET(gtk_builder_get_object(builder, "control_box"));
control_name = GTK_WIDGET(gtk_builder_get_object(builder, "control_name"));
control_slider =
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(error_close, "clicked", G_CALLBACK(on_error_close_clicked),
NULL);
g_signal_connect(settings_back, "clicked", G_CALLBACK(on_back_clicked),
NULL);
g_signal_connect(preview, "realize", G_CALLBACK(preview_realize), NULL);
g_signal_connect(preview, "render", G_CALLBACK(preview_draw), NULL);
@ -836,15 +896,14 @@ activate(GtkApplication *app, gpointer data)
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",
G_CALLBACK(on_control_slider_changed), NULL);
g_signal_connect(iso_button, "clicked", G_CALLBACK(open_iso_controls), NULL);
g_signal_connect(shutter_button, "clicked", G_CALLBACK(open_shutter_controls), NULL);
// Setup actions
create_simple_action(app, "capture", G_CALLBACK(run_capture_action));
create_simple_action(app, "camera-switch", G_CALLBACK(run_camera_switch_action));
create_simple_action(app, "open-settings", G_CALLBACK(run_open_settings_action));
create_simple_action(app, "close-settings", G_CALLBACK(run_close_settings_action));
create_simple_action(app, "open-last", G_CALLBACK(run_open_last_action));
create_simple_action(app, "open-photos", G_CALLBACK(run_open_photos_action));
create_simple_action(app, "quit", G_CALLBACK(run_quit_action));

Loading…
Cancel
Save