// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- /* * Copyright 2012 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3, as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranties of * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR * PURPOSE. See the applicable version of the GNU Lesser General Public * License for more details. * * You should have received a copy of both the GNU Lesser General Public * License version 3 along with this program. If not, see * * * Authored by: Nick Dedekind * */ #include "unity-shared/IntrospectableWrappers.h" #include "unity-shared/PreviewStyle.h" #include "unity-shared/CoverArt.h" #include "unity-shared/IconTexture.h" #include #include #include #include #include #include "MusicPreview.h" #include "ActionButton.h" #include "Tracks.h" #include "PreviewInfoHintWidget.h" #include "PreviewPlayer.h" namespace unity { namespace dash { namespace previews { namespace { const RawPixel CHILDREN_SPACE = 16_em; const RawPixel ICON_LEFT_RIGHT_PADDING = 10_em; const RawPixel WARNING_MIN_HEIGHT = 50_em; const RawPixel WARNING_MAX_WIDTH = 300_em; } DECLARE_LOGGER(logger, "unity.dash.preview.music"); NUX_IMPLEMENT_OBJECT_TYPE(MusicPreview); MusicPreview::MusicPreview(dash::Preview::Ptr preview_model) : Preview(preview_model) , actions_layout_(nullptr) , image_data_layout_(nullptr) , icon_layout_(nullptr) { SetupViews(); UpdateScale(scale); } MusicPreview::~MusicPreview() { } void MusicPreview::Draw(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); nux::GetPainter().PaintBackground(gfx_engine, base); gfx_engine.PopClippingRectangle(); } void MusicPreview::DrawContent(nux::GraphicsEngine& gfx_engine, bool force_draw) { nux::Geometry const& base = GetGeometry(); gfx_engine.PushClippingRectangle(base); unsigned int alpha, src, dest = 0; gfx_engine.GetRenderStates().GetBlend(alpha, src, dest); gfx_engine.GetRenderStates().SetBlend(true, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); if (GetCompositionLayout()) GetCompositionLayout()->ProcessDraw(gfx_engine, force_draw); gfx_engine.GetRenderStates().SetBlend(alpha, src, dest); gfx_engine.PopClippingRectangle(); } std::string MusicPreview::GetName() const { return "MusicPreview"; } void MusicPreview::AddProperties(debug::IntrospectionData& introspection) { Preview::AddProperties(introspection); } bool MusicPreview::HasUbuntuOneCredentials() { dash::Preview::InfoHintPtrList hints = preview_model_->GetInfoHints(); GVariant *preview_data = NULL; for (dash::Preview::InfoHintPtr const& info_hint : hints) { if (info_hint->id == "music_preview") { preview_data = info_hint->value; if (preview_data != NULL) { glib::Variant data(g_variant_lookup_value(preview_data, "no_credentials_label", G_VARIANT_TYPE_STRING)); if (!data) no_credentials_message_ = ""; else no_credentials_message_ = data.GetString(); } break; } } return no_credentials_message_.empty(); } void MusicPreview::SetupViews() { dash::MusicPreview* music_preview_model = dynamic_cast(preview_model_.get()); if (!music_preview_model) { LOG_ERROR(logger) << "Could not derive music preview model from given parameter."; return; } previews::Style& style = dash::previews::Style::Instance(); auto on_mouse_down = [this](int x, int y, unsigned long button_flags, unsigned long key_flags) { this->preview_container_->OnMouseDown(x, y, button_flags, key_flags); }; image_data_layout_ = new nux::HLayout(); image_data_layout_->SetSpaceBetweenChildren(style.GetPanelSplitWidth().CP(scale)); ///////////////////// // Image image_ = new CoverArt(); image_->scale = scale(); AddChild(image_.GetPointer()); UpdateCoverArtImage(image_.GetPointer()); ///////////////////// ///////////////////// // App Data Panel full_data_layout_ = new nux::VLayout(); full_data_layout_->SetPadding(style.GetDetailsTopMargin().CP(scale), 0, style.GetDetailsBottomMargin().CP(scale), style.GetDetailsLeftMargin().CP(scale)); full_data_layout_->SetSpaceBetweenChildren(CHILDREN_SPACE.CP(scale)); ///////////////////// // Music Info album_data_layout_ = new nux::VLayout(); album_data_layout_->SetSpaceBetweenChildren(style.GetSpaceBetweenTitleAndSubtitle().CP(scale)); title_ = new StaticCairoText(preview_model_->title, true, NUX_TRACKER_LOCATION); AddChild(title_.GetPointer()); title_->SetFont(style.title_font().c_str()); title_->SetLines(-1); title_->SetScale(scale); title_->mouse_click.connect(on_mouse_down); album_data_layout_->AddView(title_.GetPointer(), 1); if (!preview_model_->subtitle.Get().empty()) { subtitle_ = new StaticCairoText(preview_model_->subtitle, true, NUX_TRACKER_LOCATION); AddChild(subtitle_.GetPointer()); subtitle_->SetFont(style.subtitle_size_font().c_str()); subtitle_->SetLines(-1); subtitle_->SetScale(scale); subtitle_->mouse_click.connect(on_mouse_down); album_data_layout_->AddView(subtitle_.GetPointer(), 1); } ///////////////////// ///////////////////// // Music Tracks dash::Tracks::Ptr tracks_model = music_preview_model->GetTracksModel(); if (tracks_model) { tracks_ = new previews::Tracks(tracks_model, NUX_TRACKER_LOCATION); tracks_->scale = scale(); AddChild(tracks_.GetPointer()); tracks_->mouse_click.connect(on_mouse_down); } ///////////////////// nux::HLayout* hint_actions_layout = new nux::HLayout(); ///////////////////// // Hints && Actions nux::VLayout* hints_layout = NULL; actions_layout_ = NULL; bool has_u1_creds = HasUbuntuOneCredentials(); if (has_u1_creds) { if (!preview_model_->GetInfoHints().empty()) { hints_layout = new nux::VLayout(); hints_layout->SetSpaceBetweenChildren(0); hints_layout->AddSpace(0, 1); preview_info_hints_ = new PreviewInfoHintWidget(preview_model_, style.GetInfoHintIconSizeWidth().CP(scale)); preview_info_hints_->scale = scale(); AddChild(preview_info_hints_.GetPointer()); preview_info_hints_->request_close().connect([this]() { preview_container_->request_close.emit(); }); hints_layout->AddView(preview_info_hints_.GetPointer(), 0); // If there are actions, we use a vertical layout action_buttons_.clear(); actions_layout_ = BuildVerticalActionsLayout(preview_model_->GetActions(), action_buttons_); actions_layout_->SetLeftAndRightPadding(0, style.GetDetailsRightMargin().CP(scale)); } else // otherwise we add a grid layout. { action_buttons_.clear(); actions_layout_ = BuildGridActionsLayout(preview_model_->GetActions(), action_buttons_); if (action_buttons_.size() < 2) hint_actions_layout->AddSpace(0, 1); actions_layout_->SetLeftAndRightPadding(0, style.GetDetailsRightMargin().CP(scale)); } } else { // let the user know he needs to connect previews::Style& style = dash::previews::Style::Instance(); nux::HLayout* actions_layout = new nux::HLayout(); icon_layout_ = new nux::VLayout(); icon_layout_->SetLeftAndRightPadding(ICON_LEFT_RIGHT_PADDING.CP(scale)); warning_texture_ = new IconTexture(style.GetWarningIcon()); icon_layout_->AddView(warning_texture_.GetPointer(), 0, nux::MINOR_POSITION_START, nux::MINOR_SIZE_FULL, 100.0f, nux::NUX_LAYOUT_BEGIN); actions_layout->AddLayout(icon_layout_, 0, nux::MINOR_POSITION_CENTER); warning_msg_ = new StaticCairoText( no_credentials_message_, true, NUX_TRACKER_LOCATION); AddChild(warning_msg_.GetPointer()); warning_msg_->SetFont(style.u1_warning_font().c_str()); warning_msg_->SetLines(-2); warning_msg_->SetScale(scale); warning_msg_->SetMinimumHeight(WARNING_MIN_HEIGHT.CP(scale)); warning_msg_->SetMaximumWidth(WARNING_MAX_WIDTH.CP(scale)); actions_layout->AddView(warning_msg_.GetPointer(), 0, nux::MINOR_POSITION_CENTER); } ///////////////////// if (hints_layout) hint_actions_layout->AddView(hints_layout, 1); hint_actions_layout->AddView(actions_layout_, 0); full_data_layout_->AddLayout(album_data_layout_, 0); if (tracks_) { full_data_layout_->AddView(tracks_.GetPointer(), 1); } full_data_layout_->AddLayout(hint_actions_layout, 0); ///////////////////// image_data_layout_->AddView(image_.GetPointer(), 0); image_data_layout_->AddLayout(full_data_layout_, 1); mouse_click.connect(on_mouse_down); SetLayout(image_data_layout_); } void MusicPreview::PreLayoutManagement() { nux::Geometry geo = GetGeometry(); GetLayout()->SetGeometry(geo); previews::Style& style = dash::previews::Style::Instance(); nux::Geometry geo_art(geo.x, geo.y, style.GetAppImageAspectRatio() * geo.height, geo.height); int content_width = geo.width - style.GetPanelSplitWidth().CP(scale) - style.GetDetailsLeftMargin().CP(scale) - style.GetDetailsRightMargin().CP(scale); if (content_width - geo_art.width < style.GetDetailsPanelMinimumWidth().CP(scale)) geo_art.width = MAX(0, content_width - style.GetDetailsPanelMinimumWidth().CP(scale)); image_->SetMinMaxSize(geo_art.width, geo_art.height); int details_width = MAX(0, content_width - geo_art.width); if (title_) { title_->SetMaximumWidth(details_width); } if (subtitle_) { subtitle_->SetMaximumWidth(details_width); } for (nux::AbstractButton* button : action_buttons_) { int action_width = CLAMP((details_width - style.GetSpaceBetweenActions().CP(scale)) / 2, 0, style.GetActionButtonMaximumWidth().CP(scale)); // do not use SetMinMax because width has to be able to grow button->SetMinimumWidth(action_width); button->SetMinimumHeight(style.GetActionButtonHeight().CP(scale)); button->SetMaximumHeight(style.GetActionButtonHeight().CP(scale)); } Preview::PreLayoutManagement(); } void MusicPreview::OnNavigateOut() { PreviewPlayer player; player.Stop(); } void MusicPreview::UpdateScale(double scale) { Preview::UpdateScale(scale); if (tracks_) tracks_->scale = scale; if (preview_info_hints_) preview_info_hints_->scale = scale; if (icon_layout_) icon_layout_->SetLeftAndRightPadding(ICON_LEFT_RIGHT_PADDING.CP(scale)); if (warning_msg_) { warning_msg_->SetScale(scale); warning_msg_->SetMinimumHeight(WARNING_MIN_HEIGHT.CP(scale)); warning_msg_->SetMaximumWidth(WARNING_MAX_WIDTH.CP(scale)); } previews::Style& style = dash::previews::Style::Instance(); if (image_data_layout_) image_data_layout_->SetSpaceBetweenChildren(style.GetPanelSplitWidth().CP(scale)); if (full_data_layout_) { full_data_layout_->SetPadding(style.GetDetailsTopMargin().CP(scale), 0, style.GetDetailsBottomMargin().CP(scale), style.GetDetailsLeftMargin().CP(scale)); full_data_layout_->SetSpaceBetweenChildren(CHILDREN_SPACE.CP(scale)); } if (album_data_layout_) album_data_layout_->SetSpaceBetweenChildren(style.GetSpaceBetweenTitleAndSubtitle().CP(scale)); if (actions_layout_) actions_layout_->SetLeftAndRightPadding(0, style.GetDetailsRightMargin().CP(scale)); if (icon_layout_) icon_layout_->SetLeftAndRightPadding(ICON_LEFT_RIGHT_PADDING.CP(scale)); } } // namespace previews } // namespace dash } // namespace unity