gimpink.c 48 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
#include "core/gimpcontext.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimpimage-mask.h"
43
#include "core/gimptoolinfo.h"
44

45
#include "display/gimpdisplay.h"
46
#include "display/gimpdisplay-foreach.h"
Michael Natterer's avatar
Michael Natterer committed
47
#include "display/gimpdisplayshell.h"
48

49 50
#include "gimpinktool.h"
#include "gimpinktool-blob.h"
51
#include "paint_options.h"
52
#include "tool_manager.h"
53

54
#include "app_procs.h"
Michael Natterer's avatar
Michael Natterer committed
55 56 57
#include "gimprc.h"
#include "undo.h"

58 59
#include "libgimp/gimpintl.h"

60

61
#define SUBSAMPLE 8
62

63 64 65 66 67 68 69
typedef Blob * (* BlobFunc) (gdouble,
			     gdouble,
			     gdouble,
			     gdouble,
			     gdouble,
			     gdouble);

70

71
typedef struct _BrushWidget BrushWidget;
72
typedef struct _InkOptions  InkOptions;
Michael Natterer's avatar
Michael Natterer committed
73

74 75
struct _BrushWidget
{
76 77
  GtkWidget  *widget;
  gboolean    state;
78

79 80 81
  /* EEK */
  InkOptions *ink_options;
};
Michael Natterer's avatar
Michael Natterer committed
82

83 84
struct _InkOptions
{
85
  PaintOptions  paint_options;
86

Michael Natterer's avatar
Michael Natterer committed
87 88
  gdouble       size;
  gdouble       size_d;
89
  GtkObject    *size_w;
90

Michael Natterer's avatar
Michael Natterer committed
91 92
  gdouble       sensitivity;
  gdouble       sensitivity_d;
93
  GtkObject    *sensitivity_w;
94

Michael Natterer's avatar
Michael Natterer committed
95 96
  gdouble       vel_sensitivity;
  gdouble       vel_sensitivity_d;
97
  GtkObject    *vel_sensitivity_w;
98

Michael Natterer's avatar
Michael Natterer committed
99 100
  gdouble       tilt_sensitivity;
  gdouble       tilt_sensitivity_d;
101
  GtkObject    *tilt_sensitivity_w;
102

Michael Natterer's avatar
Michael Natterer committed
103 104
  gdouble       tilt_angle;
  gdouble       tilt_angle_d;
105
  GtkObject    *tilt_angle_w;
106

107 108 109
  BlobFunc      function;
  BlobFunc      function_d;
  GtkWidget    *function_w[3];  /* 3 radio buttons */
110

Michael Natterer's avatar
Michael Natterer committed
111 112 113 114
  gdouble       aspect;
  gdouble       aspect_d;
  gdouble       angle;
  gdouble       angle_d;
115
  BrushWidget  *brush_w;
116 117 118
};


119
/*  local function prototypes  */
120

121 122 123
static void        gimp_ink_tool_class_init      (GimpInkToolClass *klass);
static void        gimp_ink_tool_init            (GimpInkTool      *tool);

124
static void        gimp_ink_tool_finalize        (GObject          *object);
125

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
static void        gimp_ink_tool_control         (GimpTool         *tool,
                                                  ToolAction        tool_action,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_button_press    (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  guint32           time,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_button_release  (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  guint32           time,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_motion          (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  guint32           time,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);
static void        gimp_ink_tool_cursor_update   (GimpTool         *tool,
                                                  GimpCoords       *coords,
                                                  GdkModifierType   state,
                                                  GimpDisplay      *gdisp);

149 150
static Blob *      ink_pen_ellipse      (InkOptions      *options,
                                         gdouble          x_center,
151 152 153 154 155
                                         gdouble          y_center,
                                         gdouble          pressure,
                                         gdouble          xtilt,
                                         gdouble          ytilt,
                                         gdouble          velocity);
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173

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);
174 175
static void        ink_cleanup          (void);

176 177 178 179 180 181 182 183
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);
184

Michael Natterer's avatar
Michael Natterer committed
185
/*  Rendering functions  */
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
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);
206

Michael Natterer's avatar
Michael Natterer committed
207
/*  Brush pseudo-widget callbacks  */
208 209
static void   brush_widget_active_rect    (BrushWidget    *brush_widget,
					   GtkWidget      *widget,
210
					   GdkRectangle   *rect);
