gimpink.c 43.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
/* The GIMP -- an image manipulation program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
Sven Neumann's avatar
Sven Neumann committed
18

19 20
#include "config.h"

21
#include <stdlib.h>
Tor Lillqvist's avatar
Tor Lillqvist committed
22
#include <string.h>
23

24
#include <gtk/gtk.h>
Sven Neumann's avatar
Sven Neumann committed
25

26
#include "libgimpmath/gimpmath.h"
27
#include "libgimpwidgets/gimpwidgets.h"
28

Michael Natterer's avatar
Michael Natterer committed
29
#include "tools-types.h"
Sven Neumann's avatar
Sven Neumann committed
30

Michael Natterer's avatar
Michael Natterer committed
31 32 33 34 35
#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "base/tile.h"
#include "base/tile-manager.h"

36 37
#include "paint-funcs/paint-funcs.h"

Michael Natterer's avatar
Michael Natterer committed
38
#include "core/gimp.h"
39 40 41 42 43
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"

44 45 46
#include "gimpinktool.h"
#include "gimpinktool-blob.h"
#include "gimptool.h"
47
#include "paint_options.h"
48
#include "tool_manager.h"
49

Michael Natterer's avatar
Michael Natterer committed
50 51 52 53
#include "gimprc.h"
#include "undo.h"
#include "gdisplay.h"

54 55
#include "libgimp/gimpintl.h"

56

57
#define SUBSAMPLE 8
58

59 60
/*  the Ink structures  */

61 62 63 64 65 66 67
typedef Blob * (* BlobFunc) (gdouble,
			     gdouble,
			     gdouble,
			     gdouble,
			     gdouble,
			     gdouble);

68

69
typedef struct _BrushWidget BrushWidget;
Michael Natterer's avatar
Michael Natterer committed
70

71 72
struct _BrushWidget
{
73 74
  GtkWidget *widget;
  gboolean   state;
75 76
};

77
typedef struct _InkOptions InkOptions;
Michael Natterer's avatar
Michael Natterer committed
78

79 80
struct _InkOptions
{
81
  PaintOptions  paint_options;
82

Michael Natterer's avatar
Michael Natterer committed
83 84
  gdouble       size;
  gdouble       size_d;
85
  GtkObject    *size_w;
86

Michael Natterer's avatar
Michael Natterer committed
87 88
  gdouble       sensitivity;
  gdouble       sensitivity_d;
89
  GtkObject    *sensitivity_w;
90

Michael Natterer's avatar
Michael Natterer committed
91 92
  gdouble       vel_sensitivity;
  gdouble       vel_sensitivity_d;
93
  GtkObject    *vel_sensitivity_w;
94

Michael Natterer's avatar
Michael Natterer committed
95 96
  gdouble       tilt_sensitivity;
  gdouble       tilt_sensitivity_d;
97
  GtkObject    *tilt_sensitivity_w;
98

Michael Natterer's avatar
Michael Natterer committed
99 100
  gdouble       tilt_angle;
  gdouble       tilt_angle_d;
101
  GtkObject    *tilt_angle_w;
102

103 104 105
  BlobFunc      function;
  BlobFunc      function_d;
  GtkWidget    *function_w[3];  /* 3 radio buttons */
106

Michael Natterer's avatar
Michael Natterer committed
107 108 109 110
  gdouble       aspect;
  gdouble       aspect_d;
  gdouble       angle;
  gdouble       angle_d;
111
  BrushWidget  *brush_w;
112 113 114
};


115
/*  local function prototypes  */
116

117 118 119 120 121 122
static void        gimp_ink_tool_class_init      (GimpInkToolClass *klass);
static void        gimp_ink_tool_init            (GimpInkTool      *tool);

static void        gimp_ink_tool_destroy         (GtkObject        *object);

static InkOptions * ink_options_new     (void);
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
static void         ink_options_reset   (GimpToolOptions *tool_options);

static void        ink_button_press     (GimpTool        *tool,
					 GdkEventButton  *mevent,
					 GDisplay        *gdisp);
static void        ink_button_release   (GimpTool        *tool,
					 GdkEventButton  *bevent,
					 GDisplay        *gdisp);
static void        ink_motion           (GimpTool        *tool,
					 GdkEventMotion  *mevent,
					 GDisplay        *gdisp);
static void        ink_cursor_update    (GimpTool        *tool,
					 GdkEventMotion  *mevent,
					 GDisplay        *gdisp);
static void        ink_control          (GimpTool        *tool,
					 ToolAction       tool_action,
					 GDisplay        *gdisp);

static void        time_smoother_add    (GimpInkTool     *ink_tool,
					 guint32          value);
static gdouble     time_smoother_result (GimpInkTool     *ink_tool);
static void        time_smoother_init   (GimpInkTool     *ink_tool,
					 guint32          initval);
static void        dist_smoother_add    (GimpInkTool     *ink_tool,
					 gdouble          value);
