Commit 9dd0e31d authored by Jim Nelson's avatar Jim Nelson

This is all work toward #677, attempting to avoid running the pipeline when...

This is all work toward #677, attempting to avoid running the pipeline when doing edit operations.  Because the 
pipeline must be run for generating thumbnails, that run is not avoided with this check-in.  (This may be 
addressed with background threads.)  This check-in avoids the pipeline when possible with current architecture, 
and attempts to reuse an old pixbuf if the user cancels the edit tool.
parent 8f35cba8
......@@ -255,10 +255,12 @@ public abstract class PageWindow : Gtk.Window {
public void set_busy_cursor() {
window.set_cursor(new Gdk.Cursor(Gdk.CursorType.WATCH));
spin_event_loop();
}
public void set_normal_cursor() {
window.set_cursor(new Gdk.Cursor(Gdk.CursorType.ARROW));
spin_event_loop();
}
}
......
......@@ -454,7 +454,7 @@ public class TintTransformation : RGBTransformation {
matrix_entries[7] += adjusted_param;
matrix_entries[3] -= (adjusted_param / 2);
identity = false;
identity = false;
}
}
......@@ -1242,6 +1242,8 @@ public void create_auto_enhance_adjustments(Gdk.Pixbuf pixbuf,
else {
adjustments[SupportedAdjustments.TONE_EXPANSION] =
new ExpansionTransformation(analysis_histogram);
adjustments[SupportedAdjustments.SHADOWS] =
new ShadowDetailTransformation(0);
}
/* zero out any existing color transformations as these may conflict with
auto-enhancement */
......
......@@ -796,6 +796,9 @@ public class PhotoTable : DatabaseTable {
if (!keyfile.load_from_data(trans, trans.length, KeyFileFlags.NONE))
return false;
if (!keyfile.has_group(object))
return true;
keyfile.remove_group(object);
size_t length;
......
......@@ -190,6 +190,13 @@ public abstract class PhotoCanvas {
return drawable;
}
public Scaling get_scaling() {
int width, height;
drawable.get_size(out width, out height);
return Scaling.for_viewport(Dimensions(width, height));
}
public void set_drawable(Gdk.GC default_gc, Gdk.Drawable drawable) {
this.default_gc = default_gc;
this.drawable = drawable;
......@@ -310,12 +317,14 @@ public abstract class PhotoCanvas {
public abstract class EditingTool {
public PhotoCanvas canvas = null;
public static delegate EditingTool Factory();
public signal void activated();
public signal void deactivated();
public signal void applied();
public signal void applied(Gdk.Pixbuf? new_pixbuf);
public signal void cancelled();
......@@ -379,10 +388,7 @@ public abstract class EditingTool {
public virtual void paint(Gdk.GC gc, Gdk.Drawable drawable) {
}
protected void notify_apply() {
applied();
}
// Helper function that fires the cancelled signal. (Can be connected to other signals.)
protected void notify_cancel() {
cancelled();
}
......@@ -437,7 +443,11 @@ public class CropTool : EditingTool {
private int last_grab_x = -1;
private int last_grab_y = -1;
public CropTool() {
private CropTool() {
}
public static CropTool factory() {
return new CropTool();
}
public override void activate(PhotoCanvas canvas) {
......@@ -607,8 +617,8 @@ public class CropTool : EditingTool {
// store the new crop
canvas.get_photo().set_crop(crop);
// signal application
notify_apply();
// signal application; we don't have the cropped image, so the host needs to fetch it
applied(null);
}
private void update_cursor(int x, int y) {
......@@ -1037,7 +1047,7 @@ public class RedeyeTool : EditingTool {
}
private Gdk.GC thin_white_gc = null;
private Gdk.GC wider_gray_gc = null;
private Gdk.GC wider_gray_gc = null;
private RedeyeToolWindow redeye_tool_window = null;
private RedeyeInstance user_interaction_instance;
private bool is_reticle_move_in_progress = false;
......@@ -1046,6 +1056,14 @@ public class RedeyeTool : EditingTool {
private Gdk.Cursor cached_arrow_cursor;
private Gdk.Cursor cached_grab_cursor;
private Gdk.Rectangle old_scaled_pixbuf_position;
private Gdk.Pixbuf current_pixbuf = null;
private RedeyeTool() {
}
public static RedeyeTool factory() {
return new RedeyeTool();
}
private RedeyeInstance new_interaction_instance(PhotoCanvas canvas) {
Gdk.Rectangle photo_bounds = canvas.get_scaled_pixbuf_position();
......@@ -1116,8 +1134,13 @@ public class RedeyeTool : EditingTool {
RedeyeInstance.from_bounds_rect(bounds_rect_unscaled);
canvas.get_photo().add_redeye_instance(instance_unscaled);
current_pixbuf = canvas.get_photo().get_pixbuf(canvas.get_scaling());
notify_apply();
canvas.repaint();
}
private void on_close() {
applied(current_pixbuf);
}
private void on_canvas_resize() {
......@@ -1153,12 +1176,13 @@ public class RedeyeTool : EditingTool {
canvas.resized_scaled_pixbuf += on_canvas_resize;
old_scaled_pixbuf_position = canvas.get_scaled_pixbuf_position();
current_pixbuf = canvas.get_scaled_pixbuf();
redeye_tool_window = new RedeyeToolWindow(canvas.get_container());
redeye_tool_window.slider.set_value(user_interaction_instance.radius);
redeye_tool_window.slider.change_value += on_size_slider_adjust;
redeye_tool_window.apply_button.clicked += on_apply;
redeye_tool_window.close_button.clicked += notify_cancel;
redeye_tool_window.close_button.clicked += on_close;
cached_arrow_cursor = new Gdk.Cursor(Gdk.CursorType.ARROW);
cached_grab_cursor = new Gdk.Cursor(Gdk.CursorType.FLEUR);
......@@ -1180,8 +1204,7 @@ public class RedeyeTool : EditingTool {
}
public override void paint(Gdk.GC gc, Gdk.Drawable drawable) {
canvas.paint_pixbuf(canvas.get_scaled_pixbuf());
canvas.paint_pixbuf((current_pixbuf != null) ? current_pixbuf : canvas.get_scaled_pixbuf());
/* user_interaction_instance has its radius in user coords, and
draw_redeye_instance expects active region coords */
......@@ -1339,7 +1362,7 @@ public class AdjustTool : EditingTool {
pane_layouter.add(slider_organizer);
pane_layouter.add(button_layouter);
add(pane_layouter);
add(pane_layouter);
}
}
......@@ -1353,6 +1376,13 @@ public class AdjustTool : EditingTool {
private PixelTransformation[] transformations =
new PixelTransformation[SupportedAdjustments.NUM];
private float[] fp_pixel_cache = null;
private AdjustTool() {
}
public static AdjustTool factory() {
return new AdjustTool();
}
public override void activate(PhotoCanvas canvas) {
adjust_tool_window = new AdjustToolWindow(canvas.get_container());
......@@ -1449,11 +1479,8 @@ public class AdjustTool : EditingTool {
}
public override Gdk.Pixbuf? get_display_pixbuf(Scaling scaling, TransformablePhoto photo) {
return photo.get_pixbuf(scaling, TransformablePhoto.Exception.ADJUST);
}
private void on_cancel() {
notify_cancel();
return photo.has_color_adjustments()
? photo.get_pixbuf(scaling, TransformablePhoto.Exception.ADJUST) : null;
}
private void on_reset() {
......@@ -1482,9 +1509,9 @@ public class AdjustTool : EditingTool {
canvas.get_photo().set_adjustments(transformations);
notify_apply();
AppWindow.get_instance().set_normal_cursor();
applied(draw_to_pixbuf);
}
private void update_transformations(PixelTransformation[] new_transformations) {
......@@ -1552,7 +1579,7 @@ public class AdjustTool : EditingTool {
private void bind_handlers() {
adjust_tool_window.apply_button.clicked += on_apply;
adjust_tool_window.reset_button.clicked += on_reset;
adjust_tool_window.cancel_button.clicked += on_cancel;
adjust_tool_window.cancel_button.clicked += notify_cancel;
adjust_tool_window.exposure_slider.value_changed += on_exposure_adjustment;
adjust_tool_window.saturation_slider.value_changed +=
on_saturation_adjustment;
......@@ -1568,7 +1595,7 @@ public class AdjustTool : EditingTool {
private void unbind_handlers() {
adjust_tool_window.apply_button.clicked -= on_apply;
adjust_tool_window.reset_button.clicked -= on_reset;
adjust_tool_window.cancel_button.clicked -= on_cancel;
adjust_tool_window.cancel_button.clicked -= notify_cancel;
adjust_tool_window.exposure_slider.value_changed -= on_exposure_adjustment;
adjust_tool_window.saturation_slider.value_changed -=
on_saturation_adjustment;
......
......@@ -1193,7 +1193,7 @@ public abstract class SinglePhotoPage : Page {
public const Gdk.InterpType QUALITY_INTERP = Gdk.InterpType.BILINEAR;
public enum UpdateReason {
NEW_PHOTO,
NEW_PIXBUF,
QUALITY_IMPROVEMENT,
RESIZED_CANVAS
}
......@@ -1339,7 +1339,7 @@ public abstract class SinglePhotoPage : Page {
if (width <= 0 || height <= 0)
return;
bool new_photo = (scaled == null);
bool new_pixbuf = (scaled == null);
// save if reporting an image being rescaled
Dimensions old_scaled_dim = Dimensions.for_rectangle(scaled_pos);
......@@ -1359,7 +1359,7 @@ public abstract class SinglePhotoPage : Page {
repaint_interp = QUALITY_INTERP;
}
if (new_photo || new_pixmap) {
if (new_pixbuf || new_pixmap) {
// determine size of pixbuf that will fit on the canvas
Dimensions scaled_dim = Dimensions.for_pixbuf(unscaled).get_scaled_proportional(pixmap_dim);
......@@ -1381,8 +1381,8 @@ public abstract class SinglePhotoPage : Page {
scaled = resize_pixbuf(unscaled, Dimensions.for_rectangle(scaled_pos), repaint_interp);
UpdateReason reason = UpdateReason.RESIZED_CANVAS;
if (new_photo)
reason = UpdateReason.NEW_PHOTO;
if (new_pixbuf)
reason = UpdateReason.NEW_PIXBUF;
else if (interp == FAST_INTERP && repaint_interp == QUALITY_INTERP)
reason = UpdateReason.QUALITY_IMPROVEMENT;
......
......@@ -1081,7 +1081,8 @@ public abstract class TransformablePhoto: PhotoBase {
// this is to verify the generated pixbuf matches the scale requirements; crop and
// orientation are the only transformations that change the dimensions of the pixbuf, and
// must be accounted for the test to be valid
assert(scaled_to_viewport.approx_equals(Dimensions.for_pixbuf(pixbuf)));
if (is_scaled)
assert(scaled_to_viewport.approx_equals(Dimensions.for_pixbuf(pixbuf)));
#if MEASURE_PIPELINE
debug("PIPELINE %s (%s): redeye=%lf crop=%lf adjustment=%lf orientation=%lf total=%lf",
......
......@@ -36,6 +36,8 @@ public abstract class EditingHostPage : SinglePhotoPage {
private Gtk.ToolButton prev_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_GO_BACK);
private Gtk.ToolButton next_button = new Gtk.ToolButton.from_stock(Gtk.STOCK_GO_FORWARD);
private EditingTool current_tool = null;
private Gtk.ToggleToolButton current_editing_toggle = null;
private Gdk.Pixbuf cancel_editing_pixbuf = null;
private File drag_file = null;
private uint32 last_nav_key = 0;
......@@ -192,14 +194,22 @@ public abstract class EditingHostPage : SinglePhotoPage {
#if MEASURE_PIPELINE
Timer timer = new Timer();
#endif
set_pixbuf(photo.get_pixbuf(get_canvas_scaling()), false);
Gdk.Pixbuf pixbuf = null;
if (current_tool != null)
pixbuf = current_tool.get_display_pixbuf(get_canvas_scaling(), photo);
if (pixbuf == null)
pixbuf = photo.get_pixbuf(get_canvas_scaling());
set_pixbuf(pixbuf, false);
#if MEASURE_PIPELINE
debug("UPDATE_PIXBUF: total=%lf", timer.elapsed());
#endif
// fetch the original for quick comparisons, again in the background ... need to let the
// message loop run to get the real pixbuf on-screen. If no transformations, don't bother.
if (original == null && photo.has_transformations())
// TODO: Allow viewing the original while a tool is activated.
if (original == null && photo.has_transformations() && current_tool == null)
Idle.add(fetch_original);
return false;
......@@ -258,6 +268,9 @@ public abstract class EditingHostPage : SinglePhotoPage {
// tools may be allowed to be executing at the same time.
deactivate_tool();
// save current pixbuf to use if user cancels operation
cancel_editing_pixbuf = get_unscaled_pixbuf();
// see if the tool wants a different pixbuf displayed
Gdk.Pixbuf unscaled = tool.get_display_pixbuf(get_canvas_scaling(), photo);
if (unscaled != null)
......@@ -280,7 +293,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
default_repaint();
}
private void deactivate_tool() {
private void deactivate_tool(Gdk.Pixbuf? new_pixbuf = null) {
if (current_tool == null)
return;
......@@ -289,12 +302,26 @@ public abstract class EditingHostPage : SinglePhotoPage {
// deactivate with the tool taken out of the hooks
tool.deactivate();
tool = null;
// only null the toggle when the tool is completely deactivated; that is, deactive the tool
// before updating the UI
current_editing_toggle = null;
// display the (possibly) new photo
Gdk.Pixbuf replacement = null;
if (new_pixbuf != null)
replacement = new_pixbuf;
else if (cancel_editing_pixbuf != null)
replacement = cancel_editing_pixbuf;
else
replacement = photo.get_pixbuf(get_canvas_scaling());
set_pixbuf(replacement);
cancel_editing_pixbuf = null;
// return to fast interpolation for viewing
set_default_interp(FAST_INTERP);
// display the (possibly) new photo
quick_update_pixbuf();
}
private override void drag_begin(Gdk.DragContext context) {
......@@ -396,8 +423,6 @@ public abstract class EditingHostPage : SinglePhotoPage {
// signal that the photo has been altered
queryable_altered(photo);
quick_update_pixbuf();
update_ui();
}
......@@ -412,15 +437,25 @@ public abstract class EditingHostPage : SinglePhotoPage {
return false;
}
private override bool on_configure(Gdk.EventConfigure event, Gdk.Rectangle rect) {
private void track_tool_window() {
// if editing tool window is present and the user hasn't touched it, it moves with the window
if (current_tool != null) {
EditingToolWindow tool_window = current_tool.get_tool_window();
if (tool_window != null && !tool_window.has_user_moved())
place_tool_window();
}
}
private override void on_move(Gdk.Rectangle rect) {
track_tool_window();
return (base.on_configure != null) ? base.on_configure(event, rect) : false;
base.on_move(rect);
}
private override void on_resize(Gdk.Rectangle rect) {
track_tool_window();
base.on_resize(rect);
}
private override bool key_press_event(Gdk.EventKey event) {
......@@ -475,9 +510,12 @@ public abstract class EditingHostPage : SinglePhotoPage {
protected override void updated_pixbuf(Gdk.Pixbuf pixbuf, SinglePhotoPage.UpdateReason reason,
Dimensions old_dim) {
// only purpose here is to inform editing tool of change
if (current_tool != null)
// only purpose here is to inform editing tool of change and drop the cancelled
// pixbuf, which is now sized incorrectly
if (current_tool != null && reason != SinglePhotoPage.UpdateReason.QUALITY_IMPROVEMENT) {
current_tool.canvas.resized_pixbuf(old_dim, pixbuf, get_scaled_pixbuf_position());
cancel_editing_pixbuf = null;
}
}
protected override void paint(Gdk.GC gc, Gdk.Drawable drawable) {
......@@ -490,8 +528,8 @@ public abstract class EditingHostPage : SinglePhotoPage {
private void rotate(Rotation rotation) {
deactivate_tool();
// let the signal generate a repaint
photo.rotate(rotation);
quick_update_pixbuf();
}
public void on_rotate_clockwise() {
......@@ -510,6 +548,7 @@ public abstract class EditingHostPage : SinglePhotoPage {
deactivate_tool();
photo.remove_all_transformations();
quick_update_pixbuf();
queryable_altered(photo);
}
......@@ -534,92 +573,61 @@ public abstract class EditingHostPage : SinglePhotoPage {
return false;
}
private void on_crop_toggled() {
if (crop_button.active) {
// create the tool, hook its signals, and activate it
CropTool crop_tool = new CropTool();
crop_tool.activated += on_crop_activated;
crop_tool.deactivated += on_crop_deactivated;
crop_tool.applied += on_crop_done;
crop_tool.cancelled += on_crop_done;
activate_tool(crop_tool);
} else {
deactivate_tool();
}
}
private void on_redeye_toggled() {
if (redeye_button.active) {
RedeyeTool redeye_tool = new RedeyeTool();
redeye_tool.activated += on_redeye_activated;
redeye_tool.deactivated += on_redeye_deactivated;
redeye_tool.applied += on_redeye_applied;
redeye_tool.cancelled += on_redeye_closed;
activate_tool(redeye_tool);
} else {
deactivate_tool();
}
private void on_tool_button_toggled(Gtk.ToggleToolButton toggle, EditingTool.Factory factory) {
// if the button is an activate, deactivate any current tool running; if the button is
// a deactivate, deactivate the current tool and exit
bool deactivating_only = (!toggle.active && current_editing_toggle == toggle);
deactivate_tool();
if (deactivating_only)
return;
current_editing_toggle = toggle;
// create the tool, hook its signals, and activate
EditingTool tool = factory();
tool.activated += on_tool_activated;
tool.deactivated += on_tool_deactivated;
tool.applied += on_tool_applied;
tool.cancelled += on_tool_cancelled;
activate_tool(tool);
}
private void on_adjust_toggled() {
if (adjust_button.active) {
AdjustTool adjust_tool = new AdjustTool();
adjust_tool.activated += on_adjust_activated;
adjust_tool.deactivated += on_adjust_deactivated;
adjust_tool.cancelled += on_adjust_closed;
adjust_tool.applied += on_adjust_applied;
activate_tool(adjust_tool);
} else {
deactivate_tool();
}
private void on_tool_activated() {
assert(current_editing_toggle != null);
current_editing_toggle.active = true;
}
private void on_crop_done() {
deactivate_tool();
}
private void on_redeye_applied() {
}
private void on_redeye_closed() {
deactivate_tool();
private void on_tool_deactivated() {
assert(current_editing_toggle != null);
current_editing_toggle.active = false;
}
private void on_adjust_closed() {
deactivate_tool();
private void on_tool_applied(Gdk.Pixbuf? new_pixbuf) {
// if the tool didn't supply a pixbuf, it's relying on the host to generate it from Photo
Gdk.Pixbuf final_pixbuf = (new_pixbuf != null) ? new_pixbuf
: photo.get_pixbuf(get_canvas_scaling());
deactivate_tool(final_pixbuf);
}
private void on_adjust_applied() {
private void on_tool_cancelled() {
deactivate_tool();
}
private void on_crop_activated() {
crop_button.set_active(true);
}
private void on_redeye_activated() {
redeye_button.set_active(true);
}
private void on_crop_deactivated() {
crop_button.set_active(false);
}
private void on_redeye_deactivated() {
redeye_button.set_active(false);
private void on_crop_toggled() {
on_tool_button_toggled(crop_button, CropTool.factory);
}
private void on_adjust_activated() {
adjust_button.set_active(true);
private void on_redeye_toggled() {
on_tool_button_toggled(redeye_button, RedeyeTool.factory);
}
private void on_adjust_deactivated() {
adjust_button.set_active(false);
private void on_adjust_toggled() {
on_tool_button_toggled(adjust_button, AdjustTool.factory);
}
private void on_enhance_clicked() {
// because running multiple tools at once is not currently supported, deactivate any current
// tool; however, there is a special case of running enhancement while the AdjustTool is
......@@ -654,6 +662,8 @@ public abstract class EditingHostPage : SinglePhotoPage {
}
AppWindow.get_instance().set_normal_cursor();
quick_update_pixbuf();
}
private void place_tool_window() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment