Add game browser config

This commit is contained in:
N3xoX1 2025-10-04 10:59:20 +09:30
parent 4ed02bd44c
commit 3563d15e8a
18 changed files with 611 additions and 261 deletions

233
lang/english/css/base.css Normal file
View File

@ -0,0 +1,233 @@
:root {
--color-main-background: #2d2d2d;
--color-titlebar-background: #181818;
--color-titlebar-background-inactive: #2d2d2d;
--color-titlebar-text: #FFF;
--color-titlebar-icon: #FFF;
--color-titlebar-icon-hover: #0078d7;
--color-titlebar-icon-inactive: #2f7bb0;
--color-menubar-background: #181818;
--color-menubar-background-hover: #2c2c2c;
--color-menubar-background-active: #2c2c2c;
--color-menuitem-background: #2c2c2c;
--color-menuitem-background-hover: #383838;
--color-window-border: #353535;
}
html
{
border: 1px solid var(--color-window-border);
background-color: var(--color-main-background);
}
html[window-state="maximized"]
{
border: window-frame-width solid transparent;
}
html > header
{
width: *;
flow: horizontal;
background-color: var(--color-titlebar-background);
height: window-caption-height;
margin: 0;
color: var(--color-titlebar-text);
}
html[data-active="false"] > header
{
background-color: var(--color-titlebar-background-inactive);
}
html > header > window-caption
{
display: block;
line-height: window-caption-height;
width: *;
padding: 0 1em;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 0.9em;
font-weight: 100;
}
html > header > window-caption span
{
vertical-align: middle;
}
html > header > window-caption img
{
vertical-align: middle;
margin-right: 0.4em;
width: 1.5em;
height: 1.5em;
}
html > header > window-buttons
{
display: block;
flow: horizontal;
width: max-content;
height: *;
}
html > header > window-buttons > window-button {
behavior: clickable;
display: block;
height: *;
width: window-button-width;
foreground-size: 2em 1.5em;
foreground-repeat: no-repeat;
foreground-position: 50% 50%;
stroke-width: 0;
fill: var(--color-titlebar-icon);
transition: background-color linear 100ms;
padding: 0.25em;
}
html[data-active="false"] > header > window-buttons > window-button
{
fill: var(--color-titlebar-icon-inactive);
}
html > header > window-buttons > window-button:hover
{
background: var(--color-titlebar-icon-hover);
}
html > header > window-buttons > window-button[role="window-close"]
{
foreground-image: url(icon:window-close);
}
html > header > window-buttons > window-button[role="window-close"]:hover
{
background: rgb(232,17,35);
fill: #fff;
}
html > header > window-buttons > window-button[role="window-maximize"]
{
foreground-image: url(icon:window-maximize);
}
html[window-state="maximized"]
{
border-color: transparent;
}
html[window-state="maximized"] > header > window-buttons > window-button[role="window-maximize"]
{
foreground-image: url(icon:window-restore);
}
html > header > window-buttons > window-button[role="window-minimize"]
{
foreground-image: url(icon:window-minimize);
}
ul#menu-bar
{
margin: 0;
padding: 0 0.5em 0.3em 0.5em;
border-left: 1px solid transparent;
background: var(--color-menubar-background);
color: #eff0f1;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 0.9em;
font-weight: 100;
behavior:menu-bar;
flow: horizontal;
}
ul#menu-bar > li
{
padding: 0.15em 0.45em;
margin: 0;
white-space: nowrap;
width: max-content;
display: block;
flow: horizontal;
border-radius: 5px;
}
ul#menu-bar > li:hover
{
background: var(--color-menubar-background-hover);
}
ul#menu-bar:focus > li:current,
ul#menu-bar > li:owns-popup {
background-color: var(--color-menubar-background-active);
border-radius: 5px 5px 0;
}
menu
{
behavior:menu;
flow: vertical;
display:none;
margin:0;
padding: 0.2em;
max-width:max-content;
background: var(--color-menuitem-background);
color: #eff0f1;
border: 1px solid #141414;
border-top: none;
}
@media (menu-animation-supported) {
menu {
popup-animation: popup-animation(type:blend,duration:100ms);
}
}
menu menu
{
max-width: max-content;
}
menu li
{
width:*;
display:block;
flow:horizontal;
vertical-align:middle;
foreground-repeat: no-repeat;
foreground-position: left 2px top 50%;
padding: 0.2em 1.8em 0.2em 1.3em;
margin: 0;
}
menu li:hover
{
background: var(--color-menuitem-background-hover);
border-radius: 5px;
}
menu li:disabled
{
color:graytext;
foreground-image: none;
}
menu li:has-child-of-type(menu)
{
foreground-image:url(stock:arrow-right);
foreground-repeat: no-repeat;
foreground-position: top 50% right 2px;
}
menu li:has-child-of-type(menu):rtl
{
foreground-image:url(stock:arrow-left);
foreground-repeat: no-repeat;
foreground-position: top 50% left 2px;
}
hr
{
padding: 0;
margin: 0.2em 0;
}

