Merge lp:~mterry/unity-greeter/animation-fixes into lp:unity-greeter

Proposed by Michael Terry
Status: Merged
Merged at revision: 352
Proposed branch: lp:~mterry/unity-greeter/animation-fixes
Merge into: lp:unity-greeter
Prerequisite: lp:~mterry/unity-greeter/responsiveness-fixes
Diff against target: 612 lines (+181/-180)
9 files modified
src/Makefile.am (+1/-0)
src/animate-timer.vala (+30/-119)
src/background.vala (+2/-1)
src/cached-image.vala (+56/-0)
src/dash-button.vala (+12/-3)
src/fadable.vala (+1/-1)
src/main-window.vala (+6/-5)
src/session-chooser.vala (+1/-1)
src/user-list.vala (+72/-50)
To merge this branch: bzr merge lp:~mterry/unity-greeter/animation-fixes
Reviewer Review Type Date Requested Status
Ken VanDine Approve
Unity Greeter Development Team Pending
Review via email: mp+97233@code.launchpad.net

Description of the change

In conjunction with design, some further easing tweaks (different algorithm for scrolling and different duration times).

To post a comment you must log in.
Revision history for this message
Ken VanDine (ken-vandine) wrote :

Looks good to me and with the minimal testing I did, it functions well.