static gdouble     dist_smoother_result (GimpInkTool     *ink_tool);
static void        dist_smoother_init   (GimpInkTool     *ink_tool,
					 gdouble          initval);

static void        ink_init             (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable, 
					 gdouble          x, 
					 gdouble          y);
static void        ink_finish           (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable);
158 159
static void        ink_cleanup          (void);

160 161 162 163 164 165 166 167
static void        ink_type_update      (GtkWidget       *radio_button,
					 BlobFunc         function);
static GdkPixmap * blob_pixmap          (GdkColormap     *colormap,
					 GdkVisual       *visual,
					 BlobFunc         function);
static void        paint_blob           (GdkDrawable     *drawable, 
					 GdkGC           *gc,
					 Blob            *blob);
168

Michael Natterer's avatar
Michael Natterer committed
169
/*  Rendering functions  */
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
static void        ink_set_paint_area   (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable, 
					 Blob            *blob);
static void        ink_paste            (GimpInkTool     *ink_tool, 
					 GimpDrawable    *drawable,
					 Blob            *blob);

static void        ink_to_canvas_tiles  (GimpInkTool     *ink_tool,
					 Blob            *blob,
					 guchar          *color);

static void        ink_set_undo_tiles   (GimpDrawable    *drawable,
					 gint             x, 
					 gint             y,
					 gint             w, 
					 gint             h);
static void        ink_set_canvas_tiles (gint             x, 
					 gint             y,
					 gint             w, 
					 gint             h);
190

Michael Natterer's avatar
Michael Natterer committed
191
/*  Brush pseudo-widget callbacks  */
192 193
static void   brush_widget_active_rect    (BrushWidget    *brush_widget,
					   GtkWidget      *widget,
194
					   GdkRectangle   *rect);
195 196
static void   brush_widget_realize        (GtkWidget      *widget);
static void   brush_widget_expose         (GtkWidget      *widget,
197 198
					   GdkEventExpose *event,
					   BrushWidget    *brush_widget);
199
static void   brush_widget_button_press   (GtkWidget      *widget,
200 201
					   GdkEventButton *event,
					   BrushWidget    *brush_widget);
202
static void   brush_widget_button_release (GtkWidget      *widget,
203 204
					   GdkEventButton *event,
					   BrushWidget    *brush_widget);
205
static void   brush_widget_motion_notify  (GtkWidget      *widget,
206 207 208 209
					   GdkEventMotion *event,
					   BrushWidget    *brush_widget);


210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
/* local variables */

/* the ink tool options  */
static InkOptions *ink_options = NULL;

/*  undo blocks variables  */
static TileManager *undo_tiles = NULL;

/* Tiles used to render the stroke at 1 byte/pp */
static TileManager *canvas_tiles = NULL;

/* Flat buffer that is used to used to render the dirty region
 * for composition onto the destination drawable
 */
static TempBuf *canvas_buf = NULL;

226 227
static GimpToolClass *parent_class      = NULL;

228

229 230
/*  functions  */

231
void
Michael Natterer's avatar
Michael Natterer committed
232
gimp_ink_tool_register (Gimp *gimp)
233
{
Michael Natterer's avatar
Michael Natterer committed
234 235
  tool_manager_register_tool (gimp,
			      GIMP_TYPE_INK_TOOL,
236 237 238 239 240 241
			      TRUE,
			      "gimp:ink_tool",
			      _("Ink Tool"),
			      _("Draw in ink"),
			      N_("/Tools/Paint Tools/Ink"), "K",
			      NULL, "tools/ink.html",
Michael Natterer's avatar
Michael Natterer committed
242
			      GIMP_STOCK_TOOL_INK);
243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
}

GtkType
gimp_ink_tool_get_type (void)
{
  static GtkType tool_type = 0;

  if (! tool_type)
    {
      GtkTypeInfo tool_info =
      {
	"GimpInkTool",
	sizeof (GimpInkTool),
	sizeof (GimpInkToolClass),
	(GtkClassInitFunc) gimp_ink_tool_class_init,
	(GtkObjectInitFunc) gimp_ink_tool_init,
	/* reserved_1 */ NULL,
	/* reserved_2 */ NULL,
	(GtkClassInitFunc) NULL,
      };

      tool_type = gtk_type_unique (GIMP_TYPE_TOOL, &tool_info);
    }

  return tool_type;
}

static void
gimp_ink_tool_class_init (GimpInkToolClass *klass)
{
  GtkObjectClass *object_class;
  GimpToolClass  *tool_class;

  object_class = (GtkObjectClass *) klass;
  tool_class   = (GimpToolClass *) klass;

  parent_class = gtk_type_class (GIMP_TYPE_TOOL);

  object_class->destroy = gimp_ink_tool_destroy;

  tool_class->control        = ink_control;
  tool_class->button_press   = ink_button_press;
  tool_class->button_release = ink_button_release;
  tool_class->motion         = ink_motion;
  tool_class->cursor_update  = ink_cursor_update;
}

