UI fixes and refactoring...

This commit is contained in:
rock88 2021-02-14 23:10:22 +03:00
parent 934bda43dc
commit c457e48f6c
15 changed files with 99 additions and 77 deletions

View file

@ -1,5 +1,6 @@
#include "BoxArtManager.hpp" #include "BoxArtManager.hpp"
#include "Settings.hpp" #include "Settings.hpp"
#include "Data.hpp"
#include "nanovg.h" #include "nanovg.h"
#include <algorithm> #include <algorithm>
#include <mutex> #include <mutex>

View file

@ -1,19 +1,15 @@
#include "Singleton.hpp"
#include <stdio.h> #include <stdio.h>
#include <string> #include <string>
#include <map> #include <map>
#include <vector> #include <vector>
#include "Data.hpp"
#pragma once #pragma once
struct NVGcontext; struct NVGcontext;
struct Data;
class BoxArtManager { class BoxArtManager: public Singleton<BoxArtManager> {
public: public:
static BoxArtManager* manager() {
static BoxArtManager manager;
return &manager;
}
bool has_boxart(int app_id); bool has_boxart(int app_id);
void set_data(Data data, int app_id); void set_data(Data data, int app_id);
@ -21,8 +17,6 @@ public:
int texture_id(int app_id); int texture_id(int app_id);
private: private:
BoxArtManager() {};
std::map<int, bool> m_has_boxart; std::map<int, bool> m_has_boxart;
std::map<int, int> m_texture_handle; std::map<int, int> m_texture_handle;
}; };

View file

@ -16,7 +16,7 @@
GLFWgamepadstate glfw_gamepad_state; GLFWgamepadstate glfw_gamepad_state;
int moonlight_exit = 0; int moonlight_exit = 0;
int m_width, m_height, m_fb_width, m_fb_height; static int m_width, m_height, m_fb_width, m_fb_height;
int main(int argc, const char * argv[]) { int main(int argc, const char * argv[]) {
glfwInit(); glfwInit();
@ -63,6 +63,8 @@ int main(int argc, const char * argv[]) {
nanogui::window_resize_callback_event(width, height, m_fb_width, m_fb_height); nanogui::window_resize_callback_event(width, height, m_fb_width, m_fb_height);
}); });
GameStreamClient::instance().start();
MouseController::instance().init(window); MouseController::instance().init(window);
KeyboardController::instance().init(window); KeyboardController::instance().init(window);
@ -93,7 +95,7 @@ int main(int argc, const char * argv[]) {
glfwSwapBuffers(window); glfwSwapBuffers(window);
} }
GameStreamClient::client()->stop(); GameStreamClient::instance().stop();
nanogui::leave(); nanogui::leave();
nanogui::shutdown(); nanogui::shutdown();
glfwDestroyWindow(window); glfwDestroyWindow(window);

View file

