layout: Shuffle code around
This will make the next diff much cleaner. https://bugzilla.gnome.org/show_bug.cgi?id=692677
This commit is contained in:
parent
a9ad9d5e6d
commit
72405cd43f
346
js/ui/layout.js
346
js/ui/layout.js
@ -522,179 +522,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
Signals.addSignalMethods(LayoutManager.prototype);
|
Signals.addSignalMethods(LayoutManager.prototype);
|
||||||
|
|
||||||
|
|
||||||
// HotCorner:
|
|
||||||
//
|
|
||||||
// This class manages a "hot corner" that can toggle switching to
|
|
||||||
// overview.
|
|
||||||
const HotCorner = new Lang.Class({
|
|
||||||
Name: 'HotCorner',
|
|
||||||
|
|
||||||
_init : function() {
|
|
||||||
// We use this flag to mark the case where the user has entered the
|
|
||||||
// hot corner and has not left both the hot corner and a surrounding
|
|
||||||
// guard area (the "environs"). This avoids triggering the hot corner
|
|
||||||
// multiple times due to an accidental jitter.
|
|
||||||
this._entered = false;
|
|
||||||
|
|
||||||
this.actor = new Clutter.Group({ name: 'hot-corner-environs',
|
|
||||||
width: 3,
|
|
||||||
height: 3,
|
|
||||||
reactive: true });
|
|
||||||
|
|
||||||
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
|
|
||||||
width: 1,
|
|
||||||
height: 1,
|
|
||||||
opacity: 0,
|
|
||||||
reactive: true });
|
|
||||||
this._corner._delegate = this;
|
|
||||||
|
|
||||||
this.actor.add_actor(this._corner);
|
|
||||||
|
|
||||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
|
||||||
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
|
||||||
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
|
||||||
} else {
|
|
||||||
this._corner.set_position(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._activationTime = 0;
|
|
||||||
|
|
||||||
this.actor.connect('leave-event',
|
|
||||||
Lang.bind(this, this._onEnvironsLeft));
|
|
||||||
|
|
||||||
// Clicking on the hot corner environs should result in the
|
|
||||||
// same behavior as clicking on the hot corner.
|
|
||||||
this.actor.connect('button-release-event',
|
|
||||||
Lang.bind(this, this._onCornerClicked));
|
|
||||||
|
|
||||||
// In addition to being triggered by the mouse enter event,
|
|
||||||
// the hot corner can be triggered by clicking on it. This is
|
|
||||||
// useful if the user wants to undo the effect of triggering
|
|
||||||
// the hot corner once in the hot corner.
|
|
||||||
this._corner.connect('enter-event',
|
|
||||||
Lang.bind(this, this._onCornerEntered));
|
|
||||||
this._corner.connect('button-release-event',
|
|
||||||
Lang.bind(this, this._onCornerClicked));
|
|
||||||
this._corner.connect('leave-event',
|
|
||||||
Lang.bind(this, this._onCornerLeft));
|
|
||||||
|
|
||||||
// Cache the three ripples instead of dynamically creating and destroying them.
|
|
||||||
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
|
||||||
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
|
||||||
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this._ripple1);
|
|
||||||
Main.uiGroup.add_actor(this._ripple2);
|
|
||||||
Main.uiGroup.add_actor(this._ripple3);
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
this.actor.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
_animRipple : function(ripple, delay, time, startScale, startOpacity, finalScale) {
|
|
||||||
// We draw a ripple by using a source image and animating it scaling
|
|
||||||
// outwards and fading away. We want the ripples to move linearly
|
|
||||||
// or it looks unrealistic, but if the opacity of the ripple goes
|
|
||||||
// linearly to zero it fades away too quickly, so we use Tweener's
|
|
||||||
// 'onUpdate' to give a non-linear curve to the fade-away and make
|
|
||||||
// it more visible in the middle section.
|
|
||||||
|
|
||||||
ripple._opacity = startOpacity;
|
|
||||||
|
|
||||||
if (ripple.get_text_direction() == Clutter.TextDirection.RTL)
|
|
||||||
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
|
||||||
|
|
||||||
ripple.visible = true;
|
|
||||||
ripple.opacity = 255 * Math.sqrt(startOpacity);
|
|
||||||
ripple.scale_x = ripple.scale_y = startScale;
|
|
||||||
|
|
||||||
let [x, y] = this._corner.get_transformed_position();
|
|
||||||
ripple.x = x;
|
|
||||||
ripple.y = y;
|
|
||||||
|
|
||||||
Tweener.addTween(ripple, { _opacity: 0,
|
|
||||||
scale_x: finalScale,
|
|
||||||
scale_y: finalScale,
|
|
||||||
delay: delay,
|
|
||||||
time: time,
|
|
||||||
transition: 'linear',
|
|
||||||
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
|
|
||||||
onComplete: function() { ripple.visible = false; } });
|
|
||||||
},
|
|
||||||
|
|
||||||
rippleAnimation: function() {
|
|
||||||
// Show three concentric ripples expanding outwards; the exact
|
|
||||||
// parameters were found by trial and error, so don't look
|
|
||||||
// for them to make perfect sense mathematically
|
|
||||||
|
|
||||||
// delay time scale opacity => scale
|
|
||||||
this._animRipple(this._ripple1, 0.0, 0.83, 0.25, 1.0, 1.5);
|
|
||||||
this._animRipple(this._ripple2, 0.05, 1.0, 0.0, 0.7, 1.25);
|
|
||||||
this._animRipple(this._ripple3, 0.35, 1.0, 0.0, 0.3, 1);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
|
||||||
if (source != Main.xdndHandler)
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
|
|
||||||
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
|
||||||
this.rippleAnimation();
|
|
||||||
Main.overview.showTemporarily();
|
|
||||||
Main.overview.beginItemDrag(actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCornerEntered : function() {
|
|
||||||
if (!this._entered) {
|
|
||||||
this._entered = true;
|
|
||||||
if (!Main.overview.animationInProgress) {
|
|
||||||
this._activationTime = Date.now() / 1000;
|
|
||||||
|
|
||||||
this.rippleAnimation();
|
|
||||||
Main.overview.toggle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCornerClicked : function() {
|
|
||||||
if (this.shouldToggleOverviewOnClick())
|
|
||||||
Main.overview.toggle();
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onCornerLeft : function(actor, event) {
|
|
||||||
if (event.get_related() != this.actor)
|
|
||||||
this._entered = false;
|
|
||||||
// Consume event, otherwise this will confuse onEnvironsLeft
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onEnvironsLeft : function(actor, event) {
|
|
||||||
if (event.get_related() != this._corner)
|
|
||||||
this._entered = false;
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
// Checks if the Activities button is currently sensitive to
|
|
||||||
// clicks. The first call to this function within the
|
|
||||||
// HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being
|
|
||||||
// triggered will return false. This avoids opening and closing
|
|
||||||
// the overview if the user both triggered the hot corner and
|
|
||||||
// clicked the Activities button.
|
|
||||||
shouldToggleOverviewOnClick: function() {
|
|
||||||
if (Main.overview.animationInProgress)
|
|
||||||
return false;
|
|
||||||
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// This manages the shell "chrome"; the UI that's visible in the
|
// This manages the shell "chrome"; the UI that's visible in the
|
||||||
// normal mode (ie, outside the Overview), that surrounds the main
|
// normal mode (ie, outside the Overview), that surrounds the main
|
||||||
// workspace content.
|
// workspace content.
|
||||||
@ -1142,3 +969,176 @@ const Chrome = new Lang.Class({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Signals.addSignalMethods(Chrome.prototype);
|
Signals.addSignalMethods(Chrome.prototype);
|
||||||
|
|
||||||
|
|
||||||
|
// HotCorner:
|
||||||
|
//
|
||||||
|
// This class manages a "hot corner" that can toggle switching to
|
||||||
|
// overview.
|
||||||
|
const HotCorner = new Lang.Class({
|
||||||
|
Name: 'HotCorner',
|
||||||
|
|
||||||
|
_init : function() {
|
||||||
|
// We use this flag to mark the case where the user has entered the
|
||||||
|
// hot corner and has not left both the hot corner and a surrounding
|
||||||
|
// guard area (the "environs"). This avoids triggering the hot corner
|
||||||
|
// multiple times due to an accidental jitter.
|
||||||
|
this._entered = false;
|
||||||
|
|
||||||
|
this.actor = new Clutter.Group({ name: 'hot-corner-environs',
|
||||||
|
width: 3,
|
||||||
|
height: 3,
|
||||||
|
reactive: true });
|
||||||
|
|
||||||
|
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
|
||||||
|
width: 1,
|
||||||
|
height: 1,
|
||||||
|
opacity: 0,
|
||||||
|
reactive: true });
|
||||||
|
this._corner._delegate = this;
|
||||||
|
|
||||||
|
this.actor.add_actor(this._corner);
|
||||||
|
|
||||||
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
|
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
||||||
|
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
|
} else {
|
||||||
|
this._corner.set_position(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._activationTime = 0;
|
||||||
|
|
||||||
|
this.actor.connect('leave-event',
|
||||||
|
Lang.bind(this, this._onEnvironsLeft));
|
||||||
|
|
||||||
|
// Clicking on the hot corner environs should result in the
|
||||||
|
// same behavior as clicking on the hot corner.
|
||||||
|
this.actor.connect('button-release-event',
|
||||||
|
Lang.bind(this, this._onCornerClicked));
|
||||||
|
|
||||||
|
// In addition to being triggered by the mouse enter event,
|
||||||
|
// the hot corner can be triggered by clicking on it. This is
|
||||||
|
// useful if the user wants to undo the effect of triggering
|
||||||
|
// the hot corner once in the hot corner.
|
||||||
|
this._corner.connect('enter-event',
|
||||||
|
Lang.bind(this, this._onCornerEntered));
|
||||||
|
this._corner.connect('button-release-event',
|
||||||
|
Lang.bind(this, this._onCornerClicked));
|
||||||
|
this._corner.connect('leave-event',
|
||||||
|
Lang.bind(this, this._onCornerLeft));
|
||||||
|
|
||||||
|
// Cache the three ripples instead of dynamically creating and destroying them.
|
||||||
|
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
||||||
|
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
||||||
|
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
||||||
|
|
||||||
|
Main.uiGroup.add_actor(this._ripple1);
|
||||||
|
Main.uiGroup.add_actor(this._ripple2);
|
||||||
|
Main.uiGroup.add_actor(this._ripple3);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.actor.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
_animRipple : function(ripple, delay, time, startScale, startOpacity, finalScale) {
|
||||||
|
// We draw a ripple by using a source image and animating it scaling
|
||||||
|
// outwards and fading away. We want the ripples to move linearly
|
||||||
|
// or it looks unrealistic, but if the opacity of the ripple goes
|
||||||
|
// linearly to zero it fades away too quickly, so we use Tweener's
|
||||||
|
// 'onUpdate' to give a non-linear curve to the fade-away and make
|
||||||
|
// it more visible in the middle section.
|
||||||
|
|
||||||
|
ripple._opacity = startOpacity;
|
||||||
|
|
||||||
|
if (ripple.get_text_direction() == Clutter.TextDirection.RTL)
|
||||||
|
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
|
|
||||||
|
ripple.visible = true;
|
||||||
|
ripple.opacity = 255 * Math.sqrt(startOpacity);
|
||||||
|
ripple.scale_x = ripple.scale_y = startScale;
|
||||||
|
|
||||||
|
let [x, y] = this._corner.get_transformed_position();
|
||||||
|
ripple.x = x;
|
||||||
|
ripple.y = y;
|
||||||
|
|
||||||
|
Tweener.addTween(ripple, { _opacity: 0,
|
||||||
|
scale_x: finalScale,
|
||||||
|
scale_y: finalScale,
|
||||||
|
delay: delay,
|
||||||
|
time: time,
|
||||||
|
transition: 'linear',
|
||||||
|
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
|
||||||
|
onComplete: function() { ripple.visible = false; } });
|
||||||
|
},
|
||||||
|
|
||||||
|
rippleAnimation: function() {
|
||||||
|
// Show three concentric ripples expanding outwards; the exact
|
||||||
|
// parameters were found by trial and error, so don't look
|
||||||
|
// for them to make perfect sense mathematically
|
||||||
|
|
||||||
|
// delay time scale opacity => scale
|
||||||
|
this._animRipple(this._ripple1, 0.0, 0.83, 0.25, 1.0, 1.5);
|
||||||
|
this._animRipple(this._ripple2, 0.05, 1.0, 0.0, 0.7, 1.25);
|
||||||
|
this._animRipple(this._ripple3, 0.35, 1.0, 0.0, 0.3, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
|
if (source != Main.xdndHandler)
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
|
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||||
|
this.rippleAnimation();
|
||||||
|
Main.overview.showTemporarily();
|
||||||
|
Main.overview.beginItemDrag(actor);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCornerEntered : function() {
|
||||||
|
if (!this._entered) {
|
||||||
|
this._entered = true;
|
||||||
|
if (!Main.overview.animationInProgress) {
|
||||||
|
this._activationTime = Date.now() / 1000;
|
||||||
|
|
||||||
|
this.rippleAnimation();
|
||||||
|
Main.overview.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCornerClicked : function() {
|
||||||
|
if (this.shouldToggleOverviewOnClick())
|
||||||
|
Main.overview.toggle();
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCornerLeft : function(actor, event) {
|
||||||
|
if (event.get_related() != this.actor)
|
||||||
|
this._entered = false;
|
||||||
|
// Consume event, otherwise this will confuse onEnvironsLeft
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onEnvironsLeft : function(actor, event) {
|
||||||
|
if (event.get_related() != this._corner)
|
||||||
|
this._entered = false;
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Checks if the Activities button is currently sensitive to
|
||||||
|
// clicks. The first call to this function within the
|
||||||
|
// HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being
|
||||||
|
// triggered will return false. This avoids opening and closing
|
||||||
|
// the overview if the user both triggered the hot corner and
|
||||||
|
// clicked the Activities button.
|
||||||
|
shouldToggleOverviewOnClick: function() {
|
||||||
|
if (Main.overview.animationInProgress)
|
||||||
|
return false;
|
||||||
|
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user