Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions src/Gestures/GesturePropertyTransition.vala
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,28 @@ public class Gala.GesturePropertyTransition : Object {
public Value to_value { get; construct set; }

/**
* If not null this can be used to have an intermediate step before animating back to the origin.
* Therefore using this makes mostly sense if {@link to_value} equals {@link from_value}.
* This is mostly used for the nudge animations when trying to switch workspaces where there isn't one anymore.
* The lower max overshoot. The gesture percentage by which #this animates the property is bounded
* by this property on the lower end. If it is in the form X.YY with Y not 0 the animation will be linear
* until X and then take another 100% to animate until X.YY (instead of YY%).
* Default is 0.
*/
public Value? intermediate_value { get; construct; }
public double overshoot_lower_clamp { get; set; default = 0; }
/**
* Same as {@link overshoot_lower_clamp} but for the upper limit.
* If this is less than 1 and the transition is started without a gesture it will animate to
* the {@link to_value} by this percent and then back to the {@link from_value}.
* Default is 1.
*/
public double overshoot_upper_clamp { get; set; default = 1; }

/**
* This is the from value that's actually used when calculating the animation movement.
* If {@link from_value} isn't null this will be the same, otherwise it will be set to the current
* value of the target property, when calling {@link start}.
*/
private Value actual_from_value;
private float from_value_float; // Only valid in the time between start () and finish ()
private float to_value_float; // Only valid in the time between start () and finish ()

private DoneCallback? done_callback;

Expand All @@ -57,16 +67,14 @@ public class Gala.GesturePropertyTransition : Object {
GestureTracker gesture_tracker,
string property,
Value? from_value,
Value to_value,
Value? intermediate_value = null
Value to_value
) {
Object (
actor: actor,
gesture_tracker: gesture_tracker,
property: property,
from_value: from_value,
to_value: to_value,
intermediate_value: intermediate_value
to_value: to_value
);
}

Expand Down Expand Up @@ -100,20 +108,44 @@ public class Gala.GesturePropertyTransition : Object {
return;
}

// Pre calculate some things, so we don't have to do it on every update
from_value_float = value_to_float (actual_from_value);
to_value_float = value_to_float (to_value);

GestureTracker.OnBegin on_animation_begin = () => {
actor.set_property (property, actual_from_value);
};

GestureTracker.OnUpdate on_animation_update = (percentage) => {
var animation_value = GestureTracker.animation_value (value_to_float (actual_from_value), value_to_float (intermediate_value ?? to_value), percentage);
var lower_clamp_int = (int) overshoot_lower_clamp;
var upper_clamp_int = (int) overshoot_upper_clamp;

double stretched_percentage = 0;
if (percentage < lower_clamp_int) {
stretched_percentage = (percentage - lower_clamp_int) * - (overshoot_lower_clamp - lower_clamp_int);
} else if (percentage > upper_clamp_int) {
stretched_percentage = (percentage - upper_clamp_int) * (overshoot_upper_clamp - upper_clamp_int);
}

percentage = percentage.clamp (lower_clamp_int, upper_clamp_int);

var animation_value = GestureTracker.animation_value (from_value_float, to_value_float, percentage, false);

if (stretched_percentage != 0) {
animation_value += (float) stretched_percentage * (to_value_float - from_value_float);
}

actor.set_property (property, value_from_float (animation_value));
};

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action, calculated_duration) => {
GestureTracker.OnEnd on_animation_end = (percentage, completions, calculated_duration) => {
completions = completions.clamp ((int) overshoot_lower_clamp, (int) overshoot_upper_clamp);
var target_value = from_value_float + completions * (to_value_float - from_value_float);

actor.save_easing_state ();
actor.set_easing_mode (EASE_OUT_QUAD);
actor.set_easing_duration (AnimationsSettings.get_animation_duration (calculated_duration));
actor.set_property (property, cancel_action ? actual_from_value : to_value);
actor.set_property (property, value_from_float (target_value));
actor.restore_easing_state ();

unowned var transition = actor.get_transition (property);
Expand All @@ -128,21 +160,21 @@ public class Gala.GesturePropertyTransition : Object {
gesture_tracker.connect_handlers (on_animation_begin, on_animation_update, on_animation_end);
} else {
on_animation_begin (0);
if (intermediate_value != null) {
if (overshoot_upper_clamp < 1) {
actor.save_easing_state ();
actor.set_easing_mode (EASE_OUT_QUAD);
actor.set_easing_duration (AnimationsSettings.get_animation_duration (gesture_tracker.min_animation_duration));
actor.set_property (property, intermediate_value);
actor.set_property (property, value_from_float ((float) overshoot_upper_clamp * (to_value_float - from_value_float) + from_value_float));
actor.restore_easing_state ();

unowned var transition = actor.get_transition (property);
if (transition == null) {
on_animation_end (1, false, gesture_tracker.min_animation_duration);
on_animation_end (1, 1, gesture_tracker.min_animation_duration);
} else {
transition.stopped.connect (() => on_animation_end (1, false, gesture_tracker.min_animation_duration));
transition.stopped.connect (() => on_animation_end (1, 1, gesture_tracker.min_animation_duration));
}
} else {
on_animation_end (1, false, gesture_tracker.min_animation_duration);
on_animation_end (1, 1, gesture_tracker.min_animation_duration);
}
}
}
Expand Down
23 changes: 16 additions & 7 deletions src/Gestures/GestureTracker.vala
Original file line number Diff line number Diff line change
Expand Up @@ -88,12 +88,16 @@ public class Gala.GestureTracker : Object {

/**
* @param percentage Value between 0 and 1.
* @param completions How often a full cycle of the gesture was completed in this go. Can be
* negative if the gesture was started in one direction but ended in the other. This is used to update
* the UI to the according state. 0 for example means that the UI should go back to the same state
* it was in before the gesture started.
*/
public signal void on_end (double percentage, bool cancel_action, int calculated_duration);
public signal void on_end (double percentage, int completions, int calculated_duration);

public delegate void OnBegin (double percentage);
public delegate void OnUpdate (double percentage);
public delegate void OnEnd (double percentage, bool cancel_action, int calculated_duration);
public delegate void OnEnd (double percentage, int completions, int calculated_duration);

/**
* Backend used if enable_touchpad is called.
Expand Down Expand Up @@ -239,12 +243,17 @@ public class Gala.GestureTracker : Object {

private void gesture_end (double percentage, uint64 elapsed_time) {
double end_percentage = applied_percentage (percentage, percentage_delta);
bool cancel_action = (end_percentage < SUCCESS_PERCENTAGE_THRESHOLD)
&& ((end_percentage <= previous_percentage) && (velocity < SUCCESS_VELOCITY_THRESHOLD));
int completions = (int) end_percentage;
bool cancel_action = (end_percentage.abs () < SUCCESS_PERCENTAGE_THRESHOLD)
&& ((end_percentage.abs () <= previous_percentage.abs ()) && (velocity < SUCCESS_VELOCITY_THRESHOLD));
int calculated_duration = calculate_end_animation_duration (end_percentage, cancel_action);

if (!cancel_action) {
completions += end_percentage < 0 ? -1 : 1;
}

if (enabled) {
on_end (end_percentage, cancel_action, calculated_duration);
on_end (end_percentage, completions, calculated_duration);
}

disconnect_all_handlers ();
Expand All @@ -254,8 +263,8 @@ public class Gala.GestureTracker : Object {
velocity = 0;
}

private static double applied_percentage (double percentage, double percentage_delta) {
return (percentage - percentage_delta).clamp (0, 1);
private static inline double applied_percentage (double percentage, double percentage_delta) {
return percentage - percentage_delta;
}

/**
Expand Down
5 changes: 1 addition & 4 deletions src/Gestures/ScrollBackend.vala
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,7 @@ public class Gala.ScrollBackend : Object {
double finish_delta = is_horizontal ? FINISH_DELTA_HORIZONTAL : FINISH_DELTA_VERTICAL;

bool is_positive = (direction == GestureDirection.RIGHT || direction == GestureDirection.DOWN);
double clamp_low = is_positive ? 0 : -1;
double clamp_high = is_positive ? 1 : 0;

double normalized_delta = (used_delta / finish_delta).clamp (clamp_low, clamp_high).abs ();
return normalized_delta;
return (used_delta / finish_delta) * (is_positive ? 1 : -1);
}
}
64 changes: 21 additions & 43 deletions src/Widgets/MultitaskingView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -340,11 +340,6 @@ namespace Gala {
float initial_x = workspaces.x;
float target_x = 0;
bool is_nudge_animation = !target_workspace_exists;
var scale = display.get_monitor_scale (display.get_primary_monitor ());
var nudge_gap = InternalUtils.scale_to_int (WindowManagerGala.NUDGE_GAP, scale);

unowned IconGroup active_icon_group = null;
unowned IconGroup? target_icon_group = null;

if (is_nudge_animation) {
var workspaces_geometry = InternalUtils.get_workspaces_geometry (display);
Expand All @@ -355,21 +350,11 @@ namespace Gala {
var workspace = workspace_clone.workspace;

if (workspace == target_workspace) {
target_icon_group = workspace_clone.icon_group;
target_x = -workspace_clone.multitasking_view_x ();
} else if (workspace == active_workspace) {
active_icon_group = workspace_clone.icon_group;
}
}
}

if (!is_nudge_animation && active_icon_group.get_transition ("backdrop-opacity") != null) {
active_icon_group.remove_transition ("backdrop-opacity");
}
if (!is_nudge_animation && target_icon_group.get_transition ("backdrop-opacity") != null) {
target_icon_group.remove_transition ("backdrop-opacity");
}

debug ("Starting MultitaskingView switch workspace animation:");
debug ("Active workspace index: %d", active_workspace.index ());
debug ("Target workspace index: %d", target_workspace_index);
Expand All @@ -379,28 +364,24 @@ namespace Gala {
debug ("Target X: %f", target_x);

switching_workspace_with_gesture = true;
if (target_workspace != null) {
target_workspace.activate (display.get_current_time ());
}

if (is_nudge_animation) {
new GesturePropertyTransition (workspaces, workspace_gesture_tracker, "x", null, initial_x, initial_x + nudge_gap * -relative_dir).start (true);
} else {
new GesturePropertyTransition (workspaces, workspace_gesture_tracker, "x", null, target_x).start (true);
new GesturePropertyTransition (active_icon_group, workspace_gesture_tracker, "backdrop-opacity", 1f, 0f).start (true);
new GesturePropertyTransition (target_icon_group, workspace_gesture_tracker, "backdrop-opacity", 0f, 1f).start (true);
}
var upper_clamp = (direction == LEFT) ? (active_workspace.index () + 0.1) : (num_workspaces - active_workspace.index () - 0.9);
var lower_clamp = (direction == RIGHT) ? - (active_workspace.index () + 0.1) : - (num_workspaces - active_workspace.index () - 0.9);

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action, calculated_duration) => {
new GesturePropertyTransition (workspaces, workspace_gesture_tracker, "x", null, target_x) {
overshoot_lower_clamp = lower_clamp,
overshoot_upper_clamp = upper_clamp
}.start (true);

GestureTracker.OnEnd on_animation_end = (percentage, completions, calculated_duration) => {
switching_workspace_with_gesture = false;

if (is_nudge_animation || cancel_action) {
active_workspace.activate (display.get_current_time ());
}
completions = completions.clamp ((int) lower_clamp, (int) upper_clamp);
manager.get_workspace_by_index (active_workspace.index () + completions * relative_dir).activate (display.get_current_time ());
};

if (!AnimationsSettings.get_enable_animations ()) {
on_animation_end (1, false, 0);
on_animation_end (1, 1, 0);
} else {
workspace_gesture_tracker.connect_handlers (null, null, (owned) on_animation_end);
}
Expand Down Expand Up @@ -429,9 +410,6 @@ namespace Gala {

if (workspace == active_workspace) {
active_x = dest_x;
workspace_clone.icon_group.backdrop_opacity = 1.0f;
} else {
workspace_clone.icon_group.backdrop_opacity = 0.0f;
}

workspace_clone.save_easing_state ();
Expand Down Expand Up @@ -706,8 +684,8 @@ namespace Gala {
hide_docks (with_gesture, is_cancel_animation);
}

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
var animation_duration = cancel_action ? 0 : ANIMATION_DURATION;
GestureTracker.OnEnd on_animation_end = (percentage, completions) => {
var animation_duration = completions == 0 ? 0 : ANIMATION_DURATION;
Timeout.add (animation_duration, () => {
if (!opening) {
foreach (var container in window_containers_monitors) {
Expand All @@ -727,7 +705,7 @@ namespace Gala {

animating = false;

if (cancel_action) {
if (completions == 0) {
toggle (false, true);
}

Expand All @@ -736,7 +714,7 @@ namespace Gala {
};

if (!with_gesture) {
on_animation_end (1, false, 0);
on_animation_end (1, 1, 0);
} else {
multitasking_gesture_tracker.connect_handlers (null, null, (owned) on_animation_end);
}
Expand Down Expand Up @@ -792,8 +770,8 @@ namespace Gala {
clone.y = y;
};

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
if (cancel_action) {
GestureTracker.OnEnd on_animation_end = (percentage, completions) => {
if (completions == 0) {
return;
}

Expand All @@ -805,7 +783,7 @@ namespace Gala {
};

if (!with_gesture || !AnimationsSettings.get_enable_animations ()) {
on_animation_end (1, false, 0);
on_animation_end (1, 1, 0);
} else {
multitasking_gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end);
}
Expand All @@ -823,8 +801,8 @@ namespace Gala {
dock.y = y;
};

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
if (cancel_action) {
GestureTracker.OnEnd on_animation_end = (percentage, completions) => {
if (completions == 0) {
return;
}

Expand All @@ -836,7 +814,7 @@ namespace Gala {
};

if (!with_gesture || !AnimationsSettings.get_enable_animations ()) {
on_animation_end (1, false, 0);
on_animation_end (1, 1, 0);
} else {
multitasking_gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end);
}
Expand Down
12 changes: 6 additions & 6 deletions src/Widgets/WindowClone.vala
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ public class Gala.WindowClone : Clutter.Actor {
set_window_icon_position (width, height, scale, false);
};

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
if (cancel_action) {
GestureTracker.OnEnd on_animation_end = (percentage, completions) => {
if (completions == 0) {
return;
}

Expand All @@ -309,7 +309,7 @@ public class Gala.WindowClone : Clutter.Actor {
};

if (gesture_tracker == null || !with_gesture || !AnimationsSettings.get_enable_animations ()) {
on_animation_end (1, false, 0);
on_animation_end (1, 1, 0);
} else {
gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end);
}
Expand Down Expand Up @@ -356,8 +356,8 @@ public class Gala.WindowClone : Clutter.Actor {
set_window_icon_position (width, height, scale, false);
};

GestureTracker.OnEnd on_animation_end = (percentage, cancel_action) => {
if (cancel_action) {
GestureTracker.OnEnd on_animation_end = (percentage, completions) => {
if (completions == 0) {
return;
}

Expand All @@ -373,7 +373,7 @@ public class Gala.WindowClone : Clutter.Actor {
};

if (gesture_tracker == null || !with_gesture || !AnimationsSettings.get_enable_animations ()) {
on_animation_end (1, false, 0);
on_animation_end (1, 1, 0);
} else {
gesture_tracker.connect_handlers (null, (owned) on_animation_update, (owned) on_animation_end);
}
Expand Down
Loading
Loading