[gimp/wip/Jehan/issue-498-quick-brush-edit: 115/117] app: new double action "tools-mypaint-brush-pixel-size-set", used as…




commit d0fde4a3f19fecd44b39d36d04635dab278cdb8e
Author: Jehan <jehan girinstud io>
Date:   Sat Apr 2 22:29:46 2022 +0200

    app: new double action "tools-mypaint-brush-pixel-size-set", used as…
    
    … new action_pixel_size of GimpMyBrushTool.
    
    MyPaint brush tool clearly shows the limits of my trick to have some
    enum actions work with absolute values whereas others work with
    per-mille values between the property min and max.
    
    Indeed firstly MyBrush's "radius" value is logarithmic and can be
    negative. Since the enum trick relies on the fact that negative values
    are the semantic enumerated constants, it's broken in such case. The
    second issue is that while it was acceptable to use int size for most
    paint tools (even though they were double), here radius only goes from
    -2.0 to 6.0; so using int values only would leave us with jumping brush
    sizes.
    
    So now I create a proper double action which simply takes pixel size and
    use this from the on-canvas brush size changing. No weird trick, no int
    or sign limitations.
    I also add a new optional action_pixel_size in GimpToolControl.
    
    Note: I'm also updating a bit the logic for the MyPaint brush outline
    function gimp_mybrush_tool_get_outline(). Indeed after skimming a bit
    through mypaint-brush.c code in libmypaint, I am not sure at all we need
    to use the offset_by_random like this. And really this shown outline
    seems more indicative than anything else when I see the actual size
    printed by the various brushes. Finally here it was counter-productive
    as I needed to get easily the logarithmic radius from the pointer
    interaction on canvas.

 app/actions/tools-actions.c                | 11 ++++++++
 app/actions/tools-commands.c               | 36 ++++++++++++++++++++++++
 app/actions/tools-commands.h               |  3 ++
 app/display/gimpdisplayshell-tool-events.c | 45 ++++++++++++++++++++----------
 app/tools/gimpmybrushtool.c                | 25 +++++++++++------
 app/tools/gimptoolcontrol.c                | 23 +++++++++++++++
 app/tools/gimptoolcontrol.h                | 23 ++++++++++++++-
 7 files changed, 143 insertions(+), 23 deletions(-)
---
diff --git a/app/actions/tools-actions.c b/app/actions/tools-actions.c
index b78681c16d..54baea36bc 100644
--- a/app/actions/tools-actions.c
+++ b/app/actions/tools-actions.c
@@ -224,6 +224,13 @@ static const GimpEnumActionEntry tools_mybrush_radius_actions[] =
     NULL }
 };
 
