Merge lp:~unity-team/unity/unity.coverflow into lp:unity

Proposed by Jason Smith on 2012-02-12
Status: Rejected
Rejected by: Tim Penhey on 2012-08-21
Proposed branch: lp:~unity-team/unity/unity.coverflow
Merge into: lp:unity
Diff against target: 850 lines (+482/-27) 12 files modified
To merge this branch: bzr merge lp:~unity-team/unity/unity.coverflow
Reviewer Review Type Date Requested Status
John Lea design 2012-02-13 Needs Information on 2012-08-08
Francis Ginther Abstain on 2012-08-01
jenkins (community) continuous-integration Disapprove on 2012-06-25
Marco Trevisan (Treviño) Needs Fixing on 2012-02-17
Eduard Gotwig (community) Approve on 2012-02-15
David Barth Disapprove on 2012-02-14
Tim Penhey (community) Disapprove on 2012-02-13
Robert Carr Approve on 2012-02-13
Jason Smith (community) Approve on 2012-02-13
Review via email: mp+92690@code.launchpad.net

Description of the Change

Implements coverflow in dash

starting position: http://i.imgur.com/lDPpH.png
middle position: http://i.imgur.com/sXjfS.png

To post a comment you must log in.
Robert Carr (robertcarr) wrote :

Updated screenshot: http://i.imgur.com/Qe4N2.png

John Lea (johnlea) wrote :

Hi Jason, awesome work! ;-) Conditionally approved, on the understanding that the items listed below will all be fixed/implemented before user interface freeze. These changes are listed in priority order:

- The distance between the bottom of the category header and the top of the icons should be the same for both the grid view and the flow view

- In the music lens and the video lens, increase the size of the grid icons so that they match the size of the flow icons. Ideally switching between a collapsed grid and a flow should not change the vertical size, the vertical size of both should be identical.

- In the other lenses, decrease the size of the flow icons so that they match the size of the grid icons. Ideally switching between a collapsed grid and a flow should not change the vertical size, the vertical size of both should be identical.

- Change test from "See XX more results >" to "XX results"

- A very fast crossfade should be used to blend switching between the grid and flow views

- Add visual indication of keyboard focus

- draging a icon upwards should de-couple the icon so that it can be dragged and dropped on either the Launcher or outside of the Dash

- Blend hard edge where flow items enter and leave the screen with a alpha mask to make the transition less abrupt.

- Clicking the 'grid to flow' button should move the dash upwards so that all of the flow is shown on the screen *if required*.

- adjust the text underneath the icons in the flow view so that it more closely matches the text in the grid view

- add the 'blurred background' effect (used on the grid view to give a sense of depth to the dash glass) to the flow view

- Add overlay scrollbar with no thumb that only appears when dragging (iOS style). It fades very quickly out when there is no movement.

- when kenetic scrolling reaches the end of a list, it should 'bounce' instead of doing a hard stop.

- the kenetic scrolling needs to be slowed down a little bit

- any click during a fast kenetic scroll should stop the kenetic scroll and not launch the item that was clicked on. However this should not apply to clicks during *very* slow kenetic scrolls

review: Approve (design)
Jason Smith (jassmith) wrote :

Tim gave me a +1 on irc and went to bed

review: Approve
Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/274/console reported an error when processing this lp:~unity-team/unity/unity.coverflow branch.
Not merging it.

Didier Roche (didrocks) wrote :

there was a glitch in the precise archives, reapproving.

Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/275/console reported an error when processing this lp:~unity-team/unity/unity.coverflow branch.
Not merging it.

Didier Roche (didrocks) wrote :

the amd64 archives are still screwed, wait a little bit before reapproving a branch please (should be sorted shortly).

Unity Merger (unity-merger) wrote :

The Jenkins job https://jenkins.qa.ubuntu.com/job/automerge-unity/276/console reported an error when processing this lp:~unity-team/unity/unity.coverflow branch.
Not merging it.

Robert Carr (robertcarr) wrote :

+1

review: Approve
Tim Penhey (thumper) wrote :

I'm going to have to stop this landing in 5.4.

Talk to me.

review: Disapprove
Alan Bell (alanbell) wrote :

has this been tested with orca?

lp:~unity-team/unity/unity.coverflow updated on 2012-02-14
1931. By Jason Smith on 2012-02-14

merge trunk

David Barth (dbarth) wrote :

Jason, I appreciate this is a nice feature and was done on your spare time. Nonetheless, this cannot land, the reasons being:

- there are no tests; no exceptions...

- this is a feature for which performance *is* a quality requirement: the dash can't become slow because that code is not performant; the same way there were performance issues last cycle with other views, I want facts to prove that this widget / view will perform well: how does it work with 100 entries? what's the startup time impact? is icon loading performed on the fly, or in one batch at the start?
See https://wiki.canonical.com/ProductStrategyTeam/Checklist/WhatNeedsTesting for a reference.

- the list of required design changes is quite long: which means that the costs of accepting that feature is significant: impact on design, on platform, on unity-2d: i'd rather not add more to the feature development overhead and instead focus on getting higher quality for the LTS

- the feature was unplanned, not tracked anywhere: remember that we're targeting an LTS with this version of Unity

review: Disapprove
Sebastien Bacher (seb128) wrote :

David, isn't unity-2d having that feature already included for some time?

For what is worth the feature was in the staging ppa yesterday so I got it on my box (noticed this morning), what I can stay is that it:
- didn't have visible performances issues
- didn't have a visible impact on startup time
- worked quite nicely

the testing probably needs to be done but that seems worth aimed at a ffe for since the code seems mostly working before ffe and would be a great addition to unity, would be a shame to drop good work now that it's done

Jesse Wayde Brandao (jessewb) wrote :

