diff --git a/src/musikbox/CMakeLists.txt b/src/musikbox/CMakeLists.txt index 2a0c26ed8..8c3ad064a 100644 --- a/src/musikbox/CMakeLists.txt +++ b/src/musikbox/CMakeLists.txt @@ -26,6 +26,7 @@ set (BOX_SRCS ./cursespp/Checkbox.cpp ./cursespp/Colors.cpp ./cursespp/DialogOverlay.cpp + ./cursespp/InputOverlay.cpp ./cursespp/LayoutBase.cpp ./cursespp/ListOverlay.cpp ./cursespp/ListWindow.cpp diff --git a/src/musikbox/app/layout/NowPlayingLayout.cpp b/src/musikbox/app/layout/NowPlayingLayout.cpp index 3457d9ba1..134142ffa 100755 --- a/src/musikbox/app/layout/NowPlayingLayout.cpp +++ b/src/musikbox/app/layout/NowPlayingLayout.cpp @@ -66,7 +66,8 @@ NowPlayingLayout::NowPlayingLayout( : LayoutBase() , playback(playback) , library(library) -, reselectIndex(-1) { +, reselectIndex(-1) +, lastPlaylistId(-1) { this->InitializeWindows(); this->playback.Shuffled.connect(this, &NowPlayingLayout::OnPlaybackShuffled); @@ -138,6 +139,9 @@ void NowPlayingLayout::OnVisibilityChanged(bool visible) { } void NowPlayingLayout::OnTrackListRequeried(musik::glue::TrackListQueryBase* query) { + /* if the requery just finished for a regular playlist, we need to + make sure we load it into the PlaybackService. generally we just read + FROM the playback service */ if (query && query->GetId() == this->lastPlaylistId) { this->playback.CopyFrom(*query->GetResult()); this->lastPlaylistId = -1; @@ -209,6 +213,9 @@ bool NowPlayingLayout::KeyPress(const std::string& key) { std::bind(&NowPlayingLayout::OnPlaylistQueryStart, this, std::placeholders::_1)); return true; } + else if (key == "M-s") { + PlayQueueOverlays::ShowSavePlaylistOverlay(this->playback, this->library); + } else if (ProcessEditOperation(key)) { return true; } diff --git a/src/musikbox/cursespp/InputOverlay.cpp b/src/musikbox/cursespp/InputOverlay.cpp new file mode 100644 index 000000000..2837f7f84 --- /dev/null +++ b/src/musikbox/cursespp/InputOverlay.cpp @@ -0,0 +1,151 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include +#include "InputOverlay.h" +#include "Colors.h" +#include "Screen.h" +#include "Text.h" + +using namespace cursespp; + +#define VERTICAL_PADDING 2 +#define DEFAULT_WIDTH 26 +#define MAX_HEIGHT 12 + +#define DISMISS() \ + OverlayStack* overlays = this->GetOverlayStack(); \ + if (overlays) { \ + overlays->Remove(this); \ + } + +InputOverlay::InputOverlay() { + this->SetFrameVisible(true); + this->SetFrameColor(CURSESPP_OVERLAY_FRAME); + this->SetContentColor(CURSESPP_OVERLAY_BACKGROUND); + + this->width = this->height = this->setWidth = 0; + + this->textInput.reset(new TextInput()); + this->textInput->SetFocusOrder(0); + this->textInput->SetFrameColor(CURSESPP_OVERLAY_FRAME); + this->textInput->SetContentColor(CURSESPP_OVERLAY_BACKGROUND); + this->AddWindow(this->textInput); +} + +InputOverlay::~InputOverlay() { +} + +void InputOverlay::Layout() { + this->RecalculateSize(); + + if (this->width > 0 && this->height > 0) { + this->MoveAndResize( + this->x, + this->y, + this->width, + this->height); + + this->textInput->MoveAndResize( + 1, /* one pixel padding L and R */ + 2, /* below the title, plus an extra space */ + this->GetContentWidth() - 2, + 3); /* top and bottom border plus text */ + + this->Redraw(); + } +} + +InputOverlay& InputOverlay::SetTitle(const std::string& title) { + this->title = title; + this->RecalculateSize(); + this->Layout(); + this->Invalidate(); + return *this; +} + +InputOverlay& InputOverlay::SetText(const std::string& text) { + this->title = title; + this->textInput->SetText(text); + return *this; +} + +InputOverlay& InputOverlay::SetWidth(int width) { + this->setWidth = width; + + if (this->IsVisible()) { + this->Layout(); + } + + return *this; +} + +InputOverlay& InputOverlay::SetInputAcceptedCallback(InputAcceptedCallback cb) { + this->inputAcceptedCallback = cb; + return *this; +} + +void InputOverlay::OnVisibilityChanged(bool visible) { + if (visible) { + this->SetFocus(this->textInput); + this->Redraw(); + } +} + +void InputOverlay::RecalculateSize() { + this->width = this->setWidth > 0 ? this->setWidth : DEFAULT_WIDTH; + this->height = 1 + 1 + 1 + 3 + 1; /* top frame + text + space + text input + bottom frame */ + + /* constrain to app bounds */ + this->height = std::max(0, std::min(Screen::GetHeight() - 4, this->height)); + this->width = std::max(0, std::min(Screen::GetWidth(), this->width)); + + this->y = VERTICAL_PADDING; + this->x = (Screen::GetWidth() / 2) - (this->width / 2); +} + +void InputOverlay::Redraw() { + if (this->width <= 0 || this->height <= 0) { + return; + } + + WINDOW* c = this->GetContent(); + + if (this->title.size()) { + wmove(c, 0, 1); + wattron(c, A_BOLD); + wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str()); + wattroff(c, A_BOLD); + } +} \ No newline at end of file diff --git a/src/musikbox/cursespp/InputOverlay.h b/src/musikbox/cursespp/InputOverlay.h new file mode 100644 index 000000000..d4fd4c93e --- /dev/null +++ b/src/musikbox/cursespp/InputOverlay.h @@ -0,0 +1,74 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2016 musikcube team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include "OverlayBase.h" +#include "TextInput.h" + +namespace cursespp { + class InputOverlay : + public OverlayBase +#if (__clang_major__ == 7 && __clang_minor__ == 3) + , public std::enable_shared_from_this +#endif + { + public: + using InputAcceptedCallback = std::function; + + InputOverlay(); + virtual ~InputOverlay(); + + InputOverlay& SetTitle(const std::string& title); + InputOverlay& SetText(const std::string& text); + InputOverlay& SetInputAcceptedCallback(InputAcceptedCallback cb); + InputOverlay& SetWidth(int width); + + virtual void Layout(); + + protected: + virtual void OnVisibilityChanged(bool visible); + + private: + void Redraw(); + void RecalculateSize(); + + std::string title, text; + int x, y; + int width, height; + int setWidth; + std::shared_ptr textInput; + InputAcceptedCallback inputAcceptedCallback; + }; +} \ No newline at end of file diff --git a/src/musikbox/cursespp/ListOverlay.cpp b/src/musikbox/cursespp/ListOverlay.cpp index 0814978e5..d87473c6a 100644 --- a/src/musikbox/cursespp/ListOverlay.cpp +++ b/src/musikbox/cursespp/ListOverlay.cpp @@ -124,6 +124,11 @@ ListOverlay& ListOverlay::SetItemSelectedCallback(ItemSelectedCallback cb) { return *this; } +ListOverlay& ListOverlay::SetDeleteKeyCallback(DeleteKeyCallback cb) { + this->deleteKeyCallback = cb; + return *this; +} + bool ListOverlay::KeyPress(const std::string& key) { if (key == "^[") { /* esc closes */ DISMISS(); @@ -138,6 +143,15 @@ bool ListOverlay::KeyPress(const std::string& key) { DISMISS(); return true; } + else if (key == "KEY_BACKSPACE" || key == "KEY_DC") { + if (deleteKeyCallback) { + deleteKeyCallback( + this->adapter, + listWindow->GetSelectedIndex()); + + return true; + } + } return LayoutBase::KeyPress(key); } diff --git a/src/musikbox/cursespp/ListOverlay.h b/src/musikbox/cursespp/ListOverlay.h index bb3f060ca..2c1bedb2d 100644 --- a/src/musikbox/cursespp/ListOverlay.h +++ b/src/musikbox/cursespp/ListOverlay.h @@ -49,6 +49,7 @@ namespace cursespp { { public: using ItemSelectedCallback = std::function; + using DeleteKeyCallback = std::function; ListOverlay(); virtual ~ListOverlay(); @@ -56,6 +57,7 @@ namespace cursespp { ListOverlay& SetTitle(const std::string& title); ListOverlay& SetAdapter(IScrollAdapterPtr adapter); ListOverlay& SetItemSelectedCallback(ItemSelectedCallback cb); + ListOverlay& SetDeleteKeyCallback(DeleteKeyCallback cb); ListOverlay& SetSelectedIndex(size_t index); ListOverlay& SetWidth(int width); @@ -76,5 +78,6 @@ namespace cursespp { IScrollAdapterPtr adapter; std::shared_ptr listWindow; ItemSelectedCallback itemSelectedCallback; + DeleteKeyCallback deleteKeyCallback; }; } \ No newline at end of file