From df1649636b81349fc6558f7de66ee7afc2e5788d Mon Sep 17 00:00:00 2001 From: jsd1982 Date: Tue, 4 Mar 2025 21:57:38 -0600 Subject: [PATCH] ui: fix script console to use a ListView widget for performance (instead of TextEdit) and auto-scroll to the bottom when appending new items --- bsnes/target-bsnes/program/program.hpp | 1 - bsnes/target-bsnes/program/script.cpp | 13 +++---- bsnes/target-bsnes/tools/script-console.cpp | 41 +++++++++++++++------ bsnes/target-bsnes/tools/tools.hpp | 8 ++-- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/bsnes/target-bsnes/program/program.hpp b/bsnes/target-bsnes/program/program.hpp index 70daafd61..a346a8970 100644 --- a/bsnes/target-bsnes/program/program.hpp +++ b/bsnes/target-bsnes/program/program.hpp @@ -223,7 +223,6 @@ struct Program : Lock, Emulator::Platform { asIScriptEngine *engine; string location; - string console; } scriptHostState; vector, uint>> escapeKeys; diff --git a/bsnes/target-bsnes/program/script.cpp b/bsnes/target-bsnes/program/script.cpp index fd18ae16a..6d4c38811 100644 --- a/bsnes/target-bsnes/program/script.cpp +++ b/bsnes/target-bsnes/program/script.cpp @@ -5,15 +5,14 @@ auto Program::scriptMessage(const string& msg, bool alert, ::Script::MessageLeve auto levelName = ::Script::nameMessageLevel(level); // append to stdout: - printf("[%s] %.*s\n", levelName, msg.size(), msg.data()); + if (level != ::Script::MessageLevel::MSG_INFO) { + printf("[%s] %.*s\n", levelName, msg.size(), msg.data()); + } else { + printf("%.*s\n", msg.size(), msg.data()); + } // append to script console: - scriptHostState.console.append("["); - scriptHostState.console.append(levelName); - scriptHostState.console.append("] "); - scriptHostState.console.append(msg); - scriptHostState.console.append("\n"); - scriptConsole.update(); + scriptConsole.appendItem(msg, level); // alert in status bar: if (alert) { diff --git a/bsnes/target-bsnes/tools/script-console.cpp b/bsnes/target-bsnes/tools/script-console.cpp index b1f98f361..cf81d577e 100644 --- a/bsnes/target-bsnes/tools/script-console.cpp +++ b/bsnes/target-bsnes/tools/script-console.cpp @@ -2,23 +2,42 @@ auto ScriptConsole::create() -> void { setCollapsible(); setVisible(false); - #if 0 && defined(Hiro_SourceEdit) - consoleView.setFont(Font().setFamily(Font::Mono).setSize(10)); - #else - consoleView.setFont(Font().setFamily(Font::Mono)); - #endif - consoleView.setEditable(false); - consoleView.setWordWrap(false); + consoleView.reset(); + consoleView.setBatchable(true); nameLabel.setText("no script loaded"); loadButton.setText("Clear").onActivate([&] { - program.scriptHostState.console = ""; - update(); + clear(); }); } +auto ScriptConsole::appendItem(const string& msg, ::Script::MessageLevel level) -> void { + auto item = ListViewItem().setText(msg); + switch (level) { + case ::Script::MessageLevel::MSG_DEBUG: + item.setIcon(Icon::Prompt::Question); + break; + case ::Script::MessageLevel::MSG_WARN: + item.setIcon(Icon::Prompt::Warning); + break; + case ::Script::MessageLevel::MSG_ERROR: + item.setIcon(Icon::Prompt::Error); + break; + case ::Script::MessageLevel::MSG_INFO: + default: + item.setIcon(Icon::Prompt::Information); + break; + } + + consoleView.append(item); + // NOTE(jsd): hack to scroll the item into view + item.setFocused(); +} + +auto ScriptConsole::clear() -> void { + consoleView.reset(); +} + auto ScriptConsole::update() -> void { nameLabel.setText(program.scriptHostState.location); - consoleView.setText(program.scriptHostState.console); - consoleView.setTextCursor(program.scriptHostState.console.size()); } diff --git a/bsnes/target-bsnes/tools/tools.hpp b/bsnes/target-bsnes/tools/tools.hpp index 112ec738d..f4b3eeb44 100644 --- a/bsnes/target-bsnes/tools/tools.hpp +++ b/bsnes/target-bsnes/tools/tools.hpp @@ -182,17 +182,15 @@ struct ManifestViewer : VerticalLayout { struct ScriptConsole : VerticalLayout { auto create() -> void; + auto appendItem(const string& msg, ::Script::MessageLevel level = ::Script::MessageLevel::MSG_INFO) -> void; + auto clear() -> void; auto update() -> void; public: HorizontalLayout informationLayout{this, Size{~0, 0}}; Label nameLabel{&informationLayout, Size{~0, 0}}; Button loadButton{&informationLayout, Size{80_sx, 0}}; -#if 0 && defined(Hiro_SourceEdit) - SourceEdit consoleView{this, Size{~0, ~0}}; -#else - TextEdit consoleView{this, Size{~0, ~0}}; -#endif + ListView consoleView{this, Size{~0, ~0}}; }; struct ToolsWindow : Window {