Hi, all To address bug #2184: [gimp-bug] Clone tool samples "sample from" cursor, creating artifacts, I'd like to change the cursor behavior in (what I think) is an unobtrusive way. When the sampling cursor and destination cursor are within one brush width of one another, I'd like to supress the generation of the sample cursor. Currently the sampling cursor is displayed at all times between button presses and releases, even when the two cursors are in close proximity to one another. #2184 reports that when this is the case, artifacts are generated. 1. The artifacts arise from the original design of the sampling cursor. It is not a hardware cursor, but generated through gdk_draw_lines() writing directly to the window. These lines simply invert the hardware colormap, so that subsequently overwriting these lines is the same as not writing them at all. 2. The original design depended on maintaining a correct phase among (a) overwriting the sampling cursor to make it "disappear" (b) writing clone pixels, then (c) writing the sampling cursor in its new location, making it "reappear" (a), (b), and (c) would then repeat on each mouse motion event. 3. Extensive modifiations and improvements to gdisplay_flush() and related functions have effectively changed this sequence to (a)(c)(b), the actual writing of clone pixels are buffered and their writing to screen are deferred. This does not give rise to artifacts when clone pixels writes are quite far from the sample points. The erasing (a) and rewriting (c) strokes flash the sampling cursor off, then on, in a pointless but unobtrusive way. But when clone pixels write very near to the sample point, (b) partially overwrites the image created by (c), a partial "untoggling" of inverted pixels occurs. The next, so-called "erasing" step (a) properly reverts uncloned pixels, but improperly inverts cloned pixels. This leaves a partially written sampling cursor behind, an artifact. 4. Since artifact generation occurs when the sampling and "real" cursor almost coincide, It seems to me that simply supressing the generating of the sampling cursor is a more effective means of dealing with bug #2184 than attempting to restore a delicate phase relationship through gdisplay buffering code. This alteration does change user interface semantics, so I wanted to query the group before committing the change. The attached patch is a not-fully-tested implementation that illustrates the approach. It is intended to be applied to gimp/app/clone.c, CVS version 1.34 [1999, Nov 17 04:37] Awaiting opinions, or suggestions to alternate approaches. Be good, be well Garry Osgood --- gimp/app/clone.c Wed Nov 17 04:37:39 1999 +++ gimp/app/clone.c-patch Fri Dec 17 20:37:08 1999 @@ -287,7 +287,6 @@ { offset_x = src_x - dest_x; offset_y = src_y - dest_y; - first = FALSE; } src_x = dest_x + offset_x; @@ -299,6 +298,8 @@ } draw_core_pause (paint_core->core, active_tool); + if (!(paint_core->state & GDK_CONTROL_MASK) && first == TRUE) + first = FALSE; break; case INIT_PAINT : @@ -324,10 +325,15 @@ case FINISH_PAINT : draw_core_stop (paint_core->core, active_tool); if (clone_options->aligned == AlignNo && !first) - { - src_x = orig_src_x; - src_y = orig_src_y; - } + { + src_x = orig_src_x; + src_y = orig_src_y; + } + if (clone_options->aligned == AlignNo) + { + offset_x = 0; + offset_y = 0; + } return NULL; break; @@ -437,6 +443,27 @@ paint_core_free (tool); } +gboolean +clone_proximity_check(PaintCore *paint_core) +{ + /* Render clone tool source-of-copy cursor */ + /* unless its position is within the greater */ + /* of x or y brush mask extent. */ + /* Address bug 2184 <gosgood@xxxxxxx> */ + + if(first) return TRUE; + else + { + int dx2 = offset_x*offset_x; + int dy2 = offset_y*offset_y; + int pr = ((paint_core->brush->mask->width > paint_core->brush->mask->height)? + paint_core->brush->mask->width : paint_core->brush->mask->height) + 2; + + pr *= pr; + return (dx2 + dy2) > pr; + } +} + static void clone_draw (Tool *tool) { @@ -446,12 +473,15 @@ if (paint_core->core->gc != NULL && clone_options->type == IMAGE_CLONE) { - gdk_draw_line (paint_core->core->win, paint_core->core->gc, - trans_tx - (TARGET_WIDTH >> 1), trans_ty, - trans_tx + (TARGET_WIDTH >> 1), trans_ty); - gdk_draw_line (paint_core->core->win, paint_core->core->gc, - trans_tx, trans_ty - (TARGET_HEIGHT >> 1), - trans_tx, trans_ty + (TARGET_HEIGHT >> 1)); + if (clone_proximity_check(paint_core)) + { + gdk_draw_line (paint_core->core->win, paint_core->core->gc, + trans_tx - (TARGET_WIDTH >> 1), trans_ty, + trans_tx + (TARGET_WIDTH >> 1), trans_ty); + gdk_draw_line (paint_core->core->win, paint_core->core->gc, + trans_tx, trans_ty - (TARGET_HEIGHT >> 1), + trans_tx, trans_ty + (TARGET_HEIGHT >> 1)); + } } }