static void
gimp_ink_tool_init (GimpInkTool *ink_tool)
{
  GimpTool *tool;

  tool = GIMP_TOOL (ink_tool);
 
  /*  The tool options  */
  if (! ink_options)
    {
      ink_options = ink_options_new ();

      tool_manager_register_tool_options (GIMP_TYPE_INK_TOOL,
303
					  (GimpToolOptions *) ink_options);
304

305
      ink_options_reset ((GimpToolOptions *) ink_options);
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
    }
}

static void
gimp_ink_tool_destroy (GtkObject *object)
{
  GimpInkTool *ink_tool;

  ink_tool = GIMP_INK_TOOL (object);

  if (ink_tool->last_blob)
    g_free (ink_tool->last_blob);

  ink_cleanup ();

  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    GTK_OBJECT_CLASS (parent_class)->destroy (object);
}

325 326 327 328 329 330 331 332 333 334 335 336
static void 
ink_type_update (GtkWidget      *radio_button,
		 BlobFunc        function)
{
  InkOptions *options = ink_options;

  if (GTK_TOGGLE_BUTTON (radio_button)->active)
    options->function = function;

  gtk_widget_queue_draw (options->brush_w->widget);
}

337
static void
338
ink_options_reset (GimpToolOptions *tool_options)
339
{
340
  InkOptions *options;
341

342 343 344
  options = (InkOptions *) tool_options;

  paint_options_reset (tool_options);
345

346 347 348 349 350 351
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->size_w),
			    options->size_d);
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->sensitivity_w),
			    options->sensitivity_d);
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->tilt_sensitivity_w),
			    options->tilt_sensitivity_d);
352 353
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->vel_sensitivity_w),
			    options->vel_sensitivity_d);
354 355
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->tilt_angle_w),
			    options->tilt_angle_d);
356 357 358 359 360 361
  gtk_toggle_button_set_active (((options->function_d == blob_ellipse) ?
				 GTK_TOGGLE_BUTTON (options->function_w[0]) :
				 ((options->function_d == blob_square) ?
				  GTK_TOGGLE_BUTTON (options->function_w[1]) :
				  GTK_TOGGLE_BUTTON (options->function_w[2]))),
				TRUE);
362 363
  options->aspect = options->aspect_d;
  options->angle  = options->angle_d;
364
  gtk_widget_queue_draw (options->brush_w->widget);
365 366
}

367
static InkOptions *
368
ink_options_new (void)
369
{
370
  InkOptions *options;
371 372 373 374 375 376 377 378 379 380
  GtkWidget  *table;
  GtkWidget  *vbox;
  GtkWidget  *hbox;
  GtkWidget  *hbox2;
  GtkWidget  *radio_button;
  GtkWidget  *pixmap_widget;
  GtkWidget  *slider;
  GtkWidget  *frame;
  GtkWidget  *darea;
  GdkPixmap  *pixmap;
381

382
  options = g_new0 (InkOptions, 1);
383
  paint_options_init ((PaintOptions *) options,
384
		      GIMP_TYPE_INK_TOOL,
385
		      ink_options_reset);
386

387
  options->size             = options->size_d             = 4.4;
388
  options->sensitivity      = options->sensitivity_d      = 1.0;
389 390
  options->vel_sensitivity  = options->vel_sensitivity_d  = 0.8;
  options->tilt_sensitivity = options->tilt_sensitivity_d = 0.4;
391 392 393 394 395
  options->tilt_angle       = options->tilt_angle_d       = 0.0;
  options->function         = options->function_d         = blob_ellipse;
  options->aspect           = options->aspect_d           = 1.0;
  options->angle            = options->angle_d            = 0.0;

jtl's avatar
jtl committed
396 397
  /*  the main vbox  */
  vbox = gtk_vbox_new (FALSE, 2);
398
  gtk_box_pack_start (GTK_BOX (((GimpToolOptions *) options)->main_vbox), vbox,
jtl's avatar
jtl committed
399 400 401 402 403 404 405 406 407 408 409 410 411 412
		      TRUE, TRUE, 0);
  gtk_widget_show (vbox);

  /* adjust sliders */
  frame = gtk_frame_new (_("Adjustment"));
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
  gtk_widget_show (frame);

  table = gtk_table_new (2, 2, FALSE);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_container_set_border_width (GTK_CONTAINER (table), 2);
  gtk_container_add (GTK_CONTAINER (frame), table);
  gtk_widget_show (table);
413 414 415

  /*  size slider  */
  options->size_w =
416
    gtk_adjustment_new (options->size_d, 0.0, 20.0, 1.0, 2.0, 0.0);
417
  slider = gtk_hscale_new (GTK_ADJUSTMENT (options->size_w));
418
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
jtl's avatar
jtl committed
419 420 421
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 0,
			     _("Size:"), 1.0, 1.0,
			     slider, 1, FALSE);
