Skip to content

Commit 6bf330b

Browse files
authored
Add mouse-click-effects@anaximeno (#635)
1 parent 7250018 commit 6bf330b

28 files changed

+6194
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Mouse Click Effects
2+
3+
Display mouse click effects on Cinnamon.
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/* clickAnimations.js
2+
*
3+
* This program is free software: you can redistribute it and/or modify
4+
* it under the terms of the GNU General Public License as published by
5+
* the Free Software Foundation, either version 2 of the License, or
6+
* (at your option) any later version.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License
14+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
*
16+
* SPDX-License-Identifier: GPL-3.0-or-later
17+
*/
18+
'use strict';
19+
20+
const Main = imports.ui.main;
21+
const Clutter = imports.gi.Clutter;
22+
const St = imports.gi.St;
23+
24+
class ClickAnimationMode {
25+
constructor(mode) {
26+
this.mode = mode;
27+
}
28+
29+
/**
30+
* Animates the click into the screen
31+
* @param {GIcon} icon The icon that will be animated
32+
* @param {Object} options Additional options used while during the animation
33+
*/
34+
animateClick(icon, options) {
35+
// Implemented by sub-classes
36+
}
37+
}
38+
39+
class ExpansionClickAnimationMode extends ClickAnimationMode {
40+
animateClick(icon, options) {
41+
const actor_scale = options.icon_size > 20 ? 1.15 : 3;
42+
const [mouse_x, mouse_y, mask] = global.get_pointer();
43+
44+
let actor = new St.Icon({
45+
x: mouse_x,
46+
y: mouse_y,
47+
scale_x: 0,
48+
scale_y: 0,
49+
reactive: false,
50+
can_focus: false,
51+
track_hover: false,
52+
icon_size: options.icon_size,
53+
opacity: options.opacity,
54+
gicon: icon,
55+
});
56+
57+
Main.uiGroup.add_child(actor);
58+
59+
actor.ease({
60+
opacity: options.opacity * 0.08,
61+
x: mouse_x - (options.icon_size * actor_scale * global.ui_scale / 2),
62+
y: mouse_y - (options.icon_size * actor_scale * global.ui_scale / 2),
63+
scale_x: actor_scale,
64+
scale_y: actor_scale,
65+
duration: options.timeout,
66+
mode: Clutter.AnimationMode.EASE_OUT_SINE,
67+
onComplete: () => {
68+
Main.uiGroup.remove_child(actor);
69+
actor.destroy();
70+
actor = null;
71+
}
72+
});
73+
}
74+
}
75+
76+
class RetractionClickAnimationMode extends ClickAnimationMode {
77+
animateClick(icon, options) {
78+
const [mouse_x, mouse_y, mask] = global.get_pointer();
79+
80+
let actor = new St.Icon({
81+
x: mouse_x - (options.icon_size * global.ui_scale / 2),
82+
y: mouse_y - (options.icon_size * global.ui_scale / 2),
83+
reactive: false,
84+
can_focus: false,
85+
track_hover: false,
86+
icon_size: options.icon_size,
87+
opacity: options.opacity,
88+
gicon: icon,
89+
});
90+
91+
Main.uiGroup.add_child(actor);
92+
93+
actor.ease({
94+
opacity: options.opacity * 0.1,
95+
x: mouse_x,
96+
y: mouse_y,
97+
scale_x: 0,
98+
scale_y: 0,
99+
duration: options.timeout,
100+
mode: Clutter.AnimationMode.EASE_OUT_SINE,
101+
onComplete: () => {
102+
Main.uiGroup.remove_child(actor);
103+
actor.destroy();
104+
actor = null;
105+
}
106+
});
107+
}
108+
}
109+
110+
class BounceBackClickAnimationMode extends ClickAnimationMode {
111+
animateClick(icon, options) {
112+
const [mouse_x, mouse_y, mask] = global.get_pointer();
113+
114+
let actor = new St.Icon({
115+
x: mouse_x,
116+
y: mouse_y,
117+
scale_x: 0,
118+
scale_y: 0,
119+
reactive: false,
120+
can_focus: false,
121+
track_hover: false,
122+
icon_size: options.icon_size,
123+
opacity: options.opacity * 0.1,
124+
gicon: icon,
125+
});
126+
127+
Main.uiGroup.add_child(actor);
128+
129+
actor.ease({
130+
x: mouse_x - (options.icon_size * global.ui_scale / 2),
131+
y: mouse_y - (options.icon_size * global.ui_scale / 2),
132+
scale_x: 1,
133+
scale_y: 1,
134+
opacity: options.opacity,
135+
duration: options.timeout * 0.4,
136+
mode: Clutter.AnimationMode.EASE_IN_OUT_CUBIC,
137+
onComplete: () => {
138+
actor.ease({
139+
opacity: 0,
140+
x: mouse_x,
141+
y: mouse_y,
142+
scale_x: 0,
143+
scale_y: 0,
144+
duration: options.timeout * 0.6,
145+
mode: Clutter.AnimationMode.EASE_IN_OUT_CUBIC,
146+
onComplete: () => {
147+
Main.uiGroup.remove_child(actor);
148+
actor.destroy();
149+
actor = null;
150+
}
151+
});
152+
}
153+
});
154+
}
155+
}
156+
157+
class BlinkClickAnimationMode extends ClickAnimationMode {
158+
animateClick(icon, options = {}) {
159+
const [mouse_x, mouse_y, mask] = global.get_pointer();
160+
161+
let actor = new St.Icon({
162+
x: mouse_x - (options.icon_size * global.ui_scale / 2),
163+
y: mouse_y - (options.icon_size * global.ui_scale / 2),
164+
reactive: false,
165+
can_focus: false,
166+
track_hover: false,
167+
icon_size: options.icon_size,
168+
opacity: options.opacity,
169+
gicon: icon
170+
});
171+
172+
Main.uiGroup.add_child(actor);
173+
174+
actor.ease({
175+
opacity: options.opacity * 0.1,
176+
duration: options.timeout,
177+
mode: Clutter.AnimationMode.EASE_IN_OUT_CUBIC,
178+
onComplete: () => {
179+
Main.uiGroup.remove_child(actor);
180+
actor.destroy();
181+
actor = null;
182+
}
183+
});
184+
}
185+
}
186+
187+
class ClickAnimationFactory {
188+
/**
189+
* Returns an click animation mode depending on the given name
190+
* @param {String} mode Click Animation mode name to create
191+
* @returns ClickAnimationMode subclass
192+
*/
193+
static createForMode(mode) {
194+
switch (mode) {
195+
case "bounce":
196+
return new BounceBackClickAnimationMode(mode);
197+
case "retract":
198+
return new RetractionClickAnimationMode(mode);
199+
case "expand":
200+
return new ExpansionClickAnimationMode(mode);
201+
case "blink":
202+
default:
203+
return new BlinkClickAnimationMode(mode);
204+
}
205+
}
206+
}

0 commit comments

Comments
 (0)