211 212
static void   brush_widget_realize        (GtkWidget      *widget);
static void   brush_widget_expose         (GtkWidget      *widget,
213 214
					   GdkEventExpose *event,
					   BrushWidget    *brush_widget);
215
static void   brush_widget_button_press   (GtkWidget      *widget,
216 217
					   GdkEventButton *event,
					   BrushWidget    *brush_widget);
218
static void   brush_widget_button_release (GtkWidget      *widget,
219 220
					   GdkEventButton *event,
					   BrushWidget    *brush_widget);
221
static void   brush_widget_motion_notify  (GtkWidget      *widget,
222 223 224
					   GdkEventMotion *event,
					   BrushWidget    *brush_widget);

225 226 227 228
static GimpToolOptions * ink_options_new   (GimpToolInfo    *tool_info);
static void              ink_options_reset (GimpToolOptions *tool_options);
static void              ink_type_update   (GtkWidget       *radio_button,
                                            BlobFunc         function);
229

230

231 232 233 234 235 236 237 238 239 240 241 242 243
/* local variables */

/*  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;

244
static GimpToolClass *parent_class = NULL;
245

246

247
/*  public functions  */
248

249
void
250 251
gimp_ink_tool_register (Gimp                     *gimp,
                        GimpToolRegisterCallback  callback)
252
{
253 254 255 256 257 258 259 260 261 262
  (* callback) (gimp,
                GIMP_TYPE_INK_TOOL,
                ink_options_new,
                TRUE,
                "gimp:ink_tool",
                _("Ink Tool"),
                _("Draw in ink"),
                N_("/Tools/Paint Tools/Ink"), "K",
                NULL, "tools/ink.html",
                GIMP_STOCK_TOOL_INK);
263 264
}

265
GType
266 267
gimp_ink_tool_get_type (void)
{
268
  static GType tool_type = 0;
269 270 271

  if (! tool_type)
    {
272
      static const GTypeInfo tool_info =
273
      {
274 275 276 277 278 279
        sizeof (GimpInkToolClass),
	(GBaseInitFunc) NULL,
	(GBaseFinalizeFunc) NULL,
	(GClassInitFunc) gimp_ink_tool_class_init,
	NULL,           /* class_finalize */
	NULL,           /* class_data     */
280
	sizeof (GimpInkTool),
281 282
	0,              /* n_preallocs    */
	(GInstanceInitFunc) gimp_ink_tool_init,
283 284
      };

285 286 287
      tool_type = g_type_register_static (GIMP_TYPE_TOOL,
					  "GimpInkTool", 
                                          &tool_info, 0);
288 289 290 291 292
    }

  return tool_type;
}

293 294 295

/*  private functions  */

296 297 298
static void
gimp_ink_tool_class_init (GimpInkToolClass *klass)
{
299
  GObjectClass   *object_class;
300 301
  GimpToolClass  *tool_class;

302 303
  object_class = G_OBJECT_CLASS (klass);
  tool_class   = GIMP_TOOL_CLASS (klass);
304

305
  parent_class = g_type_class_peek_parent (klass);
306

307
  object_class->finalize     = gimp_ink_tool_finalize;
308

309 310 311 312 313
  tool_class->control        = gimp_ink_tool_control;
  tool_class->button_press   = gimp_ink_tool_button_press;
  tool_class->button_release = gimp_ink_tool_button_release;
  tool_class->motion         = gimp_ink_tool_motion;
  tool_class->cursor_update  = gimp_ink_tool_cursor_update;
314 315 316 317 318 319 320 321
}

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

  tool = GIMP_TOOL (ink_tool);
322 323

  tool->tool_cursor = GIMP_INK_TOOL_CURSOR;
324 325 326
}

static void
327
gimp_ink_tool_finalize (GObject *object)
328 329 330 331 332 333
{
  GimpInkTool *ink_tool;

  ink_tool = GIMP_INK_TOOL (object);

  if (ink_tool->last_blob)
334 335 336 337
    {
      g_free (ink_tool->last_blob);
      ink_tool->last_blob = NULL;
    }
338 339 340

  ink_cleanup ();

341
  G_OBJECT_CLASS (parent_class)->finalize (object);
342 343
}

344 345 346 347
static void
gimp_ink_tool_control (GimpTool    *tool,
                       ToolAction   action,
                       GimpDisplay *gdisp)
