示例#1
0
static void
gimp_blend_tool_push_status (GimpBlendTool   *blend_tool,
                             GdkModifierType  state,
                             GimpDisplay     *display)
{
  GimpTool *tool = GIMP_TOOL (blend_tool);
  gchar    *status_help;

  status_help = gimp_suggest_modifiers ("",
                                        (gimp_get_constrain_behavior_mask () |
                                         GDK_MOD1_MASK) &
                                        ~state,
                                        NULL,
                                        _("%s for constrained angles"),
                                        _("%s to move the whole line"));

  gimp_tool_push_status_coords (tool, display,
                                gimp_tool_control_get_precision (tool->control),
                                _("Blend: "),
                                blend_tool->end_x - blend_tool->start_x,
                                ", ",
                                blend_tool->end_y - blend_tool->start_y,
                                status_help);

  g_free (status_help);
}
示例#2
0
static void
gimp_blend_tool_active_modifier_key (GimpTool        *tool,
                                     GdkModifierType  key,
                                     gboolean         press,
                                     GdkModifierType  state,
                                     GimpDisplay     *display)
{
  GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);

  if (key == gimp_get_constrain_behavior_mask ())
    {
      gimp_blend_tool_point_motion (blend_tool, press);

      gimp_tool_pop_status (tool, display);
      gimp_blend_tool_push_status (blend_tool, state, display);

      gimp_blend_tool_update_items (blend_tool);

      gimp_blend_tool_update_graph (blend_tool);
      gimp_drawable_filter_apply (blend_tool->filter, NULL);
    }
  else if (key == GDK_MOD1_MASK)
    {
      gimp_tool_pop_status (tool, display);
      gimp_blend_tool_push_status (blend_tool, state, display);
    }
}
示例#3
0
static void
gimp_blend_tool_active_modifier_key (GimpTool        *tool,
                                     GdkModifierType  key,
                                     gboolean         press,
                                     GdkModifierType  state,
                                     GimpDisplay     *display)
{
  GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
  GimpDrawTool  *draw_tool  = GIMP_DRAW_TOOL (tool);

  if (key == gimp_get_constrain_behavior_mask ())
    {
      gimp_draw_tool_pause (draw_tool);
      gimp_blend_tool_point_motion (blend_tool, press);
      gimp_draw_tool_resume (draw_tool);

      gimp_tool_pop_status (tool, display);
      gimp_blend_tool_push_status (blend_tool, state, display);

      gimp_blend_tool_update_preview_coords (blend_tool);
      gimp_image_map_apply (blend_tool->image_map, NULL);
    }
  else if (key == GDK_MOD1_MASK)
    {
      gimp_tool_pop_status (tool, display);
      gimp_blend_tool_push_status (blend_tool, state, display);
    }
}
示例#4
0
static void
gimp_paint_tool_modifier_key (GimpTool        *tool,
                              GdkModifierType  key,
                              gboolean         press,
                              GdkModifierType  state,
                              GimpDisplay     *display)
{
  GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (tool);
  GimpDrawTool  *draw_tool  = GIMP_DRAW_TOOL (tool);

  if (paint_tool->pick_colors && ! paint_tool->draw_line)
    {
      if ((state & gimp_get_all_modifiers_mask ()) ==
          gimp_get_constrain_behavior_mask ())
        {
          if (! gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
            {
              GimpToolInfo *info = gimp_get_tool_info (display->gimp,
                                                       "gimp-color-picker-tool");

              if (GIMP_IS_TOOL_INFO (info))
                {
                  if (gimp_draw_tool_is_active (draw_tool))
                    gimp_draw_tool_stop (draw_tool);

                  gimp_color_tool_enable (GIMP_COLOR_TOOL (tool),
                                          GIMP_COLOR_OPTIONS (info->tool_options));

                  switch (GIMP_COLOR_TOOL (tool)->pick_mode)
                    {
                    case GIMP_COLOR_PICK_MODE_FOREGROUND:
                      gimp_tool_push_status (tool, display,
                                             _("Click in any image to pick the "
                                               "foreground color"));
                      break;

                    case GIMP_COLOR_PICK_MODE_BACKGROUND:
                      gimp_tool_push_status (tool, display,
                                             _("Click in any image to pick the "
                                               "background color"));
                      break;

                    default:
                      break;
                    }
                }
            }
        }
      else
        {
          if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
            {
              gimp_tool_pop_status (tool, display);
              gimp_color_tool_disable (GIMP_COLOR_TOOL (tool));
            }
        }
    }
}
示例#5
0
static void
gimp_blend_tool_button_press (GimpTool            *tool,
                              const GimpCoords    *coords,
                              guint32              time,
                              GdkModifierType      state,
                              GimpButtonPressType  press_type,
                              GimpDisplay         *display)
{
  GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);

  if (tool->display && display != tool->display)
    {
      gimp_tool_pop_status (tool, tool->display);
      gimp_blend_tool_halt (blend_tool);
    }

  blend_tool->grabbed_point = gimp_blend_tool_get_point_under_cursor (blend_tool);

  if (blend_tool->grabbed_point == POINT_NONE &&
      ! gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
    {
      blend_tool->start_x = coords->x;
      blend_tool->start_y = coords->y;

      if (gimp_blend_tool_is_shapeburst (blend_tool))
        {
          blend_tool->grabbed_point = POINT_FILL_MODE;
        }
      else
        {
          blend_tool->grabbed_point = POINT_INIT_MODE;
        }
    }
  else if ((state & GDK_MOD1_MASK) &&
           gimp_draw_tool_is_active (GIMP_DRAW_TOOL (tool)))
    {
      blend_tool->grabbed_point = POINT_BOTH;
    }

  gimp_blend_tool_point_motion (blend_tool,
                                state & gimp_get_constrain_behavior_mask ());

  tool->display = display;
  gimp_blend_tool_update_items (blend_tool);

  if (blend_tool->grabbed_point != POINT_FILL_MODE &&
      blend_tool->grabbed_point != POINT_INIT_MODE)
    {
      gimp_blend_tool_update_graph (blend_tool);
      gimp_drawable_filter_apply (blend_tool->filter, NULL);
    }

  gimp_tool_control_activate (tool->control);

  gimp_blend_tool_push_status (blend_tool, state, display);
}
示例#6
0
static void
gimp_blend_tool_motion (GimpTool         *tool,
                        const GimpCoords *coords,
                        guint32           time,
                        GdkModifierType   state,
                        GimpDisplay      *display)
{
  GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);

  /* Save the mouse coordinates from last call */
  gdouble last_x = blend_tool->mouse_x;
  gdouble last_y = blend_tool->mouse_y;

  blend_tool->mouse_x = coords->x;
  blend_tool->mouse_y = coords->y;

  if (blend_tool->grabbed_point == POINT_INIT_MODE)
    {
      GimpDrawTool *draw_tool = GIMP_DRAW_TOOL (blend_tool);

      gimp_draw_tool_pause (draw_tool);
      blend_tool->grabbed_point = POINT_END;
      gimp_draw_tool_resume (draw_tool);
    }

  /* Move the whole line if alt is pressed */
  if (state & GDK_MOD1_MASK)
    {
      gdouble dx = last_x - coords->x;
      gdouble dy = last_y - coords->y;

      blend_tool->start_x -= dx;
      blend_tool->start_y -= dy;

      blend_tool->end_x -= dx;
      blend_tool->end_y -= dy;
    }
  else
    {
      gimp_blend_tool_point_motion (blend_tool,
                                    state & gimp_get_constrain_behavior_mask ());
    }

  gimp_tool_pop_status (tool, display);
  gimp_blend_tool_push_status (blend_tool, state, display);

  if (GIMP_IS_CANVAS_LINE (blend_tool->line))
    gimp_blend_tool_update_items (blend_tool);

  gimp_blend_tool_update_preview_coords (blend_tool);
  gimp_image_map_apply (blend_tool->image_map, NULL);
}
示例#7
0
static void
gimp_blend_tool_motion (GimpTool         *tool,
                        const GimpCoords *coords,
                        guint32           time,
                        GdkModifierType   state,
                        GimpDisplay      *display)
{
  GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);

  /* Save the mouse coordinates from last call */
  gdouble last_x = blend_tool->mouse_x;
  gdouble last_y = blend_tool->mouse_y;

  blend_tool->mouse_x = coords->x;
  blend_tool->mouse_y = coords->y;

  if (blend_tool->grabbed_point == POINT_FILL_MODE ||
      blend_tool->grabbed_point == POINT_INIT_MODE)
    {
      blend_tool->grabbed_point = POINT_END;
      gimp_blend_tool_start (blend_tool, display);
    }

  /* Move the whole line if alt is pressed */
  if (blend_tool->grabbed_point == POINT_BOTH)
    {
      gdouble dx = last_x - coords->x;
      gdouble dy = last_y - coords->y;

      blend_tool->start_x -= dx;
      blend_tool->start_y -= dy;

      blend_tool->end_x -= dx;
      blend_tool->end_y -= dy;
    }
  else
    {
      gimp_blend_tool_point_motion (blend_tool,
                                    state & gimp_get_constrain_behavior_mask ());
    }

  gimp_tool_pop_status (tool, display);
  gimp_blend_tool_push_status (blend_tool, state, display);

  gimp_blend_tool_update_items (blend_tool);

  gimp_blend_tool_update_graph (blend_tool);
  gimp_drawable_filter_apply (blend_tool->filter, NULL);
}
示例#8
0
static void
gimp_paint_tool_oper_update (GimpTool         *tool,
                             const GimpCoords *coords,
                             GdkModifierType   state,
                             gboolean          proximity,
                             GimpDisplay      *display)
{
  GimpPaintTool    *paint_tool    = GIMP_PAINT_TOOL (tool);
  GimpDrawTool     *draw_tool     = GIMP_DRAW_TOOL (tool);
  GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
  GimpPaintCore    *core          = paint_tool->core;
  GimpDisplayShell *shell         = gimp_display_get_shell (display);
  GimpImage        *image         = gimp_display_get_image (display);
  GimpDrawable     *drawable      = gimp_image_get_active_drawable (image);

  if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
    {
      GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state,
                                                   proximity, display);
      return;
    }

  gimp_draw_tool_pause (draw_tool);

  if (gimp_draw_tool_is_active (draw_tool) &&
      draw_tool->display != display)
    gimp_draw_tool_stop (draw_tool);

  gimp_tool_pop_status (tool, display);

  if (tool->display            &&
      tool->display != display &&
      gimp_display_get_image (tool->display) == image)
    {
      /*  if this is a different display, but the same image, HACK around
       *  in tool internals AFTER stopping the current draw_tool, so
       *  straight line drawing works across different views of the
       *  same image.
       */

      tool->display = display;
    }

  if (drawable && proximity)
    {
      gboolean constrain_mask = gimp_get_constrain_behavior_mask ();
      gint     off_x, off_y;

      core->cur_coords = *coords;

      gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

      core->cur_coords.x -= off_x;
      core->cur_coords.y -= off_y;

      if (display == tool->display && (state & GIMP_PAINT_TOOL_LINE_MASK))
        {
          /*  If shift is down and this is not the first paint stroke,
           *  draw a line.
           */

          gchar   *status_help;
          gdouble  dx, dy, dist;

          gimp_paint_core_round_line (core, paint_options,
                                      (state & constrain_mask) != 0);

          dx = core->cur_coords.x - core->last_coords.x;
          dy = core->cur_coords.y - core->last_coords.y;

          status_help = gimp_suggest_modifiers (paint_tool->status_line,
                                                constrain_mask & ~state,
                                                NULL,
                                                _("%s for constrained angles"),
                                                NULL);

          /*  show distance in statusbar  */
          if (shell->unit == GIMP_UNIT_PIXEL)
            {
              dist = sqrt (SQR (dx) + SQR (dy));

              gimp_tool_push_status (tool, display, "%.1f %s.  %s",
                                     dist, _("pixels"), status_help);
            }
          else
            {
              gdouble xres;
              gdouble yres;
              gchar   format_str[64];

              gimp_image_get_resolution (image, &xres, &yres);

              g_snprintf (format_str, sizeof (format_str), "%%.%df %s.  %%s",
                          gimp_unit_get_digits (shell->unit),
                          gimp_unit_get_symbol (shell->unit));

              dist = (gimp_unit_get_factor (shell->unit) *
                      sqrt (SQR (dx / xres) +
                            SQR (dy / yres)));

              gimp_tool_push_status (tool, display, format_str,
                                     dist, status_help);
            }

          g_free (status_help);

          paint_tool->draw_line = TRUE;
        }
      else
        {
          gchar           *status;
          GdkModifierType  modifiers = 0;

          /* HACK: A paint tool may set status_ctrl to NULL to indicate that
           * it ignores the Ctrl modifier (temporarily or permanently), so
           * it should not be suggested.  This is different from how
           * gimp_suggest_modifiers() would interpret this parameter.
           */
          if (paint_tool->status_ctrl != NULL)
            modifiers |= constrain_mask;

          /* suggest drawing lines only after the first point is set
           */
          if (display == tool->display)
            modifiers |= GIMP_PAINT_TOOL_LINE_MASK;

          status = gimp_suggest_modifiers (paint_tool->status,
                                           modifiers & ~state,
                                           _("%s for a straight line"),
                                           paint_tool->status_ctrl,
                                           NULL);
          gimp_tool_push_status (tool, display, "%s", status);
          g_free (status);

          paint_tool->draw_line = FALSE;
        }

      if (! gimp_draw_tool_is_active (draw_tool))
        gimp_draw_tool_start (draw_tool, display);
    }
  else if (gimp_draw_tool_is_active (draw_tool))
    {
      gimp_draw_tool_stop (draw_tool);
    }

  GIMP_TOOL_CLASS (parent_class)->oper_update (tool, coords, state, proximity,
                                               display);

  gimp_draw_tool_resume (draw_tool);
}
示例#9
0
static void
gimp_paint_tool_button_press (GimpTool            *tool,
                              const GimpCoords    *coords,
                              guint32              time,
                              GdkModifierType      state,
                              GimpButtonPressType  press_type,
                              GimpDisplay         *display)
{
  GimpDrawTool     *draw_tool     = GIMP_DRAW_TOOL (tool);
  GimpPaintTool    *paint_tool    = GIMP_PAINT_TOOL (tool);
  GimpPaintOptions *paint_options = GIMP_PAINT_TOOL_GET_OPTIONS (tool);
  GimpPaintCore    *core          = paint_tool->core;
  GimpDisplayShell *shell         = gimp_display_get_shell (display);
  GimpImage        *image         = gimp_display_get_image (display);
  GimpDrawable     *drawable      = gimp_image_get_active_drawable (image);
  GimpCoords        curr_coords;
  gint              off_x, off_y;
  GError           *error = NULL;

  if (gimp_color_tool_is_enabled (GIMP_COLOR_TOOL (tool)))
    {
      GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
                                                    press_type, display);
      return;
    }

  if (gimp_viewable_get_children (GIMP_VIEWABLE (drawable)))
    {
      gimp_tool_message_literal (tool, display,
                                 _("Cannot paint on layer groups."));
      return;
    }

  if (gimp_item_is_content_locked (GIMP_ITEM (drawable)))
    {
      gimp_tool_message_literal (tool, display,
                                 _("The active layer's pixels are locked."));
      return;
    }

  if (! gimp_item_is_visible (GIMP_ITEM (drawable)))
    {
      gimp_tool_message_literal (tool, display,
                                 _("The active layer is not visible."));
      return;
    }

  curr_coords = *coords;

  gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);

  curr_coords.x -= off_x;
  curr_coords.y -= off_y;

  if (gimp_draw_tool_is_active (draw_tool))
    gimp_draw_tool_stop (draw_tool);

  if (tool->display            &&
      tool->display != display &&
      gimp_display_get_image (tool->display) == image)
    {
      /*  if this is a different display, but the same image, HACK around
       *  in tool internals AFTER stopping the current draw_tool, so
       *  straight line drawing works across different views of the
       *  same image.
       */

      tool->display = display;
    }

  if (! gimp_paint_core_start (core, drawable, paint_options, &curr_coords,
                               &error))
    {
      gimp_tool_message_literal (tool, display, error->message);
      g_clear_error (&error);
      return;
    }

  if ((display != tool->display) || ! paint_tool->draw_line)
    {
      /* if this is a new display, resest the "last stroke's endpoint"
       * because there is none
       */
      if (display != tool->display)
        core->start_coords = core->cur_coords;

      core->last_coords = core->cur_coords;

      core->distance    = 0.0;
      core->pixel_dist  = 0.0;
    }
  else if (paint_tool->draw_line)
    {
      gboolean constrain = (state & gimp_get_constrain_behavior_mask ()) != 0;

      /*  If shift is down and this is not the first paint
       *  stroke, then draw a line from the last coords to the pointer
       */
      gimp_paint_core_round_line (core, paint_options, constrain);
    }

  /*  chain up to activate the tool  */
  GIMP_TOOL_CLASS (parent_class)->button_press (tool, coords, time, state,
                                                press_type, display);

  /*  pause the current selection  */
  gimp_display_shell_selection_pause (shell);

  /*  Let the specific painting function initialize itself  */
  gimp_paint_core_paint (core, drawable, paint_options,
                         GIMP_PAINT_STATE_INIT, time);

  /*  Paint to the image  */
  if (paint_tool->draw_line)
    {
      gimp_paint_core_interpolate (core, drawable, paint_options,
                                   &core->cur_coords, time);
    }
  else
    {
      gimp_paint_core_paint (core, drawable, paint_options,
                             GIMP_PAINT_STATE_MOTION, time);
    }

  gimp_projection_flush_now (gimp_image_get_projection (image));
  gimp_display_flush_now (display);

  gimp_draw_tool_start (draw_tool, display);
}
示例#10
0
static void
gimp_blend_tool_button_press (GimpTool            *tool,
                              const GimpCoords    *coords,
                              guint32              time,
                              GdkModifierType      state,
                              GimpButtonPressType  press_type,
                              GimpDisplay         *display)
{
  GimpBlendTool *blend_tool = GIMP_BLEND_TOOL (tool);
  GimpDrawTool  *draw_tool  = GIMP_DRAW_TOOL (tool);

  blend_tool->mouse_x = coords->x;
  blend_tool->mouse_y = coords->y;

  if (tool->display && display != tool->display)
    {
      gimp_tool_pop_status (tool, tool->display);
      gimp_blend_tool_halt_preview (blend_tool);
    }

  gimp_draw_tool_pause (draw_tool);

  blend_tool->grabbed_point = gimp_blend_tool_get_point_under_cursor (blend_tool);

  if (blend_tool->grabbed_point == POINT_NONE)
    {
      if (gimp_draw_tool_is_active (draw_tool))
        {
          gimp_tool_control (tool, GIMP_TOOL_ACTION_COMMIT, display);
          gimp_tool_control (tool, GIMP_TOOL_ACTION_HALT, display);
        }

      if (gimp_blend_tool_is_shapeburst (blend_tool))
        {
          blend_tool->grabbed_point = POINT_FILL_MODE;
        }
      else
        {
          blend_tool->grabbed_point = POINT_INIT_MODE;

          blend_tool->start_x = coords->x;
          blend_tool->start_y = coords->y;
        }
    }

  gimp_blend_tool_point_motion (blend_tool,
                                state & gimp_get_constrain_behavior_mask ());

  tool->display = display;

  gimp_draw_tool_resume (draw_tool);

  if (blend_tool->grabbed_point != POINT_FILL_MODE &&
      blend_tool->grabbed_point != POINT_INIT_MODE)
    {
      gimp_blend_tool_update_preview_coords (blend_tool);
      gimp_image_map_apply (blend_tool->image_map, NULL);
    }

  gimp_tool_control_activate (tool->control);

  gimp_blend_tool_push_status (blend_tool, state, display);
}
示例#11
0
/**
 * gimp_transform_options_gui:
 * @tool_options: a #GimpToolOptions
 *
 * Build the Transform Tool Options.
 *
 * Return value: a container holding the transform tool options
 **/