View File

@ -1,3 +1,22 @@
:root {
--color-config-background: #181818;
--color-config-page: #2d2d2d;
--color-config-page-border: #505050;
}
html
{
background: var(--color-config-background);
}
div.ConfigPage
{
background: var(--color-config-background);
flow: horizontal;
width: 100%%;
height: 100%%;
}
popup.tooltip
{
background: #4f6459;
@ -37,7 +56,7 @@ button:active
.tab-button {
background: #2b2f32;
border: 1px solid #55575a;
border-bottom: 1px solid #76787d;
border-bottom: 1px solid var(--color-config-page-border);
border-radius: 2px 2px 0 0;
color: #eff0f1;
font-family: 'Segoe UI', Arial, sans-serif;
@ -52,7 +71,7 @@ button:active
.tab-button:hover {
border: 1px solid #55575a;
border-bottom: 1px solid #76787d;
border-bottom: 1px solid var(--color-config-page-border);
}
.tab-button:active {
@ -60,15 +79,15 @@ button:active
}
.tab-button.active {
background: #30373b;
border-color: #76787d;
border-bottom: 1px solid #30373b;
background: var(--color-config-page);
border-color: var(--color-config-page-border);
border-bottom: 1px solid var(--color-config-page);
}
.controller-body
{
background: #30373b;
border: 1px solid #76787d;
background: var(--color-config-page);
border: 1px solid var(--color-config-page-border);
width: 100%%;
height: 100%%;
flow: horizontal;
@ -92,10 +111,10 @@ button:active
.input-group
{
position: relative;
background-color: #30373b;
background-color: var(--color-config-page);
border: 1px solid #55575a;
padding: 1.2rem 0.5rem 0.5rem 0.5rem;
margin: 0 0 20px 0;
margin: 0 0 1rem 0;
}
.input-grid-directional {
@ -110,7 +129,7 @@ button:active
top: -0.5rem;
left: 0;
margin: 0 auto;
background-color: #30373b;
background-color: var(--color-config-page);
padding: 0 6px;
font-size: 0.8rem;
color: #f0f0f0;
@ -120,7 +139,7 @@ button:active
{
display: inline-block;
position: relative;
background-color: #30373b;
background-color: var(--color-config-page);
border: 1px solid #55575a;
padding: 0.4em 0.2rem 0.2rem 0.2rem;
border-radius: 2px;
@ -134,7 +153,7 @@ button:active
top: -0.7rem;
left: 0;
margin: 0 auto;
background-color: #30373b;
background-color: var(--color-config-page);
padding: 0 6px;
font-size: 0.8rem;
color: #f0f0f0;
@ -150,4 +169,10 @@ button:active
{
padding: 0.5rem 0 0;
text-align: right;
}
}
#ConfigContents {
width: 100%%;
height: 100%%;
color: #ffffff;
}

View File

@ -1,208 +1,3 @@
html
{
border: none;
background-color: #30373b;
}
html[window-state="maximized"]
{
border: window-frame-width solid transparent;
}
html > header
{
width: *;
flow: horizontal;
background-color: threedface;
height: window-caption-height;
margin: 0;
}
html > header > window-caption
{
display: block;
line-height: window-caption-height;
width: *;
padding: 0 1em;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 0.9em;
font-weight: 100;
}
html > header > window-caption span
{
vertical-align: middle;
}
html > header > window-caption img
{
vertical-align: middle;
margin-right: 0.4em;
width: 1.5em;
height: 1.5em;
}
html > header > window-buttons
{
display: block;
flow: horizontal;
width: max-content;
height: *;
}
html > header > window-buttons > window-button {
behavior: clickable;
display: block;
height: *;
width: window-button-width;
foreground-size: 2em 1.5em;
foreground-repeat: no-repeat;
foreground-position: 50% 50%;
stroke-width: 0;
fill: #000000;
transition: background-color linear 100ms;
padding: 0.25em;
}
html > header > window-buttons > window-button:hover
{
background: rgba(0,0,0,0.25);
}
html > header > window-buttons > window-button[role="window-close"]
{
foreground-image: url(icon:window-close);
}
html > header > window-buttons > window-button[role="window-close"]:hover
{
background: rgb(232,17,35);
fill: #fff;
}
html > header > window-buttons > window-button[role="window-maximize"]
{
foreground-image: url(icon:window-maximize);
}
html[window-state="maximized"]
{
border-color: transparent;
}
html[window-state="maximized"] > header > window-buttons > window-button[role="window-maximize"]
{
foreground-image: url(icon:window-restore);
}
html > header > window-buttons > window-button[role="window-minimize"]
{
foreground-image: url(icon:window-minimize);
}
ul#menu-bar
{
margin: 0;
border-bottom: 1px solid #434242;
border-left: 1px solid transparent;
background: #31363b;
color: #eff0f1;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 0.9em;
font-weight: 100;
behavior:menu-bar;
flow: horizontal;
padding: 0;
margin: 0;
}
ul#menu-bar > li
{
padding: 0.25em 0.5em 0.1em 0.5em;
border: 1px solid transparent;
margin:0;
white-space:nowrap;
width:max-content;
display:block;
flow:horizontal;
}
ul#menu-bar > li:hover
{
border: 1px solid #76797c;
}
ul#menu-bar:focus > li:current,
ul#menu-bar > li:owns-popup {
background-color: #3daee9;
}
menu
{
behavior:menu;
flow: vertical;
display:none;
margin:0;
padding: 0.2em;
max-width:max-content;
background: #31363b;
color: #eff0f1;
border: 1px solid #434242;
}
@media (menu-animation-supported) {
menu {
popup-animation: popup-animation(type:blend,duration:100ms);
}
}
menu menu
{
max-width: max-content;
}
menu li
{
width:*;
display:block;
flow:horizontal;
vertical-align:middle;
foreground-repeat: no-repeat;
foreground-position: left 2px top 50%;
padding: 0.2em 1.8em 0.2em 1.3em;
margin: 0;
}
menu li:hover
{
background: #18465d;
}
menu li:disabled
{
color:graytext;
foreground-image: none;
}
menu li:has-child-of-type(menu)
{
foreground-image:url(stock:arrow-right);
foreground-repeat: no-repeat;
foreground-position: top 50% right 2px;
}
menu li:has-child-of-type(menu):rtl
{
foreground-image:url(stock:arrow-left);
foreground-repeat: no-repeat;
foreground-position: top 50% left 2px;
}
hr
{
padding: 0;
margin: 0.2em 0;
}
#MainContents
{
width: 100%%;

View File

@ -1,7 +1,7 @@
<html window-frame="solid-with-shadow" window-icon="window-icon.png">
<head>
<link href="main_window.css" rel="stylesheet" type="text/css" />
<link href="input_config.css" rel="stylesheet" type="text/css" />
<link href="base.css" rel="stylesheet" type="text/css" />
<link href="config.css" rel="stylesheet" type="text/css" />
<title>Configure Input</title>
</head>
<header>

View File

@ -1,5 +1,6 @@
<html window-frame="solid-with-shadow" window-icon="window-icon.png" window-resizable window-min-width="640" window-min-height="480">
<head>
<link href="base.css" rel="stylesheet" type="text/css">
<link href="main_window.css" rel="stylesheet" type="text/css">
<title>NxEmu</title>
</head>

View File

@ -1,22 +1,15 @@
<html window-frame="solid-with-shadow" window-icon="window-icon.png">
<head>
<link href="main_window.css" rel="stylesheet" type="text/css" />
<link href="input_config.css" rel="stylesheet" type="text/css" />
<link href="base.css" rel="stylesheet" type="text/css" />
<link href="config.css" rel="stylesheet" type="text/css" />
<title>NxEmu Configuration</title>
<style>
#SettingsPage
{
flow: horizontal;
width: 100%%;
height: 100%%;
}
#MainTabNav {
width: 9em;
width: 12em;
height: 100%%;
border: 1px solid #54575b;
border-radius: 0.5em;
background-color: #232629;
background-color: var(--color-config-page);
margin: 0 0.4em 0 0;
color: #ffffff;
font-size: 0.9em;
@ -34,13 +27,8 @@
#MainTabNav > Page:visited
{
background: #287399;
}
#ConfigContents {
width: 100%%;
height: 100%%;
color: #ffffff;
background: #b3d9f7;
color: #303030;
}
.checkbox-row,
@ -228,11 +216,11 @@ PageNav.page_tabs {
PageNav.page_tabs page {
background: #2b2f32;
border: 1px solid #55575a;
border-bottom: 1px solid #76787d;
border-bottom: 1px solid var(--color-config-page-border);
border-radius: 2px 2px 0 0;
color: #eff0f1;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 0.8rem;
font-size: 1rem;
padding: 0.2rem 1.3rem 0.2rem 1.3rem;
margin: 0;
position: relative;
@ -244,31 +232,31 @@ PageNav.page_tabs page {
PageNav.page_tabs page:hover {
border: 1px solid #55575a;
border-bottom: 1px solid #76787d;
border-bottom: 1px solid var(--color-config-page-border);
}
PageNav.page_tabs page:visited {
background: #30373b;
border-color: #76787d;
border-bottom: 1px solid #30373b;
background: var(--color-config-page);
border-color: var(--color-config-page-border);
border-bottom: 1px solid var(--color-config-page);
}
PageNav.page_tabs page.active {
background: #30373b;
border-color: #76787d;
border-bottom: 1px solid #30373b;
background: var(--color-config-page);
border-color: var(--color-config-page-border);
border-bottom: 1px solid var(--color-config-page);
}
.page_content
{
background: #30373b;
border: 1px solid #76787d;
background: var(--color-config-page);
border: 1px solid var(--color-config-page-border);
width: 100%%;
height: 100%%;
flow: horizontal;
padding: 1em;
padding: 1em 1em 0 1em;
font-family: 'Segoe UI', Arial, sans-serif;
font-size: 0.8rem;
font-size: 0.9rem;
color: #eff0f1;
}
</style>
@ -280,10 +268,11 @@ PageNav.page_tabs page.active {
</window-buttons>
</header>
<body>
<div id="SettingsPage" tooltip-host>
<div class="ConfigPage" tooltip-host>
<PageNav target="ConfigContents" id="MainTabNav">
<Page contents="system_config_graphics.html" label="Graphics" Name="Graphics" />
<Page contents="system_config_audio.html" label="Audio" Name="Audio" />
<Page contents="system_config_game_browser.html" label="Game Browser" Name="GameBrowser" />
<Page contents="system_config_debug.html" label="Debug" Name="Debug" />
</PageNav>
<div id="ConfigContents" />

View File

@ -0,0 +1,39 @@
<style>
#gameDirectoryList {
background-color: #1e1e1e;
border: 1px solid #404040;
border-radius: 4px;
min-height: 8rem;
padding: 0.1rem;
margin-bottom: 1rem;
}
.directory-item {
padding: 0.2rem 0.3rem;
margin: 0.2rem 0.3rem;
border-radius: 3px;
}
.directory-item:hover {
background-color: #404040;
}
.directory-item:checked
{
background: #4a9eff;
}
</style>
<PageNav target="GameBrowserContents" id="GameBrowserTabNav" class="page_tabs">
<Page label="Game Browser" Name="GameBrowser">
<div class="input-group">
<div class="group-title">Game Directories </div>
<div id="gameDirectoryList" />
<div class="buttons-container">
<button id="gameDirectoryAdd">Add</button>
<button id="gameDirectoryRemove">Remove</button>
</div>
</div>
</div>
</page>
</PageNav>
<div id="GameBrowserContents" class="page_content" />

View File

@ -55,7 +55,7 @@
<div class="left"><label for="AntiAliasing">Anti-Aliasing Method:</label></div>
<div class="right"><ComboBox id="AntiAliasing" tooltip="The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA has a lower performance impact and can produce a better and more stable picture under very low resolutions."/></div>
</div>
<div class="form-row slider-row">
<div class="form-row">
<div class="left"><label for="FSPSharpness">FSP Sharpness:</label></div>
<div class="right"><input type="hslider" id="Volume" min="0" max="100" value="100" id="FSPSharpness" style="width: 19em" /><span id="FSPSharpnessDisplay">100%</span></div>
</div>

View File

@ -4,6 +4,7 @@
#include <CommDlg.h>
#include <io.h>
#include <shlobj_core.h>
const char DRIVE_DELIMITER = ':';
const char * const DIR_DOUBLEDELIM = "\\\\";
@ -371,6 +372,51 @@ bool Path::FileSelect(void * hwndOwner, const char * initialDir, const char * fi
return true;
}
Path & Path::BrowseForDirectory(void * parentWindow, const char * title)
{
*this = Path();
const HRESULT hrCo = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
IFileDialog* dlg = nullptr;
HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER,IID_PPV_ARGS(&dlg));
if (SUCCEEDED(hr))
{
DWORD options = 0;
if (SUCCEEDED(dlg->GetOptions(&options)))
{
options |= FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR;
dlg->SetOptions(options);
}
if (title && *title)
{
dlg->SetTitle(stdstr_f(title).ToUTF16().c_str());
}
hr = dlg->Show((HWND)parentWindow);
if (SUCCEEDED(hr))
{
IShellItem* result = nullptr;
if (SUCCEEDED(dlg->GetResult(&result)) && result)
{
PWSTR psz = nullptr;
if (SUCCEEDED(result->GetDisplayName(SIGDN_FILESYSPATH, &psz)) && psz)
{
*this = Path(stdstr().FromUTF16(psz).c_str(), "");
CoTaskMemFree(psz);
}
result->Release();
}
}
dlg->Release();
}
if (SUCCEEDED(hrCo))
{
CoUninitialize();
}
return *this;
}
bool Path::IsDirectory() const
{
std::string fileName;

View File

@ -59,6 +59,7 @@ public:
bool FileExists() const;
bool FileSelect(void * hwndOwner, const char * initialDir, const char * fileFilter, bool fileMustExist);
Path & BrowseForDirectory(void * parentWindow, const char * title);
bool IsDirectory() const;
bool DirectoryCreate(bool createIntermediates = true);
bool DirectoryChange() const;

View File

@ -46,6 +46,7 @@
<ClCompile Include="user_interface\settings\input_config.cpp" />
<ClCompile Include="user_interface\settings\system_config_audio.cpp" />
<ClCompile Include="user_interface\settings\system_config_debug.cpp" />
<ClCompile Include="user_interface\settings\system_config_game_browser.cpp" />
<ClCompile Include="user_interface\settings\system_config_graphics.cpp" />
</ItemGroup>
<ItemGroup>
@ -60,6 +61,7 @@
<ClInclude Include="user_interface\settings\input_config.h" />
<ClInclude Include="user_interface\settings\system_config_audio.h" />
<ClInclude Include="user_interface\settings\system_config_debug.h" />
<ClInclude Include="user_interface\settings\system_config_game_browser.h" />
<ClInclude Include="user_interface\settings\system_config_graphics.h" />
</ItemGroup>
<ItemGroup>

View File

@ -66,6 +66,9 @@
<ClCompile Include="user_interface\settings\system_config_debug.cpp">
<Filter>Source Files\user_interface\settings</Filter>
</ClCompile>
<ClCompile Include="user_interface\settings\system_config_game_browser.cpp">
<Filter>Source Files\user_interface\settings</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="user_interface\resource.h">
@ -104,6 +107,9 @@
<ClInclude Include="user_interface\settings\system_config_debug.h">
<Filter>Header Files\user_interface\settings</Filter>
</ClInclude>
<ClInclude Include="user_interface\settings\system_config_game_browser.h">
<Filter>Header Files\user_interface\settings</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="user_interface\nxemu.rc">

View File

@ -41,6 +41,7 @@ namespace
static UISetting settings[] = {
{ "RecentFiles", &uiSettings.recentFiles},
{ "GameDirectories", &uiSettings.gameDirectories},
{ "LanguageDirectory", &uiSettings.languageDir, &uiSettings.languageDirValue, GetDefaultLanguageDir(), "./lang"},
{ "LanguageBase", &uiSettings.languageBase, "english"},
{ "LanguageCurrent", &uiSettings.languageCurrent, "english"},
@ -140,12 +141,12 @@ void SaveUISetting(void)
case SettingType::StringList:
if (!setting.setting.string_list->empty())
{
JsonValue recentFiles(JsonValueType::Array);
JsonValue jsonList(JsonValueType::Array);
for (const std::string & item : *(setting.setting.string_list))
{
recentFiles.Append(JsonValue(item));
jsonList.Append(JsonValue(item));
}
json[setting.json_key] = std::move(recentFiles);
json[setting.json_key] = std::move(jsonList);
}
break;
case SettingType::Path:

View File

@ -8,6 +8,7 @@ typedef std::vector<std::string> Stringlist;
struct UISettings
{
Stringlist recentFiles;
Stringlist gameDirectories;
Path languageDir;
std::string languageDirValue;
std::string languageBase;

View File

@ -3,6 +3,7 @@
#include "system_config_audio.h"
#include "system_config_debug.h"
#include "system_config_graphics.h"
#include "system_config_game_browser.h"
#include <common/std_string.h>
#include <nxemu-core/machine/switch_system.h>
#include <nxemu-core/settings/identifiers.h>
@ -31,8 +32,8 @@ void SystemConfig::Display(void * parentWindow)
enum
{
WINDOW_HEIGHT = 300,
WINDOW_WIDTH = 300,
WINDOW_HEIGHT = 720,
WINDOW_WIDTH = 1050,
};
if (!m_sciterUI.WindowCreate(parentWindow, "system_config.html", 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, SUIW_CHILD, m_window))
@ -52,8 +53,8 @@ void SystemConfig::Display(void * parentWindow)
SciterElement okButton = root.FindFirst("button[role=\"window-ok\"]");
m_sciterUI.AttachHandler(okButton, IID_ICLICKSINK, (IClickSink*)this);
}
m_window->CenterWindow();
}
void SystemConfig::SavePage(SCITER_ELEMENT pageElement, const ConfigSetting* settings, size_t settingsCount)
@ -248,7 +249,11 @@ void SystemConfig::PageNavCreatedPage(const std::string & pageName, SCITER_ELEME
else if (pageName == "Graphics")
{
m_systemConfigGraphics.reset(new SystemConfigGraphics(m_sciterUI, *this, m_window->GetHandle(), page));
}
}
else if (pageName == "GameBrowser")
{
m_systemConfigGameBrowser.reset(new SystemConfigGameBrowser(m_sciterUI, *this, *m_window, page));
}
}
void SystemConfig::PageNavPageChanged(const std::string & /*pageName*/, SCITER_ELEMENT /*pageNav*/)
@ -272,6 +277,10 @@ bool SystemConfig::OnClick(SCITER_ELEMENT element, SCITER_ELEMENT /*source*/, ui
{
m_systemConfigGraphics->SaveSetting();
}
if (m_systemConfigGameBrowser)
{
m_systemConfigGameBrowser->SaveSetting();
}
SwitchSystem * system = SwitchSystem::GetInstance();
if (system != nullptr)
{
@ -279,7 +288,7 @@ bool SystemConfig::OnClick(SCITER_ELEMENT element, SCITER_ELEMENT /*source*/, ui
}
m_window->Destroy();
}
return false;
return true;
}
void SystemConfig::InitializeTranslations()

View File

@ -11,6 +11,7 @@ class SciterElement;
class SystemConfigAudio;
class SystemConfigGraphics;
class SystemConfigDebug;
class SystemConfigGameBrowser;
class ConfigSetting;
typedef std::pair<int32_t, std::string> SettingTranslation;
@ -60,4 +61,5 @@ private:
std::unique_ptr<SystemConfigGraphics> m_systemConfigGraphics;
std::unique_ptr<SystemConfigAudio> m_systemConfigAudio;
std::unique_ptr<SystemConfigDebug> m_systemConfigDebug;
std::unique_ptr<SystemConfigGameBrowser> m_systemConfigGameBrowser;
};

View File

@ -0,0 +1,156 @@
#include "config_setting.h"
#include "settings/ui_settings.h"
#include "system_config.h"
#include "system_config_game_browser.h"
#include <common/path.h>
#include <nxemu-core/settings/identifiers.h>
SystemConfigGameBrowser::SystemConfigGameBrowser(ISciterUI & sciterUI, SystemConfig & config, ISciterWindow & window, SciterElement page) :
m_sciterUI(sciterUI),
m_config(config),
m_window(window),
m_page(page)
{
SciterElement pageNav = page.GetElementByID("GameBrowserTabNav");
std::shared_ptr<void> interfacePtr = pageNav.IsValid() ? m_sciterUI.GetElementInterface(pageNav, IID_IPAGENAV) : nullptr;
if (interfacePtr)
{
m_pageNav = std::static_pointer_cast<IPageNav>(interfacePtr);
m_pageNav->AddSink(this);
}
}
bool SystemConfigGameBrowser::PageNavChangeFrom(const std::string& /*pageName*/, SCITER_ELEMENT /*pageNav*/)
{
return true;
}
bool SystemConfigGameBrowser::PageNavChangeTo(const std::string& /*pageName*/, SCITER_ELEMENT /*pageNav*/)
{
return true;
}
void SystemConfigGameBrowser::PageNavCreatedPage(const std::string & pageName, SCITER_ELEMENT page)
{
if (pageName == "GameBrowser")
{
SetupGameBrowserPage(page);
}
}
void SystemConfigGameBrowser::PageNavPageChanged(const std::string& /*pageName*/, SCITER_ELEMENT /*pageNav*/)
{
}
bool SystemConfigGameBrowser::OnClick(SCITER_ELEMENT element, SCITER_ELEMENT source, uint32_t /*reason*/)
{
SciterElement clickElem(element);
std::string elementID = clickElem.GetAttributeByName("id");
if (elementID == "gameDirectoryList")
{
SelectDirectoryItem(clickElem, source);
}
else if (elementID == "gameDirectoryAdd")
{
Path newDirectory = Path().BrowseForDirectory((void*)m_window.GetHandle(), "Select Game Directory");
if (newDirectory.DirectoryExists())
{
AddGameDirectory(newDirectory);
}
}
else if (elementID == "gameDirectoryRemove")
{
RemoveSelectedDirectory();
}
return true;
}
void SystemConfigGameBrowser::SetupGameBrowserPage(SciterElement page)
{
m_gameBrowserPage = page;
SciterElement root(m_window.GetRootElement());
if (root.IsValid())
{
SciterElement gameDirectoryList = root.GetElementByID("gameDirectoryList");
m_sciterUI.AttachHandler(gameDirectoryList, IID_ICLICKSINK, (IClickSink*)this);
SciterElement addButton = root.GetElementByID("gameDirectoryAdd");
m_sciterUI.AttachHandler(addButton, IID_ICLICKSINK, (IClickSink*)this);
SciterElement removeButton = root.GetElementByID("gameDirectoryRemove");
m_sciterUI.AttachHandler(removeButton, IID_ICLICKSINK, (IClickSink*)this);
}
for (size_t i = 0, n = uiSettings.gameDirectories.size(); i < n; i++)
{
AddGameDirectory(uiSettings.gameDirectories[i]);
}
}
void SystemConfigGameBrowser::SelectDirectoryItem(const SciterElement & gameDirectoryList, SCITER_ELEMENT source)
{
SciterElement target = source, directoryItem;
while (target.IsValid() && target != gameDirectoryList)
{
std::string className = target.GetAttribute("class");
if (!className.empty())
{
std::string searchIn = " " + className + " ";
if (searchIn.find(" directory-item ") != std::string::npos)
{
directoryItem = target;
break;
}
}
target = target.GetParent();
}
if (target.IsValid())
{
for (uint32_t i = 0, n = gameDirectoryList.GetChildCount(); i < n; i++)
{
SciterElement(gameDirectoryList.GetChild(i)).SetState(0, SciterElement::STATE_CHECKED, true);
}
target.SetState(SciterElement::STATE_CHECKED, 0, true);
}
}
void SystemConfigGameBrowser::AddGameDirectory(const std::string & directory)
{
SciterElement gameDirectoryList = m_page.GetElementByID("gameDirectoryList");
SciterElement item;
item.Create("div", directory.c_str());
item.SetAttribute("class", "directory-item");
item.SetAttribute("data-dir", directory.c_str());
gameDirectoryList.Insert(item, gameDirectoryList.GetChildCount());
}
void SystemConfigGameBrowser::RemoveSelectedDirectory()
{
SciterElement gameDirectoryList = m_page.GetElementByID("gameDirectoryList");
if (!gameDirectoryList.IsValid())
{
return;
}
for (uint32_t i = 0, n = gameDirectoryList.GetChildCount(); i < n; i++)
{
SciterElement item(gameDirectoryList.GetChild(i));
if ((item.GetState() & SciterElement::STATE_CHECKED) != 0)
{
item.Detach();
break;
}
}
}
void SystemConfigGameBrowser::SaveSetting(void)
{
SciterElement gameDirectoryList = m_page.GetElementByID("gameDirectoryList");
uiSettings.gameDirectories.clear();
for (uint32_t i = 0, n = gameDirectoryList.GetChildCount(); i < n; i++)
{
SciterElement item(gameDirectoryList.GetChild(i));
uiSettings.gameDirectories.push_back(item.GetAttribute("data-dir"));
}
SaveUISetting();
}

View File

@ -0,0 +1,44 @@
#pragma once
#include <sciter_ui.h>
#include <sciter_element.h>
#include <sciter_handler.h>
#include <widgets/page_nav.h>
class SystemConfig;
class SystemConfigGameBrowser :
public IPagesSink,
public IClickSink
{
public:
SystemConfigGameBrowser(ISciterUI & sciterUI, SystemConfig & config, ISciterWindow & window, SciterElement page);
~SystemConfigGameBrowser() = default;
void SaveSetting(void);
// IPagesSink
bool PageNavChangeFrom(const std::string& pageName, SCITER_ELEMENT pageNav) override;
bool PageNavChangeTo(const std::string& pageName, SCITER_ELEMENT pageNav) override;
void PageNavCreatedPage(const std::string& pageName, SCITER_ELEMENT page) override;
void PageNavPageChanged(const std::string& pageName, SCITER_ELEMENT pageNav) override;
// IClickSink
bool OnClick(SCITER_ELEMENT element, SCITER_ELEMENT source, uint32_t reason) override;
private:
SystemConfigGameBrowser() = delete;
SystemConfigGameBrowser(const SystemConfigGameBrowser&) = delete;
SystemConfigGameBrowser& operator=(const SystemConfigGameBrowser&) = delete;
void SetupGameBrowserPage(SciterElement page);
void SelectDirectoryItem(const SciterElement & gameDirectoryList, SCITER_ELEMENT source);
void AddGameDirectory(const std::string& directory);
void RemoveSelectedDirectory();
ISciterUI & m_sciterUI;
SystemConfig & m_config;
ISciterWindow & m_window;
SciterElement m_page;
std::shared_ptr<IPageNav> m_pageNav;
SciterElement m_gameBrowserPage;
};