422
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
423 424 425 426

  g_signal_connect (G_OBJECT (options->size_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->size);
jtl's avatar
jtl committed
427 428 429 430 431 432 433 434 435 436

  /* angle adjust slider */
  options->tilt_angle_w =
    gtk_adjustment_new (options->tilt_angle_d, -90.0, 90.0, 1, 10.0, 0.0);
  slider = gtk_hscale_new (GTK_ADJUSTMENT (options->tilt_angle_w));
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
			     _("Angle:"), 1.0, 1.0,
			     slider, 1, FALSE);
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
437 438 439 440

  g_signal_connect (G_OBJECT (options->tilt_angle_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->tilt_angle);
jtl's avatar
jtl committed
441 442 443 444 445 446 447 448 449 450 451 452 453 454

  /* sens sliders */
  frame = gtk_frame_new (_("Sensitivity"));
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0);
  gtk_widget_show (frame);

  table = gtk_table_new (3, 2, FALSE);
  gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  gtk_container_set_border_width (GTK_CONTAINER (table), 2);
  gtk_container_add (GTK_CONTAINER (frame), table);
  gtk_widget_show (table);

  /* size sens slider */
455 456 457
  options->sensitivity_w =
    gtk_adjustment_new (options->sensitivity_d, 0.0, 1.0, 0.01, 0.1, 0.0);
  slider = gtk_hscale_new (GTK_ADJUSTMENT (options->sensitivity_w));
458
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
jtl's avatar
jtl committed
459 460 461
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
			     _("Size:"), 1.0, 1.0,
			     slider, 1, FALSE);
462
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
463 464 465 466

  g_signal_connect (G_OBJECT (options->sensitivity_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->sensitivity);
467
  
468 469 470 471
  /* tilt sens slider */
  options->tilt_sensitivity_w =
    gtk_adjustment_new (options->tilt_sensitivity_d, 0.0, 1.0, 0.01, 0.1, 0.0);
  slider = gtk_hscale_new (GTK_ADJUSTMENT (options->tilt_sensitivity_w));
472
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
jtl's avatar
jtl committed
473 474 475
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
			     _("Tilt:"), 1.0, 1.0,
			     slider, 1, FALSE);
476
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
477 478 479 480

  g_signal_connect (G_OBJECT (options->tilt_sensitivity_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->tilt_sensitivity);
481 482 483 484 485 486

  /* velocity sens slider */
  options->vel_sensitivity_w =
    gtk_adjustment_new (options->vel_sensitivity_d, 0.0, 1.0, 0.01, 0.1, 0.0);
  slider = gtk_hscale_new (GTK_ADJUSTMENT (options->vel_sensitivity_w));
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
jtl's avatar
jtl committed
487 488 489
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
			     _("Speed:"), 1.0, 1.0,
			     slider, 1, FALSE);
490
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
491 492 493 494

  g_signal_connect (G_OBJECT (options->vel_sensitivity_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->vel_sensitivity);
495

jtl's avatar
jtl committed
496 497 498 499
  /*  bottom hbox */
  hbox = gtk_hbox_new (FALSE, 2);
  gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  gtk_widget_show (hbox);
Raph Levien's avatar
Raph Levien committed
500

501
  /* Brush type radiobuttons */
502
  frame = gtk_frame_new (_("Type"));
jtl's avatar
jtl committed
503
  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
504 505
  gtk_widget_show (frame);

jtl's avatar
jtl committed
506 507 508
  hbox2 = gtk_hbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (frame), hbox2);
  
509 510
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
jtl's avatar
jtl committed
511
  gtk_box_pack_start (GTK_BOX (hbox2), vbox, FALSE, FALSE, 0);
512 513 514 515
  gtk_widget_show (vbox);

  pixmap = blob_pixmap (gtk_widget_get_colormap (vbox),
			gtk_widget_get_visual (vbox),
516 517 518
			blob_ellipse);

  pixmap_widget = gtk_pixmap_new (pixmap, NULL);
Sven Neumann's avatar
Sven Neumann committed
519
  gdk_drawable_unref (pixmap);
jtl's avatar
jtl committed
520
  gtk_misc_set_padding (GTK_MISC (pixmap_widget), 6, 0);
521 522 523

  radio_button = gtk_radio_button_new (NULL);
  gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
524
  gtk_box_pack_start (GTK_BOX (vbox), radio_button, FALSE, FALSE, 0);
525

526 527 528 529 530
  g_signal_connect (G_OBJECT (radio_button), "toggled",
		    G_CALLBACK (ink_type_update),
		    (gpointer) blob_ellipse);


531
  options->function_w[0] = radio_button;
532 533 534

  pixmap = blob_pixmap (gtk_widget_get_colormap (vbox),
			gtk_widget_get_visual (vbox),
535 536 537
			blob_square);

  pixmap_widget = gtk_pixmap_new (pixmap, NULL);