348
{
349
  GimpInkTool *ink_tool;
350

351
  ink_tool = GIMP_INK_TOOL (tool);
352

353 354 355 356
  switch (action)
    {
    case PAUSE:
      break;
357

358 359
    case RESUME:
      break;
360

361 362 363
    case HALT:
      ink_cleanup ();
      break;
364

365 366 367
    default:
      break;
    }
368 369
}

370 371 372 373 374 375
static void
gimp_ink_tool_button_press (GimpTool        *tool,
                            GimpCoords      *coords,
                            guint32          time,
                            GdkModifierType  state,
                            GimpDisplay     *gdisp)
376
{
377
  GimpInkTool      *ink_tool;
378
  InkOptions       *options;
379 380 381
  GimpDisplayShell *shell;
  GimpDrawable     *drawable;
  Blob             *b;
382

383
  ink_tool = GIMP_INK_TOOL (tool);
384

385 386
  options = (InkOptions *) tool->tool_info->tool_options;

387
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);
388

389
  drawable = gimp_image_active_drawable (gdisp->gimage);
jtl's avatar
jtl committed
390

391
  ink_init (ink_tool, drawable, coords->x, coords->y);
jtl's avatar
jtl committed
392

393 394 395
  tool->state        = ACTIVE;
  tool->gdisp        = gdisp;
  tool->paused_count = 0;
396

397 398
  /*  pause the current selection and grab the pointer  */
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_PAUSE);
399

400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
  /* add motion memory if you press mod1 first ^ perfectmouse */
  if (((state & GDK_MOD1_MASK) != 0) != (gimprc.perfectmouse != 0))
    {
      gdk_pointer_grab (shell->canvas->window, FALSE,
                        GDK_BUTTON1_MOTION_MASK |
                        GDK_BUTTON_RELEASE_MASK,
                        NULL, NULL, time);
    }
  else
    {
      gdk_pointer_grab (shell->canvas->window, FALSE,
                        GDK_POINTER_MOTION_HINT_MASK |
                        GDK_BUTTON1_MOTION_MASK |
                        GDK_BUTTON_RELEASE_MASK,
                        NULL, NULL, time);
    }
  
417 418
  b = ink_pen_ellipse (options,
                       coords->x,
419 420 421 422 423
                       coords->y,
		       coords->pressure,
                       coords->xtilt,
                       coords->ytilt,
		       10.0);
jtl's avatar
jtl committed
424

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

428 429 430 431 432 433
  time_smoother_init (ink_tool, time);
  ink_tool->last_time = time;
  dist_smoother_init (ink_tool, 0.0);
  ink_tool->init_velocity = TRUE;
  ink_tool->lastx = coords->x;
  ink_tool->lasty = coords->y;
jtl's avatar
jtl committed
434

435 436
  gimp_display_flush_now (gdisp);
}
jtl's avatar
jtl committed
437

438 439 440 441 442 443 444 445 446
static void
gimp_ink_tool_button_release (GimpTool        *tool,
                              GimpCoords      *coords,
                              guint32          time,
                              GdkModifierType  state,
                              GimpDisplay     *gdisp)
{
  GimpInkTool *ink_tool;
  GimpImage   *gimage;
jtl's avatar
jtl committed
447

448
  ink_tool = GIMP_INK_TOOL (tool);
449

450
  gimage = gdisp->gimage;
451

452 453
  /*  resume the current selection and ungrab the pointer  */
  gimp_image_selection_control (gdisp->gimage, GIMP_SELECTION_RESUME);
454

455 456
  gdk_pointer_ungrab (time);
  gdk_flush ();
457

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

461 462 463
  /*  free the last blob  */
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = NULL;
Raph Levien's avatar
Raph Levien committed
464

465 466 467
  ink_finish (ink_tool, gimp_image_active_drawable (gdisp->gimage));
  gdisplays_flush ();
}
468

