mirror of
https://github.com/clangen/musikcube.git
synced 2025-01-29 21:32:41 +00:00
- Added the ability to configure server settings in the app, as long as
the plugin is present and loaded. - Fixed some color-related bugs in Checkbox - Fixed some nasty bugs in Window that could cause views to be drawn outside of parent or screen bounds, leading to curses crashes - Added the ability for the app to get references to plugin preferences, so it can create settings windows for them - Fixed WebSocketServer so it can be shut down and restarted
This commit is contained in:
parent
f132f778f0
commit
6836af2aec
@ -98,23 +98,21 @@ static bool stringToFile(const std::string& fn, const std::string& str) {
|
||||
return (written == str.size());
|
||||
}
|
||||
|
||||
static std::string pluginFilename(std::string name) {
|
||||
name.erase(std::remove_if(name.begin(), name.end(), ::isspace), name.end());
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
name = "plugin_" + name; /* filename = nowhitespace(tolower(name)).json */
|
||||
return name;
|
||||
}
|
||||
|
||||
void Preferences::LoadPluginPreferences() {
|
||||
typedef void(*SetPreferencesPlugin)(musik::core::sdk::IPreferences*);
|
||||
|
||||
PluginFactory::Instance().QueryFunction<SetPreferencesPlugin>(
|
||||
"SetPreferences",
|
||||
[](musik::core::sdk::IPlugin* plugin, SetPreferencesPlugin func) {
|
||||
std::string name = plugin->Name();
|
||||
name.erase(std::remove_if(name.begin(), name.end(), ::isspace), name.end());
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
name = "plugin_" + name; /* filename = nowhitespace(tolower(name)).json */
|
||||
|
||||
if (pluginCache.find(name) == pluginCache.end()) {
|
||||
pluginCache[name] = std::shared_ptr<Preferences>(
|
||||
new Preferences(name, Preferences::ModeAutoSave));
|
||||
}
|
||||
|
||||
func(pluginCache[name].get());
|
||||
auto prefs = Preferences::ForPlugin(plugin->Name());
|
||||
func(prefs.get());
|
||||
});
|
||||
}
|
||||
|
||||
@ -122,6 +120,17 @@ void Preferences::SavePluginPreferences() {
|
||||
pluginCache.clear(); /* dtors will save */
|
||||
}
|
||||
|
||||
std::shared_ptr<Preferences> Preferences::ForPlugin(const std::string& pluginName) {
|
||||
std::string name = pluginFilename(pluginName);
|
||||
|
||||
if (pluginCache.find(name) == pluginCache.end()) {
|
||||
pluginCache[name] = std::shared_ptr<Preferences>(
|
||||
new Preferences(name, Preferences::ModeAutoSave));
|
||||
}
|
||||
|
||||
return pluginCache[name];
|
||||
}
|
||||
|
||||
std::shared_ptr<Preferences> Preferences::ForComponent(
|
||||
const std::string& c, Preferences::Mode mode)
|
||||
{
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include <core/config.h>
|
||||
#include <core/db/Connection.h>
|
||||
#include <core/sdk/IPreferences.h>
|
||||
|
||||
#include <json.hpp>
|
||||
|
||||
namespace musik { namespace core {
|
||||
@ -56,6 +55,9 @@ namespace musik { namespace core {
|
||||
static void LoadPluginPreferences();
|
||||
static void SavePluginPreferences();
|
||||
|
||||
static std::shared_ptr<Preferences>
|
||||
ForPlugin(const std::string& pluginName);
|
||||
|
||||
static std::shared_ptr<Preferences>
|
||||
ForComponent(const std::string& c, Mode mode = ModeAutoSave);
|
||||
|
||||
|
@ -15,6 +15,7 @@ set (BOX_SRCS
|
||||
./app/overlay/PlaybackOverlays.cpp
|
||||
./app/overlay/PlayQueueOverlays.cpp
|
||||
./app/overlay/PluginOverlay.cpp
|
||||
./app/overlay/ServerOverlay.cpp
|
||||
./app/overlay/VisualizerOverlay.cpp
|
||||
./app/util/Hotkeys.cpp
|
||||
./app/util/GlobalHotkeys.cpp
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include <app/overlay/LocaleOverlay.h>
|
||||
#include <app/overlay/PlaybackOverlays.h>
|
||||
#include <app/overlay/PluginOverlay.h>
|
||||
#include <app/overlay/ServerOverlay.h>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
@ -99,16 +100,17 @@ SettingsLayout::SettingsLayout(
|
||||
musik::core::ILibraryPtr library,
|
||||
musik::core::sdk::IPlaybackService& playback,
|
||||
musik::glue::audio::MasterTransport& transport)
|
||||
: LayoutBase()
|
||||
, app(app)
|
||||
, library(library)
|
||||
, indexer(library->Indexer())
|
||||
, transport(transport)
|
||||
, playback(playback)
|
||||
, pathsUpdated(false) {
|
||||
: LayoutBase()
|
||||
, app(app)
|
||||
, library(library)
|
||||
, indexer(library->Indexer())
|
||||
, transport(transport)
|
||||
, playback(playback)
|
||||
, pathsUpdated(false) {
|
||||
this->prefs = Preferences::ForComponent(core::prefs::components::Settings);
|
||||
this->browseAdapter.reset(new DirectoryAdapter());
|
||||
this->addedPathsAdapter.reset(new SimpleScrollAdapter());
|
||||
this->UpdateServerAvailability();
|
||||
this->InitializeWindows();
|
||||
}
|
||||
|
||||
@ -201,6 +203,10 @@ void SettingsLayout::OnHotkeyDropdownActivate(cursespp::TextLabel* label) {
|
||||
App::Overlays().Push(overlay);
|
||||
}
|
||||
|
||||
void SettingsLayout::OnServerDropdownActivate(cursespp::TextLabel* label) {
|
||||
ServerOverlay::Show([this]() { /* nothing, for now */ });
|
||||
}
|
||||
|
||||
void SettingsLayout::OnThemeDropdownActivate(cursespp::TextLabel* label) {
|
||||
ColorThemeOverlay::Show([this]() { this->LoadPreferences(); });
|
||||
}
|
||||
@ -238,6 +244,10 @@ void SettingsLayout::OnLayout() {
|
||||
this->themeDropdown->MoveAndResize(column1, y++, columnCx, LABEL_HEIGHT);
|
||||
this->hotkeyDropdown->MoveAndResize(column1, y++, columnCx, LABEL_HEIGHT);
|
||||
|
||||
if (serverAvailable) {
|
||||
this->serverDropdown->MoveAndResize(column1, y++, columnCx, LABEL_HEIGHT);
|
||||
}
|
||||
|
||||
y = BOTTOM(this->browseList);
|
||||
#ifdef ENABLE_256_COLOR_OPTION
|
||||
this->paletteCheckbox->MoveAndResize(column2, y++, columnCx, LABEL_HEIGHT);
|
||||
@ -329,6 +339,12 @@ void SettingsLayout::InitializeWindows() {
|
||||
this->hotkeyDropdown->SetText(arrow + _TSTR("settings_hotkey_tester"));
|
||||
this->hotkeyDropdown->Activated.connect(this, &SettingsLayout::OnHotkeyDropdownActivate);
|
||||
|
||||
if (this->serverAvailable) {
|
||||
this->serverDropdown.reset(new TextLabel());
|
||||
this->serverDropdown->SetText(arrow + _TSTR("settings_server_setup"));
|
||||
this->serverDropdown->Activated.connect(this, &SettingsLayout::OnServerDropdownActivate);
|
||||
}
|
||||
|
||||
CREATE_CHECKBOX(this->dotfileCheckbox, _TSTR("settings_show_dotfiles"));
|
||||
CREATE_CHECKBOX(this->syncOnStartupCheckbox, _TSTR("settings_sync_on_startup"));
|
||||
CREATE_CHECKBOX(this->removeCheckbox, _TSTR("settings_remove_missing"));
|
||||
@ -351,6 +367,11 @@ void SettingsLayout::InitializeWindows() {
|
||||
this->pluginsDropdown->SetFocusOrder(order++);
|
||||
this->themeDropdown->SetFocusOrder(order++);
|
||||
this->hotkeyDropdown->SetFocusOrder(order++);
|
||||
|
||||
if (this->serverAvailable) {
|
||||
this->serverDropdown->SetFocusOrder(order++);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_256_COLOR_OPTION
|
||||
this->paletteCheckbox->SetFocusOrder(order++);
|
||||
#endif
|
||||
@ -372,6 +393,11 @@ void SettingsLayout::InitializeWindows() {
|
||||
this->AddWindow(this->transportDropdown);
|
||||
this->AddWindow(this->pluginsDropdown);
|
||||
this->AddWindow(this->themeDropdown);
|
||||
|
||||
if (this->serverAvailable) {
|
||||
this->AddWindow(this->serverDropdown);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_256_COLOR_OPTION
|
||||
this->AddWindow(this->paletteCheckbox);
|
||||
#endif
|
||||
@ -526,6 +552,10 @@ void SettingsLayout::DrillIntoSelectedDirectory() {
|
||||
this->browseList->ScrollTo(selectIndexAt);
|
||||
}
|
||||
|
||||
void SettingsLayout::UpdateServerAvailability() {
|
||||
this->serverAvailable = !!ServerOverlay::FindServerPlugin().get();
|
||||
}
|
||||
|
||||
bool SettingsLayout::KeyPress(const std::string& key) {
|
||||
if (key == "KEY_ENTER") {
|
||||
if (this->GetFocus() == this->browseList) {
|
||||
|
@ -93,6 +93,7 @@ namespace musik {
|
||||
void RemoveSelectedDirectory();
|
||||
void DrillIntoSelectedDirectory();
|
||||
void CheckShowFirstRunDialog();
|
||||
void UpdateServerAvailability();
|
||||
|
||||
void OnCheckboxChanged(
|
||||
cursespp::Checkbox* checkbox, bool checked);
|
||||
@ -103,6 +104,7 @@ namespace musik {
|
||||
void OnHotkeyDropdownActivate(cursespp::TextLabel* label);
|
||||
void OnThemeDropdownActivate(cursespp::TextLabel* label);
|
||||
void OnLocaleDropdownActivate(cursespp::TextLabel* label);
|
||||
void OnServerDropdownActivate(cursespp::TextLabel* label);
|
||||
|
||||
int64_t ListItemDecorator(
|
||||
cursespp::ScrollableWindow* w,
|
||||
@ -123,6 +125,7 @@ namespace musik {
|
||||
std::shared_ptr<cursespp::TextLabel> transportDropdown;
|
||||
std::shared_ptr<cursespp::TextLabel> pluginsDropdown;
|
||||
std::shared_ptr<cursespp::TextLabel> hotkeyDropdown;
|
||||
std::shared_ptr<cursespp::TextLabel> serverDropdown;
|
||||
|
||||
std::shared_ptr<cursespp::TextLabel> themeDropdown;
|
||||
std::shared_ptr<cursespp::Checkbox> paletteCheckbox;
|
||||
@ -145,6 +148,7 @@ namespace musik {
|
||||
std::shared_ptr<DirectoryAdapter> browseAdapter;
|
||||
|
||||
bool pathsUpdated = false;
|
||||
bool serverAvailable = false;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
326
src/musikbox/app/overlay/ServerOverlay.cpp
Normal file
326
src/musikbox/app/overlay/ServerOverlay.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "ServerOverlay.h"
|
||||
|
||||
#include <core/plugin/PluginFactory.h>
|
||||
#include <core/i18n/Locale.h>
|
||||
|
||||
#include <app/util/PreferenceKeys.h>
|
||||
|
||||
#include <cursespp/App.h>
|
||||
#include <cursespp/DialogOverlay.h>
|
||||
#include <cursespp/Screen.h>
|
||||
|
||||
using namespace musik;
|
||||
using namespace musik::core;
|
||||
using namespace musik::core::sdk;
|
||||
using namespace musik::box;
|
||||
using namespace cursespp;
|
||||
|
||||
static const std::string WEBSOCKET_PLUGIN_GUID = "9fc897a3-dfd5-4524-a0fc-b02f46aea4a9";
|
||||
static const char* KEY_METADATA_SERVER_ENABLED = "websocket_server_enabled";
|
||||
static const char* KEY_METADATA_SERVER_PORT = "websocket_server_port";
|
||||
static const char* KEY_AUDIO_SERVER_ENABLED = "http_server_enabled";
|
||||
static const char* KEY_AUDIO_SERVER_PORT = "http_server_port";
|
||||
static const char* KEY_TRANSCODER_CACHE_COUNT = "transcoder_cache_count";
|
||||
static const char* KEY_TRANSCODER_SYNCHRONOUS = "transcoder_synchronous";
|
||||
static const char* KEY_PASSWORD = "password";
|
||||
|
||||
#define VERTICAL_PADDING 1
|
||||
#define DEFAULT_HEIGHT 18
|
||||
#define DEFAULT_WIDTH 45
|
||||
#define PORT_INPUT_WIDTH 10
|
||||
#define PORT_INPUT_HEIGHT 3
|
||||
|
||||
#define STYLE_OVERLAY_LABEL(x) \
|
||||
x->SetContentColor(CURSESPP_OVERLAY_CONTENT);
|
||||
|
||||
#define STYLE_OVERLAY_CHECKBOX(x) \
|
||||
x->SetContentColor(CURSESPP_OVERLAY_CONTENT); \
|
||||
x->SetFocusedContentColor(CURSESPP_OVERLAY_TEXT_FOCUSED);
|
||||
|
||||
#define STYLE_OVERLAY_INPUT(x) \
|
||||
x->SetFrameColor(CURSESPP_OVERLAY_FRAME); \
|
||||
x->SetContentColor(CURSESPP_OVERLAY_CONTENT); \
|
||||
x->SetFocusedFrameColor(CURSESPP_OVERLAY_INPUT_FRAME); \
|
||||
x->SetFocusedContentColor(CURSESPP_OVERLAY_CONTENT);
|
||||
|
||||
#define RIGHT(x) (x->GetX() + x->GetWidth())
|
||||
#define TEXT_WIDTH(x) ((int) u8cols(x->GetText()))
|
||||
|
||||
#ifdef WIN32
|
||||
#define SAVE_KEY "^S"
|
||||
#else
|
||||
#define SAVE_KEY "M-s"
|
||||
#endif
|
||||
|
||||
using Callback = ServerOverlay::Callback;
|
||||
using Prefs = ServerOverlay::Prefs;
|
||||
|
||||
static std::string settingIntToString(Prefs prefs, const std::string& key, int defaultValue) {
|
||||
int resolved = prefs->GetInt(key, defaultValue);
|
||||
try {
|
||||
return std::to_string(resolved);
|
||||
}
|
||||
catch (...) {
|
||||
return std::to_string(defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
static void showInvalidDialog(Callback cb = Callback()) {
|
||||
std::shared_ptr<DialogOverlay> dialog(new DialogOverlay());
|
||||
|
||||
(*dialog)
|
||||
.SetTitle(_TSTR("settings_server_invalid_settings_title"))
|
||||
.SetMessage(_TSTR("settings_server_invalid_settings_message"))
|
||||
.AddButton("KEY_ENTER", "ENTER", _TSTR("button_ok"), [cb](std::string key) {
|
||||
if (cb) {
|
||||
cb();
|
||||
}
|
||||
});
|
||||
|
||||
App::Overlays().Push(dialog);
|
||||
}
|
||||
|
||||
static int getIntFromTextInput(TextInput* input) {
|
||||
const std::string value = input->GetText();
|
||||
if (value.size()) {
|
||||
try {
|
||||
return std::stoi(value);
|
||||
}
|
||||
catch (...) {
|
||||
/* swallow */
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
ServerOverlay::ServerOverlay(Callback callback, Plugin plugin)
|
||||
: OverlayBase() {
|
||||
this->callback = callback;
|
||||
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();
|
||||
}
|
||||
|
||||
void ServerOverlay::InitViews() {
|
||||
/* title */
|
||||
this->titleLabel.reset(new TextLabel());
|
||||
this->titleLabel->SetText(_TSTR("settings_server_setup"), text::AlignCenter);
|
||||
|
||||
/* shortcuts */
|
||||
this->shortcuts.reset(new ShortcutsWindow());
|
||||
this->shortcuts->SetAlignment(text::AlignRight);
|
||||
this->shortcuts->AddShortcut("ESC", _TSTR("button_cancel"));
|
||||
this->shortcuts->AddShortcut(SAVE_KEY, _TSTR("button_save"));
|
||||
|
||||
/* web socket server */
|
||||
this->enableWssCb.reset(new Checkbox());
|
||||
this->enableWssCb->SetText(_TSTR("settings_server_enable_websockets"));
|
||||
|
||||
this->wssPortLabel.reset(new TextLabel());
|
||||
this->wssPortLabel->SetText(_TSTR("settings_server_metadata_port"), text::AlignRight);
|
||||
this->wssPortInput.reset(new TextInput());
|
||||
|
||||
/* http server */
|
||||
this->enableHttpCb.reset(new Checkbox());
|
||||
this->enableHttpCb->SetText(_TSTR("settings_server_enable_http"));
|
||||
this->httpPortLabel.reset(new TextLabel());
|
||||
this->httpPortLabel->SetText(_TSTR("settings_server_audio_port"), text::AlignRight);
|
||||
this->httpPortInput.reset(new TextInput());
|
||||
|
||||
/* transcoder */
|
||||
this->enableSyncTransCb.reset(new Checkbox());
|
||||
this->enableSyncTransCb->SetText(_TSTR("settings_server_transcoder_synchronous"));
|
||||
|
||||
/* password */
|
||||
this->pwLabel.reset(new TextLabel());
|
||||
this->pwLabel->SetText(_TSTR("settings_server_password"), text::AlignRight);
|
||||
this->pwInput.reset(new TextInput(IInput::InputPassword));
|
||||
|
||||
/* style 'em */
|
||||
STYLE_OVERLAY_LABEL(this->titleLabel);
|
||||
STYLE_OVERLAY_CHECKBOX(this->enableWssCb);
|
||||
STYLE_OVERLAY_LABEL(this->wssPortLabel);
|
||||
STYLE_OVERLAY_INPUT(this->wssPortInput);
|
||||
STYLE_OVERLAY_CHECKBOX(this->enableHttpCb);
|
||||
STYLE_OVERLAY_LABEL(this->httpPortLabel);
|
||||
STYLE_OVERLAY_INPUT(this->httpPortInput);
|
||||
STYLE_OVERLAY_CHECKBOX(this->enableSyncTransCb);
|
||||
STYLE_OVERLAY_LABEL(this->pwLabel);
|
||||
STYLE_OVERLAY_INPUT(this->pwInput);
|
||||
|
||||
/* add 'em */
|
||||
this->AddWindow(this->titleLabel);
|
||||
this->AddWindow(this->enableWssCb);
|
||||
this->AddWindow(this->enableHttpCb);
|
||||
this->AddWindow(this->enableSyncTransCb);
|
||||
this->AddWindow(this->wssPortLabel);
|
||||
this->AddWindow(this->wssPortInput);
|
||||
this->AddWindow(this->httpPortLabel);
|
||||
this->AddWindow(this->httpPortInput);
|
||||
this->AddWindow(this->pwLabel);
|
||||
this->AddWindow(this->pwInput);
|
||||
this->AddWindow(this->shortcuts);
|
||||
|
||||
/* focus order */
|
||||
int order = 0;
|
||||
this->enableWssCb->SetFocusOrder(order++);
|
||||
this->enableHttpCb->SetFocusOrder(order++);
|
||||
this->enableSyncTransCb->SetFocusOrder(order++);
|
||||
this->wssPortInput->SetFocusOrder(order++);
|
||||
this->httpPortInput->SetFocusOrder(order++);
|
||||
this->pwInput->SetFocusOrder(order++);
|
||||
}
|
||||
|
||||
void ServerOverlay::Layout() {
|
||||
this->RecalculateSize();
|
||||
this->MoveAndResize(this->x, this->y, this->width, this->height);
|
||||
|
||||
auto clientHeight = this->GetContentHeight();
|
||||
auto clientWidth = this->GetContentWidth();
|
||||
|
||||
this->titleLabel->MoveAndResize(0, 0, clientWidth, 1);
|
||||
this->shortcuts->MoveAndResize(0, clientHeight - 1, clientWidth, 1);
|
||||
|
||||
int x = 1;
|
||||
int y = 2;
|
||||
clientWidth -= 2;
|
||||
|
||||
int labelWidth = std::max(TEXT_WIDTH(this->wssPortLabel), TEXT_WIDTH(this->httpPortLabel));
|
||||
labelWidth = std::max(labelWidth, TEXT_WIDTH(this->pwLabel));
|
||||
int inputWidth = clientWidth - labelWidth - 1;
|
||||
|
||||
this->enableWssCb->MoveAndResize(x, y++, clientWidth, 1);
|
||||
this->enableHttpCb->MoveAndResize(x, y++, clientWidth, 1);
|
||||
this->enableSyncTransCb->MoveAndResize(x, y++, clientWidth, 1);
|
||||
|
||||
this->wssPortLabel->MoveAndResize(x, y + 1, labelWidth, 1);
|
||||
this->wssPortInput->MoveAndResize(labelWidth + 2, y, inputWidth, PORT_INPUT_HEIGHT);
|
||||
y += 3;
|
||||
|
||||
this->httpPortLabel->MoveAndResize(x, y + 1, labelWidth, 1);
|
||||
this->httpPortInput->MoveAndResize(labelWidth + 2, y, inputWidth, PORT_INPUT_HEIGHT);
|
||||
y += 3;
|
||||
|
||||
this->pwLabel->MoveAndResize(x, y + 1, labelWidth, 1);
|
||||
this->pwInput->MoveAndResize(labelWidth + 2, y, inputWidth, PORT_INPUT_HEIGHT);
|
||||
}
|
||||
|
||||
void ServerOverlay::Show(Callback callback) {
|
||||
Plugin plugin = FindServerPlugin();
|
||||
std::shared_ptr<ServerOverlay> overlay(new ServerOverlay(callback, plugin));
|
||||
App::Overlays().Push(overlay);
|
||||
}
|
||||
|
||||
std::shared_ptr<IPlugin> ServerOverlay::FindServerPlugin() {
|
||||
std::shared_ptr<IPlugin> result;
|
||||
using Deleter = PluginFactory::DestroyDeleter<IPlugin>;
|
||||
PluginFactory::Instance().QueryInterface<IPlugin, Deleter>(
|
||||
"GetPlugin",
|
||||
[&result](std::shared_ptr<IPlugin> plugin, const std::string& fn) {
|
||||
if (std::string(plugin->Guid()) == WEBSOCKET_PLUGIN_GUID) {
|
||||
result = plugin;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void ServerOverlay::Load() {
|
||||
this->enableWssCb->SetChecked(prefs->GetBool(KEY_METADATA_SERVER_ENABLED, false));
|
||||
this->enableHttpCb->SetChecked(prefs->GetBool(KEY_AUDIO_SERVER_ENABLED, false));
|
||||
this->enableSyncTransCb->SetChecked(prefs->GetBool(KEY_TRANSCODER_SYNCHRONOUS, false));
|
||||
|
||||
this->wssPortInput->SetText(settingIntToString(prefs, KEY_METADATA_SERVER_PORT, 7905));
|
||||
this->httpPortInput->SetText(settingIntToString(prefs, KEY_AUDIO_SERVER_PORT, 7906));
|
||||
this->pwInput->SetText(prefs->GetString(KEY_PASSWORD, ""));
|
||||
}
|
||||
|
||||
bool ServerOverlay::Save() {
|
||||
int wssPort = getIntFromTextInput(this->wssPortInput.get());
|
||||
int httpPort = getIntFromTextInput(this->httpPortInput.get());
|
||||
|
||||
if (wssPort <= 0 || httpPort <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this->prefs->SetBool(KEY_METADATA_SERVER_ENABLED, this->enableWssCb->IsChecked());
|
||||
this->prefs->SetBool(KEY_AUDIO_SERVER_ENABLED, this->enableHttpCb->IsChecked());
|
||||
this->prefs->SetBool(KEY_TRANSCODER_SYNCHRONOUS, this->enableSyncTransCb->IsChecked());
|
||||
this->prefs->SetInt(KEY_METADATA_SERVER_PORT, wssPort);
|
||||
this->prefs->SetInt(KEY_AUDIO_SERVER_PORT, httpPort);
|
||||
this->prefs->SetString(KEY_PASSWORD, this->pwInput->GetText().c_str());
|
||||
|
||||
this->prefs->Save();
|
||||
this->plugin->Reload();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ServerOverlay::KeyPress(const std::string& key) {
|
||||
if (key == "^[") { /* esc closes */
|
||||
this->Dismiss();
|
||||
return true;
|
||||
}
|
||||
else if (key == SAVE_KEY) {
|
||||
if (Save()) {
|
||||
this->Dismiss();
|
||||
}
|
||||
else {
|
||||
showInvalidDialog();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return OverlayBase::KeyPress(key);
|
||||
}
|
||||
|
||||
void ServerOverlay::RecalculateSize() {
|
||||
this->width = _DIMEN("server_overlay_width", DEFAULT_WIDTH);
|
||||
this->height = std::max(0, std::min(Screen::GetHeight() - 2, DEFAULT_HEIGHT));
|
||||
this->width = std::max(0, std::min(Screen::GetWidth(), this->width));
|
||||
|
||||
this->y = VERTICAL_PADDING;
|
||||
this->x = (Screen::GetWidth() / 2) - (this->width / 2);
|
||||
}
|
86
src/musikbox/app/overlay/ServerOverlay.h
Normal file
86
src/musikbox/app/overlay/ServerOverlay.h
Normal file
@ -0,0 +1,86 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2007-2016 musikcube team
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// * Neither the name of the author nor the names of other contributors may
|
||||
// be used to endorse or promote products derived from this software
|
||||
// without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include <core/sdk/IPlugin.h>
|
||||
#include <core/support/Preferences.h>
|
||||
|
||||
#include <cursespp/Checkbox.h>
|
||||
#include <cursespp/TextInput.h>
|
||||
#include <cursespp/TextLabel.h>
|
||||
#include <cursespp/OverlayBase.h>
|
||||
#include <cursespp/ShortcutsWindow.h>
|
||||
|
||||
namespace musik {
|
||||
namespace box {
|
||||
class ServerOverlay : public cursespp::OverlayBase, public sigslot::has_slots<>
|
||||
#if (__clang_major__ == 7 && __clang_minor__ == 3)
|
||||
, public std::enable_shared_from_this<ServerOverlay>
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
using Callback = std::function<void()>;
|
||||
using Plugin = std::shared_ptr<musik::core::sdk::IPlugin>;
|
||||
using Prefs = std::shared_ptr<musik::core::Preferences>;
|
||||
|
||||
static void Show(Callback callback);
|
||||
static std::shared_ptr<musik::core::sdk::IPlugin> FindServerPlugin();
|
||||
|
||||
virtual void Layout();
|
||||
virtual bool KeyPress(const std::string& key);
|
||||
|
||||
private:
|
||||
ServerOverlay(Callback callback, Plugin plugin);
|
||||
|
||||
void RecalculateSize();
|
||||
void InitViews();
|
||||
bool Save();
|
||||
void Load();
|
||||
|
||||
Callback callback;
|
||||
Plugin plugin;
|
||||
Prefs prefs;
|
||||
int width, height, x, y;
|
||||
|
||||
std::shared_ptr<cursespp::TextLabel> titleLabel;
|
||||
std::shared_ptr<cursespp::Checkbox> enableWssCb, enableHttpCb, enableSyncTransCb;
|
||||
std::shared_ptr<cursespp::TextLabel> wssPortLabel, httpPortLabel, pwLabel;
|
||||
std::shared_ptr<cursespp::TextInput> wssPortInput, httpPortInput, pwInput;
|
||||
std::shared_ptr<cursespp::ShortcutsWindow> shortcuts;
|
||||
};
|
||||
}
|
||||
}
|
@ -49,6 +49,7 @@ Checkbox::Checkbox()
|
||||
: Window()
|
||||
, checked(false) {
|
||||
this->SetFrameVisible(false);
|
||||
this->SetFocusedContentColor(CURSESPP_TEXT_FOCUSED);
|
||||
}
|
||||
|
||||
Checkbox::~Checkbox() {
|
||||
@ -81,7 +82,9 @@ void Checkbox::OnRedraw() {
|
||||
std::string symbol = (this->checked ? CHECKED : UNCHECKED);
|
||||
std::string ellipsized = text::Ellipsize(symbol + " " + this->buffer, cx);
|
||||
|
||||
int64_t attrs = this->IsFocused() ? CURSESPP_TEXT_FOCUSED : CURSESPP_DEFAULT_COLOR;
|
||||
int64_t attrs = this->IsFocused()
|
||||
? this->GetFocusedContentColor()
|
||||
: this->GetContentColor();
|
||||
|
||||
if (attrs != -1) {
|
||||
wattron(c, COLOR_PAIR(attrs));
|
||||
|
@ -54,26 +54,27 @@ indicies we'll use to store them */
|
||||
#define THEME_COLOR_OVERLAY_FOREGROUND 26
|
||||
#define THEME_COLOR_OVERLAY_BORDER 27
|
||||
#define THEME_COLOR_OVERLAY_FOCUSED_BORDER 28
|
||||
#define THEME_COLOR_SHORTCUTS_BACKGROUND 29
|
||||
#define THEME_COLOR_SHORTCUTS_FOREGROUND 30
|
||||
#define THEME_COLOR_SHORTCUTS_BACKGROUND_FOCUSED 31
|
||||
#define THEME_COLOR_SHORTCUTS_FOREGROUND_FOCUSED 32
|
||||
#define THEME_COLOR_BUTTON_BACKGROUND_NORMAL 33
|
||||
#define THEME_COLOR_BUTTON_FOREGROUND_NORMAL 34
|
||||
#define THEME_COLOR_BUTTON_BACKGROUND_ACTIVE 35
|
||||
#define THEME_COLOR_BUTTON_FOREGROUND_ACTIVE 36
|
||||
#define THEME_COLOR_BANNER_BACKGROUND 37
|
||||
#define THEME_COLOR_BANNER_FOREGROUND 38
|
||||
#define THEME_COLOR_LIST_HEADER_BACKGROUND 39
|
||||
#define THEME_COLOR_LIST_HEADER_FOREGROUND 40
|
||||
#define THEME_COLOR_LIST_HEADER_HIGHLIGHTED_BACKGROUND 41
|
||||
#define THEME_COLOR_LIST_HEADER_HIGHLIGHTED_FOREGROUND 42
|
||||
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND 43
|
||||
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND 44
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_BACKGROUND 45
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_FOREGROUND 46
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_BACKGROUND 47
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_FOREGROUND 48
|
||||
#define THEME_COLOR_OVERLAY_FOCUSED_TEXT 29
|
||||
#define THEME_COLOR_SHORTCUTS_BACKGROUND 30
|
||||
#define THEME_COLOR_SHORTCUTS_FOREGROUND 31
|
||||
#define THEME_COLOR_SHORTCUTS_BACKGROUND_FOCUSED 32
|
||||
#define THEME_COLOR_SHORTCUTS_FOREGROUND_FOCUSED 33
|
||||
#define THEME_COLOR_BUTTON_BACKGROUND_NORMAL 34
|
||||
#define THEME_COLOR_BUTTON_FOREGROUND_NORMAL 35
|
||||
#define THEME_COLOR_BUTTON_BACKGROUND_ACTIVE 36
|
||||
#define THEME_COLOR_BUTTON_FOREGROUND_ACTIVE 37
|
||||
#define THEME_COLOR_BANNER_BACKGROUND 38
|
||||
#define THEME_COLOR_BANNER_FOREGROUND 39
|
||||
#define THEME_COLOR_LIST_HEADER_BACKGROUND 40
|
||||
#define THEME_COLOR_LIST_HEADER_FOREGROUND 41
|
||||
#define THEME_COLOR_LIST_HEADER_HIGHLIGHTED_BACKGROUND 42
|
||||
#define THEME_COLOR_LIST_HEADER_HIGHLIGHTED_FOREGROUND 43
|
||||
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_BACKGROUND 44
|
||||
#define THEME_COLOR_LIST_ITEM_HIGHLIGHTED_FOREGROUND 45
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_BACKGROUND 46
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_FOREGROUND 47
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_BACKGROUND 48
|
||||
#define THEME_COLOR_LIST_ITEM_ACTIVE_HIGHLIGHTED_FOREGROUND 49
|
||||
|
||||
/* user-readable names for the color identifiers above. these are
|
||||
used as key names in the config files */
|
||||
@ -90,6 +91,7 @@ used as key names in the config files */
|
||||
#define JSON_KEY_COLOR_OVERLAY_FOREGROUND "overlay_foreground"
|
||||
#define JSON_KEY_COLOR_OVERLAY_BORDER "overlay_border"
|
||||
#define JSON_KEY_COLOR_OVERLAY_FOCUSED_BORDER "overlay_focused_border"
|
||||
#define JSON_KEY_COLOR_OVERLAY_FOCUSED_TEXT "overlay_focused_text"
|
||||
#define JSON_KEY_COLOR_SHORTCUTS_BACKGROUND "shortcuts_background"
|
||||
#define JSON_KEY_COLOR_SHORTCUTS_FOREGROUND "shortcuts_foreground"
|
||||
#define JSON_KEY_COLOR_SHORTCUTS_BACKGROUND_FOCUSED "shortcuts_background_focused"
|
||||
@ -266,6 +268,7 @@ struct Theme {
|
||||
overlayForeground.Set(THEME_COLOR_OVERLAY_FOREGROUND, 220, 220, 220, COLOR_256_OFFWHITE);
|
||||
overlayBorder.Set(THEME_COLOR_OVERLAY_BORDER, 102, 217, 238, COLOR_256_BLUE);
|
||||
overlayFocusedBorder.Set(THEME_COLOR_OVERLAY_FOCUSED_BORDER, 220, 82, 86, COLOR_256_RED);
|
||||
overlayFocusedText.Set(THEME_COLOR_OVERLAY_FOCUSED_TEXT, 220, 82, 86, COLOR_256_RED);
|
||||
|
||||
/* shortcut bar */
|
||||
shortcutsBackground.Set(THEME_COLOR_SHORTCUTS_BACKGROUND, 66, 66, 56, COLOR_256_MEDIUM_GRAY);
|
||||
@ -330,6 +333,7 @@ struct Theme {
|
||||
this->overlayForeground.Set(colors.value(JSON_KEY_COLOR_OVERLAY_FOREGROUND, unset));
|
||||
this->overlayBorder.Set(colors.value(JSON_KEY_COLOR_OVERLAY_BORDER, unset));
|
||||
this->overlayFocusedBorder.Set(colors.value(JSON_KEY_COLOR_OVERLAY_FOCUSED_BORDER, unset));
|
||||
this->overlayFocusedText.Set(colors.value(JSON_KEY_COLOR_OVERLAY_FOCUSED_TEXT, unset));
|
||||
this->shortcutsBackground.Set(colors.value(JSON_KEY_COLOR_SHORTCUTS_BACKGROUND, unset));
|
||||
this->shortcutsForeground.Set(colors.value(JSON_KEY_COLOR_SHORTCUTS_FOREGROUND, unset));
|
||||
this->focusedShortcutsBackground.Set(colors.value(JSON_KEY_COLOR_SHORTCUTS_BACKGROUND_FOCUSED, unset));
|
||||
@ -387,6 +391,7 @@ struct Theme {
|
||||
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);
|
||||
|
||||
/* shortcuts */
|
||||
init_pair(
|
||||
@ -466,6 +471,7 @@ struct Theme {
|
||||
Color overlayForeground;
|
||||
Color overlayBorder;
|
||||
Color overlayFocusedBorder;
|
||||
Color overlayFocusedText;
|
||||
|
||||
/* shortcut bar */
|
||||
Color shortcutsBackground;
|
||||
|
@ -66,8 +66,9 @@
|
||||
#define CURSESPP_OVERLAY_FRAME 21
|
||||
#define CURSESPP_OVERLAY_CONTENT 22
|
||||
#define CURSESPP_OVERLAY_INPUT_FRAME 23
|
||||
#define CURSESPP_OVERLAY_TEXT_FOCUSED 24
|
||||
|
||||
#define CURSESPP_BANNER 24
|
||||
#define CURSESPP_BANNER 25
|
||||
|
||||
namespace cursespp {
|
||||
class Colors {
|
||||
|
@ -41,7 +41,8 @@ namespace cursespp {
|
||||
public:
|
||||
enum InputMode {
|
||||
InputRaw,
|
||||
InputNormal
|
||||
InputNormal,
|
||||
InputPassword
|
||||
};
|
||||
|
||||
virtual ~IInput() { }
|
||||
|
@ -348,7 +348,10 @@ IWindowPtr LayoutBase::FocusLast() {
|
||||
|
||||
IWindowPtr LayoutBase::GetFocus() {
|
||||
if (this->focused >= 0 && this->focusable.size() > 0) {
|
||||
return this->focusable[this->focused];
|
||||
auto view = this->focusable[this->focused];
|
||||
if (view->IsVisible()) {
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
return IWindowPtr();
|
||||
|
@ -41,6 +41,10 @@
|
||||
namespace cursespp {
|
||||
class OverlayBase : public LayoutBase, public IOverlay {
|
||||
public:
|
||||
OverlayBase() : LayoutBase() {
|
||||
|
||||
}
|
||||
|
||||
virtual ~OverlayBase() {
|
||||
this->stack = nullptr;
|
||||
}
|
||||
|
@ -67,7 +67,8 @@ TextInput::TextInput(IInput::InputMode inputMode)
|
||||
: Window()
|
||||
, bufferLength(0)
|
||||
, position(0)
|
||||
, inputMode(inputMode) {
|
||||
, inputMode(inputMode)
|
||||
, enterEnabled(true) {
|
||||
}
|
||||
|
||||
TextInput::~TextInput() {
|
||||
@ -76,7 +77,20 @@ TextInput::~TextInput() {
|
||||
void TextInput::OnRedraw() {
|
||||
WINDOW* c = this->GetContent();
|
||||
werase(c);
|
||||
waddstr(c, buffer.c_str());
|
||||
|
||||
if (buffer.size()) {
|
||||
if (inputMode == InputPassword) {
|
||||
size_t count = u8cols(buffer);
|
||||
std::string masked(count, '*');
|
||||
waddstr(c, masked.c_str());
|
||||
}
|
||||
else {
|
||||
waddstr(c, buffer.c_str());
|
||||
}
|
||||
}
|
||||
else if (!this->IsFocused() && hintText.size()) {
|
||||
waddstr(c, hintText.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
size_t TextInput::Length() {
|
||||
@ -116,6 +130,10 @@ bool TextInput::Write(const std::string& key) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void TextInput::SetEnterEnabled(bool enabled) {
|
||||
this->enterEnabled = enabled;
|
||||
}
|
||||
|
||||
bool TextInput::KeyPress(const std::string& key) {
|
||||
if (key == "M-KEY_BACKSPACE") {
|
||||
this->SetText("");
|
||||
@ -133,8 +151,13 @@ bool TextInput::KeyPress(const std::string& key) {
|
||||
return true;
|
||||
}
|
||||
else if (key == "KEY_ENTER") {
|
||||
this->EnterPressed(this);
|
||||
return true;
|
||||
if (enterEnabled) {
|
||||
this->EnterPressed(this);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (key == "KEY_LEFT") {
|
||||
return this->OffsetPosition(-1);
|
||||
@ -187,3 +210,8 @@ void TextInput::SetText(const std::string& value) {
|
||||
this->Redraw();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInput::SetHint(const std::string& hint) {
|
||||
this->hintText = hint;
|
||||
this->Redraw();
|
||||
}
|
@ -72,11 +72,15 @@ namespace cursespp {
|
||||
virtual void SetText(const std::string& value);
|
||||
virtual std::string GetText() { return this->buffer; }
|
||||
|
||||
void SetHint(const std::string& hint);
|
||||
void SetEnterEnabled(bool enabled);
|
||||
|
||||
private:
|
||||
bool OffsetPosition(int delta);
|
||||
|
||||
std::string buffer;
|
||||
std::string buffer, hintText;
|
||||
int position;
|
||||
bool enterEnabled;
|
||||
size_t bufferLength;
|
||||
InputMode inputMode;
|
||||
};
|
||||
|
@ -142,7 +142,7 @@ void Window::ProcessMessage(musik::core::runtime::IMessage &message) {
|
||||
}
|
||||
|
||||
bool Window::IsVisible() {
|
||||
return this->isVisible;
|
||||
return !this->badBounds && this->isVisible;
|
||||
}
|
||||
|
||||
bool Window::IsFocused() {
|
||||
@ -245,13 +245,23 @@ void Window::MoveAndResize(int x, int y, int width, int height) {
|
||||
absX != this->lastAbsoluteX ||
|
||||
absY != this->lastAbsoluteY;
|
||||
|
||||
if (sizeChanged || positionChanged) {
|
||||
if (sizeChanged || positionChanged || badBounds) {
|
||||
this->lastAbsoluteX = absX;
|
||||
this->lastAbsoluteY = absY;
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
this->RecreateForUpdatedDimensions();
|
||||
}
|
||||
else {
|
||||
this->DestroyIfBadBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::DestroyIfBadBounds() {
|
||||
if (this->CheckForBoundsError()) {
|
||||
this->badBounds = true;
|
||||
this->Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::SetSize(int width, int height) {
|
||||
@ -260,6 +270,9 @@ void Window::SetSize(int width, int height) {
|
||||
this->height = height;
|
||||
this->RecreateForUpdatedDimensions();
|
||||
}
|
||||
else {
|
||||
this->DestroyIfBadBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::SetPosition(int x, int y) {
|
||||
@ -273,6 +286,9 @@ void Window::SetPosition(int x, int y) {
|
||||
this->lastAbsoluteY = absY;
|
||||
this->RecreateForUpdatedDimensions();
|
||||
}
|
||||
else {
|
||||
this->DestroyIfBadBounds();
|
||||
}
|
||||
}
|
||||
|
||||
void Window::OnDimensionsChanged() {
|
||||
@ -510,9 +526,17 @@ bool Window::CheckForBoundsError() {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->width > this->parent->GetContentWidth() ||
|
||||
this->height > this->parent->GetContentHeight())
|
||||
{
|
||||
const int parentWidth = this->parent->GetContentWidth();
|
||||
const int parentHeight = this->parent->GetContentHeight();
|
||||
|
||||
if (this->width > parentWidth || this->height > parentHeight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const int right = this->x + cx;
|
||||
const int bottom = this->y + cy;
|
||||
|
||||
if (right > parentWidth || bottom > parentHeight) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -131,6 +131,7 @@ namespace cursespp {
|
||||
void Clear();
|
||||
void RepaintBackground();
|
||||
void RecreateForUpdatedDimensions();
|
||||
void DestroyIfBadBounds();
|
||||
|
||||
bool CheckForBoundsError();
|
||||
|
||||
|
@ -6,6 +6,8 @@
|
||||
"button_ok": "ok",
|
||||
"button_yes": "yes",
|
||||
"button_no": "no",
|
||||
"button_save": "save",
|
||||
"button_cancel": "cancel",
|
||||
|
||||
"browse_title_artists": "artists",
|
||||
"browse_title_albums": "albums",
|
||||
@ -36,6 +38,17 @@
|
||||
"settings_seek_not_scrub": "seek playback (don't scrub)",
|
||||
"settings_minimize_to_tray": "minimize to tray",
|
||||
"settings_start_minimized": "start minimized",
|
||||
"settings_server_setup": "server setup",
|
||||
|
||||
"settings_server_enable_websockets": "metadata server enabled",
|
||||
"settings_server_metadata_port": "metadata port:",
|
||||
"settings_server_enable_http": "audio streaming enabled",
|
||||
"settings_server_audio_port": "audio port:",
|
||||
"settings_server_transcoder_synchronous": "synchronous transcoding",
|
||||
"settings_server_transcoder_cache_size": "transcoder file cache count",
|
||||
"settings_server_password": "password:",
|
||||
"settings_server_invalid_settings_title": "invalid settings",
|
||||
"settings_server_invalid_settings_message": "invalid or missing settings. please check the values and try again.",
|
||||
|
||||
"locale_overlay_select_title": "select locale",
|
||||
|
||||
@ -107,6 +120,7 @@
|
||||
"playqueue_album_header_overlay": 35,
|
||||
"playqueue_playlist_add_to_queue_overlay": 35,
|
||||
"playqueue_playlist_list_overlay": 35,
|
||||
"playqueue_playlist_name_overlay": 35
|
||||
"playqueue_playlist_name_overlay": 35,
|
||||
"server_overlay_width": 45
|
||||
}
|
||||
}
|
@ -54,6 +54,10 @@
|
||||
"hex": "#dc322f",
|
||||
"palette": 160
|
||||
},
|
||||
"overlay_focused_text": {
|
||||
"hex": "#dc322f",
|
||||
"palette": 160
|
||||
},
|
||||
"shortcuts_background": {
|
||||
"hex": "#586e75",
|
||||
"palette": 240
|
||||
|
@ -54,6 +54,10 @@
|
||||
"hex": "#dc322f",
|
||||
"palette": 160
|
||||
},
|
||||
"overlay_focused_text": {
|
||||
"hex": "#dc322f",
|
||||
"palette": 160
|
||||
},
|
||||
"shortcuts_background": {
|
||||
"hex": "#586e75",
|
||||
"palette": 240
|
||||
|
@ -149,6 +149,7 @@ xcopy "$(SolutionDir)src\plugins\websocket_remote\3rdparty\win32_bin\$(Configura
|
||||
<ClCompile Include="app\overlay\PlaybackOverlays.cpp" />
|
||||
<ClCompile Include="app\overlay\PlayQueueOverlays.cpp" />
|
||||
<ClCompile Include="app\overlay\PluginOverlay.cpp" />
|
||||
<ClCompile Include="app\overlay\ServerOverlay.cpp" />
|
||||
<ClCompile Include="app\overlay\VisualizerOverlay.cpp" />
|
||||
<ClCompile Include="app\util\GlobalHotkeys.cpp" />
|
||||
<ClCompile Include="app\util\Hotkeys.cpp" />
|
||||
@ -201,6 +202,7 @@ xcopy "$(SolutionDir)src\plugins\websocket_remote\3rdparty\win32_bin\$(Configura
|
||||
<ClInclude Include="app\overlay\PlaybackOverlays.h" />
|
||||
<ClInclude Include="app\overlay\PlayQueueOverlays.h" />
|
||||
<ClInclude Include="app\overlay\PluginOverlay.h" />
|
||||
<ClInclude Include="app\overlay\ServerOverlay.h" />
|
||||
<ClInclude Include="app\overlay\VisualizerOverlay.h" />
|
||||
<ClInclude Include="app\util\GlobalHotkeys.h" />
|
||||
<ClInclude Include="app\util\Hotkeys.h" />
|
||||
|
@ -135,6 +135,9 @@
|
||||
<ClCompile Include="app\overlay\LocaleOverlay.cpp">
|
||||
<Filter>app\overlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="app\overlay\ServerOverlay.cpp">
|
||||
<Filter>app\overlay</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
@ -319,6 +322,9 @@
|
||||
<ClInclude Include="app\util\Messages.h">
|
||||
<Filter>app\util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="app\overlay\ServerOverlay.h">
|
||||
<Filter>app\overlay</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="cursespp">
|
||||
|
@ -47,6 +47,7 @@ namespace defaults {
|
||||
}
|
||||
|
||||
namespace prefs {
|
||||
static const std::string websocket_server_enabled = "websocket_server_enabled";
|
||||
static const std::string websocket_server_port = "websocket_server_port";
|
||||
static const std::string http_server_enabled = "http_server_enabled";
|
||||
static const std::string http_server_port = "http_server_port";
|
||||
|
@ -79,25 +79,27 @@ bool WebSocketServer::Start() {
|
||||
|
||||
void WebSocketServer::ThreadProc() {
|
||||
try {
|
||||
wss.reset(new server());
|
||||
|
||||
if (context.prefs->GetBool("debug")) {
|
||||
wss.get_alog().set_ostream(&std::cerr);
|
||||
wss.get_elog().set_ostream(&std::cerr);
|
||||
wss.set_access_channels(websocketpp::log::alevel::all);
|
||||
wss.clear_access_channels(websocketpp::log::alevel::frame_payload);
|
||||
wss->get_alog().set_ostream(&std::cerr);
|
||||
wss->get_elog().set_ostream(&std::cerr);
|
||||
wss->set_access_channels(websocketpp::log::alevel::all);
|
||||
wss->clear_access_channels(websocketpp::log::alevel::frame_payload);
|
||||
}
|
||||
else {
|
||||
wss.set_access_channels(websocketpp::log::alevel::none);
|
||||
wss.clear_access_channels(websocketpp::log::alevel::none);
|
||||
wss->set_access_channels(websocketpp::log::alevel::none);
|
||||
wss->clear_access_channels(websocketpp::log::alevel::none);
|
||||
}
|
||||
|
||||
wss.init_asio();
|
||||
wss.set_message_handler(std::bind(&WebSocketServer::OnMessage, this, &wss, ::_1, ::_2));
|
||||
wss.set_open_handler(std::bind(&WebSocketServer::OnOpen, this, ::_1));
|
||||
wss.set_close_handler(std::bind(&WebSocketServer::OnClose, this, ::_1));
|
||||
wss.listen(context.prefs->GetInt(prefs::websocket_server_port.c_str(), defaults::websocket_server_port));
|
||||
wss.start_accept();
|
||||
wss->init_asio();
|
||||
wss->set_message_handler(std::bind(&WebSocketServer::OnMessage, this, wss.get(), ::_1, ::_2));
|
||||
wss->set_open_handler(std::bind(&WebSocketServer::OnOpen, this, ::_1));
|
||||
wss->set_close_handler(std::bind(&WebSocketServer::OnClose, this, ::_1));
|
||||
wss->listen(context.prefs->GetInt(prefs::websocket_server_port.c_str(), defaults::websocket_server_port));
|
||||
wss->start_accept();
|
||||
|
||||
wss.run();
|
||||
wss->run();
|
||||
}
|
||||
catch (websocketpp::exception const & e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
@ -109,13 +111,17 @@ void WebSocketServer::ThreadProc() {
|
||||
std::cerr << "unknown exception" << std::endl;
|
||||
}
|
||||
|
||||
this->wss.reset();
|
||||
this->running = false;
|
||||
this->exitCondition.notify_all();
|
||||
}
|
||||
|
||||
bool WebSocketServer::Stop() {
|
||||
if (this->thread) {
|
||||
wss.stop();
|
||||
if (this->wss) {
|
||||
wss->stop();
|
||||
}
|
||||
|
||||
this->thread->join();
|
||||
this->thread.reset();
|
||||
}
|
||||
@ -167,7 +173,7 @@ void WebSocketServer::HandleAuthentication(connection_hdl connection, json& requ
|
||||
}
|
||||
}
|
||||
|
||||
this->wss.close(
|
||||
this->wss->close(
|
||||
connection,
|
||||
websocketpp::close::status::policy_violation,
|
||||
value::unauthenticated);
|
||||
@ -329,7 +335,7 @@ void WebSocketServer::Broadcast(const std::string& name, json& options) {
|
||||
|
||||
auto rl = connectionLock.Read();
|
||||
for (const auto &keyValue : this->connections) {
|
||||
wss.send(keyValue.first, str.c_str(), websocketpp::frame::opcode::text);
|
||||
wss->send(keyValue.first, str.c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
}
|
||||
|
||||
@ -341,7 +347,7 @@ void WebSocketServer::RespondWithOptions(connection_hdl connection, json& reques
|
||||
{ message::options, options }
|
||||
};
|
||||
|
||||
wss.send(connection, response.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
wss->send(connection, response.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
void WebSocketServer::RespondWithOptions(connection_hdl connection, json& request, json&& options) {
|
||||
@ -352,7 +358,7 @@ void WebSocketServer::RespondWithOptions(connection_hdl connection, json& reques
|
||||
{ message::options, options }
|
||||
};
|
||||
|
||||
wss.send(connection, response.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
wss->send(connection, response.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
void WebSocketServer::RespondWithInvalidRequest(connection_hdl connection, const std::string& name, const std::string& id)
|
||||
@ -364,7 +370,7 @@ void WebSocketServer::RespondWithInvalidRequest(connection_hdl connection, const
|
||||
{ key::error, value::invalid }
|
||||
} }
|
||||
};
|
||||
wss.send(connection, error.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
wss->send(connection, error.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
void WebSocketServer::RespondWithSuccess(connection_hdl connection, json& request) {
|
||||
@ -382,7 +388,7 @@ void WebSocketServer::RespondWithSuccess(connection_hdl connection, const std::s
|
||||
{ message::options,{ key::success, true } }
|
||||
};
|
||||
|
||||
wss.send(connection, success.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
wss->send(connection, success.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
void WebSocketServer::RespondWithFailure(connection_hdl connection, json& request) {
|
||||
@ -393,7 +399,7 @@ void WebSocketServer::RespondWithFailure(connection_hdl connection, json& reques
|
||||
{ message::options,{ key::success, false } }
|
||||
};
|
||||
|
||||
wss.send(connection, error.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
wss->send(connection, error.dump().c_str(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
|
||||
void WebSocketServer::RespondWithSetVolume(connection_hdl connection, json& request) {
|
||||
|
@ -113,8 +113,8 @@ class WebSocketServer {
|
||||
/* vars */
|
||||
Context& context;
|
||||
ConnectionList connections;
|
||||
server wss;
|
||||
ReadWriteLock connectionLock;
|
||||
std::shared_ptr<server> wss;
|
||||
std::shared_ptr<std::thread> thread;
|
||||
std::mutex exitMutex;
|
||||
std::condition_variable exitCondition;
|
||||
|
@ -53,19 +53,6 @@ using namespace musik::core::sdk;
|
||||
|
||||
static Context context;
|
||||
|
||||
static class Plugin : public IPlugin {
|
||||
public:
|
||||
virtual void Destroy() { }
|
||||
virtual const char* Name() { return "WebSockets IPlaybackRemote"; }
|
||||
virtual const char* Version() { return "0.6.0"; }
|
||||
virtual const char* Author() { return "clangen"; }
|
||||
virtual const char* Guid() { return "9fc897a3-dfd5-4524-a0fc-b02f46aea4a9"; }
|
||||
virtual bool Configurable() { return false; }
|
||||
virtual void Configure() { }
|
||||
virtual void Reload() { }
|
||||
virtual int SdkVersion() { return musik::core::sdk::SdkVersion; }
|
||||
} plugin;
|
||||
|
||||
static class PlaybackRemote : public IPlaybackRemote {
|
||||
private:
|
||||
HttpServer httpServer;
|
||||
@ -78,25 +65,24 @@ static class PlaybackRemote : public IPlaybackRemote {
|
||||
}
|
||||
|
||||
virtual ~PlaybackRemote() {
|
||||
if (this->thread) {
|
||||
httpServer.Stop();
|
||||
webSocketServer.Stop();
|
||||
this->thread->join();
|
||||
}
|
||||
this->Stop();
|
||||
}
|
||||
|
||||
virtual void Destroy() {
|
||||
}
|
||||
|
||||
void Reload() {
|
||||
auto wl = context.lock.Write();
|
||||
this->Stop();
|
||||
this->CheckRunningStatus();
|
||||
}
|
||||
|
||||
void CheckRunningStatus() {
|
||||
if (!thread && context.environment && context.playback && context.prefs && context.dataProvider) {
|
||||
thread.reset(new std::thread(std::bind(&PlaybackRemote::ThreadProc, this)));
|
||||
}
|
||||
else if (thread && (!context.environment || !context.playback || !context.prefs || !context.dataProvider)) {
|
||||
httpServer.Stop();
|
||||
webSocketServer.Stop();
|
||||
this->thread->join();
|
||||
this->thread.reset();
|
||||
this->Stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,14 +118,40 @@ static class PlaybackRemote : public IPlaybackRemote {
|
||||
httpServer.Start();
|
||||
}
|
||||
|
||||
webSocketServer.Start();
|
||||
if (context.prefs->GetBool(prefs::websocket_server_enabled.c_str(), true)) {
|
||||
webSocketServer.Start();
|
||||
}
|
||||
|
||||
httpServer.Wait();
|
||||
webSocketServer.Wait();
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
httpServer.Stop();
|
||||
webSocketServer.Stop();
|
||||
|
||||
if (this->thread) {
|
||||
this->thread->join();
|
||||
this->thread.reset();
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<std::thread> thread;
|
||||
} remote;
|
||||
|
||||
static class Plugin : public IPlugin {
|
||||
public:
|
||||
virtual void Destroy() { }
|
||||
virtual const char* Name() { return "WebSockets IPlaybackRemote"; }
|
||||
virtual const char* Version() { return "0.6.0"; }
|
||||
virtual const char* Author() { return "clangen"; }
|
||||
virtual const char* Guid() { return "9fc897a3-dfd5-4524-a0fc-b02f46aea4a9"; }
|
||||
virtual bool Configurable() { return false; }
|
||||
virtual void Configure() { }
|
||||
virtual void Reload() { remote.Reload(); }
|
||||
virtual int SdkVersion() { return musik::core::sdk::SdkVersion; }
|
||||
} plugin;
|
||||
|
||||
extern "C" DLL_EXPORT IPlugin* GetPlugin() {
|
||||
return &plugin;
|
||||
}
|
||||
@ -159,6 +171,7 @@ extern "C" DLL_EXPORT void SetPreferences(musik::core::sdk::IPreferences* prefs)
|
||||
context.prefs = prefs;
|
||||
|
||||
if (prefs) {
|
||||
prefs->GetBool(prefs::websocket_server_enabled.c_str(), true);
|
||||
prefs->GetInt(prefs::websocket_server_port.c_str(), defaults::websocket_server_port);
|
||||
prefs->GetInt(prefs::http_server_port.c_str(), defaults::http_server_port);
|
||||
prefs->GetBool(prefs::http_server_enabled.c_str(), true);
|
||||
|
Loading…
x
Reference in New Issue
Block a user