From 058c00fc3bc5f744541a21adff4f14aa3370a387 Mon Sep 17 00:00:00 2001 From: Aidan Holm Date: Fri, 20 Jul 2018 10:53:54 +0800 Subject: [PATCH] Don't render UI layers under direction chooser (stoneychips, #11525) This fixes a webtiles bug where evoking items from their inventory item description would lead to the inventory menu obscuring the direction chooser. This also fixes a secondary bug on local tiles where evoking items from their inventory item description and then pressing v to describe a cell would cause the inventory menu to appear under the description popup. Briefly, there are two main render loops for local tiles: the directn loop (which does not render UI popups), and the new UI loop (which does render the background direction chooser view). Effectively, either all popups or no popups are rendered, depending on which render loop is running on the top of the stack (they can be nested). For xv, that's the UI loop on top of the directn loop; for inv -> item -> evoke, that's the directn loop on top of the UI loop. This approach doesn't work on webtiles because it uses HTML to render the UI, and so the render loops are effectively "running in parallel". It was buggy on local tiles when describing cells after evoking an item from the inventory. The fix is to add "cutoff points" which prevent the rendering of any UI layers already pushed. Local UI and tileweb have separate UI stacks, and so have their own cutoff point API, in case non-UI code modifies the tileweb UI stack in the future. The addition of the cutoff point to show_map() is currently unnecessary, since there is currently no way to show the map from a popup view, but this might change in the future. --- crawl-ref/source/directn.cc | 4 +++ crawl-ref/source/tileweb.cc | 14 ++++++++++ crawl-ref/source/tileweb.h | 3 +++ crawl-ref/source/ui.cc | 26 ++++++++++++++++++- crawl-ref/source/ui.h | 12 +++++++++ crawl-ref/source/viewmap.cc | 4 +++ .../source/webserver/game_data/static/game.js | 9 +++++++ 7 files changed, 71 insertions(+), 1 deletion(-) diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index 28725267c0d..d44856c8e78 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -2010,6 +2010,10 @@ void direction_chooser::finalize_moves() bool direction_chooser::choose_direction() { +#ifdef USE_TILE + ui::cutoff_point ui_cutoff_point; +#endif + if (restricts == DIR_DIR) return choose_compass(); diff --git a/crawl-ref/source/tileweb.cc b/crawl-ref/source/tileweb.cc index 00e33c39dd5..c15a57a8229 100644 --- a/crawl-ref/source/tileweb.cc +++ b/crawl-ref/source/tileweb.cc @@ -654,6 +654,20 @@ void TilesFramework::ui_state_change(const string& type, unsigned state_slot) tiles.finish_message(); } +void TilesFramework::push_ui_cutoff() +{ + int cutoff = static_cast(m_menu_stack.size()); + m_ui_cutoff_stack.push_back(cutoff); + send_message("{\"msg\":\"ui_cutoff\",\"cutoff\":%d}", cutoff); +} + +void TilesFramework::pop_ui_cutoff() +{ + m_ui_cutoff_stack.pop_back(); + int cutoff = m_ui_cutoff_stack.empty() ? 0 : m_ui_cutoff_stack.back(); + send_message("{\"msg\":\"ui_cutoff\",\"cutoff\":%d}", cutoff); +} + static void _send_text_cursor(bool enabled) { tiles.send_message("{\"msg\":\"text_cursor\",\"enabled\":%s}", diff --git a/crawl-ref/source/tileweb.h b/crawl-ref/source/tileweb.h index bc06a934e15..e5dd70d5349 100644 --- a/crawl-ref/source/tileweb.h +++ b/crawl-ref/source/tileweb.h @@ -137,6 +137,8 @@ class TilesFramework void pop_ui_layout(); void pop_all_ui_layouts(); void ui_state_change(const string& type, unsigned state_slot); + void push_ui_cutoff(); + void pop_ui_cutoff(); void send_exit_reason(const string& type, const string& message = ""); void send_dump_info(const string& type, const string& filename); @@ -241,6 +243,7 @@ class TilesFramework WebtilesUIState m_ui_state; WebtilesUIState m_last_ui_state; + vector m_ui_cutoff_stack; unsigned int m_last_tick_redraw; bool m_need_redraw; diff --git a/crawl-ref/source/ui.cc b/crawl-ref/source/ui.cc index 68a7c1e3c92..0fb23240efb 100644 --- a/crawl-ref/source/ui.cc +++ b/crawl-ref/source/ui.cc @@ -13,6 +13,7 @@ #include "cio.h" #include "macro.h" # include "state.h" +#include "tileweb.h" #ifdef USE_TILE_LOCAL # include "glwrapper.h" @@ -84,6 +85,7 @@ static struct UIRoot bool needs_paint; vector keymap_stack; + vector cutoff_stack; protected: int m_w, m_h; @@ -1457,7 +1459,10 @@ void UIRoot::render() push_scissor(m_region); #ifdef USE_TILE_LOCAL - m_root.render(); + int cutoff = cutoff_stack.empty() ? 0 : cutoff_stack.back(); + ASSERT(cutoff <= static_cast(m_root.num_children())); + for (int i = cutoff; i < static_cast(m_root.num_children()); i++) + m_root.get_child(i)->render(); #else // Render only the top of the UI stack on console if (m_root.num_children() > 0) @@ -1576,6 +1581,25 @@ static void clear_text_region(i4 region) } #endif +#ifdef USE_TILE +void push_cutoff() +{ + int cutoff = static_cast(ui_root.num_children()); + ui_root.cutoff_stack.push_back(cutoff); +#ifdef USE_TILE_WEB + tiles.push_ui_cutoff(); +#endif +} + +void pop_cutoff() +{ + ui_root.cutoff_stack.pop_back(); +#ifdef USE_TILE_WEB + tiles.pop_ui_cutoff(); +#endif +} +#endif + void push_layout(shared_ptr root, KeymapContext km) { ui_root.push_child(move(root), km); diff --git a/crawl-ref/source/ui.h b/crawl-ref/source/ui.h index c43b47aa7d9..6b9b97a9b4c 100644 --- a/crawl-ref/source/ui.h +++ b/crawl-ref/source/ui.h @@ -575,6 +575,18 @@ class Dungeon : public Widget }; #endif +#ifdef USE_TILE +void push_cutoff(); +void pop_cutoff(); + +class cutoff_point +{ +public: + cutoff_point() { push_cutoff(); } + ~cutoff_point() { pop_cutoff(); } +}; +#endif + void push_layout(shared_ptr root, KeymapContext km = KMC_DEFAULT); void pop_layout(); void pump_events(int wait_event_timeout = INT_MAX); diff --git a/crawl-ref/source/viewmap.cc b/crawl-ref/source/viewmap.cc index 9fd7ef3e6df..14acbe4c73c 100644 --- a/crawl-ref/source/viewmap.cc +++ b/crawl-ref/source/viewmap.cc @@ -33,6 +33,7 @@ #include "tileview.h" #include "tiles-build-specific.h" #include "travel.h" +#include "ui.h" #include "unicode.h" #include "view.h" #include "viewchar.h" @@ -629,6 +630,9 @@ bool show_map(level_pos &lpos, tiles.do_map_display(); #endif +#ifdef USE_TILE + ui::cutoff_point ui_cutoff_point; +#endif #ifdef USE_TILE_WEB tiles_ui_control ui(UI_VIEW_MAP); #endif diff --git a/crawl-ref/source/webserver/game_data/static/game.js b/crawl-ref/source/webserver/game_data/static/game.js index e7e41d9f8a0..1caa8be4e8b 100644 --- a/crawl-ref/source/webserver/game_data/static/game.js +++ b/crawl-ref/source/webserver/game_data/static/game.js @@ -191,6 +191,14 @@ function ($, comm, client, dungeon_renderer, display, minimap, enums, messages, set_ui_state(data.state); } + function handle_set_ui_cutoff(data) + { + var popups = document.querySelectorAll("#ui-stack > .ui-popup"); + Array.from(popups).forEach(function (p, i) { + p.classList.toggle("hidden", i <= data.cutoff); + }); + } + function set_input_mode(mode) { if (mode == input_mode) return; @@ -240,6 +248,7 @@ function ($, comm, client, dungeon_renderer, display, minimap, enums, messages, "version": handle_version, "layout": handle_set_layout, "ui_state": handle_set_ui_state, + "ui_cutoff": handle_set_ui_cutoff, "input_mode": handle_set_input_mode, }); });