469 470 471 472 473 474 475 476
static void
gimp_ink_tool_motion (GimpTool        *tool,
                      GimpCoords      *coords,
                      guint32          time,
                      GdkModifierType  state,
                      GimpDisplay     *gdisp)
{
  GimpInkTool  *ink_tool;
477
  InkOptions   *options;
478 479 480 481 482 483
  GimpDrawable *drawable;
  Blob         *b, *blob_union;

  gdouble velocity;
  gdouble dist;
  gdouble lasttime, thistime;
484

485
  ink_tool = GIMP_INK_TOOL (tool);
486

487 488
  options = (InkOptions *) tool->tool_info->tool_options;

489
  drawable = gimp_image_active_drawable (gdisp->gimage);
490

491
  lasttime = ink_tool->last_time;
492

493 494
  time_smoother_add (ink_tool, time);
  thistime = ink_tool->last_time = time_smoother_result (ink_tool);
495

496 497 498 499 500 501
  /* The time resolution on X-based GDK motion events is
     bloody awful, hence the use of the smoothing function.
     Sadly this also means that there is always the chance of
     having an indeterminite velocity since this event and
     the previous several may still appear to issue at the same
     instant. -ADM */
502

503 504
  if (thistime == lasttime)
    thistime = lasttime + 1;
505

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
  if (ink_tool->init_velocity)
    {
      dist_smoother_init (ink_tool,
			  dist = sqrt ((ink_tool->lastx - coords->x) *
                                       (ink_tool->lastx - coords->x) +
				       (ink_tool->lasty - coords->y) *
                                       (ink_tool->lasty - coords->y)));
      ink_tool->init_velocity = FALSE;
    }
  else
    {
      dist_smoother_add (ink_tool,
			 sqrt ((ink_tool->lastx - coords->x) *
                               (ink_tool->lastx - coords->x) +
			       (ink_tool->lasty - coords->y) *
                               (ink_tool->lasty - coords->y)));
522

523 524
      dist = dist_smoother_result (ink_tool);
    }
525

526 527
  ink_tool->lastx = coords->x;
  ink_tool->lasty = coords->y;
528

529
  velocity = 10.0 * sqrt ((dist) / (gdouble) (thistime - lasttime));
530

531 532
  b = ink_pen_ellipse (options,
                       coords->x,
533 534 535 536 537
                       coords->y,
                       coords->pressure,
                       coords->xtilt,
		       coords->ytilt,
                       velocity);
538

539 540 541
  blob_union = blob_convex_union (ink_tool->last_blob, b);
  g_free (ink_tool->last_blob);
  ink_tool->last_blob = b;
542

543 544
  ink_paste (ink_tool, drawable, blob_union);  
  g_free (blob_union);
545

546 547
  gimp_display_flush_now (gdisp);
}
jtl's avatar
jtl committed
548

549 550 551 552 553 554 555 556 557
static void
gimp_ink_tool_cursor_update (GimpTool        *tool,
                             GimpCoords      *coords,
                             GdkModifierType  state,
                             GimpDisplay     *gdisp)
{
  GimpDisplayShell *shell;
  GimpLayer        *layer;
  GdkCursorType     ctype = GDK_TOP_LEFT_ARROW;
558

559
  shell = GIMP_DISPLAY_SHELL (gdisp->shell);
560

561 562 563
  if ((layer = gimp_image_get_active_layer (gdisp->gimage))) 
    {
      gint off_x, off_y;
564

565
      gimp_drawable_offsets (GIMP_DRAWABLE (layer), &off_x, &off_y);
566

567 568 569 570 571 572 573 574
      if (coords->x >= off_x &&
          coords->y >= off_y &&
	  coords->x < (off_x + gimp_drawable_width (GIMP_DRAWABLE (layer))) &&
	  coords->y < (off_y + gimp_drawable_height (GIMP_DRAWABLE (layer))))
	{
	  /*  One more test--is there a selected region?
	   *  if so, is cursor inside?
	   */
575
	  if (gimp_image_mask_is_empty (gdisp->gimage))
576
	    ctype = GIMP_MOUSE_CURSOR;
577
	  else if (gimp_image_mask_value (gdisp->gimage, coords->x, coords->y))
578 579 580
	    ctype = GIMP_MOUSE_CURSOR;
	}
    }
581

582 583 584 585
  gimp_display_shell_install_tool_cursor (shell,
                                          ctype,
                                          GIMP_INK_TOOL_CURSOR,
                                          GIMP_CURSOR_MODIFIER_NONE);
586 587
}

588 589 590

/*  the brush widget functions  */

