diff --git a/res/layouts/console.xml.lua b/res/layouts/console.xml.lua index 11d7bd14..7e41ddf6 100644 --- a/res/layouts/console.xml.lua +++ b/res/layouts/console.xml.lua @@ -134,6 +134,10 @@ function add_to_history(text) end function submit(text) + if #text == 0 then + document.prompt.focused = true + return + end text = text:trim() add_to_history(text) @@ -204,4 +208,11 @@ function on_open(mode) elseif mode then modes:set(mode) end + hud.close("core:ingame_chat") +end + +function on_close() + time.post_runnable(function() + hud.open_permanent("core:ingame_chat") + end) end diff --git a/res/layouts/ingame_chat.xml b/res/layouts/ingame_chat.xml new file mode 100644 index 00000000..45ad4749 --- /dev/null +++ b/res/layouts/ingame_chat.xml @@ -0,0 +1,8 @@ + + diff --git a/res/layouts/ingame_chat.xml.lua b/res/layouts/ingame_chat.xml.lua new file mode 100644 index 00000000..5e08ac9d --- /dev/null +++ b/res/layouts/ingame_chat.xml.lua @@ -0,0 +1,59 @@ +local lines = {} +local dead_lines = {} +local nextid = 0 +local timeout = 7 +local fadeout = 1 +local initialized = false +local max_lines = 15 +local animation_fps = 30 + +local function remove_line(line) + document[line[1]]:destruct() + time.post_runnable(function() document.root:reposition() end) +end + +local function update_line(line, uptime) + local diff = uptime - line[2] + if diff > timeout then + remove_line(line) + table.insert(dead_lines, i) + elseif diff > timeout-fadeout then + local opacity = (timeout - diff) / fadeout + document[line[1]].color = {0, 0, 0, opacity * 80} + document[line[1].."L"].color = {255, 255, 255, opacity * 255} + end +end + +events.on("core:chat", function(message) + local current_time = time.uptime() + local id = 'l'..tostring(nextid) + document.root:add(gui.template("chat_line", {id=id})) + document.root:reposition() + document[id.."L"].text = message + nextid = nextid + 1 + if #lines == max_lines then + remove_line(lines[1]) + table.remove(lines, 1) + end + table.insert(lines, {id, current_time}) +end) + +function on_open() + if not initialized then + initialized = true + + document.root:setInterval(1/animation_fps, function () + local uptime = time.uptime() + for _, line in ipairs(lines) do + update_line(line, uptime) + end + if #dead_lines > 0 then + for i = #dead_lines, 1, -1 do + local index = dead_lines[i] + table.remove(lines, i) + end + dead_lines = {} + end + end) + end +end diff --git a/res/layouts/templates/chat_line.xml b/res/layouts/templates/chat_line.xml new file mode 100644 index 00000000..b9939218 --- /dev/null +++ b/res/layouts/templates/chat_line.xml @@ -0,0 +1,3 @@ + + diff --git a/res/modules/internal/gui_util.lua b/res/modules/internal/gui_util.lua index 31f542dd..3cf84a33 100644 --- a/res/modules/internal/gui_util.lua +++ b/res/modules/internal/gui_util.lua @@ -95,7 +95,7 @@ function RadioGroup:__call(elements, onset, default) elements=elements, callback=onset, current=nil - }, {__index=RadioGroup}) + }, {__index=self}) group:set(default) return group end diff --git a/res/scripts/stdlib.lua b/res/scripts/stdlib.lua index d9190bce..78228254 100644 --- a/res/scripts/stdlib.lua +++ b/res/scripts/stdlib.lua @@ -351,6 +351,7 @@ function __vc_on_hud_open() hud.pause() end end) + hud.open_permanent("core:ingame_chat") end local RULES_FILE = "world:rules.toml" diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 00382420..ce29e8c1 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -217,6 +217,7 @@ void Engine::renderFrame() { Viewport viewport(Window::width, Window::height); DrawContext ctx(nullptr, viewport, nullptr); gui->draw(ctx, *assets); + gui->postAct(); } void Engine::saveSettings() { diff --git a/src/graphics/ui/GUI.cpp b/src/graphics/ui/GUI.cpp index 95d65540..2cc28024 100644 --- a/src/graphics/ui/GUI.cpp +++ b/src/graphics/ui/GUI.cpp @@ -178,12 +178,6 @@ void GUI::actFocused() { } void GUI::act(float delta, const Viewport& vp) { - while (!postRunnables.empty()) { - runnable callback = postRunnables.back(); - postRunnables.pop(); - callback(); - } - container->setSize(vp.size()); container->act(delta); auto prevfocus = focus; @@ -206,6 +200,14 @@ void GUI::act(float delta, const Viewport& vp) { } } +void GUI::postAct() { + while (!postRunnables.empty()) { + runnable callback = postRunnables.back(); + postRunnables.pop(); + callback(); + } +} + void GUI::draw(const DrawContext& pctx, const Assets& assets) { auto ctx = pctx.sub(batch2D.get()); diff --git a/src/graphics/ui/GUI.hpp b/src/graphics/ui/GUI.hpp index f8cea3ef..cb6b037e 100644 --- a/src/graphics/ui/GUI.hpp +++ b/src/graphics/ui/GUI.hpp @@ -106,6 +106,8 @@ namespace gui { /// @param assets active assets storage void draw(const DrawContext& pctx, const Assets& assets); + void postAct(); + /// @brief Add element to the main container /// @param node UI element void add(std::shared_ptr node); diff --git a/src/graphics/ui/elements/Panel.cpp b/src/graphics/ui/elements/Panel.cpp index 7bbc4231..d90b8830 100644 --- a/src/graphics/ui/elements/Panel.cpp +++ b/src/graphics/ui/elements/Panel.cpp @@ -62,6 +62,11 @@ void Panel::add(const std::shared_ptr &node) { fullRefresh(); } +void Panel::remove(const std::shared_ptr &node) { + Container::remove(node); + fullRefresh(); +} + void Panel::refresh() { UINode::refresh(); std::stable_sort(nodes.begin(), nodes.end(), [](auto a, auto b) { diff --git a/src/graphics/ui/elements/Panel.hpp b/src/graphics/ui/elements/Panel.hpp index 7e9759dd..5a6399ce 100644 --- a/src/graphics/ui/elements/Panel.hpp +++ b/src/graphics/ui/elements/Panel.hpp @@ -25,6 +25,7 @@ namespace gui { Orientation getOrientation() const; virtual void add(const std::shared_ptr& node) override; + virtual void remove(const std::shared_ptr& node) override; virtual void refresh() override; virtual void fullRefresh() override;