gimpink.c 44.1 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
static void        gimp_ink_tool_class_init      (GimpInkToolClass *klass);
static void        gimp_ink_tool_init            (GimpInkTool      *tool);

120
static void        gimp_ink_tool_finalize        (GObject          *object);
121 122

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
GType
246 247
gimp_ink_tool_get_type (void)
{
248
  static GType tool_type = 0;
249 250 251

  if (! tool_type)
    {
252
      static const GTypeInfo tool_info =
253
      {
254 255 256 257 258 259
        sizeof (GimpInkToolClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_ink_tool_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
260
	sizeof (GimpInkTool),
261 262
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_ink_tool_init,
263 264
      };

265 266 267
      tool_type = g_type_register_static (GIMP_TYPE_TOOL,
					  "GimpInkTool", 
                                          &tool_info, 0);
268 269 270 271 272 273 274 275
    }

  return tool_type;
}

static void
gimp_ink_tool_class_init (GimpInkToolClass *klass)
{
276
  GObjectClass   *object_class;
277 278
  GimpToolClass  *tool_class;

279 280
  object_class = G_OBJECT_CLASS (klass);
  tool_class   = GIMP_TOOL_CLASS (klass);
281

282
  parent_class = g_type_class_peek_parent (klass);
283

284
  object_class->finalize     = gimp_ink_tool_finalize;
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305

  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,
306
					  (GimpToolOptions *) ink_options);
307

308
      ink_options_reset ((GimpToolOptions *) ink_options);
309 310 311 312
    }
}

static void
313
gimp_ink_tool_finalize (GObject *object)
314 315 316 317 318 319
{
  GimpInkTool *ink_tool;

  ink_tool = GIMP_INK_TOOL (object);

  if (ink_tool->last_blob)
320 321 322 323
    {
      g_free (ink_tool->last_blob);
      ink_tool->last_blob = NULL;
    }
324 325 326

  ink_cleanup ();

327
  G_OBJECT_CLASS (parent_class)->finalize (object);
328 329
}

330 331 332 333 334 335 336 337 338 339 340 341
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);
}

342
static void
343
ink_options_reset (GimpToolOptions *tool_options)
344
{
345
  InkOptions *options;
346

347 348 349
  options = (InkOptions *) tool_options;

  paint_options_reset (tool_options);
350

351 352 353 354 355 356
  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);
357 358
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->vel_sensitivity_w),
			    options->vel_sensitivity_d);
359 360
  gtk_adjustment_set_value (GTK_ADJUSTMENT (options->tilt_angle_w),
			    options->tilt_angle_d);
361 362 363 364 365 366
  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);
367 368
  options->aspect = options->aspect_d;
  options->angle  = options->angle_d;
369
  gtk_widget_queue_draw (options->brush_w->widget);
370 371
}

372
static InkOptions *
373
ink_options_new (void)
374
{
375
  InkOptions *options;
376 377 378 379 380 381 382 383 384 385
  GtkWidget  *table;
  GtkWidget  *vbox;
  GtkWidget  *hbox;
  GtkWidget  *hbox2;
  GtkWidget  *radio_button;
  GtkWidget  *pixmap_widget;
  GtkWidget  *slider;
  GtkWidget  *frame;
  GtkWidget  *darea;
  GdkPixmap  *pixmap;
386

387
  options = g_new0 (InkOptions, 1);
388
  paint_options_init ((PaintOptions *) options,
389
		      GIMP_TYPE_INK_TOOL,
390
		      ink_options_reset);
391

392
  options->size             = options->size_d             = 4.4;
393
  options->sensitivity      = options->sensitivity_d      = 1.0;
394 395
  options->vel_sensitivity  = options->vel_sensitivity_d  = 0.8;
  options->tilt_sensitivity = options->tilt_sensitivity_d = 0.4;
396 397 398 399 400
  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
401 402
  /*  the main vbox  */
  vbox = gtk_vbox_new (FALSE, 2);
403
  gtk_box_pack_start (GTK_BOX (((GimpToolOptions *) options)->main_vbox), vbox,
jtl's avatar
jtl committed
404 405 406 407 408 409 410 411 412 413 414 415 416 417
		      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);
418 419 420

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

  g_signal_connect (G_OBJECT (options->size_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->size);
jtl's avatar
jtl committed
432 433 434 435 436 437 438 439 440 441

  /* 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);
442 443 444 445

  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
446 447 448 449 450 451 452 453 454 455 456 457 458 459

  /* 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 */
460 461 462
  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));
463
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
jtl's avatar
jtl committed
464 465 466
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 1,
			     _("Size:"), 1.0, 1.0,
			     slider, 1, FALSE);
