[gimp/jsbueno/zommable_curves: 2/4] Horizontal zoom for Curves Tool



commit d9189c1cafea9058bc3a4abc3e9d061fa163ab0a
Author: João S. O. Bueno <gwidion gmail com>
Date:   Thu May 15 13:33:29 2014 -0300

    Horizontal zoom for Curves Tool
    
    Working, but for the histogram, or "range x" bar
    zooming.

 app/tools/gimpcurvestool.c  |  190 +++++++++++++++++++++++++++++++++++++++--
 app/tools/gimpcurvestool.h  |   17 +++-
 app/widgets/gimpcurveview.c |  200 ++++++++++++++++++++++++++++++++++++------
 app/widgets/gimpcurveview.h |   13 +++-
 4 files changed, 379 insertions(+), 41 deletions(-)
---
diff --git a/app/tools/gimpcurvestool.c b/app/tools/gimpcurvestool.c
index a62b216..311b67e 100644
--- a/app/tools/gimpcurvestool.c
+++ b/app/tools/gimpcurvestool.c
@@ -59,6 +59,8 @@
 #define BAR_SIZE    12
 #define RADIUS       4
 
+#define CURVES_SCROLLBAR_STEP_SIZE 0.05
+#define CURVES_SCROLLBAR_PAGE_SIZE 0.75
 
 /*  local function prototypes  */
 