591
static void
592 593
brush_widget_active_rect (BrushWidget  *brush_widget,
			  GtkWidget    *widget,
594 595
			  GdkRectangle *rect)
{
596 597
  gint x,y;
  gint r;
598

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

601 602 603 604
  x = widget->allocation.width / 2 + 0.85 * r * brush_widget->ink_options->aspect / 10.0 *
    cos (brush_widget->ink_options->angle);
  y = widget->allocation.height / 2 + 0.85 * r * brush_widget->ink_options->aspect / 10.0 *
    sin (brush_widget->ink_options->angle);
605

606 607
  rect->x = x - 5;
  rect->y = y - 5;
608 609 610 611 612
  rect->width = 10;
  rect->height = 10;
}

static void
613
brush_widget_realize (GtkWidget *widget)
614
{
615
  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
616 617 618
}

static void
619 620 621 622 623
brush_widget_draw_brush (BrushWidget *brush_widget,
			 GtkWidget   *widget,
			 gdouble      xc,
			 gdouble      yc,
			 gdouble      radius)
624
{
625 626
  Blob *blob;

627 628 629 630 631 632 633
  blob = brush_widget->ink_options->function (xc, yc,
                                              radius * cos (brush_widget->ink_options->angle),
                                              radius * sin (brush_widget->ink_options->angle),
                                              (- (radius / brush_widget->ink_options->aspect) *
                                               sin (brush_widget->ink_options->angle)),
                                              ((radius / brush_widget->ink_options->aspect) *
                                               cos (brush_widget->ink_options->angle)));
634 635 636

  paint_blob (widget->window, widget->style->fg_gc[widget->state], blob);
  g_free (blob);
637 638 639
}

static void
640 641 642
brush_widget_expose (GtkWidget      *widget,
		     GdkEventExpose *event,
		     BrushWidget    *brush_widget)
643 644 645
{
  GdkRectangle rect;
  int r0;
646 647

  r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
648 649 650 651

  if (r0 < 2)
    return;

652 653 654 655 656 657 658
  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);
659

660 661
  brush_widget_active_rect (brush_widget, widget, &rect);
  gdk_draw_rectangle (widget->window, widget->style->bg_gc[GTK_STATE_NORMAL],
662 663 664
		      TRUE,	/* filled */
		      rect.x, rect.y, 
		      rect.width, rect.height);
665 666 667 668 669
  gtk_paint_shadow (widget->style, widget->window, widget->state,
                    GTK_SHADOW_OUT,
                    NULL, widget, NULL,
                    rect.x, rect.y,
                    rect.width, rect.height);
670 671 672
}

static void
673 674 675
brush_widget_button_press (GtkWidget      *widget,
			   GdkEventButton *event,
			   BrushWidget    *brush_widget)
676 677 678
{
  GdkRectangle rect;

679
  brush_widget_active_rect (brush_widget, widget, &rect);
680 681 682 683 684
  
  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;
685

686
      gtk_grab_add (brush_widget->widget);
687 688 689 690
    }
}

static void
691 692 693
brush_widget_button_release (GtkWidget      *widget,
			     GdkEventButton *event,
			     BrushWidget    *brush_widget)
694 695
{
  brush_widget->state = FALSE;
696

697
  gtk_grab_remove (brush_widget->widget);
698 699 700
}

static void
701 702 703
brush_widget_motion_notify (GtkWidget      *widget,
			    GdkEventMotion *event,
			    BrushWidget    *brush_widget)
704 705 706 707 708 709 710 711
{
  int x;
  int y;
  int r0;
  int rsquare;

  if (brush_widget->state)
    {
712 713
      x = event->x - widget->allocation.width / 2;
      y = event->y - widget->allocation.height / 2;
714 715 716 717
      rsquare = x*x + y*y;

      if (rsquare != 0)
	{
718
	  brush_widget->ink_options->angle = atan2 (y, x);
719

720
	  r0 = MIN (widget->allocation.width, widget->allocation.height) / 2;
721 722
	  brush_widget->ink_options->aspect =
	    10.0 * sqrt ((gdouble) rsquare / (r0 * r0)) / 0.85;
723

724 725 726 727
	  if (brush_widget->ink_options->aspect < 1.0)
	    brush_widget->ink_options->aspect = 1.0;
	  if (brush_widget->ink_options->aspect > 10.0)
	    brush_widget->ink_options->aspect = 10.0;
728

729
	  gtk_widget_queue_draw (widget);
730 731 732 733
	}
    }
}

