diff --git a/docs/changelog.txt b/docs/changelog.txt index 0e758b718..1174508e2 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -36,6 +36,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## New Plugins ## Fixes +-@ DF screens can no longer get "stuck" on transitions when DFHack tool windows are visible. Instead, those DF screens are force-paused while DFHack windows are visible so the player can close them first and not corrupt the screen sequence. The "force pause" indicator will appear on these DFHack windows to indicate what is happening. -@ ``Screen``: allow `gui/launcher` and `gui/quickcmd` to launch themselves without hanging the game -@ Fix issues with clicks "passing through" some DFHack window elements, like scrollbars - `getplants`: tree are now designated correctly diff --git a/library/lua/gui.lua b/library/lua/gui.lua index 233496b82..061444f5d 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -714,7 +714,7 @@ end function ZScreen:init() self.saved_pause_state = df.global.pause_state - if self.initial_pause then + if self.initial_pause and dfhack.isMapLoaded() then df.global.pause_state = true end self.defocused = false @@ -722,19 +722,39 @@ end function ZScreen:dismiss() ZScreen.super.dismiss(self) - if self.force_pause or self.initial_pause then + if (self.force_pause or self.initial_pause) and dfhack.isMapLoaded() then -- never go from unpaused to paused, just from paused to unpaused df.global.pause_state = df.global.pause_state and self.saved_pause_state end end +local NO_LOGIC_SCREENS = { + 'viewscreen_loadgamest', + 'viewscreen_export_regionst', + 'viewscreen_choose_game_typest', + 'viewscreen_worldst', +} +for _,v in ipairs(NO_LOGIC_SCREENS) do + if not df[v] then + error('invalid class name: ' .. v) + end + NO_LOGIC_SCREENS[df[v]] = true +end + -- this is necessary for middle-click map scrolling to function function ZScreen:onIdle() - if self.force_pause then + if self.force_pause and dfhack.isMapLoaded() then df.global.pause_state = true end if self._native and self._native.parent then - self._native.parent:logic() + local vs_type = dfhack.gui.getDFViewscreen(true)._type + if NO_LOGIC_SCREENS[vs_type] then + self.force_pause = true + self.pass_movement_keys = false + self.pass_mouse_clicks = false + else + self._native.parent:logic() + end end end diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index f056a8578..5627c08da 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -716,6 +716,21 @@ void dfhack_viewscreen::logic() // Various stuff works poorly unless always repainting Screen::invalidate(); + + // if the DF screen immediately beneath the DFHack viewscreens is waiting to + // be dismissed, raise it to the top so DF never gets stuck + auto *p = parent; + while (p) { + bool is_df_screen = !is_instance(p); + auto *next_p = p->parent; + if (is_df_screen && Screen::isDismissed(p)) { + DEBUG(screen).print("raising dismissed DF viewscreen %p\n", p); + Screen::raise(p); + } + if (is_df_screen) + break; + p = next_p; + } } void dfhack_viewscreen::render() @@ -806,6 +821,13 @@ int dfhack_lua_viewscreen::do_destroy(lua_State *L) auto self = get_self(L); if (!self) return 0; + if (!Screen::isDismissed(self)) { + WARN(screen).print("DFHack screen was destroyed before it was dismissed\n"); + WARN(screen).print("Please tell the DFHack team which DF screen you were just viewing\n"); + // run skipped onDismiss cleanup logic + Screen::dismiss(self); + } + lua_pushnil(L); lua_rawsetp(L, LUA_REGISTRYINDEX, self);