Merge lp:~mterry/unity-greeter/look-and-feel into lp:unity-greeter

Proposed by Michael Terry
Status: Merged
Approved by: Robert Ancell
Approved revision: 267
Merged at revision: 266
Proposed branch: lp:~mterry/unity-greeter/look-and-feel
Merge into: lp:unity-greeter
Diff against target: 920 lines (+508/-118)
11 files modified
configure.ac (+3/-0)
src/Makefile.am (+6/-1)
src/animate-timer.vala (+149/-40)
src/background.vala (+1/-1)
src/config.vapi (+1/-0)
src/dash-button.vala (+37/-0)
src/dash-entry.vala (+70/-0)
src/fadable.vala (+85/-0)
src/menu.vala (+46/-0)
src/menubar.vala (+4/-17)
src/user-list.vala (+106/-59)
To merge this branch: bzr merge lp:~mterry/unity-greeter/look-and-feel
Reviewer Review Type Date Requested Status
Robert Ancell Approve
Review via email: mp+90203@code.launchpad.net

Description of the change

This gets us much closer to design's mockups. For ideal look, you'll need Cimi's theme changes (you can get both this branch and his theme changes in ppa:mterry/ppa2)

To post a comment you must log in.
265. By Michael Terry

don't reset easing when in the middle of a scroll and we continue the scroll with another key press

266. By Michael Terry

avoid drawing some labels twice; don't allow scrolling in opposite direction we are going right now; if we get request to scroll further, add to animation time instead of resetting it

267. By Michael Terry

merge indicator_path fixes

Revision history for this message
Robert Ancell (robert-ancell) :
review: Approve
268. By Michael Terry

make multiple arrow presses smoother by allowing UserList to extend the timer as it progresses

269. By Michael Terry

wait until animation is done to set keyboard layout

270. By Michael Terry

give more freedom to timeouts used; speed up scrolling animations

271. By Michael Terry

explain that speed of animate_timer is in ms

272. By Michael Terry

