summaryrefslogtreecommitdiff
diff options
-rw-r--r--dash/CMakeLists.txt1
-rw-r--r--dash/DashController.cpp4
-rw-r--r--dash/DashView.cpp189
-rw-r--r--dash/DashView.h19
-rw-r--r--dash/LensView.cpp35
-rw-r--r--dash/LensView.h9
-rw-r--r--dash/PreviewStateMachine.cpp113
-rw-r--r--dash/PreviewStateMachine.h74
-rw-r--r--dash/ResultView.cpp13
-rw-r--r--dash/ResultView.h16
-rw-r--r--dash/ResultViewGrid.cpp89
-rw-r--r--dash/ResultViewGrid.h4
-rw-r--r--dash/StandaloneDash.cpp2
-rw-r--r--dash/previews/PreviewContainer.h4
-rw-r--r--plugins/unityshell/src/unityshell.h5
-rw-r--r--po/POTFILES.in6
-rw-r--r--tests/autopilot/unity/emulators/dash.py5
-rw-r--r--tests/autopilot/unity/tests/test_dash.py23
-rw-r--r--unity-shared/DashStyle.cpp7
-rw-r--r--unity-shared/UBusMessages.h9
20 files changed, 549 insertions, 78 deletions
diff --git a/dash/CMakeLists.txt b/dash/CMakeLists.txt
index 7d801c4b3..d20a69808 100644
--- a/dash/CMakeLists.txt
+++ b/dash/CMakeLists.txt
@@ -51,6 +51,7 @@ set (DASH_SOURCES
LensView.cpp
LensViewPrivate.cpp
PlacesGroup.cpp
+ PreviewStateMachine.cpp
ResultRenderer.cpp
ResultRendererHorizontalTile.cpp
ResultRendererTile.cpp
diff --git a/dash/DashController.cpp b/dash/DashController.cpp
index e73bf724a..4d9085c7e 100644
--- a/dash/DashController.cpp
+++ b/dash/DashController.cpp
@@ -122,7 +122,8 @@ void Controller::RegisterUBusInterests()
sigc::mem_fun(this, &Controller::OnActivateRequest));
ubus_manager_.RegisterInterest(UBUS_DASH_ABOUT_TO_SHOW,
[&] (GVariant*) { EnsureDash(); });
- ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, [&] (GVariant *data) {
+ ubus_manager_.RegisterInterest(UBUS_OVERLAY_SHOWN, [&] (GVariant *data)
+ {
unity::glib::String overlay_identity;
gboolean can_maximise = FALSE;
gint32 overlay_monitor = 0;
@@ -134,6 +135,7 @@ void Controller::RegisterUBusInterests()
HideDash(true);
}
});
+
}
void Controller::EnsureDash()
diff --git a/dash/DashView.cpp b/dash/DashView.cpp
index f1ba9ff67..1bce170e7 100644
--- a/dash/DashView.cpp
+++ b/dash/DashView.cpp
@@ -33,6 +33,8 @@
#include "unity-shared/KeyboardUtil.h"
#include "unity-shared/UnitySettings.h"
#include "unity-shared/UBusMessages.h"
+#include "unity-shared/PreviewStyle.h"
+
namespace unity
{
@@ -42,7 +44,7 @@ namespace
{
nux::logging::Logger logger("unity.dash.view");
-
+previews::Style preview_style;
}
// This is so we can access some protected members in nux::VLayout and
@@ -78,6 +80,9 @@ NUX_IMPLEMENT_OBJECT_TYPE(DashView);
DashView::DashView()
: nux::View(NUX_TRACKER_LOCATION)
, home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search")))
+ , preview_container_(nullptr)
+ , preview_displaying_(false)
+ , preview_navigation_mode_(previews::Navigation::NONE)
, active_lens_view_(0)
, last_activated_uri_("")
, search_in_progress_(false)
@@ -95,7 +100,7 @@ DashView::DashView()
Settings::Instance().changed.connect(sigc::mem_fun(this, &DashView::Relayout));
lenses_.lens_added.connect(sigc::mem_fun(this, &DashView::OnLensAdded));
mouse_down.connect(sigc::mem_fun(this, &DashView::OnMouseButtonDown));
-
+ preview_state_machine_.PreviewActivated.connect(sigc::mem_fun(this, &DashView::BuildPreview));
Relayout();
home_lens_->AddLenses(lenses_);
@@ -116,6 +121,65 @@ void DashView::SetMonitorOffset(int x, int y)
renderer_.y_offset = y;
}
+void DashView::ClosePreview()
+{
+ preview_displaying_ = false;
+ RemoveChild(preview_container_.GetPointer());
+ preview_container_ = nullptr; // free resources
+ preview_state_machine_.ClosePreview();
+ QueueDraw();
+}
+
+void DashView::BuildPreview(Preview::Ptr model)
+{
+ if (!preview_displaying_)
+ {
+ preview_container_ = previews::PreviewContainer::Ptr(new previews::PreviewContainer());
+ AddChild(preview_container_.GetPointer());
+ preview_container_->Preview(model, previews::Navigation::NONE); // no swipe left or right
+ //nux::GetWindowCompositor().SetKeyFocusArea(preview_container_.GetPointer());
+
+ preview_container_->SetParentObject(this);
+ preview_container_->SetGeometry(layout_->GetGeometry());
+ preview_displaying_ = true;
+
+ // connect to nav left/right signals to request nav left/right movement.
+ preview_container_->navigate_left.connect([&] () {
+ preview_state_machine_.Reset();
+ preview_navigation_mode_ = previews::Navigation::LEFT;
+
+ // sends a message to all result views, sending the the uri of the current preview result
+ // and the unique id of the result view that should be handling the results
+ ubus_manager_.SendMessage(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, g_variant_new("(iss)", -1, stored_preview_uri_identifier_.c_str(), stored_preview_unique_id_.c_str()));
+ });
+
+ preview_container_->navigate_right.connect([&] () {
+ preview_state_machine_.Reset();
+ preview_navigation_mode_ = previews::Navigation::RIGHT;
+
+ // sends a message to all result views, sending the the uri of the current preview result
+ // and the unique id of the result view that should be handling the results
+ ubus_manager_.SendMessage(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, g_variant_new("(iss)", 1, stored_preview_uri_identifier_.c_str(), stored_preview_unique_id_.c_str()));
+ });
+ }
+ else
+ {
+ // got a new preview whilst already displaying, we probably clicked a navigation button.
+ preview_container_->Preview(model, preview_navigation_mode_); // TODO
+ }
+
+ if (G_LIKELY(preview_state_machine_.left_results() > 0 && preview_state_machine_.right_results() > 0))
+ preview_container_->DisableNavButton(previews::Navigation::NONE);
+ else if (preview_state_machine_.left_results() > 0)
+ preview_container_->DisableNavButton(previews::Navigation::RIGHT);
+ else if (preview_state_machine_.right_results() > 0)
+ preview_container_->DisableNavButton(previews::Navigation::LEFT);
+ else
+ preview_container_->DisableNavButton(previews::Navigation::BOTH);
+
+ QueueDraw();
+}
+
void DashView::AboutToShow()
{
ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT);
@@ -127,14 +191,14 @@ void DashView::AboutToShow()
if (active_lens_view_->lens()->id() == "home.lens")
{
for (auto lens : lenses_.GetLenses())
- {
- lens->view_type = ViewType::HOME_VIEW;
- LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HOME_VIEW
- << " on '" << lens->id() << "'";
- }
+ {
+ lens->view_type = ViewType::HOME_VIEW;
+ LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HOME_VIEW
+ << " on '" << lens->id() << "'";
+ }
- home_lens_->view_type = ViewType::LENS_VIEW;
- LOG_DEBUG(logger) << "Setting ViewType " << ViewType::LENS_VIEW
+ home_lens_->view_type = ViewType::LENS_VIEW;
+ LOG_DEBUG(logger) << "Setting ViewType " << ViewType::LENS_VIEW
<< " on '" << home_lens_->id() << "'";
}
else if (active_lens_view_)
@@ -147,6 +211,12 @@ void DashView::AboutToShow()
// this will make sure the spinner animates if the search takes a while
search_bar_->ForceSearchChanged();
+ // if a preview is open, close it
+ if (preview_displaying_)
+ {
+ ClosePreview();
+ }
+
renderer_.AboutToShow();
}
@@ -199,6 +269,12 @@ void DashView::SetupViews()
content_layout_->AddView(lenses_layout_, 1, nux::MINOR_POSITION_LEFT);
home_view_ = new LensView(home_lens_, nullptr);
+ home_view_->uri_preview_activated.connect([&] (std::string const& uri, std::string const& unique_id)
+ {
+ stored_preview_unique_id_ = unique_id;
+ stored_preview_uri_identifier_ = uri;
+ });
+
AddChild(home_view_);
active_lens_view_ = home_view_;
lens_views_[home_lens_->id] = home_view_;
@@ -214,6 +290,17 @@ void DashView::SetupUBusConnections()
{
ubus_manager_.RegisterInterest(UBUS_PLACE_ENTRY_ACTIVATE_REQUEST,
sigc::mem_fun(this, &DashView::OnActivateRequest));
+
+ ubus_manager_.RegisterInterest(UBUS_DASH_PREVIEW_INFO_PAYLOAD, [&] (GVariant *data)
+ {
+ int position = -1;
+ int results_to_the_left = 0;
+ int results_to_the_right = 0;
+ g_variant_get(data, "(iii)", &position, &results_to_the_left, &results_to_the_right);
+ preview_state_machine_.SetSplitPosition(SplitPosition::CONTENT_AREA, position);
+ preview_state_machine_.left_results = results_to_the_left;
+ preview_state_machine_.right_results = results_to_the_right;
+ });
}
long DashView::PostLayoutManagement (long LayoutResult)
@@ -249,6 +336,9 @@ void DashView::Relayout()
ubus_manager_.SendMessage(UBUS_DASH_SIZE_CHANGED, g_variant_new("(ii)", content_geo_.width, content_geo_.height));
+ if (preview_displaying_)
+ preview_container_->SetGeometry(layout_->GetGeometry());
+
QueueDraw();
}
@@ -291,6 +381,13 @@ nux::Geometry DashView::GetBestFitGeometry(nux::Geometry const& for_geo)
void DashView::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
{
renderer_.DrawFull(gfx_context, content_geo_, GetAbsoluteGeometry(), GetGeometry());
+
+ // we only do this because the previews don't redraw correctly right now, so we have to force
+ // a full redraw every frame. performance sucks but we'll fix it post FF
+ if (preview_displaying_)
+ {
+ preview_container_->ProcessDraw(gfx_context, true);
+ }
}
void DashView::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
@@ -298,23 +395,28 @@ void DashView::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
renderer_.DrawInner(gfx_context, content_geo_, GetAbsoluteGeometry(), GetGeometry());
if (IsFullRedraw())
- {
nux::GetPainter().PushBackgroundStack();
- layout_->ProcessDraw(gfx_context, force_draw);
- nux::GetPainter().PopBackgroundStack();
+
+ if (preview_displaying_)
+ {
+ // disabled until the draw cycle in previews can be improved
+ //preview_container_->ProcessDraw(gfx_context, force_draw);
}
else
{
layout_->ProcessDraw(gfx_context, force_draw);
}
+
+ if (IsFullRedraw())
+ nux::GetPainter().PopBackgroundStack();
renderer_.DrawInnerCleanup(gfx_context, content_geo_, GetAbsoluteGeometry(), GetGeometry());
}
-void DashView::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key)
-{
- dash::Style& style = dash::Style::Instance();
- nux::Geometry geo(content_geo_);
+ void DashView::OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key)
+ {
+ dash::Style& style = dash::Style::Instance();
+ nux::Geometry geo(content_geo_);
if (Settings::Instance().GetFormFactor() == FormFactor::DESKTOP)
{
@@ -338,6 +440,12 @@ void DashView::OnActivateRequest(GVariant* args)
std::string id(AnalyseLensURI(uri.Str()));
+ // we got an activation request, we should probably close the preview
+ if (preview_displaying_)
+ {
+ ClosePreview();
+ }
+
if (!visible_)
{
lens_bar_->Activate(id);
@@ -443,6 +551,13 @@ void DashView::OnLensAdded(Lens::Ptr& lens)
AddChild(view);
view->SetVisible(false);
view->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated));
+ view->uri_preview_activated.connect([&] (std::string const& uri, std::string const& unique_id)
+ {
+ LOG_DEBUG(logger) << "got unique id from preview activation: " << unique_id;
+ stored_preview_unique_id_ = unique_id;
+ stored_preview_uri_identifier_ = uri;
+ });
+
lenses_layout_->AddView(view, 1);
lens_views_[lens->id] = view;
@@ -459,6 +574,13 @@ void DashView::OnLensAdded(Lens::Ptr& lens)
}
});
+ // Hook up to the new preview infrastructure
+ lens->preview_ready.connect([&] (std::string const& uri, Preview::Ptr model)
+ {
+ LOG_DEBUG(logger) << "Got preview for: " << uri;
+ preview_state_machine_.ActivatePreview(model); // this does not immediately display a preview - we now wait.
+ });
+
// global search done is handled by the home lens, no need to connect to it
// BUT, we will special case global search finished coming from
// the applications lens, because we want to be able to launch applications
@@ -492,6 +614,8 @@ void DashView::OnLensBarActivated(std::string const& id)
<< " on '" << it.first << "'";
}
+ search_bar_->SetVisible(true);
+ QueueRelayout();
search_bar_->search_string = view->search_string;
search_bar_->search_hint = view->lens()->search_hint;
// lenses typically return immediately from Search() if the search query
@@ -693,11 +817,13 @@ bool DashView::InspectKeyEvent(unsigned int eventType,
{
if ((eventType == nux::NUX_KEYDOWN) && (key_sym == NUX_VK_ESCAPE))
{
- if (search_bar_->search_string == "")
- ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
- else
+ if (preview_displaying_)
+ ClosePreview();
+ else if (search_bar_->search_string != "")
search_bar_->search_string = "";
-
+ else
+ ubus_manager_.SendMessage(UBUS_PLACE_VIEW_CLOSE_REQUEST);
+
return true;
}
return false;
@@ -737,11 +863,16 @@ void DashView::AddProperties(GVariantBuilder* builder)
wrapper.add("form_factor", form_factor);
wrapper.add("right-border-width", style.GetDashRightTileWidth());
wrapper.add("bottom-border-height", style.GetDashBottomTileHeight());
+ wrapper.add("preview_displaying", preview_displaying_);
}
nux::Area* DashView::KeyNavIteration(nux::KeyNavDirection direction)
{
- if (direction == nux::KEY_NAV_DOWN && search_bar_ && active_lens_view_)
+ if (preview_displaying_)
+ {
+ preview_container_->KeyNavIteration(direction);
+ }
+ else if (direction == nux::KEY_NAV_DOWN && search_bar_ && active_lens_view_)
{
auto show_filters = search_bar_->show_filters();
auto fscroll_view = active_lens_view_->fscroll_view();
@@ -920,5 +1051,21 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol,
return nullptr;
}
+nux::Area* DashView::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type)
+{
+ nux::Area* view = nullptr;
+ if (preview_displaying_)
+ {
+ nux::Point newpos = mouse_position;
+ view = dynamic_cast<nux::Area*>(preview_container_.GetPointer())->FindAreaUnderMouse(newpos, event_type);
+ }
+ else
+ {
+ view = View::FindAreaUnderMouse(mouse_position, event_type);
+ }
+
+ return (view == nullptr) ? this : view;
+}
+
}
}
diff --git a/dash/DashView.h b/dash/DashView.h
index 31a353c6e..e057e2f5e 100644
--- a/dash/DashView.h
+++ b/dash/DashView.h
@@ -34,6 +34,9 @@
#include "LensView.h"
#include "unity-shared/UBusWrapper.h"
#include "unity-shared/OverlayRenderer.h"
+#include "UnityCore/Preview.h"
+#include "previews/PreviewContainer.h"
+#include "PreviewStateMachine.h"
namespace unity
{
@@ -58,6 +61,9 @@ public:
void OnActivateRequest(GVariant* args);
void SetMonitorOffset(int x, int y);
+ void SetPreview(Preview::Ptr preview);
+ void ClosePreview();
+
std::string const GetIdForShortcutActivation(std::string const& shortcut) const;
std::vector<char> GetAllShortcuts();
@@ -79,7 +85,9 @@ private:
void Draw(nux::GraphicsEngine& gfx_context, bool force_draw);
void DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw);
virtual long PostLayoutManagement (long LayoutResult);
-
+ nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type);
+
+ void BuildPreview(Preview::Ptr model);
void OnMouseButtonDown(int x, int y, unsigned long button, unsigned long key);
void OnBackgroundColorChanged(GVariant* args);
void OnSearchChanged(std::string const& search_string);
@@ -106,14 +114,19 @@ private:
nux::Area* KeyNavIteration(nux::KeyNavDirection direction);
-private:
UBusManager ubus_manager_;
FilesystemLenses lenses_;
HomeLens::Ptr home_lens_;
LensViews lens_views_;
-
// View related
+ PreviewStateMachine preview_state_machine_;
+ previews::PreviewContainer::Ptr preview_container_;
+ bool preview_displaying_;
+ std::string stored_preview_unique_id_;
+ std::string stored_preview_uri_identifier_;
+ dash::previews::Navigation preview_navigation_mode_;
+
nux::VLayout* layout_;
DashLayout* content_layout_;
nux::HLayout* search_bar_layout_;
diff --git a/dash/LensView.cpp b/dash/LensView.cpp
index 123abc2e5..f64714746 100644
--- a/dash/LensView.cpp
+++ b/dash/LensView.cpp
@@ -145,11 +145,6 @@ LensView::LensView(Lens::Ptr lens, nux::Area* show_filters)
filters_expanded.changed.connect([&](bool expanded) { fscroll_view_->SetVisible(expanded); QueueRelayout(); OnColumnsChanged(); });
view_type.changed.connect(sigc::mem_fun(this, &LensView::OnViewTypeChanged));
- lens_->preview_ready.connect([&] (std::string const& uri, Preview::Ptr model)
- {
- preview_ = previews::Preview::Ptr(new previews::Preview(model));
- });
-
ubus_manager_.RegisterInterest(UBUS_RESULT_VIEW_KEYNAV_CHANGED, [&] (GVariant* data) {
// we get this signal when a result view keynav changes,
// its a bad way of doing this but nux ABI needs to be broken
@@ -284,6 +279,8 @@ void LensView::OnCategoryAdded(Category const& category)
counts_[group] = 0;
ResultViewGrid* grid = new ResultViewGrid(NUX_TRACKER_LOCATION);
+ std::string unique_id = name + lens_->name();
+ grid->unique_id = unique_id;
grid->expanded = false;
if (renderer_name == "tile-horizontal")
{
@@ -294,12 +291,25 @@ void LensView::OnCategoryAdded(Category const& category)
else
grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION));
- grid->UriActivated.connect([&] (std::string const& uri)
- {
- uri_activated.emit(uri);
- lens_->Activate(uri);
- last_activated_result_uri_ = uri;
- });
+ grid->UriActivated.connect(sigc::bind([&] (std::string const& uri, ResultView::ActivateType type, std::string const& view_id)
+ {
+ switch (type)
+ {
+ case ResultView::ActivateType::DIRECT:
+ {
+ uri_activated.emit(uri);
+ lens_->Activate(uri);
+ } break;
+ case ResultView::ActivateType::PREVIEW:
+ {
+ uri_preview_activated.emit(uri, view_id);
+ lens_->Preview(uri);
+ } break;
+ default: break;
+ };
+
+ }, unique_id));
+
group->SetChildView(grid);
/* We need the full range of method args so we can specify the offset
@@ -313,6 +323,7 @@ void LensView::OnResultAdded(Result const& result)
{
try {
PlacesGroup* group = categories_.at(result.category_index);
+
ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView());
std::string uri = result.uri;
@@ -500,6 +511,7 @@ void LensView::Draw(nux::GraphicsEngine& gfx_context, bool force_draw)
gfx_context.PushClippingRectangle(geo);
nux::GetPainter().PaintBackground(gfx_context, geo);
gfx_context.PopClippingRectangle();
+
}
void LensView::DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw)
@@ -594,6 +606,5 @@ void LensView::AddProperties(GVariantBuilder* builder)
.add("no-results-active", no_results_active_);
}
-
}
}
diff --git a/dash/LensView.h b/dash/LensView.h
index 79f6c57e5..120b4d1a7 100644
--- a/dash/LensView.h
+++ b/dash/LensView.h
@@ -36,7 +36,6 @@
#include "ResultViewGrid.h"
#include "unity-shared/UBusWrapper.h"
#include "unity-shared/PlacesVScrollBar.h"
-#include "previews/Preview.h"
namespace unity
{
@@ -70,6 +69,7 @@ public:
nux::Property<bool> can_refine_search;
sigc::signal<void, std::string const&> uri_activated;
+ sigc::signal<void, std::string const&, std::string const&> uri_preview_activated;
void PerformSearch(std::string const& search_query);
void CheckNoResults(Lens::Hints const& hints);
@@ -93,16 +93,17 @@ private:
void QueueFixRenderering();
bool FixRenderering();
+ void BuildPreview(std::string const& uri, Preview::Ptr model);
+
virtual void Draw(nux::GraphicsEngine& gfx_context, bool force_draw);
virtual void DrawContent(nux::GraphicsEngine& gfx_context, bool force_draw);
-
+
virtual bool AcceptKeyNavFocus();
virtual std::string GetName() const;
virtual void AddProperties(GVariantBuilder* builder);
std::string get_search_string() const;
-private:
Lens::Ptr lens_;
CategoryGroups categories_;
ResultCounts counts_;
@@ -118,8 +119,6 @@ private:
FilterBar* filter_bar_;
nux::StaticCairoText* no_results_;
- previews::Preview::Ptr preview_;
- std::string last_activated_result_uri_;
UBusManager ubus_manager_;
glib::Source::UniquePtr fix_rendering_idle_;
};
diff --git a/dash/PreviewStateMachine.cpp b/dash/PreviewStateMachine.cpp
new file mode 100644
index 000000000..c2fe3e42c
--- /dev/null
+++ b/dash/PreviewStateMachine.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2012 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gord Allott <gord.allott@canonical.com>>
+ */
+
+#include "PreviewStateMachine.h"
+#include <NuxCore/Logger.h>
+namespace unity
+{
+namespace dash
+{
+
+namespace
+{
+nux::logging::Logger logger("unity.dash.PreviewStateMachine");
+}
+PreviewStateMachine::PreviewStateMachine()
+ : preview_active(false)
+ , left_results(-1)
+ , right_results(-1)
+ , stored_preview_(nullptr)
+ , requires_activation_(true)
+{
+ for (int pos = SplitPosition::START; pos != SplitPosition::END; pos++)
+ {
+ split_positions_[pos] = -1;
+ }
+
+ left_results.changed.connect([&] (int value) { CheckPreviewRequirementsFulfilled();});
+ right_results.changed.connect([&] (int value) { CheckPreviewRequirementsFulfilled();});
+}
+
+PreviewStateMachine::~PreviewStateMachine()
+{
+}
+
+void PreviewStateMachine::ActivatePreview(Preview::Ptr preview)
+{
+ stored_preview_ = preview;
+ CheckPreviewRequirementsFulfilled();
+ left_results = -1;
+ right_results = -1;
+ requires_activation_ = true;
+}
+
+void PreviewStateMachine::Reset()
+{
+ left_results = -1;
+ right_results = -1;
+ stored_preview_ = nullptr;
+ requires_activation_ = true;
+}
+
+void PreviewStateMachine::ClosePreview()
+{
+ stored_preview_ = nullptr;
+ preview_active = true;
+ SetSplitPosition(SplitPosition::CONTENT_AREA, -1);
+}
+
+void PreviewStateMachine::SetSplitPosition(SplitPosition position, int coord)
+{
+ split_positions_[static_cast<int>(position)] = coord;
+ CheckPreviewRequirementsFulfilled();
+}
+
+int PreviewStateMachine::GetSplitPosition(SplitPosition position)
+{
+ return split_positions_[static_cast<int>(position)];
+}
+
+void PreviewStateMachine::CheckPreviewRequirementsFulfilled()
+{
+ if (!requires_activation_)
+ return;
+
+ if (stored_preview_ == nullptr)
+ return;
+
+ /* right now this is disabled as long as we aren't doing the fancy splitting animation
+ * as we don't care about positions
+ *
+ if (GetSplitPosition(CONTENT_AREA) < 0) return;
+ if (GetSplitPosition(FILTER_BAR) < 0) return;
+ if (GetSplitPosition(LENS_BAR) < 0) return;
+ if (GetSplitPosition(SEARCH_BAR) < 0) return;
+ */
+
+ if (left_results < 0 ||
+ right_results < 0)
+ return;
+
+ LOG_DEBUG(logger) << "activating preview: " << left_results << " - " << right_results;
+ preview_active = true;
+ PreviewActivated(stored_preview_);
+ requires_activation_ = false;
+}
+
+}
+}
diff --git a/dash/PreviewStateMachine.h b/dash/PreviewStateMachine.h
new file mode 100644
index 000000000..1652c1583
--- /dev/null
+++ b/dash/PreviewStateMachine.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2012 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Gord Allott <gord.allott@canonical.com>>
+ */
+
+#ifndef UNITY_PREVIEW_STATE_MACHINE_H_
+#define UNITY_PREVIEW_STATE_MACHINE_H_
+#include "previews/Preview.h"
+#include "previews/PreviewContainer.h"
+#include <unordered_map>
+
+namespace unity
+{
+namespace dash
+{
+
+typedef enum
+{
+ START,
+ CONTENT_AREA,
+ FILTER_BAR,
+ LENS_BAR,
+ SEARCH_BAR,
+ END
+} SplitPosition;
+
+class PreviewStateMachine
+{
+public:
+ PreviewStateMachine();
+ ~PreviewStateMachine();
+
+ void ActivatePreview(Preview::Ptr preview); // potentially async call.
+ void Reset(); // resets the state but does not close the preview
+ void ClosePreview();
+
+ void SetSplitPosition(SplitPosition position, int coord);
+ int GetSplitPosition(SplitPosition position);
+
+ nux::Property<bool> preview_active;
+ nux::Property<int> left_results;
+ nux::Property<int> right_results;
+
+ sigc::signal<void, Preview::Ptr> PreviewActivated;
+
+private:
+ void CheckPreviewRequirementsFulfilled();
+
+ // all stored co-ordinates are absolute geometry
+ // to make dealing with the views inside the scrollview easier to understand
+ std::unordered_map<int, int> split_positions_;
+
+ Preview::Ptr stored_preview_;
+ bool requires_activation_;
+ bool requires_new_position_;
+};
+
+}
+}
+
+#endif
diff --git a/dash/ResultView.cpp b/dash/ResultView.cpp
index 1554e36ee..463fbb3c5 100644
--- a/dash/ResultView.cpp
+++ b/dash/ResultView.cpp
@@ -129,6 +129,19 @@ unsigned int ResultView::GetIndexForUri(const std::string& uri)
return index;
}
+std::string ResultView::GetUriForIndex(unsigned int index)
+{
+ if (index >= results_.size())
+ return "";
+
+ return results_[index].uri();
+}
+
+unsigned int ResultView::GetModelSize()
+{
+ return results_.size();
+}
+
long ResultView::ComputeContentSize()
{
return View::ComputeContentSize();
diff --git a/dash/ResultView.h b/dash/ResultView.h
index 9ee6bfd74..b035e54ee 100644
--- a/dash/ResultView.h
+++ b/dash/ResultView.h
@@ -40,6 +40,12 @@ namespace dash
class ResultView : public nux::View, public debug::Introspectable
{
public:
+ typedef enum ActivateType_
+ {
+ DIRECT,
+ PREVIEW
+ } ActivateType;
+
NUX_DECLARE_OBJECT_TYPE(ResultView, nux::View);
typedef std::vector<Result> ResultList;
@@ -52,15 +58,15 @@ public:
void AddResult(Result& result);
void RemoveResult(Result& result);
unsigned int GetIndexForUri(const std::string& uri);
-
+ std::string GetUriForIndex(unsigned int);
+ unsigned int GetModelSize();
+
ResultList GetResultList ();
nux::Property<bool> expanded;
nux::Property<int> results_per_row;
- nux::Property<int> preview_spacer; // makes a vertical space for the preview with the value as the height
- nux::Property<std::string> preview_result_uri; //for highlighting a preview
-
- sigc::signal<void, std::string const&> UriActivated;
+ nux::Property<std::string> unique_id;
+ sigc::signal<void, std::string const&, ActivateType> UriActivated;
std::string GetName() const;
void AddProperties(GVariantBuilder* builder);
diff --git a/dash/ResultViewGrid.cpp b/dash/ResultViewGrid.cpp
index 295bfd36c..728177520 100644
--- a/dash/ResultViewGrid.cpp
+++ b/dash/ResultViewGrid.cpp
@@ -52,6 +52,7 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL)
, mouse_over_index_(-1)
, active_index_(-1)
, selected_index_(-1)
+ , activated_uri_("NULL")
, last_lazy_loaded_result_(0)
, last_mouse_down_x_(-1)
, last_mouse_down_y_(-1)
@@ -60,7 +61,6 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL)
, mouse_last_x_(-1)
, mouse_last_y_(-1)
, extra_horizontal_spacing_(0)
- , cached_preview_index_(-1)
{
SetAcceptKeyNavFocusOnMouseDown(false);
@@ -71,7 +71,10 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL)
selected_index_.changed.connect(needredraw_lambda);
key_nav_focus_change.connect(sigc::mem_fun(this, &ResultViewGrid::OnKeyNavFocusChange));
- key_nav_focus_activate.connect([&] (nux::Area *area) { UriActivated.emit (focused_uri_); });
+ key_nav_focus_activate.connect([&] (nux::Area *area)
+ {
+ UriActivated.emit (focused_uri_, ResultView::ActivateType::DIRECT);
+ });
key_down.connect(sigc::mem_fun(this, &ResultViewGrid::OnKeyDown));
mouse_move.connect(sigc::mem_fun(this, &ResultViewGrid::MouseMove));
mouse_click.connect(sigc::mem_fun(this, &ResultViewGrid::MouseClick));
@@ -98,8 +101,56 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL)
g_variant_get (data, "(ii)", &recorded_dash_width_, &recorded_dash_height_);
});
- preview_spacer.changed.connect([this] (int space) { SizeReallocate(); });
- preview_result_uri.changed.connect([this] (std::string uri) { QueueDraw(); });
+ ubus_.RegisterInterest(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, [&] (GVariant* data) {
+ int nav_mode = 0;
+ gchar* uri = NULL;
+ gchar* proposed_unique_id = NULL;
+ g_variant_get(data, "(iss)", &nav_mode, &uri, &proposed_unique_id);
+
+ if (std::string(proposed_unique_id) != unique_id())
+ return;
+
+ if (std::string(uri) == activated_uri_)
+ {
+ int current_index = GetIndexForUri(activated_uri_);
+ if (nav_mode == -1) // left
+ {
+ current_index--;
+ }
+ else if (nav_mode == 1) // right
+ {
+ current_index++;
+ }
+
+ if (current_index < 0 || static_cast<unsigned int>(current_index) >= results_.size())
+ {
+ LOG_ERROR(logger) << "requested to activated a result that does not exist: " << current_index;
+ return;
+ }
+
+ // closed
+ if (nav_mode == 0)
+ {
+ activated_uri_ = "";
+ }
+ else
+ {
+ activated_uri_ = GetUriForIndex(current_index);
+ LOG_DEBUG(logger) << "activating preview for index: "
+ << "(" << current_index << ")"
+ << " " << activated_uri_;
+ int left_results = current_index;
+ int right_results = (results_.size()) ? (results_.size() - current_index) - 1 : 0;
+ ubus_.SendMessage(UBUS_DASH_PREVIEW_INFO_PAYLOAD,
+ g_variant_new("(iii)", 0, left_results, right_results));
+ UriActivated.emit(activated_uri_, ActivateType::PREVIEW);
+ }
+ }
+
+ g_free(uri);
+ g_free(proposed_unique_id);
+
+ });
SetDndEnabled(true, false);
}
@@ -239,7 +290,6 @@ void ResultViewGrid::SizeReallocate()
if (extra_horizontal_spacing_ < 0)
extra_horizontal_spacing_ = 0;
- total_height += preview_spacer; // space needed for preview
total_height += (padding * 2); // add padding
SetMinimumHeight(total_height);
@@ -587,8 +637,8 @@ void ResultViewGrid::Draw(nux::GraphicsEngine& GfxContext, bool force_draw)
offset_x = 0;
offset_y = 0;
}
+
nux::Geometry render_geo(x_position, y_position, renderer_->width, renderer_->height);
-//nux::GetPainter().Paint2DQuadColor(GfxContext, render_geo, nux::color::Blue*0.20);
renderer_->Render(GfxContext, results_[index], state, render_geo, offset_x, offset_y);
x_position += renderer_->width + horizontal_spacing + extra_horizontal_spacing_;
@@ -638,7 +688,20 @@ void ResultViewGrid::MouseClick(int x, int y, unsigned long button_flags, unsign
Result result = results_[index];
selected_index_ = index;
focused_uri_ = result.uri;
- UriActivated.emit(result.uri);
+ if (nux::GetEventButton(button_flags) == nux::MouseButton::MOUSE_BUTTON3)
+ {
+ activated_uri_ = result.uri();
+ UriActivated.emit(result.uri, ResultView::ActivateType::PREVIEW);
+ int left_results = index;
+ int right_results = (results_.size() - index) - 1;
+ //FIXME - just uses y right now, needs to use the absolute position of the bottom of the result
+ ubus_.SendMessage(UBUS_DASH_PREVIEW_INFO_PAYLOAD,
+ g_variant_new("(iii)", y, left_results, right_results));
+ }
+ else
+ {
+ UriActivated.emit(result.uri, ResultView::ActivateType::DIRECT);
+ }
}
}
@@ -660,17 +723,6 @@ uint ResultViewGrid::GetIndexAtPosition(int x, int y)
if (y < padding)
return -1;
- if (!preview_result_uri().empty())
- {
- // we have a preview so we have to deal with special positioning
- std::tuple<int, int> preview_result_coord = GetResultPosition(cached_preview_index_);
- if (static_cast<unsigned int>(y) > std::get<1>(preview_result_coord) + row_size)
- {
- // position is below the preview
- y -= preview_spacer;
- }
- }
-
uint row_number = std::max((y - padding), 0) / row_size ;
uint column_number = std::max((x - padding), 0) / column_size;
@@ -680,7 +732,6 @@ uint ResultViewGrid::GetIndexAtPosition(int x, int y)
std::tuple<int, int> ResultViewGrid::GetResultPosition(const std::string& uri)
{
unsigned int index = GetIndexForUri(uri);
- cached_preview_index_ = index;
return GetResultPosition(index);
}
diff --git a/dash/ResultViewGrid.h b/dash/ResultViewGrid.h
index 4879b182f..6acb38de3 100644
--- a/dash/ResultViewGrid.h
+++ b/dash/ResultViewGrid.h
@@ -93,6 +93,8 @@ private:
nux::Property<int> selected_index_;
std::string focused_uri_;
+ std::string activated_uri_;
+
int last_lazy_loaded_result_;
int last_mouse_down_x_;
int last_mouse_down_y_;
@@ -107,8 +109,6 @@ private:
int extra_horizontal_spacing_;
- unsigned int cached_preview_index_;
-
UBusManager ubus_;
glib::Source::UniquePtr lazy_load_source_;
glib::Source::UniquePtr view_changed_idle_;
diff --git a/dash/StandaloneDash.cpp b/dash/StandaloneDash.cpp
index 108b79293..cbc38743c 100644
--- a/dash/StandaloneDash.cpp
+++ b/dash/StandaloneDash.cpp
@@ -31,6 +31,7 @@
#include "DashView.h"
#include "unity-shared/UnitySettings.h"
#include "unity-shared/DashStyle.h"
+#include "unity-shared/ThumbnailGenerator.h"
#define WIDTH 1024
#define HEIGHT 768
@@ -89,6 +90,7 @@ int main(int argc, char **argv)
nux::NuxInitialize(0);
nux::logging::configure_logging(::getenv("UNITY_LOG_SEVERITY"));
// The instances for the pseudo-singletons.
+ unity::ThumbnailGenerator thumb_generator;
unity::Settings settings;
unity::dash::Style dash_style;
diff --git a/dash/previews/PreviewContainer.h b/dash/previews/PreviewContainer.h
index 4a975d158..6e790295f 100644
--- a/dash/previews/PreviewContainer.h
+++ b/dash/previews/PreviewContainer.h
@@ -76,13 +76,13 @@ public:
bool AcceptKeyNavFocus();
+ nux::Area* KeyNavIteration(nux::KeyNavDirection direction);
+
protected:
void Draw(nux::GraphicsEngine& gfx_engine, bool force_draw);
void DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw);
void PreLayoutManagement();
- nux::Area* KeyNavIteration(nux::KeyNavDirection direction);
-
bool InspectKeyEvent(unsigned int eventType, unsigned int keysym, const char* character);
void OnKeyDown(unsigned long event_type, unsigned long event_keysym, unsigned long event_state, const TCHAR* character, unsigned short key_repeat_count);
diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h
index 8bc218263..7ade045d0 100644
--- a/plugins/unityshell/src/unityshell.h
+++ b/plugins/unityshell/src/unityshell.h
@@ -63,7 +63,7 @@
#include <dlfcn.h>
#include "HudController.h"
-
+#include "ThumbnailGenerator.h"
namespace unity
{
@@ -336,7 +336,8 @@ private:
UBusManager ubus_manager_;
glib::SourceManager sources_;
-
+ unity::ThumbnailGenerator thumb_generator;
+
friend class UnityWindow;
};
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 33ce23678..273ff4f1c 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,15 +6,15 @@ dash/FilterMultiRangeWidget.cpp
dash/FilterRatingsWidget.cpp
dash/LensView.cpp
dash/PlacesGroup.cpp
+dash/PreviewMusic.cpp
+dash/PreviewMusicTrack.cpp
hud/HudController.cpp
hud/HudView.cpp
-hud/StandaloneHud.cpp
launcher/BFBLauncherIcon.cpp
launcher/BamfLauncherIcon.cpp
launcher/DesktopLauncherIcon.cpp
launcher/DeviceLauncherIcon.cpp
launcher/LauncherController.cpp
-launcher/HudLauncherIcon.cpp
launcher/SoftwareCenterLauncherIcon.cpp
launcher/SpacerLauncherIcon.cpp
launcher/TrashLauncherIcon.cpp
@@ -31,8 +31,6 @@ plugins/unityshell/src/unityshell.cpp
plugins/unityshell/unityshell.xml.in
shortcuts/ShortcutHintPrivate.cpp
shortcuts/ShortcutView.cpp
-shortcuts/StandaloneShortcuts.cpp
unity-shared/DashStyle.cpp
unity-shared/SearchBar.cpp
-unity-shared/UScreen.cpp
diff --git a/tests/autopilot/unity/emulators/dash.py b/tests/autopilot/unity/emulators/dash.py
index f7d315b65..514f4f083 100644
--- a/tests/autopilot/unity/emulators/dash.py
+++ b/tests/autopilot/unity/emulators/dash.py
@@ -82,6 +82,11 @@ class Dash(KeybindingsHelper):
"""Returns the searchbar attached to the dash."""
return self.view.get_searchbar()
+ @property
+ def preview_displaying(self):
+ """Returns true if the dash is currently displaying a preview"""
+ return self.view.preview_displaying;
+
def get_num_rows(self):
"""Returns the number of displayed rows in the dash."""
return self.view.num_rows
diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py
index 7f932c102..0383ab84c 100644
--- a/tests/autopilot/unity/tests/test_dash.py
+++ b/tests/autopilot/unity/tests/test_dash.py
@@ -540,3 +540,26 @@ class CategoryHeaderTests(DashTestCase):
self.mouse.click()
self.assertThat(category.is_expanded, Eventually(Equals(is_expanded)))
+
+class PreviewInvocationTests(DashTestCase):
+ """Tests that previews can be opened and closed
+ """
+ def test_open_preview_close_preview(self):
+ """Right clicking on any result shall open a preview,
+ escaping shall close the preview
+ """
+ lens = self.dash.reveal_application_lens()
+ self.addCleanup(self.dash.ensure_hidden)
+
+ category = lens.get_category_by_name("Installed")
+
+ self.mouse.move(self.dash.view.x + 64,
+ category.header_y + category.header_height + 32)
+
+ self.mouse.click(button=3)
+ #revealing a preview may be very slow, not sure if Eventually handles that nicely
+ self.assertThat(self.dash.preview_displaying, Eventually(Equals(True)))
+
+ self.keyboard.press_and_release("Escape")
+
+ self.assertThat(self.dash.preview_displaying, Eventually(Equals(False)))
diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp
index 31d997f0f..8ac12c7d7 100644
--- a/unity-shared/DashStyle.cpp
+++ b/unity-shared/DashStyle.cpp
@@ -123,7 +123,7 @@ public:
void Text(cairo_t* cr,
nux::Color const& color,
std::string const& label,
- int font_size = -1,
+ int font_size,
double horizMargin = 4.0,
Alignment alignment = Alignment::CENTER);
@@ -1355,6 +1355,10 @@ void Style::Impl::Text(cairo_t* cr,
{
pango_font_description_set_absolute_size(desc, text_size * PANGO_SCALE);
}
+ else if (desc)
+ {
+ text_size = pango_font_description_get_size(desc) / PANGO_SCALE;
+ }
PangoWeight weight;
switch (regular_text_weight_)
@@ -1627,7 +1631,6 @@ bool Style::SquareButton(cairo_t* cr, nux::ButtonVisualState state,
int font_size, Alignment alignment,
bool zeromargin)
{
- // sanity checks
if (cairo_status(cr) != CAIRO_STATUS_SUCCESS)
return false;
diff --git a/unity-shared/UBusMessages.h b/unity-shared/UBusMessages.h
index 603baa19f..777217e0c 100644
--- a/unity-shared/UBusMessages.h
+++ b/unity-shared/UBusMessages.h
@@ -82,6 +82,15 @@
// FIXME - fix the nux focus api so we don't need this
#define UBUS_RESULT_VIEW_KEYNAV_CHANGED "RESULT_VIEW_KEYNAV_CHANGED"
+// for communicating positions to the preview state machine (iii)
+// (split y coord in absolute geometry, results to the left, results to the right)
+#define UBUS_DASH_PREVIEW_INFO_PAYLOAD "DASH_PREVIEW_INFO_PAYLOAD"
+
+// called when previews wish to navigate left/right or close (is)
+// -1 = left, 0 = close, 1 = right,
+// string is the uri string that last result activated was
+#define UBUS_DASH_PREVIEW_NAVIGATION_REQUEST "DASH_PREVIEW_NAVIGATION_REQUEST"
+
// Sends a string datatype containing the new icon name
#define UBUS_HUD_ICON_CHANGED "HUD_ICON_CHANGED"
#define UBUS_HUD_CLOSE_REQUEST "HUD_CLOSE_REQUEST"