467
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
468 469 470 471

  g_signal_connect (G_OBJECT (options->sensitivity_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->sensitivity);
472
  
473 474 475 476
  /* 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));
477
  gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
jtl's avatar
jtl committed
478 479 480
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 2,
			     _("Tilt:"), 1.0, 1.0,
			     slider, 1, FALSE);
481
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
482 483 484 485

  g_signal_connect (G_OBJECT (options->tilt_sensitivity_w), "value_changed",
		    G_CALLBACK (gimp_double_adjustment_update),
		    &options->tilt_sensitivity);
486 487 488 489 490 491

  /* 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
492 493 494
  gimp_table_attach_aligned (GTK_TABLE (table), 0, 3,
			     _("Speed:"), 1.0, 1.0,
			     slider, 1, FALSE);
495
  gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
496 497 498 499

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

jtl's avatar
jtl committed
501 502 503 504
  /*  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
505

506
  /* Brush type radiobuttons */
507
  frame = gtk_frame_new (_("Type"));
jtl's avatar
jtl committed
508
  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
509 510
  gtk_widget_show (frame);

jtl's avatar
jtl committed
511 512 513
  hbox2 = gtk_hbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (frame), hbox2);
  
514 515
  vbox = gtk_vbox_new (FALSE, 2);
  gtk_container_set_border_width (GTK_CONTAINER (vbox), 2);
jtl's avatar
jtl committed
516
  gtk_box_pack_start (GTK_BOX (hbox2), vbox, FALSE, FALSE, 0);
517 518 519 520
  gtk_widget_show (vbox);

  pixmap = blob_pixmap (gtk_widget_get_colormap (vbox),
			gtk_widget_get_visual (vbox),
521 522 523
			blob_ellipse);

  pixmap_widget = gtk_pixmap_new (pixmap, NULL);
Sven Neumann's avatar
Sven Neumann committed
524
  gdk_drawable_unref (pixmap);
jtl's avatar
jtl committed
525
  gtk_misc_set_padding (GTK_MISC (pixmap_widget), 6, 0);
526 527 528

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

531 532 533 534 535
  g_signal_connect (G_OBJECT (radio_button), "toggled",
		    G_CALLBACK (ink_type_update),
		    (gpointer) blob_ellipse);


536
  options->function_w[0] = radio_button;
537 538 539

  pixmap = blob_pixmap (gtk_widget_get_colormap (vbox),
			gtk_widget_get_visual (vbox),
540 541 542
			blob_square);

  pixmap_widget = gtk_pixmap_new (pixmap, NULL);
Sven Neumann's avatar
Sven Neumann committed
543
  gdk_drawable_unref (pixmap);
jtl's avatar
jtl committed
544
  gtk_misc_set_padding (GTK_MISC (pixmap_widget), 6, 0);
545

546 547
  radio_button =
    gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
548
  gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
549
  gtk_box_pack_start (GTK_BOX (vbox), radio_button, FALSE, FALSE, 0);
550

551 552 553 554 555
  g_signal_connect (G_OBJECT (radio_button), "toggled",
		    G_CALLBACK (ink_type_update), 
		    (gpointer) blob_square);
  

556 557
  options->function_w[1] = radio_button;

558 559
  pixmap = blob_pixmap (gtk_widget_get_colormap (vbox),
			gtk_widget_get_visual (vbox),
560 561 562
			blob_diamond);

  pixmap_widget = gtk_pixmap_new (pixmap, NULL);
Sven Neumann's avatar
Sven Neumann committed
563
  gdk_drawable_unref (pixmap);
jtl's avatar
jtl committed
564
  gtk_misc_set_padding (GTK_MISC (pixmap_widget), 6, 0);
565

566 567
  radio_button =
    gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (radio_button));
568
  gtk_container_add (GTK_CONTAINER (radio_button), pixmap_widget);
569
  gtk_box_pack_start (GTK_BOX (vbox), radio_button, FALSE, FALSE, 0);
570

571 572 573 574 575
  g_signal_connect (G_OBJECT (radio_button), "toggled",
		    G_CALLBACK (ink_type_update), 
		    (gpointer) blob_diamond);


576 577
  options->function_w[2] = radio_button;

578
  /* Brush shape widget */
579
  frame = gtk_frame_new (_("Shape"));
jtl's avatar
jtl committed
580
  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
581 582 583 584 585 586
  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);
587

jtl's avatar
jtl committed
588
  frame = gtk_aspect_frame_new (NULL, 0.0, 0.5, 1.0, FALSE);
589 590
  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
591

jtl's avatar
jtl committed
592 593 594
  options->brush_w = g_new (BrushWidget, 1);
  options->brush_w->state = FALSE;

