Add RunningScriptsWindow

This commit is contained in:
Martín Capello 2025-02-26 13:58:11 -03:00
parent 0b3e3d90c0
commit 3eba7eb48d
4 changed files with 130 additions and 11 deletions

View File

@ -38,6 +38,7 @@
#include "ui/manager.h"
#include "ui/message_loop.h"
#include "ui/mouse_button.h"
#include "ui/system.h"
#include <fstream>
#include <sstream>
@ -259,7 +260,13 @@ RunScriptTask::RunScriptTask(lua_State* L, int nelems, const std::string& descri
RunScriptTask* task = (RunScriptTask*)lua_topointer(L, -1);
lua_pop(L, 2);
if (task->wantsToStop()) {
lua_pushliteral(L, "Script stopped");
luaL_where(L, 0);
const char* where = lua_tostring(L, -1);
luaL_traceback(L, L, "Script stopped", 0);
const char* traceback = lua_tostring(L, -1);
std::string msg(fmt::format("{}{}", where, traceback));
lua_pop(L, 2);
lua_pushstring(L, msg.c_str());
lua_error(L);
}
}
@ -739,8 +746,10 @@ void Engine::callInTask(lua_State* parentL, int nargs, const std::string& descri
executeTask(parentL, nargs + 1, description, [this, nargs](lua_State* L) {
try {
if (lua_pcall(L, nargs, 0, 0)) {
if (const char* s = lua_tostring(L, -1))
consolePrint(s);
if (const char* s = lua_tostring(L, -1)) {
std::string error = std::string(s);
ui::execute_from_ui_thread([this, error]() { consolePrint(error.c_str()); });
}
}
}
catch (const std::exception& ex) {
@ -764,12 +773,14 @@ void Engine::executeTask(lua_State* parentL,
std::lock_guard<std::mutex> lock(m_mutex);
m_tasks.push_back(std::move(task));
}
TaskStart(taskPtr);
taskPtr->execute(m_threadPool);
}
void Engine::onTaskDone(const RunScriptTask* task)
{
std::lock_guard<std::mutex> lock(m_mutex);
TaskDone(task);
for (auto it = m_tasks.begin(); it != m_tasks.end(); ++it) {
if ((*it).get() == task) {
m_tasks.erase(it);
@ -810,8 +821,10 @@ bool Engine::evalUserFileInTask(const std::string& filename, const Params& param
if (luaL_loadbuffer(L, code.c_str(), code.size(), atFilename.c_str()) ||
lua_pcall(L, 0, 1, 0)) {
const char* s = lua_tostring(L, -1);
if (s)
onConsoleError(s);
if (s) {
std::string error = std::string(s);
ui::execute_from_ui_thread([this, error]() { onConsoleError(error.c_str()); });
}
ok = false;
returnCode = -1;
}
@ -873,10 +886,14 @@ void Engine::stopDebugger()
lua_sethook(L, nullptr, 0, 0);
}
void Engine::stopScript()
void Engine::stopTask(const RunScriptTask* task)
{
lua_pushliteral(L, "Script stopped");
lua_error(L);
std::lock_guard<std::mutex> lock(m_mutex);
for (const auto& t : m_tasks) {
if (t.get() == task) {
t->stop();
}
}
}
void Engine::onConsoleError(const char* text)

View File

@ -100,6 +100,8 @@ public:
int ref() const { return m_LRef; }
const std::string& description() const { return m_description; }
bool isRunning() const { return m_task.running(); }
bool isEnqueued() const { return m_task.enqueued(); }
private:
// Lua's thread state.
@ -136,7 +138,8 @@ public:
std::vector<const RunScriptTask*> tasks() const
{
std::lock_guard<std::mutex> lock(m_mutex);
std::vector<const RunScriptTask*> tasks(m_tasks.size());
std::vector<const RunScriptTask*> tasks;
tasks.reserve(m_tasks.size());
for (const auto& task : m_tasks)
tasks.push_back(task.get());
return tasks;
@ -153,8 +156,11 @@ public:
void startDebugger(DebuggerDelegate* debuggerDelegate);
void stopDebugger();
// Stops the currently running lua chunk
void stopScript();
// Stops the specified task
void stopTask(const RunScriptTask* task);
obs::signal<void(const RunScriptTask*)> TaskStart;
obs::signal<void(const RunScriptTask*)> TaskDone;
private:
void onConsoleError(const char* text);

View File

@ -22,6 +22,7 @@
#include "app/modules/gui.h"
#include "app/modules/palettes.h"
#include "app/pref/preferences.h"
#include "app/script/engine.h"
#include "app/tools/active_tool.h"
#include "app/tools/tool.h"
#include "app/ui/button_set.h"
@ -44,8 +45,16 @@
#include "fmt/format.h"
#include "gfx/size.h"
#include "os/surface.h"
#include "os/system.h"
#include "text/font.h"
#include "ui/box.h"
#include "ui/button.h"
#include "ui/label.h"
#include "ui/listbox.h"
#include "ui/listitem.h"
#include "ui/popup_window.h"
#include "ui/ui.h"
#include "ui/view.h"
#include "ver/info.h"
#include <algorithm>
@ -607,6 +616,70 @@ private:
ui::Button m_button;
};
class StatusBar::RunningScriptsWindow : public ui::Window {
public:
// TODO: Replace the title by a string
RunningScriptsWindow() : ui::Window(Type::WithTitleBar, "Running scripts")
{
setMinSize({ 500, 200 });
m_runningScripts.setExpansive(true);
m_view.setExpansive(true);
m_view.attachToView(&m_runningScripts);
addChild(&m_view);
initTheme();
refreshList();
App::instance()->scriptEngine()->TaskStart.connect([this](const script::RunScriptTask*) {
ui::execute_from_ui_thread([this] { refreshList(); });
});
App::instance()->scriptEngine()->TaskDone.connect([this](const script::RunScriptTask*) {
ui::execute_from_ui_thread([this] { refreshList(); });
});
}
void refreshList()
{
m_runningScripts.removeAllChildren();
for (const auto* task : App::instance()->scriptEngine()->tasks()) {
auto* item = new TaskItem(task);
m_runningScripts.addChild(item);
}
m_runningScripts.layout();
flushRedraw();
}
private:
class TaskItem : public ListItem {
public:
TaskItem(const script::RunScriptTask* task) : m_label(""), m_stop("Stop")
{
m_task = task;
m_label.setText(
fmt::format("{} ({})", task->description(), (task->isEnqueued() ? "enqueued" : "running")));
m_label.setExpansive(true);
m_row.setExpansive(true);
m_row.addChild(&m_label);
if (!task->isEnqueued())
m_row.addChild(&m_stop);
addChild(&m_row);
m_stop.Click.connect([this]() { App::instance()->scriptEngine()->stopTask(m_task); });
}
private:
const script::RunScriptTask* m_task;
ui::HBox m_row;
ui::Label m_label;
ui::Button m_stop;
};
ui::View m_view;
ui::ListBox m_runningScripts;
};
// This widget is used to show the current frame.
class GotoFrameEntry : public Entry {
public:
@ -886,6 +959,25 @@ void StatusBar::showSnapToGridWarning(bool state)
}
}
void StatusBar::showRunningScriptsWindow(bool state)
{
if (state) {
if (!m_runningScriptsWindow)
m_runningScriptsWindow = new RunningScriptsWindow;
m_runningScriptsWindow->setDisplay(display(), false);
if (!m_runningScriptsWindow->isVisible()) {
m_runningScriptsWindow->openWindow();
m_runningScriptsWindow->remapWindow();
// updateRunningScriptsWindowPosition();
}
}
else if (m_runningScriptsWindow) {
m_runningScriptsWindow->closeWindow(nullptr);
}
}
//////////////////////////////////////////////////////////////////////
// StatusBar message handler

View File

@ -66,6 +66,7 @@ public:
void showTile(int msecs, doc::tile_t tile, const std::string& text = std::string());
void showTool(int msecs, tools::Tool* tool);
void showSnapToGridWarning(bool state);
void showRunningScriptsWindow(bool state);
// Used by AppEditor to update the zoom level in the status bar.
void updateFromEditor(Editor* editor);
@ -119,6 +120,9 @@ private:
// Snap to grid window
class SnapToGridWindow;
SnapToGridWindow* m_snapToGridWindow;
class RunningScriptsWindow;
RunningScriptsWindow* m_runningScriptsWindow;
};
} // namespace app