Bug 520078 – Rotate brushes

2009-02-05  Sven Neumann  <sven@gimp.org>

	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.


svn path=/trunk/; revision=27987
This commit is contained in:
Sven Neumann 2009-02-05 21:47:57 +00:00 committed by Sven Neumann
parent d2a716d37f
commit 30c118b53c
16 changed files with 509 additions and 463 deletions

View File

@ -1,3 +1,30 @@
2009-02-05 Sven Neumann <sven@gimp.org>
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 <mitch@gimp.org>
* app/core/gimpdrawable.h

View File

@ -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),

View File

@ -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,

View File

@ -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);

View File

@ -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<dest_width; j++)
{
value[0] = 0;
value[1] = 0;
value[2] = 0;
fy = fy0;
y = y0;
dy = dy0;
if (dy)
{
fx = fx0;
x = x0;
dx = dx0;
if (dx)
{
factor = (dx * dy) >> 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

View File

@ -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__ */

View File

@ -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 *

View File

@ -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);

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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",