595
  darea = gtk_drawing_area_new();
596
  options->brush_w->widget = darea;
597

598 599
  gtk_drawing_area_size (GTK_DRAWING_AREA (darea), 60, 60);
  gtk_container_add (GTK_CONTAINER (frame), darea);
600

601 602 603
  gtk_widget_set_events (darea, 
			 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK
			 | GDK_POINTER_MOTION_MASK | GDK_EXPOSURE_MASK);
604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619

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

jtl's avatar
jtl committed
621
  gtk_widget_show_all (hbox);
622 623 624 625

  return options;
}

626 627 628

/*  the brush widget functions  */

629
static void
630 631
brush_widget_active_rect (BrushWidget  *brush_widget,
			  GtkWidget    *widget,
632 633 634 635 636
			  GdkRectangle *rect)
{
  int x,y;
  int r;

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

639
  x = widget->allocation.width / 2 + 0.85 * r * ink_options->aspect / 10.0 *
640
    cos (ink_options->angle);
641
  y = widget->allocation.height / 2 + 0.85 * r * ink_options->aspect / 10.0 *
642 643
    sin (ink_options->angle);

644 645
  rect->x = x - 5;
  rect->y = y - 5;
646 647 648 649 650
  rect->width = 10;
  rect->height = 10;
}

static void
651
brush_widget_realize (GtkWidget *widget)
652
{
653
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
654 655 656
}

static void
657 658 659 660 661
brush_widget_draw_brush (BrushWidget *brush_widget,
			 GtkWidget   *widget,
			 gdouble      xc,
			 gdouble      yc,
			 gdouble      radius)
662
{
663 664 665 666 667 668 669 670 671 672 673 674
  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);
675 676 677
}

static void
678 679 680
brush_widget_expose (GtkWidget      *widget,
		     GdkEventExpose *event,
		     BrushWidget    *brush_widget)
681 682 683
{
  GdkRectangle rect;
  int r0;
684 685

  r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
686 687 688 689

  if (r0 < 2)
    return;

690 691 692 693 694 695 696
  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);
697

698 699
  brush_widget_active_rect (brush_widget, widget, &rect);
  gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
700 701 702
		      TRUE,	/* filled */
		      rect.x, rect.y, 
		      rect.width, rect.height);
703
  gtk_draw_shadow (widget->style, widget->window, widget->state, GTK_SHADOW_OUT,
704 705 706 707 708
		   rect.x, rect.y,
		   rect.width, rect.height);
}

static void
709 710 711
brush_widget_button_press (GtkWidget      *widget,
			   GdkEventButton *event,
			   BrushWidget    *brush_widget)
712 713 714
{
  GdkRectangle rect;

715
  brush_widget_active_rect (brush_widget, widget, &rect);
716 717 718 719 720
  
  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;
721

722
      gtk_grab_add (brush_widget->widget);
723 724 725 726
    }
}

static void
727 728 729
brush_widget_button_release (GtkWidget      *widget,
			     GdkEventButton *event,
			     BrushWidget    *brush_widget)
730 731
{
  brush_widget->state = FALSE;
732

733
  gtk_grab_remove (brush_widget->widget);
734 735 736
}

static void
737 738 739
brush_widget_motion_notify (GtkWidget      *widget,
			    GdkEventMotion *event,
			    BrushWidget    *brush_widget)
740 741 742 743 744 745 746 747
{
  int x;
  int y;
  int r0;
  int rsquare;

  if (brush_widget->state)
    {
748 749
      x = event->x - widget->allocation.width / 2;
      y = event->y - widget->allocation.height / 2;
750 751 752 753
      rsquare = x*x + y*y;

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

756
	  r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
757
	  ink_options->aspect =
758
	    10.0 * sqrt ((double) rsquare / (r0 * r0)) / 0.85;
759 760 761 762 763 764

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

765
	  gtk_widget_draw (widget, NULL);
766 767 768 769
	}
    }
}

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

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

787 788 789 790 791
  tmp_color.red   = 0;
  tmp_color.green = 0;
  tmp_color.blue  = 0;
  gdk_colormap_alloc_colors (colormap, &tmp_color, 1, FALSE, TRUE, &success);

792 793 794
  black_gc = gdk_gc_new (pixmap);
  gdk_gc_set_foreground (black_gc, &tmp_color);

795 796 797 798 799
  tmp_color.red   = 255;
  tmp_color.green = 255;
  tmp_color.blue  = 255;
  gdk_colormap_alloc_colors (colormap, &tmp_color, 1, FALSE, TRUE, &success);

800 801 802 803 804 805 806
  white_gc = gdk_gc_new (pixmap);
  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
