more work with the sciter window, like getting it to show a loading screen

This commit is contained in:
N3xoX1 2025-04-08 21:15:43 +09:30
parent fd68d44258
commit 9a6b89f00c
14 changed files with 240 additions and 20 deletions

2
external/sciterui vendored

@ -1 +1 @@
Subproject commit ae16bf646df94d1bd15a9a5fd63335ed56deceb0
Subproject commit a6b88385f3e903011502d8257ffb08035b6c49cb

View File

@ -199,3 +199,9 @@ menu li:has-child-of-type(menu):rtl
foreground-repeat: no-repeat;
foreground-position: top 50% left 2px;
}
#MainContents
{
width: 100%%;
height: 100%%;
}

View File

@ -0,0 +1,64 @@
<style>
.loading-container {
width: 100%%;
height: 100%%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: black;
color: white;
overflow: hidden;
text-align: center;
}
.loading-text {
font-size: 2em;
margin: 50%% 0;
}
.loading-text > text
{
display: inline-block;
}
.dot-pulse-container {
display: inline-block;
justify-content: center;
align-items: center;
}
.dot-pulse {
display: inline-block;
width: 0.3em;
height: 0.3em;
margin: 0 0;
border-radius: 50%;
background-color: white;
animation: dot-pulse 1.5s infinite ease-in-out;
}
.dot-pulse:nth-child(1) { animation-delay: 0s; }
.dot-pulse:nth-child(2) { animation-delay: 0.5s; }
.dot-pulse:nth-child(3) { animation-delay: 1s; }
@keyframes dot-pulse {
0%, 100% {
opacity: 0.2;
transform: scale(0.75);
}
50% {
opacity: 1;
transform: scale(1.25);
}
}
</style>
<div class="loading-container">
<div class="loading-text"><span class="text">Loading</span>
<div class="dot-pulse-container">
<div class="dot-pulse"></div>
<div class="dot-pulse"></div>
<div class="dot-pulse"></div>
</div>
</div>
</div>

View File

@ -11,4 +11,5 @@
</window-buttons>
</header>
<mainmenu id="MainMenu" />
<div id="MainContents" />
</html>

View File

@ -19,6 +19,9 @@ struct CoreSettingsDefaults
static constexpr const char * defaultModuleOperatingSystem = "operating_system\\nxemu-os.dll";
#endif
static constexpr bool defaultShowConsole = false;
static constexpr bool defaultRomLoading = false;
static constexpr bool defaultEmulationRunning = false;
static constexpr bool defaultDisplayedFrames = false;
static Path GetDefaultModuleDir();
};
@ -63,6 +66,10 @@ void LoadCoreSetting(void)
settings.SetDefaultString(NXCoreSetting::ModuleOsSelected, CoreSettingsDefaults::defaultModuleOperatingSystem);
settings.SetDefaultBool(NXCoreSetting::ShowConsole, CoreSettingsDefaults::defaultShowConsole);
settings.SetDefaultBool(NXCoreSetting::RomLoading, CoreSettingsDefaults::defaultRomLoading);
settings.SetDefaultBool(NXCoreSetting::EmulationRunning, CoreSettingsDefaults::defaultEmulationRunning);
settings.SetDefaultBool(NXCoreSetting::DisplayedFrames, CoreSettingsDefaults::defaultDisplayedFrames);
coreSettings.moduleCpuSelected = CoreSettingsDefaults::defaultModuleCpu;
coreSettings.moduleVideoSelected = CoreSettingsDefaults::defaultModuleVideo;
coreSettings.moduleOsSelected = CoreSettingsDefaults::defaultModuleOperatingSystem;

View File

@ -8,4 +8,8 @@ constexpr const char * ModuleCpuSelected = "nxcore:ModuleCpuSelected";
constexpr const char * ModuleVideoSelected = "nxcore:ModuleVideoSelected";
constexpr const char * ModuleOsSelected = "nxcore:ModuleOsSelected";
constexpr const char * ShowConsole = "nxcore:ShowConsole";
constexpr const char * RomLoading = "nxcore:RomLoading";
constexpr const char * EmulationRunning = "nxcore:EmulationRunning";
constexpr const char * DisplayedFrames = "nxcore:DisplayedFrames";
} // namespace NXCoreSetting

