Merge lp:~nick-dedekind/unity/lp841899.filter-multi-range into lp:unity
- lp841899.filter-multi-range
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Andrea Azzarone |
Approved revision: | no longer in the source branch. |
Merged at revision: | 3156 |
Proposed branch: | lp:~nick-dedekind/unity/lp841899.filter-multi-range |
Merge into: | lp:unity |
Diff against target: |
1508 lines (+825/-185) 20 files modified
UnityCore/MultiRangeFilter.cpp (+42/-52) dash/FilterAllButton.cpp (+2/-0) dash/FilterAllButton.h (+1/-0) dash/FilterBasicButton.cpp (+2/-0) dash/FilterBasicButton.h (+1/-0) dash/FilterFactory.cpp (+1/-1) dash/FilterGenreButton.cpp (+2/-0) dash/FilterGenreButton.h (+1/-0) dash/FilterMultiRangeButton.cpp (+22/-17) dash/FilterMultiRangeButton.h (+2/-1) dash/FilterMultiRangeWidget.cpp (+243/-26) dash/FilterMultiRangeWidget.h (+24/-5) dash/FilterRatingsButton.cpp (+3/-0) dash/FilterRatingsButton.h (+1/-0) tests/CMakeLists.txt (+1/-0) tests/test_filter_multirange.h (+75/-0) tests/test_filter_widgets.cpp (+187/-0) tests/test_lens.cpp (+12/-17) unity-shared/DashStyle.cpp (+202/-66) unity-shared/DashStyle.h (+1/-0) |
To merge this branch: | bzr merge lp:~nick-dedekind/unity/lp841899.filter-multi-range |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Andrea Azzarone (community) | Approve | ||
John Lea (community) | Approve | ||
PS Jenkins bot | continuous-integration | Pending | |
Review via email: mp+140395@code.launchpad.net |
Commit message
Changed click/Dnd behaviour to match requested design. (LP: #841899)
Description of the change
= Problem description =
https:/
= The fix =
Changed click/Dnd behaviour to match requested design.
Fixed visual design of active range border.
= Test coverage =
Added unity tests for widget construction, clicking and drag logic.
Updated lens multi-range filter logic tests.
John Lea (johnlea) : | # |
Nick Dedekind (nick-dedekind) wrote : | # |
> + for (FilterOption::Ptr option : options_)
>
> auto const& option?
>
> 260 + auto func_invalidate = [&, geo](std:
> NuxCairoPtr>& pair)
>
> I think you can remove the & in the closure.
>
> 358 +FilterMultiRan
> 359 +{
> 360 +}
>
> Do we really need an empty dtor?
>
> 462 + if (mouse_inside == false)
> 463 + return NULL;
>
> Just use ! + nullptr
>
> 481 +void FilterMultiRang
> long button_flags, unsigned long key_flags)
> 482 +{
> 483 +}
>
> Empty function?
>
> I'll continue the review later.
All done.
Andrea Azzarone (azzar1) wrote : | # |
Code looks good. All tests pass.
Andrea Azzarone (azzar1) wrote : | # |
1023 + // filter_
1024 + // unity::
1025 +
1026 + // filter_
1027 + // EXPECT_
1028 + // unity::
Too fast... Please remove these commented lines.
Andrea Azzarone (azzar1) : | # |
Preview Diff
1 | === modified file 'UnityCore/MultiRangeFilter.cpp' |
2 | --- UnityCore/MultiRangeFilter.cpp 2012-10-29 09:34:54 +0000 |
3 | +++ UnityCore/MultiRangeFilter.cpp 2013-01-30 10:36:20 +0000 |
4 | @@ -88,64 +88,54 @@ |
5 | return; |
6 | |
7 | int position = PositionOfId(id); |
8 | - |
9 | + if (position < 0) |
10 | + return; |
11 | + |
12 | + bool activate = is_active; |
13 | + int position_above = position+1; |
14 | + int position_below = position-1; |
15 | + int filter_option_size = options_.size(); |
16 | + |
17 | + ignore_changes_ = true; |
18 | + |
19 | + // when activating a option, need to make sure we only have continuous ajacent options enabled relative to the enabled option. |
20 | if (is_active) |
21 | { |
22 | - if (left_pos_ == -1 && right_pos_ == -1) |
23 | - { |
24 | - left_pos_ = position; |
25 | - right_pos_ = position; |
26 | - } |
27 | - else if (left_pos_ > position) |
28 | - { |
29 | - left_pos_ = position; |
30 | - } |
31 | - else if (right_pos_ < position) |
32 | - { |
33 | - right_pos_ = position; |
34 | + while(position_below >= 0) |
35 | + { |
36 | + FilterOption::Ptr const& filter_option = options_[position_below--]; |
37 | + |
38 | + activate &= filter_option->active; |
39 | + filter_option->active = activate; |
40 | + } |
41 | + |
42 | + activate = is_active; |
43 | + while(position_above < filter_option_size) |
44 | + { |
45 | + FilterOption::Ptr const& filter_option = options_[position_above++]; |
46 | + |
47 | + activate &= filter_option->active; |
48 | + filter_option->active = activate; |
49 | } |
50 | } |
51 | else |
52 | { |
53 | - // Reset if the one and only block is deactivated |
54 | - if (position == right_pos_ && position == left_pos_) |
55 | - { |
56 | - left_pos_ = -1; |
57 | - right_pos_ = -1; |
58 | - } |
59 | - // If the deactivated block is on either end, remove it |
60 | - else if (position == right_pos_) |
61 | - { |
62 | - right_pos_ = position - 1; |
63 | - } |
64 | - else if (position == left_pos_) |
65 | - { |
66 | - left_pos_ = position + 1; |
67 | - } |
68 | - // It's in the middle of the range, see which side to shorten |
69 | - else if (position < (left_pos_ + ((right_pos_ - left_pos_)/2.0f))) |
70 | - { |
71 | - left_pos_ = position; |
72 | - } |
73 | - else |
74 | - { |
75 | - right_pos_ = position; |
76 | - } |
77 | - } |
78 | - |
79 | - ignore_changes_ = true; |
80 | - int i = 0; |
81 | - for(auto option: options_) |
82 | - { |
83 | - if (i < left_pos_) |
84 | - option->active = false; |
85 | - else if (i <= right_pos_) |
86 | - option->active = true; |
87 | - else |
88 | - option->active = false; |
89 | - |
90 | - i++; |
91 | - } |
92 | + // otherwise just ensure there is a single continuous option range |
93 | + bool active_found = false, inactive_found = false; |
94 | + for (FilterOption::Ptr const& option : options_) |
95 | + { |
96 | + if (inactive_found) |
97 | + option->active = false; |
98 | + else |
99 | + { |
100 | + if (option->active) |
101 | + active_found = true; |
102 | + else if (active_found) |
103 | + inactive_found = true; |
104 | + } |
105 | + } |
106 | + } |
107 | + |
108 | ignore_changes_ = false; |
109 | |
110 | UpdateState(); |
111 | |
112 | === modified file 'dash/FilterAllButton.cpp' |
113 | --- dash/FilterAllButton.cpp 2012-11-27 23:16:06 +0000 |
114 | +++ dash/FilterAllButton.cpp 2013-01-30 10:36:20 +0000 |
115 | @@ -32,6 +32,8 @@ |
116 | namespace dash |
117 | { |
118 | |
119 | +NUX_IMPLEMENT_OBJECT_TYPE(FilterAllButton); |
120 | + |
121 | FilterAllButton::FilterAllButton(NUX_FILE_LINE_DECL) |
122 | : FilterBasicButton(_("All"), NUX_FILE_LINE_PARAM) |
123 | { |
124 | |
125 | === modified file 'dash/FilterAllButton.h' |
126 | --- dash/FilterAllButton.h 2012-05-06 23:48:38 +0000 |
127 | +++ dash/FilterAllButton.h 2013-01-30 10:36:20 +0000 |
128 | @@ -35,6 +35,7 @@ |
129 | |
130 | class FilterAllButton : public FilterBasicButton |
131 | { |
132 | + NUX_DECLARE_OBJECT_TYPE(FilterAllButton, FilterBasicButton); |
133 | public: |
134 | FilterAllButton(NUX_FILE_LINE_PROTO); |
135 | ~FilterAllButton(); |
136 | |
137 | === modified file 'dash/FilterBasicButton.cpp' |
138 | --- dash/FilterBasicButton.cpp 2012-11-27 23:16:06 +0000 |
139 | +++ dash/FilterBasicButton.cpp 2013-01-30 10:36:20 +0000 |
140 | @@ -33,6 +33,8 @@ |
141 | { |
142 | namespace dash |
143 | { |
144 | + |
145 | +NUX_IMPLEMENT_OBJECT_TYPE(FilterBasicButton); |
146 | |
147 | FilterBasicButton::FilterBasicButton(nux::TextureArea* image, NUX_FILE_LINE_DECL) |
148 | : nux::ToggleButton(image, NUX_FILE_LINE_PARAM) |
149 | |
150 | === modified file 'dash/FilterBasicButton.h' |
151 | --- dash/FilterBasicButton.h 2012-09-06 05:36:00 +0000 |
152 | +++ dash/FilterBasicButton.h 2013-01-30 10:36:20 +0000 |
153 | @@ -33,6 +33,7 @@ |
154 | |
155 | class FilterBasicButton : public nux::ToggleButton |
156 | { |
157 | + NUX_DECLARE_OBJECT_TYPE(FilterBasicButton, nux::ToggleButton); |
158 | public: |
159 | FilterBasicButton(nux::TextureArea* image, NUX_FILE_LINE_PROTO); |
160 | FilterBasicButton(std::string const& label, NUX_FILE_LINE_PROTO); |
161 | |
162 | === modified file 'dash/FilterFactory.cpp' |
163 | --- dash/FilterFactory.cpp 2012-10-29 09:34:54 +0000 |
164 | +++ dash/FilterFactory.cpp 2013-01-30 10:36:20 +0000 |
165 | @@ -64,7 +64,7 @@ |
166 | } |
167 | else if (filter_type == renderer_type_multirange) |
168 | { |
169 | - widget = new FilterMultiRange(NUX_TRACKER_LOCATION); |
170 | + widget = new FilterMultiRangeWidget(NUX_TRACKER_LOCATION); |
171 | } |
172 | else if (filter_type == renderer_type_radio_options) |
173 | { |
174 | |
175 | === modified file 'dash/FilterGenreButton.cpp' |
176 | --- dash/FilterGenreButton.cpp 2012-05-06 23:48:38 +0000 |
177 | +++ dash/FilterGenreButton.cpp 2013-01-30 10:36:20 +0000 |
178 | @@ -26,6 +26,8 @@ |
179 | namespace dash |
180 | { |
181 | |
182 | +NUX_IMPLEMENT_OBJECT_TYPE(FilterGenreButton); |
183 | + |
184 | FilterGenreButton::FilterGenreButton(std::string const& label, NUX_FILE_LINE_DECL) |
185 | : FilterBasicButton(label, NUX_FILE_LINE_PARAM) |
186 | { |
187 | |
188 | === modified file 'dash/FilterGenreButton.h' |
189 | --- dash/FilterGenreButton.h 2012-05-06 23:48:38 +0000 |
190 | +++ dash/FilterGenreButton.h 2013-01-30 10:36:20 +0000 |
191 | @@ -35,6 +35,7 @@ |
192 | |
193 | class FilterGenreButton : public FilterBasicButton |
194 | { |
195 | + NUX_DECLARE_OBJECT_TYPE(FilterGenreButton, FilterBasicButton); |
196 | public: |
197 | FilterGenreButton(std::string const& label, NUX_FILE_LINE_PROTO); |
198 | FilterGenreButton(NUX_FILE_LINE_PROTO); |
199 | |
200 | === modified file 'dash/FilterMultiRangeButton.cpp' |
201 | --- dash/FilterMultiRangeButton.cpp 2012-12-13 14:53:32 +0000 |
202 | +++ dash/FilterMultiRangeButton.cpp 2013-01-30 10:36:20 +0000 |
203 | @@ -21,6 +21,7 @@ |
204 | #include "config.h" |
205 | |
206 | #include <Nux/Nux.h> |
207 | +#include <Nux/Layout.h> |
208 | |
209 | #include "unity-shared/DashStyle.h" |
210 | #include "FilterMultiRangeButton.h" |
211 | @@ -30,16 +31,19 @@ |
212 | namespace dash |
213 | { |
214 | |
215 | -FilterMultiRangeButton::FilterMultiRangeButton(std::string const& label, NUX_FILE_LINE_DECL) |
216 | - : nux::ToggleButton(label, NUX_FILE_LINE_PARAM) |
217 | - , has_arrow_(MultiRangeArrow::NONE) |
218 | - , side_(MultiRangeSide::CENTER) |
219 | +namespace |
220 | { |
221 | - Init(); |
222 | +const int kFontSizePx = 10; |
223 | + |
224 | +const int kLayoutPadLeftRight = 4; |
225 | +const int kLayoutPadtopBottom = 2; |
226 | } |
227 | |
228 | +NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRangeButton); |
229 | + |
230 | FilterMultiRangeButton::FilterMultiRangeButton(NUX_FILE_LINE_DECL) |
231 | : nux::ToggleButton(NUX_FILE_LINE_PARAM) |
232 | + , theme_init_(false) |
233 | , has_arrow_(MultiRangeArrow::NONE) |
234 | , side_(MultiRangeSide::CENTER) |
235 | { |
236 | @@ -53,8 +57,9 @@ |
237 | void FilterMultiRangeButton::Init() |
238 | { |
239 | InitTheme(); |
240 | + // Controlled by parent widget |
241 | SetAcceptKeyNavFocusOnMouseDown(false); |
242 | - SetAcceptKeyNavFocusOnMouseEnter(true); |
243 | + SetAcceptKeyNavFocusOnMouseEnter(false); |
244 | |
245 | state_change.connect(sigc::mem_fun(this, &FilterMultiRangeButton::OnActivated)); |
246 | key_nav_focus_change.connect([&](nux::Area*, bool, nux::KeyNavDirection) { QueueDraw(); }); |
247 | @@ -105,23 +110,22 @@ |
248 | { |
249 | long ret = nux::ToggleButton::ComputeContentSize(); |
250 | nux::Geometry const& geo = GetGeometry(); |
251 | - if (cached_geometry_ != geo) |
252 | + if (theme_init_ && cached_geometry_ != geo) |
253 | { |
254 | cached_geometry_ = geo; |
255 | |
256 | std::vector<MultiRangeSide> sides = {MultiRangeSide::LEFT, MultiRangeSide::RIGHT, MultiRangeSide::CENTER}; |
257 | std::vector<MultiRangeArrow> arrows = {MultiRangeArrow::LEFT, MultiRangeArrow::RIGHT, MultiRangeArrow::BOTH, MultiRangeArrow::NONE}; |
258 | |
259 | - for (auto arrow : arrows) |
260 | + auto func_invalidate = [geo](std::pair<const MapKey, NuxCairoPtr>& pair) |
261 | { |
262 | - for (auto side : sides) |
263 | - { |
264 | - prelight_[MapKey(arrow, side)]->Invalidate(geo); |
265 | - active_[MapKey(arrow, side)]->Invalidate(geo); |
266 | - normal_[MapKey(arrow, side)]->Invalidate(geo); |
267 | - focus_[MapKey(arrow, side)]->Invalidate(geo); |
268 | - } |
269 | - } |
270 | + pair.second->Invalidate(geo); |
271 | + }; |
272 | + |
273 | + for_each (prelight_.begin(), prelight_.end(), func_invalidate); |
274 | + for_each (active_.begin(), active_.end(), func_invalidate); |
275 | + for_each (normal_.begin(), normal_.end(), func_invalidate); |
276 | + for_each (focus_.begin(), focus_.end(), func_invalidate); |
277 | } |
278 | |
279 | return ret; |
280 | @@ -149,6 +153,7 @@ |
281 | } |
282 | |
283 | SetMinimumHeight(dash::Style::Instance().GetFilterButtonHeight() + 3); |
284 | + theme_init_ = true; |
285 | } |
286 | |
287 | void FilterMultiRangeButton::RedrawTheme(nux::Geometry const& geom, |
288 | @@ -182,7 +187,7 @@ |
289 | else |
290 | segment = Segment::RIGHT; |
291 | |
292 | - Style::Instance().MultiRangeSegment(cr, faked_state, name, arrow, segment); |
293 | + Style::Instance().MultiRangeSegment(cr, faked_state, name, kFontSizePx, arrow, segment); |
294 | NeedRedraw(); |
295 | } |
296 | |
297 | |
298 | === modified file 'dash/FilterMultiRangeButton.h' |
299 | --- dash/FilterMultiRangeButton.h 2012-05-06 23:48:38 +0000 |
300 | +++ dash/FilterMultiRangeButton.h 2013-01-30 10:36:20 +0000 |
301 | @@ -52,8 +52,8 @@ |
302 | |
303 | class FilterMultiRangeButton : public nux::ToggleButton |
304 | { |
305 | + NUX_DECLARE_OBJECT_TYPE(FilterMultiRangeButton, nux::ToggleButton); |
306 | public: |
307 | - FilterMultiRangeButton (std::string const& label, NUX_FILE_LINE_PROTO); |
308 | FilterMultiRangeButton (NUX_FILE_LINE_PROTO); |
309 | ~FilterMultiRangeButton(); |
310 | |
311 | @@ -94,6 +94,7 @@ |
312 | std::map<MapKey, NuxCairoPtr> focus_; |
313 | std::map<MapKey, NuxCairoPtr> normal_; |
314 | std::map<MapKey, NuxCairoPtr> prelight_; |
315 | + bool theme_init_; |
316 | |
317 | nux::Geometry cached_geometry_; |
318 | MultiRangeArrow has_arrow_; |
319 | |
320 | === modified file 'dash/FilterMultiRangeWidget.cpp' |
321 | --- dash/FilterMultiRangeWidget.cpp 2012-11-27 23:16:06 +0000 |
322 | +++ dash/FilterMultiRangeWidget.cpp 2013-01-30 10:36:20 +0000 |
323 | @@ -37,10 +37,11 @@ |
324 | namespace dash |
325 | { |
326 | |
327 | -NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRange); |
328 | +NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRangeWidget); |
329 | |
330 | -FilterMultiRange::FilterMultiRange(NUX_FILE_LINE_DECL) |
331 | +FilterMultiRangeWidget::FilterMultiRangeWidget(NUX_FILE_LINE_DECL) |
332 | : FilterExpanderLabel(_("Multi-range"), NUX_FILE_LINE_PARAM) |
333 | + , dragging_(false) |
334 | { |
335 | InitTheme(); |
336 | |
337 | @@ -59,21 +60,30 @@ |
338 | SetRightHandView(all_button_); |
339 | SetContents(layout_); |
340 | OnActiveChanged(false); |
341 | -} |
342 | - |
343 | -FilterMultiRange::~FilterMultiRange() |
344 | -{ |
345 | -} |
346 | - |
347 | -void FilterMultiRange::SetFilter(Filter::Ptr const& filter) |
348 | -{ |
349 | + |
350 | + mouse_move.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseMove)); |
351 | + mouse_down.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseDown)); |
352 | + mouse_up.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseUp)); |
353 | + |
354 | + mouse_drag.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::RecvMouseDrag)); |
355 | +} |
356 | + |
357 | +void FilterMultiRangeWidget::SetFilter(Filter::Ptr const& filter) |
358 | +{ |
359 | + // Reset filter. |
360 | + layout_->Clear(); |
361 | + buttons_.clear(); |
362 | + mouse_down_button_.Release(); |
363 | + mouse_down_left_active_button_.Release(); |
364 | + mouse_down_right_active_button_.Release(); |
365 | + |
366 | filter_ = std::static_pointer_cast<MultiRangeFilter>(filter); |
367 | |
368 | all_button_->SetFilter(filter_); |
369 | expanded = !filter_->collapsed(); |
370 | |
371 | - filter_->option_added.connect(sigc::mem_fun(this, &FilterMultiRange::OnOptionAdded)); |
372 | - filter_->option_removed.connect(sigc::mem_fun(this, &FilterMultiRange::OnOptionRemoved)); |
373 | + filter_->option_added.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnOptionAdded)); |
374 | + filter_->option_removed.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnOptionRemoved)); |
375 | |
376 | // finally - make sure we are up-todate with our filter list |
377 | for (auto it : filter_->options()) |
378 | @@ -82,7 +92,7 @@ |
379 | SetLabel(filter_->name); |
380 | } |
381 | |
382 | -void FilterMultiRange::OnActiveChanged(bool value) |
383 | +void FilterMultiRangeWidget::OnActiveChanged(bool value) |
384 | { |
385 | // go through all the buttons, and set the state :( |
386 | int start = 2000; |
387 | @@ -91,10 +101,11 @@ |
388 | for (auto button : buttons_) |
389 | { |
390 | FilterOption::Ptr filter = button->GetFilter(); |
391 | - bool tmp_active = filter->active; |
392 | - button->SetActive(tmp_active); |
393 | if (filter != nullptr) |
394 | { |
395 | + bool tmp_active = filter->active; |
396 | + button->SetActive(tmp_active); |
397 | + |
398 | if (filter->active) |
399 | { |
400 | if (index < start) |
401 | @@ -129,43 +140,249 @@ |
402 | } |
403 | } |
404 | |
405 | -void FilterMultiRange::OnOptionAdded(FilterOption::Ptr const& new_filter) |
406 | +void FilterMultiRangeWidget::OnOptionAdded(FilterOption::Ptr const& new_filter) |
407 | { |
408 | - FilterMultiRangeButton* button = new FilterMultiRangeButton(NUX_TRACKER_LOCATION); |
409 | + FilterMultiRangeButtonPtr button(new FilterMultiRangeButton(NUX_TRACKER_LOCATION)); |
410 | button->SetFilter(new_filter); |
411 | - layout_->AddView(button); |
412 | + layout_->AddView(button.GetPointer()); |
413 | buttons_.push_back(button); |
414 | - new_filter->active.changed.connect(sigc::mem_fun(this, &FilterMultiRange::OnActiveChanged)); |
415 | + new_filter->active.changed.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnActiveChanged)); |
416 | OnActiveChanged(false); |
417 | |
418 | + QueueRelayout(); |
419 | } |
420 | |
421 | -void FilterMultiRange::OnOptionRemoved(FilterOption::Ptr const& removed_filter) |
422 | +void FilterMultiRangeWidget::OnOptionRemoved(FilterOption::Ptr const& removed_filter) |
423 | { |
424 | for (auto it=buttons_.begin() ; it != buttons_.end(); it++) |
425 | { |
426 | if ((*it)->GetFilter() == removed_filter) |
427 | { |
428 | - layout_->RemoveChildObject(*it); |
429 | + layout_->RemoveChildObject(it->GetPointer()); |
430 | buttons_.erase(it); |
431 | break; |
432 | } |
433 | } |
434 | - |
435 | OnActiveChanged(false); |
436 | + |
437 | + QueueRelayout(); |
438 | } |
439 | |
440 | -std::string FilterMultiRange::GetFilterType() |
441 | +std::string FilterMultiRangeWidget::GetFilterType() |
442 | { |
443 | - return "FilterMultiRange"; |
444 | + return "FilterMultiRangeWidget"; |
445 | } |
446 | |
447 | -void FilterMultiRange::InitTheme() |
448 | +void FilterMultiRangeWidget::InitTheme() |
449 | { |
450 | //FIXME - build theme here - store images, cache them, fun fun fun |
451 | } |
452 | |
453 | -void FilterMultiRange::ClearRedirectedRenderChildArea() |
454 | +nux::Area* FilterMultiRangeWidget::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) |
455 | +{ |
456 | + bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); |
457 | + if (!mouse_inside) |
458 | + return nullptr; |
459 | + |
460 | + nux::Area* area = View::FindAreaUnderMouse(mouse_position, nux::NUX_MOUSE_MOVE); |
461 | + if (area && area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType)) |
462 | + { |
463 | + return this; |
464 | + } |
465 | + |
466 | + return area; |
467 | +} |
468 | + |
469 | +void FilterMultiRangeWidget::RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) |
470 | +{ |
471 | + nux::Geometry geo = GetAbsoluteGeometry(); |
472 | + nux::Point abs_cursor(geo.x + x, geo.y + y); |
473 | + UpdateMouseFocus(abs_cursor); |
474 | +} |
475 | + |
476 | +void FilterMultiRangeWidget::RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags) |
477 | +{ |
478 | + mouse_down_button_.Release(); |
479 | + mouse_down_left_active_button_.Release(); |
480 | + mouse_down_right_active_button_.Release(); |
481 | + |
482 | + dragging_ = false; |
483 | + nux::Geometry geo = GetAbsoluteGeometry(); |
484 | + nux::Point abs_cursor(geo.x + x, geo.y + y); |
485 | + |
486 | + nux::Area* area = View::FindAreaUnderMouse(nux::Point(abs_cursor.x, abs_cursor.y), nux::NUX_MOUSE_PRESSED); |
487 | + |
488 | + if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType)) |
489 | + return; |
490 | + mouse_down_button_ = static_cast<FilterMultiRangeButton*>(area); |
491 | + |
492 | + // Cache the left/right selected buttons. |
493 | + FilterMultiRangeButtonPtr last_selected_button; |
494 | + for (FilterMultiRangeButtonPtr button : buttons_) |
495 | + { |
496 | + if (button->Active()) |
497 | + { |
498 | + if (!mouse_down_left_active_button_.IsValid()) |
499 | + mouse_down_left_active_button_ = button; |
500 | + last_selected_button = button; |
501 | + } |
502 | + } |
503 | + mouse_down_right_active_button_ = last_selected_button; |
504 | +} |
505 | + |
506 | +void FilterMultiRangeWidget::RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags) |
507 | +{ |
508 | + FilterMultiRangeButtonPtr mouse_down_button(mouse_down_button_); |
509 | + mouse_down_button_.Release(); |
510 | + |
511 | + if (dragging_) |
512 | + { |
513 | + dragging_ = false; |
514 | + return; |
515 | + } |
516 | + |
517 | + nux::Geometry geo = GetAbsoluteGeometry(); |
518 | + nux::Area* area = View::FindAreaUnderMouse(nux::Point(geo.x + x, geo.y + y), nux::NUX_MOUSE_RELEASED); |
519 | + if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType)) |
520 | + return; |
521 | + |
522 | + FilterMultiRangeButtonPtr mouse_up_button; |
523 | + mouse_up_button = static_cast<FilterMultiRangeButton*>(area); |
524 | + if (mouse_up_button == mouse_down_button) |
525 | + Click(mouse_up_button); |
526 | +} |
527 | + |
528 | +void FilterMultiRangeWidget::RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags) |
529 | +{ |
530 | + nux::Geometry geo = GetAbsoluteGeometry(); |
531 | + nux::Point abs_cursor(geo.x + x, geo.y + y); |
532 | + UpdateMouseFocus(abs_cursor); |
533 | + |
534 | + if (!CheckDrag()) |
535 | + return; |
536 | + |
537 | + nux::Area* area = View::FindAreaUnderMouse(nux::Point(abs_cursor.x, abs_cursor.y), nux::NUX_MOUSE_MOVE); |
538 | + if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType)) |
539 | + return; |
540 | + |
541 | + FilterMultiRangeButtonPtr drag_over_button; |
542 | + drag_over_button = static_cast<FilterMultiRangeButton*>(area); |
543 | + if (!drag_over_button.IsValid()) |
544 | + return; |
545 | + dragging_ = true; |
546 | + |
547 | + nux::Geometry mouse_down_button_geometry = mouse_down_button_->GetAbsoluteGeometry(); |
548 | + |
549 | + nux::Geometry left_active_button_geometry = mouse_down_left_active_button_->GetAbsoluteGeometry(); |
550 | + nux::Geometry right_active_button_geometry = mouse_down_right_active_button_->GetAbsoluteGeometry(); |
551 | + |
552 | + auto end = buttons_.end(); |
553 | + int found_buttons = 0; |
554 | + for (auto iter = buttons_.begin(); iter != end; ++iter) |
555 | + { |
556 | + FilterMultiRangeButtonPtr button = *iter; |
557 | + bool activate = false; |
558 | + |
559 | + // if we've dragged the left button, we want to activate everything between the "drag over button" and the "right button" |
560 | + if (mouse_down_button_ == mouse_down_left_active_button_ && |
561 | + button == mouse_down_right_active_button_) |
562 | + { |
563 | + found_buttons++; |
564 | + activate = true; |
565 | + } |
566 | + // if we've dragged the right button, we want to activate everything between the "left button" and the "drag over button" |
567 | + else if (mouse_down_button_ == mouse_down_right_active_button_ && |
568 | + button == mouse_down_left_active_button_) |
569 | + { |
570 | + found_buttons++; |
571 | + activate = true; |
572 | + } |
573 | + |
574 | + if (button == drag_over_button) |
575 | + { |
576 | + found_buttons++; |
577 | + activate = true; |
578 | + } |
579 | + |
580 | + if (activate || (found_buttons > 0 && found_buttons < 2)) |
581 | + { |
582 | + button->Activate(); |
583 | + } |
584 | + else |
585 | + { |
586 | + button->Deactivate(); |
587 | + } |
588 | + } |
589 | +} |
590 | + |
591 | +bool FilterMultiRangeWidget::CheckDrag() |
592 | +{ |
593 | + if (!mouse_down_button_) |
594 | + return false; |
595 | + |
596 | + auto end = buttons_.end(); |
597 | + bool between = false; |
598 | + bool active_found = false; |
599 | + for (auto iter = buttons_.begin(); iter != end; ++iter) |
600 | + { |
601 | + FilterMultiRangeButtonPtr button = *iter; |
602 | + if (button->Active()) |
603 | + { |
604 | + active_found = true; |
605 | + if (button == mouse_down_button_) |
606 | + { |
607 | + between = true; |
608 | + } |
609 | + } |
610 | + else if (active_found) |
611 | + { |
612 | + active_found = false; |
613 | + break; |
614 | + } |
615 | + } |
616 | + |
617 | + if (mouse_down_button_ != mouse_down_left_active_button_ && mouse_down_button_ != mouse_down_right_active_button_) |
618 | + { |
619 | + if (between) |
620 | + return false; |
621 | + mouse_down_left_active_button_ = mouse_down_button_; |
622 | + mouse_down_right_active_button_ = mouse_down_button_; |
623 | + } |
624 | + |
625 | + return true; |
626 | +} |
627 | + |
628 | +void FilterMultiRangeWidget::UpdateMouseFocus(nux::Point const& abs_cursor_position) |
629 | +{ |
630 | + nux::Area* area = View::FindAreaUnderMouse(nux::Point(abs_cursor_position.x, abs_cursor_position.y), nux::NUX_MOUSE_MOVE); |
631 | + if (!area || !area->Type().IsDerivedFromType(FilterMultiRangeButton::StaticObjectType)) |
632 | + return; |
633 | + |
634 | + nux::GetWindowCompositor().SetKeyFocusArea(static_cast<InputArea*>(area), nux::KEY_NAV_NONE); |
635 | +} |
636 | + |
637 | +void FilterMultiRangeWidget::Click(FilterMultiRangeButtonPtr const& activated_button) |
638 | +{ |
639 | + bool current_activated = activated_button->Active(); |
640 | + bool any_others_active = false; |
641 | + |
642 | + for (FilterMultiRangeButtonPtr button : buttons_) |
643 | + { |
644 | + if (button != activated_button) |
645 | + { |
646 | + if (button->Active()) |
647 | + any_others_active = true; |
648 | + button->Deactivate(); |
649 | + } |
650 | + } |
651 | + |
652 | + if (!any_others_active && current_activated) |
653 | + activated_button->Deactivate(); |
654 | + else |
655 | + activated_button->Activate(); |
656 | +} |
657 | + |
658 | +void FilterMultiRangeWidget::ClearRedirectedRenderChildArea() |
659 | { |
660 | for (auto button : buttons_) |
661 | { |
662 | |
663 | === modified file 'dash/FilterMultiRangeWidget.h' |
664 | --- dash/FilterMultiRangeWidget.h 2012-11-27 23:16:06 +0000 |
665 | +++ dash/FilterMultiRangeWidget.h 2013-01-30 10:36:20 +0000 |
666 | @@ -39,12 +39,12 @@ |
667 | |
668 | class FilterMultiRangeButton; |
669 | |
670 | -class FilterMultiRange : public FilterExpanderLabel |
671 | +class FilterMultiRangeWidget : public FilterExpanderLabel |
672 | { |
673 | - NUX_DECLARE_OBJECT_TYPE(FilterMultiRange, FilterExpanderLabel); |
674 | + NUX_DECLARE_OBJECT_TYPE(FilterMultiRangeWidget, FilterExpanderLabel); |
675 | + typedef nux::ObjectPtr<FilterMultiRangeButton> FilterMultiRangeButtonPtr; |
676 | public: |
677 | - FilterMultiRange(NUX_FILE_LINE_PROTO); |
678 | - virtual ~FilterMultiRange(); |
679 | + FilterMultiRangeWidget(NUX_FILE_LINE_PROTO); |
680 | |
681 | void SetFilter(Filter::Ptr const& filter); |
682 | std::string GetFilterType(); |
683 | @@ -52,6 +52,13 @@ |
684 | protected: |
685 | void InitTheme(); |
686 | |
687 | + nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type); |
688 | + |
689 | + void RecvMouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); |
690 | + void RecvMouseUp(int x, int y, unsigned long button_flags, unsigned long key_flags); |
691 | + void RecvMouseDown(int x, int y, unsigned long button_flags, unsigned long key_flags); |
692 | + void RecvMouseDrag(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); |
693 | + |
694 | void ClearRedirectedRenderChildArea(); |
695 | |
696 | private: |
697 | @@ -60,11 +67,23 @@ |
698 | void OnOptionRemoved(dash::FilterOption::Ptr const& removed_filter); |
699 | void OnActiveChanged(bool value); |
700 | |
701 | + void UpdateMouseFocus(nux::Point const& abs_cursor_position); |
702 | + virtual void Click(FilterMultiRangeButtonPtr const& button); |
703 | + |
704 | + bool CheckDrag(); |
705 | + |
706 | nux::HLayout* layout_; |
707 | FilterAllButton* all_button_; |
708 | |
709 | - std::vector<FilterMultiRangeButton*> buttons_; |
710 | + std::vector<FilterMultiRangeButtonPtr> buttons_; |
711 | MultiRangeFilter::Ptr filter_; |
712 | + |
713 | + FilterMultiRangeButtonPtr mouse_down_button_; |
714 | + FilterMultiRangeButtonPtr mouse_down_left_active_button_; |
715 | + FilterMultiRangeButtonPtr mouse_down_right_active_button_; |
716 | + bool dragging_; |
717 | + |
718 | + friend class TestFilterMultiRangeWidget; |
719 | }; |
720 | |
721 | } // unityshell dash |
722 | |
723 | === modified file 'dash/FilterRatingsButton.cpp' |
724 | --- dash/FilterRatingsButton.cpp 2012-12-13 14:53:32 +0000 |
725 | +++ dash/FilterRatingsButton.cpp 2013-01-30 10:36:20 +0000 |
726 | @@ -38,6 +38,9 @@ |
727 | { |
728 | namespace dash |
729 | { |
730 | + |
731 | +NUX_IMPLEMENT_OBJECT_TYPE(FilterRatingsButton); |
732 | + |
733 | FilterRatingsButton::FilterRatingsButton(NUX_FILE_LINE_DECL) |
734 | : nux::ToggleButton(NUX_FILE_LINE_PARAM) |
735 | , focused_star_(-1) |
736 | |
737 | === modified file 'dash/FilterRatingsButton.h' |
738 | --- dash/FilterRatingsButton.h 2012-05-06 23:48:38 +0000 |
739 | +++ dash/FilterRatingsButton.h 2013-01-30 10:36:20 +0000 |
740 | @@ -36,6 +36,7 @@ |
741 | |
742 | class FilterRatingsButton : public nux::ToggleButton |
743 | { |
744 | + NUX_DECLARE_OBJECT_TYPE(FilterRatingsButton, nux::ToggleButton); |
745 | public: |
746 | FilterRatingsButton(NUX_FILE_LINE_PROTO); |
747 | virtual ~FilterRatingsButton(); |
748 | |
749 | === modified file 'tests/CMakeLists.txt' |
750 | --- tests/CMakeLists.txt 2013-01-29 23:05:50 +0000 |
751 | +++ tests/CMakeLists.txt 2013-01-30 10:36:20 +0000 |
752 | @@ -198,6 +198,7 @@ |
753 | test_desktop_launcher_icon.cpp |
754 | test_device_launcher_section.cpp |
755 | test_edge_barrier_controller.cpp |
756 | + test_filter_widgets.cpp |
757 | test_hud_button.cpp |
758 | test_hud_controller.cpp |
759 | test_hud_launcher_icon.cpp |
760 | |
761 | === added file 'tests/test_filter_multirange.h' |
762 | --- tests/test_filter_multirange.h 1970-01-01 00:00:00 +0000 |
763 | +++ tests/test_filter_multirange.h 2013-01-30 10:36:20 +0000 |
764 | @@ -0,0 +1,75 @@ |
765 | +/* |
766 | + * Copyright 2012 Canonical Ltd. |
767 | + * |
768 | + * This program is free software: you can redistribute it and/or modify it |
769 | + * under the terms of the GNU Lesser General Public License version 3, as |
770 | + * published by the Free Software Foundation. |
771 | + * |
772 | + * This program is distributed in the hope that it will be useful, but |
773 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
774 | + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
775 | + * PURPOSE. See the applicable version of the GNU Lesser General Public |
776 | + * License for more details. |
777 | + * |
778 | + * You should have received a copy of both the GNU Lesser General Public |
779 | + * License version 3 along with this program. If not, see |
780 | + * <http://www.gnu.org/licenses/> |
781 | + * |
782 | + * Authored by: Nick Dedekind <nick.dedekind@canonical.com> |
783 | + * |
784 | + */ |
785 | + |
786 | +#ifndef TEST_FILTER |
787 | +#define TEST_FILTER |
788 | + |
789 | +#include <glib-object.h> |
790 | +#include <gtest/gtest.h> |
791 | + |
792 | +#include "UnityCore/MultiRangeFilter.h" |
793 | + |
794 | +namespace unity |
795 | +{ |
796 | +namespace testing |
797 | +{ |
798 | + |
799 | +GVariantBuilder* AddFilterHint(GVariantBuilder* builder, const char* name, GVariant* value) |
800 | +{ |
801 | + if (builder == NULL) |
802 | + builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
803 | + g_variant_builder_add (builder, "{sv}", name, value); |
804 | + return builder; |
805 | +} |
806 | + |
807 | +GVariant* AddFilterOptions(std::vector<bool> option_active) |
808 | +{ |
809 | + GVariantBuilder* builder; |
810 | + builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); |
811 | + |
812 | + int i = 0; |
813 | + for (auto iter = option_active.begin(), end = option_active.end(); iter != end; ++iter) |
814 | + { |
815 | + std::stringstream name; |
816 | + name << i++; |
817 | + |
818 | + const char* pstr_name = name.str().c_str(); |
819 | + |
820 | + g_variant_builder_add (builder, "(sssb)", pstr_name, pstr_name, "", FALSE); |
821 | + } |
822 | + return g_variant_builder_end (builder); |
823 | +} |
824 | + |
825 | +void ExpectFilterRange(unity::dash::MultiRangeFilter::Ptr const& filter, int first, int last) |
826 | +{ |
827 | + int i = 0; |
828 | + for (auto option : filter->options()) |
829 | + { |
830 | + bool should_be_active = i >= first && i <= last; |
831 | + EXPECT_EQ(option->active, should_be_active); |
832 | + i++; |
833 | + } |
834 | +} |
835 | + |
836 | +} // namespace testing |
837 | +} // namespace unity |
838 | + |
839 | +#endif |
840 | \ No newline at end of file |
841 | |
842 | === added file 'tests/test_filter_widgets.cpp' |
843 | --- tests/test_filter_widgets.cpp 1970-01-01 00:00:00 +0000 |
844 | +++ tests/test_filter_widgets.cpp 2013-01-30 10:36:20 +0000 |
845 | @@ -0,0 +1,187 @@ |
846 | +/* |
847 | + * Copyright 2012 Canonical Ltd. |
848 | + * |
849 | + * This program is free software: you can redistribute it and/or modify it |
850 | + * under the terms of the GNU Lesser General Public License version 3, as |
851 | + * published by the Free Software Foundation. |
852 | + * |
853 | + * This program is distributed in the hope that it will be useful, but |
854 | + * WITHOUT ANY WARRANTY; without even the implied warranties of |
855 | + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR |
856 | + * PURPOSE. See the applicable version of the GNU Lesser General Public |
857 | + * License for more details. |
858 | + * |
859 | + * You should have received a copy of both the GNU Lesser General Public |
860 | + * License version 3 along with this program. If not, see |
861 | + * <http://www.gnu.org/licenses/> |
862 | + * |
863 | + * Authored by: Nick Dedekind <nick.dedekind@canonical.com> |
864 | + * |
865 | + */ |
866 | + |
867 | +#include <list> |
868 | + |
869 | +#include <gtest/gtest.h> |
870 | +#include "test_filter_multirange.h" |
871 | +#include "unity-shared/DashStyle.h" |
872 | +#include "unity-shared/UnitySettings.h" |
873 | + |
874 | +#include <Nux/Nux.h> |
875 | +#include <NuxGraphics/Events.h> |
876 | +#include <NuxCore/ObjectPtr.h> |
877 | + |
878 | +#include <UnityCore/GLibWrapper.h> |
879 | +#include "UnityCore/MultiRangeFilter.h" |
880 | +#include "dash/FilterMultiRangeWidget.h" |
881 | +#include "dash/FilterMultiRangeButton.h" |
882 | + |
883 | +using namespace unity; |
884 | + |
885 | +namespace unity |
886 | +{ |
887 | +namespace dash |
888 | +{ |
889 | + |
890 | +class TestFilterMultiRangeWidget : public ::testing::Test |
891 | +{ |
892 | +public: |
893 | + TestFilterMultiRangeWidget() |
894 | + : model_(dee_sequence_model_new()) |
895 | + , filter_widget_(new MockFilterMultiRangeWidget()) |
896 | + { |
897 | + dee_model_set_schema(model_, "s", "s", "s", "s", "a{sv}", "b", "b", "b", NULL); |
898 | + } |
899 | + |
900 | + void SetFilter(MultiRangeFilter::Ptr const& filter) |
901 | + { |
902 | + filter_widget_->SetFilter(filter); |
903 | + |
904 | + filter_widget_->ComputeContentSize(); |
905 | + filter_widget_->ComputeContentPosition(0,0); |
906 | + } |
907 | + |
908 | + class MockFilterMultiRangeWidget : public FilterMultiRangeWidget |
909 | + { |
910 | + public: |
911 | + MockFilterMultiRangeWidget() |
912 | + : clicked_(false) |
913 | + { |
914 | + } |
915 | + |
916 | + void ResetState() |
917 | + { |
918 | + clicked_ = false; |
919 | + } |
920 | + |
921 | + bool clicked_; |
922 | + |
923 | + using FilterMultiRangeWidget::all_button_; |
924 | + using FilterMultiRangeWidget::buttons_; |
925 | + using FilterMultiRangeWidget::dragging_; |
926 | + |
927 | + using InputArea::EmitMouseDownSignal; |
928 | + using InputArea::EmitMouseUpSignal; |
929 | + using InputArea::EmitMouseDragSignal; |
930 | + |
931 | + using FilterMultiRangeWidget::mouse_down_button_; |
932 | + |
933 | + protected: |
934 | + |
935 | + virtual void Click(FilterMultiRangeButtonPtr const& button) |
936 | + { |
937 | + clicked_ = true; |
938 | + FilterMultiRangeWidget::Click(button); |
939 | + } |
940 | + }; |
941 | + |
942 | + |
943 | + static DeeModelIter* AddMultiRangeFilterOptions(glib::Object<DeeModel> const& model) |
944 | + { |
945 | + std::vector<bool> option_active(6, false); |
946 | + GVariantBuilder* builder = nullptr; |
947 | + builder = unity::testing::AddFilterHint(builder, "options", unity::testing::AddFilterOptions(option_active)); |
948 | + GVariant* hints = g_variant_builder_end(builder); |
949 | + |
950 | + return dee_model_append(model, |
951 | + "genre", |
952 | + "Genre", |
953 | + "gtk-apply", |
954 | + "genre", |
955 | + hints, |
956 | + TRUE, |
957 | + FALSE, // collapsed |
958 | + FALSE); |
959 | + } |
960 | + |
961 | + Settings unity_settings_; |
962 | + dash::Style dash_style_; |
963 | + |
964 | + glib::Object<DeeModel> model_; |
965 | + nux::ObjectPtr<MockFilterMultiRangeWidget> filter_widget_; |
966 | +}; |
967 | + |
968 | +TEST_F(TestFilterMultiRangeWidget, TestConstruction) |
969 | +{ |
970 | + MultiRangeFilter::Ptr filter(new MultiRangeFilter(model_, AddMultiRangeFilterOptions(model_))); |
971 | + SetFilter(filter); |
972 | + |
973 | + ASSERT_EQ(filter_widget_->buttons_.size(), 6); |
974 | +} |
975 | + |
976 | +TEST_F(TestFilterMultiRangeWidget, TestClick) |
977 | +{ |
978 | + MultiRangeFilter::Ptr filter(new MultiRangeFilter(model_, AddMultiRangeFilterOptions(model_))); |
979 | + SetFilter(filter); |
980 | + |
981 | + FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button = filter_widget_->buttons_[1]; |
982 | + nux::Geometry geo_button = filter_button->GetAbsoluteGeometry(); |
983 | + nux::Point center_button1(geo_button.x + geo_button.width/2, geo_button.y + geo_button.height/2); |
984 | + |
985 | + filter_widget_->EmitMouseDownSignal(center_button1.x, center_button1.y, NUX_STATE_BUTTON1_DOWN|NUX_EVENT_BUTTON1_DOWN, 0); |
986 | + ASSERT_NE(filter_widget_->mouse_down_button_, nullptr); |
987 | + |
988 | + filter_widget_->EmitMouseUpSignal(center_button1.y, center_button1.y, NUX_EVENT_BUTTON1_UP, 0); |
989 | + ASSERT_EQ(filter_widget_->mouse_down_button_, nullptr); |
990 | + |
991 | + EXPECT_EQ(filter_widget_->clicked_, true); |
992 | + EXPECT_EQ(filter_button->Active(), true); |
993 | + EXPECT_EQ(filter->options()[1]->active, true); |
994 | +} |
995 | + |
996 | +TEST_F(TestFilterMultiRangeWidget, TestDrag) |
997 | +{ |
998 | + MultiRangeFilter::Ptr filter(new MultiRangeFilter(model_, AddMultiRangeFilterOptions(model_))); |
999 | + SetFilter(filter); |
1000 | + |
1001 | + // Genre "1" |
1002 | + FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button1 = filter_widget_->buttons_[1]; |
1003 | + nux::Geometry geo_button1 = filter_button1->GetAbsoluteGeometry(); |
1004 | + nux::Point center_button1(geo_button1.x + geo_button1.width/2, geo_button1.y + geo_button1.height/2); |
1005 | + |
1006 | + // Genre "3" |
1007 | + FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button3 = filter_widget_->buttons_[3]; |
1008 | + nux::Geometry geo_button3 = filter_button3->GetAbsoluteGeometry(); |
1009 | + nux::Point center_button3(geo_button3.x + geo_button3.width/2, geo_button3.y + geo_button3.height/2); |
1010 | + |
1011 | + // Genre "4" |
1012 | + FilterMultiRangeWidget::FilterMultiRangeButtonPtr filter_button4 = filter_widget_->buttons_[4]; |
1013 | + nux::Geometry geo_button4 = filter_button4->GetAbsoluteGeometry(); |
1014 | + nux::Point center_button4(geo_button4.x + geo_button4.width/2, geo_button4.y + geo_button4.height/2); |
1015 | + |
1016 | + filter_widget_->EmitMouseDownSignal(center_button1.x, center_button1.y, NUX_STATE_BUTTON1_DOWN|NUX_EVENT_BUTTON1_DOWN, 0); |
1017 | + |
1018 | + filter_widget_->EmitMouseDragSignal(center_button4.x, center_button4.y, center_button4.x - center_button1.x, center_button4.y - center_button1.y, NUX_STATE_BUTTON1_DOWN, 0); |
1019 | + EXPECT_EQ(filter_widget_->dragging_, true); |
1020 | + unity::testing::ExpectFilterRange(filter, 1, 4); |
1021 | + |
1022 | + |
1023 | + // filter_widget_->EmitMouseDragSignal(center_button3.x, center_button3.y, center_button4.x - center_button3.x, center_button4.y - center_button3.y, NUX_STATE_BUTTON1_DOWN, 0); |
1024 | + // unity::testing::ExpectFilterRange(filter, 1, 3); |
1025 | + |
1026 | + // filter_widget_->EmitMouseUpSignal(center_button3.x, center_button3.y, NUX_EVENT_BUTTON1_UP, 0); |
1027 | + // EXPECT_EQ(filter_widget_->dragging_, false); |
1028 | + // unity::testing::ExpectFilterRange(filter, 1, 3); |
1029 | +} |
1030 | + |
1031 | +} // namespace dash |
1032 | +} // namespace unity |
1033 | |
1034 | === modified file 'tests/test_lens.cpp' |
1035 | --- tests/test_lens.cpp 2012-11-14 08:57:56 +0000 |
1036 | +++ tests/test_lens.cpp 2013-01-30 10:36:20 +0000 |
1037 | @@ -576,27 +576,22 @@ |
1038 | EXPECT_FALSE (options[3]->active); |
1039 | |
1040 | options[0]->active = true; |
1041 | + options[1]->active = true; |
1042 | + EXPECT_TRUE (filter->filtering); |
1043 | + EXPECT_TRUE (options[0]->active); |
1044 | + EXPECT_TRUE (options[1]->active); |
1045 | + |
1046 | options[3]->active = true; |
1047 | EXPECT_TRUE (filter->filtering); |
1048 | - EXPECT_TRUE (options[0]->active); |
1049 | - EXPECT_TRUE (options[1]->active); |
1050 | - EXPECT_TRUE (options[2]->active); |
1051 | - EXPECT_TRUE (options[3]->active); |
1052 | - |
1053 | - options[0]->active = true; |
1054 | - options[2]->active = false; |
1055 | - EXPECT_TRUE (filter->filtering); |
1056 | - EXPECT_TRUE (options[0]->active); |
1057 | - EXPECT_TRUE (options[1]->active); |
1058 | - EXPECT_TRUE (options[2]->active); |
1059 | - EXPECT_FALSE (options[3]->active); |
1060 | - |
1061 | - options[0]->active = false; |
1062 | - EXPECT_TRUE (filter->filtering); |
1063 | EXPECT_FALSE (options[0]->active); |
1064 | - EXPECT_TRUE (options[1]->active); |
1065 | + EXPECT_FALSE (options[1]->active); |
1066 | + EXPECT_FALSE (options[2]->active); |
1067 | + EXPECT_TRUE (options[3]->active); |
1068 | + |
1069 | + options[2]->active = true; |
1070 | + EXPECT_TRUE (filter->filtering); |
1071 | EXPECT_TRUE (options[2]->active); |
1072 | - EXPECT_FALSE (options[3]->active); |
1073 | + EXPECT_TRUE (options[3]->active); |
1074 | |
1075 | filter->Clear(); |
1076 | EXPECT_FALSE (filter->filtering); |
1077 | |
1078 | === modified file 'unity-shared/DashStyle.cpp' |
1079 | --- unity-shared/DashStyle.cpp 2013-01-09 14:57:08 +0000 |
1080 | +++ unity-shared/DashStyle.cpp 2013-01-30 10:36:20 +0000 |
1081 | @@ -60,6 +60,9 @@ |
1082 | |
1083 | const int STATES = 5; |
1084 | |
1085 | +const double BUTTON_CORNER_RADIUS = 7.0; |
1086 | + |
1087 | + |
1088 | // These cairo overrides may also be reused somewhere... |
1089 | void cairo_set_source_rgba(cairo_t* cr, nux::Color const& color) |
1090 | { |
1091 | @@ -147,6 +150,15 @@ |
1092 | double cornerRadius, |
1093 | double width, |
1094 | double height, |
1095 | + Segment segment); |
1096 | + |
1097 | + void RoundedRectSegmentBorder(cairo_t* cr, |
1098 | + double aspect, |
1099 | + double x, |
1100 | + double y, |
1101 | + double cornerRadius, |
1102 | + double width, |
1103 | + double height, |
1104 | Segment segment, |
1105 | Arrow arrow, |
1106 | nux::ButtonVisualState state); |
1107 | @@ -963,6 +975,109 @@ |
1108 | double cornerRadius, |
1109 | double width, |
1110 | double height, |
1111 | + Segment segment) |
1112 | +{ |
1113 | + double radius = cornerRadius / aspect; |
1114 | + bool odd = true; |
1115 | + |
1116 | + odd = cairo_get_line_width (cr) == 2.0 ? false : true; |
1117 | + |
1118 | + switch (segment) |
1119 | + { |
1120 | + case Segment::LEFT: |
1121 | + // top-left, right of the corner |
1122 | + cairo_move_to(cr, _align(x + radius, odd), _align(y, odd)); |
1123 | + |
1124 | + // top-right |
1125 | + cairo_line_to(cr, _align(x + width, odd), _align(y, odd)); |
1126 | + |
1127 | + // bottom-right |
1128 | + cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1129 | + |
1130 | + // bottom-left, right of the corner |
1131 | + cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd)); |
1132 | + |
1133 | + // bottom-left, above the corner |
1134 | + cairo_arc(cr, |
1135 | + _align(x + radius, odd), |
1136 | + _align(y + height - radius, odd), |
1137 | + radius, |
1138 | + 90.0f * G_PI / 180.0f, |
1139 | + 180.0f * G_PI / 180.0f); |
1140 | + |
1141 | + // left, right of the corner |
1142 | + cairo_line_to(cr, _align(x, odd), _align(y + radius, odd)); |
1143 | + |
1144 | + // top-left, right of the corner |
1145 | + cairo_arc(cr, |
1146 | + _align(x + radius, odd), |
1147 | + _align(y + radius, odd), |
1148 | + radius, |
1149 | + 180.0f * G_PI / 180.0f, |
1150 | + 270.0f * G_PI / 180.0f); |
1151 | + |
1152 | + break; |
1153 | + |
1154 | + case Segment::MIDDLE: |
1155 | + // top-left |
1156 | + cairo_move_to(cr, _align(x, odd), _align(y, odd)); |
1157 | + |
1158 | + // top-right |
1159 | + cairo_line_to(cr, _align(x + width, odd), _align(y, odd)); |
1160 | + |
1161 | + // bottom-right |
1162 | + cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1163 | + |
1164 | + // bottom-left |
1165 | + cairo_line_to(cr, _align(x, odd), _align(y + height, odd)); |
1166 | + |
1167 | + // back to top-left |
1168 | + cairo_close_path(cr); |
1169 | + break; |
1170 | + |
1171 | + case Segment::RIGHT: |
1172 | + // top-left, right of the corner |
1173 | + cairo_move_to(cr, _align(x, odd), _align(y, odd)); |
1174 | + |
1175 | + // top-right, left of the corner |
1176 | + cairo_line_to(cr, _align(x + width - radius, odd), _align(y, odd)); |
1177 | + |
1178 | + // top-right, below the corner |
1179 | + cairo_arc(cr, |
1180 | + _align(x + width - radius, odd), |
1181 | + _align(y + radius, odd), |
1182 | + radius, |
1183 | + -90.0f * G_PI / 180.0f, |
1184 | + 0.0f * G_PI / 180.0f); |
1185 | + |
1186 | + // bottom-right, above the corner |
1187 | + cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd)); |
1188 | + |
1189 | + // bottom-right, left of the corner |
1190 | + cairo_arc(cr, |
1191 | + _align(x + width - radius, odd), |
1192 | + _align(y + height - radius, odd), |
1193 | + radius, |
1194 | + 0.0f * G_PI / 180.0f, |
1195 | + 90.0f * G_PI / 180.0f); |
1196 | + |
1197 | + // bottom-left |
1198 | + cairo_line_to(cr, _align(x, odd), _align(y + height, odd)); |
1199 | + |
1200 | + // back to top-left |
1201 | + cairo_close_path(cr); |
1202 | + break; |
1203 | + } |
1204 | +} |
1205 | + |
1206 | + |
1207 | +void Style::Impl::RoundedRectSegmentBorder(cairo_t* cr, |
1208 | + double aspect, |
1209 | + double x, |
1210 | + double y, |
1211 | + double cornerRadius, |
1212 | + double width, |
1213 | + double height, |
1214 | Segment segment, |
1215 | Arrow arrow, |
1216 | nux::ButtonVisualState state) |
1217 | @@ -982,24 +1097,29 @@ |
1218 | // top-right |
1219 | cairo_line_to(cr, _align(x + width, odd), _align(y, odd)); |
1220 | |
1221 | - if (arrow == Arrow::RIGHT && state == nux::VISUAL_STATE_PRESSED) |
1222 | - { |
1223 | + if (arrow == Arrow::RIGHT || arrow == Arrow::BOTH) |
1224 | + { |
1225 | cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 - arrow_h, odd)); |
1226 | cairo_line_to(cr, _align(x + width - arrow_w, odd), _align(y + height / 2.0, odd)); |
1227 | cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 + arrow_h, odd)); |
1228 | - } |
1229 | - |
1230 | - // bottom-right |
1231 | - cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1232 | + |
1233 | + // bottom-right |
1234 | + cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1235 | + } |
1236 | + else |
1237 | + { |
1238 | + // bottom-right |
1239 | + cairo_move_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1240 | + } |
1241 | |
1242 | // bottom-left, right of the corner |
1243 | cairo_line_to(cr, _align(x + radius, odd), _align(y + height, odd)); |
1244 | |
1245 | // bottom-left, above the corner |
1246 | cairo_arc(cr, |
1247 | - _align(x, odd) + _align(radius, odd), |
1248 | - _align(y + height, odd) - _align(radius, odd), |
1249 | - _align(radius, odd), |
1250 | + _align(x + radius, odd), |
1251 | + _align(y + height - radius, odd), |
1252 | + radius, |
1253 | 90.0f * G_PI / 180.0f, |
1254 | 180.0f * G_PI / 180.0f); |
1255 | |
1256 | @@ -1008,9 +1128,9 @@ |
1257 | |
1258 | // top-left, right of the corner |
1259 | cairo_arc(cr, |
1260 | - _align(x, odd) + _align(radius, odd), |
1261 | - _align(y, odd) + _align(radius, odd), |
1262 | - _align(radius, odd), |
1263 | + _align(x + radius, odd), |
1264 | + _align(y + radius, odd), |
1265 | + radius, |
1266 | 180.0f * G_PI / 180.0f, |
1267 | 270.0f * G_PI / 180.0f); |
1268 | |
1269 | @@ -1024,27 +1144,33 @@ |
1270 | cairo_line_to(cr, _align(x + width, odd), _align(y, odd)); |
1271 | |
1272 | if ((arrow == Arrow::RIGHT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED) |
1273 | - { |
1274 | + { |
1275 | cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 - arrow_h, odd)); |
1276 | cairo_line_to(cr, _align(x + width - arrow_w, odd), _align(y + height / 2.0, odd)); |
1277 | cairo_line_to(cr, _align(x + width, odd), _align(y + height / 2.0 + arrow_h, odd)); |
1278 | - } |
1279 | - |
1280 | - // bottom-right |
1281 | - cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1282 | + |
1283 | + // bottom-right |
1284 | + cairo_line_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1285 | + } |
1286 | + else |
1287 | + { |
1288 | + // bottom-right |
1289 | + cairo_move_to(cr, _align(x + width, odd), _align(y + height, odd)); |
1290 | + } |
1291 | |
1292 | // bottom-left |
1293 | cairo_line_to(cr, _align(x, odd), _align(y + height, odd)); |
1294 | |
1295 | if ((arrow == Arrow::LEFT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED) |
1296 | - { |
1297 | + { |
1298 | cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 + arrow_h, odd)); |
1299 | cairo_line_to(cr, _align(x + arrow_w, odd), _align(y + height / 2.0, odd)); |
1300 | cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 - arrow_h, odd)); |
1301 | - } |
1302 | - |
1303 | - // back to top-left |
1304 | - cairo_close_path(cr); |
1305 | + |
1306 | + // top-left |
1307 | + cairo_line_to(cr, _align(x, odd), _align(y, odd)); |
1308 | + } |
1309 | + |
1310 | break; |
1311 | |
1312 | case Segment::RIGHT: |
1313 | @@ -1056,9 +1182,9 @@ |
1314 | |
1315 | // top-right, below the corner |
1316 | cairo_arc(cr, |
1317 | - _align(x + width, odd) - _align(radius, odd), |
1318 | - _align(y, odd) + _align(radius, odd), |
1319 | - _align(radius, odd), |
1320 | + _align(x + width - radius, odd), |
1321 | + _align(y + radius, odd), |
1322 | + radius, |
1323 | -90.0f * G_PI / 180.0f, |
1324 | 0.0f * G_PI / 180.0f); |
1325 | |
1326 | @@ -1067,28 +1193,30 @@ |
1327 | |
1328 | // bottom-right, left of the corner |
1329 | cairo_arc(cr, |
1330 | - _align(x + width, odd) - _align(radius, odd), |
1331 | - _align(y + height, odd) - _align(radius, odd), |
1332 | - _align(radius, odd), |
1333 | + _align(x + width - radius, odd), |
1334 | + _align(y + height - radius, odd), |
1335 | + radius, |
1336 | 0.0f * G_PI / 180.0f, |
1337 | 90.0f * G_PI / 180.0f); |
1338 | |
1339 | // bottom-left |
1340 | cairo_line_to(cr, _align(x, odd), _align(y + height, odd)); |
1341 | |
1342 | - if (arrow == Arrow::LEFT && state == nux::VISUAL_STATE_PRESSED) |
1343 | - { |
1344 | + if ((arrow == Arrow::LEFT || arrow == Arrow::BOTH) && state == nux::VISUAL_STATE_PRESSED) |
1345 | + { |
1346 | cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 + arrow_h, odd)); |
1347 | cairo_line_to(cr, _align(x + arrow_w, odd), _align(y + height / 2.0, odd)); |
1348 | cairo_line_to(cr, _align(x, odd), _align(y + height / 2.0 - arrow_h, odd)); |
1349 | - } |
1350 | - |
1351 | - // back to top-left |
1352 | - cairo_close_path(cr); |
1353 | + |
1354 | + // top-left, |
1355 | + cairo_line_to(cr, _align(x, odd), _align(y, odd)); |
1356 | + } |
1357 | + |
1358 | break; |
1359 | } |
1360 | } |
1361 | |
1362 | + |
1363 | void Style::Impl::ButtonOutlinePathSegment(cairo_t* cr, Segment segment) |
1364 | { |
1365 | double x = 0.0; |
1366 | @@ -1563,7 +1691,7 @@ |
1367 | 1.0, |
1368 | (double) (garnish) + 1.0, |
1369 | (double) (garnish) + 1.0, |
1370 | - 7.0, |
1371 | + BUTTON_CORNER_RADIUS, |
1372 | w - (double) (2 * garnish) - 2.0, |
1373 | h - (double) (2 * garnish) - 2.0); |
1374 | else |
1375 | @@ -1571,7 +1699,7 @@ |
1376 | 1.0, |
1377 | (double) (garnish) + 0.5, |
1378 | (double) (garnish) + 0.5, |
1379 | - 7.0, |
1380 | + BUTTON_CORNER_RADIUS, |
1381 | w - (double) (2 * garnish) - 1.0, |
1382 | h - (double) (2 * garnish) - 1.0); |
1383 | |
1384 | @@ -1664,7 +1792,7 @@ |
1385 | cairo_move_to(cr, _align(x + width, odd), y); |
1386 | if (curve_bottom) |
1387 | { |
1388 | - double radius = 7.0; |
1389 | + double radius = BUTTON_CORNER_RADIUS; |
1390 | LOG_DEBUG(logger) << "curve: " << _align(x + width, odd) << " - " << _align(y + height - radius, odd); |
1391 | // line to bottom-right corner |
1392 | cairo_line_to(cr, _align(x + width, odd), _align(y + height - radius, odd)); |
1393 | @@ -1771,7 +1899,7 @@ |
1394 | 1.0, |
1395 | (double) 0.5, |
1396 | (double) 0.5, |
1397 | - 7.0, |
1398 | + BUTTON_CORNER_RADIUS, |
1399 | w - 1.0, |
1400 | h - 1.0); |
1401 | |
1402 | @@ -1785,6 +1913,7 @@ |
1403 | bool Style::MultiRangeSegment(cairo_t* cr, |
1404 | nux::ButtonVisualState state, |
1405 | std::string const& label, |
1406 | + int font_px_size, |
1407 | Arrow arrow, |
1408 | Segment segment) |
1409 | { |
1410 | @@ -1812,42 +1941,51 @@ |
1411 | w -= 2.0; |
1412 | } |
1413 | |
1414 | - cairo_set_line_width(cr, pimpl->button_label_border_size_[state]); |
1415 | - |
1416 | - if (pimpl->button_label_border_size_[state] == 2.0) |
1417 | - pimpl->RoundedRectSegment(cr, |
1418 | - 1.0, |
1419 | - x+1.0, |
1420 | - y+1.0, |
1421 | - (h-1.0) / 4.0, |
1422 | - w-1.0, |
1423 | - h-1.0, |
1424 | - segment, |
1425 | - arrow, |
1426 | - state); |
1427 | - else |
1428 | - pimpl->RoundedRectSegment(cr, |
1429 | + cairo_set_line_width(cr, pimpl->button_label_border_size_[nux::VISUAL_STATE_NORMAL]); |
1430 | + |
1431 | + pimpl->RoundedRectSegment(cr, |
1432 | + 1.0, |
1433 | + x, |
1434 | + y, |
1435 | + BUTTON_CORNER_RADIUS, |
1436 | + w, |
1437 | + h, |
1438 | + segment); |
1439 | + |
1440 | + if (pimpl->button_label_fill_color_[state].alpha != 0.0) |
1441 | + { |
1442 | + cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]); |
1443 | + cairo_fill_preserve(cr); |
1444 | + } |
1445 | + |
1446 | + cairo_set_source_rgba(cr, pimpl->button_label_border_color_[nux::VISUAL_STATE_NORMAL]); |
1447 | + cairo_stroke(cr); // do not preseve path |
1448 | + |
1449 | + if (state == nux::VISUAL_STATE_PRESSED) |
1450 | + { |
1451 | + int line_width = pimpl->button_label_border_size_[state]; |
1452 | + cairo_set_line_width(cr, line_width); |
1453 | + |
1454 | + pimpl->RoundedRectSegmentBorder(cr, |
1455 | 1.0, |
1456 | x, |
1457 | - y, |
1458 | - h / 4.0, |
1459 | + y + line_width/2, |
1460 | + BUTTON_CORNER_RADIUS, |
1461 | w, |
1462 | - h, |
1463 | + h - line_width, |
1464 | segment, |
1465 | arrow, |
1466 | state); |
1467 | |
1468 | - if (pimpl->button_label_fill_color_[state].alpha != 0.0) |
1469 | - { |
1470 | - cairo_set_source_rgba(cr, pimpl->button_label_fill_color_[state]); |
1471 | - cairo_fill_preserve(cr); |
1472 | + cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]); |
1473 | + cairo_stroke(cr); // do not preseve path |
1474 | } |
1475 | - cairo_set_source_rgba(cr, pimpl->button_label_border_color_[state]); |
1476 | - cairo_stroke(cr); |
1477 | + |
1478 | + |
1479 | pimpl->Text(cr, |
1480 | pimpl->button_label_text_color_[state], |
1481 | label, |
1482 | - 10); // 13px = 10pt |
1483 | + font_px_size); |
1484 | |
1485 | return true; |
1486 | } |
1487 | @@ -1888,9 +2026,7 @@ |
1488 | h / 4.0, |
1489 | w, |
1490 | h, |
1491 | - segment, |
1492 | - arrow, |
1493 | - nux::ButtonVisualState::VISUAL_STATE_PRESSED); |
1494 | + segment); |
1495 | |
1496 | cairo_set_source_rgba(cr, nux::Color(1.0f, 1.0f, 1.0f, 0.5f)); |
1497 | cairo_fill_preserve(cr); |
1498 | |
1499 | === modified file 'unity-shared/DashStyle.h' |
1500 | --- unity-shared/DashStyle.h 2012-12-17 09:28:31 +0000 |
1501 | +++ unity-shared/DashStyle.h 2013-01-30 10:36:20 +0000 |
1502 | @@ -111,6 +111,7 @@ |
1503 | virtual bool MultiRangeSegment(cairo_t* cr, |
1504 | nux::ButtonVisualState state, |
1505 | std::string const& label, |
1506 | + int font_px_size, |
1507 | Arrow arrow, |
1508 | Segment segment); |
1509 |
+ for (FilterOption::Ptr option : options_)
auto const& option?
260 + auto func_invalidate = [&, geo](std: :pair<const MapKey, NuxCairoPtr>& pair)
I think you can remove the & in the closure.
358 +FilterMultiRan geWidget: :~FilterMultiRa ngeWidget( )
359 +{
360 +}
Do we really need an empty dtor?
462 + if (mouse_inside == false)
463 + return NULL;
Just use ! + nullptr
481 +void FilterMultiRang eWidget: :RecvMouseLeave (int x, int y, unsigned long button_flags, unsigned long key_flags)
482 +{
483 +}
Empty function?
I'll continue the review later.