734 735 736 737 738 739
/*
 * Return a black-on white pixmap in the given colormap and
 * visual that represents the BlobFunc 'function'
 */
static GdkPixmap *
blob_pixmap (GdkColormap *colormap,
740 741
	     GdkVisual   *visual,
	     BlobFunc     function)
742 743
{
  GdkPixmap *pixmap;
744 745
  GdkGC     *black_gc, *white_gc;
  GdkColor   tmp_color;
746
  gboolean   success;
747
  Blob      *blob;
748 749 750

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

751 752 753 754 755
  tmp_color.red   = 0;
  tmp_color.green = 0;
  tmp_color.blue  = 0;
  gdk_colormap_alloc_colors (colormap, &tmp_color, 1, FALSE, TRUE, &success);

756 757 758
  black_gc = gdk_gc_new (pixmap);
  gdk_gc_set_foreground (black_gc, &tmp_color);

759 760 761 762 763
  tmp_color.red   = 255;
  tmp_color.green = 255;
  tmp_color.blue  = 255;
  gdk_colormap_alloc_colors (colormap, &tmp_color, 1, FALSE, TRUE, &success);

764 765 766 767 768 769 770
  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
771
  g_free (blob);
772

773 774
  g_object_unref (white_gc);
  g_object_unref (black_gc);
775 776 777 778 779 780 781 782

  return pixmap;
}

/*
 * Draw a blob onto a drawable with the specified graphics context
 */
static void
783 784 785
paint_blob (GdkDrawable *drawable,
	    GdkGC       *gc,
	    Blob        *blob)
786 787 788 789 790 791 792 793 794 795 796 797
{
  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);
    }
}

798

799
static Blob *
800 801 802 803 804 805 806
ink_pen_ellipse (InkOptions *options,
                 gdouble     x_center,
		 gdouble     y_center,
		 gdouble     pressure,
		 gdouble     xtilt,
		 gdouble     ytilt,
		 gdouble     velocity)
807
{
808 809 810 811 812 813 814 815
  gdouble size;
  gdouble tsin, tcos;
  gdouble aspect, radmin;
  gdouble x,y;
  gdouble tscale;
  gdouble tscale_c;
  gdouble tscale_s;

816 817
  /* Adjust the size depending on pressure. */

818 819
  size = options->size * (1.0 + options->sensitivity *
                          (2.0 * pressure - 1.0) );
820 821 822 823 824 825 826 827 828 829 830 831

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

832 833 834
  size = options->vel_sensitivity *
    ((4.5 * size) / (1.0 + options->vel_sensitivity * (2.0*(velocity))))
    + (1.0 - options->vel_sensitivity) * size;
835 836 837 838 839 840 841

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

  /* Clamp resulting size to sane limits */

842 843
  if (size > options->size * (1.0 + options->sensitivity))
    size = options->size * (1.0 + options->sensitivity);
844

845 846 847
  if (size*SUBSAMPLE < 1.0) size = 1.0/SUBSAMPLE;

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

Raph Levien's avatar
Raph Levien committed
849 850 851 852
  /* 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 */

853 854 855 856 857 858 859 860 861
  tscale = options->tilt_sensitivity * 10.0;
  tscale_c = tscale * cos (gimp_deg_to_rad (options->tilt_angle));
  tscale_s = tscale * sin (gimp_deg_to_rad (options->tilt_angle));

  x = (options->aspect * cos (options->angle) +
       xtilt * tscale_c - ytilt * tscale_s);
  y = (options->aspect * sin (options->angle) +
       ytilt * tscale_c + xtilt * tscale_s);

Raph Levien's avatar
Raph Levien committed
862 863
#ifdef VERBOSE
  g_print ("angle %g aspect %g; %g %g; %g %g\n",
864
	   options->angle, options->aspect, tscale_c, tscale_s, x, y);
Raph Levien's avatar
Raph Levien committed
865
#endif
866 867 868 869 870 871 872 873 874
  aspect = sqrt(x*x+y*y);

  if (aspect != 0)
    {
      tcos = x/aspect;
      tsin = y/aspect;
    }
  else
    {
875 876
      tsin = sin (options->angle);
      tcos = cos (options->angle);
877
    }
878

879 880 881 882 883 884 885 886
  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;
  
887 888 889 890 891 892
  return options->function (x_center * SUBSAMPLE,
                            y_center * SUBSAMPLE,
                            radmin * aspect * tcos,
                            radmin * aspect * tsin,  
                            -radmin * tsin,
                            radmin * tcos);
893 894 895
}

