Merge lp:~ricotz/plank/animate-add-remove into lp:plank

Proposed by Rico Tzschichholz
Status: Merged
Merged at revision: 1173
Proposed branch: lp:~ricotz/plank/animate-add-remove
Merge into: lp:plank
Diff against target: 1211 lines (+821/-73)
9 files modified
data/themes/Default/dock.theme (+1/-1)
docs/Makefile.am (+1/-0)
lib/DockController.vala (+4/-0)
lib/DockRenderer.vala (+261/-67)
lib/Drawing/DockTheme.vala (+1/-1)
lib/Drawing/Easing.vala (+548/-0)
lib/Items/DockItem.vala (+2/-4)
lib/Makefile.am (+1/-0)
lib/libplank.symbols (+2/-0)
To merge this branch: bzr merge lp:~ricotz/plank/animate-add-remove
Reviewer Review Type Date Requested Status
Docky Core Pending
Review via email: mp+246952@code.launchpad.net
To post a comment you must log in.
lp:~ricotz/plank/animate-add-remove updated
1161. By Rico Tzschichholz

Fix broken virtual LauncherEntry-items

Regression of r1057

1162. By Rico Tzschichholz

positionmanager: Alignment should have same meaning for dock and items

START and END were treated differently resulting in a contradicting
settings-behaviour of Aligment and ItemsAlignment

1163. By Rico Tzschichholz

build: Request gee-0.8 without an automatic fallback to gee-1.0

1164. By Rico Tzschichholz

build: Compatibility for BSD, use replacement for sys/prctl.h

1165. By Rico Tzschichholz

Make use of Gdk.EVENT_PROPAGATE and Gdk.EVENT_STOP

1166. By Rico Tzschichholz

po: Update translations

1167. By Rico Tzschichholz

Prepare 0.8.1 release

1168. By Rico Tzschichholz

Back to development

1169. By Rico Tzschichholz

dockitem: Fix warning while building non-HiDPI

1170. By Rico Tzschichholz

renderer: Redo final drawing to untangle the different layers

Adds additional drawing operations and therefore slows things down a bit.

1171. By Rico Tzschichholz

drawing: Add standard set of easing-functions

1172. By Rico Tzschichholz

Add add/remove animations for dock-items

1173. By Rico Tzschichholz