+static const GimpDoubleActionEntry tools_mybrush_pixel_size_actions[] =
+{
+  { "tools-mypaint-brush-pixel-size-set", GIMP_ICON_TOOL_MYPAINT_BRUSH,
+    "Set MyPaint Brush Diameter in pixel", NULL, NULL,
+    1.0, NULL }
+};
+
 static const GimpEnumActionEntry tools_mybrush_hardness_actions[] =
 {
   { "tools-mypaint-brush-hardness-set", GIMP_ICON_TOOL_MYPAINT_BRUSH,
@@ -697,6 +704,10 @@ tools_actions_setup (GimpActionGroup *group)
                                       tools_mybrush_radius_actions,
                                       G_N_ELEMENTS (tools_mybrush_radius_actions),
                                       tools_mybrush_radius_cmd_callback);
+  gimp_action_group_add_double_actions (group, NULL,
+                                        tools_mybrush_pixel_size_actions,
+                                        G_N_ELEMENTS (tools_mybrush_pixel_size_actions),
+                                        tools_mybrush_pixel_size_cmd_callback);
   gimp_action_group_add_enum_actions (group, NULL,
                                       tools_mybrush_hardness_actions,
                                       G_N_ELEMENTS (tools_mybrush_hardness_actions),
diff --git a/app/actions/tools-commands.c b/app/actions/tools-commands.c
index b840e7f3c3..e15eab59db 100644
--- a/app/actions/tools-commands.c
+++ b/app/actions/tools-commands.c
@@ -466,6 +466,42 @@ tools_mybrush_radius_cmd_callback (GimpAction *action,
     }
 }
 
+void
+tools_mybrush_pixel_size_cmd_callback (GimpAction *action,
+                                       GVariant   *value,
+                                       gpointer    data)
+{
+  GimpContext          *context;
+  GimpToolInfo         *tool_info;
+  gdouble               dvalue;
+  return_if_no_context (context, data);
+
+  dvalue = g_variant_get_double (value);
+  /* Dividing by 2.0 because the parameter is the size of the brush,
+   * hence the diameter and this tool uses the radius as parameter.
+   * Furthermore MyPaint brush radius is stored as a natural logarithm
+   * radius.
+   */
+  dvalue = log (dvalue / 2.0);
+
+  tool_info = gimp_context_get_tool (context);
+
+  if (tool_info && GIMP_IS_MYBRUSH_OPTIONS (tool_info->tool_options))
+    {
+      GParamSpec *pspec;
+
+      pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (tool_info->tool_options),
+                                            "radius");
+      dvalue = CLAMP (dvalue,
+                      G_PARAM_SPEC_DOUBLE (pspec)->minimum,
+                      G_PARAM_SPEC_DOUBLE (pspec)->maximum);
+
+      g_object_set (G_OBJECT (tool_info->tool_options),
+                    "radius", dvalue,
+                    NULL);
+    }
+}
+
 void
 tools_mybrush_hardness_cmd_callback (GimpAction *action,
                                      GVariant   *value,
diff --git a/app/actions/tools-commands.h b/app/actions/tools-commands.h
index 38ab455b25..fa77369e32 100644
--- a/app/actions/tools-commands.h
+++ b/app/actions/tools-commands.h
@@ -68,6 +68,9 @@ void   tools_airbrush_flow_cmd_callback             (GimpAction *action,
 void   tools_mybrush_radius_cmd_callback            (GimpAction *action,
                                                      GVariant   *value,
                                                      gpointer    data);
+void   tools_mybrush_pixel_size_cmd_callback        (GimpAction *action,
+                                                     GVariant   *value,
+                                                     gpointer    data);
 void   tools_mybrush_hardness_cmd_callback          (GimpAction *action,
                                                      GVariant   *value,
                                                      gpointer    data);
diff --git a/app/display/gimpdisplayshell-tool-events.c b/app/display/gimpdisplayshell-tool-events.c
index b86abb6cec..49998fd4f5 100644
--- a/app/display/gimpdisplayshell-tool-events.c
+++ b/app/display/gimpdisplayshell-tool-events.c
@@ -47,6 +47,7 @@
 #include "widgets/gimpdevicemanager.h"
 #include "widgets/gimpdevices.h"
 #include "widgets/gimpdialogfactory.h"
+#include "widgets/gimpdoubleaction.h"
 #include "widgets/gimpenumaction.h"
 #include "widgets/gimpuimanager.h"
 #include "widgets/gimpwidgets-utils.h"
@@ -138,9 +139,9 @@ static void       gimp_display_shell_untransform_event_coords (GimpDisplayShell
                                                                GimpCoords        *image_coords,
                                                                gboolean          *update_software_cursor);
 
-static void       gimp_display_shell_activate_enum_action     (GimpUIManager     *manager,
+static void       gimp_display_shell_activate_action          (GimpUIManager     *manager,
                                                                const gchar       *action_desc,
-                                                               gint               value);
+                                                               GVariant          *value);
 
 
 /*  public functions  */
@@ -1725,18 +1726,31 @@ gimp_display_shell_handle_scrolling (GimpDisplayShell *shell,
 
       /* TODO: different logics with "lock brush to view". */
       /* TODO 2: scale aware? */
-      action = gimp_tool_control_get_action_size (active_tool->control);
-
+      action = gimp_tool_control_get_action_pixel_size (active_tool->control);
       if (action)
         {
           GimpImageWindow *window  = gimp_display_shell_get_window (shell);
           GimpUIManager   *manager = gimp_image_window_get_ui_manager (window);
 
-          /* Special trick with these enum actions. If using any
-           * positive value, we get the GIMP_ACTION_SELECT_SET behavior
-           * which sets to the given value.
-           */
-          gimp_display_shell_activate_enum_action (manager, action, size);
+          gimp_display_shell_activate_action (manager, action,
+                                              g_variant_new_double ((gdouble) size));
+        }
+      else
+        {
+          action = gimp_tool_control_get_action_size (active_tool->control);
+
+          if (action)
+            {
+              GimpImageWindow *window  = gimp_display_shell_get_window (shell);
+              GimpUIManager   *manager = gimp_image_window_get_ui_manager (window);
+
+              /* Special trick with these enum actions. If using any
+               * positive value, we get the GIMP_ACTION_SELECT_SET behavior
+               * which sets to the given value.
+               */
+              gimp_display_shell_activate_action (manager, action,
+                                                  g_variant_new_int32 (size));
+            }
         }
     }
   else
@@ -2155,9 +2169,9 @@ gimp_display_shell_untransform_event_coords (GimpDisplayShell *shell,
 }
 
 static void
-gimp_display_shell_activate_enum_action (GimpUIManager *manager,
-                                         const gchar   *action_desc,
-                                         gint           value)
+gimp_display_shell_activate_action (GimpUIManager *manager,
+                                    const gchar   *action_desc,
+                                    GVariant      *value)
 {
   gchar *group_name;
   gchar *action_name;
@@ -2176,8 +2190,11 @@ gimp_display_shell_activate_enum_action (GimpUIManager *manager,
       if (GIMP_IS_ENUM_ACTION (action) &&
           GIMP_ENUM_ACTION (action)->value_variable)
         {
-          gimp_action_emit_activate (action,
-                                     g_variant_new_int32 (value));
+          gimp_action_emit_activate (action, value);
+        }
+      else if (GIMP_IS_DOUBLE_ACTION (action))
+        {
+          gimp_action_emit_activate (action, value);
         }
     }
 
diff --git a/app/tools/gimpmybrushtool.c b/app/tools/gimpmybrushtool.c
index 4576b894e3..2a7378802f 100644
--- a/app/tools/gimpmybrushtool.c
+++ b/app/tools/gimpmybrushtool.c
@@ -94,11 +94,13 @@ gimp_mybrush_tool_init (GimpMybrushTool *mybrush_tool)
 {
   GimpTool *tool = GIMP_TOOL (mybrush_tool);
 
-  gimp_tool_control_set_tool_cursor     (tool->control, GIMP_TOOL_CURSOR_INK);
-  gimp_tool_control_set_action_size     (tool->control,
-                                         "tools/tools-mypaint-brush-radius-set");
-  gimp_tool_control_set_action_hardness (tool->control,
-                                         "tools/tools-mypaint-brush-hardness-set");
+  gimp_tool_control_set_tool_cursor       (tool->control, GIMP_TOOL_CURSOR_INK);
+  gimp_tool_control_set_action_size       (tool->control,
+                                           "tools/tools-mypaint-brush-radius-set");
+  gimp_tool_control_set_action_pixel_size (tool->control,
+                                           "tools/tools-mypaint-brush-pixel-size-set");
+  gimp_tool_control_set_action_hardness   (tool->control,
+                                           "tools/tools-mypaint-brush-hardness-set");
 
   gimp_paint_tool_enable_color_picker (GIMP_PAINT_TOOL (mybrush_tool),
                                        GIMP_COLOR_PICK_TARGET_FOREGROUND);
@@ -125,11 +127,18 @@ gimp_mybrush_tool_get_outline (GimpPaintTool *paint_tool,
                                gdouble        y)
 {
   GimpMybrushOptions *options = GIMP_MYBRUSH_TOOL_GET_OPTIONS (paint_tool);
-  GimpMybrush        *brush   = gimp_context_get_mybrush (GIMP_CONTEXT (options));
   GimpCanvasItem     *item    = NULL;
   GimpDisplayShell   *shell   = gimp_display_get_shell (display);
-
-  gdouble radius = exp (options->radius) + 2 * options->radius * gimp_mybrush_get_offset_by_random (brush);
+  gdouble             radius;
+
+  /* Radius size as used by libmypaint is logarithmic.
+   * The drawn outline in the MyBrush tool is more of a general idea of
+   * the brush size. With each brush having its own logic, actual drawn
+   * dabs may be quite different, smaller but also bigger. And there are
+   * some random elements in there too.
+   * See also mypaint-brush.c code in libmypaint.
+   */
+  radius = exp (options->radius);
   radius = MAX (MAX (4 / shell->scale_x, 4 / shell->scale_y), radius);
 
   item = gimp_mybrush_tool_create_cursor (paint_tool, display, x, y, radius);
diff --git a/app/tools/gimptoolcontrol.c b/app/tools/gimptoolcontrol.c
index d8b138683f..b6103f5395 100644
--- a/app/tools/gimptoolcontrol.c
+++ b/app/tools/gimptoolcontrol.c
@@ -98,6 +98,8 @@ gimp_tool_control_finalize (GObject *object)
   g_free (control->action_object_1);
   g_free (control->action_object_2);
 
+  g_free (control->action_pixel_size);
+
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
 
@@ -725,3 +727,24 @@ gimp_tool_control_get_action_object_2 (GimpToolControl *control)
 
   return control->action_object_2;
 }
+
+void
+gimp_tool_control_set_action_pixel_size (GimpToolControl *control,
+                                         const gchar     *action)
+{
+  g_return_if_fail (GIMP_IS_TOOL_CONTROL (control));
+
+  if (action != control->action_pixel_size)
+    {
+      g_free (control->action_pixel_size);
+      control->action_pixel_size = g_strdup (action);
+    }
+}
+
+const gchar *
+gimp_tool_control_get_action_pixel_size (GimpToolControl *control)
+{
+  g_return_val_if_fail (GIMP_IS_TOOL_CONTROL (control), NULL);
+
+  return control->action_pixel_size;
+}
diff --git a/app/tools/gimptoolcontrol.h b/app/tools/gimptoolcontrol.h
index 855180698f..6617258cba 100644
--- a/app/tools/gimptoolcontrol.h
+++ b/app/tools/gimptoolcontrol.h
@@ -79,15 +79,31 @@ struct _GimpToolControl
   GimpToolCursorType   toggle_tool_cursor;
   GimpCursorModifier   toggle_cursor_modifier;
 
-  gchar               *action_opacity;
   gchar               *action_size;
   gchar               *action_aspect;
   gchar               *action_angle;
+
   gchar               *action_spacing;
+
+  gchar               *action_opacity;
   gchar               *action_hardness;
   gchar               *action_force;
+
   gchar               *action_object_1;
   gchar               *action_object_2;
+
+  /* Enum actions have a +-/min/max values which are not necessarily so
+   * useful. They also have a variable value which works as a per mille
+   * between the min and max, so it's hard to use, especially for
+   * actions which have a huge max or which can have negative values.
+   * For instance, aspect and angle can be negative. As for size and
+   * spacing, their max value can be huge. Finally "size" can be
+   * negative for the MyPaint brush tool, which uses a logarithmic
+   * radius as base value.
+   * For this reason, we also register specialized actions with clear
+   * unit if needed.
+   */
+  gchar               *action_pixel_size;
 };
 
 struct _GimpToolControlClass
@@ -251,4 +267,9 @@ void          gimp_tool_control_set_action_object_2 (GimpToolControl *control,
 const gchar * gimp_tool_control_get_action_object_2 (GimpToolControl *control);
 
 
+void          gimp_tool_control_set_action_pixel_size (GimpToolControl *control,
+                                                       const gchar     *action);
+const gchar * gimp_tool_control_get_action_pixel_size (GimpToolControl *control);
+
+
 #endif /* __GIMP_TOOL_CONTROL_H__ */


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