static void
896 897
dist_smoother_init (GimpInkTool *ink_tool,
		    gdouble      initval)
898
{
899
  gint i;
900

901
  ink_tool->dt_index = 0;
902

903
  for (i=0; i<DIST_SMOOTHER_BUFFER; i++)
904
    {
905 906 907
      ink_tool->dt_buffer[i] = initval;
    }
}
908

909 910 911 912 913
static gdouble
dist_smoother_result (GimpInkTool *ink_tool)
{
  gint    i;
  gdouble result = 0.0;
914

915 916 917
  for (i = 0; i < DIST_SMOOTHER_BUFFER; i++)
    {
      result += ink_tool->dt_buffer[i];
918
    }
919 920

  return (result / (gdouble) DIST_SMOOTHER_BUFFER);
921 922 923
}

static void
924 925
dist_smoother_add (GimpInkTool *ink_tool,
		   gdouble      value)
926
{
927
  ink_tool->dt_buffer[ink_tool->dt_index] = value;
Michael Natterer's avatar
Michael Natterer committed
928

929 930 931
  if ((++ink_tool->dt_index) == DIST_SMOOTHER_BUFFER)
    ink_tool->dt_index = 0;
}
932 933


934 935 936 937 938
static void
time_smoother_init (GimpInkTool *ink_tool,
		    guint32      initval)
{
  gint i;
939

940
  ink_tool->ts_index = 0;
941

942
  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
943
    {
944
      ink_tool->ts_buffer[i] = initval;
945
    }
946 947 948 949 950 951 952 953 954
}

static gdouble
time_smoother_result (GimpInkTool *ink_tool)
{
  gint    i;
  guint64 result = 0;

  for (i = 0; i < TIME_SMOOTHER_BUFFER; i++)
955
    {
956
      result += ink_tool->ts_buffer[i];
957
    }
958

959 960 961 962 963 964
#ifdef _MSC_VER
  return (gdouble) (gint64) (result / TIME_SMOOTHER_BUFFER);
#else
  return (result / TIME_SMOOTHER_BUFFER);
#endif
}
965 966

static void
967 968
time_smoother_add (GimpInkTool *ink_tool,
		   guint32      value)
969 970 971 972 973 974 975
{
  ink_tool->ts_buffer[ink_tool->ts_index] = value;

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

976
static void
977
ink_init (GimpInkTool  *ink_tool,
978 979 980
	  GimpDrawable *drawable, 
	  gdouble       x,
	  gdouble       y)
981 982 983 984 985 986 987 988
{
  /*  free the block structures  */
  if (undo_tiles)
    tile_manager_destroy (undo_tiles);
  if (canvas_tiles)
    tile_manager_destroy (canvas_tiles);

  /*  Allocate the undo structure  */
989 990 991
  undo_tiles = tile_manager_new (gimp_drawable_width (drawable),
				 gimp_drawable_height (drawable),
				 gimp_drawable_bytes (drawable));
992 993

  /*  Allocate the canvas blocks structure  */
994 995
  canvas_tiles = tile_manager_new (gimp_drawable_width (drawable),
				   gimp_drawable_height (drawable), 1);
996 997 998 999 1000 1001 1002

  /*  Get the initial undo extents  */
  ink_tool->x1 = ink_tool->x2 = x;
  ink_tool->y1 = ink_tool->y2 = y;
}

static void
1003 1004
ink_finish (GimpInkTool  *ink_tool,
	    GimpDrawable *drawable)
1005 1006
{
  /*  push an undo  */
Michael Natterer's avatar
Michael Natterer committed
1007 1008
  gimp_drawable_apply_image (drawable, ink_tool->x1, ink_tool->y1,
			     ink_tool->x2, ink_tool->y2, undo_tiles, TRUE);
1009 1010 1011 1012 1013
  undo_tiles = NULL;

  /*  invalidate the drawable--have to do it here, because
   *  it is not done during the actual painting.
   */
1014
  gimp_viewable_invalidate_preview (GIMP_VIEWABLE (drawable));
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024