@ -63,7 +63,7 @@ void perform_async(std::function<void()> task) {
m_tasks.push_back(task); m_tasks.push_back(task);
} }
GameStreamClient::GameStreamClient() { void GameStreamClient::start() {
start_task_loop(); start_task_loop();
} }
@ -78,7 +78,7 @@ void GameStreamClient::stop() {
void GameStreamClient::wake_up_host(const Host &host, ServerCallback<bool> callback) { void GameStreamClient::wake_up_host(const Host &host, ServerCallback<bool> callback) {
perform_async([this, host, callback] { perform_async([this, host, callback] {
if (WakeOnLanManager::manager()->wake_up_host(host)) { if (WakeOnLanManager::instance().wake_up_host(host)) {
usleep(5'000'000); usleep(5'000'000);
nanogui::async([callback] { callback(GSResult<bool>::success(true)); }); nanogui::async([callback] { callback(GSResult<bool>::success(true)); });
} else { } else {
@ -128,22 +128,31 @@ void GameStreamClient::pair(const std::string &address, const std::string &pin,
}); });
} }
void GameStreamClient::applist(const std::string &address, ServerCallback<PAPP_LIST> callback) { void GameStreamClient::applist(const std::string &address, ServerCallback<AppInfoList> callback) {
if (m_server_data.count(address) == 0) { if (m_server_data.count(address) == 0) {
callback(GSResult<PAPP_LIST>::failure("Firstly call connect() & pair()...")); callback(GSResult<AppInfoList>::failure("Firstly call connect() & pair()..."));
return; return;
} }
m_app_list[address] = PAPP_LIST();
perform_async([this, address, callback] { perform_async([this, address, callback] {
int status = gs_applist(&m_server_data[address], &m_app_list[address]); PAPP_LIST list;
nanogui::async([this, address, callback, status] { int status = gs_applist(&m_server_data[address], &list);
AppInfoList app_list;
while (list) {
app_list.push_back({ .name = list->name, .app_id = list->id });
list = list->next;
}
std::sort(app_list.begin(), app_list.end(), [](AppInfo a, AppInfo b) { return a.name < b.name; });
nanogui::async([this, app_list, callback, status] {
if (status == GS_OK) { if (status == GS_OK) {
callback(GSResult<PAPP_LIST>::success(m_app_list[address])); callback(GSResult<AppInfoList>::success(app_list));
} else { } else {
callback(GSResult<PAPP_LIST>::failure(gs_error())); callback(GSResult<AppInfoList>::failure(gs_error()));
} }
}); });
}); });

View file

@ -1,3 +1,4 @@
#include "Singleton.hpp"
#include <string> #include <string>
#include <vector> #include <vector>
#include <functional> #include <functional>
@ -49,31 +50,31 @@ template<class T> using ServerCallback = const std::function<void(GSResult<T>)>;
struct Host; struct Host;
class GameStreamClient { struct AppInfo {
std::string name;
int app_id;
};
using AppInfoList = std::vector<AppInfo>;
class GameStreamClient: public Singleton<GameStreamClient> {
public: public:
static GameStreamClient* client() {
static GameStreamClient client;
return &client;
}
SERVER_DATA server_data(const std::string &address) { SERVER_DATA server_data(const std::string &address) {
return m_server_data[address]; return m_server_data[address];
} }
void start();
void stop(); void stop();
void wake_up_host(const Host &host, ServerCallback<bool> callback); void wake_up_host(const Host &host, ServerCallback<bool> callback);
void connect(const std::string &address, ServerCallback<SERVER_DATA> callback); void connect(const std::string &address, ServerCallback<SERVER_DATA> callback);
void pair(const std::string &address, const std::string &pin, ServerCallback<bool> callback); void pair(const std::string &address, const std::string &pin, ServerCallback<bool> callback);
void applist(const std::string &address, ServerCallback<PAPP_LIST> callback); void applist(const std::string &address, ServerCallback<AppInfoList> callback);
void app_boxart(const std::string &address, int app_id, ServerCallback<Data> callback); void app_boxart(const std::string &address, int app_id, ServerCallback<Data> callback);
void start(const std::string &address, STREAM_CONFIGURATION config, int app_id, ServerCallback<STREAM_CONFIGURATION> callback); void start(const std::string &address, STREAM_CONFIGURATION config, int app_id, ServerCallback<STREAM_CONFIGURATION> callback);
void quit(const std::string &address, ServerCallback<bool> callback); void quit(const std::string &address, ServerCallback<bool> callback);
private: private:
GameStreamClient();
std::map<std::string, SERVER_DATA> m_server_data; std::map<std::string, SERVER_DATA> m_server_data;
std::map<std::string, PAPP_LIST> m_app_list;
STREAM_CONFIGURATION m_config; STREAM_CONFIGURATION m_config;
}; };

View file

@ -215,11 +215,11 @@ void MoonlightSession::start(ServerCallback<bool> callback) {
m_audio_callbacks.capabilities = m_audio_renderer->capabilities(); m_audio_callbacks.capabilities = m_audio_renderer->capabilities();
} }
GameStreamClient::client()->start(m_address, m_config, m_app_id, [this, callback](auto result) { GameStreamClient::instance().start(m_address, m_config, m_app_id, [this, callback](auto result) {
if (result.isSuccess()) { if (result.isSuccess()) {
m_config = result.value(); m_config = result.value();
auto m_data = GameStreamClient::client()->server_data(m_address); auto m_data = GameStreamClient::instance().server_data(m_address);
int result = LiStartConnection(&m_data.serverInfo, &m_config, &m_connection_callbacks, &m_video_callbacks, &m_audio_callbacks, NULL, 0, NULL, 0); int result = LiStartConnection(&m_data.serverInfo, &m_config, &m_connection_callbacks, &m_video_callbacks, &m_audio_callbacks, NULL, 0, NULL, 0);
if (result != 0) { if (result != 0) {
@ -237,7 +237,7 @@ void MoonlightSession::start(ServerCallback<bool> callback) {
void MoonlightSession::stop(int terminate_app) { void MoonlightSession::stop(int terminate_app) {
if (terminate_app) { if (terminate_app) {
GameStreamClient::client()->quit(m_address, [](auto _) {}); GameStreamClient::instance().quit(m_address, [](auto _) {});
} }
LiStopConnection(); LiStopConnection();
@ -249,9 +249,6 @@ void MoonlightSession::draw() {
AVFrameHolder::holder()->get([this](auto frame) { AVFrameHolder::holder()->get([this](auto frame) {
m_video_renderer->draw(m_config.width, m_config.height, frame); m_video_renderer->draw(m_config.width, m_config.height, frame);
}); });
// if (auto frame = m_video_decoder->frame()) {
// m_video_renderer->draw(m_config.width, m_config.height, frame);
// }
m_session_stats.video_decode_stats = *m_video_decoder->video_decode_stats(); m_session_stats.video_decode_stats = *m_video_decoder->video_decode_stats();
m_session_stats.video_render_stats = *m_video_renderer->video_render_stats(); m_session_stats.video_render_stats = *m_video_renderer->video_render_stats();

View file

@ -1,14 +1,10 @@
#include "Singleton.hpp"
#include <stdio.h> #include <stdio.h>
struct Host; struct Host;
class WakeOnLanManager { class WakeOnLanManager: public Singleton<WakeOnLanManager> {
private: private:
static WakeOnLanManager* manager() {
static WakeOnLanManager manager;
return &manager;
}
bool wake_up_host(const Host &host); bool wake_up_host(const Host &host);
friend class GameStreamClient; friend class GameStreamClient;

View file

@ -76,6 +76,7 @@ void Application::resize_callback_event(int width, int height, int fb_width, int
for (auto window: m_windows) { for (auto window: m_windows) {
window->set_size(Size(width, height)); window->set_size(Size(width, height));
window->set_fixed_size(Size(width, height)); window->set_fixed_size(Size(width, height));
window->perform_layout(nvg_context());
} }
Screen::resize_callback_event(width, height, fb_width, fb_height); Screen::resize_callback_event(width, height, fb_width, fb_height);
perform_layout(); perform_layout();

View file

@ -8,25 +8,24 @@
using namespace nanogui; using namespace nanogui;
AppButton::AppButton(Widget* parent, const std::string &address, APP_LIST app, int current_game): Button(parent, "") { AppButton::AppButton(Widget* parent, const std::string &address, AppInfo app, int current_game): Button(parent, "") {
m_address = address; m_address = address;
m_app = app; m_app = app;
set_fixed_size(Size(210, 296));
set_layout(new BoxLayout(Orientation::Vertical, Alignment::Middle));
m_label = add<Label>(m_app.name); m_label = add<Label>(m_app.name);
m_label->set_fixed_width(fixed_width() - 12);
if (m_app.id == current_game) { set_fixed_size(Size(210, 296));
set_layout(new BoxLayout(Orientation::Vertical, Alignment::Minimum, 10));
if (m_app.app_id == current_game) {
m_label->set_caption(m_label->caption() + " (Running)"); m_label->set_caption(m_label->caption() + " (Running)");
} }
if (!BoxArtManager::manager()->has_boxart(m_app.id)) { if (!BoxArtManager::instance().has_boxart(m_app.app_id)) {
inc_ref(); inc_ref();
GameStreamClient::client()->app_boxart(m_address, m_app.id, [this](auto result) { GameStreamClient::instance().app_boxart(m_address, m_app.app_id, [this](auto result) {
if (result.isSuccess()) { if (result.isSuccess()) {
BoxArtManager::manager()->set_data(result.value(), m_app.id); BoxArtManager::instance().set_data(result.value(), m_app.app_id);
} }
dec_ref(); dec_ref();
@ -37,18 +36,24 @@ AppButton::AppButton(Widget* parent, const std::string &address, APP_LIST app, i
bool AppButton::gamepad_button_event(int jid, int button, int action) { bool AppButton::gamepad_button_event(int jid, int button, int action) {
if (action && button == NANOGUI_GAMEPAD_BUTTON_Y) { if (action && button == NANOGUI_GAMEPAD_BUTTON_Y) {
if (auto application = dynamic_cast<Application *>(screen())) { if (auto application = dynamic_cast<Application *>(screen())) {
application->push_window<InputSettingsWindow>(m_app.id, m_app.name); application->push_window<InputSettingsWindow>(m_app.app_id, m_app.name);
} }
return true; return true;
} }
return Button::gamepad_button_event(jid, button, action); return Button::gamepad_button_event(jid, button, action);
} }
void AppButton::draw(NVGcontext *ctx) { void AppButton::set_fixed_size(const Vector2i &fixed_size) {
int handle = BoxArtManager::manager()->texture_id(m_app.id); m_label->set_fixed_width(fixed_size.x() - 10);
if (handle == -1 && BoxArtManager::manager()->has_boxart(m_app.id)) { Button::set_fixed_size(fixed_size);
BoxArtManager::manager()->make_texture_from_boxart(ctx, m_app.id); }
void AppButton::draw(NVGcontext *ctx) {
int handle = BoxArtManager::instance().texture_id(m_app.app_id);
if (handle == -1 && BoxArtManager::instance().has_boxart(m_app.app_id)) {
BoxArtManager::instance().make_texture_from_boxart(ctx, m_app.app_id);
} }
if (handle != -1) { if (handle != -1) {
@ -72,7 +77,7 @@ void AppButton::draw(NVGcontext *ctx) {
nvgSave(ctx); nvgSave(ctx);
nvgFillColor(ctx, Color(0, 0, 0, 200)); nvgFillColor(ctx, Color(0, 0, 0, 200));
nvgBeginPath(ctx); nvgBeginPath(ctx);
nvgRect(ctx, m_pos.x(), m_pos.y(), width(), m_label->height()); nvgRect(ctx, m_pos.x(), m_pos.y(), width(), m_label->height() + 20);
nvgFill(ctx); nvgFill(ctx);
nvgRestore(ctx); nvgRestore(ctx);

View file

@ -4,14 +4,15 @@
class AppButton: public nanogui::Button { class AppButton: public nanogui::Button {
public: public:
AppButton(Widget* parent, const std::string &address, APP_LIST app, int current_game); AppButton(Widget* parent, const std::string &address, AppInfo app, int current_game);
bool gamepad_button_event(int jid, int button, int action) override; bool gamepad_button_event(int jid, int button, int action) override;
void set_fixed_size(const nanogui::Vector2i &fixed_size);
void draw(NVGcontext *ctx) override; void draw(NVGcontext *ctx) override;
private: private:
std::string m_address; std::string m_address;
APP_LIST m_app; AppInfo m_app;
nanogui::Label* m_label; nanogui::Label* m_label;
}; };

View file

@ -15,7 +15,7 @@ HostButton::HostButton(Widget* parent, const Host &host): Button(parent, "") {
m_label->set_font_size(20); m_label->set_font_size(20);
inc_ref(); inc_ref();
GameStreamClient::client()->connect(m_host.address, [this](auto result) { GameStreamClient::instance().connect(m_host.address, [this](auto result) {
if (result.isSuccess()) { if (result.isSuccess()) {
m_is_active = true; m_is_active = true;
m_is_paired = result.value().paired; m_is_paired = result.value().paired;

View file

@ -61,7 +61,7 @@ AddHostWindow::AddHostWindow(Widget *parent): ContentWindow(parent, "Add Host")
if (text->value().size() > 0) { if (text->value().size() > 0) {
auto loader = add<LoadingOverlay>(); auto loader = add<LoadingOverlay>();
GameStreamClient::client()->connect(text->value(), [this, loader](auto result) { GameStreamClient::instance().connect(text->value(), [this, loader](auto result) {
loader->dispose(); loader->dispose();
if (result.isSuccess()) { if (result.isSuccess()) {

View file

@ -4,9 +4,28 @@
#include "StreamWindow.hpp" #include "StreamWindow.hpp"
#include "GamepadMapper.hpp" #include "GamepadMapper.hpp"
#include "Alert.hpp" #include "Alert.hpp"
#include "GameStreamClient.hpp"
using namespace nanogui; using namespace nanogui;
class AppListLayout: public GridLayout {
public:
AppListLayout(): GridLayout(Orientation::Horizontal, 5, Alignment::Minimum, 0, 18) {}
Vector2i preferred_size(NVGcontext *ctx, const Widget *widget) const override {
auto width = (widget->parent()->width() - spacing(0) * (resolution() - 1)) / resolution() - 10;
auto size = Size(width, width * 1.4f);
for (auto &child: widget->children()) {
if (child->fixed_size() != size) {
child->set_fixed_size(size);
child->perform_layout(ctx);
}
}
return GridLayout::preferred_size(ctx, widget);
}
};
AppListWindow::AppListWindow(Widget *parent, const std::string &address): ContentWindow(parent, "Applications"), m_address(address) { AppListWindow::AppListWindow(Widget *parent, const std::string &address): ContentWindow(parent, "Applications"), m_address(address) {
set_left_pop_button(); set_left_pop_button();
@ -23,7 +42,7 @@ void AppListWindow::reload(std::function<void()> callback) {
auto loader = add<LoadingOverlay>(); auto loader = add<LoadingOverlay>();
GameStreamClient::client()->connect(m_address, [this, loader, callback](auto result) { GameStreamClient::instance().connect(m_address, [this, loader, callback](auto result) {
if (result.isSuccess()) { if (result.isSuccess()) {
auto currentGame = result.value().currentGame; auto currentGame = result.value().currentGame;
@ -33,7 +52,7 @@ void AppListWindow::reload(std::function<void()> callback) {
}); });
} }
GameStreamClient::client()->applist(m_address, [this, loader, currentGame, callback](auto result) { GameStreamClient::instance().applist(m_address, [this, loader, currentGame, callback](auto result) {
loader->dispose(); loader->dispose();
if (result.isSuccess()) { if (result.isSuccess()) {
@ -41,17 +60,15 @@ void AppListWindow::reload(std::function<void()> callback) {
container()->add<Widget>()->set_fixed_height(6); container()->add<Widget>()->set_fixed_height(6);
auto button_container = container()->add<Widget>(); auto button_container = container()->add<Widget>();
button_container->set_layout(new GridLayout(Orientation::Horizontal, 5, Alignment::Minimum, 0, 18)); button_container->set_layout(new AppListLayout());
PAPP_LIST app = result.value(); for (auto &app: result.value()) {
auto button = button_container->add<AppButton>(m_address, app, currentGame);
while (app != NULL) {
auto button = button_container->add<AppButton>(m_address, *app, currentGame);
button->set_callback([this, app] { button->set_callback([this, app] {
run_game(app->id); run_game(app.app_id);
}); });
app = app->next;
} }
perform_layout(); perform_layout();
if (callback) { if (callback) {
@ -69,7 +86,7 @@ void AppListWindow::reload(std::function<void()> callback) {
} }
void AppListWindow::run_game(int app_id) { void AppListWindow::run_game(int app_id) {
int current_app_id = GameStreamClient::client()->server_data(m_address).currentGame; int current_app_id = GameStreamClient::instance().server_data(m_address).currentGame;
if (current_app_id == 0 || current_app_id == app_id) { if (current_app_id == 0 || current_app_id == app_id) {
GamepadMapper::mapper()->load_gamepad_map(app_id); GamepadMapper::mapper()->load_gamepad_map(app_id);
@ -92,7 +109,7 @@ void AppListWindow::run_game(int app_id) {
void AppListWindow::close_game(std::function<void()> callback) { void AppListWindow::close_game(std::function<void()> callback) {
auto loader = add<LoadingOverlay>(); auto loader = add<LoadingOverlay>();
GameStreamClient::client()->quit(m_address, [this, loader, callback](auto result) { GameStreamClient::instance().quit(m_address, [this, loader, callback](auto result) {
loader->dispose(); loader->dispose();
if (result.isSuccess()) { if (result.isSuccess()) {

View file

@ -1,5 +1,4 @@
#include "ContentWindow.hpp" #include "ContentWindow.hpp"
#include "GameStreamClient.hpp"
#pragma once #pragma once
class AppListWindow: public ContentWindow { class AppListWindow: public ContentWindow {
@ -14,5 +13,4 @@ private:
void close_game(std::function<void()> callback = NULL); void close_game(std::function<void()> callback = NULL);
std::string m_address; std::string m_address;
PAPP_LIST m_app_list;
}; };

View file

@ -50,7 +50,7 @@ void MainWindow::reload() {
} else { } else {
auto loader = add<LoadingOverlay>("Pairing... (Enter 0000)"); auto loader = add<LoadingOverlay>("Pairing... (Enter 0000)");
GameStreamClient::client()->pair(button->host().address, "0000", [this, loader](auto result){ GameStreamClient::instance().pair(button->host().address, "0000", [this, loader](auto result){
loader->dispose(); loader->dispose();
if (result.isSuccess()) { if (result.isSuccess()) {
@ -104,7 +104,7 @@ void MainWindow::draw(NVGcontext *ctx) {
void MainWindow::wake_up_host(const Host &host) { void MainWindow::wake_up_host(const Host &host) {
auto loader = add<LoadingOverlay>("Sending Wake Up..."); auto loader = add<LoadingOverlay>("Sending Wake Up...");
GameStreamClient::client()->wake_up_host(host, [this, loader](auto result) { GameStreamClient::instance().wake_up_host(host, [this, loader](auto result) {
loader->dispose(); loader->dispose();
if (result.isSuccess()) { if (result.isSuccess()) {