mirror of
https://github.com/dhewm/dhewm3.git
synced 2024-11-29 07:32:25 +00:00
Dhewm3SettingsMenu: Improve cursor handling and opening menu ingame
Pause the game (with g_stopTime) when the settings menu is opened while ingame, unpause it when it's closed. If the menu is open while ingame and an ImGui window has focus, the mouse cursor is shown. If the player clicks outside an ImGui window, it gets unfocused and the cursor is hidden and the player can look around. Pressing F10 (or whatever key is bound to "dhewm3Settings") will give focus back to an open ImGui window, pressing it again then will close the settings window, pressing it once again afterwards will open the settings window again. handleMouseGrab() (in sys/events.cpp) now checks if sys_imgui thinks that a cursor should be shown (via D3::ImGuiHooks::ShouldShowCursor()) and if so, shows it and ungrabs the mouse. This, together with D3::ImGuiHooks::NewFrame() checking ShouldShowCursor() to (unset) ImGuiConfigFlags_NoMouseCursorChange, should prevent flickering cursor problems that sometimes occurred when ImGui's SDL2 backend and dhewm3 disagreed on whether the cursor should be visible.
This commit is contained in:
parent
c0b6660389
commit
4bdee4f638
4 changed files with 102 additions and 10 deletions
|
@ -8,8 +8,8 @@
|
|||
|
||||
#include "KeyInput.h"
|
||||
#include "UsercmdGen.h" // key bindings
|
||||
//#include "Game.h" // idGameEdit to access entity definitions (player, weapons)
|
||||
#include "DeclEntityDef.h"
|
||||
#include "Session_local.h" // sessLocal.GetActiveMenu()
|
||||
|
||||
#include "sys/sys_imgui.h"
|
||||
#include "../libs/imgui/imgui_internal.h"
|
||||
|
@ -1697,24 +1697,59 @@ void Com_DrawDhewm3SettingsMenu()
|
|||
}
|
||||
}
|
||||
|
||||
void Com_InitDhewm3SettingsMenu()
|
||||
static void InitDhewm3SettingsMenu()
|
||||
{
|
||||
InitOptions( controlOptions, IM_ARRAYSIZE(controlOptions) );
|
||||
InitBindingEntries();
|
||||
InitOptions( controlOptions, IM_ARRAYSIZE(controlOptions) );
|
||||
|
||||
}
|
||||
|
||||
// !! Don't call this function directly, always use !!
|
||||
// !! D3::ImGuiHooks::OpenWindow( D3::ImGuiHooks::D3_ImGuiWin_Settings ) !!
|
||||
// !! or D3::ImGuiHooks::CloseWindow( D3::ImGuiHooks::D3_ImGuiWin_Settings ) !!
|
||||
// (unless you're implementing those two functions, they call this..)
|
||||
void Com_OpenCloseDhewm3SettingsMenu( bool open )
|
||||
{
|
||||
if ( open ) {
|
||||
if ( !sessLocal.IsMultiplayer() ) {
|
||||
// if we're in a SP game, pause the game.
|
||||
// g_stopTime is the best we have for this..
|
||||
// advantage of this, compared to the main menu with its settings menu:
|
||||
// gamma and brightness can be modified and the effect is visible in realtime,
|
||||
// but (at least in SP..) the player is still safe from monsters while doing this
|
||||
idCVar* stopTime = cvarSystem->Find( "g_stoptime" );
|
||||
if ( stopTime != nullptr ) {
|
||||
stopTime->SetBool( true );
|
||||
}
|
||||
}
|
||||
|
||||
InitDhewm3SettingsMenu();
|
||||
} else {
|
||||
// unset g_stopTime (no matter if we're in MP now, maybe we weren't
|
||||
// when the menu was opened, just set it to false now to be sure)
|
||||
idCVar* stopTime = cvarSystem->Find( "g_stoptime" );
|
||||
if ( stopTime != nullptr ) {
|
||||
stopTime->SetBool( false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Com_Dhewm3Settings_f( const idCmdArgs &args )
|
||||
{
|
||||
bool menuOpen = (D3::ImGuiHooks::GetOpenWindowsMask() & D3::ImGuiHooks::D3_ImGuiWin_Settings) != 0;
|
||||
if ( !menuOpen ) {
|
||||
// TODO: if in SP game, pause
|
||||
|
||||
Com_InitDhewm3SettingsMenu();
|
||||
D3::ImGuiHooks::OpenWindow( D3::ImGuiHooks::D3_ImGuiWin_Settings );
|
||||
} else {
|
||||
D3::ImGuiHooks::CloseWindow( D3::ImGuiHooks::D3_ImGuiWin_Settings );
|
||||
|
||||
// TODO: if in SP game, unpause
|
||||
if ( ImGui::IsWindowFocused( ImGuiFocusedFlags_AnyWindow ) ) {
|
||||
// if the settings window is open and an ImGui window has focus,
|
||||
// close the settings window when "dhewm3Settings" is executed
|
||||
D3::ImGuiHooks::CloseWindow( D3::ImGuiHooks::D3_ImGuiWin_Settings );
|
||||
} else {
|
||||
// if the settings window is open but no ImGui window has focus,
|
||||
// give focus to one of the ImGui windows.
|
||||
// useful to get the cursor back when ingame..
|
||||
ImGui::SetNextWindowFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1618,7 +1618,7 @@ static void handleMouseGrab() {
|
|||
bool relativeMouse = false;
|
||||
|
||||
// if com_editorActive, release everything, just like when we have no focus
|
||||
if ( in_hasFocus && !com_editorActive ) {
|
||||
if ( in_hasFocus && !com_editorActive && !D3::ImGuiHooks::ShouldShowCursor() ) {
|
||||
// Note: this generally handles fullscreen menus, but not the PDA, because the PDA
|
||||
// is an ugly hack in gamecode that doesn't go through sessLocal.guiActive.
|
||||
// It goes through weapon input code or sth? That's also the reason only
|
||||
|
|
|
@ -17,10 +17,12 @@ typedef char* (*MY_XGETDEFAULTFUN)(Display*, const char*, const char*);
|
|||
|
||||
#include "framework/Common.h"
|
||||
#include "framework/KeyInput.h"
|
||||
#include "framework/Session_local.h" // sessLocal.GetActiveMenu()
|
||||
#include "renderer/qgl.h"
|
||||
#include "renderer/tr_local.h" // glconfig
|
||||
|
||||
extern void Com_DrawDhewm3SettingsMenu(); // in framework/dhewm3SettingsMenu.cpp
|
||||
extern void Com_OpenCloseDhewm3SettingsMenu( bool open ); // ditto
|
||||
|
||||
static idCVar imgui_scale( "imgui_scale", "-1.0", CVAR_SYSTEM|CVAR_FLOAT|CVAR_ARCHIVE, "factor to scale ImGUI menus by (-1: auto)" ); // TODO: limit values?
|
||||
|
||||
|
@ -309,6 +311,12 @@ void NewFrame()
|
|||
|
||||
// Start the Dear ImGui frame
|
||||
ImGui_ImplOpenGL2_NewFrame();
|
||||
|
||||
if ( ShouldShowCursor() )
|
||||
ImGui::GetIO().ConfigFlags &= ~ImGuiConfigFlags_NoMouseCursorChange;
|
||||
else
|
||||
ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange;
|
||||
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
haveNewFrame = true;
|
||||
|
@ -409,6 +417,28 @@ void SetKeyBindMode( bool enable )
|
|||
idKeyInput::ClearStates();
|
||||
}
|
||||
|
||||
bool ShouldShowCursor()
|
||||
{
|
||||
if ( sessLocal.GetActiveMenu() != nullptr ) {
|
||||
// if we're in a menu (probably main menu), dhewm3 renders a cursor for it,
|
||||
// so only show the ImGui cursor when the mouse cursor is over an ImGui window
|
||||
return openImguiWindows != 0 && ImGui::GetIO().WantCaptureMouse;
|
||||
} else {
|
||||
// when ingame, render the ImGui/SDL/system cursor if an ImGui window is open
|
||||
// because dhewm3 does *not* render its own cursor outside ImGui windows.
|
||||
// additionally, only show it if an ImGui window has focus - this allows you
|
||||
// to click outside the ImGui window to give Doom3 focus and look around.
|
||||
// You can get focus on the ImGui window again by clicking while the invisible
|
||||
// cursor is over the window (things in it still get highlighted), or by
|
||||
// opening the main (Esc) or by opening the Dhewm3 Settings window (F10, usually),
|
||||
// which will either open it focused or give an ImGui window focus if it
|
||||
// was open but unfocused.
|
||||
// Might be nice to have a keyboard shortcut to give focus to any open
|
||||
// ImGui window, maybe Pause?
|
||||
return openImguiWindows != 0 && ImGui::IsWindowFocused( ImGuiFocusedFlags_AnyWindow );
|
||||
}
|
||||
}
|
||||
|
||||
void EndFrame()
|
||||
{
|
||||
if (openImguiWindows == 0 && !haveNewFrame)
|
||||
|
@ -464,11 +494,33 @@ void EndFrame()
|
|||
|
||||
void OpenWindow( D3ImGuiWindow win )
|
||||
{
|
||||
if ( openImguiWindows & win )
|
||||
return; // already open
|
||||
|
||||
ImGui::SetNextWindowFocus();
|
||||
|
||||
switch ( win ) {
|
||||
case D3_ImGuiWin_Settings:
|
||||
Com_OpenCloseDhewm3SettingsMenu( true );
|
||||
break;
|
||||
// TODO: other windows that need explicit opening
|
||||
}
|
||||
|
||||
openImguiWindows |= win;
|
||||
}
|
||||
|
||||
void CloseWindow( D3ImGuiWindow win )
|
||||
{
|
||||
if ( (openImguiWindows & win) == 0 )
|
||||
return; // already closed
|
||||
|
||||
switch ( win ) {
|
||||
case D3_ImGuiWin_Settings:
|
||||
Com_OpenCloseDhewm3SettingsMenu( false );
|
||||
break;
|
||||
// TODO: other windows that need explicit closing
|
||||
}
|
||||
|
||||
openImguiWindows &= ~win;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,9 @@ extern bool ProcessEvent(const void* sdlEvent);
|
|||
// even if ImGui window has focus
|
||||
extern void SetKeyBindMode( bool enable );
|
||||
|
||||
// returns true if the system cursor should be shown because an ImGui menu is active
|
||||
extern bool ShouldShowCursor();
|
||||
|
||||
// NewFrame() is called once per D3 frame, after all events have been gotten
|
||||
// => ProcessEvent() has already been called (probably multiple times)
|
||||
extern void NewFrame();
|
||||
|
@ -99,6 +102,8 @@ inline bool ProcessEvent(const void* sdlEvent) { return false; }
|
|||
|
||||
inline void SetKeyBindMode( bool enable ) {}
|
||||
|
||||
inline bool ShouldShowCursor() { return false; }
|
||||
|
||||
inline void NewFrame() {}
|
||||
|
||||
inline void EndFrame() {}
|
||||
|
|
Loading…
Reference in a new issue