GtkWidget *
gimp_transform_options_gui (GimpToolOptions *tool_options)
{
  GObject     *config = G_OBJECT (tool_options);
  GtkWidget   *vbox   = gimp_tool_options_gui (tool_options);
  GtkWidget   *hbox;
  GtkWidget   *box;
  GtkWidget   *label;
  GtkWidget   *frame;
  GtkWidget   *combo;
  GtkWidget   *scale;
  GtkWidget   *grid_box;
  const gchar *constrain_name  = NULL;
  const gchar *constrain_label = NULL;
  const gchar *constrain_tip   = NULL;

  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  gtk_widget_show (hbox);

  label = gtk_label_new (_("Transform:"));
  gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
  gtk_widget_show (label);

  box = gimp_prop_enum_icon_box_new (config, "type", "gimp", 0, 0);
  gtk_box_pack_start (GTK_BOX (hbox), box, FALSE, FALSE, 0);
  gtk_widget_show (box);

  frame = gimp_prop_enum_radio_frame_new (config, "direction",
                                          _("Direction"), 0, 0);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);

  /*  the interpolation menu  */
  combo = gimp_prop_enum_combo_box_new (config, "interpolation", 0, 0);
  gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Interpolation"));
  g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
  gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
  gtk_widget_show (combo);

  /*  the clipping menu  */
  combo = gimp_prop_enum_combo_box_new (config, "clip", 0, 0);
  gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Clipping"));
  g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
  gtk_box_pack_start (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
  gtk_widget_show (combo);

  /*  the preview frame  */
  scale = gimp_prop_spin_scale_new (config, "preview-opacity",
                                    _("Image opacity"),
                                    0.01, 0.1, 0);
  gimp_prop_widget_set_factor (scale, 100.0, 0.0, 0.0, 1);
  frame = gimp_prop_expanding_frame_new (config, "show-preview",
                                         _("Show image preview"),
                                         scale, NULL);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);

  /*  the guides frame  */
  frame = gimp_frame_new (NULL);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  gtk_widget_show (frame);

  /*  the guides type menu  */
  combo = gimp_prop_enum_combo_box_new (config, "grid-type", 0, 0);
  gimp_int_combo_box_set_label (GIMP_INT_COMBO_BOX (combo), _("Guides"));
  g_object_set (combo, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
  gtk_frame_set_label_widget (GTK_FRAME (frame), combo);
  gtk_widget_show (combo);

  /*  the grid density scale  */
  scale = gimp_prop_spin_scale_new (config, "grid-size", NULL,
                                    1.8, 8.0, 0);
  gimp_spin_scale_set_label (GIMP_SPIN_SCALE (scale), NULL);
  gtk_container_add (GTK_CONTAINER (frame), scale);

  g_object_bind_property_full (config, "grid-type",
                               scale,  "visible",
                               G_BINDING_SYNC_CREATE,
                               gimp_transform_options_sync_grid,
                               NULL,
                               NULL, NULL);

  if (tool_options->tool_info->tool_type == GIMP_TYPE_ROTATE_TOOL)
    {
      constrain_name  = "constrain-rotate";
      constrain_label = _("15 degrees  (%s)");
      constrain_tip   = _("Limit rotation steps to 15 degrees");
    }
  else if (tool_options->tool_info->tool_type == GIMP_TYPE_SCALE_TOOL)
    {
      constrain_name  = "constrain-scale";
      constrain_label = _("Keep aspect  (%s)");
      constrain_tip   = _("Keep the original aspect ratio");
    }

  //TODO: check that the selection tools use the gimp_get_*_mask() functions for constrain/etc or change to what they use
  else if (tool_options->tool_info->tool_type == GIMP_TYPE_UNIFIED_TRANSFORM_TOOL)
    {
      GdkModifierType shift = gimp_get_extend_selection_mask ();
      GdkModifierType ctrl  = gimp_get_constrain_behavior_mask ();

      struct
      {
        GdkModifierType mod;
        gchar *name;
        gchar *desc;
        gchar *tip;
      }
      opt_list[] =
      {
        { shift, NULL, "Constrain  (%s)" },
        { shift, "constrain-move", "Move",
          "Constrain movement to 45 degree angles from center  (%s)" },
        { shift, "constrain-scale", "Scale",
          "Maintain aspect ratio when scaling  (%s)" },
        { shift, "constrain-rotate", "Rotate",
          "Constrain rotation to 15 degree increments  (%s)" },
        { shift, "constrain-shear", "Shear",
          "Shear along edge direction only  (%s)" },
        { shift, "constrain-perspective", "Perspective",
          "Constrain perspective handles to move along edges and diagonal  (%s)" },

        { ctrl, NULL,
          "From pivot  (%s)" },
        { ctrl, "frompivot-scale", "Scale",
          "Scale from pivot point  (%s)" },
        { ctrl, "frompivot-shear", "Shear",
          "Shear opposite edge by same amount  (%s)" },
        { ctrl, "frompivot-perspective", "Perspective",
          "Maintain position of pivot while changing perspective  (%s)" },

        { 0, NULL,
          "Pivot" },
        { shift, "cornersnap", "Snap  (%s)",
          "Snap pivot to corners and center  (%s)" },
        { 0, "fixedpivot", "Lock",
          "Lock pivot position to canvas" },
      };

      GtkWidget *button;
      gchar     *label;
      gint       i;

      frame = NULL;

      for (i = 0; i < G_N_ELEMENTS (opt_list); i++)
        {
          if (!opt_list[i].name && !opt_list[i].desc)
            {
              frame = NULL;
              continue;
            }

          label = g_strdup_printf (opt_list[i].desc,
                                   gimp_get_mod_string (opt_list[i].mod));

          if (opt_list[i].name)
            {
              button = gimp_prop_check_button_new (config, opt_list[i].name,
                                                   label);

              gtk_box_pack_start (GTK_BOX (frame ? grid_box : vbox),
                                  button, FALSE, FALSE, 0);

              gtk_widget_show (button);

              g_free (label);
              label = g_strdup_printf (opt_list[i].tip,
                                       gimp_get_mod_string (opt_list[i].mod));

              gimp_help_set_help_data (button, label, NULL);
            }
          else
            {
              frame = gimp_frame_new (label);
              gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
              gtk_widget_show (frame);

              grid_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
              gtk_container_add (GTK_CONTAINER (frame), grid_box);
              gtk_widget_show (grid_box);
            }

          g_free (label);
        }
    }

  if (constrain_label)
    {
      GtkWidget       *button;
      gchar           *label;
      GdkModifierType  constrain_mask;

      constrain_mask = gimp_get_extend_selection_mask ();

      label = g_strdup_printf (constrain_label,
                               gimp_get_mod_string (constrain_mask));

      button = gimp_prop_check_button_new (config, constrain_name, label);
      gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
      gtk_widget_show (button);

      gimp_help_set_help_data (button, constrain_tip, NULL);

      g_free (label);
    }

  return vbox;
}