pause/resume (and should they have hotkeys)
This commit is contained in:
parent
224d34b6e4
commit
cf1172b256
|
|
@ -1,4 +1,11 @@
|
|||
:root {
|
||||
--font-ui: 'Segoe UI', Arial, sans-serif;
|
||||
--color-ui-text-primary: #eff0f1;
|
||||
--color-ui-text-muted: #b0b6bc;
|
||||
--color-statusbar-background: #31363b;
|
||||
--color-statusbar-border: #434242;
|
||||
--color-statusbar-hover-border: #76797c;
|
||||
--color-pause-panel-background: #25282c;
|
||||
--color-main-background: #2d2d2d;
|
||||
--color-titlebar-background: #181818;
|
||||
--color-titlebar-background-inactive: #2d2d2d;
|
||||
|
|
@ -52,7 +59,7 @@ html > header > window-caption
|
|||
line-height: window-caption-height;
|
||||
width: *;
|
||||
padding: 0 1em;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-family: var(--font-ui);
|
||||
font-size: 0.9em;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
|
@ -138,8 +145,8 @@ ul#menu-bar
|
|||
margin: 0;
|
||||
padding: 0 0.5em 0.3em 0.5em;
|
||||
background: var(--color-menubar-background);
|
||||
color: #eff0f1;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
color: var(--color-ui-text-primary);
|
||||
font-family: var(--font-ui);
|
||||
font-size: 0.9em;
|
||||
font-weight: 100;
|
||||
behavior:menu-bar;
|
||||
|
|
|
|||
|
|
@ -6,12 +6,12 @@
|
|||
|
||||
#StatusBar
|
||||
{
|
||||
background: #31363b;
|
||||
background: var(--color-statusbar-background);
|
||||
flow: horizontal;
|
||||
color: #eff0f1;
|
||||
color: var(--color-ui-text-primary);
|
||||
padding: 0.2em 1em;
|
||||
border-top: 1px solid #434242;
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
border-top: 1px solid var(--color-statusbar-border);
|
||||
font-family: var(--font-ui);
|
||||
font-size: 0.8em;
|
||||
font-weight: 100;
|
||||
height: 1.6rem;
|
||||
|
|
@ -37,24 +37,60 @@
|
|||
#StatusBar #volume:hover,
|
||||
#StatusBar #renderer:hover
|
||||
{
|
||||
border: 1px solid #76797c;
|
||||
border: 1px solid var(--color-statusbar-hover-border);
|
||||
}
|
||||
|
||||
#VolumePopup
|
||||
{
|
||||
background: #31363b;
|
||||
border: 1px solid #434242;
|
||||
background: var(--color-statusbar-background);
|
||||
border: 1px solid var(--color-statusbar-border);
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
#RomBrowserPanel,
|
||||
#LoadingPanel
|
||||
.main-contents-panel
|
||||
{
|
||||
width: 100%%;
|
||||
height: 100%%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#PausePanel
|
||||
{
|
||||
background: var(--color-pause-panel-background);
|
||||
color: var(--color-ui-text-primary);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#PausePanel .pause-panel-container
|
||||
{
|
||||
width: 100%%;
|
||||
height: 100%%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
padding: 2rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#PausePanel .pause-panel-title
|
||||
{
|
||||
font-family: var(--font-ui);
|
||||
font-size: 2rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 0.5rem;
|
||||
}
|
||||
|
||||
#PausePanel .pause-panel-subtitle
|
||||
{
|
||||
font-family: var(--font-ui);
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
color: var(--color-ui-text-muted);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
rombrowser
|
||||
{
|
||||
display: block;
|
||||
|
|
@ -83,7 +119,7 @@ rombrowser .config-button svg
|
|||
|
||||
rombrowser .config-button .outline
|
||||
{
|
||||
fill: #eff0f1;
|
||||
fill: var(--color-ui-text-primary);
|
||||
}
|
||||
|
||||
rombrowser .config-button:hover .outline
|
||||
|
|
@ -104,10 +140,10 @@ rombrowser .config-button:hover
|
|||
|
||||
rombrowser .games-title h1
|
||||
{
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-family: var(--font-ui);
|
||||
font-size: 1.5rem;
|
||||
font-weight: 400;
|
||||
color: #eff0f1;
|
||||
color: var(--color-ui-text-primary);
|
||||
padding: 0 0 0.6rem;
|
||||
margin: 0;
|
||||
width:*
|
||||
|
|
|
|||
|
|
@ -14,10 +14,10 @@
|
|||
</header>
|
||||
<mainmenu id="MainMenu" />
|
||||
<div id="MainContents">
|
||||
<div id="RomBrowserPanel">
|
||||
<div id="RomBrowserPanel" class="main-contents-panel">
|
||||
<rombrowser />
|
||||
</div>
|
||||
<div id="LoadingPanel">
|
||||
<div id="LoadingPanel" class="main-contents-panel">
|
||||
<div class="loading-container">
|
||||
<div class="loading-text"><span class="text">Loading</span>
|
||||
<div class="dot-pulse-container">
|
||||
|
|
@ -28,6 +28,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="PausePanel" class="main-contents-panel">
|
||||
<div class="pause-panel-container">
|
||||
<div class="pause-panel-title">Paused</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="StatusBar" ><span id="renderer" /><span id="volume" /><div id="StatusText" /></div>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ enum
|
|||
MODULE_LOADER_SPECS_VERSION = 0x0119,
|
||||
MODULE_VIDEO_SPECS_VERSION = 0x0116,
|
||||
MODULE_CPU_SPECS_VERSION = 0x010D,
|
||||
MODULE_OPERATING_SYSTEM_SPECS_VERSION = 0x0111,
|
||||
MODULE_OPERATING_SYSTEM_SPECS_VERSION = 0x0112,
|
||||
};
|
||||
|
||||
enum MODULE_TYPE : uint16_t
|
||||
|
|
|
|||
|
|
@ -431,6 +431,8 @@ nxinterface IOperatingSystem
|
|||
virtual IParamPackage * GetNextInput() const = 0;
|
||||
virtual void PumpInputEvents() const = 0;
|
||||
virtual PerfStatsResults GetAndResetPerfStats() = 0;
|
||||
virtual void SetEmulationPaused(bool paused) = 0;
|
||||
virtual bool IsEmulationPaused() const = 0;
|
||||
};
|
||||
|
||||
EXPORT IOperatingSystem * CALL CreateOperatingSystem(ISystemModules & modules);
|
||||
|
|
|
|||
|
|
@ -35,12 +35,29 @@ public:
|
|||
while (!stop_token.stop_requested())
|
||||
{
|
||||
std::unique_lock lk{m_should_run_mutex};
|
||||
if (m_should_run)
|
||||
if (m_should_run.load(std::memory_order_relaxed))
|
||||
{
|
||||
m_system.Run();
|
||||
m_stopped.Reset();
|
||||
|
||||
Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] { return !m_should_run; });
|
||||
Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] {
|
||||
return !m_should_run.load(std::memory_order_relaxed);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
m_system.Pause();
|
||||
m_stopped.Set();
|
||||
g_settings->SetInt(NXCoreSetting::EmulationState, (int32_t)EmulationState::Paused);
|
||||
|
||||
Common::CondvarWait(m_should_run_cv, lk, stop_token, [&] {
|
||||
return m_should_run.load(std::memory_order_relaxed);
|
||||
});
|
||||
|
||||
if (!stop_token.stop_requested())
|
||||
{
|
||||
g_settings->SetInt(NXCoreSetting::EmulationState, (int32_t)EmulationState::Running);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -63,7 +80,7 @@ public:
|
|||
std::mutex m_should_run_mutex;
|
||||
std::condition_variable_any m_should_run_cv;
|
||||
Common::Event m_stopped;
|
||||
bool m_should_run;
|
||||
std::atomic<bool> m_should_run;
|
||||
Core::System & m_system;
|
||||
Kernel::KProcess *& m_process;
|
||||
};
|
||||
|
|
@ -102,7 +119,7 @@ void EmuThread::SetRunning(bool should_run)
|
|||
{
|
||||
// Notify the running thread to change state.
|
||||
std::unique_lock run_lk{impl->m_should_run_mutex};
|
||||
impl->m_should_run = should_run;
|
||||
impl->m_should_run.store(should_run, std::memory_order_release);
|
||||
impl->m_should_run_cv.notify_one();
|
||||
}
|
||||
|
||||
|
|
@ -111,4 +128,9 @@ void EmuThread::SetRunning(bool should_run)
|
|||
{
|
||||
impl->m_stopped.Wait();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool EmuThread::IsRunning() const
|
||||
{
|
||||
return impl->m_should_run.load(std::memory_order_acquire);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ public:
|
|||
void Start();
|
||||
void Stop();
|
||||
void SetRunning(bool should_run);
|
||||
bool IsRunning() const;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
|
|
|
|||
|
|
@ -356,3 +356,21 @@ PerfStatsResults OSManager::GetAndResetPerfStats()
|
|||
{
|
||||
return m_coreSystem.GetAndResetPerfStats();
|
||||
}
|
||||
|
||||
void OSManager::SetEmulationPaused(bool paused)
|
||||
{
|
||||
if (!m_emuThread)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_emuThread->SetRunning(!paused);
|
||||
}
|
||||
|
||||
bool OSManager::IsEmulationPaused() const
|
||||
{
|
||||
if (!m_emuThread)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !m_emuThread->IsRunning();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,8 @@ public:
|
|||
IParamPackage * GetNextInput() const override;
|
||||
void PumpInputEvents() const override;
|
||||
PerfStatsResults GetAndResetPerfStats() override;
|
||||
void SetEmulationPaused(bool paused) override;
|
||||
bool IsEmulationPaused() const override;
|
||||
|
||||
private:
|
||||
OSManager() = delete;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace
|
|||
{Hotkey::Exit, {.key = (uint32_t)SCITER_KEY_Q, .ctrl = true}},
|
||||
{Hotkey::Fullscreen, {.key = (uint32_t)SCITER_KEY_F11, .ctrl = false, .alt = false, .shift = false}},
|
||||
{Hotkey::ExitFullscreen, {.key = (uint32_t)SCITER_KEY_ESCAPE, .ctrl = false, .alt = false, .shift = false}},
|
||||
{Hotkey::PauseContinue, {.key = (uint32_t)SCITER_KEY_F4}},
|
||||
};
|
||||
|
||||
void merge_default_hotkeys(HotkeyMap & map)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ constexpr const char LoadFile[] = "LoadFile";
|
|||
constexpr const char Exit[] = "Exit";
|
||||
constexpr const char Fullscreen[] = "Fullscreen";
|
||||
constexpr const char ExitFullscreen[] = "ExitFullscreen";
|
||||
constexpr const char PauseContinue[] = "PauseContinue";
|
||||
}
|
||||
|
||||
using HotkeyMap = std::map<std::string, MenuBarAccelerator>;
|
||||
|
|
|
|||
|
|
@ -167,6 +167,16 @@ void SciterMainWindow::ResetMenu()
|
|||
MenuBarItemList systemMenu;
|
||||
if (m_emulationRunning)
|
||||
{
|
||||
bool paused = false;
|
||||
if (m_modules.IsValid())
|
||||
{
|
||||
paused = m_modules.Modules().OperatingSystem().IsEmulationPaused();
|
||||
}
|
||||
systemMenu.push_back(MenuBarItem(
|
||||
ID_SYSTEM_PAUSE_CONTINUE,
|
||||
paused ? "Continue" : "Pause",
|
||||
nullptr,
|
||||
HotkeyAccelerator(Hotkey::PauseContinue)));
|
||||
systemMenu.push_back(MenuBarItem(ID_SYSTEM_STOP, "&Stop"));
|
||||
mainTitleMenu.push_back(MenuBarItem(MenuBarItem::SUB_MENU, "&System", &systemMenu));
|
||||
}
|
||||
|
|
@ -335,6 +345,8 @@ void SciterMainWindow::CreateRenderWindow()
|
|||
IVideo & video = m_modules.Modules().Video();
|
||||
video.UpdateFramebufferLayout(rect.right - rect.left, rect.bottom - rect.top);
|
||||
}
|
||||
|
||||
UpdatePausePanel();
|
||||
}
|
||||
|
||||
void SciterMainWindow::SetCaption(const std::string & caption)
|
||||
|
|
@ -385,11 +397,17 @@ void SciterMainWindow::EmulationStateChanged(const char * /*setting*/, void * us
|
|||
else if (state == EmulationState::Running)
|
||||
{
|
||||
impl->m_rootElement.PostEvent(EVENT_EMULATION_RUNNING);
|
||||
impl->ResetMenu();
|
||||
}
|
||||
else if (state == EmulationState::Paused)
|
||||
{
|
||||
impl->ResetMenu();
|
||||
}
|
||||
else if (state == EmulationState::Stopped)
|
||||
{
|
||||
impl->m_rootElement.PostEvent(EVENT_EMULATION_STOPPED);
|
||||
}
|
||||
impl->UpdatePausePanel();
|
||||
}
|
||||
|
||||
void SciterMainWindow::GameFileChanged(const char * /*setting*/, void * userData)
|
||||
|
|
@ -493,6 +511,26 @@ void SciterMainWindow::OnStopGame()
|
|||
settings.SetBool(NXCoreSetting::EmulationRunning, false);
|
||||
}
|
||||
|
||||
void SciterMainWindow::OnPauseContinueGame()
|
||||
{
|
||||
if (!m_emulationRunning || !m_modules.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
IOperatingSystem & os = m_modules.Modules().OperatingSystem();
|
||||
if (os.IsEmulationPaused())
|
||||
{
|
||||
PreventOSSleep();
|
||||
os.SetEmulationPaused(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
os.SetEmulationPaused(true);
|
||||
AllowOSSleep();
|
||||
}
|
||||
ResetMenu();
|
||||
}
|
||||
|
||||
void SciterMainWindow::OnSystemConfig()
|
||||
{
|
||||
ShowConfig(nullptr);
|
||||
|
|
@ -526,10 +564,19 @@ void SciterMainWindow::UpdateStatusBar()
|
|||
IVideo & video = m_modules.Modules().Video();
|
||||
std::string status;
|
||||
|
||||
if (operatingSystem.IsEmulationPaused())
|
||||
{
|
||||
status += "Paused";
|
||||
}
|
||||
|
||||
const int shaders_building = video.ShadersBuilding();
|
||||
|
||||
if (shaders_building > 0)
|
||||
{
|
||||
if (!status.empty())
|
||||
{
|
||||
status += " | ";
|
||||
}
|
||||
status += stdstr_f("Building: %d shader(s)", shaders_building);
|
||||
}
|
||||
|
||||
|
|
@ -603,6 +650,11 @@ bool SciterMainWindow::ProcessMenuBarAccelerator(const char * hotkeyId)
|
|||
OnFileExit();
|
||||
return true;
|
||||
}
|
||||
if (strcmp(hotkeyId, Hotkey::PauseContinue) == 0)
|
||||
{
|
||||
OnPauseContinueGame();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -626,6 +678,7 @@ void SciterMainWindow::OnMenuItem(int32_t id, SCITER_ELEMENT /*item*/)
|
|||
{
|
||||
case ID_FILE_LOAD_FILE: OnOpenFile(); break;
|
||||
case ID_FILE_EXIT: OnFileExit(); break;
|
||||
case ID_SYSTEM_PAUSE_CONTINUE: OnPauseContinueGame(); break;
|
||||
case ID_SYSTEM_STOP: OnStopGame(); break;
|
||||
case ID_EMULATION_CONTROLLERS: OnInputConfig(); break;
|
||||
case ID_EMULATION_CONFIGURE: OnSystemConfig(); break;
|
||||
|
|
@ -753,6 +806,37 @@ void SciterMainWindow::LayoutRenderWindow()
|
|||
IVideo & video = m_modules.Modules().Video();
|
||||
video.UpdateFramebufferLayout(width, height);
|
||||
}
|
||||
UpdatePausePanel();
|
||||
}
|
||||
|
||||
void SciterMainWindow::UpdatePausePanel()
|
||||
{
|
||||
SciterElement panel(m_rootElement.GetElementByID("PausePanel"));
|
||||
if (!panel.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const bool paused =
|
||||
m_emulationRunning && m_modules.IsValid() && m_modules.Modules().OperatingSystem().IsEmulationPaused();
|
||||
|
||||
panel.SetStyleAttribute("display", paused ? "block" : "none");
|
||||
|
||||
if (m_renderWindow == nullptr || !m_emulationRunning)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (paused)
|
||||
{
|
||||
ShowWindow((HWND)m_renderWindow, SW_HIDE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SettingsStore & settings = SettingsStore::GetInstance();
|
||||
const bool showRender = settings.GetBool(NXCoreSetting::DisplayedFrames);
|
||||
ShowWindow((HWND)m_renderWindow, showRender ? SW_SHOW : SW_HIDE);
|
||||
}
|
||||
}
|
||||
|
||||
void SciterMainWindow::ToggleFullscreen()
|
||||
|
|
@ -1064,6 +1148,7 @@ bool SciterMainWindow::OnEvent(SCITER_ELEMENT /*element*/, SCITER_ELEMENT /*sour
|
|||
{
|
||||
romBrowserPanel.SetStyleAttribute("display", "block");
|
||||
}
|
||||
UpdatePausePanel();
|
||||
}
|
||||
else if (event_code == EVENT_EMULATION_FIRST_FRAME)
|
||||
{
|
||||
|
|
@ -1077,6 +1162,7 @@ bool SciterMainWindow::OnEvent(SCITER_ELEMENT /*element*/, SCITER_ELEMENT /*sour
|
|||
LoadingPanel.SetStyleAttribute("display", "none");
|
||||
}
|
||||
}
|
||||
UpdatePausePanel();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ class SciterMainWindow :
|
|||
ID_FILE_EXIT,
|
||||
|
||||
// System Menu
|
||||
ID_SYSTEM_PAUSE_CONTINUE,
|
||||
ID_SYSTEM_STOP,
|
||||
|
||||
// Emulation Menu
|
||||
|
|
@ -94,6 +95,7 @@ private:
|
|||
void OnOpenFile();
|
||||
void OnFileExit();
|
||||
void OnStopGame();
|
||||
void OnPauseContinueGame();
|
||||
void OnSystemConfig();
|
||||
void OnInputConfig();
|
||||
void OnRecetGame(uint32_t fileIndex);
|
||||
|
|
@ -112,6 +114,7 @@ private:
|
|||
void ResetWindowSize1080();
|
||||
#endif
|
||||
void LayoutRenderWindow();
|
||||
void UpdatePausePanel();
|
||||
|
||||
// IWindowDestroySink
|
||||
void OnWindowDestroy(HWINDOW hWnd) override;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ static const HotkeyLabelEntry kHotkeyLabels[] = {
|
|||
{Hotkey::Exit, "Exit"},
|
||||
{Hotkey::Fullscreen, "Fullscreen"},
|
||||
{Hotkey::ExitFullscreen, "Exit Fullscreen"},
|
||||
{Hotkey::PauseContinue, "Pause / Continue"},
|
||||
};
|
||||
|
||||
std::string HotkeyBindingElementId(const std::string & hotkeyId)
|
||||
|
|
|
|||
Loading…
Reference in New Issue