diff --git a/ChangeLog b/ChangeLog index cc13d1dc57..b813f99d36 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,30 @@ +2009-02-05 Sven Neumann + + Bug 520078 – Rotate brushes + + Applied patch from Alexia Death: + + * app/core/gimpbrush.[ch] + * app/core/gimpbrushgenerated.c + * app/core/gimpbrush-transform.[ch]: affine transformations for + brushes. So far only scaling and rotation is supported. The + transformation is done using nearest-neighbour. This is a + regression and we need to add back interpolation before the next + release. + + * app/paint/gimpsmudge.c + * app/paint/gimppaintoptions.[ch] + * app/paint/gimpbrushcore.[ch]: allow to control the brush + rotation angle. + + * app/tools/gimppaintoptions-gui.c + * app/tools/gimpbrushtool.c: added UI for controlling the + brush rotation angle. + + * app/actions/tools-actions.c + * app/actions/tools-commands.[ch]: add actions for controlling the + brush rotation angle. + 2009-02-05 Michael Natterer * app/core/gimpdrawable.h diff --git a/app/actions/tools-actions.c b/app/actions/tools-actions.c index 4de49c5689..4af966c79d 100644 --- a/app/actions/tools-actions.c +++ b/app/actions/tools-actions.c @@ -181,6 +181,42 @@ static const GimpEnumActionEntry tools_paint_brush_scale_actions[] = NULL }, }; +static const GimpEnumActionEntry tools_paint_brush_angle_actions[] = +{ + { "tools-paint-brush-angle-set", GIMP_STOCK_TOOL_PAINTBRUSH, + "Set Brush Angle", NULL, NULL, + GIMP_ACTION_SELECT_SET, TRUE, + NULL }, + { "tools-paint-brush-angle-set-to-default", GIMP_STOCK_TOOL_PAINTBRUSH, + "Set Brush Angle To Default Value", NULL, NULL, + GIMP_ACTION_SELECT_SET_TO_DEFAULT, FALSE, + NULL }, + { "tools-paint-brush-angle-minimum", GIMP_STOCK_TOOL_PAINTBRUSH, + "Minimize Brush Angle", NULL, NULL, + GIMP_ACTION_SELECT_FIRST, FALSE, + NULL }, + { "tools-paint-brush-angle-maximum", GIMP_STOCK_TOOL_PAINTBRUSH, + "Maximize Brush Angle", NULL, NULL, + GIMP_ACTION_SELECT_LAST, FALSE, + NULL }, + { "tools-paint-brush-angle-decrease", GIMP_STOCK_TOOL_PAINTBRUSH, + "Decrease Brush Angle", NULL, NULL, + GIMP_ACTION_SELECT_PREVIOUS, FALSE, + NULL }, + { "tools-paint-brush-angle-increase", GIMP_STOCK_TOOL_PAINTBRUSH, + "Increase Brush Angle", NULL, NULL, + GIMP_ACTION_SELECT_NEXT, FALSE, + NULL }, + { "tools-paint-brush-angle-decrease-skip", GIMP_STOCK_TOOL_PAINTBRUSH, + "Decrease Brush Angle More", NULL, NULL, + GIMP_ACTION_SELECT_SKIP_PREVIOUS, FALSE, + NULL }, + { "tools-paint-brush-angle-increase-skip", GIMP_STOCK_TOOL_PAINTBRUSH, + "Increase Brush Angle More", NULL, NULL, + GIMP_ACTION_SELECT_SKIP_NEXT, FALSE, + NULL }, +}; + static const GimpEnumActionEntry tools_ink_blob_size_actions[] = { { "tools-ink-blob-size-set", GIMP_STOCK_TOOL_INK, @@ -589,6 +625,11 @@ tools_actions_setup (GimpActionGroup *group) G_N_ELEMENTS (tools_paint_brush_scale_actions), G_CALLBACK (tools_paint_brush_scale_cmd_callback)); + gimp_action_group_add_enum_actions (group, NULL, + tools_paint_brush_angle_actions, + G_N_ELEMENTS (tools_paint_brush_angle_actions), + G_CALLBACK (tools_paint_brush_angle_cmd_callback)); + gimp_action_group_add_enum_actions (group, NULL, tools_ink_blob_size_actions, G_N_ELEMENTS (tools_ink_blob_size_actions), diff --git a/app/actions/tools-commands.c b/app/actions/tools-commands.c index ce338fc250..32d9ef4348 100644 --- a/app/actions/tools-commands.c +++ b/app/actions/tools-commands.c @@ -294,6 +294,26 @@ tools_paint_brush_scale_cmd_callback (GtkAction *action, } } +void +tools_paint_brush_angle_cmd_callback (GtkAction *action, + gint value, + gpointer data) +{ + GimpContext *context; + GimpToolInfo *tool_info; + return_if_no_context (context, data); + + tool_info = gimp_context_get_tool (context); + + if (tool_info && GIMP_IS_PAINT_OPTIONS (tool_info->tool_options)) + { + action_select_property ((GimpActionSelectType) value, + G_OBJECT (tool_info->tool_options), + "brush-angle", + 0.01, 0.1, 1.0, FALSE); + } +} + void tools_ink_blob_size_cmd_callback (GtkAction *action, gint value, diff --git a/app/actions/tools-commands.h b/app/actions/tools-commands.h index b9d9ef54f3..b22e204a6f 100644 --- a/app/actions/tools-commands.h +++ b/app/actions/tools-commands.h @@ -45,6 +45,10 @@ void tools_paint_brush_scale_cmd_callback (GtkAction *action, gint value, gpointer data); +void tools_paint_brush_angle_cmd_callback (GtkAction *action, + gint value, + gpointer data); + void tools_ink_blob_size_cmd_callback (GtkAction *action, gint value, gpointer data); diff --git a/app/core/gimpbrush-transform.c b/app/core/gimpbrush-transform.c index fa35423b1a..e25ff00ce4 100644 --- a/app/core/gimpbrush-transform.c +++ b/app/core/gimpbrush-transform.c @@ -1,7 +1,7 @@ /* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * - * gimpbrush-scale.c + * gimpbrush-transform.c * * 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 @@ -23,26 +23,26 @@ #include "core-types.h" +#include "libgimpmath/gimpmath.h" + #include "gimpbrush.h" #include "gimpbrush-transform.h" -#include "base/pixel-region.h" #include "base/temp-buf.h" -#include "paint-funcs/scale-region.h" - /* local function prototypes */ -static TempBuf * gimp_brush_scale_buf_up (TempBuf *brush_buf, - gint dest_width, - gint dest_height); -static TempBuf * gimp_brush_scale_mask_down (TempBuf *brush_mask, - gint dest_width, - gint dest_height); -static TempBuf * gimp_brush_scale_pixmap_down (TempBuf *pixmap, - gint dest_width, - gint dest_height); +static void gimp_brush_transform_matrix (GimpBrush *brush, + gdouble scale, + gdouble angle, + GimpMatrix3 *matrix); +static void gimp_brush_transform_bounding_box (GimpBrush *brush, + const GimpMatrix3 *matrix, + gint *x, + gint *y, + gint *width, + gint *height); /* public functions */ @@ -50,421 +50,187 @@ static TempBuf * gimp_brush_scale_pixmap_down (TempBuf *pixmap, void gimp_brush_real_transform_size (GimpBrush *brush, gdouble scale, + gdouble angle, gint *width, gint *height) { - *width = (gint) (brush->mask->width * scale + 0.5); - *height = (gint) (brush->mask->height * scale + 0.5); + GimpMatrix3 matrix; + gint x, y; + + gimp_brush_transform_matrix (brush, scale, angle, &matrix); + gimp_brush_transform_bounding_box (brush, &matrix, &x, &y, width, height); } TempBuf * gimp_brush_real_transform_mask (GimpBrush *brush, - gdouble scale) + gdouble scale, + gdouble angle) { - gint dest_width; - gint dest_height; + TempBuf *result; + guchar *dest; + const guchar *src; + GimpMatrix3 matrix; + gint src_width; + gint src_height; + gint dest_width; + gint dest_height; + gint x, y; - gimp_brush_transform_size (brush, scale, &dest_width, &dest_height); + gimp_brush_transform_matrix (brush, scale, angle, &matrix); - if (dest_width <= 0 || dest_height <= 0) - return NULL; + if (gimp_matrix3_is_identity (&matrix)) + return temp_buf_copy (brush->mask, NULL); - if (scale <= 1.0) + src_width = brush->mask->width; + src_height = brush->mask->height; + + gimp_brush_transform_bounding_box (brush, &matrix, + &x, &y, &dest_width, &dest_height); + gimp_matrix3_translate (&matrix, -x, -y); + gimp_matrix3_invert (&matrix); + + result = temp_buf_new (dest_width, dest_height, 1, 0, 0, NULL); + + dest = temp_buf_get_data (result); + src = temp_buf_get_data (brush->mask); + + for (y = 0; y < dest_height; y++) { - /* Downscaling with brush_transform_mask is much faster than with - * gimp_brush_scale_buf. - */ - return gimp_brush_scale_mask_down (brush->mask, - dest_width, dest_height); + for (x = 0; x < dest_width; x++) + { + gdouble dx, dy; + gint ix, iy; + + gimp_matrix3_transform_point (&matrix, x, y, &dx, &dy); + + ix = ROUND (dx); + iy = ROUND (dy); + + if (ix > 0 && ix < src_width && + iy > 0 && iy < src_height) + { + *dest = src[iy * src_width + ix]; + } + else + { + *dest = 0; + } + + dest++; + } } - return gimp_brush_scale_buf_up (brush->mask, dest_width, dest_height); + return result; } TempBuf * gimp_brush_real_transform_pixmap (GimpBrush *brush, - gdouble scale) + gdouble scale, + gdouble angle) { - gint dest_width; - gint dest_height; + TempBuf *result; + guchar *dest; + const guchar *src; + GimpMatrix3 matrix; + gint src_width; + gint src_height; + gint dest_width; + gint dest_height; + gint x, y; - gimp_brush_transform_size (brush, scale, &dest_width, &dest_height); + gimp_brush_transform_matrix (brush, scale, angle, &matrix); - if (dest_width <= 0 || dest_height <= 0) - return NULL; + if (gimp_matrix3_is_identity (&matrix)) + return temp_buf_copy (brush->pixmap, NULL); - if (scale <= 1.0) + src_width = brush->pixmap->width; + src_height = brush->pixmap->height; + + gimp_brush_transform_bounding_box (brush, &matrix, + &x, &y, &dest_width, &dest_height); + gimp_matrix3_translate (&matrix, -x, -y); + gimp_matrix3_invert (&matrix); + + result = temp_buf_new (dest_width, dest_height, 3, 0, 0, NULL); + + dest = temp_buf_get_data (result); + src = temp_buf_get_data (brush->pixmap); + + for (y = 0; y < dest_height; y++) { - /* Downscaling with brush_scale_pixmap is much faster than with - * gimp_brush_scale_buf. - */ - return gimp_brush_scale_pixmap_down (brush->pixmap, - dest_width, dest_height); + for (x = 0; x < dest_width; x++) + { + gdouble dx, dy; + gint ix, iy; + + gimp_matrix3_transform_point (&matrix, x, y, &dx, &dy); + + ix = ROUND (dx); + iy = ROUND (dy); + + if (ix > 0 && ix < src_width && + iy > 0 && iy < src_height) + { + const guchar *s = src + 3 * (iy * src_width + ix); + + dest[0] = s[0]; + dest[1] = s[1]; + dest[2] = s[2]; + } + else + { + dest[0] = 0; + dest[1] = 0; + dest[2] = 0; + } + + dest += 3; + } } - return gimp_brush_scale_buf_up (brush->pixmap, dest_width, dest_height); + return result; } /* private functions */ -static TempBuf * -gimp_brush_scale_buf_up (TempBuf *brush_buf, - gint dest_width, - gint dest_height) +static void +gimp_brush_transform_matrix (GimpBrush *brush, + gdouble scale, + gdouble angle, + GimpMatrix3 *matrix) { - PixelRegion source_region; - PixelRegion dest_region; - TempBuf *dest_brush_buf; + const gdouble center_x = brush->mask->width / 2; + const gdouble center_y = brush->mask->height / 2; - pixel_region_init_temp_buf (&source_region, brush_buf, - 0, 0, brush_buf->width, brush_buf->height); - - dest_brush_buf = temp_buf_new (dest_width, dest_height, brush_buf->bytes, - 0, 0, NULL); - - pixel_region_init_temp_buf (&dest_region, dest_brush_buf, - 0, 0, dest_width, dest_height); - - scale_region (&source_region, &dest_region, - GIMP_INTERPOLATION_LINEAR, NULL, NULL); - - return dest_brush_buf; + gimp_matrix3_identity (matrix); + gimp_matrix3_translate (matrix, - center_x, - center_x); + gimp_matrix3_rotate (matrix, 2 * G_PI * angle); + gimp_matrix3_translate (matrix, center_x, center_y); + gimp_matrix3_scale (matrix, scale, scale); } -static TempBuf * -gimp_brush_scale_mask_down (TempBuf *brush_mask, - gint dest_width, - gint dest_height) +static void +gimp_brush_transform_bounding_box (GimpBrush *brush, + const GimpMatrix3 *matrix, + gint *x, + gint *y, + gint *width, + gint *height) { - TempBuf *scale_brush; - gint src_width; - gint src_height; - gint value; - gint area; - gint i, j; - gint x, x0, y, y0; - gint dx, dx0, dy, dy0; - gint fx, fx0, fy, fy0; - guchar *src, *dest; + const gdouble w = brush->mask->width; + const gdouble h = brush->mask->height; + gdouble x1, x2, x3, x4; + gdouble y1, y2, y3, y4; - g_return_val_if_fail (brush_mask != NULL && - dest_width != 0 && dest_height != 0, NULL); + gimp_matrix3_transform_point (matrix, 0, 0, &x1, &y1); + gimp_matrix3_transform_point (matrix, w, 0, &x2, &y2); + gimp_matrix3_transform_point (matrix, 0, h, &x3, &y3); + gimp_matrix3_transform_point (matrix, w, h, &x4, &y4); - src_width = brush_mask->width; - src_height = brush_mask->height; + *x = floor (MIN (MIN (x1, x2), MIN (x3, x4))); + *y = floor (MIN (MIN (y1, y2), MIN (y3, y4))); - scale_brush = temp_buf_new (dest_width, dest_height, 1, 0, 0, NULL); - g_return_val_if_fail (scale_brush != NULL, NULL); - - /* get the data */ - dest = temp_buf_get_data (scale_brush); - src = temp_buf_get_data (brush_mask); - - fx = fx0 = (src_width << 8) / dest_width; - fy = fy0 = (src_height << 8) / dest_height; - - area = (fx0 * fy0) >> 8; - - x = x0 = 0; - y = y0 = 0; - dx = dx0 = 0; - dy = dy0 = 0; - - for (i = 0; i < dest_height; i++) - { - for (j = 0; j < dest_width; j++) - { - value = 0; - - fy = fy0; - y = y0; - dy = dy0; - - if (dy) - { - fx = fx0; - x = x0; - dx = dx0; - - if (dx) - { - value += (dx * dy * src[x + src_width * y]) >> 8; - x++; - fx -= dx; - dx = 0; - } - while (fx >= 256) - { - value += dy * src[x + src_width * y]; - x++; - fx -= 256; - } - if (fx) - { - value += fx * dy * src[x + src_width * y] >> 8; - dx = 256 - fx; - } - - y++; - fy -= dy; - dy = 0; - } - - while (fy >= 256) - { - fx = fx0; - x = x0; - dx = dx0; - - if (dx) - { - value += dx * src[x + src_width * y]; - x++; - fx -= dx; - dx = 0; - } - while (fx >= 256) - { - value += 256 * src[x + src_width * y]; - x++; - fx -= 256; - } - if (fx) - { - value += fx * src[x + src_width * y]; - dx = 256 - fx; - } - - y++; - fy -= 256; - } - - if (fy) - { - fx = fx0; - x = x0; - dx = dx0; - - if (dx) - { - value += (dx * fy * src[x + src_width * y]) >> 8; - x++; - fx -= dx; - dx = 0; - } - while (fx >= 256) - { - value += fy * src[x + src_width * y]; - x++; - fx -= 256; - } - if (fx) - { - value += (fx * fy * src[x + src_width * y]) >> 8; - dx = 256 - fx; - } - - dy = 256 - fy; - } - - value /= area; - *dest++ = MIN (value, 255); - - x0 = x; - dx0 = dx; - } - - x0 = 0; - dx0 = 0; - y0 = y; - dy0 = dy; - } - - return scale_brush; + *width = (gint) (ceil (MAX (MAX (x1, x2), MAX (x3, x4))) - *x); + *height = (gint) (ceil (MAX (MAX (y1, y2), MAX (y3, y4))) - *y); } - - -#define ADD_RGB(dest, factor, src) \ - dest[0] += factor * src[0]; \ - dest[1] += factor * src[1]; \ - dest[2] += factor * src[2]; - -static TempBuf * -gimp_brush_scale_pixmap_down (TempBuf *pixmap, - gint dest_width, - gint dest_height) -{ - TempBuf *scale_brush; - gint src_width; - gint src_height; - gint value[3]; - gint factor; - gint area; - gint i, j; - gint x, x0, y, y0; - gint dx, dx0, dy, dy0; - gint fx, fx0, fy, fy0; - guchar *src, *src_ptr, *dest; - - g_return_val_if_fail (pixmap != NULL && pixmap->bytes == 3 && - dest_width != 0 && dest_height != 0, NULL); - - src_width = pixmap->width; - src_height = pixmap->height; - - scale_brush = temp_buf_new (dest_width, dest_height, 3, 0, 0, NULL); - g_return_val_if_fail (scale_brush != NULL, NULL); - - /* get the data */ - dest = temp_buf_get_data (scale_brush); - src = temp_buf_get_data (pixmap); - - fx = fx0 = (src_width << 8) / dest_width; - fy = fy0 = (src_height << 8) / dest_height; - area = (fx0 * fy0) >> 8; - - x = x0 = 0; - y = y0 = 0; - dx = dx0 = 0; - dy = dy0 = 0; - - for (i = 0; i < dest_height; i++) - { - for (j=0; j> 8; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - x++; - fx -= dx; - dx = 0; - } - while (fx >= 256) - { - factor = dy; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - x++; - fx -= 256; - } - if (fx) - { - factor = (fx * dy) >> 8; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - dx = 256 - fx; - } - - y++; - fy -= dy; - dy = 0; - } - - while (fy >= 256) - { - fx = fx0; - x = x0; - dx = dx0; - - if (dx) - { - factor = dx; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - x++; - fx -= dx; - dx = 0; - } - while (fx >= 256) - { - factor = 256; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - x++; - fx -= 256; - } - if (fx) - { - factor = fx; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - dx = 256 - fx; - } - - y++; - fy -= 256; - } - - if (fy) - { - fx = fx0; - x = x0; - dx = dx0; - - if (dx) - { - factor = (dx * fy) >> 8; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - x++; - fx -= dx; - dx = 0; - } - while (fx >= 256) - { - factor = fy; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - x++; - fx -= 256; - } - if (fx) - { - factor = (fx * fy) >> 8; - src_ptr = src + 3 * (x + y * src_width); - ADD_RGB (value, factor, src_ptr); - dx = 256 - fx; - } - - dy = 256 - fy; - } - - value[0] /= area; - value[1] /= area; - value[2] /= area; - - *dest++ = MIN (value[0], 255); - *dest++ = MIN (value[1], 255); - *dest++ = MIN (value[2], 255); - - x0 = x; - dx0 = dx; - } - - x0 = 0; - dx0 = 0; - y0 = y; - dy0 = dy; - } - - return scale_brush; -} - -#undef ADD_RGB diff --git a/app/core/gimpbrush-transform.h b/app/core/gimpbrush-transform.h index 27d7c38832..db4adbfaa9 100644 --- a/app/core/gimpbrush-transform.h +++ b/app/core/gimpbrush-transform.h @@ -25,12 +25,15 @@ void gimp_brush_real_transform_size (GimpBrush *brush, gdouble scale, + gdouble angle, gint *scaled_width, gint *scaled_height); TempBuf * gimp_brush_real_transform_mask (GimpBrush *brush, - gdouble scale); + gdouble scale, + gdouble angle); TempBuf * gimp_brush_real_transform_pixmap (GimpBrush *brush, - gdouble scale); + gdouble scale, + gdouble angle); #endif /* __GIMP_BRUSH_SCALE_H__ */ diff --git a/app/core/gimpbrush.c b/app/core/gimpbrush.c index 6922167971..1dea43c547 100644 --- a/app/core/gimpbrush.c +++ b/app/core/gimpbrush.c @@ -276,13 +276,13 @@ gimp_brush_get_new_preview (GimpViewable *viewable, if (scale != 1.0) { - mask_buf = gimp_brush_transform_mask (brush, scale); + mask_buf = gimp_brush_transform_mask (brush, scale, 0.0); if (! mask_buf) mask_buf = temp_buf_new (1, 1, 1, 0, 0, transp); if (pixmap_buf) - pixmap_buf = gimp_brush_transform_pixmap (brush, scale); + pixmap_buf = gimp_brush_transform_pixmap (brush, scale, 0.0); mask_width = mask_buf->width; mask_height = mask_buf->height; @@ -458,6 +458,7 @@ gimp_brush_want_null_motion (GimpBrush *brush, void gimp_brush_transform_size (GimpBrush *brush, gdouble scale, + gdouble angle, gint *width, gint *height) { @@ -466,7 +467,7 @@ gimp_brush_transform_size (GimpBrush *brush, g_return_if_fail (width != NULL); g_return_if_fail (height != NULL); - if (scale == 1.0) + if ((scale == 1.0) && ((angle == 0.0) || (angle == 0.5) || (angle == 1.0))) { *width = brush->mask->width; *height = brush->mask->height; @@ -474,34 +475,36 @@ gimp_brush_transform_size (GimpBrush *brush, return; } - GIMP_BRUSH_GET_CLASS (brush)->transform_size (brush, scale, width, height); + GIMP_BRUSH_GET_CLASS (brush)->transform_size (brush, scale, angle, width, height); } TempBuf * gimp_brush_transform_mask (GimpBrush *brush, - gdouble scale) + gdouble scale, + gdouble angle) { g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL); g_return_val_if_fail (scale > 0.0, NULL); - if (scale == 1.0) + if ((scale == 1.0) && (angle == 0.0)) return temp_buf_copy (brush->mask, NULL); - return GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush, scale); + return GIMP_BRUSH_GET_CLASS (brush)->transform_mask (brush, scale, angle); } TempBuf * gimp_brush_transform_pixmap (GimpBrush *brush, - gdouble scale) + gdouble scale, + gdouble angle) { g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL); g_return_val_if_fail (brush->pixmap != NULL, NULL); g_return_val_if_fail (scale > 0.0, NULL); - if (scale == 1.0) + if ((scale == 1.0) && (angle == 0.0)) return temp_buf_copy (brush->pixmap, NULL); - return GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush, scale); + return GIMP_BRUSH_GET_CLASS (brush)->transform_pixmap (brush, scale, angle); } TempBuf * diff --git a/app/core/gimpbrush.h b/app/core/gimpbrush.h index e16a884079..ac50e5f3c1 100644 --- a/app/core/gimpbrush.h +++ b/app/core/gimpbrush.h @@ -58,12 +58,15 @@ struct _GimpBrushClass GimpCoords *cur_coords); void (* transform_size) (GimpBrush *brush, gdouble scale, + gdouble angle, gint *width, gint *height); TempBuf * (* transform_mask) (GimpBrush *brush, - gdouble scale); + gdouble scale, + gdouble angle); TempBuf * (* transform_pixmap) (GimpBrush *brush, - gdouble scale); + gdouble scale, + gdouble angle); /* signals */ void (* spacing_changed) (GimpBrush *brush); @@ -85,12 +88,15 @@ gboolean gimp_brush_want_null_motion (GimpBrush *brush, /* Gets width and height of a transformed mask of the brush, for provided parameters. */ void gimp_brush_transform_size (GimpBrush *brush, gdouble scale, + gdouble angle, gint *width, gint *height); TempBuf * gimp_brush_transform_mask (GimpBrush *brush, - gdouble scale); + gdouble scale, + gdouble angle); TempBuf * gimp_brush_transform_pixmap (GimpBrush *brush, - gdouble scale); + gdouble scale, + gdouble angle); TempBuf * gimp_brush_get_mask (const GimpBrush *brush); TempBuf * gimp_brush_get_pixmap (const GimpBrush *brush); diff --git a/app/core/gimpbrushgenerated.c b/app/core/gimpbrushgenerated.c index a1eceabf9e..eb8bb97d80 100644 --- a/app/core/gimpbrushgenerated.c +++ b/app/core/gimpbrushgenerated.c @@ -65,10 +65,12 @@ static GimpData * gimp_brush_generated_duplicate (GimpData *data); static void gimp_brush_generated_transform_size(GimpBrush *gbrush, gdouble scale, + gdouble angle, gint *width, gint *height); static TempBuf * gimp_brush_generated_transform_mask(GimpBrush *gbrush, - gdouble scale); + gdouble scale, + gdouble angle); static TempBuf * gimp_brush_generated_calc (GimpBrushGenerated *brush, GimpBrushGeneratedShape shape, @@ -279,6 +281,7 @@ gimp_brush_generated_duplicate (GimpData *data) static void gimp_brush_generated_transform_size (GimpBrush *gbrush, gdouble scale, + gdouble angle, gint *width, gint *height) { @@ -292,7 +295,7 @@ gimp_brush_generated_transform_size (GimpBrush *gbrush, brush->spikes, brush->hardness, brush->aspect_ratio, - brush->angle, + (brush->angle + 360 * angle), &half_width, &half_height, NULL, NULL, NULL, NULL); @@ -302,7 +305,8 @@ gimp_brush_generated_transform_size (GimpBrush *gbrush, static TempBuf * gimp_brush_generated_transform_mask (GimpBrush *gbrush, - gdouble scale) + gdouble scale, + gdouble angle) { GimpBrushGenerated *brush = GIMP_BRUSH_GENERATED (gbrush); @@ -312,7 +316,7 @@ gimp_brush_generated_transform_mask (GimpBrush *gbrush, brush->spikes, brush->hardness, brush->aspect_ratio, - brush->angle, + (brush->angle + 360 * angle), NULL, NULL); } diff --git a/app/paint/gimpbrushcore.c b/app/paint/gimpbrushcore.c index 34ee5b386b..c73aa7df5e 100644 --- a/app/paint/gimpbrushcore.c +++ b/app/paint/gimpbrushcore.c @@ -154,9 +154,9 @@ gimp_brush_core_class_init (GimpBrushCoreClass *klass) paint_core_class->interpolate = gimp_brush_core_interpolate; paint_core_class->get_paint_area = gimp_brush_core_get_paint_area; - klass->handles_changing_brush = FALSE; - klass->handles_scaling_brush = TRUE; - klass->set_brush = gimp_brush_core_real_set_brush; + klass->handles_changing_brush = FALSE; + klass->handles_transforming_brush = TRUE; + klass->set_brush = gimp_brush_core_real_set_brush; } static void @@ -168,6 +168,7 @@ gimp_brush_core_init (GimpBrushCore *core) core->brush = NULL; core->spacing = 1.0; core->scale = 1.0; + core->angle = 1.0; core->pressure_brush = NULL; @@ -363,10 +364,14 @@ gimp_brush_core_start (GimpPaintCore *paint_core, return FALSE; } - core->scale = gimp_paint_options_get_dynamic_size (paint_options, - coords, - GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush); - + if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush) + { + core->scale = gimp_paint_options_get_dynamic_size (paint_options, + coords, + TRUE); + core->angle = gimp_paint_options_get_dynamic_angle (paint_options, + coords); + } core->spacing = (gdouble) gimp_brush_get_spacing (core->main_brush) / 100.0; core->brush = core->main_brush; @@ -696,14 +701,19 @@ gimp_brush_core_get_paint_area (GimpPaintCore *paint_core, gint drawable_width, drawable_height; gint brush_width, brush_height; - if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_scaling_brush) - core->scale = gimp_paint_options_get_dynamic_size (paint_options, - &paint_core->cur_coords, - TRUE); + if (GIMP_BRUSH_CORE_GET_CLASS (core)->handles_transforming_brush) + { + core->scale = gimp_paint_options_get_dynamic_size (paint_options, + &paint_core->cur_coords, + TRUE); + + core->angle = gimp_paint_options_get_dynamic_angle (paint_options, + &paint_core->cur_coords); + } core->scale = gimp_brush_core_clamp_brush_scale (core, core->scale); - gimp_brush_transform_size (core->brush, core->scale, &brush_width, &brush_height); + gimp_brush_transform_size (core->brush, core->scale, core->angle, &brush_width, &brush_height); /* adjust the x and y coordinates to the upper left corner of the brush */ x = (gint) floor (paint_core->cur_coords.x) - (brush_width / 2); @@ -783,18 +793,20 @@ gimp_brush_core_create_bound_segs (GimpBrushCore *core, { TempBuf *mask = NULL; gdouble scale; + gdouble angle; g_return_if_fail (GIMP_IS_BRUSH_CORE (core)); g_return_if_fail (core->main_brush != NULL); g_return_if_fail (core->brush_bound_segs == NULL); scale = paint_options->brush_scale; + angle = paint_options->brush_angle; if (scale > 0.0) { scale = gimp_brush_core_clamp_brush_scale (core, scale); - mask = gimp_brush_transform_mask (core->main_brush, scale); + mask = gimp_brush_transform_mask (core->main_brush, scale, angle); } if (mask) @@ -1296,17 +1308,18 @@ gimp_brush_core_transform_mask (GimpBrushCore *core, if (core->scale <= 0.0) return NULL; /* Should never happen now, with scale clamping. */ - if (core->scale == 1.0) + if ((core->scale == 1.0) && (core->angle == 0.0)) return brush->mask; - gimp_brush_transform_size (brush, core->scale, &width, &height); + gimp_brush_transform_size (brush, core->scale, core->angle, &width, &height); - if (! core->cache_invalid && + if (! core->cache_invalid && core->transform_brush && brush->mask == core->last_transform_brush && width == core->last_transform_width && height == core->last_transform_height && - core->scale == core->last_scale) + core->scale == core->last_scale && + core->angle == core->last_angle) { return core->transform_brush; } @@ -1315,11 +1328,13 @@ gimp_brush_core_transform_mask (GimpBrushCore *core, core->last_transform_width = width; core->last_transform_height = height; core->last_scale = core->scale; + core->last_angle = core->angle; + if (core->transform_brush) temp_buf_free (core->transform_brush); - core->transform_brush = gimp_brush_transform_mask (brush, core->scale); + core->transform_brush = gimp_brush_transform_mask (brush, core->scale, core->angle); core->cache_invalid = TRUE; core->solid_cache_invalid = TRUE; @@ -1337,16 +1352,18 @@ gimp_brush_core_transform_pixmap (GimpBrushCore *core, if (core->scale <= 0.0) return NULL; - if (core->scale == 1.0) + if ((core->scale == 1.0) && (core->angle == 0.0)) return brush->pixmap; - gimp_brush_transform_size (brush, core->scale, &width, &height); + gimp_brush_transform_size (brush, core->scale, core->angle, &width, &height); + if (! core->cache_invalid && core->transform_pixmap && brush->pixmap == core->last_transform_pixmap && width == core->last_transform_pixmap_width && - height == core->last_transform_pixmap_height) + height == core->last_transform_pixmap_height&& + core->angle == core->last_angle) { return core->transform_pixmap; } @@ -1354,11 +1371,13 @@ gimp_brush_core_transform_pixmap (GimpBrushCore *core, core->last_transform_pixmap = brush->pixmap; core->last_transform_pixmap_width = width; core->last_transform_pixmap_height = height; + core->last_angle = core->angle; if (core->transform_pixmap) temp_buf_free (core->transform_pixmap); - core->transform_pixmap = gimp_brush_transform_pixmap (brush, core->scale); + + core->transform_pixmap = gimp_brush_transform_pixmap (brush, core->scale, core->angle); core->cache_invalid = TRUE; diff --git a/app/paint/gimpbrushcore.h b/app/paint/gimpbrushcore.h index 293a4b673b..947b48cf4f 100644 --- a/app/paint/gimpbrushcore.h +++ b/app/paint/gimpbrushcore.h @@ -45,6 +45,7 @@ struct _GimpBrushCore GimpBrush *brush; gdouble spacing; gdouble scale; + gdouble angle; /* brush buffers */ TempBuf *pressure_brush; @@ -58,6 +59,7 @@ struct _GimpBrushCore gint last_transform_width; gint last_transform_height; gdouble last_scale; + gdouble last_angle; TempBuf *transform_pixmap; TempBuf *last_transform_pixmap; @@ -90,7 +92,8 @@ struct _GimpBrushCoreClass gboolean handles_changing_brush; /* Set for tools that don't mind if the brush scales while painting */ - gboolean handles_scaling_brush; + + gboolean handles_transforming_brush; void (* set_brush) (GimpBrushCore *core, GimpBrush *brush); diff --git a/app/paint/gimppaintoptions.c b/app/paint/gimppaintoptions.c index 645e04da14..a8dee79b15 100644 --- a/app/paint/gimppaintoptions.c +++ b/app/paint/gimppaintoptions.c @@ -34,6 +34,8 @@ #define DEFAULT_BRUSH_SCALE 1.0 +#define DEFAULT_BRUSH_ANGLE 0.0 + #define DEFAULT_APPLICATION_MODE GIMP_PAINT_CONSTANT #define DEFAULT_HARD FALSE @@ -45,6 +47,7 @@ #define DEFAULT_PRESSURE_SIZE FALSE #define DEFAULT_PRESSURE_INVERSE_SIZE FALSE #define DEFAULT_PRESSURE_COLOR FALSE +#define DEFAULT_PRESSURE_ANGLE FALSE #define DEFAULT_PRESSURE_PRESCALE 1.0 #define DEFAULT_VELOCITY_OPACITY FALSE @@ -53,6 +56,7 @@ #define DEFAULT_VELOCITY_SIZE FALSE #define DEFAULT_VELOCITY_INVERSE_SIZE FALSE #define DEFAULT_VELOCITY_COLOR FALSE +#define DEFAULT_VELOCITY_ANGLE FALSE #define DEFAULT_VELOCITY_PRESCALE 1.0 #define DEFAULT_RANDOM_OPACITY FALSE @@ -61,6 +65,7 @@ #define DEFAULT_RANDOM_SIZE FALSE #define DEFAULT_RANDOM_INVERSE_SIZE FALSE #define DEFAULT_RANDOM_COLOR FALSE +#define DEFAULT_RANDOM_ANGLE FALSE #define DEFAULT_RANDOM_PRESCALE 1.0 #define DEFAULT_USE_FADE FALSE @@ -82,7 +87,10 @@ enum PROP_0, PROP_PAINT_INFO, + PROP_BRUSH_SCALE, + PROP_BRUSH_ANGLE, + PROP_APPLICATION_MODE, PROP_HARD, @@ -94,6 +102,7 @@ enum PROP_PRESSURE_SIZE, PROP_PRESSURE_INVERSE_SIZE, PROP_PRESSURE_COLOR, + PROP_PRESSURE_ANGLE, PROP_PRESSURE_PRESCALE, PROP_VELOCITY_OPACITY, @@ -102,6 +111,7 @@ enum PROP_VELOCITY_SIZE, PROP_VELOCITY_INVERSE_SIZE, PROP_VELOCITY_COLOR, + PROP_VELOCITY_ANGLE, PROP_VELOCITY_PRESCALE, PROP_RANDOM_OPACITY, @@ -110,6 +120,7 @@ enum PROP_RANDOM_SIZE, PROP_RANDOM_INVERSE_SIZE, PROP_RANDOM_COLOR, + PROP_RANDOM_ANGLE, PROP_RANDOM_PRESCALE, PROP_USE_FADE, @@ -180,6 +191,11 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass) "brush-scale", NULL, 0.01, 10.0, DEFAULT_BRUSH_SCALE, GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_BRUSH_ANGLE, + "brush-angle", NULL, + -180.0, 180.0, DEFAULT_BRUSH_ANGLE, + GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_APPLICATION_MODE, "application-mode", NULL, GIMP_TYPE_PAINT_APPLICATION_MODE, @@ -215,6 +231,10 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass) "pressure-color", NULL, DEFAULT_PRESSURE_COLOR, GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_PRESSURE_ANGLE, + "pressure-angle", NULL, + DEFAULT_PRESSURE_COLOR, + GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_PRESSURE_INVERSE_SIZE, "pressure-inverse-size", NULL, DEFAULT_PRESSURE_INVERSE_SIZE, @@ -244,6 +264,10 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass) "velocity-color", NULL, DEFAULT_VELOCITY_COLOR, GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_ANGLE, + "velocity-angle", NULL, + DEFAULT_VELOCITY_COLOR, + GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_VELOCITY_INVERSE_SIZE, "velocity-inverse-size", NULL, DEFAULT_VELOCITY_INVERSE_SIZE, @@ -273,6 +297,10 @@ gimp_paint_options_class_init (GimpPaintOptionsClass *klass) "random-color", NULL, DEFAULT_RANDOM_COLOR, GIMP_PARAM_STATIC_STRINGS); + GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_RANDOM_ANGLE, + "random-angle", NULL, + DEFAULT_RANDOM_COLOR, + GIMP_PARAM_STATIC_STRINGS); GIMP_CONFIG_INSTALL_PROP_BOOLEAN (object_class, PROP_RANDOM_INVERSE_SIZE, "random-inverse-size", NULL, DEFAULT_RANDOM_INVERSE_SIZE, @@ -418,6 +446,10 @@ gimp_paint_options_set_property (GObject *object, options->brush_scale = g_value_get_double (value); break; + case PROP_BRUSH_ANGLE: + options->brush_angle = g_value_get_double (value) / 360.0; + break; + case PROP_APPLICATION_MODE: options->application_mode = g_value_get_enum (value); break; @@ -454,6 +486,10 @@ gimp_paint_options_set_property (GObject *object, pressure_options->color = g_value_get_boolean (value); break; + case PROP_PRESSURE_ANGLE: + pressure_options->angle = g_value_get_boolean (value); + break; + case PROP_PRESSURE_PRESCALE: pressure_options->prescale = g_value_get_double (value); break; @@ -482,6 +518,10 @@ gimp_paint_options_set_property (GObject *object, velocity_options->color = g_value_get_boolean (value); break; + case PROP_VELOCITY_ANGLE: + velocity_options->angle = g_value_get_boolean (value); + break; + case PROP_VELOCITY_PRESCALE: velocity_options->prescale = g_value_get_double (value); break; @@ -510,6 +550,10 @@ gimp_paint_options_set_property (GObject *object, random_options->color = g_value_get_boolean (value); break; + case PROP_RANDOM_ANGLE: + random_options->angle = g_value_get_boolean (value); + break; + case PROP_RANDOM_PRESCALE: random_options->prescale = g_value_get_double (value); break; @@ -608,6 +652,10 @@ gimp_paint_options_get_property (GObject *object, g_value_set_double (value, options->brush_scale); break; + case PROP_BRUSH_ANGLE: + g_value_set_double (value, options->brush_angle * 360.0); + break; + case PROP_APPLICATION_MODE: g_value_set_enum (value, options->application_mode); break; @@ -644,6 +692,10 @@ gimp_paint_options_get_property (GObject *object, g_value_set_boolean (value, pressure_options->color); break; + case PROP_PRESSURE_ANGLE: + g_value_set_boolean (value, pressure_options->angle); + break; + case PROP_PRESSURE_PRESCALE: g_value_set_double (value, pressure_options->prescale); break; @@ -672,6 +724,10 @@ gimp_paint_options_get_property (GObject *object, g_value_set_boolean (value, velocity_options->color); break; + case PROP_VELOCITY_ANGLE: + g_value_set_boolean (value, velocity_options->angle); + break; + case PROP_VELOCITY_PRESCALE: g_value_set_double (value, velocity_options->prescale); break; @@ -700,6 +756,10 @@ gimp_paint_options_get_property (GObject *object, g_value_set_boolean (value, random_options->color); break; + case PROP_RANDOM_ANGLE: + g_value_set_boolean (value, random_options->angle); + break; + case PROP_RANDOM_PRESCALE: g_value_set_double (value, random_options->prescale); break; @@ -1244,3 +1304,40 @@ gimp_paint_options_get_dynamic_hardness (GimpPaintOptions *paint_options, return hardness; } + +gdouble +gimp_paint_options_get_dynamic_angle (GimpPaintOptions *paint_options, + const GimpCoords *coords) +{ + gdouble angle = 1.0; + + g_return_val_if_fail (GIMP_IS_PAINT_OPTIONS (paint_options), 1.0); + g_return_val_if_fail (coords != NULL, 1.0); + + if (paint_options->pressure_options->angle || + paint_options->velocity_options->angle || + paint_options->random_options->angle) + { + gdouble pressure = -1.0; + gdouble velocity = -1.0; + gdouble random = -1.0; + + if (paint_options->pressure_options->angle) + pressure = GIMP_PAINT_PRESSURE_SCALE * coords->pressure; + + if (paint_options->velocity_options->angle) + velocity = GIMP_PAINT_VELOCITY_SCALE * (1 - coords->velocity); + + if (paint_options->random_options->angle) + random = g_random_double_range (0.0, 1.0); + + angle = gimp_paint_options_get_dynamics_mix (pressure, + paint_options->pressure_options->prescale, + velocity, + paint_options->velocity_options->prescale, + random, + paint_options->random_options->prescale); + } + + return angle + paint_options->brush_angle; +} diff --git a/app/paint/gimppaintoptions.h b/app/paint/gimppaintoptions.h index 140fe18995..624a50d662 100644 --- a/app/paint/gimppaintoptions.h +++ b/app/paint/gimppaintoptions.h @@ -42,6 +42,7 @@ struct _GimpDynamicOptions gboolean size; gboolean inverse_size; gboolean color; + gboolean angle; gdouble prescale; }; @@ -87,6 +88,7 @@ struct _GimpPaintOptions GimpPaintInfo *paint_info; gdouble brush_scale; + gdouble brush_angle; GimpPaintApplicationMode application_mode; GimpPaintApplicationMode application_mode_save; @@ -150,6 +152,9 @@ gdouble gimp_paint_options_get_dynamic_rate (GimpPaintOptions *paint_options, gdouble gimp_paint_options_get_dynamic_color (GimpPaintOptions *paint_options, const GimpCoords *coords); +gdouble gimp_paint_options_get_dynamic_angle (GimpPaintOptions *paint_options, + const GimpCoords *coords); + gdouble gimp_paint_options_get_dynamic_hardness(GimpPaintOptions *paint_options, const GimpCoords *coords); diff --git a/app/paint/gimpsmudge.c b/app/paint/gimpsmudge.c index 36fb5be582..e8c6a60eb4 100644 --- a/app/paint/gimpsmudge.c +++ b/app/paint/gimpsmudge.c @@ -89,7 +89,7 @@ gimp_smudge_class_init (GimpSmudgeClass *klass) paint_core_class->paint = gimp_smudge_paint; - brush_core_class->handles_scaling_brush = FALSE; + brush_core_class->handles_transforming_brush = FALSE; } static void @@ -329,7 +329,7 @@ gimp_smudge_brush_coords (GimpPaintCore *paint_core, gint height; gimp_brush_transform_size (brush_core->brush, brush_core->scale, - &width, &height); + brush_core->angle, &width, &height); /* Note: these are the brush mask size plus a border of 1 pixel */ *x = (gint) paint_core->cur_coords.x - width / 2 - 1; diff --git a/app/tools/gimpbrushtool.c b/app/tools/gimpbrushtool.c index 614ee680c3..d3bede8e14 100644 --- a/app/tools/gimpbrushtool.c +++ b/app/tools/gimpbrushtool.c @@ -62,21 +62,21 @@ static void gimp_brush_tool_cursor_update (GimpTool *tool, static void gimp_brush_tool_draw (GimpDrawTool *draw_tool); -static void gimp_brush_tool_brush_changed (GimpContext *context, - GimpBrush *brush, - GimpBrushTool *brush_tool); -static void gimp_brush_tool_brush_scaled (GimpPaintOptions *options, - GParamSpec *pspec, - GimpBrushTool *brush_tool); -static void gimp_brush_tool_set_brush (GimpBrushCore *brush_core, - GimpBrush *brush, - GimpBrushTool *brush_tool); -static void gimp_brush_tool_set_brush_after(GimpBrushCore *brush_core, - GimpBrush *brush, - GimpBrushTool *brush_tool); -static void gimp_brush_tool_notify_brush (GimpDisplayConfig *config, - GParamSpec *pspec, - GimpBrushTool *brush_tool); +static void gimp_brush_tool_brush_changed (GimpContext *context, + GimpBrush *brush, + GimpBrushTool *brush_tool); +static void gimp_brush_tool_brush_transformed (GimpPaintOptions *options, + GParamSpec *pspec, + GimpBrushTool *brush_tool); +static void gimp_brush_tool_set_brush (GimpBrushCore *brush_core, + GimpBrush *brush, + GimpBrushTool *brush_tool); +static void gimp_brush_tool_set_brush_after (GimpBrushCore *brush_core, + GimpBrush *brush, + GimpBrushTool *brush_tool); +static void gimp_brush_tool_notify_brush (GimpDisplayConfig *config, + GParamSpec *pspec, + GimpBrushTool *brush_tool); G_DEFINE_TYPE (GimpBrushTool, gimp_brush_tool, GIMP_TYPE_PAINT_TOOL) @@ -155,7 +155,11 @@ gimp_brush_tool_constructor (GType type, G_CALLBACK (gimp_brush_tool_brush_changed), brush_tool, 0); g_signal_connect_object (gimp_tool_get_options (tool), "notify::brush-scale", - G_CALLBACK (gimp_brush_tool_brush_scaled), + G_CALLBACK (gimp_brush_tool_brush_transformed), + brush_tool, 0); + + g_signal_connect_object (gimp_tool_get_options (tool), "notify::brush-angle", + G_CALLBACK (gimp_brush_tool_brush_transformed), brush_tool, 0); g_signal_connect (paint_tool->core, "set-brush", @@ -345,9 +349,9 @@ gimp_brush_tool_brush_changed (GimpContext *context, } static void -gimp_brush_tool_brush_scaled (GimpPaintOptions *options, - GParamSpec *pspec, - GimpBrushTool *brush_tool) +gimp_brush_tool_brush_transformed (GimpPaintOptions *options, + GParamSpec *pspec, + GimpBrushTool *brush_tool) { GimpPaintTool *paint_tool = GIMP_PAINT_TOOL (brush_tool); GimpBrushCore *brush_core = GIMP_BRUSH_CORE (paint_tool->core); diff --git a/app/tools/gimppaintoptions-gui.c b/app/tools/gimppaintoptions-gui.c index 8e68910ff5..bf94f2dabc 100644 --- a/app/tools/gimppaintoptions-gui.c +++ b/app/tools/gimppaintoptions-gui.c @@ -52,6 +52,7 @@ static gboolean tool_has_hardness_dynamics (GType tool_type); static gboolean tool_has_rate_dynamics (GType tool_type); static gboolean tool_has_size_dynamics (GType tool_type); static gboolean tool_has_color_dynamics (GType tool_type); +static gboolean tool_has_angle_dynamics (GType tool_type); static void pressure_options_gui (GimpPaintOptions *paint_options, GType tool_type, @@ -128,7 +129,8 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) /* the brush */ if (g_type_is_a (tool_type, GIMP_TYPE_BRUSH_TOOL)) { - GtkObject *adj; + GtkObject *adj_scale; + GtkObject *adj_angle; button = gimp_prop_brush_box_new (NULL, GIMP_CONTEXT (tool_options), 2, "brush-view-type", "brush-view-size"); @@ -136,12 +138,20 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) _("Brush:"), 0.0, 0.5, button, 2, FALSE); - adj = gimp_prop_scale_entry_new (config, "brush-scale", - GTK_TABLE (table), 0, table_row++, - _("Scale:"), - 0.01, 0.1, 2, - FALSE, 0.0, 0.0); - gimp_scale_entry_set_logarithmic (adj, TRUE); + adj_scale = gimp_prop_scale_entry_new (config, "brush-scale", + GTK_TABLE (table), 0, table_row++, + _("Scale:"), + 0.01, 0.1, 2, + FALSE, 0.0, 0.0); + gimp_scale_entry_set_logarithmic (adj_scale, TRUE); + + adj_angle = gimp_prop_scale_entry_new (config, "brush-angle", + GTK_TABLE (table), 0, table_row++, + _("Angle:"), + 1.0, 5.0, 2, + FALSE, 0.0, 0.0); + gimp_scale_entry_set_logarithmic (adj_angle, FALSE); + } if (tool_has_opacity_dynamics (tool_type)) @@ -168,6 +178,12 @@ gimp_paint_options_gui (GimpToolOptions *tool_options) n_dynamics++; } + if (tool_has_angle_dynamics (tool_type)) + { + dynamics_labels[n_dynamics] = gtk_label_new (_("Angle")); + n_dynamics++; + } + if (tool_has_color_dynamics (tool_type)) { dynamics_labels[n_dynamics] = gtk_label_new (_("Color")); @@ -339,6 +355,12 @@ tool_has_size_dynamics (GType tool_type) tool_type == GIMP_TYPE_ERASER_TOOL); } +static gboolean +tool_has_angle_dynamics (GType tool_type) +{ + return (g_type_is_a (tool_type, GIMP_TYPE_PAINTBRUSH_TOOL)); +} + static gboolean tool_has_color_dynamics (GType tool_type) { @@ -439,6 +461,16 @@ pressure_options_gui (GimpPaintOptions *paint_options, column++; } + if (tool_has_angle_dynamics (tool_type)) + { + button = dynamics_check_button_new (config, "pressure-angle", + table, column, row); + g_signal_connect (button, "size-allocate", + G_CALLBACK (dynamics_check_button_size_allocate), + labels[column - 1]); + column++; + } + if (tool_has_color_dynamics (tool_type)) { button = dynamics_check_button_new (config, "pressure-color", @@ -489,6 +521,12 @@ velocity_options_gui (GimpPaintOptions *paint_options, table, column++, row); } + if (tool_has_angle_dynamics (tool_type)) + { + dynamics_check_button_new (config, "velocity-angle", + table, column++, row); + } + if (tool_has_color_dynamics (tool_type)) { dynamics_check_button_new (config, "velocity-color", @@ -535,6 +573,12 @@ random_options_gui (GimpPaintOptions *paint_options, table, column++, row); } + if (tool_has_angle_dynamics (tool_type)) + { + dynamics_check_button_new (config, "random-angle", + table, column++, row); + } + if (tool_has_color_dynamics (tool_type)) { dynamics_check_button_new (config, "random-color",