Merge branch 'clangen/tracklist_headers'

This commit is contained in:
casey langen 2017-03-21 17:52:02 -07:00
commit 0a57ccce25
43 changed files with 625 additions and 280 deletions

View File

@ -673,7 +673,7 @@ class PlaybackRemote : public IPlaybackRemote {
{ key::title, album->GetDescription() },
{ key::id, album->GetId() },
{ key::thumbnail_id, 0 }, /* note: thumbnails aren't supported at the album level yet */
{ key::album_artist_id, this->GetMetadataInt64(album, key::album_artist_id) },
{ key::album_artist_id, album->GetInt64(key::album_artist_id.c_str()) },
{ key::album_artist, this->GetMetadataString(album, key::album_artist) }
});
@ -852,14 +852,14 @@ class PlaybackRemote : public IPlaybackRemote {
{ key::id, track->GetId() },
{ key::title, this->GetMetadataString(track, key::title) },
{ key::album, this->GetMetadataString(track, key::album) },
{ key::album_id, this->GetMetadataInt64(track, key::album_id) },
{ key::album_id, track->GetInt64(key::album_id.c_str()) },
{ key::album_artist, this->GetMetadataString(track, key::album_artist) },
{ key::album_artist_id, this->GetMetadataInt64(track, key::album_artist_id) },
{ key::album_artist_id, track->GetInt64(key::album_artist_id.c_str()) },
{ key::artist, this->GetMetadataString(track, key::artist) },
{ key::artist_id, this->GetMetadataInt64(track, key::artist_id) },
{ key::artist_id, track->GetInt64(key::artist_id.c_str()) },
{ key::genre, this->GetMetadataString(track, key::genre) },
{ key::genre_id, this->GetMetadataInt64(track, key::genre_id) },
{ key::thumbnail_id, this->GetMetadataInt64(track, key::thumbnail_id) },
{ key::genre_id, track->GetInt64(key::genre_id.c_str()) },
{ key::thumbnail_id, track->GetInt64(key::thumbnail_id.c_str()) },
};
}
@ -896,16 +896,6 @@ class PlaybackRemote : public IPlaybackRemote {
return std::string(threadLocalBuffer);
}
template <typename MetadataT>
unsigned long long GetMetadataInt64(MetadataT* metadata, const std::string& idKey) {
try {
return std::stoull(this->GetMetadataString(metadata, idKey));
}
catch (...) {
return -1;
}
}
void ThreadProc() {
try {
if (preferences->GetBool("debug")) {

View File

@ -41,14 +41,16 @@
#include "Locale.h"
#define KEY_STRINGS "strings"
#define KEY_DIMENSIONS "dimensions"
#define DEFAULT_LOCALE "en_US"
using namespace musik::core::i18n;
using namespace musik::core;
using namespace musik::core::prefs;
using namespace boost::filesystem;
static nlohmann::json empty;
static nlohmann::json loadLocaleData(const std::string& fn) {
char* bytes = nullptr;
int count = 0;
@ -142,13 +144,10 @@ std::string Locale::Translate(const std::string& key) {
}
std::string Locale::Translate(const char* key) {
static nlohmann::json empty;
/* get the string from the current locale */
if (!this->localeData.is_null()) {
const nlohmann::json& strings = this->localeData.value(KEY_STRINGS, empty);
auto it = strings.find(key);
if (it != strings.end()) {
return it.value();
}
@ -163,4 +162,22 @@ std::string Locale::Translate(const char* key) {
/* otherwise, just return the key! */
return key;
}
int Locale::Dimension(const char* key, int defaultValue) {
if (!this->localeData.is_null()) { /* current locale */
const nlohmann::json& strings = this->localeData.value(KEY_DIMENSIONS, empty);
auto it = strings.find(key);
if (it != strings.end()) {
return it.value();
}
}
if (!this->defaultLocaleData.is_null()) { /* fall back to default */
const nlohmann::json& strings = this->defaultLocaleData.value(KEY_DIMENSIONS, empty);
auto it = strings.find(key);
return (it != strings.end()) ? it.value() : key;
}
return defaultValue; /* not found anywhere */
}

View File

@ -62,6 +62,8 @@ namespace musik { namespace core { namespace i18n {
std::string Translate(const std::string& key);
std::string Translate(const char* key);
int Dimension(const char* key, int defaultValue);
private:
Locale();
@ -75,6 +77,7 @@ namespace musik { namespace core { namespace i18n {
#define _TSTR(KEY) (musik::core::i18n::Locale::Instance().Translate(KEY))
#define _TCP(KEY) (musik::core::i18n::Locale::Instance().Translate(KEY).c_str())
#define _DIMEN(KEY, DEFAULT) (musik::core::i18n::Locale::Instance().Dimension(KEY, DEFAULT))
} } }

View File

@ -57,6 +57,11 @@ namespace {
virtual void Release() { this->wrapped.reset(); }
virtual unsigned long long GetId() { return this->wrapped->GetId(); }
virtual int GetValue(const char* key, char* dst, int size) { return this->wrapped->GetValue(key, dst, size); }
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue) { return this->wrapped->GetUint64(key, defaultValue); }
virtual long long GetInt64(const char* key, long long defaultValue) { return this->wrapped->GetInt64(key, defaultValue); }
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue) { return this->wrapped->GetUint32(key, defaultValue); }
virtual long GetInt32(const char* key, unsigned int defaultValue) { return this->wrapped->GetInt32(key, defaultValue); }
virtual double GetDouble(const char* key, double defaultValue) { return this->wrapped->GetDouble(key, defaultValue); }
virtual const char* GetDescription() { return this->wrapped->GetDescription(); }
virtual const char* GetType() { return this->wrapped->GetType(); }
MetadataMapPtr wrapped;
@ -98,6 +103,39 @@ int MetadataMap::GetValue(const char* key, char* dst, int size) {
return 0;
}
std::string MetadataMap::GetValue(const char* key) {
auto it = metadata.find(key);
if (it != metadata.end()) {
return it->second;
}
return "";
}
unsigned long long MetadataMap::GetUint64(const char* key, unsigned long long defaultValue) {
try { return std::stoull(GetValue(key)); } catch (...) { }
return defaultValue;
}
long long MetadataMap::GetInt64(const char* key, long long defaultValue) {
try { return std::stoll(GetValue(key)); } catch (...) { }
return defaultValue;
}
unsigned long MetadataMap::GetUint32(const char* key, unsigned long defaultValue) {
try { return std::stoul(GetValue(key)); } catch (...) { }
return defaultValue;
}
long MetadataMap::GetInt32(const char* key, unsigned int defaultValue) {
try { return std::stol(GetValue(key)); } catch (...) { }
return defaultValue;
}
double MetadataMap::GetDouble(const char* key, double defaultValue) {
try { return std::stod(GetValue(key)); } catch (...) { }
return defaultValue;
}
const char* MetadataMap::GetDescription() {
return this->description.c_str();
}

View File

@ -56,12 +56,19 @@ namespace musik { namespace core {
/* IMetadataMap */
virtual void Release();
virtual unsigned long long GetId();
virtual int GetValue(const char* key, char* dst, int size);
virtual const char* GetDescription();
virtual const char* GetType();
virtual int GetValue(const char* key, char* dst, int size);
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL);
virtual long long GetInt64(const char* key, long long defaultValue = 0LL);
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0);
virtual long GetInt32(const char* key, unsigned int defaultValue = 0);
virtual double GetDouble(const char* key, double defaultValue = 0.0f);
/* implementation specific */
void SetValue(const char* key, const std::string& value);
std::string GetValue(const char* key);
musik::core::sdk::IMetadataMap* GetSdkValue();
private:

View File

@ -87,6 +87,31 @@ std::string IndexerTrack::GetValue(const char* metakey) {
return "";
}
unsigned long long IndexerTrack::GetUint64(const char* key, unsigned long long defaultValue) {
try { return std::stoull(GetValue(key)); } catch (...) { }
return defaultValue;
}
long long IndexerTrack::GetInt64(const char* key, long long defaultValue) {
try { return std::stoll(GetValue(key)); } catch (...) { }
return defaultValue;
}
unsigned long IndexerTrack::GetUint32(const char* key, unsigned long defaultValue) {
try { return std::stoul(GetValue(key)); } catch (...) { }
return defaultValue;
}
long IndexerTrack::GetInt32(const char* key, unsigned int defaultValue) {
try { return std::stol(GetValue(key)); } catch (...) { }
return defaultValue;
}
double IndexerTrack::GetDouble(const char* key, double defaultValue) {
try { return std::stod(GetValue(key)); } catch (...) { }
return defaultValue;
}
void IndexerTrack::SetValue(const char* metakey, const char* value) {
if (metakey && value) {
this->internalMetadata->metadata.insert(

View File

@ -51,6 +51,11 @@ namespace musik { namespace core {
virtual std::string GetValue(const char* metakey);
virtual int GetValue(const char* key, char* dst, int size);
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL);
virtual long long GetInt64(const char* key, long long defaultValue = 0LL);
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0);
virtual long GetInt32(const char* key, unsigned int defaultValue = 0);
virtual double GetDouble(const char* key, double defaultValue = 0.0f);
virtual std::string Uri();
virtual int Uri(char* dst, int size);

View File

@ -71,6 +71,31 @@ std::string LibraryTrack::GetValue(const char* metakey) {
return "";
}
unsigned long long LibraryTrack::GetUint64(const char* key, unsigned long long defaultValue) {
try { return std::stoull(GetValue(key)); } catch (...) { }
return defaultValue;
}
long long LibraryTrack::GetInt64(const char* key, long long defaultValue) {
try { return std::stoll(GetValue(key)); } catch (...) { }
return defaultValue;
}
unsigned long LibraryTrack::GetUint32(const char* key, unsigned long defaultValue) {
try { return std::stoul(GetValue(key)); } catch (...) { }
return defaultValue;
}
long LibraryTrack::GetInt32(const char* key, unsigned int defaultValue) {
try { return std::stol(GetValue(key)); } catch (...) { }
return defaultValue;
}
double LibraryTrack::GetDouble(const char* key, double defaultValue) {
try { return std::stod(GetValue(key)); } catch (...) { }
return defaultValue;
}
void LibraryTrack::SetValue(const char* metakey, const char* value) {
std::unique_lock<std::mutex> lock(this->data.mutex);
this->data.metadata.insert(std::pair<std::string, std::string>(metakey,value));

View File

@ -59,6 +59,12 @@ namespace musik { namespace core {
virtual void SetThumbnail(const char *data, long size);
virtual std::string GetValue(const char* metakey);
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL);
virtual long long GetInt64(const char* key, long long defaultValue = 0LL);
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0);
virtual long GetInt32(const char* key, unsigned int defaultValue = 0);
virtual double GetDouble(const char* key, double defaultValue = 0.0f);
virtual std::string Uri();
virtual int GetValue(const char* key, char* dst, int size);

View File

@ -61,6 +61,26 @@ int RetainedTrack::Uri(char* dst, int size) {
return track->Uri(dst, size);
}
unsigned long long RetainedTrack::GetUint64(const char* key, unsigned long long defaultValue) {
return track->GetUint64(key, defaultValue);
}
long long RetainedTrack::GetInt64(const char* key, long long defaultValue) {
return track->GetInt64(key, defaultValue);
}
unsigned long RetainedTrack::GetUint32(const char* key, unsigned long defaultValue) {
return track->GetUint32(key, defaultValue);
}
long RetainedTrack::GetInt32(const char* key, unsigned int defaultValue) {
return track->GetInt32(key, defaultValue);
}
double RetainedTrack::GetDouble(const char* key, double defaultValue) {
return track->GetDouble(key, defaultValue);
}
unsigned long long RetainedTrack::GetId() {
return track->GetId();
}

View File

@ -45,7 +45,14 @@ namespace musik { namespace core {
virtual unsigned long long GetId();
virtual void Release();
virtual int GetValue(const char* key, char* dst, int size);
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL);
virtual long long GetInt64(const char* key, long long defaultValue = 0LL);
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0);
virtual long GetInt32(const char* key, unsigned int defaultValue = 0);
virtual double GetDouble(const char* key, double defaultValue = 0.0f);
virtual int Uri(char* dst, int size);
private:

View File

@ -67,6 +67,12 @@ namespace musik { namespace core {
virtual std::string Uri() = 0;
virtual int GetValue(const char* key, char* dst, int size) = 0;
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL) = 0;
virtual long long GetInt64(const char* key, long long defaultValue = 0LL) = 0;
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0) = 0;
virtual long GetInt32(const char* key, unsigned int defaultValue = 0) = 0;
virtual double GetDouble(const char* key, double defaultValue = 0.0f) = 0;
virtual int Uri(char* dst, int size) = 0;
virtual MetadataIteratorRange GetValues(const char* metakey) = 0;

View File

@ -45,8 +45,11 @@ namespace musik {
virtual ~IMessageQueue() { }
virtual void Post(IMessagePtr message, int64 delayMs = 0) = 0;
virtual int Remove(IMessageTarget *target, int type = -1) = 0;
virtual void Broadcast(IMessagePtr message, int64 delayMs = 0) = 0;
virtual bool Contains(IMessageTarget *target, int type = -1) = 0;
virtual void Debounce(IMessagePtr message, int64 delayMs = 0) = 0;
virtual void RegisterForBroadcasts(IMessageTargetPtr target) = 0;
virtual void UnregisterForBroadcasts(IMessageTargetPtr target) = 0;
virtual void WaitAndDispatch() = 0;
virtual void Dispatch() = 0;
};

View File

@ -37,9 +37,13 @@
#include "IMessage.h"
namespace musik { namespace core { namespace runtime {
class IMessageTarget {
public:
virtual ~IMessageTarget() { }
virtual void ProcessMessage(IMessage &message) = 0;
};
typedef std::shared_ptr<IMessageTarget> IMessageTargetPtr;
} } }

View File

@ -49,8 +49,8 @@ namespace musik { namespace core { namespace runtime {
static IMessagePtr Create(
IMessageTarget* target,
int messageType,
int64 data1,
int64 data2);
int64 data1 = 0LL,
int64 data2 = 0LL);
virtual ~Message() {
}

View File

@ -124,6 +124,19 @@ void MessageQueue::Dispatch() {
}
}
void MessageQueue::RegisterForBroadcasts(IMessageTargetPtr target) {
LockT lock(this->queueMutex);
this->receivers.insert(target);
}
void MessageQueue::UnregisterForBroadcasts(IMessageTargetPtr target) {
LockT lock(this->queueMutex);
auto it = this->receivers.find(target);
if (it != this->receivers.end()) {
this->receivers.erase(it);
}
}
int MessageQueue::Remove(IMessageTarget *target, int type) {
LockT lock(this->queueMutex);
@ -169,6 +182,14 @@ bool MessageQueue::Contains(IMessageTarget *target, int type) {
return false;
}
void MessageQueue::Broadcast(IMessagePtr message, int64 delayMs) {
if (message->Target()) {
throw new std::runtime_error("broadcasts cannot have a target!");
}
this->Post(message, delayMs);
}
void MessageQueue::Post(IMessagePtr message, int64 delayMs) {
LockT lock(this->queueMutex);
@ -215,5 +236,23 @@ void MessageQueue::Debounce(IMessagePtr message, int64 delayMs) {
}
void MessageQueue::Dispatch(IMessagePtr message) {
message->Target()->ProcessMessage(*message);
if (message->Target()) {
message->Target()->ProcessMessage(*message);
}
else {
std::set<IMessageTargetPtr> copy;
{
LockT lock(this->queueMutex);
std::copy(
receivers.begin(),
receivers.end(),
std::inserter(copy, copy.begin()));
}
for (auto receiver : copy) {
receiver->ProcessMessage(*message);
}
}
}

View File

@ -41,6 +41,7 @@
#include <condition_variable>
#include <chrono>
#include <atomic>
#include <set>
namespace musik { namespace core { namespace runtime {
class MessageQueue : public IMessageQueue {
@ -49,9 +50,12 @@ namespace musik { namespace core { namespace runtime {
virtual ~MessageQueue();
virtual void Post(IMessagePtr message, int64 delayMs = 0);
virtual void Broadcast(IMessagePtr message, int64 messageMs = 0);
virtual int Remove(IMessageTarget *target, int type = -1);
virtual bool Contains(IMessageTarget *target, int type = -1);
virtual void Debounce(IMessagePtr message, int64 delayMs = 0);
virtual void RegisterForBroadcasts(IMessageTargetPtr target);
virtual void UnregisterForBroadcasts(IMessageTargetPtr target);
virtual void WaitAndDispatch();
virtual void Dispatch();
@ -69,6 +73,7 @@ namespace musik { namespace core { namespace runtime {
std::mutex queueMutex;
std::list<EnqueuedMessage*> queue;
std::list<EnqueuedMessage*> dispatch;
std::set<IMessageTargetPtr> receivers;
std::condition_variable_any waitForDispatch;
std::atomic<int64> nextMessageTime;

View File

@ -41,6 +41,11 @@ namespace musik { namespace core { namespace sdk {
virtual void Release() = 0;
virtual unsigned long long GetId() = 0;
virtual int GetValue(const char* key, char* dst, int size) = 0;
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL) = 0;
virtual long long GetInt64(const char* key, long long defaultValue = 0LL) = 0;
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0) = 0;
virtual long GetInt32(const char* key, unsigned int defaultValue = 0) = 0;
virtual double GetDouble(const char* key, double defaultValue = 0.0f) = 0;
virtual const char* GetDescription() = 0;
virtual const char* GetType() = 0;
};

View File

@ -40,6 +40,11 @@ namespace musik { namespace core { namespace sdk {
public:
virtual unsigned long long GetId() = 0;
virtual int GetValue(const char* key, char* dst, int size) = 0;
virtual unsigned long long GetUint64(const char* key, unsigned long long defaultValue = 0ULL) = 0;
virtual long long GetInt64(const char* key, long long defaultValue = 0LL) = 0;
virtual unsigned long GetUint32(const char* key, unsigned long defaultValue = 0) = 0;
virtual long GetInt32(const char* key, unsigned int defaultValue = 0) = 0;
virtual double GetDouble(const char* key, double defaultValue = 0.0f) = 0;
virtual int Uri(char* dst, int size) = 0;
};

View File

@ -108,5 +108,5 @@ namespace musik {
static const char* AlbumId = "album_id";
}
static const int SdkVersion = 3;
static const int SdkVersion = 4;
} } }

View File

@ -21,7 +21,6 @@ set (BOX_SRCS
./app/util/PreferenceKeys.cpp
./app/util/Playback.cpp
./app/window/CategoryListView.cpp
./app/window/EntryWithHeader.cpp
./app/window/LogWindow.cpp
./app/window/TrackListView.cpp
./app/window/TransportWindow.cpp

View File

@ -56,6 +56,8 @@ using namespace cursespp;
static size_t MAX_CATEGORY_WIDTH = 40;
static int MIN_LIST_TITLE_HEIGHT = 26;
#define MESSAGE_INDEXER_PROGRESS 2033
#define DEFAULT_CATEGORY constants::Track::ARTIST
#define DEFAULT_CATEGORY_NAME FIELD_TO_TITLE[DEFAULT_CATEGORY]
@ -137,6 +139,14 @@ void BrowseLayout::InitializeWindows() {
this, &BrowseLayout::OnCategoryViewInvalidated);
}
void BrowseLayout::ProcessMessage(musik::core::runtime::IMessage &message) {
if (message.Type() == MESSAGE_INDEXER_PROGRESS) {
this->categoryList->Requery();
}
LayoutBase::ProcessMessage(message);
}
void BrowseLayout::ScrollTo(const std::string& fieldType, DBID fieldId) {
this->SetFocus(this->trackList);
this->categoryList->RequeryWithField(fieldType, "", fieldId);
@ -153,12 +163,13 @@ void BrowseLayout::OnVisibilityChanged(bool visible) {
LayoutBase::OnVisibilityChanged(visible);
if (visible) {
Window::MessageQueue().RegisterForBroadcasts(shared_from_this());
this->categoryList->Requery();
}
}
void BrowseLayout::OnIndexerProgress(int count) {
this->categoryList->Requery();
this->PostMessage(MESSAGE_INDEXER_PROGRESS);
}
void BrowseLayout::RequeryTrackList(ListWindow *view) {
@ -201,8 +212,11 @@ bool BrowseLayout::KeyPress(const std::string& key) {
}
else if (Hotkeys::Is(Hotkeys::ContextMenu, key)) {
if (this->GetFocus() == this->trackList) {
PlayQueueOverlays::ShowAddTrackOverlay(this->playback, *this->trackList);
return true;
TrackPtr track = this->trackList->GetSelectedTrack();
if (track) {
PlayQueueOverlays::ShowAddTrackOverlay(this->playback, track->GetId());
return true;
}
}
}
else if (Hotkeys::Is(Hotkeys::ViewRefresh, key)) {

View File

@ -65,7 +65,7 @@ namespace musik {
virtual void OnVisibilityChanged(bool visible);
virtual cursespp::IWindowPtr GetFocus();
virtual bool KeyPress(const std::string& key);
virtual void ProcessMessage(musik::core::runtime::IMessage &message);
void ScrollTo(const std::string& fieldType, DBID fieldId);
protected:

View File

@ -39,6 +39,7 @@
#include <core/library/LocalLibraryConstants.h>
#include <app/overlay/PlayQueueOverlays.h>
#include <app/util/Hotkeys.h>
#include <glue/util/Playback.h>
@ -146,6 +147,7 @@ void LibraryLayout::ShowTrackSearch() {
void LibraryLayout::InitializeWindows() {
this->browseLayout.reset(new BrowseLayout(this->playback, this->library));
this->nowPlayingLayout.reset(new NowPlayingLayout(this->playback, this->library));
this->searchLayout.reset(new SearchLayout(this->playback, this->library));
@ -194,6 +196,14 @@ void LibraryLayout::UpdateShortcutsWindow() {
}
}
void LibraryLayout::OnAddedToParent(IWindow* parent) {
MessageQueue().RegisterForBroadcasts(shared_from_this());
}
void LibraryLayout::OnRemovedFromParent(IWindow* parent) {
MessageQueue().UnregisterForBroadcasts(shared_from_this());
}
void LibraryLayout::OnSearchResultSelected(
SearchLayout* layout, std::string fieldType, DBID fieldId)
{
@ -255,6 +265,14 @@ bool LibraryLayout::SetFocus(cursespp::IWindowPtr window) {
return this->visibleLayout->SetFocus(window);
}
void LibraryLayout::ProcessMessage(musik::core::runtime::IMessage &message) {
if (message.Type() == PlayQueueOverlays::BROADCAST_JUMP_TO_ALBUM) {
this->OnSearchResultSelected(nullptr, constants::Track::ALBUM, message.UserData1());
}
LayoutBase::ProcessMessage(message);
}
bool LibraryLayout::KeyPress(const std::string& key) {
if (key == "^[") { /* switches between browse/now playing */
if (this->visibleLayout != this->browseLayout) {

View File

@ -68,6 +68,7 @@ namespace musik {
virtual cursespp::IWindowPtr FocusPrev();
virtual cursespp::IWindowPtr GetFocus();
virtual bool SetFocus(cursespp::IWindowPtr window);
virtual void ProcessMessage(musik::core::runtime::IMessage &message);
virtual void SetShortcutsWindow(
cursespp::ShortcutsWindow* w);
@ -76,6 +77,8 @@ namespace musik {
protected:
virtual void OnLayout();
virtual void OnAddedToParent(IWindow* newParent);
virtual void OnRemovedFromParent(IWindow* oldParent);
private:
void OnSearchResultSelected(

View File

@ -152,7 +152,10 @@ bool TrackSearchLayout::KeyPress(const std::string& key) {
return true;
}
else if (Hotkeys::Is(Hotkeys::ContextMenu, key)) {
PlayQueueOverlays::ShowAddTrackOverlay(this->playback, *this->trackList);
TrackPtr track = this->trackList->GetSelectedTrack();
if (track) {
PlayQueueOverlays::ShowAddTrackOverlay(this->playback, track->GetId());
}
}
else if (key == "KEY_DOWN") {
if (this->GetFocus() == this->input) {

View File

@ -44,6 +44,7 @@
#include <core/library/query/local/GetPlaylistQuery.h>
#include <core/library/query/local/SavePlaylistQuery.h>
#include <core/library/query/local/DeletePlaylistQuery.h>
#include <core/runtime/Message.h>
#include <cursespp/App.h>
#include <cursespp/SimpleScrollAdapter.h>
@ -114,7 +115,7 @@ static void showPlaylistListOverlay(
dialog->SetAdapter(adapter)
.SetTitle(title)
.SetWidth(DEFAULT_OVERLAY_WIDTH)
.SetWidth(_DIMEN("playqueue_playlist_list_overlay", DEFAULT_OVERLAY_WIDTH))
.SetSelectedIndex(selectedIndex)
.SetItemSelectedCallback(callback);
@ -153,7 +154,7 @@ static void createNewPlaylist(
std::shared_ptr<InputOverlay> dialog(new InputOverlay());
dialog->SetTitle(_TSTR("playqueue_overlay_playlist_name_title"))
.SetWidth(DEFAULT_OVERLAY_WIDTH)
.SetWidth(_DIMEN("playqueue_playlist_name_overlay", DEFAULT_OVERLAY_WIDTH))
.SetText("")
.SetInputAcceptedCallback(
[tracks, library](const std::string& name) {
@ -173,7 +174,7 @@ static void renamePlaylist(
std::shared_ptr<InputOverlay> dialog(new InputOverlay());
dialog->SetTitle(_TSTR("playqueue_overlay_new_playlist_name_title"))
.SetWidth(DEFAULT_OVERLAY_WIDTH)
.SetWidth(_DIMEN("playqueue_playlist_name_overlay", DEFAULT_OVERLAY_WIDTH))
.SetText(oldName)
.SetInputAcceptedCallback(
[library, playlistId](const std::string& name) {
@ -221,29 +222,51 @@ static void showNoPlaylistsDialog() {
App::Overlays().Push(dialog);
}
static void handleAddCategorySelection(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
const std::string& fieldColumn,
DBID fieldId,
size_t type)
{
std::shared_ptr<CategoryTrackListQuery> query(
new CategoryTrackListQuery(library, fieldColumn, fieldId));
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
auto editor = playback.Edit();
auto tracks = query->GetResult();
size_t position = playback.GetIndex();
if (type == 0 || position == ListWindow::NO_SELECTION) { /* end */
for (size_t i = 0; i < tracks->Count(); i++) {
editor.Add(tracks->GetId(i));
}
}
else { /* after next */
for (size_t i = 0; i < tracks->Count(); i++) {
editor.Insert(tracks->GetId(i), position + 1 + i);
}
}
}
}
PlayQueueOverlays::PlayQueueOverlays() {
}
void PlayQueueOverlays::ShowAddTrackOverlay(
PlaybackService& playback,
TrackListView& trackList)
unsigned long long trackId)
{
size_t selectedIndex = trackList.GetSelectedIndex();
if (selectedIndex == ListWindow::NO_SELECTION) {
return;
}
DBID trackId = trackList.Get(selectedIndex)->GetId();
auto adapter = createAddToAdapter();
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
dialog->SetAdapter(adapter)
.SetTitle(_TSTR("playqueue_overlay_add_to_queue_title"))
.SetWidth(_DIMEN("playqueue_playlist_add_to_queue_overlay", DEFAULT_OVERLAY_WIDTH))
.SetSelectedIndex(0)
.SetWidth(DEFAULT_OVERLAY_WIDTH)
.SetItemSelectedCallback(
[trackId, &playback](ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
auto editor = playback.Edit();
@ -276,8 +299,8 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
dialog->SetAdapter(adapter)
.SetTitle(_TSTR("playqueue_overlay_add_to_queue_title"))
.SetWidth(_DIMEN("playqueue_playlist_add_to_queue_overlay", DEFAULT_OVERLAY_WIDTH))
.SetSelectedIndex(0)
.SetWidth(DEFAULT_OVERLAY_WIDTH)
.SetItemSelectedCallback(
[&playback, library, fieldColumn, fieldId]
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
@ -285,35 +308,53 @@ void PlayQueueOverlays::ShowAddCategoryOverlay(
return;
}
std::shared_ptr<CategoryTrackListQuery>
query(new CategoryTrackListQuery(
library,
fieldColumn,
fieldId));
library->Enqueue(query, ILibrary::QuerySynchronous);
if (query->GetStatus() == IQuery::Finished) {
auto editor = playback.Edit();
auto tracks = query->GetResult();
size_t position = playback.GetIndex();
if (index == 0 || position == ListWindow::NO_SELECTION) { /* end */
for (size_t i = 0; i < tracks->Count(); i++) {
editor.Add(tracks->GetId(i));
}
}
else { /* after next */
for (size_t i = 0; i < tracks->Count(); i++) {
editor.Insert(tracks->GetId(i), position + 1 + i);
}
}
}
handleAddCategorySelection(playback, library, fieldColumn, fieldId, index);
});
cursespp::App::Overlays().Push(dialog);
}
void PlayQueueOverlays::ShowAlbumDividerOverlay(
musik::core::runtime::IMessageQueue& messageQueue,
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
musik::core::TrackPtr firstTrack)
{
std::shared_ptr<Adapter> adapter(new Adapter());
adapter->AddEntry(_TSTR("playqueue_overlay_album_jump_to"));
adapter->AddEntry(_TSTR("playqueue_overlay_add_to_end_in_queue"));
adapter->AddEntry(_TSTR("playqueue_overlay_add_as_next_in_queue"));
adapter->SetSelectable(true);
std::shared_ptr<ListOverlay> dialog(new ListOverlay());
dialog->SetAdapter(adapter)
.SetTitle(_TSTR("playqueue_overlay_album_header"))
.SetWidth(_DIMEN("playqueue_album_header_overlay", DEFAULT_OVERLAY_WIDTH))
.SetSelectedIndex(0)
.SetItemSelectedCallback(
[&playback, library, &messageQueue, firstTrack]
(ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) {
if (index == ListWindow::NO_SELECTION) {
return;
}
auto albumIdColumn = library::constants::Track::ALBUM_ID;
auto albumColumn = library::constants::Track::ALBUM;
auto albumId = firstTrack->GetUint64(albumIdColumn);
if (index == 0) {
messageQueue.Broadcast(runtime::Message::Create(
nullptr, PlayQueueOverlays::BROADCAST_JUMP_TO_ALBUM, albumId));
}
else {
handleAddCategorySelection(playback, library, albumColumn, albumId, index - 1);
}
});
cursespp::App::Overlays().Push(dialog);
}
void PlayQueueOverlays::ShowLoadPlaylistOverlay(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,

View File

@ -43,11 +43,13 @@ namespace musik {
namespace box {
class PlayQueueOverlays {
public:
static const int BROADCAST_JUMP_TO_ALBUM = 3000;
using PlaylistSelectedCallback = std::function<void(DBID)>;
static void ShowAddTrackOverlay(
musik::core::audio::PlaybackService& playback,
musik::box::TrackListView& trackList);
unsigned long long trackId);
static void ShowAddCategoryOverlay(
musik::core::audio::PlaybackService& playback,
@ -55,6 +57,12 @@ namespace musik {
const std::string& fieldColumn,
DBID fieldId);
static void ShowAlbumDividerOverlay(
musik::core::runtime::IMessageQueue& messageQueue,
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
musik::core::TrackPtr firstTrack);
static void ShowLoadPlaylistOverlay(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,

View File

@ -50,8 +50,14 @@ namespace musik {
auto tracks = trackList->GetTrackList();
if (tracks && tracks->Count()) {
size_t index = (focused.get() == trackList.get())
? trackList->GetSelectedIndex() : 0;
size_t index = 0;
if (focused.get() == trackList.get()) {
index = trackList->GetSelectedTrackIndex();
if (index == cursespp::ListWindow::NO_SELECTION) {
return;
}
}
playback.Play(*tracks, index);
}

View File

@ -1,77 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 "EntryWithHeader.h"
#include <boost/algorithm/string.hpp>
#include <cursespp/Text.h>
using namespace musik::box;
using namespace cursespp;
EntryWithHeader::EntryWithHeader(
const std::string& header, const std::string& value)
{
this->header = header;
this->value = value;
this->attrs = -1;
}
void EntryWithHeader::SetWidth(size_t width) {
this->width = width;
}
int64 EntryWithHeader::GetAttrs(size_t line) {
return (line == 0) ? this->headerAttrs : this->attrs;
}
void EntryWithHeader::SetAttrs(int64 headerAttrs, int64 attrs) {
this->headerAttrs = headerAttrs;
this->attrs = attrs;
}
size_t EntryWithHeader::GetLineCount() {
return 2;
}
#define TRUNCATE(value, width) \
u8substr(value, 0, width > 0 ? width : 0)
std::string EntryWithHeader::GetLine(size_t line) {
if (line == 0) {
return text::Ellipsize(this->header, this->width);
}
return TRUNCATE(this->value, this->width);
}

View File

@ -1,59 +0,0 @@
//////////////////////////////////////////////////////////////////////////////
//
// 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 <cursespp/IScrollAdapter.h>
namespace musik {
namespace box {
class EntryWithHeader : public cursespp::IScrollAdapter::IEntry {
public:
EntryWithHeader(const std::string& header, const std::string& value);
virtual ~EntryWithHeader() { }
virtual void SetWidth(size_t width);
virtual int64 GetAttrs(size_t line);
virtual size_t GetLineCount();
virtual std::string GetLine(size_t line);
void SetAttrs(int64 headerAttrs, int64 attrs);
private:
size_t width;
std::string header, value;
int64 headerAttrs, attrs;
};
}
}

View File

@ -44,7 +44,7 @@
#include <glue/util/Duration.h>
#include <app/util/Hotkeys.h>
#include <app/window/EntryWithHeader.h>
#include <app/overlay/PlayQueueOverlays.h>
#include <boost/format.hpp>
@ -109,14 +109,14 @@ void TrackListView::Requery(std::shared_ptr<TrackListQueryBase> query) {
void TrackListView::OnQueryCompleted(IQuery* query) {
if (this->query && query == this->query.get()) {
if (this->query->GetStatus() == IQuery::Finished) {
this->metadata = this->query->GetResult();
this->headers = this->query->GetHeaders();
this->tracks = this->query->GetResult();
this->headers.Set(this->query->GetHeaders());
/* if the query was functionally the same as the last query, don't
mess with the selected index */
if (this->lastQueryHash != this->query->GetQueryHash()) {
this->SetSelectedIndex(0);
this->ScrollToTop();
this->SetSelectedIndex(this->headers.HeaderAt(0) ? 1 : 0);
}
this->lastQueryHash = this->query->GetQueryHash();
@ -130,12 +130,12 @@ void TrackListView::OnQueryCompleted(IQuery* query) {
}
std::shared_ptr<const TrackList> TrackListView::GetTrackList() {
return this->metadata;
return this->tracks;
}
void TrackListView::SetTrackList(std::shared_ptr<const TrackList> trackList) {
if (this->metadata != trackList) {
this->metadata = trackList;
if (this->tracks != trackList) {
this->tracks = trackList;
this->SetSelectedIndex(0);
this->ScrollToTop();
this->OnAdapterChanged();
@ -147,24 +147,34 @@ void TrackListView::SetTrackList(std::shared_ptr<const TrackList> trackList) {
void TrackListView::Clear() {
this->query.reset();
this->metadata.reset(new TrackList(this->library));
this->headers.reset(new std::set<size_t>());
this->tracks.reset(new TrackList(this->library));
this->headers.Reset();
this->OnAdapterChanged();
}
TrackPtr TrackListView::Get(size_t index) {
return this->metadata->Get(index);
TrackPtr TrackListView::GetSelectedTrack() {
auto i = this->GetSelectedTrackIndex();
return (i == ListWindow::NO_SELECTION) ? TrackPtr() : this->tracks->Get(i);
}
size_t TrackListView::GetSelectedTrackIndex() {
auto i = this->GetSelectedIndex();
if (i != ListWindow::NO_SELECTION) {
auto entry = adapter->GetEntry(this, i);
return static_cast<TrackListEntry*>(entry.get())->GetIndex();
}
return ListWindow::NO_SELECTION;
}
size_t TrackListView::Count() {
return this->metadata ? this->metadata->Count() : 0;
return this->tracks ? this->tracks->Count() : 0;
}
void TrackListView::ScrollToPlaying() {
if (this->playing && this->metadata) {
if (this->playing && this->tracks) {
DBID id = this->playing->GetId();
for (size_t i = 0; i < this->metadata->Count(); i++) {
if (this->metadata->GetId(i) == id) {
for (size_t i = 0; i < this->tracks->Count(); i++) {
if (this->tracks->GetId(i) == id) {
this->SetSelectedIndex(i);
auto pos = this->GetScrollPosition();
@ -188,12 +198,30 @@ void TrackListView::ProcessMessage(IMessage &message) {
bool TrackListView::KeyPress(const std::string& key) {
bool handled = false;
if (Hotkeys::Is(Hotkeys::NavigateJumpToPlaying, key)) {
if (key == "KEY_ENTER") {
if (headers.HeaderAt(this->GetSelectedIndex())) {
auto track = this->GetSelectedTrack();
PlayQueueOverlays::ShowAlbumDividerOverlay(
MessageQueue(), this->playback, this->library, track);
//PlayQueueOverlays::ShowAddCategoryOverlay(
// this->playback,
// this->library,
// constants::Track::ALBUM,
// track->GetUint64(constants::Track::ALBUM_ID));
handled = true;
}
}
else if (Hotkeys::Is(Hotkeys::NavigateJumpToPlaying, key)) {
this->ScrollToPlaying();
handled = true;
}
handled = ListWindow::KeyPress(key);
if (!handled) {
handled = ListWindow::KeyPress(key);
}
if (handled) {
this->lastChanged = now();
@ -224,8 +252,54 @@ TrackListView::Adapter::Adapter(TrackListView &parent)
: parent(parent) {
}
/* * * * TrackListView::HeaderCalculator * * * */
void TrackListView::HeaderCalculator::Set(Headers rawOffsets) {
this->rawOffsets = rawOffsets;
this->absoluteOffsets.reset();
if (rawOffsets) {
this->absoluteOffsets.reset(new std::set<size_t>());
size_t i = 0;
for (auto val : (*this->rawOffsets)) {
this->absoluteOffsets->insert(val + i);
i++;
}
}
}
void TrackListView::HeaderCalculator::Reset() {
this->absoluteOffsets.reset();
this->rawOffsets.reset();
}
size_t TrackListView::HeaderCalculator::OffsetTrackIndex(size_t index) {
size_t result = index;
if (this->absoluteOffsets) {
for (auto offset : (*this->absoluteOffsets)) {
if (result != 0 && offset <= index) {
--result;
}
else {
break;
}
}
}
return result;
}
size_t TrackListView::HeaderCalculator::Count() {
return this->absoluteOffsets ? this->absoluteOffsets->size() : 0;
}
bool TrackListView::HeaderCalculator::HeaderAt(size_t index) {
return this->absoluteOffsets &&
this->absoluteOffsets->find(index) != this->absoluteOffsets->end();
}
/* * * * TrackListView::Adapter * * * */
size_t TrackListView::Adapter::GetEntryCount() {
return parent.metadata ? parent.metadata->Count() : 0;
return parent.tracks ? parent.tracks->Count() + parent.headers.Count() : 0;
}
#define TRACK_COL_WIDTH 3
@ -267,8 +341,28 @@ static std::string formatWithoutAlbum(TrackPtr track, size_t width) {
% trackNum % title % duration % artist);
}
IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWindow* window, size_t index) {
TrackPtr track = parent.metadata->Get(index);
IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWindow* window, size_t rawIndex) {
bool selected = (rawIndex == parent.GetSelectedIndex());
if (this->parent.headers.HeaderAt(rawIndex)) {
/* the next track at the next logical index will have the album
tracks we're interesetd in. */
auto trackIndex = this->parent.headers.OffsetTrackIndex(rawIndex + 1);
TrackPtr track = parent.tracks->Get(trackIndex);
std::string album = track->GetValue(constants::Track::ALBUM);
std::shared_ptr<TrackListEntry> entry(new
TrackListEntry(album, trackIndex, RowType::Separator));
entry->SetAttrs(selected
? COLOR_PAIR(CURSESPP_LIST_ITEM_HIGHLIGHTED_HEADER)
: COLOR_PAIR(CURSESPP_LIST_ITEM_HEADER));
return entry;
}
size_t trackIndex = this->parent.headers.OffsetTrackIndex(rawIndex);
TrackPtr track = parent.tracks->Get(trackIndex);
if (!track) {
return MISSING_ENTRY;
@ -277,11 +371,9 @@ IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWi
int64 attrs = CURSESPP_DEFAULT_COLOR;
if (parent.decorator) {
attrs = parent.decorator(track, index);
attrs = parent.decorator(track, trackIndex);
}
else {
bool selected = index == parent.GetSelectedIndex();
attrs = selected
? COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM)
: CURSESPP_DEFAULT_COLOR;
@ -304,15 +396,10 @@ IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWi
? parent.formatter(track, this->GetWidth())
: formatWithoutAlbum(track, this->GetWidth());
if (this->parent.headers && this->parent.headers->find(index) != this->parent.headers->end()) {
std::string album = track->GetValue(constants::Track::ALBUM);
std::shared_ptr<EntryWithHeader> entry(new EntryWithHeader(album, text));
entry->SetAttrs(COLOR_PAIR(CURSESPP_LIST_ITEM_HEADER), attrs);
return entry;
}
else {
std::shared_ptr<SingleLineEntry> entry(new SingleLineEntry(text));
entry->SetAttrs(attrs);
return entry;
}
std::shared_ptr<TrackListEntry> entry(
new TrackListEntry(text, trackIndex, RowType::Track));
entry->SetAttrs(attrs);
return entry;
}

View File

@ -38,6 +38,7 @@
#include <cursespp/ScrollAdapterBase.h>
#include <cursespp/IKeyHandler.h>
#include <cursespp/ListWindow.h>
#include <cursespp/SingleLineEntry.h>
#include <core/library/query/local/TrackListQueryBase.h>
#include <core/audio/PlaybackService.h>
@ -55,8 +56,10 @@ namespace musik {
public sigslot::has_slots<>
{
public:
/* events */
sigslot::signal1<musik::core::db::local::TrackListQueryBase*> Requeried;
/* types */
typedef std::function<std::string(
musik::core::TrackPtr, size_t)> RowFormatter;
@ -65,8 +68,27 @@ namespace musik {
typedef std::shared_ptr<std::set<size_t> > Headers;
enum class RowType : char { Track = 't', Separator = 's' };
/* our special type of list entry */
class TrackListEntry : public cursespp::SingleLineEntry {
public:
TrackListEntry(const std::string& str, int index, RowType type)
: cursespp::SingleLineEntry(str), index(index), type(type) { }
virtual ~TrackListEntry() { }
RowType GetType() { return type; }
int GetIndex() { return index; }
private:
RowType type;
int index;
};
typedef musik::core::db::local::TrackListQueryBase TrackListQueryBase;
/* ctor, dtor */
TrackListView(
musik::core::audio::PlaybackService& playback,
musik::core::ILibraryPtr library,
@ -75,14 +97,16 @@ namespace musik {
virtual ~TrackListView();
/* IWindow */
virtual void ProcessMessage(musik::core::runtime::IMessage &message);
virtual bool KeyPress(const std::string& key);
/* regular methods */
std::shared_ptr<const musik::core::TrackList> GetTrackList();
void SetTrackList(std::shared_ptr<const musik::core::TrackList> trackList);
musik::core::TrackPtr GetSelectedTrack();
size_t GetSelectedTrackIndex();
void Clear();
musik::core::TrackPtr Get(size_t index);
size_t Count();
void Requery(std::shared_ptr<TrackListQueryBase> query);
@ -105,12 +129,26 @@ namespace musik {
};
private:
/* class to help with header offset calculation */
class HeaderCalculator {
public:
void Set(Headers rawOffsets);
void Reset();
size_t OffsetTrackIndex(size_t index);
bool HeaderAt(size_t index);
size_t Count();
private:
Headers absoluteOffsets;
Headers rawOffsets;
};
void OnTrackChanged(size_t index, musik::core::TrackPtr track);
void ScrollToPlaying();
std::shared_ptr<TrackListQueryBase> query;
std::shared_ptr<const musik::core::TrackList> metadata;
Headers headers;
std::shared_ptr<const musik::core::TrackList> tracks;
HeaderCalculator headers;
Adapter* adapter;
musik::core::audio::PlaybackService& playback;
musik::core::TrackPtr playing;

View File

@ -66,12 +66,14 @@ indicies we'll use to store them */
#define THEME_COLOR_BANNER_FOREGROUND 38
#define THEME_COLOR_LIST_HEADER_BACKGROUND 39
#define THEME_COLOR_LIST_HEADER_FOREGROUND 40
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND 41
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND 42
#define THEME_COLOR_LIST_ITEM_ACTIVE_BACKGROUND 43
#define THEME_COLOR_LIST_ITEM_ACTIVE_FOREGROUND 44
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_BACKGROUND 45
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_FOREGROUND 46
#define THEME_COLOR_LIST_HEADER_HIGHLIGHTED_BACKGROUND 41
#define THEME_COLOR_LIST_HEADER_HIGHLIGHTED_FOREGROUND 42
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND 43
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND 44
#define THEME_COLOR_LIST_ITEM_ACTIVE_BACKGROUND 45
#define THEME_COLOR_LIST_ITEM_ACTIVE_FOREGROUND 46
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_BACKGROUND 47
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_FOREGROUND 48
/* user-readable names for the color identifiers above. these are
used as key names in the config files */
@ -100,6 +102,8 @@ used as key names in the config files */
#define JSON_KEY_COLOR_BANNER_FOREGROUND "banner_foreground"
#define JSON_KEY_COLOR_LIST_HEADER_BACKGROUND "list_header_background"
#define JSON_KEY_COLOR_LIST_HEADER_FOREGROUND "list_header_foreground"
#define JSON_KEY_COLOR_LIST_HEADER_HIGHLIGHTED_BACKGROUND "list_header_highlighted_background"
#define JSON_KEY_COLOR_LIST_HEADER_HIGHLIGHTED_FOREGROUND "list_header_highlighted_foreground"
#define JSON_KEY_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND "list_item_highlighted_background"
#define JSON_KEY_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND "list_item_highlighted_foreground"
#define JSON_KEY_COLOR_LIST_ITEM_ACTIVE_BACKGROUND "list_item_active_background"
@ -282,6 +286,8 @@ struct Theme {
/* listview */
listHeaderBackground.Set(THEME_COLOR_LIST_HEADER_BACKGROUND, 36, 36, 31, -1);
listHeaderForeground.Set(THEME_COLOR_LIST_HEADER_FOREGROUND, 166, 226, 46, COLOR_256_GREEN);
listHeaderHighlightedBackground.Set(THEME_COLOR_LIST_HEADER_HIGHLIGHTED_BACKGROUND, 166, 226, 46, COLOR_256_GREEN);
listHeaderHighlightedForeground.Set(THEME_COLOR_LIST_HEADER_HIGHLIGHTED_FOREGROUND, 36, 36, 31, COLOR_BLACK);
listHighlightedBackground.Set(THEME_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND, 166, 226, 46, COLOR_256_GREEN);
listHighlightedForeground.Set(THEME_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND, 24, 24, 20, COLOR_BLACK);
listActiveBackground.Set(THEME_COLOR_LIST_ITEM_ACTIVE_BACKGROUND, 66, 66, 56, COLOR_256_MEDIUM_GRAY);
@ -336,6 +342,8 @@ struct Theme {
this->bannerForeground.Set(colors.value(JSON_KEY_COLOR_BANNER_FOREGROUND, unset));
this->listHeaderBackground.Set(colors.value(JSON_KEY_COLOR_LIST_HEADER_BACKGROUND, unset));
this->listHeaderForeground.Set(colors.value(JSON_KEY_COLOR_LIST_HEADER_FOREGROUND, unset));
this->listHeaderHighlightedBackground.Set(colors.value(JSON_KEY_COLOR_LIST_HEADER_HIGHLIGHTED_BACKGROUND, unset));
this->listHeaderHighlightedForeground.Set(colors.value(JSON_KEY_COLOR_LIST_HEADER_HIGHLIGHTED_FOREGROUND, unset));
this->listHighlightedBackground.Set(colors.value(JSON_KEY_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND, unset));
this->listHighlightedForeground.Set(colors.value(JSON_KEY_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND, unset));
this->listActiveBackground.Set(colors.value(JSON_KEY_COLOR_LIST_ITEM_ACTIVE_BACKGROUND, unset));
@ -414,6 +422,11 @@ struct Theme {
listHeaderForeground.Id(mode, COLOR_GREEN),
listHeaderBackground.Id(mode, -1));
init_pair(
CURSESPP_LIST_ITEM_HIGHLIGHTED_HEADER,
listHeaderHighlightedForeground.Id(mode, -1),
listHeaderHighlightedBackground.Id(mode, COLOR_GREEN));
init_pair(
CURSESPP_SELECTED_LIST_ITEM,
listActiveForeground.Id(mode, COLOR_YELLOW),
@ -468,6 +481,8 @@ struct Theme {
/* listview */
Color listHeaderBackground;
Color listHeaderForeground;
Color listHeaderHighlightedBackground;
Color listHeaderHighlightedForeground;
Color listHighlightedBackground;
Color listHighlightedForeground;
Color listActiveForeground;

View File

@ -42,30 +42,31 @@
#define CURSESPP_HIGHLIGHTED_LIST_ITEM 2
#define CURSESPP_HIGHLIGHTED_SELECTED_LIST_ITEM 3
#define CURSESPP_LIST_ITEM_HEADER 4
#define CURSESPP_LIST_ITEM_HIGHLIGHTED_HEADER 5
#define CURSESPP_DEFAULT_CONTENT_COLOR 5
#define CURSESPP_DEFAULT_FRAME_COLOR 6
#define CURSESPP_FOCUSED_FRAME_COLOR 7
#define CURSESPP_DEFAULT_CONTENT_COLOR 6
#define CURSESPP_DEFAULT_FRAME_COLOR 7
#define CURSESPP_FOCUSED_FRAME_COLOR 8
#define CURSESPP_TEXT_DEFAULT 8
#define CURSESPP_TEXT_DISABLED 9
#define CURSESPP_TEXT_FOCUSED 10
#define CURSESPP_TEXT_ACTIVE 11
#define CURSESPP_TEXT_WARNING 12
#define CURSESPP_TEXT_ERROR 13
#define CURSESPP_TEXT_HIDDEN 14
#define CURSESPP_TEXT_DEFAULT 9
#define CURSESPP_TEXT_DISABLED 10
#define CURSESPP_TEXT_FOCUSED 11
#define CURSESPP_TEXT_ACTIVE 12
#define CURSESPP_TEXT_WARNING 13
#define CURSESPP_TEXT_ERROR 14
#define CURSESPP_TEXT_HIDDEN 15
#define CURSESPP_BUTTON_NORMAL 16
#define CURSESPP_BUTTON_HIGHLIGHTED 18
#define CURSESPP_BUTTON_HIGHLIGHTED 17
#define CURSESPP_SHORTCUT_ROW_NORMAL 19
#define CURSESPP_SHORTCUT_ROW_FOCUSED 20
#define CURSESPP_SHORTCUT_ROW_NORMAL 18
#define CURSESPP_SHORTCUT_ROW_FOCUSED 19
#define CURSESPP_OVERLAY_FRAME 21
#define CURSESPP_OVERLAY_CONTENT 22
#define CURSESPP_OVERLAY_INPUT_FRAME 23
#define CURSESPP_OVERLAY_FRAME 20
#define CURSESPP_OVERLAY_CONTENT 21
#define CURSESPP_OVERLAY_INPUT_FRAME 22
#define CURSESPP_BANNER 24
#define CURSESPP_BANNER 23
namespace cursespp {
class Colors {

View File

@ -48,7 +48,7 @@ namespace cursespp {
virtual std::string GetLine(size_t line);
void SetAttrs(int64 attrs);
private:
size_t width;
std::string value;

View File

@ -203,12 +203,20 @@ void Window::SetParent(IWindow* parent) {
if (this->parent != parent) {
IWindowGroup* group = dynamic_cast<IWindowGroup*>(this->parent);
IWindow* oldParent = this->parent;
this->parent = parent;
if (this->frame) {
this->Hide();
this->Show();
}
if (parent) {
this->OnAddedToParent(parent);
}
else {
this->OnRemovedFromParent(oldParent);
}
}
}
@ -283,6 +291,14 @@ void Window::OnRedraw() {
/* for subclass use */
}
void Window::OnAddedToParent(IWindow* newParent) {
/* for subclass use */
}
void Window::OnRemovedFromParent(IWindow* oldParent) {
/* for subclass use */
}
void Window::Redraw() {
this->isDirty = true;
@ -450,7 +466,7 @@ void Window::OnParentVisibilityChanged(bool visible) {
this->Destroy();
}
this->OnVisibilityChanged(false);
//this->OnVisibilityChanged(false);
}
else if (visible && this->isVisible) {
if (this->framePanel) {
@ -460,7 +476,7 @@ void Window::OnParentVisibilityChanged(bool visible) {
this->Recreate();
}
this->OnVisibilityChanged(true);
//this->OnVisibilityChanged(true);
}
}

View File

@ -138,6 +138,8 @@ namespace cursespp {
virtual void OnVisibilityChanged(bool visible);
virtual void OnFocusChanged(bool focused);
virtual void OnRedraw();
virtual void OnAddedToParent(IWindow* newParent);
virtual void OnRemovedFromParent(IWindow* oldParent);
private:
IWindow* parent;

View File

@ -57,6 +57,11 @@
"playqueue_overlay_new_playlist_name_title": "new playlist name",
"playqueue_overlay_confirm_delete_message": "are you sure you want to delete '%s'?",
"playqueue_overlay_load_playlists_none_message": "you haven't saved any playlists yet!",
"playqueue_overlay_album_header": "album actions",
"playqueue_overlay_album_jump_to": "jump to album in library",
"playqueue_overlay_add_to_end_in_queue": "add to end of play queue",
"playqueue_overlay_add_as_next_in_queue": "add as next in play queue",
"visualizer_overlay_title": "visualizers",
"visualizer_overlay_no_visualizers_message": "no visualizers found!",
@ -85,5 +90,12 @@
"transport_repeat_off": "repeat off",
"main_syncing_banner": "syncing metadata (%d tracks processed)"
},
"dimensions": {
"playqueue_album_header_overlay": 35,
"playqueue_playlist_add_to_queue_overlay": 30,
"playqueue_playlist_list_overlay": 30,
"playqueue_playlist_name_overlay": 30
}
}

View File

@ -101,6 +101,14 @@
"list_header_foreground": {
"hex": "#859900",
"palette": 64
},
"list_header_highlighted_background": {
"hex": "#859900",
"palette": 64
},
"list_header_highlighted_foreground": {
"hex": "#002b36",
"palette": 234
},
"list_item_highlighted_background": {
"hex": "#93a1a1",

View File

@ -102,6 +102,14 @@
"hex": "#859900",
"palette": 64
},
"list_header_highlighted_background": {
"hex": "#859900",
"palette": 64
},
"list_header_highlighted_foreground": {
"hex": "#fdf6e3",
"palette": 230
},
"list_item_highlighted_background": {
"hex": "#93a1a1",
"palette": 245

View File

@ -149,7 +149,6 @@ xcopy "$(ProjectDir)data\locales\*" "$(TargetDir)locales\" /Y /e</Command>
<ClCompile Include="app\util\Playback.cpp" />
<ClCompile Include="app\util\PreferenceKeys.cpp" />
<ClCompile Include="app\window\CategoryListView.cpp" />
<ClCompile Include="app\window\EntryWithHeader.cpp" />
<ClCompile Include="app\window\LogWindow.cpp" />
<ClCompile Include="app\window\TrackListView.cpp" />
<ClCompile Include="app\window\TransportWindow.cpp" />
@ -203,7 +202,6 @@ xcopy "$(ProjectDir)data\locales\*" "$(TargetDir)locales\" /Y /e</Command>
<ClInclude Include="app\util\PreferenceKeys.h" />
<ClInclude Include="app\util\Version.h" />
<ClInclude Include="app\window\CategoryListView.h" />
<ClInclude Include="app\window\EntryWithHeader.h" />
<ClInclude Include="app\window\LogWindow.h" />
<ClInclude Include="app\window\TrackListView.h" />
<ClInclude Include="app\window\TransportWindow.h" />

View File

@ -48,9 +48,6 @@
<ClCompile Include="app\util\GlobalHotkeys.cpp">
<Filter>app\util</Filter>
</ClCompile>
<ClCompile Include="app\window\EntryWithHeader.cpp">
<Filter>app\window</Filter>
</ClCompile>
<ClCompile Include="app\layout\ConsoleLayout.cpp">
<Filter>app\layout</Filter>
</ClCompile>
@ -219,9 +216,6 @@
<ClInclude Include="cursespp\IOrderable.h">
<Filter>cursespp</Filter>
</ClInclude>
<ClInclude Include="app\window\EntryWithHeader.h">
<Filter>app\window</Filter>
</ClInclude>
<ClInclude Include="app\layout\ConsoleLayout.h">
<Filter>app\layout</Filter>
</ClInclude>