Caught this in the staging ppa and I must say, it was a delightful surprise to find, it still needs some work, but I'm certain it could still make it in to the 12.04 LTS.
At least on my hardware it worked nicely, it'd be a shame to not have this land in the next release.

Tim Penhey (thumper) wrote :

On 15/02/12 03:44, David Barth wrote:
> Review: Disapprove
>
> Jason, I appreciate this is a nice feature and was done on your spare time. Nonetheless, this cannot land, the reasons being:
>
> - there are no tests; no exceptions...

This is the prime blocker at this stage.

> - this is a feature for which performance *is* a quality requirement: the dash can't become slow because that code is not performant; the same way there were performance issues last cycle with other views, I want facts to prove that this widget / view will perform well: how does it work with 100 entries? what's the startup time impact? is icon loading performed on the fly, or in one batch at the start?
> See https://wiki.canonical.com/ProductStrategyTeam/Checklist/WhatNeedsTesting for a reference.

This isn't an issue as it is using all the same loading code as the grid.

>
> - the list of required design changes is quite long: which means that the costs of accepting that feature is significant: impact on design, on platform, on unity-2d: i'd rather not add more to the feature development overhead and instead focus on getting higher quality for the LTS

Obviously there are some that are needed prior to landing, and others
that are "ideal". It is up to design to work out what is what there.

> - the feature was unplanned, not tracked anywhere: remember that we're targeting an LTS with this version of Unity

I don't think that this is a valid reason at all.

A key part of open source is being able to scratch your own itch.
Obviously for a group of talented hackers, coverflow was certainly an
itch that they wanted to scratch.

Since this was done during their own time, and design did reviews in
their own time, as long as the work meets the quality needs, I see
absolutely no reason why the feature couldn't land just because it
wasn't on the "planned deliverables for the shell team".

So, things blocking this landing are:
  - sufficient testing
  - design sign-off

Ideally we'd like to land this in a feature complete mode, not one where
we need to do a lot of extra work. I'm very excited to see this work
and I'd like to see it land, but I also want to make sure the quality of
what we ship stays high.

Thanks,
Tim

Viktor Reseleshki (vikktor91) wrote :

+1

nick rundy (nrundy) wrote :

This is an LTS. So shouldn't you guys be SOLELY concerned with refining and bug fixing what already exists? Like being able to use PageUp & PageDown in the Dash. Or being able to use the keyboard shortcuts (e.g., Alt+F10) when in the Dash. Or being able to set the time & date format so that it is universally shown the same way throughout the OS. Or being able to use the up/down keys to navigate to the launcher apps that are represented in Spread Mode.

There are so many "small" things. Bugs are a big problem in Ubuntu. Honestly, if you guys want to add "new features", DELAY the release of Precise and add them. You guys choose to stick to a six month release. So come LTS time, stay disciplined and give users a highly refined product. That is, spend all your time refining and bug fixing.

Cover Flow is pretty cool. I'm not knocking it. But bug fixing and refinement is more important to users, especially for an LTS. And especially considering that many of the same bugs that plagued 10.04 still exist. There are more than a dozen bugs that might be deemed "minor" but that really detract from a positive user-experience on Ubuntu. I would really like to see these bugs fixed for the LTS. If adding this Cover Flow takes any time away from bug fixing "minor" stuff, I say do NOT do it.

Eduard Gotwig (gotwig) wrote :

I realy like this idea, if this works for all lenses / scopes it would be realy good. even if this would be optional, I would definitly love it !

Eduard Gotwig (gotwig) wrote :

+1

review: Approve
Marco Trevisan (Treviño) (3v1n0) wrote :

82 + icon_texture_->texture_updated.connect([&] (nux::BaseTexture *texture)
83 + {
84 + if (parent_)
85 + parent_->NeedRedraw();
86 + });

Please, disconnect this on destroy (with a sigc::connection or using sigc::mem_fun) ;)

review: Needs Fixing
lp:~unity-team/unity/unity.coverflow updated on 2012-02-20
1932. By Jason Smith on 2012-02-20

merge el trunko

Eduard Gotwig (gotwig) wrote :

so is this going to go into unity 5.4 or not by default ?

lp:~unity-team/unity/unity.coverflow updated on 2012-02-24
1933. By Jason Smith on 2012-02-24

merge trunk

It doesn't look like there are any hooks for lenses to request the coverflow view directly? Ie. by setting the renderer_name property like what we have for "tile-horizontal". I think lens authors would expect this.

When compiling this branch I get some errors about a missing LensDirectoryReader from test_filesystem_lenses.cpp in the test_gtest_dbus target.

When running the branch (by hacking CMakeLists.txt) - holy moly that is one responsive ui :-D maybe a tad too responsive as noted by John. But I feel like my laptop is turbo charged, so that's nice though :-)

Interaction wise it took me quite some time to grok how to scroll the flow (dragging only occured to me as an option after reading John's comments here). I think I was expecting it to scroll when the mouse neared the left/right edges of the row. This would also match the scrolling behaviour of the launcher.

I was also puzzled why the list was offset to the middle of the dash initially, so the leftmost 50% was empty.

Regarding John's comments about special behaviour in different lenses we need to put some hooks in libunity to let the lenses themselves control this and then update the lenses themselves to use these hooks. I am thinking two new renderer names "tile-flow" (which uses icon size similar to the current "tile-*" renderers) and a "cover-flow" renderer that uses bigger cover like icons.

Eduard Gotwig (gotwig) wrote :

ok, that thing wont go into 12.04

Muhammad Nabil (ghogaru) wrote :

I think you might want to consider to change the name "coverflow" to something like "stackflow", "airflow" or whatever as the naming of "coverflow" is identical to Apple Inc.

jenkins (martin-mrazik+qa) wrote :

FAILED: Continuous integration, rev:1933
http://s-jenkins:8080/job/unity-ci/17/

review: Disapprove (continuous-integration)
MC Return (mc-return) wrote :

Jason Smith, are you still working on that ?
From the screenshots it looks awesome, would be nice to see this in action ;)