Sven Neumann's avatar
Sven Neumann committed
538
  gdk_drawable_unref (pixmap);
jtl's avatar
jtl committed
539
  gtk_misc_set_padding (GTK_MISC (pixmap_widget), 6, 0);
540

541 542
  radio_button =
    gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
543
  gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
544
  gtk_box_pack_start (GTK_BOX (vbox), radio_button, FALSE, FALSE, 0);
545

546 547 548 549 550
  g_signal_connect (G_OBJECT (radio_button), "toggled",
		    G_CALLBACK (ink_type_update), 
		    (gpointer) blob_square);
  

551 552
  options->function_w[1] = radio_button;

553 554
  pixmap = blob_pixmap (gtk_widget_get_colormap (vbox),
			gtk_widget_get_visual (vbox),
555 556 557
			blob_diamond);

  pixmap_widget = gtk_pixmap_new (pixmap, NULL);
Sven Neumann's avatar
Sven Neumann committed
558
  gdk_drawable_unref (pixmap);
jtl's avatar
jtl committed
559
  gtk_misc_set_padding (GTK_MISC (pixmap_widget), 6, 0);
560

561 562
  radio_button =
    gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
563
  gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
564
  gtk_box_pack_start (GTK_BOX (vbox), radio_button, FALSE, FALSE, 0);
565

566 567 568 569 570
  g_signal_connect (G_OBJECT (radio_button), "toggled",
		    G_CALLBACK (ink_type_update), 
		    (gpointer) blob_diamond);


571 572
  options->function_w[2] = radio_button;

573
  /* Brush shape widget */
574
  frame = gtk_frame_new (_("Shape"));
jtl's avatar
jtl committed
575
  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
576 577 578 579 580 581
  gtk_widget_show (frame);

  vbox = gtk_vbox_new (FALSE, 2);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
  gtk_container_add (GTK_CONTAINER (frame), vbox);
  gtk_widget_show (vbox);
582

jtl's avatar
jtl committed
583
  frame = gtk_aspect_frame_new (NULL, 0.0, 0.5, 1.0, FALSE);
584 585
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
586

jtl's avatar
jtl committed
587 588 589
  options->brush_w = g_new (BrushWidget, 1);
  options->brush_w->state = FALSE;

590
  darea = gtk_drawing_area_new();
591
  options->brush_w->widget = darea;
592

593 594
  gtk_drawing_area_size (GTK_DRAWING_AREA (darea), 60, 60);
  gtk_container_add (GTK_CONTAINER (frame), darea);
595

596 597 598
  gtk_widget_set_events (darea, 
			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
			 | GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK);
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614

  g_signal_connect (G_OBJECT (darea), "button_press_event",
		    G_CALLBACK (brush_widget_button_press),
		    options->brush_w);
  g_signal_connect (G_OBJECT (darea), "button_release_event",
		    G_CALLBACK (brush_widget_button_release),
		    options->brush_w);
  g_signal_connect (G_OBJECT (darea), "motion_notify_event",
		    G_CALLBACK (brush_widget_motion_notify),
		    options->brush_w);
  g_signal_connect (G_OBJECT (darea), "expose_event",
		    G_CALLBACK (brush_widget_expose), 
		    options->brush_w);
  g_signal_connect (G_OBJECT (darea), "realize",
		    G_CALLBACK (brush_widget_realize),
		    options->brush_w);
615

jtl's avatar
jtl committed
616
  gtk_widget_show_all (hbox);
617 618 619 620

  return options;
}

621 622 623

/*  the brush widget functions  */

624
static void
625 626
brush_widget_active_rect (BrushWidget  *brush_widget,
			  GtkWidget    *widget,
627 628 629 630 631
			  GdkRectangle *rect)
{
  int x,y;
  int r;

632
  r = MIN (widget->allocation.width, widget->allocation.height) / 2;
633

634
  x = widget->allocation.width / 2 + 0.85 * r * ink_options->aspect / 10.0 *
635
    cos (ink_options->angle);
636
  y = widget->allocation.height / 2 + 0.85 * r * ink_options->aspect / 10.0 *
637 638
    sin (ink_options->angle);

639 640
  rect->x = x - 5;
  rect->y = y - 5;
641 642 643 644 645
  rect->width = 10;
  rect->height = 10;
}

static void
646
brush_widget_realize (GtkWidget *widget)
647
{
648
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
649 650 651
}

static void
652 653 654 655 656
brush_widget_draw_brush (BrushWidget *brush_widget,
			 GtkWidget   *widget,
			 gdouble      xc,
			 gdouble      yc,
			 gdouble      radius)
657
{
658 659 660 661 662 663 664 665 666 667 668 669
  Blob *blob;

  blob = ink_options->function (xc, yc,
				radius * cos (ink_options->angle),
				radius * sin (ink_options->angle),
				(- (radius / ink_options->aspect) *
				 sin (ink_options->angle)),
				((radius / ink_options->aspect) *
				 cos (ink_options->angle)));

  paint_blob (widget->window, widget->style->fg_gc[widget->state], blob);
  g_free (blob);
670 671 672
}

