eraser.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. /* The GIMP -- an image manipulation program
  2. * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include "config.h"
  19. #include <gtk/gtk.h>
  20. #include <gdk/gdkkeysyms.h>
  21. #include "apptypes.h"
  22. #include "appenv.h"
  23. #include "cursorutil.h"
  24. #include "drawable.h"
  25. #include "gdisplay.h"
  26. #include "gimage_mask.h"
  27. #include "gimpui.h"
  28. #include "paint_funcs.h"
  29. #include "paint_core.h"
  30. #include "paint_options.h"
  31. #include "eraser.h"
  32. #include "selection.h"
  33. #include "tools.h"
  34. #include "libgimp/gimpintl.h"
  35. /* Defaults */
  36. #define ERASER_DEFAULT_HARD FALSE
  37. #define ERASER_DEFAULT_INCREMENTAL FALSE
  38. #define ERASER_DEFAULT_ANTI_ERASE FALSE
  39. /* the eraser structures */
  40. typedef struct _EraserOptions EraserOptions;
  41. struct _EraserOptions
  42. {
  43. PaintOptions paint_options;
  44. gboolean hard;
  45. gboolean hard_d;
  46. GtkWidget *hard_w;
  47. gboolean anti_erase;
  48. gboolean anti_erase_d;
  49. GtkWidget *anti_erase_w;
  50. };
  51. /* the eraser tool options */
  52. static EraserOptions *eraser_options = NULL;
  53. /* local variables */
  54. static gboolean non_gui_hard;
  55. static gboolean non_gui_incremental;
  56. static gboolean non_gui_anti_erase;
  57. /* forward function declarations */
  58. static void eraser_motion (PaintCore *, GimpDrawable *,
  59. PaintPressureOptions *,
  60. gboolean, gboolean, gboolean);
  61. /* functions */
  62. static void
  63. eraser_options_reset (void)
  64. {
  65. EraserOptions *options = eraser_options;
  66. paint_options_reset ((PaintOptions *) options);
  67. gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->hard_w),
  68. options->hard_d);
  69. gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->anti_erase_w),
  70. options->anti_erase_d);
  71. }
  72. static EraserOptions *
  73. eraser_options_new (void)
  74. {
  75. EraserOptions *options;
  76. GtkWidget *vbox;
  77. /* the new eraser tool options structure */
  78. options = g_new (EraserOptions, 1);
  79. paint_options_init ((PaintOptions *) options,
  80. ERASER,
  81. eraser_options_reset);
  82. options->hard = options->hard_d = ERASER_DEFAULT_HARD;
  83. options->anti_erase = options->anti_erase_d = ERASER_DEFAULT_ANTI_ERASE;
  84. /* the main vbox */
  85. vbox = ((ToolOptions *) options)->main_vbox;
  86. /* the hard toggle */
  87. options->hard_w = gtk_check_button_new_with_label (_("Hard Edge"));
  88. gtk_box_pack_start (GTK_BOX (vbox), options->hard_w, FALSE, FALSE, 0);
  89. gtk_signal_connect (GTK_OBJECT (options->hard_w), "toggled",
  90. GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  91. &options->hard);
  92. gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->hard_w),
  93. options->hard_d);
  94. gtk_widget_show (options->hard_w);
  95. /* the anti_erase toggle */
  96. options->anti_erase_w = gtk_check_button_new_with_label (_("Anti Erase"));
  97. gtk_box_pack_start (GTK_BOX (vbox), options->anti_erase_w, FALSE, FALSE, 0);
  98. gtk_signal_connect (GTK_OBJECT (options->anti_erase_w), "toggled",
  99. GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  100. &options->anti_erase);
  101. gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (options->anti_erase_w),
  102. options->anti_erase_d);
  103. gtk_widget_show (options->anti_erase_w);
  104. return options;
  105. }
  106. static void
  107. eraser_modifier_key_func (Tool *tool,
  108. GdkEventKey *kevent,
  109. gpointer gdisp_ptr)
  110. {
  111. switch (kevent->keyval)
  112. {
  113. case GDK_Alt_L:
  114. case GDK_Alt_R:
  115. break;
  116. case GDK_Shift_L:
  117. case GDK_Shift_R:
  118. if (kevent->state & GDK_CONTROL_MASK) /* reset tool toggle */
  119. gtk_toggle_button_set_active
  120. (GTK_TOGGLE_BUTTON (eraser_options->anti_erase_w),
  121. ! eraser_options->anti_erase);
  122. break;
  123. case GDK_Control_L:
  124. case GDK_Control_R:
  125. if (!(kevent->state & GDK_SHIFT_MASK)) /* shift enables line draw mode */
  126. gtk_toggle_button_set_active
  127. (GTK_TOGGLE_BUTTON (eraser_options->anti_erase_w),
  128. ! eraser_options->anti_erase);
  129. break;
  130. }
  131. tool->toggled = eraser_options->anti_erase;
  132. }
  133. void *
  134. eraser_paint_func (PaintCore *paint_core,
  135. GimpDrawable *drawable,
  136. int state)
  137. {
  138. switch (state)
  139. {
  140. case INIT_PAINT:
  141. break;
  142. case MOTION_PAINT:
  143. eraser_motion (paint_core,
  144. drawable,
  145. eraser_options->paint_options.pressure_options,
  146. eraser_options->hard,
  147. eraser_options->paint_options.incremental,
  148. eraser_options->anti_erase);
  149. break;
  150. case FINISH_PAINT:
  151. break;
  152. default:
  153. break;
  154. }
  155. return NULL;
  156. }
  157. Tool *
  158. tools_new_eraser (void)
  159. {
  160. Tool * tool;
  161. PaintCore * private;
  162. /* The tool options */
  163. if (! eraser_options)
  164. {
  165. eraser_options = eraser_options_new ();
  166. tools_register (ERASER, (ToolOptions *) eraser_options);
  167. }
  168. tool = paint_core_new (ERASER);
  169. private = (PaintCore *) tool->private;
  170. private->paint_func = eraser_paint_func;
  171. private->flags |= TOOL_CAN_HANDLE_CHANGING_BRUSH;
  172. tool->modifier_key_func = eraser_modifier_key_func;
  173. return tool;
  174. }
  175. void
  176. tools_free_eraser (Tool *tool)
  177. {
  178. paint_core_free (tool);
  179. }
  180. static void
  181. eraser_motion (PaintCore *paint_core,
  182. GimpDrawable *drawable,
  183. PaintPressureOptions *pressure_options,
  184. gboolean hard,
  185. gboolean incremental,
  186. gboolean anti_erase)
  187. {
  188. GImage *gimage;
  189. gint opacity;
  190. TempBuf * area;
  191. unsigned char col[MAX_CHANNELS];
  192. gdouble scale;
  193. if (! (gimage = drawable_gimage (drawable)))
  194. return;
  195. gimage_get_background (gimage, drawable, col);
  196. if (pressure_options->size)
  197. scale = paint_core->curpressure;
  198. else
  199. scale = 1.0;
  200. /* Get a region which can be used to paint to */
  201. if (! (area = paint_core_get_paint_area (paint_core, drawable, scale)))
  202. return;
  203. /* set the alpha channel */
  204. col[area->bytes - 1] = OPAQUE_OPACITY;
  205. /* color the pixels */
  206. color_pixels (temp_buf_data (area), col,
  207. area->width * area->height, area->bytes);
  208. opacity = 255 * gimp_context_get_opacity (NULL);
  209. if (pressure_options->opacity)
  210. opacity = opacity * 2.0 * paint_core->curpressure;
  211. /* paste the newly painted canvas to the gimage which is being worked on */
  212. paint_core_paste_canvas (paint_core, drawable,
  213. MIN (opacity, 255),
  214. (int) (gimp_context_get_opacity (NULL) * 255),
  215. anti_erase ? ANTI_ERASE_MODE : ERASE_MODE,
  216. hard ? HARD : (pressure_options->pressure ? PRESSURE : SOFT),
  217. scale,
  218. incremental ? INCREMENTAL : CONSTANT);
  219. }
  220. static void *
  221. eraser_non_gui_paint_func (PaintCore *paint_core,
  222. GimpDrawable *drawable,
  223. int state)
  224. {
  225. eraser_motion (paint_core, drawable,
  226. &non_gui_pressure_options,
  227. non_gui_hard, non_gui_incremental, non_gui_anti_erase);
  228. return NULL;
  229. }
  230. gboolean
  231. eraser_non_gui_default (GimpDrawable *drawable,
  232. int num_strokes,
  233. double *stroke_array)
  234. {
  235. gboolean hardness = ERASER_DEFAULT_HARD;
  236. gboolean method = ERASER_DEFAULT_INCREMENTAL;
  237. gboolean anti_erase = ERASER_DEFAULT_ANTI_ERASE;
  238. EraserOptions *options = eraser_options;
  239. if (options)
  240. {
  241. hardness = options->hard;
  242. method = options->paint_options.incremental;
  243. anti_erase = options->anti_erase;
  244. }
  245. return eraser_non_gui (drawable, num_strokes, stroke_array,
  246. hardness, method, anti_erase);
  247. }
  248. gboolean
  249. eraser_non_gui (GimpDrawable *drawable,
  250. int num_strokes,
  251. double *stroke_array,
  252. int hardness,
  253. int method,
  254. int anti_erase)
  255. {
  256. int i;
  257. if (paint_core_init (&non_gui_paint_core, drawable,
  258. stroke_array[0], stroke_array[1]))
  259. {
  260. non_gui_hard = hardness;
  261. non_gui_incremental = method;
  262. non_gui_anti_erase = anti_erase;
  263. /* Set the paint core's paint func */
  264. non_gui_paint_core.paint_func = eraser_non_gui_paint_func;
  265. non_gui_paint_core.startx = non_gui_paint_core.lastx = stroke_array[0];
  266. non_gui_paint_core.starty = non_gui_paint_core.lasty = stroke_array[1];
  267. eraser_non_gui_paint_func (&non_gui_paint_core, drawable, 0);
  268. for (i = 1; i < num_strokes; i++)
  269. {
  270. non_gui_paint_core.curx = stroke_array[i * 2 + 0];
  271. non_gui_paint_core.cury = stroke_array[i * 2 + 1];
  272. paint_core_interpolate (&non_gui_paint_core, drawable);
  273. non_gui_paint_core.lastx = non_gui_paint_core.curx;
  274. non_gui_paint_core.lasty = non_gui_paint_core.cury;
  275. }
  276. /* Finish the painting */
  277. paint_core_finish (&non_gui_paint_core, drawable, -1);
  278. /* Cleanup */
  279. paint_core_cleanup ();
  280. return TRUE;
  281. }
  282. else
  283. return FALSE;
  284. }