Francis Ginther (fginther) wrote :

Review was claimed by accident, please ignore.

review: Abstain
John Lea (johnlea) wrote :

Need to see working before approving.

review: Needs Information (design)
Tim Penhey (thumper) wrote :

this is the old proposal,

most of the comments here no longer apply

Rejecting this one.

Unmerged revisions

1933. By Jason Smith on 2012-02-24

merge trunk

1932. By Jason Smith on 2012-02-20

merge el trunko

1931. By Jason Smith on 2012-02-14

merge trunk

1930. By Jason Smith on 2012-02-13

merge el trunko

1929. By Jason Smith on 2012-02-13

tighten up padding further

1928. By Jason Smith on 2012-02-13

Shorten cover reflection

1927. By Jason Smith on 2012-02-13

reduce reflection strength

1926. By Jason Smith on 2012-02-13

change settings to look closer to design

1925. By Jason Smith on 2012-02-13

Respect new upstream coverflow changes

1924. By Robert Carr on 2012-02-12

Merge lp:~unity-team/unity/unity.coverflow

Preview Diff

1=== added file 'plugins/unityshell/src/CoverflowResultView.cpp'
2--- plugins/unityshell/src/CoverflowResultView.cpp 1970-01-01 00:00:00 +0000
3+++ plugins/unityshell/src/CoverflowResultView.cpp 2012-02-24 17:53:50 +0000
4@@ -0,0 +1,207 @@
5+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
6+/*
7+ * Copyright (C) 2012 Canonical Ltd
8+ *
9+ * This program is free software: you can redistribute it and/or modify
10+ * it under the terms of the GNU General Public License version 3 as
11+ * published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope that it will be useful,
14+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+ * GNU General Public License for more details.
17+ *
18+ * You should have received a copy of the GNU General Public License
19+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
20+ *
21+ * Authored by: Jason Smith <jason.smith@canonical.com>
22+ */
23+
24+#include "CoverflowResultView.h"
25+#include "IconLoader.h"
26+#include "IconTexture.h"
27+#include <Nux/Nux.h>
28+#include <Nux/View.h>
29+#include <Nux/Coverflow.h>
30+#include <Nux/CoverflowModel.h>
31+#include <Nux/CoverflowItem.h>
32+#include <Nux/HLayout.h>
33+
34+
35+namespace unity
36+{
37+namespace dash
38+{
39+
40+NUX_IMPLEMENT_OBJECT_TYPE(CoverflowResultView);
41+
42+class CoverflowResultItem : public nux::CoverflowItem
43+{
44+public:
45+ CoverflowResultItem(Result& result, CoverflowResultView *parent);
46+ ~CoverflowResultItem();
47+
48+ nux::ObjectPtr<nux::BaseTexture> GetTexture() const;
49+ void Activate();
50+
51+ Result result_;
52+ CoverflowResultView* parent_;
53+ IconTexture *icon_texture_;
54+};
55+
56+class CoverflowResultView::Impl : public sigc::trackable
57+{
58+public:
59+ Impl(CoverflowResultView *parent);
60+ ~Impl();
61+
62+ void ComputeFlatIcons();
63+
64+ CoverflowResultView *parent_;
65+ nux::Coverflow *coverflow_;
66+ nux::HLayout* layout_;
67+};
68+
69+CoverflowResultItem::CoverflowResultItem(Result& result, CoverflowResultView *parent)
70+ : CoverflowItem(result.name())
71+ , result_(result)
72+ , parent_(parent)
73+{
74+ std::string const& icon_hint = result.icon_hint;
75+ std::string icon_name = !icon_hint.empty() ? icon_hint : ". GThemedIcon text-x-preview";
76+ static const int element_size = 128;
77+
78+ icon_texture_ = new IconTexture(icon_name.c_str(), element_size, true);
79+ icon_texture_->add_border = true;
80+ icon_texture_->LoadIcon();
81+
82+ icon_texture_->texture_updated.connect([&] (nux::BaseTexture *texture)
83+ {
84+ if (parent_)
85+ parent_->NeedRedraw();
86+ });
87+}
88+
89+CoverflowResultItem::~CoverflowResultItem()
90+{
91+
92+}
93+
94+nux::ObjectPtr<nux::BaseTexture> CoverflowResultItem::GetTexture() const
95+{
96+ return nux::ObjectPtr<nux::BaseTexture>(icon_texture_->texture());
97+}
98+
99+void CoverflowResultItem::Activate()
100+{
101+ parent_->UriActivated.emit(result_.uri);
102+}
103+
104+CoverflowResultView::Impl::Impl(CoverflowResultView *parent)
105+ : parent_(parent)
106+ , coverflow_(new nux::Coverflow)
107+ , layout_(new nux::HLayout())
108+{
109+ layout_->AddView(coverflow_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL);
110+ parent_->SetLayout(layout_);
111+
112+ coverflow_->SetCameraDistance(1.44);
113+ coverflow_->fov = 60;
114+ coverflow_->folding_angle = 45;
115+ coverflow_->true_perspective = false;
116+ coverflow_->camera_motion_drift_enabled = false;
117+ coverflow_->show_reflection = true;
118+ coverflow_->folding_depth = .25;
119+ coverflow_->reflection_strength = .2f;
120+ //coverflow_->folding_rate = 3.5;
121+ coverflow_->kinetic_scroll_rate = 0.05f;
122+ coverflow_->mouse_drag_rate = 1.5f;
123+ coverflow_->pinching = 0.2f;
124+ coverflow_->y_offset = 0.15f;
125+ coverflow_->reflection_size = .5f;
126+}
127+
128+CoverflowResultView::Impl::~Impl()
129+{
130+
131+}
132+
133+CoverflowResultView::CoverflowResultView(NUX_FILE_LINE_DECL)
134+ : ResultView(NUX_FILE_LINE_PARAM)
135+ , pimpl(new CoverflowResultView::Impl(this))
136+{
137+ SetMinimumHeight(180);
138+}
139+
140+CoverflowResultView::~CoverflowResultView()
141+{
142+
143+}
144+
145+void CoverflowResultView::SetModelRenderer(ResultRenderer* renderer)
146+{
147+ return; // abstracting breaks down here. Needs to be reworked.
148+}
149+
150+void CoverflowResultView::AddResult(Result& result)
151+{
152+ results_.push_back (result);
153+
154+ nux::CoverflowItem::Ptr result_item(new CoverflowResultItem(result, this));
155+ pimpl->coverflow_->model()->AddItem(result_item);
156+}
157+
158+void CoverflowResultView::RemoveResult(Result& result)
159+{
160+ ResultView::RemoveResult(result);
161+ // Ineffecient, API needs to be improved in Coverflow?
162+ for (nux::CoverflowItem::Ptr item : pimpl->coverflow_->model()->Items())
163+ {
164+ CoverflowResultItem *result_item = static_cast<CoverflowResultItem*>(item.GetPointer());
165+
166+ if (result_item->result_.uri == result.uri) // maybe?
167+ {
168+ pimpl->coverflow_->model()->RemoveItem(item);
169+ break;
170+ }
171+ }
172+}
173+
174+void CoverflowResultView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
175+{
176+ // do nothing here
177+}
178+
179+void CoverflowResultView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw)
180+{
181+ nux::Geometry base = GetGeometry();
182+ GfxContext.PushClippingRectangle(base);
183+
184+ if (GetCompositionLayout())
185+ {
186+ nux::Geometry geo = GetCompositionLayout()->GetGeometry();
187+ GetCompositionLayout()->ProcessDraw(GfxContext, force_draw);
188+ }
189+
190+ GfxContext.PopClippingRectangle();
191+}
192+
193+void CoverflowResultView::Impl::ComputeFlatIcons()
194+{
195+ float width = coverflow_->ViewportWidthAtDepth(0);
196+ width /= coverflow_->space_between_icons();
197+
198+ int flat_icons = static_cast<int>(std::floor((width - 2.0f) / 2.0f));
199+ coverflow_->flat_icons = flat_icons;
200+}
201+
202+long CoverflowResultView::ComputeContentSize()
203+{
204+ pimpl->ComputeFlatIcons();
205+ long ret = ResultView::ComputeContentSize();
206+ return ret;
207+}
208+
209+
210+}
211+}
212
213=== added file 'plugins/unityshell/src/CoverflowResultView.h'
214--- plugins/unityshell/src/CoverflowResultView.h 1970-01-01 00:00:00 +0000
215+++ plugins/unityshell/src/CoverflowResultView.h 2012-02-24 17:53:50 +0000
216@@ -0,0 +1,56 @@
217+// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
218+/*
219+ * Copyright (C) 2012 Canonical Ltd
220+ *
221+ * This program is free software: you can redistribute it and/or modify
222+ * it under the terms of the GNU General Public License version 3 as
223+ * published by the Free Software Foundation.
224+ *
225+ * This program is distributed in the hope that it will be useful,
226+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
227+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
228+ * GNU General Public License for more details.
229+ *
230+ * You should have received a copy of the GNU General Public License
231+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
232+ *
233+ * Authored by: Jason Smith <jason.smith@canonical.com>
234+ */
235+
236+#ifndef UNITY_COVERFLOWRESULTVIEW_H
237+#define UNITY_COVERFLOWRESULTVIEW_H
238+
239+#include "ResultView.h"
240+
241+namespace unity
242+{
243+namespace dash
244+{
245+
246+class CoverflowResultView : public ResultView
247+{
248+ NUX_DECLARE_OBJECT_TYPE(CoverflowResultView, ResultView);
249+
250+public:
251+ CoverflowResultView(NUX_FILE_LINE_DECL);
252+ ~CoverflowResultView();
253+
254+ virtual void SetModelRenderer(ResultRenderer* renderer);
255+
256+ virtual void AddResult(Result& result);
257+ virtual void RemoveResult(Result& result);
258+
259+protected:
260+ virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw);
261+ virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw);
262+ virtual long ComputeContentSize();
263+
264+private:
265+ struct Impl;
266+ Impl* pimpl;
267+};
268+
269+}
270+}
271+
272+#endif
273\ No newline at end of file
274
275=== modified file 'plugins/unityshell/src/DashStyle.cpp'
276--- plugins/unityshell/src/DashStyle.cpp 2012-02-20 11:59:12 +0000
277+++ plugins/unityshell/src/DashStyle.cpp 2012-02-24 17:53:50 +0000
278@@ -212,6 +212,9 @@
279
280 LazyLoadTexture group_unexpand_texture_;
281 LazyLoadTexture group_expand_texture_;
282+
283+ LazyLoadTexture group_grid_texture_;
284+ LazyLoadTexture group_coverflow_texture_;
285
286 LazyLoadTexture star_deselected_texture_;
287 LazyLoadTexture star_selected_texture_;
288@@ -248,6 +251,8 @@
289 , search_spin_glow_texture_("/search_spin_glow.png")
290 , group_unexpand_texture_("/dash_group_unexpand.png")
291 , group_expand_texture_("/dash_group_expand.png")
292+ , group_grid_texture_("/grid-view.svg")
293+ , group_coverflow_texture_ ("/flow-view.svg")
294 , star_deselected_texture_("/star_deselected.png")
295 , star_selected_texture_("/star_selected.png")
296 , star_highlight_texture_("/star_highlight.png")
297@@ -2139,6 +2144,16 @@
298 return pimpl->group_expand_texture_.texture();
299 }
300
301+nux::BaseTexture* Style::GetGroupGridIcon()
302+{
303+ return pimpl->group_grid_texture_.texture();
304+}
305+
306+nux::BaseTexture* Style::GetGroupCoverflowIcon()
307+{
308+ return pimpl->group_coverflow_texture_.texture();
309+}
310+
311 nux::BaseTexture* Style::GetStarDeselectedIcon()
312 {
313 return pimpl->star_deselected_texture_.texture();
314
315=== modified file 'plugins/unityshell/src/DashStyle.h'
316--- plugins/unityshell/src/DashStyle.h 2012-02-20 11:59:12 +0000
317+++ plugins/unityshell/src/DashStyle.h 2012-02-24 17:53:50 +0000
318@@ -185,6 +185,9 @@
319
320 nux::BaseTexture* GetGroupUnexpandIcon();
321 nux::BaseTexture* GetGroupExpandIcon();
322+
323+ nux::BaseTexture* GetGroupGridIcon();
324+ nux::BaseTexture* GetGroupCoverflowIcon();
325
326 nux::BaseTexture* GetStarDeselectedIcon();
327 nux::BaseTexture* GetStarSelectedIcon();
328
329=== modified file 'plugins/unityshell/src/IconTexture.cpp'
330--- plugins/unityshell/src/IconTexture.cpp 2012-02-07 22:04:45 +0000
331+++ plugins/unityshell/src/IconTexture.cpp 2012-02-24 17:53:50 +0000
332@@ -46,6 +46,7 @@
333 IconTexture::IconTexture(nux::BaseTexture* texture, guint width, guint height)
334 : TextureArea(NUX_TRACKER_LOCATION),
335 _accept_key_nav_focus(false),
336+ _pixbuf_cached(NULL),
337 _icon_name(NULL),
338 _size(height),
339 _texture_cached(texture),
340@@ -60,6 +61,7 @@
341 IconTexture::IconTexture(const char* icon_name, unsigned int size, bool defer_icon_loading)
342 : TextureArea(NUX_TRACKER_LOCATION),
343 _accept_key_nav_focus(false),
344+ _pixbuf_cached(NULL),
345 _icon_name(NULL),
346 _size(size),
347 _texture_width(0),
348@@ -76,6 +78,8 @@
349 IconTexture::~IconTexture()
350 {
351 g_free(_icon_name);
352+ if (_pixbuf_cached)
353+ g_object_unref(_pixbuf_cached);
354 }
355
356 void IconTexture::SetByIconName(const char* icon_name, unsigned int size)
357@@ -134,7 +138,12 @@
358
359 void IconTexture::Refresh(GdkPixbuf* pixbuf)
360 {
361+ if (pixbuf == _pixbuf_cached)
362+ return;
363+
364 TextureCache& cache = TextureCache::GetDefault();
365+ if (_pixbuf_cached)
366+ g_object_unref(_pixbuf_cached);
367 _pixbuf_cached = pixbuf;
368
369 // Cache the pixbuf dimensions so we scale correctly
370@@ -152,12 +161,38 @@
371 _loading = false;
372 }
373
374+GdkPixbuf* IconTexture::AddBorderToPixbuf(GdkPixbuf* pixbuf)
375+{
376+ int width = gdk_pixbuf_get_width(pixbuf);
377+ int height = gdk_pixbuf_get_height(pixbuf);
378+ GdkPixbuf* result = gdk_pixbuf_new(gdk_pixbuf_get_colorspace(pixbuf),
379+ TRUE,
380+ gdk_pixbuf_get_bits_per_sample(pixbuf),
381+ width + 2, height + 2);
382+
383+ guchar* pixels = gdk_pixbuf_get_pixels(result);
384+ memset(pixels, 0, gdk_pixbuf_get_byte_length(result));
385+
386+ gdk_pixbuf_copy_area(pixbuf, 0, 0, width, height, result, 1, 1);
387+ return result;
388+}
389+
390 void IconTexture::IconLoaded(std::string const& icon_name, unsigned size,
391 GdkPixbuf* pixbuf)
392 {
393 if (GDK_IS_PIXBUF(pixbuf))
394 {
395- Refresh(pixbuf);
396+ if (add_border)
397+ {
398+ // Dont ref this, we already own a ref
399+ GdkPixbuf* result = AddBorderToPixbuf(pixbuf);
400+ Refresh(result);
401+ }
402+ else
403+ {
404+ g_object_ref(pixbuf);
405+ Refresh(pixbuf);
406+ }
407 }
408 else
409 {
410
411=== modified file 'plugins/unityshell/src/IconTexture.h'
412--- plugins/unityshell/src/IconTexture.h 2012-02-07 07:42:12 +0000
413+++ plugins/unityshell/src/IconTexture.h 2012-02-24 17:53:50 +0000
414@@ -40,6 +40,8 @@
415 IconTexture(const char* icon_name, unsigned int size, bool defer_icon_loading = false);
416 ~IconTexture();
417
418+ nux::Property<bool> add_border;
419+
420 void SetByIconName(const char* icon_name, unsigned int size);
421 void SetByFilePath(const char* file_path, unsigned int size);
422 void GetTextureSize(int* width, int* height);
423@@ -72,6 +74,7 @@
424 nux::BaseTexture* CreateTextureCallback(std::string const& texid, int width, int height);
425 void Refresh(GdkPixbuf* pixbuf);
426 void IconLoaded(std::string const& icon_name, unsigned size, GdkPixbuf* pixbuf);
427+ GdkPixbuf* AddBorderToPixbuf(GdkPixbuf* pixbuf);
428
429 // FIXME: make _icon_name a std::string.
430 char* _icon_name;
431
432=== modified file 'plugins/unityshell/src/LensView.cpp'
433--- plugins/unityshell/src/LensView.cpp 2012-02-21 20:10:05 +0000
434+++ plugins/unityshell/src/LensView.cpp 2012-02-24 17:53:50 +0000
435@@ -24,6 +24,7 @@
436 #include <NuxCore/Logger.h>
437
438 #include "DashStyle.h"
439+#include "CoverflowResultView.h"
440 #include "ResultRendererTile.h"
441 #include "ResultRendererHorizontalTile.h"
442 #include "UBusMessages.h"
443@@ -268,15 +269,9 @@
444 /* Reset result count */
445 counts_[group] = 0;
446
447- ResultViewGrid* grid = new ResultViewGrid(NUX_TRACKER_LOCATION);
448- grid->expanded = false;
449- if (renderer_name == "tile-horizontal")
450- grid->SetModelRenderer(new ResultRendererHorizontalTile(NUX_TRACKER_LOCATION));
451- else
452- grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION));
453
454- grid->UriActivated.connect([&] (std::string const& uri) { uri_activated.emit(uri); lens_->Activate(uri); });
455- group->SetChildView(grid);
456+ group->SetRendererName(renderer_name.c_str());
457+ group->UriActivated.connect([&] (std::string const& uri) { uri_activated.emit(uri); lens_->Activate(uri); });
458
459 /* We need the full range of method args so we can specify the offset
460 * of the group into the layout */
461@@ -289,7 +284,7 @@
462 {
463 try {
464 PlacesGroup* group = categories_.at(result.category_index);
465- ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
466+ ResultView* grid = static_cast<ResultView*>(group->GetChildView());
467
468 std::string uri = result.uri;
469 LOG_TRACE(logger) << "Result added: " << uri;
470@@ -308,7 +303,7 @@
471 {
472 try {
473 PlacesGroup* group = categories_.at(result.category_index);
474- ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
475+ ResultView* grid = static_cast<ResultView*>(group->GetChildView());
476
477 std::string uri = result.uri;
478 LOG_TRACE(logger) << "Result removed: " << uri;
479@@ -364,7 +359,7 @@
480
481 void LensView::OnGroupExpanded(PlacesGroup* group)
482 {
483- ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
484+ ResultView* grid = static_cast<ResultView*>(group->GetChildView());
485 grid->expanded = group->GetExpanded();
486 ubus_manager_.SendMessage(UBUS_PLACE_VIEW_QUEUE_DRAW);
487 }
488
489=== modified file 'plugins/unityshell/src/PlacesGroup.cpp'
490--- plugins/unityshell/src/PlacesGroup.cpp 2012-02-21 20:10:05 +0000
491+++ plugins/unityshell/src/PlacesGroup.cpp 2012-02-24 17:53:50 +0000
492@@ -44,6 +44,14 @@
493 #include "ubus-server.h"
494 #include "UBusMessages.h"
495
496+#include "ResultView.h"
497+#include "ResultViewGrid.h"
498+#include "ResultRendererTile.h"
499+#include "ResultRendererHorizontalTile.h"
500+#include "CoverflowResultView.h"
501+#include "FilterBasicButton.h"
502+
503+
504 namespace unity
505 {
506 namespace
507@@ -112,7 +120,9 @@
508 _is_expanded(true),
509 _n_visible_items_in_unexpand_mode(0),
510 _n_total_items(0),
511- _draw_sep(true)
512+ _draw_sep(true),
513+ _coverflow_enabled(false),
514+ _coverflow_button(nullptr)
515 {
516 SetAcceptKeyNavFocusOnMouseDown(false);
517 SetAcceptKeyNavFocusOnMouseEnter(false);
518@@ -127,7 +137,7 @@
519 _group_layout->AddLayout(new nux::SpaceLayout(15,15,15,15), 0);
520
521 _header_view = new HeaderView(NUX_TRACKER_LOCATION);
522- _group_layout->AddView(_header_view, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_FIX);
523+ _group_layout->AddView(_header_view, 0, nux::MINOR_POSITION_TOP, nux::MINOR_SIZE_FULL);
524
525 _header_layout = new nux::HLayout(NUX_TRACKER_LOCATION);
526 _header_layout->SetHorizontalInternalMargin(10);
527@@ -166,14 +176,40 @@
528 SetLayout(_group_layout);
529
530 // don't need to disconnect these signals as they are disconnected when this object destroys the contents
531+ _header_view->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter));
532+ _header_view->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave));
533 _header_view->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick));
534 _header_view->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged));
535 _header_view->key_nav_focus_activate.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelActivated));
536 _icon->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick));
537+ _icon->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter));
538+ _icon->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave));
539+ _icon->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged));
540 _name->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick));
541+ _name->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter));
542+ _name->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave));
543+ _name->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged));
544 _expand_label->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick));
545+ _expand_label->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter));
546+ _expand_label->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave));
547+ _expand_label->key_nav_focus_activate.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelActivated));
548+ _expand_label->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged));
549 _expand_icon->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseClick));
550+ _expand_icon->mouse_enter.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseEnter));
551+ _expand_icon->mouse_leave.connect(sigc::mem_fun(this, &PlacesGroup::RecvMouseLeave));
552+ _expand_icon->key_nav_focus_change.connect(sigc::mem_fun(this, &PlacesGroup::OnLabelFocusChanged));
553+
554+ dash::ResultView *grid = new dash::CoverflowResultView(NUX_TRACKER_LOCATION);
555+ grid->expanded = false;
556
557+ grid->SetModelRenderer(new dash::ResultRendererTile(NUX_TRACKER_LOCATION));
558+
559+ SetChildView(grid);
560+
561+ nux::BaseTexture *grid_texture = dash::Style::Instance().GetGroupCoverflowIcon();
562+ _coverflow_button = new IconTexture(grid_texture, 32, 32);
563+
564+ _coverflow_button->mouse_click.connect(sigc::mem_fun(this, &PlacesGroup::CoverflowButtonClicked));
565 key_nav_focus_change.connect([&](nux::Area* area, bool has_focus, nux::KeyNavDirection direction)
566 {
567 if (!has_focus)
568@@ -184,6 +220,15 @@
569 else
570 nux::GetWindowCompositor().SetKeyFocusArea(GetHeaderFocusableView(), direction);
571 });
572+ nux::HLayout *toggle_layout = new nux::HLayout();
573+ toggle_layout->SetHorizontalInternalMargin(8);
574+ toggle_layout->SetHorizontalExternalMargin(6);
575+ nux::Layout *toggle_space = new nux::SpaceLayout(1, 10000, 0, 1);
576+ toggle_layout->AddLayout(toggle_space, 1);
577+ toggle_layout->AddView(_coverflow_button, 0, nux::MINOR_POSITION_CENTER);
578+
579+ _header_layout->AddLayout(toggle_layout, 1);
580+
581 }
582
583 PlacesGroup::~PlacesGroup()
584@@ -216,6 +261,48 @@
585 }
586
587 void
588+PlacesGroup::CoverflowButtonClicked(int x, int y, unsigned long button_flags, unsigned long key_flags)
589+{
590+ dash::ResultView *new_view, *old_view;
591+
592+ old_view = _child_view;
593+
594+ if (_coverflow_enabled == false)
595+ {
596+ new_view = new dash::CoverflowResultView(NUX_TRACKER_LOCATION);
597+ _coverflow_enabled = true;
598+
599+ _coverflow_button->SetTexture(dash::Style::Instance().GetGroupGridIcon());
600+ }
601+ else
602+ {
603+ new_view = new dash::ResultViewGrid (NUX_TRACKER_LOCATION);
604+ _coverflow_enabled = false;
605+
606+ _coverflow_button->SetTexture(dash::Style::Instance().GetGroupCoverflowIcon());
607+
608+ if (_renderer_name == "tile-horizontal")
609+ new_view->SetModelRenderer(new dash::ResultRendererHorizontalTile(NUX_TRACKER_LOCATION));
610+ else
611+ new_view->SetModelRenderer(new dash::ResultRendererTile(NUX_TRACKER_LOCATION));
612+
613+
614+ }
615+
616+ for (dash::Result result: old_view->GetResultList())
617+ {
618+ new_view->AddResult(result);
619+ }
620+
621+ new_view->expanded = (bool)(old_view)->expanded;
622+
623+ SetChildView (new_view);
624+
625+ SetExpanded (new_view->expanded);
626+ QueueRelayout();
627+}
628+
629+void
630 PlacesGroup::SetName(const char* name)
631 {
632 gchar* final = NULL;
633@@ -234,6 +321,17 @@
634 g_free(final);
635 }
636
637+void
638+PlacesGroup::SetRendererName(const char *renderer_name)
639+{
640+ _renderer_name = renderer_name;
641+
642+ if (g_strcmp0(renderer_name, "tile-horizontal") == 0)
643+ _child_view->SetModelRenderer(new dash::ResultRendererHorizontalTile(NUX_TRACKER_LOCATION));
644+ else
645+ _child_view->SetModelRenderer(new dash::ResultRendererTile(NUX_TRACKER_LOCATION));
646+}
647+
648 nux::StaticCairoText*
649 PlacesGroup::GetLabel()
650 {
651@@ -253,14 +351,23 @@
652 }
653
654 void
655-PlacesGroup::SetChildView(nux::View* view)
656+PlacesGroup::SetChildView(dash::ResultView *view)
657 {
658+ if (_child_view != NULL)
659+ {
660+ _group_layout->RemoveChildObject(_child_view);
661+ }
662 _child_view = view;
663 _group_layout->AddView(_child_view, 1);
664 QueueDraw();
665+
666+ view->UriActivated.connect([&] (std::string const& uri)
667+ {
668+ UriActivated.emit(uri);
669+ });
670 }
671
672-nux::View*
673+dash::ResultView *
674 PlacesGroup::GetChildView()
675 {
676 return _child_view;
677@@ -307,6 +414,20 @@
678 _expand_label->SetText(final);
679 _expand_label->SetVisible(_n_visible_items_in_unexpand_mode < _n_total_items);
680
681+ _icon->SetAcceptKeyNavFocus(false);
682+ _name->SetAcceptKeyNavFocus(false);
683+ _expand_label->SetAcceptKeyNavFocus(false);
684+ _expand_icon->SetAcceptKeyNavFocus(false);
685+
686+ if (_expand_label->IsVisible())
687+ _expand_label->SetAcceptKeyNavFocus(true);
688+ else if (_expand_icon->IsVisible())
689+ _expand_icon->SetAcceptKeyNavFocus(true);
690+ else if (_name->IsVisible())
691+ _name->SetAcceptKeyNavFocus(true);
692+ else if (_icon->IsVisible())
693+ _icon->SetAcceptKeyNavFocus(true);
694+
695 QueueDraw();
696
697 g_free((result_string));
698@@ -441,11 +562,11 @@
699 void
700 PlacesGroup::SetExpanded(bool is_expanded)
701 {
702- if (_is_expanded == is_expanded)
703+ /* if (_is_expanded == is_expanded)
704 return;
705
706 if (is_expanded && _n_total_items <= _n_visible_items_in_unexpand_mode)
707- return;
708+ return;*/
709
710 _is_expanded = is_expanded;
711
712
713=== modified file 'plugins/unityshell/src/PlacesGroup.h'
714--- plugins/unityshell/src/PlacesGroup.h 2012-02-13 17:09:05 +0000
715+++ plugins/unityshell/src/PlacesGroup.h 2012-02-24 17:53:50 +0000
716@@ -31,6 +31,7 @@
717 #include "Introspectable.h"
718 #include "StaticCairoText.h"
719 #include "UBusWrapper.h"
720+#include "ResultView.h"
721
722 namespace nux
723 {
724@@ -50,12 +51,13 @@
725
726 void SetIcon(const char* icon);
727 void SetName(const char* name);
728+ void SetRendererName(const char *renderer_name);
729
730 nux::StaticCairoText* GetLabel();
731 nux::StaticCairoText* GetExpandLabel();
732
733- void SetChildView(nux::View* view);
734- nux::View* GetChildView();
735+ void SetChildView(dash::ResultView* view);
736+ dash::ResultView* GetChildView();
737
738 void SetChildLayout(nux::Layout* layout);
739
740@@ -73,6 +75,7 @@
741 void SetDrawSeparator(bool draw_it);
742
743 sigc::signal<void, PlacesGroup*> expanded;
744+ sigc::signal<void, std::string const&> UriActivated;
745
746 protected:
747 long ComputeContentSize();
748@@ -100,6 +103,8 @@
749 void OnLabelActivated(nux::Area* label);
750 void OnLabelFocusChanged(nux::Area* label, bool has_focus, nux::KeyNavDirection direction);
751 void RefreshLabel();
752+
753+ void CoverflowButtonClicked(int x, int y, unsigned long button_flags, unsigned long key_flags);
754
755 private:
756 nux::VLayout* _group_layout;
757@@ -107,7 +112,7 @@
758 nux::HLayout* _header_layout;
759 nux::HLayout* _text_layout;
760 nux::HLayout* _expand_layout;
761- nux::View* _child_view;
762+ dash::ResultView *_child_view;
763 nux::AbstractPaintLayer* _focus_layer;
764
765 IconTexture* _icon;
766@@ -123,6 +128,11 @@
767 char* _cached_name;
768 bool _draw_sep;
769 nux::Geometry _cached_geometry;
770+
771+ std::string _renderer_name;
772+ bool _coverflow_enabled;
773+
774+ IconTexture *_coverflow_button;
775
776 UBusManager _ubus;
777 };
778
779=== modified file 'plugins/unityshell/src/ResultView.cpp'
780--- plugins/unityshell/src/ResultView.cpp 2012-02-21 23:19:50 +0000
781+++ plugins/unityshell/src/ResultView.cpp 2012-02-24 17:53:50 +0000
782@@ -68,6 +68,10 @@
783
784 ResultView::~ResultView()
785 {
786+ if (renderer_ == NULL)
787+ {
788+ return;
789+ }
790 ClearIntrospectableWrappers();
791
792 for (auto result : results_)
793@@ -100,7 +104,9 @@
794 void ResultView::AddResult(Result& result)
795 {
796 results_.push_back(result);
797- renderer_->Preload(result);
798+
799+ if (renderer_ != NULL)
800+ renderer_->Preload(result);
801
802 NeedRedraw();
803 }
804@@ -118,7 +124,9 @@
805 break;
806 }
807 }
808- renderer_->Unload(result);
809+
810+ if (renderer_ != NULL)
811+ renderer_->Unload(result);
812 }
813
814 ResultView::ResultList ResultView::GetResultList()
815
816=== modified file 'plugins/unityshell/src/ResultView.h'
817--- plugins/unityshell/src/ResultView.h 2012-02-21 23:19:50 +0000
818+++ plugins/unityshell/src/ResultView.h 2012-02-24 17:53:50 +0000
819@@ -48,14 +48,14 @@
820 ResultView(NUX_FILE_LINE_DECL);
821 virtual ~ResultView();
822
823- void SetModelRenderer(ResultRenderer* renderer);
824+ virtual void SetModelRenderer(ResultRenderer* renderer);
825
826- void AddResult(Result& result);
827- void RemoveResult(Result& result);
828+ virtual void AddResult(Result& result);
829+ virtual void RemoveResult(Result& result);
830
831 ResultList GetResultList ();
832
833- void SetPreview(PreviewBase* preview, Result& related_result);
834+ virtual void SetPreview(PreviewBase* preview, Result& related_result);
835
836 nux::Property<bool> expanded;
837 sigc::signal<void, std::string const&> UriActivated;
838
839=== modified file 'standalone-clients/CMakeLists.txt'
840--- standalone-clients/CMakeLists.txt 2012-02-21 00:11:20 +0000
841+++ standalone-clients/CMakeLists.txt 2012-02-24 17:53:50 +0000
842@@ -47,6 +47,8 @@
843 ${UNITY_SRC}/BackgroundEffectHelper.h
844 ${UNITY_SRC}/BGHash.cpp
845 ${UNITY_SRC}/BGHash.h
846+ ${UNITY_SRC}/CoverflowResultView.cpp
847+ ${UNITY_SRC}/CoverflowResultView.h
848 ${UNITY_SRC}/SearchBar.cpp
849 ${UNITY_SRC}/SearchBar.h
850 ${UNITY_SRC}/SearchBarSpinner.cpp