static void
673 674 675
brush_widget_expose (GtkWidget      *widget,
		     GdkEventExpose *event,
		     BrushWidget    *brush_widget)
676 677 678
{
  GdkRectangle rect;
  int r0;
679 680

  r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
681 682 683 684

  if (r0 < 2)
    return;

685 686 687 688 689 690 691
  gdk_window_clear_area (widget->window, 0, 0,
			 widget->allocation.width,
			 widget->allocation.height);
  brush_widget_draw_brush (brush_widget, widget,
			   widget->allocation.width / 2,
			   widget->allocation.height / 2,
			   0.9 * r0);
692

693 694
  brush_widget_active_rect (brush_widget, widget, &rect);
  gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
695 696 697
		      TRUE,	/* filled */
		      rect.x, rect.y, 
		      rect.width, rect.height);
698
  gtk_draw_shadow (widget->style, widget->window, widget->state, GTK_SHADOW_OUT,
699 700 701 702 703
		   rect.x, rect.y,
		   rect.width, rect.height);
}

static void
704 705 706
brush_widget_button_press (GtkWidget      *widget,
			   GdkEventButton *event,
			   BrushWidget    *brush_widget)
707 708 709
{
  GdkRectangle rect;

710
  brush_widget_active_rect (brush_widget, widget, &rect);
711 712 713 714 715
  
  if ((event->x >= rect.x) && (event->x-rect.x < rect.width) &&
      (event->y >= rect.y) && (event->y-rect.y < rect.height))
    {
      brush_widget->state = TRUE;
716

717
      gtk_grab_add (brush_widget->widget);
718 719 720 721
    }
}

static void
722 723 724
brush_widget_button_release (GtkWidget      *widget,
			     GdkEventButton *event,
			     BrushWidget    *brush_widget)
725 726
{
  brush_widget->state = FALSE;
727

728
  gtk_grab_remove (brush_widget->widget);
729 730 731
}

static void
732 733 734
brush_widget_motion_notify (GtkWidget      *widget,
			    GdkEventMotion *event,
			    BrushWidget    *brush_widget)
735 736 737 738 739 740 741 742
{
  int x;
  int y;
  int r0;
  int rsquare;

  if (brush_widget->state)
    {
743 744
      x = event->x - widget->allocation.width / 2;
      y = event->y - widget->allocation.height / 2;
745 746 747 748
      rsquare = x*x + y*y;

      if (rsquare != 0)
	{
749
	  ink_options->angle = atan2 (y, x);
750

751
	  r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
752
	  ink_options->aspect =
753
	    10.0 * sqrt ((double) rsquare / (r0 * r0)) / 0.85;
754 755 756 757 758 759

	  if (ink_options->aspect < 1.0)
	    ink_options->aspect = 1.0;
	  if (ink_options->aspect > 10.0)
	    ink_options->aspect = 10.0;

760
	  gtk_widget_draw (widget, NULL);
761 762 763 764
	}
    }
}

765 766 767 768 769 770
/*
 * Return a black-on white pixmap in the given colormap and
 * visual that represents the BlobFunc 'function'
 */
static GdkPixmap *
blob_pixmap (GdkColormap *colormap,
771 772
	     GdkVisual   *visual,
	     BlobFunc     function)
773 774
{
  GdkPixmap *pixmap;
775 776 777
  GdkGC     *black_gc, *white_gc;
  GdkColor   tmp_color;
  Blob      *blob;
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792

  pixmap = gdk_pixmap_new (NULL, 22, 21, visual->depth);

  black_gc = gdk_gc_new (pixmap);
  gdk_color_black (colormap, &tmp_color);
  gdk_gc_set_foreground (black_gc, &tmp_color);

  white_gc = gdk_gc_new (pixmap);
  gdk_color_white (colormap, &tmp_color);
  gdk_gc_set_foreground (white_gc, &tmp_color);

  gdk_draw_rectangle (pixmap, white_gc, TRUE, 0, 0, 21, 20);
  gdk_draw_rectangle (pixmap, black_gc, FALSE, 0, 0, 21, 20);
  blob = (*function) (10, 10, 8, 0, 0, 8);
  paint_blob (pixmap, black_gc, blob);
Sven Neumann's avatar
Sven Neumann committed
793
  g_free (blob);
794 795 796 797 798 799 800 801 802 803 804

  gdk_gc_unref (white_gc);
  gdk_gc_unref (black_gc);

  return pixmap;
}

/*
 * Draw a blob onto a drawable with the specified graphics context
 */
static void
805 806 807
paint_blob (GdkDrawable *drawable,
	    GdkGC       *gc,
	    Blob        *blob)
