summaryrefslogtreecommitdiffstats
path: root/app/display/gimpcursorview.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/display/gimpcursorview.c')
-rw-r--r--app/display/gimpcursorview.c887
1 files changed, 887 insertions, 0 deletions
diff --git a/app/display/gimpcursorview.c b/app/display/gimpcursorview.c
new file mode 100644
index 0000000..846df91
--- /dev/null
+++ b/app/display/gimpcursorview.c
@@ -0,0 +1,887 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * gimpcursorview.c
+ * Copyright (C) 2005-2016 Michael Natterer <mitch@gimp.org>
+ *
+ * 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 3 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpmath/gimpmath.h"
+#include "libgimpcolor/gimpcolor.h"
+#include "libgimpwidgets/gimpwidgets.h"
+
+#include "display-types.h"
+
+#include "config/gimpcoreconfig.h"
+
+#include "core/gimp.h"
+#include "core/gimpcontext.h"
+#include "core/gimpimage.h"
+#include "core/gimpimage-pick-color.h"
+#include "core/gimpitem.h"
+
+#include "widgets/gimpcolorframe.h"
+#include "widgets/gimpdocked.h"
+#include "widgets/gimpmenufactory.h"
+#include "widgets/gimpsessioninfo-aux.h"
+
+#include "gimpcursorview.h"
+#include "gimpdisplay.h"
+#include "gimpdisplayshell.h"
+
+#include "gimp-intl.h"
+
+
+enum
+{
+ PROP_0,
+ PROP_SAMPLE_MERGED
+};
+
+
+struct _GimpCursorViewPrivate
+{
+ GimpEditor parent_instance;
+
+ GtkWidget *coord_hbox;
+ GtkWidget *selection_hbox;
+ GtkWidget *color_hbox;
+
+ GtkWidget *pixel_x_label;
+ GtkWidget *pixel_y_label;
+ GtkWidget *unit_x_label;
+ GtkWidget *unit_y_label;
+ GtkWidget *selection_x_label;
+ GtkWidget *selection_y_label;
+ GtkWidget *selection_width_label;
+ GtkWidget *selection_height_label;
+ GtkWidget *color_frame_1;
+ GtkWidget *color_frame_2;
+
+ gboolean sample_merged;
+
+ GimpContext *context;
+ GimpDisplayShell *shell;
+ GimpImage *image;
+ GimpUnit unit;
+
+ guint cursor_idle_id;
+ GimpImage *cursor_image;
+ GimpUnit cursor_unit;
+ gdouble cursor_x;
+ gdouble cursor_y;
+};
+
+
+static void gimp_cursor_view_docked_iface_init (GimpDockedInterface *iface);
+
+static void gimp_cursor_view_dispose (GObject *object);
+static void gimp_cursor_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gimp_cursor_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gimp_cursor_view_style_set (GtkWidget *widget,
+ GtkStyle *prev_style);
+
+static void gimp_cursor_view_set_aux_info (GimpDocked *docked,
+ GList *aux_info);
+static GList * gimp_cursor_view_get_aux_info (GimpDocked *docked);
+
+static void gimp_cursor_view_set_context (GimpDocked *docked,
+ GimpContext *context);
+static void gimp_cursor_view_image_changed (GimpCursorView *view,
+ GimpImage *image,
+ GimpContext *context);
+static void gimp_cursor_view_mask_changed (GimpCursorView *view,
+ GimpImage *image);
+static void gimp_cursor_view_diplay_changed (GimpCursorView *view,
+ GimpDisplay *display,
+ GimpContext *context);
+static void gimp_cursor_view_shell_unit_changed (GimpCursorView *view,
+ GParamSpec *pspec,
+ GimpDisplayShell *shell);
+static void gimp_cursor_view_format_as_unit (GimpUnit unit,
+ gchar *output_buf,
+ gint output_buf_size,
+ gdouble pixel_value,
+ gdouble image_res);
+static void gimp_cursor_view_set_label_italic (GtkWidget *label,
+ gboolean italic);
+static void gimp_cursor_view_update_selection_info (GimpCursorView *view,
+ GimpImage *image,
+ GimpUnit unit);
+static gboolean gimp_cursor_view_cursor_idle (GimpCursorView *view);
+
+
+G_DEFINE_TYPE_WITH_CODE (GimpCursorView, gimp_cursor_view, GIMP_TYPE_EDITOR,
+ G_ADD_PRIVATE (GimpCursorView)
+ G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
+ gimp_cursor_view_docked_iface_init))
+
+#define parent_class gimp_cursor_view_parent_class
+
+static GimpDockedInterface *parent_docked_iface = NULL;
+
+
+static void
+gimp_cursor_view_class_init (GimpCursorViewClass* klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ object_class->dispose = gimp_cursor_view_dispose;
+ object_class->get_property = gimp_cursor_view_get_property;
+ object_class->set_property = gimp_cursor_view_set_property;
+
+ widget_class->style_set = gimp_cursor_view_style_set;
+
+ g_object_class_install_property (object_class, PROP_SAMPLE_MERGED,
+ g_param_spec_boolean ("sample-merged",
+ NULL, NULL,
+ TRUE,
+ GIMP_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT));
+}
+
+static void
+gimp_cursor_view_init (GimpCursorView *view)
+{
+ GtkWidget *frame;
+ GtkWidget *table;
+ GtkWidget *toggle;
+ gint content_spacing;
+
+ view->priv = gimp_cursor_view_get_instance_private (view);
+
+ view->priv->sample_merged = TRUE;
+ view->priv->context = NULL;
+ view->priv->shell = NULL;
+ view->priv->image = NULL;
+ view->priv->unit = GIMP_UNIT_PIXEL;
+ view->priv->cursor_idle_id = 0;
+
+ gtk_widget_style_get (GTK_WIDGET (view),
+ "content-spacing", &content_spacing,
+ NULL);
+
+
+ /* cursor information */
+
+ view->priv->coord_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
+ content_spacing);
+ gtk_box_set_homogeneous (GTK_BOX (view->priv->coord_hbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (view), view->priv->coord_hbox,
+ FALSE, FALSE, 0);
+ gtk_widget_show (view->priv->coord_hbox);
+
+ view->priv->selection_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
+ content_spacing);
+ gtk_box_set_homogeneous (GTK_BOX (view->priv->selection_hbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (view), view->priv->selection_hbox,
+ FALSE, FALSE, 0);
+ gtk_widget_show (view->priv->selection_hbox);
+
+
+ /* Pixels */
+
+ frame = gimp_frame_new (_("Pixels"));
+ gtk_box_pack_start (GTK_BOX (view->priv->coord_hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ view->priv->pixel_x_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->pixel_x_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("X"), 0.5, 0.5,
+ view->priv->pixel_x_label, 1, FALSE);
+
+ view->priv->pixel_y_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->pixel_y_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ _("Y"), 0.5, 0.5,
+ view->priv->pixel_y_label, 1, FALSE);
+
+
+ /* Units */
+
+ frame = gimp_frame_new (_("Units"));
+ gtk_box_pack_start (GTK_BOX (view->priv->coord_hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 4);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ view->priv->unit_x_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->unit_x_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("X"), 0.5, 0.5,
+ view->priv->unit_x_label, 1, FALSE);
+
+ view->priv->unit_y_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->unit_y_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ _("Y"), 0.5, 0.5,
+ view->priv->unit_y_label, 1, FALSE);
+
+
+ /* Selection Bounding Box */
+
+ frame = gimp_frame_new (_("Selection"));
+ gtk_box_pack_start (GTK_BOX (view->priv->selection_hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ gimp_help_set_help_data (frame, _("The selection's bounding box"), NULL);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 6);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ view->priv->selection_x_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->selection_x_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ _("X"), 0.5, 0.5,
+ view->priv->selection_x_label, 1, FALSE);
+
+ view->priv->selection_y_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->selection_y_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ _("Y"), 0.5, 0.5,
+ view->priv->selection_y_label, 1, FALSE);
+
+ frame = gimp_frame_new ("");
+ gtk_box_pack_start (GTK_BOX (view->priv->selection_hbox), frame, TRUE, TRUE, 0);
+ gtk_widget_show (frame);
+
+ table = gtk_table_new (2, 2, FALSE);
+ gtk_table_set_col_spacings (GTK_TABLE (table), 4);
+ gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+ gtk_container_add (GTK_CONTAINER (frame), table);
+ gtk_widget_show (table);
+
+ view->priv->selection_width_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->selection_width_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
+ /* Width */
+ _("W"), 0.5, 0.5,
+ view->priv->selection_width_label, 1, FALSE);
+
+ view->priv->selection_height_label = gtk_label_new (_("n/a"));
+ gtk_label_set_xalign (GTK_LABEL (view->priv->selection_height_label), 1.0);
+ gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
+ /* Height */
+ _("H"), 0.5, 0.5,
+ view->priv->selection_height_label, 1, FALSE);
+
+
+ /* color information */
+
+ view->priv->color_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL,
+ content_spacing);
+ gtk_box_set_homogeneous (GTK_BOX (view->priv->color_hbox), TRUE);
+ gtk_box_pack_start (GTK_BOX (view), view->priv->color_hbox, FALSE, FALSE, 0);
+ gtk_widget_show (view->priv->color_hbox);
+
+ view->priv->color_frame_1 = gimp_color_frame_new ();
+ gimp_color_frame_set_mode (GIMP_COLOR_FRAME (view->priv->color_frame_1),
+ GIMP_COLOR_PICK_MODE_PIXEL);
+ gimp_color_frame_set_ellipsize (GIMP_COLOR_FRAME (view->priv->color_frame_1),
+ PANGO_ELLIPSIZE_END);
+ gtk_box_pack_start (GTK_BOX (view->priv->color_hbox), view->priv->color_frame_1,
+ TRUE, TRUE, 0);
+ gtk_widget_show (view->priv->color_frame_1);
+
+ view->priv->color_frame_2 = gimp_color_frame_new ();
+ gimp_color_frame_set_mode (GIMP_COLOR_FRAME (view->priv->color_frame_2),
+ GIMP_COLOR_PICK_MODE_RGB_PERCENT);
+ gtk_box_pack_start (GTK_BOX (view->priv->color_hbox), view->priv->color_frame_2,
+ TRUE, TRUE, 0);
+ gtk_widget_show (view->priv->color_frame_2);
+
+ /* sample merged toggle */
+
+ toggle = gimp_prop_check_button_new (G_OBJECT (view), "sample-merged",
+ _("_Sample Merged"));
+ gtk_box_pack_start (GTK_BOX (view), toggle, FALSE, FALSE, 0);
+ gtk_widget_show (toggle);
+}
+
+static void
+gimp_cursor_view_docked_iface_init (GimpDockedInterface *iface)
+{
+ parent_docked_iface = g_type_interface_peek_parent (iface);
+
+ if (! parent_docked_iface)
+ parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
+
+ iface->set_aux_info = gimp_cursor_view_set_aux_info;
+ iface->get_aux_info = gimp_cursor_view_get_aux_info;
+ iface->set_context = gimp_cursor_view_set_context;
+}
+
+static void
+gimp_cursor_view_dispose (GObject *object)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (object);
+
+ if (view->priv->context)
+ gimp_docked_set_context (GIMP_DOCKED (view), NULL);
+
+ if (view->priv->cursor_idle_id)
+ {
+ g_source_remove (view->priv->cursor_idle_id);
+ view->priv->cursor_idle_id = 0;
+ }
+
+ g_clear_object (&view->priv->cursor_image);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gimp_cursor_view_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (object);
+
+ switch (property_id)
+ {
+ case PROP_SAMPLE_MERGED:
+ view->priv->sample_merged = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gimp_cursor_view_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (object);
+
+ switch (property_id)
+ {
+ case PROP_SAMPLE_MERGED:
+ g_value_set_boolean (value, view->priv->sample_merged);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+#define AUX_INFO_FRAME_1_MODE "frame-1-mode"
+#define AUX_INFO_FRAME_2_MODE "frame-2-mode"
+
+static void
+gimp_cursor_view_set_aux_info (GimpDocked *docked,
+ GList *aux_info)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (docked);
+ GList *list;
+
+ parent_docked_iface->set_aux_info (docked, aux_info);
+
+ for (list = aux_info; list; list = g_list_next (list))
+ {
+ GimpSessionInfoAux *aux = list->data;
+ GtkWidget *frame = NULL;
+
+ if (! strcmp (aux->name, AUX_INFO_FRAME_1_MODE))
+ frame = view->priv->color_frame_1;
+ else if (! strcmp (aux->name, AUX_INFO_FRAME_2_MODE))
+ frame = view->priv->color_frame_2;
+
+ if (frame)
+ {
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+
+ enum_class = g_type_class_peek (GIMP_TYPE_COLOR_PICK_MODE);
+ enum_value = g_enum_get_value_by_nick (enum_class, aux->value);
+
+ if (enum_value)
+ gimp_color_frame_set_mode (GIMP_COLOR_FRAME (frame),
+ enum_value->value);
+ }
+ }
+}
+
+static GList *
+gimp_cursor_view_get_aux_info (GimpDocked *docked)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (docked);
+ GList *aux_info;
+ const gchar *nick;
+ GimpSessionInfoAux *aux;
+
+ aux_info = parent_docked_iface->get_aux_info (docked);
+
+ if (gimp_enum_get_value (GIMP_TYPE_COLOR_PICK_MODE,
+ GIMP_COLOR_FRAME (view->priv->color_frame_1)->pick_mode,
+ NULL, &nick, NULL, NULL))
+ {
+ aux = gimp_session_info_aux_new (AUX_INFO_FRAME_1_MODE, nick);
+ aux_info = g_list_append (aux_info, aux);
+ }
+
+ if (gimp_enum_get_value (GIMP_TYPE_COLOR_PICK_MODE,
+ GIMP_COLOR_FRAME (view->priv->color_frame_2)->pick_mode,
+ NULL, &nick, NULL, NULL))
+ {
+ aux = gimp_session_info_aux_new (AUX_INFO_FRAME_2_MODE, nick);
+ aux_info = g_list_append (aux_info, aux);
+ }
+
+ return aux_info;
+}
+
+static void
+gimp_cursor_view_format_as_unit (GimpUnit unit,
+ gchar *output_buf,
+ gint output_buf_size,
+ gdouble pixel_value,
+ gdouble image_res)
+{
+ gchar format_buf[32];
+ gdouble value;
+ gint unit_digits = 0;
+ const gchar *unit_str = "";
+
+ value = gimp_pixels_to_units (pixel_value, unit, image_res);
+
+ if (unit != GIMP_UNIT_PIXEL)
+ {
+ unit_digits = gimp_unit_get_scaled_digits (unit, image_res);
+ unit_str = gimp_unit_get_abbreviation (unit);
+ }
+
+ g_snprintf (format_buf, sizeof (format_buf),
+ "%%.%df %s", unit_digits, unit_str);
+
+ g_snprintf (output_buf, output_buf_size, format_buf, value);
+}
+
+static void
+gimp_cursor_view_set_label_italic (GtkWidget *label,
+ gboolean italic)
+{
+ PangoStyle attribute = italic ? PANGO_STYLE_ITALIC : PANGO_STYLE_NORMAL;
+
+ gimp_label_set_attributes (GTK_LABEL (label),
+ PANGO_ATTR_STYLE, attribute,
+ -1);
+}
+
+static void
+gimp_cursor_view_style_set (GtkWidget *widget,
+ GtkStyle *prev_style)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (widget);
+ gint content_spacing;
+
+ GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
+
+ gtk_widget_style_get (GTK_WIDGET (view),
+ "content-spacing", &content_spacing,
+ NULL);
+
+ gtk_box_set_spacing (GTK_BOX (view->priv->coord_hbox), content_spacing);
+ gtk_box_set_spacing (GTK_BOX (view->priv->selection_hbox), content_spacing);
+ gtk_box_set_spacing (GTK_BOX (view->priv->color_hbox), content_spacing);
+}
+
+static void
+gimp_cursor_view_set_context (GimpDocked *docked,
+ GimpContext *context)
+{
+ GimpCursorView *view = GIMP_CURSOR_VIEW (docked);
+ GimpColorConfig *config = NULL;
+ GimpDisplay *display = NULL;
+ GimpImage *image = NULL;
+
+ if (context == view->priv->context)
+ return;
+
+ if (view->priv->context)
+ {
+ g_signal_handlers_disconnect_by_func (view->priv->context,
+ gimp_cursor_view_diplay_changed,
+ view);
+ g_signal_handlers_disconnect_by_func (view->priv->context,
+ gimp_cursor_view_image_changed,
+ view);
+
+ g_object_unref (view->priv->context);
+ }
+
+ view->priv->context = context;
+
+ if (view->priv->context)
+ {
+ g_object_ref (view->priv->context);
+
+ g_signal_connect_swapped (view->priv->context, "display-changed",
+ G_CALLBACK (gimp_cursor_view_diplay_changed),
+ view);
+
+ g_signal_connect_swapped (view->priv->context, "image-changed",
+ G_CALLBACK (gimp_cursor_view_image_changed),
+ view);
+
+ config = context->gimp->config->color_management;
+ display = gimp_context_get_display (context);
+ image = gimp_context_get_image (context);
+ }
+
+ gimp_color_frame_set_color_config (GIMP_COLOR_FRAME (view->priv->color_frame_1),
+ config);
+ gimp_color_frame_set_color_config (GIMP_COLOR_FRAME (view->priv->color_frame_2),
+ config);
+
+ gimp_cursor_view_diplay_changed (view, display, view->priv->context);
+ gimp_cursor_view_image_changed (view, image, view->priv->context);
+}
+
+static void
+gimp_cursor_view_image_changed (GimpCursorView *view,
+ GimpImage *image,
+ GimpContext *context)
+{
+ g_return_if_fail (GIMP_IS_CURSOR_VIEW (view));
+
+ if (image == view->priv->image)
+ return;
+
+ if (view->priv->image)
+ {
+ g_signal_handlers_disconnect_by_func (view->priv->image,
+ gimp_cursor_view_mask_changed,
+ view);
+ }
+
+ view->priv->image = image;
+
+ if (view->priv->image)
+ {
+ g_signal_connect_swapped (view->priv->image, "mask-changed",
+ G_CALLBACK (gimp_cursor_view_mask_changed),
+ view);
+ }
+
+ gimp_cursor_view_mask_changed (view, view->priv->image);
+}
+
+static void
+gimp_cursor_view_mask_changed (GimpCursorView *view,
+ GimpImage *image)
+{
+ gimp_cursor_view_update_selection_info (view,
+ view->priv->image,
+ view->priv->unit);
+}
+
+static void
+gimp_cursor_view_diplay_changed (GimpCursorView *view,
+ GimpDisplay *display,
+ GimpContext *context)
+{
+ GimpDisplayShell *shell = NULL;
+
+ if (display)
+ shell = gimp_display_get_shell (display);
+
+ if (view->priv->shell)
+ {
+ g_signal_handlers_disconnect_by_func (view->priv->shell,
+ gimp_cursor_view_shell_unit_changed,
+ view);
+ }
+
+ view->priv->shell = shell;
+
+ if (view->priv->shell)
+ {
+ g_signal_connect_swapped (view->priv->shell, "notify::unit",
+ G_CALLBACK (gimp_cursor_view_shell_unit_changed),
+ view);
+ }
+
+ gimp_cursor_view_shell_unit_changed (view,
+ NULL,
+ view->priv->shell);
+}
+
+static void
+gimp_cursor_view_shell_unit_changed (GimpCursorView *view,
+ GParamSpec *pspec,
+ GimpDisplayShell *shell)
+{
+ GimpUnit new_unit = GIMP_UNIT_PIXEL;
+
+ if (shell)
+ {
+ new_unit = gimp_display_shell_get_unit (shell);
+ }
+
+ if (view->priv->unit != new_unit)
+ {
+ gimp_cursor_view_update_selection_info (view, view->priv->image, new_unit);
+ view->priv->unit = new_unit;
+ }
+}
+
+static void
+gimp_cursor_view_update_selection_info (GimpCursorView *view,
+ GimpImage *image,
+ GimpUnit unit)
+{
+ gint x, y, width, height;
+
+ if (image &&
+ gimp_item_bounds (GIMP_ITEM (gimp_image_get_mask (image)),
+ &x, &y, &width, &height))
+ {
+ gdouble xres, yres;
+ gchar buf[32];
+
+ gimp_image_get_resolution (image, &xres, &yres);
+
+ gimp_cursor_view_format_as_unit (unit, buf, sizeof (buf), x, xres);
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_x_label), buf);
+
+ gimp_cursor_view_format_as_unit (unit, buf, sizeof (buf), y, yres);
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_y_label), buf);
+
+ gimp_cursor_view_format_as_unit (unit, buf, sizeof (buf), width, xres);
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_width_label), buf);
+
+ gimp_cursor_view_format_as_unit (unit, buf, sizeof (buf), height, yres);
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_height_label), buf);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_x_label),
+ _("n/a"));
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_y_label),
+ _("n/a"));
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_width_label),
+ _("n/a"));
+ gtk_label_set_text (GTK_LABEL (view->priv->selection_height_label),
+ _("n/a"));
+ }
+}
+
+static gboolean
+gimp_cursor_view_cursor_idle (GimpCursorView *view)
+{
+
+ if (view->priv->cursor_image)
+ {
+ GimpImage *image = view->priv->cursor_image;
+ GimpUnit unit = view->priv->cursor_unit;
+ gdouble x = view->priv->cursor_x;
+ gdouble y = view->priv->cursor_y;
+ gboolean in_image;
+ gchar buf[32];
+ const Babl *sample_format;
+ gdouble pixel[4];
+ GimpRGB color;
+ gdouble xres;
+ gdouble yres;
+ gint int_x;
+ gint int_y;
+
+ if (unit == GIMP_UNIT_PIXEL)
+ unit = gimp_image_get_unit (image);
+
+ gimp_image_get_resolution (image, &xres, &yres);
+
+ in_image = (x >= 0.0 && x < gimp_image_get_width (image) &&
+ y >= 0.0 && y < gimp_image_get_height (image));
+
+ g_snprintf (buf, sizeof (buf), "%d", (gint) floor (x));
+ gtk_label_set_text (GTK_LABEL (view->priv->pixel_x_label), buf);
+ gimp_cursor_view_set_label_italic (view->priv->pixel_x_label, ! in_image);
+
+ g_snprintf (buf, sizeof (buf), "%d", (gint) floor (y));
+ gtk_label_set_text (GTK_LABEL (view->priv->pixel_y_label), buf);
+ gimp_cursor_view_set_label_italic (view->priv->pixel_y_label, ! in_image);
+
+ gimp_cursor_view_format_as_unit (unit, buf, sizeof (buf), x, xres);
+ gtk_label_set_text (GTK_LABEL (view->priv->unit_x_label), buf);
+ gimp_cursor_view_set_label_italic (view->priv->unit_x_label, ! in_image);
+
+ gimp_cursor_view_format_as_unit (unit, buf, sizeof (buf), y, yres);
+ gtk_label_set_text (GTK_LABEL (view->priv->unit_y_label), buf);
+ gimp_cursor_view_set_label_italic (view->priv->unit_y_label, ! in_image);
+
+ int_x = (gint) floor (x);
+ int_y = (gint) floor (y);
+
+ if (gimp_image_pick_color (image, NULL,
+ int_x, int_y,
+ view->priv->shell->show_all,
+ view->priv->sample_merged,
+ FALSE, 0.0,
+ &sample_format, pixel, &color))
+ {
+ gimp_color_frame_set_color (GIMP_COLOR_FRAME (view->priv->color_frame_1),
+ FALSE, sample_format, pixel, &color,
+ int_x, int_y);
+ gimp_color_frame_set_color (GIMP_COLOR_FRAME (view->priv->color_frame_2),
+ FALSE, sample_format, pixel, &color,
+ int_x, int_y);
+ }
+ else
+ {
+ gimp_color_frame_set_invalid (GIMP_COLOR_FRAME (view->priv->color_frame_1));
+ gimp_color_frame_set_invalid (GIMP_COLOR_FRAME (view->priv->color_frame_2));
+ }
+
+ /* Show the selection info from the image under the cursor if any */
+ gimp_cursor_view_update_selection_info (view,
+ image,
+ view->priv->cursor_unit);
+
+ g_clear_object (&view->priv->cursor_image);
+ }
+ else
+ {
+ gtk_label_set_text (GTK_LABEL (view->priv->pixel_x_label), _("n/a"));
+ gtk_label_set_text (GTK_LABEL (view->priv->pixel_y_label), _("n/a"));
+ gtk_label_set_text (GTK_LABEL (view->priv->unit_x_label), _("n/a"));
+ gtk_label_set_text (GTK_LABEL (view->priv->unit_y_label), _("n/a"));
+
+ gimp_color_frame_set_invalid (GIMP_COLOR_FRAME (view->priv->color_frame_1));
+ gimp_color_frame_set_invalid (GIMP_COLOR_FRAME (view->priv->color_frame_2));
+
+ /* Start showing selection info from the active image again */
+ gimp_cursor_view_update_selection_info (view,
+ view->priv->image,
+ view->priv->unit);
+ }
+
+ view->priv->cursor_idle_id = 0;
+
+ return G_SOURCE_REMOVE;
+}
+
+
+/* public functions */
+
+GtkWidget *
+gimp_cursor_view_new (GimpMenuFactory *menu_factory)
+{
+ g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
+
+ return g_object_new (GIMP_TYPE_CURSOR_VIEW,
+ "menu-factory", menu_factory,
+ "menu-identifier", "<CursorInfo>",
+ "ui-path", "/cursor-info-popup",
+ NULL);
+}
+
+void
+gimp_cursor_view_set_sample_merged (GimpCursorView *view,
+ gboolean sample_merged)
+{
+ g_return_if_fail (GIMP_IS_CURSOR_VIEW (view));
+
+ sample_merged = sample_merged ? TRUE : FALSE;
+
+ if (view->priv->sample_merged != sample_merged)
+ {
+ view->priv->sample_merged = sample_merged;
+
+ g_object_notify (G_OBJECT (view), "sample-merged");
+ }
+}
+
+gboolean
+gimp_cursor_view_get_sample_merged (GimpCursorView *view)
+{
+ g_return_val_if_fail (GIMP_IS_CURSOR_VIEW (view), FALSE);
+
+ return view->priv->sample_merged;
+}
+
+void
+gimp_cursor_view_update_cursor (GimpCursorView *view,
+ GimpImage *image,
+ GimpUnit shell_unit,
+ gdouble x,
+ gdouble y)
+{
+ g_return_if_fail (GIMP_IS_CURSOR_VIEW (view));
+ g_return_if_fail (GIMP_IS_IMAGE (image));
+
+ g_clear_object (&view->priv->cursor_image);
+
+ view->priv->cursor_image = g_object_ref (image);
+ view->priv->cursor_unit = shell_unit;
+ view->priv->cursor_x = x;
+ view->priv->cursor_y = y;
+
+ if (view->priv->cursor_idle_id == 0)
+ {
+ view->priv->cursor_idle_id =
+ g_idle_add ((GSourceFunc) gimp_cursor_view_cursor_idle, view);
+ }
+}
+
+void
+gimp_cursor_view_clear_cursor (GimpCursorView *view)
+{
+ g_return_if_fail (GIMP_IS_CURSOR_VIEW (view));
+
+ g_clear_object (&view->priv->cursor_image);
+
+ if (view->priv->cursor_idle_id == 0)
+ {
+ view->priv->cursor_idle_id =
+ g_idle_add ((GSourceFunc) gimp_cursor_view_cursor_idle, view);
+ }
+}