@@ -67,15 +69,25 @@ static void       gimp_curves_tool_constructed     (GObject              *object
 static gboolean   gimp_curves_tool_initialize      (GimpTool             *tool,
                                                     GimpDisplay          *display,
                                                     GError              **error);
+
+static gboolean   gimp_curves_tool_key_press       (GimpTool             *tool,
+                                                    GdkEventKey          *kevent,
+                                                    GimpDisplay          *display);
+
 static void       gimp_curves_tool_button_release  (GimpTool             *tool,
                                                     const GimpCoords     *coords,
                                                     guint32               time,
                                                     GdkModifierType       state,
                                                     GimpButtonReleaseType release_type,
                                                     GimpDisplay          *display);
-static gboolean   gimp_curves_tool_key_press       (GimpTool             *tool,
-                                                    GdkEventKey          *kevent,
-                                                    GimpDisplay          *display);
+
+static gboolean   gimp_curves_tool_control_events  (GtkWidget            *widget,
+                                                    GdkEvent             *event,
+                                                    GimpCurvesTool       *tool);
+
+static void       gimp_curves_tool_zoom            (GimpCurvesTool       *tool,
+                                                    GimpZoomType         zoom_type);
+
 static void       gimp_curves_tool_oper_update     (GimpTool             *tool,
                                                     const GimpCoords     *coords,
                                                     GdkModifierType       state,
@@ -105,6 +117,8 @@ static void       gimp_curves_tool_reset           (GimpFilterTool       *filter
 static gboolean   gimp_curves_tool_settings_import (GimpFilterTool       *filter_tool,
                                                     GInputStream         *input,
                                                     GError              **error);
+
+
 static gboolean   gimp_curves_tool_settings_export (GimpFilterTool       *filter_tool,
                                                     GOutputStream        *output,
                                                     GError              **error);
@@ -118,6 +132,13 @@ static void       gimp_curves_tool_config_notify   (GObject              *object
                                                     GParamSpec           *pspec,
                                                     GimpCurvesTool       *tool);
 
+
+static void       gimp_curves_tool_scrollbar_update(GtkAdjustment       *adjustment,
+                                                    GimpCurvesTool      *tool);
+static void       gimp_curves_tool_set_offsets     (GimpCurvesTool      *tool,
+                                                    gdouble             starting_offset,
+                                                    gdouble             ending_offset);
+
 static void       curves_channel_callback          (GtkWidget            *widget,
                                                     GimpCurvesTool       *tool);
 static void       curves_channel_reset_callback    (GtkWidget            *widget,
@@ -133,6 +154,7 @@ static gboolean   curves_get_channel_color         (GtkWidget            *widget
                                                     GimpHistogramChannel  channel,
                                                     GimpRGB              *color);
 
+static const GimpRGB * curves_get_channel_color    (GimpHistogramChannel  channel);
 
 G_DEFINE_TYPE (GimpCurvesTool, gimp_curves_tool, GIMP_TYPE_FILTER_TOOL)
 
@@ -316,6 +338,111 @@ gimp_curves_tool_key_press (GimpTool    *tool,
   return GIMP_TOOL_CLASS (parent_class)->key_press (tool, kevent, display);
 }
 
+/* Zoom Control */
+static gboolean
+gimp_curves_tool_control_events (GtkWidget          *widget,
+                                 GdkEvent           *event,
+                                 GimpCurvesTool     *tool)
+
+{
+  if (event->type == GDK_SCROLL)
+    {
+      GdkEventScroll *sevent = (GdkEventScroll *) event;
+
+      if (sevent->state & gimp_get_toggle_behavior_mask ())
+        {
+          if (sevent->direction == GDK_SCROLL_UP)
+            gimp_curves_tool_zoom (tool, GIMP_ZOOM_IN);
+          else
+            gimp_curves_tool_zoom (tool, GIMP_ZOOM_OUT);
+        }
+      else
+        {
+          GtkAdjustment *adj = tool->scroll_data;
+          gfloat new_value;
+          new_value = (gtk_adjustment_get_value (adj) +
+                       ((sevent->direction == GDK_SCROLL_UP) ?
+                        - gtk_adjustment_get_page_increment (adj) / 2 :
+                        gtk_adjustment_get_page_increment (adj) / 2));
+          new_value = CLAMP (new_value,
+                             gtk_adjustment_get_lower (adj),
+                             gtk_adjustment_get_upper (adj) -
+                             gtk_adjustment_get_page_size (adj));
+          gtk_adjustment_set_value (adj, new_value);
+        }
+
+      return TRUE;
+    }
+  return FALSE;
+}
+
+/* FIXME: As of now, almost a verbatim copy
+ * of gimp_gradient_editor_zoom -
+ * maybe it should be factored-out
+ */
+static void
+gimp_curves_tool_zoom (GimpCurvesTool *tool,
+                       GimpZoomType    zoom_type)
+{
+  GtkAdjustment *adjustment;
+  gdouble        old_value;
+  gdouble        old_page_size;
+  gdouble        value     = 0.0;
+  gdouble        page_size = 1.0;
+
+  g_return_if_fail (GIMP_IS_CURVES_TOOL (tool));
+
+  adjustment = tool->scroll_data;
+
+  old_value     = gtk_adjustment_get_value (adjustment);
+  old_page_size = gtk_adjustment_get_page_size (adjustment);
+
+    switch (zoom_type)
+    {
+    case GIMP_ZOOM_IN_MAX:
+    case GIMP_ZOOM_IN_MORE:
+    case GIMP_ZOOM_IN:
+      tool->zoom_factor++;
+
+      page_size = 1.0 / tool->zoom_factor;
+      value     = old_value + (old_page_size - page_size) / 2.0;
+      break;
+
+    case GIMP_ZOOM_OUT_MORE:
+    case GIMP_ZOOM_OUT:
+      if (tool->zoom_factor <= 1)
+        return;
+
+      tool->zoom_factor--;
+
+      page_size = 1.0 / tool->zoom_factor;
+      value     = old_value - (page_size - old_page_size) / 2.0;
+
+      if (value < 0.0)
+        value = 0.0;
+      else if ((value + page_size) > 1.0)
+        value = 1.0 - page_size;
+      break;
+
+    case GIMP_ZOOM_OUT_MAX:
+    case GIMP_ZOOM_TO: /* abused as ZOOM_ALL */
+      tool->zoom_factor = 1;
+
+      value     = 0.0;
+      page_size = 1.0;
+      break;
+    }
+
+  gtk_adjustment_configure (adjustment,
+                            value,
+                            gtk_adjustment_get_lower (adjustment),
+                            gtk_adjustment_get_upper (adjustment),
+                            page_size * CURVES_SCROLLBAR_STEP_SIZE,
+                            page_size * CURVES_SCROLLBAR_PAGE_SIZE,
+                            page_size);
+}
+
+
 static void
 gimp_curves_tool_oper_update (GimpTool         *tool,
                               const GimpCoords *coords,
@@ -554,6 +681,12 @@ gimp_curves_tool_dialog (GimpFilterTool *filter_tool)
                           G_OBJECT (tool->graph),  "histogram-scale",
                           G_BINDING_SYNC_CREATE |
                           G_BINDING_BIDIRECTIONAL);
+  g_signal_connect (tool->graph, "event",
+                    G_CALLBACK (gimp_curves_tool_control_events),
+                    tool);
+
+  gimp_histogram_options_connect_view (GIMP_HISTOGRAM_OPTIONS (tool_options),
+                                       GIMP_HISTOGRAM_VIEW (tool->graph));
 
   /*  The bottom color bar  */
   hbox2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
@@ -576,9 +709,29 @@ gimp_curves_tool_dialog (GimpFilterTool *filter_tool)
   gtk_box_pack_start (GTK_BOX (vbox), tool->xrange, TRUE, TRUE, 0);
   gtk_widget_show (tool->xrange);
 
-  bar = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
-  gtk_box_pack_start (GTK_BOX (vbox), bar, TRUE, TRUE, 0);
-  gtk_widget_show (bar);
+  tool->horizontal_scale = gimp_color_bar_new (GTK_ORIENTATION_HORIZONTAL);
+  gtk_box_pack_start (GTK_BOX (vbox), tool->horizontal_scale, TRUE, TRUE, 0);
+  gtk_widget_show (tool->horizontal_scale);
+
+  /* Scrollbar */
+
+  tool->zoom_factor = 1;
+
+  tool->scroll_data = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 1.0,
+                                                          CURVES_SCROLLBAR_STEP_SIZE,
+                                                          CURVES_SCROLLBAR_PAGE_SIZE,
+                                                          1.0));
+  g_signal_connect (tool->scroll_data, "value-changed",
+                    G_CALLBACK (gimp_curves_tool_scrollbar_update),
+                    tool);
+  g_signal_connect (tool->scroll_data, "changed",
+                    G_CALLBACK (gimp_curves_tool_scrollbar_update),
+                    tool);
+
+  tool->scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_HORIZONTAL,
+                                       tool->scroll_data);
+  gtk_box_pack_start (GTK_BOX (vbox), tool->scrollbar, FALSE, FALSE, 0);
+  gtk_widget_show (tool->scrollbar);
 
   gtk_widget_show (table);
 
@@ -806,6 +959,31 @@ gimp_curves_tool_config_notify (GObject        *object,
 }
 
 static void
+gimp_curves_tool_scrollbar_update (GtkAdjustment      *adj,
+                                   GimpCurvesTool *tool)
+{
+  gimp_curves_tool_set_offsets (tool,
+                                gtk_adjustment_get_value (adj),
+                                gtk_adjustment_get_value (adj) +
+                                gtk_adjustment_get_page_size (adj));
+}
+
+static void
+gimp_curves_tool_set_offsets (GimpCurvesTool *tool,
+                              gdouble starting_offset,
+                              gdouble ending_offset)
+{
+
+  gimp_curve_view_set_left_offset (tool->graph, starting_offset);
+  gimp_curve_view_set_right_offset (tool->graph, ending_offset);
+
+  gimp_color_bar_set_starting (GIMP_COLOR_BAR (tool->horizontal_scale),
+                               starting_offset);
+  gimp_color_bar_set_ending  (GIMP_COLOR_BAR (tool->horizontal_scale),
+                              ending_offset);
+}
+
+static void
 curves_channel_callback (GtkWidget      *widget,
                          GimpCurvesTool *tool)
 {
diff --git a/app/tools/gimpcurvestool.h b/app/tools/gimpcurvestool.h
index ea2d5ff..bcf27a2 100644
--- a/app/tools/gimpcurvestool.h
+++ b/app/tools/gimpcurvestool.h
@@ -39,11 +39,18 @@ struct _GimpCurvesTool
   /* dialog */
   gdouble           picked_color[5];
 
-  GtkWidget        *channel_menu;
-  GtkWidget        *xrange;
-  GtkWidget        *yrange;
-  GtkWidget        *graph;
-  GtkWidget        *curve_type;
+ GtkWidget            *channel_menu;
+  GtkWidget            *xrange;
+  GtkWidget            *yrange;
+  GtkWidget            *graph;
+  GtkWidget            *curve_type;
+  GtkWidget            *horizontal_scale;
+  GtkWidget            *scrollbar;
+
+  /* zoom and scroll control */
+
+  guint                 zoom_factor;
+  GtkAdjustment        *scroll_data;
 
   /* export dialog */
   gboolean          export_old_format;
diff --git a/app/widgets/gimpcurveview.c b/app/widgets/gimpcurveview.c
index 08e9795..e0eaf9c 100644
--- a/app/widgets/gimpcurveview.c
+++ b/app/widgets/gimpcurveview.c
@@ -47,7 +47,9 @@ enum
   PROP_GRID_ROWS,
   PROP_GRID_COLUMNS,
   PROP_X_AXIS_LABEL,
-  PROP_Y_AXIS_LABEL
+  PROP_Y_AXIS_LABEL,
+  PROP_LEFT_OFFSET,
+  PROP_RIGHT_OFFSET
 };
 
 enum
@@ -100,7 +102,7 @@ static void       gimp_curve_view_paste_clipboard (GimpCurveView    *view);
 static void       gimp_curve_view_set_cursor      (GimpCurveView    *view,
                                                    gdouble           x,
                                                    gdouble           y);
-static void       gimp_curve_view_unset_cursor    (GimpCurveView *view);
+static void       gimp_curve_view_unset_cursor    (GimpCurveView    *view);
 
 
 G_DEFINE_TYPE (GimpCurveView, gimp_curve_view,
@@ -170,6 +172,19 @@ gimp_curve_view_class_init (GimpCurveViewClass *klass)
                                                         NULL,
                                                         GIMP_PARAM_READWRITE));
 