808 809 810 811 812 813 814 815 816 817 818 819
{
  int i;

  for (i=0;i<blob->height;i++)
    {
      if (blob->data[i].left <= blob->data[i].right)
	gdk_draw_line (drawable, gc,
		       blob->data[i].left,i+blob->y,
		       blob->data[i].right+1,i+blob->y);
    }
}

820

821
static Blob *
822 823 824 825 826
ink_pen_ellipse (gdouble x_center,
		 gdouble y_center,
		 gdouble pressure,
		 gdouble xtilt,
		 gdouble ytilt,
827
		 gdouble velocity)
828 829 830 831 832
{
  double size;
  double tsin, tcos;
  double aspect, radmin;
  double x,y;
833
  double tscale;
Raph Levien's avatar
Raph Levien committed
834 835
  double tscale_c;
  double tscale_s;
836
  
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
  /* Adjust the size depending on pressure. */

  size = ink_options->size * (1.0 + ink_options->sensitivity *
			      (2.0 * pressure - 1.0) );

  /* Adjust the size further depending on pointer velocity
     and velocity-sensitivity.  These 'magic constants' are
     'feels natural' tigert-approved. --ADM */

  if (velocity < 3.0)
    velocity = 3.0;

#ifdef VERBOSE
  g_print("%f (%f) -> ", (float)size, (float)velocity);
#endif  

  size = ink_options->vel_sensitivity *
    ((4.5 * size) / (1.0 + ink_options->vel_sensitivity * (2.0*(velocity))))
    + (1.0 - ink_options->vel_sensitivity) * size;

#ifdef VERBOSE
  g_print("%f\n", (float)size);
#endif

  /* Clamp resulting size to sane limits */

  if (size > ink_options->size * (1.0 + ink_options->sensitivity))
    size = ink_options->size * (1.0 + ink_options->sensitivity);
865

866 867 868
  if (size*SUBSAMPLE < 1.0) size = 1.0/SUBSAMPLE;

  /* Add brush angle/aspect to tilt vectorially */
869

Raph Levien's avatar
Raph Levien committed
870 871 872 873
  /* I'm not happy with the way the brush widget info is combined with
     tilt info from the brush. My personal feeling is that representing
     both as affine transforms would make the most sense. -RLL */

874
  tscale = ink_options->tilt_sensitivity * 10.0;
875 876
  tscale_c = tscale * cos (gimp_deg_to_rad (ink_options->tilt_angle));
  tscale_s = tscale * sin (gimp_deg_to_rad (ink_options->tilt_angle));
Raph Levien's avatar
Raph Levien committed
877 878 879 880 881 882 883 884
  x = ink_options->aspect*cos(ink_options->angle) +
    xtilt * tscale_c - ytilt * tscale_s;
  y = ink_options->aspect*sin(ink_options->angle) +
    ytilt * tscale_c + xtilt * tscale_s;
#ifdef VERBOSE
  g_print ("angle %g aspect %g; %g %g; %g %g\n",
	   ink_options->angle, ink_options->aspect, tscale_c, tscale_s, x, y);
#endif
885 886 887 888 889 890 891 892 893 894 895 896
  aspect = sqrt(x*x+y*y);

  if (aspect != 0)
    {
      tcos = x/aspect;
      tsin = y/aspect;
    }
  else
    {
      tsin = sin(ink_options->angle);
      tcos = cos(ink_options->angle);
    }
897

898 899 900 901 902 903 904 905
  if (aspect < 1.0) 
    aspect = 1.0;
  else if (aspect > 10.0) 
    aspect = 10.0;

  radmin = SUBSAMPLE * size/aspect;
  if (radmin < 1.0) radmin = 1.0;
  
906 907 908
  return ink_options->function (x_center * SUBSAMPLE, y_center * SUBSAMPLE,
				radmin*aspect*tcos, radmin*aspect*tsin,  
				-radmin*tsin, radmin*tcos);
909 910 911
}

static void
912
ink_button_press (GimpTool       *tool,
913
		  GdkEventButton *bevent,
914
		  GDisplay       *gdisp)