theme: Increase default ItemMoveTime to 450ms

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/themes/Default/dock.theme'
2--- data/themes/Default/dock.theme 2013-10-01 14:44:00 +0000
3+++ data/themes/Default/dock.theme 2015-01-26 20:17:08 +0000
4@@ -59,4 +59,4 @@
5 #The hue-shift (-180 to 180) of the urgent indicator color.
6 UrgentHueShift=150
7 #The time (in ms) to move an item to its new position.
8-ItemMoveTime=150
9+ItemMoveTime=450
10
11=== modified file 'docs/Makefile.am'
12--- docs/Makefile.am 2014-10-10 07:01:51 +0000
13+++ docs/Makefile.am 2015-01-26 20:17:08 +0000
14@@ -34,6 +34,7 @@
15 $(top_srcdir)/lib/Drawing/DrawingService.vala \
16 $(top_srcdir)/lib/Drawing/DockSurface.vala \
17 $(top_srcdir)/lib/Drawing/DockTheme.vala \
18+ $(top_srcdir)/lib/Drawing/Easing.vala \
19 $(top_srcdir)/lib/Drawing/Theme.vala \
20 $(top_srcdir)/lib/Factories/AbstractMain.vala \
21 $(top_srcdir)/lib/Factories/Factory.vala \
22
23=== modified file 'lib/DockController.vala'
24--- lib/DockController.vala 2014-11-04 09:54:12 +0000
25+++ lib/DockController.vala 2015-01-26 20:17:08 +0000
26@@ -225,6 +225,10 @@
27 if (provider == default_provider)
28 serialize_item_positions ();
29
30+ // Schedule added/removed items for special animations
31+ renderer.animate_items (added);
32+ renderer.animate_items (removed);
33+
34 update_visible_items ();
35
36 if (prefs.Alignment != Gtk.Align.FILL
37
38=== modified file 'lib/DockRenderer.vala'
39--- lib/DockRenderer.vala 2015-01-05 10:54:40 +0000
40+++ lib/DockRenderer.vala 2015-01-26 20:17:08 +0000
41@@ -43,11 +43,14 @@
42 [CCode (notify = false)]
43 double opacity { get; private set; }
44
45+ DockSurface? main_buffer = null;
46+ DockSurface? fade_buffer = null;
47+ DockSurface? item_buffer = null;
48+ DockSurface? shadow_buffer = null;
49+
50 DockSurface? background_buffer = null;
51 Gdk.Rectangle background_rect;
52- DockSurface? main_buffer = null;
53 DockSurface? indicator_buffer = null;
54- DockSurface? shadow_buffer = null;
55 DockSurface? urgent_indicator_buffer = null;
56 DockSurface? urgent_glow_buffer = null;
57
58@@ -61,6 +64,9 @@
59
60 ulong gtk_theme_name_changed_id = 0;
61
62+ double dynamic_animation_offset = 0.0;
63+
64+ Gee.HashSet<DockItem> transient_items;
65 #if BENCHMARK
66 Gee.ArrayList<string> benchmark;
67 #endif
68@@ -78,6 +84,7 @@
69
70 construct
71 {
72+ transient_items = new Gee.HashSet<DockItem> ();
73 #if BENCHMARK
74 benchmark = new Gee.ArrayList<string> ();
75 #endif
76@@ -187,9 +194,12 @@
77 Logger.verbose ("DockRenderer.reset_buffers ()");
78
79 main_buffer = null;
80+ fade_buffer = null;
81+ item_buffer = null;
82+ shadow_buffer = null;
83+
84 background_buffer = null;
85 indicator_buffer = null;
86- shadow_buffer = null;
87 urgent_indicator_buffer = null;
88 urgent_glow_buffer = null;
89
90@@ -213,6 +223,7 @@
91 {
92 frame_time = GLib.get_monotonic_time ();
93 screen_is_composited = controller.position_manager.screen_is_composited;
94+ dynamic_animation_offset = 0.0;
95
96 var fade_opacity = theme.FadeOpacity;
97
98@@ -258,6 +269,13 @@
99 #endif
100 }
101
102+ if (item_buffer == null) {
103+ item_buffer = new DockSurface.with_surface (win_rect.width, win_rect.height, cr.get_target ());
104+#if HAVE_HIDPI
105+ cairo_surface_set_device_scale (item_buffer.Internal, window_scale_factor, window_scale_factor);
106+#endif
107+ }
108+
109 if (shadow_buffer == null) {
110 shadow_buffer = new DockSurface.with_surface (win_rect.width, win_rect.height, cr.get_target ());
111 #if HAVE_HIDPI
112@@ -282,60 +300,179 @@
113 return;
114 }
115
116+ if (opacity < 1.0 && fade_buffer == null) {
117+ fade_buffer = new DockSurface.with_surface (win_rect.width, win_rect.height, cr.get_target ());
118+#if HAVE_HIDPI
119+ cairo_surface_set_device_scale (fade_buffer.Internal, window_scale_factor, window_scale_factor);
120+#endif
121+ }
122+
123 #if BENCHMARK
124+ DateTime start, start2, end, end2;
125 benchmark.clear ();
126- var start = new DateTime.now_local ();
127+ start = new DateTime.now_local ();
128 #endif
129
130 main_buffer.clear ();
131+ item_buffer.clear ();
132 shadow_buffer.clear ();
133-
134-#if BENCHMARK
135- var start2 = new DateTime.now_local ();
136-#endif
137- draw_dock_background ();
138-#if BENCHMARK
139- var end2 = new DateTime.now_local ();
140+ unowned Cairo.Context item_cr = item_buffer.Context;
141+
142+ // draw transient items onto the dock buffer and calculate the resulting
143+ // dynamic-animation-offset used to animate the background-resize
144+ if (screen_is_composited) {
145+ var add_time = 0LL;
146+ var remove_time = 0LL;
147+ var move_time = 0LL;
148+ var move_duration = theme.ItemMoveTime * 1000;
149+
150+ var transient_items_it = transient_items.iterator ();
151+ while (transient_items_it.next ()) {
152+ var item = transient_items_it.get ();
153+ add_time = item.AddTime;
154+ remove_time = item.RemoveTime;
155+
156+ if (add_time > remove_time) {
157+ move_time = frame_time - add_time;
158+ if (move_time < move_duration) {
159+ var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_QUINT, move_time, move_duration);
160+ dynamic_animation_offset -= move_animation_progress * (position_manager.IconSize + position_manager.ItemPadding);
161+ } else {
162+ transient_items_it.remove ();
163+ }
164+ } else if (remove_time > 0) {
165+ move_time = frame_time - remove_time;
166+ if (move_time < move_duration) {
167+ var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_IN_QUINT, move_time, move_duration);
168+ dynamic_animation_offset += move_animation_progress * (position_manager.IconSize + position_manager.ItemPadding);
169+ } else {
170+ transient_items_it.remove ();
171+ }
172+ } else {
173+ continue;
174+ }
175+#if BENCHMARK
176+ start2 = new DateTime.now_local ();
177+#endif
178+ // Do not draw the currently dragged item or items which are suppose to be drawn later
179+ if (move_time < move_duration && dragged_item != item && !items.contains (item))
180+ draw_item (item_cr, item);
181+#if BENCHMARK
182+ end2 = new DateTime.now_local ();
183+ benchmark.add ("item render time - %f ms".printf (end2.difference (start2) / 1000.0));
184+#endif
185+ }
186+ } else {
187+ transient_items.clear ();
188+ }
189+
190+ background_rect = position_manager.get_background_region ();
191+
192+ // calculate drawing offset
193+ var x_offset = 0, y_offset = 0;
194+ if (opacity == 1.0)
195+ position_manager.get_dock_draw_position (out x_offset, out y_offset);
196+
197+ // calculate drawing animation-offset
198+ var x_animation_offset = 0, y_animation_offset = 0;
199+ switch (controller.prefs.Alignment) {
200+ default:
201+ case Gtk.Align.CENTER:
202+ if (position_manager.is_horizontal_dock ())
203+ x_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
204+ else
205+ y_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
206+ background_rect = { background_rect.x + x_animation_offset, background_rect.y + y_animation_offset,
207+ background_rect.width -2 * x_animation_offset, background_rect.height -2 * y_animation_offset };
208+ break;
209+ case Gtk.Align.START:
210+ if (position_manager.is_horizontal_dock ())
211+ background_rect = { background_rect.x, background_rect.y,
212+ background_rect.width + (int) Math.round (dynamic_animation_offset), background_rect.height };
213+ else
214+ background_rect = { background_rect.x, background_rect.y,
215+ background_rect.width, background_rect.height + (int) Math.round (dynamic_animation_offset) };
216+ break;
217+ case Gtk.Align.END:
218+ if (position_manager.is_horizontal_dock ())
219+ x_animation_offset -= (int) Math.round (dynamic_animation_offset);
220+ else
221+ y_animation_offset -= (int) Math.round (dynamic_animation_offset);
222+ background_rect = { background_rect.x + x_animation_offset, background_rect.y + y_animation_offset,
223+ background_rect.width - x_animation_offset, background_rect.height - y_animation_offset };
224+ break;
225+ case Gtk.Align.FILL:
226+ switch (controller.prefs.ItemsAlignment) {
227+ default:
228+ case Gtk.Align.FILL:
229+ case Gtk.Align.CENTER:
230+ if (position_manager.is_horizontal_dock ())
231+ x_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
232+ else
233+ y_animation_offset -= (int) Math.round (dynamic_animation_offset / 2.0);
234+ break;
235+ case Gtk.Align.START:
236+ break;
237+ case Gtk.Align.END:
238+ if (position_manager.is_horizontal_dock ())
239+ x_animation_offset -= (int) Math.round (dynamic_animation_offset);
240+ else
241+ y_animation_offset -= (int) Math.round (dynamic_animation_offset);
242+ break;
243+ }
244+ break;
245+ }
246+
247+ // composite dock layers and make sure to draw onto the window's context with one operation
248+ main_buffer.clear ();
249+ unowned Cairo.Context main_cr = main_buffer.Context;
250+ main_cr.set_operator (Cairo.Operator.OVER);
251+
252+ // draw items-shadow-layer
253+ main_cr.set_source_surface (shadow_buffer.Internal, x_animation_offset, y_animation_offset);
254+ main_cr.paint ();
255+
256+#if BENCHMARK
257+ start2 = new DateTime.now_local ();
258+#endif
259+ // draw background-layer
260+ draw_dock_background (main_cr, background_rect);
261+#if BENCHMARK
262+ end2 = new DateTime.now_local ();
263 benchmark.add ("background render time - %f ms".printf (end2.difference (start2) / 1000.0));
264 #endif
265
266-
267 // draw each item onto the dock buffer
268- foreach (var item in items)
269- {
270+ foreach (var item in items) {
271 #if BENCHMARK
272 start2 = new DateTime.now_local ();
273 #endif
274 // Do not draw the currently dragged item
275 if (dragged_item != item)
276- draw_item (item);
277+ draw_item (item_cr, item);
278 #if BENCHMARK
279 end2 = new DateTime.now_local ();
280 benchmark.add ("item render time - %f ms".printf (end2.difference (start2) / 1000.0));
281 #endif
282 }
283
284- // calculate drawing offset
285- var x_offset = 0, y_offset = 0;
286- if (opacity == 1.0)
287- position_manager.get_dock_draw_position (out x_offset, out y_offset);
288-
289- // composite dock layers and make sure to draw onto the window's context with one operation
290- unowned Cairo.Context composite_cr = shadow_buffer.Context;
291- composite_cr.set_operator (Cairo.Operator.OVER);
292- composite_cr.set_source_surface (main_buffer.Internal, 0, 0);
293- composite_cr.paint ();
294-
295- // fade the dock if need be
296+ // draw items-layer
297+ main_cr.set_source_surface (item_buffer.Internal, x_animation_offset, y_animation_offset);
298+ main_cr.paint ();
299+
300+ // draw the dock on the window and fade it if need be
301+ cr.set_operator (Cairo.Operator.SOURCE);
302 if (opacity < 1.0) {
303- composite_cr.set_operator (Cairo.Operator.SOURCE);
304- composite_cr.set_source_rgba (0, 0, 0, 0);
305- composite_cr.paint_with_alpha (1 - opacity);
306+ fade_buffer.clear ();
307+ unowned Cairo.Context fade_cr = fade_buffer.Context;
308+ fade_cr.set_operator (Cairo.Operator.OVER);
309+ fade_cr.set_source_surface (main_buffer.Internal, 0, 0);
310+ fade_cr.paint_with_alpha (opacity);
311+
312+ cr.set_source_surface (fade_buffer.Internal, x_offset, y_offset);
313+ } else {
314+ cr.set_source_surface (main_buffer.Internal, x_offset, y_offset);
315 }
316-
317- // draw the dock on the window
318- cr.set_operator (Cairo.Operator.SOURCE);
319- cr.set_source_surface (shadow_buffer.Internal, x_offset, y_offset);
320 cr.paint ();
321
322 // draw urgent-glow if dock is completely hidden
323@@ -345,7 +482,7 @@
324 }
325
326 #if BENCHMARK
327- var end = new DateTime.now_local ();
328+ end = new DateTime.now_local ();
329 var diff = end.difference (start) / 1000.0;
330 if (diff > 5.0)
331 foreach (var s in benchmark)
332@@ -356,12 +493,10 @@
333 is_first_frame = false;
334 }
335
336- void draw_dock_background ()
337+ void draw_dock_background (Cairo.Context cr, Gdk.Rectangle background_rect)
338 {
339 unowned PositionManager position_manager = controller.position_manager;
340
341- background_rect = position_manager.get_background_region ();
342-
343 if (background_rect.width <= 0 || background_rect.height <= 0) {
344 background_buffer = null;
345 return;
346@@ -372,28 +507,28 @@
347 background_buffer = theme.create_background (background_rect.width, background_rect.height,
348 position_manager.Position, main_buffer);
349
350- unowned Cairo.Context cr = main_buffer.Context;
351 cr.set_source_surface (background_buffer.Internal, background_rect.x, background_rect.y);
352 cr.paint ();
353 }
354
355- void draw_item (DockItem item)
356+ void draw_item (Cairo.Context cr, DockItem item)
357 {
358 unowned PositionManager position_manager = controller.position_manager;
359 unowned DockItem hovered_item = controller.window.HoveredItem;
360 unowned DragManager drag_manager = controller.drag_manager;
361
362- unowned Cairo.Context main_cr = main_buffer.Context;
363 unowned Cairo.Context shadow_cr = shadow_buffer.Context;
364 var icon_size = position_manager.IconSize;
365 var shadow_size = position_manager.IconShadowSize;
366 var position = position_manager.Position;
367+ var show_indicator = true;
368+ var item_opacity = 1.0;
369
370 // load the icon
371 #if BENCHMARK
372 var start = new DateTime.now_local ();
373 #endif
374- var icon_surface = item.get_surface_copy (icon_size * window_scale_factor, icon_size * window_scale_factor, main_buffer);
375+ var icon_surface = item.get_surface_copy (icon_size * window_scale_factor, icon_size * window_scale_factor, item_buffer);
376 unowned Cairo.Context icon_cr = icon_surface.Context;
377
378 DockSurface? icon_shadow_surface = null;
379@@ -471,9 +606,9 @@
380 if (hover_time < max_hover_time) {
381 var hover_animation_progress = 0.0;
382 if (hovered_item == item) {
383- hover_animation_progress = double.min (1.0, hover_time / (double) max_hover_time);
384+ hover_animation_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, hover_time, max_hover_time);
385 } else {
386- hover_animation_progress = double.max (0.0, 1.0 - hover_time / (double) max_hover_time);
387+ hover_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.LINEAR, hover_time, max_hover_time);
388 }
389
390 switch (item.HoveredAnimation) {
391@@ -524,23 +659,55 @@
392
393 // animate icon movement on move state
394 if ((item.State & ItemState.MOVE) != 0) {
395+ var move_duration = theme.ItemMoveTime * 1000;
396 var move_time = frame_time - item.LastMove;
397- var move_animation_progress = move_time / (double) (theme.ItemMoveTime * 1000);
398- if (move_animation_progress < 1.0) {
399- var change = (1.0 - move_animation_progress) * (icon_size + position_manager.ItemPadding);
400+ if (move_time < move_duration) {
401+ var move_animation_progress = 0.0;
402+ if (transient_items.size > 0) {
403+ if (dynamic_animation_offset > 0)
404+ move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_IN_QUINT, move_time, move_duration);
405+ else
406+ move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_QUINT, move_time, move_duration);
407+ } else {
408+ move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_CIRC, move_time, move_duration);
409+ }
410+ var change = move_animation_progress * (icon_size + position_manager.ItemPadding);
411 draw_value.move_right (position, (item.Position < item.LastPosition ? change : -change));
412 } else {
413 item.unset_move_state ();
414 }
415 }
416-
417+
418+ // animate addition/removal
419+ if (screen_is_composited && item.AddTime > item.RemoveTime) {
420+ var move_duration = theme.ItemMoveTime * 1000;
421+ var move_time = frame_time - item.AddTime;
422+ if (move_time < move_duration) {
423+ var move_animation_progress = 1.0 - Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
424+ item_opacity = Drawing.easing_for_mode (AnimationMode.EASE_IN_EXPO, move_time, move_duration);
425+ var change = move_animation_progress * (icon_size + position_manager.BottomPadding);
426+ draw_value.move_in (position, -change);
427+ show_indicator = false;
428+ }
429+ } else if (screen_is_composited && item.RemoveTime > 0) {
430+ var move_duration = theme.ItemMoveTime * 1000;
431+ var move_time = frame_time - item.RemoveTime;
432+ if (move_time < move_duration) {
433+ var move_animation_progress = Drawing.easing_for_mode (AnimationMode.LINEAR, move_time, move_duration);
434+ item_opacity = 1.0 - Drawing.easing_for_mode (AnimationMode.EASE_OUT_EXPO, move_time, move_duration);
435+ var change = move_animation_progress * (icon_size + position_manager.BottomPadding);
436+ draw_value.move_in (position, -change);
437+ show_indicator = false;
438+ }
439+ }
440+
441 // draw active glow
442 var active_time = frame_time - item.LastActive;
443 var opacity = double.min (1, active_time / (double) (theme.ActiveTime * 1000));
444 if ((item.State & ItemState.ACTIVE) == 0)
445 opacity = 1 - opacity;
446 if (opacity > 0) {
447- theme.draw_active_glow (main_buffer, background_rect, draw_value.background_region, item.AverageIconColor, opacity, position);
448+ theme.draw_active_glow (item_buffer, background_rect, draw_value.background_region, item.AverageIconColor, opacity, position);
449 }
450
451 // draw the icon shadow
452@@ -551,23 +718,29 @@
453 }
454 shadow_cr.set_operator (Cairo.Operator.OVER);
455 shadow_cr.set_source_surface (icon_shadow_surface.Internal, (draw_value.draw_region.x - shadow_size) * window_scale_factor, (draw_value.draw_region.y - shadow_size) * window_scale_factor);
456- shadow_cr.paint ();
457+ if (item_opacity < 1.0)
458+ shadow_cr.paint_with_alpha (item_opacity);
459+ else
460+ shadow_cr.paint ();
461 if (window_scale_factor > 1)
462 shadow_cr.restore ();
463 }
464
465 // draw the icon
466 if (window_scale_factor > 1) {
467- main_cr.save ();
468- main_cr.scale (1.0 / window_scale_factor, 1.0 / window_scale_factor);
469+ cr.save ();
470+ cr.scale (1.0 / window_scale_factor, 1.0 / window_scale_factor);
471 }
472- main_cr.set_source_surface (icon_surface.Internal, draw_value.draw_region.x * window_scale_factor, draw_value.draw_region.y * window_scale_factor);
473- main_cr.paint ();
474+ cr.set_source_surface (icon_surface.Internal, draw_value.draw_region.x * window_scale_factor, draw_value.draw_region.y * window_scale_factor);
475+ if (item_opacity < 1.0)
476+ cr.paint_with_alpha (item_opacity);
477+ else
478+ cr.paint ();
479 if (window_scale_factor > 1)
480- main_cr.restore ();
481+ cr.restore ();
482
483 // draw indicators
484- if (item.Indicator != IndicatorState.NONE)
485+ if (show_indicator && item.Indicator != IndicatorState.NONE)
486 draw_indicator_state (draw_value.hover_region, item.Indicator, item.State);
487 }
488
489@@ -648,24 +821,24 @@
490 if (indicator_buffer == null) {
491 var indicator_color = get_styled_color ();
492 indicator_color.set_min_sat (0.4);
493- indicator_buffer = theme.create_indicator (position_manager.IndicatorSize, indicator_color, main_buffer);
494+ indicator_buffer = theme.create_indicator (position_manager.IndicatorSize, indicator_color, item_buffer);
495 }
496 if (urgent_indicator_buffer == null) {
497 var urgent_indicator_color = get_styled_color ();
498 urgent_indicator_color.add_hue (theme.UrgentHueShift);
499 urgent_indicator_color.set_sat (1.0);
500- urgent_indicator_buffer = theme.create_indicator (position_manager.IndicatorSize, urgent_indicator_color, main_buffer);
501+ urgent_indicator_buffer = theme.create_indicator (position_manager.IndicatorSize, urgent_indicator_color, item_buffer);
502 }
503
504 unowned DockSurface indicator_surface = (item_state & ItemState.URGENT) != 0 ? urgent_indicator_buffer : indicator_buffer;
505- unowned Cairo.Context main_cr = main_buffer.Context;
506+ unowned Cairo.Context cr = item_buffer.Context;
507
508 var x = 0.0, y = 0.0;
509 switch (position_manager.Position) {
510 default:
511 case Gtk.PositionType.BOTTOM:
512 x = item_rect.x + item_rect.width / 2.0 - indicator_surface.Width / 2.0;
513- y = main_buffer.Height - indicator_surface.Height / 2.0 - 2.0 * theme.get_bottom_offset () - indicator_surface.Height / 24.0;
514+ y = item_buffer.Height - indicator_surface.Height / 2.0 - 2.0 * theme.get_bottom_offset () - indicator_surface.Height / 24.0;
515 break;
516 case Gtk.PositionType.TOP:
517 x = item_rect.x + item_rect.width / 2.0 - indicator_surface.Width / 2.0;
518@@ -676,14 +849,14 @@
519 y = item_rect.y + item_rect.height / 2.0 - indicator_surface.Height / 2.0;
520 break;
521 case Gtk.PositionType.RIGHT:
522- x = main_buffer.Width - indicator_surface.Width / 2.0 - 2.0 * theme.get_bottom_offset () - indicator_surface.Width / 24.0;
523+ x = item_buffer.Width - indicator_surface.Width / 2.0 - 2.0 * theme.get_bottom_offset () - indicator_surface.Width / 24.0;
524 y = item_rect.y + item_rect.height / 2.0 - indicator_surface.Height / 2.0;
525 break;
526 }
527
528 if (indicator == IndicatorState.SINGLE) {
529- main_cr.set_source_surface (indicator_surface.Internal, x, y);
530- main_cr.paint ();
531+ cr.set_source_surface (indicator_surface.Internal, x, y);
532+ cr.paint ();
533 } else {
534 var x_offset = 0.0, y_offset = 0.0;
535 if (position_manager.is_horizontal_dock ())
536@@ -691,10 +864,10 @@
537 else
538 y_offset = position_manager.IconSize / 16.0;
539
540- main_cr.set_source_surface (indicator_surface.Internal, x - x_offset, y - y_offset);
541- main_cr.paint ();
542- main_cr.set_source_surface (indicator_surface.Internal, x + x_offset, y + y_offset);
543- main_cr.paint ();
544+ cr.set_source_surface (indicator_surface.Internal, x - x_offset, y - y_offset);
545+ cr.paint ();
546+ cr.set_source_surface (indicator_surface.Internal, x + x_offset, y + y_offset);
547+ cr.paint ();
548 }
549 }
550
551@@ -754,6 +927,20 @@
552 animated_draw ();
553 }
554
555+ public void animate_items (Gee.List<DockElement> elements)
556+ {
557+ if (!screen_is_composited)
558+ return;
559+
560+ foreach (var element in elements) {
561+ DockItem? item = (element as DockItem);
562+ if (item != null)
563+ transient_items.add (item);
564+ }
565+
566+ animated_draw ();
567+ }
568+
569 /**
570 * {@inheritDoc}
571 */
572@@ -767,6 +954,9 @@
573 return true;
574 }
575
576+ if (transient_items.size > 0)
577+ return true;
578+
579 foreach (var item in controller.Items) {
580 if (item.ClickedAnimation != Animation.NONE
581 && render_time - item.LastClicked <= (item.ClickedAnimation == Animation.BOUNCE ? theme.LaunchBounceTime : theme.ClickTime) * 1000)
582@@ -783,6 +973,10 @@
583 return true;
584 if (render_time - item.LastMove <= theme.ItemMoveTime * 1000)
585 return true;
586+ if (render_time - item.AddTime <= theme.ItemMoveTime * 1000)
587+ return true;
588+ if (render_time - item.RemoveTime <= theme.ItemMoveTime * 1000)
589+ return true;
590 }
591
592 return false;
593
594=== modified file 'lib/Drawing/DockTheme.vala'
595--- lib/Drawing/DockTheme.vala 2014-11-20 08:05:10 +0000
596+++ lib/Drawing/DockTheme.vala 2015-01-26 20:17:08 +0000
597@@ -133,7 +133,7 @@
598 GlowTime = 10000;
599 GlowPulseTime = 2000;
600 UrgentHueShift = 150;
601- ItemMoveTime = 150;
602+ ItemMoveTime = 450;
603 }
604
605 /**
606
607=== added file 'lib/Drawing/Easing.vala'
608--- lib/Drawing/Easing.vala 1970-01-01 00:00:00 +0000
609+++ lib/Drawing/Easing.vala 2015-01-26 20:17:08 +0000
610@@ -0,0 +1,548 @@
611+//
612+// Copyright (C) 2015 Rico Tzschichholz
613+//
614+// This program is free software: you can redistribute it and/or modify
615+// it under the terms of the GNU General Public License as published by
616+// the Free Software Foundation, either version 3 of the License, or
617+// (at your option) any later version.
618+//
619+// This program is distributed in the hope that it will be useful,
620+// but WITHOUT ANY WARRANTY; without even the implied warranty of
621+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
622+// GNU General Public License for more details.
623+//
624+// You should have received a copy of the GNU General Public License
625+// along with this program. If not, see <http://www.gnu.org/licenses/>.
626+//
627+
628+namespace Plank.Drawing
629+{
630+ /**
631+ * Utility functions to calculate progress of transitions.
632+ * Initially ported from clutter's clutter-enums.h and clutter-easing.c
633+ */
634+
635+ /**
636+ * The available animation modes
637+ */
638+ public enum AnimationMode
639+ {
640+ CUSTOM = 0,
641+
642+ /**
643+ * linear tweening
644+ */
645+ LINEAR,
646+
647+ /**
648+ * quadratic tweening
649+ */
650+ EASE_IN_QUAD,
651+ /**
652+ * quadratic tweening, inverse of EASE_IN_QUAD
653+ */
654+ EASE_OUT_QUAD,
655+ /**
656+ * quadratic tweening, combininig EASE_IN_QUAD and EASE_OUT_QUAD
657+ */
658+ EASE_IN_OUT_QUAD,
659+
660+ /**
661+ * cubic tweening
662+ */
663+ EASE_IN_CUBIC,
664+ /**
665+ * cubic tweening, invers of EASE_IN_CUBIC
666+ */
667+ EASE_OUT_CUBIC,
668+ /**
669+ * cubic tweening, combining EASE_IN_CUBIC and EASE_OUT_CUBIC
670+ */
671+ EASE_IN_OUT_CUBIC,
672+
673+ /**
674+ * quartic tweening
675+ */
676+ EASE_IN_QUART,
677+ /**
678+ * quartic tweening, inverse of EASE_IN_QUART
679+ */
680+ EASE_OUT_QUART,
681+ /**
682+ * quartic tweening, combining EASE_IN_QUART and EASE_OUT_QUART
683+ */
684+ EASE_IN_OUT_QUART,
685+
686+ /**
687+ * quintic tweening
688+ */
689+ EASE_IN_QUINT,
690+ /**
691+ * quintic tweening, inverse of EASE_IN_QUINT
692+ */
693+ EASE_OUT_QUINT,
694+ /**
695+ * fifth power tweening, combining EASE_IN_QUINT and EASE_OUT_QUINT
696+ */
697+ EASE_IN_OUT_QUINT,
698+
699+ /**
700+ * sinusoidal tweening
701+ */
702+ EASE_IN_SINE,
703+ /**
704+ * sinusoidal tweening, inverse of EASE_IN_SINE
705+ */
706+ EASE_OUT_SINE,
707+ /**
708+ * sine wave tweening, combining EASE_IN_SINE and EASE_OUT_SINE
709+ */
710+ EASE_IN_OUT_SINE,
711+
712+ /**
713+ * exponential tweening
714+ */
715+ EASE_IN_EXPO,
716+ /**
717+ * exponential tweening, inverse of EASE_IN_EXPO
718+ */
719+ EASE_OUT_EXPO,
720+ /**
721+ * exponential tweening, combining EASE_IN_EXPO and EASE_OUT_EXPO
722+ */
723+ EASE_IN_OUT_EXPO,
724+
725+ /**
726+ * circular tweening
727+ */
728+ EASE_IN_CIRC,
729+ /**
730+ * circular tweening, inverse of EASE_IN_CIRC
731+ */
732+ EASE_OUT_CIRC,
733+ /**
734+ * circular tweening, combining EASE_IN_CIRC and EASE_OUT_CIRC
735+ */
736+ EASE_IN_OUT_CIRC,
737+
738+ /**
739+ * elastic tweening, with offshoot on start
740+ */
741+ EASE_IN_ELASTIC,
742+ /**
743+ * elastic tweening, with offshoot on end
744+ */
745+ EASE_OUT_ELASTIC,
746+ /**
747+ * elastic tweening with offshoot on both ends
748+ */
749+ EASE_IN_OUT_ELASTIC,
750+
751+ /**
752+ * overshooting cubic tweening, with backtracking on start
753+ */
754+ EASE_IN_BACK,
755+ /**
756+ * overshooting cubic tweening, with backtracking on end
757+ */
758+ EASE_OUT_BACK,
759+ /**
760+ * overshooting cubic tweening, with backtracking on both ends
761+ */
762+ EASE_IN_OUT_BACK,
763+
764+ /**
765+ * exponentially decaying parabolic (bounce) tweening, with bounce on start
766+ */
767+ EASE_IN_BOUNCE,
768+ /**
769+ * exponentially decaying parabolic (bounce) tweening, with bounce on end
770+ */
771+ EASE_OUT_BOUNCE,
772+ /**
773+ * exponentially decaying parabolic (bounce) tweening, with bounce on both ends
774+ */
775+ EASE_IN_OUT_BOUNCE,
776+
777+ /* guard, before registered alpha functions */
778+ LAST
779+ }
780+
781+ /**
782+ * Internal type for the easing functions.
783+ *
784+ * @param t elapsed time
785+ * @param d total duration
786+ * @return the interpolated value, between -1.0 and 2.0
787+ */
788+ [CCode (has_target = false)]
789+ delegate double EasingFunc (double t, double d);
790+
791+ struct AnimationModeMapping
792+ {
793+ AnimationMode mode;
794+ EasingFunc func;
795+ string name;
796+ }
797+
798+ const AnimationModeMapping[] animation_modes = {
799+ { AnimationMode.CUSTOM, null, "custom" },
800+
801+ { AnimationMode.LINEAR, linear, "linear" },
802+ { AnimationMode.EASE_IN_QUAD, ease_in_quad, "easeInQuad" },
803+ { AnimationMode.EASE_OUT_QUAD, ease_out_quad, "easeOutQuad" },
804+ { AnimationMode.EASE_IN_OUT_QUAD, ease_in_out_quad, "easeInOutQuad" },
805+ { AnimationMode.EASE_IN_CUBIC, ease_in_cubic, "easeInCubic" },
806+ { AnimationMode.EASE_OUT_CUBIC, ease_out_cubic, "easeOutCubic" },
807+ { AnimationMode.EASE_IN_OUT_CUBIC, ease_in_out_cubic, "easeInOutCubic" },
808+ { AnimationMode.EASE_IN_QUART, ease_in_quart, "easeInQuart" },
809+ { AnimationMode.EASE_OUT_QUART, ease_out_quart, "easeOutQuart" },
810+ { AnimationMode.EASE_IN_OUT_QUART, ease_in_out_quart, "easeInOutQuart" },
811+ { AnimationMode.EASE_IN_QUINT, ease_in_quint, "easeInQuint" },
812+ { AnimationMode.EASE_OUT_QUINT, ease_out_quint, "easeOutQuint" },
813+ { AnimationMode.EASE_IN_OUT_QUINT, ease_in_out_quint, "easeInOutQuint" },
814+ { AnimationMode.EASE_IN_SINE, ease_in_sine, "easeInSine" },
815+ { AnimationMode.EASE_OUT_SINE, ease_out_sine, "easeOutSine" },
816+ { AnimationMode.EASE_IN_OUT_SINE, ease_in_out_sine, "easeInOutSine" },
817+ { AnimationMode.EASE_IN_EXPO, ease_in_expo, "easeInExpo" },
818+ { AnimationMode.EASE_OUT_EXPO, ease_out_expo, "easeOutExpo" },
819+ { AnimationMode.EASE_IN_OUT_EXPO, ease_in_out_expo, "easeInOutExpo" },
820+ { AnimationMode.EASE_IN_CIRC, ease_in_circ, "easeInCirc" },
821+ { AnimationMode.EASE_OUT_CIRC, ease_out_circ, "easeOutCirc" },
822+ { AnimationMode.EASE_IN_OUT_CIRC, ease_in_out_circ, "easeInOutCirc" },
823+ { AnimationMode.EASE_IN_ELASTIC, ease_in_elastic, "easeInElastic" },
824+ { AnimationMode.EASE_OUT_ELASTIC, ease_out_elastic, "easeOutElastic" },
825+ { AnimationMode.EASE_IN_OUT_ELASTIC, ease_in_out_elastic, "easeInOutElastic" },
826+ { AnimationMode.EASE_IN_BACK, ease_in_back, "easeInBack" },
827+ { AnimationMode.EASE_OUT_BACK, ease_out_back, "easeOutBack" },
828+ { AnimationMode.EASE_IN_OUT_BACK, ease_in_out_back, "easeInOutBack" },
829+ { AnimationMode.EASE_IN_BOUNCE, ease_in_bounce, "easeInBounce" },
830+ { AnimationMode.EASE_OUT_BOUNCE, ease_out_bounce, "easeOutBounce" },
831+ { AnimationMode.EASE_IN_OUT_BOUNCE, ease_in_out_bounce, "easeInOutBounce" },
832+
833+ { AnimationMode.LAST, null, "sentinel" }
834+ };
835+
836+ EasingFunc easing_func_for_mode (AnimationMode mode)
837+ {
838+ assert (animation_modes[mode].mode == mode);
839+ assert (animation_modes[mode].func != null);
840+
841+ return animation_modes[mode].func;
842+ }
843+
844+ unowned string easing_name_for_mode (AnimationMode mode)
845+ {
846+ assert (animation_modes[mode].mode == mode);
847+ assert (animation_modes[mode].func != null);
848+
849+ return animation_modes[mode].name;
850+ }
851+
852+ public double easing_for_mode (AnimationMode mode, double t, double d)
853+ {
854+ assert (animation_modes[mode].mode == mode);
855+ assert (animation_modes[mode].func != null);
856+
857+ return animation_modes[mode].func (t, d);
858+ }
859+
860+ double linear (double t, double d)
861+ {
862+ return t / d;
863+ }
864+
865+ double ease_in_quad (double t, double d)
866+ {
867+ double p = t / d;
868+
869+ return p * p;
870+ }
871+
872+ double ease_out_quad (double t, double d)
873+ {
874+ double p = t / d;
875+
876+ return -1.0 * p * (p - 2);
877+ }
878+
879+ double ease_in_out_quad (double t, double d)
880+ {
881+ double p = t / (d / 2);
882+
883+ if (p < 1)
884+ return 0.5 * p * p;
885+
886+ p -= 1;
887+
888+ return -0.5 * (p * (p - 2) - 1);
889+ }
890+
891+ double ease_in_cubic (double t, double d)
892+ {
893+ double p = t / d;
894+
895+ return p * p * p;
896+ }
897+
898+ double ease_out_cubic (double t, double d)
899+ {
900+ double p = t / d - 1;
901+
902+ return p * p * p + 1;
903+ }
904+
905+ double ease_in_out_cubic (double t, double d)
906+ {
907+ double p = t / (d / 2);
908+
909+ if (p < 1)
910+ return 0.5 * p * p * p;
911+
912+ p -= 2;
913+
914+ return 0.5 * (p * p * p + 2);
915+ }
916+
917+ double ease_in_quart (double t, double d)
918+ {
919+ double p = t / d;
920+
921+ return p * p * p * p;
922+ }
923+
924+ double ease_out_quart (double t, double d)
925+ {
926+ double p = t / d - 1;
927+
928+ return -1.0 * (p * p * p * p - 1);
929+ }
930+
931+ double ease_in_out_quart (double t, double d)
932+ {
933+ double p = t / (d / 2);
934+
935+ if (p < 1)
936+ return 0.5 * p * p * p * p;
937+
938+ p -= 2;
939+
940+ return -0.5 * (p * p * p * p - 2);
941+ }
942+
943+ double ease_in_quint (double t, double d)
944+ {
945+ double p = t / d;
946+
947+ return p * p * p * p * p;
948+ }
949+
950+ double ease_out_quint (double t, double d)
951+ {
952+ double p = t / d - 1;
953+
954+ return p * p * p * p * p + 1;
955+ }
956+
957+ double ease_in_out_quint (double t, double d)
958+ {
959+ double p = t / (d / 2);
960+
961+ if (p < 1)
962+ return 0.5 * p * p * p * p * p;
963+
964+ p -= 2;
965+
966+ return 0.5 * (p * p * p * p * p + 2);
967+ }
968+
969+ double ease_in_sine (double t, double d)
970+ {
971+ return -1.0 * Math.cos (t / d * Math.PI_2) + 1.0;
972+ }
973+
974+ double ease_out_sine (double t, double d)
975+ {
976+ return Math.sin (t / d * Math.PI_2);
977+ }
978+
979+ double ease_in_out_sine (double t, double d)
980+ {
981+ return -0.5 * (Math.cos (Math.PI * t / d) - 1);
982+ }
983+
984+ double ease_in_expo (double t, double d)
985+ {
986+ return (t == 0) ? 0.0 : Math.pow (2, 10 * (t / d - 1));
987+ }
988+
989+ double ease_out_expo (double t, double d)
990+ {
991+ return (t == d) ? 1.0 : -Math.pow (2, -10 * t / d) + 1;
992+ }
993+
994+ double ease_in_out_expo (double t, double d)
995+ {
996+ double p;
997+
998+ if (t == 0)
999+ return 0.0;
1000+
1001+ if (t == d)
1002+ return 1.0;
1003+
1004+ p = t / (d / 2);
1005+
1006+ if (p < 1)
1007+ return 0.5 * Math.pow (2, 10 * (p - 1));
1008+
1009+ p -= 1;
1010+
1011+ return 0.5 * (-Math.pow (2, -10 * p) + 2);
1012+ }
1013+
1014+ double ease_in_circ (double t, double d)
1015+ {
1016+ double p = t / d;
1017+
1018+ return -1.0 * (Math.sqrt (1 - p * p) - 1);
1019+ }
1020+
1021+ double ease_out_circ (double t, double d)
1022+ {
1023+ double p = t / d - 1;
1024+
1025+ return Math.sqrt (1 - p * p);
1026+ }
1027+
1028+ double ease_in_out_circ (double t, double d)
1029+ {
1030+ double p = t / (d / 2);
1031+
1032+ if (p < 1)
1033+ return -0.5 * (Math.sqrt (1 - p * p) - 1);
1034+
1035+ p -= 2;
1036+
1037+ return 0.5 * (Math.sqrt (1 - p * p) + 1);
1038+ }
1039+
1040+ double ease_in_elastic (double t, double d)
1041+ {
1042+ double p = d * 0.3;
1043+ double s = p / 4;
1044+ double q = t / d;
1045+
1046+ if (q == 1)
1047+ return 1.0;
1048+
1049+ q -= 1;
1050+
1051+ return -(Math.pow (2, 10 * q) * Math.sin ((q * d - s) * (2 * Math.PI) / p));
1052+ }
1053+
1054+ double ease_out_elastic (double t, double d)
1055+ {
1056+ double p = d * 0.3;
1057+ double s = p / 4;
1058+ double q = t / d;
1059+
1060+ if (q == 1)
1061+ return 1.0;
1062+
1063+ return Math.pow (2, -10 * q) * Math.sin ((q * d - s) * (2 * Math.PI) / p) + 1.0;
1064+ }
1065+
1066+ double ease_in_out_elastic (double t, double d)
1067+ {
1068+ double p = d * (0.3 * 1.5);
1069+ double s = p / 4;
1070+ double q = t / (d / 2);
1071+
1072+ if (q == 2)
1073+ return 1.0;
1074+
1075+ if (q < 1) {
1076+ q -= 1;
1077+
1078+ return -0.5 * (Math.pow (2, 10 * q) * Math.sin ((q * d - s) * (2 * Math.PI) / p));
1079+ } else {
1080+ q -= 1;
1081+
1082+ return Math.pow (2, -10 * q)
1083+ * Math.sin ((q * d - s) * (2 * Math.PI) / p)
1084+ * 0.5 + 1.0;
1085+ }
1086+ }
1087+
1088+ double ease_in_back (double t, double d)
1089+ {
1090+ double p = t / d;
1091+
1092+ return p * p * ((1.70158 + 1) * p - 1.70158);
1093+ }
1094+
1095+ double ease_out_back (double t, double d)
1096+ {
1097+ double p = t / d - 1;
1098+
1099+ return p * p * ((1.70158 + 1) * p + 1.70158) + 1;
1100+ }
1101+
1102+ double ease_in_out_back (double t, double d)
1103+ {
1104+ double p = t / (d / 2);
1105+ double s = 1.70158 * 1.525;
1106+
1107+ if (p < 1)
1108+ return 0.5 * (p * p * ((s + 1) * p - s));
1109+
1110+ p -= 2;
1111+
1112+ return 0.5 * (p * p * ((s + 1) * p + s) + 2);
1113+ }
1114+
1115+ static inline double ease_out_bounce_internal (double t, double d)
1116+ {
1117+ double p = t / d;
1118+
1119+ if (p < (1 / 2.75)) {
1120+ return 7.5625 * p * p;
1121+ } else if (p < (2 / 2.75)) {
1122+ p -= (1.5 / 2.75);
1123+
1124+ return 7.5625 * p * p + 0.75;
1125+ } else if (p < (2.5 / 2.75)) {
1126+ p -= (2.25 / 2.75);
1127+
1128+ return 7.5625 * p * p + 0.9375;
1129+ } else {
1130+ p -= (2.625 / 2.75);
1131+
1132+ return 7.5625 * p * p + 0.984375;
1133+ }
1134+ }
1135+
1136+ static inline double ease_in_bounce_internal (double t, double d)
1137+ {
1138+ return 1.0 - ease_out_bounce_internal (d - t, d);
1139+ }
1140+
1141+ double ease_in_bounce (double t, double d)
1142+ {
1143+ return ease_in_bounce_internal (t, d);
1144+ }
1145+
1146+ double ease_out_bounce (double t, double d)
1147+ {
1148+ return ease_out_bounce_internal (t, d);
1149+ }
1150+
1151+ double ease_in_out_bounce (double t, double d)
1152+ {
1153+ if (t < d / 2)
1154+ return ease_in_bounce_internal (t * 2, d) * 0.5;
1155+ else
1156+ return ease_out_bounce_internal (t * 2 - d, d) * 0.5 + 1.0 * 0.5;
1157+ }
1158+}
1159
1160=== modified file 'lib/Items/DockItem.vala'
1161--- lib/Items/DockItem.vala 2014-11-19 14:06:10 +0000
1162+++ lib/Items/DockItem.vala 2015-01-26 20:17:08 +0000
1163@@ -396,14 +396,12 @@
1164 */
1165 protected virtual void draw_icon (DockSurface surface)
1166 {
1167- double x_scale = 1.0, y_scale = 1.0;
1168-#if HAVE_HIDPI
1169- cairo_surface_get_device_scale (surface.Internal, out x_scale, out y_scale);
1170-#endif
1171 Cairo.Surface? icon = null;
1172 Gdk.Pixbuf? pbuf = ForcePixbuf;
1173 if (pbuf == null) {
1174 #if HAVE_HIDPI
1175+ double x_scale = 1.0, y_scale = 1.0;
1176+ cairo_surface_get_device_scale (surface.Internal, out x_scale, out y_scale);
1177 icon = DrawingService.load_icon_for_scale (Icon, surface.Width, surface.Height, (int) double.max (x_scale, y_scale));
1178 if (icon != null)
1179 cairo_surface_set_device_scale (icon, 1.0, 1.0);
1180
1181=== modified file 'lib/Makefile.am'
1182--- lib/Makefile.am 2015-01-06 12:58:35 +0000
1183+++ lib/Makefile.am 2015-01-26 20:17:08 +0000
1184@@ -72,6 +72,7 @@
1185 Drawing/DrawingService.vala \
1186 Drawing/DockSurface.vala \
1187 Drawing/DockTheme.vala \
1188+ Drawing/Easing.vala \
1189 Drawing/Theme.vala \
1190 Factories/AbstractMain.vala \
1191 Factories/Factory.vala \
1192
1193=== modified file 'lib/libplank.symbols'
1194--- lib/libplank.symbols 2015-01-18 16:49:22 +0000
1195+++ lib/libplank.symbols 2015-01-26 20:17:08 +0000
1196@@ -82,6 +82,7 @@
1197 plank_drawing_animated_renderer_construct
1198 plank_drawing_animated_renderer_get_type
1199 plank_drawing_animated_renderer_get_widget
1200+plank_drawing_animation_mode_get_type
1201 plank_drawing_color_add_hue
1202 plank_drawing_color_brighten_val
1203 plank_drawing_color_darken_by_sat
1204@@ -185,6 +186,7 @@
1205 plank_drawing_drawing_service_load_icon
1206 plank_drawing_drawing_service_load_icon_for_scale
1207 plank_drawing_drawing_service_try_get_icon_file
1208+plank_drawing_easing_for_mode
1209 plank_drawing_theme_construct
1210 plank_drawing_theme_construct_with_name
1211 plank_drawing_theme_draw_background

Subscribers

People subscribed via source and target branches

to status/vote changes: