[Scummvm-git-logs] scummvm master -> b9b7788aeb2abc8b38611099ff096bf9c2478a83
scemino
noreply at scummvm.org
Mon May 20 09:48:13 UTC 2024
This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
76bf0bd8c7 DIRECTOR: Start syntax highlighting
b9b7788aeb DIRECTOR: Add breakpoint list window
Commit: 76bf0bd8c7f3f0c8af4f2dab634a106207945327
https://github.com/scummvm/scummvm/commit/76bf0bd8c7f3f0c8af4f2dab634a106207945327
Author: scemino (scemino74 at gmail.com)
Date: 2024-05-20T11:47:38+02:00
Commit Message:
DIRECTOR: Start syntax highlighting
Changed paths:
engines/director/debugtools.cpp
diff --git a/engines/director/debugtools.cpp b/engines/director/debugtools.cpp
index ac66d688726..2c055b1affc 100644
--- a/engines/director/debugtools.cpp
+++ b/engines/director/debugtools.cpp
@@ -72,38 +72,70 @@ typedef struct ImGuiScript {
Common::String handlerId;
Common::String handlerName;
Common::String moviePath;
- Common::Array<ImGuiScriptCodeLine> lingoCode;
- Common::Array<ImGuiScriptCodeLine> byteCode;
bool operator==(const ImGuiScript &c) const {
- return moviePath == c.moviePath && score == c.score && id == c.id && type == c.type && handlerId == c.handlerId;
+ return moviePath == c.moviePath && score == c.score && id == c.id && handlerId == c.handlerId;
}
bool operator!=(const ImGuiScript &c) const {
return !(*this == c);
}
} ImGuiScript;
-class ImGuiNodeVisitor : public LingoDec::NodeVisitor {
-public:
- explicit ImGuiNodeVisitor(ImGuiScript &script) : _script(script) {}
+typedef struct ImGuiState {
+ struct {
+ Common::HashMap<Graphics::Surface *, ImGuiImage> _textures;
+ bool _listView = true;
+ int _thumbnailSize = 64;
+ ImGuiTextFilter _nameFilter;
+ int _typeFilter = 0x7FFF;
+ } _cast;
+ struct {
+ ImGuiScript _script;
+ ImGuiTextFilter _nameFilter;
+ bool _showScript = false;
+ bool _showByteCode = false;
+ } _functions;
+ bool _showControlPanel = true;
+ bool _showCallStack = false;
+ bool _showVars = false;
+ bool _showChannels = false;
+ bool _showCast = false;
+ bool _showFuncList = false;
+ bool _showScore = false;
+ Common::List<CastMemberID> _scriptCasts;
+ Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _breakpoints;
+ Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
+ int _prevFrame = -1;
+ struct {
+ int frame = -1;
+ int channel = -1;
+ } _selectedScoreCast;
+} ImGuiState;
- virtual void visit(const LingoDec::BlockNode &node) override {
- _indent++;
- for (const auto &child : node.children) {
- child->accept(*this);
- }
- _indent--;
- }
+ImGuiState *_state = nullptr;
+
+static void setScriptToDisplay(const ImGuiScript &script);
+
+class RenderScriptVisitor : public LingoDec::NodeVisitor {
+public:
+ explicit RenderScriptVisitor(ImGuiScript &script, bool showByteCode) : _script(script), _showByteCode(showByteCode) {}
virtual void visit(const LingoDec::HandlerNode &node) override {
- byteCode(node);
+ _handler = node.handler;
+ LingoDec::Script *script = node.handler->script;
+ if (!script)
+ return;
+
+ if (_showByteCode) {
+ byteCode(node);
+ return;
+ }
if (node.handler->isGenericEvent) {
node.block->accept(*this);
return;
}
- LingoDec::Script *script = node.handler->script;
bool isMethod = script->isFactory();
{
Common::String code;
@@ -125,41 +157,116 @@ public:
write(node._startOffset, code);
}
- {
- Common::String code;
- if (isMethod && node.handler->script->propertyNames.size() > 0 && node.handler == &node.handler->script->handlers[0]) {
- code += "instance ";
- for (size_t i = 0; i < node.handler->script->propertyNames.size(); i++) {
- if (i > 0)
- code += ", ";
- code += node.handler->script->propertyNames[i];
- }
- write(node._startOffset, code);
+ if (isMethod && node.handler->script->propertyNames.size() > 0 && node.handler == &node.handler->script->handlers[0]) {
+ write(node._startOffset, "instance");
+ ImGui::SameLine();
+ for (size_t i = 0; i < node.handler->script->propertyNames.size(); i++) {
+ if (i > 0)
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ ImGui::TextColored((ImVec4)ImColor(var_color), "%s", node.handler->script->propertyNames[i].c_str());
+ ImGui::SameLine();
}
+ ImGui::NewLine();
}
- {
- if (node.handler->globalNames.size() > 0) {
- Common::String code;
- code += "global ";
- for (size_t i = 0; i < node.handler->globalNames.size(); i++) {
- if (i > 0)
- code += ", ";
- code += node.handler->globalNames[i];
- }
- write(node._startOffset, code);
+ if (node.handler->globalNames.size() > 0) {
+ write(node._startOffset, "global ");
+ ImGui::SameLine();
+ for (size_t i = 0; i < node.handler->globalNames.size(); i++) {
+ if (i > 0)
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ ImGui::TextColored((ImVec4)ImColor(var_color), "%s", node.handler->globalNames[i].c_str());
+ ImGui::SameLine();
}
+ ImGui::NewLine();
}
node.block->accept(*this);
- {
- Common::String code;
- if (!isMethod) {
- code += "end";
+ if (!isMethod) {
+ write(node.block->_endOffset, "end");
+ }
+ }
+
+ virtual void visit(const LingoDec::LiteralNode &node) override {
+ LingoDec::CodeWriterVisitor code(_dot, false);
+ node.accept(code);
+ ImGui::TextColored(literal_color, "%s", code._str.c_str());
+ ImGui::SameLine();
+ }
+
+ virtual void visit(const LingoDec::ObjCallV4Node &node) override {
+ if (node.isStatement) {
+ renderLine(node._startOffset);
+ renderIndentation();
+ }
+
+ node.obj->accept(*this);
+ ImGui::SameLine();
+ ImGui::Text("(");
+ ImGui::SameLine();
+ node.argList->accept(*this);
+ ImGui::SameLine();
+ ImGui::Text(")");
+ if (!node.isStatement) {
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::CallNode &node) override {
+ int32 obj = 0;
+ for (int i = 0; i < _handler->bytecodeArray.size(); i++) {
+ if (node._startOffset == _handler->bytecodeArray[i].pos) {
+ obj = _handler->bytecodeArray[i].obj;
+ break;
}
- write(node.block->_endOffset, code);
}
+
+ // new line only if it's a statement
+ if (node.isStatement) {
+ renderLine(node._startOffset);
+ renderIndentation();
+ }
+
+ const ImVec4 color = (ImVec4)ImColor(g_lingo->_builtinCmds.contains(node.name) ? builtin_color : call_color);
+ ImGui::TextColored(color, "%s", node.name.c_str());
+ if (!g_lingo->_builtinCmds.contains(node.name) && ImGui::IsItemHovered() && ImGui::BeginTooltip()) {
+ ImGui::Text("Go to definition");
+ ImGui::EndTooltip();
+ }
+ if (!g_lingo->_builtinCmds.contains(node.name) && ImGui::IsItemClicked()) {
+ ImGuiScript script;
+ script.moviePath = _script.moviePath;
+ script.handlerId = node.name;
+ script.id = CastMemberID(obj, _script.id.castLib);
+ script.handlerName = node.name;
+ setScriptToDisplay(script);
+ }
+ ImGui::SameLine();
+
+ LingoDec::CodeWriterVisitor code(_dot, false);
+ if (node.noParens()) {
+ node.argList->accept(code);
+ } else {
+ code.write("(");
+ node.argList->accept(code);
+ code.write(")");
+ }
+
+ ImGui::Text("%s", code._str.c_str());
+ if (!node.isStatement) {
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::BlockNode &node) override {
+ _indent++;
+ for (const auto &child : node.children) {
+ child->accept(*this);
+ }
+ _indent--;
}
virtual void visit(const LingoDec::RepeatWhileStmtNode &node) override {
@@ -203,11 +310,13 @@ public:
virtual void visit(const LingoDec::IfStmtNode &node) override {
{
- LingoDec::CodeWriterVisitor code(_dot, false);
- code.write("if ");
- node.condition->accept(code);
- code.write(" then");
- write(node._startOffset, code._str);
+ renderLine(node._startOffset);
+ renderIndentation();
+ ImGui::Text("if ");
+ ImGui::SameLine();
+ node.condition->accept(*this);
+ ImGui::SameLine();
+ ImGui::Text(" then");
}
node.block1->accept(*this);
if (node.hasElse) {
@@ -229,11 +338,15 @@ public:
virtual void defaultVisit(const LingoDec::Node &node) override {
LingoDec::CodeWriterVisitor code(_dot, false);
node.accept(code);
- write(node._startOffset, code._str);
+ if (node.isStatement) {
+ renderLine(node._startOffset);
+ renderIndentation();
+ }
+ ImGui::Text("%s", code._str.c_str());
}
private:
- void byteCode(const LingoDec::HandlerNode &node) {
+ void byteCode(const LingoDec::HandlerNode &node) const {
LingoDec::Handler *handler = node.handler;
bool isMethod = handler->script->isFactory();
@@ -304,65 +417,88 @@ private:
}
}
- void write(uint32 offset, const Common::String &code) {
+ void write(uint32 offset, const Common::String &code) const {
+ renderLine(offset);
+ renderIndentation();
+ ImGui::Text("%s", code.c_str());
+ }
+
+ void writeByteCode(uint32 offset, const Common::String &code) const {
+ renderLine(offset);
Common::String s;
for (int i = 0; i < _indent; i++) {
s += " ";
}
- _script.lingoCode.push_back({offset, s + code});
+ ImGui::Text("%s", (s + code).c_str());
}
- void writeByteCode(uint32 offset, const Common::String &code) {
- Common::String s;
- for (int i = 0; i < _indent; i++) {
- s += " ";
+ void renderLine(uint pc) const {
+ ImDrawList *dl = ImGui::GetWindowDrawList();
+ ImVec2 pos = ImGui::GetCursorScreenPos();
+ const ImVec2 mid(pos.x + 7, pos.y + 7);
+ Common::String bpName = Common::String::format("%s-%d", _script.handlerId.c_str(), pc);
+
+ ImU32 color = bp_color_disabled;
+
+ if (_state->_breakpoints.contains(bpName))
+ color = bp_color_enabled;
+
+ ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
+ if (ImGui::IsItemClicked(0)) {
+ if (color == bp_color_enabled) {
+ _state->_breakpoints.erase(bpName);
+ color = bp_color_disabled;
+ } else {
+ _state->_breakpoints[bpName] = true;
+ color = bp_color_enabled;
+ }
}
- _script.byteCode.push_back({offset, s + code});
+
+ if (color == bp_color_disabled && ImGui::IsItemHovered()) {
+ color = bp_color_hover;
+ }
+
+ dl->AddCircleFilled(mid, 4.0f, color);
+ dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), line_color);
+
+ ImGui::SetItemTooltip("Click to add a breakpoint");
+
+ ImGui::SameLine();
+ ImGui::Text("[%5d] ", pc);
+ ImGui::SameLine();
+ }
+
+ void renderIndentation(int indent) const {
+ for (int i = 0; i < indent; i++) {
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ }
+ }
+
+ void renderIndentation() const {
+ renderIndentation(_indent);
}
- Common::String posToString(int32 pos) {
+ Common::String posToString(int32 pos) const {
return Common::String::format("[%3d]", pos);
}
private:
ImGuiScript &_script;
+ bool _showByteCode = false;
bool _dot = false;
int _indent = 0;
-};
+ LingoDec::Handler *_handler = nullptr;
-typedef struct ImGuiState {
- struct {
- Common::HashMap<Graphics::Surface *, ImGuiImage> _textures;
- bool _listView = true;
- int _thumbnailSize = 64;
- ImGuiTextFilter _nameFilter;
- int _typeFilter = 0x7FFF;
- } _cast;
- struct {
- ImGuiScript _script;
- ImGuiTextFilter _nameFilter;
- bool _showScript = false;
- bool _showByteCode = false;
- } _functions;
- bool _showControlPanel = true;
- bool _showCallStack = false;
- bool _showVars = false;
- bool _showChannels = false;
- bool _showCast = false;
- bool _showFuncList = false;
- bool _showScore = false;
- Common::List<CastMemberID> _scriptCasts;
- Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _breakpoints;
- Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
- int _prevFrame = -1;
-
- struct {
- int frame = -1;
- int channel = -1;
- } _selectedScoreCast;
-} ImGuiState;
-
-ImGuiState *_state = nullptr;
+ const ImU32 bp_color_disabled = ImGui::GetColorU32(ImVec4(0.9f, 0.08f, 0.0f, 0.0f));
+ const ImU32 bp_color_enabled = ImGui::GetColorU32(ImVec4(0.9f, 0.08f, 0.0f, 1.0f));
+ const ImU32 bp_color_hover = ImGui::GetColorU32(ImVec4(0.42f, 0.17f, 0.13f, 1.0f));
+ const ImU32 line_color = ImGui::GetColorU32(ImVec4(0.44f, 0.44f, 0.44f, 1.0f));
+ const ImVec4 call_color = ImVec4(0.44f, 0.44f, 0.88f, 1.0f);
+ const ImVec4 builtin_color = ImColor(IM_COL32_WHITE);
+ const ImVec4 var_color = ImColor(IM_COL32_WHITE);
+ const ImVec4 literal_color = ImColor(IM_COL32_WHITE);
+};
static void showControlPanel() {
if (!_state->_showControlPanel)
@@ -1183,47 +1319,27 @@ static void renderCastScript(Symbol &sym) {
}
static void renderScript(ImGuiScript &script, bool showByteCode) {
- ImDrawList *dl = ImGui::GetWindowDrawList();
-
- const ImU32 bp_color_disabled = ImGui::GetColorU32(ImVec4(0.9f, 0.08f, 0.0f, 0.0f));
- const ImU32 bp_color_enabled = ImGui::GetColorU32(ImVec4(0.9f, 0.08f, 0.0f, 1.0f));
- const ImU32 bp_color_hover = ImGui::GetColorU32(ImVec4(0.42f, 0.17f, 0.13f, 1.0f));
- const ImU32 line_color = ImGui::GetColorU32(ImVec4(0.44f, 0.44f, 0.44f, 1.0f));
- ImU32 color;
-
- const Common::Array<ImGuiScriptCodeLine> &code = showByteCode ? script.byteCode : script.lingoCode;
- for (const auto& line : code) {
- ImVec2 pos = ImGui::GetCursorScreenPos();
- const ImVec2 mid(pos.x + 7, pos.y + 7);
- Common::String bpName = Common::String::format("%s-%d", script.handlerId.c_str(), line.pc);
-
- color = bp_color_disabled;
-
- if (_state->_breakpoints.contains(bpName))
- color = bp_color_enabled;
+ Director::Movie *movie = g_director->getCurrentMovie();
+ const Common::String &moviePath = movie->getArchive()->getPathName().toString();
+ if (moviePath != script.moviePath)
+ return;
- ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
- if (ImGui::IsItemClicked(0)) {
- if (color == bp_color_enabled) {
- _state->_breakpoints.erase(bpName);
- color = bp_color_disabled;
- } else {
- _state->_breakpoints[bpName] = true;
- color = bp_color_enabled;
- }
- }
+ const Director::Cast *cast = movie->getCast(script.id);
+ if (!cast->_lingodec)
+ return;
- if (color == bp_color_disabled && ImGui::IsItemHovered()) {
- color = bp_color_hover;
+ Common::SharedPtr<LingoDec::Node> node;
+ for (auto it : cast->_lingodec->scripts) {
+ for (const LingoDec::Handler &h : it.second->handlers) {
+ if (h.name != script.handlerId)
+ continue;
+ node = h.ast.root;
}
+ }
- dl->AddCircleFilled(mid, 4.0f, color);
- dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), line_color);
-
- ImGui::SetItemTooltip("Click to add a breakpoint");
-
- ImGui::SameLine();
- ImGui::Text("[%5d] %s", line.pc, line.codeLine.c_str());
+ if (node) {
+ RenderScriptVisitor visitor(script, showByteCode);
+ node->accept(visitor);
}
}
@@ -1344,17 +1460,8 @@ static void showFuncList() {
ImGuiScript script;
script.moviePath = movie->getArchive()->getPathName().toString();
script.score = true;
- script.type = csc->_scriptType;
script.handlerId = functionHandler._key;
script.handlerName = getHandlerName(functionHandler._value);
- uint32 scriptId = movie->getCast()->getCastMemberInfo(csc->_id)->scriptId;
- const LingoDec::Script *s = movie->getCast()->_lingodec->scripts[scriptId];
- ImGuiNodeVisitor visitor(script);
- for (auto &h : s->handlers) {
- if (h.name != functionHandler._key)
- continue;
- h.ast.root->accept(visitor);
- }
setScriptToDisplay(script);
}
ImGui::TableNextColumn();
@@ -1389,17 +1496,8 @@ static void showFuncList() {
ImGuiScript script;
script.moviePath = movie->getArchive()->getPathName().toString();
script.id = memberID;
- script.type = (ScriptType)i;
script.handlerId = functionHandler._key;
script.handlerName = getHandlerName(functionHandler._value);
- uint32 scriptId = movie->getCastMemberInfo(memberID)->scriptId;
- const LingoDec::Script *s = cast._value->_lingodec->scripts[scriptId];
- ImGuiNodeVisitor visitor(script);
- for (auto &h : s->handlers) {
- if (h.name != functionHandler._key)
- continue;
- h.ast.root->accept(visitor);
- }
setScriptToDisplay(script);
}
ImGui::TableNextColumn();
@@ -1437,17 +1535,8 @@ static void showFuncList() {
ImGuiScript script;
script.moviePath = movie->getArchive()->getPathName().toString();
script.id = memberID;
- script.type = (ScriptType)i;
script.handlerId = functionHandler._key;
script.handlerName = getHandlerName(functionHandler._value);
- uint32 scriptId = sharedCast->getCastMemberInfo(scriptContext._key)->scriptId;
- const LingoDec::Script *s = sharedCast->_lingodec->scripts[scriptId];
- ImGuiNodeVisitor visitor(script);
- for (auto &h : s->handlers) {
- if (h.name != functionHandler._key)
- continue;
- h.ast.root->accept(visitor);
- }
setScriptToDisplay(script);
}
ImGui::TableNextColumn();
Commit: b9b7788aeb2abc8b38611099ff096bf9c2478a83
https://github.com/scummvm/scummvm/commit/b9b7788aeb2abc8b38611099ff096bf9c2478a83
Author: scemino (scemino74 at gmail.com)
Date: 2024-05-20T11:47:38+02:00
Commit Message:
DIRECTOR: Add breakpoint list window
Changed paths:
engines/director/debugger.cpp
engines/director/debugger.h
engines/director/debugtools.cpp
engines/director/lingo/lingo.cpp
engines/director/lingo/lingo.h
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index f04c3bd6976..5ef1d5ddc4b 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -121,18 +121,6 @@ Debugger::Debugger(): GUI::Debugger() {
_nextCounter = 0;
_lingoEval = false;
_lingoReplMode = false;
- _bpNextId = 1;
- _bpCheckFunc = false;
- _bpCheckMoviePath = false;
- _bpNextMovieMatch = false;
- _bpMatchScriptId = 0;
- _bpCheckPropRead = false;
- _bpCheckPropWrite = false;
- _bpCheckVarRead = false;
- _bpCheckVarWrite = false;
- _bpCheckEntityRead = false;
- _bpCheckEntityWrite = false;
- _bpCheckEvent = false;
}
Debugger::~Debugger() {
@@ -207,7 +195,7 @@ bool Debugger::cmdHelp(int argc, const char **argv) {
return true;
}
-Common::String Breakpoint::format() {
+Common::String Breakpoint::format() const {
Common::String result = Common::String::format("Breakpoint %d, ", id);
switch (type) {
case kBreakpointFunction:
@@ -660,7 +648,6 @@ bool Debugger::cmdFinish(int argc, const char **argv) {
bool Debugger::cmdBpSet(int argc, const char **argv) {
Breakpoint bp;
- bp.id = _bpNextId;
bp.type = kBreakpointFunction;
if (argc == 1) {
Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
@@ -720,21 +707,18 @@ bool Debugger::cmdBpSet(int argc, const char **argv) {
debugPrintf("Too many arguments.\n");
return true;
}
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
- _bpNextId++;
return true;
}
bool Debugger::cmdBpMovie(int argc, const char **argv) {
if (argc == 2) {
Breakpoint bp;
- bp.id = _bpNextId;
- _bpNextId++;
bp.type = kBreakpointMovie;
bp.moviePath = argv[1];
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
} else {
@@ -780,9 +764,7 @@ bool Debugger::cmdBpEntity(int argc, const char **argv) {
bp.varRead = true;
bp.varWrite = true;
}
- bp.id = _bpNextId;
- _bpNextId++;
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
} else {
@@ -808,9 +790,7 @@ bool Debugger::cmdBpProp(int argc, const char **argv) {
bp.varRead = true;
bp.varWrite = true;
}
- bp.id = _bpNextId;
- _bpNextId++;
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
} else {
@@ -836,9 +816,7 @@ bool Debugger::cmdBpVar(int argc, const char **argv) {
bp.varRead = true;
bp.varWrite = true;
}
- bp.id = _bpNextId;
- _bpNextId++;
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
} else {
@@ -861,9 +839,7 @@ bool Debugger::cmdBpEvent(int argc, const char **argv) {
debugPrintf("Event %s not found.\n", argv[1]);
return true;
}
- bp.id = _bpNextId;
- _bpNextId++;
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
} else {
@@ -880,8 +856,6 @@ bool Debugger::cmdBpFrame(int argc, const char **argv) {
Movie *movie = g_director->getCurrentMovie();
if (argc == 2 || argc == 3) {
Breakpoint bp;
- bp.id = _bpNextId;
- _bpNextId++;
bp.type = kBreakpointMovieFrame;
Common::String target(argv[1]);
if (argc == 3) {
@@ -895,7 +869,7 @@ bool Debugger::cmdBpFrame(int argc, const char **argv) {
debugPrintf("Must specify a valid frame ID.\n");
return true;
}
- _breakpoints.push_back(bp);
+ g_lingo->addBreakpoint(bp);
bpUpdateState();
debugPrintf("Added %s\n", bp.format().c_str());
} else {
@@ -906,18 +880,12 @@ bool Debugger::cmdBpFrame(int argc, const char **argv) {
bool Debugger::cmdBpDel(int argc, const char **argv) {
if (argc == 2 && atoi(argv[1]) > 0) {
- bool found = false;
- for (auto it = _breakpoints.begin(); it != _breakpoints.end(); ++it) {
- if (it->id == atoi(argv[1])) {
- it = _breakpoints.erase(it);
- found = true;
- bpUpdateState();
- debugPrintf("Deleted breakpoint %s.\n", argv[1]);
- break;
- }
- }
- if (!found)
+ if (g_lingo->delBreakpoint(atoi(argv[1]))) {
+ debugPrintf("Deleted breakpoint %s.\n", argv[1]);
+ } else {
debugPrintf("No breakpoint with ID %s.\n", argv[1]);
+ }
+ bpUpdateState();
} else {
debugPrintf("Must specify a breakpoint ID.\n");
}
@@ -926,17 +894,12 @@ bool Debugger::cmdBpDel(int argc, const char **argv) {
bool Debugger::cmdBpEnable(int argc, const char **argv) {
if (argc == 2 && atoi(argv[1]) > 0) {
- bool found = false;
- for (auto &it : _breakpoints) {
- if (it.id == atoi(argv[1])) {
- it.enabled = true;
- found = true;
- bpUpdateState();
- debugPrintf("Enabled breakpoint %s.\n", argv[1]);
- break;
- }
- }
- if (!found)
+ Breakpoint *bp = g_lingo->getBreakpoint(atoi(argv[1]));
+ if (bp) {
+ bp->enabled = true;
+ bpUpdateState();
+ debugPrintf("Enabled breakpoint %s.\n", argv[1]);
+ } else
debugPrintf("No breakpoint with ID %s.\n", argv[1]);
} else {
debugPrintf("Must specify a breakpoint ID.\n");
@@ -946,17 +909,12 @@ bool Debugger::cmdBpEnable(int argc, const char **argv) {
bool Debugger::cmdBpDisable(int argc, const char **argv) {
if (argc == 2 && atoi(argv[1]) > 0) {
- bool found = false;
- for (auto &it : _breakpoints) {
- if (it.id == atoi(argv[1])) {
- it.enabled = false;
- found = true;
- bpUpdateState();
- debugPrintf("Disabled breakpoint %s.\n", argv[1]);
- break;
- }
- }
- if (!found)
+ Breakpoint *bp = g_lingo->getBreakpoint(atoi(argv[1]));
+ if (bp) {
+ bp->enabled = false;
+ bpUpdateState();
+ debugPrintf("Disabled breakpoint %s.\n", argv[1]);
+ } else
debugPrintf("No breakpoint with ID %s.\n", argv[1]);
} else {
debugPrintf("Must specify a breakpoint ID.\n");
@@ -965,8 +923,9 @@ bool Debugger::cmdBpDisable(int argc, const char **argv) {
}
bool Debugger::cmdBpList(int argc, const char **argv) {
- if (_breakpoints.size()) {
- for (auto &it : _breakpoints) {
+ const Common::Array<Breakpoint> &bps = g_lingo->getBreakpoints();
+ if (bps.size()) {
+ for (auto &it : bps) {
debugPrintf("%s (%s)\n", it.format().c_str(), it.enabled ? "enabled" : "disabled");
}
} else {
@@ -1057,7 +1016,7 @@ void Debugger::bpUpdateState() {
_bpCheckEvent = false;
Movie *movie = g_director->getCurrentMovie();
Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (!it.enabled)
continue;
if (it.type == kBreakpointFunction) {
@@ -1129,7 +1088,7 @@ void Debugger::bpTest(bool forceCheck) {
// Print the breakpoints that matched
if (stop) {
debugPrintf("Hit a breakpoint:\n");
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (!it.enabled)
continue;
if (it.type == kBreakpointFunction) {
@@ -1237,7 +1196,7 @@ void Debugger::movieHook() {
void Debugger::eventHook(LEvent eventId) {
if (_bpCheckEvent) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointEvent && eventId == it.eventId) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
@@ -1272,7 +1231,7 @@ void Debugger::builtinHook(const Symbol &funcSym) {
bpUpdateState();
bool builtinMatch = false;
if (_bpCheckFunc) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type != kBreakpointFunction)
continue;
if (it.funcName.equalsIgnoreCase(*funcSym.name)) {
@@ -1288,7 +1247,7 @@ void Debugger::propReadHook(const Common::String &name) {
if (name.empty())
return;
if (_bpCheckPropRead) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointProperty && it.varRead && it.varName.equalsIgnoreCase(name)) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
@@ -1305,7 +1264,7 @@ void Debugger::propWriteHook(const Common::String &name) {
if (name.empty())
return;
if (_bpCheckPropWrite) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointProperty && it.varWrite && it.varName.equalsIgnoreCase(name)) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
@@ -1322,7 +1281,7 @@ void Debugger::varReadHook(const Common::String &name) {
if (name.empty())
return;
if (_bpCheckVarRead) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointVariable && it.varRead && it.varName.equalsIgnoreCase(name)) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
@@ -1339,7 +1298,7 @@ void Debugger::varWriteHook(const Common::String &name) {
if (name.empty())
return;
if (_bpCheckVarWrite) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointVariable && it.varWrite && it.varName.equalsIgnoreCase(name)) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
@@ -1354,7 +1313,7 @@ void Debugger::varWriteHook(const Common::String &name) {
void Debugger::entityReadHook(int entity, int field) {
if (_bpCheckEntityRead) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointEntity && it.varRead && it.entity == entity && it.field == field) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
@@ -1369,7 +1328,7 @@ void Debugger::entityReadHook(int entity, int field) {
void Debugger::entityWriteHook(int entity, int field) {
if (_bpCheckEntityWrite) {
- for (auto &it : _breakpoints) {
+ for (auto &it : g_lingo->getBreakpoints()) {
if (it.type == kBreakpointEntity && it.varWrite && it.entity == entity && it.field == field) {
debugPrintf("Hit a breakpoint:\n");
debugPrintf("%s\n", it.format().c_str());
diff --git a/engines/director/debugger.h b/engines/director/debugger.h
index 1d0771075fe..4b8dd42b1fb 100644
--- a/engines/director/debugger.h
+++ b/engines/director/debugger.h
@@ -59,7 +59,7 @@ struct Breakpoint {
bool varRead = false;
bool varWrite = false;
- Common::String format();
+ Common::String format() const;
};
@@ -144,23 +144,21 @@ private:
bool _lingoEval;
bool _lingoReplMode;
- Common::Array<Breakpoint> _breakpoints;
- int _bpNextId;
- bool _bpCheckFunc;
- bool _bpCheckMoviePath;
- bool _bpNextMovieMatch;
+ bool _bpCheckFunc = false;
+ bool _bpCheckMoviePath = false;
+ bool _bpNextMovieMatch = false;
Common::String _bpMatchFuncName;
- uint _bpMatchScriptId;
+ uint _bpMatchScriptId = 0;
Common::String _bpMatchMoviePath;
Common::HashMap<uint, void *> _bpMatchFuncOffsets;
Common::HashMap<uint, void *> _bpMatchFrameOffsets;
- bool _bpCheckPropRead;
- bool _bpCheckPropWrite;
- bool _bpCheckVarRead;
- bool _bpCheckVarWrite;
- bool _bpCheckEntityRead;
- bool _bpCheckEntityWrite;
- bool _bpCheckEvent;
+ bool _bpCheckPropRead = false;
+ bool _bpCheckPropWrite = false;
+ bool _bpCheckVarRead = false;
+ bool _bpCheckVarWrite = false;
+ bool _bpCheckEntityRead = false;
+ bool _bpCheckEntityWrite = false;
+ bool _bpCheckEvent = false;
};
diff --git a/engines/director/debugtools.cpp b/engines/director/debugtools.cpp
index 2c055b1affc..ea46486df52 100644
--- a/engines/director/debugtools.cpp
+++ b/engines/director/debugtools.cpp
@@ -45,6 +45,7 @@
#include "director/castmember/script.h"
#include "director/channel.h"
#include "director/debugtools.h"
+#include "director/debugger.h"
#include "director/frame.h"
#include "director/movie.h"
#include "director/picture.h"
@@ -102,8 +103,8 @@ typedef struct ImGuiState {
bool _showCast = false;
bool _showFuncList = false;
bool _showScore = false;
+ bool _showBpList = false;
Common::List<CastMemberID> _scriptCasts;
- Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _breakpoints;
Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
int _prevFrame = -1;
struct {
@@ -116,6 +117,16 @@ ImGuiState *_state = nullptr;
static void setScriptToDisplay(const ImGuiScript &script);
+static Director::Breakpoint *getBreakpoint(const Common::String &handlerName, int pc) {
+ auto &bps = g_lingo->getBreakpoints();
+ for (uint i = 0; i < bps.size(); i++) {
+ if (bps[i].type == kBreakpointFunction && bps[i].funcName == handlerName && bps[i].funcOffset == pc) {
+ return &bps[i];
+ }
+ }
+ return nullptr;
+}
+
class RenderScriptVisitor : public LingoDec::NodeVisitor {
public:
explicit RenderScriptVisitor(ImGuiScript &script, bool showByteCode) : _script(script), _showByteCode(showByteCode) {}
@@ -436,20 +447,24 @@ private:
ImDrawList *dl = ImGui::GetWindowDrawList();
ImVec2 pos = ImGui::GetCursorScreenPos();
const ImVec2 mid(pos.x + 7, pos.y + 7);
- Common::String bpName = Common::String::format("%s-%d", _script.handlerId.c_str(), pc);
ImU32 color = bp_color_disabled;
- if (_state->_breakpoints.contains(bpName))
+ Director::Breakpoint *bp = getBreakpoint(_script.handlerName, pc);
+ if (bp)
color = bp_color_enabled;
ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
if (ImGui::IsItemClicked(0)) {
if (color == bp_color_enabled) {
- _state->_breakpoints.erase(bpName);
+ g_lingo->delBreakpoint(bp->id);
color = bp_color_disabled;
} else {
- _state->_breakpoints[bpName] = true;
+ Director::Breakpoint newBp;
+ newBp.type = kBreakpointFunction;
+ newBp.funcName = _script.handlerName;
+ newBp.funcOffset = pc;
+ g_lingo->addBreakpoint(newBp);
color = bp_color_enabled;
}
}
@@ -458,7 +473,10 @@ private:
color = bp_color_hover;
}
- dl->AddCircleFilled(mid, 4.0f, color);
+ if(!bp || bp->enabled)
+ dl->AddCircleFilled(mid, 4.0f, color);
+ else
+ dl->AddCircle(mid, 4.0f, line_color);
dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), line_color);
ImGui::SetItemTooltip("Click to add a breakpoint");
@@ -1288,16 +1306,21 @@ static void renderCastScript(Symbol &sym) {
color = bp_color_disabled;
- if (_state->_breakpoints.contains(bpName))
+ Director::Breakpoint *bp = getBreakpoint(handlerName, pc);
+ if (bp)
color = bp_color_enabled;
ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
if (ImGui::IsItemClicked(0)) {
- if (color == bp_color_enabled) {
- _state->_breakpoints.erase(bpName);
+ if (bp) {
+ g_lingo->delBreakpoint(bp->id);
color = bp_color_disabled;
} else {
- _state->_breakpoints[bpName] = true;
+ Director::Breakpoint newBp;
+ newBp.type = kBreakpointFunction;
+ newBp.funcName = handlerName;
+ newBp.funcOffset = pc;
+ g_lingo->addBreakpoint(newBp);
color = bp_color_enabled;
}
}
@@ -1556,6 +1579,112 @@ static void showFuncList() {
ImGui::End();
}
+// Make the UI compact because there are so many fields
+static void PushStyleCompact()
+{
+ ImGuiStyle& style = ImGui::GetStyle();
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
+}
+
+static void PopStyleCompact()
+{
+ ImGui::PopStyleVar(2);
+}
+
+static void showBreakpointList() {
+ if (!_state->_showBpList)
+ return;
+
+ const ImU32 bp_color_disabled = ImGui::GetColorU32(ImVec4(0.9f, 0.08f, 0.0f, 0.0f));
+ const ImU32 bp_color_enabled = ImGui::GetColorU32(ImVec4(0.9f, 0.08f, 0.0f, 1.0f));
+ const ImU32 bp_color_hover = ImGui::GetColorU32(ImVec4(0.42f, 0.17f, 0.13f, 1.0f));
+ const ImU32 line_color = ImGui::GetColorU32(ImVec4(0.44f, 0.44f, 0.44f, 1.0f));
+
+ ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(480, 240), ImGuiCond_FirstUseEver);
+ if (ImGui::Begin("Breakpoints", &_state->_showBpList)) {
+ auto &bps = g_lingo->getBreakpoints();
+ if (ImGui::BeginTable("BreakpointsTable", 5, ImGuiTableFlags_SizingFixedFit)) {
+ for (uint i = 0; i < bps.size(); i++) {
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn();
+
+ ImDrawList *dl = ImGui::GetWindowDrawList();
+ ImVec2 pos = ImGui::GetCursorScreenPos();
+ const ImVec2 mid(pos.x + 7, pos.y + 7);
+
+ ImU32 color = bp_color_disabled;
+
+ if (bps[i].enabled)
+ color = bp_color_enabled;
+
+ ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
+ if (ImGui::IsItemClicked(0)) {
+ if (bps[i].enabled) {
+ bps[i].enabled = false;
+ color = bp_color_disabled;
+ } else {
+ bps[i].enabled = true;
+ color = bp_color_enabled;
+ }
+ }
+
+ if (color == bp_color_disabled && ImGui::IsItemHovered()) {
+ color = bp_color_hover;
+ }
+
+ if (bps[i].enabled)
+ dl->AddCircleFilled(mid, 4.0f, color);
+ else
+ dl->AddCircle(mid, 4.0f, line_color);
+
+ // enabled column
+ ImGui::TableNextColumn();
+ PushStyleCompact();
+ ImGui::PushID(i);
+ ImGui::Checkbox("", &bps[i].enabled);
+ PopStyleCompact();
+
+ // description
+ ImGui::TableNextColumn();
+ Common::String desc;
+ if (bps[i].scriptId)
+ desc = Common::String::format("%d: %s", bps[i].scriptId, bps[i].funcName.c_str());
+ else
+ desc = bps[i].funcName;
+ ImGui::Text("%s", desc.c_str());
+
+ // remove bp
+ ImGui::TableNextColumn();
+ pos = ImGui::GetCursorScreenPos();
+ const bool del = ImGui::InvisibleButton("DelBp", ImVec2(16, ImGui::GetFontSize()));
+ const bool hovered = ImGui::IsItemHovered();
+ const float fontSize = ImGui::GetFontSize();
+ const float cross_extent = ImGui::GetFontSize() * 0.5f * 0.7071f - 1.0f;
+ const ImU32 cross_col = ImGui::GetColorU32(ImGuiCol_Text);
+ const ImVec2 center = pos + ImVec2(0.5f + fontSize * 0.5f, 1.0f + fontSize * 0.5f);
+ if (hovered)
+ dl->AddCircleFilled(center, MAX(2.0f, fontSize * 0.5f + 1.0f), ImGui::GetColorU32(ImGuiCol_ButtonActive));
+ dl->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f);
+ dl->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f);
+
+ // offset
+ ImGui::TableNextColumn();
+ ImGui::Text("%5d", bps[i].funcOffset);
+ ImGui::PopID();
+
+ if(del) {
+ g_lingo->delBreakpoint(bps[i].id);
+ break;
+ }
+ }
+ ImGui::EndTable();
+ }
+ }
+ ImGui::End();
+}
+
static void showScore() {
if (!_state->_showScore)
return;
@@ -1812,6 +1941,7 @@ void onImGuiRender() {
ImGui::MenuItem("Channels", NULL, &_state->_showChannels);
ImGui::MenuItem("Cast", NULL, &_state->_showCast);
ImGui::MenuItem("Functions", NULL, &_state->_showFuncList);
+ ImGui::MenuItem("Breakpoints", NULL, &_state->_showBpList);
ImGui::MenuItem("Score", NULL, &_state->_showScore);
ImGui::EndMenu();
}
@@ -1828,6 +1958,7 @@ void onImGuiRender() {
showCast();
showFuncList();
showScore();
+ showBreakpointList();
}
void onImGuiCleanup() {
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index dc1ec563c00..ef9d027ace0 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -1864,6 +1864,31 @@ void Lingo::exposeXObject(const char *name, Datum obj) {
_globalvars[name].ignoreGlobal = true;
}
+void Lingo::addBreakpoint(Breakpoint &bp) {
+ bp.id = _bpNextId;
+ _breakpoints.push_back(bp);
+ _bpNextId++;
+}
+
+bool Lingo::delBreakpoint(int id) {
+ for (auto it = _breakpoints.begin(); it != _breakpoints.end(); ++it) {
+ if (it->id == id) {
+ it = _breakpoints.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+Breakpoint *Lingo::getBreakpoint(int id) {
+ for (auto &it : _breakpoints) {
+ if (it.id == id) {
+ return ⁢
+ }
+ }
+ return nullptr;
+}
+
PictureReference::~PictureReference() {
delete _picture;
}
diff --git a/engines/director/lingo/lingo.h b/engines/director/lingo/lingo.h
index ffe25efc3b3..f1dd15b3217 100644
--- a/engines/director/lingo/lingo.h
+++ b/engines/director/lingo/lingo.h
@@ -47,6 +47,7 @@ class ScriptContext;
class DirectorEngine;
class Frame;
class LingoCompiler;
+struct Breakpoint;
typedef void (*inst)(void);
#define STOP (inst)0
@@ -561,6 +562,18 @@ private:
public:
Common::String normalizeString(const Common::String &str);
+
+public:
+ void addBreakpoint(Breakpoint &bp);
+ bool delBreakpoint(int id);
+ Breakpoint *getBreakpoint(int id);
+
+ const Common::Array<Breakpoint> &getBreakpoints() const { return _breakpoints; }
+ Common::Array<Breakpoint> &getBreakpoints() { return _breakpoints; }
+
+private:
+ int _bpNextId = 1;
+ Common::Array<Breakpoint> _breakpoints;
};
extern Lingo *g_lingo;
More information about the Scummvm-git-logs
mailing list