915
{
916
  GimpInkTool  *ink_tool;
917 918
  GimpDrawable *drawable;
  Blob         *b;
919
  gdouble       x, y;
920

921
  ink_tool = GIMP_INK_TOOL (tool);
922 923 924 925

  /*  Keep the coordinates of the target  */
  gdisplay_untransform_coords_f (gdisp, bevent->x, bevent->y,
				 &x, &y, TRUE);
926
  drawable = gimp_image_active_drawable (gdisp->gimage);
927 928 929

  ink_init (ink_tool, drawable, x, y);

930 931
  tool->state        = ACTIVE;
  tool->gdisp        = gdisp;
932 933 934
  tool->paused_count = 0;

  /*  pause the current selection and grab the pointer  */
935
  gdisplays_selection_visibility (gdisp->gimage, SELECTION_PAUSE);
936

937
  /* add motion memory if you press mod1 first ^ perfectmouse */
938
  if (((bevent->state & GDK_MOD1_MASK) != 0) != (gimprc.perfectmouse != 0))
939 940 941 942 943
    gdk_pointer_grab (gdisp->canvas->window, FALSE,
		      GDK_BUTTON1_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
		      NULL, NULL, bevent->time);
  else
    gdk_pointer_grab (gdisp->canvas->window, FALSE,
944 945
		      GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK |
		      GDK_BUTTON_RELEASE_MASK,
946 947
		      NULL, NULL, bevent->time);
  
948
  tool->gdisp = gdisp;
949 950
  tool->state = ACTIVE;

951 952 953
#warning FIXME: presure, tilt

  b = ink_pen_ellipse (x, y,
954
		       1.0, 0.5, 0.5,
955 956
		       /* bevent->pressure, bevent->xtilt, bevent->ytilt, */
		       10.0);
957 958 959 960

  ink_paste (ink_tool, drawable, b);
  ink_tool->last_blob = b;

961 962 963 964 965 966 967
  time_smoother_init (ink_tool, bevent->time);
  ink_tool->last_time = bevent->time;
  dist_smoother_init (ink_tool, 0.0);
  ink_tool->init_velocity = TRUE;
  ink_tool->lastx = x;
  ink_tool->lasty = y;

968
  gdisplay_flush_now (gdisp);
969 970 971
}

static void
972
ink_button_release (GimpTool       *tool,
973
		    GdkEventButton *bevent,
974
		    GDisplay       *gdisp)
975
{
976 977
  GimpInkTool *ink_tool;
  GimpImage   *gimage;
978

979 980 981
  ink_tool = GIMP_INK_TOOL (tool);

  gimage = gdisp->gimage;
982 983

  /*  resume the current selection and ungrab the pointer  */
984
  gdisplays_selection_visibility (gdisp->gimage, SELECTION_RESUME);
985 986 987 988 989 990 991

  gdk_pointer_ungrab (bevent->time);
  gdk_flush ();

  /*  Set tool state to inactive -- no longer painting */
  tool->state = INACTIVE;

992 993 994 995
  /*  free the last blob  */
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = NULL;

996
  ink_finish (ink_tool, gimp_image_active_drawable (gdisp->gimage));
997 998 999
  gdisplays_flush ();
}

1000 1001

static void
1002 1003
dist_smoother_init (GimpInkTool *ink_tool,
		    gdouble      initval)
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
{
  gint i;

  ink_tool->dt_index = 0;

  for (i=0; i<DIST_SMOOTHER_BUFFER; i++)
    {
      ink_tool->dt_buffer[i] = initval;
    }
}

static gdouble
1016
dist_smoother_result (GimpInkTool *ink_tool)
1017
{
1018
  gint    i;
1019 1020
  gdouble result = 0.0;

1021
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
1022 1023 1024 1025
    {
      result += ink_tool->dt_buffer[i];
    }

1026
  return (result / (gdouble) DIST_SMOOTHER_BUFFER);
1027 1028 1029
}

static void
1030 1031
dist_smoother_add (GimpInkTool *ink_tool,
		   gdouble      value)
1032 1033 1034 1035 1036 1037 1038 1039 1040
{
  ink_tool->dt_buffer[ink_tool->dt_index] = value;

  if ((++ink_tool->dt_index) == DIST_SMOOTHER_BUFFER)
    ink_tool->dt_index = 0;
}


static void
1041 1042
time_smoother_init (GimpInkTool *ink_tool,
		    guint32      initval)
1043 1044 1045 1046 1047
{
  gint i;

  ink_tool->ts_index = 0;

1048
  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
1049 1050 1051 1052 1053 1054
    {
      ink_tool->ts_buffer[i] = initval;
    }
}

static gdouble
1055
time_smoother_result (GimpInkTool *ink_tool)
1056
{
1057
  gint    i;
1058 1059
  guint64 result = 0;

1060
  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
1061 1062 1063 1064
    {
      result += ink_tool->ts_buffer[i];
    }

Tor Lillqvist's avatar
Tor Lillqvist committed
1065 1066 1067
#ifdef _MSC_VER
  return (gdouble) (gint64) (result / TIME_SMOOTHER_BUFFER);
#else
1068
  return (result / TIME_SMOOTHER_BUFFER);
Tor Lillqvist's avatar
Tor Lillqvist committed
1069
#endif
1070 1071 1072
}

static void
1073 1074
time_smoother_add (GimpInkTool *ink_tool,
		   guint32      value)
1075 1076 1077 1078 1079 1080 1081 1082
{
  ink_tool->ts_buffer[ink_tool->ts_index] = value;

  if ((++ink_tool->ts_index) == TIME_SMOOTHER_BUFFER)
    ink_tool->ts_index = 0;
}


1083
static void
1084
ink_motion (GimpTool       *tool,
1085