807
  g_free (blob);
808 809 810 811 812 813 814 815 816 817 818

  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
819 820 821
paint_blob (GdkDrawable *drawable,
	    GdkGC       *gc,
	    Blob        *blob)
822 823 824 825 826 827 828 829 830 831 832 833
{
  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);
    }
}

834

835
static Blob *
836 837 838 839 840
ink_pen_ellipse (gdouble x_center,
		 gdouble y_center,
		 gdouble pressure,
		 gdouble xtilt,
		 gdouble ytilt,
841
		 gdouble velocity)
842 843 844 845 846
{
  double size;
  double tsin, tcos;
  double aspect, radmin;
  double x,y;
847
  double tscale;
Raph Levien's avatar
Raph Levien committed
848 849
  double tscale_c;
  double tscale_s;
850
  
851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878
  /* 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);
879

880 881 882
  if (size*SUBSAMPLE < 1.0) size = 1.0/SUBSAMPLE;

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

Raph Levien's avatar
Raph Levien committed
884 885 886 887
  /* 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 */

888
  tscale = ink_options->tilt_sensitivity * 10.0;
889 890
  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
891 892 893 894 895 896 897 898
  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
899 900 901 902 903 904 905 906 907 908 909 910
  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);
    }
911

912 913 914 915 916 917 918 919
  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;
  
920 921 922
  return ink_options->function (x_center * SUBSAMPLE, y_center * SUBSAMPLE,
				radmin*aspect*tcos, radmin*aspect*tsin,  
				-radmin*tsin, radmin*tcos);
923 924 925
}

static void
926
ink_button_press (GimpTool       *tool,
927
		  GdkEventButton *bevent,
928
		  GDisplay       *gdisp)
929
{
930
  GimpInkTool  *ink_tool;
931 932
  GimpDrawable *drawable;
  Blob         *b;
933
  gdouble       x, y;
934

935
  ink_tool = GIMP_INK_TOOL (tool);
936 937 938 939

  /*  Keep the coordinates of the target  */
  gdisplay_untransform_coords_f (gdisp, bevent->x, bevent->y,
				 &x, &y, TRUE);
940
  drawable = gimp_image_active_drawable (gdisp->gimage);
941 942 943

  ink_init (ink_tool, drawable, x, y);

944 945
  tool->state        = ACTIVE;
  tool->gdisp        = gdisp;
946 947 948
  tool->paused_count = 0;

  /*  pause the current selection and grab the pointer  */
949
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_PAUSE);
950

951
  /* add motion memory if you press mod1 first ^ perfectmouse */
952
  if (((bevent->state & GDK_MOD1_MASK) != 0) != (gimprc.perfectmouse != 0))
953 954 955 956 957
    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,
958 959
		      GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON1_MOTION_MASK |
		      GDK_BUTTON_RELEASE_MASK,
960 961
		      NULL, NULL, bevent->time);
  
962
  tool->gdisp = gdisp;
963
  tool->state = ACTIVE;
Hans Breuer's avatar
Hans Breuer committed
964
#ifdef __GNUC__
965
#warning FIXME: presure, tilt
Hans Breuer's avatar
Hans Breuer committed
966
#endif
967
  b = ink_pen_ellipse (x, y,
968
		       1.0, 0.5, 0.5,
969 970
		       /* bevent->pressure, bevent->xtilt, bevent->ytilt, */
		       10.0);
971 972 973 974

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

975 976 977 978 979 980 981
  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;

982
  gdisplay_flush_now (gdisp);
983 984 985
}

static void
986
ink_button_release (GimpTool       *tool,
987
		    GdkEventButton *bevent,
988
		    GDisplay       *gdisp)
989
{
990 991
  GimpInkTool *ink_tool;
  GimpImage   *gimage;
992

993 994 995
  ink_tool = GIMP_INK_TOOL (tool);

  gimage = gdisp->gimage;
996 997

  /*  resume the current selection and ungrab the pointer  */
998
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_RESUME);
999 1000 1001 1002 1003 1004 1005

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

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

1006 1007 1008 1009
  /*  free the last blob  */
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = NULL;

1010
  ink_finish (ink_tool, gimp_image_active_drawable (gdisp->gimage));
1011 1012 1013
  gdisplays_flush ();
}

1014 1015

static void
1016 1017
dist_smoother_init (GimpInkTool *ink_tool,
		    gdouble      initval)
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
{
  gint i;

  ink_tool->dt_index = 0;

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

static gdouble
1030
dist_smoother_result (GimpInkTool *ink_tool)
1031
{
1032
  gint    i;
1033 1034
  gdouble result = 0.0;