mirror of
https://github.com/clangen/musikcube.git
synced 2025-03-14 13:21:13 +00:00
Incremental work to support dynamic visualization selection by the user.
Added a new ListOverlay type (not quite done yet).
This commit is contained in:
parent
05b404c0f0
commit
a85b4f49e7
@ -32,8 +32,6 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pch.hpp"
|
||||
#include "Visualizer.h"
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
@ -46,6 +44,10 @@ static std::vector<std::shared_ptr<ISpectrumVisualizer> > spectrumVisualizers;
|
||||
static std::vector<std::shared_ptr<IPcmVisualizer> > pcmVisualizers;
|
||||
static std::atomic<bool> initialized;
|
||||
|
||||
static std::shared_ptr<IVisualizer> selectedVisualizer;
|
||||
static ISpectrumVisualizer* spectrumVisualizer = nullptr;
|
||||
static IPcmVisualizer* pcmVisualizer = nullptr;
|
||||
|
||||
namespace musik {
|
||||
namespace core {
|
||||
namespace audio {
|
||||
@ -69,45 +71,37 @@ namespace musik {
|
||||
}
|
||||
|
||||
ISpectrumVisualizer* SpectrumVisualizer() {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
if (spectrumVisualizers.size()) {
|
||||
return spectrumVisualizers[0].get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return spectrumVisualizer;
|
||||
}
|
||||
|
||||
IPcmVisualizer* PcmVisualizer() {
|
||||
return pcmVisualizer;
|
||||
}
|
||||
|
||||
std::shared_ptr<IVisualizer> GetVisualizer(size_t index) {
|
||||
if (index < pcmVisualizers.size()) {
|
||||
return pcmVisualizers.at(index);
|
||||
}
|
||||
|
||||
return spectrumVisualizers.at(index - pcmVisualizers.size());
|
||||
}
|
||||
|
||||
size_t VisualizerCount() {
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
if (pcmVisualizers.size()) {
|
||||
return pcmVisualizers[0].get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return pcmVisualizers.size() + spectrumVisualizers.size();
|
||||
}
|
||||
|
||||
IVisualizer* SelectedVisualizer() {
|
||||
IVisualizer* vis = SpectrumVisualizer();
|
||||
return vis ? vis : PcmVisualizer();
|
||||
void SetSelectedVisualizer(std::shared_ptr<IVisualizer> visualizer) {
|
||||
selectedVisualizer = visualizer;
|
||||
pcmVisualizer = dynamic_cast<IPcmVisualizer*>(visualizer.get());
|
||||
spectrumVisualizer = dynamic_cast<ISpectrumVisualizer*>(visualizer.get());
|
||||
}
|
||||
|
||||
void ToggleSelectedVisualizer() {
|
||||
IVisualizer* vis = SelectedVisualizer();
|
||||
|
||||
if (vis) {
|
||||
if (vis->Visible()) {
|
||||
vis->Hide();
|
||||
}
|
||||
else {
|
||||
vis->Show();
|
||||
}
|
||||
}
|
||||
std::shared_ptr<IVisualizer> SelectedVisualizer() {
|
||||
return selectedVisualizer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,10 @@ namespace musik { namespace core { namespace audio { namespace vis {
|
||||
|
||||
ISpectrumVisualizer* SpectrumVisualizer();
|
||||
IPcmVisualizer* PcmVisualizer();
|
||||
IVisualizer* SelectedVisualizer();
|
||||
void ToggleSelectedVisualizer();
|
||||
|
||||
std::shared_ptr<IVisualizer> GetVisualizer(size_t index);
|
||||
size_t VisualizerCount();
|
||||
void SetSelectedVisualizer(std::shared_ptr<IVisualizer> visualizer);
|
||||
std::shared_ptr<IVisualizer> SelectedVisualizer();
|
||||
|
||||
} } } }
|
||||
|
@ -40,10 +40,10 @@
|
||||
namespace musik { namespace core { namespace audio {
|
||||
|
||||
class IDecoderFactory{
|
||||
public:
|
||||
public:
|
||||
virtual IDecoder* CreateDecoder() = 0;
|
||||
virtual void Destroy() = 0;
|
||||
virtual bool CanHandle(const char* type) const = 0;
|
||||
};
|
||||
|
||||
} } }
|
||||
} } }
|
||||
|
@ -34,9 +34,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "IPlugin.h"
|
||||
|
||||
namespace musik { namespace core { namespace audio {
|
||||
|
||||
class IVisualizer {
|
||||
class IVisualizer : public IPlugin {
|
||||
public:
|
||||
virtual void Show() = 0;
|
||||
virtual void Hide() = 0;
|
||||
|
@ -145,7 +145,7 @@ void DirectoryAdapter::SetDotfilesVisible(bool visible) {
|
||||
}
|
||||
}
|
||||
|
||||
IScrollAdapter::EntryPtr DirectoryAdapter::GetEntry(size_t index) {
|
||||
IScrollAdapter::EntryPtr DirectoryAdapter::GetEntry(cursespp::ScrollableWindow* window, size_t index) {
|
||||
if (dir.has_parent_path()) {
|
||||
if (index == 0) {
|
||||
return IScrollAdapter::EntryPtr(new SingleLineEntry(".."));
|
||||
|
@ -46,7 +46,7 @@ namespace musik {
|
||||
virtual ~DirectoryAdapter();
|
||||
|
||||
virtual size_t GetEntryCount();
|
||||
virtual EntryPtr GetEntry(size_t index);
|
||||
virtual EntryPtr GetEntry(cursespp::ScrollableWindow* window, size_t index);
|
||||
|
||||
void Select(size_t index);
|
||||
std::string GetFullPathAt(size_t index);
|
||||
|
75
src/musikbox/app/overlay/VisualizerOverlay.cpp
Normal file
75
src/musikbox/app/overlay/VisualizerOverlay.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "stdafx.h"
|
||||
|
||||
#include "VisualizerOverlay.h"
|
||||
|
||||
#include <core/audio/Visualizer.h>
|
||||
|
||||
#include <cursespp/App.h>
|
||||
#include <cursespp/SimpleScrollAdapter.h>
|
||||
#include <cursespp/ListOverlay.h>
|
||||
|
||||
using namespace musik::box;
|
||||
using namespace musik::core::audio;
|
||||
using namespace cursespp;
|
||||
|
||||
VisualizerOverlay::VisualizerOverlay() {
|
||||
}
|
||||
|
||||
void VisualizerOverlay::Show() {
|
||||
using Adapter = cursespp::SimpleScrollAdapter;
|
||||
using ListOverlay = cursespp::ListOverlay;
|
||||
|
||||
std::shared_ptr<Adapter> adapter(new Adapter());
|
||||
|
||||
for (size_t i = 0; i < vis::VisualizerCount(); i++) {
|
||||
adapter->AddEntry(vis::GetVisualizer(i)->Name());
|
||||
}
|
||||
|
||||
adapter->SetSelectable(true);
|
||||
|
||||
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
|
||||
|
||||
dialog->SetAdapter(adapter)
|
||||
.SetTitle("visualizers")
|
||||
.SetItemSelectedCallback(
|
||||
[&](cursespp::IScrollAdapterPtr adapter, size_t index) {
|
||||
vis::SetSelectedVisualizer(vis::GetVisualizer(index));
|
||||
vis::SelectedVisualizer()->Show();
|
||||
});
|
||||
|
||||
cursespp::App::Overlays().Push(dialog);
|
||||
}
|
47
src/musikbox/app/overlay/VisualizerOverlay.h
Normal file
47
src/musikbox/app/overlay/VisualizerOverlay.h
Normal file
@ -0,0 +1,47 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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
|
||||
|
||||
namespace musik {
|
||||
namespace box {
|
||||
class VisualizerOverlay {
|
||||
public:
|
||||
static void Show();
|
||||
|
||||
private:
|
||||
VisualizerOverlay();
|
||||
};
|
||||
}
|
||||
}
|
@ -35,7 +35,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "GlobalHotkeys.h"
|
||||
#include "Hotkeys.h"
|
||||
|
||||
#include <app/overlay/VisualizerOverlay.h>
|
||||
#include <app/util/Playback.h>
|
||||
|
||||
#include <core/audio/Visualizer.h>
|
||||
|
||||
using musik::core::LibraryPtr;
|
||||
@ -99,7 +102,13 @@ bool GlobalHotkeys::Handle(const std::string& kn) {
|
||||
return true;
|
||||
}
|
||||
else if (Hotkeys::Is(Hotkeys::ToggleVisualizer, kn)) {
|
||||
vis::ToggleSelectedVisualizer();
|
||||
std::shared_ptr<IVisualizer> selected = vis::SelectedVisualizer();
|
||||
if (selected && selected->Visible()) {
|
||||
selected->Hide();
|
||||
}
|
||||
else {
|
||||
VisualizerOverlay::Show();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -225,7 +225,7 @@ size_t CategoryListView::Adapter::GetEntryCount() {
|
||||
return parent.metadata ? parent.metadata->size() : 0;
|
||||
}
|
||||
|
||||
IScrollAdapter::EntryPtr CategoryListView::Adapter::GetEntry(size_t index) {
|
||||
IScrollAdapter::EntryPtr CategoryListView::Adapter::GetEntry(cursespp::ScrollableWindow* window, size_t index) {
|
||||
std::string value = parent.metadata->at(index)->displayValue;
|
||||
|
||||
bool playing =
|
||||
|
@ -98,7 +98,7 @@ namespace musik {
|
||||
Adapter(CategoryListView &parent);
|
||||
|
||||
virtual size_t GetEntryCount();
|
||||
virtual EntryPtr GetEntry(size_t index);
|
||||
virtual EntryPtr GetEntry(cursespp::ScrollableWindow* window, size_t index);
|
||||
|
||||
private:
|
||||
CategoryListView &parent;
|
||||
|
@ -244,7 +244,7 @@ static std::string formatWithoutAlbum(TrackPtr track, size_t width) {
|
||||
% trackNum % title % duration % artist);
|
||||
}
|
||||
|
||||
IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(size_t index) {
|
||||
IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWindow* window, size_t index) {
|
||||
bool selected = index == parent.GetSelectedIndex();
|
||||
int64 attrs = selected ? COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM) : -1LL;
|
||||
|
||||
|
@ -86,7 +86,7 @@ namespace musik {
|
||||
virtual ~Adapter() { }
|
||||
|
||||
virtual size_t GetEntryCount();
|
||||
virtual EntryPtr GetEntry(size_t index);
|
||||
virtual EntryPtr GetEntry(cursespp::ScrollableWindow* window, size_t index);
|
||||
|
||||
private:
|
||||
TrackListView &parent;
|
||||
|
@ -190,7 +190,7 @@ void DialogOverlay::Redraw() {
|
||||
if (this->title.size()) {
|
||||
wmove(c, currentY, currentX);
|
||||
wattron(c, A_BOLD);
|
||||
wprintw(c, text::Ellipsize(this->title, this->width - 2).c_str());
|
||||
wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
wattroff(c, A_BOLD);
|
||||
currentY += 2;
|
||||
}
|
||||
|
@ -72,7 +72,9 @@ namespace cursespp {
|
||||
|
||||
virtual void SetDisplaySize(size_t width, size_t height) = 0;
|
||||
virtual size_t GetEntryCount() = 0;
|
||||
virtual EntryPtr GetEntry(size_t index) = 0;
|
||||
virtual EntryPtr GetEntry(ScrollableWindow* window, size_t index) = 0;
|
||||
virtual void DrawPage(ScrollableWindow* window, size_t index, ScrollPosition *result = NULL) = 0;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<IScrollAdapter> IScrollAdapterPtr;
|
||||
}
|
||||
|
188
src/musikbox/cursespp/ListOverlay.cpp
Normal file
188
src/musikbox/cursespp/ListOverlay.cpp
Normal file
@ -0,0 +1,188 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 <stdafx.h>
|
||||
#include "ListOverlay.h"
|
||||
#include "Colors.h"
|
||||
#include "Screen.h"
|
||||
#include "Text.h"
|
||||
|
||||
using namespace cursespp;
|
||||
|
||||
#define HORIZONTAL_PADDING 4
|
||||
#define VERTICAL_PADDING 2
|
||||
|
||||
#define DISMISS() \
|
||||
OverlayStack* overlays = this->GetOverlayStack(); \
|
||||
if (overlays) { \
|
||||
overlays->Remove(this); \
|
||||
}
|
||||
|
||||
ListOverlay::ListOverlay() {
|
||||
this->SetFrameVisible(true);
|
||||
this->SetFrameColor(CURSESPP_OVERLAY_FRAME);
|
||||
this->SetContentColor(CURSESPP_OVERLAY_BACKGROUND);
|
||||
|
||||
this->width = this->height = 0;
|
||||
|
||||
this->listWindow.reset(new ListWindow());
|
||||
this->listWindow->SetFrameVisible(false);
|
||||
this->listWindow->SetFocusOrder(0);
|
||||
this->AddWindow(this->listWindow);
|
||||
}
|
||||
|
||||
ListOverlay::~ListOverlay() {
|
||||
}
|
||||
|
||||
void ListOverlay::Layout() {
|
||||
this->RecalculateSize();
|
||||
|
||||
if (this->width > 0 && this->height > 0) {
|
||||
this->MoveAndResize(
|
||||
HORIZONTAL_PADDING,
|
||||
VERTICAL_PADDING,
|
||||
this->width,
|
||||
this->height);
|
||||
|
||||
int y = VERTICAL_PADDING + 3; /* below the border + title */
|
||||
int cy = this->height - 4; /* top and bottom padding + title */
|
||||
|
||||
this->listWindow->MoveAndResize(
|
||||
HORIZONTAL_PADDING + 1, y,
|
||||
this->GetContentWidth(), cy);
|
||||
}
|
||||
}
|
||||
|
||||
ListOverlay& ListOverlay::SetTitle(const std::string& title) {
|
||||
this->title = title;
|
||||
this->RecalculateSize();
|
||||
this->Layout();
|
||||
this->Repaint();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListOverlay& ListOverlay::SetAdapter(IScrollAdapterPtr adapter) {
|
||||
if (this->adapter != adapter) {
|
||||
this->adapter = adapter;
|
||||
this->listWindow->SetAdapter(adapter.get());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ListOverlay& ListOverlay::SetItemSelectedCallback(ItemSelectedCallback cb) {
|
||||
this->itemSelectedCallback = cb;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ListOverlay::KeyPress(const std::string& key) {
|
||||
if (key == "^[") { /* esc closes */
|
||||
DISMISS();
|
||||
return true;
|
||||
}
|
||||
else if (key == "KEY_ENTER") {
|
||||
if (itemSelectedCallback) {
|
||||
itemSelectedCallback(
|
||||
this->adapter,
|
||||
listWindow->GetSelectedIndex());
|
||||
}
|
||||
DISMISS();
|
||||
return true;
|
||||
}
|
||||
|
||||
return LayoutBase::KeyPress(key);
|
||||
}
|
||||
|
||||
void ListOverlay::OnVisibilityChanged(bool visible) {
|
||||
if (visible) {
|
||||
this->SetFocus(this->listWindow);
|
||||
this->Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void ListOverlay::RecalculateSize() {
|
||||
this->width = 20;
|
||||
this->height = 10;
|
||||
|
||||
//int lastWidth = this->width;
|
||||
|
||||
//this->width = std::max(0, Screen::GetWidth() - (HORIZONTAL_PADDING * 2));
|
||||
|
||||
//if (lastWidth != this->width) {
|
||||
// /* 4 here: 2 for the frame padding (left/right), then two for the
|
||||
// inner content padding so things aren't bunched up (left/right) */
|
||||
// messageLines = text::BreakLines(this->message, this->width - 4);
|
||||
//}
|
||||
|
||||
//this->height = 0; /* top padding */
|
||||
//this->height += (this->title.size()) ? 2 : 0;
|
||||
//this->height += (this->messageLines.size()) ? messageLines.size() + 1 : 0;
|
||||
//this->height += 1; /* shortcuts */
|
||||
|
||||
///* ensure the overlay doesn't exceed the height of the screen,
|
||||
//or things may get crashy. normally this will be done for us automatically
|
||||
//in Window, but because we're free-floating we need to do it manually here. */
|
||||
//int top = this->GetY();
|
||||
//int bottom = top + this->height + VERTICAL_PADDING;
|
||||
//int screenHeight = Screen::GetHeight();
|
||||
//if (bottom > screenHeight) {
|
||||
// this->height = screenHeight - top - VERTICAL_PADDING;
|
||||
//}
|
||||
|
||||
//int left = this->GetX();
|
||||
//int right = left + this->width + HORIZONTAL_PADDING;
|
||||
//int screenWidth = Screen::GetWidth();
|
||||
//if (right > screenWidth) {
|
||||
// this->width = screenWidth - left - HORIZONTAL_PADDING;
|
||||
//}
|
||||
}
|
||||
|
||||
void ListOverlay::Redraw() {
|
||||
if (this->width <= 0 || this->height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
WINDOW* c = this->GetContent();
|
||||
|
||||
const int currentX = 1;
|
||||
int currentY = 0;
|
||||
|
||||
if (this->title.size()) {
|
||||
wmove(c, currentY, currentX);
|
||||
wattron(c, A_BOLD);
|
||||
wprintw(c, text::Ellipsize(this->title, this->width - 4).c_str());
|
||||
wattroff(c, A_BOLD);
|
||||
currentY += 2;
|
||||
}
|
||||
}
|
76
src/musikbox/cursespp/ListOverlay.h
Normal file
76
src/musikbox/cursespp/ListOverlay.h
Normal file
@ -0,0 +1,76 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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 "ListWindow.h"
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
namespace cursespp {
|
||||
class ListOverlay :
|
||||
public OverlayBase
|
||||
#if (__clang_major__ == 7 && __clang_minor__ == 3)
|
||||
, public std::enable_shared_from_this<ListOverlay>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
using ItemSelectedCallback = std::function<void(IScrollAdapterPtr adapter, size_t index)>;
|
||||
|
||||
ListOverlay();
|
||||
virtual ~ListOverlay();
|
||||
|
||||
ListOverlay& SetTitle(const std::string& title);
|
||||
ListOverlay& SetAdapter(IScrollAdapterPtr adapter);
|
||||
ListOverlay& SetItemSelectedCallback(ItemSelectedCallback cb);
|
||||
|
||||
virtual void Layout();
|
||||
virtual bool KeyPress(const std::string& key);
|
||||
|
||||
protected:
|
||||
virtual void OnVisibilityChanged(bool visible);
|
||||
|
||||
private:
|
||||
void Redraw();
|
||||
void RecalculateSize();
|
||||
|
||||
std::string title;
|
||||
int width, height;
|
||||
IScrollAdapterPtr adapter;
|
||||
std::shared_ptr<ListWindow> listWindow;
|
||||
ItemSelectedCallback itemSelectedCallback;
|
||||
};
|
||||
}
|
@ -46,7 +46,7 @@ class EmptyAdapter : public IScrollAdapter {
|
||||
public:
|
||||
virtual void SetDisplaySize(size_t width, size_t height) { }
|
||||
virtual size_t GetEntryCount() { return 0; }
|
||||
virtual EntryPtr GetEntry(size_t index) { return IScrollAdapter::EntryPtr(); }
|
||||
virtual EntryPtr GetEntry(cursespp::ScrollableWindow* window, size_t index) { return IScrollAdapter::EntryPtr(); }
|
||||
virtual void DrawPage(ScrollableWindow* window, size_t index, ScrollPosition *result = NULL) { }
|
||||
};
|
||||
|
||||
@ -63,6 +63,13 @@ ListWindow::~ListWindow() {
|
||||
|
||||
}
|
||||
|
||||
void ListWindow::SetAdapter(IScrollAdapter* adapter) {
|
||||
if (adapter != this->adapter) {
|
||||
this->adapter = adapter;
|
||||
this->ScrollToTop();
|
||||
}
|
||||
}
|
||||
|
||||
void ListWindow::ScrollToTop() {
|
||||
this->SetSelectedIndex(0);
|
||||
this->ScrollTo(0);
|
||||
|
@ -66,6 +66,8 @@ namespace cursespp {
|
||||
virtual size_t GetSelectedIndex();
|
||||
virtual void SetSelectedIndex(size_t index);
|
||||
|
||||
virtual void SetAdapter(IScrollAdapter* adapter);
|
||||
|
||||
virtual void OnAdapterChanged();
|
||||
|
||||
protected:
|
||||
|
@ -138,7 +138,7 @@ void MessageQueue::Post(IMessagePtr message, int64 delayMs) {
|
||||
this->queue.insert(curr, m);
|
||||
}
|
||||
|
||||
void MessageQueue::Debounce(IMessagePtr message, int delayMs) {
|
||||
void MessageQueue::Debounce(IMessagePtr message, int64 delayMs) {
|
||||
Remove(message->Target(), message->Type());
|
||||
Post(message, delayMs);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace cursespp {
|
||||
|
||||
void Post(IMessagePtr message, int64 delayMs = 0);
|
||||
void Remove(IMessageTarget *target, int type = -1);
|
||||
void Debounce(IMessagePtr message, int delayMs = 0);
|
||||
void Debounce(IMessagePtr message, int64 delayMs = 0);
|
||||
|
||||
void Dispatch();
|
||||
|
||||
|
@ -36,11 +36,18 @@
|
||||
#include "ScrollAdapterBase.h"
|
||||
#include "ScrollableWindow.h"
|
||||
#include "MultiLineEntry.h"
|
||||
#include "ListWindow.h"
|
||||
|
||||
using namespace cursespp;
|
||||
|
||||
typedef IScrollAdapter::EntryPtr EntryPtr;
|
||||
|
||||
/* used for some calculations. it's ok to let this leak. if it's
|
||||
a static instance var we will have non-deterministic behavior when
|
||||
the instance is destructed, because the global message queue may
|
||||
be torn down as well */
|
||||
static ListWindow* DUMMY_SCROLLABLE_WINDOW = new ListWindow();
|
||||
|
||||
ScrollAdapterBase::ScrollAdapterBase() {
|
||||
this->height = 0;
|
||||
this->width = 0;
|
||||
@ -72,7 +79,7 @@ void ScrollAdapterBase::GetVisibleItems(
|
||||
/* forward search first... */
|
||||
int end = (int) GetEntryCount();
|
||||
for (int i = (int) desired; i < end && totalHeight > 0; i++) {
|
||||
EntryPtr entry = this->GetEntry(i);
|
||||
EntryPtr entry = this->GetEntry(DUMMY_SCROLLABLE_WINDOW, i);
|
||||
entry->SetWidth(this->width);
|
||||
totalHeight -= entry->GetLineCount();
|
||||
target.push_back(entry);
|
||||
@ -85,7 +92,7 @@ void ScrollAdapterBase::GetVisibleItems(
|
||||
totalHeight = this->height;
|
||||
int i = GetEntryCount() - 1;
|
||||
while (i >= 0 && totalHeight >= 0) {
|
||||
EntryPtr entry = this->GetEntry(i);
|
||||
EntryPtr entry = this->GetEntry(DUMMY_SCROLLABLE_WINDOW, i);
|
||||
entry->SetWidth(this->width);
|
||||
|
||||
int lines = entry->GetLineCount();
|
||||
|
@ -59,7 +59,7 @@ namespace cursespp {
|
||||
ScrollPosition *result = nullptr);
|
||||
|
||||
virtual size_t GetEntryCount() = 0;
|
||||
virtual EntryPtr GetEntry(size_t index) = 0;
|
||||
virtual EntryPtr GetEntry(cursespp::ScrollableWindow* window, size_t index) = 0;
|
||||
|
||||
virtual void SetItemDecorator(ItemDecorator decorator) { this->decorator = decorator; }
|
||||
|
||||
|
@ -49,7 +49,7 @@ typedef IScrollAdapter::ScrollPosition ScrollPos;
|
||||
|
||||
#define REDRAW_VISIBLE_PAGE() \
|
||||
{ \
|
||||
ScrollPos& pos = GetScrollPosition(); \
|
||||
ScrollPos& pos = GetMutableScrollPosition(); \
|
||||
GetScrollAdapter().DrawPage( \
|
||||
this, \
|
||||
pos.firstVisibleEntryIndex, \
|
||||
@ -68,14 +68,17 @@ void ScrollableWindow::OnDimensionsChanged() {
|
||||
Window::OnDimensionsChanged();
|
||||
|
||||
IScrollAdapter& adapter = this->GetScrollAdapter();
|
||||
ScrollPos& pos = this->GetScrollPosition();
|
||||
|
||||
adapter.SetDisplaySize(
|
||||
this->GetContentWidth(),
|
||||
this->GetContentHeight());
|
||||
}
|
||||
|
||||
ScrollPos& ScrollableWindow::GetScrollPosition() {
|
||||
ScrollPos& ScrollableWindow::GetMutableScrollPosition() {
|
||||
return this->scrollPosition;
|
||||
}
|
||||
|
||||
const ScrollPos& ScrollableWindow::GetScrollPosition() const {
|
||||
return this->scrollPosition;
|
||||
}
|
||||
|
||||
@ -91,13 +94,13 @@ bool ScrollableWindow::KeyPress(const std::string& key) {
|
||||
|
||||
if (key == "KEY_NPAGE") { this->PageDown(); return true; }
|
||||
else if (key == "KEY_PPAGE") { this->PageUp(); return true; }
|
||||
else if (key == "KEY_DOWN") {
|
||||
else if (key == "KEY_DOWN") {
|
||||
const size_t before = this->GetScrollPosition().logicalIndex;
|
||||
this->ScrollDown();
|
||||
const size_t after = this->GetScrollPosition().logicalIndex;
|
||||
return !this->allowArrowKeyPropagation || (before != after);
|
||||
}
|
||||
else if (key == "KEY_UP") {
|
||||
else if (key == "KEY_UP") {
|
||||
const size_t before = this->GetScrollPosition().logicalIndex;
|
||||
this->ScrollUp();
|
||||
const size_t after = this->GetScrollPosition().logicalIndex;
|
||||
@ -117,7 +120,7 @@ void ScrollableWindow::OnAdapterChanged() {
|
||||
this->ScrollToBottom();
|
||||
}
|
||||
else {
|
||||
ScrollPos &pos = this->GetScrollPosition();
|
||||
ScrollPos &pos = this->GetMutableScrollPosition();
|
||||
adapter->DrawPage(this, pos.firstVisibleEntryIndex, &pos);
|
||||
this->Repaint();
|
||||
}
|
||||
@ -129,7 +132,7 @@ void ScrollableWindow::Show() {
|
||||
}
|
||||
|
||||
void ScrollableWindow::ScrollToTop() {
|
||||
GetScrollAdapter().DrawPage(this, 0, &this->GetScrollPosition());
|
||||
GetScrollAdapter().DrawPage(this, 0, &this->GetMutableScrollPosition());
|
||||
this->Repaint();
|
||||
}
|
||||
|
||||
@ -137,13 +140,13 @@ void ScrollableWindow::ScrollToBottom() {
|
||||
GetScrollAdapter().DrawPage(
|
||||
this,
|
||||
GetScrollAdapter().GetEntryCount(),
|
||||
&this->GetScrollPosition());
|
||||
&this->GetMutableScrollPosition());
|
||||
|
||||
this->Repaint();
|
||||
}
|
||||
|
||||
void ScrollableWindow::ScrollUp(int delta) {
|
||||
ScrollPos &pos = this->GetScrollPosition();
|
||||
ScrollPos &pos = this->GetMutableScrollPosition();
|
||||
|
||||
if (pos.firstVisibleEntryIndex > 0) {
|
||||
GetScrollAdapter().DrawPage(
|
||||
@ -154,7 +157,7 @@ void ScrollableWindow::ScrollUp(int delta) {
|
||||
}
|
||||
|
||||
void ScrollableWindow::ScrollDown(int delta) {
|
||||
ScrollPos &pos = this->GetScrollPosition();
|
||||
ScrollPos &pos = this->GetMutableScrollPosition();
|
||||
|
||||
GetScrollAdapter().DrawPage(
|
||||
this, pos.firstVisibleEntryIndex + delta, &pos);
|
||||
@ -169,7 +172,7 @@ size_t ScrollableWindow::GetPreviousPageEntryIndex() {
|
||||
|
||||
int i = this->GetScrollPosition().firstVisibleEntryIndex;
|
||||
while (i >= 0) {
|
||||
IScrollAdapter::EntryPtr entry = adapter->GetEntry(i);
|
||||
IScrollAdapter::EntryPtr entry = adapter->GetEntry(this, i);
|
||||
entry->SetWidth(width);
|
||||
|
||||
int count = entry->GetLineCount();
|
||||
@ -195,7 +198,7 @@ void ScrollableWindow::PageDown() {
|
||||
}
|
||||
|
||||
bool ScrollableWindow::IsLastItemVisible() {
|
||||
ScrollPos &pos = this->GetScrollPosition();
|
||||
ScrollPos &pos = this->GetMutableScrollPosition();
|
||||
|
||||
size_t lastIndex = pos.totalEntries;
|
||||
lastIndex = (lastIndex == 0) ? lastIndex : lastIndex - 1;
|
||||
|
@ -65,9 +65,11 @@ namespace cursespp {
|
||||
|
||||
void SetAllowArrowKeyPropagation(bool allow = true);
|
||||
|
||||
const IScrollAdapter::ScrollPosition& GetScrollPosition() const;
|
||||
|
||||
protected:
|
||||
virtual IScrollAdapter& GetScrollAdapter() = 0;
|
||||
virtual IScrollAdapter::ScrollPosition& GetScrollPosition();
|
||||
virtual IScrollAdapter::ScrollPosition& GetMutableScrollPosition();
|
||||
|
||||
size_t GetPreviousPageEntryIndex();
|
||||
bool IsLastItemVisible();
|
||||
|
@ -37,6 +37,8 @@
|
||||
#include "SimpleScrollAdapter.h"
|
||||
#include "SingleLineEntry.h"
|
||||
#include "MultiLineEntry.h"
|
||||
#include "ScrollableWindow.h"
|
||||
#include "Colors.h"
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <utf8/utf8/unchecked.h>
|
||||
|
||||
@ -48,12 +50,17 @@ typedef IScrollAdapter::EntryPtr EntryPtr;
|
||||
|
||||
SimpleScrollAdapter::SimpleScrollAdapter() {
|
||||
this->maxEntries = MAX_ENTRY_COUNT;
|
||||
this->selectable = false;
|
||||
}
|
||||
|
||||
SimpleScrollAdapter::~SimpleScrollAdapter() {
|
||||
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::SetSelectable(bool selectable) {
|
||||
this->selectable = selectable;
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::Clear() {
|
||||
this->entries.clear();
|
||||
}
|
||||
@ -66,8 +73,19 @@ void SimpleScrollAdapter::SetMaxEntries(size_t maxEntries) {
|
||||
this->maxEntries = maxEntries;
|
||||
}
|
||||
|
||||
EntryPtr SimpleScrollAdapter::GetEntry(size_t index) {
|
||||
return this->entries.at(index);
|
||||
EntryPtr SimpleScrollAdapter::GetEntry(cursespp::ScrollableWindow* window, size_t index) {
|
||||
auto entry = this->entries.at(index);
|
||||
|
||||
SingleLineEntry* styleable = static_cast<SingleLineEntry*>(entry.get());
|
||||
styleable->SetAttrs(COLOR_PAIR(CURSESPP_TEXT_DEFAULT));
|
||||
|
||||
if (window && this->selectable) {
|
||||
if (index == window->GetScrollPosition().logicalIndex) {
|
||||
styleable->SetAttrs(COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM));
|
||||
}
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::AddEntry(std::shared_ptr<IEntry> entry) {
|
||||
@ -78,3 +96,8 @@ void SimpleScrollAdapter::AddEntry(std::shared_ptr<IEntry> entry) {
|
||||
entries.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleScrollAdapter::AddEntry(const std::string& value) {
|
||||
EntryPtr entry(new SingleLineEntry(value));
|
||||
this->AddEntry(entry);
|
||||
}
|
||||
|
@ -49,7 +49,10 @@ namespace cursespp {
|
||||
virtual void Clear();
|
||||
|
||||
virtual size_t GetEntryCount();
|
||||
virtual EntryPtr GetEntry(size_t index);
|
||||
virtual EntryPtr GetEntry(cursespp::ScrollableWindow* window, size_t index);
|
||||
|
||||
void SetSelectable(bool selectable);
|
||||
void AddEntry(const std::string& entry);
|
||||
|
||||
private:
|
||||
typedef std::deque<EntryPtr> EntryList; /* TODO: this is O(n) lookup */
|
||||
@ -57,5 +60,6 @@ namespace cursespp {
|
||||
|
||||
EntryList entries;
|
||||
size_t maxEntries;
|
||||
bool selectable;
|
||||
};
|
||||
}
|
||||
|
@ -127,6 +127,7 @@
|
||||
<ClCompile Include="app\layout\TrackSearchLayout.cpp" />
|
||||
<ClCompile Include="app\model\DirectoryAdapter.cpp" />
|
||||
<ClCompile Include="app\model\TrackList.cpp" />
|
||||
<ClCompile Include="app\overlay\VisualizerOverlay.cpp" />
|
||||
<ClCompile Include="app\query\CategoryListViewQuery.cpp" />
|
||||
<ClCompile Include="app\query\NowPlayingTrackListQuery.cpp" />
|
||||
<ClCompile Include="app\query\CategoryTrackListQuery.cpp" />
|
||||
@ -148,6 +149,7 @@
|
||||
<ClCompile Include="cursespp\Colors.cpp" />
|
||||
<ClCompile Include="cursespp\DialogOverlay.cpp" />
|
||||
<ClCompile Include="cursespp\LayoutBase.cpp" />
|
||||
<ClCompile Include="cursespp\ListOverlay.cpp" />
|
||||
<ClCompile Include="cursespp\ListWindow.cpp" />
|
||||
<ClCompile Include="cursespp\MultiLineEntry.cpp" />
|
||||
<ClCompile Include="cursespp\OverlayStack.cpp" />
|
||||
@ -181,6 +183,7 @@
|
||||
<ClInclude Include="app\layout\TrackSearchLayout.h" />
|
||||
<ClInclude Include="app\model\DirectoryAdapter.h" />
|
||||
<ClInclude Include="app\model\TrackList.h" />
|
||||
<ClInclude Include="app\overlay\VisualizerOverlay.h" />
|
||||
<ClInclude Include="app\query\CategoryListViewQuery.h" />
|
||||
<ClInclude Include="app\query\NowPlayingTrackListQuery.h" />
|
||||
<ClInclude Include="app\query\SearchTrackListQuery.h" />
|
||||
@ -217,6 +220,7 @@
|
||||
<ClInclude Include="cursespp\IWindowGroup.h" />
|
||||
<ClInclude Include="cursespp\IMessage.h" />
|
||||
<ClInclude Include="cursespp\LayoutBase.h" />
|
||||
<ClInclude Include="cursespp\ListOverlay.h" />
|
||||
<ClInclude Include="cursespp\ListWindow.h" />
|
||||
<ClInclude Include="cursespp\MultiLineEntry.h" />
|
||||
<ClInclude Include="cursespp\OverlayBase.h" />
|
||||
|
@ -141,6 +141,12 @@
|
||||
<ClCompile Include="cursespp\DialogOverlay.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="cursespp\ListOverlay.cpp">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="app\overlay\VisualizerOverlay.cpp">
|
||||
<Filter>app\overlay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
@ -333,6 +339,12 @@
|
||||
<ClInclude Include="app\util\Version.h">
|
||||
<Filter>app\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="cursespp\ListOverlay.h">
|
||||
<Filter>cursespp</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="app\overlay\VisualizerOverlay.h">
|
||||
<Filter>app\overlay</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="cursespp">
|
||||
@ -359,5 +371,8 @@
|
||||
<Filter Include="app\model">
|
||||
<UniqueIdentifier>{b6720351-dd55-4b14-936a-09df56193c15}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="app\overlay">
|
||||
<UniqueIdentifier>{a84f242d-d70b-49e9-975e-63fc73954a2b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user