diff options
97 files changed, 1749 insertions, 659 deletions
diff --git a/UnityCore/Model-inl.h b/UnityCore/Model-inl.h index c97edf3a6..f560c8137 100644 --- a/UnityCore/Model-inl.h +++ b/UnityCore/Model-inl.h @@ -35,6 +35,9 @@ nux::logging::Logger _model_inl_logger("unity.dash.model"); template<class RowAdaptor> Model<RowAdaptor>::Model() : model_type_(ModelType::REMOTE) + , cached_adaptor1_(nullptr, nullptr, nullptr) + , cached_adaptor2_(nullptr, nullptr, nullptr) + , cached_adaptor3_(nullptr, nullptr, nullptr) { Init(); } @@ -42,6 +45,9 @@ Model<RowAdaptor>::Model() template<class RowAdaptor> Model<RowAdaptor>::Model (ModelType model_type) : model_type_(model_type) + , cached_adaptor1_(nullptr, nullptr, nullptr) + , cached_adaptor2_(nullptr, nullptr, nullptr) + , cached_adaptor3_(nullptr, nullptr, nullptr) { Init(); @@ -118,22 +124,31 @@ Model<RowAdaptor>::~Model() template<class RowAdaptor> void Model<RowAdaptor>::OnRowAdded(DeeModel* model, DeeModelIter* iter) { - RowAdaptor it(model, iter, renderer_tag_); - row_added.emit(it); + // careful here - adding rows to the model inside the callback + // will invalidate the cached_adaptor! + // This needs to be used as a listener only! + cached_adaptor1_.SetTarget(model, iter, renderer_tag_); + row_added.emit(cached_adaptor1_); } template<class RowAdaptor> void Model<RowAdaptor>::OnRowChanged(DeeModel* model, DeeModelIter* iter) { - RowAdaptor it(model, iter, renderer_tag_); - row_changed.emit(it); + // careful here - changing rows inside the callback will invalidate + // the cached_adaptor! + // This needs to be used as a listener only! + cached_adaptor2_.SetTarget(model, iter, renderer_tag_); + row_changed.emit(cached_adaptor2_); } template<class RowAdaptor> void Model<RowAdaptor>::OnRowRemoved(DeeModel* model, DeeModelIter* iter) { - RowAdaptor it(model, iter, renderer_tag_); - row_removed.emit(it); + // careful here - removing rows from the model inside the callback + // will invalidate the cached_adaptor! + // This needs to be used as a listener only! + cached_adaptor3_.SetTarget(model, iter, renderer_tag_); + row_removed.emit(cached_adaptor3_); } template<class RowAdaptor> diff --git a/UnityCore/Model.h b/UnityCore/Model.h index 1c14067a7..fdc9eeafe 100644 --- a/UnityCore/Model.h +++ b/UnityCore/Model.h @@ -88,6 +88,10 @@ private: glib::SignalManager sig_manager_; DeeModelTag* renderer_tag_; ModelType model_type_; + + RowAdaptor cached_adaptor1_; + RowAdaptor cached_adaptor2_; + RowAdaptor cached_adaptor3_; }; } diff --git a/UnityCore/ModelRowAdaptor.cpp b/UnityCore/ModelRowAdaptor.cpp index 644cf38c0..5f701400d 100644 --- a/UnityCore/ModelRowAdaptor.cpp +++ b/UnityCore/ModelRowAdaptor.cpp @@ -45,7 +45,14 @@ RowAdaptorBase& RowAdaptorBase::operator=(RowAdaptorBase const& other) return *this; } -std::string RowAdaptorBase::GetStringAt(int position) +void RowAdaptorBase::SetTarget(DeeModel* model, DeeModelIter* iter, DeeModelTag* tag) +{ + model_ = model; + iter_ = iter; + tag_ = tag; +} + +std::string RowAdaptorBase::GetStringAt(int position) const { if (!model_ || !iter_) return ""; @@ -56,28 +63,28 @@ std::string RowAdaptorBase::GetStringAt(int position) return ""; // std::strings don't like null. } -bool RowAdaptorBase::GetBoolAt(int position) +bool RowAdaptorBase::GetBoolAt(int position) const { if (!model_ || !iter_) return 0; return dee_model_get_bool(model_, iter_, position); } -int RowAdaptorBase::GetIntAt(int position) +int RowAdaptorBase::GetIntAt(int position) const { if (!model_ || !iter_) return 0; return dee_model_get_int32(model_, iter_, position); } -unsigned int RowAdaptorBase::GetUIntAt(int position) +unsigned int RowAdaptorBase::GetUIntAt(int position) const { if (!model_ || !iter_) return 0; return dee_model_get_uint32(model_, iter_, position); } -float RowAdaptorBase::GetFloatAt(int position) +float RowAdaptorBase::GetFloatAt(int position) const { if (!model_ || !iter_) return 0.0; diff --git a/UnityCore/ModelRowAdaptor.h b/UnityCore/ModelRowAdaptor.h index 4747d4e84..b4fc929b4 100644 --- a/UnityCore/ModelRowAdaptor.h +++ b/UnityCore/ModelRowAdaptor.h @@ -52,11 +52,13 @@ public: RowAdaptorBase(RowAdaptorBase const& other); RowAdaptorBase& operator=(RowAdaptorBase const& other); - std::string GetStringAt(int position); - bool GetBoolAt(int position); - int GetIntAt(int position); - unsigned int GetUIntAt(int position); - float GetFloatAt(int position); + std::string GetStringAt(int position) const; + bool GetBoolAt(int position) const; + int GetIntAt(int position) const; + unsigned int GetUIntAt(int position) const; + float GetFloatAt(int position) const; + + void SetTarget(DeeModel* model, DeeModelIter* iter, DeeModelTag* tag); template<typename T> void set_renderer(T renderer); diff --git a/UnityCore/Preview.cpp b/UnityCore/Preview.cpp index 6f8b6bfff..3c9342994 100644 --- a/UnityCore/Preview.cpp +++ b/UnityCore/Preview.cpp @@ -177,7 +177,8 @@ Preview::Impl::Impl(Preview* owner, glib::Object<GObject> const& proto_obj) actions_list_.push_back(std::make_shared<Action>( raw_action->id, raw_action->display_name, raw_action->icon_hint, - static_cast<LayoutHint>(raw_action->layout_hint))); + static_cast<LayoutHint>(raw_action->layout_hint), + raw_action->hints)); } int info_hints_len; diff --git a/UnityCore/Preview.h b/UnityCore/Preview.h index 1b43b1033..b9b1f5f4f 100644 --- a/UnityCore/Preview.h +++ b/UnityCore/Preview.h @@ -59,16 +59,31 @@ public: std::string id; std::string display_name; std::string icon_hint; + std::string extra_text; LayoutHint layout_hint; // TODO: there's also a HashTable here (although unused atm) Action() {}; Action(const gchar* id_, const gchar* display_name_, - const gchar* icon_hint_, LayoutHint layout_hint_) + const gchar* icon_hint_, LayoutHint layout_hint_, + GHashTable* hints) : id(id_ != NULL ? id_ : "") , display_name(display_name_ != NULL ? display_name_ : "") , icon_hint(icon_hint_ != NULL ? icon_hint_ : "") - , layout_hint(layout_hint_) {}; + , layout_hint(layout_hint_) + { + GHashTableIter iter; + gpointer key, value; + g_hash_table_iter_init(&iter, hints); + while (g_hash_table_iter_next(&iter, &key, &value)) + { + if (g_strcmp0((gchar*)key, "extra-text") == 0) + { + glib::Variant val(static_cast<GVariant*>(value)); + extra_text = val.GetString(); + } + } + }; }; struct InfoHint diff --git a/UnityCore/ResultIterator.cpp b/UnityCore/ResultIterator.cpp index aa569e952..46592f97d 100644 --- a/UnityCore/ResultIterator.cpp +++ b/UnityCore/ResultIterator.cpp @@ -34,7 +34,6 @@ ResultIterator::ResultIterator(glib::Object<DeeModel> model) , iter_(model ? dee_model_get_first_iter(model) : NULL) , tag_(NULL) , iter_result_(model_, iter_, tag_) - , cache_invalidated_(false) { } @@ -43,7 +42,6 @@ ResultIterator::ResultIterator(glib::Object<DeeModel> model, DeeModelIter* iter, , iter_(iter) , tag_(tag) , iter_result_(model_, iter_, tag_) - , cache_invalidated_(false) { } @@ -57,8 +55,7 @@ ResultIterator& ResultIterator::operator=(ResultIterator const& rhs) model_ = rhs.model_; iter_ = rhs.iter_; tag_ = rhs.tag_; - iter_result_ = Result(model_, iter_, tag_); - cache_invalidated_ = false; + iter_result_.SetTarget(model_, iter_, tag_); return *this; } @@ -66,7 +63,6 @@ ResultIterator& ResultIterator::operator=(ResultIterator const& rhs) ResultIterator& ResultIterator::operator++() { iter_ = dee_model_next(model_, iter_); - cache_invalidated_ = true; return *this; } @@ -78,7 +74,6 @@ ResultIterator& ResultIterator::operator+=(int count) for (int index = 0; index < count; index++) iter_ = dee_model_next(model_, iter_); - cache_invalidated_ = true; return *this; } @@ -99,7 +94,6 @@ ResultIterator ResultIterator::operator+(int count) const ResultIterator& ResultIterator::operator--() { iter_ = dee_model_prev(model_, iter_); - cache_invalidated_ = true; return *this; } @@ -111,7 +105,6 @@ ResultIterator& ResultIterator::operator-=(int count) for (int index = 0; index < count; index++) iter_ = dee_model_prev(model_, iter_); - cache_invalidated_ = true; return *this; } @@ -131,8 +124,7 @@ ResultIterator ResultIterator::operator-(int count) const Result& ResultIterator::operator*() { - if (cache_invalidated_) - iter_result_ = Result(model_, iter_, tag_); + iter_result_.SetTarget(model_, iter_, tag_); return iter_result_; } diff --git a/UnityCore/ResultIterator.h b/UnityCore/ResultIterator.h index 402357390..8e7f4636b 100644 --- a/UnityCore/ResultIterator.h +++ b/UnityCore/ResultIterator.h @@ -37,7 +37,7 @@ class ResultIterator : public std::iterator<std::random_access_iterator_tag, Res public: ResultIterator(glib::Object<DeeModel> model); ResultIterator(glib::Object<DeeModel> model, DeeModelIter* iter_, DeeModelTag* tag); - ResultIterator(ResultIterator const& copy) : model_(copy.model_), iter_(copy.iter_), tag_(copy.tag_), iter_result_(copy.iter_result_), cache_invalidated_(false){}; + ResultIterator(ResultIterator const& copy) : model_(copy.model_), iter_(copy.iter_), tag_(copy.tag_), iter_result_(copy.iter_result_){}; ResultIterator& operator=(ResultIterator const& rhs); @@ -93,7 +93,6 @@ private: DeeModelIter* iter_; DeeModelTag* tag_; Result iter_result_; - bool cache_invalidated_; }; } diff --git a/dash/CoverflowResultView.cpp b/dash/CoverflowResultView.cpp index c73b4e109..8d40cb00b 100755 --- a/dash/CoverflowResultView.cpp +++ b/dash/CoverflowResultView.cpp @@ -161,11 +161,12 @@ CoverflowResultView::Impl::Impl(CoverflowResultView *parent) ubus_.RegisterInterest(UBUS_DASH_PREVIEW_NAVIGATION_REQUEST, [&] (GVariant* data) { int nav_mode = 0; - gchar* uri = NULL; - gchar* proposed_unique_id = NULL; + glib::String uri; + glib::String proposed_unique_id; + g_variant_get(data, "(iss)", &nav_mode, &uri, &proposed_unique_id); - if (std::string(proposed_unique_id) != parent_->unique_id()) + if (proposed_unique_id.Str() != parent_->unique_id()) return; unsigned num_results = coverflow_->model()->Items().size(); @@ -192,10 +193,6 @@ CoverflowResultView::Impl::Impl(CoverflowResultView *parent) ubus_.SendMessage(UBUS_DASH_PREVIEW_INFO_PAYLOAD, g_variant_new("(iii)", 0, left_results, right_results)); } - - g_free(uri); - g_free(proposed_unique_id); - }); } diff --git a/dash/DashController.cpp b/dash/DashController.cpp index ed80001e1..7cba3e165 100644 --- a/dash/DashController.cpp +++ b/dash/DashController.cpp @@ -20,6 +20,7 @@ #include <NuxCore/Logger.h> #include <Nux/HLayout.h> +#include <UnityCore/GLibWrapper.h> #include "unity-shared/UnitySettings.h" #include "unity-shared/PanelStyle.h" @@ -38,8 +39,22 @@ namespace { nux::logging::Logger logger("unity.dash.controller"); const unsigned int PRELOAD_TIMEOUT_LENGTH = 40; + +const std::string DBUS_PATH = "/com/canonical/Unity/Dash"; +const std::string DBUS_INTROSPECTION =\ + "<node>" + " <interface name='com.canonical.Unity.Dash'>" + "" + " <method name='HideDash'>" + " </method>" + "" + " </interface>" + "</node>"; } +GDBusInterfaceVTable Controller::interface_vtable = + { Controller::OnDBusMethodCall, NULL, NULL}; + Controller::Controller() : launcher_width(64) , use_primary(false) @@ -49,6 +64,7 @@ Controller::Controller() , view_(nullptr) , ensure_timeout_(PRELOAD_TIMEOUT_LENGTH) , timeline_animator_(90) + , dbus_connect_cancellable_(g_cancellable_new()) { SetupRelayoutCallbacks(); RegisterUBusInterests(); @@ -70,6 +86,13 @@ Controller::Controller() auto spread_cb = sigc::bind(sigc::mem_fun(this, &Controller::HideDash), true); PluginAdapter::Default()->initiate_spread.connect(spread_cb); + + g_bus_get (G_BUS_TYPE_SESSION, dbus_connect_cancellable_, OnBusAcquired, this); +} + +Controller::~Controller() +{ + g_cancellable_cancel(dbus_connect_cancellable_); } void Controller::SetupWindow() @@ -171,7 +194,7 @@ int Controller::GetIdealMonitor() { UScreen *uscreen = UScreen::GetDefault(); int primary_monitor; - if (visible_) + if (window_->IsVisible()) primary_monitor = monitor_; else if (use_primary) primary_monitor = uscreen->GetPrimaryMonitor(); @@ -261,17 +284,8 @@ void Controller::ShowDash() return; } - /* GetIdealMonitor must get called before visible_ is set */ monitor_ = GetIdealMonitor(); - // The launcher must receive UBUS_OVERLAY_SHOW before window_->EnableInputWindow(). - // Other wise the Launcher gets focus for X, which causes XIM to fail. - sources_.AddIdle([this] { - GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_); - ubus_manager_.SendMessage(UBUS_OVERLAY_SHOWN, info); - return false; - }); - view_->AboutToShow(); window_->ShowWindow(true); @@ -288,6 +302,9 @@ void Controller::ShowDash() visible_ = true; StartShowHideTimeline(); + + GVariant* info = g_variant_new(UBUS_OVERLAY_FORMAT_STRING, "dash", TRUE, monitor_); + ubus_manager_.SendMessage(UBUS_OVERLAY_SHOWN, info); } void Controller::HideDash(bool restore) @@ -377,6 +394,57 @@ void Controller::AddProperties(GVariantBuilder* builder) .add("monitor", monitor_); } +bool Controller::IsVisible() const +{ + return visible_; +} + +void Controller::OnBusAcquired(GObject *obj, GAsyncResult *result, gpointer user_data) +{ + glib::Error error; + glib::Object<GDBusConnection> connection(g_bus_get_finish (result, &error)); + + if (!connection || error) + { + LOG_WARNING(logger) << "Failed to connect to DBus:" << error; + } + else + { + GDBusNodeInfo* introspection_data = g_dbus_node_info_new_for_xml(DBUS_INTROSPECTION.c_str(), nullptr); + unsigned int reg_id; + + if (!introspection_data) + { + LOG_WARNING(logger) << "No introspection data loaded."; + return; + } + + reg_id = g_dbus_connection_register_object(connection, DBUS_PATH.c_str(), + introspection_data->interfaces[0], + &interface_vtable, user_data, + nullptr, nullptr); + if (!reg_id) + { + LOG_WARNING(logger) << "Object registration failed. Dash DBus interface not available."; + } + + g_dbus_node_info_unref(introspection_data); + } +} + +void Controller::OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, + const gchar* object_path, const gchar* interface_name, + const gchar* method_name, GVariant* parameters, + GDBusMethodInvocation* invocation, gpointer user_data) +{ + if (g_strcmp0(method_name, "HideDash") == 0) + { + auto self = static_cast<Controller*>(user_data); + self->HideDash(); + g_dbus_method_invocation_return_value(invocation, nullptr); + } +} + } } diff --git a/dash/DashController.h b/dash/DashController.h index a03745782..d6854d5f8 100644 --- a/dash/DashController.h +++ b/dash/DashController.h @@ -45,6 +45,7 @@ public: typedef std::shared_ptr<Controller> Ptr; Controller(); + ~Controller(); nux::BaseWindow* window() const; @@ -58,6 +59,8 @@ public: void HideDash(bool restore_focus = true); + bool IsVisible() const; + protected: std::string GetName() const; void AddProperties(GVariantBuilder* builder); @@ -84,6 +87,12 @@ private: void StartShowHideTimeline(); void OnViewShowHideFrame(double progress); + static void OnBusAcquired(GObject *obj, GAsyncResult *result, gpointer user_data); + static void OnDBusMethodCall(GDBusConnection* connection, const gchar* sender, + const gchar* object_path, const gchar* interface_name, + const gchar* method_name, GVariant* parameters, + GDBusMethodInvocation* invocation, gpointer user_data); + static void OnWindowConfigure(int width, int height, nux::Geometry& geo, void* data); private: @@ -97,9 +106,11 @@ private: sigc::connection screen_ungrabbed_slot_; glib::SignalManager sig_manager_; glib::TimeoutSeconds ensure_timeout_; - glib::SourceManager sources_; Animator timeline_animator_; UBusManager ubus_manager_; + unsigned int dbus_owner_; + glib::Object<GCancellable> dbus_connect_cancellable_; + static GDBusInterfaceVTable interface_vtable; }; diff --git a/dash/DashView.cpp b/dash/DashView.cpp index 171d61368..2f48005a8 100644 --- a/dash/DashView.cpp +++ b/dash/DashView.cpp @@ -382,7 +382,7 @@ nux::Geometry DashView::GetBestFitGeometry(nux::Geometry const& for_geo) height = search_bar_->GetGeometry().height; height += tile_height * 3; - height += (style.GetPlacesGroupTopSpace() - 2 + 24 + 8) * 3; // adding three group headers + height += (style.GetPlacesGroupTopSpace() - 2 + 24 + 2) * 3; // adding three group headers height += 1*2; // hseparator height height += style.GetDashViewTopPadding(); height += lens_bar_->GetGeometry().height; diff --git a/dash/FilterBar.cpp b/dash/FilterBar.cpp index 752d7d547..8493fb772 100644 --- a/dash/FilterBar.cpp +++ b/dash/FilterBar.cpp @@ -82,8 +82,6 @@ void FilterBar::AddFilter(Filter::Ptr const& filter) AddChild(filter_view); filter_map_[filter] = filter_view; GetLayout()->AddView(filter_view, 0, nux::MINOR_POSITION_LEFT, nux::MINOR_SIZE_FULL); - - UpdateDrawSeparators(); } void FilterBar::RemoveFilter(Filter::Ptr const& filter) @@ -99,8 +97,6 @@ void FilterBar::RemoveFilter(Filter::Ptr const& filter) break; } } - - UpdateDrawSeparators(); } void FilterBar::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) @@ -120,24 +116,6 @@ void FilterBar::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) GfxContext.PopClippingRectangle(); } -void FilterBar::UpdateDrawSeparators() -{ - std::list<Area*> children = GetLayout()->GetChildren(); - std::list<Area*>::reverse_iterator rit; - bool found_one = false; - - for (rit = children.rbegin(); rit != children.rend(); ++rit) - { - FilterExpanderLabel* widget = dynamic_cast<FilterExpanderLabel*>(*rit); - - if (!widget) - continue; - - widget->draw_separator = found_one; - found_one = true; - } -} - // // Key navigation // diff --git a/dash/FilterBar.h b/dash/FilterBar.h index b36c6b02f..56e0bb459 100644 --- a/dash/FilterBar.h +++ b/dash/FilterBar.h @@ -60,7 +60,6 @@ protected: private: void Init(); - void UpdateDrawSeparators(); FilterFactory factory_; Filters::Ptr filters_; diff --git a/dash/FilterExpanderLabel.cpp b/dash/FilterExpanderLabel.cpp index 8d47b000a..7f26e8d8b 100644 --- a/dash/FilterExpanderLabel.cpp +++ b/dash/FilterExpanderLabel.cpp @@ -33,7 +33,7 @@ const float EXPAND_DEFAULT_ICON_OPACITY = 1.0f; const int EXPANDER_LAYOUT_SPACE_BETWEEN_CHILDREN = 8; // font -const char* const FONT_EXPANDER_LABEL = "Ubuntu Bold 13"; // 17px = 13 +const char* const FONT_EXPANDER_LABEL = "Ubuntu 13"; // 17px = 13 class ExpanderView : public nux::View { diff --git a/dash/LensBar.cpp b/dash/LensBar.cpp index 0fefc0de2..7b0bb1f99 100644 --- a/dash/LensBar.cpp +++ b/dash/LensBar.cpp @@ -31,7 +31,9 @@ namespace nux::logging::Logger logger("unity.dash.lensbar"); -const int LENSBAR_HEIGHT = 44; +// according to Q design the inner area of the lensbar should be 40px +// (without any borders) +const int LENSBAR_HEIGHT = 41; } diff --git a/dash/LensView.cpp b/dash/LensView.cpp index 2e8ab0903..a8e425e60 100755 --- a/dash/LensView.cpp +++ b/dash/LensView.cpp @@ -147,7 +147,14 @@ LensView::LensView(Lens::Ptr lens, nux::Area* show_filters) lens_->connected.changed.connect([&](bool is_connected) { if (is_connected) initial_activation_ = true; }); lens_->categories_reordered.connect(sigc::mem_fun(this, &LensView::OnCategoryOrderChanged)); search_string.SetGetterFunction(sigc::mem_fun(this, &LensView::get_search_string)); - filters_expanded.changed.connect([&](bool expanded) { fscroll_view_->SetVisible(expanded); QueueRelayout(); OnColumnsChanged(); }); + filters_expanded.changed.connect([&](bool expanded) + { + fscroll_view_->SetVisible(expanded); + QueueRelayout(); + OnColumnsChanged(); + ubus_manager_.SendMessage(UBUS_REFINE_STATUS, + g_variant_new(UBUS_REFINE_STATUS_FORMAT_STRING, expanded ? TRUE : FALSE)); + }); view_type.changed.connect(sigc::mem_fun(this, &LensView::OnViewTypeChanged)); ubus_manager_.RegisterInterest(UBUS_RESULT_VIEW_KEYNAV_CHANGED, [&] (GVariant* data) { @@ -189,10 +196,15 @@ void LensView::SetupViews(nux::Area* show_filters) scroll_view_ = new LensScrollView(new PlacesVScrollBar(NUX_TRACKER_LOCATION), NUX_TRACKER_LOCATION); - scroll_view_->EnableVerticalScrollBar(true); + scroll_view_->EnableVerticalScrollBar(false); scroll_view_->EnableHorizontalScrollBar(false); layout_->AddView(scroll_view_); + scroll_view_->OnGeometryChanged.connect([this] (nux::Area *area, nux::Geometry& geo) + { + CheckScrollBarState(); + }); + scroll_layout_ = new nux::VLayout(NUX_TRACKER_LOCATION); scroll_view_->SetLayout(scroll_layout_); scroll_view_->SetRightArea(show_filters); @@ -313,12 +325,15 @@ void LensView::OnCategoryAdded(Category const& category) 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); @@ -385,6 +400,8 @@ void LensView::OnCategoryAdded(Category const& category) scroll_layout_->AddView(group, 0, nux::MinorDimensionPosition::eAbove, nux::MinorDimensionSize::eFull, 100.0f, (nux::LayoutPosition)index); + + group->SetMinimumWidth(GetGeometry().width); } void LensView::OnCategoryOrderChanged() @@ -440,6 +457,8 @@ ResultViewGrid* LensView::GetGridForCategory(unsigned category_index) 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; @@ -453,9 +472,16 @@ void LensView::OnResultAdded(Result const& result) CheckNoResults(Lens::Hints()); } - // Check if all results so far are from one category - // If so, then expand that category. - CheckCategoryExpansion(); + 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) @@ -612,6 +638,20 @@ void LensView::OnGroupExpanded(PlacesGroup* group) ResultViewGrid* grid = static_cast<ResultViewGrid*>(group->GetChildView()); grid->expanded = group->GetExpanded(); ubus_manager_.SendMessage(UBUS_PLACE_VIEW_QUEUE_DRAW); + + CheckScrollBarState(); +} + +void LensView::CheckScrollBarState() +{ + if (scroll_layout_->GetGeometry().height > scroll_view_->GetGeometry().height) + { + scroll_view_->EnableVerticalScrollBar(true); + } + else + { + scroll_view_->EnableVerticalScrollBar(false); + } } void LensView::OnColumnsChanged() diff --git a/dash/LensView.h b/dash/LensView.h index 7dbe940d4..1453f96fc 100644 --- a/dash/LensView.h +++ b/dash/LensView.h @@ -88,6 +88,7 @@ private: void OnResultRemoved(Result const& result); void UpdateCounts(PlacesGroup* group); void OnGroupExpanded(PlacesGroup* group); + void CheckScrollBarState(); void OnColumnsChanged(); void OnFilterAdded(Filter::Ptr filter); void OnFilterRemoved(Filter::Ptr filter); @@ -126,6 +127,7 @@ private: UBusManager ubus_manager_; glib::Source::UniquePtr fix_rendering_idle_; + glib::Source::UniquePtr model_updated_timeout_; int last_good_filter_model_; glib::Source::UniquePtr fix_filter_models_idle_; }; diff --git a/dash/PlacesGroup.cpp b/dash/PlacesGroup.cpp index 76ffcd869..76de3fd48 100755 --- a/dash/PlacesGroup.cpp +++ b/dash/PlacesGroup.cpp @@ -58,6 +58,7 @@ namespace const nux::Color kExpandDefaultTextColor(1.0f, 1.0f, 1.0f, 0.5f); const float kExpandDefaultIconOpacity = 0.5f; +const int kCategoryIconSize = 22; // Category highlight const int kHighlightHeight = 24; const int kHighlightRightPadding = 10 - 3; // -3 because the scrollbar is not a real overlay scrollbar! @@ -114,7 +115,7 @@ NUX_IMPLEMENT_OBJECT_TYPE(PlacesGroup); PlacesGroup::PlacesGroup() : AbstractPlacesGroup(), _child_view(nullptr), - _is_expanded(true), + _is_expanded(false), _n_visible_items_in_unexpand_mode(0), _n_total_items(0), _category_index(0), @@ -127,6 +128,21 @@ PlacesGroup::PlacesGroup() SetAcceptKeyNavFocusOnMouseEnter(false); nux::BaseTexture* arrow = style.GetGroupUnexpandIcon(); + + _background = style.GetCategoryBackground(); + _background_nofilters = style.GetCategoryBackgroundNoFilters(); + + nux::ROPConfig rop; + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + nux::TexCoordXForm texxform; + _background_layer.reset(new nux::TextureLayer(_background_nofilters->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); _group_layout = new nux::VLayout("", NUX_TRACKER_LOCATION); @@ -142,8 +158,8 @@ PlacesGroup::PlacesGroup() _header_layout->SetSpaceBetweenChildren(10); _header_view->SetLayout(_header_layout); - _icon = new IconTexture("", 24); - _icon->SetMinMaxSize(24, 24); + _icon = new IconTexture("", kCategoryIconSize); + _icon->SetMinMaxSize(kCategoryIconSize, kCategoryIconSize); _header_layout->AddView(_icon, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); _text_layout = new nux::HLayout(NUX_TRACKER_LOCATION); @@ -176,15 +192,6 @@ PlacesGroup::PlacesGroup() _expand_icon->SetVisible(false); _expand_layout->AddView(_expand_icon, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FIX); - separator_layout_ = new nux::HLayout(); - separator_layout_->SetLeftAndRightPadding(style.GetCategorySeparatorLeftPadding(), - style.GetCategorySeparatorRightPadding() - style.GetScrollbarWidth()); - - separator_ = new HSeparator; - separator_layout_->AddView(separator_, 1); - - draw_separator.changed.connect(sigc::mem_fun(this, &PlacesGroup::DrawSeparatorChanged)); - SetLayout(_group_layout); // don't need to disconnect these signals as they are disconnected when this object destroys the contents @@ -206,15 +213,40 @@ PlacesGroup::PlacesGroup() else nux::GetWindowCompositor().SetKeyFocusArea(GetHeaderFocusableView(), direction); }); -} -void PlacesGroup::DrawSeparatorChanged(bool draw) -{ - if (draw and !separator_layout_->IsChildOf(_group_layout)) - _group_layout->AddView(separator_layout_.GetPointer(), 0); - else if (!draw and separator_layout_->IsChildOf(_group_layout)) - _group_layout->RemoveChildObject(separator_layout_.GetPointer()); - QueueDraw(); + _ubus.RegisterInterest(UBUS_REFINE_STATUS, [this] (GVariant *data) + { + gboolean status; + g_variant_get(data, UBUS_REFINE_STATUS_FORMAT_STRING, &status); + + nux::ROPConfig rop; + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + nux::TexCoordXForm texxform; + if (status && _using_nofilters_background) + { + _background_layer.reset(new nux::TextureLayer(_background->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + _using_nofilters_background = false; + } + else if (!status && !_using_nofilters_background) + { + _background_layer.reset(new nux::TextureLayer(_background_nofilters->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + + _using_nofilters_background = true; + } + QueueDraw(); + }); + } void @@ -252,7 +284,7 @@ PlacesGroup::SetRendererName(const char *renderer_name) if (g_strcmp0(renderer_name, "tile-horizontal") == 0) (static_cast<dash::ResultView*>(_child_view))->SetModelRenderer(new dash::ResultRendererHorizontalTile(NUX_TRACKER_LOCATION)); - else + else if (g_strcmp0(renderer_name, "tile-vertical") == 0) (static_cast<dash::ResultView*>(_child_view))->SetModelRenderer(new dash::ResultRendererTile(NUX_TRACKER_LOCATION)); } @@ -277,7 +309,7 @@ PlacesGroup::GetExpandLabel() void PlacesGroup::SetIcon(std::string const& path_to_emblem) { - _icon->SetByIconName(path_to_emblem, 24); + _icon->SetByIconName(path_to_emblem, kCategoryIconSize); } void @@ -298,7 +330,7 @@ PlacesGroup::SetChildView(dash::ResultView* view) layout->AddView(_child_view, 0); layout->SetLeftAndRightPadding(25, 0); - _group_layout->AddLayout(new nux::SpaceLayout(8,8,8,8), 0); // top padding + _group_layout->AddLayout(new nux::SpaceLayout(2,2,2,2), 0); // top padding _group_layout->AddLayout(layout, 1); view->results_per_row.changed.connect([&] (int results_per_row) @@ -395,6 +427,8 @@ PlacesGroup::OnIdleRelayout() { if (GetChildView()) { + + Refresh(); QueueDraw(); _group_layout->QueueDraw(); @@ -416,10 +450,8 @@ long PlacesGroup::ComputeContentSize() if (_cached_geometry.GetWidth() != geo.GetWidth()) { _focus_layer.reset(dash::Style::Instance().FocusOverlay(geo.width - kHighlightLeftPadding - kHighlightRightPadding, kHighlightHeight)); - _cached_geometry = geo; } - return ret; } @@ -429,6 +461,7 @@ void PlacesGroup::Draw(nux::GraphicsEngine& graphics_engine, nux::Geometry const& base = GetGeometry(); graphics_engine.PushClippingRectangle(base); + if (ShouldBeHighlighted()) { nux::Geometry geo(_header_layout->GetGeometry()); @@ -439,6 +472,20 @@ void PlacesGroup::Draw(nux::GraphicsEngine& graphics_engine, _focus_layer->Renderlayer(graphics_engine); } + nux::Geometry bg_geo = GetGeometry(); + int bg_width = 0; + if (_using_nofilters_background) + bg_width = _background_nofilters->GetWidth(); + else + bg_width = _background->GetWidth(); + + bg_geo.x = std::max(bg_geo.width - bg_width,0); + + bg_geo.width = std::min(bg_width, bg_geo.GetWidth()) + 1; // to render into a space left over by the scrollview + bg_geo.height = _background->GetHeight(); + + _background_layer->SetGeometry(bg_geo); + _background_layer->Renderlayer(graphics_engine); graphics_engine.PopClippingRectangle(); } @@ -448,7 +495,24 @@ PlacesGroup::DrawContent(nux::GraphicsEngine& graphics_engine, bool force_draw) nux::Geometry const& base = GetGeometry(); graphics_engine.PushClippingRectangle(base); + nux::Geometry bg_geo = GetGeometry(); + + int bg_width = 0; + if (_using_nofilters_background) + bg_width = _background_nofilters->GetWidth(); + else + bg_width = _background->GetWidth(); + + // if the dash is smaller, resize to fit, otherwise move to the right edge + bg_geo.x = std::max(bg_geo.width - bg_width, 0); + bg_geo.width = std::min(bg_width, bg_geo.GetWidth()) + 1; // to render into a space left over by the scrollview + + bg_geo.height = _background->GetHeight(); + if (!IsFullRedraw()) + { + nux::GetPainter().PushLayer(graphics_engine, bg_geo, _background_layer.get()); + } if (ShouldBeHighlighted() && !IsFullRedraw() && _focus_layer) { nux::GetPainter().PushLayer(graphics_engine, _focus_layer->GetGeometry(), _focus_layer.get()); diff --git a/dash/PlacesGroup.h b/dash/PlacesGroup.h index acabd48f7..c35969b04 100644 --- a/dash/PlacesGroup.h +++ b/dash/PlacesGroup.h @@ -123,8 +123,6 @@ private: nux::HLayout* _expand_label_layout; nux::HLayout* _expand_layout; nux::View* _child_view; - nux::ObjectPtr<nux::HLayout> separator_layout_; - HSeparator* separator_; std::unique_ptr<nux::AbstractPaintLayer> _focus_layer; IconTexture* _icon; @@ -132,12 +130,16 @@ private: nux::StaticCairoText* _expand_label; IconTexture* _expand_icon; + nux::BaseTexture* _background; + nux::BaseTexture* _background_nofilters; + bool _using_nofilters_background; + std::unique_ptr<nux::AbstractPaintLayer> _background_layer; + bool _is_expanded; unsigned _n_visible_items_in_unexpand_mode; unsigned _n_total_items; unsigned _category_index; std::string _cached_name; - bool _draw_sep; nux::Geometry _cached_geometry; std::string _renderer_name; diff --git a/dash/ResultRendererTile.cpp b/dash/ResultRendererTile.cpp index cbe627d7f..0729c27c3 100644 --- a/dash/ResultRendererTile.cpp +++ b/dash/ResultRendererTile.cpp @@ -53,6 +53,8 @@ namespace nux::logging::Logger logger("unity.dash.results"); const int FONT_SIZE = 10; + +const float CORNER_HIGHTLIGHT_RADIUS = 2.0f; } namespace dash @@ -62,7 +64,6 @@ NUX_IMPLEMENT_OBJECT_TYPE(ResultRendererTile); ResultRendererTile::ResultRendererTile(NUX_FILE_LINE_DECL) : ResultRenderer(NUX_FILE_LINE_PARAM) - , highlight_padding(6) , spacing(10) , padding(6) { @@ -78,9 +79,8 @@ ResultRendererTile::ResultRendererTile(NUX_FILE_LINE_DECL) // pre-load the highlight texture // try and get a texture from the texture cache TextureCache& cache = TextureCache::GetDefault(); - int prelight_texture_size = style.GetTileIconSize() + (highlight_padding * 2); prelight_cache_ = cache.FindTexture("ResultRendererTile.PreLightTexture", - prelight_texture_size, prelight_texture_size, + style.GetTileIconHightlightWidth(), style.GetTileIconHightlightHeight(), sigc::mem_fun(this, &ResultRendererTile::DrawHighlight)); } @@ -99,7 +99,7 @@ void ResultRendererTile::Render(nux::GraphicsEngine& GfxContext, return; dash::Style& style = dash::Style::Instance(); - int tile_icon_size = style.GetTileIconSize(); + int tile_icon_size = style.GetTileImageSize(); // set up our texture mode nux::TexCoordXForm texxform; @@ -118,22 +118,14 @@ void ResultRendererTile::Render(nux::GraphicsEngine& GfxContext, int icon_left_hand_side = geometry.x + (geometry.width - icon_width) / 2; int icon_top_side = geometry.y + padding + (tile_icon_size - icon_height) / 2; - if (container->blurred_icon && state == ResultRendererState::RESULT_RENDERER_NORMAL) - { - GfxContext.QRP_1Tex(icon_left_hand_side - 5 - x_offset, - icon_top_side - 5 - y_offset, - container->blurred_icon->GetWidth(), - container->blurred_icon->GetHeight(), - container->blurred_icon->GetDeviceTexture(), - texxform, - nux::Color(0.15f, 0.15f, 0.15f, 0.15f)); - } - // render highlight if its needed if (container->prelight && state != ResultRendererState::RESULT_RENDERER_NORMAL) { - GfxContext.QRP_1Tex(icon_left_hand_side - highlight_padding, - icon_top_side - highlight_padding, + int highlight_x = (geometry.x + geometry.width/2) - style.GetTileIconHightlightWidth()/2; + int highlight_y = (geometry.y + padding + tile_icon_size / 2) - style.GetTileIconHightlightHeight()/2; + + GfxContext.QRP_1Tex(highlight_x, + highlight_y, container->prelight->GetWidth(), container->prelight->GetHeight(), container->prelight->GetDeviceTexture(), @@ -168,63 +160,27 @@ void ResultRendererTile::Render(nux::GraphicsEngine& GfxContext, nux::BaseTexture* ResultRendererTile::DrawHighlight(std::string const& texid, int width, int height) { nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, width, height); - cairo_t* cr = cairo_graphics.GetContext(); + cairo_t* cr = cairo_graphics.GetInternalContext(); + + cairo_scale(cr, 1.0f, 1.0f); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.0); cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); cairo_paint(cr); - int PADDING = 4; - int BLUR_SIZE = 5; - - int bg_width = width - PADDING - BLUR_SIZE; - int bg_height = height - PADDING - BLUR_SIZE; - int bg_x = BLUR_SIZE - 1; - int bg_y = BLUR_SIZE - 1; - - // draw the glow + // draw the highlight cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_line_width(cr, 1.0f); - cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 0.75f); + cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 0.2f); cairo_graphics.DrawRoundedRectangle(cr, - 1.0f, - bg_x, - bg_y, - 5.0, - bg_width, - bg_height, - true); + 1.0f, + 0.0f, + 0.0f, + CORNER_HIGHTLIGHT_RADIUS, + width, + height, + false); cairo_fill(cr); - cairo_graphics.BlurSurface(BLUR_SIZE - 2); - - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_graphics.DrawRoundedRectangle(cr, - 1.0, - bg_x, - bg_y, - 5.0, - bg_width, - bg_height, - true); - cairo_clip(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - cairo_graphics.DrawRoundedRectangle(cr, - 1.0, - bg_x, - bg_y, - 5.0, - bg_width, - bg_height, - true); - cairo_set_source_rgba(cr, 240 / 255.0f, 240 / 255.0f, 240 / 255.0f, 1.0f); - cairo_fill_preserve(cr); - - cairo_set_source_rgba(cr, 1.0f, 1.0f, 1.0f, 1.0); - cairo_stroke(cr); - - cairo_destroy(cr); - return texture_from_cairo_graphics(cairo_graphics); } @@ -248,12 +204,12 @@ void ResultRendererTile::Unload(Result& row) void ResultRendererTile::LoadIcon(Result& row) { Style& style = Style::Instance(); - std::string const& icon_hint = row.icon_hint; + std::string icon_hint(row.icon_hint); #define DEFAULT_GICON ". GThemedIcon text-x-preview" std::string icon_name; if (G_UNLIKELY(neko)) { - int tmp1 = style.GetTileIconSize() + (rand() % 16) - 8; + int tmp1 = style.GetTileGIconSize() + (rand() % 16) - 8; gsize tmp3; gchar* tmp2 = (gchar*)g_base64_decode("aHR0cDovL3BsYWNla2l0dGVuLmNvbS8laS8laS8=", &tmp3); gchar* tmp4 = g_strdup_printf(tmp2, tmp1, tmp1); @@ -266,26 +222,20 @@ void ResultRendererTile::LoadIcon(Result& row) icon_name = !icon_hint.empty() ? icon_hint : DEFAULT_GICON; } - GIcon* icon = g_icon_new_for_string(icon_name.c_str(), NULL); + glib::Object<GIcon> icon(g_icon_new_for_string(icon_name.c_str(), NULL)); TextureContainer* container = row.renderer<TextureContainer*>(); IconLoader::IconLoaderCallback slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), icon_hint, row); - if (g_strrstr(icon_name.c_str(), "://")) + if (icon.IsType(G_TYPE_ICON)) { - container->slot_handle = IconLoader::GetDefault().LoadFromURI(icon_name, style.GetTileIconSize(), slot); - } - else if (G_IS_ICON(icon)) - { - container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(icon_name, style.GetTileIconSize(), slot); + bool use_large_icon = icon.IsType(G_TYPE_FILE_ICON) || !icon.IsType(G_TYPE_THEMED_ICON); + container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(icon_name, style.GetTileImageSize(), use_large_icon ? style.GetTileImageSize() : style.GetTileGIconSize(), slot); } else { - container->slot_handle = IconLoader::GetDefault().LoadFromIconName(icon_name, style.GetTileIconSize(), slot); + container->slot_handle = IconLoader::GetDefault().LoadFromIconName(icon_name, -1, style.GetTileGIconSize(), slot); } - - if (icon != NULL) - g_object_unref(icon); } nux::BaseTexture* ResultRendererTile::CreateTextureCallback(std::string const& texid, @@ -318,7 +268,7 @@ nux::BaseTexture* ResultRendererTile::CreateTextureCallback(std::string const& t float aspect = static_cast<float>(pixbuf_height) / pixbuf_width; // already sanitized width/height so can not be 0.0 if (aspect < 1.0f) { - pixbuf_width = style.GetTileWidth() - (padding * 2); + pixbuf_width = style.GetTileImageSize(); pixbuf_height = pixbuf_width * aspect; if (pixbuf_height > height) @@ -363,68 +313,27 @@ nux::BaseTexture* ResultRendererTile::CreateTextureCallback(std::string const& t } -nux::BaseTexture* ResultRendererTile::CreateBlurredTextureCallback(std::string const& texid, - int width, - int height, - glib::Object<GdkPixbuf> const& pixbuf) -{ - int pixbuf_width, pixbuf_height; - pixbuf_width = gdk_pixbuf_get_width(pixbuf); - pixbuf_height = gdk_pixbuf_get_height(pixbuf); - - nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, width + 10, height + 10); - cairo_t* cr = cairo_graphics.GetInternalContext(); - - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_translate(cr, 5, 5); - cairo_paint(cr); - - float scale; - if (pixbuf_width > pixbuf_height) - scale = pixbuf_height / static_cast<float>(pixbuf_width); - else - scale = pixbuf_width / static_cast<float>(pixbuf_height); - - cairo_translate(cr, - static_cast<int>((width - (pixbuf_width * scale)) * 0.5), - static_cast<int>((height - (pixbuf_height * scale)) * 0.5)); - - cairo_scale(cr, scale, scale); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); - - cairo_paint(cr); - - cairo_graphics.BlurSurface(4); - - return texture_from_cairo_graphics(cairo_graphics); -} - void ResultRendererTile::IconLoaded(std::string const& texid, - unsigned size, + int max_width, + int max_height, glib::Object<GdkPixbuf> const& pixbuf, std::string icon_name, Result& row) { TextureContainer *container = row.renderer<TextureContainer*>(); - Style& style = Style::Instance(); + + dash::Style& style = dash::Style::Instance(); if (pixbuf && container) { TextureCache& cache = TextureCache::GetDefault(); - BaseTexturePtr texture(cache.FindTexture(icon_name, style.GetTileIconSize(), style.GetTileIconSize(), + BaseTexturePtr texture(cache.FindTexture(icon_name, max_width, max_height, sigc::bind(sigc::mem_fun(this, &ResultRendererTile::CreateTextureCallback), pixbuf))); - std::string blur_texid = icon_name + "_blurred"; - BaseTexturePtr texture_blurred(cache.FindTexture(blur_texid, style.GetTileIconSize(), style.GetTileIconSize(), - sigc::bind(sigc::mem_fun(this, &ResultRendererTile::CreateBlurredTextureCallback), pixbuf))); - - BaseTexturePtr texture_prelight(cache.FindTexture("resultview_prelight", texture->GetWidth() + highlight_padding*2, texture->GetHeight() + highlight_padding*2, sigc::mem_fun(this, &ResultRendererTile::DrawHighlight))); + BaseTexturePtr texture_prelight(cache.FindTexture("resultview_prelight", style.GetTileIconHightlightWidth(), style.GetTileIconHightlightHeight(), sigc::mem_fun(this, &ResultRendererTile::DrawHighlight))); container->icon = texture; - container->blurred_icon = texture_blurred; container->prelight = texture_prelight; NeedsRedraw.emit(); @@ -436,9 +345,8 @@ void ResultRendererTile::IconLoaded(std::string const& texid, { // we need to load a missing icon IconLoader::IconLoaderCallback slot = sigc::bind(sigc::mem_fun(this, &ResultRendererTile::IconLoaded), icon_name, row); - container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(". GThemedIcon text-x-preview", style.GetTileIconSize(), slot); + container->slot_handle = IconLoader::GetDefault().LoadFromGIconString(". GThemedIcon text-x-preview", max_width, max_height, slot); } - } @@ -447,7 +355,7 @@ void ResultRendererTile::LoadText(Result& row) Style& style = Style::Instance(); nux::CairoGraphics _cairoGraphics(CAIRO_FORMAT_ARGB32, style.GetTileWidth() - (padding * 2), - style.GetTileHeight() - style.GetTileIconSize() - spacing); + style.GetTileHeight() - style.GetTileImageSize() - spacing); cairo_t* cr = _cairoGraphics.GetContext(); diff --git a/dash/ResultRendererTile.h b/dash/ResultRendererTile.h index 165b60653..5f10f5b94 100644 --- a/dash/ResultRendererTile.h +++ b/dash/ResultRendererTile.h @@ -80,7 +80,6 @@ public: // unload any previous grabbed images virtual void Unload(Result& row); - int highlight_padding; int spacing; int padding; @@ -91,15 +90,12 @@ protected: nux::ObjectPtr<nux::BaseTexture> normal_cache_; private: //icon loading callbacks - void IconLoaded(std::string const& texid, unsigned size, + void IconLoaded(std::string const& texid, int max_width, int max_height, glib::Object<GdkPixbuf> const& pixbuf, std::string icon_name, Result& row); nux::BaseTexture* CreateTextureCallback(std::string const& texid, int width, int height, glib::Object<GdkPixbuf> const& pixbuf); - nux::BaseTexture* CreateBlurredTextureCallback(std::string const& texid, - int width, int height, - glib::Object<GdkPixbuf> const& pixbuf); nux::BaseTexture* DrawHighlight(std::string const& texid, int width, int height); }; diff --git a/dash/ResultView.cpp b/dash/ResultView.cpp index 679524dab..13effa95f 100644 --- a/dash/ResultView.cpp +++ b/dash/ResultView.cpp @@ -44,6 +44,7 @@ ResultView::ResultView(NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , expanded(true) , renderer_(NULL) + , cached_result_(nullptr, nullptr, nullptr) { expanded.changed.connect([&](bool value) { @@ -99,14 +100,14 @@ void ResultView::RemoveResult(Result& result) void ResultView::OnRowAdded(DeeModel* model, DeeModelIter* iter) { - Result result(model, iter, renderer_tag_); - AddResult(result); + cached_result_.SetTarget(model, iter, renderer_tag_); + AddResult(cached_result_); } void ResultView::OnRowRemoved(DeeModel* model, DeeModelIter* iter) { - Result result(model, iter, renderer_tag_); - RemoveResult(result); + cached_result_.SetTarget(model, iter, renderer_tag_); + RemoveResult(cached_result_); } void ResultView::SetModel(glib::Object<DeeModel> const& model, DeeModelTag* tag) diff --git a/dash/ResultView.h b/dash/ResultView.h index 91a840002..97c9c8796 100644 --- a/dash/ResultView.h +++ b/dash/ResultView.h @@ -91,6 +91,8 @@ protected: private: void OnRowAdded(DeeModel* model, DeeModelIter* iter); void OnRowRemoved(DeeModel* model, DeeModelIter* iter); + + Result cached_result_; }; } diff --git a/dash/previews/ActionButton.cpp b/dash/previews/ActionButton.cpp index 72f6d793e..fd940847a 100644 --- a/dash/previews/ActionButton.cpp +++ b/dash/previews/ActionButton.cpp @@ -29,7 +29,7 @@ namespace { -const int kMinButtonHeight = 36; +const int kMinButtonHeight = 34; const int kMinButtonWidth = 48; const int icon_size = 24; @@ -50,7 +50,7 @@ ActionButton::ActionButton(std::string const& action_hint, std::string const& la SetAcceptKeyNavFocusOnMouseDown(false); SetAcceptKeyNavFocusOnMouseEnter(false); Init(); - BuildLayout(label, icon_hint); + BuildLayout(label, icon_hint, ""); } ActionButton::~ActionButton() @@ -105,7 +105,19 @@ void ActionButton::InitTheme() SetMinimumWidth(kMinButtonWidth); } -void ActionButton::BuildLayout(std::string const& label, std::string const& icon_hint) +void ActionButton::SetExtraHint(std::string const& extra_hint, std::string const& font_hint) +{ + extra_font_hint_= font_hint; + if (extra_text_) + { + extra_text_->SetFont(extra_font_hint_); + ComputeContentSize(); + QueueDraw(); + } + BuildLayout(label_, icon_hint_, extra_hint); +} + +void ActionButton::BuildLayout(std::string const& label, std::string const& icon_hint, std::string const& extra_hint) { if (icon_hint != icon_hint_) { @@ -121,7 +133,7 @@ void ActionButton::BuildLayout(std::string const& label, std::string const& icon image_ = new IconTexture(icon_hint, icon_size); image_->texture_updated.connect([&](nux::BaseTexture*) { - BuildLayout(label_, icon_hint_); + BuildLayout(label_, icon_hint_, extra_hint_); }); image_->SetInputEventSensitivity(false); image_->SetMinMaxSize(icon_size, icon_size); @@ -147,16 +159,37 @@ void ActionButton::BuildLayout(std::string const& label, std::string const& icon } } + if (extra_hint != extra_hint_) + { + extra_hint_ = extra_hint; + if (extra_text_) + { + extra_text_.Release(); + extra_text_ = NULL; + } + + if (!extra_hint_.empty()) + { + extra_text_ = new nux::StaticCairoText(extra_hint_, true, NUX_TRACKER_LOCATION); + if (!extra_font_hint_.empty()) + extra_text_->SetFont(extra_font_hint_); + extra_text_->SetInputEventSensitivity(false); + extra_text_->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_CENTRE); + } + } + RemoveLayout(); nux::HLayout* layout = new nux::HLayout(); layout->SetHorizontalInternalMargin(6); - layout->SetPadding(2, 11, 2, 11); + layout->SetPadding(2, 0, 2, 0); layout->AddSpace(0,1); if (image_) layout->AddView(image_.GetPointer(), 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); if (static_text_) layout->AddView(static_text_.GetPointer(), 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); + if (extra_text_) + layout->AddView(extra_text_.GetPointer(), 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_MATCHCONTENT); layout->AddSpace(0,1); SetLayout(layout); @@ -302,5 +335,15 @@ void ActionButton::Deactivate() QueueDraw(); } +std::string ActionButton::GetLabel() const +{ + return label_; +} + +std::string ActionButton::GetExtraText() const +{ + return extra_hint_; +} + } // namespace dash } // namespace unity diff --git a/dash/previews/ActionButton.h b/dash/previews/ActionButton.h index 0abce4e67..a87193971 100644 --- a/dash/previews/ActionButton.h +++ b/dash/previews/ActionButton.h @@ -49,10 +49,14 @@ public: sigc::signal<void, ActionButton*, std::string const&> click; void SetFont(std::string const& font_hint); + void SetExtraHint(std::string const& extra_hint, std::string const& font_hint); void Activate(); void Deactivate(); + std::string GetLabel() const; + std::string GetExtraText() const; + protected: virtual long ComputeContentSize(); virtual void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); @@ -64,7 +68,7 @@ protected: void RedrawTheme(nux::Geometry const& geom, cairo_t* cr, nux::ButtonVisualState faked_state); void RedrawFocusOverlay(nux::Geometry const& geom, cairo_t* cr); - void BuildLayout(std::string const& label, std::string const& icon_hint); + void BuildLayout(std::string const& label, std::string const& icon_hint, std::string const& extra_hint); // From debug::Introspectable std::string GetName() const; @@ -83,9 +87,12 @@ private: std::string action_hint_; std::string icon_hint_; std::string font_hint_; + std::string extra_hint_; + std::string extra_font_hint_; nux::ObjectPtr<IconTexture> image_; nux::ObjectPtr<nux::StaticCairoText> static_text_; + nux::ObjectPtr<nux::StaticCairoText> extra_text_; }; } // namespace dash diff --git a/dash/previews/ApplicationPreview.cpp b/dash/previews/ApplicationPreview.cpp index 79841fe15..111005d50 100644 --- a/dash/previews/ApplicationPreview.cpp +++ b/dash/previews/ApplicationPreview.cpp @@ -50,7 +50,6 @@ namespace previews namespace { nux::logging::Logger logger("unity.dash.previews.applicationpreview"); - } class DetailsScrollView : public nux::ScrollView @@ -82,10 +81,12 @@ void ApplicationPreview::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + gfx_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfx_engine, base); - if (full_data_layout_) + if (enable_bg_shadows && full_data_layout_) { unsigned int alpha, src, dest = 0; gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); @@ -105,7 +106,9 @@ void ApplicationPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); - if (!IsFullRedraw()) + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PushLayer(gfx_engine, details_bg_layer_->GetGeometry(), details_bg_layer_.get()); unsigned int alpha, src, dest = 0; @@ -117,7 +120,7 @@ void ApplicationPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); - if (!IsFullRedraw()) + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PopBackground(); gfx_engine.PopClippingRectangle(); diff --git a/dash/previews/GenericPreview.cpp b/dash/previews/GenericPreview.cpp index b48ba6c13..6a0f1f6a8 100644 --- a/dash/previews/GenericPreview.cpp +++ b/dash/previews/GenericPreview.cpp @@ -77,10 +77,12 @@ void GenericPreview::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + gfx_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfx_engine, base); - if (full_data_layout_) + if (enable_bg_shadows && full_data_layout_) { unsigned int alpha, src, dest = 0; gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); @@ -100,7 +102,9 @@ void GenericPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_dra nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); - if (!IsFullRedraw()) + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PushLayer(gfx_engine, details_bg_layer_->GetGeometry(), details_bg_layer_.get()); unsigned int alpha, src, dest = 0; @@ -112,7 +116,7 @@ void GenericPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_dra gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); - if (!IsFullRedraw()) + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PopBackground(); gfx_engine.PopClippingRectangle(); diff --git a/dash/previews/MoviePreview.cpp b/dash/previews/MoviePreview.cpp index 261bdc4a9..3ec06b036 100644 --- a/dash/previews/MoviePreview.cpp +++ b/dash/previews/MoviePreview.cpp @@ -88,10 +88,12 @@ void MoviePreview::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + gfx_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfx_engine, base); - if (full_data_layout_) + if (enable_bg_shadows && full_data_layout_) { unsigned int alpha, src, dest = 0; gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); @@ -111,7 +113,9 @@ void MoviePreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); - if (!IsFullRedraw()) + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PushLayer(gfx_engine, details_bg_layer_->GetGeometry(), details_bg_layer_.get()); unsigned int alpha, src, dest = 0; @@ -123,7 +127,7 @@ void MoviePreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); - if (!IsFullRedraw()) + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PopBackground(); gfx_engine.PopClippingRectangle(); diff --git a/dash/previews/MusicPreview.cpp b/dash/previews/MusicPreview.cpp index 039b74152..40d82ccb0 100644 --- a/dash/previews/MusicPreview.cpp +++ b/dash/previews/MusicPreview.cpp @@ -69,10 +69,12 @@ void MusicPreview::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + gfx_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfx_engine, base); - if (full_data_layout_) + if (enable_bg_shadows && full_data_layout_) { unsigned int alpha, src, dest = 0; gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); @@ -92,7 +94,9 @@ void MusicPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); - if (!IsFullRedraw()) + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PushLayer(gfx_engine, details_bg_layer_->GetGeometry(), details_bg_layer_.get()); unsigned int alpha, src, dest = 0; @@ -104,7 +108,7 @@ void MusicPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); - if (!IsFullRedraw()) + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PopBackground(); gfx_engine.PopClippingRectangle(); diff --git a/dash/previews/Preview.cpp b/dash/previews/Preview.cpp index 1185accf3..b7d4d9463 100644 --- a/dash/previews/Preview.cpp +++ b/dash/previews/Preview.cpp @@ -136,6 +136,8 @@ nux::Layout* Preview::BuildGridActionsLayout(dash::Preview::ActionPtrList action dash::Preview::ActionPtr action = actions[action_iter]; ActionButton* 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()); AddChild(button); button->click.connect(sigc::mem_fun(this, &Preview::OnActionActivated)); buttons.push_back(button); @@ -165,9 +167,11 @@ nux::Layout* Preview::BuildVerticalActionsLayout(dash::Preview::ActionPtrList ac uint action_iter = 0; for (uint i = 0; i < actions.size(); i++) { - dash::Preview::ActionPtr action = actions[action_iter]; + dash::Preview::ActionPtr action = actions[action_iter++]; ActionButton* 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()); AddChild(button); button->click.connect(sigc::mem_fun(this, &Preview::OnActionActivated)); buttons.push_back(button); diff --git a/dash/previews/PreviewContainer.cpp b/dash/previews/PreviewContainer.cpp index 54cc3bf99..3bca735c3 100644 --- a/dash/previews/PreviewContainer.cpp +++ b/dash/previews/PreviewContainer.cpp @@ -62,6 +62,7 @@ public: PreviewContent(PreviewContainer*const parent) : parent_(parent) , progress_(0.0) + , curve_progress_(0.0) , animating_(false) , waiting_preview_(false) , rotation_(0.0) @@ -69,6 +70,11 @@ public: , nav_complete_(0) , relative_nav_index_(0) { + OnGeometryChanged.connect([&](nux::Area*, nux::Geometry& geo) + { + // Need to update the preview geometries when updating the container geo. + UpdateAnimationProgress(progress_, curve_progress_); + }); Style& style = previews::Style::Instance(); spin_= style.GetSearchSpinIcon(256); @@ -98,6 +104,9 @@ public: if (preview) { + // the parents layout will not change based on the previews. + preview->SetReconfigureParentLayoutOnGeometryChange(false); + AddChild(preview.GetPointer()); AddView(preview.GetPointer()); preview->SetVisible(false); @@ -123,6 +132,7 @@ public: void UpdateAnimationProgress(float progress, float curve_progress) { progress_ = progress; + curve_progress_ = curve_progress; if (!animating_) { @@ -171,39 +181,43 @@ public: if (progress >= 1.0) { - animating_ = false; - if (current_preview_) - { - RemoveChild(current_preview_.GetPointer()); - RemoveChildObject(current_preview_.GetPointer()); - current_preview_.Release(); - } - if (swipe_.preview) + // if we were animating, we need to remove the old preview, and replace it with the new. + if (animating_) { - if (swipe_.direction == Navigation::RIGHT) - relative_nav_index_++; - else if (swipe_.direction == Navigation::LEFT) - relative_nav_index_--; - - current_preview_ = swipe_.preview; - swipe_.preview.Release(); + animating_ = false; if (current_preview_) - current_preview_->OnNavigateInComplete(); - } - - // another swipe? - if (!push_preview_.empty()) - { - progress_ = 0; - continue_navigation.emit(); - } - else - { - end_navigation.emit(); + { + RemoveChild(current_preview_.GetPointer()); + RemoveChildObject(current_preview_.GetPointer()); + current_preview_.Release(); + } + if (swipe_.preview) + { + if (swipe_.direction == Navigation::RIGHT) + relative_nav_index_++; + else if (swipe_.direction == Navigation::LEFT) + relative_nav_index_--; + + current_preview_ = swipe_.preview; + swipe_.preview.Release(); + if (current_preview_) + current_preview_->OnNavigateInComplete(); + } + + // another swipe? + if (!push_preview_.empty()) + { + progress_ = 0; + continue_navigation.emit(); + } + else + { + end_navigation.emit(); + } } // set the geometry to the whole layout. - if (current_preview_ && current_preview_->GetGeometry() != geometry) + if (current_preview_) { current_preview_->SetGeometry(geometry); } @@ -332,6 +346,7 @@ private: PreviewSwipe swipe_; float progress_; + float curve_progress_; bool animating_; // wait animation glib::Source::UniquePtr preview_wait_timer_; @@ -409,6 +424,7 @@ void PreviewContainer::SetupViews() previews::Style& style = previews::Style::Instance(); layout_ = new nux::HLayout(); + layout_->SetSpaceBetweenChildren(6); SetLayout(layout_); layout_->AddSpace(0, 1); diff --git a/dash/previews/PreviewNavigator.cpp b/dash/previews/PreviewNavigator.cpp index 83dae0d96..445352aa9 100644 --- a/dash/previews/PreviewNavigator.cpp +++ b/dash/previews/PreviewNavigator.cpp @@ -48,8 +48,10 @@ PreviewNavigator::PreviewNavigator(Orientation direction, NUX_FILE_LINE_DECL) : View(NUX_FILE_LINE_PARAM) , direction_(direction) , texture_(nullptr) + , visual_state_(VisualState::NORMAL) { SetupViews(); + UpdateTexture(); } void PreviewNavigator::SetEnabled(bool enabled) @@ -138,13 +140,47 @@ void PreviewNavigator::SetupViews() if (texture_) { AddChild(texture_); - texture_->mouse_click.connect([&](int, int, unsigned long, unsigned long) { activated.emit(); }); layout_->AddView(texture_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); + + texture_->mouse_click.connect([&](int, int, unsigned long, unsigned long) { activated.emit(); }); + texture_->mouse_enter.connect(sigc::mem_fun(this, &PreviewNavigator::TexRecvMouseEnter)); + texture_->mouse_leave.connect(sigc::mem_fun(this, &PreviewNavigator::TexRecvMouseLeave)); } layout_->AddSpace(0, 1); } +void PreviewNavigator::TexRecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + visual_state_ = VisualState::ACTIVE; + UpdateTexture(); + QueueDraw(); +} + +void PreviewNavigator::TexRecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags) +{ + visual_state_ = VisualState::NORMAL; + UpdateTexture(); + QueueDraw(); +} + +void PreviewNavigator::UpdateTexture() +{ + if (!texture_) + return; + + switch (visual_state_) + { + case VisualState::ACTIVE: + texture_->SetOpacity(1.0); + break; + case VisualState::NORMAL: + default: + texture_->SetOpacity(0.2); + break; + } +} + } // namespace previews } // namespace dash diff --git a/dash/previews/PreviewNavigator.h b/dash/previews/PreviewNavigator.h index fce87c64f..53a14e447 100644 --- a/dash/previews/PreviewNavigator.h +++ b/dash/previews/PreviewNavigator.h @@ -58,12 +58,24 @@ private: virtual void Draw(nux::GraphicsEngine& gfx_engine, bool force_draw); virtual void DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw); + virtual void TexRecvMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags); + virtual void TexRecvMouseLeave(int x, int y, unsigned long button_flags, unsigned long key_flags); + + void UpdateTexture(); + void SetupViews(); private: const Orientation direction_; nux::Layout* layout_; IconTexture* texture_; + + enum class VisualState + { + NORMAL, + ACTIVE + }; + VisualState visual_state_; }; } // namespace previews diff --git a/dash/previews/StandaloneApplicationPreview.cpp b/dash/previews/StandaloneApplicationPreview.cpp index f9873f0fa..324d35666 100644 --- a/dash/previews/StandaloneApplicationPreview.cpp +++ b/dash/previews/StandaloneApplicationPreview.cpp @@ -164,6 +164,9 @@ The service allows users to communicate with peers by voice, video, and instant glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/5/lens-nav-home.svg", NULL)); glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/unity/5/lens-nav-people.svg", NULL)); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); @@ -173,13 +176,12 @@ The service allows users to communicate with peers by voice, video, and instant unity_protocol_application_preview_set_rating(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 0.5); unity_protocol_application_preview_set_num_ratings(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), 17); - unity_protocol_preview_set_image_source_uri(proto_obj, "file:///home/nick/Skype.png"); unity_protocol_preview_set_title(proto_obj, app_name.str().c_str()); unity_protocol_preview_set_subtitle(proto_obj, subtitle); unity_protocol_preview_set_description(proto_obj, description); unity_protocol_preview_add_action(proto_obj, "uninstall", "Uninstall", iconHint1, 0); - unity_protocol_preview_add_action(proto_obj, "launch", "Launch", iconHint2, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "launch", "Download", iconHint2, 0, action_hints1); unity_protocol_preview_add_info_hint(proto_obj, "time", "Total time", iconHint1, g_variant_new("s", "16 h 34miin 45sec")); unity_protocol_preview_add_info_hint(proto_obj, "energy", "Energy", iconHint2, g_variant_new("s", "58.07 mWh")); unity_protocol_preview_add_info_hint(proto_obj, "load", "CPU Load", iconHint3, g_variant_new("i", 12)); @@ -190,6 +192,7 @@ The service allows users to communicate with peers by voice, video, and instant dash::Preview::Ptr preview_model(dash::Preview::PreviewForVariant(v)); container_->Preview(preview_model, previews::Navigation::RIGHT); + g_hash_table_unref(action_hints1); } void TestRunner::NavRight() @@ -206,9 +209,10 @@ The service allows users to communicate with peers by voice, video, and instant glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/5/lens-nav-home.svg", NULL)); glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/unity/5/lens-nav-people.svg", NULL)); - glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); - + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Proprietary"); @@ -222,7 +226,7 @@ The service allows users to communicate with peers by voice, video, and instant unity_protocol_preview_set_subtitle(proto_obj, subtitle); unity_protocol_preview_set_description(proto_obj, description); unity_protocol_preview_add_action(proto_obj, "uninstall", "Uninstall", iconHint1, 0); - unity_protocol_preview_add_action(proto_obj, "launch", "Launch", iconHint2, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "launch", "Download", iconHint2, 0, action_hints1); unity_protocol_preview_add_info_hint(proto_obj, "time", "Total time", iconHint1, g_variant_new("s", "16 h 34miin 45sec")); unity_protocol_preview_add_info_hint(proto_obj, "energy", "Energy", iconHint2, g_variant_new("s", "58.07 mWh")); unity_protocol_preview_add_info_hint(proto_obj, "load", "CPU Load", iconHint3, g_variant_new("d", 12.1)); @@ -232,6 +236,8 @@ The service allows users to communicate with peers by voice, video, and instant dash::Preview::Ptr preview_model(dash::Preview::PreviewForVariant(v)); container_->Preview(preview_model, previews::Navigation::RIGHT); + + g_hash_table_unref(action_hints1); } void TestRunner::NavLeft() @@ -251,7 +257,10 @@ void TestRunner::NavLeft() glib::Object<GIcon> iconHint2(g_icon_new_for_string("/usr/share/unity/5/lens-nav-home.svg", NULL)); glib::Object<GIcon> iconHint3(g_icon_new_for_string("/usr/share/unity/5/lens-nav-people.svg", NULL)); - glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); + + glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); @@ -266,7 +275,7 @@ void TestRunner::NavLeft() unity_protocol_preview_set_subtitle(proto_obj, subtitle); unity_protocol_preview_set_description(proto_obj, description); unity_protocol_preview_add_action(proto_obj, "uninstall", "Uninstall", iconHint1, 0); - unity_protocol_preview_add_action(proto_obj, "launch", "Launch", iconHint2, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "launch", "Download", iconHint2, 0, action_hints1); unity_protocol_preview_add_info_hint(proto_obj, "time", "Total time", iconHint1, g_variant_new("s", "16 h 34miin 45sec")); unity_protocol_preview_add_info_hint(proto_obj, "energy", "Energy", iconHint2, g_variant_new("s", "58.07 mWh")); unity_protocol_preview_add_info_hint(proto_obj, "load", "CPU Load", iconHint3, g_variant_new("i", 22)); @@ -277,6 +286,8 @@ void TestRunner::NavLeft() dash::Preview::Ptr preview_model(dash::Preview::PreviewForVariant(v)); container_->Preview(preview_model, previews::Navigation::LEFT); + g_hash_table_unref(action_hints1); + return false; })); } diff --git a/dash/previews/Track.cpp b/dash/previews/Track.cpp index ca02a59d9..3f8efffdd 100644 --- a/dash/previews/Track.cpp +++ b/dash/previews/Track.cpp @@ -194,19 +194,16 @@ void Track::SetupViews() nux::BaseTexture* tex_play = style.GetPlayIcon(); IconTexture* status_play = new IconTexture(tex_play, style.GetStatusIconSize(), style.GetStatusIconSize()); status_play->SetDrawMode(IconTexture::DrawMode::STRETCH_WITH_ASPECT); - status_play->SetInputEventSensitivity(false); nux::BaseTexture* tex_pause = style.GetPauseIcon(); IconTexture* status_pause = new IconTexture(tex_pause, style.GetStatusIconSize(), style.GetStatusIconSize()); status_pause->SetDrawMode(IconTexture::DrawMode::STRETCH_WITH_ASPECT); - status_pause->SetInputEventSensitivity(false); track_number_ = new nux::StaticCairoText("", NUX_TRACKER_LOCATION); track_number_->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_CENTRE); track_number_->SetTextVerticalAlignment(nux::StaticCairoText::NUX_ALIGN_CENTRE); track_number_->SetLines(-1); track_number_->SetFont(style.track_font()); - track_number_->SetInputEventSensitivity(false); title_ = new nux::StaticCairoText("", NUX_TRACKER_LOCATION); title_->SetTextAlignment(nux::StaticCairoText::NUX_ALIGN_LEFT); @@ -229,26 +226,18 @@ void Track::SetupViews() status_play_layout_->GetLayout()->AddSpace(0, 1); status_play_layout_->GetLayout()->AddView(status_play, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); status_play_layout_->GetLayout()->AddSpace(0, 1); - status_play_layout_->mouse_click.connect([&](int, int, unsigned long, unsigned long) { play.emit(uri_); }); - status_play_layout_->mouse_enter.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseEnter)); - status_play_layout_->mouse_leave.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseLeave)); status_pause_layout_ = new TmpView(); status_pause_layout_->SetLayout(new nux::HLayout()); status_pause_layout_->GetLayout()->AddSpace(0, 1); status_pause_layout_->GetLayout()->AddView(status_pause, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); status_pause_layout_->GetLayout()->AddSpace(0, 1); - status_pause_layout_->mouse_click.connect([&](int, int, unsigned long, unsigned long) { pause.emit(uri_); }); - status_pause_layout_->mouse_enter.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseEnter)); - status_pause_layout_->mouse_leave.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseLeave)); track_number_layout_ = new TmpView(); track_number_layout_->SetLayout(new nux::HLayout()); track_number_layout_->GetLayout()->AddSpace(0, 1); track_number_layout_->GetLayout()->AddView(track_number_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); track_number_layout_->GetLayout()->AddSpace(0, 1); - track_number_layout_->mouse_enter.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseEnter)); - track_number_layout_->mouse_leave.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseLeave)); track_status_layout_ = new nux::LayeredLayout(); track_status_layout_->AddLayer(status_play_layout_, true); @@ -269,6 +258,23 @@ void Track::SetupViews() layout->AddLayout(title_layout_, 1, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); layout->AddLayout(duration_layout_, 0, nux::MINOR_POSITION_CENTER, nux::MINOR_SIZE_FULL); SetLayout(layout); + + mouse_enter.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseEnter)); + mouse_leave.connect(sigc::mem_fun(this, &Track::OnTrackControlMouseLeave)); + mouse_click.connect([&](int, int, unsigned long, unsigned long) + { + switch (play_state_) + { + case dash::PLAYING: + pause.emit(uri_); + break; + case dash::PAUSED: + case dash::STOPPED: + default: + play.emit(uri_); + break; + } + }); } void Track::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) @@ -341,9 +347,18 @@ void Track::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) gfx_engine.PopClippingRectangle(); } +nux::Area* Track::FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type) +{ + bool mouse_inside = TestMousePointerInclusionFilterMouseWheel(mouse_position, event_type); + if (mouse_inside == false) + return NULL; + + return this; +} + bool Track::HasStatusFocus() const { - return play_state_ == dash::PLAYING || play_state_ == dash::PAUSED; + return mouse_over_ || play_state_ == dash::PLAYING || play_state_ == dash::PAUSED; } void Track::OnTrackControlMouseEnter(int x, int y, unsigned long button_flags, unsigned long key_flags) diff --git a/dash/previews/Track.h b/dash/previews/Track.h index 0c177f0fe..b7873ce66 100644 --- a/dash/previews/Track.h +++ b/dash/previews/Track.h @@ -61,6 +61,7 @@ protected: virtual void Draw(nux::GraphicsEngine& gfx_engine, bool force_draw); virtual void DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw); virtual void PreLayoutManagement(); + virtual nux::Area* FindAreaUnderMouse(const nux::Point& mouse_position, nux::NuxEventType event_type); // From debug::Introspectable std::string GetName() const; diff --git a/hud/HudController.cpp b/hud/HudController.cpp index f43c82868..a28d65819 100644 --- a/hud/HudController.cpp +++ b/hud/HudController.cpp @@ -87,14 +87,20 @@ Controller::Controller(std::function<AbstractView*(void)> const& function) void Controller::SetupWindow() { - window_.Adopt(new nux::BaseWindow("Hud")); + // Since BaseWindow is a View it is initially unowned. This means that the first + // reference that is taken grabs ownership of the pointer. Since the smart pointer + // references it, it becomes the owner, so no need to adopt the pointer here. + window_ = new nux::BaseWindow("Hud"); window_->SetBackgroundColor(nux::Color(0.0f, 0.0f, 0.0f, 0.0f)); window_->SetConfigureNotifyCallback(&Controller::OnWindowConfigure, this); window_->ShowWindow(false); window_->SetOpacity(0.0f); - window_->mouse_down_outside_pointer_grab_area.connect(sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow)); - - /* FIXME - first time we load our windows there is a race that causes the input window not to actually get input, this side steps that by causing an input window show and hide before we really need it. */ + window_->mouse_down_outside_pointer_grab_area.connect( + sigc::mem_fun(this, &Controller::OnMouseDownOutsideWindow)); + + /* FIXME - first time we load our windows there is a race that causes the + * input window not to actually get input, this side steps that by causing + * an input window show and hide before we really need it. */ auto wm = WindowManager::Default(); wm->saveInputFocus (); window_->EnableInputWindow(true, "Hud", true, false); @@ -125,7 +131,7 @@ void Controller::SetupHudView() int Controller::GetIdealMonitor() { int ideal_monitor; - if (visible_) + if (window_->IsVisible()) ideal_monitor = monitor_index_; else ideal_monitor = UScreen::GetDefault()->GetMonitorWithMouse(); diff --git a/launcher/DeviceNotificationDisplayImp.cpp b/launcher/DeviceNotificationDisplayImp.cpp index cbb04c77d..0ab336cdf 100644 --- a/launcher/DeviceNotificationDisplayImp.cpp +++ b/launcher/DeviceNotificationDisplayImp.cpp @@ -40,12 +40,13 @@ public: void Show(std::string const& icon_name, std::string const& volume_name) { int icon_size = 48; - IconLoader::GetDefault().LoadFromGIconString(icon_name, icon_size, + IconLoader::GetDefault().LoadFromGIconString(icon_name, -1, icon_size, sigc::bind(sigc::mem_fun(this, &Impl::ShowNotificationWhenIconIsReady), volume_name)); } void ShowNotificationWhenIconIsReady(std::string const& icon_name, - unsigned size, + int max_width, + int max_height, glib::Object<GdkPixbuf> const& pixbuf, std::string const& volume_name) { @@ -55,7 +56,7 @@ public: notify_notification_set_hint(notification, "x-canonical-private-synchronous", g_variant_new_boolean(TRUE)); - if (GDK_IS_PIXBUF(pixbuf.RawPtr())) + if (pixbuf) notify_notification_set_image_from_pixbuf(notification, pixbuf); notify_notification_show(notification, nullptr); diff --git a/launcher/LauncherController.cpp b/launcher/LauncherController.cpp index bcc372fcb..bcc59bdca 100644 --- a/launcher/LauncherController.cpp +++ b/launcher/LauncherController.cpp @@ -244,7 +244,7 @@ void Controller::Impl::OnWindowFocusChanged (guint32 xid) { static bool keynav_first_focus = false; - if (parent_->IsOverlayOpen()) + if (parent_->IsOverlayOpen() || launcher_->GetParent()->GetInputWindowId() == xid) keynav_first_focus = false; if (keynav_first_focus) diff --git a/manual-tests/Dash.txt b/manual-tests/Dash.txt index 9ab7579ca..9174f8ceb 100644 --- a/manual-tests/Dash.txt +++ b/manual-tests/Dash.txt @@ -100,6 +100,19 @@ Expected result: * When a single row of results isn't enough to contain all returned search results, and there are no other category headers, the displayed category header expands automatically + +Test the Panel does not lose track of when the Dash is opened then closed. +-------------------------------------------------------------------------- +This tests shows the panel will not think the Dash is opened when it is closed. +(see lp:1044086) + +Actions: +#. Press Super twice (Quickly) + +Expected Result: + The screen should look the same as if you had never opened the dash. + + Filter Results Tests ======================== These tests show that the dash "All" button works well. diff --git a/manual-tests/Preview.txt b/manual-tests/Preview.txt index 4b6e6093c..47a9770c6 100644 --- a/manual-tests/Preview.txt +++ b/manual-tests/Preview.txt @@ -5,7 +5,7 @@ This tests the dash preview open animation Setup: #. Open dash super -#. Open a lens which supports previeing (eg Application, Music, File) +#. Open a lens which supports previewing (e.g. Application, Music, File) #. Enter arbitrary search string and ensure a result is available. Actions: @@ -23,7 +23,7 @@ This tests the dash preview navigate left animation Setup: #. Open dash super -#. Open a lens which supports previeing (eg Application, Music, File) +#. Open a lens which supports previewing (e.g. Application, Music, File) #. Enter arbitrary search string and ensure at least 2 results are available. #. Right-click the mouse on at least the second result. #. Wait for the preview window to open and finish animating. @@ -32,7 +32,7 @@ Actions: #. Click the 'navigate left' icon. Expected Result: - The current preview will swipe out and the new prevew result will swipe from right + The current preview will swipe out and the new preview result will swipe from right to left using an ease in-out curve progression. @@ -43,7 +43,7 @@ This tests the dash preview navigate right animation Setup: #. Open dash super -#. Open a lens which supports previeing (eg Application, Music, File) +#. Open a lens which supports previewing (e.g. Application, Music, File) #. Enter arbitrary search string and ensure at least 2 results are available. #. Right-click the mouse on at most the second last result. #. Wait for the preview window to open and finish animating. @@ -52,7 +52,7 @@ Actions: #. Click the navigate right icon. Expected Result: - The current preview will swipe out and the new prevew result will swipe from right + The current preview will swipe out and the new preview result will swipe from right to left using an ease in-out curve progression. @@ -73,7 +73,7 @@ Expected Result: The Track information will contain a title and duration. -Preview Music Play +Preview Music Track Play note: Should be automated. ------------ This tests the dash music preview track play @@ -84,14 +84,16 @@ Setup: #. Open a preview for a result which contains tracks. Actions: -#. Play first track. +#. Hover over track number for the track you wish to play. +#. Click play icon. Expected Result: + When hovering on track number, it will change to a play icon. Music Player daemon will start playing track and update status of the track in the preview to playing as well as update it's progress. -Preview Music Pause +Preview Music Track Pause note: Should be automated. ------------ This tests the dash preview preview navigate right animation @@ -100,14 +102,16 @@ Setup: #. Open music lens (Super+M) #. Enter arbitrary search string and ensure a result is available. #. Open a preview for a result which contains tracks. -#. Play first track. +#. Play first track. (by hovering+click on track number.) Actions: -#. Pause playing track. +#. Hover over pause icon for the track which is playing. +#. Click pause icon. Expected Result: + When hovering on play icon, it will change to a pause icon. Music Player daemon will pause the playing track and update it's status - to paused. Progress will stop incresing. + to paused. Progress will stop increasing. Preview Application Launch @@ -126,3 +130,24 @@ Actions: Expected Result: Preview should close and launch the gedit application. + + +Preview Open Geometry +------------ +This tests the dash preview opens with the correct size and +its geometry is updated when changing between form factor (desktop & netbook) + +Setup: +#. Open dash super +#. Ensure dash is in windowed mode (not full screen) +#. Open a lens which supports previewing (e.g. Application, Music, File) +#. Enter arbitrary search string and ensure a result is available. + +Actions: +#. Open preview for result. +#. Resize dash to full screen. +#. Resize dash back to windowed mode. + +Expected Result: + A preview will open with the correct size initially (no size flicker). + When the dash is resized, the preview will center its geometry and stay the correct size. diff --git a/panel/PanelController.cpp b/panel/PanelController.cpp index 1de0a530d..250c040a7 100644 --- a/panel/PanelController.cpp +++ b/panel/PanelController.cpp @@ -53,6 +53,7 @@ public: std::vector<nux::Geometry> GetGeometries() const; // NOTE: nux::Property maybe? + void SetLauncherWidth(int width); void SetOpacity(float opacity); void SetOpacityMaximizedToggle(bool enabled); @@ -147,6 +148,14 @@ void Controller::Impl::SetOpacity(float opacity) } } +void Controller::Impl::SetLauncherWidth(int width) +{ + for (auto const& window: windows_) + { + ViewForWindow(window)->SetLauncherWidth(width); + } +} + void Controller::Impl::SetOpacityMaximizedToggle(bool enabled) { opacity_maximized_toggle_ = enabled; @@ -297,6 +306,11 @@ Controller::Controller() UScreen* screen = UScreen::GetDefault(); screen->changed.connect(sigc::mem_fun(this, &Controller::OnScreenChanged)); OnScreenChanged(screen->GetPrimaryMonitor(), screen->GetMonitors()); + + launcher_width.changed.connect([&] (int width) + { + pimpl->SetLauncherWidth(width); + }); } Controller::~Controller() diff --git a/panel/PanelController.h b/panel/PanelController.h index 2c8a9c1bc..1b1caa736 100644 --- a/panel/PanelController.h +++ b/panel/PanelController.h @@ -44,6 +44,8 @@ public: std::vector<nux::View*> GetPanelViews() const; std::vector<nux::Geometry> GetGeometries() const; + nux::Property<int> launcher_width; + // NOTE: nux::Property maybe? void SetOpacity(float opacity); void SetOpacityMaximizedToggle(bool enabled); diff --git a/panel/PanelView.cpp b/panel/PanelView.cpp index 27bbfc3a5..9287a19b3 100644 --- a/panel/PanelView.cpp +++ b/panel/PanelView.cpp @@ -44,7 +44,8 @@ namespace { -nux::logging::Logger logger("unity.PanelView"); +nux::logging::Logger logger("unity.panel.view"); +const int refine_gradient_midpoint = 959; } namespace unity @@ -61,6 +62,8 @@ PanelView::PanelView(NUX_FILE_LINE_DECL) , _overlay_is_open(false) , _opacity(1.0f) , _monitor(0) + , _stored_dash_width(0) + , _launcher_width(0) { panel::Style::Instance().changed.connect(sigc::mem_fun(this, &PanelView::ForceUpdateBackground)); @@ -98,7 +101,47 @@ PanelView::PanelView(NUX_FILE_LINE_DECL) _ubus_manager.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, sigc::mem_fun(this, &PanelView::OnBackgroundUpdate)); _ubus_manager.RegisterInterest(UBUS_OVERLAY_HIDDEN, sigc::mem_fun(this, &PanelView::OnOverlayHidden)); _ubus_manager.RegisterInterest(UBUS_OVERLAY_SHOWN, sigc::mem_fun(this, &PanelView::OnOverlayShown)); + _ubus_manager.RegisterInterest(UBUS_DASH_SIZE_CHANGED, [&] (GVariant *data) + { + int width, height; + g_variant_get(data, "(ii)", &width, &height); + _stored_dash_width = width; + QueueDraw(); + }); + + _ubus_manager.RegisterInterest(UBUS_REFINE_STATUS, [this] (GVariant *data) + { + gboolean status; + g_variant_get(data, UBUS_REFINE_STATUS_FORMAT_STRING, &status); + + _refine_is_open = status; + + nux::ROPConfig rop; + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + nux::TexCoordXForm texxform; + if (_refine_is_open) + { + _bg_refine_layer.reset(new nux::TextureLayer(_bg_refine_tex->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + } + else + { + _bg_refine_layer.reset(new nux::TextureLayer(_bg_refine_no_refine_tex->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + + } + QueueDraw(); + }); + // request the latest colour from bghash _ubus_manager.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT); @@ -116,6 +159,61 @@ PanelView::PanelView(NUX_FILE_LINE_DECL) { _panel_sheen.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true)); } + + //FIXME (gord) like 12 months later, still not async loading! + pixbuf = gdk_pixbuf_new_from_file(PKGDATADIR "/refine_gradient_panel.png", &error); + if (error) + { + LOG_WARN(logger) << "Unable to texture " << PKGDATADIR << "/refine_gradient_panel.png"; + } + else + { + _bg_refine_tex.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true)); + } + + //FIXME (gord) like 12 months later, still not async loading! + pixbuf = gdk_pixbuf_new_from_file(PKGDATADIR "/refine_gradient_panel_no_refine.png", &error); + if (error) + { + LOG_WARN(logger) << "Unable to texture " << PKGDATADIR << "/refine_gradient_panel_no_refine.png"; + } + else + { + _bg_refine_no_refine_tex.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true)); + } + + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + nux::TexCoordXForm texxform; + _bg_refine_layer.reset(new nux::TextureLayer(_bg_refine_tex->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + + //FIXME (gord) like 12 months later, still not async loading! + pixbuf = gdk_pixbuf_new_from_file(PKGDATADIR "/refine_gradient_panel_single_column.png", &error); + if (error) + { + LOG_WARN(logger) << "Unable to texture " << PKGDATADIR << "/refine_gradient_panel_single_column.png"; + } + else + { + _bg_refine_single_column_tex.Adopt(nux::CreateTexture2DFromPixbuf(pixbuf, true)); + } + + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + _bg_refine_single_column_layer.reset(new nux::TextureLayer(_bg_refine_single_column_tex->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + } PanelView::~PanelView() @@ -138,6 +236,12 @@ Window PanelView::GetTrayXid() const return _tray->xid(); } +void PanelView::SetLauncherWidth(int width) +{ + _launcher_width = width; + QueueDraw(); +} + void PanelView::OnBackgroundUpdate(GVariant *data) { gdouble red, green, blue, alpha; @@ -285,6 +389,28 @@ PanelView::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) if (_overlay_is_open) { nux::GetPainter().RenderSinglePaintLayer(GfxContext, geo, _bg_darken_layer.get()); + + GfxContext.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + nux::TexCoordXForm refine_texxform; + + int refine_x_pos = geo.x + (_stored_dash_width - refine_gradient_midpoint); + + refine_x_pos += _launcher_width; + GfxContext.QRP_1Tex(refine_x_pos, + geo.y, + _bg_refine_tex->GetWidth(), + _bg_refine_tex->GetHeight(), + _bg_refine_tex->GetDeviceTexture(), + refine_texxform, + nux::color::White); + + GfxContext.QRP_1Tex(refine_x_pos + _bg_refine_tex->GetWidth(), + geo.y, + geo.width, + geo.height, + _bg_refine_single_column_tex->GetDeviceTexture(), + refine_texxform, + nux::color::White); } } @@ -360,6 +486,24 @@ PanelView::DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw) { nux::GetPainter().PushLayer(GfxContext, geo, _bg_darken_layer.get()); bgs++; + + nux::Geometry refine_geo = geo; + + int refine_x_pos = geo.x + (_stored_dash_width - refine_gradient_midpoint); + refine_x_pos += _launcher_width; + + refine_geo.x = refine_x_pos; + refine_geo.width = _bg_refine_tex->GetWidth(); + refine_geo.height = _bg_refine_tex->GetHeight(); + + nux::GetPainter().PushLayer(GfxContext, refine_geo, _bg_refine_layer.get()); + bgs++; + + refine_geo.x += refine_geo.width; + refine_geo.width = geo.width; + refine_geo.height = geo.height; + nux::GetPainter().PushLayer(GfxContext, refine_geo, _bg_refine_single_column_layer.get()); + bgs++; } } diff --git a/panel/PanelView.h b/panel/PanelView.h index 9dac92ea1..769112a93 100644 --- a/panel/PanelView.h +++ b/panel/PanelView.h @@ -64,6 +64,8 @@ public: Window GetTrayXid() const; + void SetLauncherWidth(int width); + protected: void Draw(nux::GraphicsEngine& GfxContext, bool force_draw); void DrawContent(nux::GraphicsEngine& GfxContext, bool force_draw); @@ -105,6 +107,12 @@ private: nux::ObjectPtr<nux::BaseTexture> _panel_sheen; nux::HLayout* _layout; + nux::ObjectPtr <nux::BaseTexture> _bg_refine_tex; + nux::ObjectPtr <nux::BaseTexture> _bg_refine_no_refine_tex; + + std::unique_ptr<nux::AbstractPaintLayer> _bg_refine_layer; + nux::ObjectPtr <nux::BaseTexture> _bg_refine_single_column_tex; + std::unique_ptr<nux::AbstractPaintLayer> _bg_refine_single_column_layer; nux::Geometry _last_geo; nux::Color _bg_color; @@ -115,6 +123,9 @@ private: bool _overlay_is_open; float _opacity; int _monitor; + int _stored_dash_width; + int _launcher_width; + bool _refine_is_open; std::string _active_overlay; diff --git a/panel/StandalonePanel.cpp b/panel/StandalonePanel.cpp index 0ca26601f..88f9bbc7e 100644 --- a/panel/StandalonePanel.cpp +++ b/panel/StandalonePanel.cpp @@ -18,11 +18,12 @@ * */ -#include "Nux/Nux.h" -#include "Nux/VLayout.h" -#include "Nux/HLayout.h" -#include "Nux/WindowThread.h" -#include "NuxGraphics/GraphicsEngine.h" +#include <Nux/Nux.h> +#include <Nux/VLayout.h> +#include <Nux/HLayout.h> +#include <Nux/WindowThread.h> +#include <NuxGraphics/GraphicsEngine.h> +#include <NuxCore/Logger.h> #include <gtk/gtk.h> #include "unity-shared/UnitySettings.h" @@ -47,7 +48,8 @@ int main(int argc, char** argv) g_type_init(); gtk_init(&argc, &argv); nux::NuxInitialize(0); - + nux::logging::configure_logging(::getenv("UNITY_LOG_SEVERITY")); + // The instances for the pseudo-singletons. unity::Settings settings; unity::panel::Style panel_style; diff --git a/plugins/unityshell/resources/album_missing.png b/plugins/unityshell/resources/album_missing.png Binary files differnew file mode 100644 index 000000000..dbb56373b --- /dev/null +++ b/plugins/unityshell/resources/album_missing.png diff --git a/plugins/unityshell/resources/album_missing_preview.png b/plugins/unityshell/resources/album_missing_preview.png Binary files differnew file mode 100644 index 000000000..2cd95245e --- /dev/null +++ b/plugins/unityshell/resources/album_missing_preview.png diff --git a/plugins/unityshell/resources/category_gradient.png b/plugins/unityshell/resources/category_gradient.png Binary files differnew file mode 100644 index 000000000..e6c8e66f6 --- /dev/null +++ b/plugins/unityshell/resources/category_gradient.png diff --git a/plugins/unityshell/resources/category_gradient_no_refine.png b/plugins/unityshell/resources/category_gradient_no_refine.png Binary files differnew file mode 100644 index 000000000..527a875a2 --- /dev/null +++ b/plugins/unityshell/resources/category_gradient_no_refine.png diff --git a/plugins/unityshell/resources/emblem_apps.svg b/plugins/unityshell/resources/emblem_apps.svg new file mode 100644 index 000000000..6af364db0 --- /dev/null +++ b/plugins/unityshell/resources/emblem_apps.svg @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="14px" height="14px" viewBox="0 0 14 14" enable-background="new 0 0 14 14" xml:space="preserve"> +<path fill="#DC4A26" d="M8.5,4.504v7.997c0,0.55-0.469,0.999-1.018,0.999H6.498c-0.55,0-0.998-0.449-0.998-0.999V4.504H8.5z"/> +<g> + <path fill="#DC4A26" d="M4.5,4.504h-2v-1h2V1.505c0-0.55-0.45-1-1-1H1.501c-0.55,0-1,0.45-1,1L0.5,12.501 + c0,0.55,0.45,0.999,1,0.999h1.999c0.55,0,1-0.449,1-0.999V10.5L2.5,10.502v-1L4.499,9.5V7.503H2.5v-1h2"/> +</g> +<path fill="#DC4A26" d="M4.5,6.503v-1l0,0V6.503L4.5,6.503z"/> +<path fill="#DC4A26" d="M4.5,9.502v-1h0L4.5,9.502L4.5,9.502z"/> +<path fill="#DC4A26" d="M4.5,12.499L4.5,12.499L4.5,12.499L4.5,12.499L4.5,12.499z"/> +<path fill="#DC4A26" d="M11.866,0.508v1.237C12.102,1.856,12.3,2.052,12.3,2.286c0,0.354-0.358,0.64-0.8,0.64s-0.8-0.286-0.8-0.64 + c0-0.234,0.198-0.43,0.433-0.541V0.508C10.66,0.972,9.5,2.321,9.5,2.917c0,0.884,1.116,1.6,2,1.6s2-0.716,2-1.6 + C13.5,2.321,12.34,0.972,11.866,0.508z"/> +<path fill="#DC4A26" d="M5.501,3.499L7.047,0.5L8.5,3.499H5.501z"/> +<path fill="#DC4A26" d="M13.5,5.503v6.998c0,0.55-0.45,0.999-1,0.999h-2c-0.55,0-1-0.449-1-0.999V5.503H13.5z"/> +</svg> diff --git a/plugins/unityshell/resources/emblem_books.svg b/plugins/unityshell/resources/emblem_books.svg new file mode 100644 index 000000000..89cfdfd14 --- /dev/null +++ b/plugins/unityshell/resources/emblem_books.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="14px" height="14px" viewBox="0 0 14 14" enable-background="new 0 0 14 14" xml:space="preserve"> +<path fill="#DC4A26" d="M7,1.879C6.961,1.473,6.427,0.227,1,1.5c0,3.222,0,7.449,0,11C7.009,10.945,7,13,7,13s-0.009-2.055,6-0.5 + c0-3.551,0-7.778,0-11C7.574,0.227,7.039,1.473,7,1.879z M5,9H2V8h3V9z M5,7H2V6h3V7z M5,5H2V4h3V5z M7.5,12h-1V2h1V12z M12,9H9V8h3 + V9z M12,7H9V6h3V7z M12,5H9V4h3V5z"/> +</svg> diff --git a/plugins/unityshell/resources/emblem_clothes.svg b/plugins/unityshell/resources/emblem_clothes.svg new file mode 100644 index 000000000..882a09b3d --- /dev/null +++ b/plugins/unityshell/resources/emblem_clothes.svg @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="14px" height="14px" viewBox="0 0 14 14" enable-background="new 0 0 14 14" xml:space="preserve"> +<path fill="#DC4A26" d="M10.997,13V5.013l1.505,0.772L14,2.942L10.974,1L8.988,1.002c0,1.121-0.916,2.029-2.046,2.029 + S5.012,2.123,5.012,1.002L2.969,1L0,2.942l1.498,2.843l1.447-0.772V13H10.997z"/> +</svg> diff --git a/plugins/unityshell/resources/emblem_music.svg b/plugins/unityshell/resources/emblem_music.svg new file mode 100644 index 000000000..998583d85 --- /dev/null +++ b/plugins/unityshell/resources/emblem_music.svg @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="14px" height="14px" viewBox="0 0 14 14" enable-background="new 0 0 14 14" xml:space="preserve"> +<g> + <g> + <path fill="#DC4A26" d="M13,0.598c0-0.386-0.307-0.651-0.683-0.588L5.672,1.186C5.296,1.249,5,1.617,5,2.005v7.249 + C4.228,8.862,3.14,8.925,2.157,9.52c-1.393,0.841-2.033,2.413-1.43,3.506c0.603,1.094,2.223,1.299,3.615,0.455 + c1.078-0.65,1.697-1.735,1.648-2.699L6,10.789V3.624c0-0.386,0.277-0.756,0.653-0.818l4.684-0.823C11.712,1.919,12,2.184,12,2.57 + v4.684c-0.771-0.393-1.86-0.329-2.843,0.265C7.764,8.36,7.123,9.931,7.727,11.024c0.603,1.094,2.222,1.3,3.615,0.456 + c1.069-0.646,1.689-1.721,1.649-2.68L13,8.808V0.598z"/> + </g> +</g> +</svg> diff --git a/plugins/unityshell/resources/emblem_video.svg b/plugins/unityshell/resources/emblem_video.svg new file mode 100644 index 000000000..a8ad76142 --- /dev/null +++ b/plugins/unityshell/resources/emblem_video.svg @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="14px" height="14px" viewBox="0 0 14 14" enable-background="new 0 0 14 14" xml:space="preserve"> +<g> + <g> + <path fill="#DC4A26" d="M12.301,2.5H1.7C1.315,2.5,1,2.813,1,3.196v7.608C1,11.188,1.315,11.5,1.7,11.5h10.601 + c0.385,0,0.699-0.312,0.699-0.696V3.196C13,2.813,12.686,2.5,12.301,2.5z M2.989,10.455H1.994V9.498h0.996V10.455z M2.989,8.49 + H1.994V7.5h0.996V8.49z M2.989,6.494H1.994V5.535h0.996V6.494z M2.989,4.496H1.994V3.538h0.996V4.496z M8.006,7.841 + C7.659,8.126,7.308,8.404,6.954,8.677C6.6,8.947,6.255,9.197,5.92,9.426c-0.335,0.229-0.64,0.422-0.913,0.579V4.026 + c0.261,0.158,0.559,0.35,0.894,0.578c0.335,0.229,0.68,0.476,1.034,0.74c0.354,0.265,0.708,0.54,1.061,0.825 + c0.355,0.286,0.687,0.565,0.998,0.836C8.684,7.276,8.354,7.555,8.006,7.841z M11.992,10.455h-0.996V9.498h0.996V10.455z + M11.992,8.49h-0.996V7.5h0.996V8.49z M11.992,6.494h-0.996V5.535h0.996V6.494z M11.992,4.496h-0.996V3.538h0.996V4.496z"/> + </g> +</g> +</svg> diff --git a/plugins/unityshell/resources/lens-nav-app.svg b/plugins/unityshell/resources/lens-nav-app.svg index 2ea0066c8..b0bb63120 100644 --- a/plugins/unityshell/resources/lens-nav-app.svg +++ b/plugins/unityshell/resources/lens-nav-app.svg @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> -<g> - <g> - <path fill="#FFFFFF" d="M9.5,21c0,0.55,0.45,1,1,1h3c0.55,0,1-0.45,1-1V8h-5V21z M6.5,2H3.501c-0.55,0-1,0.45-1,1L2.5,21 - c0,0.55,0.45,1,1,1h2.999c0.55,0,1-0.45,1-1v-2.969H5.5v-1h1.999V14H5.5v-1h2v-3h-2V9h2V6h-2V5h2V3C7.5,2.45,7.05,2,6.5,2z - M7.5,10V9V10L7.5,10z M7.5,14v-1h0L7.5,14L7.5,14z M7.5,18.031v-1H7.499L7.5,18.031L7.5,18.031z M19,8.015 - c1.104,0,2.5-1.119,2.5-2.5c0-0.933-1.408-2.79-2-3.515v1.515c0.293,0.174,0.5,0.48,0.5,0.847c0,0.553-0.447,1-1,1s-1-0.447-1-1 - c0-0.366,0.207-0.673,0.5-0.847V2c-0.592,0.725-2,2.582-2,3.515C16.5,6.896,17.896,8.015,19,8.015z M9.438,7H14.5l-2.531-5 - L9.438,7z M16.5,21c0,0.55,0.45,1,1,1h3c0.55,0,1-0.45,1-1V9h-5V21z"/> - </g> -</g> +<path fill="#FFFFFF" d="M14,8v12c0,0.55-0.45,1-1,1h-2c-0.55,0-1-0.45-1-1V8H14z"/> +<path fill="#FFFFFF" d="M8,11H6v-1h2V8H6V7h2V4c0-0.55-0.45-1-1-1H5.001c-0.55,0-1,0.45-1,1L4,20c0,0.55,0.45,1,1,1h2 + c0.55,0,1-0.45,1-1v-3H6v-1h2v-2H6v-1h2V11z"/> +<path fill="#FFFFFF" d="M8,8L8,8V7l0,0V8z"/> +<path fill="#FFFFFF" d="M18.366,3v1.542C18.602,4.681,18.8,4.925,18.8,5.217c0,0.441-0.358,0.799-0.8,0.799s-0.8-0.358-0.8-0.799 + c0-0.292,0.198-0.537,0.433-0.675V3C17.16,3.578,16,5.26,16,6.005C16,7.106,17.116,8,18,8s2-0.894,2-1.995 + C20,5.26,18.84,3.578,18.366,3z"/> +<path fill="#FFFFFF" d="M20,9v11c0,0.55-0.45,1-1,1h-2c-0.55,0-1-0.45-1-1V9H20z"/> +<path fill="#FFFFFF" d="M12.552,3.991c0.191,0.349,0.378,0.7,0.56,1.056c0.182,0.355,0.349,0.701,0.502,1.038 + C13.766,6.42,13.895,6.726,14,7h-4c0.105-0.262,0.234-0.561,0.387-0.897c0.153-0.336,0.318-0.682,0.495-1.038 + c0.177-0.354,0.36-0.71,0.552-1.065c0.191-0.355,0.377-0.688,0.559-1C12.175,3.312,12.36,3.642,12.552,3.991z"/> </svg> - \ No newline at end of file diff --git a/plugins/unityshell/resources/lens-nav-file.svg b/plugins/unityshell/resources/lens-nav-file.svg index 3c0e66ca6..48fb41c3b 100644 --- a/plugins/unityshell/resources/lens-nav-file.svg +++ b/plugins/unityshell/resources/lens-nav-file.svg @@ -1,13 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> -<g> - <g> - <path fill="#FFFFFF" d="M14.969,2H14v6h6V7L14.969,2z M13,2H5C4.45,2,4,2.45,4,3v18c0,0.55,0.45,1,1,1h14c0.551,0,1-0.45,1-1 - V9.007h-7V2z"/> - </g> -</g> +<path fill="#FFFFFF" d="M15,3v4h4V6l-3.031-3H15z"/> +<path fill="#FFFFFF" d="M18,21H6c-0.55,0-1-0.45-1-1V4c0-0.55,0.45-1,1-1h8v5.007h5V20C19,20.55,18.551,21,18,21z"/> </svg> - \ No newline at end of file diff --git a/plugins/unityshell/resources/lens-nav-gwibber.svg b/plugins/unityshell/resources/lens-nav-gwibber.svg new file mode 100644 index 000000000..07361aa25 --- /dev/null +++ b/plugins/unityshell/resources/lens-nav-gwibber.svg @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> +<path fill="#FFFFFF" d="M23,11.38c-0.774,0.14-1.897-0.005-2.492-0.267c1.236-0.108,2.073-0.701,2.396-1.505 + c-0.445,0.29-1.829,0.604-2.593,0.304c-0.038-0.189-0.078-0.369-0.121-0.533c-0.581-2.256-2.576-4.074-4.663-3.854 + c0.169-0.073,0.34-0.139,0.512-0.2c0.229-0.087,1.577-0.318,1.365-0.82c-0.179-0.442-1.828,0.332-2.138,0.435 + c0.41-0.162,1.087-0.441,1.159-0.939c-0.627,0.091-1.243,0.404-1.72,0.86c0.173-0.195,0.304-0.432,0.331-0.689 + c-1.675,1.129-2.652,3.405-3.443,5.613c-0.621-0.637-1.173-1.136-1.667-1.416C8.541,7.584,6.883,6.766,4.282,5.746 + c-0.08,0.909,0.426,2.118,1.881,2.92C5.848,8.621,5.271,8.722,4.811,8.838c0.188,1.042,0.801,1.899,2.463,2.312 + c-0.759,0.053-1.153,0.237-1.508,0.629c0.346,0.725,1.191,1.576,2.708,1.401c-1.689,0.769-0.688,2.19,0.686,1.979 + C6.817,17.715,3.122,17.525,1,15.39c5.539,7.969,17.581,4.712,19.374-2.963C21.721,12.438,22.51,11.936,23,11.38z"/> +</svg> diff --git a/plugins/unityshell/resources/lens-nav-home.svg b/plugins/unityshell/resources/lens-nav-home.svg index dd042315f..0f30fda7c 100644 --- a/plugins/unityshell/resources/lens-nav-home.svg +++ b/plugins/unityshell/resources/lens-nav-home.svg @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> -<path fill="#FFFFFF" d="M12.707,2.298C12.513,2.1,12.256,2,12,2s-0.513,0.1-0.707,0.298L2,11.788h2v9.191C4,21.539,4.45,22,5,22 - h5.02v-6.127h3.968V22H19c0.55,0,1-0.461,1-1.021v-9.191h2L12.707,2.298z"/> +<path fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M12.678,3.268C12.5,3.089,12.266,3,12.031,3 + c-0.235,0-0.47,0.089-0.647,0.268L3,12h2v8c0,0.553,0.447,1,1,1h12c0.553,0,1-0.447,1-1v-8h2L12.678,3.268z M14,20.998h-4v-5h4 + V20.998z"/> </svg> - \ No newline at end of file diff --git a/plugins/unityshell/resources/lens-nav-music.svg b/plugins/unityshell/resources/lens-nav-music.svg index ef341e717..ada6ce9e4 100644 --- a/plugins/unityshell/resources/lens-nav-music.svg +++ b/plugins/unityshell/resources/lens-nav-music.svg @@ -1,16 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> -<g> - <g> - <path fill="#FFFFFF" d="M21,2.85c0-0.55-0.443-0.927-0.986-0.837L9.986,3.687C9.444,3.776,9,4.301,9,4.851v10.268l0.02,0.026 - c-1.062-0.301-2.393-0.131-3.61,0.578c-2.025,1.178-2.956,3.379-2.079,4.911s3.232,1.819,5.258,0.637 - c1.437-0.835,2.307-2.182,2.389-3.441l0.022,0.03V7.155c0-0.55,0.444-1.075,0.986-1.165l6.028-1.006 - C18.557,4.894,19,5.271,19,5.821v7.296l0.02,0.026c-1.062-0.3-2.393-0.131-3.609,0.578c-2.025,1.179-2.957,3.379-2.079,4.911 - c0.877,1.533,3.231,1.82,5.257,0.638c1.438-0.835,2.308-2.183,2.39-3.442L21,15.859V2.85z"/> - </g> -</g> +<path fill="#FFFFFF" d="M19.964,14.964L20,15V3.849c0-0.55-0.444-0.926-0.986-0.835l-8.027,1.67C10.444,4.774,10,5.299,10,5.849 + v9.603c-0.984-0.633-2.52-0.61-3.892,0.172c-1.772,1.009-2.587,2.895-1.819,4.207c0.767,1.312,2.828,1.559,4.6,0.545 + c1.441-0.819,2.232-2.213,2.074-3.412L11,17V6.849c0-0.55,0.444-1.075,0.986-1.167l6.028-1.365C18.557,4.224,19,4.599,19,5.148 + v8.302c-0.984-0.632-2.521-0.609-3.891,0.174c-1.773,1.01-2.588,2.894-1.82,4.206c0.768,1.312,2.828,1.56,4.601,0.546 + C19.331,17.557,20.122,16.163,19.964,14.964z"/> </svg> - \ No newline at end of file diff --git a/plugins/unityshell/resources/lens-nav-photo.svg b/plugins/unityshell/resources/lens-nav-photo.svg index 91e80f44b..7c91448a0 100644 --- a/plugins/unityshell/resources/lens-nav-photo.svg +++ b/plugins/unityshell/resources/lens-nav-photo.svg @@ -1,16 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> -<g> - <g> - <path fill="#FFFFFF" d="M12.009,9.51c-2.218,0-4.016,1.797-4.016,4.013s1.798,4.013,4.016,4.013s4.016-1.797,4.016-4.013 - S14.227,9.51,12.009,9.51z M21,6.511H3c-0.55,0-1,0.45-1,0.999v11.991c0,0.55,0.45,0.999,1,0.999h18c0.55,0,1-0.449,1-0.999V7.51 - C22,6.961,21.55,6.511,21,6.511z M12,19.501c-3.313,0-6-2.684-6-5.995c0-3.312,2.687-5.996,6-5.996s6,2.684,6,5.996 - C18,16.817,15.313,19.501,12,19.501z M15.664,5.55l-0.368-1.102C15.122,3.927,14.53,3.5,13.979,3.5h-4 - c-0.55,0-1.142,0.427-1.316,0.948L8.296,5.55C8.122,6.071,7.53,6.498,6.98,6.498h10C16.431,6.498,15.838,6.071,15.664,5.55z"/> - </g> -</g> +<path fill="#FFFFFF" d="M16,13.5c0,2.21-1.79,4-4,4s-4-1.79-4-4s1.79-4,4-4S16,11.29,16,13.5z"/> +<path fill="#FFFFFF" d="M20,7.5h-3c-0.55,0-1.162-0.433-1.336-0.956l-0.368-1.103C15.122,4.92,14.55,4.5,14,4.5h-4 + c-0.55,0-1.162,0.42-1.337,0.942L8.296,6.544C8.122,7.067,7.55,7.5,7,7.5H4c-0.55,0-1,0.45-1,1v10c0,0.551,0.45,1,1,1h16 + c0.55,0,1-0.449,1-1v-10C21,7.95,20.55,7.5,20,7.5z M12,18.5c-2.762,0-5-2.238-5-5c0-2.763,2.238-5,5-5c2.761,0,5,2.237,5,5 + C17,16.262,14.761,18.5,12,18.5z"/> </svg> - \ No newline at end of file diff --git a/plugins/unityshell/resources/lens-nav-video.svg b/plugins/unityshell/resources/lens-nav-video.svg index 4fe5ffe3e..7c07198a9 100644 --- a/plugins/unityshell/resources/lens-nav-video.svg +++ b/plugins/unityshell/resources/lens-nav-video.svg @@ -1,14 +1,13 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 14.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 43363) --> +<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> -<g> - <g> - <path fill="#FFFFFF" d="M21,4H3C2.45,4,2,4.45,2,5v14c0,0.55,0.45,1,1,1h18c0.55,0,1-0.45,1-1V5C22,4.45,21.55,4,21,4z M5,19H3v-2 - h2V19z M5,16H3v-2h2V16z M5,13H3v-2h2V13z M5,10H3V8h2V10z M5,7H3V5h2V7z M9,15.98V8l7.036,4L9,15.98z M21,19h-2v-2h2V19z M21,16 - h-2v-2h2V16z M21,13h-2v-2h2V13z M21,10h-2V8h2V10z M21,7h-2V5h2V7z"/> - </g> -</g> +<path fill="#FFFFFF" d="M20,4.5H4c-0.532,0-1,0.467-1,1v13c0,0.533,0.468,1,1,1h16c0.533,0,1-0.467,1-1v-13 + C21,4.967,20.533,4.5,20,4.5z M5.5,18.5h-1v-1h1V18.5z M5.5,16.5h-1v-1h1V16.5z M5.5,14.5h-1v-1h1V14.5z M5.5,12.5h-1v-1h1V12.5z + M5.5,10.5h-1v-1h1V10.5z M5.5,8.5h-1v-1h1V8.5z M5.5,6.5h-1v-1h1V6.5z M14.267,13.241c-0.61,0.431-1.226,0.85-1.849,1.259 + c-0.621,0.408-1.226,0.785-1.815,1.129C10.015,15.973,9.479,16.263,9,16.5v-9c0.458,0.236,0.981,0.527,1.57,0.871 + c0.588,0.343,1.194,0.715,1.816,1.113c0.621,0.398,1.243,0.812,1.864,1.242c0.622,0.429,1.205,0.849,1.75,1.257 + C15.455,12.392,14.877,12.812,14.267,13.241z M19.5,18.5h-1v-1h1V18.5z M19.5,16.5h-1v-1h1V16.5z M19.5,14.5h-1v-1h1V14.5z + M19.5,12.5h-1v-1h1V12.5z M19.5,10.5h-1v-1h1V10.5z M19.5,8.5h-1v-1h1V8.5z M19.5,6.5h-1v-1h1V6.5z"/> </svg> - \ No newline at end of file diff --git a/plugins/unityshell/resources/refine_gradient.png b/plugins/unityshell/resources/refine_gradient.png Binary files differnew file mode 100644 index 000000000..20620258d --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient.png diff --git a/plugins/unityshell/resources/refine_gradient_corner.png b/plugins/unityshell/resources/refine_gradient_corner.png Binary files differnew file mode 100644 index 000000000..a7ab65744 --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_corner.png diff --git a/plugins/unityshell/resources/refine_gradient_dash.png b/plugins/unityshell/resources/refine_gradient_dash.png Binary files differnew file mode 100644 index 000000000..26fe103c8 --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_dash.png diff --git a/plugins/unityshell/resources/refine_gradient_dash_no_refine.png b/plugins/unityshell/resources/refine_gradient_dash_no_refine.png Binary files differnew file mode 100644 index 000000000..c8cb44728 --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_dash_no_refine.png diff --git a/plugins/unityshell/resources/refine_gradient_no_refine_dash.png b/plugins/unityshell/resources/refine_gradient_no_refine_dash.png Binary files differnew file mode 100644 index 000000000..12ab5956e --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_no_refine_dash.png diff --git a/plugins/unityshell/resources/refine_gradient_panel.png b/plugins/unityshell/resources/refine_gradient_panel.png Binary files differnew file mode 100644 index 000000000..d283f0977 --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_panel.png diff --git a/plugins/unityshell/resources/refine_gradient_panel_no_refine.png b/plugins/unityshell/resources/refine_gradient_panel_no_refine.png Binary files differnew file mode 100644 index 000000000..f50902e56 --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_panel_no_refine.png diff --git a/plugins/unityshell/resources/refine_gradient_panel_single_column.png b/plugins/unityshell/resources/refine_gradient_panel_single_column.png Binary files differnew file mode 100644 index 000000000..7ce0efa2f --- /dev/null +++ b/plugins/unityshell/resources/refine_gradient_panel_single_column.png diff --git a/plugins/unityshell/resources/video_missing.png b/plugins/unityshell/resources/video_missing.png Binary files differnew file mode 100644 index 000000000..0de4797e9 --- /dev/null +++ b/plugins/unityshell/resources/video_missing.png diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index ba6684a90..f00fd11bd 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -132,7 +132,6 @@ UnityScreen::UnityScreen(CompScreen* screen) , panel_texture_has_changed_(true) , paint_panel_(false) , scale_just_activated_(false) - , scale_highlighted_window_(0) , minimize_speed_controller(new WindowMinimizeSpeedController()) { Timer timer; @@ -360,7 +359,7 @@ UnityScreen::UnityScreen(CompScreen* screen) g_variant_get(data, UBUS_OVERLAY_FORMAT_STRING, &overlay_identity, &can_maximise, &overlay_monitor); - dash_monitor_ = overlay_monitor; + overlay_monitor_ = overlay_monitor; RaiseInputWindows(); }); @@ -371,7 +370,6 @@ UnityScreen::UnityScreen(CompScreen* screen) } panel::Style::Instance().changed.connect(sigc::mem_fun(this, &UnityScreen::OnPanelStyleChanged)); - WindowManager::Default()->terminate_spread.connect([this] { scale_highlighted_window_ = 0; }); minimize_speed_controller->DurationChanged.connect( sigc::mem_fun(this, &UnityScreen::OnMinimizeDurationChanged) @@ -572,7 +570,7 @@ void UnityScreen::paintPanelShadow(const GLMatrix& matrix) i++; } - if (!(launcher_controller_->IsOverlayOpen() && current_monitor == dash_monitor_) + if (!(launcher_controller_->IsOverlayOpen() && current_monitor == overlay_monitor_) && panel_controller_->opacity() > 0.0f) { foreach(GLTexture * tex, _shadow_texture) @@ -1380,14 +1378,17 @@ void UnityScreen::nuxDamageCompiz() void UnityScreen::handleEvent(XEvent* event) { bool skip_other_plugins = false; + auto wm = PluginAdapter::Default(); + switch (event->type) { case FocusIn: case FocusOut: if (event->xfocus.mode == NotifyGrab) - PluginAdapter::Default()->OnScreenGrabbed(); + wm->OnScreenGrabbed(); else if (event->xfocus.mode == NotifyUngrab) - PluginAdapter::Default()->OnScreenUngrabbed(); + wm->OnScreenUngrabbed(); + if (_key_nav_mode_requested) { // Close any overlay that is open. @@ -1401,9 +1402,10 @@ void UnityScreen::handleEvent(XEvent* event) _key_nav_mode_requested = false; break; case MotionNotify: - if (scale_highlighted_window_ && PluginAdapter::Default()->IsScaleActive()) + if (wm->IsScaleActive()) { - if (CompWindow *w = screen->findWindow(scale_highlighted_window_)) + ScaleScreen* ss = ScaleScreen::get(screen); + if (CompWindow *w = screen->findWindow(ss->getSelectedWindow())) skip_other_plugins = UnityWindow::get(w)->handleEvent(event); } break; @@ -1413,12 +1415,21 @@ void UnityScreen::handleEvent(XEvent* event) launcher_controller_->KeyNavTerminate(false); EnableCancelAction(CancelActionTarget::LAUNCHER_SWITCHER, false); } - if (scale_highlighted_window_ && PluginAdapter::Default()->IsScaleActive()) + if (wm->IsScaleActive()) { - if (CompWindow *w = screen->findWindow(scale_highlighted_window_)) + ScaleScreen* ss = ScaleScreen::get(screen); + if (CompWindow *w = screen->findWindow(ss->getSelectedWindow())) skip_other_plugins = UnityWindow::get(w)->handleEvent(event); } - + if (launcher_controller_->IsOverlayOpen()) + { + int monitor_with_mouse = UScreen::GetDefault()->GetMonitorWithMouse(); + if (overlay_monitor_ != monitor_with_mouse) + { + dash_controller_->HideDash(false); + hud_controller_->HideHud(false); + } + } break; case ButtonRelease: if (switcher_controller_ && switcher_controller_->Visible()) @@ -1438,10 +1449,11 @@ void UnityScreen::handleEvent(XEvent* event) } } } - else if (scale_highlighted_window_ && PluginAdapter::Default()->IsScaleActive()) + else if (wm->IsScaleActive()) { - if (CompWindow *w = screen->findWindow(scale_highlighted_window_)) - UnityWindow::get(w)->handleEvent(event); + ScaleScreen* ss = ScaleScreen::get(screen); + if (CompWindow *w = screen->findWindow(ss->getSelectedWindow())) + skip_other_plugins = UnityWindow::get(w)->handleEvent(event); } break; case KeyPress: @@ -2557,7 +2569,8 @@ void UnityWindow::windowNotify(CompWindowNotify n) UnityScreen* us = UnityScreen::get(screen); CompWindow *lw; - if (us->launcher_controller_->IsOverlayOpen()) + // can't rely on launcher->IsOverlayVisible on focus change (because ubus is async close on focus change.) + if (us && (us->dash_controller_->IsVisible() || us->hud_controller_->IsVisible())) { lw = screen->findWindow(us->launcher_controller_->LauncherWindowId(0)); lw->moveInputFocusTo(); @@ -2771,6 +2784,7 @@ void UnityScreen::optionChanged(CompOption* opt, UnityshellOptions::Options num) * that must not be considered when drawing an overlay */ hud_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1; dash_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1; + panel_controller_->launcher_width = launcher_controller_->launcher().GetAbsoluteWidth() - 1; if (p) { @@ -3599,8 +3613,8 @@ void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib, if (!scale_win->hasSlot()) // animation not finished return; - UnityScreen* us = UnityScreen::get(screen); - const bool highlighted = (us->scale_highlighted_window_ == window->id()); + ScaleScreen* ss = ScaleScreen::get(screen); + const bool highlighted = (ss->getSelectedWindow() == window->id()); ScalePosition const& pos = scale_win->getCurrentPosition(); auto const& border_rect = window->borderRect(); @@ -3653,16 +3667,6 @@ void UnityWindow::scalePaintDecoration(GLWindowPaintAttrib const& attrib, } } -void UnityWindow::scaleSelectWindow() -{ - ScaleWindow::get(window)->scaleSelectWindow(); - - UnityScreen* us = UnityScreen::get(screen); - - if (us->scale_highlighted_window_ != window->id()) - us->scale_highlighted_window_ = window->id(); -} - void UnityWindow::OnInitiateSpreed() { auto const windows = screen->windows(); diff --git a/plugins/unityshell/src/unityshell.h b/plugins/unityshell/src/unityshell.h index a1de06832..b970a7567 100644 --- a/plugins/unityshell/src/unityshell.h +++ b/plugins/unityshell/src/unityshell.h @@ -312,7 +312,7 @@ private: bool queryForShader (); - int dash_monitor_; + int overlay_monitor_; CompScreen::GrabHandle grab_index_; CompWindowList fullscreen_windows_; bool painting_tray_; @@ -333,8 +333,6 @@ private: glib::SourceManager sources_; unity::ThumbnailGenerator thumb_generator; - Window scale_highlighted_window_; - WindowMinimizeSpeedController* minimize_speed_controller; friend class UnityWindow; }; @@ -409,7 +407,6 @@ public: //! Emited when CompWindowNotifyBeforeDestroy is received sigc::signal<void> being_destroyed; - void scaleSelectWindow(); void scalePaintDecoration(const GLWindowPaintAttrib &, const GLMatrix &, const CompRegion &, diff --git a/tests/autopilot/unity/emulators/dash.py b/tests/autopilot/unity/emulators/dash.py index 22e5da883..0d38591e8 100644 --- a/tests/autopilot/unity/emulators/dash.py +++ b/tests/autopilot/unity/emulators/dash.py @@ -9,6 +9,7 @@ from __future__ import absolute_import +from autopilot.emulators.dbus_handler import session_bus from autopilot.emulators.X11 import Keyboard, Mouse from autopilot.keybindings import KeybindingsHelper from testtools.matchers import GreaterThan @@ -16,7 +17,7 @@ from testtools.matchers import GreaterThan from unity.emulators import UnityIntrospectionObject import logging from time import sleep - +import dbus logger = logging.getLogger(__name__) @@ -162,6 +163,13 @@ class DashController(UnityIntrospectionObject): """Get the dash view that's attached to this controller.""" return self.get_children_by_type(DashView)[0] + def hide_dash_via_dbus(self): + """ Emulate a DBus call for dash hiding """ + dash_object = session_bus.get_object('com.canonical.Unity', + '/com/canonical/Unity/Dash') + dash_iface = dbus.Interface(dash_object, 'com.canonical.Unity.Dash') + dash_iface.HideDash() + class DashView(UnityIntrospectionObject): """The dash view.""" diff --git a/tests/autopilot/unity/tests/test_dash.py b/tests/autopilot/unity/tests/test_dash.py index 305712c69..226ee5e17 100644 --- a/tests/autopilot/unity/tests/test_dash.py +++ b/tests/autopilot/unity/tests/test_dash.py @@ -107,22 +107,6 @@ class DashRevealTests(DashTestCase): self.dash.reveal_application_lens() self.assertThat(self.dash.active_lens, Eventually(Equals('applications.lens'))) - def test_dash_stays_on_same_monitor(self): - """If the dash is opened, then the mouse is moved to another monitor and - the keyboard is used. The Dash must not move to that monitor. - """ - - if self.screen_geo.get_num_monitors() < 2: - self.skip ("This test must be ran with more then 1 monitor.") - - self.dash.ensure_visible() - self.addCleanup(self.dash.ensure_hidden) - - self.screen_geo.move_mouse_to_monitor(1) - self.keyboard.type("abc") - - self.assertThat(self.dash.ideal_monitor, Eventually(Equals(0))) - class DashSearchInputTests(DashTestCase): """Test features involving input to the dash search""" @@ -435,6 +419,9 @@ class DashClipboardTests(DashTestCase): class DashKeyboardFocusTests(DashTestCase): """Tests that keyboard focus works.""" + def assertSearchText(self, text): + self.assertThat(self.dash.search_string, Eventually(Equals(text))) + def test_filterbar_expansion_leaves_kb_focus(self): """Expanding or collapsing the filterbar must keave keyboard focus in the search bar. @@ -447,7 +434,19 @@ class DashKeyboardFocusTests(DashTestCase): filter_bar.ensure_expanded() self.addCleanup(filter_bar.ensure_collapsed) self.keyboard.type(" world") - self.assertThat(self.dash.search_string, Eventually(Equals("hello world"))) + self.assertSearchText("hello world") + + def test_keep_focus_on_application_opens(self): + """The Dash must keep key focus as well as stay open if an app gets opened from an external source. """ + + self.dash.ensure_visible() + self.addCleanup(self.hud.ensure_hidden) + + self.start_app_window("Calculator") + sleep(1) + + self.keyboard.type("HasFocus") + self.assertSearchText("HasFocus") class DashLensResultsTests(DashTestCase): @@ -847,3 +846,51 @@ class PreviewNavigateTests(DashTestCase): self.assertThat(self.dash.preview_displaying, Eventually(Equals(False))) + +class DashDBusIfaceTests(DashTestCase): + """Test the Unity dash DBus interface.""" + + def test_dash_hide(self): + """Ensure we can hide the dash via HideDash() dbus method.""" + self.dash.ensure_visible() + self.dash.controller.hide_dash_via_dbus() + self.assertThat(self.dash.visible, Eventually(Equals(False))) + self.dash.ensure_hidden() + + +class DashCrossMonitorsTests(DashTestCase): + """Multi-monitor dash tests.""" + + def setUp(self): + super(DashCrossMonitorsTests, self).setUp() + if self.screen_geo.get_num_monitors() < 2: + self.skipTest("This test requires more than 1 monitor.") + + def test_dash_stays_on_same_monitor(self): + """If the dash is opened, then the mouse is moved to another monitor and + the keyboard is used. The Dash must not move to that monitor. + """ + current_monitor = self.dash.ideal_monitor + + self.dash.ensure_visible() + self.addCleanup(self.dash.ensure_hidden) + + self.screen_geo.move_mouse_to_monitor((current_monitor + 1) % self.screen_geo.get_num_monitors()) + self.keyboard.type("abc") + + self.assertThat(self.dash.ideal_monitor, Eventually(Equals(current_monitor))) + + def test_dash_close_on_cross_monitor_click(self): + """Dash must close when clicking on a window in a different screen.""" + + self.addCleanup(self.dash.ensure_hidden) + + for monitor in range(self.screen_geo.get_num_monitors()-1): + self.screen_geo.move_mouse_to_monitor(monitor) + self.dash.ensure_visible() + + self.screen_geo.move_mouse_to_monitor(monitor+1) + sleep(.5) + self.mouse.click() + + self.assertThat(self.dash.visible, Eventually(Equals(False))) diff --git a/tests/autopilot/unity/tests/test_hud.py b/tests/autopilot/unity/tests/test_hud.py index 7ab18f86e..73137ff41 100644 --- a/tests/autopilot/unity/tests/test_hud.py +++ b/tests/autopilot/unity/tests/test_hud.py @@ -357,22 +357,6 @@ class HudBehaviorTests(HudTestsBase): self.assertThat(self.hud.visible, Eventually(Equals(False))) - def test_hud_stays_on_same_monitor(self): - """If the hud is opened, then the mouse is moved to another monitor and - the keyboard is used. The hud must not move to that monitor. - """ - - if self.screen_geo.get_num_monitors() < 2: - self.skip ("This test must be ran with more then 1 monitor.") - - self.hud.ensure_visible() - self.addCleanup(self.hud.ensure_hidden) - - self.screen_geo.move_mouse_to_monitor(1) - self.keyboard.type("abc") - - self.assertThat(self.hud.ideal_monitor, Eventually(Equals(0))) - def test_mouse_changes_selected_hud_button(self): """This tests moves the mouse from the top of the screen to the bottom, this must change the selected button from 1 to 5. @@ -408,6 +392,18 @@ class HudBehaviorTests(HudTestsBase): self.assertThat(self.hud.view.selected_button, Eventually(Equals(1))) + def test_keep_focus_on_application_opens(self): + """The Hud must keep key focus as well as stay open if an app gets opened from an external source. """ + + self.hud.ensure_visible() + self.addCleanup(self.hud.ensure_hidden) + + self.start_app_window("Calculator") + sleep(1) + + self.keyboard.type("HasFocus") + self.assertThat(self.hud.search_string, Eventually(Equals("HasFocus"))) + class HudLauncherInteractionsTests(HudTestsBase): @@ -661,3 +657,42 @@ class HudAlternativeKeybindingTests(HudTestsBase): # Don't use reveal_hud, but be explicit in the keybindings. self.keyboard.press_and_release("Ctrl+Alt+h") self.assertThat(self.hud.visible, Eventually(Equals(True))) + + +class HudCrossMonitorsTests(HudTestsBase): + """Multi-monitor hud tests.""" + + def setUp(self): + super(HudCrossMonitorsTests, self).setUp() + if self.screen_geo.get_num_monitors() < 2: + self.skipTest("This test requires more than 1 monitor.") + + def test_hud_stays_on_same_monitor(self): + """If the hud is opened, then the mouse is moved to another monitor and + the keyboard is used. The hud must not move to that monitor. + """ + + current_monitor = self.hud.ideal_monitor + + self.hud.ensure_visible() + self.addCleanup(self.hud.ensure_hidden) + + self.screen_geo.move_mouse_to_monitor((current_monitor + 1) % self.screen_geo.get_num_monitors()) + self.keyboard.type("abc") + + self.assertThat(self.hud.ideal_monitor, Eventually(Equals(current_monitor))) + + def test_hud_close_on_cross_monitor_click(self): + """Hud must close when clicking on a window in a different screen.""" + + self.addCleanup(self.hud.ensure_hidden) + + for monitor in range(self.screen_geo.get_num_monitors()-1): + self.screen_geo.move_mouse_to_monitor(monitor) + self.hud.ensure_visible() + + self.screen_geo.move_mouse_to_monitor(monitor+1) + sleep(.5) + self.mouse.click() + + self.assertThat(self.hud.visible, Eventually(Equals(False))) diff --git a/tests/test_icon_loader.cpp b/tests/test_icon_loader.cpp index f717bf585..509cdf541 100644 --- a/tests/test_icon_loader.cpp +++ b/tests/test_icon_loader.cpp @@ -47,7 +47,7 @@ struct LoadResult bool got_callback; LoadResult() : pixbuf(NULL), got_callback(false) {} - void IconLoaded(std::string const& icon_name, unsigned size, + void IconLoaded(std::string const& icon_name, int max_width, int max_height, glib::Object<GdkPixbuf> const& buf) { pixbuf = buf; @@ -71,7 +71,7 @@ TEST(TestIconLoader, TestGetOneIcon) IconLoader& icon_loader = IconLoader::GetDefault(); volatile bool timeout_reached = false; - icon_loader.LoadFromIconName("gedit-icon", 48, sigc::mem_fun(load_result, + icon_loader.LoadFromIconName("gedit-icon", -1, 48, sigc::mem_fun(load_result, &LoadResult::IconLoaded)); guint tid = g_timeout_add (10000, TimeoutReached, (gpointer)(&timeout_reached)); @@ -93,7 +93,7 @@ TEST(TestIconLoader, TestGetAnnotatedIcon) volatile bool timeout_reached = false; - icon_loader.LoadFromGIconString(". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'gedit-icon'%3E,%20'ribbon':%20%3C'foo'%3E%7D", 48, sigc::mem_fun(load_result, + icon_loader.LoadFromGIconString(". UnityProtocolAnnotatedIcon %7B'base-icon':%20%3C'gedit-icon'%3E,%20'ribbon':%20%3C'foo'%3E%7D", -1, 48, sigc::mem_fun(load_result, &LoadResult::IconLoaded)); guint tid = g_timeout_add (10000, TimeoutReached, (gpointer)(&timeout_reached)); @@ -125,7 +125,7 @@ TEST(TestIconLoader, TestGetOneIconManyTimes) // be cached already! for (int i = 0; i < load_count; i++) { - handles[i] = icon_loader.LoadFromIconName("web-browser", 48, + handles[i] = icon_loader.LoadFromIconName("web-browser", -1, 48, sigc::mem_fun(results[i], &LoadResult::IconLoaded)); } @@ -190,7 +190,7 @@ TEST(TestIconLoader, TestGetManyIcons) for (GList *it = icons; it != NULL; it = it->next) { const char *icon_name = static_cast<char*>(it->data); - icon_loader.LoadFromIconName(icon_name, 48, sigc::mem_fun(results[i++], + icon_loader.LoadFromIconName(icon_name, -1, 48, sigc::mem_fun(results[i++], &LoadResult::IconLoaded)); if (i >= icon_count) break; } @@ -235,7 +235,7 @@ TEST(TestIconLoader, TestCancelSome) for (GList *it = icons; it != NULL; it = it->next) { const char *icon_name = static_cast<char*>(it->data); - int handle = icon_loader.LoadFromIconName(icon_name, 48, sigc::mem_fun( + int handle = icon_loader.LoadFromIconName(icon_name, -1, 48, sigc::mem_fun( results[i], &LoadResult::IconLoaded)); handles[i++] = handle; if (i >= icon_count) break; diff --git a/tests/test_previews.cpp b/tests/test_previews.cpp index a688c7727..7707bd05e 100644 --- a/tests/test_previews.cpp +++ b/tests/test_previews.cpp @@ -77,8 +77,11 @@ TEST(TestPreviews, DeserializeGenericWithMeta) unity_protocol_preview_set_description(proto_obj, "Description"); unity_protocol_preview_set_image(proto_obj, icon); unity_protocol_preview_set_image_source_uri(proto_obj, "Source"); + + GHashTable* hints = g_hash_table_new(g_str_hash, g_str_equal); + g_hash_table_insert(hints, g_strdup("extra-text"), g_variant_new_string("Foo")); unity_protocol_preview_add_action(proto_obj, "action1", "Action #1", NULL, 0); - unity_protocol_preview_add_action(proto_obj, "action2", "Action #2", NULL, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action #2", NULL, 0, hints); unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("i", 34)); unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint")); @@ -106,11 +109,13 @@ TEST(TestPreviews, DeserializeGenericWithMeta) EXPECT_EQ(action1->display_name, "Action #1"); EXPECT_EQ(action1->icon_hint, ""); EXPECT_EQ(action1->layout_hint, 0); + EXPECT_EQ(action1->extra_text, ""); auto action2 = actions[1]; EXPECT_EQ(action2->id, "action2"); EXPECT_EQ(action2->display_name, "Action #2"); EXPECT_EQ(action2->icon_hint, ""); + EXPECT_EQ(action2->extra_text, "Foo"); EXPECT_EQ(info_hints.size(), 2); auto hint1 = info_hints[0]; diff --git a/tests/test_previews_application.cpp b/tests/test_previews_application.cpp index b98233b49..4ce33ed7d 100644 --- a/tests/test_previews_application.cpp +++ b/tests/test_previews_application.cpp @@ -34,6 +34,7 @@ using namespace testing; #include "dash/previews/ApplicationPreview.h" #include "dash/previews/PreviewInfoHintWidget.h" #include "dash/previews/PreviewRatingsWidget.h" +#include "dash/previews/ActionButton.h" #include "test_utils.h" using namespace unity; using namespace unity::dash; @@ -69,6 +70,9 @@ public: { glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_application_preview_new())); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£30.99")); + unity_protocol_application_preview_set_app_icon(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), g_icon_new_for_string("/home/nick/SkypeIcon.png", NULL)); unity_protocol_application_preview_set_license(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "License & special char"); unity_protocol_application_preview_set_copyright(UNITY_PROTOCOL_APPLICATION_PREVIEW(proto_obj.RawPtr()), "Copywrite & special char"); @@ -81,13 +85,15 @@ public: unity_protocol_preview_set_subtitle(proto_obj, "Application Subtitle > special char"); unity_protocol_preview_set_description(proto_obj, "Application Desctiption < special char"); unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); - unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1); unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); preview_model_ = dash::Preview::PreviewForVariant(v); + + g_hash_table_unref(action_hints1); } nux::BaseWindow* parent_window_; @@ -119,6 +125,24 @@ TEST_F(TestPreviewApplication, TestUIValues) EXPECT_EQ(preview_view->app_rating_->GetRating(), 0.8f); EXPECT_EQ(preview_view->action_buttons_.size(), 2); + + if (preview_view->action_buttons_.size() >= 2) + { + auto iter = preview_view->action_buttons_.begin(); + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 1"); + EXPECT_EQ(action->GetExtraText(), ""); + } + iter++; + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 2"); + EXPECT_EQ(action->GetExtraText(), "£30.99"); + } + } } } diff --git a/tests/test_previews_generic.cpp b/tests/test_previews_generic.cpp index b88020720..19f34f071 100644 --- a/tests/test_previews_generic.cpp +++ b/tests/test_previews_generic.cpp @@ -32,6 +32,7 @@ using namespace testing; #include <unity-protocol.h> #include "UnityCore/GenericPreview.h" #include "dash/previews/GenericPreview.h" +#include "dash/previews/ActionButton.h" #include "test_utils.h" using namespace unity; using namespace unity::dash; @@ -63,18 +64,23 @@ public: { glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_generic_preview_new())); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("2.00")); + unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg"); unity_protocol_preview_set_title(proto_obj, "Generic Title & special char"); unity_protocol_preview_set_subtitle(proto_obj, "Generic Subtitle > special char"); unity_protocol_preview_set_description(proto_obj, "Generic Desctiption < special char"); unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); - unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1); unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); preview_model_ = dash::Preview::PreviewForVariant(v); + + g_hash_table_unref(action_hints1); } nux::BaseWindow* parent_window_; @@ -102,6 +108,24 @@ TEST_F(TestPreviewGeneric, TestUIValues) EXPECT_EQ(preview_view->description_->GetText(), "Generic Desctiption < special char"); EXPECT_EQ(preview_view->action_buttons_.size(), 2); + + if (preview_view->action_buttons_.size() >= 2) + { + auto iter = preview_view->action_buttons_.begin(); + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 1"); + EXPECT_EQ(action->GetExtraText(), ""); + } + iter++; + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 2"); + EXPECT_EQ(action->GetExtraText(), "2.00"); + } + } } } diff --git a/tests/test_previews_movie.cpp b/tests/test_previews_movie.cpp index d22a25d07..aead90d58 100644 --- a/tests/test_previews_movie.cpp +++ b/tests/test_previews_movie.cpp @@ -34,6 +34,7 @@ using namespace testing; #include "dash/previews/MoviePreview.h" #include "dash/previews/PreviewInfoHintWidget.h" #include "dash/previews/PreviewRatingsWidget.h" +#include "dash/previews/ActionButton.h" #include "test_utils.h" using namespace unity; using namespace unity::dash; @@ -66,6 +67,9 @@ public: { glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_movie_preview_new())); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£1.00")); + unity_protocol_movie_preview_set_rating(UNITY_PROTOCOL_MOVIE_PREVIEW(proto_obj.RawPtr()), 0.8); unity_protocol_movie_preview_set_num_ratings(UNITY_PROTOCOL_MOVIE_PREVIEW(proto_obj.RawPtr()), 12); @@ -74,13 +78,15 @@ public: unity_protocol_preview_set_subtitle(proto_obj, "Movie Subtitle > special char"); unity_protocol_preview_set_description(proto_obj, "Movie Desctiption < special char"); unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); - unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1); unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); unity_protocol_preview_add_info_hint(proto_obj, "hint2", "Hint 2", NULL, g_variant_new("s", "string hint 2")); unity_protocol_preview_add_info_hint(proto_obj, "hint3", "Hint 3", NULL, g_variant_new("i", 12)); glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); preview_model_ = dash::Preview::PreviewForVariant(v); + + g_hash_table_unref(action_hints1); } nux::BaseWindow* parent_window_; @@ -109,6 +115,24 @@ TEST_F(TestPreviewMovie, TestUIValues) EXPECT_EQ(preview_view->rating_->GetRating(), 0.8f); EXPECT_EQ(preview_view->action_buttons_.size(), 2); + + if (preview_view->action_buttons_.size() >= 2) + { + auto iter = preview_view->action_buttons_.begin(); + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 1"); + EXPECT_EQ(action->GetExtraText(), ""); + } + iter++; + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 2"); + EXPECT_EQ(action->GetExtraText(), "£1.00"); + } + } } } diff --git a/tests/test_previews_music.cpp b/tests/test_previews_music.cpp index aa43117ef..a8437feef 100644 --- a/tests/test_previews_music.cpp +++ b/tests/test_previews_music.cpp @@ -34,6 +34,7 @@ using namespace testing; #include "dash/previews/MusicPreview.h" #include "dash/previews/PreviewInfoHintWidget.h" #include "dash/previews/PreviewRatingsWidget.h" +#include "dash/previews/ActionButton.h" #include "test_utils.h" using namespace unity; using namespace unity::dash; @@ -64,12 +65,15 @@ public: { glib::Object<UnityProtocolPreview> proto_obj(UNITY_PROTOCOL_PREVIEW(unity_protocol_music_preview_new())); + GHashTable* action_hints1(g_hash_table_new(g_direct_hash, g_direct_equal)); + g_hash_table_insert (action_hints1, g_strdup ("extra-text"), g_variant_new_string("£3.99")); + unity_protocol_preview_set_image_source_uri(proto_obj, "http://ia.media-imdb.com/images/M/MV5BMTM3NDM5MzY5Ml5BMl5BanBnXkFtZTcwNjExMDUwOA@@._V1._SY317_.jpg"); unity_protocol_preview_set_title(proto_obj, "Music Title & special char"); unity_protocol_preview_set_subtitle(proto_obj, "Music Subtitle > special char"); unity_protocol_preview_set_description(proto_obj, "Music Desctiption < special char"); unity_protocol_preview_add_action(proto_obj, "action1", "Action 1", NULL, 0); - unity_protocol_preview_add_action(proto_obj, "action2", "Action 2", NULL, 0); + unity_protocol_preview_add_action_with_hints(proto_obj, "action2", "Action 2", NULL, 0, action_hints1); unity_protocol_preview_add_action(proto_obj, "action3", "Action 3", NULL, 0); unity_protocol_preview_add_action(proto_obj, "action4", "Action 4", NULL, 0); unity_protocol_preview_add_info_hint(proto_obj, "hint1", "Hint 1", NULL, g_variant_new("s", "string hint 1")); @@ -78,6 +82,8 @@ public: glib::Variant v(dee_serializable_serialize(DEE_SERIALIZABLE(proto_obj.RawPtr())), glib::StealRef()); preview_model_ = dash::Preview::PreviewForVariant(v); + + g_hash_table_unref(action_hints1); } nux::BaseWindow* parent_window_; @@ -104,6 +110,24 @@ TEST_F(TestPreviewMusic, TestUIValues) EXPECT_EQ(preview_view->subtitle_->GetText(), "Music Subtitle > special char"); EXPECT_EQ(preview_view->action_buttons_.size(), 4); + + if (preview_view->action_buttons_.size() >= 2) + { + auto iter = preview_view->action_buttons_.begin(); + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 1"); + EXPECT_EQ(action->GetExtraText(), ""); + } + iter++; + if ((*iter)->Type().IsDerivedFromType(ActionButton::StaticObjectType)) + { + ActionButton *action = static_cast<ActionButton*>(*iter); + EXPECT_EQ(action->GetLabel(), "Action 2"); + EXPECT_EQ(action->GetExtraText(), "£3.99"); + } + } } } diff --git a/unity-shared/CoverArt.cpp b/unity-shared/CoverArt.cpp index ac8044e5a..725e038e2 100644 --- a/unity-shared/CoverArt.cpp +++ b/unity-shared/CoverArt.cpp @@ -41,7 +41,7 @@ namespace { nux::logging::Logger logger("unity.dash.previews.coverart"); -const int icon_width = 256; +const int ICON_SIZE = 256; } NUX_IMPLEMENT_OBJECT_TYPE(CoverArt); @@ -109,9 +109,9 @@ void CoverArt::SetImage(std::string const& image_hint) // texture from file. if (bLoadTexture) - { + { StartWaiting(); - slot_handle_ = IconLoader::GetDefault().LoadFromGIconString(image_hint, ~0, sigc::mem_fun(this, &CoverArt::TextureLoaded)); + slot_handle_ = IconLoader::GetDefault().LoadFromGIconString(image_hint, -1, -1, sigc::mem_fun(this, &CoverArt::TextureLoaded)); } else if (!image_hint.empty()) { @@ -121,12 +121,12 @@ void CoverArt::SetImage(std::string const& image_hint) if (G_IS_ICON(icon)) { StartWaiting(); - slot_handle_ = IconLoader::GetDefault().LoadFromGIconString(image_hint, icon_width, sigc::mem_fun(this, &CoverArt::IconLoaded)); + slot_handle_ = IconLoader::GetDefault().LoadFromGIconString(image_hint, ICON_SIZE, ICON_SIZE, sigc::mem_fun(this, &CoverArt::IconLoaded)); } else { StartWaiting(); - slot_handle_ = IconLoader::GetDefault().LoadFromIconName(image_hint, icon_width, sigc::mem_fun(this, &CoverArt::IconLoaded)); + slot_handle_ = IconLoader::GetDefault().LoadFromIconName(image_hint, ICON_SIZE, ICON_SIZE, sigc::mem_fun(this, &CoverArt::IconLoaded)); } } else @@ -195,7 +195,10 @@ void CoverArt::SetNoImageAvailable() } } -void CoverArt::IconLoaded(std::string const& texid, unsigned size, glib::Object<GdkPixbuf> const& pixbuf) +void CoverArt::IconLoaded(std::string const& texid, + int max_width, + int max_height, + glib::Object<GdkPixbuf> const& pixbuf) { // Finished waiting StopWaiting(); @@ -207,7 +210,7 @@ void CoverArt::IconLoaded(std::string const& texid, unsigned size, glib::Object< return; } - int height = size; + int height = max_height; int pixbuf_width, pixbuf_height; pixbuf_width = gdk_pixbuf_get_width(pixbuf); @@ -232,7 +235,7 @@ void CoverArt::IconLoaded(std::string const& texid, unsigned size, glib::Object< float aspect = static_cast<float>(pixbuf_height) / pixbuf_width; // already sanitized width/height so can not be 0.0 if (aspect < 1.0f) { - pixbuf_width = icon_width; + pixbuf_width = ICON_SIZE; pixbuf_height = pixbuf_width * aspect; if (pixbuf_height > height) @@ -274,7 +277,10 @@ void CoverArt::IconLoaded(std::string const& texid, unsigned size, glib::Object< } } -void CoverArt::TextureLoaded(std::string const& texid, unsigned size, glib::Object<GdkPixbuf> const& pixbuf) +void CoverArt::TextureLoaded(std::string const& texid, + int max_width, + int max_height, + glib::Object<GdkPixbuf> const& pixbuf) { // Finished waiting StopWaiting(); @@ -293,10 +299,12 @@ void CoverArt::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + gfx_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfx_engine, base); - if (bg_layer_) + if (enable_bg_shadows && bg_layer_) { unsigned int alpha, src, dest = 0; gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); @@ -317,7 +325,9 @@ void CoverArt::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); - if (!IsFullRedraw()) + bool enable_bg_shadows = dash::previews::Style::Instance().GetShadowBackgroundEnabled(); + + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PushLayer(gfx_engine, bg_layer_->GetGeometry(), bg_layer_.get()); unsigned int alpha, src, dest = 0; @@ -416,7 +426,7 @@ void CoverArt::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) if (GetLayout()) GetLayout()->ProcessDraw(gfx_engine, force_draw); - if (!IsFullRedraw()) + if (enable_bg_shadows && !IsFullRedraw()) nux::GetPainter().PopBackground(); gfx_engine.PopClippingRectangle(); @@ -489,4 +499,4 @@ bool CoverArt::OnFrameTimeout() } } -} \ No newline at end of file +} diff --git a/unity-shared/CoverArt.h b/unity-shared/CoverArt.h index 747633d1d..592eec2b9 100644 --- a/unity-shared/CoverArt.h +++ b/unity-shared/CoverArt.h @@ -70,8 +70,8 @@ protected: void OnThumbnailError(std::string const& error_hint); bool OnFrameTimeout(); - void IconLoaded(std::string const& texid, unsigned size, glib::Object<GdkPixbuf> const& pixbuf); - void TextureLoaded(std::string const& texid, unsigned size, glib::Object<GdkPixbuf> const& pixbuf); + void IconLoaded(std::string const& texid, int max_width, int max_height, glib::Object<GdkPixbuf> const& pixbuf); + void TextureLoaded(std::string const& texid, int max_width, int max_height, glib::Object<GdkPixbuf> const& pixbuf); void StartWaiting(); void StopWaiting(); @@ -105,4 +105,4 @@ private: } } -#endif // APPLICATIONSCREENSHOT_H \ No newline at end of file +#endif // APPLICATIONSCREENSHOT_H diff --git a/unity-shared/DashStyle.cpp b/unity-shared/DashStyle.cpp index 8ac12c7d7..27c730f0c 100755 --- a/unity-shared/DashStyle.cpp +++ b/unity-shared/DashStyle.cpp @@ -196,6 +196,8 @@ public: int text_height_; int number_of_columns_; + LazyLoadTexture category_texture_; + LazyLoadTexture category_texture_no_filters_; LazyLoadTexture dash_bottom_texture_; LazyLoadTexture dash_bottom_texture_mask_; LazyLoadTexture dash_right_texture_; @@ -218,6 +220,11 @@ public: LazyLoadTexture search_close_texture_; LazyLoadTexture search_spin_texture_; + + LazyLoadTexture refine_gradient_corner_; + LazyLoadTexture refine_gradient_dash_; + LazyLoadTexture refine_gradient_no_refine_dash_; + LazyLoadTexture group_unexpand_texture_; LazyLoadTexture group_expand_texture_; @@ -239,6 +246,8 @@ Style::Impl::Impl(Style* owner) , text_width_(0) , text_height_(0) , number_of_columns_(6) + , category_texture_("/category_gradient.png") + , category_texture_no_filters_("/category_gradient_no_refine.png") , dash_bottom_texture_("/dash_bottom_border_tile.png") , dash_bottom_texture_mask_("/dash_bottom_border_tile_mask.png") , dash_right_texture_("/dash_right_border_tile.png") @@ -258,6 +267,9 @@ Style::Impl::Impl(Style* owner) , search_circle_texture_("/search_circle.svg", 32) , search_close_texture_("/search_close.svg", 32) , search_spin_texture_("/search_spin.svg", 32) + , refine_gradient_corner_("/refine_gradient_corner.png") + , refine_gradient_dash_("/refine_gradient_dash.png") + , refine_gradient_no_refine_dash_("/refine_gradient_dash_no_refine.png") , group_unexpand_texture_("/dash_group_unexpand.png") , group_expand_texture_("/dash_group_expand.png") , star_deselected_texture_("/star_deselected.png") @@ -2044,11 +2056,16 @@ void Style::SetDefaultNColumns(int n_cols) columns_changed.emit(); } -int Style::GetTileIconSize() const +int Style::GetTileGIconSize() const { return 64; } +int Style::GetTileImageSize() const +{ + return 96; +} + int Style::GetTileWidth() const { return std::max(pimpl->text_width_, 150); @@ -2056,8 +2073,18 @@ int Style::GetTileWidth() const int Style::GetTileHeight() const { - return std::max(GetTileIconSize() + (pimpl->text_height_ * 2) + 10, - GetTileIconSize() + 50 + 18); // magic design numbers. + return std::max(GetTileImageSize() + (pimpl->text_height_ * 2) + 15, + GetTileImageSize() + 32); // magic design numbers. +} + +int Style::GetTileIconHightlightHeight() const +{ + return 106; +} + +int Style::GetTileIconHightlightWidth() const +{ + return 106; } int Style::GetHomeTileIconSize() const @@ -2081,6 +2108,16 @@ int Style::GetTextLineHeight() const } +nux::BaseTexture* Style::GetCategoryBackground() +{ + return pimpl->category_texture_.texture(); +} + +nux::BaseTexture* Style::GetCategoryBackgroundNoFilters() +{ + return pimpl->category_texture_no_filters_.texture(); +} + nux::BaseTexture* Style::GetDashBottomTile() { return pimpl->dash_bottom_texture_.texture(); @@ -2171,6 +2208,21 @@ nux::BaseTexture* Style::GetSearchSpinIcon() return pimpl->search_spin_texture_.texture(); } +nux::BaseTexture* Style::GetRefineTextureCorner() +{ + return pimpl->refine_gradient_corner_.texture(); +} + +nux::BaseTexture* Style::GetRefineNoRefineTextureDash() +{ + return pimpl->refine_gradient_no_refine_dash_.texture(); +} + +nux::BaseTexture* Style::GetRefineTextureDash() +{ + return pimpl->refine_gradient_dash_.texture(); +} + nux::BaseTexture* Style::GetGroupUnexpandIcon() { return pimpl->group_unexpand_texture_.texture(); @@ -2315,7 +2367,7 @@ int Style::GetCategoryHighlightHeight() const int Style::GetPlacesGroupTopSpace() const { - return 15; + return 7; } int Style::GetCategoryHeaderLeftPadding() const diff --git a/unity-shared/DashStyle.h b/unity-shared/DashStyle.h index 440914d7d..0592fdbe2 100755 --- a/unity-shared/DashStyle.h +++ b/unity-shared/DashStyle.h @@ -155,9 +155,12 @@ public: void SetDefaultNColumns(int n_cols); sigc::signal<void> columns_changed; - int GetTileIconSize() const; + int GetTileGIconSize() const; + int GetTileImageSize() const; int GetTileWidth() const; int GetTileHeight() const; + int GetTileIconHightlightHeight() const; + int GetTileIconHightlightWidth() const; int GetHomeTileIconSize() const; int GetHomeTileWidth() const; @@ -165,6 +168,8 @@ public: int GetTextLineHeight() const; + nux::BaseTexture* GetCategoryBackground(); + nux::BaseTexture* GetCategoryBackgroundNoFilters(); nux::BaseTexture* GetDashBottomTile(); nux::BaseTexture* GetDashBottomTileMask(); nux::BaseTexture* GetDashRightTile(); @@ -196,7 +201,11 @@ public: nux::BaseTexture* GetStarDeselectedIcon(); nux::BaseTexture* GetStarSelectedIcon(); nux::BaseTexture* GetStarHighlightIcon(); - + + nux::BaseTexture* GetRefineTextureCorner(); + nux::BaseTexture* GetRefineTextureDash(); + nux::BaseTexture* GetRefineNoRefineTextureDash(); + // Returns the width of the separator between the dash and the launcher. int GetVSeparatorSize() const; @@ -206,6 +215,7 @@ public: // Practically it is the space between the top border of the dash and the searchbar. int GetDashViewTopPadding() const; + // Search bar int GetSearchBarLeftPadding() const; int GetSearchBarRightPadding() const; diff --git a/unity-shared/IconLoader.cpp b/unity-shared/IconLoader.cpp index 7d236cb19..7812b6b25 100644 --- a/unity-shared/IconLoader.cpp +++ b/unity-shared/IconLoader.cpp @@ -18,6 +18,7 @@ */ #include "IconLoader.h" +#include "config.h" #include <queue> #include <sstream> @@ -39,7 +40,8 @@ namespace unity namespace { nux::logging::Logger logger("unity.iconloader"); -const unsigned MIN_ICON_SIZE = 2; +const int MIN_ICON_SIZE = 2; +const int RIBBON_PADDING = 2; } class IconLoader::Impl @@ -48,25 +50,29 @@ public: // The Handle typedef is used to explicitly indicate which integers are // infact our opaque handles. typedef int Handle; - static const int FONT_SIZE = 10; - static const int MIN_FONT_SIZE = 6; + static const int FONT_SIZE = 8; + static const int MIN_FONT_SIZE = 5; Impl(); Handle LoadFromIconName(std::string const& icon_name, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); Handle LoadFromGIconString(std::string const& gicon_string, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); Handle LoadFromFilename(std::string const& filename, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); Handle LoadFromURI(std::string const& uri, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); void DisconnectHandle(Handle handle); @@ -88,7 +94,8 @@ private: IconLoaderRequestType type; std::string data; - unsigned int size; + int max_width; + int max_height; std::string key; IconLoaderCallback slot; Handle handle; @@ -103,12 +110,14 @@ private: IconLoaderTask(IconLoaderRequestType type_, std::string const& data_, - unsigned size_, + int max_width_, + int max_height_, std::string const& key_, IconLoaderCallback slot_, Handle handle_, Impl* self_) - : type(type_), data(data_), size(size_), key(key_) + : type(type_), data(data_), max_width(max_width_) + , max_height(max_height_), key(key_) , slot(slot_), handle(handle_), impl(self_) , icon_info(nullptr), no_cache(false), helper_handle(0), idle_id(0) {} @@ -126,13 +135,16 @@ private: void InvokeSlot() { if (slot) - slot(data, size, result); + slot(data, max_width, max_height, result); // notify shadow tasks for (auto shadow_task : shadow_tasks) { if (shadow_task->slot) - shadow_task->slot(shadow_task->data, shadow_task->size, result); + shadow_task->slot(shadow_task->data, + shadow_task->max_width, + shadow_task->max_height, + result); impl->task_map_.erase(shadow_task->handle); } @@ -143,10 +155,10 @@ private: bool Process() { // Check the cache again, as previous tasks might have wanted the same - if (impl->CacheLookup(key, data, size, slot)) + if (impl->CacheLookup(key, data, max_width, max_height, slot)) return true; - LOG_DEBUG(logger) << "Processing " << data << " at size " << size; + LOG_DEBUG(logger) << "Processing " << data << " at size " << max_height; // Rely on the compiler to tell us if we miss a new type switch (type) @@ -161,7 +173,7 @@ private: LOG_WARNING(logger) << "Request type " << type << " is not supported (" << data - << " " << size << ")"; + << " " << max_width << "x" << max_height << ")"; result = nullptr; InvokeSlot(); @@ -170,6 +182,7 @@ private: bool ProcessIconNameTask() { + int size = max_height < 0 ? max_width : (max_width < 0 ? max_height : MIN(max_height, max_width)); GtkIconInfo* info = ::gtk_icon_theme_lookup_icon(impl->theme_, data.c_str(), size, static_cast<GtkIconLookupFlags>(0)); if (info) @@ -195,6 +208,7 @@ private: { glib::Error error; glib::Object<GIcon> icon(::g_icon_new_for_string(data.c_str(), &error)); + int size = max_height < 0 ? max_width : (max_width < 0 ? max_height : MIN(max_height, max_width)); if (icon.IsType(UNITY_PROTOCOL_TYPE_ANNOTATED_ICON)) { @@ -205,8 +219,12 @@ private: no_cache = true; auto helper_slot = sigc::bind(sigc::mem_fun(this, &IconLoaderTask::BaseIconLoaded), glib::object_cast<UnityProtocolAnnotatedIcon>(icon)); + int base_icon_width = max_width > 0 ? max_width - RIBBON_PADDING * 2 : -1; + int base_icon_height = base_icon_width < 0 ? max_height - RIBBON_PADDING *2 : max_height; helper_handle = impl->LoadFromGIconString(gicon_string.Str(), - size, helper_slot); + base_icon_width, + base_icon_height, + helper_slot); return false; } @@ -271,40 +289,32 @@ private: return false; } - void CategoryIconLoaded(std::string const& base_icon_string, unsigned size, + void CategoryIconLoaded(std::string const& base_icon_string, + int max_width, int max_height, glib::Object<GdkPixbuf> const& category_pixbuf, glib::Object<UnityProtocolAnnotatedIcon> const& anno_icon) { helper_handle = 0; - if (category_pixbuf) - { - // assuming the category pixbuf is smaller than result - gdk_pixbuf_composite(category_pixbuf, result, // src, dest - 0, 0, // dest_x, dest_y - gdk_pixbuf_get_width(category_pixbuf), // dest_w - gdk_pixbuf_get_height(category_pixbuf), // dest_h - 0.0, 0.0, // offset_x, offset_y - 1.0, 1.0, // scale_x, scale_y - GDK_INTERP_NEAREST, // interpolation - 255); // src_alpha - } + bool has_emblem = category_pixbuf; const gchar* detail_text = unity_protocol_annotated_icon_get_ribbon(anno_icon); if (detail_text) { + const int SHADOW_BOTTOM_PADDING = 2; + const int SHADOW_SIDE_PADDING = 1; int icon_w = gdk_pixbuf_get_width(result); int icon_h = gdk_pixbuf_get_height(result); int max_font_height; CalculateTextHeight(nullptr, &max_font_height); - max_font_height = max_font_height * 9 / 8; // let's have some padding on the stripe - int pixbuf_size = static_cast<int>( - sqrt(max_font_height*max_font_height*8)); - if (pixbuf_size > icon_w) pixbuf_size = icon_w; + // FIXME: design wants the tags 2px wider than the original icon + int pixbuf_width = icon_w; + int pixbuf_height = max_font_height * 5 / 4 + SHADOW_BOTTOM_PADDING; + if (pixbuf_height > icon_h) pixbuf_height = icon_h; nux::CairoGraphics cairo_graphics(CAIRO_FORMAT_ARGB32, - pixbuf_size, pixbuf_size); + pixbuf_width, pixbuf_height); std::shared_ptr<cairo_t> cr(cairo_graphics.GetContext(), cairo_destroy); glib::Object<PangoLayout> layout; @@ -325,10 +335,9 @@ private: pango_layout_set_font_description(layout, desc.get()); pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER); - double size_dbl = static_cast<double>(pixbuf_size); - // we'll allow tiny bit of overflow since the text is rotated and there - // is some space left... FIXME: 10/9? / 11/10? - double max_text_width = sqrt(size_dbl*size_dbl / 2) * 9/8; + // magic constant for the text width based on the white curve + double max_text_width = has_emblem ? + pixbuf_width * 0.72 : pixbuf_width; pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END); @@ -337,9 +346,8 @@ private: pango_layout_set_markup(layout, escaped_text, -1); pango_context = pango_layout_get_context(layout); // is not ref'ed - // FIXME: for reasons unknown, it looks better without this - //pango_cairo_context_set_font_options(pango_context, - // gdk_screen_get_font_options(screen)); + pango_cairo_context_set_font_options(pango_context, + gdk_screen_get_font_options(screen)); pango_cairo_context_set_resolution(pango_context, dpi == -1 ? 96.0f : dpi/(float) PANGO_SCALE); pango_layout_context_changed(layout); @@ -361,32 +369,117 @@ private: cairo_set_operator(cr.get(), CAIRO_OPERATOR_OVER); - // draw the trapezoid - cairo_move_to(cr.get(), 0.0, size_dbl); - cairo_line_to(cr.get(), size_dbl, 0.0); - cairo_line_to(cr.get(), size_dbl, size_dbl / 2.0); - cairo_line_to(cr.get(), size_dbl / 2.0, size_dbl); - cairo_close_path(cr.get()); - // this should be #dd4814 - cairo_set_source_rgba(cr.get(), 0.86666f, 0.28235f, 0.07843f, 1.0f); + const double ORANGE_R = 0.86666; + const double ORANGE_G = 0.28235; + const double ORANGE_B = 0.07843; + + double belt_w = static_cast<double>(pixbuf_width - SHADOW_SIDE_PADDING * 2); + double belt_h = static_cast<double>(pixbuf_height - SHADOW_BOTTOM_PADDING); + + // translate to make space for the shadow + cairo_save(cr.get()); + cairo_translate(cr.get(), 1.0, 1.0); + + cairo_set_source_rgba(cr.get(), ORANGE_R, ORANGE_G, ORANGE_B, 1.0); + + cairo_rectangle(cr.get(), 0.0, 0.0, belt_w, belt_h); + cairo_fill_preserve(cr.get()); + + std::shared_ptr<cairo_pattern_t> pattern( + cairo_pattern_create_linear(0.0, 0.0, belt_w, 0.0), + cairo_pattern_destroy); + cairo_pattern_add_color_stop_rgba(pattern.get(), 0.0, 1.0, 1.0, 1.0, 0.235294); + cairo_pattern_add_color_stop_rgba(pattern.get(), 0.02, 1.0, 1.0, 1.0, 0.0); + if (!has_emblem) + { + cairo_pattern_add_color_stop_rgba(pattern.get(), 0.98, 1.0, 1.0, 1.0, 0.0); + cairo_pattern_add_color_stop_rgba(pattern.get(), 1.0, 1.0, 1.0, 1.0, 0.235294); + } + cairo_pattern_add_color_stop_rgba(pattern.get(), 1.0, 1.0, 1.0, 1.0, 0.0); + + cairo_set_source(cr.get(), pattern.get()); cairo_fill(cr.get()); - // draw the text (rotated!) - cairo_set_source_rgba(cr.get(), 1.0f, 1.0f, 1.0f, 1.0f); - cairo_move_to(cr.get(), size_dbl * 0.25, size_dbl); - cairo_rotate(cr.get(), -G_PI_4); // rotate by -45 degrees + if (has_emblem) + { + // paint the curve + const double CURVE_START_XPOS = 0.631163; // 0.651163 + const double CURVE_CP1_XPOS = CURVE_START_XPOS + 0.068023; + const double CURVE_CP2_XPOS = CURVE_START_XPOS + 0.07; + const double CURVE_CP3_XPOS = CURVE_START_XPOS + 0.102965; + const double CURVE_CP4_XPOS = CURVE_START_XPOS + 0.161511; + const double CURVE_CP5_XPOS = CURVE_START_XPOS + 0.197093; + const double CURVE_END_XPOS = CURVE_START_XPOS + 0.265779; + + const double CURVE_START_X = CURVE_START_XPOS * belt_w; + + cairo_set_source_rgba(cr.get(), 1.0, 1.0, 1.0, 1.0); + + cairo_move_to(cr.get(), CURVE_START_XPOS * belt_w, belt_h); + cairo_curve_to(cr.get(), CURVE_CP1_XPOS * belt_w, belt_h, + CURVE_CP2_XPOS * belt_w, 0.9825 * belt_h, + CURVE_CP3_XPOS * belt_w, 0.72725 * belt_h); + cairo_line_to(cr.get(), CURVE_CP4_XPOS * belt_w, 0.27275 * belt_h); + cairo_curve_to(cr.get(), CURVE_CP5_XPOS * belt_w, 0.0, + CURVE_CP5_XPOS * belt_w, 0.0, + CURVE_END_XPOS * belt_w, 0.0); + cairo_line_to(cr.get(), belt_w, 0.0); + cairo_line_to(cr.get(), belt_w, belt_h); + cairo_close_path(cr.get()); + cairo_fill(cr.get()); + + // and the highlight + pattern.reset(cairo_pattern_create_linear(CURVE_START_X, 0.0, belt_w, 0.0), + cairo_pattern_destroy); + cairo_pattern_add_color_stop_rgba(pattern.get(), 0.0, 1.0, 1.0, 1.0, 0.0); + cairo_pattern_add_color_stop_rgba(pattern.get(), 0.95, 1.0, 1.0, 1.0, 0.0); + cairo_pattern_add_color_stop_rgba(pattern.get(), 1.0, 0.0, 0.0, 0.0, 0.235294); + cairo_set_source(cr.get(), pattern.get()); + cairo_rectangle(cr.get(), CURVE_START_X, 0.0, belt_w - CURVE_START_X, belt_h); + cairo_fill(cr.get()); + + // paint the emblem + int category_pb_w = gdk_pixbuf_get_width(category_pixbuf); + int category_pb_h = gdk_pixbuf_get_height(category_pixbuf); + double category_pb_x = + belt_w - category_pb_w > CURVE_CP4_XPOS * belt_w ? + CURVE_CP4_XPOS * belt_w + ((1 - CURVE_CP4_XPOS) * belt_w - category_pb_w) / 2 : CURVE_CP4_XPOS * belt_w; + gdk_cairo_set_source_pixbuf(cr.get(), category_pixbuf, + category_pb_x, (belt_h - category_pb_h) / 2); + cairo_paint(cr.get()); + } - pango_cairo_update_layout(cr.get(), layout); + cairo_set_source_rgba(cr.get(), 1.0, 1.0, 1.0, 1.0); + cairo_move_to(cr.get(), 0.0, belt_h / 2); pango_layout_get_pixel_size(layout, nullptr, &text_height); // current point is now in the middle of the stripe, need to translate // it, so that the text is centered cairo_rel_move_to(cr.get(), 0.0, text_height / -2.0); - double diagonal = sqrt(size_dbl*size_dbl*2); - // x coordinate also needs to be shifted - cairo_rel_move_to(cr.get(), (diagonal - max_text_width) / 4, 0.0); pango_cairo_show_layout(cr.get(), layout); + // paint the shadow + cairo_restore(cr.get()); + + pattern.reset(cairo_pattern_create_linear(0.0, belt_h, 0.0, belt_h + SHADOW_BOTTOM_PADDING), + cairo_pattern_destroy); + cairo_pattern_add_color_stop_rgba(pattern.get(), 0.0, 0.0, 0.0, 0.0, 0.2); + cairo_pattern_add_color_stop_rgba(pattern.get(), 1.0, 0.0, 0.0, 0.0, 0.0); + + cairo_set_source(cr.get(), pattern.get()); + + cairo_rectangle(cr.get(), 0.0, belt_h, belt_w, SHADOW_BOTTOM_PADDING); + cairo_fill(cr.get()); + + cairo_set_source_rgba(cr.get(), 0.0, 0.0, 0.0, 0.1); + cairo_move_to(cr.get(), 0.0, 1.0); + cairo_line_to(cr.get(), 0.0, belt_h); + cairo_stroke(cr.get()); + + cairo_move_to(cr.get(), belt_w, 1.0); + cairo_line_to(cr.get(), belt_w, belt_h); + cairo_stroke(cr.get()); + // FIXME: going from image_surface to pixbuf, and then to texture :( glib::Object<GdkPixbuf> detail_pb( gdk_pixbuf_get_from_surface(cairo_graphics.GetSurface(), @@ -394,13 +487,14 @@ private: cairo_graphics.GetWidth(), cairo_graphics.GetHeight())); + int y_pos = icon_h - pixbuf_height - max_font_height / 2; gdk_pixbuf_composite(detail_pb, result, // src, dest - icon_w - pixbuf_size, // dest_x - icon_h - pixbuf_size, // dest_y - pixbuf_size, // dest_w - pixbuf_size, // dest_h - icon_w - pixbuf_size, // offset_x - icon_h - pixbuf_size, // offset_y + 0, // dest_x + y_pos, // dest_y + pixbuf_width, // dest_w + pixbuf_height, // dest_h + 0, // offset_x + y_pos, // offset_y 1.0, 1.0, // scale_x, scale_y GDK_INTERP_NEAREST, // interpolation 255); // src_alpha @@ -409,29 +503,76 @@ private: idle_id = g_idle_add(LoadIconComplete, this); } - void BaseIconLoaded(std::string const& base_icon_string, unsigned size, + void BaseIconLoaded(std::string const& base_icon_string, + int max_width, int max_height, glib::Object<GdkPixbuf> const& base_pixbuf, glib::Object<UnityProtocolAnnotatedIcon> const& anno_icon) { helper_handle = 0; if (base_pixbuf) { - result = gdk_pixbuf_copy(base_pixbuf); + LOG_DEBUG(logger) << "Base icon loaded: '" << base_icon_string << + "' size: " << gdk_pixbuf_get_width(base_pixbuf) << 'x' << + gdk_pixbuf_get_height(base_pixbuf); + + // we need extra space for the ribbon + result = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, + gdk_pixbuf_get_width(base_pixbuf) + RIBBON_PADDING * 2, + gdk_pixbuf_get_height(base_pixbuf)); + gdk_pixbuf_fill(result, 0x0); + gdk_pixbuf_copy_area(base_pixbuf, 0, 0, + gdk_pixbuf_get_width(base_pixbuf), + gdk_pixbuf_get_height(base_pixbuf), + result, + RIBBON_PADDING, 0); // FIXME: can we composite the pixbuf in helper thread? UnityProtocolCategoryType category = unity_protocol_annotated_icon_get_category(anno_icon); auto helper_slot = sigc::bind(sigc::mem_fun(this, &IconLoaderTask::CategoryIconLoaded), anno_icon); - unsigned cat_size = size / 4; - // FIXME: we still don't have the category assets + int max_font_height; + CalculateTextHeight(nullptr, &max_font_height); + unsigned cat_size = max_font_height * 9 / 8; switch (category) { + case UNITY_PROTOCOL_CATEGORY_TYPE_BOOK: + helper_handle = + impl->LoadFromFilename(PKGDATADIR"/emblem_books.svg", -1, cat_size, helper_slot); + break; case UNITY_PROTOCOL_CATEGORY_TYPE_MUSIC: helper_handle = - impl->LoadFromIconName("emblem-favorite", cat_size, helper_slot); + impl->LoadFromFilename(PKGDATADIR"/emblem_music.svg", -1, cat_size, helper_slot); break; + case UNITY_PROTOCOL_CATEGORY_TYPE_MOVIE: + helper_handle = + impl->LoadFromFilename(PKGDATADIR"/emblem_video.svg", -1, cat_size, helper_slot); + break; + case UNITY_PROTOCOL_CATEGORY_TYPE_CLOTHES: + case UNITY_PROTOCOL_CATEGORY_TYPE_SHOES: + helper_handle = + impl->LoadFromFilename(PKGDATADIR"/emblem_clothes.svg", -1, cat_size, helper_slot); + break; + case UNITY_PROTOCOL_CATEGORY_TYPE_GAMES: + case UNITY_PROTOCOL_CATEGORY_TYPE_ELECTRONICS: + case UNITY_PROTOCOL_CATEGORY_TYPE_COMPUTERS: + case UNITY_PROTOCOL_CATEGORY_TYPE_OFFICE: + case UNITY_PROTOCOL_CATEGORY_TYPE_HOME: + case UNITY_PROTOCOL_CATEGORY_TYPE_GARDEN: + case UNITY_PROTOCOL_CATEGORY_TYPE_PETS: + case UNITY_PROTOCOL_CATEGORY_TYPE_TOYS: + case UNITY_PROTOCOL_CATEGORY_TYPE_CHILDREN: + case UNITY_PROTOCOL_CATEGORY_TYPE_BABY: + case UNITY_PROTOCOL_CATEGORY_TYPE_WATCHES: + case UNITY_PROTOCOL_CATEGORY_TYPE_SPORTS: + case UNITY_PROTOCOL_CATEGORY_TYPE_OUTDOORS: + case UNITY_PROTOCOL_CATEGORY_TYPE_GROCERY: + case UNITY_PROTOCOL_CATEGORY_TYPE_HEALTH: + case UNITY_PROTOCOL_CATEGORY_TYPE_BEAUTY: + case UNITY_PROTOCOL_CATEGORY_TYPE_DIY: + case UNITY_PROTOCOL_CATEGORY_TYPE_TOOLS: + case UNITY_PROTOCOL_CATEGORY_TYPE_CAR: default: // rest of the processing is the CategoryIconLoaded, lets invoke it glib::Object<GdkPixbuf> null_pixbuf; - helper_slot("", cat_size, null_pixbuf); + helper_slot("", -1, cat_size, null_pixbuf); break; } } @@ -463,32 +604,23 @@ private: glib::String contents; gsize length = 0; - if (::g_file_load_contents(file, canc, &contents, &length, + if (g_file_load_contents(file, canc, &contents, &length, nullptr, &task->error)) { glib::Object<GInputStream> stream( - ::g_memory_input_stream_new_from_data(contents.Value(), length, nullptr)); - - if (task->size != static_cast<unsigned int>(~0)) - { - task->result = ::gdk_pixbuf_new_from_stream_at_scale(stream, - -1, - task->size, - TRUE, - canc, - &task->error); - } - else - { - task->result = ::gdk_pixbuf_new_from_stream(stream, - canc, - &task->error); - } - ::g_input_stream_close(stream, canc, nullptr); + g_memory_input_stream_new_from_data(contents.Value(), length, nullptr)); + + task->result = gdk_pixbuf_new_from_stream_at_scale(stream, + task->max_width, + task->max_height, + TRUE, + canc, + &task->error); + g_input_stream_close(stream, canc, nullptr); } } - ::g_io_scheduler_job_send_to_mainloop_async (job, LoadIconComplete, task, nullptr); + g_io_scheduler_job_send_to_mainloop_async (job, LoadIconComplete, task, nullptr); return FALSE; } @@ -509,7 +641,9 @@ private: task->result = nullptr; LOG_WARNING(logger) << "Unable to load icon " << task->data - << " at size " << task->size << ": " << task->error; + << " at size " + << task->max_width << "x" << task->max_height + << ": " << task->error; } impl->finished_tasks_.push_back(task); @@ -528,21 +662,24 @@ private: }; Handle ReturnCachedOrQueue(std::string const& data, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot, IconLoaderRequestType type); Handle QueueTask(std::string const& key, std::string const& data, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot, IconLoaderRequestType type); - std::string Hash(std::string const& data, unsigned size); + std::string Hash(std::string const& data, int max_width, int max_height); bool CacheLookup(std::string const& key, std::string const& data, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); // Looping idle callback function @@ -600,52 +737,67 @@ IconLoader::Impl::Impl() } int IconLoader::Impl::LoadFromIconName(std::string const& icon_name, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - if (no_load_ || icon_name.empty() || size < MIN_ICON_SIZE || !slot) + if (no_load_ || icon_name.empty() || !slot || + ((max_width >= 0 && max_width < MIN_ICON_SIZE) || + (max_height >= 0 && max_height < MIN_ICON_SIZE))) return 0; // We need to check this because of legacy desktop files if (icon_name[0] == '/') { - return LoadFromFilename(icon_name, size, slot); + return LoadFromFilename(icon_name, max_width, max_height, slot); } - return ReturnCachedOrQueue(icon_name, size, slot, REQUEST_TYPE_ICON_NAME); + return ReturnCachedOrQueue(icon_name, max_width, max_height, slot, + REQUEST_TYPE_ICON_NAME); } int IconLoader::Impl::LoadFromGIconString(std::string const& gicon_string, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - if (no_load_ || gicon_string.empty() || size < MIN_ICON_SIZE || !slot) + if (no_load_ || gicon_string.empty() || !slot || + ((max_width >= 0 && max_width < MIN_ICON_SIZE) || + (max_height >= 0 && max_height < MIN_ICON_SIZE))) return 0; - return ReturnCachedOrQueue(gicon_string, size, slot, REQUEST_TYPE_GICON_STRING); + return ReturnCachedOrQueue(gicon_string, max_width, max_height, slot, + REQUEST_TYPE_GICON_STRING); } int IconLoader::Impl::LoadFromFilename(std::string const& filename, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - if (no_load_ || filename.empty() || size < MIN_ICON_SIZE || !slot) + if (no_load_ || filename.empty() || !slot || + ((max_width >= 0 && max_width < MIN_ICON_SIZE) || + (max_height >= 0 && max_height < MIN_ICON_SIZE))) return 0; glib::Object<GFile> file(::g_file_new_for_path(filename.c_str())); glib::String uri(::g_file_get_uri(file)); - return LoadFromURI(uri.Str(), size, slot); + return LoadFromURI(uri.Str(), max_width, max_height, slot); } int IconLoader::Impl::LoadFromURI(std::string const& uri, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - if (no_load_ || uri.empty() || size < MIN_ICON_SIZE || !slot) + if (no_load_ || uri.empty() || !slot || + ((max_width >= 0 && max_width < MIN_ICON_SIZE) || + (max_height >= 0 && max_height < MIN_ICON_SIZE))) return 0; - return ReturnCachedOrQueue(uri, size, slot, REQUEST_TYPE_URI); + return ReturnCachedOrQueue(uri, max_width, max_height, slot, + REQUEST_TYPE_URI); } void IconLoader::Impl::DisconnectHandle(Handle handle) @@ -699,16 +851,17 @@ void IconLoader::Impl::CalculateTextHeight(int* width, int* height) // int IconLoader::Impl::ReturnCachedOrQueue(std::string const& data, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot, IconLoaderRequestType type) { Handle result = 0; - std::string key(Hash(data, size)); + std::string key(Hash(data, max_width, max_height)); - if (!CacheLookup(key, data, size, slot)) + if (!CacheLookup(key, data, max_width, max_height, slot)) { - result = QueueTask(key, data, size, slot, type); + result = QueueTask(key, data, max_width, max_height, slot, type); } return result; } @@ -716,11 +869,15 @@ int IconLoader::Impl::ReturnCachedOrQueue(std::string const& data, int IconLoader::Impl::QueueTask(std::string const& key, std::string const& data, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot, IconLoaderRequestType type) { - auto task = std::make_shared<IconLoaderTask>(type, data, size, key, slot, ++handle_counter_, this); + auto task = std::make_shared<IconLoaderTask>(type, data, + max_width, max_height, + key, slot, + ++handle_counter_, this); auto iter = queued_tasks_.find(key); if (iter != queued_tasks_.end()) @@ -744,7 +901,8 @@ int IconLoader::Impl::QueueTask(std::string const& key, tasks_.push(task); task_map_[task->handle] = task; - LOG_DEBUG(logger) << "Pushing task " << data << " at size " << size + LOG_DEBUG(logger) << "Pushing task " << data << " at size " + << max_width << "x" << max_height << ", queue size now at " << tasks_.size(); if (!idle_) @@ -754,16 +912,17 @@ int IconLoader::Impl::QueueTask(std::string const& key, return task->handle; } -std::string IconLoader::Impl::Hash(std::string const& data, unsigned size) +std::string IconLoader::Impl::Hash(std::string const& data, int max_width, int max_height) { std::ostringstream sout; - sout << data << ":" << size; + sout << data << ":" << max_width << "x" << max_height; return sout.str(); } bool IconLoader::Impl::CacheLookup(std::string const& key, std::string const& data, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { auto iter = cache_.find(key); @@ -772,7 +931,7 @@ bool IconLoader::Impl::CacheLookup(std::string const& key, if (found && slot) { glib::Object<GdkPixbuf> const& pixbuf = iter->second; - slot(data, size, pixbuf); + slot(data, max_width, max_height, pixbuf); } return found; @@ -848,31 +1007,35 @@ IconLoader& IconLoader::GetDefault() } int IconLoader::LoadFromIconName(std::string const& icon_name, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - return pimpl->LoadFromIconName(icon_name, size, slot); + return pimpl->LoadFromIconName(icon_name, max_width, max_height, slot); } int IconLoader::LoadFromGIconString(std::string const& gicon_string, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - return pimpl->LoadFromGIconString(gicon_string, size, slot); + return pimpl->LoadFromGIconString(gicon_string, max_width, max_height, slot); } int IconLoader::LoadFromFilename(std::string const& filename, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - return pimpl->LoadFromFilename(filename, size, slot); + return pimpl->LoadFromFilename(filename, max_width, max_height, slot); } int IconLoader::LoadFromURI(std::string const& uri, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot) { - return pimpl->LoadFromURI(uri, size, slot); + return pimpl->LoadFromURI(uri, max_width, max_height, slot); } void IconLoader::DisconnectHandle(int handle) diff --git a/unity-shared/IconLoader.h b/unity-shared/IconLoader.h index 099bf059f..3fea5abd6 100644 --- a/unity-shared/IconLoader.h +++ b/unity-shared/IconLoader.h @@ -32,7 +32,7 @@ namespace unity class IconLoader : public boost::noncopyable { public: - typedef std::function<void(std::string const&, unsigned, glib::Object<GdkPixbuf> const&)> IconLoaderCallback; + typedef std::function<void(std::string const&, int, int, glib::Object<GdkPixbuf> const&)> IconLoaderCallback; IconLoader(); ~IconLoader(); @@ -45,19 +45,23 @@ public: */ int LoadFromIconName(std::string const& icon_name, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); int LoadFromGIconString(std::string const& gicon_string, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); int LoadFromFilename(std::string const& filename, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); int LoadFromURI(std::string const& uri, - unsigned size, + int max_width, + int max_height, IconLoaderCallback slot); void DisconnectHandle(int handle); diff --git a/unity-shared/IconTexture.cpp b/unity-shared/IconTexture.cpp index c324a2e29..c03a8c619 100644 --- a/unity-shared/IconTexture.cpp +++ b/unity-shared/IconTexture.cpp @@ -111,21 +111,21 @@ void IconTexture::LoadIcon() glib::Object<GIcon> icon(g_icon_new_for_string(_icon_name.empty() ? DEFAULT_GICON : _icon_name.c_str(), NULL)); - if (G_IS_ICON(icon.RawPtr())) + if (icon.IsType(G_TYPE_ICON)) { _handle = IconLoader::GetDefault().LoadFromGIconString(_icon_name.empty() ? DEFAULT_GICON : _icon_name.c_str(), - _size, + -1, _size, sigc::mem_fun(this, &IconTexture::IconLoaded)); } else if (_icon_name.find("http://") == 0) { _handle = IconLoader::GetDefault().LoadFromURI(_icon_name, - _size, sigc::mem_fun(this, &IconTexture::IconLoaded)); + -1, _size, sigc::mem_fun(this, &IconTexture::IconLoaded)); } else { _handle = IconLoader::GetDefault().LoadFromIconName(_icon_name, - _size, + -1, _size, sigc::mem_fun(this, &IconTexture::IconLoaded)); } } @@ -153,7 +153,9 @@ void IconTexture::Refresh(glib::Object<GdkPixbuf> const& pixbuf) _loading = false; } -void IconTexture::IconLoaded(std::string const& icon_name, unsigned size, +void IconTexture::IconLoaded(std::string const& icon_name, + int max_width, + int max_height, glib::Object<GdkPixbuf> const& pixbuf) { _handle = 0; @@ -226,7 +228,7 @@ void IconTexture::Draw(nux::GraphicsEngine& GfxContext, bool force_draw) imageDest.height - (border_width * 2), _texture_cached.GetPointer()->GetDeviceTexture(), texxform, - nux::color::White); + col); } else { diff --git a/unity-shared/IconTexture.h b/unity-shared/IconTexture.h index 83364a1f7..6e9672080 100644 --- a/unity-shared/IconTexture.h +++ b/unity-shared/IconTexture.h @@ -79,7 +79,7 @@ protected: private: nux::BaseTexture* CreateTextureCallback(std::string const& texid, int width, int height); void Refresh(glib::Object<GdkPixbuf> const& pixbuf); - void IconLoaded(std::string const& icon_name, unsigned size, glib::Object<GdkPixbuf> const& pixbuf); + void IconLoaded(std::string const& icon_name, int max_width, int max_height, glib::Object<GdkPixbuf> const& pixbuf); std::string _icon_name; unsigned int _size; diff --git a/unity-shared/OverlayRenderer.cpp b/unity-shared/OverlayRenderer.cpp index 5666733b1..24978e04e 100644 --- a/unity-shared/OverlayRenderer.cpp +++ b/unity-shared/OverlayRenderer.cpp @@ -64,10 +64,19 @@ public: nux::ObjectPtr <nux::IOpenGLBaseTexture> bg_blur_texture_; nux::ObjectPtr <nux::IOpenGLBaseTexture> bg_shine_texture_; + + nux::ObjectPtr<nux::BaseTexture> bg_refine_tex_; + nux::ObjectPtr<nux::BaseTexture> bg_refine_no_refine_tex_; + nux::ObjectPtr<nux::BaseTexture> bg_refine_corner_tex_; + std::unique_ptr<nux::AbstractPaintLayer> bg_refine_gradient_; + std::unique_ptr<nux::AbstractPaintLayer> bg_refine_gradient_corner_; + // temporary variable that stores the number of backgrounds we have rendered int bgs; bool visible; + bool refine_is_open_; + UBusManager ubus_manager_; OverlayRenderer *parent; @@ -107,16 +116,67 @@ void OverlayRendererImpl::Init() rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; bg_layer_ = new nux::ColorLayer(nux::Color(0.0f, 0.0f, 0.0f, 0.9), true, rop); + nux::TexCoordXForm texxform; + bg_refine_tex_ = unity::dash::Style::Instance().GetRefineTextureDash(); + bg_refine_no_refine_tex_ = unity::dash::Style::Instance().GetRefineNoRefineTextureDash(); + + bg_refine_gradient_.reset(new nux::TextureLayer(bg_refine_tex_->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + + bg_refine_corner_tex_ = unity::dash::Style::Instance().GetRefineTextureCorner(); + + bg_refine_gradient_corner_.reset(new nux::TextureLayer(bg_refine_corner_tex_->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + + ubus_manager_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, + sigc::mem_fun(this, &OverlayRendererImpl::OnBackgroundColorChanged)); + rop.Blend = true; rop.SrcBlend = GL_ZERO; rop.DstBlend = GL_SRC_COLOR; bg_darken_layer_ = new nux::ColorLayer(nux::Color(0.9f, 0.9f, 0.9f, 1.0f), false, rop); bg_shine_texture_ = unity::dash::Style::Instance().GetDashShine()->GetDeviceTexture(); - ubus_manager_.RegisterInterest(UBUS_BACKGROUND_COLOR_CHANGED, - sigc::mem_fun(this, &OverlayRendererImpl::OnBackgroundColorChanged)); - ubus_manager_.SendMessage(UBUS_BACKGROUND_REQUEST_COLOUR_EMIT); + + ubus_manager_.RegisterInterest(UBUS_REFINE_STATUS, [this] (GVariant *data) + { + gboolean status; + g_variant_get(data, UBUS_REFINE_STATUS_FORMAT_STRING, &status); + + refine_is_open_ = status; + nux::ROPConfig rop; + rop.Blend = true; + rop.SrcBlend = GL_ONE; + rop.DstBlend = GL_ONE_MINUS_SRC_ALPHA; + + nux::TexCoordXForm texxform; + + if (refine_is_open_) + { + bg_refine_gradient_.reset(new nux::TextureLayer(bg_refine_tex_->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + } + else + { + bg_refine_gradient_.reset(new nux::TextureLayer(bg_refine_no_refine_tex_->GetDeviceTexture(), + texxform, + nux::color::White, + false, + rop)); + } + + parent->need_redraw.emit(); + }); } void OverlayRendererImpl::OnBackgroundColorChanged(GVariant* args) @@ -442,9 +502,7 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c gfx_context.GetRenderStates().SetPremultipliedBlend(nux::SRC_OVER); const double line_opacity = 0.1f; - const int gradient_width = 130; const int gradient_height = 50; - const int horizontal_padding = 40; const int vertical_padding = 20; // Now that we mask the corners of the dash, @@ -470,23 +528,6 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c geometry.y + content_geo.height + INNER_CORNER_RADIUS + corner_overlap, line_color * 0.7f); // less opacity - // Horizontal panel/dash separator - nux::GetPainter().Paint2DQuadColor(gfx_context, - nux::Geometry(geometry.x + horizontal_padding, - geometry.y, - gradient_width, - style.GetHSeparatorSize()), - nux::color::Transparent, - nux::color::Transparent, - line_color, - line_color); - nux::GetPainter().Draw2DLine(gfx_context, - geometry.x + horizontal_padding + gradient_width, - geometry.y, - geometry.x + content_geo.width + INNER_CORNER_RADIUS + corner_overlap, - style.GetHSeparatorSize(), - line_color); - // Draw the background bg_darken_layer_->SetGeometry(larger_content_geo); nux::GetPainter().RenderSinglePaintLayer(gfx_context, larger_content_geo, bg_darken_layer_); @@ -510,6 +551,33 @@ void OverlayRendererImpl::Draw(nux::GraphicsEngine& gfx_context, nux::Geometry c larger_content_geo.width, larger_content_geo.height, bg_shine_texture_, texxform_absolute_bg, nux::color::White); + gfx_context.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + nux::TexCoordXForm refine_texxform; + + if (refine_is_open_) + { + gfx_context.QRP_1Tex(larger_content_geo.x + larger_content_geo.width - bg_refine_tex_->GetWidth(), + larger_content_geo.y, + bg_refine_tex_->GetWidth(), + std::min(bg_refine_tex_->GetHeight(), larger_content_geo.height), + bg_refine_tex_->GetDeviceTexture(), + refine_texxform, + nux::color::White + ); + } + else + { + gfx_context.QRP_1Tex(larger_content_geo.x + larger_content_geo.width - bg_refine_no_refine_tex_->GetWidth(), + larger_content_geo.y, + bg_refine_no_refine_tex_->GetWidth(), + std::min(bg_refine_no_refine_tex_->GetHeight(), larger_content_geo.height), + bg_refine_no_refine_tex_->GetDeviceTexture(), + refine_texxform, + nux::color::White + ); + } + + if (Settings::Instance().GetFormFactor() != FormFactor::NETBOOK || force_edges) { // Paint the edges @@ -850,6 +918,24 @@ void OverlayRendererImpl::DrawContent(nux::GraphicsEngine& gfx_context, nux::Geo false, rop); bgs++; + + nux::Geometry refine_geo = larger_content_geo; + + if (refine_is_open_) + { + refine_geo.x += larger_content_geo.width - bg_refine_tex_->GetWidth(); + refine_geo.width = bg_refine_tex_->GetWidth(); + refine_geo.height = bg_refine_tex_->GetHeight(); + } + else + { + refine_geo.x += larger_content_geo.width - bg_refine_no_refine_tex_->GetWidth(); + refine_geo.width = bg_refine_no_refine_tex_->GetWidth(); + refine_geo.height = bg_refine_no_refine_tex_->GetHeight(); + } + + nux::GetPainter().PushLayer(gfx_context, refine_geo, bg_refine_gradient_.get()); + bgs++; } void OverlayRendererImpl::DrawContentCleanup(nux::GraphicsEngine& gfx_context, nux::Geometry content_geo, nux::Geometry absolute_geo, nux::Geometry geometry) diff --git a/unity-shared/PreviewStyle.cpp b/unity-shared/PreviewStyle.cpp index ef8df611f..b440d0e36 100644 --- a/unity-shared/PreviewStyle.cpp +++ b/unity-shared/PreviewStyle.cpp @@ -224,7 +224,7 @@ int Style::GetMusicDurationWidth() const int Style::GetActionButtonHeight() const { - return 36; + return 34; } int Style::GetActionButtonMaximumWidth() const @@ -305,6 +305,15 @@ std::string Style::subtitle_size_font() const std::string Style::description_font() const { return "Ubuntu Light 10"; + +} +std::string Style::action_font() const +{ + return "Ubuntu 11"; +} +std::string Style::action_extra_font() const +{ + return "Ubuntu Bold 11"; } std::string Style::app_license_font() const @@ -347,7 +356,10 @@ std::string Style::track_font() const return "Ubuntu Light 10"; } - +bool Style::GetShadowBackgroundEnabled() const +{ + return false; +} nux::BaseTexture* Style::GetNavLeftIcon() { diff --git a/unity-shared/PreviewStyle.h b/unity-shared/PreviewStyle.h index ac197f29d..89274736b 100644 --- a/unity-shared/PreviewStyle.h +++ b/unity-shared/PreviewStyle.h @@ -86,10 +86,15 @@ public: int GetRatingWidgetHeight() const; + bool GetShadowBackgroundEnabled() const; + std::string title_font() const; std::string subtitle_size_font() const; std::string description_font() const; + std::string action_font() const; + std::string action_extra_font() const; + nux::AbstractPaintLayer* GetBackgroundLayer() const; //////////////////////////////// diff --git a/unity-shared/SearchBar.cpp b/unity-shared/SearchBar.cpp index 0be1c8361..8f1b9175f 100644 --- a/unity-shared/SearchBar.cpp +++ b/unity-shared/SearchBar.cpp @@ -54,7 +54,7 @@ const std::string PANGO_ENTRY_DEFAULT_FONT_FAMILY = "Ubuntu"; const int PANGO_ENTRY_FONT_SIZE = 22; const std::string SHOW_FILTERS_LABEL_FONT_SIZE = "13"; -const std::string SHOW_FILTERS_LABEL_FONT_STYLE = "Bold"; +const std::string SHOW_FILTERS_LABEL_FONT_STYLE = ""; const std::string SHOW_FILTERS_LABEL_DEFAULT_FONT = "Ubuntu " + SHOW_FILTERS_LABEL_FONT_STYLE + " " + SHOW_FILTERS_LABEL_FONT_SIZE; } diff --git a/unity-shared/UBusMessages.h b/unity-shared/UBusMessages.h index a020dd28e..7330a70e6 100644 --- a/unity-shared/UBusMessages.h +++ b/unity-shared/UBusMessages.h @@ -40,6 +40,9 @@ #define UBUS_OVERLAY_HIDDEN "OVERLAY_HIDDEN" #define UBUS_OVERLAY_SHOWN "OVERLAY_SHOWN" +#define UBUS_REFINE_STATUS_FORMAT_STRING "(b)" +#define UBUS_REFINE_STATUS "REFINE_STATUS" + #define UBUS_PLACE_VIEW_QUEUE_DRAW "PLACE_VIEW_QUEUE_DRAW" // Signal send by Launcher/Quicklist when it wants to exit key-nav and wants to diff --git a/unity-standalone/StandaloneUnity.cpp b/unity-standalone/StandaloneUnity.cpp index fa0662bed..a5dba677c 100644 --- a/unity-standalone/StandaloneUnity.cpp +++ b/unity-standalone/StandaloneUnity.cpp @@ -45,7 +45,7 @@ namespace { - static int display_width = 1280; + static int display_width = 1200; static int display_height = 720; static gboolean no_window_decorations = FALSE; static gboolean force_tv = FALSE; @@ -89,7 +89,9 @@ void UnityStandalone::Init () launcher_controller.reset(new launcher::Controller(0)); panel_controller.reset(new panel::Controller()); dash_controller.reset(new dash::Controller()); + dash_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1; + panel_controller->launcher_width = launcher_controller->launcher().GetAbsoluteWidth() - 1; } void UnityStandalone::InitWindowThread(nux::NThread* thread, void* InitData) |
