[gthumb] curves: added presets
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] curves: added presets
- Date: Sun, 25 Jan 2015 12:05:52 +0000 (UTC)
commit d61c706af154bd8fe81d5dc06436441d66d9d67a
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Jan 7 12:52:07 2015 +0100
curves: added presets
data/icons/hicolor/16x16/actions/Makefile.am | 1 +
.../hicolor/16x16/actions/presets-symbolic.svg | 124 +++++
.../file_tools/data/ui/curve-preset-editor.ui | 93 ++++
extensions/file_tools/data/ui/curves-options.ui | 92 ++--
extensions/file_tools/gth-curve-editor.h | 2 +-
.../file_tools/gth-curve-preset-editor-dialog.c | 274 +++++++++++
.../file_tools/gth-curve-preset-editor-dialog.h | 56 +++
extensions/file_tools/gth-curve-preset.c | 487 ++++++++++++++++++++
extensions/file_tools/gth-curve-preset.h | 92 ++++
extensions/file_tools/gth-file-tool-curves.c | 396 +++++++++++++++-
extensions/file_tools/gth-points.c | 58 +++
extensions/file_tools/gth-points.h | 13 +
gthumb/gth-browser.c | 13 +-
gthumb/gth-browser.h | 2 +
gthumb/gth-filter-grid.c | 95 ++++
gthumb/gth-filter-grid.h | 7 +
gthumb/gth-marshal.list | 1 +
gthumb/gth-toolbox.c | 1 -
gthumb/gthumb.gresource.xml | 1 +
gthumb/gtk-utils.c | 73 +++
gthumb/gtk-utils.h | 8 +
gthumb/resources/Makefile.am | 3 +-
gthumb/resources/gthumb.css | 8 +
gthumb/resources/request-dialog.ui | 92 ++++
24 files changed, 1918 insertions(+), 74 deletions(-)
---
diff --git a/data/icons/hicolor/16x16/actions/Makefile.am b/data/icons/hicolor/16x16/actions/Makefile.am
index 979a236..197e4e7 100644
--- a/data/icons/hicolor/16x16/actions/Makefile.am
+++ b/data/icons/hicolor/16x16/actions/Makefile.am
@@ -40,6 +40,7 @@ icons_DATA = \
image-sharpen-symbolic.svg \
map-symbolic.svg \
palette-symbolic.svg \
+ presets-symbolic.svg \
site-facebook.png \
site-flickr.png \
site-photobucket.png \
diff --git a/data/icons/hicolor/16x16/actions/presets-symbolic.svg
b/data/icons/hicolor/16x16/actions/presets-symbolic.svg
new file mode 100644
index 0000000..8a3cc74
--- /dev/null
+++ b/data/icons/hicolor/16x16/actions/presets-symbolic.svg
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<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"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="16"
+ height="16"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91+devel r13821 custom"
+ sodipodi:docname="presets-symbolic.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient3946">
+ <stop
+ id="stop3948"
+ offset="0"
+ style="stop-color:#000000;stop-opacity:0.74698794;" />
+ <stop
+ id="stop3950"
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0.02409638;" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3830-9">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.74698794;"
+ offset="0"
+ id="stop3832-7" />
+ <stop
+ style="stop-color:#000000;stop-opacity:0.02409638;"
+ offset="1"
+ id="stop3834-5" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3984">
+ <stop
+ style="stop-color:#f4deba;stop-opacity:1;"
+ offset="0"
+ id="stop3986" />
+ <stop
+ style="stop-color:#de9625;stop-opacity:0;"
+ offset="1"
+ id="stop3988" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#555753"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1"
+ inkscape:pageshadow="2"
+ inkscape:zoom="26.927936"
+ inkscape:cx="3.0134443"
+ inkscape:cy="9.7536827"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:snap-grids="false"
+ inkscape:window-width="1680"
+ inkscape:window-height="984"
+ inkscape:window-x="0"
+ inkscape:window-y="27"
+ inkscape:window-maximized="1"
+ showborder="true"
+ fit-margin-top="0"
+ fit-margin-right="0"
+ fit-margin-left="0"
+ fit-margin-bottom="0"
+ showguides="true"
+ inkscape:guide-bbox="true">
+ <inkscape:grid
+ type="xygrid"
+ id="grid7044"
+ empspacing="8"
+ visible="true"
+ enabled="true"
+ snapvisiblegridlinesonly="true"
+ originx="-31.97559px"
+ originy="-816.00002px" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <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>
+ <g
+ inkscape:label="Livello 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-31.97559,-220.36218)">
+ <path
+
style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m 33.991817,221.40082 5.013383,0 0,5.9984 -5.013383,0 z"
+ id="rect4153" />
+ <path
+
style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m 41.047688,221.36369 5.013382,0 0,5.99841 -5.013382,0 z"
+ id="rect4155" />
+ <path
+
style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m 41.047688,229.34796 5.013382,0 0,5.99841 -5.013382,0 z"
+ id="rect4157" />
+ <path
+
style="opacity:1;fill:#bebebe;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ d="m 33.954681,229.34796 5.013383,0 0,5.99841 -5.013383,0 z"
+ id="rect4159" />
+ </g>
+</svg>
diff --git a/extensions/file_tools/data/ui/curve-preset-editor.ui
b/extensions/file_tools/data/ui/curve-preset-editor.ui
new file mode 100644
index 0000000..2510d37
--- /dev/null
+++ b/extensions/file_tools/data/ui/curve-preset-editor.ui
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+ <requires lib="gtk+" version="3.12"/>
+ <object class="GtkListStore" id="preset_liststore">
+ <columns>
+ <!-- column-name id -->
+ <column type="gint"/>
+ <!-- column-name name -->
+ <column type="gchararray"/>
+ <!-- column-name icon-name -->
+ <column type="gchararray"/>
+ </columns>
+ </object>
+ <object class="GtkBox" id="curve_preset_editor">
+ <property name="width_request">300</property>
+ <property name="height_request">300</property>
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="shadow_type">in</property>
+ <child>
+ <object class="GtkTreeView" id="preset_treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="model">preset_liststore</property>
+ <property name="headers_visible">False</property>
+ <property name="reorderable">True</property>
+ <child internal-child="selection">
+ <object class="GtkTreeSelection" id="treeview-selection1"/>
+ </child>
+ <child>
+ <object class="GtkTreeViewColumn" id="treeviewcolumn1">
+ <child>
+ <object class="GtkCellRendererPixbuf" id="cellrendererpixbuf1">
+ <property name="xpad">5</property>
+ </object>
+ <attributes>
+ <attribute name="icon-name">2</attribute>
+ </attributes>
+ </child>
+ <child>
+ <object class="GtkCellRendererText" id="preset_name_cellrenderertext">
+ <property name="editable">True</property>
+ </object>
+ <attributes>
+ <attribute name="text">1</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkToolbar" id="toolbar1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_size">2</property>
+ <child>
+ <object class="GtkToolButton" id="delete_toolbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="use_underline">True</property>
+ <property name="icon_name">list-remove-symbolic</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="homogeneous">True</property>
+ </packing>
+ </child>
+ <style>
+ <class name="inline-toolbar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/extensions/file_tools/data/ui/curves-options.ui b/extensions/file_tools/data/ui/curves-options.ui
index 8afd626..2e7e750 100644
--- a/extensions/file_tools/data/ui/curves-options.ui
+++ b/extensions/file_tools/data/ui/curves-options.ui
@@ -2,61 +2,26 @@
<!-- Generated with glade 3.18.3 -->
<interface>
<requires lib="gtk+" version="3.12"/>
- <object class="GtkAlignment" id="options">
+ <object class="GtkBox" id="options">
<property name="visible">True</property>
<property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
<child>
- <object class="GtkBox" id="box1">
+ <object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">12</property>
<property name="orientation">vertical</property>
+ <property name="spacing">10</property>
<child>
- <object class="GtkAlignment" id="alignment1">
+ <object class="GtkBox" id="curves_box">
+ <property name="height_request">350</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="bottom_padding">12</property>
+ <property name="orientation">vertical</property>
<child>
- <object class="GtkBox" id="box2">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="spacing">10</property>
- <child>
- <object class="GtkBox" id="curves_box">
- <property name="height_request">350</property>
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <child>
- <placeholder/>
- </child>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">0</property>
- </packing>
- </child>
- <child>
- <object class="GtkCheckButton" id="preview_checkbutton">
- <property name="label" translatable="yes">_Preview</property>
- <property name="use_action_appearance">False</property>
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="receives_default">False</property>
- <property name="use_underline">True</property>
- <property name="xalign">0</property>
- <property name="active">True</property>
- <property name="draw_indicator">True</property>
- </object>
- <packing>
- <property name="expand">False</property>
- <property name="fill">True</property>
- <property name="position">2</property>
- </packing>
- </child>
- </object>
+ <placeholder/>
</child>
</object>
<packing>
@@ -65,7 +30,46 @@
<property name="position">0</property>
</packing>
</child>
+ <child>
+ <object class="GtkCheckButton" id="preview_checkbutton">
+ <property name="label" translatable="yes">_Preview</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkCheckButton" id="preview_channel_checkbutton">
+ <property name="label" translatable="yes">Include current channel</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="xalign">0</property>
+ <property name="active">True</property>
+ <property name="draw_indicator">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
</object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
</child>
</object>
</interface>
diff --git a/extensions/file_tools/gth-curve-editor.h b/extensions/file_tools/gth-curve-editor.h
index 7324f54..d8ae459 100644
--- a/extensions/file_tools/gth-curve-editor.h
+++ b/extensions/file_tools/gth-curve-editor.h
@@ -50,7 +50,7 @@ struct _GthCurveEditorClass {
/*< signals >*/
- void (*changed) (GthCurveEditor *self);
+ void (*changed) (GthCurveEditor *self);
};
GType gth_curve_editor_get_type (void);
diff --git a/extensions/file_tools/gth-curve-preset-editor-dialog.c
b/extensions/file_tools/gth-curve-preset-editor-dialog.c
new file mode 100644
index 0000000..f706163
--- /dev/null
+++ b/extensions/file_tools/gth-curve-preset-editor-dialog.c
@@ -0,0 +1,274 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2008-2014 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "gth-curve-preset-editor-dialog.h"
+
+
+#define ORDER_CHANGED_DELAY 250
+
+
+enum {
+ COLUMN_ID,
+ COLUMN_NAME,
+ COLUMN_ICON_NAME
+};
+
+
+#define GET_WIDGET(name) _gtk_builder_get_widget (self->priv->builder, (name))
+
+
+struct _GthCurvePresetEditorDialogPrivate {
+ GtkBuilder *builder;
+ GthCurvePreset *preset;
+ guint changed_id;
+};
+
+
+G_DEFINE_TYPE (GthCurvePresetEditorDialog, gth_curve_preset_editor_dialog, GTK_TYPE_DIALOG)
+
+
+static void
+gth_curve_preset_editor_dialog_finalize (GObject *object)
+{
+ GthCurvePresetEditorDialog *self;
+
+ self = GTH_CURVE_PRESET_EDITOR_DIALOG (object);
+
+ if (self->priv->changed_id != 0)
+ g_source_remove (self->priv->changed_id);
+ g_object_unref (self->priv->builder);
+ g_object_unref (self->priv->preset);
+
+ G_OBJECT_CLASS (gth_curve_preset_editor_dialog_parent_class)->finalize (object);
+}
+
+
+static void
+gth_curve_preset_editor_dialog_class_init (GthCurvePresetEditorDialogClass *klass)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (klass, sizeof (GthCurvePresetEditorDialogPrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = gth_curve_preset_editor_dialog_finalize;
+}
+
+
+static void
+gth_curve_preset_editor_dialog_init (GthCurvePresetEditorDialog *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG,
GthCurvePresetEditorDialogPrivate);
+ self->priv->changed_id = 0;
+}
+
+
+static void
+preset_name_edited_cb (GtkCellRendererText *renderer,
+ gchar *path,
+ gchar *new_text,
+ gpointer user_data)
+{
+ GthCurvePresetEditorDialog *self = user_data;
+ GtkListStore *list_store;
+ GtkTreePath *tree_path;
+ GtkTreeIter iter;
+ int id;
+
+ list_store = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "preset_liststore");
+ tree_path = gtk_tree_path_new_from_string (path);
+ if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (list_store),
+ &iter,
+ tree_path))
+ {
+ gtk_tree_path_free (tree_path);
+ return;
+ }
+ gtk_tree_path_free (tree_path);
+
+ gtk_tree_model_get (GTK_TREE_MODEL (list_store), &iter, COLUMN_ID, &id, -1);
+ gtk_list_store_set (list_store, &iter, COLUMN_NAME, new_text, -1);
+ gth_curve_preset_rename (self->priv->preset, id, new_text);
+}
+
+
+static void
+delete_toolbutton_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GthCurvePresetEditorDialog *self = user_data;
+ GtkWidget *tree_view;
+ GtkTreeSelection *tree_selection;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+ int id;
+
+ tree_view = (GtkWidget *) gtk_builder_get_object (self->priv->builder, "preset_treeview");
+ tree_selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+
+ if (! gtk_tree_selection_get_selected (tree_selection, &tree_model, &iter))
+ return;
+
+ gtk_tree_model_get (tree_model, &iter, COLUMN_ID, &id, -1);
+ gtk_list_store_remove (GTK_LIST_STORE (tree_model), &iter);
+ gth_curve_preset_remove (self->priv->preset, id);
+}
+
+
+static gboolean
+order_changed (gpointer user_data)
+{
+ GthCurvePresetEditorDialog *self = user_data;
+ GList *id_list;
+ GtkTreeModel *tree_model;
+ GtkTreeIter iter;
+
+ if (self->priv->changed_id != 0)
+ g_source_remove (self->priv->changed_id);
+ self->priv->changed_id = 0;
+
+ id_list = NULL;
+ tree_model = (GtkTreeModel *) gtk_builder_get_object (self->priv->builder, "preset_liststore");
+ if (gtk_tree_model_get_iter_first (tree_model, &iter)) {
+ do {
+ int id;
+ gtk_tree_model_get (tree_model, &iter, COLUMN_ID, &id, -1);
+ id_list = g_list_prepend (id_list, GINT_TO_POINTER (id));
+ }
+ while (gtk_tree_model_iter_next (tree_model, &iter));
+ }
+ id_list = g_list_reverse (id_list);
+ gth_curve_preset_change_order (self->priv->preset, id_list);
+
+ g_list_free (id_list);
+
+ return FALSE;
+}
+
+
+static void
+row_deleted_cb (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ gpointer user_data)
+{
+ GthCurvePresetEditorDialog *self = user_data;
+
+ if (self->priv->changed_id != 0)
+ g_source_remove (self->priv->changed_id);
+ self->priv->changed_id = gdk_threads_add_timeout (ORDER_CHANGED_DELAY, order_changed, self);
+}
+
+
+static void
+row_inserted_cb (GtkTreeModel *tree_model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer user_data)
+{
+ GthCurvePresetEditorDialog *self = user_data;
+
+ if (self->priv->changed_id != 0)
+ g_source_remove (self->priv->changed_id);
+ self->priv->changed_id = gdk_threads_add_timeout (ORDER_CHANGED_DELAY, order_changed, self);
+}
+
+
+static void
+gth_curve_preset_editor_dialog_construct (GthCurvePresetEditorDialog *self,
+ GtkWindow *parent,
+ GthCurvePreset *preset)
+{
+ GtkWidget *button;
+ GtkWidget *content;
+ GtkListStore *list_store;
+ int n, i;
+ GtkTreeIter iter;
+
+ gtk_window_set_title (GTK_WINDOW (self), _("Presets"));
+ if (parent != NULL)
+ gtk_window_set_transient_for (GTK_WINDOW (self), parent);
+ gtk_window_set_resizable (GTK_WINDOW (self), TRUE);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), 8);
+ gtk_container_set_border_width (GTK_CONTAINER (self), 5);
+ button = gtk_dialog_add_button (GTK_DIALOG (self), _GTK_LABEL_CLOSE, GTK_RESPONSE_CLOSE);
+ g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), self);
+
+ self->priv->builder = _gtk_builder_new_from_file ("curve-preset-editor.ui", "file_tools");
+
+ content = _gtk_builder_get_widget (self->priv->builder, "curve_preset_editor");
+ gtk_container_set_border_width (GTK_CONTAINER (content), 0);
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (self))), content, TRUE, TRUE,
0);
+
+ g_signal_connect (gtk_builder_get_object (self->priv->builder, "preset_name_cellrenderertext"),
+ "edited",
+ G_CALLBACK (preset_name_edited_cb),
+ self);
+
+ self->priv->preset = g_object_ref (preset);
+
+ list_store = (GtkListStore *) gtk_builder_get_object (self->priv->builder, "preset_liststore");
+ n = gth_curve_preset_get_size (self->priv->preset);
+ for (i = 0; i < n; i++) {
+ const char *name;
+ int id;
+
+ gth_curve_preset_get_nth (self->priv->preset, i, &id, &name, NULL);
+ gtk_list_store_append (list_store, &iter);
+ gtk_list_store_set (list_store, &iter,
+ COLUMN_ID, id,
+ COLUMN_NAME, name,
+ COLUMN_ICON_NAME, "curves-symbolic",
+ -1);
+ }
+
+ g_signal_connect (list_store,
+ "row-deleted",
+ G_CALLBACK (row_deleted_cb),
+ self);
+ g_signal_connect (list_store,
+ "row-inserted",
+ G_CALLBACK (row_inserted_cb),
+ self);
+
+ g_signal_connect (gtk_builder_get_object (self->priv->builder, "delete_toolbutton"),
+ "clicked",
+ G_CALLBACK (delete_toolbutton_clicked_cb),
+ self);
+}
+
+
+GtkWidget *
+gth_curve_preset_editor_dialog_new (GtkWindow *parent,
+ GthCurvePreset *preset)
+{
+ GthCurvePresetEditorDialog *self;
+
+ g_return_val_if_fail (preset != NULL, NULL);
+
+ self = g_object_new (GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG, NULL);
+ gth_curve_preset_editor_dialog_construct (self, parent, preset);
+
+ return (GtkWidget *) self;
+}
diff --git a/extensions/file_tools/gth-curve-preset-editor-dialog.h
b/extensions/file_tools/gth-curve-preset-editor-dialog.h
new file mode 100644
index 0000000..c909747
--- /dev/null
+++ b/extensions/file_tools/gth-curve-preset-editor-dialog.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_CURVE_PRESET_EDITOR_DIALOG_H
+#define GTH_CURVE_PRESET_EDITOR_DIALOG_H
+
+#include <gtk/gtk.h>
+#include "gth-curve-preset.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG (gth_curve_preset_editor_dialog_get_type ())
+#define GTH_CURVE_PRESET_EDITOR_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG, GthCurvePresetEditorDialog))
+#define GTH_CURVE_PRESET_EDITOR_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG, GthCurvePresetEditorDialogClass))
+#define GTH_IS_CURVE_PRESET_EDITOR_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG))
+#define GTH_IS_CURVE_PRESET_EDITOR_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG))
+#define GTH_CURVE_PRESET_EDITOR_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
GTH_TYPE_CURVE_PRESET_EDITOR_DIALOG, GthCurvePresetEditorDialogClass))
+
+typedef struct _GthCurvePresetEditorDialog GthCurvePresetEditorDialog;
+typedef struct _GthCurvePresetEditorDialogClass GthCurvePresetEditorDialogClass;
+typedef struct _GthCurvePresetEditorDialogPrivate GthCurvePresetEditorDialogPrivate;
+
+struct _GthCurvePresetEditorDialog {
+ GtkDialog parent_instance;
+ GthCurvePresetEditorDialogPrivate *priv;
+};
+
+struct _GthCurvePresetEditorDialogClass {
+ GtkDialogClass parent_class;
+};
+
+GType gth_curve_preset_editor_dialog_get_type (void);
+GtkWidget * gth_curve_preset_editor_dialog_new (GtkWindow *parent,
+ GthCurvePreset *preset);
+
+G_END_DECLS
+
+#endif /* GTH_CURVE_PRESET_EDITOR_DIALOG_H */
diff --git a/extensions/file_tools/gth-curve-preset.c b/extensions/file_tools/gth-curve-preset.c
new file mode 100644
index 0000000..18c2058
--- /dev/null
+++ b/extensions/file_tools/gth-curve-preset.c
@@ -0,0 +1,487 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include "enum-types.h"
+#include "gth-curve-preset.h"
+
+
+/* Signals */
+enum {
+ CHANGED,
+ PRESET_CHANGED,
+ LAST_SIGNAL
+};
+
+
+typedef struct {
+ GthPoints points[GTH_HISTOGRAM_N_CHANNELS];
+ int id;
+ char *name;
+} Preset;
+
+
+struct _GthCurvePresetPrivate {
+ GFile *file;
+ GList *set;
+ int next_id;
+};
+
+
+static guint gth_curve_preset_signals[LAST_SIGNAL] = { 0 };
+
+
+G_DEFINE_TYPE (GthCurvePreset, gth_curve_preset, G_TYPE_OBJECT)
+
+
+static char * Channel_Names[GTH_HISTOGRAM_N_CHANNELS] = { "value", "red", "green", "blue", "alpha" };
+
+
+static int
+get_channel_number (const char *name)
+{
+ int i;
+
+ for (i = 0; i < GTH_HISTOGRAM_N_CHANNELS; i++)
+ if (g_strcmp0 (Channel_Names[i], name) == 0)
+ return i;
+
+ return -1;
+}
+
+
+static Preset *
+preset_new (int id)
+{
+ Preset *preset;
+ int c;
+
+ preset = g_new (Preset, 1);
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ gth_points_init (&preset->points[c], 0);
+ preset->id = id;
+ preset->name = NULL;
+
+ return preset;
+}
+
+
+static DomElement *
+preset_create_element (Preset *preset,
+ DomDocument *doc)
+{
+ DomElement *element;
+ int c;
+
+ element = dom_document_create_element (doc, "preset", "name", preset->name, NULL);
+
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++) {
+ DomElement *channel;
+ int i;
+
+ channel = dom_document_create_element (doc, "channel", "type", Channel_Names[c], NULL);
+ for (i = 0; i < preset->points[c].n; i++) {
+ GthPoint *p = preset->points[c].p + i;
+ char *x;
+ char *y;
+
+ x = g_strdup_printf ("%d", (int) p->x);
+ y = g_strdup_printf ("%d", (int) p->y);
+ dom_element_append_child (channel, dom_document_create_element (doc, "point", "x", x,
"y", y, NULL));
+
+ g_free (x);
+ g_free (y);
+ }
+ dom_element_append_child (element, channel);
+ }
+
+ return element;
+}
+
+
+static void
+preset_load_from_element (Preset *preset,
+ DomElement *element)
+{
+ int c;
+ DomElement *node;
+
+ g_return_if_fail (element != NULL);
+ g_return_if_fail (g_strcmp0 (element->tag_name, "preset") == 0);
+
+ g_free (preset->name);
+ preset->name = g_strdup (dom_element_get_attribute (element, "name"));
+
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ gth_points_dispose (&preset->points[c]);
+
+ for (node = element->first_child; node; node = node->next_sibling) {
+ if (g_strcmp0 (node->tag_name, "channel") == 0) {
+ int n_channel;
+
+ n_channel = get_channel_number (dom_element_get_attribute (node, "type"));
+ if (n_channel > -1) {
+ DomElement *point;
+
+ for (point = node->first_child; point; point = point->next_sibling) {
+ if (g_strcmp0 (point->tag_name, "point") == 0) {
+ const char *sx, *sy;
+ int x, y;
+
+ sx = dom_element_get_attribute (point, "x");
+ sy = dom_element_get_attribute (point, "y");
+
+ if (sscanf (sx, "%d", &x) != 1)
+ continue;
+ if (sscanf (sy, "%d", &y) != 1)
+ continue;
+
+ gth_points_add_point (&preset->points[n_channel], x, y);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+static void
+preset_free (Preset *preset)
+{
+ int c;
+
+ g_return_if_fail (preset != NULL);
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ gth_points_dispose (&preset->points[c]);
+ g_free (preset->name);
+ g_free (preset);
+}
+
+
+static void
+gth_curve_preset_finalize (GObject *obj)
+{
+ GthCurvePreset *self;
+
+ self = GTH_CURVE_PRESET (obj);
+ g_list_free_full (self->priv->set, (GDestroyNotify) preset_free);
+ _g_object_unref (self->priv->file);
+
+ G_OBJECT_CLASS (gth_curve_preset_parent_class)->finalize (obj);
+}
+
+
+static void
+gth_curve_preset_class_init (GthCurvePresetClass *klass)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (klass, sizeof (GthCurvePresetPrivate));
+
+ object_class = (GObjectClass*) klass;
+ object_class->finalize = gth_curve_preset_finalize;
+
+ /* signals */
+
+ gth_curve_preset_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GthCurvePresetClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+ gth_curve_preset_signals[PRESET_CHANGED] =
+ g_signal_new ("preset-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GthCurvePresetClass, preset_changed),
+ NULL, NULL,
+ gth_marshal_VOID__ENUM_INT,
+ G_TYPE_NONE,
+ 2,
+ GTH_TYPE_PRESET_ACTION,
+ G_TYPE_INT);
+}
+
+
+static void
+gth_curve_preset_changed (GthCurvePreset *self)
+{
+ g_signal_emit (self, gth_curve_preset_signals[CHANGED], 0);
+}
+
+
+static void
+gth_curve_preset_init (GthCurvePreset *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GTH_TYPE_CURVE_PRESET, GthCurvePresetPrivate);
+ self->priv->set = NULL;
+ self->priv->file = NULL;
+ self->priv->next_id = 0;
+}
+
+
+GthCurvePreset *
+gth_curve_preset_new_from_file (GFile *file)
+{
+ GthCurvePreset *self;
+ DomDocument *doc;
+ void *buffer;
+ gsize size;
+
+ self = (GthCurvePreset *) g_object_new (GTH_TYPE_CURVE_PRESET, NULL);
+ self->priv->file = g_file_dup (file);
+
+ doc = dom_document_new ();
+ if (_g_file_load_in_buffer (self->priv->file, &buffer, &size, NULL, NULL)) {
+ if (dom_document_load (doc, buffer, size, NULL)) {
+ DomElement *presets = DOM_ELEMENT (doc)->first_child;
+
+ if ((presets != NULL) && (g_strcmp0 (presets->tag_name, "presets") == 0)) {
+ DomElement *node;
+
+ for (node = presets->first_child; node; node = node->next_sibling) {
+ if (g_strcmp0 (node->tag_name, "preset") == 0) {
+ Preset *preset;
+
+ preset = preset_new (self->priv->next_id++);
+ preset_load_from_element (preset, node);
+ self->priv->set = g_list_append (self->priv->set, preset);
+ }
+ }
+ }
+ }
+ g_free (buffer);
+ }
+
+ g_object_unref (doc);
+
+ return self;
+}
+
+
+int
+gth_curve_preset_get_size (GthCurvePreset *self)
+{
+ return g_list_length (self->priv->set);
+}
+
+
+gboolean
+gth_curve_preset_get_nth (GthCurvePreset *self,
+ int n,
+ int *id,
+ const char **name,
+ GthPoints **points)
+{
+ Preset *preset;
+
+ preset = g_list_nth_data (self->priv->set, n);
+ if (preset == NULL)
+ return FALSE;
+
+ if (id) *id = preset->id;
+ if (name) *name = preset->name;
+ if (points) *points = preset->points;
+
+ return TRUE;
+}
+
+
+gboolean
+gth_curve_preset_get_by_id (GthCurvePreset *self,
+ int id,
+ const char **name,
+ GthPoints **points)
+{
+ GList *scan;
+
+ for (scan = self->priv->set; scan; scan = scan->next) {
+ Preset *preset = scan->data;
+
+ if (preset->id == id) {
+ if (name) *name = preset->name;
+ if (points) *points = preset->points;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+int
+gth_curve_preset_get_pos (GthCurvePreset *self,
+ int id)
+{
+ GList *scan;
+ int pos;
+
+ for (pos = 0, scan = self->priv->set; scan; scan = scan->next, pos++) {
+ Preset *preset = scan->data;
+
+ if (preset->id == id)
+ return pos;
+ }
+
+ return -1;
+}
+
+
+int
+gth_curve_preset_add (GthCurvePreset *self,
+ const char *name,
+ GthPoints *points)
+{
+ Preset *preset;
+ int c;
+
+ preset = preset_new (self->priv->next_id++);
+ preset->name = g_strdup (name);
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ gth_points_copy (points + c, &preset->points[c]);
+ self->priv->set = g_list_append (self->priv->set, preset);
+ gth_curve_preset_changed (self);
+ g_signal_emit (self, gth_curve_preset_signals[PRESET_CHANGED], 0, GTH_PRESET_ACTION_ADDED,
preset->id);
+
+ return preset->id;
+}
+
+
+static int
+compare_preset_by_id (Preset *a,
+ gpointer id_p)
+{
+ int id = GPOINTER_TO_INT (id_p);
+ return (a->id == id) ? 0 : (a->id > id) ? 1 : -1;
+}
+
+
+void
+gth_curve_preset_remove (GthCurvePreset *self,
+ int id)
+{
+ GList *link;
+
+ link = g_list_find_custom (self->priv->set, GINT_TO_POINTER (id), (GCompareFunc)
compare_preset_by_id);
+ if (link == NULL)
+ return;
+
+ self->priv->set = g_list_remove_link (self->priv->set, link);
+ gth_curve_preset_changed (self);
+ g_signal_emit (self, gth_curve_preset_signals[PRESET_CHANGED], 0, GTH_PRESET_ACTION_REMOVED, id);
+
+ g_list_free_full (link, (GDestroyNotify) preset_free);
+}
+
+
+void
+gth_curve_preset_rename (GthCurvePreset *self,
+ int id,
+ const char *new_name)
+{
+ GList *link;
+ Preset *preset;
+
+ link = g_list_find_custom (self->priv->set, GINT_TO_POINTER (id), (GCompareFunc)
compare_preset_by_id);
+ g_return_if_fail (link != NULL);
+
+ preset = link->data;
+ g_free (preset->name);
+ preset->name = g_strdup (new_name);
+
+ gth_curve_preset_changed (self);
+ g_signal_emit (self, gth_curve_preset_signals[PRESET_CHANGED], 0, GTH_PRESET_ACTION_RENAMED, id);
+}
+
+
+void
+gth_curve_preset_change_order (GthCurvePreset *self,
+ GList *id_list)
+{
+ GList *set, *scan;
+
+ set = NULL;
+ for (scan = id_list; scan; scan = scan->next) {
+ int id = GPOINTER_TO_INT (scan->data);
+ GList *link;
+
+ link = g_list_find_custom (self->priv->set, GINT_TO_POINTER (id), (GCompareFunc)
compare_preset_by_id);
+ g_return_if_fail (link != NULL);
+
+ set = g_list_prepend (set, link->data);
+ }
+ set = g_list_reverse (set);
+
+ g_list_free (self->priv->set);
+ self->priv->set = set;
+
+ gth_curve_preset_changed (self);
+ g_signal_emit (self, gth_curve_preset_signals[PRESET_CHANGED], 0, GTH_PRESET_ACTION_CHANGED_ORDER,
-1);
+}
+
+
+GList *
+gth_curve_preset_get_order (GthCurvePreset *self)
+{
+ GList *id_list, *scan;
+
+ id_list = NULL;
+ for (scan = self->priv->set; scan; scan = scan->next) {
+ Preset *preset = scan->data;
+ id_list = g_list_prepend (id_list, GINT_TO_POINTER (preset->id));
+ }
+
+ return g_list_reverse (id_list);
+}
+
+
+gboolean
+gth_curve_preset_save (GthCurvePreset *self,
+ GError **error)
+{
+ DomDocument *doc;
+ DomElement *curves;
+ GList *scan;
+ char *buffer;
+ gsize size;
+ gboolean result;
+
+ g_return_val_if_fail (self->priv->file != NULL, FALSE);
+
+ doc = dom_document_new ();
+ curves = dom_document_create_element (doc, "presets", NULL);
+ for (scan = self->priv->set; scan; scan = scan->next) {
+ Preset *preset = scan->data;
+ dom_element_append_child (curves, preset_create_element (preset, doc));
+ }
+ dom_element_append_child (DOM_ELEMENT (doc), curves);
+
+ buffer = dom_document_dump (doc, &size);
+ result = _g_file_write (self->priv->file, FALSE, G_FILE_CREATE_NONE, buffer, size, NULL, error);
+
+ g_free (buffer);
+ g_object_unref (doc);
+
+ return result;
+}
diff --git a/extensions/file_tools/gth-curve-preset.h b/extensions/file_tools/gth-curve-preset.h
new file mode 100644
index 0000000..75a4222
--- /dev/null
+++ b/extensions/file_tools/gth-curve-preset.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2014 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_CURVE_PRESET_H
+#define GTH_CURVE_PRESET_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gthumb.h>
+#include "gth-points.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GTH_PRESET_ACTION_ADDED,
+ GTH_PRESET_ACTION_RENAMED,
+ GTH_PRESET_ACTION_REMOVED,
+ GTH_PRESET_ACTION_CHANGED_ORDER
+} GthPresetAction;
+
+#define GTH_TYPE_CURVE_PRESET (gth_curve_preset_get_type ())
+#define GTH_CURVE_PRESET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_CURVE_PRESET, GthCurvePreset))
+#define GTH_CURVE_PRESET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_CURVE_PRESET,
GthCurvePresetClass))
+#define GTH_IS_CURVE_PRESET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_CURVE_PRESET))
+#define GTH_IS_CURVE_PRESET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_CURVE_PRESET))
+#define GTH_CURVE_PRESET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTH_TYPE_CURVE_PRESET,
GthCurvePresetClass))
+
+typedef struct _GthCurvePresetPrivate GthCurvePresetPrivate;
+
+typedef struct {
+ GObject parent_instance;
+ GthCurvePresetPrivate *priv;
+} GthCurvePreset;
+
+typedef struct {
+ GObjectClass parent_class;
+
+ /*< signals >*/
+
+ void (*changed) (GthCurvePreset *self);
+ void (*preset_changed) (GthCurvePreset *self,
+ int id,
+ GthPresetAction action);
+} GthCurvePresetClass;
+
+GType gth_curve_preset_get_type (void);
+GthCurvePreset * gth_curve_preset_new_from_file (GFile *file);
+int gth_curve_preset_get_size (GthCurvePreset *self);
+gboolean gth_curve_preset_get_nth (GthCurvePreset *self,
+ int n,
+ int *id,
+ const char **name,
+ GthPoints **points);
+gboolean gth_curve_preset_get_by_id (GthCurvePreset *self,
+ int id,
+ const char **name,
+ GthPoints **points);
+int gth_curve_preset_get_pos (GthCurvePreset *self,
+ int id);
+int gth_curve_preset_add (GthCurvePreset *self,
+ const char *name,
+ GthPoints *points);
+void gth_curve_preset_remove (GthCurvePreset *self,
+ int id);
+void gth_curve_preset_rename (GthCurvePreset *self,
+ int id,
+ const char *new_name);
+void gth_curve_preset_change_order (GthCurvePreset *self,
+ GList *id_list);
+GList * gth_curve_preset_get_order (GthCurvePreset *self);
+gboolean gth_curve_preset_save (GthCurvePreset *self,
+ GError **error);
+
+#endif /* GTH_CURVE_PRESET_H */
diff --git a/extensions/file_tools/gth-file-tool-curves.c b/extensions/file_tools/gth-file-tool-curves.c
index 8b6bdd0..c2aefbb 100644
--- a/extensions/file_tools/gth-file-tool-curves.c
+++ b/extensions/file_tools/gth-file-tool-curves.c
@@ -22,6 +22,8 @@
#include <config.h>
#include <math.h>
#include "gth-curve-editor.h"
+#include "gth-curve-preset.h"
+#include "gth-curve-preset-editor-dialog.h"
#include "gth-file-tool-curves.h"
#include "gth-curve.h"
#include "gth-points.h"
@@ -47,7 +49,16 @@ struct _GthFileToolCurvesPrivate {
gboolean view_original;
gboolean apply_to_original;
gboolean closing;
+ gboolean apply_current_curve;
GtkWidget *curve_editor;
+ GtkWidget *preview_button;
+ GtkWidget *preview_channel_button;
+ GtkWidget *stack;
+ GtkWidget *show_presets_button;
+ GtkWidget *reset_button;
+ GtkWidget *add_preset_button;
+ GthCurvePreset *preset;
+ GtkWidget *filter_grid;
};
@@ -57,6 +68,8 @@ struct _GthFileToolCurvesPrivate {
typedef struct {
long *value_map[GTH_HISTOGRAM_N_CHANNELS];
GthCurve *curve[GTH_HISTOGRAM_N_CHANNELS];
+ int current_curve;
+ gboolean apply_current_curve;
} TaskData;
@@ -70,9 +83,16 @@ curves_setup (TaskData *task_data,
for (c = GTH_HISTOGRAM_CHANNEL_VALUE; c <= GTH_HISTOGRAM_CHANNEL_BLUE; c++) {
task_data->value_map[c] = g_new (long, 256);
for (v = 0; v <= 255; v++) {
- double u = gth_curve_eval (task_data->curve[c], v);
+ double u;
+
+ if ((c != task_data->current_curve) || task_data->apply_current_curve)
+ u = gth_curve_eval (task_data->curve[c], v);
+ else
+ u = v;
+
if (c > GTH_HISTOGRAM_CHANNEL_VALUE)
u = task_data->value_map[GTH_HISTOGRAM_CHANNEL_VALUE][(int)u];
+
task_data->value_map[c][v] = u;
}
}
@@ -251,6 +271,26 @@ task_data_destroy (gpointer user_data)
}
+static GthTask *
+get_curves_task (GthPoints *points,
+ int current_curve,
+ gboolean apply_current_curve)
+{
+ TaskData *task_data;
+
+ task_data = task_data_new (points);
+ task_data->current_curve = current_curve;
+ task_data->apply_current_curve = apply_current_curve;
+
+ return gth_image_task_new (_("Applying changes"),
+ NULL,
+ curves_exec,
+ NULL,
+ task_data,
+ task_data_destroy);
+}
+
+
static gboolean
apply_cb (gpointer user_data)
{
@@ -258,7 +298,6 @@ apply_cb (gpointer user_data)
GtkWidget *window;
GthPoints points[GTH_HISTOGRAM_N_CHANNELS];
int c;
- TaskData *task_data;
if (self->priv->apply_event != 0) {
g_source_remove (self->priv->apply_event);
@@ -272,21 +311,17 @@ apply_cb (gpointer user_data)
window = gth_file_tool_get_window (GTH_FILE_TOOL (self));
- for (c = 0; c <= GTH_HISTOGRAM_N_CHANNELS; c++)
- gth_points_init (points + c, 0);
+ gth_points_array_init (points);
gth_curve_editor_get_points (GTH_CURVE_EDITOR (self->priv->curve_editor), points);
- task_data = task_data_new (points);
- self->priv->image_task = gth_image_task_new (_("Applying changes"),
- NULL,
- curves_exec,
- NULL,
- task_data,
- task_data_destroy);
+ self->priv->image_task = get_curves_task (points,
+ gth_curve_editor_get_current_channel (GTH_CURVE_EDITOR
(self->priv->curve_editor)),
+ self->priv->apply_current_curve);
+ gth_points_array_dispose (points);
+
if (self->priv->apply_to_original)
gth_image_task_set_source_surface (GTH_IMAGE_TASK (self->priv->image_task),
gth_image_viewer_page_tool_get_source (GTH_IMAGE_VIEWER_PAGE_TOOL (self)));
else
gth_image_task_set_source_surface (GTH_IMAGE_TASK (self->priv->image_task),
self->priv->preview);
-
g_signal_connect (self->priv->image_task,
"completed",
G_CALLBACK (image_task_completed_cb),
@@ -318,11 +353,79 @@ reset_button_clicked_cb (GtkButton *button,
static void
+add_to_presets_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+ char *preset_name;
+ GthPoints points[GTH_HISTOGRAM_N_CHANNELS];
+
+ preset_name = _gtk_request_dialog_run (GTK_WINDOW (gth_file_tool_get_window (GTH_FILE_TOOL (self))),
+ GTK_DIALOG_MODAL,
+ _("Add to Presets"),
+ _("_Name:"),
+ "",
+ 0,
+ _GTK_LABEL_CANCEL,
+ _GTK_LABEL_SAVE);
+
+ if (preset_name == NULL)
+ return;
+
+ gth_points_array_init (points);
+ gth_curve_editor_get_points (GTH_CURVE_EDITOR (self->priv->curve_editor), points);
+ gth_curve_preset_add (self->priv->preset, preset_name, points);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->show_presets_button), TRUE);
+
+ gth_points_array_dispose (points);
+ g_free (preset_name);
+}
+
+
+static void
curve_editor_changed_cb (GthCurveEditor *curve_editor,
gpointer user_data)
{
GthFileToolCurves *self = user_data;
+
apply_changes (self);
+ if (g_strcmp0 (gtk_stack_get_visible_child_name (GTK_STACK (self->priv->stack)), "presets") != 0)
+ gth_filter_grid_activate (GTH_FILTER_GRID (self->priv->filter_grid),
GTH_FILTER_GRID_NO_FILTER);
+}
+
+
+static void
+curve_editor_current_channel_changed_cb (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+
+ if (! self->priv->apply_current_curve)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->preview_channel_button), TRUE);
+}
+
+
+static void
+_gth_file_tool_curves_set_view_original (GthFileToolCurves *self,
+ gboolean view_original,
+ gboolean update_image)
+{
+ self->priv->view_original = view_original;
+
+ g_signal_handlers_block_by_data (self->priv->preview_button, self);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->preview_button), !
self->priv->view_original);
+ g_signal_handlers_unblock_by_data (self->priv->preview_button, self);
+
+ gtk_toggle_button_set_inconsistent (GTK_TOGGLE_BUTTON (self->priv->preview_channel_button),
self->priv->view_original);
+ gtk_widget_set_sensitive (self->priv->preview_channel_button, ! self->priv->view_original);
+
+ if (update_image) {
+ if (self->priv->view_original)
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->preview);
+ else
+ gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->destination);
+ }
}
@@ -331,12 +434,130 @@ preview_checkbutton_toggled_cb (GtkToggleButton *togglebutton,
gpointer user_data)
{
GthFileToolCurves *self = user_data;
+ _gth_file_tool_curves_set_view_original (self, ! gtk_toggle_button_get_active (togglebutton), TRUE);
+}
- self->priv->view_original = ! gtk_toggle_button_get_active (togglebutton);
- if (self->priv->view_original)
- gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool), self->priv->preview);
- else
- gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool),
self->priv->destination);
+
+static void
+preview_channel_checkbutton_toggled_cb (GtkToggleButton *togglebutton,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+
+ self->priv->apply_current_curve = gtk_toggle_button_get_active (togglebutton);
+ apply_changes (self);
+}
+
+
+static void
+show_options_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+
+ gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), "options");
+
+ g_signal_handlers_block_matched (self->priv->show_presets_button, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
NULL, self);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (self->priv->show_presets_button), FALSE);
+ g_signal_handlers_unblock_matched (self->priv->show_presets_button, G_SIGNAL_MATCH_DATA, 0, 0, NULL,
NULL, self);
+
+ gtk_widget_set_visible (self->priv->reset_button, TRUE);
+ gtk_widget_set_visible (self->priv->add_preset_button, TRUE);
+}
+
+
+static void
+edit_presets_button_clicked_cb (GtkButton *button,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+ GtkWidget *dialog;
+
+ dialog = gth_curve_preset_editor_dialog_new (GTK_WINDOW (gth_file_tool_get_window (GTH_FILE_TOOL
(self))), self->priv->preset);
+ gtk_widget_show (dialog);
+}
+
+
+static void
+preset_changed_cb (GthCurvePreset *preset,
+ GthPresetAction action,
+ int preset_id,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+ gboolean saved;
+ const char *preset_name;
+ GthPoints *points;
+ GError *error = NULL;
+ GList *order;
+
+ if (! gth_curve_preset_save (self->priv->preset, &error)) {
+ _gtk_error_dialog_from_gerror_show (NULL, _("Could not save the file"), error);
+ g_clear_error (&error);
+ return;
+ }
+
+ switch (action) {
+ case GTH_PRESET_ACTION_ADDED:
+ if (gth_curve_preset_get_by_id (preset, preset_id, &preset_name, &points)) {
+ gth_filter_grid_add_filter (GTH_FILTER_GRID (self->priv->filter_grid),
+ preset_id,
+ get_curves_task (points, 0, TRUE),
+ preset_name,
+ NULL);
+ gth_filter_grid_generate_preview (GTH_FILTER_GRID (self->priv->filter_grid),
+ preset_id,
+ self->priv->preview);
+ }
+ break;
+ case GTH_PRESET_ACTION_REMOVED:
+ gth_filter_grid_remove_filter (GTH_FILTER_GRID (self->priv->filter_grid), preset_id);
+ break;
+ case GTH_PRESET_ACTION_RENAMED:
+ if (gth_curve_preset_get_by_id (preset, preset_id, &preset_name, NULL))
+ gth_filter_grid_rename_filter (GTH_FILTER_GRID (self->priv->filter_grid), preset_id,
preset_name);
+ break;
+ case GTH_PRESET_ACTION_CHANGED_ORDER:
+ order = gth_curve_preset_get_order (preset);
+ gth_filter_grid_change_order (GTH_FILTER_GRID (self->priv->filter_grid), order);
+ g_list_free (order);
+ break;
+ }
+}
+
+
+static void
+filter_grid_activated_cb (GthFilterGrid *filter_grid,
+ int filter_id,
+ gpointer user_data)
+{
+ GthFileToolCurves *self = user_data;
+
+ _gth_file_tool_curves_set_view_original (self, FALSE, FALSE);
+
+ if (filter_id == GTH_FILTER_GRID_NO_FILTER) {
+ if (g_strcmp0 (gtk_stack_get_visible_child_name (GTK_STACK (self->priv->stack)), "presets")
== 0) {
+ GthPoints points[GTH_HISTOGRAM_N_CHANNELS];
+ int c;
+
+ /* reset the curve */
+
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++) {
+ GthPoints *p = points + c;
+ gth_points_init (p, 2);
+ gth_points_set_point (p, 0, 0, 0);
+ gth_points_set_point (p, 1, 255, 255);
+ }
+ gth_curve_editor_set_points (GTH_CURVE_EDITOR (self->priv->curve_editor), points);
+ gth_points_array_dispose (points);
+ }
+ }
+ else {
+ GthPoints *points;
+
+ if (gth_curve_preset_get_by_id (GTH_CURVE_PRESET (self->priv->preset), filter_id, NULL,
&points))
+ gth_curve_editor_set_points (GTH_CURVE_EDITOR (self->priv->curve_editor), points);
+ }
}
@@ -350,6 +571,7 @@ gth_file_tool_curves_get_options (GthFileTool *base)
GtkWidget *options;
int width, height;
GtkAllocation allocation;
+ GtkWidget *container;
self = (GthFileToolCurves *) base;
@@ -378,9 +600,17 @@ gth_file_tool_curves_get_options (GthFileTool *base)
self->priv->view_original = FALSE;
self->priv->closing = FALSE;
+ container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+
+ self->priv->stack = gtk_stack_new ();
+ gtk_stack_set_transition_type (GTK_STACK (self->priv->stack), GTK_STACK_TRANSITION_TYPE_CROSSFADE);
+ gtk_box_pack_start (GTK_BOX (container), self->priv->stack, FALSE, FALSE, 0);
+ gtk_widget_show (self->priv->stack);
+
self->priv->builder = _gtk_builder_new_from_file ("curves-options.ui", "file_tools");
options = _gtk_builder_get_widget (self->priv->builder, "options");
gtk_widget_show (options);
+ gtk_stack_add_named (GTK_STACK (self->priv->stack), options, "options");
self->priv->curve_editor = gth_curve_editor_new (self->priv->histogram);
gtk_widget_show (self->priv->curve_editor);
@@ -390,19 +620,101 @@ gth_file_tool_curves_get_options (GthFileTool *base)
"changed",
G_CALLBACK (curve_editor_changed_cb),
self);
+ g_signal_connect (self->priv->curve_editor,
+ "notify::current-channel",
+ G_CALLBACK (curve_editor_current_channel_changed_cb),
+ self);
- g_signal_connect (GET_WIDGET ("preview_checkbutton"),
+ self->priv->preview_button = GET_WIDGET ("preview_checkbutton");
+ g_signal_connect (self->priv->preview_button,
"toggled",
G_CALLBACK (preview_checkbutton_toggled_cb),
self);
+ self->priv->preview_channel_button = GET_WIDGET ("preview_channel_checkbutton");
+ g_signal_connect (self->priv->preview_channel_button,
+ "toggled",
+ G_CALLBACK (preview_channel_checkbutton_toggled_cb),
+ self);
+
+ {
+ GtkWidget *header_bar;
+ GtkWidget *button;
+ GFile *file;
+ int i;
+ GtkWidget *presets;
+
+ header_bar = gtk_header_bar_new ();
+ gtk_header_bar_set_title (GTK_HEADER_BAR (header_bar), _("Presets"));
+
+ button = gtk_button_new_from_icon_name ("go-previous-symbolic", GTK_ICON_SIZE_BUTTON);
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (show_options_button_clicked_cb),
+ self);
+ gtk_widget_show (button);
+ gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar), button);
+
+ button = gtk_button_new_from_icon_name ("edit-symbolic", GTK_ICON_SIZE_BUTTON);
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (edit_presets_button_clicked_cb),
+ self);
+ gtk_widget_show (button);
+ gtk_header_bar_pack_end (GTK_HEADER_BAR (header_bar), button);
+
+ gtk_widget_show (header_bar);
+
+ file = gth_user_dir_get_file_for_write (GTH_DIR_CONFIG, "gthumb", "curves.xml", NULL);
+ self->priv->preset = gth_curve_preset_new_from_file (file);
+ g_object_unref (file);
+
+ g_signal_connect (self->priv->preset,
+ "preset_changed",
+ G_CALLBACK (preset_changed_cb),
+ self);
+
+ self->priv->filter_grid = gth_filter_grid_new ();
+ for (i = 0; i < gth_curve_preset_get_size (self->priv->preset); i++) {
+ GthPoints *points;
+ int c;
+ const char *name;
+ int id;
+
+ if (gth_curve_preset_get_nth (self->priv->preset, i, &id, &name, &points))
+ gth_filter_grid_add_filter (GTH_FILTER_GRID (self->priv->filter_grid),
+ id,
+ get_curves_task (points, 0, TRUE),
+ name,
+ NULL);
+ }
+
+ g_signal_connect (self->priv->filter_grid,
+ "activated",
+ G_CALLBACK (filter_grid_activated_cb),
+ self);
+
+ gtk_widget_show (self->priv->filter_grid);
+
+ presets = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
+ gtk_box_pack_start (GTK_BOX (presets), header_bar, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (presets), self->priv->filter_grid, FALSE, FALSE, 0);
+ gtk_widget_show (presets);
+ gtk_stack_add_named (GTK_STACK (self->priv->stack), presets, "presets");
+
+ gth_filter_grid_generate_previews (GTH_FILTER_GRID (self->priv->filter_grid),
self->priv->preview);
+ }
+
+ gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), "options");
+ gtk_widget_show_all (container);
+
self->priv->preview_tool = gth_preview_tool_new ();
gth_preview_tool_set_image (GTH_PREVIEW_TOOL (self->priv->preview_tool), self->priv->preview);
gth_image_viewer_set_tool (GTH_IMAGE_VIEWER (viewer), self->priv->preview_tool);
gth_histogram_calculate_for_image (self->priv->histogram, self->priv->preview);
apply_changes (self);
- return options;
+ return container;
}
@@ -441,6 +753,19 @@ gth_file_tool_curves_apply_options (GthFileTool *base)
static void
+presets_toggled_cb (GtkToggleButton *button,
+ GthFileToolCurves * self)
+{
+ gboolean show_presets;
+
+ show_presets = gtk_toggle_button_get_active (button);
+ gtk_stack_set_visible_child_name (GTK_STACK (self->priv->stack), show_presets ? "presets" :
"options");
+ gtk_widget_set_visible (self->priv->reset_button, ! show_presets);
+ gtk_widget_set_visible (self->priv->add_preset_button, ! show_presets);
+}
+
+
+static void
gth_file_tool_curves_populate_headerbar (GthFileTool *base,
GthBrowser *browser)
{
@@ -459,10 +784,40 @@ gth_file_tool_curves_populate_headerbar (GthFileTool *base,
_("Reset"),
NULL,
NULL);
+ self->priv->reset_button = button;
g_signal_connect (button,
"clicked",
G_CALLBACK (reset_button_clicked_cb),
self);
+
+ /* add to presets */
+
+ button = gth_browser_add_header_bar_button (browser,
+ GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS,
+ "list-add-symbolic",
+ _("Add to presets"),
+ NULL,
+ NULL);
+ self->priv->add_preset_button = button;
+ g_signal_connect (button,
+ "clicked",
+ G_CALLBACK (add_to_presets_button_clicked_cb),
+ self);
+
+ /* presets */
+
+ button = gth_browser_add_header_bar_toggle_button (browser,
+ GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS,
+ "presets-symbolic",
+ _("Presets"),
+ NULL,
+ NULL);
+ gtk_widget_set_margin_left (button, GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
+ self->priv->show_presets_button = button;
+ g_signal_connect (button,
+ "toggled",
+ G_CALLBACK (presets_toggled_cb),
+ self);
}
@@ -498,9 +853,10 @@ gth_file_tool_curves_init (GthFileToolCurves *self)
self->priv->builder = NULL;
self->priv->image_task = NULL;
self->priv->view_original = FALSE;
+ self->priv->apply_current_curve = TRUE;
self->priv->histogram = gth_histogram_new ();
- gth_file_tool_construct (GTH_FILE_TOOL (self), "curves-symbolic", _("Curves"),
GTH_TOOLBOX_SECTION_COLORS);
+ gth_file_tool_construct (GTH_FILE_TOOL (self), "curves-symbolic", _("Color Curves"),
GTH_TOOLBOX_SECTION_COLORS);
gtk_widget_set_tooltip_text (GTK_WIDGET (self), _("Adjust color curves"));
}
diff --git a/extensions/file_tools/gth-points.c b/extensions/file_tools/gth-points.c
index 8d4c620..33c42e6 100644
--- a/extensions/file_tools/gth-points.c
+++ b/extensions/file_tools/gth-points.c
@@ -20,6 +20,7 @@
*/
#include <config.h>
+#include <math.h>
#include "gth-points.h"
@@ -141,3 +142,60 @@ gth_points_delete_point (GthPoints *points,
g_free (old_p);
}
+
+
+void
+gth_points_set_point (GthPoints *points,
+ int n,
+ double x,
+ double y)
+{
+ g_return_if_fail ((points != NULL) && (n >= 0) && (n < points->n));
+ points->p[n].x = x;
+ points->p[n].y = y;
+}
+
+
+void
+gth_points_set_pointv (GthPoints *points,
+ va_list args,
+ int n_points)
+{
+ int i;
+
+ gth_points_dispose (points);
+ gth_points_init (points, n_points);
+ for (i = 0; i < n_points; i++) {
+ int x = va_arg (args, int);
+ int y = va_arg (args, int);
+ gth_points_set_point (points, i, x , y);
+ }
+}
+
+
+void
+gth_points_array_init (GthPoints *points)
+{
+ int c;
+
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ gth_points_init (points + c, 0);
+}
+
+
+void
+gth_points_array_dispose (GthPoints *points)
+{
+ int c;
+
+ for (c = 0; c < GTH_HISTOGRAM_N_CHANNELS; c++)
+ gth_points_dispose (points + c);
+}
+
+
+double
+gth_point_distance (GthPoint *p1,
+ GthPoint *p2)
+{
+ return sqrt (SQR (p1->x - p2->x) + SQR (p1->y - p2->y));
+}
diff --git a/extensions/file_tools/gth-points.h b/extensions/file_tools/gth-points.h
index 4d59a03..e03bb5e 100644
--- a/extensions/file_tools/gth-points.h
+++ b/extensions/file_tools/gth-points.h
@@ -50,6 +50,19 @@ int gth_points_add_point (GthPoints *points,
double y);
void gth_points_delete_point (GthPoints *points,
int n_point);
+void gth_points_set_point (GthPoints *points,
+ int n,
+ double x,
+ double y);
+void gth_points_set_pointv (GthPoints *points,
+ va_list args,
+ int n_points);
+
+void gth_points_array_init (GthPoints *points);
+void gth_points_array_dispose(GthPoints *points);
+
+double gth_point_distance (GthPoint *p1,
+ GthPoint *p2);
G_END_DECLS
diff --git a/gthumb/gth-browser.c b/gthumb/gth-browser.c
index 9900653..5da47eb 100644
--- a/gthumb/gth-browser.c
+++ b/gthumb/gth-browser.c
@@ -74,7 +74,6 @@
#define SHIRNK_WRAP_HEIGHT_OFFSET 125
#define FILE_PROPERTIES_MINIMUM_HEIGHT 100
#define HISTORY_FILE "history.xbel"
-#define SECTION_BIG_MARGIN 12
#define OVERLAY_MARGIN 10
@@ -4267,12 +4266,12 @@ gth_browser_init (GthBrowser *browser)
rtl = gtk_widget_get_direction (header_bar) == GTK_TEXT_DIR_RTL;
- gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_COMMANDS], SECTION_BIG_MARGIN);
- gtk_widget_set_margin_right
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_VIEW], SECTION_BIG_MARGIN);
- gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT], SECTION_BIG_MARGIN);
- gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_VIEW], SECTION_BIG_MARGIN);
- gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS], SECTION_BIG_MARGIN);
- gtk_widget_set_margin_right
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS], SECTION_BIG_MARGIN);
+ gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_COMMANDS],
GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
+ gtk_widget_set_margin_right
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
+ gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_EDIT], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
+ gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_VIEW], GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
+ gtk_widget_set_margin_left
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS],
GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
+ gtk_widget_set_margin_right
(browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_EDITOR_COMMANDS],
GTH_BROWSER_HEADER_BAR_BIG_MARGIN);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar),
browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_NAVIGATION]);
gtk_header_bar_pack_start (GTK_HEADER_BAR (header_bar),
browser->priv->header_sections[GTH_BROWSER_HEADER_SECTION_BROWSER_LOCATIONS]);
diff --git a/gthumb/gth-browser.h b/gthumb/gth-browser.h
index f2c4f96..a0ddeef 100644
--- a/gthumb/gth-browser.h
+++ b/gthumb/gth-browser.h
@@ -57,6 +57,8 @@ G_BEGIN_DECLS
#define GTH_BROWSER_MENU_MANAGER_FOLDER_FOLDER_ACTIONS "folder.folder-actions"
#define GTH_BROWSER_MENU_MANAGER_FOLDER_OTHER_ACTIONS "folder.other-actions"
+#define GTH_BROWSER_HEADER_BAR_BIG_MARGIN 12
+
#define GTH_TYPE_BROWSER (gth_browser_get_type ())
#define GTH_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_BROWSER, GthBrowser))
#define GTH_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_BROWSER_TYPE, GthBrowserClass))
diff --git a/gthumb/gth-filter-grid.c b/gthumb/gth-filter-grid.c
index 9795753..869f2e6 100644
--- a/gthumb/gth-filter-grid.c
+++ b/gthumb/gth-filter-grid.c
@@ -659,3 +659,98 @@ gth_filter_grid_get_task (GthFilterGrid *self,
return _g_object_ref (cell_data->task);
}
+
+
+void
+gth_filter_grid_rename_filter (GthFilterGrid *self,
+ int filter_id,
+ const char *new_name)
+{
+ CellData *cell_data;
+
+ cell_data = g_hash_table_lookup (self->priv->cell_data, GINT_TO_POINTER (filter_id));
+ g_return_if_fail (cell_data != NULL);
+
+ gtk_label_set_text (GTK_LABEL (cell_data->label), new_name);
+}
+
+
+static void
+_gth_filter_grid_reflow (GthFilterGrid *self)
+{
+ GList *children;
+ GList *scan;
+
+ self->priv->current_row = 0;
+ self->priv->current_column = 0;
+
+ children = NULL;
+ for (scan = self->priv->filter_ids; scan; scan = scan->next)
+ children = g_list_prepend (children, g_hash_table_lookup (self->priv->cell_data, scan->data));
+ children = g_list_reverse (children);
+
+ for (scan = children; scan; scan = scan->next) {
+ CellData *cell_data = scan->data;
+
+ g_object_ref (G_OBJECT (cell_data->cell));
+ gtk_container_remove (GTK_CONTAINER (self->priv->grid), cell_data->cell);
+ }
+
+ for (scan = children; scan; scan = scan->next) {
+ CellData *cell_data = scan->data;
+
+ _gth_filter_grid_append_cell (self, GTK_WIDGET (cell_data->cell));
+ g_object_unref (G_OBJECT (cell_data->cell));
+ }
+
+ g_list_free (children);
+}
+
+
+void
+gth_filter_grid_remove_filter (GthFilterGrid *self,
+ int filter_id)
+{
+ CellData *cell_data;
+ GList *scan, *link;
+
+ cell_data = g_hash_table_lookup (self->priv->cell_data, GINT_TO_POINTER (filter_id));
+ g_return_if_fail (cell_data != NULL);
+
+ /* update filter_ids */
+
+ link = NULL;
+ for (scan = self->priv->filter_ids; scan; scan = scan->next) {
+ if (GPOINTER_TO_INT (scan->data) == filter_id) {
+ link = scan;
+ break;
+ }
+ }
+ if (link != NULL) {
+ self->priv->filter_ids = g_list_remove_link (self->priv->filter_ids, link);
+ g_list_free (link);
+ }
+
+ /* update active_button */
+
+ if (cell_data->button == self->priv->active_button)
+ self->priv->active_button = NULL;
+
+ /* remove the cell */
+
+ gtk_container_remove (GTK_CONTAINER (self->priv->grid), cell_data->cell);
+ cell_data->cell = NULL;
+ _gth_filter_grid_reflow (self);
+ g_hash_table_remove (self->priv->cell_data, GINT_TO_POINTER (filter_id));
+}
+
+
+void
+gth_filter_grid_change_order (GthFilterGrid *self,
+ GList *id_list)
+{
+ g_list_free (self->priv->filter_ids);
+ self->priv->filter_ids = g_list_copy (id_list);
+
+ _gth_filter_grid_reflow (self);
+}
diff --git a/gthumb/gth-filter-grid.h b/gthumb/gth-filter-grid.h
index b541add..cf84d12 100644
--- a/gthumb/gth-filter-grid.h
+++ b/gthumb/gth-filter-grid.h
@@ -80,6 +80,13 @@ void gth_filter_grid_generate_preview (GthFilterGrid *self,
cairo_surface_t *image);
GthTask * gth_filter_grid_get_task (GthFilterGrid *self,
int filter_id);
+void gth_filter_grid_rename_filter (GthFilterGrid *self,
+ int filter_id,
+ const char *new_name);
+void gth_filter_grid_remove_filter (GthFilterGrid *self,
+ int filter_id);
+void gth_filter_grid_change_order (GthFilterGrid *self,
+ GList *id_list);
G_END_DECLS
diff --git a/gthumb/gth-marshal.list b/gthumb/gth-marshal.list
index 602db29..3d5a98c 100644
--- a/gthumb/gth-marshal.list
+++ b/gthumb/gth-marshal.list
@@ -3,6 +3,7 @@ BOOLEAN:VOID
VOID:BOOLEAN, POINTER
VOID:BOXED, BOXED
VOID:ENUM, ENUM
+VOID:ENUM, INT
VOID:INT, INT
VOID:OBJECT, BOOLEAN
VOID:OBJECT, BOXED, ENUM
diff --git a/gthumb/gth-toolbox.c b/gthumb/gth-toolbox.c
index 68f3aaf..3edaca9 100644
--- a/gthumb/gth-toolbox.c
+++ b/gthumb/gth-toolbox.c
@@ -243,7 +243,6 @@ gth_toolbox_init (GthToolbox *toolbox)
g_signal_connect (ok_button, "clicked", G_CALLBACK (ok_button_clicked_cb), toolbox);
toolbox->priv->options = gtk_scrolled_window_new (NULL, NULL);
- gtk_widget_set_margin_top (toolbox->priv->options, 24);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (toolbox->priv->options), GTK_SHADOW_NONE);
gtk_widget_show (toolbox->priv->options);
gtk_box_pack_start (GTK_BOX (options_box), toolbox->priv->options, TRUE, TRUE, 0);
diff --git a/gthumb/gthumb.gresource.xml b/gthumb/gthumb.gresource.xml
index 5b315be..936c305 100644
--- a/gthumb/gthumb.gresource.xml
+++ b/gthumb/gthumb.gresource.xml
@@ -9,5 +9,6 @@
<file compressed="true">resources/gthumb.css</file>
<file compressed="true">resources/history-menu.ui</file>
<file compressed="true">resources/message-dialog.ui</file>
+ <file compressed="true">resources/request-dialog.ui</file>
</gresource>
</gresources>
diff --git a/gthumb/gtk-utils.c b/gthumb/gtk-utils.c
index dc9f0c1..75f779d 100644
--- a/gthumb/gtk-utils.c
+++ b/gthumb/gtk-utils.c
@@ -187,6 +187,79 @@ _gtk_yesno_dialog_new (GtkWindow *parent,
}
+static GtkWidget *
+create_button (const char *text)
+{
+ GtkWidget *button;
+
+ button = gtk_button_new_with_mnemonic (text);
+ gtk_widget_set_can_default (button, TRUE);
+ gtk_widget_show (button);
+
+ return button;
+}
+
+
+char *
+_gtk_request_dialog_run (GtkWindow *parent,
+ GtkDialogFlags flags,
+ const char *title,
+ const char *message,
+ const char *default_value,
+ int max_length,
+ const gchar *no_button_text,
+ const gchar *yes_button_text)
+{
+ GtkBuilder *builder;
+ GtkWidget *dialog;
+ GtkWidget *label;
+ GtkWidget *entry;
+ char *result;
+
+ builder = _gtk_builder_new_from_resource ("request-dialog.ui");
+ dialog = _gtk_builder_get_widget (builder, "request_dialog");
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+ gtk_window_set_modal (GTK_WINDOW (dialog), (flags & GTK_DIALOG_MODAL));
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), (flags & GTK_DIALOG_DESTROY_WITH_PARENT));
+ gtk_window_set_title (GTK_WINDOW (dialog), title);
+ g_object_weak_ref (G_OBJECT (dialog), (GWeakNotify) g_object_unref, builder);
+
+ if (flags & GTK_DIALOG_MODAL)
+ _gtk_dialog_add_to_window_group (GTK_DIALOG (dialog));
+
+ label = _gtk_builder_get_widget (builder, "message_label");
+ gtk_label_set_text_with_mnemonic (GTK_LABEL (label), message);
+
+ entry = _gtk_builder_get_widget (builder, "value_entry");
+ gtk_entry_set_max_length (GTK_ENTRY (entry), max_length);
+ gtk_entry_set_text (GTK_ENTRY (entry), default_value);
+
+ /* Add buttons */
+
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
+ create_button (no_button_text),
+ GTK_RESPONSE_CANCEL);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog),
+ create_button (yes_button_text),
+ GTK_RESPONSE_YES);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
+
+ /* Run dialog */
+
+ gtk_widget_grab_focus (entry);
+
+ if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
+ result = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
+ else
+ result = NULL;
+
+ gtk_widget_destroy (dialog);
+
+ return result;
+}
+
+
void
_gtk_error_dialog_from_gerror_run (GtkWindow *parent,
const char *title,
diff --git a/gthumb/gtk-utils.h b/gthumb/gtk-utils.h
index b2c1e3a..1dced73 100644
--- a/gthumb/gtk-utils.h
+++ b/gthumb/gtk-utils.h
@@ -61,6 +61,14 @@ GtkWidget * _gtk_yesno_dialog_new (GtkWindow *pa
const char *message,
const char *no_button_text,
const char *yes_button_text);
+gchar * _gtk_request_dialog_run (GtkWindow *parent,
+ GtkDialogFlags flags,
+ const char *title,
+ const char *message,
+ const char *default_value,
+ int max_length,
+ const char *no_button_text,
+ const char *yes_button_text);
void _gtk_error_dialog_from_gerror_run (GtkWindow *parent,
const char *title,
GError *gerror);
diff --git a/gthumb/resources/Makefile.am b/gthumb/resources/Makefile.am
index 0465be8..0447c9f 100644
--- a/gthumb/resources/Makefile.am
+++ b/gthumb/resources/Makefile.am
@@ -6,6 +6,7 @@ EXTRA_DIST = \
gears-menu.ui \
gthumb.css \
history-menu.ui \
- message-dialog.ui
+ message-dialog.ui \
+ request-dialog.ui
-include $(top_srcdir)/git.mk
\ No newline at end of file
diff --git a/gthumb/resources/gthumb.css b/gthumb/resources/gthumb.css
index 220155e..b434c64 100644
--- a/gthumb/resources/gthumb.css
+++ b/gthumb/resources/gthumb.css
@@ -137,3 +137,11 @@ GtkButton.filter-preview:checked {
background-color: @theme_unfocused_selected_bg_color;
color: @theme_unfocused_selected_fg_color;
}
+
+/* -- header-bar inside the toolbox -- */
+
+GthToolbox .header-bar {
+ border-radius: 0;
+ box-shadow: none;
+ background-image: none;
+}
diff --git a/gthumb/resources/request-dialog.ui b/gthumb/resources/request-dialog.ui
new file mode 100644
index 0000000..5a86d32
--- /dev/null
+++ b/gthumb/resources/request-dialog.ui
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.18.3 -->
+<interface>
+ <requires lib="gtk+" version="3.10"/>
+ <object class="GtkDialog" id="request_dialog">
+ <property name="width_request">500</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">10</property>
+ <property name="resizable">False</property>
+ <property name="type_hint">dialog</property>
+ <child internal-child="vbox">
+ <object class="GtkBox" id="dialog-vbox3">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">10</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox" id="dialog-action_area3">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">end</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="hbox28">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="border_width">0</property>
+ <property name="spacing">12</property>
+ <child>
+ <object class="GtkBox" id="box1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">4</property>
+ <child>
+ <object class="GtkLabel" id="message_label">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">value_entry</property>
+ <property name="ellipsize">end</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="value_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">●</property>
+ <property name="activates_default">True</property>
+ <property name="width_chars">50</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]