View File

@ -1,8 +1,17 @@
#include "switch_rom.h"
#include <nxemu-core/settings/identifiers.h>
#include "machine/switch_system.h"
#include "settings/settings.h"
#include "switch_rom.h"
bool LaunchSwitchRom(IRenderWindow & window, const char * romFile)
{
Settings & settings = Settings::GetInstance();
settings.SetBool(NXCoreSetting::RomLoading, true);
// settings on rom loading, emulation running, content rendering
//
// hide rom list, show loading screen
// hide loading screen on first frame
if (!SwitchSystem::Create(window))
{
return false;
@ -12,6 +21,8 @@ bool LaunchSwitchRom(IRenderWindow & window, const char * romFile)
{
return false;
}
settings.SetBool(NXCoreSetting::RomLoading, false);
settings.SetBool(NXCoreSetting::EmulationRunning, true);
system->StartEmulation();
return true;
}

View File

@ -4,6 +4,9 @@
#include <Windows.h>
#include <glad/glad.h>
#include <nxemu-module-spec/video.h>
#include <nxemu-core/settings/identifiers.h>
extern IModuleSettings * g_settings;
class OpenGLSharedContext : public Core::Frontend::GraphicsContext
{
@ -93,7 +96,8 @@ class DummyContext : public Core::Frontend::GraphicsContext
};
RenderWindow::RenderWindow(IRenderWindow & renderWindow) :
m_renderWindow(renderWindow)
m_renderWindow(renderWindow),
m_firstFrame(false)
{
NotifyClientAreaSizeChanged({ 0,0 });
UpdateCurrentFramebufferLayout(640, 480);
@ -106,6 +110,11 @@ RenderWindow::RenderWindow(IRenderWindow & renderWindow) :
void RenderWindow::OnFrameDisplayed()
{
if (!m_firstFrame)
{
m_firstFrame = true;
g_settings->SetBool(NXCoreSetting::DisplayedFrames, true);
}
}
std::unique_ptr<Core::Frontend::GraphicsContext> RenderWindow::CreateSharedContext() const

View File

@ -19,4 +19,5 @@ private:
void LoadOpenGL();
IRenderWindow & m_renderWindow;
bool m_firstFrame;
};

View File

@ -29,7 +29,7 @@ int WINAPI WinMain(_In_ HINSTANCE /*hInstance*/, _In_opt_ HINSTANCE /*hPrevInsta
if (Res)
{
RegisterWidgets(*sciterUI);
SciterMainWindow window(*sciterUI);
SciterMainWindow window(*sciterUI, stdstr_f("NXEmu %s", VER_FILE_VERSION_STR).c_str());
window.Show();
sciterUI->Run();
}

View File

@ -93,7 +93,14 @@ void SaveUISetting(void)
{
json["EnableModuleConfiguration"] = JsonValue(uiSettings.enableModuleConfiguration);
}
if (uiSettings.sciterUI != UISettingsDefaults::sciterUI)
{
json["SciterUI"] = JsonValue(uiSettings.sciterUI);
}
if (uiSettings.languageDirValue != UISettingsDefaults::defaultLanguageDirValue)
{
json["LanguageDirectory"] = JsonValue(uiSettings.languageDirValue);
}
Settings & settings = Settings::GetInstance();
settings.SetSettings("UI", json);
settings.Save();

View File

@ -226,7 +226,7 @@ void * MainWindow::RenderSurface(void) const
void MainWindow::GameNameChanged(void)
{
std::string gameName = Settings::GetInstance().GetString("nxcore:GameName");
std::string gameName = Settings::GetInstance().GetString(NXCoreSetting::GameName);
if (gameName.length() > 0)
{
std::wstring Caption;

View File

@ -1,16 +1,26 @@
#include "sciter_main_window.h"
#include "settings/settings_config.h"
#include "settings/ui_settings.h"
#include <Windows.h>
#include <common/std_string.h>
#include <nxemu-core/settings/identifiers.h>
#include <nxemu-core/settings/settings.h>
#include <nxemu-core/switch_rom.h>
#include <nxemu-core/version.h>
#include <sciter_element.h>
#include <widgets/menubar.h>
SciterMainWindow::SciterMainWindow(ISciterUI & SciterUI) :
SciterMainWindow::SciterMainWindow(ISciterUI & SciterUI, const char * windowTitle) :
m_sciterUI(SciterUI),
m_window(nullptr),
m_renderWindow(nullptr)
m_renderWindow(nullptr),
m_windowTitle(windowTitle)
{
Settings & settings = Settings::GetInstance();
settings.RegisterCallback(NXCoreSetting::GameFile, std::bind(&SciterMainWindow::GameFileChanged, this));
settings.RegisterCallback(NXCoreSetting::GameName, std::bind(&SciterMainWindow::GameNameChanged, this));
settings.RegisterCallback(NXCoreSetting::RomLoading, std::bind(&SciterMainWindow::RomLoadingChanged, this));
settings.RegisterCallback(NXCoreSetting::DisplayedFrames, std::bind(&SciterMainWindow::DisplayedFramesChanged, this));
}
void SciterMainWindow::ResetMenu()
@ -63,27 +73,113 @@ bool SciterMainWindow::Show(void)
{
return false;
}
SciterElement rootElement(m_window->GetRootElement());
m_window->OnDestroySinkAdd(this);
m_window->CenterWindow();
stdstr_f windowTitle("NxEmu - %s", VER_FILE_VERSION_STR);
SciterElement rootElement(m_window->GetRootElement());
rootElement.Eval(stdstr_f("Window.this.caption = \"%s\";", windowTitle.c_str()).c_str());
SciterElement caption(rootElement.FindFirst("[role='window-caption'] > span"));
if (caption.IsValid())
{
caption.SetHTML((uint8_t *)windowTitle.data(), windowTitle.size());
}
SetCaption(m_windowTitle);
SciterElement menuElement(rootElement.GetElementByID("MainMenu"));
void * interfacePtr = nullptr;
if (menuElement.IsValid() && m_sciterUI.GetElementInterface(menuElement, IID_IMENUBAR, &interfacePtr))
{
m_menuBar = std::shared_ptr<IMenuBar>(reinterpret_cast<IMenuBar *>(interfacePtr), [](IMenuBar *) {});
m_menuBar = std::shared_ptr<IMenuBar>(reinterpret_cast<IMenuBar *>(interfacePtr), [](IMenuBar*) {});
ResetMenu();
}
m_sciterUI.UpdateWindow(rootElement.GetElementHwnd(true));
SciterElement::RECT rect = { 20, 20, 660, 500 };
SciterElement mainContents(rootElement.GetElementByID("MainContents"));
if (mainContents.IsValid())
{
rect = mainContents.GetLocation();
}
m_renderWindow = CreateWindowExW(0, L"Static", L"", WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
rect.left, rect.top, rect.right, rect.bottom, (HWND)m_window->GetHandle(), nullptr, GetModuleHandle(nullptr), nullptr);
ShowWindow((HWND)m_renderWindow, SW_HIDE);
return true;
}
void SciterMainWindow::ShowLoadingScreen()
{
SciterElement rootElement(m_window->GetRootElement());
SciterElement mainContents(rootElement.GetElementByID("MainContents"));
if (mainContents.IsValid())
{
m_sciterUI.SetElementHtmlFromResource(mainContents, "loading.html");
}
}
void SciterMainWindow::SetCaption(const std::string & caption)
{
SciterElement rootElement(m_window->GetRootElement());
rootElement.Eval(stdstr_f("Window.this.caption = \"%s\";", caption.c_str()).c_str());
SciterElement captionElement(rootElement.FindFirst("[role='window-caption'] > span"));
if (captionElement.IsValid())
{
captionElement.SetHTML((uint8_t*)caption.data(), caption.size());
}
}
void SciterMainWindow::GameFileChanged(void)
{
enum
{
maxRememberedFiles = 10
};
Stringlist& recentFiles = uiSettings.recentFiles;
std::string gameFile = Settings::GetInstance().GetString(NXCoreSetting::GameFile);
for (Stringlist::const_iterator itr = recentFiles.begin(); itr != recentFiles.end(); itr++)
{
if (_stricmp(gameFile.c_str(), itr->c_str()) != 0)
{
continue;
}
recentFiles.erase(itr);
break;
}
recentFiles.insert(recentFiles.begin(), gameFile);
if (recentFiles.size() > maxRememberedFiles)
{
recentFiles.resize(maxRememberedFiles);
}
ResetMenu();
SaveUISetting();
}
void SciterMainWindow::GameNameChanged(void)
{
std::string gameName = Settings::GetInstance().GetString(NXCoreSetting::GameName);
if (gameName.length() > 0)
{
std::string caption;
caption += gameName;
caption += " | ";
caption += m_windowTitle;
SetCaption(caption);
}
}
void SciterMainWindow::RomLoadingChanged(void)
{
bool loading = Settings::GetInstance().GetBool(NXCoreSetting::RomLoading);
if (loading)
{
ShowLoadingScreen();
}
}
void SciterMainWindow::DisplayedFramesChanged(void)
{
SciterElement rootElement(m_window->GetRootElement());
SciterElement mainContents(rootElement.GetElementByID("MainContents"));
if (mainContents.IsValid())
{
mainContents.SetHTML((uint8_t*)"", 0, SciterElement::SIH_REPLACE_CONTENT);
}
ShowWindow((HWND)m_renderWindow, SW_SHOW);
}
void SciterMainWindow::OnOpenGame(void)
{
Path fileToOpen;
@ -101,10 +197,16 @@ void SciterMainWindow::OnFileExit(void)
void SciterMainWindow::OnSettings(void)
{
SettingConfig().Display((HWND)m_window->GetHandle());
}
void SciterMainWindow::OnRecetGame(uint32_t fileIndex)
{
Stringlist & recentFiles = uiSettings.recentFiles;
if (fileIndex < recentFiles.size())
{
LaunchSwitchRom(*this, recentFiles[fileIndex].c_str());
}
}
void SciterMainWindow::OnWindowDestroy(HWINDOW /*hWnd*/)
@ -112,7 +214,7 @@ void SciterMainWindow::OnWindowDestroy(HWINDOW /*hWnd*/)
m_sciterUI.Stop();
}
void SciterMainWindow::OnMenuItem(int32_t id, SCITER_ELEMENT item)
void SciterMainWindow::OnMenuItem(int32_t id, SCITER_ELEMENT /*item*/)
{
switch (id)
{

View File

@ -24,7 +24,7 @@ class SciterMainWindow :
};
public:
SciterMainWindow(ISciterUI & SciterUI);
SciterMainWindow(ISciterUI & SciterUI, const char * windowTitle);
void ResetMenu();
bool Show(void);
@ -34,6 +34,13 @@ private:
SciterMainWindow(const SciterMainWindow &) = delete;
SciterMainWindow & operator=(const SciterMainWindow &) = delete;
void SetCaption(const std::string& caption);
void GameFileChanged(void);
void GameNameChanged(void);
void RomLoadingChanged(void);
void DisplayedFramesChanged(void);
void ShowLoadingScreen(void);
void OnOpenGame(void);
void OnFileExit(void);
void OnSettings(void);
@ -52,4 +59,5 @@ private:
ISciterWindow * m_window;
std::shared_ptr<IMenuBar> m_menuBar;
void * m_renderWindow;
std::string m_windowTitle;
};