Merge lp:~azzar1/unity/focus-highlight-category-headers into lp:unity
- focus-highlight-category-headers
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Andrea Azzarone |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1921 |
Proposed branch: | lp:~azzar1/unity/focus-highlight-category-headers |
Merge into: | lp:unity |
Diff against target: |
753 lines (+265/-92) 12 files modified
plugins/unityshell/src/DashStyle.cpp (+1/-1) plugins/unityshell/src/DashStyle.h (+4/-0) plugins/unityshell/src/DashView.cpp (+3/-1) plugins/unityshell/src/FilterBar.cpp (+0/-1) plugins/unityshell/src/IconTexture.cpp (+2/-2) plugins/unityshell/src/LensBar.cpp (+2/-2) plugins/unityshell/src/LensView.cpp (+5/-4) plugins/unityshell/src/PlacesGroup.cpp (+173/-68) plugins/unityshell/src/PlacesGroup.h (+27/-12) plugins/unityshell/src/SearchBar.cpp (+2/-1) tests/autopilot/autopilot/emulators/unity.py (+10/-0) tests/autopilot/autopilot/tests/test_dash.py (+36/-0) |
To merge this branch: | bzr merge lp:~azzar1/unity/focus-highlight-category-headers |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomi Richards (community) | Approve | ||
Alex Launi | Pending | ||
John Lea | design | Pending | |
Review via email: mp+91917@code.launchpad.net |
This proposal supersedes a proposal from 2012-02-06.
Commit message
Implements the new design for the focus/over state for the category headers. Fixes bug #843026 and #919559 too.
Description of the change
For the design review:
[*] http://
[*] http://
P.S: sometimes backward navigation doesn't work. Not my fault. Someone broke it in trunk.
Alex Launi (alexlauni) wrote : Posted in a previous version of this proposal | # |
John Lea (johnlea) wrote : Posted in a previous version of this proposal | # |
Reviewed and signed off by design. Thx!
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
> Needs testing. It should be simple enough to write an autopilot test for this.
We're using the nux key navigation that is already auto-tested. The bug #843026 was caused by a uninitialized variable...
Andrea Azzarone (azzar1) wrote : Posted in a previous version of this proposal | # |
Added an AP test btw..
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Your code has lots of integer literals in it:
30 + width += 19 + 40; // add the left padding and the group plugin padding
362 + _focus_layer = dash::Style:
398 + base.x + base.width - 10, base.y + base.height - 1,
408 + geo.x = base.x + 11;
409 + geo.width = base.width - 16;
Can we put these integer literals into a const int? these are just meaningless numbers rigth now.
In IconTExture.cpp, in the constructor, instead of doing this:
_accept_
please use the class initialiser list.
In the PlacesGroup class, the following methods should all be const:
int GetHeaderHeight()
bool HeaderHasKeyFoc
bool ShouldBeHighlig
All member variables should have a trailing underscore, not a leading one. The style guide says:
"""Variable names are all lowercase, with underscores between words. Class member variables have trailing underscores. For instance: my_exciting_
Please add a docstring to this test:
663 + def test_category_
that describes what it's testing.
Overall, this looks good, but there are a few small issues that need to be fixed.
Thanks
Andrea Azzarone (azzar1) wrote : | # |
> Your code has lots of integer literals in it:
>
> 30 + width += 19 + 40; // add the left padding and the group plugin
> padding
> 362 + _focus_layer = dash::Style:
> kFocusHighlight
> 398 + base.x + base.width - 10, base.y + base.height - 1,
> 408 + geo.x = base.x + 11;
> 409 + geo.width = base.width - 16;
>
Done.
>
> Can we put these integer literals into a const int? these are just meaningless
> numbers rigth now.
>
> In IconTExture.cpp, in the constructor, instead of doing this:
>
> _accept_
>
> please use the class initialiser list.
>
Done.
>
> In the PlacesGroup class, the following methods should all be const:
>
> int GetHeaderHeight()
> bool HeaderHasKeyFoc
> bool ShouldBeHighlig
>
Done. Added const to GetExpanded too...
> All member variables should have a trailing underscore, not a leading one. The
> style guide says:
>
> """Variable names are all lowercase, with underscores between words. Class
> member variables have trailing underscores. For instance:
> my_exciting_
>
PlacesGroup use the old style so for the moment I prefer to be consistent.
> Please add a docstring to this test:
>
> 663 + def test_category_
>
> that describes what it's testing.
>
Done.
>
>
> Overall, this looks good, but there are a few small issues that need to be
> fixed.
>
> Thanks
Thank you too.
Thomi Richards (thomir-deactivatedaccount) wrote : | # |
Looks much better, thanks!
Preview Diff
1 | === modified file 'plugins/unityshell/src/DashStyle.cpp' |
2 | --- plugins/unityshell/src/DashStyle.cpp 2012-02-07 20:12:24 +0000 |
3 | +++ plugins/unityshell/src/DashStyle.cpp 2012-02-07 22:51:21 +0000 |
4 | @@ -1615,7 +1615,7 @@ |
5 | width, |
6 | height); |
7 | |
8 | - cairo_set_source_rgba(cr, nux::color::White * 0.50f); |
9 | + cairo_set_source_rgba(cr, nux::Color(1.0f, 1.0f, 1.0f, 0.2f)); |
10 | cairo_fill(cr); |
11 | |
12 | // Create the texture layer |
13 | |
14 | === modified file 'plugins/unityshell/src/DashStyle.h' |
15 | --- plugins/unityshell/src/DashStyle.h 2012-02-07 20:12:24 +0000 |
16 | +++ plugins/unityshell/src/DashStyle.h 2012-02-07 22:51:21 +0000 |
17 | @@ -192,6 +192,10 @@ |
18 | nux::BaseTexture* GetGroupUnexpandIcon(); |
19 | nux::BaseTexture* GetGroupExpandIcon(); |
20 | |
21 | + // Paddings |
22 | + static const int FILTERS_LEFT_PADDING = 0; |
23 | + static const int FILTERS_RIGHT_PADDING = 8; |
24 | + |
25 | sigc::signal<void> changed; |
26 | |
27 | private: |
28 | |
29 | === modified file 'plugins/unityshell/src/DashView.cpp' |
30 | --- plugins/unityshell/src/DashView.cpp 2012-02-07 12:00:04 +0000 |
31 | +++ plugins/unityshell/src/DashView.cpp 2012-02-07 22:51:21 +0000 |
32 | @@ -149,6 +149,7 @@ |
33 | content_layout_->AddView(lenses_layout_, 1, nux::MINOR_POSITION_LEFT); |
34 | |
35 | home_view_ = new LensView(home_lens_); |
36 | + AddChild(home_view_); |
37 | active_lens_view_ = home_view_; |
38 | lens_views_[home_lens_->id] = home_view_; |
39 | lenses_layout_->AddView(home_view_); |
40 | @@ -219,7 +220,7 @@ |
41 | |
42 | width = MAX(width, tile_width * 6); |
43 | |
44 | - width += 19 + 32; // add the left padding and the group plugin padding |
45 | + width += 19 + 32 + dash::Style::FILTERS_LEFT_PADDING + dash::Style::FILTERS_RIGHT_PADDING; // add the left padding and the group plugin padding |
46 | |
47 | height = search_bar_->GetGeometry().height; |
48 | height += tile_height * 3; |
49 | @@ -375,6 +376,7 @@ |
50 | lens_bar_->AddLens(lens); |
51 | |
52 | LensView* view = new LensView(lens); |
53 | + AddChild(view); |
54 | view->SetVisible(false); |
55 | view->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated)); |
56 | lenses_layout_->AddView(view, 1); |
57 | |
58 | === modified file 'plugins/unityshell/src/FilterBar.cpp' |
59 | --- plugins/unityshell/src/FilterBar.cpp 2012-02-04 05:28:23 +0000 |
60 | +++ plugins/unityshell/src/FilterBar.cpp 2012-02-07 22:51:21 +0000 |
61 | @@ -139,4 +139,3 @@ |
62 | |
63 | } // namespace dash |
64 | } // namespace unity |
65 | - |
66 | |
67 | === modified file 'plugins/unityshell/src/IconTexture.cpp' |
68 | --- plugins/unityshell/src/IconTexture.cpp 2012-02-07 07:42:12 +0000 |
69 | +++ plugins/unityshell/src/IconTexture.cpp 2012-02-07 22:51:21 +0000 |
70 | @@ -45,6 +45,7 @@ |
71 | |
72 | IconTexture::IconTexture(nux::BaseTexture* texture, guint width, guint height) |
73 | : TextureArea(NUX_TRACKER_LOCATION), |
74 | + _accept_key_nav_focus(false), |
75 | _icon_name(NULL), |
76 | _size(height), |
77 | _texture_cached(texture), |
78 | @@ -54,12 +55,11 @@ |
79 | _opacity(1.0f) |
80 | { |
81 | SetMinMaxSize(width, height); |
82 | - |
83 | - _accept_key_nav_focus = false; |
84 | } |
85 | |
86 | IconTexture::IconTexture(const char* icon_name, unsigned int size, bool defer_icon_loading) |
87 | : TextureArea(NUX_TRACKER_LOCATION), |
88 | + _accept_key_nav_focus(false), |
89 | _icon_name(NULL), |
90 | _size(size), |
91 | _texture_width(0), |
92 | |
93 | === modified file 'plugins/unityshell/src/LensBar.cpp' |
94 | --- plugins/unityshell/src/LensBar.cpp 2012-02-07 12:00:04 +0000 |
95 | +++ plugins/unityshell/src/LensBar.cpp 2012-02-07 22:51:21 +0000 |
96 | @@ -84,7 +84,7 @@ |
97 | icons_.push_back(icon); |
98 | layout_->AddView(icon, 0, nux::eCenter, nux::MINOR_SIZE_FULL); |
99 | |
100 | - icon->mouse_click.connect([&, icon] (int x, int y, unsigned long button, unsigned long keyboard) { SetActive(icon); }); |
101 | + icon->mouse_click.connect([&, icon] (int x, int y, unsigned long button, unsigned long keyboard) { SetActive(icon); QueueDraw(); }); |
102 | icon->mouse_enter.connect([&] (int x, int y, unsigned long button, unsigned long keyboard) { QueueDraw(); }); |
103 | icon->mouse_leave.connect([&] (int x, int y, unsigned long button, unsigned long keyboard) { QueueDraw(); }); |
104 | icon->mouse_down.connect([&] (int x, int y, unsigned long button, unsigned long keyboard) { QueueDraw(); }); |
105 | @@ -100,7 +100,7 @@ |
106 | icons_.push_back(icon); |
107 | layout_->AddView(icon, 0, nux::eCenter, nux::eFix); |
108 | |
109 | - icon->mouse_click.connect([&, icon] (int x, int y, unsigned long button, unsigned long keyboard) { SetActive(icon); }); |
110 | + icon->mouse_click.connect([&, icon] (int x, int y, unsigned long button, unsigned long keyboard) { SetActive(icon); QueueDraw(); }); |
111 | icon->mouse_enter.connect([&] (int x, int y, unsigned long button, unsigned long keyboard) { QueueDraw(); }); |
112 | icon->mouse_leave.connect([&] (int x, int y, unsigned long button, unsigned long keyboard) { QueueDraw(); }); |
113 | icon->mouse_down.connect([&] (int x, int y, unsigned long button, unsigned long keyboard) { QueueDraw(); }); |
114 | |
115 | === modified file 'plugins/unityshell/src/LensView.cpp' |
116 | --- plugins/unityshell/src/LensView.cpp 2012-02-07 12:00:04 +0000 |
117 | +++ plugins/unityshell/src/LensView.cpp 2012-02-07 22:51:21 +0000 |
118 | @@ -38,6 +38,7 @@ |
119 | namespace |
120 | { |
121 | nux::logging::Logger logger("unity.dash.lensview"); |
122 | + |
123 | } |
124 | |
125 | // This is so we can access some protected members in scrollview. |
126 | @@ -144,8 +145,6 @@ |
127 | void LensView::SetupViews() |
128 | { |
129 | layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); |
130 | - |
131 | - layout_->SetHorizontalExternalMargin(8); |
132 | |
133 | scroll_view_ = new LensScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION), |
134 | NUX_TRACKER_LOCATION); |
135 | @@ -164,6 +163,7 @@ |
136 | layout_->AddView(fscroll_view_, 1); |
137 | |
138 | fscroll_layout_ = new nux::VLayout(); |
139 | + fscroll_layout_->SetLeftAndRightPadding(dash::Style::FILTERS_LEFT_PADDING, dash::Style::FILTERS_RIGHT_PADDING); |
140 | fscroll_view_->SetLayout(fscroll_layout_); |
141 | |
142 | filter_bar_ = new FilterBar(); |
143 | @@ -214,6 +214,7 @@ |
144 | << ", " << boost::lexical_cast<int>(index) << ")"; |
145 | |
146 | PlacesGroup* group = new PlacesGroup(); |
147 | + AddChild(group); |
148 | group->SetName(name.c_str()); |
149 | group->SetIcon(icon_hint.c_str()); |
150 | group->SetExpanded(false); |
151 | @@ -345,8 +346,8 @@ |
152 | filter_bar_->AddFilter(filter); |
153 | |
154 | int width = dash::Style::Instance().GetTileWidth(); |
155 | - fscroll_view_->SetMinimumWidth(width*2); |
156 | - fscroll_view_->SetMaximumWidth(width*2); |
157 | + fscroll_view_->SetMinimumWidth(width * 2 + dash::Style::FILTERS_LEFT_PADDING + dash::Style::FILTERS_RIGHT_PADDING); |
158 | + fscroll_view_->SetMaximumWidth(width * 2 + dash::Style::FILTERS_LEFT_PADDING + dash::Style::FILTERS_RIGHT_PADDING); |
159 | |
160 | can_refine_search = true; |
161 | } |
162 | |
163 | === modified file 'plugins/unityshell/src/PlacesGroup.cpp' |
164 | --- plugins/unityshell/src/PlacesGroup.cpp 2012-02-04 05:28:23 +0000 |
165 | +++ plugins/unityshell/src/PlacesGroup.cpp 2012-02-07 22:51:21 +0000 |
166 | @@ -29,8 +29,6 @@ |
167 | |
168 | #include "StaticCairoText.h" |
169 | |
170 | -#include "Introspectable.h" |
171 | - |
172 | #include <sigc++/trackable.h> |
173 | #include <sigc++/signal.h> |
174 | #include <sigc++/functors/ptr_fun.h> |
175 | @@ -41,24 +39,61 @@ |
176 | #include <glib/gi18n-lib.h> |
177 | |
178 | #include <Nux/Utils.h> |
179 | - |
180 | +#include <UnityCore/Variant.h> |
181 | #include "DashStyle.h" |
182 | |
183 | +namespace unity |
184 | +{ |
185 | namespace |
186 | { |
187 | -const nux::Color kExpandDefaultTextColor(1.0f, 1.0f, 1.0f, 0.5f); |
188 | + |
189 | +const nux::Color kExpandDefaultTextColor(1.0f, 1.0f, 1.0f, 1.0f); |
190 | const nux::Color kExpandHoverTextColor(1.0f, 1.0f, 1.0f, 1.0f); |
191 | -const float kExpandDefaultIconOpacity = 0.5f; |
192 | +const float kExpandDefaultIconOpacity = 1.0f; |
193 | const float kExpandHoverIconOpacity = 1.0f; |
194 | + |
195 | +// Category header highlight |
196 | +const int kHighlightHeight = 24; |
197 | +const int kHighlightWidthSubtractor = 16; |
198 | +const int kHighlightLeftPadding = 11; |
199 | + |
200 | +// Line Separator |
201 | +const int kSeparatorLeftPadding = 16; |
202 | +const int kSeparatorWidthSubtractor = 10; |
203 | + |
204 | +class HeaderView : public nux::View |
205 | +{ |
206 | +public: |
207 | + HeaderView(NUX_FILE_LINE_DECL) |
208 | + : nux::View(NUX_FILE_LINE_PARAM) |
209 | + { |
210 | + } |
211 | + |
212 | +protected: |
213 | + void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) |
214 | + { |
215 | + }; |
216 | + |
217 | + void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) |
218 | + { |
219 | + if (GetLayout()) |
220 | + GetLayout()->ProcessDraw(graphics_engine, force_draw); |
221 | + } |
222 | + |
223 | + bool AcceptKeyNavFocus() |
224 | + { |
225 | + return false; |
226 | + } |
227 | +}; |
228 | + |
229 | } |
230 | |
231 | -namespace unity |
232 | -{ |
233 | NUX_IMPLEMENT_OBJECT_TYPE(PlacesGroup); |
234 | |
235 | PlacesGroup::PlacesGroup() |
236 | : View(NUX_TRACKER_LOCATION), |
237 | - _child_view(NULL), |
238 | + _child_view(nullptr), |
239 | + _focus_layer(nullptr), |
240 | _idle_id(0), |
241 | _is_expanded(true), |
242 | _n_visible_items_in_unexpand_mode(0), |
243 | @@ -69,14 +104,17 @@ |
244 | |
245 | _cached_name = NULL; |
246 | _group_layout = new nux::VLayout("", NUX_TRACKER_LOCATION); |
247 | - _group_layout->SetHorizontalExternalMargin(12); |
248 | + _group_layout->SetHorizontalExternalMargin(20); |
249 | _group_layout->SetVerticalExternalMargin(1); |
250 | |
251 | _group_layout->AddLayout(new nux::SpaceLayout(15,15,15,15), 0); |
252 | |
253 | + _header_view = new HeaderView(NUX_TRACKER_LOCATION); |
254 | + _group_layout->AddView(_header_view, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_FIX); |
255 | + |
256 | _header_layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
257 | _header_layout->SetHorizontalInternalMargin(10); |
258 | - _group_layout->AddLayout(_header_layout, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_FIX); |
259 | + _header_view->SetLayout(_header_layout); |
260 | |
261 | _icon = new IconTexture("", 24); |
262 | _icon->SetMinMaxSize(24, 24); |
263 | @@ -85,7 +123,7 @@ |
264 | _text_layout = new nux::HLayout(NUX_TRACKER_LOCATION); |
265 | _text_layout->SetHorizontalInternalMargin(15); |
266 | _header_layout->AddLayout(_text_layout, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); |
267 | - |
268 | + |
269 | _name = new nux::StaticCairoText("", NUX_TRACKER_LOCATION); |
270 | _name->SetTextEllipsize(nux::StaticCairoText::NUX_ELLIPSIZE_END); |
271 | _name->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_LEFT); |
272 | @@ -99,9 +137,6 @@ |
273 | _expand_label->SetTextEllipsize(nux::StaticCairoText::NUX_ELLIPSIZE_END); |
274 | _expand_label->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_LEFT); |
275 | _expand_label->SetTextColor(kExpandDefaultTextColor); |
276 | - _expand_label->SetAcceptKeyNavFocus(true); |
277 | - _expand_label->key_nav_focus_activate.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelActivated)); |
278 | - _expand_label->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged)); |
279 | |
280 | _expand_layout->AddView(_expand_label, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); |
281 | |
282 | @@ -113,19 +148,27 @@ |
283 | |
284 | SetLayout(_group_layout); |
285 | |
286 | - /* don't need to disconnect these signals as they are disconnected when this object destroys the contents */ |
287 | + // don't need to disconnect these signals as they are disconnected when this object destroys the contents |
288 | + _header_view->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter)); |
289 | + _header_view->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave)); |
290 | + _header_view->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick)); |
291 | _icon->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick)); |
292 | _icon->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter)); |
293 | _icon->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave)); |
294 | + _icon->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged)); |
295 | _name->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick)); |
296 | _name->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter)); |
297 | _name->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave)); |
298 | + _name->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged)); |
299 | _expand_label->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick)); |
300 | _expand_label->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter)); |
301 | _expand_label->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave)); |
302 | + _expand_label->key_nav_focus_activate.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelActivated)); |
303 | + _expand_label->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged)); |
304 | _expand_icon->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick)); |
305 | _expand_icon->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter)); |
306 | _expand_icon->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave)); |
307 | + _expand_icon->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged)); |
308 | } |
309 | |
310 | PlacesGroup::~PlacesGroup() |
311 | @@ -135,6 +178,8 @@ |
312 | |
313 | if (_cached_name != NULL) |
314 | g_free(_cached_name); |
315 | + |
316 | + delete _focus_layer; |
317 | } |
318 | |
319 | void |
320 | @@ -146,17 +191,9 @@ |
321 | void |
322 | PlacesGroup::OnLabelFocusChanged(nux::Area* label, bool has_focus, nux::KeyNavDirection direction) |
323 | { |
324 | - if (_expand_label->HasKeyFocus() || _expand_icon->HasKeyFocus()) |
325 | - { |
326 | - _expand_label->SetTextColor(kExpandHoverTextColor); |
327 | - _expand_icon->SetOpacity(kExpandHoverIconOpacity); |
328 | - } |
329 | - else if (!IsMouseInside()) |
330 | - { |
331 | - _expand_label->SetTextColor(kExpandDefaultTextColor); |
332 | - _expand_icon->SetOpacity(kExpandDefaultIconOpacity); |
333 | - } |
334 | + QueueDraw(); |
335 | } |
336 | + |
337 | void |
338 | PlacesGroup::SetName(const char* name) |
339 | { |
340 | @@ -248,21 +285,20 @@ |
341 | |
342 | _expand_label->SetText(final); |
343 | _expand_label->SetVisible(_n_visible_items_in_unexpand_mode < _n_total_items); |
344 | - _expand_label->SetAcceptKeyNavFocus((_n_visible_items_in_unexpand_mode < _n_total_items) ? true : false); |
345 | - |
346 | - if (_expand_label->IsVisible() == false) |
347 | - { |
348 | - if (_expand_icon->IsVisible()) |
349 | - { |
350 | - _expand_icon->SetAcceptKeyNavFocus(true); |
351 | - _expand_icon->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged)); |
352 | - } |
353 | - } |
354 | - |
355 | - if (_expand_icon->IsVisible() == false) |
356 | - { |
357 | - _expand_icon->SetAcceptKeyNavFocus(false); |
358 | - } |
359 | + |
360 | + _icon->SetAcceptKeyNavFocus(false); |
361 | + _name->SetAcceptKeyNavFocus(false); |
362 | + _expand_label->SetAcceptKeyNavFocus(false); |
363 | + _expand_icon->SetAcceptKeyNavFocus(false); |
364 | + |
365 | + if (_expand_label->IsVisible()) |
366 | + _expand_label->SetAcceptKeyNavFocus(true); |
367 | + else if (_expand_icon->IsVisible()) |
368 | + _expand_icon->SetAcceptKeyNavFocus(true); |
369 | + else if (_name->IsVisible()) |
370 | + _name->SetAcceptKeyNavFocus(true); |
371 | + else if (_icon->IsVisible()) |
372 | + _icon->SetAcceptKeyNavFocus(true); |
373 | |
374 | QueueDraw(); |
375 | |
376 | @@ -302,39 +338,80 @@ |
377 | return FALSE; |
378 | } |
379 | |
380 | -void PlacesGroup::Draw(nux::GraphicsEngine& GfxContext, |
381 | +long PlacesGroup::ComputeContentSize() |
382 | +{ |
383 | + long ret = nux::View::ComputeContentSize(); |
384 | + |
385 | + nux::Geometry const& geo = GetGeometry(); |
386 | + |
387 | + if (_cached_geometry != geo) |
388 | + { |
389 | + if (_focus_layer) |
390 | + delete _focus_layer; |
391 | + |
392 | + _focus_layer = dash::Style::Instance().FocusOverlay(geo.width - kHighlightWidthSubtractor, kHighlightHeight); |
393 | + |
394 | + _cached_geometry = geo; |
395 | + } |
396 | + |
397 | + return ret; |
398 | +} |
399 | + |
400 | +void PlacesGroup::Draw(nux::GraphicsEngine& graphics_engine, |
401 | bool forceDraw) |
402 | { |
403 | - nux::Geometry base = GetGeometry(); |
404 | - GfxContext.PushClippingRectangle(base); |
405 | - |
406 | - nux::Color col(0.15f, 0.15f, 0.15f, 0.15f); |
407 | + nux::Geometry const& base = GetGeometry(); |
408 | + graphics_engine.PushClippingRectangle(base); |
409 | + |
410 | + nux::GetPainter().PaintBackground(graphics_engine, base); |
411 | + |
412 | + graphics_engine.GetRenderStates().SetColorMask(true, true, true, false); |
413 | + graphics_engine.GetRenderStates().SetBlend(true); |
414 | + graphics_engine.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); |
415 | |
416 | if (_draw_sep) |
417 | { |
418 | - GfxContext.GetRenderStates().SetColorMask(true, true, true, true); |
419 | - GfxContext.GetRenderStates().SetBlend(true); |
420 | - GfxContext.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); |
421 | - nux::GetPainter().Draw2DLine(GfxContext, |
422 | - base.x + 15, base.y + base.height - 1, |
423 | - base.x + base.width - 15, base.y + base.height - 1, |
424 | + nux::Color col(0.15f, 0.15f, 0.15f, 0.15f); |
425 | + |
426 | + nux::GetPainter().Draw2DLine(graphics_engine, |
427 | + base.x + kSeparatorLeftPadding, base.y + base.height - 1, |
428 | + base.x + base.width - kSeparatorWidthSubtractor, base.y + base.height - 1, |
429 | col); |
430 | } |
431 | |
432 | - GfxContext.PopClippingRectangle(); |
433 | + graphics_engine.GetRenderStates().SetColorMask(true, true, true, true); |
434 | + |
435 | + if (ShouldBeHighlighted()) |
436 | + { |
437 | + nux::Geometry geo(_header_layout->GetGeometry()); |
438 | + geo.x = base.x + kHighlightLeftPadding; |
439 | + geo.width = base.width - kHighlightWidthSubtractor; |
440 | + |
441 | + _focus_layer->SetGeometry(geo); |
442 | + _focus_layer->Renderlayer(graphics_engine); |
443 | + } |
444 | + |
445 | + graphics_engine.PopClippingRectangle(); |
446 | } |
447 | |
448 | void |
449 | -PlacesGroup::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) |
450 | +PlacesGroup::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) |
451 | { |
452 | - nux::Geometry base = GetGeometry(); |
453 | - GfxContext.PushClippingRectangle(base); |
454 | - |
455 | - _group_layout->ProcessDraw(GfxContext, force_draw); |
456 | - GfxContext.PopClippingRectangle(); |
457 | + nux::Geometry const& base = GetGeometry(); |
458 | + |
459 | + graphics_engine.PushClippingRectangle(base); |
460 | + |
461 | + if (ShouldBeHighlighted() && !IsFullRedraw()) |
462 | + { |
463 | + nux::GetPainter().PushLayer(graphics_engine, _focus_layer->GetGeometry(), _focus_layer); |
464 | + } |
465 | + |
466 | + _group_layout->ProcessDraw(graphics_engine, force_draw); |
467 | + |
468 | + graphics_engine.PopClippingRectangle(); |
469 | } |
470 | |
471 | -void PlacesGroup::PostDraw(nux::GraphicsEngine& GfxContext, |
472 | +void PlacesGroup::PostDraw(nux::GraphicsEngine& graphics_engine, |
473 | bool forceDraw) |
474 | { |
475 | } |
476 | @@ -349,7 +426,7 @@ |
477 | } |
478 | |
479 | bool |
480 | -PlacesGroup::GetExpanded() |
481 | +PlacesGroup::GetExpanded() const |
482 | { |
483 | return _is_expanded; |
484 | } |
485 | @@ -385,22 +462,17 @@ |
486 | void |
487 | PlacesGroup::RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags) |
488 | { |
489 | - _expand_label->SetTextColor(kExpandHoverTextColor); |
490 | - _expand_icon->SetOpacity(kExpandHoverIconOpacity); |
491 | + QueueDraw(); |
492 | } |
493 | |
494 | void |
495 | PlacesGroup::RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags) |
496 | { |
497 | - if (!_expand_label->HasKeyFocus()) |
498 | - { |
499 | - _expand_label->SetTextColor(kExpandDefaultTextColor); |
500 | - _expand_icon->SetOpacity(kExpandDefaultIconOpacity); |
501 | - } |
502 | + QueueDraw(); |
503 | } |
504 | |
505 | int |
506 | -PlacesGroup::GetHeaderHeight() |
507 | +PlacesGroup::GetHeaderHeight() const |
508 | { |
509 | return _header_layout->GetGeometry().height; |
510 | } |
511 | @@ -413,6 +485,20 @@ |
512 | QueueDraw(); |
513 | } |
514 | |
515 | +bool PlacesGroup::HeaderHasKeyFocus() const |
516 | +{ |
517 | + return (_icon && _icon->HasKeyFocus()) || |
518 | + (_name && _name->HasKeyFocus()) || |
519 | + (_expand_label && _expand_label->HasKeyFocus()) || |
520 | + (_expand_icon && _expand_icon->HasKeyFocus()); |
521 | +} |
522 | + |
523 | +bool PlacesGroup::ShouldBeHighlighted() const |
524 | +{ |
525 | + return (_header_view && _header_view->IsMousePointerInside()) || |
526 | + HeaderHasKeyFocus(); |
527 | +} |
528 | + |
529 | // |
530 | // Key navigation |
531 | // |
532 | @@ -422,4 +508,23 @@ |
533 | return false; |
534 | } |
535 | |
536 | +// |
537 | +// Introspection |
538 | +// |
539 | +std::string PlacesGroup::GetName() const |
540 | +{ |
541 | + return "PlacesGroup"; |
542 | +} |
543 | + |
544 | +void PlacesGroup::AddProperties(GVariantBuilder* builder) |
545 | +{ |
546 | + unity::variant::BuilderWrapper wrapper(builder); |
547 | + |
548 | + wrapper.add("header-x", _header_view->GetAbsoluteX()); |
549 | + wrapper.add("header-y", _header_view->GetAbsoluteY()); |
550 | + wrapper.add("header-width", _header_view->GetAbsoluteWidth()); |
551 | + wrapper.add("header-height", _header_view->GetAbsoluteHeight()); |
552 | + wrapper.add("header-has-keyfocus", HeaderHasKeyFocus()); |
553 | +} |
554 | + |
555 | } // namespace unity |
556 | |
557 | === modified file 'plugins/unityshell/src/PlacesGroup.h' |
558 | --- plugins/unityshell/src/PlacesGroup.h 2012-02-04 05:28:23 +0000 |
559 | +++ plugins/unityshell/src/PlacesGroup.h 2012-02-07 22:51:21 +0000 |
560 | @@ -17,8 +17,8 @@ |
561 | * Authored by: Gordon Allott <gord.allott@canonical.com> |
562 | */ |
563 | |
564 | -#ifndef PLACES_GROUP_H |
565 | -#define PLACES_GROUP_H |
566 | +#ifndef UNITYSHELL_PLACES_GROUP_H |
567 | +#define UNITYSHELL_PLACES_GROUP_H |
568 | |
569 | #include <Nux/Nux.h> |
570 | #include <Nux/VLayout.h> |
571 | @@ -28,12 +28,18 @@ |
572 | #include <sigc++/sigc++.h> |
573 | |
574 | #include "IconTexture.h" |
575 | +#include "Introspectable.h" |
576 | #include "StaticCairoText.h" |
577 | |
578 | +namespace nux |
579 | +{ |
580 | +class AbstractPaintLayer; |
581 | +} |
582 | + |
583 | namespace unity |
584 | { |
585 | |
586 | -class PlacesGroup : public nux::View |
587 | +class PlacesGroup : public nux::View , public debug::Introspectable |
588 | { |
589 | NUX_DECLARE_OBJECT_TYPE(PlacesGroup, nux::View); |
590 | public: |
591 | @@ -47,7 +53,7 @@ |
592 | nux::StaticCairoText* GetLabel(); |
593 | nux::StaticCairoText* GetExpandLabel(); |
594 | |
595 | - void SetChildView(nux::View* view); |
596 | + void SetChildView(nux::View* view); |
597 | nux::View* GetChildView(); |
598 | |
599 | void SetChildLayout(nux::Layout* layout); |
600 | @@ -57,27 +63,34 @@ |
601 | void SetCounts(guint n_visible_items_in_unexpand_mode, guint n_total_items); |
602 | |
603 | void SetExpanded(bool is_expanded); |
604 | - bool GetExpanded(); |
605 | + bool GetExpanded() const; |
606 | |
607 | - int GetHeaderHeight(); |
608 | + int GetHeaderHeight() const; |
609 | |
610 | void SetDrawSeparator(bool draw_it); |
611 | |
612 | sigc::signal<void, PlacesGroup*> expanded; |
613 | |
614 | protected: |
615 | + long ComputeContentSize(); |
616 | + void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw); |
617 | + void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw); |
618 | + void PostDraw (nux::GraphicsEngine &graphics_engine, bool force_draw); |
619 | + |
620 | // Key navigation |
621 | virtual bool AcceptKeyNavFocus(); |
622 | |
623 | + // Introspection |
624 | + virtual std::string GetName() const; |
625 | + virtual void AddProperties(GVariantBuilder* builder); |
626 | + |
627 | private: |
628 | void Refresh(); |
629 | - |
630 | - void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); |
631 | - void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); |
632 | - void PostDraw (nux::GraphicsEngine &GfxContext, bool force_draw); |
633 | - |
634 | static gboolean OnIdleRelayout(PlacesGroup* self); |
635 | |
636 | + bool HeaderHasKeyFocus() const; |
637 | + bool ShouldBeHighlighted() const; |
638 | + |
639 | void RecvMouseClick(int x, int y, unsigned long button_flags, unsigned long key_flags); |
640 | void RecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); |
641 | void RecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); |
642 | @@ -87,10 +100,12 @@ |
643 | |
644 | private: |
645 | nux::VLayout* _group_layout; |
646 | + nux::View* _header_view; |
647 | nux::HLayout* _header_layout; |
648 | nux::HLayout* _text_layout; |
649 | nux::HLayout* _expand_layout; |
650 | nux::View* _child_view; |
651 | + nux::AbstractPaintLayer* _focus_layer; |
652 | |
653 | IconTexture* _icon; |
654 | nux::StaticCairoText* _name; |
655 | @@ -104,7 +119,7 @@ |
656 | guint _n_total_items; |
657 | char* _cached_name; |
658 | bool _draw_sep; |
659 | - |
660 | + nux::Geometry _cached_geometry; |
661 | }; |
662 | |
663 | } |
664 | |
665 | === modified file 'plugins/unityshell/src/SearchBar.cpp' |
666 | --- plugins/unityshell/src/SearchBar.cpp 2012-02-07 07:42:12 +0000 |
667 | +++ plugins/unityshell/src/SearchBar.cpp 2012-02-07 22:51:21 +0000 |
668 | @@ -166,7 +166,7 @@ |
669 | filter_layout_ = new nux::HLayout(); |
670 | filter_layout_->SetHorizontalInternalMargin(8); |
671 | filter_layout_->SetHorizontalExternalMargin(6); |
672 | - filter_space_ = new nux::SpaceLayout(100, 10000, 0, 1); |
673 | + filter_space_ = new nux::SpaceLayout(1, 10000, 0, 1); |
674 | filter_layout_->AddLayout(filter_space_, 1); |
675 | filter_layout_->AddView(show_filters_, 0, nux::MINOR_POSITION_CENTER); |
676 | |
677 | @@ -181,6 +181,7 @@ |
678 | |
679 | layout_->AddView(filter_layout_, 1, nux::MINOR_POSITION_RIGHT, nux::MINOR_SIZE_FULL); |
680 | } |
681 | + |
682 | sig_manager_.Add(new Signal<void, GtkSettings*, GParamSpec*> |
683 | (gtk_settings_get_default(), |
684 | "notify::gtk-font-name", |
685 | |
686 | === modified file 'tests/autopilot/autopilot/emulators/unity.py' |
687 | --- tests/autopilot/autopilot/emulators/unity.py 2012-02-07 19:18:45 +0000 |
688 | +++ tests/autopilot/autopilot/emulators/unity.py 2012-02-07 22:51:21 +0000 |
689 | @@ -372,3 +372,13 @@ |
690 | def reveal_command_lens(self): |
691 | """Reveal the 'run command' lens.""" |
692 | self._keyboard.press_and_release('Alt+F2') |
693 | + |
694 | + def get_focused_category(self): |
695 | + """Returns the current focused category. """ |
696 | + groups = self.get_state("//PlacesGroup[header-has-keyfocus=True]") |
697 | + |
698 | + if len(groups) >= 1: |
699 | + return groups[0] |
700 | + else: |
701 | + return None |
702 | + |
703 | |
704 | === modified file 'tests/autopilot/autopilot/tests/test_dash.py' |
705 | --- tests/autopilot/autopilot/tests/test_dash.py 2012-02-07 12:00:04 +0000 |
706 | +++ tests/autopilot/autopilot/tests/test_dash.py 2012-02-07 22:51:21 +0000 |
707 | @@ -10,6 +10,7 @@ |
708 | |
709 | from autopilot.emulators.unity import Dash |
710 | from autopilot.emulators.X11 import Keyboard |
711 | +from autopilot.emulators.X11 import Mouse |
712 | from autopilot.tests import AutopilotTestCase |
713 | from autopilot.glibrunner import GlibRunner |
714 | |
715 | @@ -100,6 +101,41 @@ |
716 | # ... the lens bar should lose the key focus |
717 | self.assertEqual(self.dash.get_focused_lens_icon(), "") |
718 | |
719 | + def test_category_header_keynav(self): |
720 | + """ This test makes sure that: |
721 | + 1. A category header can get the focus. |
722 | + 2. A category header stays highlight when it loses the focus |
723 | + and mouse is close to it (but not inside). |
724 | + """ |
725 | + self.dash.ensure_hidden() |
726 | + self.dash.reveal_application_lens() |
727 | + |
728 | + kb = Keyboard() |
729 | + mouse = Mouse() |
730 | + |
731 | + # Make sure that a category have the focus. |
732 | + kb.press_and_release("Down") |
733 | + category = self.dash.get_focused_category() |
734 | + self.assertIsNot(category, None) |
735 | + |
736 | + # Make sure that the category is highlighted. |
737 | + self.assertTrue(category['header-is-highlighted'], True) |
738 | + |
739 | + # Get the geometry of that category header. |
740 | + x = category['header-x'] |
741 | + y = category['header-y'] |
742 | + w = category['header-width'] |
743 | + h = category['header-height'] |
744 | + |
745 | + # Move the mouse close the view, and press down. |
746 | + mouse.move(x+w+10, y+h/2, True) |
747 | + sleep(1) |
748 | + kb.press_and_release("Down") |
749 | + |
750 | + category = self.dash.get_focused_category() |
751 | + self.assertEqual(category, None) |
752 | + |
753 | + |
754 | |
755 | |
756 |
Needs testing. It should be simple enough to write an autopilot test for this.