diff options
| author | Manuel de la Pena <manuel@canonical.com> | 2013-05-06 13:57:14 +0200 |
|---|---|---|
| committer | Manuel de la Pena <manuel@canonical.com> | 2013-05-06 13:57:14 +0200 |
| commit | ae6ff369d9a9bbc475c3e755c58869ee75937748 (patch) | |
| tree | 98d5263885b0590ace837979bd95a9385207cfad /dash | |
| parent | 25c90fdef54fa888275bbe3d604dbf72bcceb7e2 (diff) | |
| parent | b0477dbe8dfe65756eec88b8e68824923d0d213f (diff) | |
Merged with libunity breackage.
(bzr r3263.2.24)
Diffstat (limited to 'dash')
53 files changed, 2242 insertions, 1785 deletions
diff --git a/dash/CMakeLists.txt b/dash/CMakeLists.txt index 31472f51c..af230a327 100644 --- a/dash/CMakeLists.txt +++ b/dash/CMakeLists.txt @@ -35,9 +35,9 @@ set (DASH_SOURCES FilterMultiRangeWidget.cpp FilterRatingsButton.cpp FilterRatingsWidget.cpp - LensBar.cpp - LensBarIcon.cpp - LensView.cpp + ScopeBar.cpp + ScopeBarIcon.cpp + ScopeView.cpp PlacesGroup.cpp PreviewStateMachine.cpp ResultRenderer.cpp diff --git a/dash/CoverflowResultView.cpp b/dash/CoverflowResultView.cpp index fc696419e..3c9180ef5 100755 --- a/dash/CoverflowResultView.cpp +++ b/dash/CoverflowResultView.cpp @@ -66,8 +66,6 @@ public: ~Impl(); void ComputeFlatIcons(); - int GetIndexForUri(std::string uri); - std::string GetUriForIndex(int index); CoverflowResultView *parent_; nux::Coverflow *coverflow_; @@ -133,10 +131,10 @@ void CoverflowResultItem::Activate(int button) //Left and right click take you to previews. if (button == 1 || button == 3) - parent_->Activate(result_.uri, index, ResultView::ActivateType::PREVIEW); + parent_->Activate(LocalResult(result_), index, ResultView::ActivateType::PREVIEW); //Scroll click opens up music player. else if (button == 2) - parent_->Activate(result_.uri, index, ResultView::ActivateType::DIRECT); + parent_->Activate(LocalResult(result_), index, ResultView::ActivateType::DIRECT); } @@ -165,16 +163,18 @@ CoverflowResultView::Impl::Impl(CoverflowResultView *parent) ubus_.RegisterInterest(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, [&] (GVariant* data) { int nav_mode = 0; - glib::String uri; + GVariant* local_result_variant = nullptr; glib::String proposed_unique_id; - g_variant_get(data, "(iss)", &nav_mode, &uri, &proposed_unique_id); + g_variant_get(data, "(ivs)", &nav_mode, &local_result_variant, &proposed_unique_id); + LocalResult local_result(LocalResult::FromVariant(local_result_variant)); + g_variant_unref(local_result_variant); if (proposed_unique_id.Str() != parent_->unique_id()) return; unsigned num_results = coverflow_->model()->Items().size(); - int current_index = GetIndexForUri(uri); + int current_index = parent->GetIndexForLocalResult(local_result); if (nav_mode == -1) // left { current_index--; @@ -191,8 +191,7 @@ CoverflowResultView::Impl::Impl(CoverflowResultView *parent) if (nav_mode) { - std::string uri = GetUriForIndex(current_index); - parent_->Activate(uri, current_index, ActivateType::PREVIEW); + parent_->Activate(parent_->GetLocalResultForIndex(current_index), current_index, ActivateType::PREVIEW); } }); } @@ -202,23 +201,6 @@ CoverflowResultView::Impl::~Impl() } -int CoverflowResultView::Impl::GetIndexForUri(std::string uri) -{ - int i = 0; - for (auto item : coverflow_->model()->Items()) - { - if (uri == static_cast<CoverflowResultItem*>(item.GetPointer())->Uri()) - return i; - i++; - } - return -1; -} - -std::string CoverflowResultView::Impl::GetUriForIndex(int index) -{ - return static_cast<CoverflowResultItem*>(coverflow_->model()->Items()[index].GetPointer())->Uri(); -} - CoverflowResultView::CoverflowResultView(NUX_FILE_LINE_DECL) : ResultView(NUX_FILE_LINE_PARAM) , pimpl(new CoverflowResultView::Impl(this)) @@ -296,7 +278,7 @@ long CoverflowResultView::ComputeContentSize() } -void CoverflowResultView::Activate(std::string const& uri, int index, ResultView::ActivateType type) +void CoverflowResultView::Activate(LocalResult const& local_result, int index, ResultView::ActivateType type) { unsigned num_results = pimpl->coverflow_->model()->Items().size(); @@ -308,7 +290,7 @@ void CoverflowResultView::Activate(std::string const& uri, int index, ResultView int column_width = GetWidth(); glib::Variant data(g_variant_new("(iiii)", column_x, row_y, column_width, row_height, left_results, right_results)); - UriActivated.emit(uri, type, data); + ResultActivated.emit(local_result, type, data); } diff --git a/dash/CoverflowResultView.h b/dash/CoverflowResultView.h index d841d211c..c87017a37 100755 --- a/dash/CoverflowResultView.h +++ b/dash/CoverflowResultView.h @@ -40,7 +40,7 @@ public: virtual void AddResult(Result& result); virtual void RemoveResult(Result& result); - virtual void Activate(std::string const& uri, int index, ActivateType type); + virtual void Activate(LocalResult const& local_result, int index, ActivateType type); protected: virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); diff --git a/dash/DashController.cpp b/dash/DashController.cpp index cbd08d8e8..7c0635114 100644 --- a/dash/DashController.cpp +++ b/dash/DashController.cpp @@ -22,6 +22,7 @@ #include <NuxCore/Logger.h> #include <Nux/HLayout.h> #include <UnityCore/GLibWrapper.h> +#include "UnityCore/GSettingsScopes.h" #include "ApplicationStarterImp.h" #include "unity-shared/DashStyle.h" @@ -140,7 +141,7 @@ void Controller::SetupWindow() void Controller::SetupDashView() { - view_ = new DashView(std::make_shared<FilesystemLenses>(), std::make_shared<ApplicationStarterImp>()); + view_ = new DashView(std::make_shared<GSettingsScopes>(), std::make_shared<ApplicationStarterImp>()); AddChild(view_); nux::HLayout* layout = new nux::HLayout(NUX_TRACKER_LOCATION); @@ -411,14 +412,14 @@ void Controller::OnActivateRequest(GVariant* variant) gboolean Controller::CheckShortcutActivation(const char* key_string) { EnsureDash(); - std::string lens_id = view_->GetIdForShortcutActivation(std::string(key_string)); - if (lens_id != "") + std::string scope_id = view_->GetIdForShortcutActivation(std::string(key_string)); + if (scope_id != "") { WindowManager& wm = WindowManager::Default(); if (wm.IsScaleActive()) wm.TerminateScale(); - GVariant* args = g_variant_new("(sus)", lens_id.c_str(), dash::GOTO_DASH_URI, ""); + GVariant* args = g_variant_new("(sus)", scope_id.c_str(), dash::GOTO_DASH_URI, ""); OnActivateRequest(args); g_variant_unref(args); return true; diff --git a/dash/DashView.cpp b/dash/DashView.cpp index 2db9f54ae..5f9d6488d 100644 --- a/dash/DashView.cpp +++ b/dash/DashView.cpp @@ -94,11 +94,9 @@ public: { SetRedirectRenderingToTexture(true); } - ~DashContentView() {} void Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) - { - } + {} void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) { @@ -110,15 +108,13 @@ public: NUX_IMPLEMENT_OBJECT_TYPE(DashView); -DashView::DashView(Lenses::Ptr const& lenses, ApplicationStarter::Ptr const& application_starter) +DashView::DashView(Scopes::Ptr const& scopes, ApplicationStarter::Ptr const& application_starter) : nux::View(NUX_TRACKER_LOCATION) - , lenses_(lenses) - , home_lens_(new HomeLens(_("Home"), _("Home screen"), _("Search your computer and online sources"))) + , scopes_(scopes) , application_starter_(application_starter) , preview_container_(nullptr) , preview_displaying_(false) , preview_navigation_mode_(previews::Navigation::NONE) - , last_activated_uri_("") , last_activated_timestamp_(0) , search_in_progress_(false) , activate_on_finish_(false) @@ -142,35 +138,28 @@ DashView::DashView(Lenses::Ptr const& lenses, ApplicationStarter::Ptr const& app AddChild(overlay_window_buttons_.GetPointer()); - 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(); - for (auto lens : lenses_->GetLenses()) - lenses_->lens_added.emit(lens); - - home_lens_->AddLenses(lenses_); - lens_bar_->Activate("home.lens"); - - // we will special case when applications lens finishes global search - // because we want to be able to launch applications immediately - // without waiting for the search finished signal which will - // be delayed by all the lenses we're searching - home_lens_->lens_search_finished.connect(sigc::mem_fun(this, &DashView::OnAppsGlobalSearchFinished)); - // We are interested in the color of the desktop background. ubus_manager_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, sigc::mem_fun(this, &DashView::OnBGColorChanged)); // request the latest colour from bghash ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT); + if (scopes_) + { + scopes_->scope_added.connect(sigc::mem_fun(this, &DashView::OnScopeAdded)); + scopes_->LoadScopes(); + } } DashView::~DashView() { + scope_can_refine_connection_.disconnect(); // Do this explicitely, otherwise dee will complain about invalid access - // to the lens models + // to the scope models RemoveLayout(); } @@ -191,12 +180,13 @@ void DashView::SetMonitorOffset(int x, int y) bool DashView::IsCommandLensOpen() const { - return (lens_bar_->GetActiveLensId() == "commands.lens"); + return (scope_bar_->GetActiveScopeId() == "commands.scope"); } -void DashView::OnUriActivated(ResultView::ActivateType type, std::string const& uri, GVariant* data, std::string const& unique_id) + +void DashView::OnResultActivated(ResultView::ActivateType type, LocalResult const& local_result, GVariant* data, std::string const& unique_id) { - last_activated_uri_ = uri; + last_activated_result_ = local_result; stored_activated_unique_id_ = unique_id; if (data) @@ -234,12 +224,12 @@ void DashView::BuildPreview(Preview::Ptr model) StartPreviewAnimation(); content_view_->SetPresentRedirectedView(false); - preview_lens_view_ = active_lens_view_; - if (preview_lens_view_) + preview_scope_view_ = active_scope_view_; + if (preview_scope_view_) { - preview_lens_view_->ForceCategoryExpansion(stored_activated_unique_id_, true); - preview_lens_view_->EnableResultTextures(true); - preview_lens_view_->PushFilterExpansion(false); + preview_scope_view_->ForceCategoryExpansion(stored_activated_unique_id_, true); + preview_scope_view_->EnableResultTextures(true); + preview_scope_view_->PushFilterExpansion(false); } if (!preview_container_) @@ -251,7 +241,7 @@ void DashView::BuildPreview(Preview::Ptr model) } preview_container_->Preview(model, previews::Navigation::NONE); // no swipe left or right - preview_container_->SetGeometry(lenses_layout_->GetGeometry()); + preview_container_->SetGeometry(scopes_layout_->GetGeometry()); preview_displaying_ = true; // connect to nav left/right signals to request nav left/right movement. @@ -260,7 +250,7 @@ void DashView::BuildPreview(Preview::Ptr model) // 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, last_activated_uri_.c_str(), stored_activated_unique_id_.c_str())); + ubus_manager_.SendMessage(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, g_variant_new("(ivs)", -1, g_variant_ref(last_activated_result_.Variant()), stored_activated_unique_id_.c_str())); }); preview_container_->navigate_right.connect([&] () { @@ -268,7 +258,7 @@ void DashView::BuildPreview(Preview::Ptr model) // 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, last_activated_uri_.c_str(), stored_activated_unique_id_.c_str())); + ubus_manager_.SendMessage(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, g_variant_new("(ivs)", 1, g_variant_ref(last_activated_result_.Variant()), stored_activated_unique_id_.c_str())); }); preview_container_->request_close.connect([&] () { ClosePreview(); }); @@ -368,8 +358,8 @@ void DashView::StartPreviewAnimation() preview_container_animation_->Start(); } - if (preview_lens_view_) - preview_lens_view_->SetResultsPreviewAnimationValue(animate_split_value_); + if (preview_scope_view_) + preview_scope_view_->SetResultsPreviewAnimationValue(animate_split_value_); }); split_animation_->finished.connect(sigc::mem_fun(this, &DashView::OnPreviewAnimationFinished)); @@ -429,8 +419,8 @@ void DashView::EndPreviewAnimation() split_animation_->finished.connect(sigc::mem_fun(this, &DashView::OnPreviewAnimationFinished)); split_animation_->Start(); - // if (preview_lens_view_) - // preview_lens_view_->PopFilterExpansion(); + // if (preview_scope_view_) + // preview_scope_view_->PopFilterExpansion(); } }); @@ -459,14 +449,14 @@ void DashView::OnPreviewAnimationFinished() } // reset the saturation. - if (preview_lens_view_.IsValid()) + if (preview_scope_view_.IsValid()) { - preview_lens_view_->SetResultsPreviewAnimationValue(0.0); - preview_lens_view_->ForceCategoryExpansion(stored_activated_unique_id_, false); - preview_lens_view_->EnableResultTextures(false); - preview_lens_view_->PopFilterExpansion(); + preview_scope_view_->SetResultsPreviewAnimationValue(0.0); + preview_scope_view_->ForceCategoryExpansion(stored_activated_unique_id_, false); + preview_scope_view_->EnableResultTextures(false); + preview_scope_view_->PopFilterExpansion(); } - preview_lens_view_.Release(); + preview_scope_view_.Release(); content_view_->SetPresentRedirectedView(true); } @@ -476,42 +466,25 @@ void DashView::AboutToShow() visible_ = true; search_bar_->text_entry()->SelectAll(); - /* Give the lenses a chance to prep data before we map them */ - lens_bar_->Activate(active_lens_view_->lens()->id()); - if (active_lens_view_) - { - active_lens_view_->SetVisible(true); + /* Give the scopes a chance to prep data before we map them */ + if (active_scope_view_) + { + scope_bar_->Activate(active_scope_view_->scope()->id()); - 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() << "'"; - } - - home_lens_->view_type = ViewType::LENS_VIEW; - LOG_DEBUG(logger) << "Setting ViewType " << ViewType::LENS_VIEW - << " on '" << home_lens_->id() << "'"; - } - else - { - // careful here, the lens_view's view_type doesn't get reset when the dash - // hides, but lens' view_type does, so we need to update the lens directly - active_lens_view_->lens()->view_type = ViewType::LENS_VIEW; - } + active_scope_view_->SetVisible(true); + active_scope_view_->scope()->view_type = ScopeViewType::SCOPE_VIEW; + + // this will make sure the spinner animates if the search takes a while + search_bar_->ForceLiveSearch(); } - // 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(); } + overlay_window_buttons_->Show(); renderer_.AboutToShow(); @@ -522,19 +495,18 @@ void DashView::AboutToHide() visible_ = false; renderer_.AboutToHide(); - for (auto lens : lenses_->GetLenses()) + if (scopes_) { - lens->view_type = ViewType::HIDDEN; - LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN - << " on '" << lens->id() << "'"; + for (auto scope : scopes_->GetScopes()) + { + scope->view_type = ScopeViewType::HIDDEN; + LOG_DEBUG(logger) << "Setting ViewType " << ScopeViewType::HIDDEN + << " on '" << scope->id() << "'"; + } } - home_lens_->view_type = ViewType::HIDDEN; - LOG_DEBUG(logger) << "Setting ViewType " << ViewType::HIDDEN - << " on '" << home_lens_->id() << "'"; - - if (active_lens_view_.IsValid()) - active_lens_view_->SetVisible(false); + if (active_scope_view_.IsValid()) + active_scope_view_->SetVisible(false); // if a preview is open, close it if (preview_displaying_) @@ -576,30 +548,22 @@ void DashView::SetupViews() search_bar_->live_search_reached.connect(sigc::mem_fun(this, &DashView::OnLiveSearchReached)); search_bar_->showing_filters.changed.connect([&] (bool showing) { - if (active_lens_view_) + if (active_scope_view_) { - active_lens_view_->filters_expanded = showing; + active_scope_view_->filters_expanded = showing; QueueDraw(); } }); search_bar_layout_->AddView(search_bar_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); content_layout_->SetSpecialArea(search_bar_->show_filters()); - lenses_layout_ = new nux::VLayout(); - content_layout_->AddLayout(lenses_layout_, 1, nux::MINOR_POSITION_START); - - home_view_ = new LensView(home_lens_, nullptr); - home_view_->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated)); + scopes_layout_ = new nux::VLayout(); + content_layout_->AddLayout(scopes_layout_, 1, nux::MINOR_POSITION_START); - AddChild(home_view_.GetPointer()); - active_lens_view_ = home_view_; - lens_views_[home_lens_->id] = home_view_; - lenses_layout_->AddView(home_view_.GetPointer()); - - lens_bar_ = new LensBar(); - AddChild(lens_bar_); - lens_bar_->lens_activated.connect(sigc::mem_fun(this, &DashView::OnLensBarActivated)); - content_layout_->AddView(lens_bar_, 0, nux::MINOR_POSITION_CENTER); + scope_bar_ = new ScopeBar(); + AddChild(scope_bar_); + scope_bar_->scope_activated.connect(sigc::mem_fun(this, &DashView::OnScopeBarActivated)); + content_layout_->AddView(scope_bar_, 0, nux::MINOR_POSITION_CENTER); } void DashView::SetupUBusConnections() @@ -623,8 +587,8 @@ void DashView::Relayout() // kinda hacky, but it makes sure the content isn't so big that it throws // the bottom of the dash off the screen // not hugely happy with this, so FIXME - lenses_layout_->SetMaximumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - lens_bar_->GetGeometry().height - style.GetDashViewTopPadding())); - lenses_layout_->SetMinimumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - lens_bar_->GetGeometry().height - style.GetDashViewTopPadding())); + scopes_layout_->SetMaximumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - scope_bar_->GetGeometry().height - style.GetDashViewTopPadding())); + scopes_layout_->SetMinimumHeight (std::max(0, content_geo_.height - search_bar_->GetGeometry().height - scope_bar_->GetGeometry().height - style.GetDashViewTopPadding())); layout_->SetMinMaxSize(content_geo_.width, content_geo_.y + content_geo_.height); @@ -667,7 +631,7 @@ nux::Geometry DashView::GetBestFitGeometry(nux::Geometry const& for_geo) height += style.GetDashViewTopPadding(); height += search_bar_->GetGeometry().height; height += category_height * DASH_DEFAULT_CATEGORY_COUNT; // adding three categories - height += lens_bar_->GetGeometry().height; + height += scope_bar_->GetGeometry().height; // width/height shouldn't be bigger than the geo available. width = std::min(width, for_geo.width); // launcher width is taken into account in for_geo. @@ -733,7 +697,7 @@ void DashView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw graphics_engine.PushClippingRectangle(geo_split_clip); - if (preview_lens_view_.IsValid()) + if (preview_scope_view_.IsValid()) { DrawPreviewResultTextures(graphics_engine, force_draw); } @@ -755,8 +719,6 @@ void DashView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw nux::GetPainter().PopBackgroundStack(); } - overlay_window_buttons_->QueueDraw(); - graphics_engine.PopClippingRectangle(); renderer_.DrawInnerCleanup(graphics_engine, content_geo_, renderer_geo_abs, renderer_geo); @@ -780,29 +742,29 @@ void DashView::DrawDashSplit(nux::GraphicsEngine& graphics_engine, nux::Geometry texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); texxform.FlipVCoord(true); - // Lens Bar - texxform.uoffset = (lens_bar_->GetX() - content_view_->GetX())/(float)content_view_->GetWidth(); - texxform.voffset = (lens_bar_->GetY() - content_view_->GetY())/(float)content_view_->GetHeight(); + // Scope Bar + texxform.uoffset = (scope_bar_->GetX() - content_view_->GetX())/(float)content_view_->GetWidth(); + texxform.voffset = (scope_bar_->GetY() - content_view_->GetY())/(float)content_view_->GetHeight(); - int start_y = lens_bar_->GetY(); + int start_y = scope_bar_->GetY(); int final_y = geo_layout.y + geo_layout.height + PREVIEW_ICON_SPLIT_OFFSCREEN_OFFSET; - int lens_y = (1.0f - animate_split_value_) * start_y + (animate_split_value_ * final_y); + int scope_y = (1.0f - animate_split_value_) * start_y + (animate_split_value_ * final_y); graphics_engine.QRP_1Tex ( - lens_bar_->GetX(), - lens_y, - lens_bar_->GetWidth(), - lens_bar_->GetHeight(), + scope_bar_->GetX(), + scope_y, + scope_bar_->GetWidth(), + scope_bar_->GetHeight(), content_view_->BackupTexture(), texxform, nux::Color((1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_)) ); - split_clip.height = std::min(lens_y, geo_layout.height); + split_clip.height = std::min(scope_y, geo_layout.height); - if (active_lens_view_ && active_lens_view_->GetPushedFilterExpansion()) + if (active_scope_view_ && active_scope_view_->GetPushedFilterExpansion()) { // Search Bar texxform.uoffset = (search_bar_->GetX() - content_view_->GetX())/(float)content_view_->GetWidth(); @@ -815,7 +777,7 @@ void DashView::DrawDashSplit(nux::GraphicsEngine& graphics_engine, nux::Geometry ( search_bar_->GetX(), (1.0f - animate_split_value_) * start_y + (animate_split_value_ * final_y), - search_bar_->GetWidth() - active_lens_view_->filter_bar()->GetWidth(), + search_bar_->GetWidth() - active_scope_view_->filter_bar()->GetWidth(), search_bar_->GetHeight(), content_view_->BackupTexture(), texxform, @@ -823,10 +785,10 @@ void DashView::DrawDashSplit(nux::GraphicsEngine& graphics_engine, nux::Geometry ); // Filter Bar - texxform.uoffset = (active_lens_view_->filter_bar()->GetX() -content_view_->GetX())/(float)content_view_->GetWidth(); + texxform.uoffset = (active_scope_view_->filter_bar()->GetX() -content_view_->GetX())/(float)content_view_->GetWidth(); texxform.voffset = (search_bar_->GetY() - content_view_->GetY())/(float)content_view_->GetHeight(); - int start_x = active_lens_view_->filter_bar()->GetX(); + int start_x = active_scope_view_->filter_bar()->GetX(); int final_x = content_view_->GetX() + content_view_->GetWidth() + PREVIEW_ICON_SPLIT_OFFSCREEN_OFFSET; int filter_x = (1.0f - animate_split_value_) * start_x + (animate_split_value_ * final_x); @@ -835,8 +797,8 @@ void DashView::DrawDashSplit(nux::GraphicsEngine& graphics_engine, nux::Geometry ( filter_x, search_bar_->GetY(), - active_lens_view_->filter_bar()->GetWidth(), - active_lens_view_->filter_bar()->GetY() + active_lens_view_->filter_bar()->GetHeight(), + active_scope_view_->filter_bar()->GetWidth(), + active_scope_view_->filter_bar()->GetY() + active_scope_view_->filter_bar()->GetHeight(), content_view_->BackupTexture(), texxform, nux::Color((1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_), (1.0-animate_split_value_)) @@ -953,7 +915,7 @@ void DashView::DrawPreviewResultTextures(nux::GraphicsEngine& graphics_engine, b texxform.voffset = 0.0f; texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); - std::vector<ResultViewTexture::Ptr> result_textures = preview_lens_view_->GetResultTextureContainers(); + std::vector<ResultViewTexture::Ptr> result_textures = preview_scope_view_->GetResultTextureContainers(); std::vector<ResultViewTexture::Ptr> top_textures; int height_concat_below = 0; @@ -991,7 +953,7 @@ void DashView::DrawPreviewResultTextures(nux::GraphicsEngine& graphics_engine, b // off the bottom if (geo_tex_top.y <= geo_layout.y + geo_layout.height) { - preview_lens_view_->RenderResultTexture(result_texture); + preview_scope_view_->RenderResultTexture(result_texture); // If we haven't got it now, we're not going to get it if (!result_texture->texture.IsValid()) continue; @@ -1032,7 +994,7 @@ void DashView::DrawPreviewResultTextures(nux::GraphicsEngine& graphics_engine, b // off the top if (geo_tex_top.y + geo_tex_top.height >= geo_layout.y) { - preview_lens_view_->RenderResultTexture(result_texture); + preview_scope_view_->RenderResultTexture(result_texture); // If we haven't got it now, we're not going to get it if (!result_texture->texture.IsValid()) continue; @@ -1124,11 +1086,13 @@ void DashView::OnActivateRequest(GVariant* args) { glib::String uri; glib::String search_string; - dash::HandledType handled_type; + ScopeHandledType handled_type; g_variant_get(args, "(sus)", &uri, &handled_type, &search_string); - std::string id(AnalyseLensURI(uri.Str())); + std::string id(AnalyseScopeURI(uri.Str())); + + LOG_DEBUG(logger) << "External activation request: " << id << " (uri: "<< uri.Str() << ")"; // we got an activation request, we should probably close the preview if (preview_displaying_) @@ -1136,45 +1100,48 @@ void DashView::OnActivateRequest(GVariant* args) ClosePreview(); } - if (!visible_) - { - lens_bar_->Activate(id); - ubus_manager_.SendMessage(UBUS_DASH_EXTERNAL_ACTIVATION); - } - else if (/* visible_ && */ handled_type == NOT_HANDLED) + if (visible_ && handled_type == ScopeHandledType::NOT_HANDLED) { ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST, NULL, - glib::Source::Priority::HIGH); + glib::Source::Priority::HIGH); } - else if (/* visible_ && */ handled_type == GOTO_DASH_URI) - { - lens_bar_->Activate(id); + else if (!visible_ || handled_type == ScopeHandledType::GOTO_DASH_URI) + { + if (!scopes_->GetScope(id)) + { + // should trigger the addition of the scope. + scopes_->AppendScope(id); + } + scope_bar_->Activate(id); + + if (!visible_) + ubus_manager_.SendMessage(UBUS_DASH_EXTERNAL_ACTIVATION); } } -std::string DashView::AnalyseLensURI(std::string const& uri) +std::string DashView::AnalyseScopeURI(std::string const& uri) { - impl::LensFilter filter = impl::parse_lens_uri(uri); + impl::ScopeFilter filter = impl::parse_scope_uri(uri); if (!filter.filters.empty()) { - lens_views_[filter.id]->filters_expanded = true; - // update the lens for each filter + scope_views_[filter.id]->filters_expanded = true; + // update the scope for each filter for (auto p : filter.filters) { - UpdateLensFilter(filter.id, p.first, p.second); + UpdateScopeFilter(filter.id, p.first, p.second); } } return filter.id; } -void DashView::UpdateLensFilter(std::string lens_id, std::string filter_name, std::string value) +void DashView::UpdateScopeFilter(std::string scope_id, std::string filter_name, std::string value) { - if (lenses_->GetLens(lens_id)) + if (scopes_ && scopes_->GetScope(scope_id)) { - Lens::Ptr lens = lenses_->GetLens(lens_id); + Scope::Ptr scope = scopes_->GetScope(scope_id); - Filters::Ptr filters = lens->filters; + Filters::Ptr filters = scope->filters; for (unsigned int i = 0; i < filters->count(); ++i) { @@ -1182,13 +1149,13 @@ void DashView::UpdateLensFilter(std::string lens_id, std::string filter_name, st if (filter->id() == filter_name) { - UpdateLensFilterValue(filter, value); + UpdateScopeFilterValue(filter, value); } } } } -void DashView::UpdateLensFilterValue(Filter::Ptr filter, std::string value) +void DashView::UpdateScopeFilterValue(Filter::Ptr filter, std::string value) { if (filter->renderer_name == "filter-radiooption") { @@ -1203,65 +1170,66 @@ void DashView::UpdateLensFilterValue(Filter::Ptr filter, std::string value) void DashView::OnSearchChanged(std::string const& search_string) { - LOG_DEBUG(logger) << "Search changed: " << search_string; - if (active_lens_view_) - { - search_in_progress_ = true; - // it isn't guaranteed that we get a SearchFinished signal, so we need - // FIXME: it is now actually!! - // to make sure this isn't set even though we aren't doing any search - // 250ms for the Search method call, rest for the actual search - searching_timeout_.reset(new glib::Timeout(500, [&] () { - search_in_progress_ = false; - activate_on_finish_ = false; - return false; - })); - - // 150ms to hide the no reults message if its take a while to return results - hide_message_delay_.reset(new glib::Timeout(150, [&] () { - active_lens_view_->HideResultsMessage(); - return false; - })); - } + search_in_progress_ = true; } void DashView::OnLiveSearchReached(std::string const& search_string) { + // reset and set it again once we're sure a search is happening + search_in_progress_ = false; + LOG_DEBUG(logger) << "Live search reached: " << search_string; - if (active_lens_view_) + if (active_scope_view_) { - active_lens_view_->PerformSearch(search_string, - sigc::mem_fun(this, &DashView::OnSearchFinished)); + if (active_scope_view_->PerformSearch(search_string, sigc::mem_fun(this, &DashView::OnScopeSearchFinished))) + { + search_in_progress_ = true; + } } } -void DashView::OnLensAdded(Lens::Ptr& lens) +void DashView::OnScopeSearchFinished(std::string const& scope_id, std::string const& search_string, glib::Error const& err) { - lens_bar_->AddLens(lens); + // match active scope? + auto scope_pos = scope_views_.find(scope_id); + if (scope_pos == scope_views_.end() || scope_pos->second != active_scope_view_) + return; + + if (search_string == search_bar_->search_string) + { + if (err) + LOG_WARNING(logger) << "Search failed '"<< search_string <<"'=> " << err; + else + LOG_DEBUG(logger) << "Search completed: " << search_string; - nux::ObjectPtr<LensView> view(new LensView(lens, search_bar_->show_filters())); + search_bar_->SetSearchFinished(); + search_in_progress_ = false; + + if (activate_on_finish_ && !err) + OnEntryActivated(); + activate_on_finish_= false; + } +} + +void DashView::OnScopeAdded(Scope::Ptr const& scope, int position) +{ + LOG_DEBUG(logger) << "Scope Added: " << scope->id(); + + scope_bar_->AddScope(scope); + + nux::ObjectPtr<ScopeView> view(new ScopeView(scope, search_bar_->show_filters())); AddChild(view.GetPointer()); view->SetVisible(false); - view->uri_activated.connect(sigc::mem_fun(this, &DashView::OnUriActivated)); + view->result_activated.connect(sigc::mem_fun(this, &DashView::OnResultActivated)); - lenses_layout_->AddView(view.GetPointer(), 1); - lens_views_[lens->id] = view; + scopes_layout_->AddView(view.GetPointer(), 1); + scope_views_[scope->id] = view; - lens->activated.connect(sigc::mem_fun(this, &DashView::OnUriActivatedReply)); - lens->connected.changed.connect([&] (bool value) - { - std::string const& search_string = search_bar_->search_string; - if (value && lens->search_in_global && active_lens_view_ == home_view_ - && !search_string.empty()) - { - // force a (global!) search with the correct string - lens->GlobalSearch(search_bar_->search_string, - sigc::mem_fun(this, &DashView::OnSearchFinished)); - } - }); + scope->activated.connect(sigc::mem_fun(this, &DashView::OnResultActivatedReply)); + scope->connected.changed.connect([&] (bool value) { }); // Hook up to the new preview infrastructure - lens->preview_ready.connect([&] (std::string const& uri, Preview::Ptr model) + scope->preview_ready.connect([&] (LocalResult const& result, Preview::Ptr model) { // HACK: Atm we don't support well the fact that a preview can be sent from // an ActionResponse and therefore transition does not work, this hack allows @@ -1274,28 +1242,32 @@ void DashView::OnLensAdded(Lens::Ptr& lens) } preview_state_machine_.ActivatePreview(model); // this does not immediately display a preview - we now wait. }); + + if (!active_scope_view_) + scope_bar_->Activate(scope->id); } -void DashView::OnLensBarActivated(std::string const& id) +void DashView::OnScopeBarActivated(std::string const& id) { - if (lens_views_.find(id) == lens_views_.end()) + if (scope_views_.find(id) == scope_views_.end()) { - LOG_WARN(logger) << "Unable to find Lens " << id; + LOG_WARN(logger) << "Unable to find Scope " << id; return; } - if (active_lens_view_.IsValid()) - active_lens_view_->SetVisible(false); + if (active_scope_view_.IsValid()) + active_scope_view_->SetVisible(false); + scope_can_refine_connection_.disconnect(); - nux::ObjectPtr<LensView> view = active_lens_view_ = lens_views_[id]; + nux::ObjectPtr<ScopeView> view = active_scope_view_ = scope_views_[id]; view->SetVisible(true); view->AboutToShow(); - for (auto it: lens_views_) + for (auto it: scope_views_) { bool id_matches = it.first == id; - ViewType view_type = id_matches ? LENS_VIEW : (view == home_view_ ? HOME_VIEW : HIDDEN); + ScopeViewType view_type = id_matches ? ScopeViewType::SCOPE_VIEW : ScopeViewType::HIDDEN; it.second->SetVisible(id_matches); it.second->view_type = view_type; @@ -1306,72 +1278,32 @@ void DashView::OnLensBarActivated(std::string const& id) 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 - // doesn't change, so SearchFinished will be called in a few ms - // FIXME: if we're forcing a search here, why don't we get rid of view types? - search_bar_->ForceSearchChanged(); - - bool expanded = view->filters_expanded; - search_bar_->showing_filters = expanded; - - nux::GetWindowCompositor().SetKeyFocusArea(default_focus()); + search_bar_->search_hint = view->scope()->search_hint; + search_bar_->showing_filters = view->filters_expanded(); + search_bar_->ForceLiveSearch(); search_bar_->text_entry()->SelectAll(); search_bar_->can_refine_search = view->can_refine_search(); - hide_message_delay_.reset(); + scope_can_refine_connection_ = view->can_refine_search.changed.connect([this] (bool can_refine_search) { + search_bar_->can_refine_search = can_refine_search; + }); + + // Fix for a nux quirk. Unparented objects cannot have focus because there will be a break in the + // parent tree and the compositor will not be able to walk the focus tree. This still needs to be here + // for when scopes switch via the scope bar and the focus nees to move away from the scope bar to the search bar.. + if (GetParentObject()) + nux::GetWindowCompositor().SetKeyFocusArea(default_focus()); view->QueueDraw(); QueueDraw(); } -void DashView::OnSearchFinished(Lens::Hints const& hints, glib::Error const& err) -{ - hide_message_delay_.reset(); - - if (!active_lens_view_.IsValid()) return; - - // FIXME: bind the lens_view in PerformSearch - active_lens_view_->CheckNoResults(hints); - std::string const& search_string = search_bar_->search_string; - - if (active_lens_view_->search_string == search_string) - { - search_bar_->SearchFinished(); - search_in_progress_ = false; - if (activate_on_finish_) - this->OnEntryActivated(); - } -} - -void DashView::OnGlobalSearchFinished(Lens::Hints const& hints, glib::Error const& error) -{ - if (active_lens_view_ == home_view_) - OnSearchFinished(hints, error); -} - -void DashView::OnAppsGlobalSearchFinished(Lens::Ptr const& lens) -{ - if (active_lens_view_ == home_view_ && lens->id() == "applications.lens") - { - /* HACKITY HACK! We're resetting the state of search_in_progress when - * doing searches in the home lens and we get results from apps lens. - * This way typing a search query and pressing enter immediately will - * wait for the apps lens results and will run correct application. - * See lp:966417 and lp:856206 for more info about why we do this. - */ - search_in_progress_ = false; - if (activate_on_finish_) - this->OnEntryActivated(); - } -} - -void DashView::OnUriActivatedReply(std::string const& uri, HandledType type, Lens::Hints const&) +void DashView::OnResultActivatedReply(LocalResult const& local_result, ScopeHandledType type, glib::HintsMap const&) { // We don't want to close the dash if there was another activation pending if (type == NOT_HANDLED) { - if (!DoFallbackActivation(uri)) + if (!DoFallbackActivation(local_result.uri)) return; } else if (type == SHOW_DASH) @@ -1382,13 +1314,8 @@ void DashView::OnUriActivatedReply(std::string const& uri, HandledType type, Len ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); } -bool DashView::DoFallbackActivation(std::string const& fake_uri) +bool DashView::DoFallbackActivation(std::string const& uri) { - size_t pos = fake_uri.find(":"); - std::string uri = fake_uri.substr(++pos); - - LOG_DEBUG(logger) << "Fallback activating " << uri; - if (g_str_has_prefix(uri.c_str(), "application://")) { std::string const& appname = uri.substr(14); @@ -1411,9 +1338,9 @@ void DashView::DisableBlur() } void DashView::OnEntryActivated() { - if (active_lens_view_.IsValid() && !search_in_progress_) + if (active_scope_view_.IsValid() && !search_in_progress_) { - active_lens_view_->ActivateFirst(); + active_scope_view_->ActivateFirst(); } // delay the activation until we get the SearchFinished signal activate_on_finish_ = search_in_progress_; @@ -1427,9 +1354,9 @@ bool DashView::AcceptKeyNavFocus() std::string const DashView::GetIdForShortcutActivation(std::string const& shortcut) const { - Lens::Ptr lens = lenses_->GetLensForShortcut(shortcut); - if (lens) - return lens->id; + Scope::Ptr scope = scopes_ ? scopes_->GetScopeForShortcut(shortcut) : Scope::Ptr(); + if (scope) + return scope->id; return ""; } @@ -1437,11 +1364,14 @@ std::vector<char> DashView::GetAllShortcuts() { std::vector<char> result; - for (Lens::Ptr lens: lenses_->GetLenses()) + if (scopes_) { - std::string shortcut = lens->shortcut; - if(shortcut.size() > 0) - result.push_back(shortcut.at(0)); + for (Scope::Ptr scope: scopes_->GetScopes()) + { + std::string shortcut = scope->shortcut; + if(shortcut.size() > 0) + result.push_back(shortcut.at(0)); + } } return result; } @@ -1480,8 +1410,8 @@ void DashView::AddProperties(GVariantBuilder* builder) dash::Style& style = dash::Style::Instance(); int num_rows = 1; // The search bar - if (active_lens_view_.IsValid()) - num_rows += active_lens_view_->GetNumRows(); + if (active_scope_view_.IsValid()) + num_rows += active_scope_view_->GetNumRows(); std::string form_factor("unknown"); @@ -1510,17 +1440,17 @@ nux::Area* DashView::KeyNavIteration(nux::KeyNavDirection direction) { return preview_container_->KeyNavIteration(direction); } - else if (direction == nux::KEY_NAV_DOWN && search_bar_ && active_lens_view_.IsValid()) + else if (direction == nux::KEY_NAV_DOWN && search_bar_ && active_scope_view_.IsValid()) { auto show_filters = search_bar_->show_filters(); - auto fscroll_view = active_lens_view_->fscroll_view(); + auto fscroll_view = active_scope_view_->fscroll_view(); if (show_filters && show_filters->HasKeyFocus()) { if (fscroll_view->IsVisible() && fscroll_view) return fscroll_view->KeyNavIteration(direction); else - return active_lens_view_->KeyNavIteration(direction); + return active_scope_view_->KeyNavIteration(direction); } } return this; @@ -1528,7 +1458,11 @@ nux::Area* DashView::KeyNavIteration(nux::KeyNavDirection direction) void DashView::ProcessDndEnter() { - ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); + auto const& event = nux::GetGraphicsDisplay()->GetCurrentEvent(); + + // Don't close the dash if the mouse is over the vertical line between the dash and the launcher. + if (event.x != GetAbsoluteX()) + ubus_manager_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); } nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol, @@ -1598,12 +1532,12 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol, if (direction != KEY_NAV_NONE && key_symbol == nux::NUX_KEYDOWN && !search_bar_->im_preedit) { std::list<nux::Area*> tabs; - if (active_lens_view_.IsValid()) + if (active_scope_view_.IsValid()) { - for (auto category : active_lens_view_->categories()) + for (auto category : active_scope_view_->GetOrderedCategoryViews()) { if (category->IsVisible()) - tabs.push_back(category); + tabs.push_back(category.GetPointer()); } } @@ -1613,11 +1547,11 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol, tabs.push_back(search_bar_->show_filters()); } - if (active_lens_view_.IsValid() && - active_lens_view_->filter_bar() && active_lens_view_->fscroll_view() && - active_lens_view_->fscroll_view()->IsVisible()) + if (active_scope_view_.IsValid() && + active_scope_view_->filter_bar() && active_scope_view_->fscroll_view() && + active_scope_view_->fscroll_view()->IsVisible()) { - for (auto child : active_lens_view_->filter_bar()->GetLayout()->GetChildren()) + for (auto child : active_scope_view_->filter_bar()->GetLayout()->GetChildren()) { FilterExpanderLabel* filter = dynamic_cast<FilterExpanderLabel*>(child); if (filter) @@ -1629,7 +1563,7 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol, { if (ctrl) { - lens_bar_->ActivatePrevious(); + scope_bar_->ActivatePrevious(); } else { @@ -1656,7 +1590,7 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol, { if (ctrl) { - lens_bar_->ActivateNext(); + scope_bar_->ActivateNext(); } else { @@ -1687,7 +1621,7 @@ nux::Area* DashView::FindKeyFocusArea(unsigned int key_symbol, } } - if (search_key || search_bar_->im_preedit) + if (!preview_displaying_ && (search_key || search_bar_->im_preedit)) { // then send the event to the search entry return search_bar_->text_entry(); diff --git a/dash/DashView.h b/dash/DashView.h index cf1974263..28105e2fe 100644 --- a/dash/DashView.h +++ b/dash/DashView.h @@ -24,13 +24,12 @@ #include <Nux/View.h> #include <Nux/VLayout.h> -#include <UnityCore/FilesystemLenses.h> -#include <UnityCore/HomeLens.h> +#include <UnityCore/Scopes.h> #include <UnityCore/GLibSource.h> +#include "ScopeBar.h" +#include "ScopeView.h" #include "ApplicationStarter.h" -#include "LensBar.h" -#include "LensView.h" #include "previews/PreviewContainer.h" #include "PreviewStateMachine.h" #include "UnityCore/Preview.h" @@ -56,10 +55,10 @@ class DashLayout; class DashView : public nux::View, public unity::debug::Introspectable { NUX_DECLARE_OBJECT_TYPE(DashView, nux::View); - typedef std::map<std::string, nux::ObjectPtr<LensView>> LensViews; + typedef std::map<std::string, nux::ObjectPtr<ScopeView>> ScopeViews; public: - DashView(Lenses::Ptr const& lenses, ApplicationStarter::Ptr const& application_starter); + DashView(Scopes::Ptr const& scopes, ApplicationStarter::Ptr const& application_starter); ~DashView(); void AboutToShow(); @@ -111,20 +110,17 @@ private: void OnBackgroundColorChanged(GVariant* args); void OnSearchChanged(std::string const& search_string); void OnLiveSearchReached(std::string const& search_string); - void OnLensAdded(Lens::Ptr& lens); - void OnLensBarActivated(std::string const& id); - void OnSearchFinished(Lens::Hints const& hints, glib::Error const& error); - void OnGlobalSearchFinished(Lens::Hints const& hints, glib::Error const& error); - void OnAppsGlobalSearchFinished(Lens::Ptr const& lens); - void OnUriActivated(ResultView::ActivateType type, std::string const& uri, GVariant* data, std::string const& unique_id); - void OnUriActivatedReply(std::string const& uri, HandledType type, Lens::Hints const&); + void OnScopeAdded(Scope::Ptr const& scope, int position); + void OnScopeBarActivated(std::string const& id); + void OnScopeSearchFinished(std::string const& scope_id, std::string const& search_string, glib::Error const& err); + void OnResultActivated(ResultView::ActivateType type, LocalResult const& local_result, GVariant* data, std::string const& unique_id); + void OnResultActivatedReply(LocalResult const& local_result, ScopeHandledType type, glib::HintsMap const& hints); bool DoFallbackActivation(std::string const& uri); bool LaunchApp(std::string const& appname); void OnEntryActivated(); - std::string AnalyseLensURI(std::string const& uri); - void UpdateLensFilter(std::string lens, std::string filter, std::string value); - void UpdateLensFilterValue(Filter::Ptr filter, std::string value); - void EnsureLensesInitialized(); + std::string AnalyseScopeURI(std::string const& uri); + void UpdateScopeFilter(std::string scope_id, std::string filter, std::string value); + void UpdateScopeFilterValue(Filter::Ptr filter, std::string value); bool AcceptKeyNavFocus(); bool InspectKeyEvent(unsigned int eventType, unsigned int key_sym, const char* character); @@ -134,9 +130,8 @@ private: nux::Area* KeyNavIteration(nux::KeyNavDirection direction); UBusManager ubus_manager_; - Lenses::Ptr lenses_; - HomeLens::Ptr home_lens_; - LensViews lens_views_; + Scopes::Ptr scopes_; + ScopeViews scope_views_; ApplicationStarter::Ptr application_starter_; @@ -152,27 +147,24 @@ private: nux::View* content_view_; nux::HLayout* search_bar_layout_; SearchBar* search_bar_; - nux::VLayout* lenses_layout_; - LensBar* lens_bar_; + nux::VLayout* scopes_layout_; + ScopeBar* scope_bar_; - nux::ObjectPtr<LensView> home_view_; - nux::ObjectPtr<LensView> active_lens_view_; - nux::ObjectPtr<LensView> preview_lens_view_; + nux::ObjectPtr<ScopeView> active_scope_view_; + nux::ObjectPtr<ScopeView> preview_scope_view_; + sigc::connection scope_can_refine_connection_; // Drawing related nux::Geometry content_geo_; OverlayRenderer renderer_; - std::string last_activated_uri_; + LocalResult last_activated_result_; guint64 last_activated_timestamp_; bool search_in_progress_; bool activate_on_finish_; bool visible_; - glib::Source::UniquePtr searching_timeout_; - glib::Source::UniquePtr hide_message_delay_; - nux::ObjectPtr<nux::IOpenGLBaseTexture> dash_view_copy_; nux::ObjectPtr<nux::IOpenGLBaseTexture> search_view_copy_; nux::ObjectPtr<nux::IOpenGLBaseTexture> filter_view_copy_; @@ -195,6 +187,8 @@ private: float animate_preview_value_; nux::ObjectPtr<OverlayWindowButtons> overlay_window_buttons_; + + friend class TestDashView; }; diff --git a/dash/DashViewPrivate.cpp b/dash/DashViewPrivate.cpp index 796619730..6dca9572e 100644 --- a/dash/DashViewPrivate.cpp +++ b/dash/DashViewPrivate.cpp @@ -28,9 +28,9 @@ namespace dash namespace impl { -LensFilter parse_lens_uri(std::string const& uri) +ScopeFilter parse_scope_uri(std::string const& uri) { - LensFilter filter; + ScopeFilter filter; filter.id = uri; std::size_t pos = uri.find("?"); diff --git a/dash/DashViewPrivate.h b/dash/DashViewPrivate.h index cb03cb562..9e3855634 100644 --- a/dash/DashViewPrivate.h +++ b/dash/DashViewPrivate.h @@ -29,13 +29,13 @@ namespace dash namespace impl { -struct LensFilter +struct ScopeFilter { std::string id; std::map<std::string, std::string> filters; }; -LensFilter parse_lens_uri(std::string const& uri); +ScopeFilter parse_scope_uri(std::string const& uri); } // namespace impl } // namespace dash diff --git a/dash/FilterAllButton.cpp b/dash/FilterAllButton.cpp index 474e40134..bef183d04 100644 --- a/dash/FilterAllButton.cpp +++ b/dash/FilterAllButton.cpp @@ -45,6 +45,7 @@ FilterAllButton::FilterAllButton(NUX_FILE_LINE_DECL) FilterAllButton::~FilterAllButton() { + filtering_connection_.disconnect(); } void FilterAllButton::SetFilter(Filter::Ptr const& filter) diff --git a/dash/FilterBar.cpp b/dash/FilterBar.cpp index 60135a0c1..b5cca7a68 100644 --- a/dash/FilterBar.cpp +++ b/dash/FilterBar.cpp @@ -33,17 +33,13 @@ namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.filter.bar"); +DECLARE_LOGGER(logger, "unity.dash.filterbar"); NUX_IMPLEMENT_OBJECT_TYPE(FilterBar); FilterBar::FilterBar(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) { - // TODO - does the filterbar associate itself with a model of some sort? - // does libunity provide a Lens.Filters model or something that we can update on? - // don't want to associate a Filterbar with just a lens model, its a filter bar not a - // lens parser Init(); } @@ -95,6 +91,17 @@ void FilterBar::RemoveFilter(Filter::Ptr const& filter) } } +void FilterBar::ClearFilters() +{ + for (auto iter: filter_map_) + { + FilterExpanderLabel* filter_view = iter.second; + RemoveChild(filter_view); + GetLayout()->RemoveChildObject(filter_view); + } + filter_map_.clear(); +} + void FilterBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) { diff --git a/dash/FilterBar.h b/dash/FilterBar.h index 56e0bb459..668065275 100644 --- a/dash/FilterBar.h +++ b/dash/FilterBar.h @@ -48,6 +48,7 @@ public: void AddFilter(Filter::Ptr const& filter); void RemoveFilter(Filter::Ptr const& filter); + void ClearFilters(); protected: virtual bool AcceptKeyNavFocus(); diff --git a/dash/FilterExpanderLabel.cpp b/dash/FilterExpanderLabel.cpp index 5b08540c3..b2fda6b34 100644 --- a/dash/FilterExpanderLabel.cpp +++ b/dash/FilterExpanderLabel.cpp @@ -62,12 +62,10 @@ protected: nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) { - bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); - - if (mouse_inside == false) + if (event_type != nux::EVENT_MOUSE_WHEEL && TestMousePointerInclusion(mouse_position, event_type)) + return this; + else return nullptr; - - return this; } }; @@ -106,11 +104,18 @@ void FilterExpanderLabel::SetLabel(std::string const& label) void FilterExpanderLabel::SetRightHandView(nux::View* view) { dash::Style& style = dash::Style::Instance(); - - right_hand_contents_ = view; - right_hand_contents_->SetMinimumHeight(style.GetAllButtonHeight()); - right_hand_contents_->SetMaximumHeight(style.GetAllButtonHeight()); - top_bar_layout_->AddView(right_hand_contents_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); + if (right_hand_contents_) + { + top_bar_layout_->RemoveChildObject(right_hand_contents_); + right_hand_contents_ = nullptr; + } + if (view) + { + right_hand_contents_ = view; + right_hand_contents_->SetMinimumHeight(style.GetAllButtonHeight()); + right_hand_contents_->SetMaximumHeight(style.GetAllButtonHeight()); + top_bar_layout_->AddView(right_hand_contents_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); + } } void FilterExpanderLabel::SetContents(nux::Layout* contents) diff --git a/dash/FilterGenreWidget.cpp b/dash/FilterGenreWidget.cpp index ea638e95e..cb2475e9b 100644 --- a/dash/FilterGenreWidget.cpp +++ b/dash/FilterGenreWidget.cpp @@ -39,13 +39,13 @@ namespace dash NUX_IMPLEMENT_OBJECT_TYPE(FilterGenre); FilterGenre::FilterGenre(int columns, NUX_FILE_LINE_DECL) - : FilterExpanderLabel(_("Categories"), NUX_FILE_LINE_PARAM) +: FilterExpanderLabel(_("Categories"), NUX_FILE_LINE_PARAM) +, all_button_(nullptr) { dash::Style& style = dash::Style::Instance(); InitTheme(); - all_button_ = new FilterAllButton(NUX_TRACKER_LOCATION); genre_layout_ = new nux::GridHLayout(NUX_TRACKER_LOCATION); genre_layout_->ForceChildrenSize(true); @@ -64,7 +64,6 @@ FilterGenre::FilterGenre(int columns, NUX_FILE_LINE_DECL) genre_layout_->SetSpaceBetweenChildren (10, 12); } - SetRightHandView(all_button_); SetContents(genre_layout_); } @@ -76,7 +75,17 @@ void FilterGenre::SetFilter(Filter::Ptr const& filter) { filter_ = std::static_pointer_cast<CheckOptionFilter>(filter); - all_button_->SetFilter(filter_); + // all button + auto show_button_func = [this] (bool show_all_button) + { + all_button_ = show_all_button ? new FilterAllButton(NUX_TRACKER_LOCATION) : nullptr; + SetRightHandView(all_button_); + if (all_button_) + all_button_->SetFilter(filter_); + }; + show_button_func(filter_->show_all_button); + filter_->show_all_button.changed.connect(show_button_func); + expanded = !filter_->collapsed(); filter_->option_added.connect(sigc::mem_fun(this, &FilterGenre::OnOptionAdded)); @@ -100,6 +109,8 @@ void FilterGenre::OnOptionAdded(FilterOption::Ptr const& new_filter) button->SetFilter(new_filter); genre_layout_->AddView(button, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); buttons_.push_back(button); + + QueueRelayout(); } void FilterGenre::OnOptionRemoved(FilterOption::Ptr const& removed_filter) @@ -110,6 +121,8 @@ void FilterGenre::OnOptionRemoved(FilterOption::Ptr const& removed_filter) { genre_layout_->RemoveChildObject(*it); buttons_.erase(it); + + QueueRelayout(); break; } } diff --git a/dash/FilterMultiRangeWidget.cpp b/dash/FilterMultiRangeWidget.cpp index d42268342..8a95217f5 100644 --- a/dash/FilterMultiRangeWidget.cpp +++ b/dash/FilterMultiRangeWidget.cpp @@ -41,6 +41,7 @@ NUX_IMPLEMENT_OBJECT_TYPE(FilterMultiRangeWidget); FilterMultiRangeWidget::FilterMultiRangeWidget(NUX_FILE_LINE_DECL) : FilterExpanderLabel(_("Multi-range"), NUX_FILE_LINE_PARAM) + , all_button_(nullptr) , dragging_(false) { InitTheme(); @@ -51,13 +52,10 @@ FilterMultiRangeWidget::FilterMultiRangeWidget(NUX_FILE_LINE_DECL) const int top_padding = style.GetSpaceBetweenFilterWidgets() - style.GetFilterHighlightPadding() - 2; const int bottom_padding = style.GetFilterHighlightPadding() - 1; - all_button_ = new FilterAllButton(NUX_TRACKER_LOCATION); - layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); layout_->SetLeftAndRightPadding(left_padding, right_padding); layout_->SetTopAndBottomPadding(top_padding, bottom_padding); - SetRightHandView(all_button_); SetContents(layout_); OnActiveChanged(false); @@ -79,7 +77,17 @@ void FilterMultiRangeWidget::SetFilter(Filter::Ptr const& filter) filter_ = std::static_pointer_cast<MultiRangeFilter>(filter); - all_button_->SetFilter(filter_); + // all button + auto show_button_func = [this] (bool show_all_button) + { + all_button_ = show_all_button ? new FilterAllButton(NUX_TRACKER_LOCATION) : nullptr; + SetRightHandView(all_button_); + if (all_button_) + all_button_->SetFilter(filter_); + }; + show_button_func(filter_->show_all_button); + filter_->show_all_button.changed.connect(show_button_func); + expanded = !filter_->collapsed(); filter_->option_added.connect(sigc::mem_fun(this, &FilterMultiRangeWidget::OnOptionAdded)); diff --git a/dash/FilterRatingsButton.cpp b/dash/FilterRatingsButton.cpp index 2f2374b26..c73df3a11 100644 --- a/dash/FilterRatingsButton.cpp +++ b/dash/FilterRatingsButton.cpp @@ -90,7 +90,7 @@ void FilterRatingsButton::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) // FIXME: 9/26/2011 // We should probably support an API for saying whether the ratings // should or shouldn't support half stars...but our only consumer at - // the moment is the applications lens which according to design + // the moment is the applications scope which according to design // (Bug #839759) shouldn't. So for now just force rounding. // int total_half_stars = rating % 2; // int total_full_stars = rating / 2; diff --git a/dash/FilterRatingsWidget.cpp b/dash/FilterRatingsWidget.cpp index ae89d965d..1fd083315 100644 --- a/dash/FilterRatingsWidget.cpp +++ b/dash/FilterRatingsWidget.cpp @@ -46,10 +46,9 @@ namespace dash NUX_IMPLEMENT_OBJECT_TYPE(FilterRatingsWidget); FilterRatingsWidget::FilterRatingsWidget(NUX_FILE_LINE_DECL) - : FilterExpanderLabel(_("Rating"), NUX_FILE_LINE_PARAM) +: FilterExpanderLabel(_("Rating"), NUX_FILE_LINE_PARAM) +, all_button_(nullptr) { - all_button_ = new FilterAllButton(NUX_TRACKER_LOCATION); - dash::Style& style = dash::Style::Instance(); const int top_padding = style.GetSpaceBetweenFilterWidgets() - style.GetFilterHighlightPadding() - 1; // -1 (PNGs have an 1px top padding) const int bottom_padding = style.GetFilterHighlightPadding(); @@ -61,7 +60,6 @@ FilterRatingsWidget::FilterRatingsWidget(NUX_FILE_LINE_DECL) layout->AddView(ratings_); - SetRightHandView(all_button_); SetContents(layout); } @@ -73,6 +71,17 @@ void FilterRatingsWidget::SetFilter(Filter::Ptr const& filter) { filter_ = std::static_pointer_cast<RatingsFilter>(filter); + // all button + auto show_button_func = [this] (bool show_all_button) + { + all_button_ = show_all_button ? new FilterAllButton(NUX_TRACKER_LOCATION) : nullptr; + SetRightHandView(all_button_); + if (all_button_) + all_button_->SetFilter(filter_); + }; + show_button_func(filter_->show_all_button); + filter_->show_all_button.changed.connect(show_button_func); + all_button_->SetFilter(filter_); expanded = !filter_->collapsed(); ratings_->SetFilter(filter_); diff --git a/dash/LensView.cpp b/dash/LensView.cpp deleted file mode 100755 index e972e3f94..000000000 --- a/dash/LensView.cpp +++ /dev/null @@ -1,946 +0,0 @@ -// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- -/* - * Copyright (C) 2010, 2011 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: Neil Jagdish Patel <neil.patel@canonical.com> - */ - -#include "LensView.h" - -#include <boost/lexical_cast.hpp> - -#include <NuxCore/Logger.h> -#include <Nux/HScrollBar.h> -#include <Nux/VScrollBar.h> - -#include "unity-shared/DashStyle.h" -#include "CoverflowResultView.h" - -#include "ResultRendererTile.h" -#include "ResultRendererHorizontalTile.h" -#include "unity-shared/UBusMessages.h" -#include "unity-shared/UBusWrapper.h" -#include "unity-shared/PlacesVScrollBar.h" -#include "unity-shared/PlacesOverlayVScrollBar.h" -#include "unity-shared/GraphicsUtils.h" - -#include "config.h" -#include <glib/gi18n-lib.h> - -namespace unity -{ -namespace dash -{ -DECLARE_LOGGER(logger, "unity.dash.lensview"); -namespace -{ -const int CARD_VIEW_GAP_VERT = 24; // pixels -const int CARD_VIEW_GAP_HORIZ = 25; // pixels -} - -// This is so we can access some protected members in scrollview. -class LensScrollView: public nux::ScrollView -{ -public: - LensScrollView(nux::VScrollBar* scroll_bar, NUX_FILE_LINE_DECL) - : nux::ScrollView(NUX_FILE_LINE_PARAM) - , right_area_(nullptr) - , up_area_(nullptr) - { - SetVScrollBar(scroll_bar); - - OnVisibleChanged.connect([&] (nux::Area* /*area*/, bool visible) { - if (m_horizontal_scrollbar_enable) - _hscrollbar->SetVisible(visible); - if (m_vertical_scrollbar_enable) - _vscrollbar->SetVisible(visible); - }); - } - - void ScrollToPosition(nux::Geometry const& position) - { - // much of this code is copied from Nux/ScrollView.cpp - nux::Geometry const& geo = GetGeometry(); - - int child_y = position.y - geo.y; - int child_y_diff = child_y - abs (_delta_y); - - if (child_y_diff + position.height < geo.height && child_y_diff >= 0) - { - return; - } - - if (child_y_diff < 0) - { - ScrollUp (1, abs (child_y_diff)); - } - else - { - int size = child_y_diff - geo.height; - - // always keeps the top of a view on the screen - size += position.height; - - ScrollDown (1, size); - } - } - - void SetRightArea(nux::Area* area) - { - right_area_ = area; - } - - void SetUpArea(nux::Area* area) - { - up_area_ = area; - } - - void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) - { - if (RedirectedAncestor()) - { - if (m_horizontal_scrollbar_enable && _hscrollbar->IsRedrawNeeded()) - graphics::ClearGeometry(_hscrollbar->GetGeometry()); - if (m_vertical_scrollbar_enable && _vscrollbar->IsRedrawNeeded()) - graphics::ClearGeometry(_vscrollbar->GetGeometry()); - } - - ScrollView::DrawContent(graphics_engine, force_draw); - } - - void EnableScrolling(bool enable_scrolling) - { - _vscrollbar->SetInputEventSensitivity(enable_scrolling); - } - -protected: - - // This is so we can break the natural key navigation path. - nux::Area* KeyNavIteration(nux::KeyNavDirection direction) - { - nux::Area* focus_area = nux::GetWindowCompositor().GetKeyFocusArea(); - - if (direction == nux::KEY_NAV_RIGHT && focus_area && focus_area->IsChildOf(this)) - return right_area_; - else if (direction == nux::KEY_NAV_UP && focus_area && focus_area->IsChildOf(this)) - return up_area_; - else - return nux::ScrollView::KeyNavIteration(direction); - } - -private: - nux::Area* right_area_; - nux::Area* up_area_; -}; - - -NUX_IMPLEMENT_OBJECT_TYPE(LensView); - -LensView::LensView(Lens::Ptr lens, nux::Area* show_filters) - : nux::View(NUX_TRACKER_LOCATION) - , filters_expanded(false) - , can_refine_search(false) - , lens_(lens) - , initial_activation_(true) - , no_results_active_(false) - , last_expanded_group_(nullptr) - , last_good_filter_model_(-1) - , filter_expansion_pushed_(false) -{ - SetupViews(show_filters); - SetupCategories(); - SetupResults(); - SetupFilters(); - - dash::Style::Instance().columns_changed.connect(sigc::mem_fun(this, &LensView::OnColumnsChanged)); - - search_string.SetGetterFunction(sigc::mem_fun(this, &LensView::get_search_string)); - filters_expanded.changed.connect(sigc::mem_fun(this, &LensView::OnLensFilterExpanded)); - view_type.changed.connect(sigc::mem_fun(this, &LensView::OnViewTypeChanged)); - if (lens_) - { - lens_->connected.changed.connect([&](bool is_connected) - { - if (is_connected) - initial_activation_ = true; - }); - lens_->categories_reordered.connect(sigc::mem_fun(this, &LensView::OnCategoryOrderChanged)); - } - - 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 - // to do it properly - nux::Geometry focused_pos; - g_variant_get (data, "(iiii)", &focused_pos.x, &focused_pos.y, &focused_pos.width, &focused_pos.height); - - for (auto category : categories_) - { - if (category->GetLayout() != nullptr) - { - auto expand_label = category->GetHeaderFocusableView(); - auto child = category->GetChildView(); - - if ((child && child->HasKeyFocus()) || - (expand_label && expand_label->HasKeyFocus())) - { - focused_pos.x += child->GetGeometry().x; - focused_pos.y += child->GetGeometry().y - 30; - focused_pos.height += 30; - scroll_view_->ScrollToPosition(focused_pos); - break; - } - } - } - }); - - OnVisibleChanged.connect([&] (nux::Area* area, bool visible) { - scroll_view_->SetVisible(visible); - }); - -} - -void LensView::SetupViews(nux::Area* show_filters) -{ - dash::Style& style = dash::Style::Instance(); - - layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); - layout_->SetSpaceBetweenChildren(style.GetSpaceBetweenLensAndFilters()); - - scroll_view_ = new LensScrollView(new PlacesOverlayVScrollBar(NUX_TRACKER_LOCATION), - NUX_TRACKER_LOCATION); - scroll_view_->EnableVerticalScrollBar(true); - scroll_view_->EnableHorizontalScrollBar(false); - layout_->AddView(scroll_view_); - - scroll_layout_ = new nux::VLayout(NUX_TRACKER_LOCATION); - scroll_view_->SetLayout(scroll_layout_); - scroll_view_->SetRightArea(show_filters); - - no_results_ = new StaticCairoText("", NUX_TRACKER_LOCATION); - no_results_->SetTextColor(nux::color::White); - no_results_->SetVisible(false); - scroll_layout_->AddView(no_results_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); - - fscroll_view_ = new LensScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION), NUX_TRACKER_LOCATION); - fscroll_view_->EnableVerticalScrollBar(true); - fscroll_view_->EnableHorizontalScrollBar(false); - fscroll_view_->SetVisible(false); - fscroll_view_->SetUpArea(show_filters); - layout_->AddView(fscroll_view_, 1); - - fscroll_layout_ = new nux::VLayout(); - fscroll_view_->SetLayout(fscroll_layout_); - - filter_bar_ = new FilterBar(); - int width = style.GetFilterBarWidth() + - style.GetFilterBarLeftPadding() + - style.GetFilterBarRightPadding(); - - fscroll_view_->SetMinimumWidth(width + style.GetFilterViewRightPadding()); - fscroll_view_->SetMaximumWidth(width + style.GetFilterViewRightPadding()); - filter_bar_->SetMinimumWidth(width); - filter_bar_->SetMaximumWidth(width); - AddChild(filter_bar_); - fscroll_layout_->AddView(filter_bar_, 0); - - SetLayout(layout_); -} - -void LensView::SetupCategories() -{ - if (!lens_) - return; - - Categories::Ptr categories = lens_->categories; - categories->category_added.connect(sigc::mem_fun(this, &LensView::OnCategoryAdded)); - - for (unsigned int i = 0; i < categories->count(); ++i) - OnCategoryAdded(categories->RowAtIndex(i)); -} - -void LensView::SetupResults() -{ - if (!lens_) - return; - - Results::Ptr results = lens_->results; - results->result_added.connect(sigc::mem_fun(this, &LensView::OnResultAdded)); - results->result_removed.connect(sigc::mem_fun(this, &LensView::OnResultRemoved)); - - results->model.changed.connect([this] (glib::Object<DeeModel> model) - { - for (unsigned int i = 0; i < categories_.size(); ++i) - { - ResultViewGrid* grid = GetGridForCategory(i); - glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(i)); - Results::Ptr results_model = lens_->results; - grid->SetModel(filter_model, results_model->GetTag()); - } - }); - - for (unsigned int i = 0; i < results->count(); ++i) - OnResultAdded(results->RowAtIndex(i)); -} - -void LensView::SetupFilters() -{ - if (!lens_) - return; - - Filters::Ptr filters = lens_->filters; - filters->filter_added.connect(sigc::mem_fun(this, &LensView::OnFilterAdded)); - filters->filter_removed.connect(sigc::mem_fun(this, &LensView::OnFilterRemoved)); - - for (unsigned int i = 0; i < filters->count(); ++i) - OnFilterAdded(filters->FilterAtIndex(i)); -} - -void LensView::OnCategoryAdded(Category const& category) -{ - std::string name = category.name; - std::string icon_hint = category.icon_hint; - std::string renderer_name = category.renderer_name; - unsigned index = (category.index == unsigned(-1)) ? categories_.size() : category.index; - bool reset_filter_models = false; - - LOG_DEBUG(logger) << "Category added: " << name - << "(" << icon_hint - << ", " << renderer_name - << ", " << boost::lexical_cast<int>(index) << ")"; - - if (index < categories_.size()) - { - // the lens might have restarted and we don't want to create - // new PlacesGroup if we can reuse the old one - PlacesGroup* existing_group = categories_.at(index); - if (existing_group->GetCategoryIndex() == index) return; - } - - PlacesGroup* group = CreatePlacesGroup(); - AddChild(group); - group->SetName(name); - group->SetIcon(icon_hint); - group->SetCategoryIndex(index); - group->SetExpanded(false); - group->SetVisible(false); - group->expanded.connect(sigc::mem_fun(this, &LensView::OnGroupExpanded)); - - reset_filter_models = index < categories_.size(); - /* Add the group at the correct offset into the categories vector */ - categories_.insert(categories_.begin() + index, group); - - /* Reset result count */ - counts_[group] = 0; - - ResultView* grid; - - if (renderer_name == "tile-horizontal") - { - grid = new ResultViewGrid(NUX_TRACKER_LOCATION); - grid->SetModelRenderer(new ResultRendererHorizontalTile(NUX_TRACKER_LOCATION)); - static_cast<ResultViewGrid*> (grid)->horizontal_spacing = CARD_VIEW_GAP_HORIZ; - static_cast<ResultViewGrid*> (grid)->vertical_spacing = CARD_VIEW_GAP_VERT; - } - /* - * The flow renderer is disabled for now, expecting return later - else if (renderer_name == "flow" && nux::GetWindowThread()->GetGraphicsEngine().UsingGLSLCodePath()) - { - grid = new CoverflowResultView(NUX_TRACKER_LOCATION); - grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION)); - group->SetHeaderCountVisible(false); - } - */ - else - { - grid = new ResultViewGrid(NUX_TRACKER_LOCATION); - grid->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION)); - } - group->SetChildView(grid); - - if (lens_) - { - std::string unique_id = name + lens_->name(); - grid->unique_id = unique_id; - grid->expanded = false; - - group->SetRendererName(renderer_name.c_str()); - grid->UriActivated.connect([this, unique_id] (std::string const& uri, ResultView::ActivateType type, GVariant* data) - { - uri_activated.emit(type, uri, data, unique_id); - switch (type) - { - case ResultView::ActivateType::DIRECT: - { - lens_->Activate(uri); - } break; - case ResultView::ActivateType::PREVIEW: - { - lens_->Preview(uri); - } break; - default: break; - }; - }); - - - /* Set up filter model for this category */ - Results::Ptr results_model = lens_->results; - if (results_model->model()) - { - glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(index)); - grid->SetModel(filter_model, results_model->GetTag()); - } - - if (reset_filter_models) - { - /* HomeLens is reodering the categories, and since their index is based - * on the row position in the model, we need to re-initialize the filter - * models if we got insert and not an append */ - for (auto it = categories_.begin() + (index + 1); it != categories_.end(); ++it) - { - grid = static_cast<ResultViewGrid*>((*it)->GetChildView()); - grid->SetModel(glib::Object<DeeModel>(), NULL); - } - - if (static_cast<int>(index) < last_good_filter_model_ || last_good_filter_model_ < 0) - { - last_good_filter_model_ = index; - } - if (!fix_filter_models_idle_) - { - fix_filter_models_idle_.reset(new glib::Idle(sigc::mem_fun(this, &LensView::ReinitializeFilterModels), glib::Source::Priority::HIGH)); - } - } - } - - /* We need the full range of method args so we can specify the offset - * of the group into the layout */ - scroll_layout_->AddView(group, 0, nux::MinorDimensionPosition::MINOR_POSITION_START, - nux::MinorDimensionSize::MINOR_SIZE_FULL, 100.0f, - (nux::LayoutPosition)index); -} - -void LensView::OnCategoryOrderChanged() -{ - LOG_DEBUG(logger) << "Reordering categories for " << lens_->name(); - - // need references so that the Layout doesn't destroy the views - std::vector<nux::ObjectPtr<PlacesGroup> > child_views; - for (unsigned i = 0; i < categories_.size(); i++) - { - child_views.push_back(nux::ObjectPtr<PlacesGroup>(categories_.at(i))); - scroll_layout_->RemoveChildObject(categories_.at(i)); - } - - if (lens_) - { - // there should be ~10 categories, so this shouldn't be too big of a deal - std::vector<unsigned> order(lens_->GetCategoriesOrder()); - for (unsigned i = 0; i < order.size(); i++) - { - unsigned desired_category_index = order[i]; - for (unsigned j = 0; j < child_views.size(); j++) - { - if (child_views[j]->GetCategoryIndex() == desired_category_index) - { - scroll_layout_->AddView(child_views[j].GetPointer(), 0); - break; - } - } - } - } -} - -bool LensView::ReinitializeFilterModels() -{ - if (!lens_) - return false; - - Results::Ptr results_model = lens_->results; - for (unsigned i = last_good_filter_model_ + 1; i < categories_.size(); ++i) - { - ResultViewGrid* grid = GetGridForCategory(i); - glib::Object<DeeModel> filter_model(lens_->GetFilterModelForCategory(i)); - grid->SetModel(filter_model, results_model->GetTag()); - } - - last_good_filter_model_ = -1; - fix_filter_models_idle_.reset(); - return false; -} - -ResultViewGrid* LensView::GetGridForCategory(unsigned category_index) -{ - if (category_index >= categories_.size()) return nullptr; - PlacesGroup* group = categories_.at(category_index); - return static_cast<ResultViewGrid*>(group->GetChildView()); -} - -ResultView* LensView::GetResultViewForCategory(unsigned category_index) -{ - if (category_index >= categories_.size()) return nullptr; - PlacesGroup* group = categories_.at(category_index); - return static_cast<ResultView*>(group->GetChildView()); -} - -void LensView::OnResultAdded(Result const& result) -{ - try { - // Anything done in this method needs to be super fast, if in doubt, add - // it to the model_updated_timeout_ callback! - PlacesGroup* group = categories_.at(result.category_index); - - std::string uri = result.uri; - LOG_TRACE(logger) << "Result added: " << uri; - - UpdateCounts(group, ++counts_[group]); - // make sure we don't display the no-results-hint if we do have results - if (G_UNLIKELY (no_results_active_)) - { - CheckNoResults(Lens::Hints()); - } - - if (!model_updated_timeout_) - { - model_updated_timeout_.reset(new glib::Idle([&] () { - // Check if all results so far are from one category - // If so, then expand that category. - CheckCategoryExpansion(); - model_updated_timeout_.reset(); - return false; - }, glib::Source::Priority::HIGH)); - } - } catch (std::out_of_range& oor) { - LOG_WARN(logger) << "Result does not have a valid category index: " - << boost::lexical_cast<unsigned int>(result.category_index) - << ". Is out of range."; - } -} - -void LensView::OnResultRemoved(Result const& result) -{ - try { - PlacesGroup* group = categories_.at(result.category_index); - - std::string uri = result.uri; - LOG_TRACE(logger) << "Result removed: " << uri; - - UpdateCounts(group, --counts_[group]); - } catch (std::out_of_range& oor) { - LOG_WARN(logger) << "Result does not have a valid category index: " - << boost::lexical_cast<unsigned int>(result.category_index) - << ". Is out of range."; - } -} - -void LensView::UpdateCounts(PlacesGroup* group, unsigned int new_counts) -{ - unsigned int columns = dash::Style::Instance().GetDefaultNColumns(); - columns -= filters_expanded ? 2 : 0; - - group->SetCounts(columns, new_counts); - group->SetVisible(new_counts); -} - -void LensView::CheckNoResults(Lens::Hints const& hints) -{ - gint count = lens_->results()->count(); - - if (count == 0 && !no_results_active_ && !search_string_.empty()) - { - std::stringstream markup; - Lens::Hints::const_iterator it; - - it = hints.find("no-results-hint"); - markup << "<span size='larger' weight='bold'>"; - - if (it != hints.end()) - { - markup << it->second.GetString(); - } - else - { - markup << _("Sorry, there is nothing that matches your search."); - } - markup << "</span>"; - - LOG_DEBUG(logger) << "The no-result-hint is: " << markup.str(); - - scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_CENTER); - - no_results_active_ = true; - no_results_->SetText(markup.str()); - no_results_->SetVisible(true); - } - else if (count && no_results_active_) - { - scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_START); - - no_results_active_ = false; - no_results_->SetText(""); - no_results_->SetVisible(false); - } -} - -void LensView::CheckCategoryExpansion() -{ - int number_of_displayed_categories = 0; - - // Check if we had expanded a group in last run - // If so, collapse it for now - if (last_expanded_group_ != nullptr) - { - last_expanded_group_->SetExpanded(false); - last_expanded_group_ = nullptr; - } - - // Cycle through all categories - for (auto category : categories_) - { - if (counts_[category] > 0) { - number_of_displayed_categories++; - last_expanded_group_ = category; - } - } - - if (number_of_displayed_categories == 1 && last_expanded_group_ != nullptr) - last_expanded_group_->SetExpanded(true); - else - last_expanded_group_ = nullptr; -} - -void LensView::HideResultsMessage() -{ - if (no_results_active_) - { - scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_START); - no_results_active_ = false; - no_results_->SetText(""); - no_results_->SetVisible(false); - } -} - -void LensView::PerformSearch(std::string const& search_query, Lens::SearchFinishedCallback const& cb) -{ - search_string_ = search_query; - if (lens_) - { - lens_->Search(search_query, cb); - } -} - -std::string LensView::get_search_string() const -{ - return search_string_; -} - -void LensView::OnGroupExpanded(PlacesGroup* group) -{ - ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); - grid->expanded = group->GetExpanded(); - - QueueRelayout(); -} - -void LensView::CheckScrollBarState() -{ - if (scroll_layout_->GetHeight() > scroll_view_->GetHeight()) - { - scroll_view_->EnableVerticalScrollBar(true); - } - else - { - scroll_view_->EnableVerticalScrollBar(false); - } -} - -void LensView::OnColumnsChanged() -{ - unsigned int columns = dash::Style::Instance().GetDefaultNColumns(); - columns -= filters_expanded ? 2 : 0; - - for (auto group: categories_) - { - group->SetCounts(columns, counts_[group]); - } -} - -void LensView::OnFilterAdded(Filter::Ptr filter) -{ - filter_bar_->AddFilter(filter); - can_refine_search = true; -} - -void LensView::OnFilterRemoved(Filter::Ptr filter) -{ - filter_bar_->RemoveFilter(filter); -} - -void LensView::OnViewTypeChanged(ViewType view_type) -{ - if (!lens_) - return; - - if (view_type != HIDDEN && initial_activation_) - { - /* We reset the lens for ourselves, in case this is a restart or something */ - lens_->Search(search_string_, [] (Lens::Hints const&, glib::Error const&) {}); - initial_activation_ = false; - } - - lens_->view_type = view_type; -} - -void LensView::OnLensFilterExpanded(bool expanded) -{ - if (fscroll_view_->IsVisible() != expanded) - { - fscroll_view_->SetVisible(expanded); - QueueRelayout(); - OnColumnsChanged(); - } - - for (auto it = categories_.begin(); it != categories_.end(); ++it) - { - (*it)->SetFiltersExpanded(expanded); - } -} - -void LensView::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) -{ - if (RedirectedAncestor()) - graphics::ClearGeometry(GetGeometry()); -} - -void LensView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) -{ - nux::Geometry const& geo(GetGeometry()); - graphics_engine.PushClippingRectangle(geo); - CheckScrollBarState(); - - if (!IsFullRedraw() && RedirectedAncestor()) - { - for (PlacesGroup* category : categories_) - { - if (category->IsRedrawNeeded() && category->IsVisible()) - graphics::ClearGeometry(category->GetGeometry()); - } - if (filter_bar_ && filter_bar_->IsVisible() && filter_bar_->IsRedrawNeeded()) - graphics::ClearGeometry(filter_bar_->GetGeometry()); - } - - layout_->ProcessDraw(graphics_engine, force_draw); - graphics_engine.PopClippingRectangle(); -} - -Lens::Ptr LensView::lens() const -{ - return lens_; -} - -nux::Area* LensView::fscroll_view() const -{ - return fscroll_view_; -} - -int LensView::GetNumRows() -{ - unsigned int columns = dash::Style::Instance().GetDefaultNColumns(); - columns -= filters_expanded ? 2 : 0; - - int num_rows = 0; - for (auto group: categories_) - { - if (group->IsVisible()) - { - num_rows += 1; // The category header - - if (group->GetExpanded() && columns) - num_rows += ceil(counts_[group] / static_cast<double>(columns)); - else - num_rows += 1; - } - } - - return num_rows; -} - -void LensView::AboutToShow() -{ - JumpToTop(); - OnLensFilterExpanded(filters_expanded); -} - -void LensView::JumpToTop() -{ - scroll_view_->ScrollToPosition(nux::Geometry(0, 0, 0, 0)); -} - -void LensView::ActivateFirst() -{ - if (!lens_) - return; - - Results::Ptr results = lens_->results; - if (results->count()) - { - // the first displayed category might not be categories_[0] - auto category_order = lens_->GetCategoriesOrder(); - for (unsigned int i = 0; i < category_order.size(); i++) - { - unsigned cat_index = category_order.at(i); - ResultView* result_view = GetResultViewForCategory(cat_index); - if (result_view == nullptr) continue; - auto it = result_view->GetIteratorAtRow(0); - if (!it.IsLast()) - { - Result result(*it); - result_view->Activate(result.uri, result_view->GetIndexForUri(result.uri), ResultView::ActivateType::DIRECT); - return; - } - } - - // Fallback - Result result = results->RowAtIndex(0); - if (result.uri != "") - { - uri_activated.emit(ResultView::ActivateType::DIRECT, result.uri, nullptr, ""); - lens_->Activate(result.uri); - } - } -} - -// Keyboard navigation -bool LensView::AcceptKeyNavFocus() -{ - return false; -} - -void LensView::ForceCategoryExpansion(std::string const& view_id, bool expand) -{ - for (auto it = categories_.begin(); it != categories_.end(); ++it) - { - if ((*it)->GetChildView()->unique_id == view_id) - { if (expand) - { - (*it)->PushExpanded(); - (*it)->SetExpanded(true); - } - else - { - (*it)->PopExpanded(); - } - } - } -} - -void LensView::SetResultsPreviewAnimationValue(float preview_animation) -{ - for (auto it = categories_.begin(); it != categories_.end(); ++it) - { - (*it)->SetResultsPreviewAnimationValue(preview_animation); - } -} - -void LensView::EnableResultTextures(bool enable_result_textures) -{ - scroll_view_->EnableScrolling(!enable_result_textures); - - for (auto it = categories_.begin(); it != categories_.end(); ++it) - { - ResultView* result_view = (*it)->GetChildView(); - if (result_view) - { - result_view->enable_texture_render = enable_result_textures; - } - } -} - -std::vector<ResultViewTexture::Ptr> LensView::GetResultTextureContainers() -{ - // iterate in visual order - std::vector<ResultViewTexture::Ptr> textures; - auto category_order = lens_->GetCategoriesOrder(); - for (unsigned int i = 0; i < category_order.size(); i++) - { - unsigned category_index = category_order.at(i); - if (categories_.size() <= category_index) - continue; - - PlacesGroup* category = categories_.at(category_index); - if (!category || !category->IsVisible()) - continue; - - ResultView* result_view = category->GetChildView(); - if (result_view) - { - // concatenate textures - std::vector<ResultViewTexture::Ptr> const& category_textures = result_view->GetResultTextureContainers(); - for (auto it = category_textures.begin(); it != category_textures.end(); ++it) - { - ResultViewTexture::Ptr const& result_texture = *it; - result_texture->category_index = category_index; - textures.push_back(result_texture); - } - } - } - return textures; -} - -void LensView::RenderResultTexture(ResultViewTexture::Ptr const& result_texture) -{ - ResultView* result_view = GetResultViewForCategory(result_texture->category_index); - if (result_view) - result_view->RenderResultTexture(result_texture); -} - -void LensView::PushFilterExpansion(bool expand) -{ - filter_expansion_pushed_ = filters_expanded; - filters_expanded = expand; -} - -void LensView::PopFilterExpansion() -{ - filters_expanded = GetPushedFilterExpansion(); -} - -bool LensView::GetPushedFilterExpansion() const -{ - return filter_expansion_pushed_; -} - -PlacesGroup* LensView::CreatePlacesGroup() -{ - return new PlacesGroup(dash::Style::Instance()); -} - -// Introspectable -std::string LensView::GetName() const -{ - return "LensView"; -} - -void LensView::AddProperties(GVariantBuilder* builder) -{ - unity::variant::BuilderWrapper(builder) - .add("name", lens_->id) - .add("lens-name", lens_->name) - .add("visible", IsVisible()) - .add("no-results-active", no_results_active_); -} - -} -} diff --git a/dash/PlacesGroup.cpp b/dash/PlacesGroup.cpp index b9419ba59..c85282fa0 100755 --- a/dash/PlacesGroup.cpp +++ b/dash/PlacesGroup.cpp @@ -122,7 +122,6 @@ PlacesGroup::PlacesGroup(dash::StyleInterface& style) _is_expanded_pushed(false), _n_visible_items_in_unexpand_mode(0), _n_total_items(0), - _category_index(0), _coverflow_enabled(false), disabled_header_count_(false) { @@ -244,17 +243,6 @@ PlacesGroup::SetName(std::string const& name) } } -void -PlacesGroup::SetRendererName(const char *renderer_name) -{ - _renderer_name = renderer_name; - - if (g_strcmp0(renderer_name, "tile-horizontal") == 0) - (static_cast<dash::ResultView*>(_child_view))->SetModelRenderer(new dash::ResultRendererHorizontalTile(NUX_TRACKER_LOCATION)); - else if (g_strcmp0(renderer_name, "tile-vertical") == 0) - (static_cast<dash::ResultView*>(_child_view))->SetModelRenderer(new dash::ResultRendererTile(NUX_TRACKER_LOCATION)); -} - void PlacesGroup::SetHeaderCountVisible(bool disable) { disabled_header_count_ = !disable; @@ -342,7 +330,7 @@ PlacesGroup::RefreshLabel() } else { - LOG_DEBUG(logger) << _n_total_items << " - " << _n_visible_items_in_unexpand_mode; + LOG_TRACE(logger) << _n_total_items << " - " << _n_visible_items_in_unexpand_mode; result_string = glib::String(g_strdup_printf(g_dngettext(GETTEXT_PACKAGE, "See one more result", "See %d more results", @@ -353,7 +341,7 @@ PlacesGroup::RefreshLabel() bool visible = !(_n_visible_items_in_unexpand_mode >= _n_total_items && _n_total_items != 0); - _expand_icon->SetVisible(visible);; + _expand_icon->SetVisible(visible); SetName(_cached_name); _expand_label->SetText(result_string); @@ -511,20 +499,7 @@ PlacesGroup::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) } void -PlacesGroup::SetCategoryIndex(unsigned index) -{ - _category_index = index; -} - -unsigned -PlacesGroup::GetCategoryIndex() const -{ - return _category_index; -} - -void -PlacesGroup::SetCounts(unsigned n_visible_items_in_unexpand_mode, - unsigned n_total_items) +PlacesGroup::SetCounts(unsigned n_total_items) { _n_total_items = n_total_items; diff --git a/dash/PlacesGroup.h b/dash/PlacesGroup.h index e76f3ca7c..b0b105541 100644 --- a/dash/PlacesGroup.h +++ b/dash/PlacesGroup.h @@ -55,12 +55,12 @@ class PlacesGroup : public nux::View, public debug::Introspectable { NUX_DECLARE_OBJECT_TYPE(PlacesGroup, nux::View); public: + typedef nux::ObjectPtr<PlacesGroup> Ptr; PlacesGroup(dash::StyleInterface& style); void SetIcon(std::string const& icon); void SetName(std::string const& name); - void SetRendererName(const char *renderer_name); void SetHeaderCountVisible(bool disable); StaticCairoText* GetLabel(); @@ -69,15 +69,12 @@ public: void SetChildView(dash::ResultView* view); dash::ResultView* GetChildView(); + void SetChildLayout(nux::Layout* layout); void Relayout(); - void SetCategoryIndex(unsigned index); - unsigned GetCategoryIndex() const; - - void SetCounts(unsigned n_visible_items_in_unexpand_mode, - unsigned n_total_items); + void SetCounts(unsigned n_total_items); void SetExpanded(bool is_expanded); bool GetExpanded() const; @@ -94,7 +91,6 @@ public: void SetFiltersExpanded(bool filters_expanded); sigc::signal<void, PlacesGroup*> expanded; - sigc::signal<void, std::string const&> UriActivated; protected: long ComputeContentSize(); @@ -125,6 +121,7 @@ private: void RefreshLabel(); private: + std::string _category_id; dash::StyleInterface& _style; nux::VLayout* _group_layout; @@ -151,11 +148,9 @@ private: bool _is_expanded_pushed; unsigned _n_visible_items_in_unexpand_mode; unsigned _n_total_items; - unsigned _category_index; std::string _cached_name; nux::Geometry _cached_geometry; - std::string _renderer_name; bool _coverflow_enabled; bool disabled_header_count_; @@ -163,7 +158,7 @@ private: glib::Source::UniquePtr _relayout_idle; UBusManager _ubus; - friend class TestLensView; + friend class TestScopeView; }; } // namespace dash diff --git a/dash/PreviewStateMachine.cpp b/dash/PreviewStateMachine.cpp index 3a48eeab0..3e0c65c0b 100644 --- a/dash/PreviewStateMachine.cpp +++ b/dash/PreviewStateMachine.cpp @@ -93,7 +93,7 @@ void PreviewStateMachine::CheckPreviewRequirementsFulfilled() * if (GetSplitPosition(CONTENT_AREA) < 0) return; if (GetSplitPosition(FILTER_BAR) < 0) return; - if (GetSplitPosition(LENS_BAR) < 0) return; + if (GetSplitPosition(SCOPE_BAR) < 0) return; if (GetSplitPosition(SEARCH_BAR) < 0) return; */ diff --git a/dash/PreviewStateMachine.h b/dash/PreviewStateMachine.h index f98c73f47..08839c84b 100644 --- a/dash/PreviewStateMachine.h +++ b/dash/PreviewStateMachine.h @@ -32,7 +32,7 @@ typedef enum START, CONTENT_AREA, FILTER_BAR, - LENS_BAR, + SCOPE_BAR, SEARCH_BAR, END } SplitPosition; diff --git a/dash/ResultRenderer.cpp b/dash/ResultRenderer.cpp index 7ddc35391..2454d298b 100644 --- a/dash/ResultRenderer.cpp +++ b/dash/ResultRenderer.cpp @@ -133,12 +133,12 @@ void ResultRenderer::Render(nux::GraphicsEngine& GfxContext, nux::GetPainter().PushDrawSliceScaledTextureLayer(GfxContext, geometry, nux::eBUTTON_NORMAL, nux::color::White, nux::eAllCorners); } -void ResultRenderer::Preload(Result& row) +void ResultRenderer::Preload(Result const& row) { // pre-load the given row } -void ResultRenderer::Unload(Result& row) +void ResultRenderer::Unload(Result const& row) { // unload any resources } diff --git a/dash/ResultRenderer.h b/dash/ResultRenderer.h index a26429b6f..d9f3689c0 100644 --- a/dash/ResultRenderer.h +++ b/dash/ResultRenderer.h @@ -59,10 +59,10 @@ public: // this is just to start preloading images and text that the renderer might // need - can be ignored - virtual void Preload(Result& row); + virtual void Preload(Result const& row); // unload any previous grabbed images - virtual void Unload(Result& row); + virtual void Unload(Result const& row); // get a image to drag virtual nux::NBitmapData* GetDndImage(Result const& row) const; diff --git a/dash/ResultRendererHorizontalTile.cpp b/dash/ResultRendererHorizontalTile.cpp index 65f4e26a4..26b13ac9b 100644 --- a/dash/ResultRendererHorizontalTile.cpp +++ b/dash/ResultRendererHorizontalTile.cpp @@ -268,7 +268,7 @@ nux::BaseTexture* ResultRendererHorizontalTile::DrawNormal(std::string const& te return texture_from_cairo_graphics(cairo_graphics); } -void ResultRendererHorizontalTile::LoadText(Result& row) +void ResultRendererHorizontalTile::LoadText(Result const& row) { std::stringstream final_text; char *name = g_markup_escape_text(row.name().c_str() , -1); diff --git a/dash/ResultRendererHorizontalTile.h b/dash/ResultRendererHorizontalTile.h index 3efbeb278..476c66ac7 100644 --- a/dash/ResultRendererHorizontalTile.h +++ b/dash/ResultRendererHorizontalTile.h @@ -51,7 +51,7 @@ public: virtual nux::NBitmapData* GetDndImage(Result const& row) const; protected: - virtual void LoadText(Result& row); + virtual void LoadText(Result const& row); private: nux::BaseTexture* DrawHighlight(std::string const& texid, diff --git a/dash/ResultRendererTile.cpp b/dash/ResultRendererTile.cpp index a3c9781a1..4e6c34fa8 100644 --- a/dash/ResultRendererTile.cpp +++ b/dash/ResultRendererTile.cpp @@ -208,21 +208,26 @@ nux::BaseTexture* ResultRendererTile::DrawHighlight(std::string const& texid, in return texture_from_cairo_graphics(cairo_graphics); } -void ResultRendererTile::Preload(Result& row) +void ResultRendererTile::Preload(Result const& row) { if (row.renderer<TextureContainer*>() == nullptr) { - row.set_renderer(new TextureContainer()); + // Shouldn't really do this, but it's safe in this case and quicker than making a copy. + const_cast<Result&>(row).set_renderer(new TextureContainer()); LoadIcon(row); LoadText(row); } } -void ResultRendererTile::Unload(Result& row) +void ResultRendererTile::Unload(Result const& row) { TextureContainer *container = row.renderer<TextureContainer*>(); - delete container; - row.set_renderer<TextureContainer*>(nullptr); + if (container) + { + delete container; + // Shouldn't really do this, but it's safe in this case and quicker than making a copy. + const_cast<Result&>(row).set_renderer<TextureContainer*>(nullptr); + } } nux::NBitmapData* ResultRendererTile::GetDndImage(Result const& row) const @@ -239,7 +244,7 @@ nux::NBitmapData* ResultRendererTile::GetDndImage(Result const& row) const return bitmap ? bitmap : ResultRenderer::GetDndImage(row); } -void ResultRendererTile::LoadIcon(Result& row) +void ResultRendererTile::LoadIcon(Result const& row) { Style& style = Style::Instance(); std::string icon_hint(row.icon_hint); @@ -354,7 +359,7 @@ void ResultRendererTile::IconLoaded(std::string const& texid, int max_height, glib::Object<GdkPixbuf> const& pixbuf, std::string icon_name, - Result& row) + Result const& row) { TextureContainer *container = row.renderer<TextureContainer*>(); @@ -386,7 +391,7 @@ void ResultRendererTile::IconLoaded(std::string const& texid, } -void ResultRendererTile::LoadText(Result& row) +void ResultRendererTile::LoadText(Result const& row) { Style& style = Style::Instance(); nux::CairoGraphics _cairoGraphics(CAIRO_FORMAT_ARGB32, diff --git a/dash/ResultRendererTile.h b/dash/ResultRendererTile.h index 4349d66c4..929f93f60 100644 --- a/dash/ResultRendererTile.h +++ b/dash/ResultRendererTile.h @@ -69,8 +69,8 @@ public: nux::Color const& color, float saturate); - virtual void Preload(Result& row); - virtual void Unload(Result& row); + virtual void Preload(Result const& row); + virtual void Unload(Result const& row); virtual nux::NBitmapData* GetDndImage(Result const& row) const; @@ -78,15 +78,15 @@ public: int padding; protected: - virtual void LoadText(Result& row); - void LoadIcon(Result& row); + virtual void LoadText(Result const& row); + void LoadIcon(Result const& row); nux::ObjectPtr<nux::BaseTexture> prelight_cache_; nux::ObjectPtr<nux::BaseTexture> normal_cache_; private: //icon loading callbacks void IconLoaded(std::string const& texid, int max_width, int max_height, glib::Object<GdkPixbuf> const& pixbuf, - std::string icon_name, Result& row); + std::string icon_name, Result const& row); nux::BaseTexture* CreateTextureCallback(std::string const& texid, int width, int height, glib::Object<GdkPixbuf> const& pixbuf); diff --git a/dash/ResultView.cpp b/dash/ResultView.cpp index f279e2e67..0d18cf3bf 100644 --- a/dash/ResultView.cpp +++ b/dash/ResultView.cpp @@ -89,68 +89,44 @@ void ResultView::SetModelRenderer(ResultRenderer* renderer) NeedRedraw(); } -void ResultView::AddResult(Result& result) +void ResultView::AddResult(Result const& result) { renderer_->Preload(result); NeedRedraw(); } -void ResultView::RemoveResult(Result& result) +void ResultView::RemoveResult(Result const& result) { renderer_->Unload(result); } -void ResultView::OnRowAdded(DeeModel* model, DeeModelIter* iter) -{ - cached_result_.SetTarget(model, iter, renderer_tag_); - AddResult(cached_result_); -} - -void ResultView::OnRowRemoved(DeeModel* model, DeeModelIter* iter) -{ - cached_result_.SetTarget(model, iter, renderer_tag_); - RemoveResult(cached_result_); -} - -void ResultView::SetModel(glib::Object<DeeModel> const& model, DeeModelTag* tag) +void ResultView::SetResultsModel(Results::Ptr const& result_model) { // cleanup if (result_model_) { - sig_manager_.Disconnect(result_model_); - + result_added_connection_.disconnect(); + result_removed_connection_.disconnect(); for (ResultIterator it(GetIteratorAtRow(0)); !it.IsLast(); ++it) { RemoveResult(*it); } } - result_model_ = model; - renderer_tag_ = tag; + result_model_ = result_model; - if (model) + if (result_model_) { - typedef glib::Signal<void, DeeModel*, DeeModelIter*> RowSignalType; - - sig_manager_.Add(new RowSignalType(model, - "row-added", - sigc::mem_fun(this, &ResultView::OnRowAdded))); - sig_manager_.Add(new RowSignalType(model, - "row-removed", - sigc::mem_fun(this, &ResultView::OnRowRemoved))); - - for (ResultIterator it(GetIteratorAtRow(0)); !it.IsLast(); ++it) - { - AddResult(*it); - } + result_added_connection_ = result_model_->result_added.connect(sigc::mem_fun(this, &ResultView::AddResult)); + result_removed_connection_ = result_model_->result_removed.connect(sigc::mem_fun(this, &ResultView::RemoveResult)); } } unsigned ResultView::GetNumResults() { if (result_model_) - return dee_model_get_n_rows(result_model_); + return result_model_->count(); return 0; } @@ -160,20 +136,23 @@ ResultIterator ResultView::GetIteratorAtRow(unsigned row) DeeModelIter* iter = NULL; if (result_model_) { - iter = row > 0 ? dee_model_get_iter_at_row(result_model_, row) : - dee_model_get_first_iter(result_model_); + if (result_model_->model()) + { + iter = row > 0 ? dee_model_get_iter_at_row(result_model_->model(), row) : + dee_model_get_first_iter(result_model_->model()); + + return ResultIterator(result_model_->model(), iter, result_model_->GetTag()); + } } - return ResultIterator(result_model_, iter, renderer_tag_); + return ResultIterator(glib::Object<DeeModel>()); } -// it would be nice to return a result here, but c++ does not have a good mechanism -// for indicating out of bounds errors. so i return the index -unsigned int ResultView::GetIndexForUri(const std::string& uri) +unsigned int ResultView::GetIndexForLocalResult(LocalResult const& local_result) { unsigned int index = 0; for (ResultIterator it(GetIteratorAtRow(0)); !it.IsLast(); ++it) { - if ((*it).uri == uri) + if ((*it).uri == local_result.uri) break; index++; @@ -182,23 +161,16 @@ unsigned int ResultView::GetIndexForUri(const std::string& uri) return index; } -std::string ResultView::GetUriForIndex(unsigned int index) +LocalResult ResultView::GetLocalResultForIndex(unsigned int index) { if (index >= GetNumResults()) - return ""; + return LocalResult(); - return (*GetIteratorAtRow(index)).uri(); -} - -long ResultView::ComputeContentSize() -{ - return View::ComputeContentSize(); + return LocalResult(*GetIteratorAtRow(index)); } void ResultView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) -{ - -} +{} void ResultView::DrawContent(nux::GraphicsEngine& GfxContent, bool force_draw) { @@ -290,6 +262,12 @@ std::string ResultView::GetName() const return "ResultView"; } +void ResultView::GetResultDimensions(int& rows, int& columns) +{ + columns = results_per_row; + rows = result_model_ ? ceil(static_cast<double>(result_model_->count()) / static_cast<double>(std::max(1, columns))) : 0.0; +} + void ResultView::AddProperties(GVariantBuilder* builder) { unity::variant::BuilderWrapper(builder) @@ -310,7 +288,7 @@ debug::Introspectable::IntrospectableList ResultView::GetIntrospectableChildren( int index = 0; if (result_model_) { - for (ResultIterator iter(result_model_); !iter.IsLast(); ++iter) + for (ResultIterator iter(result_model_->model()); !iter.IsLast(); ++iter) { Result const& result = *iter; diff --git a/dash/ResultView.h b/dash/ResultView.h index e7124fb57..5dbc316d7 100644 --- a/dash/ResultView.h +++ b/dash/ResultView.h @@ -29,7 +29,6 @@ #include <UnityCore/GLibSignal.h> #include <UnityCore/Results.h> -#include <UnityCore/ResultIterator.h> #include "unity-shared/Introspectable.h" #include "ResultRenderer.h" @@ -70,37 +69,38 @@ public: virtual ~ResultView(); void SetModelRenderer(ResultRenderer* renderer); - void SetModel(glib::Object<DeeModel> const& model, DeeModelTag* tag); + void SetResultsModel(Results::Ptr const& results); - unsigned int GetIndexForUri(const std::string& uri); - std::string GetUriForIndex(unsigned int); + unsigned int GetIndexForLocalResult(LocalResult const& local_result); + LocalResult GetLocalResultForIndex(unsigned int); nux::Property<bool> expanded; nux::Property<int> results_per_row; nux::Property<std::string> unique_id; nux::Property<float> desaturation_progress; nux::Property<bool> enable_texture_render; - sigc::signal<void, std::string const&, ActivateType, GVariant*> UriActivated; + sigc::signal<void, LocalResult const&, ActivateType, GVariant*> ResultActivated; std::string GetName() const; ResultIterator GetIteratorAtRow(unsigned row); void AddProperties(GVariantBuilder* builder); IntrospectableList GetIntrospectableChildren(); - virtual void Activate(std::string const& uri, int index, ActivateType type) = 0; + virtual void Activate(LocalResult const& local_result, int index, ActivateType type) = 0; std::vector<ResultViewTexture::Ptr> const& GetResultTextureContainers(); virtual void RenderResultTexture(ResultViewTexture::Ptr const& result_texture); + virtual void GetResultDimensions(int& rows, int& columns); + protected: virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); virtual void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); - virtual long ComputeContentSize(); virtual void UpdateRenderTextures(); - virtual void AddResult(Result& result); - virtual void RemoveResult(Result& result); + virtual void AddResult(Result const& result); + virtual void RemoveResult(Result const& result); unsigned GetNumResults(); @@ -111,9 +111,7 @@ protected: // properties ResultRenderer* renderer_; - glib::Object<DeeModel> result_model_; - DeeModelTag* renderer_tag_; - glib::SignalManager sig_manager_; + Results::Ptr result_model_; std::map<std::string, debug::ResultWrapper*> introspectable_children_; std::vector<ResultViewTexture::Ptr> result_textures_; @@ -123,6 +121,8 @@ private: void OnRowRemoved(DeeModel* model, DeeModelIter* iter); Result cached_result_; + sigc::connection result_added_connection_; + sigc::connection result_removed_connection_; }; } diff --git a/dash/ResultViewGrid.cpp b/dash/ResultViewGrid.cpp index 134b8c021..cfeb7aacb 100644 --- a/dash/ResultViewGrid.cpp +++ b/dash/ResultViewGrid.cpp @@ -63,8 +63,8 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL) , mouse_over_index_(-1) , active_index_(-1) , selected_index_(-1) - , activated_uri_("NULL") , last_lazy_loaded_result_(0) + , all_results_preloaded_(true) , last_mouse_down_x_(-1) , last_mouse_down_y_(-1) , drag_index_(~0) @@ -81,11 +81,13 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL) vertical_spacing.changed.connect(needredraw_lambda); padding.changed.connect(needredraw_lambda); selected_index_.changed.connect(needredraw_lambda); + expanded.changed.connect([&](bool value) { if (value) all_results_preloaded_ = false; }); + results_per_row.changed.connect([&](int value) { if (value > 0) all_results_preloaded_ = false; }); key_nav_focus_change.connect(sigc::mem_fun(this, &ResultViewGrid::OnKeyNavFocusChange)); - key_nav_focus_activate.connect([&] (nux::Area *area) - { - Activate(focused_uri_, selected_index_, ResultView::ActivateType::DIRECT); + key_nav_focus_activate.connect([&] (nux::Area *area) + { + Activate(focused_result_, selected_index_, ResultView::ActivateType::DIRECT); }); key_down.connect(sigc::mem_fun(this, &ResultViewGrid::OnKeyDown)); mouse_move.connect(sigc::mem_fun(this, &ResultViewGrid::MouseMove)); @@ -125,17 +127,19 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL) 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); + GVariant* local_result_variant = NULL; + glib::String proposed_unique_id; + g_variant_get(data, "(ivs)", &nav_mode, &local_result_variant, &proposed_unique_id); + LocalResult local_result(LocalResult::FromVariant(local_result_variant)); + g_variant_unref(local_result_variant); - if (std::string(proposed_unique_id) != unique_id()) + if (proposed_unique_id.Str() != unique_id()) return; unsigned num_results = GetNumResults(); - if (std::string(uri) == activated_uri_) + if (local_result == activated_result_) { - int current_index = GetIndexForUri(activated_uri_); + int current_index = GetIndexForLocalResult(activated_result_); if (nav_mode == -1) // left { current_index--; @@ -154,29 +158,25 @@ ResultViewGrid::ResultViewGrid(NUX_FILE_LINE_DECL) // closed if (nav_mode == 0) { - activated_uri_ = ""; + activated_result_.clear(); } else { selected_index_ = active_index_ = current_index; - activated_uri_ = GetUriForIndex(current_index); + activated_result_ = GetLocalResultForIndex(current_index); LOG_DEBUG(logger) << "activating preview for index: " << "(" << current_index << ")" - << " " << activated_uri_; - Activate(activated_uri_, current_index, ActivateType::PREVIEW); + << " " << activated_result_.uri; + Activate(activated_result_, current_index, ActivateType::PREVIEW); } - } - g_free(uri); - g_free(proposed_unique_id); - }); SetDndEnabled(true, false); } -void ResultViewGrid::Activate(std::string const& uri, int index, ResultView::ActivateType type) +void ResultViewGrid::Activate(LocalResult const& local_result, int index, ResultView::ActivateType type) { unsigned num_results = GetNumResults(); @@ -210,28 +210,44 @@ void ResultViewGrid::Activate(std::string const& uri, int index, ResultView::Act active_index_ = index; guint64 timestamp = nux::GetGraphicsDisplay()->GetCurrentEvent().x11_timestamp; glib::Variant data(g_variant_new("(tiiiiii)", timestamp, column_x, row_y, column_width, row_height, left_results, right_results)); - UriActivated.emit(uri, type, data); + ResultActivated.emit(local_result, type, data); } void ResultViewGrid::QueueLazyLoad() { - lazy_load_source_.reset(new glib::Idle(glib::Source::Priority::DEFAULT)); - lazy_load_source_->Run(sigc::mem_fun(this, &ResultViewGrid::DoLazyLoad)); - last_lazy_loaded_result_ = 0; // we always want to reset the lazy load index here + if (all_results_preloaded_ || GetNumResults() == 0) + return; + + if (results_changed_idle_) + return; + + if (!lazy_load_source_) + { + lazy_load_source_.reset(new glib::Idle(glib::Source::Priority::DEFAULT)); + // dont need to reset the last start index as all the previous ones would have been preloaded already. + lazy_load_source_->Run(sigc::mem_fun(this, &ResultViewGrid::DoLazyLoad)); + } } -void ResultViewGrid::QueueViewChanged() +void ResultViewGrid::QueueResultsChanged() { - if (!view_changed_idle_) + // even if we're not going to run the lazy load, we need to reset the start in case it's running already. + last_lazy_loaded_result_ = 0; + + if (!results_changed_idle_) { // using glib::Source::Priority::HIGH because this needs to happen *before* next draw - view_changed_idle_.reset(new glib::Idle(glib::Source::Priority::HIGH)); - view_changed_idle_->Run([&] () { + results_changed_idle_.reset(new glib::Idle(glib::Source::Priority::HIGH)); + results_changed_idle_->Run([this] () { SizeReallocate(); - last_lazy_loaded_result_ = 0; // reset the lazy load index - DoLazyLoad(); // also calls QueueDraw - - view_changed_idle_.reset(); + results_changed_idle_.reset(); + lazy_load_source_.reset(); // no point doing this one as well. + + if (!all_results_preloaded_) + { + last_lazy_loaded_result_ = 0; // reset the lazy load index in case we got an insert + DoLazyLoad(); // also calls QueueDraw + } return false; }); } @@ -239,26 +255,6 @@ void ResultViewGrid::QueueViewChanged() bool ResultViewGrid::DoLazyLoad() { - // FIXME - so this code was nice, it would only load the visible entries on the screen - // however nux does not give us a good enough indicator right now that we are scrolling, - // thus if you scroll more than a screen in one frame, you will end up with at least one frame where - // no icons are displayed (they have not been preloaded yet) - it sucked. we should fix this next cycle when we can break api - //~ int index = 0; -//~ - //~ ResultListBounds visible_bounds = GetVisableResults(); - //~ int lower_bound = std::get<0>(visible_bounds); - //~ int upper_bound = std::get<1>(visible_bounds); -//~ - //~ ResultList::iterator it; - //~ for (it = results_.begin(); it != results_.end(); it++) - //~ { - //~ if (index >= lower_bound && index <= upper_bound) - //~ { - //~ renderer_->Preload((*it)); - //~ } - //~ index++; - //~ } - util::Timer timer; bool queue_additional_load = false; // if this is set, we will return early and start loading more next frame @@ -270,31 +266,34 @@ bool ResultViewGrid::DoLazyLoad() if ((!expanded && index < items_per_row) || expanded) { renderer_->Preload(*it); - last_lazy_loaded_result_ = index; } + if (!expanded && index >= items_per_row) + break; //early exit + if (timer.ElapsedSeconds() > 0.008) { queue_additional_load = true; break; } - if (!expanded && index >= items_per_row) - break; //early exit - + last_lazy_loaded_result_++; index++; } - if (queue_additional_load) + if (!queue_additional_load) { - //we didn't load all the results because we exceeded our time budget, so queue another lazy load - lazy_load_source_.reset(new glib::Timeout(1000/60 - 8)); - lazy_load_source_->Run(sigc::mem_fun(this, &ResultViewGrid::DoLazyLoad)); + all_results_preloaded_ = true; + lazy_load_source_.reset(); + } + else if (!lazy_load_source_) + { + lazy_load_source_.reset(new glib::Idle(glib::Source::Priority::DEFAULT)); + lazy_load_source_->Run(sigc::mem_fun(this, &ResultViewGrid::DoLazyLoad)); } - QueueDraw(); - return false; + return queue_additional_load; } @@ -304,21 +303,28 @@ int ResultViewGrid::GetItemsPerRow() return (items_per_row) ? items_per_row : 1; // always at least one item per row } +void ResultViewGrid::GetResultDimensions(int& rows, int& columns) +{ + columns = GetItemsPerRow(); + rows = result_model_ ? ceil(static_cast<double>(result_model_->count()) / static_cast<double>(std::max<int>(1, columns))) : 0.0; +} + void ResultViewGrid::SetModelRenderer(ResultRenderer* renderer) { ResultView::SetModelRenderer(renderer); SizeReallocate(); } -void ResultViewGrid::AddResult(Result& result) +void ResultViewGrid::AddResult(Result const& result) { - QueueViewChanged(); + all_results_preloaded_ = false; + QueueResultsChanged(); } -void ResultViewGrid::RemoveResult(Result& result) +void ResultViewGrid::RemoveResult(Result const& result) { ResultView::RemoveResult(result); - QueueViewChanged(); + QueueResultsChanged(); } void ResultViewGrid::SizeReallocate() @@ -461,8 +467,8 @@ void ResultViewGrid::OnKeyDown (unsigned long event_type, unsigned long event_ke // if we got this far, we definately got a keynav signal - if (focused_uri_.empty()) - focused_uri_ = (*GetIteratorAtRow(0)).uri; + if (focused_result_.uri.empty()) + focused_result_ = (*GetIteratorAtRow(0)); int items_per_row = GetItemsPerRow(); unsigned num_results = GetNumResults(); @@ -507,7 +513,7 @@ void ResultViewGrid::OnKeyDown (unsigned long event_type, unsigned long event_ke selected_index_ = std::max(0, selected_index_()); selected_index_ = std::min(static_cast<int>(num_results - 1), selected_index_()); ResultIterator iter(GetIteratorAtRow(selected_index_)); - focused_uri_ = (*iter).uri; + focused_result_ = (*iter); std::tuple<int, int> focused_coord = GetResultPosition(selected_index_); @@ -520,7 +526,7 @@ void ResultViewGrid::OnKeyDown (unsigned long event_type, unsigned long event_ke if (event_type == nux::NUX_KEYDOWN && event_keysym == XK_Menu) { - Activate(focused_uri_, selected_index_, ActivateType::PREVIEW); + Activate(focused_result_, selected_index_, ActivateType::PREVIEW); } } @@ -533,10 +539,10 @@ void ResultViewGrid::OnKeyNavFocusChange(nux::Area *area, bool has_focus, nux::K { if (HasKeyFocus()) { - if (selected_index_ < 0 && GetNumResults()) + if (result_model_ && selected_index_ < 0 && GetNumResults()) { - ResultIterator first_iter(result_model_); - focused_uri_ = (*first_iter).uri; + ResultIterator first_iter(result_model_->model()); + focused_result_ = (*first_iter); selected_index_ = 0; } @@ -568,7 +574,7 @@ void ResultViewGrid::OnKeyNavFocusChange(nux::Area *area, bool has_focus, nux::K else { selected_index_ = -1; - focused_uri_.clear(); + focused_result_.clear(); selection_change.emit(); } @@ -790,13 +796,13 @@ void ResultViewGrid::MouseClick(int x, int y, unsigned long button_flags, unsign ResultIterator it(GetIteratorAtRow(index)); Result result = *it; selected_index_ = index; - focused_uri_ = result.uri; + focused_result_ = result; ActivateType type = nux::GetEventButton(button_flags) == nux::MouseButton::MOUSE_BUTTON3 ? ResultView::ActivateType::PREVIEW : ResultView::ActivateType::DIRECT; - activated_uri_ = result.uri(); - Activate(activated_uri_, index, type); + activated_result_ = result; + Activate(activated_result_, index, type); } } @@ -824,9 +830,9 @@ unsigned ResultViewGrid::GetIndexAtPosition(int x, int y) return (row_number * items_per_row) + column_number; } -std::tuple<int, int> ResultViewGrid::GetResultPosition(const std::string& uri) +std::tuple<int, int> ResultViewGrid::GetResultPosition(LocalResult const& local_result) { - unsigned int index = GetIndexForUri(uri); + unsigned int index = GetIndexForLocalResult(local_result); return GetResultPosition(index); } @@ -863,15 +869,13 @@ bool ResultViewGrid::DndSourceDragBegin() Reference(); ResultIterator iter(GetIteratorAtRow(drag_index_)); - Result drag_result = *iter; - - current_drag_uri_ = drag_result.dnd_uri; - if (current_drag_uri_ == "") - current_drag_uri_ = drag_result.uri().substr(drag_result.uri().find(":") + 1); + current_drag_result_ = *iter; + if (current_drag_result_.empty()) + current_drag_result_.uri = current_drag_result_.uri.substr(current_drag_result_.uri.find(":") + 1); LOG_DEBUG (logger) << "Dnd begin at " << last_mouse_down_x_ << ", " << last_mouse_down_y_ << " - using; " - << current_drag_uri_; + << current_drag_result_.uri; return true; #else @@ -901,10 +905,10 @@ const char* ResultViewGrid::DndSourceGetDataForType(const char* type, int* size, { *format = 8; - if (!current_drag_uri_.empty()) + if (!current_drag_result_.empty()) { - *size = strlen(current_drag_uri_.c_str()); - return current_drag_uri_.c_str(); + *size = strlen(current_drag_result_.uri.c_str()); + return current_drag_result_.uri.c_str(); } else { @@ -919,7 +923,7 @@ void ResultViewGrid::DndSourceDragFinished(nux::DndAction result) UnReference(); last_mouse_down_x_ = -1; last_mouse_down_y_ = -1; - current_drag_uri_.clear(); + current_drag_result_.clear(); drag_index_ = ~0; // We need this because the drag can start in a ResultViewGrid and can diff --git a/dash/ResultViewGrid.h b/dash/ResultViewGrid.h index 822689980..9c066185d 100644 --- a/dash/ResultViewGrid.h +++ b/dash/ResultViewGrid.h @@ -23,7 +23,6 @@ #ifndef UNITYSHELL_RESULTVIEWGRID_H #define UNITYSHELL_RESULTVIEWGRID_H -#include <UnityCore/Categories.h> #include <UnityCore/GLibSource.h> #include "ResultView.h" @@ -53,10 +52,12 @@ public: int GetSelectedIndex(); virtual unsigned GetIndexAtPosition(int x, int y); - virtual void Activate(std::string const& uri, int index, ActivateType type); + virtual void Activate(LocalResult const& local_result, int index, ActivateType type); virtual void RenderResultTexture(ResultViewTexture::Ptr const& result_texture); + virtual void GetResultDimensions(int& rows, int& columns); + protected: void MouseMove(int x, int y, int dx, int dy, unsigned long button_flags, unsigned long key_flags); void MouseClick(int x, int y, unsigned long button_flags, unsigned long key_flags); @@ -79,8 +80,8 @@ protected: virtual void UpdateRenderTextures(); - void AddResult(Result& result); - void RemoveResult(Result& result); + virtual void AddResult(Result const& result); + virtual void RemoveResult(Result const& result); // This is overridden so we can include position of results. virtual debug::ResultWrapper* CreateResultWrapper(Result const& result, int index); @@ -93,25 +94,26 @@ private: void DrawRow(nux::GraphicsEngine& GfxContext, ResultListBounds const& visible_bounds, int row_index, int y_position, nux::Geometry const& absolute_position); void QueueLazyLoad(); - void QueueViewChanged(); + void QueueResultsChanged(); bool DoLazyLoad(); int GetItemsPerRow(); void SizeReallocate(); - std::tuple<int, int> GetResultPosition(const std::string& uri); + std::tuple<int, int> GetResultPosition(LocalResult const& local_result); std::tuple<int, int> GetResultPosition(const unsigned int& index); unsigned mouse_over_index_; int active_index_; nux::Property<int> selected_index_; - std::string focused_uri_; + LocalResult focused_result_; - std::string activated_uri_; + LocalResult activated_result_; unsigned last_lazy_loaded_result_; + bool all_results_preloaded_; int last_mouse_down_x_; int last_mouse_down_y_; - std::string current_drag_uri_; + LocalResult current_drag_result_; unsigned drag_index_; int recorded_dash_width_; @@ -124,7 +126,7 @@ private: UBusManager ubus_; glib::Source::UniquePtr lazy_load_source_; - glib::Source::UniquePtr view_changed_idle_; + glib::Source::UniquePtr results_changed_idle_; nux::Color background_color_; }; diff --git a/dash/LensBar.cpp b/dash/ScopeBar.cpp index d01689626..ce9f87690 100644 --- a/dash/LensBar.cpp +++ b/dash/ScopeBar.cpp @@ -17,7 +17,7 @@ */ #include <glib/gstdio.h> -#include "LensBar.h" +#include "ScopeBar.h" #include <NuxCore/Logger.h> #include "config.h" #include <Nux/HLayout.h> @@ -27,25 +27,24 @@ #include "unity-shared/StaticCairoText.h" #include "unity-shared/CairoTexture.h" #include "unity-shared/GraphicsUtils.h" -#include "LensBar.h" #include "unity-shared/UBusMessages.h" namespace unity { namespace dash { -DECLARE_LOGGER(logger, "unity.dash.lensbar"); +DECLARE_LOGGER(logger, "unity.dash.scopebar"); namespace { -// according to Q design the inner area of the lensbar should be 40px +// according to Q design the inner area of the scopebar should be 40px // (without any borders) -const int LENSBAR_HEIGHT = 41; +const int SCOPEBAR_HEIGHT = 41; } -NUX_IMPLEMENT_OBJECT_TYPE(LensBar); +NUX_IMPLEMENT_OBJECT_TYPE(ScopeBar); -LensBar::LensBar() +ScopeBar::ScopeBar() : nux::View(NUX_TRACKER_LOCATION) , info_previously_shown_(false) { @@ -55,10 +54,9 @@ LensBar::LensBar() SetupBackground(); SetupLayout(); - SetupHomeLens(); } -void LensBar::SetupBackground() +void ScopeBar::SetupBackground() { nux::ROPConfig rop; rop.Blend = true; @@ -67,7 +65,7 @@ void LensBar::SetupBackground() bg_layer_.reset(new nux::ColorLayer(nux::Color(0.0f, 0.0f, 0.0f, 0.2f), true, rop)); } -void LensBar::SetupLayout() +void ScopeBar::SetupLayout() { legal_layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); std::string legal_text("<span underline='single'>"); @@ -113,24 +111,11 @@ void LensBar::SetupLayout() SetLayout(layered_layout_); - SetMinimumHeight(LENSBAR_HEIGHT); - SetMaximumHeight(LENSBAR_HEIGHT); + SetMinimumHeight(SCOPEBAR_HEIGHT); + SetMaximumHeight(SCOPEBAR_HEIGHT); } -void LensBar::SetupHomeLens() -{ - LensBarIcon* icon = new LensBarIcon("home.lens", PKGDATADIR"/lens-nav-home.svg"); - icon->SetVisible(true); - icon->active = true; - icons_.push_back(icon); - layout_->AddView(icon, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); - AddChild(icon); - - icon->mouse_click.connect([&, icon] (int x, int y, unsigned long button, unsigned long keyboard) { SetActive(icon); }); - icon->key_nav_focus_activate.connect([&, icon](nux::Area*){ SetActive(icon); }); -} - -void LensBar::DoOpenLegalise() +void ScopeBar::DoOpenLegalise() { glib::Error error; std::string legal_file_path = "file://"; @@ -147,11 +132,12 @@ void LensBar::DoOpenLegalise() ubus_.SendMessage(UBUS_OVERLAY_CLOSE_REQUEST); } -void LensBar::AddLens(Lens::Ptr& lens) +void ScopeBar::AddScope(Scope::Ptr const& scope) { - LensBarIcon* icon = new LensBarIcon(lens->id, lens->icon_hint); - icon->SetVisible(lens->visible); - lens->visible.changed.connect([icon](bool visible) { icon->SetVisible(visible); } ); + ScopeBarIcon* icon = new ScopeBarIcon(scope->id, scope->icon_hint); + + icon->SetVisible(scope->visible); + scope->visible.changed.connect([icon](bool visible) { icon->SetVisible(visible); } ); icons_.push_back(icon); layout_->AddView(icon, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); AddChild(icon); @@ -160,7 +146,7 @@ void LensBar::AddLens(Lens::Ptr& lens) icon->key_nav_focus_activate.connect([&, icon](nux::Area*){ SetActive(icon); }); } -void LensBar::Activate(std::string id) +void ScopeBar::Activate(std::string id) { for (auto icon: icons_) { @@ -172,7 +158,7 @@ void LensBar::Activate(std::string id) } } -void LensBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) +void ScopeBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); @@ -190,7 +176,7 @@ void LensBar::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) graphics_engine.PopClippingRectangle(); } -void LensBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) +void ScopeBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); @@ -201,7 +187,7 @@ void LensBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) { if (RedirectedAncestor()) { - // Whole Lens bar needs to be cleared because the PaintAll forces redraw. + // Whole Scope bar needs to be cleared because the PaintAll forces redraw. graphics::ClearGeometry(base); } @@ -251,10 +237,10 @@ void LensBar::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) graphics_engine.PopClippingRectangle(); } -nux::Area* LensBar::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) +nux::Area* ScopeBar::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) { //LayeredLayout is acting a little screwy, events are not passing past the first layout like instructed, - //so we manually override if the cursor is on the right hand side of the lensbar + //so we manually override if the cursor is on the right hand side of the scopebar auto geo = GetAbsoluteGeometry(); int info_width = (info_previously_shown_) ? info_icon_->GetGeometry().width : legal_->GetGeometry().width; @@ -272,7 +258,7 @@ nux::Area* LensBar::FindAreaUnderMouse(const nux::Point& mouse_position, nux::Nu } -void LensBar::SetActive(LensBarIcon* activated) +void ScopeBar::SetActive(ScopeBarIcon* activated) { bool state_changed = false; @@ -287,24 +273,17 @@ void LensBar::SetActive(LensBarIcon* activated) } if (state_changed) - lens_activated.emit(activated->id); + scope_activated.emit(activated->id); } -void LensBar::ActivateNext() +void ScopeBar::ActivateNext() { - // Special case when switching from the command lens. - if (GetActiveLensId() == "commands.lens") - { - SetActive(icons_[0]); - return; - } - bool activate_next = false; for (auto it = icons_.begin(); it < icons_.end(); it++) { - LensBarIcon *icon = *it; + ScopeBarIcon *icon = *it; if (activate_next && icon->IsVisible()) { @@ -314,25 +293,27 @@ void LensBar::ActivateNext() if (icon->active) activate_next = true; } - SetActive(icons_[0]); - -} -void LensBar::ActivatePrevious() -{ - // Special case when switching from the command lens. - if (GetActiveLensId() == "commands.lens") + // fallback. select first visible icon. + for (auto it = icons_.begin(); it != icons_.end(); ++it) { - SetActive(icons_.back()); - return; + ScopeBarIcon *icon = *it; + if (icon->IsVisible()) + { + SetActive(icon); + break; + } } +} +void ScopeBar::ActivatePrevious() +{ bool activate_previous = false; - for (auto it = icons_.rbegin(); - it < icons_.rend(); - ++it) + for (auto rit = icons_.rbegin(); + rit < icons_.rend(); + ++rit) { - LensBarIcon *icon = *it; + ScopeBarIcon *icon = *rit; if (activate_previous && icon->IsVisible()) { @@ -342,39 +323,48 @@ void LensBar::ActivatePrevious() if (icon->active) activate_previous = true; } - SetActive(icons_.back()); + // fallback. select last visible icon. + for (auto rit = icons_.rbegin(); rit != icons_.rend(); ++rit) + { + ScopeBarIcon *icon = *rit; + if (icon->IsVisible()) + { + SetActive(icon); + break; + } + } } // Keyboard navigation -bool LensBar::AcceptKeyNavFocus() +bool ScopeBar::AcceptKeyNavFocus() { return false; } // Introspectable -std::string LensBar::GetName() const +std::string ScopeBar::GetName() const { - return "LensBar"; + return "ScopeBar"; } -void LensBar::AddProperties(GVariantBuilder* builder) +void ScopeBar::AddProperties(GVariantBuilder* builder) { unity::variant::BuilderWrapper wrapper(builder); - wrapper.add("focused-lens-icon", ""); + wrapper.add("focused-scope-icon", ""); for( auto icon : icons_) { if (icon->active) - wrapper.add("active-lens", icon->id.Get()); + wrapper.add("active-scope", icon->id.Get()); if (icon->HasKeyFocus()) - wrapper.add("focused-lens-icon", icon->id.Get()); + wrapper.add("focused-scope-icon", icon->id.Get()); } } -std::string LensBar::GetActiveLensId() const +std::string ScopeBar::GetActiveScopeId() const { for (auto icon : icons_) { diff --git a/dash/LensBar.h b/dash/ScopeBar.h index 49869736c..fa87eea88 100644 --- a/dash/LensBar.h +++ b/dash/ScopeBar.h @@ -16,8 +16,8 @@ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> */ -#ifndef UNITYSHELL_LENS_BAR_H -#define UNITYSHELL_LENS_BAR_H +#ifndef UNITYSHELL_SCOPE_BAR_H +#define UNITYSHELL_SCOPE_BAR_H #include <memory> #include <string> @@ -27,12 +27,12 @@ #include <Nux/Nux.h> #include <Nux/PaintLayer.h> #include <Nux/View.h> -#include <UnityCore/Lens.h> +#include <UnityCore/Scope.h> #include "unity-shared/IconTexture.h" #include "unity-shared/Introspectable.h" #include "unity-shared/UBusWrapper.h" -#include "LensBarIcon.h" +#include "ScopeBarIcon.h" namespace nux { @@ -49,26 +49,26 @@ class StaticCairoText; namespace dash { -class LensBar : public nux::View, public unity::debug::Introspectable +class ScopeBar : public nux::View, public unity::debug::Introspectable { - NUX_DECLARE_OBJECT_TYPE(LensBar, nux::View); - typedef std::vector<LensBarIcon*> LensIcons; + NUX_DECLARE_OBJECT_TYPE(ScopeBar, nux::View); + typedef std::vector<ScopeBarIcon*> ScopeIcons; public: - LensBar(); + ScopeBar(); - void AddLens(Lens::Ptr& lens); + void AddScope(Scope::Ptr const& scope); void Activate(std::string id); void ActivateNext(); void ActivatePrevious(); - std::string GetActiveLensId() const; - sigc::signal<void, std::string const&> lens_activated; + std::string GetActiveScopeId() const; + + sigc::signal<void, std::string const&> scope_activated; private: void SetupBackground(); void SetupLayout(); - void SetupHomeLens(); void DoOpenLegalise(); void Draw(nux::GraphicsEngine& gfx_context, bool force_draw); @@ -76,7 +76,7 @@ private: nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type); - void SetActive(LensBarIcon* icon); + void SetActive(ScopeBarIcon* icon); bool AcceptKeyNavFocus(); std::string GetName() const; @@ -84,7 +84,7 @@ private: typedef std::unique_ptr<nux::AbstractPaintLayer> LayerPtr; - LensIcons icons_; + ScopeIcons icons_; UBusManager ubus_; @@ -97,9 +97,11 @@ private: bool info_previously_shown_; std::string legal_seen_file_path_; + + friend class TestScopeBar; }; } // namespace dash } // namespace unity -#endif // UNITYSHELL_LENS_BAR_H +#endif // UNITYSHELL_SCOPE_BAR_H diff --git a/dash/LensBarIcon.cpp b/dash/ScopeBarIcon.cpp index 3f4a7682b..ed8519cc8 100644 --- a/dash/LensBarIcon.cpp +++ b/dash/ScopeBarIcon.cpp @@ -19,7 +19,7 @@ #include <UnityCore/Variant.h> #include "unity-shared/DashStyle.h" -#include "LensBarIcon.h" +#include "ScopeBarIcon.h" #include "config.h" @@ -35,9 +35,9 @@ const int FOCUS_OVERLAY_WIDTH = 60; } -NUX_IMPLEMENT_OBJECT_TYPE(LensBarIcon); +NUX_IMPLEMENT_OBJECT_TYPE(ScopeBarIcon); -LensBarIcon::LensBarIcon(std::string id_, std::string icon_hint) +ScopeBarIcon::ScopeBarIcon(std::string id_, std::string icon_hint) : IconTexture(icon_hint, 24) , id(id_) , active(false) @@ -56,14 +56,14 @@ LensBarIcon::LensBarIcon(std::string id_, std::string icon_hint) SetAcceptKeyNavFocusOnMouseDown(false); SetAcceptKeyNavFocusOnMouseEnter(true); - active.changed.connect(sigc::mem_fun(this, &LensBarIcon::OnActiveChanged)); + active.changed.connect(sigc::mem_fun(this, &ScopeBarIcon::OnActiveChanged)); key_nav_focus_change.connect([&](nux::Area*, bool, nux::KeyNavDirection){ QueueDraw(); }); } -LensBarIcon::~LensBarIcon() +ScopeBarIcon::~ScopeBarIcon() {} -void LensBarIcon::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) +void ScopeBarIcon::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) { nux::Geometry const& geo = GetGeometry(); @@ -109,18 +109,18 @@ void LensBarIcon::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) graphics_engine.PopClippingRectangle(); } -void LensBarIcon::OnActiveChanged(bool is_active) +void ScopeBarIcon::OnActiveChanged(bool is_active) { QueueDraw(); } // Introspectable -std::string LensBarIcon::GetName() const +std::string ScopeBarIcon::GetName() const { - return "LensBarIcon"; + return "ScopeBarIcon"; } -void LensBarIcon::AddProperties(GVariantBuilder* builder) +void ScopeBarIcon::AddProperties(GVariantBuilder* builder) { unity::variant::BuilderWrapper wrapper(builder); diff --git a/dash/LensBarIcon.h b/dash/ScopeBarIcon.h index ba150d8cb..a07d64e47 100644 --- a/dash/LensBarIcon.h +++ b/dash/ScopeBarIcon.h @@ -16,8 +16,8 @@ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> */ -#ifndef UNITY_LENS_BAR_ICON_H_ -#define UNITY_LENS_BAR_ICON_H_ +#ifndef UNITY_SCOPE_BAR_ICON_H_ +#define UNITY_SCOPE_BAR_ICON_H_ #include <string> @@ -33,12 +33,12 @@ namespace unity namespace dash { -class LensBarIcon : public IconTexture +class ScopeBarIcon : public IconTexture { - NUX_DECLARE_OBJECT_TYPE(LensBarIcon, IconTexture); + NUX_DECLARE_OBJECT_TYPE(ScopeBarIcon, IconTexture); public: - LensBarIcon(std::string id, std::string icon_hint); - ~LensBarIcon(); + ScopeBarIcon(std::string id, std::string icon_hint); + ~ScopeBarIcon(); nux::Property<std::string> id; nux::Property<bool> active; @@ -60,4 +60,4 @@ private: } } -#endif +#endif // UNITY_SCOPE_BAR_ICON_H_ diff --git a/dash/ScopeView.cpp b/dash/ScopeView.cpp new file mode 100755 index 000000000..ee85a9b48 --- /dev/null +++ b/dash/ScopeView.cpp @@ -0,0 +1,1106 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2010, 2011 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: Neil Jagdish Patel <neil.patel@canonical.com> + */ + +#include "ScopeView.h" + +#include <boost/lexical_cast.hpp> + +#include <NuxCore/Logger.h> +#include <Nux/HScrollBar.h> +#include <Nux/VScrollBar.h> + +#include "unity-shared/DashStyle.h" +#include "CoverflowResultView.h" + +#include "ResultRendererTile.h" +#include "ResultRendererHorizontalTile.h" +#include "unity-shared/UBusMessages.h" +#include "unity-shared/UBusWrapper.h" +#include "unity-shared/PlacesOverlayVScrollBar.h" +#include "unity-shared/GraphicsUtils.h" + +#include "config.h" +#include <glib/gi18n-lib.h> + +namespace unity +{ +namespace dash +{ +DECLARE_LOGGER(logger, "unity.dash.scopeview"); +namespace +{ +const int CARD_VIEW_GAP_VERT = 24; // pixels +const int CARD_VIEW_GAP_HORIZ = 25; // pixels +} + +// This is so we can access some protected members in scrollview. +class ScopeScrollView: public nux::ScrollView +{ +public: + ScopeScrollView(nux::VScrollBar* scroll_bar, NUX_FILE_LINE_DECL) + : nux::ScrollView(NUX_FILE_LINE_PARAM) + , right_area_(nullptr) + , up_area_(nullptr) + { + SetVScrollBar(scroll_bar); + + OnVisibleChanged.connect([&] (nux::Area* /*area*/, bool visible) { + if (m_horizontal_scrollbar_enable) + _hscrollbar->SetVisible(visible); + if (m_vertical_scrollbar_enable) + _vscrollbar->SetVisible(visible); + }); + } + + void ScrollToPosition(nux::Geometry const& position) + { + // much of this code is copied from Nux/ScrollView.cpp + nux::Geometry const& geo = GetGeometry(); + + int child_y = position.y - geo.y; + int child_y_diff = child_y - abs (_delta_y); + + if (child_y_diff + position.height < geo.height && child_y_diff >= 0) + { + return; + } + + if (child_y_diff < 0) + { + ScrollUp (1, abs (child_y_diff)); + } + else + { + int size = child_y_diff - geo.height; + + // always keeps the top of a view on the screen + size += position.height; + + ScrollDown (1, size); + } + } + + void SetRightArea(nux::Area* area) + { + right_area_ = area; + } + + void SetUpArea(nux::Area* area) + { + up_area_ = area; + } + + void DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) + { + if (RedirectedAncestor()) + { + if (m_horizontal_scrollbar_enable && _hscrollbar->IsRedrawNeeded()) + graphics::ClearGeometry(_hscrollbar->GetGeometry()); + if (m_vertical_scrollbar_enable && _vscrollbar->IsRedrawNeeded()) + graphics::ClearGeometry(_vscrollbar->GetGeometry()); + } + + ScrollView::DrawContent(graphics_engine, force_draw); + } + + void EnableScrolling(bool enable_scrolling) + { + _vscrollbar->SetInputEventSensitivity(enable_scrolling); + } + +protected: + + // This is so we can break the natural key navigation path. + nux::Area* KeyNavIteration(nux::KeyNavDirection direction) + { + nux::Area* focus_area = nux::GetWindowCompositor().GetKeyFocusArea(); + + if (direction == nux::KEY_NAV_RIGHT && focus_area && focus_area->IsChildOf(this)) + return right_area_; + else if (direction == nux::KEY_NAV_UP && focus_area && focus_area->IsChildOf(this)) + return up_area_; + else + return nux::ScrollView::KeyNavIteration(direction); + } + +private: + nux::Area* right_area_; + nux::Area* up_area_; +}; + + +NUX_IMPLEMENT_OBJECT_TYPE(ScopeView); + +ScopeView::ScopeView(Scope::Ptr scope, nux::Area* show_filters) +: nux::View(NUX_TRACKER_LOCATION) +, filters_expanded(false) +, can_refine_search(false) +, scope_(scope) +, cancellable_(g_cancellable_new()) +, no_results_active_(false) +, last_good_filter_model_(-1) +, filter_expansion_pushed_(false) +, scope_connected_(scope ? scope->connected : false) +, search_on_next_connect_(false) +{ + SetupViews(show_filters); + + search_string.SetGetterFunction(sigc::mem_fun(this, &ScopeView::get_search_string)); + filters_expanded.changed.connect(sigc::mem_fun(this, &ScopeView::OnScopeFilterExpanded)); + view_type.changed.connect(sigc::mem_fun(this, &ScopeView::OnViewTypeChanged)); + + if (scope_) + { + categories_updated = scope_->categories.changed.connect([this](Categories::Ptr const& categories) { SetupCategories(categories); }); + SetupCategories(scope->categories); + + results_updated = scope_->results.changed.connect([this](Results::Ptr const& results) { SetupResults(results); }); + SetupResults(scope->results); + + filters_updated = scope_->filters.changed.connect([this](Filters::Ptr const& filters) { SetupFilters(filters); }); + SetupFilters(scope->filters); + + scope_->connected.changed.connect([&](bool is_connected) + { + // We need to search again if we were reconnected after being connected before. + if (scope_connected_ && !is_connected) + search_on_next_connect_ = true; + else if (is_connected && search_on_next_connect_) + { + search_on_next_connect_ = false; + if (IsVisible()) + PerformSearch(search_string_, nullptr); + } + scope_connected_ = is_connected; + }); + } + + 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 + // to do it properly + nux::Geometry focused_pos; + g_variant_get (data, "(iiii)", &focused_pos.x, &focused_pos.y, &focused_pos.width, &focused_pos.height); + + for (auto group : category_views_) + { + if (group->GetLayout() != nullptr) + { + auto expand_label = group->GetHeaderFocusableView(); + auto child = group->GetChildView(); + + if ((child && child->HasKeyFocus()) || + (expand_label && expand_label->HasKeyFocus())) + { + focused_pos.x += child->GetGeometry().x; + focused_pos.y += child->GetGeometry().y - 30; + focused_pos.height += 30; + scroll_view_->ScrollToPosition(focused_pos); + break; + } + } + } + }); + + OnVisibleChanged.connect([&] (nux::Area* area, bool visible) { + scroll_view_->SetVisible(visible); + }); +} + +ScopeView::~ScopeView() +{ + results_updated.disconnect(); + result_added_connection.disconnect(); + result_removed_connection.disconnect(); + + categories_updated.disconnect(); + category_added_connection.disconnect(); + category_changed_connection.disconnect(); + category_removed_connection.disconnect(); + + filters_updated.disconnect(); + filter_added_connection.disconnect(); + filter_removed_connection.disconnect(); + + g_cancellable_cancel(cancellable_); + if (search_cancellable_) g_cancellable_cancel(search_cancellable_); +} + +void ScopeView::SetupViews(nux::Area* show_filters) +{ + dash::Style& style = dash::Style::Instance(); + + layout_ = new nux::HLayout(NUX_TRACKER_LOCATION); + layout_->SetSpaceBetweenChildren(style.GetSpaceBetweenScopeAndFilters()); + + scroll_view_ = new ScopeScrollView(new PlacesOverlayVScrollBar(NUX_TRACKER_LOCATION), + NUX_TRACKER_LOCATION); + scroll_view_->EnableVerticalScrollBar(true); + scroll_view_->EnableHorizontalScrollBar(false); + layout_->AddView(scroll_view_); + + scroll_layout_ = new nux::VLayout(NUX_TRACKER_LOCATION); + scroll_view_->SetLayout(scroll_layout_); + scroll_view_->SetRightArea(show_filters); + + no_results_ = new StaticCairoText("", NUX_TRACKER_LOCATION); + no_results_->SetTextColor(nux::color::White); + no_results_->SetVisible(false); + scroll_layout_->AddView(no_results_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); + + fscroll_view_ = new ScopeScrollView(new PlacesOverlayVScrollBar(NUX_TRACKER_LOCATION), NUX_TRACKER_LOCATION); + fscroll_view_->EnableVerticalScrollBar(true); + fscroll_view_->EnableHorizontalScrollBar(false); + fscroll_view_->SetVisible(false); + fscroll_view_->SetUpArea(show_filters); + layout_->AddView(fscroll_view_, 1); + + fscroll_layout_ = new nux::VLayout(); + fscroll_view_->SetLayout(fscroll_layout_); + + filter_bar_ = new FilterBar(); + int width = style.GetFilterBarWidth() + + style.GetFilterBarLeftPadding() + + style.GetFilterBarRightPadding(); + + fscroll_view_->SetMinimumWidth(width + style.GetFilterViewRightPadding()); + fscroll_view_->SetMaximumWidth(width + style.GetFilterViewRightPadding()); + filter_bar_->SetMinimumWidth(width); + filter_bar_->SetMaximumWidth(width); + AddChild(filter_bar_); + fscroll_layout_->AddView(filter_bar_, 0); + + SetLayout(layout_); +} + +void ScopeView::SetupCategories(Categories::Ptr const& categories) +{ + category_added_connection.disconnect(); + category_changed_connection.disconnect(); + category_removed_connection.disconnect(); + + if (!categories) + return; + + category_added_connection = categories->category_added.connect(sigc::mem_fun(this, &ScopeView::OnCategoryAdded)); + category_changed_connection = categories->category_changed.connect(sigc::mem_fun(this, &ScopeView::OnCategoryChanged)); + category_removed_connection = categories->category_removed.connect(sigc::mem_fun(this, &ScopeView::OnCategoryRemoved)); + + auto resync_categories = [categories, this] (glib::Object<DeeModel> model) + { + ClearCategories(); + for (unsigned int i = 0; i < categories->count(); ++i) + OnCategoryAdded(categories->RowAtIndex(i)); + }; + + categories->model.changed.connect(resync_categories); + resync_categories(categories->model()); + + scope_->category_order.changed.connect([this](std::vector<unsigned int> const& category_order) { + category_order_ = category_order; + OnCategoryOrderChanged(); + }); +} + + +void ScopeView::OnCategoryOrderChanged() +{ + LOG_DEBUG(logger) << "Reordering categories for " << scope_->name(); + + for (auto iter = category_views_.begin(); iter != category_views_.end(); ++iter) + { + PlacesGroup::Ptr group = *iter; + scroll_layout_->RemoveChildObject(group.GetPointer()); + } + + if (scope_) + { + Categories::Ptr category_model = scope_->categories(); + if (!category_model) + return; + + // there should be ~10 categories, so this shouldn't be too big of a deal + for (unsigned i = 0; i < category_order_.size(); i++) + { + unsigned int desired_category_index = category_order_[i]; + + if (category_views_.size() <= desired_category_index) + continue; + + scroll_layout_->AddView(category_views_[desired_category_index].GetPointer(), 0); + } + } + QueueRelayout(); +} + +void ScopeView::SetupResults(Results::Ptr const& results) +{ + result_added_connection.disconnect(); + result_removed_connection.disconnect(); + + if (!results) + return; + + result_added_connection = results->result_added.connect(sigc::mem_fun(this, &ScopeView::OnResultAdded)); + result_added_connection = results->result_removed.connect(sigc::mem_fun(this, &ScopeView::OnResultRemoved)); + + results->model.changed.connect([this] (glib::Object<DeeModel> model) + { + for (unsigned int i = 0; i < category_views_.size(); ++i) + { + ResultView* result_view = GetResultViewForCategory(i); + if (result_view) + { + result_view->SetResultsModel(scope_->GetResultsForCategory(i)); + } + } + }); + + for (unsigned int i = 0; i < results->count(); ++i) + OnResultAdded(results->RowAtIndex(i)); +} + +void ScopeView::SetupFilters(Filters::Ptr const& filters) +{ + filter_added_connection.disconnect(); + filter_removed_connection.disconnect(); + + if (!filters) + return; + + filter_added_connection = filters->filter_added.connect(sigc::mem_fun(this, &ScopeView::OnFilterAdded)); + filter_removed_connection = filters->filter_removed.connect(sigc::mem_fun(this, &ScopeView::OnFilterRemoved)); + + auto resync_filters = [filters, this] (glib::Object<DeeModel> model) + { + bool blocked = filter_added_connection.block(true); + + filter_bar_->ClearFilters(); + for (unsigned int i = 0; i < filters->count(); ++i) + OnFilterAdded(filters->FilterAtIndex(i)); + + filter_added_connection.block(blocked); + }; + + filters->model.changed.connect(resync_filters); + resync_filters(filters->model()); +} + +void ScopeView::OnCategoryAdded(Category const& category) +{ + std::string name = category.name; + std::string icon_hint = category.icon_hint; + std::string renderer_name = category.renderer_name; + if (category.index == unsigned(-1)) + return; + unsigned index = category.index; + bool reset_filter_models = index < category_views_.size(); + + LOG_DEBUG(logger) << "Category added '" << (scope_ ? scope_->name() : "unknown") << "': " + << name + << "(" << icon_hint + << ", " << renderer_name + << ", " << boost::lexical_cast<int>(index) << ")"; + + + PlacesGroup::Ptr group(CreatePlacesGroup(category)); + AddChild(group.GetPointer()); + group->SetName(name); + group->SetIcon(icon_hint); + group->SetExpanded(false); + group->SetVisible(false); + + int view_index = category_order_.size(); + auto find_view_index = std::find(category_order_.begin(), category_order_.end(), index); + if (find_view_index == category_order_.end()) + { + category_order_.push_back(index); + } + else + view_index = find_view_index - category_order_.begin(); + + category_views_.insert(category_views_.begin() + index, group); + + group->expanded.connect(sigc::mem_fun(this, &ScopeView::OnGroupExpanded)); + + /* Reset result count */ + counts_[group] = 0; + + ResultView* results_view = nullptr; + if (category.renderer_name == "tile-horizontal") + { + results_view = new ResultViewGrid(NUX_TRACKER_LOCATION); + results_view->SetModelRenderer(new ResultRendererHorizontalTile(NUX_TRACKER_LOCATION)); + static_cast<ResultViewGrid*> (results_view)->horizontal_spacing = CARD_VIEW_GAP_HORIZ; + static_cast<ResultViewGrid*> (results_view)->vertical_spacing = CARD_VIEW_GAP_VERT; + } + else + { + results_view = new ResultViewGrid(NUX_TRACKER_LOCATION); + results_view->SetModelRenderer(new ResultRendererTile(NUX_TRACKER_LOCATION)); + } + + if (scope_) + { + std::string unique_id = category.name() + scope_->name(); + results_view->unique_id = unique_id; + results_view->expanded = false; + + results_view->ResultActivated.connect([this, unique_id] (LocalResult const& local_result, ResultView::ActivateType type, GVariant* data) + { + result_activated.emit(type, local_result, data, unique_id); + switch (type) + { + case ResultView::ActivateType::DIRECT: + { + scope_->Activate(local_result, nullptr, cancellable_); + } break; + case ResultView::ActivateType::PREVIEW: + { + scope_->Preview(local_result, nullptr, cancellable_); + } break; + default: break; + }; + }); + + /* Set up filter model for this category */ + Results::Ptr results_model = scope_->GetResultsForCategory(index); + counts_[group] = results_model ? results_model->count() : 0; + + results_view->SetResultsModel(results_model); + } + + group->SetChildView(results_view); + + /* We need the full range of method args so we can specify the offset + * of the group into the layout */ + scroll_layout_->AddView(group.GetPointer(), 0, nux::MinorDimensionPosition::MINOR_POSITION_START, + nux::MinorDimensionSize::MINOR_SIZE_FULL, 100.0f, + (nux::LayoutPosition)view_index); + + if (reset_filter_models) + { + QueueReinitializeFilterCategoryModels(index); + } + + QueueCategoryCountsCheck(); +} + +void ScopeView::OnCategoryChanged(Category const& category) +{ + if (category_views_.size() <= category.index) + return; + + PlacesGroup::Ptr group = category_views_[category.index]; + + group->SetName(category.name); + group->SetIcon(category.icon_hint); + + QueueCategoryCountsCheck(); +} + +void ScopeView::OnCategoryRemoved(Category const& category) +{ + std::string name = category.name; + std::string icon_hint = category.icon_hint; + std::string renderer_name = category.renderer_name; + unsigned index = category.index; + if (index == unsigned(-1) || category_views_.size() <= index) + return; + bool reset_filter_models = index < category_views_.size()-1; + + LOG_DEBUG(logger) << "Category removed '" << (scope_ ? scope_->name() : "unknown") << "': " + << name + << "(" << icon_hint + << ", " << renderer_name + << ", " << boost::lexical_cast<int>(index) << ")"; + + auto category_pos = category_views_.begin() + index; + PlacesGroup::Ptr group = *category_pos; + + if (last_expanded_group_ == group) + last_expanded_group_.Release(); + + counts_.erase(group); + category_views_.erase(category_pos); + + // remove from order + auto order_pos = std::find(category_order_.begin(), category_order_.end(), index); + if (order_pos != category_order_.end()) + category_order_.erase(order_pos); + + scroll_layout_->RemoveChildObject(group.GetPointer()); + RemoveChild(group.GetPointer()); + QueueRelayout(); + + if (reset_filter_models) + { + QueueReinitializeFilterCategoryModels(index); + } +} + +void ScopeView::ClearCategories() +{ + for (auto iter = category_views_.begin(), end = category_views_.end(); iter != end; ++iter) + { + PlacesGroup::Ptr group = *iter; + RemoveChild(group.GetPointer()); + scroll_layout_->RemoveChildObject(group.GetPointer()); + } + counts_.clear(); + category_views_.clear(); + last_expanded_group_.Release(); + QueueRelayout(); +} + +void ScopeView::QueueReinitializeFilterCategoryModels(unsigned int start_category_index) +{ + if (!scope_) + return; + + Categories::Ptr category_model = scope_->categories(); + unsigned int category_count = 0; + if (!category_model || (category_count=category_model->count()) <= start_category_index) + return; + + if (category_views_.size() <= (start_category_index + 1)) + return; + + /* Scope is reodering the categories, and since their category index is based + * on the row position in the model, we need to re-initialize the category result + * models if we got insert and not an append */ + for (auto iter = category_views_.begin() + start_category_index +1, end = category_views_.end(); iter != end; ++iter) + { + ResultView* result_view = (*iter)->GetChildView(); + if (result_view) + result_view->SetResultsModel(Results::Ptr()); + } + + if (last_good_filter_model_ == -1 || static_cast<int>(start_category_index) < last_good_filter_model_) + { + last_good_filter_model_ = static_cast<int>(start_category_index); + } + if (!fix_filter_models_idle_) + { + fix_filter_models_idle_.reset(new glib::Idle(sigc::mem_fun(this, &ScopeView::ReinitializeCategoryResultModels), glib::Source::Priority::HIGH)); + } +} + +bool ScopeView::ReinitializeCategoryResultModels() +{ + if (!scope_) + return false; + + if (last_good_filter_model_ < 0) + return false; + + if (category_views_.size() > static_cast<unsigned int>(last_good_filter_model_)+1) + { + unsigned int category_index = static_cast<unsigned int>(last_good_filter_model_) +1; + for (auto iter = category_views_.begin() + category_index, end = category_views_.end(); iter != end; ++iter, category_index++) + { + ResultView* result_view = (*iter)->GetChildView(); + if (result_view) + result_view->SetResultsModel(scope_->GetResultsForCategory(category_index)); + } + } + + last_good_filter_model_ = -1; + fix_filter_models_idle_.reset(); + return false; +} + +ResultView* ScopeView::GetResultViewForCategory(unsigned int category_index) +{ + if (category_views_.size() <= category_index) + return nullptr; + + auto category_pos = category_views_.begin() + category_index; + PlacesGroup::Ptr group = *category_pos; + return static_cast<ResultView*>(group->GetChildView()); +} + +void ScopeView::OnResultAdded(Result const& result) +{ + // category not added yet. + if (category_views_.size() <= result.category_index) + return; + + std::string uri = result.uri; + LOG_TRACE(logger) << "Result added '" << (scope_ ? scope_->name() : "unknown") << "': " << uri; + + counts_[category_views_[result.category_index]]++; + // make sure we don't display the no-results-hint if we do have results + CheckNoResults(glib::HintsMap()); + + QueueCategoryCountsCheck(); +} + +void ScopeView::OnResultRemoved(Result const& result) +{ + // category not added yet. + if (category_views_.size() <= result.category_index) + return; + + std::string uri = result.uri; + LOG_TRACE(logger) << "Result removed '" << (scope_ ? scope_->name() : "unknown") << "': " << uri; + + counts_[category_views_[result.category_index]]--; + // make sure we don't display the no-results-hint if we do have results + CheckNoResults(glib::HintsMap()); + + QueueCategoryCountsCheck(); +} + +void ScopeView::CheckNoResults(glib::HintsMap const& hints) +{ + gint const count = scope_->results()->count(); + + if (count == 0) + { + std::stringstream markup; + glib::HintsMap::const_iterator it; + + it = hints.find("no-results-hint"); + markup << "<span size='larger' weight='bold'>"; + + if (it != hints.end()) + markup << it->second.GetString(); + else + markup << _("Sorry, there is nothing that matches your search."); + + markup << "</span>"; + + LOG_DEBUG(logger) << "The no-result-hint is: " << markup.str(); + + scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_CENTER); + + no_results_active_ = true; + no_results_->SetText(markup.str()); + no_results_->SetVisible(true); + } + else if (count && no_results_active_) + { + scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_START); + + no_results_active_ = false; + no_results_->SetText(""); + no_results_->SetVisible(false); + } +} + +void ScopeView::QueueCategoryCountsCheck() +{ + if (!model_updated_timeout_) + { + model_updated_timeout_.reset(new glib::Idle([&] () { + // Check if all results so far are from one category + // If so, then expand that category. + CheckCategoryCounts(); + model_updated_timeout_.reset(); + return false; + }, glib::Source::Priority::HIGH)); + } +} + +void ScopeView::CheckCategoryCounts() +{ + int number_of_displayed_categories = 0; + + PlacesGroup::Ptr new_expanded_group; + + for (auto iter = category_order_.begin(); iter != category_order_.end(); ++iter) + { + unsigned int category_index = *iter; + if (category_views_.size() <= category_index) + continue; + + PlacesGroup::Ptr group = category_views_[category_index]; + + group->SetCounts(counts_[group]); + group->SetVisible(counts_[group] > 0); + + if (counts_[group] > 0) + { + number_of_displayed_categories++; + new_expanded_group = group; + } + } + + if (new_expanded_group && get_search_string().empty()) + { + // only expand the category if we have only one with results. + if (number_of_displayed_categories <= 2) + new_expanded_group->SetExpanded(true); + if (last_expanded_group_ && last_expanded_group_ != new_expanded_group) + last_expanded_group_->SetExpanded(false); + } + else if (last_expanded_group_) + { + last_expanded_group_->SetExpanded(false); + } + + last_expanded_group_ = new_expanded_group; +} + +void ScopeView::HideResultsMessage() +{ + if (no_results_active_) + { + scroll_layout_->SetContentDistribution(nux::MAJOR_POSITION_START); + no_results_active_ = false; + no_results_->SetText(""); + no_results_->SetVisible(false); + } +} + +bool ScopeView::PerformSearch(std::string const& search_query, SearchCallback const& callback) +{ + search_string_ = search_query; + if (scope_) + { + // 150ms to hide the no reults message if its take a while to return results + hide_message_delay_.reset(new glib::Timeout(150, [&] () { + HideResultsMessage(); + return false; + })); + + // cancel old search. + if (search_cancellable_) g_cancellable_cancel (search_cancellable_); + search_cancellable_ = g_cancellable_new (); + + scope_->Search(search_query, [this, callback] (std::string const& search_string, glib::HintsMap const& hints, glib::Error const& err) + { + if (err && !scope_connected_) + { + // if we've failed a search due to connection issue, we need to try again when we re-connect + search_on_next_connect_ = true; + } + + CheckNoResults(hints); + hide_message_delay_.reset(); + if (callback) + callback(scope_->id(), search_string, err); + }, search_cancellable_); + return true; + } + return false; +} + +std::string ScopeView::get_search_string() const +{ + return search_string_; +} + +void ScopeView::OnGroupExpanded(PlacesGroup* group) +{ + ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); + grid->expanded = group->GetExpanded(); + + QueueRelayout(); +} + +void ScopeView::CheckScrollBarState() +{ + if (scroll_layout_->GetHeight() > scroll_view_->GetHeight()) + { + scroll_view_->EnableVerticalScrollBar(true); + } + else + { + scroll_view_->EnableVerticalScrollBar(false); + } +} + +void ScopeView::OnFilterAdded(Filter::Ptr filter) +{ + filter_bar_->AddFilter(filter); + can_refine_search = true; +} + +void ScopeView::OnFilterRemoved(Filter::Ptr filter) +{ + filter_bar_->RemoveFilter(filter); +} + +void ScopeView::OnViewTypeChanged(ScopeViewType view_type) +{ + if (!scope_) + return; + + scope_->view_type = view_type; +} + +void ScopeView::OnScopeFilterExpanded(bool expanded) +{ + if (fscroll_view_->IsVisible() != expanded) + { + fscroll_view_->SetVisible(expanded); + QueueRelayout(); + } + + for (auto category_view : category_views_) + category_view->SetFiltersExpanded(expanded); +} + +void ScopeView::Draw(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + if (RedirectedAncestor()) + graphics::ClearGeometry(GetGeometry()); +} + +void ScopeView::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) +{ + nux::Geometry const& geo = GetGeometry(); + graphics_engine.PushClippingRectangle(geo); + CheckScrollBarState(); + + if (!IsFullRedraw() && RedirectedAncestor()) + { + if (filter_bar_ && filter_bar_->IsVisible() && filter_bar_->IsRedrawNeeded()) + graphics::ClearGeometry(filter_bar_->GetGeometry()); + else if (no_results_ && no_results_->IsVisible() && no_results_->IsRedrawNeeded()) + graphics::ClearGeometry(no_results_->GetGeometry()); + } + + layout_->ProcessDraw(graphics_engine, force_draw); + graphics_engine.PopClippingRectangle(); +} + +Scope::Ptr ScopeView::scope() const +{ + return scope_; +} + +nux::Area* ScopeView::fscroll_view() const +{ + return fscroll_view_; +} + +int ScopeView::GetNumRows() +{ + int num_rows = 0; + for (PlacesGroup::Ptr const& group : category_views_) + { + if (group->IsVisible() && group->GetChildView()) + { + num_rows += 1; // The category header + + if (group->GetExpanded()) + { + int result_rows = 0, result_columns = 0; + group->GetChildView()->GetResultDimensions(result_rows, result_columns); + num_rows += result_rows; + } + else + num_rows += 1; + } + } + + return num_rows; +} + +void ScopeView::AboutToShow() +{ + JumpToTop(); + OnScopeFilterExpanded(filters_expanded); +} + +void ScopeView::JumpToTop() +{ + scroll_view_->ScrollToPosition(nux::Geometry(0, 0, 0, 0)); +} + +void ScopeView::ActivateFirst() +{ + if (!scope_) + return; + + Results::Ptr results = scope_->results; + if (results->count()) + { + // the first displayed category might not be category_views_[0] + for (auto iter = category_order_.begin(); iter != category_order_.end(); ++iter) + { + unsigned int category_index = *iter; + if (category_views_.size() <= category_index) + continue; + PlacesGroup::Ptr group = category_views_[category_index]; + + ResultView* result_view = group->GetChildView(); + if (result_view == nullptr) continue; + + auto it = result_view->GetIteratorAtRow(0); + if (!it.IsLast()) + { + Result result(*it); + result_view->Activate(result, result_view->GetIndexForLocalResult(result), ResultView::ActivateType::DIRECT); + return; + } + } + + // Fallback + Result result = results->RowAtIndex(0); + if (result.uri != "") + { + result_activated.emit(ResultView::ActivateType::DIRECT, LocalResult(result), nullptr, ""); + scope_->Activate(result); + } + } +} + +// Keyboard navigation +bool ScopeView::AcceptKeyNavFocus() +{ + return false; +} + +void ScopeView::ForceCategoryExpansion(std::string const& view_id, bool expand) +{ + for (auto iter = category_views_.begin(); iter != category_views_.end(); ++iter) + { + PlacesGroup::Ptr group = *iter; + if (group->GetChildView()->unique_id == view_id) + { + if (expand) + { + group->PushExpanded(); + group->SetExpanded(true); + } + else + { + group->PopExpanded(); + } + } + } +} + +void ScopeView::SetResultsPreviewAnimationValue(float preview_animation) +{ + for (auto it = category_views_.begin(); it != category_views_.end(); ++it) + { + (*it)->SetResultsPreviewAnimationValue(preview_animation); + } +} + +void ScopeView::EnableResultTextures(bool enable_result_textures) +{ + scroll_view_->EnableScrolling(!enable_result_textures); + + for (auto it = category_views_.begin(); it != category_views_.end(); ++it) + { + ResultView* result_view = (*it)->GetChildView(); + if (result_view) + { + result_view->enable_texture_render = enable_result_textures; + } + } +} + +std::vector<ResultViewTexture::Ptr> ScopeView::GetResultTextureContainers() +{ + // iterate in visual order + std::vector<ResultViewTexture::Ptr> textures; + + for (auto iter = category_order_.begin(); iter != category_order_.end(); ++iter) + { + unsigned int category_index = *iter; + if (category_views_.size() <= category_index) + continue; + PlacesGroup::Ptr cateogry_view = category_views_[category_index]; + + if (!cateogry_view || !cateogry_view->IsVisible()) + continue; + + ResultView* result_view = cateogry_view->GetChildView(); + if (result_view) + { + // concatenate textures + std::vector<ResultViewTexture::Ptr> const& category_textures = result_view->GetResultTextureContainers(); + for (auto iter2 = category_textures.begin(); iter2 != category_textures.end(); ++iter2) + { + ResultViewTexture::Ptr const& result_texture = *iter2; + result_texture->category_index = category_index; + textures.push_back(result_texture); + } + } + } + return textures; +} + +void ScopeView::RenderResultTexture(ResultViewTexture::Ptr const& result_texture) +{ + ResultView* result_view = GetResultViewForCategory(result_texture->category_index); + if (result_view) + result_view->RenderResultTexture(result_texture); +} + +void ScopeView::PushFilterExpansion(bool expand) +{ + filter_expansion_pushed_ = filters_expanded; + filters_expanded = expand; +} + +void ScopeView::PopFilterExpansion() +{ + filters_expanded = GetPushedFilterExpansion(); +} + +bool ScopeView::GetPushedFilterExpansion() const +{ + return filter_expansion_pushed_; +} + +PlacesGroup::Ptr ScopeView::CreatePlacesGroup(Category const& category) +{ + return PlacesGroup::Ptr(new PlacesGroup(dash::Style::Instance())); +} + +ScopeView::CategoryGroups ScopeView::GetOrderedCategoryViews() const +{ + CategoryGroups category_view_ordered; + for (auto iter = category_order_.begin(); iter != category_order_.end(); ++iter) + { + unsigned int category_index = *iter; + if (category_views_.size() <= category_index) + continue; + + PlacesGroup::Ptr group = category_views_[category_index]; + category_view_ordered.push_back(group); + } + return category_view_ordered; +} + +// Introspectable +std::string ScopeView::GetName() const +{ + return "ScopeView"; +} + +void ScopeView::AddProperties(GVariantBuilder* builder) +{ + unity::variant::BuilderWrapper(builder) + .add("name", scope_->id) + .add("scope-name", scope_->name) + .add("visible", IsVisible()) + .add("no-results-active", no_results_active_); +} + +} +} diff --git a/dash/LensView.h b/dash/ScopeView.h index 503fd53ce..4263e05a0 100644 --- a/dash/LensView.h +++ b/dash/ScopeView.h @@ -17,8 +17,8 @@ * Authored by: Neil Jagdish Patel <neil.patel@canonical.com> */ -#ifndef UNITY_LENS_VIEW_H_ -#define UNITY_LENS_VIEW_H_ +#ifndef UNITY_SCOPE_VIEW_H_ +#define UNITY_SCOPE_VIEW_H_ #include <string> @@ -27,7 +27,7 @@ #include <Nux/HLayout.h> #include <Nux/View.h> #include <Nux/VLayout.h> -#include <UnityCore/Lens.h> +#include <UnityCore/Scope.h> #include <UnityCore/GLibSource.h> #include "FilterBar.h" @@ -42,20 +42,21 @@ namespace unity namespace dash { -class LensScrollView; +class ScopeScrollView; -class LensView : public nux::View, public unity::debug::Introspectable +class ScopeView : public nux::View, public unity::debug::Introspectable { - NUX_DECLARE_OBJECT_TYPE(LensView, nux::View); - typedef std::vector<PlacesGroup*> CategoryGroups; - typedef std::map<PlacesGroup*, unsigned int> ResultCounts; + NUX_DECLARE_OBJECT_TYPE(ScopeView, nux::View); + typedef std::vector<PlacesGroup::Ptr> CategoryGroups; + typedef std::map<PlacesGroup::Ptr, unsigned int> ResultCounts; public: - LensView(Lens::Ptr lens, nux::Area* show_filters); + ScopeView(Scope::Ptr scope, nux::Area* show_filters); + ~ScopeView(); - CategoryGroups& categories() { return categories_; } + CategoryGroups GetOrderedCategoryViews() const; FilterBar* filter_bar() const { return filter_bar_; } - Lens::Ptr lens() const; + Scope::Ptr scope() const; nux::Area* fscroll_view() const; int GetNumRows(); @@ -66,15 +67,13 @@ public: nux::ROProperty<std::string> search_string; nux::Property<bool> filters_expanded; - nux::Property<ViewType> view_type; + nux::Property<ScopeViewType> view_type; nux::Property<bool> can_refine_search; - sigc::signal<void, ResultView::ActivateType, std::string const&, GVariant*, std::string const&> uri_activated; + sigc::signal<void, ResultView::ActivateType, LocalResult const&, GVariant*, std::string const&> result_activated; - void PerformSearch(std::string const& search_query, Lens::SearchFinishedCallback const& cb); - void CheckNoResults(Lens::Hints const& hints); - void CheckCategoryExpansion(); - void HideResultsMessage(); + typedef std::function<void(std::string const& scope_id, std::string const& search_query, glib::Error const& err)> SearchCallback; + bool PerformSearch(std::string const& search_query, SearchCallback const& callback); void ForceCategoryExpansion(std::string const& view_id, bool expand); void PushFilterExpansion(bool expand); @@ -89,27 +88,40 @@ public: private: void SetupViews(nux::Area* show_filters); - void SetupCategories(); - void SetupResults(); - void SetupFilters(); + void SetupCategories(Categories::Ptr const& categories); + void SetupResults(Results::Ptr const& results); + void SetupFilters(Filters::Ptr const& filters); void OnCategoryAdded(Category const& category); - void OnCategoryOrderChanged(); + void OnCategoryChanged(Category const& category); + void OnCategoryRemoved(Category const& category); + void OnResultAdded(Result const& result); void OnResultRemoved(Result const& result); - void UpdateCounts(PlacesGroup* group, unsigned int); + + void OnSearchComplete(std::string const& search_string, glib::HintsMap const& hints, glib::Error const& err); + void OnGroupExpanded(PlacesGroup* group); void CheckScrollBarState(); void OnColumnsChanged(); void OnFilterAdded(Filter::Ptr filter); void OnFilterRemoved(Filter::Ptr filter); - void OnViewTypeChanged(ViewType view_type); - void OnLensFilterExpanded(bool expanded); - bool ReinitializeFilterModels(); - ResultViewGrid* GetGridForCategory(unsigned category_index); - ResultView* GetResultViewForCategory(unsigned category_index); + void OnViewTypeChanged(ScopeViewType view_type); + void OnScopeFilterExpanded(bool expanded); + void QueueReinitializeFilterCategoryModels(unsigned int index); + bool ReinitializeCategoryResultModels(); + void ClearCategories(); + void OnCategoryOrderChanged(); - virtual PlacesGroup* CreatePlacesGroup(); + void QueueCategoryCountsCheck(); + void CheckCategoryCounts(); + + void CheckNoResults(glib::HintsMap const& hints); + void HideResultsMessage(); + + ResultView* GetResultViewForCategory(unsigned int category_index); + + virtual PlacesGroup::Ptr CreatePlacesGroup(Category const& category); void BuildPreview(std::string const& uri, Preview::Ptr model); @@ -122,18 +134,21 @@ private: std::string get_search_string() const; - Lens::Ptr lens_; - CategoryGroups categories_; + CategoryGroups category_views_; + + Scope::Ptr scope_; + glib::Object<GCancellable> cancellable_; + glib::Object<GCancellable> search_cancellable_; + std::vector<unsigned int> category_order_; ResultCounts counts_; - bool initial_activation_; bool no_results_active_; std::string search_string_; - PlacesGroup* last_expanded_group_; + PlacesGroup::Ptr last_expanded_group_; nux::HLayout* layout_; - LensScrollView* scroll_view_; + ScopeScrollView* scroll_view_; nux::VLayout* scroll_layout_; - LensScrollView* fscroll_view_; + ScopeScrollView* fscroll_view_; nux::VLayout* fscroll_layout_; FilterBar* filter_bar_; StaticCairoText* no_results_; @@ -142,13 +157,30 @@ private: glib::Source::UniquePtr model_updated_timeout_; int last_good_filter_model_; glib::Source::UniquePtr fix_filter_models_idle_; + glib::Source::UniquePtr hide_message_delay_; bool filter_expansion_pushed_; - friend class TestLensView; + sigc::connection results_updated; + sigc::connection result_added_connection; + sigc::connection result_removed_connection; + + sigc::connection categories_updated; + sigc::connection category_added_connection; + sigc::connection category_changed_connection; + sigc::connection category_removed_connection; + + sigc::connection filters_updated; + sigc::connection filter_added_connection; + sigc::connection filter_removed_connection; + + bool scope_connected_; + bool search_on_next_connect_; + + friend class TestScopeView; }; +} // namespace dash +} // namespace unity -} -} -#endif +#endif // UNITY_SCOPE_VIEW_H_ diff --git a/dash/StandaloneDash.cpp b/dash/StandaloneDash.cpp index a6e69e1be..326e3a28a 100644 --- a/dash/StandaloneDash.cpp +++ b/dash/StandaloneDash.cpp @@ -36,6 +36,7 @@ #include "unity-shared/DashStyle.h" #include "unity-shared/PanelStyle.h" #include "unity-shared/ThumbnailGenerator.h" +#include "UnityCore/GSettingsScopes.h" #define WIDTH 1024 #define HEIGHT 768 @@ -65,7 +66,7 @@ void TestRunner::Init () { layout = new nux::HLayout(NUX_TRACKER_LOCATION); - DashView* view = new DashView(std::make_shared<unity::dash::FilesystemLenses>(), + DashView* view = new DashView(std::make_shared<unity::dash::GSettingsScopes>(), std::make_shared<unity::ApplicationStarterImp>()); view->DisableBlur(); view->SetMinMaxSize(WIDTH, HEIGHT); @@ -75,6 +76,7 @@ void TestRunner::Init () view->AboutToShow(); nux::GetWindowThread()->SetLayout (layout); + nux::GetWindowCompositor().SetKeyFocusArea(view->default_focus()); } void TestRunner::InitWindowThread(nux::NThread* thread, void* InitData) diff --git a/dash/previews/ApplicationPreview.cpp b/dash/previews/ApplicationPreview.cpp index f2e898f70..7ab91a2d2 100644 --- a/dash/previews/ApplicationPreview.cpp +++ b/dash/previews/ApplicationPreview.cpp @@ -153,14 +153,16 @@ void ApplicationPreview::SetupViews() app_icon_->mouse_click.connect(on_mouse_down); icon_layout->AddView(app_icon_.GetPointer(), 0); - app_rating_ = new PreviewRatingsWidget(); - AddChild(app_rating_.GetPointer()); - app_rating_->SetMaximumHeight(style.GetRatingWidgetHeight()); - app_rating_->SetMinimumHeight(style.GetRatingWidgetHeight()); - app_rating_->SetRating(app_preview_model->rating); - app_rating_->SetReviews(app_preview_model->num_ratings); - app_rating_->request_close().connect([this]() { preview_container_->request_close.emit(); }); - icon_layout->AddView(app_rating_.GetPointer(), 0); + if (app_preview_model->rating >= 0) { + app_rating_ = new PreviewRatingsWidget(); + AddChild(app_rating_.GetPointer()); + app_rating_->SetMaximumHeight(style.GetRatingWidgetHeight()); + app_rating_->SetMinimumHeight(style.GetRatingWidgetHeight()); + app_rating_->SetRating(app_preview_model->rating); + app_rating_->SetReviews(app_preview_model->num_ratings); + app_rating_->request_close().connect([this]() { preview_container_->request_close.emit(); }); + icon_layout->AddView(app_rating_.GetPointer(), 0); + } ///////////////////// diff --git a/dash/previews/DBusTestRunner.h b/dash/previews/DBusTestRunner.h index b271bea34..54b856151 100644 --- a/dash/previews/DBusTestRunner.h +++ b/dash/previews/DBusTestRunner.h @@ -24,7 +24,6 @@ #include <UnityCore/GLibDBusProxy.h> #include <UnityCore/Preview.h> -#include <UnityCore/Lens.h> #include <UnityCore/Results.h> #include <NuxCore/Logger.h> diff --git a/dash/previews/LensDBusTestRunner.h b/dash/previews/LensDBusTestRunner.h index 0eb594068..745981745 100644 --- a/dash/previews/LensDBusTestRunner.h +++ b/dash/previews/LensDBusTestRunner.h @@ -23,6 +23,7 @@ #include "DBusTestRunner.h" +#include "UnityCore/ScopeProxyInterface.h" namespace unity { @@ -31,18 +32,18 @@ namespace dash namespace previews { -class LensDBusTestRunner : public DBusTestRunner +class ScopeDBusTestRunner : public DBusTestRunner { public: typedef std::map<std::string, unity::glib::Variant> Hints; - LensDBusTestRunner(std::string const& dbus_name, std::string const& dbus_path, std::string const& interface_name) + ScopeDBusTestRunner(std::string const& dbus_name, std::string const& dbus_path, std::string const& interface_name) : DBusTestRunner(dbus_name, dbus_path, interface_name) , results_(new Results(ModelType::REMOTE)) , results_variant_(NULL) { - proxy_->Connect("Changed", sigc::mem_fun(this, &LensDBusTestRunner::OnChanged)); - results_->end_transaction.connect(sigc::mem_fun(this, &LensDBusTestRunner::ResultsModelUpdated)); + proxy_->Connect("Changed", sigc::mem_fun(this, &ScopeDBusTestRunner::OnChanged)); + results_->end_transaction.connect(sigc::mem_fun(this, &ScopeDBusTestRunner::ResultsModelUpdated)); } void OnProxyConnectionChanged() @@ -52,7 +53,7 @@ public: if (proxy_->IsConnected()) { proxy_->Call("InfoRequest"); - proxy_->Call("SetViewType", g_variant_new("(u)", LENS_VIEW)); + proxy_->Call("SetViewType", g_variant_new("(u)", ScopeViewType::SCOPE_VIEW)); } } @@ -81,7 +82,7 @@ public: &filters_model_name, &hints_iter); - LOG_DEBUG(logger) << "Lens info changed for " << dbus_name_ << "\n" + LOG_DEBUG(logger) << "Scope info changed for " << dbus_name_ << "\n" << " Path: " << dbus_path << "\n" << " SearchInGlobal: " << search_in_global << "\n" << " Visible: " << visible << "\n" @@ -125,7 +126,7 @@ public: g_variant_new("(sa{sv})", search_string.c_str(), &b), - sigc::mem_fun(this, &LensDBusTestRunner::OnSearchFinished), + sigc::mem_fun(this, &ScopeDBusTestRunner::OnSearchFinished), search_cancellable_); g_variant_builder_clear(&b); @@ -183,7 +184,7 @@ public: proxy_->Call("Activate", g_variant_new("(su)", uri.c_str(), UNITY_PROTOCOL_ACTION_TYPE_PREVIEW_RESULT), - sigc::mem_fun(this, &LensDBusTestRunner::ActivationReply), + sigc::mem_fun(this, &ScopeDBusTestRunner::ActivationReply), preview_cancellable_); } @@ -208,7 +209,7 @@ public: { dash::Preview::Ptr preview(dash::Preview::PreviewForVariant(iter->second)); - // would be nice to make parent_lens a shared_ptr, + // would be nice to make parent_scope a shared_ptr, // but that's not really doable from here preview_ready.emit(uri.Str(), preview); return; diff --git a/dash/previews/MusicPaymentPreview.cpp b/dash/previews/MusicPaymentPreview.cpp index f85b7578c..69d5e4b17 100644 --- a/dash/previews/MusicPaymentPreview.cpp +++ b/dash/previews/MusicPaymentPreview.cpp @@ -1,4 +1,4 @@ -// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 4 -*- +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012-2013 Canonical Ltd. * @@ -94,7 +94,7 @@ void MusicPaymentPreview::OnActionActivated(ActionButton* button, std::string co // HACK: We need to think a better way to do this auto const& password = password_entry_->text_entry()->GetText(); glib::Variant variant_pw(g_variant_new_string(password.c_str())); - Lens::Hints hints { + glib::HintsMap hints { std::make_pair(MusicPaymentPreview::DATA_PASSWORD_KEY, variant_pw) }; preview_model_->PerformAction(id, hints); diff --git a/dash/previews/MusicPaymentPreview.h b/dash/previews/MusicPaymentPreview.h index 423ac6547..40062f562 100644 --- a/dash/previews/MusicPaymentPreview.h +++ b/dash/previews/MusicPaymentPreview.h @@ -25,7 +25,6 @@ #include <Nux/Nux.h> #include <Nux/AbstractButton.h> -#include <UnityCore/Lens.h> #include <UnityCore/PaymentPreview.h> #include "ActionButton.h" #include "ActionLink.h" diff --git a/dash/previews/MusicPreview.cpp b/dash/previews/MusicPreview.cpp index 21e4f2868..9e1fb98f0 100644 --- a/dash/previews/MusicPreview.cpp +++ b/dash/previews/MusicPreview.cpp @@ -34,6 +34,7 @@ #include "ActionButton.h" #include "Tracks.h" #include "PreviewInfoHintWidget.h" +#include "PreviewPlayer.h" namespace unity { @@ -177,8 +178,6 @@ void MusicPreview::SetupViews() { tracks_ = new previews::Tracks(tracks_model, NUX_TRACKER_LOCATION); AddChild(tracks_.GetPointer()); - tracks_->play.connect(sigc::mem_fun(this, &MusicPreview::OnPlayTrack)); - tracks_->pause.connect(sigc::mem_fun(this, &MusicPreview::OnPauseTrack)); tracks_->mouse_click.connect(on_mouse_down); } ///////////////////// @@ -264,30 +263,6 @@ void MusicPreview::SetupViews() SetLayout(image_data_layout); } -void MusicPreview::OnPlayTrack(std::string const& uri) -{ - dash::MusicPreview* music_preview_model = dynamic_cast<dash::MusicPreview*>(preview_model_.get()); - if (!music_preview_model) - { - LOG_ERROR(logger) << "Play failed. No preview found"; - return; - } - - music_preview_model->PlayUri(uri); -} - -void MusicPreview::OnPauseTrack(std::string const& uri) -{ - dash::MusicPreview* music_preview_model = dynamic_cast<dash::MusicPreview*>(preview_model_.get()); - if (!music_preview_model) - { - LOG_ERROR(logger) << "Pause failed. No preview found"; - return; - } - - music_preview_model->PauseUri(uri); -} - void MusicPreview::PreLayoutManagement() { nux::Geometry geo = GetGeometry(); @@ -314,6 +289,12 @@ void MusicPreview::PreLayoutManagement() Preview::PreLayoutManagement(); } +void MusicPreview::OnNavigateOut() +{ + PreviewPlayer player; + player.Stop(); } -} -} + +} // namespace previews +} // namespace dash +} // namespace unity diff --git a/dash/previews/MusicPreview.h b/dash/previews/MusicPreview.h index cf56b1e0e..f215dadd5 100644 --- a/dash/previews/MusicPreview.h +++ b/dash/previews/MusicPreview.h @@ -54,9 +54,7 @@ protected: virtual void SetupViews(); - void OnPlayTrack(std::string const& uri); - void OnPauseTrack(std::string const& uri); - bool HasUbuntuOneCredentials(); + virtual void OnNavigateOut(); protected: nux::ObjectPtr<Tracks> tracks_; diff --git a/dash/previews/PaymentPreview.cpp.moved b/dash/previews/PaymentPreview.cpp.moved new file mode 100644 index 000000000..388734b34 --- /dev/null +++ b/dash/previews/PaymentPreview.cpp.moved @@ -0,0 +1,368 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright 2012-2013 Canonical Ltd. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Lesser 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 warranties of + * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the applicable version of the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of both the GNU Lesser General Public + * License version 3 along with this program. If not, see + * <http://www.gnu.org/licenses/> + * + * Authored by: Diego Sarmentero <diego.sarmentero@canonical.com> + * Manuel de la Pena <manuel.delapena@canonical.com> + * + */ +#include <NuxCore/Logger.h> +#include "PaymentPreview.h" +#include "unity-shared/CoverArt.h" +#include "unity-shared/PreviewStyle.h" + +namespace unity +{ + +namespace dash +{ + +namespace previews +{ + +namespace +{ + +nux::logging::Logger logger("unity.dash.previews.payment.preview"); + +} + +class OverlaySpinner : public unity::debug::Introspectable, public nux::View +{ + NUX_DECLARE_OBJECT_TYPE(OverlaySpinner, nux::View); +public: + OverlaySpinner(); + + void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); + void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); + +protected: + // Introspectable methods + std::string GetName() const; + void AddProperties(GVariantBuilder* builder); + + // Key navigation + virtual bool AcceptKeyNavFocus(); + +private: + bool OnFrameTimeout(); + + nux::BaseTexture* spin_; + + glib::Source::UniquePtr frame_timeout_; + + nux::Matrix4 rotate_; + float rotation_; +}; + +NUX_IMPLEMENT_OBJECT_TYPE(OverlaySpinner); + +OverlaySpinner::OverlaySpinner() + : nux::View(NUX_TRACKER_LOCATION), + rotation_(0.0f) +{ + previews::Style& style = dash::previews::Style::Instance(); + + spin_ = style.GetSearchSpinIcon(); + + rotate_.Identity(); + rotate_.Rotate_z(0.0); +} + +void OverlaySpinner::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) +{ + nux::Geometry const& geo = GetGeometry(); + nux::TexCoordXForm texxform; + + GfxContext.PushClippingRectangle(geo); + + nux::GetPainter().PaintBackground(GfxContext, geo); + + texxform.SetTexCoordType(nux::TexCoordXForm::OFFSET_COORD); + texxform.SetWrap(nux::TEXWRAP_REPEAT, nux::TEXWRAP_REPEAT); + texxform.min_filter = nux::TEXFILTER_LINEAR; + texxform.mag_filter = nux::TEXFILTER_LINEAR; + + unsigned int current_alpha_blend; + unsigned int current_src_blend_factor; + unsigned int current_dest_blend_factor; + GfxContext.GetRenderStates().GetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); + GfxContext.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + nux::Geometry spin_geo(geo.x + ((geo.width - spin_->GetWidth()) / 2), + geo.y + ((geo.height - spin_->GetHeight()) / 2), + spin_->GetWidth(), + spin_->GetHeight()); + // Geometry (== Rect) uses integers which were rounded above, + // hence an extra 0.5 offset for odd sizes is needed + // because pure floating point is not being used. + int spin_offset_w = !(geo.width % 2) ? 0 : 1; + int spin_offset_h = !(geo.height % 2) ? 0 : 1; + + nux::Matrix4 matrix_texture; + matrix_texture = nux::Matrix4::TRANSLATE(-spin_geo.x - (spin_geo.width + spin_offset_w) / 2.0f, + -spin_geo.y - (spin_geo.height + spin_offset_h) / 2.0f, 0) * matrix_texture; + matrix_texture = rotate_ * matrix_texture; + matrix_texture = nux::Matrix4::TRANSLATE(spin_geo.x + (spin_geo.width + spin_offset_w) / 2.0f, + spin_geo.y + (spin_geo.height + spin_offset_h) / 2.0f, 0) * matrix_texture; + + GfxContext.SetModelViewMatrix(GfxContext.GetModelViewMatrix() * matrix_texture); + + GfxContext.QRP_1Tex(spin_geo.x, + spin_geo.y, + spin_geo.width, + spin_geo.height, + spin_->GetDeviceTexture(), + texxform, + nux::color::White); + + // revert to model view matrix stack + GfxContext.ApplyModelViewMatrix(); + + GfxContext.PopClippingRectangle(); + + GfxContext.GetRenderStates().SetBlend(current_alpha_blend, current_src_blend_factor, current_dest_blend_factor); + + if (!frame_timeout_) + { + frame_timeout_.reset(new glib::Timeout(22, sigc::mem_fun(this, &OverlaySpinner::OnFrameTimeout))); + } +} + + +void OverlaySpinner::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) +{ +} + + +bool OverlaySpinner::OnFrameTimeout() +{ + rotation_ += 0.1f; + + if (rotation_ >= 360.0f) + rotation_ = 0.0f; + + rotate_.Rotate_z(rotation_); + QueueDraw(); + + frame_timeout_.reset(); + return false; +} + +std::string OverlaySpinner::GetName() const +{ + return "OverlaySpinner"; +} + +void OverlaySpinner::AddProperties(GVariantBuilder* builder) +{ + nux::Geometry geo = GetGeometry(); + + variant::BuilderWrapper(builder) + .add("x", geo.x) + .add("y", geo.y) + .add("width", geo.width) + .add("height", geo.height); +} + + +bool OverlaySpinner::AcceptKeyNavFocus() +{ + return false; +} + +PaymentPreview::PaymentPreview(dash::Preview::Ptr preview_model) +: Preview(preview_model) +, data_(nullptr) +, full_data_layout_(nullptr) +{ +} + +std::string PaymentPreview::GetName() const +{ + return ""; +} + + +nux::Layout* PaymentPreview::GetHeader() +{ + nux::HLayout* header_data_layout = new nux::HLayout(); + header_data_layout->SetSpaceBetweenChildren(10); + header_data_layout->SetMaximumHeight(76); + header_data_layout->SetMinimumHeight(76); + + image_ = new CoverArt(); + image_->SetMinMaxSize(64, 64); + AddChild(image_.GetPointer()); + UpdateCoverArtImage(image_.GetPointer()); + + header_data_layout->AddView(image_.GetPointer(), 0); + header_data_layout->AddLayout(GetTitle(), 0); + header_data_layout->AddSpace(10, 1); + header_data_layout->AddLayout(GetPrice(), 0); + return header_data_layout; +} + +nux::ObjectPtr<ActionLink> PaymentPreview::CreateLink(dash::Preview::ActionPtr action) +{ + previews::Style& style = dash::previews::Style::Instance(); + + nux::ObjectPtr<ActionLink> link; + link = new ActionLink(action->id, + action->display_name, NUX_TRACKER_LOCATION); + link->font_hint.Set(style.payment_form_labels_font().c_str()); + link->SetMinimumWidth(178); + link->SetMaximumHeight(34); + return link; +} + + +nux::ObjectPtr<ActionButton> PaymentPreview::CreateButton(dash::Preview::ActionPtr action) +{ + previews::Style& style = dash::previews::Style::Instance(); + + nux::ObjectPtr<ActionButton> button; + button = new ActionButton(action->id, + action->display_name, action->icon_hint, + NUX_TRACKER_LOCATION); + button->SetFont(style.action_font()); + button->SetExtraHint(action->extra_text, style.action_extra_font()); + button->SetMinimumWidth(178); + button->SetMaximumHeight(34); + return button; +} + + +void PaymentPreview::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) +{ + nux::Geometry const& base = GetGeometry(); + + gfx_engine.PushClippingRectangle(base); + nux::GetPainter().PaintBackground(gfx_engine, base); + + if (full_data_layout_) + { + unsigned int alpha, src, dest = 0; + gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); + gfx_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + details_bg_layer_->SetGeometry(full_data_layout_->GetGeometry()); + nux::GetPainter().RenderSinglePaintLayer(gfx_engine, full_data_layout_->GetGeometry(), details_bg_layer_.get()); + + gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); + } + + gfx_engine.PopClippingRectangle(); +} + +void PaymentPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) +{ + nux::Geometry const& base = GetGeometry(); + gfx_engine.PushClippingRectangle(base); + + if (!IsFullRedraw()) + nux::GetPainter().PushLayer(gfx_engine, details_bg_layer_->GetGeometry(), details_bg_layer_.get()); + + unsigned int alpha, src, dest = 0; + gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); + gfx_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + if (GetCompositionLayout()) + GetCompositionLayout()->ProcessDraw(gfx_engine, force_draw); + + gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); + + if (!IsFullRedraw()) + nux::GetPainter().PopBackground(); + + gfx_engine.PopClippingRectangle(); +} + +void PaymentPreview::ShowOverlay(bool isShown) +{ + if (!full_data_layout_) + return; + + if (isShown) + { + full_data_layout_->SetActiveLayerN(1); + } + else + { + full_data_layout_->SetActiveLayerN(0); + } + QueueDraw(); +} + +void PaymentPreview::ShowOverlay() +{ + ShowOverlay(true); +} + +void PaymentPreview::HideOverlay() +{ + ShowOverlay(false); +} + +void PaymentPreview::SetupBackground() +{ + details_bg_layer_.reset(dash::previews::Style::Instance().GetBackgroundLayer()); +} + +void PaymentPreview::SetupViews() +{ + full_data_layout_ = new nux::LayeredLayout(); + + // layout to be used to show the info + content_data_layout_ = new nux::VLayout(); + content_data_layout_->SetSpaceBetweenChildren(5); + content_data_layout_->SetPadding(10, 10, 0, 10); + + header_layout_ = GetHeader(); + + content_data_layout_->AddLayout(header_layout_.GetPointer(), 1); + + body_layout_ = GetBody(); + content_data_layout_->AddLayout(body_layout_.GetPointer(), 1); + + footer_layout_ = GetFooter(); + content_data_layout_->AddLayout(footer_layout_.GetPointer(), 1); + + full_data_layout_->AddLayout(content_data_layout_.GetPointer()); + + // layout to draw an overlay + overlay_layout_ = new nux::VLayout(); + StaticCairoText* calculating = new StaticCairoText( + "Performing purchase", true, + NUX_TRACKER_LOCATION); + + OverlaySpinner* spinner_ = new OverlaySpinner(); + overlay_layout_->AddSpace(20, 1); + overlay_layout_->AddView(calculating, 0, nux::MINOR_POSITION_CENTER); + overlay_layout_->AddView(spinner_, 1, nux::MINOR_POSITION_CENTER); + overlay_layout_->AddSpace(20, 1); + + full_data_layout_->AddLayout(overlay_layout_.GetPointer()); + + SetLayout(full_data_layout_.GetPointer()); +} + +} + +} + +} diff --git a/dash/previews/PaymentPreview.h b/dash/previews/PaymentPreview.h index 3359d8952..3a09e895b 100644 --- a/dash/previews/PaymentPreview.h +++ b/dash/previews/PaymentPreview.h @@ -28,7 +28,6 @@ #include <Nux/HLayout.h> #include <Nux/LayeredLayout.h> #include <Nux/AbstractButton.h> -#include <UnityCore/Lens.h> #include <UnityCore/PaymentPreview.h> #include "ActionButton.h" #include "ActionLink.h" diff --git a/dash/previews/Preview.cpp b/dash/previews/Preview.cpp index 44eaca080..c32038444 100644 --- a/dash/previews/Preview.cpp +++ b/dash/previews/Preview.cpp @@ -88,10 +88,6 @@ previews::Preview::Ptr Preview::PreviewForModel(dash::Preview::Ptr model) { return Preview::Ptr(new SocialPreview(model)); } - // else if (renderer_name == "preview-series") - // { - // return Preview::Ptr(new SeriesPreview(model)); - // } else { LOG_WARN(logger) << "Unable to create Preview for renderer: " << model->renderer_name.Get() << "; using generic"; @@ -116,9 +112,6 @@ Preview::Preview(dash::Preview::Ptr preview_model) Preview::~Preview() { - if (preview_model_) - preview_model_->EmitClosed(); - delete tab_iterator_; } @@ -131,7 +124,7 @@ void Preview::AddProperties(GVariantBuilder* builder) { variant::BuilderWrapper(builder) .add(GetAbsoluteGeometry()) - .add("uri", preview_model_->preview_uri.Get()); + .add("uri", preview_model_->preview_result.uri); } void Preview::OnActionActivated(ActionButton* button, std::string const& id) diff --git a/dash/previews/StandaloneMusicPreview.cpp b/dash/previews/StandaloneMusicPreview.cpp index 830fdd330..c4680e587 100644 --- a/dash/previews/StandaloneMusicPreview.cpp +++ b/dash/previews/StandaloneMusicPreview.cpp @@ -116,7 +116,7 @@ protected: LayerPtr bg_layer_; }; -class TestRunner : public previews::LensDBusTestRunner +class TestRunner : public previews::ScopeDBusTestRunner { public: TestRunner(std::string const& search_string); @@ -136,7 +136,7 @@ public: }; TestRunner::TestRunner (std::string const& search_string) -: LensDBusTestRunner("com.canonical.Unity.Lens.Music","/com/canonical/unity/lens/music", "com.canonical.Unity.Lens") +: ScopeDBusTestRunner("com.canonical.Unity.Scope.Music","/com/canonical/unity/scope/music", "com.canonical.Unity.Scope") , search_string_(search_string) , first_(true) { diff --git a/dash/previews/Track.cpp b/dash/previews/Track.cpp index 92e38ece2..0e43f3bc1 100644 --- a/dash/previews/Track.cpp +++ b/dash/previews/Track.cpp @@ -125,7 +125,8 @@ private: Track::Track(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) - , play_state_(dash::STOPPED) + , play_state_(PlayerState::STOPPED) + , progress_(0.0) , mouse_over_(false) { SetupBackground(); @@ -134,6 +135,7 @@ Track::Track(NUX_FILE_LINE_DECL) Track::~Track() { + player_connection_.disconnect(); } std::string Track::GetName() const @@ -145,7 +147,7 @@ void Track::AddProperties(GVariantBuilder* builder) { variant::BuilderWrapper(builder) .add("uri", uri_) - .add("play-state", play_state_) + .add("play-state", (int)play_state_) .add("progress", progress_) .add("playpause-x", track_status_layout_->GetAbsoluteX()) .add("playpause-y", track_status_layout_->GetAbsoluteX()) @@ -156,8 +158,6 @@ void Track::AddProperties(GVariantBuilder* builder) void Track::Update(dash::Track const& track) { uri_ = track.uri; - progress_ = track.progress; - title_->SetText(track.title, true); std::stringstream ss_track_number; @@ -168,9 +168,25 @@ void Track::Update(dash::Track const& track) duration_->SetText(duration); g_free(duration); - play_state_ = track.play_state; - UpdateTrackState(); + player_connection_.disconnect(); + player_connection_ = player_.updated.connect([this](std::string const& uri, PlayerState player_state, double progress) + { + if (uri != uri_) + { + // If we're received an update for another track, we're obviously not playing this track anymore. + if (progress_ != 0.0 || play_state_ != PlayerState::STOPPED) + { + progress_ = 0.0; + play_state_ = PlayerState::STOPPED; + UpdateTrackState(); + } + return; + } + progress_ = progress; + play_state_ = player_state; + UpdateTrackState(); + }); QueueDraw(); } @@ -264,13 +280,17 @@ void Track::SetupViews() { switch (play_state_) { - case dash::PLAYING: - pause.emit(uri_); + case PlayerState::PLAYING: + player_.Pause(); + break; + + case PlayerState::PAUSED: + player_.Resume(); break; - case dash::PAUSED: - case dash::STOPPED: + + case PlayerState::STOPPED: default: - play.emit(uri_); + player_.Play(uri_); break; } }); @@ -357,7 +377,7 @@ nux::Area* Track::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxE bool Track::HasStatusFocus() const { - return mouse_over_ || play_state_ == dash::PLAYING || play_state_ == dash::PAUSED; + return mouse_over_ || play_state_ == PlayerState::PLAYING || play_state_ == PlayerState::PAUSED; } void Track::OnTrackControlMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags) @@ -382,11 +402,11 @@ void Track::UpdateTrackState() { switch (play_state_) { - case dash::PLAYING: + case PlayerState::PLAYING: track_status_layout_->SetActiveLayer(status_pause_layout_); break; - case dash::PAUSED: - case dash::STOPPED: + case PlayerState::PAUSED: + case PlayerState::STOPPED: default: track_status_layout_->SetActiveLayer(status_play_layout_); break; @@ -396,18 +416,19 @@ void Track::UpdateTrackState() { switch (play_state_) { - case dash::PLAYING: + case PlayerState::PLAYING: track_status_layout_->SetActiveLayer(status_play_layout_); break; - case dash::PAUSED: + case PlayerState::PAUSED: track_status_layout_->SetActiveLayer(status_pause_layout_); break; - case dash::STOPPED: + case PlayerState::STOPPED: default: track_status_layout_->SetActiveLayer(track_number_layout_); break; } } + QueueDraw(); } @@ -425,8 +446,6 @@ void Track::PreLayoutManagement() View::PreLayoutManagement(); } - - -} -} -} +} // namespace previews +} // namespace dash +} // namesapce unity diff --git a/dash/previews/Track.h b/dash/previews/Track.h index b1815dae1..329e17f9e 100644 --- a/dash/previews/Track.h +++ b/dash/previews/Track.h @@ -27,6 +27,7 @@ #include <Nux/View.h> #include <UnityCore/Tracks.h> #include "unity-shared/Introspectable.h" +#include "PreviewPlayer.h" namespace nux { @@ -54,9 +55,6 @@ public: void Update(dash::Track const& track_row); - sigc::signal<void, std::string const&> play; - sigc::signal<void, std::string const&> pause; - protected: virtual void Draw(nux::GraphicsEngine& gfx_engine, bool force_draw); virtual void DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw); @@ -81,7 +79,11 @@ protected: protected: std::string uri_; + PlayerState play_state_; float progress_; + PreviewPlayer player_; + sigc::connection player_connection_; + unity::StaticCairoText* track_number_; unity::StaticCairoText* title_; unity::StaticCairoText* duration_; @@ -97,7 +99,6 @@ protected: nux::View* track_number_layout_; nux::LayeredLayout* track_status_layout_; - dash::PlayState play_state_; bool mouse_over_; }; diff --git a/dash/previews/Tracks.cpp b/dash/previews/Tracks.cpp index 1c5a3872c..7f53519cc 100644 --- a/dash/previews/Tracks.cpp +++ b/dash/previews/Tracks.cpp @@ -47,9 +47,9 @@ Tracks::Tracks(dash::Tracks::Ptr tracks, NUX_FILE_LINE_DECL) if (tracks_) { - tracks_->track_added.connect(sigc::mem_fun(this, &Tracks::OnTrackAdded)); - tracks_->track_changed.connect(sigc::mem_fun(this, &Tracks::OnTrackUpdated)); - tracks_->track_removed.connect(sigc::mem_fun(this, &Tracks::OnTrackRemoved)); + add_track_ = tracks_->track_added.connect(sigc::mem_fun(this, &Tracks::OnTrackAdded)); + change_track_ = tracks_->track_changed.connect(sigc::mem_fun(this, &Tracks::OnTrackUpdated)); + remove_track_ = tracks_->track_removed.connect(sigc::mem_fun(this, &Tracks::OnTrackRemoved)); // Add what we've got. for (std::size_t i = 0; i < tracks_->count.Get(); i++) @@ -61,6 +61,9 @@ Tracks::Tracks(dash::Tracks::Ptr tracks, NUX_FILE_LINE_DECL) Tracks::~Tracks() { + add_track_.disconnect(); + change_track_.disconnect(); + remove_track_.disconnect(); } std::string Tracks::GetName() const @@ -105,8 +108,6 @@ void Tracks::OnTrackAdded(dash::Track const& track_row) previews::Track::Ptr track_view(new previews::Track(NUX_TRACKER_LOCATION)); AddChild(track_view.GetPointer()); - track_view->play.connect([&](std::string const& uri) { play.emit(uri); }); - track_view->pause.connect([&](std::string const& uri) { pause.emit(uri); }); track_view->Update(track_row); track_view->SetMinimumHeight(style.GetTrackHeight()); diff --git a/dash/previews/Tracks.h b/dash/previews/Tracks.h index ca4a0a25c..1854ddc01 100644 --- a/dash/previews/Tracks.h +++ b/dash/previews/Tracks.h @@ -56,9 +56,6 @@ public: std::string GetName() const; void AddProperties(GVariantBuilder* builder); - sigc::signal<void, std::string const&> play; - sigc::signal<void, std::string const&> pause; - protected: virtual bool AcceptKeyNavFocus() { return false; } @@ -68,15 +65,14 @@ protected: void OnTrackAdded(dash::Track const& track); void OnTrackRemoved(dash::Track const&track); - void onPlayTrack(std::string const& uri); - void onPauseTrack(std::string const& uri); - protected: dash::Tracks::Ptr tracks_; nux::VLayout* layout_; std::map<std::string, previews::Track::Ptr> m_tracks; - int track_count_; + sigc::connection add_track_; + sigc::connection change_track_; + sigc::connection remove_track_; }; } |
