diff --git a/src/musikcube/Main.cpp b/src/musikcube/Main.cpp index 6122ad5a8..256ecdef5 100644 --- a/src/musikcube/Main.cpp +++ b/src/musikcube/Main.cpp @@ -63,10 +63,8 @@ #include #ifdef WIN32 - #include - #include "resource.h" - #undef MOUSE_MOVED - #pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#include +#include "resource.h" #endif using namespace musik; diff --git a/src/musikcube/app/layout/BrowseLayout.cpp b/src/musikcube/app/layout/BrowseLayout.cpp index 5a71f5b65..16ce3d51b 100755 --- a/src/musikcube/app/layout/BrowseLayout.cpp +++ b/src/musikcube/app/layout/BrowseLayout.cpp @@ -151,7 +151,7 @@ void BrowseLayout::InitializeWindows() { this->modifiedLabel.reset(new TextLabel()); this->modifiedLabel->SetText(getModifiedText(), text::AlignCenter); - this->modifiedLabel->SetContentColor(CURSESPP_BANNER); + this->modifiedLabel->SetContentColor(Color::Banner); this->modifiedLabel->Hide(); this->AddWindow(this->categoryList); @@ -228,7 +228,7 @@ void BrowseLayout::OnVisibilityChanged(bool visible) { } void BrowseLayout::OnIndexerProgress(int count) { - this->PostMessage(message::IndexerProgress); + this->Post(message::IndexerProgress); } void BrowseLayout::RequeryTrackList(ListWindow *view) { diff --git a/src/musikcube/app/layout/ConsoleLayout.cpp b/src/musikcube/app/layout/ConsoleLayout.cpp index de8e37641..f227a84ec 100755 --- a/src/musikcube/app/layout/ConsoleLayout.cpp +++ b/src/musikcube/app/layout/ConsoleLayout.cpp @@ -124,10 +124,10 @@ void ConsoleLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) { shortcuts->SetChangedCallback([this](std::string key) { if (Hotkeys::Is(Hotkeys::NavigateSettings, key)) { - this->BroadcastMessage(message::JumpToSettings); + this->Broadcast(message::JumpToSettings); } if (Hotkeys::Is(Hotkeys::NavigateLibrary, key)) { - this->BroadcastMessage(message::JumpToLibrary); + this->Broadcast(message::JumpToLibrary); } else if (key == "^D") { App::Instance().Quit(); @@ -141,7 +141,7 @@ void ConsoleLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) { } } -void ConsoleLayout::WriteOutput(const std::string& str, int64_t attrs) { +void ConsoleLayout::WriteOutput(const std::string& str, Color attrs) { this->outputAdapter->AddEntry(EntryPtr(new MultiLineEntry(str, attrs))); this->output->OnAdapterChanged(); } @@ -150,14 +150,14 @@ void ConsoleLayout::OnEnterPressed(TextInput *input) { std::string command = this->commands->GetText(); this->commands->SetText(""); - this->WriteOutput("> " + command + "\n", COLOR_PAIR(CURSESPP_TEXT_DEFAULT)); + this->WriteOutput("> " + command + "\n", Color::TextDefault); if (!this->ProcessCommand(command)) { if (command.size()) { this->WriteOutput( "illegal command: '" + command + - "'\n", COLOR_PAIR(CURSESPP_TEXT_ERROR)); + "'\n", Color::TextError); } } } @@ -186,7 +186,7 @@ void ConsoleLayout::SetVolume(float volume) { } void ConsoleLayout::Help() { - int64_t s = -1; + Color s = Color::Default; this->WriteOutput("help:\n", s); this->WriteOutput(" to switch between windows", s); @@ -241,7 +241,7 @@ bool ConsoleLayout::ProcessCommand(const std::string& cmd) { } else if (name == "version") { const std::string v = boost::str(boost::format("v%s") % VERSION); - this->WriteOutput(v, -1); + this->WriteOutput(v, Color::Default); } else if (name == "play" || name == "pl" || name == "p") { return this->PlayFile(args); @@ -336,6 +336,6 @@ void ConsoleLayout::ListPlugins() { " version: " + std::string((*it)->Version()) + "\n" " by " + std::string((*it)->Author()) + "\n"; - this->WriteOutput(format, COLOR_PAIR(CURSESPP_TEXT_DEFAULT)); + this->WriteOutput(format, Color::TextDefault); } } diff --git a/src/musikcube/app/layout/ConsoleLayout.h b/src/musikcube/app/layout/ConsoleLayout.h index c3e30fcb7..d5da4ade1 100755 --- a/src/musikcube/app/layout/ConsoleLayout.h +++ b/src/musikcube/app/layout/ConsoleLayout.h @@ -34,6 +34,7 @@ #pragma once +#include #include #include #include @@ -84,7 +85,9 @@ namespace musik { void SetVolume(float volume); void Help(); - void WriteOutput(const std::string& str, int64_t attrs = -1); + void WriteOutput( + const std::string& str, + cursespp::Color attrs = cursespp::Color::Default); std::shared_ptr logs; std::shared_ptr commands; diff --git a/src/musikcube/app/layout/DirectoryLayout.cpp b/src/musikcube/app/layout/DirectoryLayout.cpp index ecc4ab205..f570e8178 100644 --- a/src/musikcube/app/layout/DirectoryLayout.cpp +++ b/src/musikcube/app/layout/DirectoryLayout.cpp @@ -255,7 +255,7 @@ bool DirectoryLayout::KeyPress(const std::string& key) { return LayoutBase::KeyPress(key); } -int64_t DirectoryLayout::ListItemDecorator( +Color DirectoryLayout::ListItemDecorator( ScrollableWindow* scrollable, size_t index, size_t line, @@ -263,8 +263,8 @@ int64_t DirectoryLayout::ListItemDecorator( { if (scrollable == this->directoryList.get()) { if (this->directoryList->GetSelectedIndex() == index) { - return COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM); + return Color::ListItemHighlighted; } } - return -1; + return Color::Default; } \ No newline at end of file diff --git a/src/musikcube/app/layout/DirectoryLayout.h b/src/musikcube/app/layout/DirectoryLayout.h index 61eef30fb..760692645 100644 --- a/src/musikcube/app/layout/DirectoryLayout.h +++ b/src/musikcube/app/layout/DirectoryLayout.h @@ -34,6 +34,7 @@ #pragma once +#include #include #include @@ -79,7 +80,7 @@ namespace musik { bool IsParentSelected(); bool IsParentRoot(); - int64_t ListItemDecorator( + cursespp::Color ListItemDecorator( cursespp::ScrollableWindow* scrollable, size_t index, size_t line, diff --git a/src/musikcube/app/layout/HotkeysLayout.cpp b/src/musikcube/app/layout/HotkeysLayout.cpp index e5cf9dfc1..1bb3ea01d 100644 --- a/src/musikcube/app/layout/HotkeysLayout.cpp +++ b/src/musikcube/app/layout/HotkeysLayout.cpp @@ -175,11 +175,11 @@ static void showDeleteOverlay(Hotkeys::Id id, Callback cb) { HotkeysLayout::HotkeysLayout() { auto adapter = std::make_shared(); - adapter->SetItemDecorator([this](ScrollableWindow*, size_t index, size_t, Entry) -> int64_t { + adapter->SetItemDecorator([this](ScrollableWindow*, size_t index, size_t, Entry) -> Color { if (this->listWindow->GetSelectedIndex() == index) { - return COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM); + return Color::ListItemHighlighted; } - return -1LL; + return Color::Default; }); this->listWindow = std::make_shared(); @@ -258,11 +258,11 @@ bool HotkeysLayout::KeyPress(const std::string& kn) { return true; } else if (Hotkeys::Is(Hotkeys::NavigateSettings, kn)) { - this->BroadcastMessage(message::JumpToSettings); + this->Broadcast(message::JumpToSettings); return true; } else if (Hotkeys::Is(Hotkeys::NavigateLibrary, kn)) { - this->BroadcastMessage(message::JumpToLibrary); + this->Broadcast(message::JumpToLibrary); return true; } diff --git a/src/musikcube/app/layout/LibraryLayout.cpp b/src/musikcube/app/layout/LibraryLayout.cpp index cdf8c4666..05675f018 100755 --- a/src/musikcube/app/layout/LibraryLayout.cpp +++ b/src/musikcube/app/layout/LibraryLayout.cpp @@ -251,7 +251,7 @@ void LibraryLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) { this->shortcuts->SetChangedCallback([this](std::string key) { if (Hotkeys::Is(Hotkeys::NavigateSettings, key)) { - this->BroadcastMessage(message::JumpToSettings); + this->Broadcast(message::JumpToSettings); } else if (key == "^D") { App::Instance().Quit(); diff --git a/src/musikcube/app/layout/MainLayout.cpp b/src/musikcube/app/layout/MainLayout.cpp index 54eab819c..384369c5b 100755 --- a/src/musikcube/app/layout/MainLayout.cpp +++ b/src/musikcube/app/layout/MainLayout.cpp @@ -107,7 +107,6 @@ MainLayout::MainLayout( this->Initialize(); this->prefs = Preferences::ForComponent("settings"); - this->ResizeToViewport(); library->Indexer()->Started.connect(this, &MainLayout::OnIndexerStarted); library->Indexer()->Finished.connect(this, &MainLayout::OnIndexerFinished); @@ -132,10 +131,6 @@ MainLayout::~MainLayout() { updateCheck.Cancel(); } -void MainLayout::ResizeToViewport() { - this->MoveAndResize(0, 0, Screen::GetWidth(), Screen::GetHeight()); -} - void MainLayout::OnLayout() { size_t cx = Screen::GetWidth(), cy = Screen::GetHeight(); @@ -179,13 +174,13 @@ void MainLayout::Initialize() { #if ENABLE_DEMO_MODE this->hotkey.reset(new TextLabel()); - this->hotkey->SetContentColor(CURSESPP_FOOTER); + this->hotkey->SetContentColor(Color::Footer); this->hotkey->SetText("keypress: ", text::AlignCenter); this->AddWindow(this->hotkey); #endif this->syncing.reset(new TextLabel()); - this->syncing->SetContentColor(CURSESPP_BANNER); + this->syncing->SetContentColor(Color::Banner); this->syncing->Hide(); this->AddWindow(this->syncing); } @@ -380,15 +375,15 @@ void MainLayout::ProcessMessage(musik::core::runtime::IMessage &message) { } void MainLayout::OnIndexerStarted() { - this->PostMessage(message::IndexerStarted); + this->Post(message::IndexerStarted); } void MainLayout::OnIndexerProgress(int count) { - this->PostMessage(message::IndexerProgress, count); + this->Post(message::IndexerProgress, count); } void MainLayout::OnIndexerFinished(int count) { - this->PostMessage(message::IndexerFinished); + this->Post(message::IndexerFinished); } void MainLayout::RunUpdateCheck() { diff --git a/src/musikcube/app/layout/MainLayout.h b/src/musikcube/app/layout/MainLayout.h index c1433a623..bf8076c45 100755 --- a/src/musikcube/app/layout/MainLayout.h +++ b/src/musikcube/app/layout/MainLayout.h @@ -39,7 +39,6 @@ #include #include #include -#include #include #include @@ -56,7 +55,6 @@ namespace musik { namespace cube { class MainLayout : public cursespp::LayoutBase, - public cursespp::IViewRoot, #if (__clang_major__ == 7 && __clang_minor__ == 3) public std::enable_shared_from_this, #endif @@ -78,7 +76,6 @@ namespace musik { virtual cursespp::IWindowPtr GetFocus() override; virtual cursespp::IWindowPtr FocusNext() override; virtual cursespp::IWindowPtr FocusPrev() override; - virtual void ResizeToViewport() override; virtual void ProcessMessage(musik::core::runtime::IMessage &message) override; void SetMainLayout(std::shared_ptr layout); diff --git a/src/musikcube/app/layout/NowPlayingLayout.cpp b/src/musikcube/app/layout/NowPlayingLayout.cpp index a17b2f361..dd207b048 100755 --- a/src/musikcube/app/layout/NowPlayingLayout.cpp +++ b/src/musikcube/app/layout/NowPlayingLayout.cpp @@ -89,13 +89,10 @@ NowPlayingLayout::NowPlayingLayout( NowPlayingLayout::~NowPlayingLayout() { } -int64_t NowPlayingLayout::RowDecorator(musik::core::TrackPtr track, size_t index) { +Color NowPlayingLayout::RowDecorator(musik::core::TrackPtr track, size_t index) { bool selected = index == trackListView->GetSelectedIndex(); - int64_t attrs = selected - ? COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM) - : CURSESPP_DEFAULT_COLOR; - + Color attrs = selected ? Color::ListItemHighlighted : Color::Default; size_t playingIndex = playback.GetIndex(); if (index == playingIndex) { @@ -106,10 +103,10 @@ int64_t NowPlayingLayout::RowDecorator(musik::core::TrackPtr track, size_t index playing->LibraryId() == track->LibraryId()) { if (selected) { - attrs = COLOR_PAIR(CURSESPP_HIGHLIGHTED_SELECTED_LIST_ITEM); + attrs = Color::ListItemHighlightedSelected; } else { - attrs = COLOR_PAIR(CURSESPP_SELECTED_LIST_ITEM); + attrs = Color::ListItemSelected; } } } diff --git a/src/musikcube/app/layout/NowPlayingLayout.h b/src/musikcube/app/layout/NowPlayingLayout.h index d4489e6e2..b17d21c29 100755 --- a/src/musikcube/app/layout/NowPlayingLayout.h +++ b/src/musikcube/app/layout/NowPlayingLayout.h @@ -34,8 +34,8 @@ #pragma once +#include #include - #include #include #include @@ -75,7 +75,7 @@ namespace musik { /* callbacks */ void OnTrackListRequeried(musik::core::db::local::TrackListQueryBase* query); - int64_t RowDecorator(musik::core::TrackPtr track, size_t index); + cursespp::Color RowDecorator(musik::core::TrackPtr track, size_t index); void OnPlaylistSelected(int64_t playlistId); musik::core::audio::PlaybackService& playback; diff --git a/src/musikcube/app/layout/SettingsLayout.cpp b/src/musikcube/app/layout/SettingsLayout.cpp index 3f0fb34f1..64594896d 100755 --- a/src/musikcube/app/layout/SettingsLayout.cpp +++ b/src/musikcube/app/layout/SettingsLayout.cpp @@ -128,15 +128,6 @@ static void setTransportType(TransportType type) { playback->SetInt(core::prefs::keys::Transport, (int) type); } -static std::string resolveThemeName(const std::string& themePath) { - const boost::filesystem::path p(themePath); - if (p.has_extension() && p.extension().string() == ".json") { - std::string fn = p.filename().string(); - return fn.substr(0, fn.rfind(".")); - } - return _TSTR("settings_default_theme_name"); -} - SettingsLayout::SettingsLayout( cursespp::App& app, musik::core::ILibraryPtr library, @@ -264,7 +255,7 @@ void SettingsLayout::OnPluginsDropdownActivate(cursespp::TextLabel* label) { } void SettingsLayout::OnHotkeyDropdownActivate(cursespp::TextLabel* label) { - this->BroadcastMessage(message::JumpToHotkeys); + this->Broadcast(message::JumpToHotkeys); } void SettingsLayout::OnServerDropdownActivate(cursespp::TextLabel* label) { @@ -357,7 +348,7 @@ void SettingsLayout::RefreshAddedPaths() { this->addedPathsList->OnAdapterChanged(); } -int64_t SettingsLayout::ListItemDecorator( +Color SettingsLayout::ListItemDecorator( ScrollableWindow* scrollable, size_t index, size_t line, @@ -368,10 +359,10 @@ int64_t SettingsLayout::ListItemDecorator( { ListWindow* lw = static_cast(scrollable); if (lw->GetSelectedIndex() == index) { - return COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM); + return Color::ListItemHighlighted; } } - return -1; + return Color::Default; } void SettingsLayout::InitializeWindows() { @@ -525,10 +516,10 @@ void SettingsLayout::SetShortcutsWindow(ShortcutsWindow* shortcuts) { shortcuts->SetChangedCallback([this](std::string key) { if (Hotkeys::Is(Hotkeys::NavigateConsole, key)) { - this->BroadcastMessage(message::JumpToConsole); + this->Broadcast(message::JumpToConsole); } if (Hotkeys::Is(Hotkeys::NavigateLibrary, key)) { - this->BroadcastMessage(message::JumpToLibrary); + this->Broadcast(message::JumpToLibrary); } else if (key == "^D") { app.Quit(); @@ -623,9 +614,7 @@ void SettingsLayout::LoadPreferences() { colorTheme = _TSTR("settings_8color_theme_name"); } - this->themeDropdown->SetText( - arrow + _TSTR("settings_color_theme") + - resolveThemeName(colorTheme)); + this->themeDropdown->SetText(arrow + _TSTR("settings_color_theme") + colorTheme); #ifdef ENABLE_256_COLOR_OPTION this->paletteCheckbox->CheckChanged.disconnect(this); diff --git a/src/musikcube/app/layout/SettingsLayout.h b/src/musikcube/app/layout/SettingsLayout.h index c12fbb1b8..e2b40f751 100755 --- a/src/musikcube/app/layout/SettingsLayout.h +++ b/src/musikcube/app/layout/SettingsLayout.h @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -111,7 +112,7 @@ namespace musik { void OnUpdateDropdownActivate(cursespp::TextLabel* label); void OnLastFmDropdownActivate(cursespp::TextLabel* label); - int64_t ListItemDecorator( + cursespp::Color ListItemDecorator( cursespp::ScrollableWindow* w, size_t index, size_t line, diff --git a/src/musikcube/app/layout/TrackSearchLayout.cpp b/src/musikcube/app/layout/TrackSearchLayout.cpp index 9ae7da1ba..7934ad6e8 100755 --- a/src/musikcube/app/layout/TrackSearchLayout.cpp +++ b/src/musikcube/app/layout/TrackSearchLayout.cpp @@ -152,7 +152,7 @@ void TrackSearchLayout::ProcessMessage(IMessage &message) { void TrackSearchLayout::OnInputChanged(cursespp::TextInput* sender, std::string value) { if (this->IsVisible()) { - DebounceMessage(message::RequeryTrackList, 0, 0, REQUERY_INTERVAL_MS); + Debounce(message::RequeryTrackList, 0, 0, REQUERY_INTERVAL_MS); } } diff --git a/src/musikcube/app/overlay/ColorThemeOverlay.cpp b/src/musikcube/app/overlay/ColorThemeOverlay.cpp index ebbcf8931..b83a1ef23 100644 --- a/src/musikcube/app/overlay/ColorThemeOverlay.cpp +++ b/src/musikcube/app/overlay/ColorThemeOverlay.cpp @@ -48,8 +48,6 @@ #include #include -#include - using namespace musik; using namespace musik::core; using namespace musik::cube; @@ -58,11 +56,6 @@ using namespace boost::filesystem; using Callback = std::function; -struct ThemeInfo { - std::string name; - std::string path; -}; - static void showNeedsRestart(Callback cb = Callback()) { std::shared_ptr dialog(new DialogOverlay()); @@ -78,25 +71,6 @@ static void showNeedsRestart(Callback cb = Callback()) { App::Overlays().Push(dialog); } -static void indexThemes( - const std::string& directory, - std::shared_ptr> themes) -{ - path colorPath(directory); - if (exists(colorPath)) { - directory_iterator end; - for (directory_iterator file(colorPath); file != end; file++) { - const path& p = file->path(); - - if (p.has_extension() && p.extension().string() == ".json") { - std::string fn = p.filename().string(); - std::string name = fn.substr(0, fn.rfind(".")); - themes->push_back({ name, p.string() }); - } - } - } -} - ColorThemeOverlay::ColorThemeOverlay() { } @@ -113,24 +87,14 @@ void ColorThemeOverlay::Show(std::function callback) { int selectedIndex = disableCustomColors ? 1 : 0; std::shared_ptr adapter(new Adapter()); - adapter->AddEntry(_TSTR("settings_default_theme_name")); adapter->AddEntry(_TSTR("settings_8color_theme_name")); - std::shared_ptr> themes(new std::vector()); - indexThemes(musik::core::GetApplicationDirectory() + "/themes/", themes); - indexThemes(musik::core::GetDataDirectory() + "/themes/", themes); + auto themes = Colors::ListThemes(); - std::sort( - themes->begin(), - themes->end(), - [](const ThemeInfo& a, const ThemeInfo& b) -> bool { - return a.name < b.name; - }); - - for (size_t i = 0; i < themes->size(); i++) { - adapter->AddEntry(themes->at(i).name); - if (themes->at(i).path == currentTheme) { - selectedIndex = i + 2; + for (size_t i = 0; i < themes.size(); i++) { + adapter->AddEntry(themes.at(i)); + if (themes.at(i) == currentTheme) { + selectedIndex = i + 1; } } @@ -146,15 +110,6 @@ void ColorThemeOverlay::Show(std::function callback) { [callback, prefs, themes, currentTheme, disableCustomColors] (ListOverlay* overlay, IScrollAdapterPtr adapter, size_t index) { if (index == 0) { - prefs->SetString(cube::prefs::keys::ColorTheme, ""); - prefs->SetBool(cube::prefs::keys::DisableCustomColors, false); - Colors::SetTheme(""); - - if (disableCustomColors) { - showNeedsRestart(); - } - } - else if (index == 1) { prefs->SetString(cube::prefs::keys::ColorTheme, ""); prefs->SetBool(cube::prefs::keys::DisableCustomColors, true); @@ -163,12 +118,11 @@ void ColorThemeOverlay::Show(std::function callback) { } } else { - std::string selected = themes->at(index - 2).path; + std::string selected = themes.at(index - 1); if (selected != currentTheme) { prefs->SetString(cube::prefs::keys::ColorTheme, selected.c_str()); prefs->SetBool(cube::prefs::keys::DisableCustomColors, false); Colors::SetTheme(selected); - if (disableCustomColors) { showNeedsRestart(); } diff --git a/src/musikcube/app/overlay/EqualizerOverlay.cpp b/src/musikcube/app/overlay/EqualizerOverlay.cpp index 7fad09590..bd378c9e5 100644 --- a/src/musikcube/app/overlay/EqualizerOverlay.cpp +++ b/src/musikcube/app/overlay/EqualizerOverlay.cpp @@ -59,7 +59,7 @@ static const std::vector BANDS = { "65", "92", "131", "185", "262", "370", "523", "740", "1047", "1480", "2093", "2960", "4186", "5920", "8372", - "11840", "16744" + "11840", "16744", "22000" }; static const int UPDATE_DEBOUNCE_MS = 350; @@ -154,10 +154,6 @@ void EqualizerOverlay::ShowOverlay() { App::Overlays().Push(std::make_shared()); } -bool EqualizerOverlay::CanScroll(int listViewHeight) { - return listViewHeight < this->adapter->GetEntryCount(); -} - std::shared_ptr EqualizerOverlay::FindPlugin() { std::shared_ptr result; using Deleter = PluginFactory::ReleaseDeleter; @@ -227,7 +223,7 @@ bool EqualizerOverlay::KeyPress(const std::string& key) { void EqualizerOverlay::NotifyAndRedraw() { this->listView->OnAdapterChanged(); - this->DebounceMessage(message::UpdateEqualizer, 0, 0, UPDATE_DEBOUNCE_MS); + this->Debounce(message::UpdateEqualizer, 0, 0, UPDATE_DEBOUNCE_MS); } void EqualizerOverlay::ProcessMessage(musik::core::runtime::IMessage &message) { @@ -266,9 +262,9 @@ ScrollAdapterBase::EntryPtr EqualizerOverlay::BandsAdapter::GetEntry(cursespp::S band, prefs->GetDouble(band.c_str(), 0.0))); - entry->SetAttrs(CURSESPP_DEFAULT_COLOR); + entry->SetAttrs(Color::Default); if (index == window->GetScrollPosition().logicalIndex) { - entry->SetAttrs(COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM)); + entry->SetAttrs(Color::ListItemHighlighted); } return entry; diff --git a/src/musikcube/app/overlay/EqualizerOverlay.h b/src/musikcube/app/overlay/EqualizerOverlay.h index a298e2f0d..c6ebbae09 100644 --- a/src/musikcube/app/overlay/EqualizerOverlay.h +++ b/src/musikcube/app/overlay/EqualizerOverlay.h @@ -77,7 +77,6 @@ namespace musik { Prefs prefs; }; - bool CanScroll(int listViewHeight); void UpdateSelectedBand(double delta); void NotifyAndRedraw(); diff --git a/src/musikcube/app/overlay/LastFmOverlay.cpp b/src/musikcube/app/overlay/LastFmOverlay.cpp index 1be0aea22..51d815975 100644 --- a/src/musikcube/app/overlay/LastFmOverlay.cpp +++ b/src/musikcube/app/overlay/LastFmOverlay.cpp @@ -107,7 +107,7 @@ void LastFmOverlay::CreateSession() { } void LastFmOverlay::PostState(State state) { - this->PostMessage(message::SetLastFmState, (int64_t) state); + this->Post(message::SetLastFmState, (int64_t) state); } void LastFmOverlay::SetState(State state) { diff --git a/src/musikcube/app/overlay/PluginOverlay.cpp b/src/musikcube/app/overlay/PluginOverlay.cpp index aa3a5f7b4..70b7f6b8b 100644 --- a/src/musikcube/app/overlay/PluginOverlay.cpp +++ b/src/musikcube/app/overlay/PluginOverlay.cpp @@ -163,9 +163,9 @@ class StringListAdapter : public ScrollAdapterBase { auto entry = std::make_shared( text::Ellipsize(items[index], window->GetWidth())); - entry->SetAttrs(CURSESPP_DEFAULT_COLOR); + entry->SetAttrs(Color::Default); if (index == window->GetScrollPosition().logicalIndex) { - entry->SetAttrs(COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM)); + entry->SetAttrs(Color::ListItemHighlighted); } return entry; @@ -201,9 +201,9 @@ class SchemaAdapter: public ScrollAdapterBase { SinglePtr result = SinglePtr(new SingleLineEntry(text::Ellipsize(display, width))); - result->SetAttrs(CURSESPP_DEFAULT_COLOR); + result->SetAttrs(Color::Default); if (index == window->GetScrollPosition().logicalIndex) { - result->SetAttrs(COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM)); + result->SetAttrs(Color::ListItemHighlighted); } return result; @@ -481,10 +481,9 @@ class PluginListAdapter : public ScrollAdapterBase { SinglePtr result = SinglePtr(new SingleLineEntry(text::Ellipsize(display, this->GetWidth()))); - result->SetAttrs(CURSESPP_DEFAULT_COLOR); - + result->SetAttrs(Color::Default); if (index == window->GetScrollPosition().logicalIndex) { - result->SetAttrs(COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM)); + result->SetAttrs(Color::ListItemHighlighted); } return result; diff --git a/src/musikcube/app/overlay/PreampOverlay.cpp b/src/musikcube/app/overlay/PreampOverlay.cpp index ee6f333a9..fde36bf13 100644 --- a/src/musikcube/app/overlay/PreampOverlay.cpp +++ b/src/musikcube/app/overlay/PreampOverlay.cpp @@ -58,24 +58,6 @@ using namespace cursespp; #define INPUT_LENGTH 7 #define ARROW std::string("> ") -static void applyLabelOverlayStyle(TextLabel& label) { - label.SetContentColor(CURSESPP_OVERLAY_CONTENT); - label.SetFocusedContentColor(CURSESPP_OVERLAY_TEXT_FOCUSED); -} - -static void applyInputOverlayStyle(TextInput& input) { - if (input.GetStyle() == TextInput::StyleBox) { - input.SetFrameColor(CURSESPP_OVERLAY_FRAME); - input.SetContentColor(CURSESPP_OVERLAY_CONTENT); - input.SetFocusedFrameColor(CURSESPP_OVERLAY_INPUT_FRAME); - input.SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT); - } - else { - input.SetContentColor(CURSESPP_OVERLAY_CONTENT); - input.SetFocusedContentColor(CURSESPP_OVERLAY_TEXT_FOCUSED); - } -} - #define RIGHT(x) (x->GetX() + x->GetWidth()) #define TEXT_WIDTH(x) ((int) u8cols(x->GetText())) #define INVALID_PREAMP_GAIN -999.9f @@ -137,8 +119,8 @@ PreampOverlay::PreampOverlay(IPlaybackService& playback, Callback callback) this->width = this->height = 0; this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); this->InitViews(); this->Load(); @@ -173,10 +155,10 @@ void PreampOverlay::InitViews() { this->replayGainDropdown->Activated.connect(this, &PreampOverlay::OnReplayGainPressed); /* style 'em */ - applyLabelOverlayStyle(*this->titleLabel); - applyLabelOverlayStyle(*this->preampLabel); - applyInputOverlayStyle(*this->preampInput); - applyLabelOverlayStyle(*this->replayGainDropdown); + style(*this->titleLabel); + style(*this->preampLabel); + style(*this->preampInput); + style(*this->replayGainDropdown); /* add 'em */ this->AddWindow(this->titleLabel); diff --git a/src/musikcube/app/overlay/ReassignHotkeyOverlay.cpp b/src/musikcube/app/overlay/ReassignHotkeyOverlay.cpp index 3fc31a3ae..b44490f32 100644 --- a/src/musikcube/app/overlay/ReassignHotkeyOverlay.cpp +++ b/src/musikcube/app/overlay/ReassignHotkeyOverlay.cpp @@ -45,11 +45,6 @@ using namespace musik::cube; #define DEFAULT_HEIGHT 10 #define DEFAULT_WIDTH 35 -static void applyLabelOverlayStyle(TextLabel& label) { - label.SetContentColor(CURSESPP_OVERLAY_CONTENT); - label.SetFocusedContentColor(CURSESPP_OVERLAY_TEXT_FOCUSED); -} - void ReassignHotkeyOverlay::Show(Hotkeys::Id id, Callback callback) { using T = ReassignHotkeyOverlay; auto overlay = std::shared_ptr(new T(id, callback)); @@ -108,25 +103,25 @@ void ReassignHotkeyOverlay::RecalculateSize() { void ReassignHotkeyOverlay::InitViews() { this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); this->titleLabel = std::make_shared(); - applyLabelOverlayStyle(*this->titleLabel); + style(*this->titleLabel); this->titleLabel->SetText(_TSTR("hotkeys_reassign_overlay_title"), text::AlignCenter); this->titleLabel->SetBold(true); this->hotkeyLabel = std::make_shared(); - applyLabelOverlayStyle(*this->hotkeyLabel); + style(*this->hotkeyLabel); this->hotkeyInput = std::make_shared( TextInput::Style::StyleBox, TextInput::InputRaw); this->hotkeyInput->SetRawKeyBlacklist({ "KEY_ENTER", "^[" }); this->hotkeyInput->SetFocusOrder(0); - this->hotkeyInput->SetFocusedFrameColor(CURSESPP_OVERLAY_INPUT_FRAME); + this->hotkeyInput->SetFocusedFrameColor(Color::OverlayTextInputFrame); this->hotkeyInput->SetText(Hotkeys::Get(this->id)); - this->hotkeyInput->SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT); + this->hotkeyInput->SetFocusedContentColor(Color::OverlayContent); this->shortcuts = std::make_shared(); this->shortcuts->SetAlignment(text::AlignRight); diff --git a/src/musikcube/app/overlay/ServerOverlay.cpp b/src/musikcube/app/overlay/ServerOverlay.cpp index 48320bdf3..aa5b03a6d 100644 --- a/src/musikcube/app/overlay/ServerOverlay.cpp +++ b/src/musikcube/app/overlay/ServerOverlay.cpp @@ -109,11 +109,6 @@ ServerOverlay::ServerOverlay(Callback callback, Plugin plugin) this->plugin = plugin; this->prefs = Preferences::ForPlugin(plugin->Name()); this->width = this->height = 0; - - this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); - this->InitViews(); this->Load(); } diff --git a/src/musikcube/app/window/CategoryListView.cpp b/src/musikcube/app/window/CategoryListView.cpp index 85574b8f9..9a2e50889 100755 --- a/src/musikcube/app/window/CategoryListView.cpp +++ b/src/musikcube/app/window/CategoryListView.cpp @@ -293,17 +293,14 @@ IScrollAdapter::EntryPtr CategoryListView::Adapter::GetEntry(cursespp::Scrollabl } bool selected = (index == parent.GetSelectedIndex()); - - int64_t attrs = selected - ? COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM) - : CURSESPP_DEFAULT_COLOR; + Color attrs = selected ? Color::ListItemHighlighted : Color::Default; if (playing) { if (selected) { - attrs = COLOR_PAIR(CURSESPP_HIGHLIGHTED_SELECTED_LIST_ITEM); + attrs = Color::ListItemHighlightedSelected; } else { - attrs = COLOR_PAIR(CURSESPP_SELECTED_LIST_ITEM); + attrs = Color::ListItemSelected; } } diff --git a/src/musikcube/app/window/LogWindow.cpp b/src/musikcube/app/window/LogWindow.cpp index df44e999e..4f37b2a6b 100755 --- a/src/musikcube/app/window/LogWindow.cpp +++ b/src/musikcube/app/window/LogWindow.cpp @@ -47,7 +47,7 @@ using namespace cursespp; typedef IScrollAdapter::IEntry IEntry; -#define DEBOUNCE_REFRESH() this->DebounceMessage(message::RefreshLogs, 0, 0, 250) +#define DEBOUNCE_REFRESH() this->Debounce(message::RefreshLogs, 0, 0, 250) LogWindow::LogWindow(IWindow *parent) : ScrollableWindow(nullptr, parent) { @@ -96,18 +96,18 @@ void LogWindow::Update() { } for (size_t i = 0; i < pending.size(); i++) { - int64_t attrs = COLOR_PAIR(CURSESPP_TEXT_DEFAULT); + Color attrs = Color::TextDefault; LogEntry* entry = pending[i]; switch (entry->level) { case musik::debug::level_error: { - attrs = COLOR_PAIR(CURSESPP_TEXT_ERROR); + attrs = Color::TextError; break; } case musik::debug::level_warning: { - attrs = COLOR_PAIR(CURSESPP_TEXT_WARNING); + attrs = Color::TextWarning; break; } } diff --git a/src/musikcube/app/window/TrackListView.cpp b/src/musikcube/app/window/TrackListView.cpp index 140077a84..1f4cd6586 100755 --- a/src/musikcube/app/window/TrackListView.cpp +++ b/src/musikcube/app/window/TrackListView.cpp @@ -271,7 +271,7 @@ bool TrackListView::KeyPress(const std::string& key) { if (handled) { this->lastChanged = now(); - this->DebounceMessage( + this->Debounce( WINDOW_MESSAGE_SCROLL_TO_PLAYING, 0, 0, AUTO_SCROLL_COOLDOWN.count()); } @@ -427,8 +427,8 @@ IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWi TrackListEntry(album, trackIndex, RowType::Separator)); entry->SetAttrs(selected - ? COLOR_PAIR(CURSESPP_LIST_ITEM_HIGHLIGHTED_HEADER) - : COLOR_PAIR(CURSESPP_LIST_ITEM_HEADER)); + ? Color::ListItemHeaderHighlighted + : Color::ListItemHeader); return entry; } @@ -439,22 +439,17 @@ IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWi if (!track) { auto entry = std::shared_ptr(new SingleLineEntry("track missing")); - - entry->SetAttrs(COLOR_PAIR(selected - ? CURSESPP_HIGHLIGHTED_ERROR_LIST_ITEM : CURSESPP_TEXT_ERROR)); - + entry->SetAttrs(selected ? Color::ListItemHighlighted : Color::TextError); return entry; } - int64_t attrs = CURSESPP_DEFAULT_COLOR; + Color attrs = Color::Default; if (parent.decorator) { attrs = parent.decorator(track, trackIndex); } else { - attrs = selected - ? COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM) - : CURSESPP_DEFAULT_COLOR; + attrs = selected ? Color::ListItemHighlighted : Color::Default; TrackPtr playing = parent.playing; if (playing && @@ -462,10 +457,10 @@ IScrollAdapter::EntryPtr TrackListView::Adapter::GetEntry(cursespp::ScrollableWi playing->LibraryId() == track->LibraryId()) { if (selected) { - attrs = COLOR_PAIR(CURSESPP_HIGHLIGHTED_SELECTED_LIST_ITEM); + attrs = Color::ListItemHighlightedSelected; } else { - attrs = COLOR_PAIR(CURSESPP_SELECTED_LIST_ITEM); + attrs = Color::ListItemSelected; } } } diff --git a/src/musikcube/app/window/TrackListView.h b/src/musikcube/app/window/TrackListView.h index feec8fa3d..f79a4067f 100755 --- a/src/musikcube/app/window/TrackListView.h +++ b/src/musikcube/app/window/TrackListView.h @@ -35,6 +35,7 @@ #pragma once #include +#include #include #include #include @@ -66,7 +67,7 @@ namespace musik { /* types */ typedef std::function RowFormatter; - typedef std::function RowDecorator; + typedef std::function RowDecorator; typedef std::shared_ptr > Headers; /* ctor, dtor */ diff --git a/src/musikcube/app/window/TransportWindow.cpp b/src/musikcube/app/window/TransportWindow.cpp index 9317b7cf7..c49165bcb 100755 --- a/src/musikcube/app/window/TransportWindow.cpp +++ b/src/musikcube/app/window/TransportWindow.cpp @@ -79,10 +79,10 @@ using namespace cursespp; #define MIN_HEIGHT 2 #define DEBOUNCE_REFRESH(mode, delay) \ - this->DebounceMessage(message::RefreshTransport, (int64_t) mode, 0, delay); + this->Debounce(message::RefreshTransport, (int64_t) mode, 0, delay); -#define ON(w, a) if (a != CURSESPP_DEFAULT_COLOR) { wattron(w, a); } -#define OFF(w, a) if (a != CURSESPP_DEFAULT_COLOR) { wattroff(w, a); } +#define ON(w, a) if (a != Color::Default) { wattron(w, a); } +#define OFF(w, a) if (a != Color::Default) { wattroff(w, a); } struct Token { enum Type { Normal, Placeholder }; @@ -235,15 +235,15 @@ static size_t writePlayingFormat( TokenList tokens; tokenize(Strings.PLAYING_FORMAT, tokens); - int64_t dim = COLOR_PAIR(CURSESPP_TEXT_DISABLED); - int64_t gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE); + Color dim = Color::TextDisabled; + Color gb = Color::TextActive; size_t remaining = width; auto it = tokens.begin(); while (it != tokens.end() && remaining > 0) { Token *token = it->get(); - int64_t attr = dim; + Color attr = dim; std::string value; size_t cols; @@ -532,20 +532,20 @@ void TransportWindow::Update(TimeMode timeMode) { bool muted = transport.IsMuted(); bool replayGainEnabled = (this->replayGainMode != ReplayGainMode::Disabled); - int64_t gb = COLOR_PAIR(CURSESPP_TEXT_ACTIVE); - int64_t disabled = COLOR_PAIR(CURSESPP_TEXT_DISABLED); - int64_t bright = COLOR_PAIR(CURSESPP_TEXT_DEFAULT); + Color gb = Color::TextActive; + Color disabled = Color::TextDisabled; + Color bright = Color::TextDefault; + Color volumeAttrs = Color::Default; - int64_t volumeAttrs = CURSESPP_DEFAULT_COLOR; if (this->focus == FocusVolume) { - volumeAttrs = COLOR_PAIR(CURSESPP_TEXT_FOCUSED); + volumeAttrs = Color::TextFocused; } else if (muted) { volumeAttrs = gb; } - int64_t timerAttrs = (this->focus == FocusTime) - ? COLOR_PAIR(CURSESPP_TEXT_FOCUSED) : CURSESPP_DEFAULT_COLOR; + Color timerAttrs = (this->focus == FocusTime) + ? Color::TextFocused : Color::Default; /* prepare the "shuffle" label */ @@ -568,7 +568,7 @@ void TransportWindow::Update(TimeMode timeMode) { /* draw the "shuffle" label */ const int shuffleOffset = cx - shuffleWidth; wmove(c, 0, shuffleOffset); - int64_t shuffleAttrs = this->playback.IsShuffled() ? gb : disabled; + Color shuffleAttrs = this->playback.IsShuffled() ? gb : disabled; ON(c, shuffleAttrs); checked_wprintw(c, shuffleLabel.c_str()); OFF(c, shuffleAttrs); @@ -603,7 +603,7 @@ void TransportWindow::Update(TimeMode timeMode) { RepeatMode mode = this->playback.GetRepeatMode(); std::string repeatModeLabel; - int64_t repeatAttrs = CURSESPP_DEFAULT_COLOR; + Color repeatAttrs = Color::Default; switch (mode) { case RepeatList: repeatModeLabel += Strings.REPEAT_LIST; @@ -621,14 +621,14 @@ void TransportWindow::Update(TimeMode timeMode) { /* time slider */ - int64_t currentTimeAttrs = timerAttrs; + Color currentTimeAttrs = timerAttrs; if (paused) { /* blink the track if paused */ int64_t now = duration_cast( system_clock::now().time_since_epoch()).count(); if (now % 2 == 0) { - currentTimeAttrs = COLOR_PAIR(CURSESPP_TEXT_HIDDEN); + currentTimeAttrs = Color::TextHidden; } } diff --git a/src/musikcube/cursespp/App.cpp b/src/musikcube/cursespp/App.cpp index 97763aee0..fbcb3c3e3 100755 --- a/src/musikcube/cursespp/App.cpp +++ b/src/musikcube/cursespp/App.cpp @@ -46,10 +46,13 @@ #ifdef WIN32 #include "Win32Util.h" +#undef MOUSE_MOVED +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif #ifndef WIN32 #include +#include #endif using namespace cursespp; @@ -93,12 +96,15 @@ App::App(const std::string& title) { #ifdef WIN32 this->iconId = 0; this->appTitle = title; + this->colorMode = Colors::RGB; win32::ConfigureDpiAwareness(); + PDC_set_default_menu_visibility(0); #else setlocale(LC_ALL, ""); std::signal(SIGWINCH, resizedHandler); std::signal(SIGHUP, hangupHandler); std::signal(SIGPIPE, SIG_IGN); + this->colorMode = Colors::Palette; #endif #ifdef __PDCURSES__ @@ -211,8 +217,9 @@ void App::OnResized() { Window::Unfreeze(); if (this->state.layout) { - if (this->state.viewRoot) { - this->state.viewRoot->ResizeToViewport(); + if (this->state.rootWindow) { + this->state.rootWindow->MoveAndResize( + 0, 0, Screen::GetWidth(), Screen::GetHeight()); } this->state.layout->Layout(); @@ -459,10 +466,11 @@ void App::ChangeLayout(ILayoutPtr newLayout) { if (newLayout) { this->state.layout = newLayout; - this->state.viewRoot = dynamic_cast(this->state.layout.get()); + this->state.rootWindow = dynamic_cast(this->state.layout.get()); - if (this->state.viewRoot) { - this->state.viewRoot->ResizeToViewport(); + if (this->state.rootWindow) { + this->state.rootWindow->MoveAndResize( + 0, 0, Screen::GetWidth(), Screen::GetHeight()); } this->state.layout->Show(); diff --git a/src/musikcube/cursespp/App.h b/src/musikcube/cursespp/App.h index 1dabc5ad0..55574477b 100755 --- a/src/musikcube/cursespp/App.h +++ b/src/musikcube/cursespp/App.h @@ -35,7 +35,6 @@ #pragma once #include -#include "IViewRoot.h" #include "ILayout.h" #include "IInput.h" #include "IKeyHandler.h" @@ -59,7 +58,7 @@ namespace cursespp { void SetResizeHandler(ResizeHandler handler); void SetColorMode(Colors::Mode mode); void SetColorBackgroundType(Colors::BgType bgType); - void SetColorTheme(const std::string& fn); + void SetColorTheme(const std::string& name); void SetMinimumSize(int width, int height); void SetMouseEnabled(bool enabled); bool IsOverlayVisible() { return this->state.overlay != nullptr; } @@ -90,19 +89,12 @@ namespace cursespp { private: struct WindowState { ILayoutPtr overlay; - IWindow* overlayWindow; + IWindow* overlayWindow{ nullptr }; ILayoutPtr layout; IWindowPtr focused; - IViewRoot* viewRoot; - IInput* input; - IKeyHandler* keyHandler; - - WindowState() { - this->overlayWindow = nullptr; - this->viewRoot = nullptr; - this->input = nullptr; - this->keyHandler = nullptr; - } + IWindow* rootWindow{ nullptr }; + IInput* input{ nullptr }; + IKeyHandler* keyHandler{ nullptr }; inline ILayoutPtr ActiveLayout() { /* if there's a visible overlay, it's always the current diff --git a/src/musikcube/cursespp/AppLayout.cpp b/src/musikcube/cursespp/AppLayout.cpp new file mode 100644 index 000000000..bc0b8ac5c --- /dev/null +++ b/src/musikcube/cursespp/AppLayout.cpp @@ -0,0 +1,274 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2017 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 +#include +#include + +#include + +using namespace cursespp; + +static std::map lastFocusMap; + +#define ENABLE_DEMO_MODE 0 + +#if ENABLE_DEMO_MODE +static std::string lastKey; +static int lastKeyRepeat = 0; +#endif + +static int last(ILayout* layout) { + auto it = lastFocusMap.find(layout); + return (it == lastFocusMap.end()) ? 0 : it->second; +} + +static void last(ILayout* layout, int last) { + lastFocusMap[layout] = last; +} + +AppLayout::AppLayout(cursespp::App& app) +: shortcutsFocused(false) +, topLevelLayout(nullptr) +, LayoutBase() { + this->Initialize(); + this->EnableDemoModeIfNecessary(); +} + +AppLayout::~AppLayout() { +} + +void AppLayout::OnLayout() { + size_t cx = Screen::GetWidth() - (paddingL + paddingR); + size_t cy = Screen::GetHeight() - (paddingT + paddingB); + +#if ENABLE_DEMO_MODE + this->hotkey->MoveAndResize(0, cy - 1, cx, 1); + --cy; +#endif + + if (this->layout) { + this->layout->MoveAndResize(paddingL, paddingT, cx, cy - 1); + this->layout->Show(); + this->layout->BringToTop(); + + if (this->shortcutsFocused) { + this->layout->SetFocus(IWindowPtr()); + } + } + + this->shortcuts->MoveAndResize( + 0, Screen::GetHeight() - 1, + Screen::GetWidth(), 1); +} + +void AppLayout::Initialize() { + this->shortcuts.reset(new ShortcutsWindow()); + this->AddWindow(this->shortcuts); + +#if ENABLE_DEMO_MODE + this->hotkey.reset(new TextLabel()); + this->hotkey->SetContentColor(Color::Footer); + this->hotkey->SetText("keypress: ", text::AlignCenter); + this->AddWindow(this->hotkey); +#endif +} + +void AppLayout::SetPadding(size_t t, size_t l, size_t b, size_t r) { + this->paddingT = t; + this->paddingL = l; + this->paddingB = b; + this->paddingR = r; +} + +cursespp::IWindowPtr AppLayout::GetFocus() { + if (this->shortcutsFocused) { + return this->shortcuts; + } + if (this->layout) { + return this->layout->GetFocus(); + } + return cursespp::IWindowPtr(); +} + +IWindowPtr AppLayout::FocusNext() { + if (this->shortcutsFocused) { + return this->BlurShortcuts(); + } + else if (this->layout) { + return this->layout->FocusNext(); + } + return cursespp::IWindowPtr(); +} + +IWindowPtr AppLayout::FocusPrev() { + if (this->shortcutsFocused) { + return this->BlurShortcuts(); + } + else if (this->layout) { + return this->layout->FocusPrev(); + } + return cursespp::IWindowPtr(); +} + +void AppLayout::SetLayout(std::shared_ptr layout) { + if (layout != this->layout) { + if (this->layout) { + if (this->lastFocus) { + this->layout->SetFocus(this->lastFocus); + } + + this->RemoveWindow(this->layout); + last(this->layout.get(), this->layout->GetFocusIndex()); + this->layout->SetFocusIndex(-1); + this->layout->Hide(); + } + + this->lastFocus.reset(); + + if (this->topLevelLayout) { + this->topLevelLayout->SetShortcutsWindow(nullptr); + } + + this->layout = layout; + this->shortcuts->RemoveAll(); + + if (this->layout) { + this->topLevelLayout = dynamic_cast(layout.get()); + if (this->topLevelLayout) { + this->topLevelLayout->SetShortcutsWindow(this->shortcuts.get()); + } + + this->AddWindow(this->layout); + this->layout->SetFocusOrder(0); + this->layout->SetFocusIndex(last(this->layout.get())); + this->Layout(); + } + } +} + +cursespp::IWindowPtr AppLayout::BlurShortcuts() { + this->shortcuts->Blur(); + this->shortcutsFocused = false; + + if (this->layout) { + bool refocused = false; + if (this->lastFocus) { + refocused = this->layout->SetFocus(this->lastFocus); + this->lastFocus.reset(); + } + + if (!refocused) { + this->layout->FocusNext(); + } + } + + return this->layout ? this->layout->GetFocus() : IWindowPtr(); +} + +void AppLayout::FocusShortcuts() { + this->shortcuts->Focus(); + + if (this->layout) { + this->lastFocus = this->layout->GetFocus(); + + if (this->lastFocus) { + this->lastFocus->Blur(); + } + + this->layout->SetFocus(IWindowPtr()); + } + + this->shortcuts->Focus(); +} + +bool AppLayout::KeyPress(const std::string& key) { + /* otherwise, see if the user is monkeying around with the + shortcut bar focus... */ + if (key == "^[" || + (key == "KEY_ENTER" && this->shortcutsFocused) || + (key == "KEY_UP" && this->shortcutsFocused)) + { + this->shortcutsFocused = !this->shortcutsFocused; + if (this->shortcutsFocused) { + this->FocusShortcuts(); + } + else { + this->BlurShortcuts(); + } + return true; + } + + if (this->shortcutsFocused) { + if (key == "KEY_DOWN" || key == "KEY_LEFT" || + key == "KEY_UP" || key == "KEY_RIGHT") + { + /* layouts allow focusing via TAB and sometimes arrow + keys. suppress these from bubbling. */ + return true; + } + } + + /* otherwise, pass along to our child layout */ + return this->layout ? this->layout->KeyPress(key) : false; +} + +void AppLayout::EnableDemoModeIfNecessary() { +#if ENABLE_DEMO_MODE + App::Instance().SetKeyHook([this](const std::string& key) -> bool { + static std::map SANITIZE = { + { "^I", "TAB" }, { " ", "SPACE" }, { "^[", "ESC" } + }; + + auto it = SANITIZE.find(key); + std::string normalized = (it == SANITIZE.end()) ? key : it->second; + + if (normalized == lastKey) { + ++lastKeyRepeat; + if (lastKeyRepeat >= 2) { + normalized = normalized + " (x" + std::to_string(lastKeyRepeat) + ")"; + } + } + else { + lastKey = normalized; + lastKeyRepeat = 1; + } + + std::string keypress = "keypress: " + (normalized.size() ? normalized : ""); + this->hotkey->SetText(keypress, text::AlignCenter); + return false; + }); +#endif +} \ No newline at end of file diff --git a/src/musikcube/cursespp/AppLayout.h b/src/musikcube/cursespp/AppLayout.h new file mode 100644 index 000000000..dc97a5c40 --- /dev/null +++ b/src/musikcube/cursespp/AppLayout.h @@ -0,0 +1,86 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2017 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 +#include +#include +#include +#include +#include + +#include + +namespace cursespp { + class AppLayout : + public cursespp::LayoutBase, +#if (__clang_major__ == 7 && __clang_minor__ == 3) + public std::enable_shared_from_this, +#endif + public sigslot::has_slots<> + { + public: + AppLayout(cursespp::App& app); + + virtual ~AppLayout(); + + virtual bool KeyPress(const std::string& key) override; + virtual void OnLayout() override; + virtual cursespp::IWindowPtr GetFocus() override; + virtual cursespp::IWindowPtr FocusNext() override; + virtual cursespp::IWindowPtr FocusPrev() override; + + void SetLayout(std::shared_ptr layout); + + protected: + virtual void SetPadding(size_t t, size_t l, size_t b, size_t r); + + private: + void Initialize(); + + void EnableDemoModeIfNecessary(); + + cursespp::IWindowPtr BlurShortcuts(); + void FocusShortcuts(); + + std::shared_ptr shortcuts; + std::shared_ptr layout; + std::shared_ptr hotkey; + cursespp::IWindowPtr lastFocus; + ITopLevelLayout* topLevelLayout; + size_t paddingT{0}, paddingL{0}, paddingB{0}, paddingR{0}; + bool shortcutsFocused; + }; +} diff --git a/src/musikcube/cursespp/Checkbox.cpp b/src/musikcube/cursespp/Checkbox.cpp index 911bd9bb8..d3cdb2b50 100755 --- a/src/musikcube/cursespp/Checkbox.cpp +++ b/src/musikcube/cursespp/Checkbox.cpp @@ -49,7 +49,7 @@ Checkbox::Checkbox() : Window() , checked(false) { this->SetFrameVisible(false); - this->SetFocusedContentColor(CURSESPP_TEXT_FOCUSED); + this->SetFocusedContentColor(Color::TextFocused); } Checkbox::~Checkbox() { @@ -87,13 +87,13 @@ void Checkbox::OnRedraw() { : this->GetContentColor(); if (attrs != -1) { - wattron(c, COLOR_PAIR(attrs)); + wattron(c, attrs); } checked_wprintw(c, ellipsized.c_str()); if (attrs != -1) { - wattroff(c, COLOR_PAIR(attrs)); + wattroff(c, attrs); } } } diff --git a/src/musikcube/cursespp/Colors.cpp b/src/musikcube/cursespp/Colors.cpp index fb7700c56..677ab8ab9 100755 --- a/src/musikcube/cursespp/Colors.cpp +++ b/src/musikcube/cursespp/Colors.cpp @@ -35,9 +35,13 @@ #include #include #include "Colors.h" +#include +#include +using namespace musik::core; using namespace cursespp; using namespace nlohmann; +using namespace boost::filesystem; /* if the terminal supports custom colors, these are the palette indicies we'll use to store them */ @@ -138,119 +142,73 @@ palette, use ones that most closely match our desired colors */ #define SCALE(x) ((x * 1000) / 255) -/* as much as I hate to do this, it was copied directly from -musik::core::FileToByteArray to keep things properly encapsulated. */ -static bool fileToByteArray(const std::string& path, char** target, int& size) { -#ifdef WIN32 - std::wstring u16fn = u8to16(path); - FILE* file = _wfopen(u16fn.c_str(), L"rb"); -#else - FILE* file = fopen(path.c_str(), "rb"); -#endif - - *target = nullptr; - size = 0; - - if (!file) { - return false; +struct ThemeColor { + ThemeColor() { + Set(0, 0, 0, 0, -1); } - bool success = false; - - if (fseek(file, 0L, SEEK_END) == 0) { - long fileSize = ftell(file); - if (fileSize == -1) { - goto close_and_return; - } - - if (fseek(file, 0L, SEEK_SET) != 0) { - goto close_and_return; - } - - *target = (char*)malloc(sizeof(char) * (fileSize + 1)); - size = fread(*target, sizeof(char), fileSize, file); - - if (size == fileSize) { - (*target)[size] = 0; - success = true; - } + void Set(int colorId, int r, int g, int b, int palette) { + this->colorId = colorId; + this->r = r; + this->g = g; + this->b = b; + this->palette = palette; } -close_and_return: - fclose(file); + void Set(const json& obj) { + if (!obj.is_null()) { + std::string hex = obj.value(JSON_KEY_HEX, ""); + long palette = obj.value(JSON_KEY_PALETTE, -1); - if (!success) { - free(*target); - } + if (hex.length() == 7 && hex[0] == '#') { + int rgb = strtol(hex.substr(1).c_str(), 0, 16); + this->b = rgb & 0x0000ff; + this->r = rgb >> 16; + this->g = (rgb >> 8) & 0x0000ff; + } + else if (palette > 15 && palette < 256) { + /* we may have already been initialized with a default + color. but if we have a palette color, clear the RGB + values and prefer the value from the theme. */ + this->r = this->b = this->g = -1; + } - return success; -} - -struct Theme { - struct Color { - Color() { - Set(0, 0, 0, 0, -1); - } - - void Set(int colorId, int r, int g, int b, int palette) { - this->colorId = colorId; - this->r = r; - this->g = g; - this->b = b; - this->palette = palette; - } - - void Set(const json& obj) { - if (!obj.is_null()) { - std::string hex = obj.value(JSON_KEY_HEX, ""); - long palette = obj.value(JSON_KEY_PALETTE, -1); - - if (hex.length() == 7 && hex[0] == '#') { - int rgb = strtol(hex.substr(1).c_str(), 0, 16); - this->b = rgb & 0x0000ff; - this->r = rgb >> 16; - this->g = (rgb >> 8) & 0x0000ff; - } - else if (palette > 15 && palette < 256) { - /* we may have already been initialized with a default - color. but if we have a palette color, clear the RGB - values and prefer the value from the theme. */ - this->r = this->b = this->g = -1; - } - - if (palette != -1) { - this->palette = palette; - } + if (palette != -1) { + this->palette = palette; } } + } - int Id(Colors::Mode mode, int defaultValue) { - if (mode == Colors::Basic) { - return defaultValue; - } - else if (mode == Colors::Palette) { - return this->palette; + int Id(Colors::Mode mode, int defaultValue) { + if (mode == Colors::Basic) { + return defaultValue; + } + else if (mode == Colors::Palette) { + return this->palette; + } + else { + if (this->colorId > 15 && this->r >= 0 && this->g >= 0 && this->b >= 0) { + init_color(this->colorId, SCALE(this->r), SCALE(this->g), SCALE(this->b)); + return this->colorId; } else { - if (this->colorId > 15 && this->r >= 0 && this->g >= 0 && this->b >= 0) { - init_color(this->colorId, SCALE(this->r), SCALE(this->g), SCALE(this->b)); - return this->colorId; - } - else { - /* if RGB mode was requested but no RGB value exists, fall back to the - palette value. */ - return this->palette; - } + /* if RGB mode was requested but no RGB value exists, fall back to the + palette value. */ + return this->palette; } - return -1; } + return -1; + } - int colorId; - int r, g, b; - int palette; - }; + int colorId; + int r, g, b; + int palette; +}; +struct Theme { Theme() { + this->name = "default"; + this->Reset(); } void Reset() { @@ -316,7 +274,7 @@ struct Theme { char* buffer = nullptr; int size = 0; - if (fileToByteArray(fn, &buffer, size)) { + if (FileToByteArray(fn, &buffer, size, true)) { try { json data = json::parse(buffer); @@ -365,6 +323,9 @@ struct Theme { this->listActiveHighlightedBackground.Set(colors.value(JSON_KEY_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_BACKGROUND, unset)); this->listActiveHighlightedForeground.Set(colors.value(JSON_KEY_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_FOREGROUND, unset)); + this->fn = fn; + this->name = data.value("name", "unnamed"); + success = true; } } @@ -379,149 +340,155 @@ struct Theme { /* initializes all of the color pairs from the specified colors, then applies them to the current session! */ void Apply(Colors::Mode mode, Colors::BgType bgType) { +#ifdef WIN32 + bgType = Colors::Theme; +#endif int backgroundId = (bgType == Colors::BgType::Theme) ? background.Id(mode, -1) : -1; int foregroundId = foreground.Id(mode, -1); /* main */ - init_pair(CURSESPP_DEFAULT_CONTENT_COLOR, foregroundId, backgroundId); - init_pair(CURSESPP_DEFAULT_FRAME_COLOR, foregroundId, backgroundId); - init_pair(CURSESPP_FOCUSED_FRAME_COLOR, focusedBorder.Id(mode, COLOR_RED),backgroundId); + init_pair(Color::ContentColorDefault, foregroundId, backgroundId); + init_pair(Color::FrameColorDefault, foregroundId, backgroundId); + init_pair(Color::FrameColorFocused, focusedBorder.Id(mode, COLOR_RED),backgroundId); /* text */ - init_pair(CURSESPP_TEXT_DEFAULT, foregroundId, backgroundId); - init_pair(CURSESPP_TEXT_DISABLED, textDisabled.Id(mode, -1), backgroundId); - init_pair(CURSESPP_TEXT_FOCUSED, textFocused.Id(mode, COLOR_RED), backgroundId); - init_pair(CURSESPP_TEXT_ACTIVE, textActive.Id(mode, COLOR_GREEN), backgroundId); - init_pair(CURSESPP_TEXT_WARNING, textWarning.Id(mode, COLOR_YELLOW), backgroundId); - init_pair(CURSESPP_TEXT_ERROR, textError.Id(mode, COLOR_RED), backgroundId); - init_pair(CURSESPP_TEXT_HIDDEN, textHidden.Id(mode, COLOR_BLACK), backgroundId); + init_pair(Color::TextDefault, foregroundId, backgroundId); + init_pair(Color::TextDisabled, textDisabled.Id(mode, -1), backgroundId); + init_pair(Color::TextFocused, textFocused.Id(mode, COLOR_RED), backgroundId); + init_pair(Color::TextActive, textActive.Id(mode, COLOR_GREEN), backgroundId); + init_pair(Color::TextWarning, textWarning.Id(mode, COLOR_YELLOW), backgroundId); + init_pair(Color::TextError, textError.Id(mode, COLOR_RED), backgroundId); + init_pair(Color::TextHidden, textHidden.Id(mode, COLOR_BLACK), backgroundId); /* overlay */ int overlayBgId = overlayBackground.Id(mode, -1); - init_pair(CURSESPP_OVERLAY_FRAME, overlayBorder.Id(mode, COLOR_BLUE), overlayBgId); - init_pair(CURSESPP_OVERLAY_CONTENT, overlayForeground.Id(mode, -1), overlayBgId); - init_pair(CURSESPP_OVERLAY_INPUT_FRAME, overlayFocusedBorder.Id(mode, COLOR_RED), overlayBgId); - init_pair(CURSESPP_OVERLAY_TEXT_FOCUSED, overlayFocusedText.Id(mode, COLOR_RED), overlayBgId); - init_pair(CURSESPP_OVERLAY_LIST_FRAME, foregroundId, overlayBgId); - init_pair(CURSESPP_OVERLAY_LIST_FRAME_FOCUSED, focusedBorder.Id(mode, COLOR_RED), overlayBgId); + init_pair(Color::OverlayFrame, overlayBorder.Id(mode, COLOR_BLUE), overlayBgId); + init_pair(Color::OverlayContent, overlayForeground.Id(mode, -1), overlayBgId); + init_pair(Color::OverlayTextInputFrame, overlayFocusedBorder.Id(mode, COLOR_RED), overlayBgId); + init_pair(Color::OverlayTextFocused, overlayFocusedText.Id(mode, COLOR_RED), overlayBgId); + init_pair(Color::OverlayListFrame, foregroundId, overlayBgId); + init_pair(Color::OverlayListFrameFocused, focusedBorder.Id(mode, COLOR_RED), overlayBgId); /* shortcuts */ init_pair( - CURSESPP_SHORTCUT_ROW_NORMAL, + Color::ShortcutRowDefault, shortcutsForeground.Id(mode, COLOR_YELLOW), shortcutsBackground.Id(mode, -1)); init_pair( - CURSESPP_SHORTCUT_ROW_FOCUSED, + Color::ShortcutRowFocused, focusedShortcutsForeground.Id(mode, COLOR_WHITE), focusedShortcutsBackground.Id(mode, COLOR_RED)); /* buttons */ init_pair( - CURSESPP_BUTTON_NORMAL, + Color::ButtonDefault, buttonForegroundNormal.Id(mode, COLOR_BLACK), buttonBackgroundNormal.Id(mode, COLOR_YELLOW)); init_pair( - CURSESPP_BUTTON_HIGHLIGHTED, + Color::ButtonHighlighted, buttonForegroundActive.Id(mode, COLOR_BLACK), buttonBackgroundActive.Id(mode, COLOR_GREEN)); /* banner */ init_pair( - CURSESPP_BANNER, + Color::Banner, bannerForeground.Id(mode, COLOR_BLACK), bannerBackground.Id(mode, COLOR_YELLOW)); /* footer */ init_pair( - CURSESPP_FOOTER, + Color::Footer, footerForeground.Id(mode, COLOR_BLACK), footerBackground.Id(mode, COLOR_BLUE)); /* list items */ init_pair( - CURSESPP_LIST_ITEM_HEADER, + Color::ListItemHeader, listHeaderForeground.Id(mode, COLOR_GREEN), listHeaderBackground.Id(mode, -1)); init_pair( - CURSESPP_LIST_ITEM_HIGHLIGHTED_HEADER, + Color::ListItemHeaderHighlighted, listHeaderHighlightedForeground.Id(mode, -1), listHeaderHighlightedBackground.Id(mode, COLOR_GREEN)); init_pair( - CURSESPP_SELECTED_LIST_ITEM, + Color::ListItemSelected, listActiveForeground.Id(mode, COLOR_YELLOW), listActiveBackground.Id(mode, COLOR_BLACK)); init_pair( - CURSESPP_HIGHLIGHTED_LIST_ITEM, + Color::ListItemHighlighted, listHighlightedForeground.Id(mode, COLOR_BLACK), listHighlightedBackground.Id(mode, COLOR_GREEN)); init_pair( - CURSESPP_HIGHLIGHTED_SELECTED_LIST_ITEM, + Color::ListItemHighlightedSelected, listActiveHighlightedForeground.Id(mode, COLOR_BLACK), listActiveHighlightedBackground.Id(mode, COLOR_YELLOW)); init_pair( - CURSESPP_HIGHLIGHTED_ERROR_LIST_ITEM, + Color::ListItemError, textError.Id(mode, COLOR_RED), listHighlightedBackground.Id(mode, COLOR_GREEN)); } + std::string name; + std::string fn; + /* main */ - Color background; - Color foreground; - Color focusedBorder; + ThemeColor background; + ThemeColor foreground; + ThemeColor focusedBorder; /* text */ - Color textFocused; - Color textActive; - Color textDisabled; - Color textHidden; - Color textWarning; - Color textError; + ThemeColor textFocused; + ThemeColor textActive; + ThemeColor textDisabled; + ThemeColor textHidden; + ThemeColor textWarning; + ThemeColor textError; /* overlay */ - Color overlayBackground; - Color overlayForeground; - Color overlayBorder; - Color overlayFocusedBorder; - Color overlayFocusedText; + ThemeColor overlayBackground; + ThemeColor overlayForeground; + ThemeColor overlayBorder; + ThemeColor overlayFocusedBorder; + ThemeColor overlayFocusedText; /* shortcut bar */ - Color shortcutsBackground; - Color shortcutsForeground; - Color focusedShortcutsBackground; - Color focusedShortcutsForeground; + ThemeColor shortcutsBackground; + ThemeColor shortcutsForeground; + ThemeColor focusedShortcutsBackground; + ThemeColor focusedShortcutsForeground; /* buttons */ - Color buttonBackgroundNormal; - Color buttonForegroundNormal; - Color buttonBackgroundActive; - Color buttonForegroundActive; + ThemeColor buttonBackgroundNormal; + ThemeColor buttonForegroundNormal; + ThemeColor buttonBackgroundActive; + ThemeColor buttonForegroundActive; /* banner */ - Color bannerBackground; - Color bannerForeground; + ThemeColor bannerBackground; + ThemeColor bannerForeground; /* footer */ - Color footerBackground; - Color footerForeground; + ThemeColor footerBackground; + ThemeColor footerForeground; /* listview */ - Color listHeaderBackground; - Color listHeaderForeground; - Color listHeaderHighlightedBackground; - Color listHeaderHighlightedForeground; - Color listHighlightedBackground; - Color listHighlightedForeground; - Color listActiveForeground; - Color listActiveBackground; - Color listActiveHighlightedBackground; - Color listActiveHighlightedForeground; + ThemeColor listHeaderBackground; + ThemeColor listHeaderForeground; + ThemeColor listHeaderHighlightedBackground; + ThemeColor listHeaderHighlightedForeground; + ThemeColor listHighlightedBackground; + ThemeColor listHighlightedForeground; + ThemeColor listActiveForeground; + ThemeColor listActiveBackground; + ThemeColor listActiveHighlightedBackground; + ThemeColor listActiveHighlightedForeground; }; /* some terminals report custom colors are supported, and also @@ -545,10 +512,46 @@ static bool canChangeColors() { Colors::Colors() { } +static std::string lastTheme = "default"; static Theme theme; +static std::vector themes; static Colors::Mode colorMode = Colors::Basic; static Colors::BgType bgType = Colors::Theme; +static void indexThemes(const std::string& directory) { + path colorPath(directory); + if (exists(colorPath)) { + directory_iterator end; + for (directory_iterator file(colorPath); file != end; file++) { + const path& p = file->path(); + + if (p.has_extension() && p.extension().string() == ".json") { + std::string fn = p.filename().string(); + Theme theme; + if (theme.LoadFromFile(directory + "/" + fn)) { + ::themes.push_back(theme); + } + } + } + } +} + +static void indexThemes() { + if (!::themes.size()) { + ::themes.push_back(Theme()); /* default */ + + indexThemes(GetApplicationDirectory() + "/themes/"); + indexThemes(GetDataDirectory() + "/themes/"); + + std::sort( + ::themes.begin(), + ::themes.end(), + [](const Theme& a, const Theme& b) -> bool { + return a.name < b.name; + }); + } +} + void Colors::Init(Colors::Mode mode, Colors::BgType bgType) { start_color(); use_default_colors(); @@ -565,12 +568,24 @@ void Colors::Init(Colors::Mode mode, Colors::BgType bgType) { } } - theme.Reset(); - theme.Apply(::colorMode, ::bgType); + SetTheme(::lastTheme); } -void Colors::SetTheme(const std::string& fn) { - theme.Reset(); - theme.LoadFromFile(fn); - theme.Apply(::colorMode, ::bgType); -} \ No newline at end of file +void Colors::SetTheme(const std::string& name) { + indexThemes(); + for (auto& t : ::themes) { + if (name == t.name) { + ::lastTheme = name; + t.Apply(::colorMode, ::bgType); + } + } +} + +std::vector Colors::ListThemes() { + indexThemes(); + std::vector names; + for (auto& t : ::themes) { + names.push_back(t.name); + } + return names; +} diff --git a/src/musikcube/cursespp/Colors.h b/src/musikcube/cursespp/Colors.h index 861490d97..d25b3e6f8 100755 --- a/src/musikcube/cursespp/Colors.h +++ b/src/musikcube/cursespp/Colors.h @@ -37,44 +37,68 @@ #include "curses_config.h" #include -#define CURSESPP_DEFAULT_COLOR -1LL - -#define CURSESPP_SELECTED_LIST_ITEM 1 -#define CURSESPP_HIGHLIGHTED_LIST_ITEM 2 -#define CURSESPP_HIGHLIGHTED_ERROR_LIST_ITEM 3 -#define CURSESPP_HIGHLIGHTED_SELECTED_LIST_ITEM 4 -#define CURSESPP_LIST_ITEM_HEADER 5 -#define CURSESPP_LIST_ITEM_HIGHLIGHTED_HEADER 6 - -#define CURSESPP_DEFAULT_CONTENT_COLOR 7 -#define CURSESPP_DEFAULT_FRAME_COLOR 8 -#define CURSESPP_FOCUSED_FRAME_COLOR 9 - -#define CURSESPP_TEXT_DEFAULT 10 -#define CURSESPP_TEXT_DISABLED 11 -#define CURSESPP_TEXT_FOCUSED 12 -#define CURSESPP_TEXT_ACTIVE 13 -#define CURSESPP_TEXT_WARNING 14 -#define CURSESPP_TEXT_ERROR 15 -#define CURSESPP_TEXT_HIDDEN 16 - -#define CURSESPP_BUTTON_NORMAL 17 -#define CURSESPP_BUTTON_HIGHLIGHTED 18 - -#define CURSESPP_SHORTCUT_ROW_NORMAL 19 -#define CURSESPP_SHORTCUT_ROW_FOCUSED 20 - -#define CURSESPP_OVERLAY_FRAME 21 -#define CURSESPP_OVERLAY_CONTENT 22 -#define CURSESPP_OVERLAY_INPUT_FRAME 23 -#define CURSESPP_OVERLAY_TEXT_FOCUSED 24 -#define CURSESPP_OVERLAY_LIST_FRAME 25 -#define CURSESPP_OVERLAY_LIST_FRAME_FOCUSED 26 - -#define CURSESPP_BANNER 27 -#define CURSESPP_FOOTER 28 - namespace cursespp { + class Color { + public: + enum Type { + Default = -1, + + ListItemSelected = 1, + ListItemHighlighted = 2, + ListItemError = 3, + ListItemHighlightedSelected = 4, + ListItemHeader = 5, + ListItemHeaderHighlighted = 6, + + ContentColorDefault = 7, + FrameColorDefault = 8, + FrameColorFocused = 9, + + TextDefault = 10, + TextDisabled = 11, + TextFocused = 12, + TextActive = 13, + TextWarning = 14, + TextError = 15, + TextHidden = 16, + + ButtonDefault = 17, + ButtonHighlighted = 18, + + ShortcutRowDefault = 19, + ShortcutRowFocused = 20, + + OverlayFrame = 21, + OverlayContent = 22, + OverlayTextInputFrame = 23, + OverlayTextFocused = 24, + OverlayListFrame = 25, + OverlayListFrameFocused = 26, + + Banner = 27, + Footer = 28 + }; + + Color() { + this->value = -1LL; + } + + Color(Type type) { + this->value = (type == Default) ? -1LL : COLOR_PAIR(type); + } + + Color(const Color& color) { + this->value = color; + } + + operator int64_t() const { + return this->value; + } + + private: + int64_t value; + }; + class Colors { private: Colors(); @@ -92,6 +116,7 @@ namespace cursespp { }; static void Init(Mode mode = Mode::Basic, BgType bgType = BgType::Theme); - static void SetTheme(const std::string& fn); + static void SetTheme(const std::string& name); + static std::vector ListThemes(); }; } diff --git a/src/musikcube/cursespp/DialogOverlay.cpp b/src/musikcube/cursespp/DialogOverlay.cpp index a7c7f355f..247213f47 100644 --- a/src/musikcube/cursespp/DialogOverlay.cpp +++ b/src/musikcube/cursespp/DialogOverlay.cpp @@ -45,8 +45,8 @@ using namespace cursespp; DialogOverlay::DialogOverlay() { this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); this->width = this->height = 0; this->autoDismiss = true; diff --git a/src/musikcube/cursespp/IViewRoot.h b/src/musikcube/cursespp/ITopLevelLayout.h similarity index 90% rename from src/musikcube/cursespp/IViewRoot.h rename to src/musikcube/cursespp/ITopLevelLayout.h index 67d2ac971..264c90d70 100644 --- a/src/musikcube/cursespp/IViewRoot.h +++ b/src/musikcube/cursespp/ITopLevelLayout.h @@ -34,11 +34,12 @@ #pragma once -#include +#include namespace cursespp { - class IViewRoot { + class ITopLevelLayout { public: - virtual void ResizeToViewport() = 0; + virtual ~ITopLevelLayout() { } + virtual void SetShortcutsWindow(cursespp::ShortcutsWindow* w) = 0; }; -} \ No newline at end of file +} diff --git a/src/musikcube/cursespp/IWindow.h b/src/musikcube/cursespp/IWindow.h index d5b95e6d6..7ed2b041c 100755 --- a/src/musikcube/cursespp/IWindow.h +++ b/src/musikcube/cursespp/IWindow.h @@ -38,6 +38,7 @@ #include "IDisplayable.h" #include "IOrderable.h" #include "IMouseHandler.h" +#include "Colors.h" #include #include @@ -56,14 +57,14 @@ namespace cursespp { virtual void SetParent(IWindow* parent) = 0; virtual void Focus() = 0; virtual void Blur() = 0; - virtual void SetContentColor(int64_t color) = 0; - virtual void SetFrameColor(int64_t color) = 0; - virtual void SetFocusedFrameColor(int64_t color) = 0; - virtual void SetFocusedContentColor(int64_t color) = 0; - virtual int64_t GetContentColor() = 0; - virtual int64_t GetFrameColor() = 0; - virtual int64_t GetFocusedContentColor() = 0; - virtual int64_t GetFocusedFrameColor() = 0; + virtual void SetContentColor(Color color) = 0; + virtual void SetFrameColor(Color color) = 0; + virtual void SetFocusedFrameColor(Color color) = 0; + virtual void SetFocusedContentColor(Color color) = 0; + virtual Color GetContentColor() = 0; + virtual Color GetFrameColor() = 0; + virtual Color GetFocusedContentColor() = 0; + virtual Color GetFocusedFrameColor() = 0; virtual void SetFrameVisible(bool visible) = 0; virtual bool IsFrameVisible() = 0; virtual void SetSize(int width, int height) = 0; diff --git a/src/musikcube/cursespp/InputOverlay.cpp b/src/musikcube/cursespp/InputOverlay.cpp index 8286054c5..d9e7b2579 100644 --- a/src/musikcube/cursespp/InputOverlay.cpp +++ b/src/musikcube/cursespp/InputOverlay.cpp @@ -54,17 +54,17 @@ using namespace cursespp; InputOverlay::InputOverlay() { this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); 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_CONTENT); - this->textInput->SetFocusedFrameColor(CURSESPP_OVERLAY_INPUT_FRAME); - this->textInput->SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT); + this->textInput->SetFrameColor(Color::OverlayFrame); + this->textInput->SetContentColor(Color::OverlayContent); + this->textInput->SetFocusedFrameColor(Color::OverlayTextInputFrame); + this->textInput->SetFocusedContentColor(Color::OverlayContent); this->textInput->EnterPressed.connect(this, &InputOverlay::OnInputEnterPressed); this->textInput->TextChanged.connect(this, &InputOverlay::OnInputKeyPress); this->AddWindow(this->textInput); diff --git a/src/musikcube/cursespp/ListOverlay.cpp b/src/musikcube/cursespp/ListOverlay.cpp index 715512cbd..0012b4744 100644 --- a/src/musikcube/cursespp/ListOverlay.cpp +++ b/src/musikcube/cursespp/ListOverlay.cpp @@ -83,8 +83,8 @@ class ListOverlay::CustomListWindow : public ListWindow { ListOverlay::ListOverlay() { this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); this->autoDismiss = true; @@ -101,11 +101,11 @@ ListOverlay::ListOverlay() { this->scrollbar.reset(new Window()); this->scrollbar->SetFrameVisible(false); - this->scrollbar->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->scrollbar->SetContentColor(Color::OverlayContent); this->listWindow.reset(new CustomListWindow(decorator, adapterChanged)); - this->listWindow->SetContentColor(CURSESPP_OVERLAY_CONTENT); - this->listWindow->SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT); + this->listWindow->SetContentColor(Color::OverlayContent); + this->listWindow->SetFocusedContentColor(Color::OverlayContent); this->listWindow->SetFrameVisible(false); this->listWindow->EntryActivated.connect(this, &ListOverlay::OnListEntryActivated); diff --git a/src/musikcube/cursespp/ListWindow.cpp b/src/musikcube/cursespp/ListWindow.cpp index 8d3347a7f..9b91b1d8c 100755 --- a/src/musikcube/cursespp/ListWindow.cpp +++ b/src/musikcube/cursespp/ListWindow.cpp @@ -302,6 +302,12 @@ bool ListWindow::KeyPress(const std::string& key) { this->OnEntryActivated(selected); } } + else if (key == "M-enter") { + auto selected = this->GetSelectedIndex(); + if (selected != NO_SELECTION) { + this->OnEntryContextMenu(selected); + } + } return ScrollableWindow::KeyPress(key); } diff --git a/src/musikcube/cursespp/NumberValidator.h b/src/musikcube/cursespp/NumberValidator.h new file mode 100644 index 000000000..43a879f19 --- /dev/null +++ b/src/musikcube/cursespp/NumberValidator.h @@ -0,0 +1,84 @@ +////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2007-2017 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 +#include + +namespace cursespp { + + template + struct NumberValidator : public InputOverlay::IValidator { + using Formatter = std::function; + + NumberValidator(T minimum, T maximum, Formatter formatter) + : minimum(minimum), maximum(maximum), formatter(formatter) { + } + + virtual bool IsValid(const std::string& input) const override { + try { + double result = std::stod(input); + if (bounded(minimum, maximum) && (result < minimum || result > maximum)) { + return false; + } + } + catch (std::invalid_argument) { + return false; + } + return true; + } + + virtual const std::string ErrorMessage() const override { + if (bounded(minimum, maximum)) { + std::string result = _TSTR("validator_dialog_number_parse_bounded_error"); + f8n::str::replace(result, "{{minimum}}", formatter(minimum)); + f8n::str::replace(result, "{{maximum}}", formatter(maximum)); + return result; + } + return _TSTR("validator_dialog_number_parse_error"); + } + + static bool bounded(T minimum, T maximum) { + return + minimum != std::numeric_limits::min() && + maximum != std::numeric_limits::max(); + } + + + Formatter formatter; + T minimum, maximum; + }; + +} diff --git a/src/musikcube/cursespp/OverlayBase.h b/src/musikcube/cursespp/OverlayBase.h index 209ad07fb..c7c43451e 100644 --- a/src/musikcube/cursespp/OverlayBase.h +++ b/src/musikcube/cursespp/OverlayBase.h @@ -48,8 +48,8 @@ namespace cursespp { public: OverlayBase() : LayoutBase() { this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); } virtual ~OverlayBase() { @@ -76,32 +76,33 @@ namespace cursespp { protected: static void style(TextLabel& label) { - label.SetContentColor(CURSESPP_OVERLAY_CONTENT); + label.SetContentColor(Color::OverlayContent); + label.SetFocusedContentColor(Color::OverlayTextFocused); } static void style(Checkbox& cb) { - cb.SetContentColor(CURSESPP_OVERLAY_CONTENT); - cb.SetFocusedContentColor(CURSESPP_OVERLAY_TEXT_FOCUSED); + cb.SetContentColor(Color::OverlayContent); + cb.SetFocusedContentColor(Color::OverlayTextFocused); } static void style(TextInput& input) { if (input.GetStyle() == TextInput::StyleBox) { - input.SetFrameColor(CURSESPP_OVERLAY_FRAME); - input.SetContentColor(CURSESPP_OVERLAY_CONTENT); - input.SetFocusedFrameColor(CURSESPP_OVERLAY_INPUT_FRAME); - input.SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT); + input.SetFrameColor(Color::OverlayFrame); + input.SetContentColor(Color::OverlayContent); + input.SetFocusedFrameColor(Color::OverlayTextInputFrame); + input.SetFocusedContentColor(Color::OverlayContent); } else { - input.SetContentColor(CURSESPP_OVERLAY_CONTENT); - input.SetFocusedContentColor(CURSESPP_OVERLAY_TEXT_FOCUSED); + input.SetContentColor(Color::OverlayContent); + input.SetFocusedContentColor(Color::OverlayTextFocused); } } static void style(ListWindow& listWindow, bool frameVisible = false) { - listWindow.SetContentColor(CURSESPP_OVERLAY_CONTENT); - listWindow.SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT); - listWindow.SetFrameColor(CURSESPP_OVERLAY_LIST_FRAME); - listWindow.SetFocusedFrameColor(CURSESPP_OVERLAY_LIST_FRAME_FOCUSED); + listWindow.SetContentColor(Color::OverlayContent); + listWindow.SetFocusedContentColor(Color::OverlayContent); + listWindow.SetFrameColor(Color::OverlayListFrame); + listWindow.SetFocusedFrameColor(Color::OverlayListFrameFocused); listWindow.SetFrameVisible(frameVisible); } diff --git a/src/musikcube/cursespp/OverlayStack.h b/src/musikcube/cursespp/OverlayStack.h index 0dd1a9180..d85d45b56 100644 --- a/src/musikcube/cursespp/OverlayStack.h +++ b/src/musikcube/cursespp/OverlayStack.h @@ -35,6 +35,7 @@ #pragma once #include "ILayout.h" +#include namespace cursespp { class OverlayStack { diff --git a/src/musikcube/cursespp/ShortcutsWindow.cpp b/src/musikcube/cursespp/ShortcutsWindow.cpp index 4ee527708..82ca82ced 100755 --- a/src/musikcube/cursespp/ShortcutsWindow.cpp +++ b/src/musikcube/cursespp/ShortcutsWindow.cpp @@ -44,8 +44,8 @@ ShortcutsWindow::ShortcutsWindow() : Window(nullptr) , alignment(text::AlignCenter) { this->SetFrameVisible(false); - this->SetFocusedContentColor(CURSESPP_SHORTCUT_ROW_FOCUSED); - this->SetContentColor(CURSESPP_SHORTCUT_ROW_NORMAL); + this->SetFocusedContentColor(Color::ShortcutRowFocused); + this->SetContentColor(Color::ShortcutRowDefault); } ShortcutsWindow::~ShortcutsWindow() { @@ -195,8 +195,8 @@ int ShortcutsWindow::getActiveIndex() { void ShortcutsWindow::OnRedraw() { this->Clear(); - int64_t normalAttrs = COLOR_PAIR(CURSESPP_BUTTON_NORMAL); - int64_t activeAttrs = COLOR_PAIR(CURSESPP_BUTTON_HIGHLIGHTED); + Color normalAttrs = Color(Color::ButtonDefault); + Color activeAttrs = Color(Color::ButtonHighlighted); WINDOW* c = this->GetContent(); @@ -208,7 +208,7 @@ void ShortcutsWindow::OnRedraw() { for (size_t i = 0; i < this->entries.size() && remaining > 0; i++) { auto e = this->entries[i]; - int64_t keyAttrs = (e->attrs == -1) ? normalAttrs : COLOR_PAIR(e->attrs); + int64_t keyAttrs = (e->attrs == -1) ? normalAttrs : e->attrs; keyAttrs = (e->key == this->activeKey) ? activeAttrs : keyAttrs; checked_wprintw(c, " "); diff --git a/src/musikcube/cursespp/SimpleScrollAdapter.cpp b/src/musikcube/cursespp/SimpleScrollAdapter.cpp index befe99fa8..e95f04752 100755 --- a/src/musikcube/cursespp/SimpleScrollAdapter.cpp +++ b/src/musikcube/cursespp/SimpleScrollAdapter.cpp @@ -62,6 +62,7 @@ void SimpleScrollAdapter::SetSelectable(bool selectable) { void SimpleScrollAdapter::Clear() { this->entries.clear(); + this->Changed(this); } size_t SimpleScrollAdapter::GetEntryCount() { @@ -77,17 +78,19 @@ EntryPtr SimpleScrollAdapter::GetEntry(cursespp::ScrollableWindow* window, size_ /* this is pretty damned gross, but super convenient. */ if (window && selectable) { - SingleLineEntry* single = dynamic_cast(entry.get()); - if (single) { - single->SetAttrs(CURSESPP_DEFAULT_COLOR); - + SingleLineEntry* single = static_cast(entry.get()); + single->SetAttrs(Color(Color::Default)); if (index == window->GetScrollPosition().logicalIndex) { - single->SetAttrs(COLOR_PAIR(CURSESPP_HIGHLIGHTED_LIST_ITEM)); + single->SetAttrs(Color(Color::ListItemHighlighted)); } } - } return entry; + } + +std::string SimpleScrollAdapter::StringAt(size_t index) { + auto entry = this->entries.at(index); + return static_cast(entry.get())->GetValue(); } void SimpleScrollAdapter::AddEntry(std::shared_ptr entry) { @@ -97,6 +100,8 @@ void SimpleScrollAdapter::AddEntry(std::shared_ptr entry) { while (entries.size() > this->maxEntries) { entries.pop_front(); } + + this->Changed(this); } void SimpleScrollAdapter::AddEntry(const std::string& value) { diff --git a/src/musikcube/cursespp/SimpleScrollAdapter.h b/src/musikcube/cursespp/SimpleScrollAdapter.h index 2f326d1e0..511d9098a 100755 --- a/src/musikcube/cursespp/SimpleScrollAdapter.h +++ b/src/musikcube/cursespp/SimpleScrollAdapter.h @@ -41,6 +41,8 @@ namespace cursespp { class SimpleScrollAdapter : public ScrollAdapterBase { public: + sigslot::signal1 Changed; + SimpleScrollAdapter(); virtual ~SimpleScrollAdapter(); @@ -53,6 +55,7 @@ namespace cursespp { void SetSelectable(bool selectable); void AddEntry(const std::string& entry); + std::string StringAt(size_t index); private: typedef std::deque EntryList; /* TODO: this is O(n) lookup */ diff --git a/src/musikcube/cursespp/SingleLineEntry.cpp b/src/musikcube/cursespp/SingleLineEntry.cpp index 3ddb52014..f0b585336 100755 --- a/src/musikcube/cursespp/SingleLineEntry.cpp +++ b/src/musikcube/cursespp/SingleLineEntry.cpp @@ -34,6 +34,7 @@ #include #include "SingleLineEntry.h" +#include "Text.h" using namespace cursespp; @@ -50,7 +51,7 @@ int64_t SingleLineEntry::GetAttrs(size_t line) { return this->attrs; } -void SingleLineEntry::SetAttrs(int64_t attrs) { +void SingleLineEntry::SetAttrs(Color attrs) { this->attrs = attrs; } @@ -59,5 +60,5 @@ size_t SingleLineEntry::GetLineCount() { } std::string SingleLineEntry::GetLine(size_t line) { - return u8substr(this->value, 0, this->width > 0 ? this->width : 0); + return text::Ellipsize(this->value, this->width); } \ No newline at end of file diff --git a/src/musikcube/cursespp/SingleLineEntry.h b/src/musikcube/cursespp/SingleLineEntry.h index bbfe07a78..47e1618ca 100755 --- a/src/musikcube/cursespp/SingleLineEntry.h +++ b/src/musikcube/cursespp/SingleLineEntry.h @@ -35,6 +35,7 @@ #pragma once #include "IScrollAdapter.h" +#include "Colors.h" namespace cursespp { class SingleLineEntry : public IScrollAdapter::IEntry { @@ -47,7 +48,9 @@ namespace cursespp { virtual size_t GetLineCount(); virtual std::string GetLine(size_t line); - void SetAttrs(int64_t attrs); + void SetAttrs(Color attrs); + + std::string GetValue() { return value; } private: size_t width; diff --git a/src/musikcube/cursespp/TextInput.h b/src/musikcube/cursespp/TextInput.h index 58f8b891c..8edb895b1 100755 --- a/src/musikcube/cursespp/TextInput.h +++ b/src/musikcube/cursespp/TextInput.h @@ -34,10 +34,10 @@ #pragma once -#include -#include -#include -#include +#include "curses_config.h" +#include "Window.h" +#include "IInput.h" +#include "IKeyHandler.h" #include namespace cursespp { diff --git a/src/musikcube/cursespp/TextLabel.cpp b/src/musikcube/cursespp/TextLabel.cpp index 8b723a00f..66e6a3a2e 100755 --- a/src/musikcube/cursespp/TextLabel.cpp +++ b/src/musikcube/cursespp/TextLabel.cpp @@ -46,51 +46,43 @@ using namespace cursespp; TextLabel::TextLabel() : Window() , alignment(text::AlignLeft) { - this->SetFrameVisible(false); - this->SetContentColor(CURSESPP_DEFAULT_COLOR); - this->SetFocusedContentColor(CURSESPP_TEXT_FOCUSED); - this->bold = false; + this->ApplyDefaultStyle(); +} + +TextLabel::TextLabel(const std::string& value) +: Window() +, alignment(text::AlignLeft) { + this->ApplyDefaultStyle(); + this->SetText(value); +} + +TextLabel::TextLabel(const std::string& value, const text::TextAlign alignment) +: Window() +, alignment(alignment) { + this->ApplyDefaultStyle(); + this->SetText(value, alignment); } TextLabel::~TextLabel() { } +void TextLabel::ApplyDefaultStyle() { + this->SetFrameVisible(false); + this->SetContentColor(Color::Default); + this->SetFocusedContentColor(Color::TextFocused); + this->bold = false; +} + void TextLabel::OnRedraw() { std::string aligned = text::Align( this->buffer, alignment, this->GetContentWidth()); WINDOW* c = this->GetContent(); - int64_t attrs = this->GetContentColor(); - if (attrs != -1) { - wbkgd(c, COLOR_PAIR(attrs)); - } - else { - werase(c); - } - - attrs = this->IsFocused() - ? this->GetFocusedContentColor() - : this->GetContentColor(); - - if (attrs != -1) { - wattron(c, COLOR_PAIR(attrs)); - } - - if (this->bold) { - wattron(c, A_BOLD); - } - + if (this->bold) { wattron(c, A_BOLD); } wmove(c, 0, 0); checked_waddstr(c, aligned.c_str()); - - if (this->bold) { - wattroff(c, A_BOLD); - } - - if (attrs != -1) { - wattroff(c, COLOR_PAIR(attrs)); - } + if (this->bold) { wattroff(c, A_BOLD); } } void TextLabel::SetText(const std::string& value, const text::TextAlign alignment) { @@ -101,6 +93,10 @@ void TextLabel::SetText(const std::string& value, const text::TextAlign alignmen } } +void TextLabel::SetText(const std::string& value) { + this->SetText(value, this->alignment); +} + void TextLabel::SetBold(bool bold) { if (bold != this->bold) { this->bold = bold; diff --git a/src/musikcube/cursespp/TextLabel.h b/src/musikcube/cursespp/TextLabel.h index 45bdae1cd..4d85d120b 100755 --- a/src/musikcube/cursespp/TextLabel.h +++ b/src/musikcube/cursespp/TextLabel.h @@ -55,11 +55,16 @@ namespace cursespp { sigslot::signal1 Activated; TextLabel(); + TextLabel(const std::string& value); + TextLabel(const std::string& value, const text::TextAlign alignment); + virtual ~TextLabel(); virtual void SetText( const std::string& value, - const text::TextAlign alignment = text::AlignLeft); + const text::TextAlign alignment); + + virtual void SetText(const std::string& value); virtual std::string GetText() { return this->buffer; } virtual size_t Length() { return u8cols(this->buffer); } @@ -71,6 +76,8 @@ namespace cursespp { virtual bool MouseEvent(const IMouseHandler::Event& event); private: + void ApplyDefaultStyle(); + std::string buffer; text::TextAlign alignment; bool bold; diff --git a/src/musikcube/cursespp/ToastOverlay.cpp b/src/musikcube/cursespp/ToastOverlay.cpp index 5200957b9..42748896f 100644 --- a/src/musikcube/cursespp/ToastOverlay.cpp +++ b/src/musikcube/cursespp/ToastOverlay.cpp @@ -39,12 +39,12 @@ #include "Screen.h" #include "Text.h" -static const int MESSAGE_HIDE = 1000; +static const int TOAST_MESSAGE_HIDE = 1000; using namespace cursespp; using namespace musik::core::runtime; -void ToastOverlay::Show(const std::string& text, long durationMs) { +void ToastOverlay::Show(const std::string& text, int durationMs) { std::shared_ptr overlay(new ToastOverlay(text, durationMs)); App::Overlays().Push(overlay); } @@ -55,8 +55,8 @@ ToastOverlay::ToastOverlay(const std::string& text, long durationMs) { this->width = this->height = 0; this->ticking = false; this->SetFrameVisible(true); - this->SetFrameColor(CURSESPP_OVERLAY_FRAME); - this->SetContentColor(CURSESPP_OVERLAY_CONTENT); + this->SetFrameColor(Color::OverlayFrame); + this->SetContentColor(Color::OverlayContent); } ToastOverlay::~ToastOverlay() { @@ -73,28 +73,30 @@ void ToastOverlay::Layout() { bool ToastOverlay::KeyPress(const std::string& key) { this->Dismiss(); /* any key closes */ - this->RemoveMessage(MESSAGE_HIDE); + this->Remove(TOAST_MESSAGE_HIDE); return true; } void ToastOverlay::OnVisibilityChanged(bool visible) { if (visible && !ticking) { - PostMessage(MESSAGE_HIDE, 0, 0, this->durationMs); + if (this->durationMs >= 0) { + this->Post(TOAST_MESSAGE_HIDE, 0, 0, this->durationMs); + } this->ticking = true; } } void ToastOverlay::ProcessMessage(IMessage &message) { - if (message.Type() == MESSAGE_HIDE) { + if (message.Type() == TOAST_MESSAGE_HIDE) { this->Dismiss(); } } void ToastOverlay::RecalculateSize() { int cols = (int) u8cols(this->title); - this->width = std::min(cols + 4, (Screen::GetWidth() * 2) / 3); + this->width = std::min(cols + 4, (Screen::GetWidth() * 4) / 5); this->titleLines = text::BreakLines(this->title, this->width - 4); - this->height = (int) this->titleLines.size() + 2; + this->height = std::min((int) this->titleLines.size() + 2, Screen::GetHeight() - 4); this->x = (Screen::GetWidth() / 2) - (this->width / 2); this->y = 2; } diff --git a/src/musikcube/cursespp/ToastOverlay.h b/src/musikcube/cursespp/ToastOverlay.h index c7660c583..41c221b9a 100644 --- a/src/musikcube/cursespp/ToastOverlay.h +++ b/src/musikcube/cursespp/ToastOverlay.h @@ -46,7 +46,7 @@ namespace cursespp { #endif { public: - static void Show(const std::string& text, long durationMs = 3000); + static void Show(const std::string& text, int durationMs = 3000); virtual ~ToastOverlay(); diff --git a/src/musikcube/cursespp/Window.cpp b/src/musikcube/cursespp/Window.cpp index 66b736b78..3a745edfb 100755 --- a/src/musikcube/cursespp/Window.cpp +++ b/src/musikcube/cursespp/Window.cpp @@ -73,6 +73,16 @@ static inline void DrawCursor(IInput* input) { } } +static inline void DrawTooSmall() { + static const std::string error = "terminal too small"; + int64_t color = Color(Color::TextError); + wclear(stdscr); + wmove(stdscr, 0, 0); + wattron(stdscr, color); + waddstr(stdscr, error.c_str()); + wattroff(stdscr, color); +} + bool Window::WriteToScreen(IInput* input) { if (drawPending && !freeze) { drawPending = false; @@ -81,12 +91,16 @@ bool Window::WriteToScreen(IInput* input) { DrawCursor(input); return true; } + else if (freeze) { + drawPending = false; + DrawTooSmall(); + } return false; } void Window::InvalidateScreen() { - wclear(stdscr); + werase(stdscr); drawPending = true; } @@ -118,10 +132,10 @@ Window::Window(IWindow *parent) { this->y = 0; this->lastAbsoluteX = 0; this->lastAbsoluteY = 0; - this->contentColor = CURSESPP_DEFAULT_CONTENT_COLOR; - this->frameColor = CURSESPP_DEFAULT_FRAME_COLOR; - this->focusedContentColor = CURSESPP_DEFAULT_CONTENT_COLOR; - this->focusedFrameColor = CURSESPP_FOCUSED_FRAME_COLOR; + this->contentColor = Color(Color::ContentColorDefault); + this->frameColor = Color(Color::FrameColorDefault); + this->focusedContentColor = Color(Color::ContentColorDefault); + this->focusedFrameColor = Color(Color::FrameColorFocused); this->drawFrame = true; this->isVisibleInParent = false; this->isFocused = false; @@ -178,19 +192,19 @@ void Window::SendToBottom() { } } -void Window::PostMessage(int messageType, int64_t user1, int64_t user2, int64_t delay) { +void Window::Post(int messageType, int64_t user1, int64_t user2, int64_t delay) { messageQueue.Post(Message::Create(this, messageType, user1, user2), delay); } -void Window::BroadcastMessage(int messageType, int64_t user1, int64_t user2, int64_t delay) { +void Window::Broadcast(int messageType, int64_t user1, int64_t user2, int64_t delay) { messageQueue.Broadcast(Message::Create(nullptr, messageType, user1, user2), delay); } -void Window::DebounceMessage(int messageType, int64_t user1, int64_t user2, int64_t delay) { +void Window::Debounce(int messageType, int64_t user1, int64_t user2, int64_t delay) { messageQueue.Debounce(Message::Create(this, messageType, user1, user2), delay); } -void Window::RemoveMessage(int messageType) { +void Window::Remove(int messageType) { messageQueue.Remove(this, messageType); } @@ -375,32 +389,36 @@ int Window::GetY() const { return this->y; } -void Window::SetContentColor(int64_t color) { - this->contentColor = (color == CURSESPP_DEFAULT_COLOR) - ? CURSESPP_DEFAULT_CONTENT_COLOR : color; +void Window::SetContentColor(Color color) { + this->contentColor = (color == Color::Default) + ? Color::ContentColorDefault : color; this->RepaintBackground(); + this->Redraw(); } -void Window::SetFocusedContentColor(int64_t color) { - this->focusedContentColor = (color == CURSESPP_DEFAULT_COLOR) - ? CURSESPP_DEFAULT_CONTENT_COLOR : color; +void Window::SetFocusedContentColor(Color color) { + this->focusedContentColor = (color == Color::Default) + ? Color::ContentColorDefault : color; this->RepaintBackground(); + this->Redraw(); } -void Window::SetFrameColor(int64_t color) { - this->frameColor = (color == CURSESPP_DEFAULT_COLOR) - ? CURSESPP_DEFAULT_FRAME_COLOR : color; +void Window::SetFrameColor(Color color) { + this->frameColor = (color == Color::Default) + ? Color::FrameColorDefault : color; this->RepaintBackground(); + this->Redraw(); } -void Window::SetFocusedFrameColor(int64_t color) { - this->focusedFrameColor = (color == CURSESPP_DEFAULT_COLOR) - ? CURSESPP_FOCUSED_FRAME_COLOR : color; +void Window::SetFocusedFrameColor(Color color) { + this->focusedFrameColor = (color == Color::Default) + ? Color::FrameColorFocused : color; this->RepaintBackground(); + this->Redraw(); } void Window::DrawFrameAndTitle() { @@ -424,19 +442,18 @@ void Window::RepaintBackground() { bool focused = IsFocused(); if (this->drawFrame && - this->frameColor != CURSESPP_DEFAULT_COLOR && + this->frameColor != Color::Default && this->frame && this->content != this->frame) { - wbkgd(this->frame, COLOR_PAIR(focused - ? this->focusedFrameColor : this->frameColor)); - + werase(this->frame); + wbkgd(this->frame, focused? this->focusedFrameColor : this->frameColor); this->DrawFrameAndTitle(); } if (this->content) { - wbkgd(this->content, COLOR_PAIR(focused - ? this->focusedContentColor : this->contentColor)); + werase(this->content); + wbkgd(this->content, focused ? this->focusedContentColor : this->contentColor); } this->Invalidate(); @@ -653,10 +670,7 @@ void Window::Create() { if (!this->drawFrame) { this->content = this->frame; - - if (currentContentColor != CURSESPP_DEFAULT_COLOR) { - wbkgd(this->frame, COLOR_PAIR(currentContentColor)); - } + this->RepaintBackground(); } /* otherwise we'll draw a box around the frame, and create a content @@ -677,15 +691,7 @@ void Window::Create() { } this->contentPanel = new_panel(this->content); - - if (currentFrameColor != CURSESPP_DEFAULT_COLOR) { - wbkgd(this->frame, COLOR_PAIR(currentFrameColor)); - } - - if (currentContentColor != CURSESPP_DEFAULT_COLOR) { - wbkgd(this->content, COLOR_PAIR(currentContentColor)); - } - + this->RepaintBackground(); this->DrawFrameAndTitle(); } @@ -767,11 +773,11 @@ void Window::Clear() { int64_t frameColor = isFocused ? this->focusedFrameColor : this->frameColor; if (this->content == this->frame) { - wbkgd(this->frame, COLOR_PAIR(contentColor)); + wbkgd(this->frame, contentColor); } else { - wbkgd(this->frame, COLOR_PAIR(frameColor)); - wbkgd(this->content, COLOR_PAIR(contentColor)); + wbkgd(this->frame, frameColor); + wbkgd(this->content, contentColor); } } diff --git a/src/musikcube/cursespp/Window.h b/src/musikcube/cursespp/Window.h index 00d2e75f0..a1e02c41c 100755 --- a/src/musikcube/cursespp/Window.h +++ b/src/musikcube/cursespp/Window.h @@ -71,15 +71,15 @@ namespace cursespp { virtual void Focus(); virtual void Blur(); - virtual void SetContentColor(int64_t color); - virtual void SetFrameColor(int64_t color); - virtual void SetFocusedContentColor(int64_t color); - virtual void SetFocusedFrameColor(int64_t color); + virtual void SetContentColor(Color color); + virtual void SetFrameColor(Color color); + virtual void SetFocusedContentColor(Color color); + virtual void SetFocusedFrameColor(Color color); - virtual int64_t GetContentColor() { return this->contentColor; } - virtual int64_t GetFrameColor() { return this->frameColor; } - virtual int64_t GetFocusedContentColor() { return this->focusedContentColor; } - virtual int64_t GetFocusedFrameColor() { return this->focusedFrameColor; } + virtual Color GetContentColor() { return this->contentColor; } + virtual Color GetFrameColor() { return this->frameColor; } + virtual Color GetFocusedContentColor() { return this->focusedContentColor; } + virtual Color GetFocusedFrameColor() { return this->focusedFrameColor; } virtual void SetSize(int width, int height); virtual void SetPosition(int x, int y); @@ -132,10 +132,10 @@ namespace cursespp { protected: - void BroadcastMessage(int messageType, int64_t user1 = 0, int64_t user2 = 0, int64_t delay = 0); - void PostMessage(int messageType, int64_t user1 = 0, int64_t user2 = 0, int64_t delay = 0); - void DebounceMessage(int messageType, int64_t user1 = 0, int64_t user2 = 0, int64_t delay = 0); - void RemoveMessage(int messageType); + void Broadcast(int messageType, int64_t user1 = 0, int64_t user2 = 0, int64_t delay = 0); + void Post(int messageType, int64_t user1 = 0, int64_t user2 = 0, int64_t delay = 0); + void Debounce(int messageType, int64_t user1 = 0, int64_t user2 = 0, int64_t delay = 0); + void Remove(int messageType); bool FocusInParent(); static INavigationKeys& NavigationKeys(); @@ -172,8 +172,8 @@ namespace cursespp { bool isVisibleInParent, isFocused, isDirty; int focusOrder; int id; - int64_t contentColor, frameColor; - int64_t focusedContentColor, focusedFrameColor; + Color contentColor, frameColor; + Color focusedContentColor, focusedFrameColor; std::string title; int width, height, x, y; int lastAbsoluteX, lastAbsoluteY; diff --git a/src/musikcube/cursespp/curses_config.h b/src/musikcube/cursespp/curses_config.h index c4095143d..102d87903 100755 --- a/src/musikcube/cursespp/curses_config.h +++ b/src/musikcube/cursespp/curses_config.h @@ -36,6 +36,7 @@ #ifdef WIN32 #define PDC_WIDE +#define PDC_FORCE_UTF8 #undef MOUSE_MOVED #endif diff --git a/src/musikcube/musikcube.vcxproj b/src/musikcube/musikcube.vcxproj index 87fedf979..28bdb5940 100755 --- a/src/musikcube/musikcube.vcxproj +++ b/src/musikcube/musikcube.vcxproj @@ -178,6 +178,7 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win32\font\*.ttf" "$(TargetDir)fonts\" /Y + @@ -244,6 +245,7 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win32\font\*.ttf" "$(TargetDir)fonts\" /Y + @@ -259,13 +261,14 @@ xcopy "$(SolutionDir)src\3rdparty\bin\win32\font\*.ttf" "$(TargetDir)fonts\" /Y - + + diff --git a/src/musikcube/musikcube.vcxproj.filters b/src/musikcube/musikcube.vcxproj.filters index d6366220d..62d0dac02 100755 --- a/src/musikcube/musikcube.vcxproj.filters +++ b/src/musikcube/musikcube.vcxproj.filters @@ -39,9 +39,6 @@ app\model - - cursespp - app\util @@ -63,9 +60,6 @@ app\overlay - - app\overlay - app\overlay @@ -78,78 +72,12 @@ app\util - - cursespp\window - - - cursespp\overlay - - - cursespp\overlay - - - cursespp\overlay - - - cursespp\overlay - - - cursespp\window - - - cursespp\window - - - cursespp\layout - - - cursespp\adapter - - - cursespp\adapter - - - cursespp\window - - - cursespp\window - - - cursespp\window - - - cursespp\window - - - cursespp\adapter - - - cursespp\adapter - - - cursespp\util - - - cursespp\util - - - cursespp\overlay - - - cursespp\util - - - cursespp\util - app\overlay app\overlay - - cursespp\util - app\layout @@ -159,9 +87,6 @@ app\overlay - - cursespp - app\layout @@ -174,36 +99,87 @@ app\overlay + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + app\overlay + - - cursespp - - - cursespp - - - cursespp - - - cursespp - - - cursespp - - - cursespp - - - cursespp - - - cursespp - - - cursespp - app\layout @@ -222,9 +198,6 @@ app\util - - cursespp - app\layout @@ -243,9 +216,6 @@ app\model - - cursespp - app\util @@ -261,24 +231,15 @@ app\util - - cursespp - app\overlay app\overlay - - cursespp - app\overlay - - app\overlay - app\overlay @@ -295,84 +256,12 @@ app\util - - cursespp\window - - - cursespp\overlay - - - cursespp\overlay - - - cursespp\overlay - - - cursespp\overlay - - - cursespp\window - - - cursespp\window - - - cursespp\layout - - - cursespp\overlay - - - cursespp\adapter - - - cursespp\adapter - - - cursespp\window - - - cursespp\window - - - cursespp\window - - - cursespp\window - - - cursespp\adapter - - - cursespp\adapter - - - cursespp\util - - - cursespp\util - - - cursespp\overlay - - - cursespp\util - - - cursespp\util - - - cursespp - app\overlay app\overlay - - cursespp\util - app\layout @@ -382,9 +271,6 @@ app\overlay - - cursespp - app\layout @@ -400,6 +286,129 @@ app\overlay + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + cursespp + + + app\overlay + @@ -423,21 +432,6 @@ {a84f242d-d70b-49e9-975e-63fc73954a2b} - - {3e0fdd20-9aa9-430c-b675-43a7906ee79e} - - - {c5e4f69d-5019-4f35-93e1-364bd6428841} - - - {efa39f43-ed8e-4772-a7d8-ed65ac4c6154} - - - {4a6b94ec-80fd-476a-b924-d7bc0495744a} - - - {adfba99d-6228-438a-9e4b-d3c4daf6202b} - diff --git a/src/plugins/supereqdsp/SuperEqDsp.cpp b/src/plugins/supereqdsp/SuperEqDsp.cpp index 89cdefc46..1d027a811 100644 --- a/src/plugins/supereqdsp/SuperEqDsp.cpp +++ b/src/plugins/supereqdsp/SuperEqDsp.cpp @@ -39,13 +39,11 @@ using namespace musik::core::sdk; static IPreferences* prefs = nullptr; static std::atomic currentState; -static const double LN_10 = 2.3025850929940002f; - static const std::vector BANDS = { "65", "92", "131", "185", "262", "370", "523", "740", "1047", "1480", "2093", "2960", "4186", "5920", "8372", - "11840", "16744" + "11840", "16744", "22000", }; extern "C" DLLEXPORT void SetPreferences(IPreferences* prefs) { @@ -85,11 +83,11 @@ bool SuperEqDsp::Process(IBuffer* buffer) { } void *params = paramlist_alloc(); - float bands[17]; + float bands[18]; for (size_t i = 0; i < BANDS.size(); i++) { double dB = prefs->GetDouble(BANDS[i].c_str(), 0.0); - double amp = exp(LN_10 * dB / 20.f); + double amp = pow(10, dB / 20.f); bands[i] = (float) amp; }