+  g_object_class_install_property (object_class, PROP_LEFT_OFFSET,
+                                   g_param_spec_double ("left-offset", NULL, NULL,
+                                                        -1000000.0, 1000000.0,
+                                                        0.0,
+                                                        GIMP_PARAM_READWRITE));
+
+  g_object_class_install_property (object_class, PROP_RIGHT_OFFSET,
+                                   g_param_spec_double ("right-offset", NULL, NULL,
+                                                        -1000000.0, 1000000.0,
+                                                        255.0,
+                                                        GIMP_PARAM_READWRITE));
+
+
   curve_view_signals[CUT_CLIPBOARD] =
     g_signal_new ("cut-clipboard",
                   G_TYPE_FROM_CLASS (klass),
@@ -222,6 +237,8 @@ gimp_curve_view_init (GimpCurveView *view)
   view->range_x_max = 1.0;
   view->range_y_min = 0.0;
   view->range_y_max = 1.0;
+  view->left_offset = 0.0;
+  view->right_offset= 1.0;
 
   view->x_axis_label = NULL;
   view->y_axis_label = NULL;
@@ -309,6 +326,12 @@ gimp_curve_view_set_property (GObject      *object,
     case PROP_Y_AXIS_LABEL:
       gimp_curve_view_set_y_axis_label (view, g_value_get_string (value));
       break;
+    case PROP_LEFT_OFFSET:
+        gimp_curve_view_set_left_offset (view, g_value_get_double (value));
+        break;
+    case PROP_RIGHT_OFFSET:
+        gimp_curve_view_set_right_offset (view, g_value_get_double (value));
+        break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
@@ -343,12 +366,73 @@ gimp_curve_view_get_property (GObject    *object,
     case PROP_Y_AXIS_LABEL:
       g_value_set_string (value, view->y_axis_label);
       break;
+    case PROP_LEFT_OFFSET:
+      g_value_set_double (value, view->left_offset);
+      break;
+    case PROP_RIGHT_OFFSET:
+      g_value_set_double (value, view->right_offset);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
       break;
     }
 }
 
+static gdouble
+gimp_curve_view_x_to_curve_coord (GimpCurveView *view,
+                                  gdouble x_value)
+{
+  gdouble range = view->right_offset - view->left_offset;
+  return view->left_offset + x_value * range;
+}
+
+static gdouble
+gimp_curve_view_x_to_display_coord (GimpCurveView *view,
+                                    gdouble x_value)
+{
+  gdouble range = view->right_offset - view->left_offset;
+  if (range == 0.0)
+    return 0;
+  return (x_value - view->left_offset) / range;
+
+}
+
+static void
+gimp_curve_view_set_point_with_offsets (GimpCurveView *view,
+                                        GimpCurve     *curve,
+                                        gint           point,
+                                        gdouble        x,
+                                        gdouble        y)
+{
+  gdouble fixed_x = gimp_curve_view_x_to_curve_coord (view, x);
+
+  gimp_curve_set_point (curve, point, fixed_x, y);
+}
+
+static void
+gimp_curve_view_get_point_with_offsets (GimpCurveView *view,
+                                        GimpCurve     *curve,
+                                        gint           point,
+                                        gdouble        *x,
+                                        gdouble        *y)
+{
+  gimp_curve_get_point (curve, point, x, y);
+  if (x != NULL)
+    {
+      *x = gimp_curve_view_x_to_display_coord (view, *x);
+    }
+}
+
+static gdouble
+gimp_curve_view_map_value_with_offsets (GimpCurveView *view,
+                                        GimpCurve *curve,
+                                        gdouble value)
+{
+  return gimp_curve_map_value (curve,
+                               gimp_curve_view_x_to_curve_coord (view,
+                                                                 value));
+}
+
 static void
 gimp_curve_view_style_set (GtkWidget *widget,
                            GtkStyle  *prev_style)
@@ -392,9 +476,16 @@ gimp_curve_view_draw_grid (GimpCurveView *view,
 
   for (i = 1; i < view->grid_columns; i++)
     {
-      gint x = i * (width - 1) / view->grid_columns;
+      /* TODO: subdivide the grid when using large zoom levels */
+
+      gdouble curve_x = (gdouble) i / view->grid_columns;
+      gdouble display_x = gimp_curve_view_x_to_display_coord(view, curve_x);
+      gint x = display_x * (width - 1);
 
-      if ((view->grid_columns % 2) == 0 && (i == view->grid_columns / 2))
+      /* if ((view->grid_columns % 2) == 0 && (i == view->grid_columns / 2))
+        continue; */
+
+      if (display_x < 0.0 || display_x > 1.0)
         continue;
 
       cairo_move_to (cr, border + x, border);
@@ -418,13 +509,18 @@ gimp_curve_view_draw_grid (GimpCurveView *view,
       cairo_line_to (cr, border + width - 1, border + y);
     }
 
-  if ((view->grid_columns % 2) == 0)
+  /* without the zoom code this was special cased,
+   * I could not figure out why
+   */
+
+  /* if ((view->grid_columns % 2) == 0)
     {
       gint x = (width - 1) / 2;
 
       cairo_move_to (cr, border + x, border);
       cairo_line_to (cr, border + x, border + height - 1);
     }
+  */
 
   cairo_set_line_width (cr, 1.0);
   cairo_stroke (cr);
@@ -440,7 +536,7 @@ gimp_curve_view_draw_point (GimpCurveView *view,
 {
   gdouble x, y;
 
-  gimp_curve_get_point (view->curve, i, &x, &y);
+  gimp_curve_view_get_point_with_offsets (view, view->curve, i, &x, &y);
 
   if (x < 0.0)
     return;
@@ -471,7 +567,7 @@ gimp_curve_view_draw_curve (GimpCurveView *view,
   gint    i;
 
   x = 0.0;
-  y = 1.0 - gimp_curve_map_value (curve, 0.0);
+  y = 1.0 - gimp_curve_view_map_value_with_offsets (view, curve, 0.0);
 
   cairo_move_to (cr,
                  border + (gdouble) (width  - 1) * x,
@@ -480,7 +576,7 @@ gimp_curve_view_draw_curve (GimpCurveView *view,
   for (i = 1; i < 256; i++)
     {
       x = (gdouble) i / 255.0;
-      y = 1.0 - gimp_curve_map_value (curve, x);
+      y = 1.0 - gimp_curve_view_map_value_with_offsets (view, curve, x);
 
       cairo_line_to (cr,
                      border + (gdouble) (width  - 1) * x,
@@ -507,6 +603,7 @@ gimp_curve_view_expose (GtkWidget      *widget,
   gint           layout_y;
   gdouble        x, y;
   gint           i;
+  gdouble        display_xpos;
 
   GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
 
@@ -641,8 +738,9 @@ gimp_curve_view_expose (GtkWidget      *widget,
           cairo_fill (cr);
        }
     }
+  display_xpos = gimp_curve_view_x_to_display_coord(view, view->xpos);
 
-  if (view->xpos >= 0.0)
+  if (display_xpos >= 0.0 && display_xpos <= 1.0)
     {
       gchar buf[32];
 
@@ -650,10 +748,10 @@ gimp_curve_view_expose (GtkWidget      *widget,
 
       /* draw the color line */
       cairo_move_to (cr,
-                     border + ROUND ((gdouble) (width - 1) * view->xpos),
+                     border + ROUND ((gdouble) (width - 1) * display_xpos),
                      border + 1);
       cairo_line_to (cr,
-                     border + ROUND ((gdouble) (width - 1) * view->xpos),
+                     border + ROUND ((gdouble) (width - 1) * display_xpos),
                      border + height - 1);
       cairo_stroke (cr);
 
@@ -689,13 +787,13 @@ gimp_curve_view_expose (GtkWidget      *widget,
       pango_layout_set_text (view->layout, buf, -1);
       pango_layout_get_pixel_size (view->layout, &layout_x, &layout_y);
 
-      if (view->xpos < 0.5)
+      if (display_xpos < 0.5)
         layout_x = border;
       else
         layout_x = -(layout_x + border);
 
       cairo_move_to (cr,
-                     border + (gdouble) width * view->xpos + layout_x,
+                     border + (gdouble) width * display_xpos + layout_x,
                      border + height - border - layout_y);
       pango_cairo_show_layout (cr, view->layout);
     }
@@ -705,6 +803,7 @@ gimp_curve_view_expose (GtkWidget      *widget,
     {
       gchar  buf[32];
       gint   w, h;
+      gdouble curve_x = gimp_curve_view_x_to_curve_coord (view, view->cursor_x);
 
       if (! view->cursor_layout)
         view->cursor_layout = gtk_widget_create_pango_layout (widget, NULL);
@@ -715,7 +814,7 @@ gimp_curve_view_expose (GtkWidget      *widget,
           /*  stupid heuristic: special-case for 0..255  */
 
           g_snprintf (buf, sizeof (buf), "x:%3d y:%3d",
-                      (gint) (view->cursor_x *
+                      (gint) (curve_x *
                               (view->range_x_max - view->range_x_min) +
                               view->range_x_min),
                       (gint) ((1.0 - view->cursor_y) *
@@ -728,7 +827,7 @@ gimp_curve_view_expose (GtkWidget      *widget,
           /*  and for 0..100  */
 
           g_snprintf (buf, sizeof (buf), "x:%0.2f y:%0.2f",
-                      view->cursor_x *
+                      curve_x *
                       (view->range_x_max - view->range_x_min) +
                       view->range_x_min,
                       (1.0 - view->cursor_y) *
@@ -738,7 +837,7 @@ gimp_curve_view_expose (GtkWidget      *widget,
       else
         {
           g_snprintf (buf, sizeof (buf), "x:%0.3f y:%0.3f",
-                      view->cursor_x *
+                      curve_x *
                       (view->range_x_max - view->range_x_min) +
                       view->range_x_min,
                       (1.0 - view->cursor_y) *
@@ -826,7 +925,9 @@ gimp_curve_view_button_press (GtkWidget      *widget,
   x = CLAMP (x, 0.0, 1.0);
   y = CLAMP (y, 0.0, 1.0);
 
-  closest_point = gimp_curve_get_closest_point (curve, x);
+  closest_point = gimp_curve_get_closest_point (
+                                  curve,
+                                  gimp_curve_view_x_to_curve_coord(view, x));
 
   view->grabbed = TRUE;
 
@@ -835,7 +936,7 @@ gimp_curve_view_button_press (GtkWidget      *widget,
   switch (gimp_curve_get_curve_type (curve))
     {
     case GIMP_CURVE_SMOOTH:
-      /*  determine the leftmost and rightmost points  */
+      /*  determine the leftmost and rightmost points of the curve (not display) */
       view->leftmost = -1.0;
       for (i = closest_point - 1; i >= 0; i--)
         {
@@ -866,14 +967,18 @@ gimp_curve_view_button_press (GtkWidget      *widget,
 
       gimp_curve_view_set_selected (view, closest_point);
 
-      gimp_curve_set_point (curve, view->selected, x, 1.0 - y);
+      gimp_curve_view_set_point_with_offsets (view,
+                                              curve,
+                                              view->selected, x, 1.0 - y);
       break;
 
     case GIMP_CURVE_FREE:
       view->last_x = x;
       view->last_y = y;
 
-      gimp_curve_set_curve (curve, x, 1.0 - y);
+      gimp_curve_set_curve (curve,
+                            gimp_curve_view_x_to_curve_coord (view, x),
+                            1.0 - y);
       break;
     }
 
@@ -929,14 +1034,19 @@ gimp_curve_view_motion_notify (GtkWidget      *widget,
   x = CLAMP (x, 0.0, 1.0);
   y = CLAMP (y, 0.0, 1.0);
 
-  closest_point = gimp_curve_get_closest_point (curve, x);
+  closest_point = gimp_curve_get_closest_point (
+                                  curve,
+                                  gimp_curve_view_x_to_curve_coord(view, x));
 
   switch (gimp_curve_get_curve_type (curve))
     {
     case GIMP_CURVE_SMOOTH:
       if (! view->grabbed) /*  If no point is grabbed...  */
         {
-          gimp_curve_get_point (curve, closest_point, &point_x, NULL);
+          gimp_curve_view_get_point_with_offsets (view,
+                                                  curve,
+                                                  closest_point,
+                                                  &point_x, NULL);
 
           if (point_x >= 0.0)
             new_cursor = GDK_FLEUR;
@@ -945,24 +1055,26 @@ gimp_curve_view_motion_notify (GtkWidget      *widget,
         }
       else /*  Else, drag the grabbed point  */
         {
+          gdouble curve_x = gimp_curve_view_x_to_curve_coord(view, x);
+
           new_cursor = GDK_TCROSS;
 
           gimp_data_freeze (GIMP_DATA (curve));
 
           gimp_curve_set_point (curve, view->selected, -1.0, -1.0);
 
-          if (x > view->leftmost && x < view->rightmost)
+          if (curve_x > view->leftmost && curve_x < view->rightmost)
             {
               gint n_points = gimp_curve_get_n_points (curve);
 
-              closest_point = ROUND (x * (gdouble) (n_points - 1));
+              closest_point = ROUND (curve_x * (gdouble) (n_points - 1));
 
               gimp_curve_get_point (curve, closest_point, &point_x, NULL);
 
               if (point_x < 0.0)
                 gimp_curve_view_set_selected (view, closest_point);
 
-              gimp_curve_set_point (curve, view->selected, x, 1.0 - y);
+              gimp_curve_set_point (curve, view->selected, curve_x, 1.0 - y);
             }
 
           gimp_data_thaw (GIMP_DATA (curve));
@@ -1004,7 +1116,9 @@ gimp_curve_view_motion_notify (GtkWidget      *widget,
                   gdouble xpos = (gdouble) i / (gdouble) (n_samples - 1);
                   gdouble ypos = (y1 + ((y2 - y1) * (xpos - x1)) / (x2 - x1));
 
-                  xpos = CLAMP (xpos, 0.0, 1.0);
+                  xpos = gimp_curve_view_x_to_curve_coord(
+                                                     view,
+                                                     CLAMP (xpos, 0.0, 1.0));
                   ypos = CLAMP (ypos, 0.0, 1.0);
 
                   gimp_curve_set_curve (curve, xpos, 1.0 - ypos);
@@ -1061,14 +1175,15 @@ gimp_curve_view_key_press (GtkWidget   *widget,
       gint    i = view->selected;
       gdouble x, y;
 
-      gimp_curve_get_point (curve, i, NULL, &y);
+      gimp_curve_view_get_point_with_offsets (view, curve, i, NULL, &y);
 
       switch (kevent->keyval)
         {
         case GDK_KEY_Left:
           for (i = i - 1; i >= 0 && ! handled; i--)
             {
-              gimp_curve_get_point (curve, i, &x, NULL);
+              gimp_curve_view_get_point_with_offsets (view,
+                                                      curve, i, &x, NULL);
 
               if (x >= 0.0)
                 {
@@ -1082,7 +1197,8 @@ gimp_curve_view_key_press (GtkWidget   *widget,
         case GDK_KEY_Right:
           for (i = i + 1; i < curve->n_points && ! handled; i++)
             {
-              gimp_curve_get_point (curve, i, &x, NULL);
+              gimp_curve_view_get_point_with_offsets (view,
+                                                      curve, i, &x, NULL);
 
               if (x >= 0.0)
                 {
@@ -1371,6 +1487,14 @@ gimp_curve_view_set_range_x (GimpCurveView *view,
   view->range_x_min = min;
   view->range_x_max = max;
 
+  /* Reset the viewing slice as if zoom factor is 1.0
+   * if this causes strange behavior, if that
+   * is not the case, calling code should set
+   * left_ and right_ offsets after setting the range
+   */
+  view->left_offset = 0.0;
+  view->right_offset = 1.0;
+
   gtk_widget_queue_draw (GTK_WIDGET (view));
 }
 
@@ -1430,6 +1554,23 @@ gimp_curve_view_set_y_axis_label (GimpCurveView *view,
   gtk_widget_queue_draw (GTK_WIDGET (view));
 }
 
+void
+gimp_curve_view_set_left_offset (GimpCurveView *view,
+                                 gdouble value)
+{
+  g_return_if_fail (GIMP_IS_CURVE_VIEW (view));
+  view->left_offset = value;
+  gtk_widget_queue_draw (GTK_WIDGET (view));
+}
+
+void
+gimp_curve_view_set_right_offset (GimpCurveView *view,
+                                  gdouble value)
+{
+  g_return_if_fail (GIMP_IS_CURVE_VIEW (view));
+  view->right_offset = value;
+  gtk_widget_queue_draw (GTK_WIDGET (view));
+}
 
 /*  private functions  */
 
@@ -1454,3 +1595,4 @@ gimp_curve_view_unset_cursor (GimpCurveView *view)
   /* TODO: only invalidate the cursor label area */
   gtk_widget_queue_draw (GTK_WIDGET (view));
 }
+
diff --git a/app/widgets/gimpcurveview.h b/app/widgets/gimpcurveview.h
index 6b1cdb9..b029807 100644
--- a/app/widgets/gimpcurveview.h
+++ b/app/widgets/gimpcurveview.h
@@ -65,6 +65,14 @@ struct _GimpCurveView
   gdouble            range_y_min;
   gdouble            range_y_max;
 
+  /* Used for showing a partial curve when zooming in */
+  gdouble            left_offset;
+  gdouble            right_offset;
+
+  /*
+   *gdouble          top_offset;
+   *gdouble          bottom_offset;
+   */
   gdouble            cursor_x;
   gdouble            cursor_y;
   PangoLayout       *cursor_layout;
@@ -116,6 +124,9 @@ void        gimp_curve_view_set_x_axis_label  (GimpCurveView *view,
                                                const gchar   *label);
 void        gimp_curve_view_set_y_axis_label  (GimpCurveView *view,
                                                const gchar   *label);
-
+void        gimp_curve_view_set_left_offset   (GimpCurveView *view,
+                                              gdouble         value);
+void        gimp_curve_view_set_right_offset  (GimpCurveView *view,
+                                              gdouble         value);
 
 #endif /* __GIMP_CURVE_VIEW_H__ */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]