My only comment is the old code that was removed included some really great comments describing how the animations are calculated. It would be nice to have similar comments describing the current calculations. Certainly not a blocker, but the previous code comments seemed like excellent documentation of the logic used.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2012-02-21 17:31:59 +0000
+++ src/Makefile.am 2012-03-13 14:51:31 +0000
@@ -8,6 +8,7 @@
8 indicator.vapi \8 indicator.vapi \
9 animate-timer.vala \9 animate-timer.vala \
10 background.vala \10 background.vala \
11 cached-image.vala \
11 dash-box.vala \12 dash-box.vala \
12 dash-button.vala \13 dash-button.vala \
13 dash-entry.vala \14 dash-entry.vala \
1415
=== modified file 'src/animate-timer.vala'
--- src/animate-timer.vala 2012-02-21 17:31:59 +0000
+++ src/animate-timer.vala 2012-03-13 14:51:31 +0000
@@ -20,6 +20,9 @@
2020
21private class AnimateTimer : Object21private class AnimateTimer : Object
22{22{
23 /* x and y are 0.0 to 1.0 */
24 public delegate double EasingFunc (double x);
25
23 /* The following are the same intervals that Unity uses */26 /* The following are the same intervals that Unity uses */
24 public static const int INSTANT = 150; /* Good for animations that don't convey any information */27 public static const int INSTANT = 150; /* Good for animations that don't convey any information */
25 public static const int FAST = 250; /* Good for animations that convey duplicated information */28 public static const int FAST = 250; /* Good for animations that convey duplicated information */
@@ -27,6 +30,7 @@
27 public static const int SLOW = 1000; /* Good for animations that convey information that is only presented in the animation */30 public static const int SLOW = 1000; /* Good for animations that convey information that is only presented in the animation */
2831
29 /* speed is in milliseconds */32 /* speed is in milliseconds */
33 public unowned EasingFunc easing_func {get; private set;}
30 public int speed {get; set;}34 public int speed {get; set;}
31 public bool is_running { get { return timeout != 0; } }35 public bool is_running { get { return timeout != 0; } }
32 public double progress {get; private set;}36 public double progress {get; private set;}
@@ -35,9 +39,10 @@
35 public signal void animate (double progress);39 public signal void animate (double progress);
3640
37 /* speed is in milliseconds */41 /* speed is in milliseconds */
38 public AnimateTimer (int speed)42 public AnimateTimer (EasingFunc func, int speed)
39 {43 {
40 Object (speed: speed);44 Object (speed: speed);
45 this.easing_func = func;
41 }46 }
4247
43 /* temp_speed is in milliseconds */48 /* temp_speed is in milliseconds */
@@ -57,38 +62,6 @@
57 length = temp_speed * TimeSpan.MILLISECOND;62 length = temp_speed * TimeSpan.MILLISECOND;
58 }63 }
5964
60 /* This tells us the consumer of our progress reports is changing the
61 goalposts on us. So we need to adjust our reports accordingly.
62 'extra_progress' is how much progress is being added to the animation.
63 */
64 public bool extend (double new_progress)
65 {
66 /* As an example, say a consumer is animating from point A to point C in
67 150ms. This is two points to cover, and at 75ms, they will be 0.5 done.
68
69 Now, they extend it to point D. This adds an extra point, which is half
70 the original progress. So now they call extend (0.5).
71
72 We extend in the middle, so we need the slope at halfway through our
73 progress function. That is a constant we have (see calculate_progress
74 for details). So we'd need to add the same amount of normalized time
75 to our process as progress, which is 0.5 / HALFWAY_VELOCITY = 0.318 in
76 this example. Which is (length * 0.318) = 47.7ms more time to add.
77
78 Now we have 197.7ms as length of our animation. Which changes the
79 progress values we give out. We further need to adjust our progress
80 function to take this 'pause' in the middle of the function into
81 account.
82 */
83
84 if (progress > HALFWAY_PROGRESS)
85 return false;
86
87 extra_progress += new_progress;
88 extra_time = (TimeSpan)(length * extra_progress / HALFWAY_VELOCITY);
89 return true;
90 }
91
92 public void stop ()65 public void stop ()
93 {66 {
94 if (timeout != 0)67 if (timeout != 0)
@@ -102,13 +75,6 @@
102 private TimeSpan extra_time = 0;75 private TimeSpan extra_time = 0;
103 private double extra_progress = 0.0;76 private double extra_progress = 0.0;
10477
105 /* Derivative of our easing function at 0.5 (the halfway point).
106 See calculate_progress() for functions. */
107 private static const double HALFWAY_VELOCITY = 1.5708;
108
109 /* The y value of our easing function at 0.5 (the halway point) */
110 private static const double HALFWAY_PROGRESS = 0.75;
111
112 private bool animate_cb ()78 private bool animate_cb ()
113 {79 {
114 if (start_time == 0)80 if (start_time == 0)
@@ -129,94 +95,39 @@
129 /* Returns 0.0 to 1.0 where 1.0 is at or past end_time */95 /* Returns 0.0 to 1.0 where 1.0 is at or past end_time */
130 private double normalize_time (TimeSpan now)96 private double normalize_time (TimeSpan now)
131 {97 {
132 var total = length;98 return (((double)(now - start_time)) / length).clamp (0.0, 1.0);
133 var halfway = start_time + length / 2;
134 if (now > halfway)
135 now -= extra_time;
136
137 return (((double)(now - start_time)) / total).clamp (0.0, 1.0);
138 }
139
140 /* Incoming progress count is original, un-extra-time enhanced progress */
141 private double normalize_progress (double p)
142 {
143 /* So without extra time, progress goes from 0.0 to 1.0. But with
144 extra time, the beginning and end want to keep the same function,
145 just squeezed into a smaller place in the graph. So we figure out
146 that mapping here. */
147 var extra_mapped = extra_progress / (1.0 + extra_progress);
148 var half_mapped = HALFWAY_PROGRESS / (1.0 + extra_progress);
149 if (p < HALFWAY_PROGRESS)
150 return p * (half_mapped / HALFWAY_PROGRESS);
151 else
152 {
153 var end = 1.0 - half_mapped - extra_mapped;
154 return (p - HALFWAY_PROGRESS) * (end / (1 - HALFWAY_PROGRESS)) + half_mapped + extra_mapped;
155 }
156 }99 }
157100
158 /* Returns 0.0 to 1.0 where 1.0 is done.101 /* Returns 0.0 to 1.0 where 1.0 is done.
159 time is not normalized yet! */102 time is not normalized yet! */
160 private double calculate_progress (TimeSpan time)103 private double calculate_progress (TimeSpan time)
161 {104 {
162 /* Use a sine wave function similar to what Unity uses. They call it105 var x = normalize_time (time);
163 'easing' and is designed to make the animation start and end slower106 var y = easing_func (x);
164 than in the middle.
165
166 ((1 - Math.cos (Math.PI * time)) / 2) is the basic sine curve for
167 easing, used by Unity and others. By squaring that and reversing
168 the curve (by using 1 - x and 1 - y), we get a more exaggerated
169 slowdown.
170
171 For clarity, here is the whole function:
172 y = 1 - ((1 - cos (pi * (1 - x))) / 2) ^ 2
173
174 Here is the derivative of that function (useful for calculating
175 slope at a given point, used elsewhere in this class):
176 y = (pi * (cos (pi * (x - 1)) - 1)) * sin (pi * (x - 1)) / 2
177
178 */
179
180 /* But due to the ability to add extra time into the equation, we
181 are actually three functions:
182 1) x=[0,A) = normal
183 2) x=[A,B] = halfway slope
184 3) x=(B,1.0] = picks up where first function left off */
185
186 var y = 0.0;
187 var orig_half_point = start_time + length / 2;
188
189 if (time > start_time + length + extra_time)
190 {
191 y = 1.0;
192 }
193 else if (time < orig_half_point)
194 {
195 var x = normalize_time (time);
196 y = easing_function (x);
197 y = normalize_progress (y);
198 }
199 else if (time < orig_half_point + extra_time)
200 {
201 var xpercent = (time - orig_half_point) / (double)extra_time;
202 y = (xpercent * extra_progress + HALFWAY_PROGRESS) / (1.0 + extra_progress);
203 }
204 else
205 {
206 var x = normalize_time (time);
207 y = easing_function (x);
208 y = normalize_progress (y);
209 }
210
211 return y.clamp (0.0, 1.0);107 return y.clamp (0.0, 1.0);
212 }108 }
213109
214 private double easing_function (double x)110 public static double ease_in_out (double x)
215 {111 {
216 var y = (1 - Math.cos (Math.PI * (1.0 - x))) / 2;112 return (1 - Math.cos (Math.PI * x)) / 2;
217 y = y * y;113 }
218 y = 1.0 - y;114
219 return y;115 /*public static double ease_in_quad (double x)
116 {
117 return Math.pow (x, 2);
118 }*/
119 /*public static double ease_out_quad (double x)
120 {
121 return -1 * Math.pow (x - 1, 2) + 1;
122 }*/
123
124 /*public static double ease_in_quint (double x)
125 {
126 return Math.pow (x, 5);
127 }*/
128 public static double ease_out_quint (double x)
129 {
130 return Math.pow (x - 1, 5) + 1;
220 }131 }
221}132}
222133
223134
=== modified file 'src/background.vala'
--- src/background.vala 2012-02-21 22:36:02 +0000
+++ src/background.vala 2012-03-13 14:51:31 +0000
@@ -247,7 +247,7 @@
247 public Background (Cairo.Surface target_surface)247 public Background (Cairo.Surface target_surface)
248 {248 {
249 this.target_surface = target_surface;249 this.target_surface = target_surface;
250 timer = new AnimateTimer (AnimateTimer.INSTANT);250 timer = new AnimateTimer (AnimateTimer.ease_in_out, 700);
251 timer.animate.connect (animate_cb);251 timer.animate.connect (animate_cb);
252252
253 loaders = new HashTable<string?, BackgroundLoader> (str_hash, str_equal);253 loaders = new HashTable<string?, BackgroundLoader> (str_hash, str_equal);
@@ -426,6 +426,7 @@
426 {426 {
427 old = current;427 old = current;
428 current = new_background;428 current = new_background;
429 timer.stop ();
429 }430 }
430431
431 queue_draw ();432 queue_draw ();
432433
=== added file 'src/cached-image.vala'
--- src/cached-image.vala 1970-01-01 00:00:00 +0000
+++ src/cached-image.vala 2012-03-13 14:51:31 +0000
@@ -0,0 +1,56 @@
1/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
2 *
3 * Copyright (C) 2012 Canonical Ltd
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Authors: Michael Terry <michael.terry@canonical.com>
18 */
19
20public class CachedImage : Gtk.Image
21{
22 private static HashTable<Gdk.Pixbuf, Cairo.Surface> surface_table;
23
24 public static Cairo.Surface? get_cached_surface (Cairo.Context c, Gdk.Pixbuf pixbuf)
25 {
26 if (surface_table == null)
27 surface_table = new HashTable<Gdk.Pixbuf, Cairo.Surface> (direct_hash, direct_equal);
28
29 var surface = surface_table.lookup (pixbuf);
30 if (surface == null)
31 {
32 surface = new Cairo.Surface.similar (c.get_target (), Cairo.Content.COLOR_ALPHA, pixbuf.width, pixbuf.height);
33 var new_c = new Cairo.Context (surface);
34 Gdk.cairo_set_source_pixbuf (new_c, pixbuf, 0, 0);
35 new_c.paint ();
36 surface_table.insert (pixbuf, surface);
37 }
38 return surface;
39 }
40
41 public CachedImage (Gdk.Pixbuf? pixbuf)
42 {
43 Object (pixbuf: pixbuf);
44 }
45
46 public override bool draw (Cairo.Context c)
47 {
48 var cached_surface = get_cached_surface (c, pixbuf);
49 if (cached_surface != null)
50 {
51 c.set_source_surface (cached_surface, 0, 0);
52 c.paint ();
53 }
54 return false;
55 }
56}
057
=== modified file 'src/dash-button.vala'
--- src/dash-button.vala 2012-03-09 05:12:16 +0000
+++ src/dash-button.vala 2012-03-13 14:51:31 +0000
@@ -54,9 +54,18 @@
54 this.text = text;54 this.text = text;
5555
56 // add chevron56 // add chevron
57 var image = new Gtk.Image.from_file (Path.build_filename (Config.PKGDATADIR, "arrow_right.png", null));57 var path = Path.build_filename (Config.PKGDATADIR, "arrow_right.png", null);
58 sizes.add_widget (image);58 try
59 hbox.add (image);59 {
60 var pixbuf = new Gdk.Pixbuf.from_file (path);
61 var image = new CachedImage (pixbuf);
62 sizes.add_widget (image);
63 hbox.add (image);
64 }
65 catch (Error e)
66 {
67 debug ("Error loading image %s: %s", path, e.message);
68 }
6069
61 hbox.show_all ();70 hbox.show_all ();
62 add (hbox);71 add (hbox);
6372
=== modified file 'src/fadable.vala'
--- src/fadable.vala 2012-02-21 17:31:59 +0000
+++ src/fadable.vala 2012-03-13 14:51:31 +0000
@@ -48,7 +48,7 @@
4848
49 construct49 construct
50 {50 {
51 timer = new AnimateTimer (AnimateTimer.INSTANT);51 timer = new AnimateTimer (AnimateTimer.ease_out_quint, AnimateTimer.INSTANT);
52 timer.animate.connect (animate_cb);52 timer.animate.connect (animate_cb);
53 }53 }
5454
5555
=== modified file 'src/main-window.vala'
--- src/main-window.vala 2012-03-09 05:00:29 +0000
+++ src/main-window.vala 2012-03-13 14:51:31 +0000
@@ -64,7 +64,10 @@
6464
65 user_list = new UserList (background, menubar);65 user_list = new UserList (background, menubar);
66 user_list.expand = true;66 user_list.expand = true;
67 user_list.user_displayed.connect (() => {67 user_list.user_displayed_start.connect (() => {
68 change_background ();
69 });
70 user_list.user_displayed_done.connect (() => {
68 menubar.set_layouts (user_list.selected_entry.keyboard_layouts);71 menubar.set_layouts (user_list.selected_entry.keyboard_layouts);
69 change_background ();72 change_background ();
70 });73 });
@@ -145,12 +148,10 @@
145148
146 private void change_background ()149 private void change_background ()
147 {150 {
148 /* Set background after user stops scrolling */
149 if (background.current_background != null)151 if (background.current_background != null)
150 {152 {
151 if (change_background_timeout != 0)153 if (change_background_timeout == 0)
152 Source.remove (change_background_timeout);154 change_background_timeout = Idle.add (change_background_timeout_cb);
153 change_background_timeout = Timeout.add (200, change_background_timeout_cb);
154 }155 }
155 else156 else
156 change_background_timeout_cb ();157 change_background_timeout_cb ();
157158
=== modified file 'src/session-chooser.vala'
--- src/session-chooser.vala 2012-02-23 14:46:37 +0000
+++ src/session-chooser.vala 2012-03-13 14:51:31 +0000
@@ -80,7 +80,7 @@
80 var pixbuf = get_badge (key);80 var pixbuf = get_badge (key);
81 if (pixbuf != null)81 if (pixbuf != null)
82 {82 {
83 var image = new Gtk.Image.from_pixbuf (pixbuf);83 var image = new CachedImage (pixbuf);
84 hbox.pack_start (image, false, false, 0);84 hbox.pack_start (image, false, false, 0);
85 }85 }
8686
8787
=== modified file 'src/user-list.vala'
--- src/user-list.vala 2012-03-13 13:47:33 +0000
+++ src/user-list.vala 2012-03-13 14:51:31 +0000
@@ -45,6 +45,10 @@
4545
46 /* Default session for this user */46 /* Default session for this user */
47 public string session;47 public string session;
48
49 /* Cached cairo surfaces */
50 public Cairo.Surface label_in_box_surface;
51 public Cairo.Surface label_out_of_box_surface;
48}52}
4953
50private class AuthenticationMessage54private class AuthenticationMessage
@@ -113,7 +117,7 @@
113 private DashButton login_button;117 private DashButton login_button;
114 private Fadable prompt_widget_to_show;118 private Fadable prompt_widget_to_show;
115 private Gtk.Button session_button;119 private Gtk.Button session_button;
116 private Gtk.Image session_image;120 private CachedImage session_image;
117 private SessionChooser session_chooser;121 private SessionChooser session_chooser;
118 122
119 private enum Mode123 private enum Mode
@@ -153,7 +157,8 @@
153 }157 }
154158
155 public signal void user_selected (string? username);159 public signal void user_selected (string? username);
156 public signal void user_displayed ();160 public signal void user_displayed_start ();
161 public signal void user_displayed_done ();
157 public signal void respond_to_prompt (string text);162 public signal void respond_to_prompt (string text);
158 public signal void start_session ();163 public signal void start_session ();
159164
@@ -235,7 +240,7 @@
235 session_button = new Gtk.Button ();240 session_button = new Gtk.Button ();
236 session_button.focus_on_click = false;241 session_button.focus_on_click = false;
237 session_button.get_accessible ().set_name (_("Session Options"));242 session_button.get_accessible ().set_name (_("Session Options"));
238 session_image = new Gtk.Image.from_pixbuf (get_badge ());243 session_image = new CachedImage (get_badge ());
239 session_image.show ();244 session_image.show ();
240 session_button.relief = Gtk.ReliefStyle.NONE;245 session_button.relief = Gtk.ReliefStyle.NONE;
241 session_button.add (session_image);246 session_button.add (session_image);
@@ -243,7 +248,7 @@
243 session_button.show ();248 session_button.show ();
244 add_with_class (session_button);249 add_with_class (session_button);
245250
246 scroll_timer = new AnimateTimer (AnimateTimer.FAST);251 scroll_timer = new AnimateTimer (AnimateTimer.ease_out_quint, AnimateTimer.FAST);
247 scroll_timer.animate.connect (scroll_animate_cb);252 scroll_timer.animate.connect (scroll_animate_cb);
248 }253 }
249254
@@ -659,6 +664,7 @@
659 {664 {
660 prompt_widget_to_show.fade_in ();665 prompt_widget_to_show.fade_in ();
661 prompt_widget_to_show = null;666 prompt_widget_to_show = null;
667 user_displayed_start ();
662 }668 }
663669
664 /* Stop when we get there */670 /* Stop when we get there */
@@ -669,7 +675,7 @@
669 private void finished_scrolling ()675 private void finished_scrolling ()
670 {676 {
671 session_button.show ();677 session_button.show ();
672 user_displayed ();678 user_displayed_done ();
673 mode = Mode.LOGIN;679 mode = Mode.LOGIN;
674 }680 }
675681
@@ -687,27 +693,15 @@
687693
688 if (scroll_target_location != entries.index (entry))694 if (scroll_target_location != entries.index (entry))
689 {695 {
690 var old_target = scroll_target_location;
691 var new_target = entries.index (entry);696 var new_target = entries.index (entry);
692 var new_direction = direction;697 var new_direction = direction;
693 var new_start = (mode == Mode.SCROLLING) ? scroll_start_location : scroll_location;698 var new_start = scroll_location;
694
695 if (mode == Mode.SCROLLING && scroll_direction != new_direction)
696 return; /* ignore requests when we're already scrolling the opposite way */
697699
698 if (scroll_location != new_target)700 if (scroll_location != new_target)
699 {701 {
700 var new_distance = new_direction * (new_target - new_start);702 var new_distance = new_direction * (new_target - new_start);
701 if (mode == Mode.SCROLLING)703 // Base rate is 350 (250 + 100). If we find ourselves going further, slow down animation
702 {704 scroll_timer.reset (250 + int.min((int)(100 * (new_distance)), 500));
703 var old_distance = new_direction * (old_target - new_start);
704 if (!scroll_timer.extend ((new_distance - old_distance) / old_distance))
705 return;
706 }
707 else if (new_distance > 1)
708 scroll_timer.reset (600);
709 else
710 scroll_timer.reset (400);
711705
712 if (prompt_entry.visible)706 if (prompt_entry.visible)
713 prompt_widget_to_show = prompt_entry;707 prompt_widget_to_show = prompt_entry;
@@ -733,7 +727,7 @@
733 user_selected (selected_entry.name);727 user_selected (selected_entry.name);
734728
735 if (mode == Mode.LOGIN)729 if (mode == Mode.LOGIN)
736 user_displayed (); /* didn't need to move, make sure we trigger side effects */730 user_displayed_done (); /* didn't need to move, make sure we trigger side effects */
737 }731 }
738 }732 }
739 733
@@ -828,6 +822,47 @@
828 session_button.size_allocate (child_allocation);822 session_button.size_allocate (child_allocation);
829 }823 }
830824
825 private Cairo.Surface entry_ensure_label_surface (UserEntry entry, Cairo.Context orig_c, bool in_box)
826 {
827 if (in_box && entry.label_in_box_surface != null)
828 return entry.label_in_box_surface;
829 else if (!in_box && entry.label_out_of_box_surface != null)
830 return entry.label_out_of_box_surface;
831
832 int w, h;
833 entry.layout.get_pixel_size (out w, out h);
834
835 var bw = (box_width - (in_box ? 1.5 : 0.5)) * grid_size;
836
837 var surface = new Cairo.Surface.similar (orig_c.get_target (), Cairo.Content.COLOR_ALPHA, (int)(bw+1), h);
838 var c = new Cairo.Context (surface);
839
840 if (w > bw)
841 {
842 var mask = new Cairo.Pattern.linear (0, 0, bw, 0);
843 if (in_box)
844 {
845 mask.add_color_stop_rgba (1.0 - 27.0 / bw, 1.0, 1.0, 1.0, 1.0);
846 mask.add_color_stop_rgba (1.0 - 21.6 / bw, 1.0, 1.0, 1.0, 0.5);
847 }
848 else
849 mask.add_color_stop_rgba (1.0 - 64.0 / bw, 1.0, 1.0, 1.0, 1.0);
850 mask.add_color_stop_rgba (1.0, 1.0, 1.0, 1.0, 0.0);
851 c.set_source (mask);
852 }
853 else
854 c.set_source_rgba (1.0, 1.0, 1.0, 1.0);
855
856 Pango.cairo_show_layout (c, entry.layout);
857
858 if (in_box)
859 entry.label_in_box_surface = surface;
860 else
861 entry.label_out_of_box_surface = surface;
862
863 return surface;
864 }
865
831 private void draw_entry (Cairo.Context c, UserEntry entry, double alpha = 0.5, bool in_box = false, Gdk.Pixbuf? badge = null)866 private void draw_entry (Cairo.Context c, UserEntry entry, double alpha = 0.5, bool in_box = false, Gdk.Pixbuf? badge = null)
832 {867 {
833 c.save ();868 c.save ();
@@ -848,32 +883,18 @@
848 int w, h;883 int w, h;
849 entry.layout.get_pixel_size (out w, out h);884 entry.layout.get_pixel_size (out w, out h);
850885
851 /* Trim label if too wide */886 var label_x = grid_size / 2;
852 var bw = (box_width - (in_box ? 1.1 : 0.5)) * grid_size;887 var label_y = (grid_size - h) / 2 + border;
853 if (w > bw)888 var label_surface = entry_ensure_label_surface (entry, c, in_box);
854 {889 c.set_source_surface (label_surface, label_x, label_y);
855 var mask = new Cairo.Pattern.linear (0, 0, bw, 0);890 c.paint_with_alpha (alpha);
856 if (in_box)891
857 {892 var bw = (int) ((box_width - (in_box ? 1.5 : 0.5)) * grid_size);
858 mask.add_color_stop_rgba (1.0 - 27.0 / bw, 1.0, 1.0, 1.0, 1.0);893 if (entry.has_messages && (!in_box || label_x + w + 6 + message_pixbuf.get_width () < bw))
859 mask.add_color_stop_rgba (1.0 - 21.6 / bw, 1.0, 1.0, 1.0, 0.5);894 {
860 }895 c.translate (label_x + w + 6, label_y + (h - message_pixbuf.get_height ()) / 2);
861 else896 var surface = CachedImage.get_cached_surface (c, message_pixbuf);
862 mask.add_color_stop_rgba (1.0 - 64.0 / bw, 1.0, 1.0, 1.0, alpha);897 c.set_source_surface (surface, 0, 0);
863 mask.add_color_stop_rgba (1.0, 1.0, 1.0, 1.0, 0.0);
864 c.set_source (mask);
865 }
866 else
867 c.set_source_rgba (1.0, 1.0, 1.0, alpha);
868
869 c.translate (grid_size / 2, (grid_size - h) / 2 + border);
870 c.move_to (0, 0);
871 Pango.cairo_show_layout (c, entry.layout);
872
873 if (entry.has_messages && (!in_box || w + 6 + message_pixbuf.get_width () < bw))
874 {
875 c.translate (w + 6, (h - message_pixbuf.get_height ()) / 2);
876 Gdk.cairo_set_source_pixbuf (c, message_pixbuf, 0, 0);
877 c.paint_with_alpha (alpha);898 c.paint_with_alpha (alpha);
878 }899 }
879900
@@ -887,7 +908,8 @@
887 /* FIXME: The 18px offset here is because the visual assets changed size from 40px to 22px. It should be fixed properly somewhere... */908 /* FIXME: The 18px offset here is because the visual assets changed size from 40px to 22px. It should be fixed properly somewhere... */
888 var ypadding = (grid_size - badge.height) / 2 - 18;909 var ypadding = (grid_size - badge.height) / 2 - 18;
889 c.translate (box_width * grid_size - grid_size - grid_size / 4 + xpadding, grid_size / 4 - ypadding - border);910 c.translate (box_width * grid_size - grid_size - grid_size / 4 + xpadding, grid_size / 4 - ypadding - border);
890 Gdk.cairo_set_source_pixbuf (c, badge, 0, 0);911 var surface = CachedImage.get_cached_surface (c, badge);
912 c.set_source_surface (surface, 0, 0);
891 c.paint ();913 c.paint ();
892 c.restore ();914 c.restore ();
893 }915 }
@@ -954,7 +976,7 @@
954 var position = index - scroll_location;976 var position = index - scroll_location;
955977
956 /* Draw entries above the box */978 /* Draw entries above the box */
957 if (where == NameLocation.OUTSIDE_BOX && position < 0)979 if (where == NameLocation.OUTSIDE_BOX && position < 0 && position > -1 * (int)(n_above + 1))
958 {980 {
959 var h_above = (double) (n_above + 1) * grid_size;981 var h_above = (double) (n_above + 1) * grid_size;
960 c.save ();982 c.save ();
@@ -987,7 +1009,7 @@
987 }1009 }
9881010
989 /* Draw entries below the box */1011 /* Draw entries below the box */
990 if (where == NameLocation.OUTSIDE_BOX && position > 0)1012 if (where == NameLocation.OUTSIDE_BOX && position > 0 && position < n_below + 1)
991 {1013 {
992 var h_below = (double) (n_below + 1) * grid_size;1014 var h_below = (double) (n_below + 1) * grid_size;
993 c.save ();1015 c.save ();

Subscribers

People subscribed via source and target branches