center name better with option button

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.ac'
2--- configure.ac 2012-01-19 03:55:57 +0000
3+++ configure.ac 2012-01-30 18:00:33 +0000
4@@ -26,6 +26,9 @@
5 cairo-ft
6 ])
7
8+INDICATORDIR=`$PKG_CONFIG --variable=indicatordir indicator3-0.4`
9+AC_SUBST(INDICATORDIR)
10+
11 dnl ###########################################################################
12 dnl Internationalization
13 dnl ###########################################################################
14
15=== modified file 'src/Makefile.am'
16--- src/Makefile.am 2012-01-14 16:24:09 +0000
17+++ src/Makefile.am 2012-01-30 18:00:33 +0000
18@@ -9,6 +9,10 @@
19 animate-timer.vala \
20 background.vala \
21 dash-box.vala \
22+ dash-button.vala \
23+ dash-entry.vala \
24+ fadable.vala \
25+ menu.vala \
26 menubar.vala \
27 settings-daemon.vala \
28 unity-greeter.vala \
29@@ -21,7 +25,8 @@
30 -DLOCALEDIR=\""$(localedir)"\" \
31 -DVERSION=\"$(VERSION)\" \
32 -DCONFIG_FILE=\""$(sysconfdir)/lightdm/unity-greeter.conf"\" \
33- -DPKGDATADIR=\""$(pkgdatadir)"\"
34+ -DPKGDATADIR=\""$(pkgdatadir)"\" \
35+ -DINDICATORDIR=\""$(INDICATORDIR)"\"
36
37 unity_greeter_VALAFLAGS = \
38 --pkg posix \
39
40=== modified file 'src/animate-timer.vala'
41--- src/animate-timer.vala 2012-01-11 13:15:05 +0000
42+++ src/animate-timer.vala 2012-01-30 18:00:33 +0000
43@@ -20,49 +20,72 @@
44
45 private class AnimateTimer : Object
46 {
47- public enum Speed
48- {
49- INSTANT, /* Good for animations that don't convey any information */
50- FAST, /* Good for animations that convey duplicated information (e.g. scrolling) */
51- NORMAL,
52- SLOW, /* Good for animations that convey information that is only presented in the animation */
53- }
54+ /* The following are the same intervals that Unity uses */
55+ public static const int INSTANT = 150; /* Good for animations that don't convey any information */
56+ public static const int FAST = 250; /* Good for animations that convey duplicated information */
57+ public static const int NORMAL = 500;
58+ public static const int SLOW = 1000; /* Good for animations that convey information that is only presented in the animation */
59
60- public Speed speed {get; construct;}
61+ /* speed is in milliseconds */
62+ public int speed {get; set;}
63 public bool is_running { get { return timeout != 0; } }
64+ public double progress {get; private set;}
65
66 /* progress is from 0.0 to 1.0 */
67 public signal void animate (double progress);
68
69- public AnimateTimer (Speed speed)
70+ /* speed is in milliseconds */
71+ public AnimateTimer (int speed)
72 {
73 Object (speed: speed);
74 }
75
76- public void reset ()
77+ /* temp_speed is in milliseconds */
78+ public void reset (int temp_speed = 0)
79 {
80 stop ();
81+
82 timeout = Timeout.add (16, animate_cb);
83-
84- start_time = GLib.get_monotonic_time ();
85-
86- /* The following are the same intervals that Unity uses */
87- switch (speed)
88- {
89- default:
90- case Speed.INSTANT:
91- length = 150 * TimeSpan.MILLISECOND;
92- break;
93- case Speed.FAST:
94- length = 250 * TimeSpan.MILLISECOND;
95- break;
96- case Speed.NORMAL:
97- length = 500 * TimeSpan.MILLISECOND;
98- break;
99- case Speed.SLOW:
100- length = 1000 * TimeSpan.MILLISECOND;
101- break;
102- }
103+ start_time = 0;
104+ extra_time = 0;
105+ extra_progress = 0;
106+
107+ if (temp_speed == 0)
108+ temp_speed = speed;
109+
110+ length = temp_speed * TimeSpan.MILLISECOND;
111+ }
112+
113+ /* This tells us the consumer of our progress reports is changing the
114+ goalposts on us. So we need to adjust our reports accordingly.
115+ 'extra_progress' is how much progress is being added to the animation.
116+ */
117+ public bool extend (double new_progress)
118+ {
119+ /* As an example, say a consumer is animating from point A to point C in
120+ 150ms. This is two points to cover, and at 75ms, they will be 0.5 done.
121+
122+ Now, they extend it to point D. This adds an extra point, which is half
123+ the original progress. So now they call extend (0.5).
124+
125+ We extend in the middle, so we need the slope at halfway through our
126+ progress function. That is a constant we have (see calculate_progress
127+ for details). So we'd need to add the same amount of normalized time
128+ to our process as progress, which is 0.5 / HALFWAY_VELOCITY = 0.318 in
129+ this example. Which is (length * 0.318) = 47.7ms more time to add.
130+
131+ Now we have 197.7ms as length of our animation. Which changes the
132+ progress values we give out. We further need to adjust our progress
133+ function to take this 'pause' in the middle of the function into
134+ account.
135+ */
136+
137+ if (progress > HALFWAY_PROGRESS)
138+ return false;
139+
140+ extra_progress += new_progress;
141+ extra_time = (TimeSpan)(length * extra_progress / HALFWAY_VELOCITY);
142+ return true;
143 }
144
145 public void stop ()
146@@ -75,12 +98,22 @@
147 private uint timeout = 0;
148 private TimeSpan start_time = 0;
149 private TimeSpan length = 0;
150+ private TimeSpan extra_time = 0;
151+ private double extra_progress = 0.0;
152+
153+ /* Derivative of our easing function at 0.5 (the halfway point).
154+ See calculate_progress() for functions. */
155+ private static const double HALFWAY_VELOCITY = 1.5708;
156+
157+ /* The y value of our easing function at 0.5 (the halway point) */
158+ private static const double HALFWAY_PROGRESS = 0.75;
159
160 private bool animate_cb ()
161 {
162- var time = normalize_time ();
163- var progress = normalize_progress (time);
164+ if (start_time == 0)
165+ start_time = GLib.get_monotonic_time ();
166
167+ progress = calculate_progress (GLib.get_monotonic_time ());
168 animate (progress);
169
170 if (progress >= 1.0)
171@@ -93,20 +126,96 @@
172 }
173
174 /* Returns 0.0 to 1.0 where 1.0 is at or past end_time */
175- private double normalize_time ()
176- {
177- var now = GLib.get_monotonic_time ();
178- return (((double)(now - start_time)) / length).clamp (0.0, 1.0);
179+ private double normalize_time (TimeSpan now)
180+ {
181+ var total = length;
182+ var halfway = start_time + length / 2;
183+ if (now > halfway)
184+ now -= extra_time;
185+
186+ return (((double)(now - start_time)) / total).clamp (0.0, 1.0);
187+ }
188+
189+ /* Incoming progress count is original, un-extra-time enhanced progress */
190+ private double normalize_progress (double p)
191+ {
192+ /* So without extra time, progress goes from 0.0 to 1.0. But with
193+ extra time, the beginning and end want to keep the same function,
194+ just squeezed into a smaller place in the graph. So we figure out
195+ that mapping here. */
196+ var extra_mapped = extra_progress / (1.0 + extra_progress);
197+ var half_mapped = HALFWAY_PROGRESS / (1.0 + extra_progress);
198+ if (p < HALFWAY_PROGRESS)
199+ return p * (half_mapped / HALFWAY_PROGRESS);
200+ else
201+ {
202+ var end = 1.0 - half_mapped - extra_mapped;
203+ return (p - HALFWAY_PROGRESS) * (end / (1 - HALFWAY_PROGRESS)) + half_mapped + extra_mapped;
204+ }
205 }
206
207 /* Returns 0.0 to 1.0 where 1.0 is done.
208- time is normalized time from 0.0 to 1.0. */
209- private double normalize_progress (double time)
210+ time is not normalized yet! */
211+ private double calculate_progress (TimeSpan time)
212 {
213 /* Use a sine wave function similar to what Unity uses. They call it
214 'easing' and is designed to make the animation start and end slower
215- than in the middle. */
216- return ((-1 * Math.cos (Math.PI * time) + 1) / 2).clamp (0.0, 1.0);
217+ than in the middle.
218+
219+ ((1 - Math.cos (Math.PI * time)) / 2) is the basic sine curve for
220+ easing, used by Unity and others. By squaring that and reversing
221+ the curve (by using 1 - x and 1 - y), we get a more exaggerated
222+ slowdown.
223+
224+ For clarity, here is the whole function:
225+ y = 1 - ((1 - cos (pi * (1 - x))) / 2) ^ 2
226+
227+ Here is the derivative of that function (useful for calculating
228+ slope at a given point, used elsewhere in this class):
229+ y = (pi * (cos (pi * (x - 1)) - 1)) * sin (pi * (x - 1)) / 2
230+
231+ */
232+
233+ /* But due to the ability to add extra time into the equation, we
234+ are actually three functions:
235+ 1) x=[0,A) = normal
236+ 2) x=[A,B] = halfway slope
237+ 3) x=(B,1.0] = picks up where first function left off */
238+
239+ var y = 0.0;
240+ var orig_half_point = start_time + length / 2;
241+
242+ if (time > start_time + length + extra_time)
243+ {
244+ y = 1.0;
245+ }
246+ else if (time < orig_half_point)
247+ {
248+ var x = normalize_time (time);
249+ y = easing_function (x);
250+ y = normalize_progress (y);
251+ }
252+ else if (time < orig_half_point + extra_time)
253+ {
254+ var xpercent = (time - orig_half_point) / (double)extra_time;
255+ y = (xpercent * extra_progress + HALFWAY_PROGRESS) / (1.0 + extra_progress);
256+ }
257+ else
258+ {
259+ var x = normalize_time (time);
260+ y = easing_function (x);
261+ y = normalize_progress (y);
262+ }
263+
264+ return y.clamp (0.0, 1.0);
265+ }
266+
267+ private double easing_function (double x)
268+ {
269+ var y = (1 - Math.cos (Math.PI * (1.0 - x))) / 2;
270+ y = y * y;
271+ y = 1.0 - y;
272+ return y;
273 }
274 }
275
276
277=== modified file 'src/background.vala'
278--- src/background.vala 2012-01-14 16:24:09 +0000
279+++ src/background.vala 2012-01-30 18:00:33 +0000
280@@ -271,7 +271,7 @@
281 {
282 orientation = Gtk.Orientation.VERTICAL;
283
284- timer = new AnimateTimer (AnimateTimer.Speed.INSTANT);
285+ timer = new AnimateTimer (AnimateTimer.INSTANT);
286 timer.animate.connect (animate_cb);
287
288 loaders = new HashTable<string?, BackgroundLoader> (str_hash, str_equal);
289
290=== modified file 'src/config.vapi'
291--- src/config.vapi 2011-08-24 03:15:08 +0000
292+++ src/config.vapi 2012-01-30 18:00:33 +0000
293@@ -6,4 +6,5 @@
294 public const string VERSION;
295 public const string CONFIG_FILE;
296 public const string PKGDATADIR;
297+ public const string INDICATORDIR;
298 }
299
300=== added file 'src/dash-button.vala'
301--- src/dash-button.vala 1970-01-01 00:00:00 +0000
302+++ src/dash-button.vala 2012-01-30 18:00:33 +0000
303@@ -0,0 +1,37 @@
304+/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
305+ *
306+ * Copyright (C) 2012 Canonical Ltd
307+ *
308+ * This program is free software: you can redistribute it and/or modify
309+ * it under the terms of the GNU General Public License version 3 as
310+ * published by the Free Software Foundation.
311+ *
312+ * This program is distributed in the hope that it will be useful,
313+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
314+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
315+ * GNU General Public License for more details.
316+ *
317+ * You should have received a copy of the GNU General Public License
318+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
319+ *
320+ * Authors: Michael Terry <michael.terry@canonical.com>
321+ */
322+
323+public class DashButton : Gtk.Button, Fadable
324+{
325+ protected FadeTracker fade_tracker {get; protected set;}
326+
327+ construct
328+ {
329+ fade_tracker = new FadeTracker (this);
330+ }
331+
332+ public override bool draw (Cairo.Context c)
333+ {
334+ c.push_group ();
335+ base.draw (c);
336+ c.pop_group_to_source ();
337+ c.paint_with_alpha (fade_tracker.alpha);
338+ return false;
339+ }
340+}
341
342=== added file 'src/dash-entry.vala'
343--- src/dash-entry.vala 1970-01-01 00:00:00 +0000
344+++ src/dash-entry.vala 2012-01-30 18:00:33 +0000
345@@ -0,0 +1,70 @@
346+/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
347+ *
348+ * Copyright (C) 2012 Canonical Ltd
349+ *
350+ * This program is free software: you can redistribute it and/or modify
351+ * it under the terms of the GNU General Public License version 3 as
352+ * published by the Free Software Foundation.
353+ *
354+ * This program is distributed in the hope that it will be useful,
355+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
356+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
357+ * GNU General Public License for more details.
358+ *
359+ * You should have received a copy of the GNU General Public License
360+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
361+ *
362+ * Authors: Michael Terry <michael.terry@canonical.com>
363+ */
364+
365+/* Vala's vapi for gtk3 is broken for lookup_color (it forgets the out keyword) */
366+[CCode (cheader_filename = "gtk/gtk.h")]
367+extern bool gtk_style_context_lookup_color (Gtk.StyleContext ctx, string color_name, out Gdk.RGBA color);
368+
369+public class DashEntry : Gtk.Entry, Fadable
370+{
371+ public string constant_placeholder_text {get; set;}
372+
373+ protected FadeTracker fade_tracker {get; protected set;}
374+
375+ construct
376+ {
377+ fade_tracker = new FadeTracker (this);
378+ }
379+
380+ public override bool draw (Cairo.Context c)
381+ {
382+ c.save ();
383+ c.push_group ();
384+ base.draw (c);
385+ c.pop_group_to_source ();
386+ c.paint_with_alpha (fade_tracker.alpha);
387+ c.restore ();
388+
389+ /* Now draw the prompt text */
390+ if (get_text_length () == 0 && constant_placeholder_text.length > 0)
391+ draw_prompt_text (c);
392+
393+ return false;
394+ }
395+
396+ private void draw_prompt_text (Cairo.Context c)
397+ {
398+ /* Position text */
399+ int x, y;
400+ get_layout_offsets (out x, out y);
401+ c.move_to (x, y);
402+
403+ /* Set foreground color */
404+ var fg = Gdk.RGBA ();
405+ var context = get_style_context ();
406+ if (!gtk_style_context_lookup_color (context, "placeholder_text_color", out fg))
407+ fg.parse ("ccc");
408+ c.set_source_rgba (fg.red, fg.green, fg.blue, fg.alpha);
409+
410+ /* Draw text */
411+ var layout = create_pango_layout (constant_placeholder_text);
412+ layout.set_font_description (Pango.FontDescription.from_string ("Ubuntu 14"));
413+ Pango.cairo_show_layout (c, layout);
414+ }
415+}
416
417=== added file 'src/fadable.vala'
418--- src/fadable.vala 1970-01-01 00:00:00 +0000
419+++ src/fadable.vala 2012-01-30 18:00:33 +0000
420@@ -0,0 +1,85 @@
421+/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
422+ *
423+ * Copyright (C) 2012 Canonical Ltd
424+ *
425+ * This program is free software: you can redistribute it and/or modify
426+ * it under the terms of the GNU General Public License version 3 as
427+ * published by the Free Software Foundation.
428+ *
429+ * This program is distributed in the hope that it will be useful,
430+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
431+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
432+ * GNU General Public License for more details.
433+ *
434+ * You should have received a copy of the GNU General Public License
435+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
436+ *
437+ * Authors: Michael Terry <michael.terry@canonical.com>
438+ */
439+
440+public class FadeTracker : Object
441+{
442+ public double alpha {get; private set; default = 1.0;}
443+ public Gtk.Widget widget {get; construct;}
444+
445+ public enum Mode
446+ {
447+ FADE_IN,
448+ FADE_OUT,
449+ }
450+
451+ public FadeTracker (Gtk.Widget widget)
452+ {
453+ Object (widget: widget);
454+ }
455+
456+ public void reset (Mode mode)
457+ {
458+ this.mode = mode;
459+ animate_cb (0.0);
460+ widget.show ();
461+ timer.reset ();
462+ }
463+
464+ private AnimateTimer timer;
465+ private Mode mode;
466+
467+ construct
468+ {
469+ timer = new AnimateTimer (AnimateTimer.INSTANT);
470+ timer.animate.connect (animate_cb);
471+ }
472+
473+ private void animate_cb (double progress)
474+ {
475+ if (mode == Mode.FADE_IN)
476+ {
477+ alpha = progress;
478+ if (progress == 1.0)
479+ widget.grab_focus ();
480+ }
481+ else
482+ {
483+ alpha = 1.0 - progress;
484+ if (progress == 1.0)
485+ widget.hide (); /* finish the job */
486+ }
487+
488+ widget.queue_draw ();
489+ }
490+}
491+
492+public interface Fadable : Gtk.Widget
493+{
494+ protected abstract FadeTracker fade_tracker {get; protected set;}
495+
496+ public void fade_in ()
497+ {
498+ fade_tracker.reset (FadeTracker.Mode.FADE_IN);
499+ }
500+
501+ public void fade_out ()
502+ {
503+ fade_tracker.reset (FadeTracker.Mode.FADE_OUT);
504+ }
505+}
506
507=== added file 'src/menu.vala'
508--- src/menu.vala 1970-01-01 00:00:00 +0000
509+++ src/menu.vala 2012-01-30 18:00:33 +0000
510@@ -0,0 +1,46 @@
511+/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*-
512+ *
513+ * Copyright (C) 2011,2012 Canonical Ltd
514+ *
515+ * This program is free software: you can redistribute it and/or modify
516+ * it under the terms of the GNU General Public License version 3 as
517+ * published by the Free Software Foundation.
518+ *
519+ * This program is distributed in the hope that it will be useful,
520+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
521+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
522+ * GNU General Public License for more details.
523+ *
524+ * You should have received a copy of the GNU General Public License
525+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
526+ *
527+ * Authors: Andrea Cimitan <andrea.cimitan@canonical.com>
528+ */
529+
530+
531+public class Menu : Gtk.Menu
532+{
533+ public Background? background {get; construct; default = null;}
534+
535+ public Menu (Background bg)
536+ {
537+ Object (background: bg);
538+ }
539+
540+ public override bool draw (Cairo.Context c)
541+ {
542+ if (background != null)
543+ {
544+ int x, y;
545+ Gdk.Window window = get_window ();
546+ window.get_origin (out x, out y);
547+ c.save ();
548+ c.translate (-x, -y);
549+ background.draw_full (c, Background.DrawFlags.NONE);
550+ c.restore ();
551+ }
552+
553+ base.draw (c);
554+ return false;
555+ }
556+}
557
558=== modified file 'src/menubar.vala'
559--- src/menubar.vala 2012-01-14 16:24:09 +0000
560+++ src/menubar.vala 2012-01-30 18:00:33 +0000
561@@ -85,19 +85,6 @@
562
563 public override bool draw (Cairo.Context c)
564 {
565- if (background != null)
566- {
567- int x, y;
568- background.translate_coordinates (this, 0, 0, out x, out y);
569- c.save ();
570- c.translate (x, y);
571- background.draw_full (c, Background.DrawFlags.NONE);
572- c.restore ();
573- }
574-
575- c.set_source_rgb (0, 0, 0);
576- c.paint_with_alpha (0.5);
577-
578 foreach (var child in get_children ())
579 {
580 propagate_draw (child, c);
581@@ -289,10 +276,10 @@
582 insert (a11y_item, (int) get_children ().length () - 1);
583
584 debug ("LANG=%s LANGUAGE=%s", Environment.get_variable ("LANG"), Environment.get_variable ("LANGUAGE"));
585- string[] filenames = {"/usr/lib/indicators3/6/libsession.so",
586- "/usr/lib/indicators3/6/libdatetime.so",
587- "/usr/lib/indicators3/6/libpower.so",
588- "/usr/lib/indicators3/6/libsoundmenu.so"};
589+ string[] filenames = {Path.build_filename (Config.INDICATORDIR, "libsession.so"),
590+ Path.build_filename (Config.INDICATORDIR, "libdatetime.so"),
591+ Path.build_filename (Config.INDICATORDIR, "libpower.so"),
592+ Path.build_filename (Config.INDICATORDIR, "libsoundmenu.so")};
593 foreach (var filename in filenames)
594 {
595 var io = new Indicator.Object.from_file (filename);
596
597=== modified file 'src/user-list.vala'
598--- src/user-list.vala 2012-01-23 15:42:22 +0000
599+++ src/user-list.vala 2012-01-30 18:00:33 +0000
600@@ -48,8 +48,6 @@
601
602 public class UserList : Gtk.Container
603 {
604- private int frame_count = 0;
605-
606 public Background background;
607 private uint change_background_timeout = 0;
608
609@@ -71,16 +69,17 @@
610 private string? message;
611
612 private Gtk.Box login_box;
613- private Gtk.Entry prompt_entry;
614- private Gtk.Button login_button;
615- private Gtk.Widget prompt_widget_to_show;
616+ private DashEntry prompt_entry;
617+ private DashButton login_button;
618+ private Fadable prompt_widget_to_show;
619 private Gtk.Button options_button;
620- private Gtk.Menu options_menu;
621+ private Menu options_menu;
622 private Gdk.Pixbuf options_pixbuf;
623 unowned GLib.SList<SessionMenuItem> session_group = null;
624
625 private bool complete = false;
626-
627+
628+ private int border = 4;
629 private int box_width = 7;
630
631 private uint n_above = 3;
632@@ -153,19 +152,13 @@
633 login_box.show ();
634 add (login_box);
635
636- prompt_entry = new Gtk.Entry ();
637+ prompt_entry = new DashEntry ();
638 prompt_entry.caps_lock_warning = true;
639- prompt_entry.has_frame = false;
640- var b = Gtk.Border ();
641- b.left = 15;
642- b.right = 15;
643- b.top = 15;
644- b.bottom = 15;
645- prompt_entry.set_inner_border (b);
646+
647 prompt_entry.activate.connect (prompt_entry_activate_cb);
648 add (prompt_entry);
649
650- login_button = new Gtk.Button ();
651+ login_button = new DashButton ();
652 var label = new Gtk.Label ("<span font_size=\"large\">%s</span>".printf (/* 'Log In' here is the button for logging in. */
653 _("Log In")));
654 label.use_markup = true;
655@@ -192,12 +185,24 @@
656 options_button.show ();
657 add (options_button);
658
659- options_menu = new Gtk.Menu ();
660+ options_menu = new Menu (background);
661+ add_style_class (options_menu);
662
663- scroll_timer = new AnimateTimer (AnimateTimer.Speed.FAST);
664+ scroll_timer = new AnimateTimer (AnimateTimer.FAST);
665 scroll_timer.animate.connect (scroll_animate_cb);
666 }
667
668+ private void add_style_class (Gtk.Widget widget)
669+ {
670+ /* Add style context class lightdm-user-list
671+ * to each widget added to UserList.
672+ * FIXME Ideally, we should set the style context
673+ * only on the parent of those, and once,
674+ * so it gets applied automatically to all children. */
675+ var ctx = widget.get_style_context ();
676+ ctx.add_class ("lightdm");
677+ }
678+
679 private void redraw_user_list ()
680 {
681 queue_draw_area (box_x, box_y - (int) (n_above + 1) * grid_size,
682@@ -220,7 +225,23 @@
683 {
684 login_button.hide ();
685 prompt_entry.hide ();
686- message = text;
687+ if (text.contains ("\n"))
688+ {
689+ message = text;
690+ prompt_entry.constant_placeholder_text = "";
691+ }
692+ else
693+ {
694+ /* Strip trailing colon if present (also handle CJK version) */
695+ var placeholder = text;
696+ if (placeholder.has_suffix (":") || placeholder.has_suffix (":"))
697+ {
698+ var len = placeholder.char_count ();
699+ placeholder = placeholder.substring (0, placeholder.index_of_nth_char (len - 1));
700+ }
701+ message = "";
702+ prompt_entry.constant_placeholder_text = placeholder;
703+ }
704 prompt_entry.text = "";
705 prompt_entry.sensitive = true;
706 prompt_entry.visibility = !secret;
707@@ -422,7 +443,7 @@
708 private void change_background ()
709 {
710 /* Set background after user stops scrolling */
711- if (frame_count > 0)
712+ if (background.current_background != null)
713 {
714 if (change_background_timeout != 0)
715 Source.remove (change_background_timeout);
716@@ -435,26 +456,53 @@
717 private void finished_animating ()
718 {
719 if (prompt_widget_to_show != null) {
720- prompt_widget_to_show.show ();
721- prompt_widget_to_show = null;
722+ prompt_widget_to_show.fade_in ();
723+ prompt_widget_to_show = null;
724+ change_background ();
725 }
726+ menubar.set_layout (selected_entry.keyboard_layout);
727 options_button.show ();
728 }
729
730 private void select_entry (UserEntry entry, double direction)
731 {
732- if (get_realized ())
733+ if (get_realized () && scroll_target_location != entries.index (entry))
734 {
735- scroll_target_location = entries.index (entry);
736- scroll_start_location = scroll_location;
737- scroll_direction = direction;
738- if (scroll_location != scroll_target_location)
739+ var old_target = scroll_target_location;
740+ var new_target = entries.index (entry);
741+ var new_direction = direction;
742+ var new_start = scroll_timer.is_running ? scroll_start_location : scroll_location;
743+
744+ if (scroll_timer.is_running && scroll_direction != new_direction)
745+ return; /* ignore requests when we're already scrolling the opposite way */
746+
747+ if (scroll_location != new_target)
748 {
749- scroll_timer.reset ();
750+ var new_distance = new_direction * (new_target - new_start);
751+ if (scroll_timer.is_running)
752+ {
753+ var old_distance = new_direction * (old_target - new_start);
754+ if (!scroll_timer.extend ((new_distance - old_distance) / old_distance))
755+ return;
756+ }
757+ else if (new_distance > 1)
758+ scroll_timer.reset (600);
759+ else
760+ scroll_timer.reset (400);
761+
762+ if (prompt_entry.visible)
763+ prompt_widget_to_show = prompt_entry;
764+ else if (login_button.visible)
765+ prompt_widget_to_show = login_button;
766+
767 prompt_entry.hide ();
768 login_button.hide ();
769 options_button.hide ();
770 }
771+
772+ scroll_target_location = new_target;
773+ scroll_direction = new_direction;
774+ scroll_start_location = new_start;
775 }
776
777 if (selected_entry != entry)
778@@ -463,16 +511,15 @@
779
780 if (get_realized ())
781 {
782- change_background ();
783 user_selected (selected_entry.name);
784 }
785-
786- menubar.set_layout (selected_entry.keyboard_layout);
787 }
788 }
789
790 public override void add (Gtk.Widget widget)
791 {
792+ add_style_class (widget);
793+
794 children.append (widget);
795 if (get_realized ())
796 widget.set_parent_window (get_window ());
797@@ -494,6 +541,7 @@
798 public override void realize ()
799 {
800 change_background ();
801+ menubar.set_layout (selected_entry.keyboard_layout);
802
803 set_realized (true);
804
805@@ -617,7 +665,7 @@
806 else
807 c.set_source_rgba (1.0, 1.0, 1.0, alpha);
808
809- c.translate (grid_size / 2, grid_size - (grid_size - (h)) / 2 - h);
810+ c.translate (grid_size / 2, (grid_size - h) / 2 + border);
811 c.move_to (0, 0);
812 Pango.cairo_show_layout (c, entry.layout);
813
814@@ -629,7 +677,7 @@
815 c.save ();
816 var xpadding = (grid_size - options_pixbuf.width) / 2;
817 var ypadding = (grid_size - options_pixbuf.height) / 2;
818- c.translate (box_width * grid_size - grid_size - grid_size / 4 + xpadding, grid_size / 4 - ypadding);
819+ c.translate (box_width * grid_size - grid_size - grid_size / 4 + xpadding, grid_size / 4 - ypadding - border);
820 Gdk.cairo_set_source_pixbuf (c, options_pixbuf, 0, 0);
821 c.paint ();
822 c.restore ();
823@@ -645,18 +693,13 @@
824 if (position < 0)
825 alpha = 1.0 + position / (n_above + 1);
826 else
827- alpha = 1.0 - (position - 2) / (n_below + 1);
828+ alpha = 1.0 - (position - 2) / (n_below + 1);
829 draw_entry (c, entry, alpha, in_box);
830 c.restore ();
831 }
832
833 public override bool draw (Cairo.Context c)
834 {
835- if (frame_count == 0)
836- debug ("Rendered first frame");
837-
838- frame_count++;
839-
840 foreach (var child in children)
841 propagate_draw (child, c);
842
843@@ -664,22 +707,23 @@
844
845 c.translate (box_x, box_y);
846
847- var border = 4;
848-
849 var index = 0;
850 foreach (var entry in entries)
851 {
852 var position = index - scroll_location;
853
854 /* Draw entries above the box */
855- var h_above = (double) (n_above + 1) * grid_size;
856- c.save ();
857-
858- c.rectangle (0, -h_above, box_width * grid_size, h_above);
859- c.clip ();
860- draw_entry_at_position (c, entry, position);
861-
862- c.restore ();
863+ if (position < 0)
864+ {
865+ var h_above = (double) (n_above + 1) * grid_size;
866+ c.save ();
867+
868+ c.rectangle (0, -h_above, box_width * grid_size, h_above);
869+ c.clip ();
870+ draw_entry_at_position (c, entry, position);
871+
872+ c.restore ();
873+ }
874
875 /* Draw entries in the box */
876 if (position > -1 && position < 1 && scroll_timer.is_running)
877@@ -698,14 +742,17 @@
878 }
879
880 /* Draw entries below the box */
881- var h_below = (double) (n_below + 1) * grid_size;
882- c.save ();
883-
884- c.rectangle (0, box_height * grid_size, box_width * grid_size, h_below);
885- c.clip ();
886- draw_entry_at_position (c, entry, position + box_height - 1);
887-
888- c.restore ();
889+ if (position > 0)
890+ {
891+ var h_below = (double) (n_below + 1) * grid_size;
892+ c.save ();
893+
894+ c.rectangle (0, box_height * grid_size, box_width * grid_size, h_below);
895+ c.clip ();
896+ draw_entry_at_position (c, entry, position + box_height - 1);
897+
898+ c.restore ();
899+ }
900
901 index++;
902 }
903@@ -721,7 +768,7 @@
904
905 c.save ();
906 c.translate (0, text_y);
907- draw_entry (c, selected_entry, 1.0);
908+ draw_entry (c, selected_entry, 1.0, true);
909 c.restore ();
910
911 c.restore();
912@@ -740,7 +787,7 @@
913 int w, h;
914 layout.get_pixel_size (out w, out h);
915
916- c.move_to (grid_size / 2, grid_size * 1.25 - h);
917+ c.move_to (grid_size / 2, grid_size * 1.25 - h + border);
918
919 var r = 1.0;
920 var g = 1.0;

Subscribers

People subscribed via source and target branches