[recipes] Add editor functionality to GrImageViewer
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [recipes] Add editor functionality to GrImageViewer
- Date: Sat, 17 Dec 2016 01:45:16 +0000 (UTC)
commit 138f5cee2b2f4be7bb443efafe299b9d9b6bc8d5
Author: Matthias Clasen <mclasen redhat com>
Date: Fri Dec 16 18:01:48 2016 -0500
Add editor functionality to GrImageViewer
We will end up close to where we started with GrImageEditor.
Just with a new name. This also adds new functionality to
the viewer, namely crossfades when switching images, and a
nice, rounded outline.
src/gr-image-viewer.c | 231 ++++++++++++++++++++++++++++++++++++++++++++---
src/gr-image-viewer.h | 11 ++-
src/gr-image-viewer.ui | 43 +++++++++-
3 files changed, 266 insertions(+), 19 deletions(-)
---
diff --git a/src/gr-image-viewer.c b/src/gr-image-viewer.c
index d08a216..cb4a372 100644
--- a/src/gr-image-viewer.c
+++ b/src/gr-image-viewer.c
@@ -20,6 +20,8 @@
#include "config.h"
+#include <glib/gi18n.h>
+
#include "gr-image-viewer.h"
#include "gr-image-editor.h"
#include "gr-utils.h"
@@ -30,7 +32,9 @@ struct _GrImageViewer
GtkEventBox parent_instance;
GtkWidget *overlay;
- GtkWidget *image;
+ GtkWidget *image1;
+ GtkWidget *image2;
+ GtkWidget *stack;
GtkWidget *event_box;
GtkWidget *next_revealer;
GtkWidget *prev_revealer;
@@ -48,6 +52,13 @@ struct _GrImageViewer
G_DEFINE_TYPE (GrImageViewer, gr_image_viewer, GTK_TYPE_BOX)
+enum {
+ PROP_0,
+ PROP_IMAGES,
+ N_PROPS
+};
+
+
GrImageViewer *
gr_image_viewer_new (void)
{
@@ -80,17 +91,33 @@ set_current_image (GrImageViewer *viewer)
{
GtkFlowBoxChild *child;
- if (!viewer->images)
+ if (viewer->index >= viewer->images->len) {
+ gtk_stack_set_visible_child_name (GTK_STACK (viewer->stack), "placeholder");
return;
+ }
if (viewer->images->len > viewer->index) {
- GrRotatedImage *ri = &g_array_index (viewer->images, GrRotatedImage, viewer->index);
- g_autoptr(GdkPixbuf) pb = load_pixbuf_fill_size (ri->path, ri->angle, 360, 240);
- gtk_image_set_from_pixbuf (GTK_IMAGE (viewer->image), pb);
+ GrRotatedImage *ri = NULL;
+ g_autoptr(GdkPixbuf) pixbuf = NULL;
+ const char *vis;
+
+ ri = &g_array_index (viewer->images, GrRotatedImage, viewer->index);
+ pixbuf = load_pixbuf_fill_size (ri->path, ri->angle, 360, 240);
+
+ vis = gtk_stack_get_visible_child_name (GTK_STACK (viewer->stack));
+ if (strcmp (vis, "image1") == 0) {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (viewer->image2), pixbuf);
+ gtk_stack_set_visible_child_name (GTK_STACK (viewer->stack), "image2");
+ }
+ else {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (viewer->image1), pixbuf);
+ gtk_stack_set_visible_child_name (GTK_STACK (viewer->stack), "image1");
+ }
}
child = gtk_flow_box_get_child_at_index (GTK_FLOW_BOX (viewer->preview_list), viewer->index);
- gtk_flow_box_select_child (GTK_FLOW_BOX (viewer->preview_list), child);
+ if (child)
+ gtk_flow_box_select_child (GTK_FLOW_BOX (viewer->preview_list), child);
}
static void
@@ -257,8 +284,10 @@ preview_selected (GrImageViewer *viewer)
child = l->data;
g_list_free (l);
- viewer->index = gtk_flow_box_child_get_index (child);
- set_current_image (viewer);
+ if (viewer->index != gtk_flow_box_child_get_index (child)) {
+ viewer->index = gtk_flow_box_child_get_index (child);
+ set_current_image (viewer);
+ }
}
static gboolean
@@ -303,6 +332,45 @@ gr_image_viewer_init (GrImageViewer *self)
self->gesture = gtk_gesture_multi_press_new (self->event_box);
gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (self->gesture), GTK_PHASE_BUBBLE);
g_signal_connect_swapped (self->gesture, "pressed", G_CALLBACK (button_press), self);
+ self->images = gr_rotated_image_array_new ();
+}
+
+static void
+gr_image_viewer_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GrImageViewer *self = GR_IMAGE_VIEWER (object);
+
+ switch (prop_id)
+ {
+ case PROP_IMAGES:
+ g_value_set_boxed (value, self->images);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+gr_image_viewer_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GrImageViewer *self = GR_IMAGE_VIEWER (object);
+
+ switch (prop_id)
+ {
+ case PROP_IMAGES:
+ gr_image_viewer_set_images (self, (GArray *) g_value_get_boxed (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
}
static void
@@ -310,11 +378,21 @@ gr_image_viewer_class_init (GrImageViewerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+ GParamSpec *pspec;
object_class->finalize = gr_image_viewer_finalize;
+ object_class->get_property = gr_image_viewer_get_property;
+ object_class->set_property = gr_image_viewer_set_property;
+
+ pspec = g_param_spec_boxed ("images", NULL, NULL,
+ G_TYPE_ARRAY,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_IMAGES, pspec);
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Recipes/gr-image-viewer.ui");
- gtk_widget_class_bind_template_child (widget_class, GrImageViewer, image);
+ gtk_widget_class_bind_template_child (widget_class, GrImageViewer, image1);
+ gtk_widget_class_bind_template_child (widget_class, GrImageViewer, image2);
+ gtk_widget_class_bind_template_child (widget_class, GrImageViewer, stack);
gtk_widget_class_bind_template_child (widget_class, GrImageViewer, event_box);
gtk_widget_class_bind_template_child (widget_class, GrImageViewer, overlay);
gtk_widget_class_bind_template_child (widget_class, GrImageViewer, prev_revealer);
@@ -326,18 +404,141 @@ gr_image_viewer_class_init (GrImageViewerClass *klass)
gtk_widget_class_bind_template_callback (widget_class, preview_selected);
}
+static void
+add_image (GrImageViewer *viewer,
+ GrRotatedImage *ri,
+ gboolean select)
+{
+ g_array_append_vals (viewer->images, ri, 1);
+ ri = &g_array_index (viewer->images, GrRotatedImage, viewer->images->len - 1);
+ ri->path = g_strdup (ri->path);
+
+ populate_preview (viewer);
+ if (select)
+ viewer->index = viewer->images->len - 1;
+ set_current_image (viewer);
+
+ g_object_notify (G_OBJECT (viewer), "images");
+}
+
void
gr_image_viewer_set_images (GrImageViewer *viewer,
GArray *images)
{
- if (viewer->images)
- g_array_unref (viewer->images);
- viewer->images = images;
- if (viewer->images)
- g_array_ref (viewer->images);
+ int i;
- populate_preview (viewer);
+ g_object_freeze_notify (G_OBJECT (viewer));
+ g_array_remove_range (viewer->images, 0, viewer->images->len);
+ g_object_notify (G_OBJECT (viewer), "images");
+
+ for (i = 0; i < images->len; i++) {
+ GrRotatedImage *ri = &g_array_index (images, GrRotatedImage, i);
+ add_image (viewer, ri, FALSE);
+ }
+
+ populate_preview (viewer);
viewer->index = 0;
set_current_image (viewer);
+
+ g_object_thaw_notify (G_OBJECT (viewer));
+}
+
+static void
+file_chooser_response (GtkNativeDialog *self,
+ gint response_id,
+ GrImageViewer *viewer)
+{
+ if (response_id == GTK_RESPONSE_ACCEPT) {
+ GrRotatedImage ri;
+ const char *dark;
+
+ ri.path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (self));
+ ri.angle = 0;
+
+ dark = gtk_file_chooser_get_choice (GTK_FILE_CHOOSER (self), "dark");
+
+ ri.dark_text = g_strcmp0 (dark, "true") == 0;
+
+ add_image (viewer, &ri, TRUE);
+
+ g_free (ri.path);
+
+ show_controls (viewer);
+ }
+}
+
+static void
+open_filechooser (GrImageViewer *viewer)
+{
+ GtkWidget *window;
+ GtkFileChooserNative *chooser;
+ g_autoptr(GtkFileFilter) filter = NULL;
+
+ window = gtk_widget_get_ancestor (GTK_WIDGET (viewer), GTK_TYPE_APPLICATION_WINDOW);
+ chooser = gtk_file_chooser_native_new (_("Select an Image"),
+ GTK_WINDOW (window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ _("Open"),
+ _("Cancel"));
+ gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (chooser), TRUE);
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_set_name (filter, _("Image files"));
+ gtk_file_filter_add_mime_type (filter, "image/*");
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (chooser), filter);
+ gtk_file_chooser_add_choice (GTK_FILE_CHOOSER (chooser), "dark", _("Use dark text"), NULL, NULL);
+
+ g_signal_connect (chooser, "response", G_CALLBACK (file_chooser_response), viewer);
+
+ gtk_native_dialog_show (GTK_NATIVE_DIALOG (chooser));
+}
+
+void
+gr_image_viewer_add_image (GrImageViewer *viewer)
+{
+ open_filechooser (viewer);
+}
+
+void
+gr_image_viewer_remove_image (GrImageViewer *viewer)
+{
+ g_array_remove_index (viewer->images, viewer->index);
+
+ if (viewer->index < viewer->images->len) {
+ populate_preview (viewer);
+ set_current_image (viewer);
+ }
+ else if (viewer->index > 0) {
+ viewer->index -= 1;
+ populate_preview (viewer);
+ set_current_image (viewer);
+ }
+
+ if (viewer->images->len == 0) {
+ gtk_stack_set_visible_child_name (GTK_STACK (viewer->stack), "placeholder");
+ hide_controls (viewer);
+ }
+ else
+ show_controls (viewer);
+
+ g_object_notify (G_OBJECT (viewer), "images");
+}
+
+void
+gr_image_viewer_rotate_image (GrImageViewer *viewer,
+ int angle)
+{
+ GrRotatedImage *ri;
+
+ g_assert (angle == 0 || angle == 90 || angle == 180 || angle == 270);
+
+ ri = &g_array_index (viewer->images, GrRotatedImage, viewer->index);
+ ri->angle = (ri->angle + angle) % 360;
+
+ populate_preview (viewer);
+ set_current_image (viewer);
+
+ g_object_notify (G_OBJECT (viewer), "images");
}
diff --git a/src/gr-image-viewer.h b/src/gr-image-viewer.h
index 21f40f0..5ed2b80 100644
--- a/src/gr-image-viewer.h
+++ b/src/gr-image-viewer.h
@@ -28,9 +28,14 @@ G_BEGIN_DECLS
G_DECLARE_FINAL_TYPE (GrImageViewer, gr_image_viewer, GR, IMAGE_VIEWER, GtkBox)
-GrImageViewer *gr_image_viewer_new (void);
-void gr_image_viewer_set_images (GrImageViewer *viewer,
- GArray *images);
+GrImageViewer *gr_image_viewer_new (void);
+void gr_image_viewer_set_images (GrImageViewer *viewer,
+ GArray *images);
+
+void gr_image_viewer_add_image (GrImageViewer *viewer);
+void gr_image_viewer_remove_image (GrImageViewer *viewer);
+void gr_image_viewer_rotate_image (GrImageViewer *viewer,
+ int angle);
G_END_DECLS
diff --git a/src/gr-image-viewer.ui b/src/gr-image-viewer.ui
index 60eaafc..c4c2a7e 100644
--- a/src/gr-image-viewer.ui
+++ b/src/gr-image-viewer.ui
@@ -90,8 +90,49 @@
<property name="above-child">1</property>
<property name="can-focus">1</property>
<child>
- <object class="GtkImage" id="image">
+ <object class="GtkStack" id="stack">
<property name="visible">1</property>
+ <property name="transition-type">crossfade</property>
+ <property name="transition-duration">500</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">1</property>
+ <property name="width-request">360</property>
+ <property name="height-request">240</property>
+ <property name="icon-name">camera-photo-symbolic</property>
+ <property name="pixel-size">96</property>
+ <style>
+ <class name="dim-label"/>
+ <class name="framed"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">placeholder</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image1">
+ <property name="visible">1</property>
+ <style>
+ <class name="framed"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">image1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="image2">
+ <property name="visible">1</property>
+ <style>
+ <class name="framed"/>
+ </style>
+ </object>
+ <packing>
+ <property name="name">image2</property>
+ </packing>
+ </child>
+ <property name="visible-child-name">placeholder</property>
</object>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]