[Scummvm-git-logs] scummvm master -> 55eeb64759c3e00a07e578a8399c189a41c2c441
sev-
noreply at scummvm.org
Sat Jun 1 18:45:32 UTC 2024
This automated email contains information about 9 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
1d38b62529 DIRECTOR: DEBUGGER: Remove custom strdup() implementation
b189868e56 DIRECTOR: DT: SPlit out logger to a separate file, wrapped everything in namespace
6476e4d4b4 DIRECTOR: LINGO: Remove leftover debug output
df16f21570 DIRECTOR: DT: Moved struct definitions to dt-internal.h
59ce105429 DIRECTOR: DT: Split out script code highlighters into separate files
7d0a75e85a DIRECTOR: DT: Moved Score and Cast windows to dt-score.cpp
208c346ce2 DIRECTOR: DT: Moved Control Panel window to a separate file
2a908bb2dc DIRECTOR: DT: Moved script rendering windows to dt-scripts.cpp
55eeb64759 DIRECTOR: DT: Move Cast window to dt-cast.cpp
Commit: 1d38b625292684dee2320b99ef8fc3739e61151c
https://github.com/scummvm/scummvm/commit/1d38b625292684dee2320b99ef8fc3739e61151c
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:00+02:00
Commit Message:
DIRECTOR: DEBUGGER: Remove custom strdup() implementation
Changed paths:
engines/director/debugger/debugtools.cpp
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index a4b9e94ea21..415da0b1131 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -174,7 +174,7 @@ struct ImGuiLogger {
vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
buf[IM_ARRAYSIZE(buf) - 1] = 0;
va_end(args);
- _items.push_back(Strdup(buf));
+ _items.push_back(scumm_strdup(buf));
}
void draw(const char *title, bool *p_open) {
@@ -354,14 +354,6 @@ struct ImGuiLogger {
ImGui::EndChild();
ImGui::End();
}
-
-private:
- static char *Strdup(const char *str) {
- size_t len = strlen(str) + 1;
- void *buf = malloc(len);
- IM_ASSERT(buf);
- return (char *)memcpy(buf, (const void *)str, len);
- }
};
typedef struct ImGuiState {
Commit: b189868e56043eef879cd24da099fdcdd022a715
https://github.com/scummvm/scummvm/commit/b189868e56043eef879cd24da099fdcdd022a715
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:00+02:00
Commit Message:
DIRECTOR: DT: SPlit out logger to a separate file, wrapped everything in namespace
Changed paths:
A engines/director/debugger/dt-internal.h
A engines/director/debugger/dt-logger.cpp
engines/director/debugger/debugtools.cpp
engines/director/debugger/debugtools.h
engines/director/director.cpp
engines/director/module.mk
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 415da0b1131..01810cceb5e 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -19,12 +19,7 @@
*
*/
-#define IMGUI_DEFINE_MATH_OPERATORS
-
-#include "backends/imgui/imgui.h"
-#include "backends/imgui/imgui_fonts.h"
#include "common/config-manager.h"
-#include "common/debug-channels.h"
#include "common/system.h"
#include "graphics/surface.h"
#include "graphics/opengl/shader.h"
@@ -59,10 +54,13 @@
#include "director/window.h"
#include "director/debugger/debugtools.h"
+#include "director/debugger/dt-internal.h"
#include "director/debugger/imgui_memory_editor.h"
namespace Director {
+namespace DT {
+
#define kMaxColumnsInTable 512
typedef struct ImGuiImage {
@@ -118,7 +116,7 @@ typedef struct ImGuiWindows {
bool watchedVars = false;
} ImGuiWindows;
-static bool toggleButton(const char *label, bool *p_value, bool inverse = false) {
+bool toggleButton(const char *label, bool *p_value, bool inverse) {
int pop = 0;
if (*p_value != inverse) {
ImVec4 hovered = ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered];
@@ -133,229 +131,6 @@ static bool toggleButton(const char *label, bool *p_value, bool inverse = false)
return result;
}
-struct ImGuiLogger {
- char _inputBuf[256];
- ImVector<char *> _items;
- ImVector<char *> _history;
- int _historyPos; // -1: new line, 0.._history.Size-1 browsing history.
- ImGuiTextFilter _filter;
- bool _autoScroll;
- bool _scrollToBottom;
- bool _showError = true;
- bool _showWarn = true;
- bool _showInfo = true;
- bool _showdebug = true;
-
- ImGuiLogger() {
- clear();
- memset(_inputBuf, 0, sizeof(_inputBuf));
- _historyPos = -1;
- _autoScroll = true;
- _scrollToBottom = false;
- }
-
- ~ImGuiLogger() {
- clear();
- for (int i = 0; i < _history.Size; i++)
- free(_history[i]);
- }
-
- void clear() {
- for (int i = 0; i < _items.Size; i++)
- free(_items[i]);
- _items.clear();
- }
-
- void addLog(const char *fmt, ...) IM_FMTARGS(2) {
- // FIXME-OPT
- char buf[1024];
- va_list args;
- va_start(args, fmt);
- vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
- buf[IM_ARRAYSIZE(buf) - 1] = 0;
- va_end(args);
- _items.push_back(scumm_strdup(buf));
- }
-
- void draw(const char *title, bool *p_open) {
- if (!*p_open)
- return;
-
- ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
- if (!ImGui::Begin(title, p_open)) {
- ImGui::End();
- return;
- }
-
- // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar.
- // Here we create a context menu only available from the title bar.
- if (ImGui::BeginPopupContextItem()) {
- if (ImGui::MenuItem("Close ImGuiLogger"))
- *p_open = false;
- ImGui::EndPopup();
- }
-
- // Clear
- if (ImGui::Button("\ue0b8")) {
- clear();
- }
- ImGui::SetItemTooltip("Clear");
- ImGui::SameLine();
-
- // Copy
- bool copy_to_clipboard = ImGui::Button("\ue14d");
- ImGui::SetItemTooltip("Copy to clipboard");
- ImGui::SameLine();
-
- // debug channels
- int numChannels = 0;
- auto channels = DebugMan.getDebugChannels();
- for (auto &channel : channels) {
- if (channel.name == "imgui")
- continue;
- bool enabled = DebugMan.isDebugChannelEnabled(channel.channel);
- if (enabled)
- numChannels++;
- }
-
- Common::String selChannels(Common::String::format("(%d channel%s)", numChannels, numChannels > 1 ? "s" : ""));
- ImGui::PushItemWidth(120);
- if (ImGui::BeginCombo("##Channels", selChannels.c_str())) {
- for (auto &channel : channels) {
- if (channel.name == "imgui")
- continue;
- bool enabled = DebugMan.isDebugChannelEnabled(channel.channel);
- if (ImGui::Checkbox(channel.name.c_str(), &enabled)) {
- if (enabled) {
- DebugMan.enableDebugChannel(channel.channel);
- } else {
- DebugMan.disableDebugChannel(channel.channel);
- }
- }
- ImGui::SetItemTooltip("%s", channel.description.c_str());
- }
- ImGui::EndCombo();
- }
- ImGui::SameLine();
-
- // Options menu
- if (ImGui::BeginPopup("Options")) {
- if (ImGui::InputInt("Debug Level", &gDebugLevel)) {
- if (gDebugLevel < 0)
- gDebugLevel = 0;
- }
- ImGui::Separator();
- ImGui::Checkbox("Auto-scroll", &_autoScroll);
- ImGui::EndPopup();
- }
-
- // Options, Filter
- if (ImGui::Button("\ue8b8"))
- ImGui::OpenPopup("Options");
- ImGui::SetItemTooltip("Options");
- ImGui::SameLine();
-
- ImGui::Spacing();
- ImGui::SameLine();
-
- // Error
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f));
- toggleButton("\ue160", &_showError);
- ImGui::PopStyleColor();
- ImGui::SetItemTooltip("Show Errors");
- ImGui::SameLine();
-
- // Warning
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 0.f, 1.f));
- toggleButton("\ue002", &_showWarn);
- ImGui::PopStyleColor();
- ImGui::SetItemTooltip("Show Warnings");
- ImGui::SameLine();
-
- // Info
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f));
- toggleButton("\ue88e", &_showInfo);
- ImGui::PopStyleColor();
- ImGui::SetItemTooltip("Show Info");
- ImGui::SameLine();
-
- // Debug
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.f));
- toggleButton("\ue868", &_showdebug);
- ImGui::PopStyleColor();
- ImGui::SetItemTooltip("Show Debug");
- ImGui::SameLine();
-
- _filter.Draw("Filter (\"incl,-excl\") (\"warn\")", 180);
- ImGui::Separator();
-
- ImGui::BeginChild("ScrollingRegion", ImVec2(), false, ImGuiWindowFlags_HorizontalScrollbar);
- if (ImGui::BeginPopupContextWindow()) {
- if (ImGui::Selectable("\ue0b8 Clear"))
- clear();
- if (ImGui::Selectable("\ue14d Copy"))
- copy_to_clipboard = true;
- ImGui::EndPopup();
- }
-
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
- if (copy_to_clipboard)
- ImGui::LogToClipboard();
- for (int i = 0; i < _items.Size; i++) {
- const char *item = _items[i];
- bool isError = strstr(item, "[error]");
- if (!_showError && isError)
- continue;
-
- bool isWarn = strstr(item, "[warn]");
- if (!_showWarn && isWarn)
- continue;
-
- bool isDebug = strstr(item, "[debug]");
- if (!_showdebug && isDebug)
- continue;
-
- if (!_showInfo && !isError && !isWarn && !isDebug)
- continue;
-
- if (!_filter.PassFilter(item))
- continue;
-
- // Normally you would store more information in your item (e.g. make _items[] an array of structure, store color/type etc.)
- bool pop_color = false;
- if (isError) {
- item += 7;
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f));
- pop_color = true;
- } else if (isWarn) {
- item += 6;
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
- pop_color = true;
- } else if (isDebug) {
- item += 7;
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
- pop_color = true;
- } else if (strncmp(item, "> ", 2) == 0) {
- ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f));
- pop_color = true;
- }
- ImGui::TextUnformatted(item);
- if (pop_color)
- ImGui::PopStyleColor();
- }
- if (copy_to_clipboard)
- ImGui::LogFinish();
-
- if (_scrollToBottom || (_autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
- ImGui::SetScrollHereY(1.0f);
- _scrollToBottom = false;
-
- ImGui::PopStyleVar();
- ImGui::EndChild();
- ImGui::End();
- }
-};
-
typedef struct ImGuiState {
struct {
Common::HashMap<Graphics::Surface *, ImGuiImage> _textures;
@@ -4540,4 +4315,7 @@ void onImGuiCleanup() {
delete _state;
_state = nullptr;
}
+
+} // namespace DT
+
} // namespace Director
diff --git a/engines/director/debugger/debugtools.h b/engines/director/debugger/debugtools.h
index 1ef7eb0c8d4..a46eb2806d0 100644
--- a/engines/director/debugger/debugtools.h
+++ b/engines/director/debugger/debugtools.h
@@ -23,9 +23,11 @@
#define DIRECTOR_DEBUGTOOLS_H
namespace Director {
+namespace DT {
void onImGuiInit();
void onImGuiRender();
void onImGuiCleanup();
+} // namespace DT
} // namespace Director
#endif
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
new file mode 100644
index 00000000000..279552561e8
--- /dev/null
+++ b/engines/director/debugger/dt-internal.h
@@ -0,0 +1,61 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_DEBUGER_DT_INTERNAL_H
+#define DIRECTOR_DEBUGER_DT_INTERNAL_H
+
+#define IMGUI_DEFINE_MATH_OPERATORS
+
+#include "backends/imgui/imgui.h"
+#include "backends/imgui/imgui_fonts.h"
+
+namespace Director {
+
+namespace DT {
+
+class ImGuiLogger {
+ char _inputBuf[256];
+ ImVector<char *> _items;
+ ImVector<char *> _history;
+ int _historyPos; // -1: new line, 0.._history.Size-1 browsing history.
+ ImGuiTextFilter _filter;
+ bool _autoScroll;
+ bool _scrollToBottom;
+ bool _showError = true;
+ bool _showWarn = true;
+ bool _showInfo = true;
+ bool _showdebug = true;
+
+public:
+ ImGuiLogger();
+ ~ImGuiLogger();
+ void clear();
+ void addLog(const char *fmt, ...) IM_FMTARGS(2);
+ void draw(const char *title, bool *p_open);
+};
+
+bool toggleButton(const char *label, bool *p_value, bool inverse = false);
+
+}
+
+};
+
+#endif
diff --git a/engines/director/debugger/dt-logger.cpp b/engines/director/debugger/dt-logger.cpp
new file mode 100644
index 00000000000..bce26d25243
--- /dev/null
+++ b/engines/director/debugger/dt-logger.cpp
@@ -0,0 +1,241 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/debug.h"
+#include "common/debug-channels.h"
+
+#include "director/debugger/dt-internal.h"
+
+namespace Director {
+namespace DT {
+
+ImGuiLogger::ImGuiLogger() {
+ clear();
+ memset(_inputBuf, 0, sizeof(_inputBuf));
+ _historyPos = -1;
+ _autoScroll = true;
+ _scrollToBottom = false;
+}
+
+ImGuiLogger::~ImGuiLogger() {
+ clear();
+ for (int i = 0; i < _history.Size; i++)
+ free(_history[i]);
+}
+
+void ImGuiLogger::clear() {
+ for (int i = 0; i < _items.Size; i++)
+ free(_items[i]);
+ _items.clear();
+}
+
+void ImGuiLogger::addLog(const char *fmt, ...) IM_FMTARGS(2) {
+ // FIXME-OPT
+ char buf[1024];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buf, IM_ARRAYSIZE(buf), fmt, args);
+ buf[IM_ARRAYSIZE(buf) - 1] = 0;
+ va_end(args);
+ _items.push_back(scumm_strdup(buf));
+}
+
+void ImGuiLogger::draw(const char *title, bool *p_open) {
+ if (!*p_open)
+ return;
+
+ ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
+ if (!ImGui::Begin(title, p_open)) {
+ ImGui::End();
+ return;
+ }
+
+ // As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar. So e.g. IsItemHovered() will return true when hovering the title bar.
+ // Here we create a context menu only available from the title bar.
+ if (ImGui::BeginPopupContextItem()) {
+ if (ImGui::MenuItem("Close ImGuiLogger"))
+ *p_open = false;
+ ImGui::EndPopup();
+ }
+
+ // Clear
+ if (ImGui::Button("\ue0b8")) {
+ clear();
+ }
+ ImGui::SetItemTooltip("Clear");
+ ImGui::SameLine();
+
+ // Copy
+ bool copy_to_clipboard = ImGui::Button("\ue14d");
+ ImGui::SetItemTooltip("Copy to clipboard");
+ ImGui::SameLine();
+
+ // debug channels
+ int numChannels = 0;
+ auto channels = DebugMan.getDebugChannels();
+ for (auto &channel : channels) {
+ if (channel.name == "imgui")
+ continue;
+ bool enabled = DebugMan.isDebugChannelEnabled(channel.channel);
+ if (enabled)
+ numChannels++;
+ }
+
+ Common::String selChannels(Common::String::format("(%d channel%s)", numChannels, numChannels > 1 ? "s" : ""));
+ ImGui::PushItemWidth(120);
+ if (ImGui::BeginCombo("##Channels", selChannels.c_str())) {
+ for (auto &channel : channels) {
+ if (channel.name == "imgui")
+ continue;
+ bool enabled = DebugMan.isDebugChannelEnabled(channel.channel);
+ if (ImGui::Checkbox(channel.name.c_str(), &enabled)) {
+ if (enabled) {
+ DebugMan.enableDebugChannel(channel.channel);
+ } else {
+ DebugMan.disableDebugChannel(channel.channel);
+ }
+ }
+ ImGui::SetItemTooltip("%s", channel.description.c_str());
+ }
+ ImGui::EndCombo();
+ }
+ ImGui::SameLine();
+
+ // Options menu
+ if (ImGui::BeginPopup("Options")) {
+ if (ImGui::InputInt("Debug Level", &gDebugLevel)) {
+ if (gDebugLevel < 0)
+ gDebugLevel = 0;
+ }
+ ImGui::Separator();
+ ImGui::Checkbox("Auto-scroll", &_autoScroll);
+ ImGui::EndPopup();
+ }
+
+ // Options, Filter
+ if (ImGui::Button("\ue8b8"))
+ ImGui::OpenPopup("Options");
+ ImGui::SetItemTooltip("Options");
+ ImGui::SameLine();
+
+ ImGui::Spacing();
+ ImGui::SameLine();
+
+ // Error
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 0.f, 0.f, 1.f));
+ toggleButton("\ue160", &_showError);
+ ImGui::PopStyleColor();
+ ImGui::SetItemTooltip("Show Errors");
+ ImGui::SameLine();
+
+ // Warning
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 0.f, 1.f));
+ toggleButton("\ue002", &_showWarn);
+ ImGui::PopStyleColor();
+ ImGui::SetItemTooltip("Show Warnings");
+ ImGui::SameLine();
+
+ // Info
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.f, 1.f, 1.f, 1.f));
+ toggleButton("\ue88e", &_showInfo);
+ ImGui::PopStyleColor();
+ ImGui::SetItemTooltip("Show Info");
+ ImGui::SameLine();
+
+ // Debug
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.f));
+ toggleButton("\ue868", &_showdebug);
+ ImGui::PopStyleColor();
+ ImGui::SetItemTooltip("Show Debug");
+ ImGui::SameLine();
+
+ _filter.Draw("Filter (\"incl,-excl\") (\"warn\")", 180);
+ ImGui::Separator();
+
+ ImGui::BeginChild("ScrollingRegion", ImVec2(), false, ImGuiWindowFlags_HorizontalScrollbar);
+ if (ImGui::BeginPopupContextWindow()) {
+ if (ImGui::Selectable("\ue0b8 Clear"))
+ clear();
+ if (ImGui::Selectable("\ue14d Copy"))
+ copy_to_clipboard = true;
+ ImGui::EndPopup();
+ }
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
+ if (copy_to_clipboard)
+ ImGui::LogToClipboard();
+ for (int i = 0; i < _items.Size; i++) {
+ const char *item = _items[i];
+ bool isError = strstr(item, "[error]");
+ if (!_showError && isError)
+ continue;
+
+ bool isWarn = strstr(item, "[warn]");
+ if (!_showWarn && isWarn)
+ continue;
+
+ bool isDebug = strstr(item, "[debug]");
+ if (!_showdebug && isDebug)
+ continue;
+
+ if (!_showInfo && !isError && !isWarn && !isDebug)
+ continue;
+
+ if (!_filter.PassFilter(item))
+ continue;
+
+ // Normally you would store more information in your item (e.g. make _items[] an array of structure, store color/type etc.)
+ bool pop_color = false;
+ if (isError) {
+ item += 7;
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.4f, 0.4f, 1.0f));
+ pop_color = true;
+ } else if (isWarn) {
+ item += 6;
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
+ pop_color = true;
+ } else if (isDebug) {
+ item += 7;
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
+ pop_color = true;
+ } else if (strncmp(item, "> ", 2) == 0) {
+ ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.6f, 1.0f));
+ pop_color = true;
+ }
+ ImGui::TextUnformatted(item);
+ if (pop_color)
+ ImGui::PopStyleColor();
+ }
+ if (copy_to_clipboard)
+ ImGui::LogFinish();
+
+ if (_scrollToBottom || (_autoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
+ ImGui::SetScrollHereY(1.0f);
+ _scrollToBottom = false;
+
+ ImGui::PopStyleVar();
+ ImGui::EndChild();
+ ImGui::End();
+}
+
+} // namespace DT
+
+} // namespace Director
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 7a5aab0ae93..587a5cd26ca 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -291,9 +291,9 @@ Common::Error DirectorEngine::run() {
#ifdef USE_IMGUI
ImGuiCallbacks callbacks;
- callbacks.init = onImGuiInit;
- callbacks.render = onImGuiRender;
- callbacks.cleanup = onImGuiCleanup;
+ callbacks.init = DT::onImGuiInit;
+ callbacks.render = DT::onImGuiRender;
+ callbacks.cleanup = DT::onImGuiCleanup;
_system->setImGuiCallbacks(callbacks);
#endif
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 351caca0789..9ab58e6bdf5 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -159,6 +159,7 @@ MODULE_OBJS = \
ifdef USE_IMGUI
MODULE_OBJS += \
debugger/debugtools.o \
+ debugger/dt-logger.o \
endif
Commit: 6476e4d4b454bdb7c75f581d583bf664b7b4f1bd
https://github.com/scummvm/scummvm/commit/6476e4d4b454bdb7c75f581d583bf664b7b4f1bd
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:00+02:00
Commit Message:
DIRECTOR: LINGO: Remove leftover debug output
Changed paths:
engines/director/lingo/lingo-codegen.cpp
diff --git a/engines/director/lingo/lingo-codegen.cpp b/engines/director/lingo/lingo-codegen.cpp
index 63f86e49b98..9d4f91e07e4 100644
--- a/engines/director/lingo/lingo-codegen.cpp
+++ b/engines/director/lingo/lingo-codegen.cpp
@@ -132,7 +132,6 @@ ScriptContext *LingoCompiler::compileLingo(const Common::U32String &code, LingoA
_assemblyArchive = archive;
_assemblyAST = nullptr;
_assemblyId = id.member;
- warning("%s: %s", scriptName.c_str(), code.encode().c_str());
ScriptContext *mainContext = _assemblyContext = new ScriptContext(scriptName, type, _assemblyId);
_currentAssembly = new ScriptData;
Commit: df16f21570e7f8d67555289af98c5ef61980e0fa
https://github.com/scummvm/scummvm/commit/df16f21570e7f8d67555289af98c5ef61980e0fa
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:00+02:00
Commit Message:
DIRECTOR: DT: Moved struct definitions to dt-internal.h
Changed paths:
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-internal.h
engines/director/debugger/dt-logger.cpp
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 01810cceb5e..3741ee100c6 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -21,7 +21,6 @@
#include "common/config-manager.h"
#include "common/system.h"
-#include "graphics/surface.h"
#include "graphics/opengl/shader.h"
#include "image/png.h"
@@ -31,10 +30,8 @@
#include "director/lingo/lingo-code.h"
#include "director/lingo/lingo-object.h"
#include "director/lingo/lingo-the.h"
-#include "director/lingo/lingodec/ast.h"
#include "director/lingo/lingodec/codewritervisitor.h"
#include "director/lingo/lingodec/context.h"
-#include "director/lingo/lingodec/handler.h"
#include "director/lingo/lingodec/names.h"
#include "director/lingo/lingodec/resolver.h"
#include "director/lingo/lingodec/script.h"
@@ -55,66 +52,11 @@
#include "director/debugger/debugtools.h"
#include "director/debugger/dt-internal.h"
-#include "director/debugger/imgui_memory_editor.h"
namespace Director {
namespace DT {
-#define kMaxColumnsInTable 512
-
-typedef struct ImGuiImage {
- ImTextureID id;
- int16 width;
- int16 height;
-} ImGuiImage;
-
-typedef struct ImGuiScriptCodeLine {
- uint32 pc;
- Common::String codeLine;
-} ImGuiScriptCodeLine;
-
-typedef struct ImGuiScript {
- bool score = false;
- CastMemberID id;
- ScriptType type;
- Common::String handlerId;
- Common::String handlerName;
- Common::String moviePath;
- Common::Array<uint32> byteOffsets;
-
- bool isMethod = false;
- bool isGenericEvent = false;
- Common::StringArray argumentNames;
- Common::StringArray propertyNames;
- Common::StringArray globalNames;
- Common::SharedPtr<LingoDec::HandlerNode> root;
- Common::Array<LingoDec::Bytecode> bytecodeArray;
- Common::Array<uint> startOffsets;
- Common::SharedPtr<Node> oldAst;
-
- bool operator==(const ImGuiScript &c) const {
- return moviePath == c.moviePath && score == c.score && id == c.id && handlerId == c.handlerId;
- }
- bool operator!=(const ImGuiScript &c) const {
- return !(*this == c);
- }
-} ImGuiScript;
-
-typedef struct ImGuiWindows {
- bool controlPanel = true;
- bool callStack = false;
- bool vars = false;
- bool channels = false;
- bool cast = false;
- bool funcList = false;
- bool score = false;
- bool bpList = false;
- bool settings = false;
- bool logger = false;
- bool archive = false;
- bool watchedVars = false;
-} ImGuiWindows;
bool toggleButton(const char *label, bool *p_value, bool inverse) {
int pop = 0;
@@ -131,80 +73,6 @@ bool toggleButton(const char *label, bool *p_value, bool inverse) {
return result;
}
-typedef struct ImGuiState {
- struct {
- Common::HashMap<Graphics::Surface *, ImGuiImage> _textures;
- bool _listView = true;
- int _thumbnailSize = 64;
- ImGuiTextFilter _nameFilter;
- int _typeFilter = 0x7FFF;
- } _cast;
- struct {
- Common::Array<ImGuiScript> _scripts;
- uint _current = 0;
- ImGuiTextFilter _nameFilter;
- bool _showByteCode = false;
- bool _showScript = false;
- } _functions;
- struct {
- uint _lastLinePC = 0;
- uint _callstackSize = 0;
- bool _isScriptDirty = false; // indicates whether or not we have to display the script corresponding to the current stackframe
- } _dbg;
-
- struct {
- ImVec4 _bp_color_disabled = ImVec4(0.9f, 0.08f, 0.0f, 0.0f);
- ImVec4 _bp_color_enabled = ImVec4(0.9f, 0.08f, 0.0f, 1.0f);
- ImVec4 _bp_color_hover = ImVec4(0.42f, 0.17f, 0.13f, 1.0f);
- ImVec4 _current_statement = ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0xFF));
- ImVec4 _line_color = ImVec4(0.44f, 0.44f, 0.44f, 1.0f);
- ImVec4 _call_color = ImColor(IM_COL32(0xFF, 0xC5, 0x5C, 0xFF));
- ImVec4 _builtin_color = ImColor(IM_COL32(0x60, 0x7C, 0xFF, 0xFF));
- ImVec4 _var_color = ImColor(IM_COL32(0x4B, 0xCD, 0x5E, 0xFF));
- ImVec4 _literal_color = ImColor(IM_COL32(0xFF, 0x9F, 0xDA, 0x9E));
- ImVec4 _comment_color = ImColor(IM_COL32(0xFF, 0xA5, 0x9D, 0x95));
- ImVec4 _type_color = ImColor(IM_COL32(0x13, 0xC5, 0xF9, 0xFF));
- ImVec4 _keyword_color = ImColor(IM_COL32(0xC1, 0xC1, 0xC1, 0xFF));
- ImVec4 _the_color = ImColor(IM_COL32(0xFF, 0x49, 0xEF, 0xFF));
- } _colors;
-
- struct {
- DatumHash _locals;
- DatumHash _globals;
- uint32 _lastTimeRefreshed = 0;
- } _vars;
-
- ImGuiWindows _w;
- ImGuiWindows _savedW;
- bool _wasHidden = false;
-
- Common::List<CastMemberID> _scriptCasts;
- Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
- int _prevFrame = -1;
- struct {
- int frame = -1;
- int channel = -1;
- } _selectedScoreCast;
-
- int _scoreMode = 0;
- int _scoreFrameOffset = 1;
-
- ImFont *_tinyFont = nullptr;
-
- struct {
- Common::Path path;
- uint32 resType = 0;
- uint32 resId = 0;
-
- byte *data = nullptr;
- uint32 dataSize = 0;
-
- MemoryEditor memEdit;
- } _archive;
-
- ImGuiLogger _logger;
-} ImGuiState;
-
ImGuiState *_state = nullptr;
const LingoDec::Handler *getHandler(const Cast *cast, CastMemberID id, const Common::String &handlerId) {
@@ -4157,16 +4025,16 @@ static void showArchive() {
void onLog(LogMessageType::Type type, int level, uint32 debugChannels, const char *message) {
switch (type) {
case LogMessageType::kError:
- _state->_logger.addLog("[error]%s", message);
+ _state->_logger->addLog("[error]%s", message);
break;
case LogMessageType::kWarning:
- _state->_logger.addLog("[warn]%s", message);
+ _state->_logger->addLog("[warn]%s", message);
break;
case LogMessageType::kInfo:
- _state->_logger.addLog("%s", message);
+ _state->_logger->addLog("%s", message);
break;
case LogMessageType::kDebug:
- _state->_logger.addLog("[debug]%s", message);
+ _state->_logger->addLog("[debug]%s", message);
break;
}
}
@@ -4225,6 +4093,8 @@ void onImGuiInit() {
_state->_archive.memEdit.ReadOnly = true;
+ _state->_logger = new ImGuiLogger;
+
Common::setLogWatcher(onLog);
}
@@ -4302,7 +4172,7 @@ void onImGuiRender() {
showSettings();
showArchive();
showWatchedVars();
- _state->_logger.draw("Logger", &_state->_w.logger);
+ _state->_logger->draw("Logger", &_state->_w.logger);
}
void onImGuiCleanup() {
@@ -4310,6 +4180,8 @@ void onImGuiCleanup() {
if (_state) {
delete _state->_tinyFont;
free(_state->_archive.data);
+
+ delete _state->_logger;
}
delete _state;
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 279552561e8..078f96e1bf3 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -24,13 +24,154 @@
#define IMGUI_DEFINE_MATH_OPERATORS
+#include "graphics/surface.h"
+
#include "backends/imgui/imgui.h"
#include "backends/imgui/imgui_fonts.h"
+#include "director/debugger/imgui_memory_editor.h"
+
+#include "director/types.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingodec/ast.h"
+#include "director/lingo/lingodec/handler.h"
+
namespace Director {
namespace DT {
+class ImGuiLogger;
+
+#define kMaxColumnsInTable 512
+
+typedef struct ImGuiImage {
+ ImTextureID id;
+ int16 width;
+ int16 height;
+} ImGuiImage;
+
+typedef struct ImGuiScriptCodeLine {
+ uint32 pc;
+ Common::String codeLine;
+} ImGuiScriptCodeLine;
+
+typedef struct ImGuiScript {
+ bool score = false;
+ CastMemberID id;
+ ScriptType type;
+ Common::String handlerId;
+ Common::String handlerName;
+ Common::String moviePath;
+ Common::Array<uint32> byteOffsets;
+
+ bool isMethod = false;
+ bool isGenericEvent = false;
+ Common::StringArray argumentNames;
+ Common::StringArray propertyNames;
+ Common::StringArray globalNames;
+ Common::SharedPtr<LingoDec::HandlerNode> root;
+ Common::Array<LingoDec::Bytecode> bytecodeArray;
+ Common::Array<uint> startOffsets;
+ Common::SharedPtr<Node> oldAst;
+
+ bool operator==(const ImGuiScript &c) const {
+ return moviePath == c.moviePath && score == c.score && id == c.id && handlerId == c.handlerId;
+ }
+ bool operator!=(const ImGuiScript &c) const {
+ return !(*this == c);
+ }
+} ImGuiScript;
+
+typedef struct ImGuiWindows {
+ bool controlPanel = true;
+ bool callStack = false;
+ bool vars = false;
+ bool channels = false;
+ bool cast = false;
+ bool funcList = false;
+ bool score = false;
+ bool bpList = false;
+ bool settings = false;
+ bool logger = false;
+ bool archive = false;
+ bool watchedVars = false;
+} ImGuiWindows;
+
+typedef struct ImGuiState {
+ struct {
+ Common::HashMap<Graphics::Surface *, ImGuiImage> _textures;
+ bool _listView = true;
+ int _thumbnailSize = 64;
+ ImGuiTextFilter _nameFilter;
+ int _typeFilter = 0x7FFF;
+ } _cast;
+ struct {
+ Common::Array<ImGuiScript> _scripts;
+ uint _current = 0;
+ ImGuiTextFilter _nameFilter;
+ bool _showByteCode = false;
+ bool _showScript = false;
+ } _functions;
+ struct {
+ uint _lastLinePC = 0;
+ uint _callstackSize = 0;
+ bool _isScriptDirty = false; // indicates whether or not we have to display the script corresponding to the current stackframe
+ } _dbg;
+
+ struct {
+ ImVec4 _bp_color_disabled = ImVec4(0.9f, 0.08f, 0.0f, 0.0f);
+ ImVec4 _bp_color_enabled = ImVec4(0.9f, 0.08f, 0.0f, 1.0f);
+ ImVec4 _bp_color_hover = ImVec4(0.42f, 0.17f, 0.13f, 1.0f);
+ ImVec4 _current_statement = ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0xFF));
+ ImVec4 _line_color = ImVec4(0.44f, 0.44f, 0.44f, 1.0f);
+ ImVec4 _call_color = ImColor(IM_COL32(0xFF, 0xC5, 0x5C, 0xFF));
+ ImVec4 _builtin_color = ImColor(IM_COL32(0x60, 0x7C, 0xFF, 0xFF));
+ ImVec4 _var_color = ImColor(IM_COL32(0x4B, 0xCD, 0x5E, 0xFF));
+ ImVec4 _literal_color = ImColor(IM_COL32(0xFF, 0x9F, 0xDA, 0x9E));
+ ImVec4 _comment_color = ImColor(IM_COL32(0xFF, 0xA5, 0x9D, 0x95));
+ ImVec4 _type_color = ImColor(IM_COL32(0x13, 0xC5, 0xF9, 0xFF));
+ ImVec4 _keyword_color = ImColor(IM_COL32(0xC1, 0xC1, 0xC1, 0xFF));
+ ImVec4 _the_color = ImColor(IM_COL32(0xFF, 0x49, 0xEF, 0xFF));
+ } _colors;
+
+ struct {
+ DatumHash _locals;
+ DatumHash _globals;
+ uint32 _lastTimeRefreshed = 0;
+ } _vars;
+
+ ImGuiWindows _w;
+ ImGuiWindows _savedW;
+ bool _wasHidden = false;
+
+ Common::List<CastMemberID> _scriptCasts;
+ Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
+ int _prevFrame = -1;
+ struct {
+ int frame = -1;
+ int channel = -1;
+ } _selectedScoreCast;
+
+ int _scoreMode = 0;
+ int _scoreFrameOffset = 1;
+
+ ImFont *_tinyFont = nullptr;
+
+ struct {
+ Common::Path path;
+ uint32 resType = 0;
+ uint32 resId = 0;
+
+ byte *data = nullptr;
+ uint32 dataSize = 0;
+
+ MemoryEditor memEdit;
+ } _archive;
+
+ ImGuiLogger *_logger = nullptr;
+} ImGuiState;
+
+
class ImGuiLogger {
char _inputBuf[256];
ImVector<char *> _items;
diff --git a/engines/director/debugger/dt-logger.cpp b/engines/director/debugger/dt-logger.cpp
index bce26d25243..cbb4339c881 100644
--- a/engines/director/debugger/dt-logger.cpp
+++ b/engines/director/debugger/dt-logger.cpp
@@ -22,6 +22,7 @@
#include "common/debug.h"
#include "common/debug-channels.h"
+#include "director/director.h"
#include "director/debugger/dt-internal.h"
namespace Director {
Commit: 59ce105429b82c34dc703de43bde245b50737abd
https://github.com/scummvm/scummvm/commit/59ce105429b82c34dc703de43bde245b50737abd
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:00+02:00
Commit Message:
DIRECTOR: DT: Split out script code highlighters into separate files
Changed paths:
A engines/director/debugger/dt-script-d2.cpp
A engines/director/debugger/dt-script-d4.cpp
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-internal.h
engines/director/debugger/dt-logger.cpp
engines/director/module.mk
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 3741ee100c6..86b53e4feb2 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -19,25 +19,14 @@
*
*/
-#include "common/config-manager.h"
-#include "common/system.h"
#include "graphics/opengl/shader.h"
-#include "image/png.h"
#include "director/director.h"
#include "director/lingo/lingo.h"
-#include "director/lingo/lingo-ast.h"
-#include "director/lingo/lingo-code.h"
-#include "director/lingo/lingo-object.h"
-#include "director/lingo/lingo-the.h"
-#include "director/lingo/lingodec/codewritervisitor.h"
#include "director/lingo/lingodec/context.h"
-#include "director/lingo/lingodec/names.h"
-#include "director/lingo/lingodec/resolver.h"
#include "director/lingo/lingodec/script.h"
#include "director/cast.h"
#include "director/castmember/bitmap.h"
-#include "director/castmember/castmember.h"
#include "director/castmember/text.h"
#include "director/castmember/script.h"
#include "director/channel.h"
@@ -46,9 +35,6 @@
#include "director/movie.h"
#include "director/picture.h"
#include "director/score.h"
-#include "director/sprite.h"
-#include "director/types.h"
-#include "director/window.h"
#include "director/debugger/debugtools.h"
#include "director/debugger/dt-internal.h"
@@ -57,2077 +43,99 @@ namespace Director {
namespace DT {
+ImGuiState *_state = nullptr;
-bool toggleButton(const char *label, bool *p_value, bool inverse) {
- int pop = 0;
- if (*p_value != inverse) {
- ImVec4 hovered = ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered];
- ImGui::PushStyleColor(ImGuiCol_Button, hovered);
- pop = 1;
- }
- bool result = ImGui::Button(label);
- if (result) {
- *p_value = !*p_value;
- }
- ImGui::PopStyleColor(pop);
- return result;
-}
-
-ImGuiState *_state = nullptr;
-
-const LingoDec::Handler *getHandler(const Cast *cast, CastMemberID id, const Common::String &handlerId) {
- if (!cast)
- return nullptr;
- const ScriptContext *ctx = cast->_lingoArchive->findScriptContext(id.member);
- if (!ctx || !ctx->_functionHandlers.contains(handlerId))
- return nullptr;
- // for the moment it's happening with Director version < 4
- if (!cast->_lingodec)
- return nullptr;
- for (auto p : cast->_lingodec->scripts) {
- if ((p.second->castID & 0xFFFF) != id.member)
- continue;
- ;
- for (const LingoDec::Handler &handler : p.second->handlers) {
- if (handler.name == handlerId) {
- return &handler;
- }
- }
- }
- return nullptr;
-}
-
-const LingoDec::Handler *getHandler(CastMemberID id, const Common::String &handlerId) {
- const Director::Movie *movie = g_director->getCurrentMovie();
- for (const auto it : *movie->getCasts()) {
- const Cast *cast = it._value;
- const LingoDec::Handler *handler = getHandler(cast, id, handlerId);
- if (handler)
- return handler;
- }
- return getHandler(movie->getSharedCast(), id, handlerId);
-}
-
-static ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId) {
- ImGuiScript result;
- result.id = id;
- result.handlerId = handlerId;
- result.type = scriptType;
-
- const LingoDec::Handler *handler = getHandler(id, handlerId);
- if (!handler) {
- const ScriptContext *ctx;
- if (id.castLib == SHARED_CAST_LIB) {
- ctx = g_director->getCurrentMovie()->getSharedCast()->_lingoArchive->getScriptContext(scriptType, id.member);
- } else {
- ctx = g_director->getCurrentMovie()->getScriptContext(scriptType, id);
- }
- if (!ctx) return result;
- result.oldAst = ctx->_assemblyAST;
- return result;
- }
-
- result.bytecodeArray = handler->bytecodeArray;
- result.root = handler->ast.root;
- result.isGenericEvent = handler->isGenericEvent;
- result.argumentNames = handler->argumentNames;
- result.propertyNames = handler->script->propertyNames;
- result.globalNames = handler->globalNames;
-
- LingoDec::Script *script = handler->script;
- if (!script)
- return result;
-
- result.isMethod = script->isFactory();
- return result;
-}
-
-static void setScriptToDisplay(const ImGuiScript &script);
-
-static Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 scriptId, uint pc) {
- auto &bps = g_lingo->getBreakpoints();
- for (uint i = 0; i < bps.size(); i++) {
- if (bps[i].type == kBreakpointFunction && bps[i].scriptId == scriptId && bps[i].funcName == handlerName && bps[i].funcOffset == pc) {
- return &bps[i];
- }
- }
- return nullptr;
-}
-
-class RenderOldScriptVisitor : public NodeVisitor {
-private:
- ImGuiScript &_script;
- int _indent = 0;
- bool _isScriptInDebug = false;
- bool _currentStatementDisplayed = false;
-
-public:
- explicit RenderOldScriptVisitor(ImGuiScript &script) : _script(script) {
- Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
- if (!callstack.empty()) {
- CFrame *head = callstack[callstack.size() - 1];
- _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
- }
- _script.startOffsets.clear();
- }
-
- virtual bool visitHandlerNode(HandlerNode *node) {
- ImGui::Text("on ");
- ImGui::SameLine();
- ImGui::TextColored(_state->_colors._call_color, "%s", node->name->c_str());
- if (!node->args->empty()) {
- ImGui::SameLine();
- ImGui::Text(" ");
- ImGui::SameLine();
- for (uint i = 0; i < node->args->size(); i++) {
- Common::String *arg = (*node->args)[i];
- ImGui::Text("%s", arg->c_str());
- ImGui::SameLine();
- if (i != (node->args->size() - 1)) {
- ImGui::Text(", ");
- ImGui::SameLine();
- }
- }
- ImGui::NewLine();
- }
- indent();
- for (uint i = 0; i < node->stmts->size(); i++) {
- Node *stmt = (*node->stmts)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- }
- unindent();
- renderLine(node->endOffset);
- ImGui::TextColored(_state->_colors._keyword_color, "end");
- return true;
- }
-
- virtual bool visitScriptNode(ScriptNode *node) {
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
- for (Node *child : *node->children) {
- if (child->type == kHandlerNode && *((HandlerNode *)child)->name != _script.handlerId)
- continue;
- renderLine(child->startOffset);
- child->accept(this);
- }
- ImGui::PopStyleVar();
- return true;
- }
-
- virtual bool visitFactoryNode(FactoryNode *node) {
- ImGui::Text("factory %s", node->name->c_str());
- ImGui::NewLine();
- indent();
- for (uint i = 0; i < node->methods->size(); i++) {
- Node *method = (*node->methods)[i];
- renderLine(method->startOffset);
- method->accept(this);
- ImGui::NewLine();
- }
- unindent();
- return true;
- }
-
- virtual bool visitCmdNode(CmdNode *node) {
- ImGui::Text("%s ", node->name->c_str());
- ImGui::SameLine();
- if (*node->name == "go") {
- ImGui::TextColored(_state->_colors._keyword_color, "to ");
- ImGui::SameLine();
- }
- for (uint i = 0; i < node->args->size(); i++) {
- Node *arg = (*node->args)[i];
- if ((i != 0) || (node->args->size() < 2) || ((*node->args)[1]->type != kMovieNode)) {
- arg->accept(this);
- ImGui::SameLine();
- if (i != (node->args->size() - 1)) {
- ImGui::Text(", ");
- ImGui::SameLine();
- }
- }
- }
- return true;
- }
-
- virtual bool visitPutIntoNode(PutIntoNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "put ");
- ImGui::SameLine();
- node->val->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " into ");
- ImGui::SameLine();
- node->var->accept(this);
- return true;
- }
-
- virtual bool visitPutAfterNode(PutAfterNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "put ");
- ImGui::SameLine();
- node->val->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " after ");
- ImGui::SameLine();
- node->var->accept(this);
- return true;
- }
-
- virtual bool visitPutBeforeNode(PutBeforeNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "put ");
- ImGui::SameLine();
- node->val->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " before ");
- ImGui::SameLine();
- node->var->accept(this);
- return true;
- }
-
- virtual bool visitSetNode(SetNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "set ");
- ImGui::SameLine();
- node->val->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " to ");
- ImGui::SameLine();
- node->var->accept(this);
- return true;
- }
-
- void displayDefineVar(const char *name, IDList *names) {
- ImGui::Text("%s ", name);
- ImGui::SameLine();
- for (uint i = 0; i < names->size(); i++) {
- Common::String *arg = (*names)[i];
- ImGui::Text("%s", arg->c_str());
- ImGui::SameLine();
- if (i != (names->size() - 1)) {
- ImGui::Text(" ");
- ImGui::SameLine();
- }
- }
- }
-
- virtual bool visitGlobalNode(GlobalNode *node) {
- displayDefineVar("global", node->names);
- return true;
- }
-
- virtual bool visitPropertyNode(PropertyNode *node) {
- displayDefineVar("property", node->names);
- return true;
- }
-
- virtual bool visitInstanceNode(InstanceNode *node) {
- displayDefineVar("instance", node->names);
- return true;
- }
-
- virtual bool visitIfStmtNode(IfStmtNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "if ");
- ImGui::SameLine();
- node->cond->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " then ");
- if (node->stmts->size() == 1) {
- ImGui::SameLine();
- (*node->stmts)[0]->accept(this);
- } else {
- indent();
- for (uint i = 0; i < node->stmts->size(); i++) {
- Node *stmt = (*node->stmts)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- }
- unindent();
- renderLine(node->endOffset);
- ImGui::TextColored(_state->_colors._keyword_color, "endif");
- ImGui::SameLine();
- }
- return true;
- }
-
- virtual bool visitIfElseStmtNode(IfElseStmtNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "if ");
- ImGui::SameLine();
- node->cond->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " then ");
- if (node->stmts1->size() == 1) {
- ImGui::SameLine();
- (*node->stmts1)[0]->accept(this);
- ImGui::Text(" ");
- ImGui::SameLine();
- } else {
- uint offset = node->cond->endOffset;
- indent();
- for (uint i = 0; i < node->stmts1->size(); i++) {
- Node *stmt = (*node->stmts1)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- offset = stmt->endOffset;
- }
- unindent();
- renderLine(offset);
- }
- ImGui::TextColored(_state->_colors._keyword_color, "else ");
- if (node->stmts2->size() == 1) {
- ImGui::SameLine();
- (*node->stmts2)[0]->accept(this);
- } else {
- uint offset = node->cond->endOffset;
- indent();
- for (uint i = 0; i < node->stmts2->size(); i++) {
- Node *stmt = (*node->stmts2)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- offset = stmt->endOffset;
- }
- unindent();
- renderLine(offset);
- ImGui::TextColored(_state->_colors._keyword_color, "endif");
- ImGui::SameLine();
- }
- return true;
- }
-
- virtual bool visitRepeatWhileNode(RepeatWhileNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "repeat while ");
- ImGui::SameLine();
- node->cond->accept(this);
- ImGui::NewLine();
- indent();
- uint offset = node->cond->endOffset;
- for (uint i = 0; i < node->stmts->size(); i++) {
- Node *stmt = (*node->stmts)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- offset = stmt->endOffset;
- }
- unindent();
- renderLine(offset);
- ImGui::TextColored(_state->_colors._keyword_color, "endrepeat");
- return true;
- }
-
- virtual bool visitRepeatWithToNode(RepeatWithToNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "repeat with ");
- ImGui::SameLine();
- ImGui::Text("%s = ", node->var->c_str());
- ImGui::SameLine();
- node->start->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, " %s ", node->down ? "down to" : "to");
- node->end->accept(this);
- ImGui::NewLine();
- indent();
- for (uint i = 0; i < node->stmts->size(); i++) {
- Node *stmt = (*node->stmts)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- }
- unindent();
- renderLine(node->endOffset);
- ImGui::TextColored(_state->_colors._keyword_color, "endrepeat");
- return true;
- }
-
- virtual bool visitRepeatWithInNode(RepeatWithInNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "repeat with ");
- ImGui::SameLine();
- ImGui::Text("%s in ", node->var->c_str());
- ImGui::SameLine();
- node->list->accept(this);
- ImGui::NewLine();
- indent();
- for (uint i = 0; i < node->stmts->size(); i++) {
- Node *stmt = (*node->stmts)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- }
- unindent();
- renderLine(node->endOffset);
- ImGui::TextColored(_state->_colors._keyword_color, "endrepeat");
- return true;
- }
-
- virtual bool visitNextRepeatNode(NextRepeatNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "next repeat");
- return true;
- }
-
- virtual bool visitExitRepeatNode(ExitRepeatNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "exit repeat");
- return true;
- }
-
- virtual bool visitExitNode(ExitNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "exit");
- return true;
- }
-
- virtual bool visitReturnNode(ReturnNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "return");
- if (node->expr) {
- ImGui::Text(" ");
- ImGui::SameLine();
- node->expr->accept(this);
- ImGui::NewLine();
- }
- return true;
- }
-
- virtual bool visitTellNode(TellNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "tell ");
- node->target->accept(this);
- if (node->stmts->size() == 1) {
- ImGui::SameLine();
- ImGui::TextColored(_state->_colors._keyword_color, " to ");
- ImGui::SameLine();
- (*node->stmts)[0]->accept(this);
- } else {
- indent();
- for (uint i = 0; i < node->stmts->size(); i++) {
- Node *stmt = (*node->stmts)[i];
- renderLine(stmt->startOffset);
- stmt->accept(this);
- ImGui::NewLine();
- }
- unindent();
- renderLine(node->endOffset);
- ImGui::TextColored(_state->_colors._keyword_color, "endtell");
- }
- return true;
- }
-
- virtual bool visitWhenNode(WhenNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "when ");
- ImGui::SameLine();
- ImGui::Text("%s", node->event->c_str());
- ImGui::SameLine();
- ImGui::TextColored(_state->_colors._keyword_color, " then ");
- ImGui::SameLine();
- ImGui::Text("%s", node->code->c_str());
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitDeleteNode(DeleteNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "delete ");
- ImGui::SameLine();
- node->chunk->accept(this);
- return true;
- }
-
- virtual bool visitHiliteNode(HiliteNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "hilite ");
- ImGui::SameLine();
- node->chunk->accept(this);
- return true;
- }
-
- virtual bool visitAssertErrorNode(AssertErrorNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "scummvmAssertError ");
- ImGui::SameLine();
- node->stmt->accept(this);
- return true;
- }
-
- virtual bool visitIntNode(IntNode *node) {
- ImGui::TextColored(_state->_colors._literal_color, "%d", node->val);
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitFloatNode(FloatNode *node) {
- ImGui::TextColored(_state->_colors._literal_color, "%g", node->val);
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitSymbolNode(SymbolNode *node) {
- ImGui::TextColored(_state->_colors._literal_color, "%s", node->val->c_str());
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitStringNode(StringNode *node) {
- ImGui::TextColored(_state->_colors._literal_color, "\"%s\"", node->val->c_str());
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitListNode(ListNode *node) {
- ImGui::Text("[");
- ImGui::SameLine();
- for (uint i = 0; i < node->items->size(); i++) {
- Node *prop = (*node->items)[i];
- prop->accept(this);
- if (i != (node->items->size() - 1)) {
- ImGui::Text(",");
- ImGui::SameLine();
- }
- }
- ImGui::Text("]");
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitPropListNode(PropListNode *node) {
- ImGui::Text("[");
- ImGui::SameLine();
- if (node->items->empty()) {
- ImGui::Text(":");
- ImGui::SameLine();
- } else {
- for (uint i = 0; i < node->items->size(); i++) {
- Node *prop = (*node->items)[i];
- prop->accept(this);
- if (i != (node->items->size() - 1)) {
- ImGui::Text(",");
- ImGui::SameLine();
- }
- }
- }
- ImGui::Text("]");
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitPropPairNode(PropPairNode *node) {
- node->key->accept(this);
- ImGui::Text(":");
- ImGui::SameLine();
- node->val->accept(this);
- return true;
- }
-
- virtual bool visitFuncNode(FuncNode *node) {
- const bool isBuiltin = g_lingo->_builtinCmds.contains(*node->name);
- const ImVec4 color = (ImVec4)ImColor(isBuiltin ? _state->_colors._builtin_color : _state->_colors._call_color);
- ImGui::TextColored(color, "%s(", node->name->c_str());
- if (!isBuiltin && ImGui::IsItemHovered() && ImGui::BeginTooltip()) {
- ImGui::Text("Go to definition");
- ImGui::EndTooltip();
- }
- if (!isBuiltin && ImGui::IsItemClicked()) {
- int obj = 0;
- for (uint i = 0; i < _script.bytecodeArray.size(); i++) {
- if (node->startOffset == _script.bytecodeArray[i].pos) {
- obj = _script.bytecodeArray[i].obj;
- break;
- }
- }
-
- ImGuiScript script = toImGuiScript(_script.type, CastMemberID(obj, _script.id.castLib), *node->name);
- script.moviePath = _script.moviePath;
- script.handlerName = *node->name;
- setScriptToDisplay(script);
- }
- ImGui::SameLine();
- for (uint i = 0; i < node->args->size(); i++) {
- Node *arg = (*node->args)[i];
- arg->accept(this);
- if (i != (node->args->size() - 1)) {
- ImGui::Text(",");
- ImGui::SameLine();
- }
- }
- ImGui::Text(")");
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitVarNode(VarNode *node) {
- ImGui::TextColored(_state->_colors._var_color, "%s", node->name->c_str());
- if (ImGui::IsItemHovered() && g_lingo->_globalvars.contains(*node->name)) {
- const Datum &val = g_lingo->_globalvars.getVal(*node->name);
- ImGui::BeginTooltip();
- ImGui::Text("Click to add to watches.");
- ImGui::Text("= %s", val.asString(true).c_str());
- ImGui::EndTooltip();
- }
- if (ImGui::IsItemClicked()) {
- _state->_variables[*node->name] = true;
- }
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitParensNode(ParensNode *node) {
- ImGui::Text("(");
- ImGui::SameLine();
- node->expr->accept(this);
- ImGui::Text(")");
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitUnaryOpNode(UnaryOpNode *node) {
- char op = '?';
- if (node->op == LC::c_negate) {
- op = '-';
- } else if (node->op == LC::c_not) {
- op = '!';
- }
- ImGui::Text("%c", op);
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitBinaryOpNode(BinaryOpNode *node) {
- node->a->accept(this);
- static struct {
- inst op;
- const char *name;
- } ops[] = {
- {LC::c_add, "+"},
- {LC::c_sub, "-"},
- {LC::c_mul, "*"},
- {LC::c_div, "/"},
- {LC::c_mod, "mod"},
- {LC::c_gt, ">"},
- {LC::c_lt, "<"},
- {LC::c_eq, "="},
- {LC::c_neq, "<>"},
- {LC::c_ge, ">="},
- {LC::c_le, "<="},
- {LC::c_and, "and"},
- {LC::c_or, "or"},
- {LC::c_ampersand, "&"},
- {LC::c_concat, "&&"},
- {LC::c_contains, "contains"},
- {LC::c_starts, "starts"},
- };
- for (auto &op : ops) {
- if (op.op == node->op) {
- ImGui::Text(" %s ", op.name);
- ImGui::SameLine();
- break;
- }
- }
- node->b->accept(this);
- return true;
- }
-
- virtual bool visitFrameNode(FrameNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "frame ");
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitMovieNode(MovieNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "movie ");
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitIntersectsNode(IntersectsNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "sprite ");
- ImGui::SameLine();
- node->sprite1->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, "intersects ");
- node->sprite2->accept(this);
- return true;
- }
-
- virtual bool visitWithinNode(WithinNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "sprite ");
- ImGui::SameLine();
- node->sprite1->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, "within ");
- node->sprite2->accept(this);
- return true;
- }
-
- virtual bool visitTheNode(TheNode *node) {
- ImGui::TextColored(_state->_colors._the_color, "the %s", node->prop->c_str());
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitTheOfNode(TheOfNode *node) {
- ImGui::TextColored(_state->_colors._the_color, "the %s of ", node->prop->c_str());
- ImGui::SameLine();
- node->obj->accept(this);
- return true;
- }
-
- virtual bool visitTheNumberOfNode(TheNumberOfNode *node) {
- ImGui::TextColored(_state->_colors._the_color, "the number of ");
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitTheLastNode(TheLastNode *node) {
- // TODO: change the node to know if it's 'in' or 'of'
- ImGui::TextColored(_state->_colors._the_color, "the last %s in/of ", toString(node->type).c_str());
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitTheDateTimeNode(TheDateTimeNode *node) {
- const char *key1 = "";
- switch (node->field) {
- case kTheAbbr:
- key1 = "abbreviated";
- break;
- case kTheLong:
- key1 = "long";
- break;
- case kTheShort:
- key1 = "short";
- break;
- }
- const char *key2 = node->entity == kTheDate ? "date" : "time";
- ImGui::TextColored(_state->_colors._the_color, "the %s %s", key1, key2);
- ImGui::SameLine();
- return true;
- }
-
- virtual bool visitMenuNode(MenuNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "menu ");
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitMenuItemNode(MenuItemNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "menuitem ");
- ImGui::SameLine();
- node->arg1->accept(this);
- ImGui::TextColored(_state->_colors._keyword_color, "of menu ");
- ImGui::SameLine();
- node->arg2->accept(this);
- return true;
- }
-
- virtual bool visitSoundNode(SoundNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "sound ");
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitSpriteNode(SpriteNode *node) {
- ImGui::TextColored(_state->_colors._keyword_color, "sprite ");
- ImGui::SameLine();
- node->arg->accept(this);
- return true;
- }
-
- virtual bool visitChunkExprNode(ChunkExprNode *node) {
- const char *key1 = "";
- switch (node->type) {
- case kChunkChar:
- key1 = "char";
- break;
- case kChunkWord:
- key1 = "word";
- break;
- case kChunkItem:
- key1 = "item";
- break;
- case kChunkLine:
- key1 = "line";
- break;
- }
- ImGui::Text("%s", key1);
- ImGui::SameLine();
- node->start->accept(this);
- if (node->end) {
- ImGui::TextColored(_state->_colors._keyword_color, " to ");
- ImGui::SameLine();
- node->end->accept(this);
- }
- ImGui::TextColored(_state->_colors._keyword_color, " of ");
- ImGui::SameLine();
- node->src->accept(this);
- return true;
- }
-
-private:
- static Common::String toString(ChunkType chunkType) {
- // TODO: this method could be used in ChunkExprNode
- switch (chunkType) {
- case kChunkChar:
- return "char";
- case kChunkWord:
- return "word";
- case kChunkItem:
- return "item";
- case kChunkLine:
- return "line";
- }
- return "<unknown>";
- }
-
- void indent() {
- _indent++;
- }
-
- void unindent() {
- if (_indent > 0)
- _indent--;
- }
-
- void renderIndentation() const {
- for (int i = 0; i < _indent; i++) {
- ImGui::Text(" ");
- ImGui::SameLine();
- }
- }
-
- void renderLine(uint32 pc) {
- bool showCurrentStatement = false;
- _script.startOffsets.push_back(pc);
-
- if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
- // check current statement
- if (!_currentStatementDisplayed) {
- if (g_lingo->_state->pc <= pc) {
- showCurrentStatement = true;
- _currentStatementDisplayed = true;
- }
- }
- }
-
- ImDrawList *dl = ImGui::GetWindowDrawList();
- const ImVec2 pos = ImGui::GetCursorScreenPos();
- const float width = ImGui::GetContentRegionAvail().x;
- const ImVec2 mid(pos.x + 7, pos.y + 7);
-
- ImVec4 color = _state->_colors._bp_color_disabled;
- const Director::Breakpoint *bp = getBreakpoint(_script.handlerId, _script.id.member, pc);
- if (bp)
- color = _state->_colors._bp_color_enabled;
-
- ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
-
- // click on breakpoint column?
- if (ImGui::IsItemClicked(0)) {
- if (color == _state->_colors._bp_color_enabled) {
- g_lingo->delBreakpoint(bp->id);
- color = _state->_colors._bp_color_disabled;
- } else {
- Director::Breakpoint newBp;
- newBp.type = kBreakpointFunction;
- newBp.scriptId = _script.id.member;
- newBp.funcName = _script.handlerId;
- newBp.funcOffset = pc;
- g_lingo->addBreakpoint(newBp);
- color = _state->_colors._bp_color_enabled;
- }
- }
-
- if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) {
- color = _state->_colors._bp_color_hover;
- }
-
- // draw breakpoint
- if (!bp || bp->enabled)
- dl->AddCircleFilled(mid, 4.0f, ImColor(color));
- else
- dl->AddCircle(mid, 4.0f, ImColor(_state->_colors._line_color));
-
- // draw current statement
- if (showCurrentStatement) {
- dl->AddQuadFilled(ImVec2(pos.x, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 10.f), ImVec2(pos.x, pos.y + 10.f), ImColor(_state->_colors._current_statement));
- dl->AddTriangleFilled(ImVec2(pos.x + 8.f, pos.y), ImVec2(pos.x + 14.f, pos.y + 7.f), ImVec2(pos.x + 8.f, pos.y + 14.f), ImColor(_state->_colors._current_statement));
- if (_state->_dbg._isScriptDirty && !ImGui::IsItemVisible()) {
- ImGui::SetScrollHereY(0.5f);
- }
- dl->AddRectFilled(ImVec2(pos.x + 16.f, pos.y), ImVec2(pos.x + width, pos.y + 16.f), ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0x20)), 0.4f);
- }
- // draw separator
- dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color));
-
- ImGui::SetItemTooltip("Click to add a breakpoint");
- ImGui::SameLine();
-
- // draw offset
- ImGui::Text("[%5d] ", pc == 0xFFFFFFFF ? -1 : pc);
- ImGui::SameLine();
- renderIndentation();
- }
-};
-
-class RenderScriptVisitor : public LingoDec::NodeVisitor {
-public:
- RenderScriptVisitor(ImGuiScript &script, bool showByteCode) : _script(script), _showByteCode(showByteCode) {
- Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
- if (!callstack.empty()) {
- CFrame *head = callstack[callstack.size() - 1];
- _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
- }
- _script.startOffsets.clear();
- }
-
- virtual void visit(const LingoDec::HandlerNode &node) override {
- if (_showByteCode) {
- byteCode(node);
- return;
- }
-
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
- lingoCode(node);
- ImGui::PopStyleVar();
- }
-
- virtual void visit(const LingoDec::CommentNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._comment_color), "-- %s", node.text.c_str());
- ImGui::SameLine();
- }
-
- virtual void visit(const LingoDec::LiteralNode &node) override {
- write(*node.value);
- }
-
- virtual void visit(const LingoDec::NewObjNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), "new");
- ImGui::SameLine();
- ImGui::TextColored(ImColor(_state->_colors._type_color), "%s", node.objType.c_str());
- ImGui::SameLine();
- ImGui::Text(" (");
- ImGui::SameLine();
- node.objArgs->accept(*this);
- ImGui::Text(")");
- 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 (uint i = 0; i < _script.bytecodeArray.size(); i++) {
- if (node._startOffset == _script.bytecodeArray[i].pos) {
- obj = _script.bytecodeArray[i].obj;
- break;
- }
- }
-
- // 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) ? _state->_colors._builtin_color : _state->_colors._call_color);
- ImGui::TextColored(color, "%s", node.name.c_str());
- // TODO: we should test Director::builtins too (but inaccessible)
- 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 = toImGuiScript(_script.type, CastMemberID(obj, _script.id.castLib), node.name);
- script.moviePath = _script.moviePath;
- script.handlerName = node.name;
- setScriptToDisplay(script);
- }
- ImGui::SameLine();
-
- if (node.noParens()) {
- ImGui::Text(" ");
- ImGui::SameLine();
- node.argList->accept(*this);
- } else {
- ImGui::Text("(");
- ImGui::SameLine();
- node.argList->accept(*this);
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- if (node.isStatement) {
- ImGui::NewLine();
- }
- }
-
- virtual void visit(const LingoDec::BlockNode &node) override {
- indent();
- for (const auto &child : node.children) {
- child->accept(*this);
- }
- unindent();
- }
-
- virtual void visit(const LingoDec::PutStmtNode &node) override {
- write(node._startOffset, "put ", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.value->accept(*this);
- ImGui::Text(" ");
- ImGui::SameLine();
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), LingoDec::StandardNames::putTypeNames[node.type]);
- ImGui::SameLine();
- ImGui::Text(" ");
- ImGui::SameLine();
- node.variable->accept(*this);
- ImGui::NewLine();
- }
-
- virtual void visit(const LingoDec::TheExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s", node.prop.c_str());
- ImGui::SameLine();
- }
-
- virtual void visit(const LingoDec::ExitStmtNode &node) override {
- write(node._startOffset, "exit", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::WhenStmtNode &node) override {
- write(node._startOffset, "when ", _state->_colors._keyword_color);
- ImGui::SameLine();
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), LingoDec::StandardNames::whenEventNames[node.event]);
- ImGui::SameLine();
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " then ");
- ImGui::SameLine();
- ImGui::Text("%s", node.script.c_str());
- }
-
- virtual void visit(const LingoDec::RepeatWhileStmtNode &node) override {
- write(node._startOffset, "repeat while ", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.condition->accept(*this);
- ImGui::NewLine();
- node.block->accept(*this);
- write(node._endOffset, "end repeat", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::RepeatWithInStmtNode &node) override {
- write(node._startOffset, "repeat with ", _state->_colors._keyword_color);
- ImGui::SameLine();
- renderVar(node.varName);
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " in ");
- ImGui::SameLine();
- node.list->accept(*this);
- ImGui::NewLine();
- node.block->accept(*this);
- write(node._endOffset, "end repeat", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::RepeatWithToStmtNode &node) override {
- write(node._startOffset, "repeat with ", _state->_colors._keyword_color);
- ImGui::SameLine();
- renderVar(node.varName);
- ImGui::Text(" = ");
- ImGui::SameLine();
- node.start->accept(*this);
- if (node.up) {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " to ");
- ImGui::SameLine();
- } else {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " down to ");
- ImGui::SameLine();
- }
- node.end->accept(*this);
- ImGui::NewLine();
- node.block->accept(*this);
- write(node._endOffset, "end repeat", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::IfStmtNode &node) override {
- {
- write(node._startOffset, "if ", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.condition->accept(*this);
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " then ");
- }
- node.block1->accept(*this);
- if (node.hasElse) {
- write(node.block2->_startOffset, "else ", _state->_colors._keyword_color);
- node.block2->accept(*this);
- }
- write(node._endOffset, "end if", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::TellStmtNode &node) override {
- write(node._startOffset, "tell ", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.window->accept(*this);
- ImGui::NewLine();
- node.block->accept(*this);
- write(node._endOffset, "end tell", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::EndCaseNode &node) override {
- write(node._endOffset, "end case", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::CaseLabelNode &node) override {
- renderLine(node._startOffset);
- renderIndentation();
- bool parenValue = node.value->hasSpaces(_dot);
- if (parenValue) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.value->accept(*this);
- if (parenValue) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- if (node.nextOr) {
- ImGui::Text(",");
- ImGui::SameLine();
- node.nextOr->accept(*this);
- } else {
- ImGui::Text(":");
- node.block->accept(*this);
- }
- if (node.nextLabel) {
- node.nextLabel->accept(*this);
- }
- }
-
- virtual void visit(const LingoDec::ChunkExprNode &node) override {
- ImGui::Text(LingoDec::StandardNames::chunkTypeNames[node.type]);
- ImGui::SameLine();
- ImGui::Text(" ");
- ImGui::SameLine();
- node.first->accept(*this);
- if (!(node.last->type == LingoDec::kLiteralNode && node.last->getValue()->type == LingoDec::kDatumInt && node.last->getValue()->i == 0)) {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " to ");
- ImGui::SameLine();
- node.last->accept(*this);
- }
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
- ImGui::SameLine();
- node.string->accept(*this);
- }
-
- virtual void visit(const LingoDec::InverseOpNode &node) override {
- ImGui::Text("-");
- ImGui::SameLine();
-
- bool parenOperand = node.operand->hasSpaces(_dot);
- if (parenOperand) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.operand->accept(*this);
- if (parenOperand) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::CaseStmtNode &node) override {
- write(node._startOffset, "case ", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.value->accept(*this);
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
- indent();
- if (node.firstLabel) {
- node.firstLabel->accept(*this);
- }
- if (node.otherwise) {
- node.otherwise->accept(*this);
- }
- unindent();
- write(node._endOffset, "end case", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::ObjCallNode &node) override {
- auto &rawArgs = node.argList->getValue()->l;
-
- auto &obj = rawArgs[0];
- bool parenObj = obj->hasSpaces(_dot);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::Text(".");
- ImGui::SameLine();
- ImGui::Text(node.name.c_str());
- ImGui::SameLine();
- ImGui::Text("(");
- ImGui::SameLine();
- for (size_t i = 1; i < rawArgs.size(); i++) {
- if (i > 1) {
- ImGui::Text(",");
- ImGui::SameLine();
- }
- rawArgs[i]->accept(*this);
- }
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- virtual void visit(const LingoDec::ObjPropExprNode &node) override {
- if (_dot) {
- bool parenObj = node.obj->hasSpaces(_dot);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::Text(".");
- ImGui::SameLine();
- ImGui::Text("%s", node.prop.c_str());
- ImGui::SameLine();
- } else {
- ImGui::TextColored(_state->_colors._the_color, "the %s", node.prop.c_str());
- ImGui::SameLine();
- ImGui::TextColored(_state->_colors._keyword_color, " of ");
- ImGui::SameLine();
-
- bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
- }
-
- virtual void visit(const LingoDec::BinaryOpNode &node) override {
- unsigned int precedence = node.getPrecedence();
- bool parenLeft = false;
- bool parenRight = false;
- if (precedence) {
- if (node.left->type == LingoDec::kBinaryOpNode) {
- auto leftBinaryOpNode = static_cast<LingoDec::BinaryOpNode *>(node.left.get());
- parenLeft = (leftBinaryOpNode->getPrecedence() != precedence);
- }
- parenRight = (node.right->type == LingoDec::kBinaryOpNode);
- }
-
- if (parenLeft) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.left->accept(*this);
- if (parenLeft) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::Text(" ");
- ImGui::SameLine();
- ImGui::Text(LingoDec::StandardNames::binaryOpNames[node.opcode]);
- ImGui::SameLine();
- ImGui::Text(" ");
- ImGui::SameLine();
-
- if (parenRight) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.right->accept(*this);
- if (parenRight) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::OtherwiseNode &node) override {
- write(node._startOffset, "otherwise:", _state->_colors._keyword_color);
- node.block->accept(*this);
- }
-
- virtual void visit(const LingoDec::MemberExprNode &node) override {
- bool hasCastID = node.castID && !(node.castID->type == LingoDec::kLiteralNode && node.castID->getValue()->type == LingoDec::kDatumInt && node.castID->getValue()->i == 0);
- ImGui::Text(node.type.c_str());
- ImGui::SameLine();
- ImGui::Text(" ");
- ImGui::SameLine();
- if (_dot) {
- ImGui::Text("(");
- ImGui::SameLine();
- node.memberID->accept(*this);
- if (hasCastID) {
- ImGui::Text(",");
- ImGui::SameLine();
- node.castID->accept(*this);
- }
- ImGui::Text(")");
- ImGui::SameLine();
- } else {
- bool parenMemberID = (node.memberID->type == LingoDec::kBinaryOpNode);
- if (parenMemberID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.memberID->accept(*this);
- if (parenMemberID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- if (hasCastID) {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), "of castLib");
- ImGui::SameLine();
-
- bool parenCastID = (node.castID->type == LingoDec::kBinaryOpNode);
- if (parenCastID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.castID->accept(*this);
- if (parenCastID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
- }
- }
-
- virtual void visit(const LingoDec::PlayCmdStmtNode &node) override {
- auto &rawArgs = node.argList->getValue()->l;
-
- write(node._startOffset, "play ", _state->_colors._keyword_color);
- ImGui::SameLine();
-
- if (rawArgs.size() == 0) {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " done");
- ImGui::SameLine();
- return;
- }
-
- auto &frame = rawArgs[0];
- if (rawArgs.size() == 1) {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " frame ");
- ImGui::SameLine();
- frame->accept(*this);
- return;
- }
-
- auto &movie = rawArgs[1];
- if (!(frame->type == LingoDec::kLiteralNode && frame->getValue()->type == LingoDec::kDatumInt && frame->getValue()->i == 1)) {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " frame ");
- ImGui::SameLine();
- frame->accept(*this);
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
- ImGui::SameLine();
- }
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " movie ");
- ImGui::SameLine();
- movie->accept(*this);
- }
-
- virtual void visit(const LingoDec::ThePropExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), "the ");
- ImGui::SameLine();
- ImGui::Text(node.prop.c_str());
- ImGui::SameLine();
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
- ImGui::SameLine();
-
- bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::MenuPropExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of menu ", LingoDec::StandardNames::menuPropertyNames[node.prop]);
- ImGui::SameLine();
-
- bool parenMenuID = (node.menuID->type == LingoDec::kBinaryOpNode);
- if (parenMenuID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.menuID->accept(*this);
- if (parenMenuID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::SoundCmdStmtNode &node) override {
- write(node._startOffset, "sound ", _state->_colors._keyword_color);
- ImGui::SameLine();
- ImGui::Text(node.cmd.c_str());
- ImGui::SameLine();
- ImGui::Text(" ");
- ImGui::SameLine();
- if (node.argList->getValue()->l.size() > 0) {
- node.argList->accept(*this);
- }
- ImGui::NewLine();
- }
-
- virtual void visit(const LingoDec::SoundPropExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of sound ", LingoDec::StandardNames::soundPropertyNames[node.prop]);
- ImGui::SameLine();
-
- bool parenSoundID = (node.soundID->type == LingoDec::kBinaryOpNode);
- if (parenSoundID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.soundID->accept(*this);
- if (parenSoundID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::AssignmentStmtNode &node) override {
- if (!_dot) {
- write(node._startOffset, "set ", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.variable->accept(*this);
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " to ");
- ImGui::SameLine();
- node.value->accept(*this);
- } else {
- node.variable->accept(*this);
- ImGui::Text(" = ");
- ImGui::SameLine();
- node.value->accept(*this);
- }
- ImGui::NewLine();
- }
-
- virtual void visit(const LingoDec::ExitRepeatStmtNode &node) override {
- write(node._startOffset, "exit repeat", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::NextRepeatStmtNode &node) override {
- write(node._startOffset, "next repeat", _state->_colors._keyword_color);
- }
-
- virtual void visit(const LingoDec::ObjBracketExprNode &node) override {
- bool parenObj = node.obj->hasSpaces(_dot);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::Text("[");
- ImGui::SameLine();
- node.prop->accept(*this);
- ImGui::Text("]");
- ImGui::SameLine();
- }
-
- virtual void visit(const LingoDec::SpritePropExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of sprite ", LingoDec::StandardNames::spritePropertyNames[node.prop]);
- ImGui::SameLine();
-
- bool parenSpriteID = (node.spriteID->type == LingoDec::kBinaryOpNode);
- if (parenSpriteID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.spriteID->accept(*this);
- if (parenSpriteID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::ChunkDeleteStmtNode &node) override {
- write(node._startOffset, "delete", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.chunk->accept(*this);
- }
-
- virtual void visit(const LingoDec::ChunkHiliteStmtNode &node) override {
- write(node._startOffset, "hilite", _state->_colors._keyword_color);
- ImGui::SameLine();
- node.chunk->accept(*this);
- }
-
- virtual void visit(const LingoDec::MenuItemPropExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of menuItem ", LingoDec::StandardNames::menuItemPropertyNames[node.prop]);
- ImGui::SameLine();
-
- bool parenItemID = (node.itemID->type == LingoDec::kBinaryOpNode);
- if (parenItemID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.itemID->accept(*this);
- if (parenItemID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of menu ");
- ImGui::SameLine();
-
- bool parenMenuID = (node.menuID->type == LingoDec::kBinaryOpNode);
- if (parenMenuID) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.menuID->accept(*this);
- if (parenMenuID) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::ObjPropIndexExprNode &node) override {
- bool parenObj = node.obj->hasSpaces(_dot);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::Text(".");
- ImGui::SameLine();
- ImGui::Text(node.prop.c_str());
- ImGui::SameLine();
- ImGui::Text("[");
- ImGui::SameLine();
- node.index->accept(*this);
- if (node.index2) {
- ImGui::Text("..");
- ImGui::SameLine();
- node.index2->accept(*this);
- }
- ImGui::Text("]");
- ImGui::SameLine();
- }
-
- virtual void visit(const LingoDec::SpriteWithinExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), "sprite ");
- ImGui::SameLine();
-
- bool parenFirstSprite = (node.firstSprite->type == LingoDec::kBinaryOpNode);
- if (parenFirstSprite) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.firstSprite->accept(*this);
- if (parenFirstSprite) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " within ");
- ImGui::SameLine();
-
- bool parenSecondSprite = (node.secondSprite->type == LingoDec::kBinaryOpNode);
- if (parenSecondSprite) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.secondSprite->accept(*this);
- if (parenSecondSprite) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::LastStringChunkExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the last %s in ", LingoDec::StandardNames::chunkTypeNames[node.type]);
- ImGui::SameLine();
-
- bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::SpriteIntersectsExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), "sprite ");
- ImGui::SameLine();
-
- bool parenFirstSprite = (node.firstSprite->type == LingoDec::kBinaryOpNode);
- if (parenFirstSprite) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.firstSprite->accept(*this);
- if (parenFirstSprite) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
-
- ImGui::TextColored(ImColor(_state->_colors._keyword_color), " intersects ");
- ImGui::SameLine();
-
- bool parenSecondSprite = (node.secondSprite->type == LingoDec::kBinaryOpNode);
- if (parenSecondSprite) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.secondSprite->accept(*this);
- if (parenSecondSprite) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::StringChunkCountExprNode &node) override {
- ImGui::TextColored(ImColor(_state->_colors._the_color), "the number of %ss in ", LingoDec::StandardNames::chunkTypeNames[node.type]);
- ImGui::SameLine();
-
- bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
- if (parenObj) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.obj->accept(*this);
- if (parenObj) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void visit(const LingoDec::VarNode &node) override {
- renderVar(node.varName);
- }
-
- virtual void visit(const LingoDec::NotOpNode &node) override {
- ImGui::Text("not ");
- ImGui::SameLine();
-
- bool parenOperand = node.operand->hasSpaces(_dot);
- if (parenOperand) {
- ImGui::Text("(");
- ImGui::SameLine();
- }
- node.operand->accept(*this);
- if (parenOperand) {
- ImGui::Text(")");
- ImGui::SameLine();
- }
- }
-
- virtual void defaultVisit(const LingoDec::Node &node) override {
- LingoDec::CodeWriterVisitor code(_dot, false);
- node.accept(code);
- if (node.isStatement) {
- renderLine(node._startOffset);
- renderIndentation();
- }
- ImGui::Text("%s", code._str.c_str());
- }
-
-private:
- void write(LingoDec::Datum &datum) {
- switch (datum.type) {
- case LingoDec::kDatumVoid:
- ImGui::TextColored(_state->_colors._keyword_color, "VOID");
- ImGui::SameLine();
- return;
- case LingoDec::kDatumSymbol:
- ImGui::Text("#%s", datum.s.c_str());
- ImGui::SameLine();
- return;
- case LingoDec::kDatumVarRef:
- ImGui::TextColored(_state->_colors._var_color, datum.s.c_str());
- ImGui::SameLine();
- return;
- case LingoDec::kDatumString:
- if (datum.s.empty()) {
- ImGui::TextColored(_state->_colors._keyword_color, "EMPTY");
- ImGui::SameLine();
- return;
- }
- if (datum.s.size() == 1) {
- switch (datum.s[0]) {
- case '\x03':
- ImGui::TextColored(_state->_colors._keyword_color, "ENTER");
- ImGui::SameLine();
- return;
- case '\x08':
- ImGui::TextColored(_state->_colors._keyword_color, "BACKSPACE");
- ImGui::SameLine();
- return;
- case '\t':
- ImGui::TextColored(_state->_colors._keyword_color, "TAB");
- ImGui::SameLine();
- return;
- case '\r':
- ImGui::TextColored(_state->_colors._keyword_color, "RETURN");
- ImGui::SameLine();
- return;
- case '"':
- ImGui::TextColored(_state->_colors._keyword_color, "QUOTE");
- ImGui::SameLine();
- return;
- default:
- break;
- }
- }
- ImGui::Text("\"%s\"", datum.s.c_str());
- ImGui::SameLine();
- return;
- case LingoDec::kDatumInt:
- ImGui::TextColored(_state->_colors._literal_color, "%d", datum.i);
- ImGui::SameLine();
- return;
- case LingoDec::kDatumFloat:
- ImGui::TextColored(_state->_colors._literal_color, "%g", datum.f);
- ImGui::SameLine();
- return;
- case LingoDec::kDatumList:
- case LingoDec::kDatumArgList:
- case LingoDec::kDatumArgListNoRet: {
- if (datum.type == LingoDec::kDatumList) {
- ImGui::Text("[");
- ImGui::SameLine();
- }
- for (size_t ii = 0; ii < datum.l.size(); ii++) {
- if (ii > 0) {
- ImGui::Text(", ");
- ImGui::SameLine();
- }
- datum.l[ii]->accept(*this);
- }
- if (datum.type == LingoDec::kDatumList) {
- ImGui::Text("]");
- ImGui::SameLine();
- }
- }
- return;
- case LingoDec::kDatumPropList: {
- ImGui::Text("[");
- if (datum.l.size() == 0) {
- ImGui::Text(":");
- ImGui::SameLine();
- } else {
- for (size_t ii = 0; ii < datum.l.size(); ii += 2) {
- if (ii > 0) {
- ImGui::Text(", ");
- ImGui::SameLine();
- }
- datum.l[ii]->accept(*this);
- ImGui::Text(": ");
- ImGui::SameLine();
- datum.l[ii + 1]->accept(*this);
- }
- }
- ImGui::Text("]");
- ImGui::SameLine();
- }
- return;
- }
+bool toggleButton(const char *label, bool *p_value, bool inverse) {
+ int pop = 0;
+ if (*p_value != inverse) {
+ ImVec4 hovered = ImGui::GetStyle().Colors[ImGuiCol_ButtonHovered];
+ ImGui::PushStyleColor(ImGuiCol_Button, hovered);
+ pop = 1;
}
-
- void renderVar(const Common::String &varName) {
- ImGui::TextColored(_state->_colors._var_color, "%s", varName.c_str());
- if (ImGui::IsItemHovered() && g_lingo->_globalvars.contains(varName)) {
- const Datum &val = g_lingo->_globalvars.getVal(varName);
- ImGui::BeginTooltip();
- ImGui::Text("Click to add to watches.");
- ImGui::Text("= %s", val.asString(true).c_str());
- ImGui::EndTooltip();
- }
- if (ImGui::IsItemClicked()) {
- _state->_variables[varName] = true;
- }
- ImGui::SameLine();
+ bool result = ImGui::Button(label);
+ if (result) {
+ *p_value = !*p_value;
}
+ ImGui::PopStyleColor(pop);
+ return result;
+}
- void lingoCode(const LingoDec::HandlerNode &node) {
- if (_script.isGenericEvent) {
- node.block->accept(*this);
- return;
- }
-
- bool isMethod = _script.isMethod;
- write(node._startOffset, isMethod ? "method " : "on ", _state->_colors._keyword_color);
- ImGui::SameLine();
- ImGui::TextColored(_state->_colors._call_color, "%s", _script.handlerId.c_str());
- ImGui::SameLine();
-
- if (!_script.argumentNames.empty()) {
- ImGui::Text(" ");
- ImGui::SameLine();
- for (size_t i = 0; i < _script.argumentNames.size(); i++) {
- if (i > 0) {
- ImGui::Text(", ");
- ImGui::SameLine();
- }
- ImGui::Text("%s", _script.argumentNames[i].c_str());
- ImGui::SameLine();
- }
- }
- indent();
-
- if (isMethod && !_script.propertyNames.empty() && node.handler == &node.handler->script->handlers[0]) {
- ImGui::NewLine();
- write(node._startOffset, "instance ");
- ImGui::SameLine();
- for (size_t i = 0; i < _script.propertyNames.size(); i++) {
- if (i > 0)
- ImGui::Text(",");
- ImGui::SameLine();
- ImGui::TextColored(_state->_colors._var_color, "%s", _script.propertyNames[i].c_str());
- ImGui::SameLine();
- }
- }
-
- if (!_script.globalNames.empty()) {
- ImGui::NewLine();
- write(node._startOffset, "global ");
- ImGui::SameLine();
- for (size_t i = 0; i < _script.globalNames.size(); i++) {
- if (i > 0) {
- ImGui::Text(",");
- ImGui::SameLine();
- }
- ImGui::TextColored(_state->_colors._var_color, "%s", _script.globalNames[i].c_str());
- ImGui::SameLine();
+const LingoDec::Handler *getHandler(const Cast *cast, CastMemberID id, const Common::String &handlerId) {
+ if (!cast)
+ return nullptr;
+ const ScriptContext *ctx = cast->_lingoArchive->findScriptContext(id.member);
+ if (!ctx || !ctx->_functionHandlers.contains(handlerId))
+ return nullptr;
+ // for the moment it's happening with Director version < 4
+ if (!cast->_lingodec)
+ return nullptr;
+ for (auto p : cast->_lingodec->scripts) {
+ if ((p.second->castID & 0xFFFF) != id.member)
+ continue;
+ ;
+ for (const LingoDec::Handler &handler : p.second->handlers) {
+ if (handler.name == handlerId) {
+ return &handler;
}
}
-
- ImGui::NewLine();
- unindent();
- node.block->accept(*this);
-
- if (!isMethod) {
- write(node._endOffset, "end", _state->_colors._keyword_color);
- }
}
+ return nullptr;
+}
- void byteCode(const LingoDec::HandlerNode &node) {
- bool isMethod = _script.isMethod;
- if (!_script.isGenericEvent) {
- Common::String code;
- if (isMethod) {
- code += "method ";
- } else {
- code += "on ";
- }
- code += _script.handlerId;
- if (_script.argumentNames.size() > 0) {
- code += " ";
- for (size_t i = 0; i < _script.argumentNames.size(); i++) {
- if (i > 0)
- code += ", ";
- code += _script.argumentNames[i];
- }
- }
- writeByteCode(0, code);
- }
- for (uint i = 0; i < _script.bytecodeArray.size(); i++) {
- LingoDec::CodeWriterVisitor code(_dot, true);
- code.indent();
- auto &bytecode = _script.bytecodeArray[i];
- code.write(LingoDec::StandardNames::getOpcodeName(bytecode.opID));
- switch (bytecode.opcode) {
- case LingoDec::kOpJmp:
- case LingoDec::kOpJmpIfZ:
- code.write(" ");
- code.write(posToString(bytecode.pos + bytecode.obj));
- break;
- case LingoDec::kOpEndRepeat:
- code.write(" ");
- code.write(posToString(bytecode.pos - bytecode.obj));
- break;
- case LingoDec::kOpPushFloat32:
- code.write(" ");
- code.write(Common::String::format("%g", (*(const float *)(&bytecode.obj))));
- break;
- default:
- if (bytecode.opID > 0x40) {
- code.write(" ");
- code.write(Common::String::format("%d", bytecode.obj));
- }
- break;
- }
- if (bytecode.translation) {
- code.write(" ...");
- while (code.lineWidth() < 49) {
- code.write(".");
- }
- code.write(" ");
- if (bytecode.translation->isExpression) {
- code.write("<");
- }
- bytecode.translation->accept(code);
- if (bytecode.translation->isExpression) {
- code.write(">");
- }
- }
- writeByteCode(bytecode.pos, code._str);
- }
- if (!_script.isGenericEvent) {
- if (!isMethod) {
- writeByteCode(node._endOffset, "end");
- }
- }
+const LingoDec::Handler *getHandler(CastMemberID id, const Common::String &handlerId) {
+ const Director::Movie *movie = g_director->getCurrentMovie();
+ for (const auto it : *movie->getCasts()) {
+ const Cast *cast = it._value;
+ const LingoDec::Handler *handler = getHandler(cast, id, handlerId);
+ if (handler)
+ return handler;
}
+ return getHandler(movie->getSharedCast(), id, handlerId);
+}
- void write(uint32 offset, const Common::String &code, ImVec4 color = ImVec4(1, 1, 1, 1)) {
- renderLine(offset);
- renderIndentation();
- ImGui::TextColored(color, "%s", code.c_str());
- }
+ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId) {
+ ImGuiScript result;
+ result.id = id;
+ result.handlerId = handlerId;
+ result.type = scriptType;
- void writeByteCode(uint32 offset, const Common::String &code) {
- renderLine(offset);
- Common::String s;
- for (int i = 0; i < _indent; i++) {
- s += " ";
+ const LingoDec::Handler *handler = getHandler(id, handlerId);
+ if (!handler) {
+ const ScriptContext *ctx;
+ if (id.castLib == SHARED_CAST_LIB) {
+ ctx = g_director->getCurrentMovie()->getSharedCast()->_lingoArchive->getScriptContext(scriptType, id.member);
+ } else {
+ ctx = g_director->getCurrentMovie()->getScriptContext(scriptType, id);
}
- ImGui::Text("%s", (s + code).c_str());
+ if (!ctx) return result;
+ result.oldAst = ctx->_assemblyAST;
+ return result;
}
- void renderLine(uint p) {
- bool showCurrentStatement = false;
- p = MIN(p, _script.byteOffsets.size() - 1);
- uint pc = _script.byteOffsets[p];
- _script.startOffsets.push_back(pc);
-
- if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
- // check current statement
- if (!_currentStatementDisplayed) {
- if (g_lingo->_state->pc <= pc) {
- showCurrentStatement = true;
- _currentStatementDisplayed = true;
- }
- }
- }
-
- ImDrawList *dl = ImGui::GetWindowDrawList();
- const ImVec2 pos = ImGui::GetCursorScreenPos();
- const float width = ImGui::GetContentRegionAvail().x;
- const ImVec2 mid(pos.x + 7, pos.y + 7);
-
- ImVec4 color = _state->_colors._bp_color_disabled;
- const Director::Breakpoint *bp = getBreakpoint(_script.handlerId, _script.id.member, pc);
- if (bp)
- color = _state->_colors._bp_color_enabled;
-
- ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
-
- // click on breakpoint column?
- if (ImGui::IsItemClicked(0)) {
- if (color == _state->_colors._bp_color_enabled) {
- g_lingo->delBreakpoint(bp->id);
- color = _state->_colors._bp_color_disabled;
- } else {
- Director::Breakpoint newBp;
- newBp.type = kBreakpointFunction;
- newBp.scriptId = _script.id.member;
- newBp.funcName = _script.handlerId;
- newBp.funcOffset = pc;
- g_lingo->addBreakpoint(newBp);
- color = _state->_colors._bp_color_enabled;
- }
- }
-
- if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) {
- color = _state->_colors._bp_color_hover;
- }
-
- // draw breakpoint
- if (!bp || bp->enabled)
- dl->AddCircleFilled(mid, 4.0f, ImColor(color));
- else
- dl->AddCircle(mid, 4.0f, ImColor(_state->_colors._line_color));
-
- // draw current statement
- if (showCurrentStatement) {
- dl->AddQuadFilled(ImVec2(pos.x, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 10.f), ImVec2(pos.x, pos.y + 10.f), ImColor(_state->_colors._current_statement));
- dl->AddTriangleFilled(ImVec2(pos.x + 8.f, pos.y), ImVec2(pos.x + 14.f, pos.y + 7.f), ImVec2(pos.x + 8.f, pos.y + 14.f), ImColor(_state->_colors._current_statement));
- if (_state->_dbg._isScriptDirty && !ImGui::IsItemVisible()) {
- ImGui::SetScrollHereY(0.5f);
- }
- dl->AddRectFilled(ImVec2(pos.x + 16.f, pos.y), ImVec2(pos.x + width, pos.y + 16.f), ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0x20)), 0.4f);
- }
- // draw separator
- dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color));
+ result.bytecodeArray = handler->bytecodeArray;
+ result.root = handler->ast.root;
+ result.isGenericEvent = handler->isGenericEvent;
+ result.argumentNames = handler->argumentNames;
+ result.propertyNames = handler->script->propertyNames;
+ result.globalNames = handler->globalNames;
- ImGui::SetItemTooltip("Click to add a breakpoint");
- ImGui::SameLine();
+ LingoDec::Script *script = handler->script;
+ if (!script)
+ return result;
- // draw offset
- ImGui::Text("[%5d] ", pc);
- ImGui::SameLine();
- }
+ result.isMethod = script->isFactory();
+ return result;
+}
- void renderIndentation(int indent) const {
- for (int i = 0; i < indent; i++) {
- ImGui::Text(" ");
- ImGui::SameLine();
+Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 scriptId, uint pc) {
+ auto &bps = g_lingo->getBreakpoints();
+ for (uint i = 0; i < bps.size(); i++) {
+ if (bps[i].type == kBreakpointFunction && bps[i].scriptId == scriptId && bps[i].funcName == handlerName && bps[i].funcOffset == pc) {
+ return &bps[i];
}
}
-
- void renderIndentation() const {
- renderIndentation(_indent);
- }
-
- void indent() {
- _indent++;
- }
-
- void unindent() {
- if (_indent > 0)
- _indent--;
- }
-
- static Common::String posToString(int32 pos) {
- return Common::String::format("[%3d]", pos);
- }
-
-private:
- ImGuiScript &_script;
- bool _showByteCode = false;
- bool _dot = false;
- int _indent = 0;
- bool _currentStatementDisplayed = false;
- bool _isScriptInDebug = false;
-};
+ return nullptr;
+}
static uint32 getLineFromPC() {
const uint pc = g_lingo->_state->pc;
@@ -2878,7 +886,7 @@ static void addScriptCastToDisplay(CastMemberID &id) {
_state->_scriptCasts.push_back(id);
}
-static void setScriptToDisplay(const ImGuiScript &script) {
+void setScriptToDisplay(const ImGuiScript &script) {
uint index = _state->_functions._scripts.size();
if (index && _state->_functions._scripts[index - 1] == script) {
_state->_functions._showScript = true;
@@ -3090,16 +1098,15 @@ static void renderCastScript(Symbol &sym) {
static void renderScript(ImGuiScript &script, bool showByteCode) {
if (script.oldAst) {
- RenderOldScriptVisitor oldVisitor(script);
- script.oldAst->accept(&oldVisitor);
+ renderOldScriptAST(script, showByteCode);
_state->_dbg._isScriptDirty = false;
return;
}
- if(!script.root) return;
+ if (!script.root)
+ return;
- RenderScriptVisitor visitor(script, showByteCode);
- script.root->accept(visitor);
+ renderScriptAST(script, showByteCode);
_state->_dbg._isScriptDirty = false;
}
@@ -4189,5 +2196,4 @@ void onImGuiCleanup() {
}
} // namespace DT
-
} // namespace Director
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 078f96e1bf3..3cac86148ae 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -194,6 +194,14 @@ public:
};
bool toggleButton(const char *label, bool *p_value, bool inverse = false);
+ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId);
+void setScriptToDisplay(const ImGuiScript &script);
+Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 scriptId, uint pc);
+
+void renderOldScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d2.cpp
+void renderScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d4.cpp
+
+extern ImGuiState *_state;
}
diff --git a/engines/director/debugger/dt-logger.cpp b/engines/director/debugger/dt-logger.cpp
index cbb4339c881..333bdac7dd6 100644
--- a/engines/director/debugger/dt-logger.cpp
+++ b/engines/director/debugger/dt-logger.cpp
@@ -238,5 +238,4 @@ void ImGuiLogger::draw(const char *title, bool *p_open) {
}
} // namespace DT
-
} // namespace Director
diff --git a/engines/director/debugger/dt-script-d2.cpp b/engines/director/debugger/dt-script-d2.cpp
new file mode 100644
index 00000000000..1b9e8bbf9ca
--- /dev/null
+++ b/engines/director/debugger/dt-script-d2.cpp
@@ -0,0 +1,844 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "director/director.h"
+#include "director/debugger/dt-internal.h"
+
+#include "director/debugger.h"
+
+#include "director/lingo/lingo-ast.h"
+#include "director/lingo/lingo-code.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-the.h"
+
+namespace Director {
+namespace DT {
+
+class RenderOldScriptVisitor : public NodeVisitor {
+private:
+ ImGuiScript &_script;
+ int _indent = 0;
+ bool _isScriptInDebug = false;
+ bool _currentStatementDisplayed = false;
+
+public:
+ explicit RenderOldScriptVisitor(ImGuiScript &script) : _script(script) {
+ Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
+ if (!callstack.empty()) {
+ CFrame *head = callstack[callstack.size() - 1];
+ _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
+ }
+ _script.startOffsets.clear();
+ }
+
+ virtual bool visitHandlerNode(HandlerNode *node) {
+ ImGui::Text("on ");
+ ImGui::SameLine();
+ ImGui::TextColored(_state->_colors._call_color, "%s", node->name->c_str());
+ if (!node->args->empty()) {
+ ImGui::SameLine();
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ for (uint i = 0; i < node->args->size(); i++) {
+ Common::String *arg = (*node->args)[i];
+ ImGui::Text("%s", arg->c_str());
+ ImGui::SameLine();
+ if (i != (node->args->size() - 1)) {
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ }
+ }
+ ImGui::NewLine();
+ }
+ indent();
+ for (uint i = 0; i < node->stmts->size(); i++) {
+ Node *stmt = (*node->stmts)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ }
+ unindent();
+ renderLine(node->endOffset);
+ ImGui::TextColored(_state->_colors._keyword_color, "end");
+ return true;
+ }
+
+ virtual bool visitScriptNode(ScriptNode *node) {
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
+ for (Node *child : *node->children) {
+ if (child->type == kHandlerNode && *((HandlerNode *)child)->name != _script.handlerId)
+ continue;
+ renderLine(child->startOffset);
+ child->accept(this);
+ }
+ ImGui::PopStyleVar();
+ return true;
+ }
+
+ virtual bool visitFactoryNode(FactoryNode *node) {
+ ImGui::Text("factory %s", node->name->c_str());
+ ImGui::NewLine();
+ indent();
+ for (uint i = 0; i < node->methods->size(); i++) {
+ Node *method = (*node->methods)[i];
+ renderLine(method->startOffset);
+ method->accept(this);
+ ImGui::NewLine();
+ }
+ unindent();
+ return true;
+ }
+
+ virtual bool visitCmdNode(CmdNode *node) {
+ ImGui::Text("%s ", node->name->c_str());
+ ImGui::SameLine();
+ if (*node->name == "go") {
+ ImGui::TextColored(_state->_colors._keyword_color, "to ");
+ ImGui::SameLine();
+ }
+ for (uint i = 0; i < node->args->size(); i++) {
+ Node *arg = (*node->args)[i];
+ if ((i != 0) || (node->args->size() < 2) || ((*node->args)[1]->type != kMovieNode)) {
+ arg->accept(this);
+ ImGui::SameLine();
+ if (i != (node->args->size() - 1)) {
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ }
+ }
+ }
+ return true;
+ }
+
+ virtual bool visitPutIntoNode(PutIntoNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "put ");
+ ImGui::SameLine();
+ node->val->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " into ");
+ ImGui::SameLine();
+ node->var->accept(this);
+ return true;
+ }
+
+ virtual bool visitPutAfterNode(PutAfterNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "put ");
+ ImGui::SameLine();
+ node->val->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " after ");
+ ImGui::SameLine();
+ node->var->accept(this);
+ return true;
+ }
+
+ virtual bool visitPutBeforeNode(PutBeforeNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "put ");
+ ImGui::SameLine();
+ node->val->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " before ");
+ ImGui::SameLine();
+ node->var->accept(this);
+ return true;
+ }
+
+ virtual bool visitSetNode(SetNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "set ");
+ ImGui::SameLine();
+ node->val->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " to ");
+ ImGui::SameLine();
+ node->var->accept(this);
+ return true;
+ }
+
+ void displayDefineVar(const char *name, IDList *names) {
+ ImGui::Text("%s ", name);
+ ImGui::SameLine();
+ for (uint i = 0; i < names->size(); i++) {
+ Common::String *arg = (*names)[i];
+ ImGui::Text("%s", arg->c_str());
+ ImGui::SameLine();
+ if (i != (names->size() - 1)) {
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ }
+ }
+ }
+
+ virtual bool visitGlobalNode(GlobalNode *node) {
+ displayDefineVar("global", node->names);
+ return true;
+ }
+
+ virtual bool visitPropertyNode(PropertyNode *node) {
+ displayDefineVar("property", node->names);
+ return true;
+ }
+
+ virtual bool visitInstanceNode(InstanceNode *node) {
+ displayDefineVar("instance", node->names);
+ return true;
+ }
+
+ virtual bool visitIfStmtNode(IfStmtNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "if ");
+ ImGui::SameLine();
+ node->cond->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " then ");
+ if (node->stmts->size() == 1) {
+ ImGui::SameLine();
+ (*node->stmts)[0]->accept(this);
+ } else {
+ indent();
+ for (uint i = 0; i < node->stmts->size(); i++) {
+ Node *stmt = (*node->stmts)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ }
+ unindent();
+ renderLine(node->endOffset);
+ ImGui::TextColored(_state->_colors._keyword_color, "endif");
+ ImGui::SameLine();
+ }
+ return true;
+ }
+
+ virtual bool visitIfElseStmtNode(IfElseStmtNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "if ");
+ ImGui::SameLine();
+ node->cond->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " then ");
+ if (node->stmts1->size() == 1) {
+ ImGui::SameLine();
+ (*node->stmts1)[0]->accept(this);
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ } else {
+ uint offset = node->cond->endOffset;
+ indent();
+ for (uint i = 0; i < node->stmts1->size(); i++) {
+ Node *stmt = (*node->stmts1)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ offset = stmt->endOffset;
+ }
+ unindent();
+ renderLine(offset);
+ }
+ ImGui::TextColored(_state->_colors._keyword_color, "else ");
+ if (node->stmts2->size() == 1) {
+ ImGui::SameLine();
+ (*node->stmts2)[0]->accept(this);
+ } else {
+ uint offset = node->cond->endOffset;
+ indent();
+ for (uint i = 0; i < node->stmts2->size(); i++) {
+ Node *stmt = (*node->stmts2)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ offset = stmt->endOffset;
+ }
+ unindent();
+ renderLine(offset);
+ ImGui::TextColored(_state->_colors._keyword_color, "endif");
+ ImGui::SameLine();
+ }
+ return true;
+ }
+
+ virtual bool visitRepeatWhileNode(RepeatWhileNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "repeat while ");
+ ImGui::SameLine();
+ node->cond->accept(this);
+ ImGui::NewLine();
+ indent();
+ uint offset = node->cond->endOffset;
+ for (uint i = 0; i < node->stmts->size(); i++) {
+ Node *stmt = (*node->stmts)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ offset = stmt->endOffset;
+ }
+ unindent();
+ renderLine(offset);
+ ImGui::TextColored(_state->_colors._keyword_color, "endrepeat");
+ return true;
+ }
+
+ virtual bool visitRepeatWithToNode(RepeatWithToNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "repeat with ");
+ ImGui::SameLine();
+ ImGui::Text("%s = ", node->var->c_str());
+ ImGui::SameLine();
+ node->start->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, " %s ", node->down ? "down to" : "to");
+ node->end->accept(this);
+ ImGui::NewLine();
+ indent();
+ for (uint i = 0; i < node->stmts->size(); i++) {
+ Node *stmt = (*node->stmts)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ }
+ unindent();
+ renderLine(node->endOffset);
+ ImGui::TextColored(_state->_colors._keyword_color, "endrepeat");
+ return true;
+ }
+
+ virtual bool visitRepeatWithInNode(RepeatWithInNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "repeat with ");
+ ImGui::SameLine();
+ ImGui::Text("%s in ", node->var->c_str());
+ ImGui::SameLine();
+ node->list->accept(this);
+ ImGui::NewLine();
+ indent();
+ for (uint i = 0; i < node->stmts->size(); i++) {
+ Node *stmt = (*node->stmts)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ }
+ unindent();
+ renderLine(node->endOffset);
+ ImGui::TextColored(_state->_colors._keyword_color, "endrepeat");
+ return true;
+ }
+
+ virtual bool visitNextRepeatNode(NextRepeatNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "next repeat");
+ return true;
+ }
+
+ virtual bool visitExitRepeatNode(ExitRepeatNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "exit repeat");
+ return true;
+ }
+
+ virtual bool visitExitNode(ExitNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "exit");
+ return true;
+ }
+
+ virtual bool visitReturnNode(ReturnNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "return");
+ if (node->expr) {
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ node->expr->accept(this);
+ ImGui::NewLine();
+ }
+ return true;
+ }
+
+ virtual bool visitTellNode(TellNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "tell ");
+ node->target->accept(this);
+ if (node->stmts->size() == 1) {
+ ImGui::SameLine();
+ ImGui::TextColored(_state->_colors._keyword_color, " to ");
+ ImGui::SameLine();
+ (*node->stmts)[0]->accept(this);
+ } else {
+ indent();
+ for (uint i = 0; i < node->stmts->size(); i++) {
+ Node *stmt = (*node->stmts)[i];
+ renderLine(stmt->startOffset);
+ stmt->accept(this);
+ ImGui::NewLine();
+ }
+ unindent();
+ renderLine(node->endOffset);
+ ImGui::TextColored(_state->_colors._keyword_color, "endtell");
+ }
+ return true;
+ }
+
+ virtual bool visitWhenNode(WhenNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "when ");
+ ImGui::SameLine();
+ ImGui::Text("%s", node->event->c_str());
+ ImGui::SameLine();
+ ImGui::TextColored(_state->_colors._keyword_color, " then ");
+ ImGui::SameLine();
+ ImGui::Text("%s", node->code->c_str());
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitDeleteNode(DeleteNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "delete ");
+ ImGui::SameLine();
+ node->chunk->accept(this);
+ return true;
+ }
+
+ virtual bool visitHiliteNode(HiliteNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "hilite ");
+ ImGui::SameLine();
+ node->chunk->accept(this);
+ return true;
+ }
+
+ virtual bool visitAssertErrorNode(AssertErrorNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "scummvmAssertError ");
+ ImGui::SameLine();
+ node->stmt->accept(this);
+ return true;
+ }
+
+ virtual bool visitIntNode(IntNode *node) {
+ ImGui::TextColored(_state->_colors._literal_color, "%d", node->val);
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitFloatNode(FloatNode *node) {
+ ImGui::TextColored(_state->_colors._literal_color, "%g", node->val);
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitSymbolNode(SymbolNode *node) {
+ ImGui::TextColored(_state->_colors._literal_color, "%s", node->val->c_str());
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitStringNode(StringNode *node) {
+ ImGui::TextColored(_state->_colors._literal_color, "\"%s\"", node->val->c_str());
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitListNode(ListNode *node) {
+ ImGui::Text("[");
+ ImGui::SameLine();
+ for (uint i = 0; i < node->items->size(); i++) {
+ Node *prop = (*node->items)[i];
+ prop->accept(this);
+ if (i != (node->items->size() - 1)) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ }
+ }
+ ImGui::Text("]");
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitPropListNode(PropListNode *node) {
+ ImGui::Text("[");
+ ImGui::SameLine();
+ if (node->items->empty()) {
+ ImGui::Text(":");
+ ImGui::SameLine();
+ } else {
+ for (uint i = 0; i < node->items->size(); i++) {
+ Node *prop = (*node->items)[i];
+ prop->accept(this);
+ if (i != (node->items->size() - 1)) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ }
+ }
+ }
+ ImGui::Text("]");
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitPropPairNode(PropPairNode *node) {
+ node->key->accept(this);
+ ImGui::Text(":");
+ ImGui::SameLine();
+ node->val->accept(this);
+ return true;
+ }
+
+ virtual bool visitFuncNode(FuncNode *node) {
+ const bool isBuiltin = g_lingo->_builtinCmds.contains(*node->name);
+ const ImVec4 color = (ImVec4)ImColor(isBuiltin ? _state->_colors._builtin_color : _state->_colors._call_color);
+ ImGui::TextColored(color, "%s(", node->name->c_str());
+ if (!isBuiltin && ImGui::IsItemHovered() && ImGui::BeginTooltip()) {
+ ImGui::Text("Go to definition");
+ ImGui::EndTooltip();
+ }
+ if (!isBuiltin && ImGui::IsItemClicked()) {
+ int obj = 0;
+ for (uint i = 0; i < _script.bytecodeArray.size(); i++) {
+ if (node->startOffset == _script.bytecodeArray[i].pos) {
+ obj = _script.bytecodeArray[i].obj;
+ break;
+ }
+ }
+
+ ImGuiScript script = toImGuiScript(_script.type, CastMemberID(obj, _script.id.castLib), *node->name);
+ script.moviePath = _script.moviePath;
+ script.handlerName = *node->name;
+ setScriptToDisplay(script);
+ }
+ ImGui::SameLine();
+ for (uint i = 0; i < node->args->size(); i++) {
+ Node *arg = (*node->args)[i];
+ arg->accept(this);
+ if (i != (node->args->size() - 1)) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ }
+ }
+ ImGui::Text(")");
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitVarNode(VarNode *node) {
+ ImGui::TextColored(_state->_colors._var_color, "%s", node->name->c_str());
+ if (ImGui::IsItemHovered() && g_lingo->_globalvars.contains(*node->name)) {
+ const Datum &val = g_lingo->_globalvars.getVal(*node->name);
+ ImGui::BeginTooltip();
+ ImGui::Text("Click to add to watches.");
+ ImGui::Text("= %s", val.asString(true).c_str());
+ ImGui::EndTooltip();
+ }
+ if (ImGui::IsItemClicked()) {
+ _state->_variables[*node->name] = true;
+ }
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitParensNode(ParensNode *node) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ node->expr->accept(this);
+ ImGui::Text(")");
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitUnaryOpNode(UnaryOpNode *node) {
+ char op = '?';
+ if (node->op == LC::c_negate) {
+ op = '-';
+ } else if (node->op == LC::c_not) {
+ op = '!';
+ }
+ ImGui::Text("%c", op);
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitBinaryOpNode(BinaryOpNode *node) {
+ node->a->accept(this);
+ static struct {
+ inst op;
+ const char *name;
+ } ops[] = {
+ {LC::c_add, "+"},
+ {LC::c_sub, "-"},
+ {LC::c_mul, "*"},
+ {LC::c_div, "/"},
+ {LC::c_mod, "mod"},
+ {LC::c_gt, ">"},
+ {LC::c_lt, "<"},
+ {LC::c_eq, "="},
+ {LC::c_neq, "<>"},
+ {LC::c_ge, ">="},
+ {LC::c_le, "<="},
+ {LC::c_and, "and"},
+ {LC::c_or, "or"},
+ {LC::c_ampersand, "&"},
+ {LC::c_concat, "&&"},
+ {LC::c_contains, "contains"},
+ {LC::c_starts, "starts"},
+ };
+ for (auto &op : ops) {
+ if (op.op == node->op) {
+ ImGui::Text(" %s ", op.name);
+ ImGui::SameLine();
+ break;
+ }
+ }
+ node->b->accept(this);
+ return true;
+ }
+
+ virtual bool visitFrameNode(FrameNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "frame ");
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitMovieNode(MovieNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "movie ");
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitIntersectsNode(IntersectsNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "sprite ");
+ ImGui::SameLine();
+ node->sprite1->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, "intersects ");
+ node->sprite2->accept(this);
+ return true;
+ }
+
+ virtual bool visitWithinNode(WithinNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "sprite ");
+ ImGui::SameLine();
+ node->sprite1->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, "within ");
+ node->sprite2->accept(this);
+ return true;
+ }
+
+ virtual bool visitTheNode(TheNode *node) {
+ ImGui::TextColored(_state->_colors._the_color, "the %s", node->prop->c_str());
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitTheOfNode(TheOfNode *node) {
+ ImGui::TextColored(_state->_colors._the_color, "the %s of ", node->prop->c_str());
+ ImGui::SameLine();
+ node->obj->accept(this);
+ return true;
+ }
+
+ virtual bool visitTheNumberOfNode(TheNumberOfNode *node) {
+ ImGui::TextColored(_state->_colors._the_color, "the number of ");
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitTheLastNode(TheLastNode *node) {
+ // TODO: change the node to know if it's 'in' or 'of'
+ ImGui::TextColored(_state->_colors._the_color, "the last %s in/of ", toString(node->type).c_str());
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitTheDateTimeNode(TheDateTimeNode *node) {
+ const char *key1 = "";
+ switch (node->field) {
+ case kTheAbbr:
+ key1 = "abbreviated";
+ break;
+ case kTheLong:
+ key1 = "long";
+ break;
+ case kTheShort:
+ key1 = "short";
+ break;
+ }
+ const char *key2 = node->entity == kTheDate ? "date" : "time";
+ ImGui::TextColored(_state->_colors._the_color, "the %s %s", key1, key2);
+ ImGui::SameLine();
+ return true;
+ }
+
+ virtual bool visitMenuNode(MenuNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "menu ");
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitMenuItemNode(MenuItemNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "menuitem ");
+ ImGui::SameLine();
+ node->arg1->accept(this);
+ ImGui::TextColored(_state->_colors._keyword_color, "of menu ");
+ ImGui::SameLine();
+ node->arg2->accept(this);
+ return true;
+ }
+
+ virtual bool visitSoundNode(SoundNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "sound ");
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitSpriteNode(SpriteNode *node) {
+ ImGui::TextColored(_state->_colors._keyword_color, "sprite ");
+ ImGui::SameLine();
+ node->arg->accept(this);
+ return true;
+ }
+
+ virtual bool visitChunkExprNode(ChunkExprNode *node) {
+ const char *key1 = "";
+ switch (node->type) {
+ case kChunkChar:
+ key1 = "char";
+ break;
+ case kChunkWord:
+ key1 = "word";
+ break;
+ case kChunkItem:
+ key1 = "item";
+ break;
+ case kChunkLine:
+ key1 = "line";
+ break;
+ }
+ ImGui::Text("%s", key1);
+ ImGui::SameLine();
+ node->start->accept(this);
+ if (node->end) {
+ ImGui::TextColored(_state->_colors._keyword_color, " to ");
+ ImGui::SameLine();
+ node->end->accept(this);
+ }
+ ImGui::TextColored(_state->_colors._keyword_color, " of ");
+ ImGui::SameLine();
+ node->src->accept(this);
+ return true;
+ }
+
+private:
+ static Common::String toString(ChunkType chunkType) {
+ // TODO: this method could be used in ChunkExprNode
+ switch (chunkType) {
+ case kChunkChar:
+ return "char";
+ case kChunkWord:
+ return "word";
+ case kChunkItem:
+ return "item";
+ case kChunkLine:
+ return "line";
+ }
+ return "<unknown>";
+ }
+
+ void indent() {
+ _indent++;
+ }
+
+ void unindent() {
+ if (_indent > 0)
+ _indent--;
+ }
+
+ void renderIndentation() const {
+ for (int i = 0; i < _indent; i++) {
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ }
+ }
+
+ void renderLine(uint32 pc) {
+ bool showCurrentStatement = false;
+ _script.startOffsets.push_back(pc);
+
+ if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
+ // check current statement
+ if (!_currentStatementDisplayed) {
+ if (g_lingo->_state->pc <= pc) {
+ showCurrentStatement = true;
+ _currentStatementDisplayed = true;
+ }
+ }
+ }
+
+ ImDrawList *dl = ImGui::GetWindowDrawList();
+ const ImVec2 pos = ImGui::GetCursorScreenPos();
+ const float width = ImGui::GetContentRegionAvail().x;
+ const ImVec2 mid(pos.x + 7, pos.y + 7);
+
+ ImVec4 color = _state->_colors._bp_color_disabled;
+ const Director::Breakpoint *bp = getBreakpoint(_script.handlerId, _script.id.member, pc);
+ if (bp)
+ color = _state->_colors._bp_color_enabled;
+
+ ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
+
+ // click on breakpoint column?
+ if (ImGui::IsItemClicked(0)) {
+ if (color == _state->_colors._bp_color_enabled) {
+ g_lingo->delBreakpoint(bp->id);
+ color = _state->_colors._bp_color_disabled;
+ } else {
+ Director::Breakpoint newBp;
+ newBp.type = kBreakpointFunction;
+ newBp.scriptId = _script.id.member;
+ newBp.funcName = _script.handlerId;
+ newBp.funcOffset = pc;
+ g_lingo->addBreakpoint(newBp);
+ color = _state->_colors._bp_color_enabled;
+ }
+ }
+
+ if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) {
+ color = _state->_colors._bp_color_hover;
+ }
+
+ // draw breakpoint
+ if (!bp || bp->enabled)
+ dl->AddCircleFilled(mid, 4.0f, ImColor(color));
+ else
+ dl->AddCircle(mid, 4.0f, ImColor(_state->_colors._line_color));
+
+ // draw current statement
+ if (showCurrentStatement) {
+ dl->AddQuadFilled(ImVec2(pos.x, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 10.f), ImVec2(pos.x, pos.y + 10.f), ImColor(_state->_colors._current_statement));
+ dl->AddTriangleFilled(ImVec2(pos.x + 8.f, pos.y), ImVec2(pos.x + 14.f, pos.y + 7.f), ImVec2(pos.x + 8.f, pos.y + 14.f), ImColor(_state->_colors._current_statement));
+ if (_state->_dbg._isScriptDirty && !ImGui::IsItemVisible()) {
+ ImGui::SetScrollHereY(0.5f);
+ }
+ dl->AddRectFilled(ImVec2(pos.x + 16.f, pos.y), ImVec2(pos.x + width, pos.y + 16.f), ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0x20)), 0.4f);
+ }
+ // draw separator
+ dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color));
+
+ ImGui::SetItemTooltip("Click to add a breakpoint");
+ ImGui::SameLine();
+
+ // draw offset
+ ImGui::Text("[%5d] ", pc == 0xFFFFFFFF ? -1 : pc);
+ ImGui::SameLine();
+ renderIndentation();
+ }
+};
+
+void renderOldScriptAST(ImGuiScript &script, bool showByteCode) {
+ RenderOldScriptVisitor oldVisitor(script);
+ script.oldAst->accept(&oldVisitor);
+}
+
+} // namespace DT
+
+} // namespace Director
diff --git a/engines/director/debugger/dt-script-d4.cpp b/engines/director/debugger/dt-script-d4.cpp
new file mode 100644
index 00000000000..91f28262766
--- /dev/null
+++ b/engines/director/debugger/dt-script-d4.cpp
@@ -0,0 +1,1216 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "director/director.h"
+#include "director/debugger/dt-internal.h"
+
+#include "director/debugger.h"
+
+#include "director/lingo/lingo-object.h"
+
+#include "director/lingo/lingodec/codewritervisitor.h"
+#include "director/lingo/lingodec/names.h"
+#include "director/lingo/lingodec/script.h"
+
+namespace Director {
+namespace DT {
+
+class RenderScriptVisitor : public LingoDec::NodeVisitor {
+public:
+ RenderScriptVisitor(ImGuiScript &script, bool showByteCode) : _script(script), _showByteCode(showByteCode) {
+ Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
+ if (!callstack.empty()) {
+ CFrame *head = callstack[callstack.size() - 1];
+ _isScriptInDebug = (head->sp.ctx->_id == script.id.member) && (*head->sp.name == script.handlerId);
+ }
+ _script.startOffsets.clear();
+ }
+
+ virtual void visit(const LingoDec::HandlerNode &node) override {
+ if (_showByteCode) {
+ byteCode(node);
+ return;
+ }
+
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2());
+ lingoCode(node);
+ ImGui::PopStyleVar();
+ }
+
+ virtual void visit(const LingoDec::CommentNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._comment_color), "-- %s", node.text.c_str());
+ ImGui::SameLine();
+ }
+
+ virtual void visit(const LingoDec::LiteralNode &node) override {
+ write(*node.value);
+ }
+
+ virtual void visit(const LingoDec::NewObjNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), "new");
+ ImGui::SameLine();
+ ImGui::TextColored(ImColor(_state->_colors._type_color), "%s", node.objType.c_str());
+ ImGui::SameLine();
+ ImGui::Text(" (");
+ ImGui::SameLine();
+ node.objArgs->accept(*this);
+ ImGui::Text(")");
+ 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 (uint i = 0; i < _script.bytecodeArray.size(); i++) {
+ if (node._startOffset == _script.bytecodeArray[i].pos) {
+ obj = _script.bytecodeArray[i].obj;
+ break;
+ }
+ }
+
+ // 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) ? _state->_colors._builtin_color : _state->_colors._call_color);
+ ImGui::TextColored(color, "%s", node.name.c_str());
+ // TODO: we should test Director::builtins too (but inaccessible)
+ 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 = toImGuiScript(_script.type, CastMemberID(obj, _script.id.castLib), node.name);
+ script.moviePath = _script.moviePath;
+ script.handlerName = node.name;
+ setScriptToDisplay(script);
+ }
+ ImGui::SameLine();
+
+ if (node.noParens()) {
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ node.argList->accept(*this);
+ } else {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ node.argList->accept(*this);
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ if (node.isStatement) {
+ ImGui::NewLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::BlockNode &node) override {
+ indent();
+ for (const auto &child : node.children) {
+ child->accept(*this);
+ }
+ unindent();
+ }
+
+ virtual void visit(const LingoDec::PutStmtNode &node) override {
+ write(node._startOffset, "put ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.value->accept(*this);
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), LingoDec::StandardNames::putTypeNames[node.type]);
+ ImGui::SameLine();
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ node.variable->accept(*this);
+ ImGui::NewLine();
+ }
+
+ virtual void visit(const LingoDec::TheExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s", node.prop.c_str());
+ ImGui::SameLine();
+ }
+
+ virtual void visit(const LingoDec::ExitStmtNode &node) override {
+ write(node._startOffset, "exit", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::WhenStmtNode &node) override {
+ write(node._startOffset, "when ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), LingoDec::StandardNames::whenEventNames[node.event]);
+ ImGui::SameLine();
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " then ");
+ ImGui::SameLine();
+ ImGui::Text("%s", node.script.c_str());
+ }
+
+ virtual void visit(const LingoDec::RepeatWhileStmtNode &node) override {
+ write(node._startOffset, "repeat while ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.condition->accept(*this);
+ ImGui::NewLine();
+ node.block->accept(*this);
+ write(node._endOffset, "end repeat", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::RepeatWithInStmtNode &node) override {
+ write(node._startOffset, "repeat with ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ renderVar(node.varName);
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " in ");
+ ImGui::SameLine();
+ node.list->accept(*this);
+ ImGui::NewLine();
+ node.block->accept(*this);
+ write(node._endOffset, "end repeat", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::RepeatWithToStmtNode &node) override {
+ write(node._startOffset, "repeat with ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ renderVar(node.varName);
+ ImGui::Text(" = ");
+ ImGui::SameLine();
+ node.start->accept(*this);
+ if (node.up) {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " to ");
+ ImGui::SameLine();
+ } else {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " down to ");
+ ImGui::SameLine();
+ }
+ node.end->accept(*this);
+ ImGui::NewLine();
+ node.block->accept(*this);
+ write(node._endOffset, "end repeat", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::IfStmtNode &node) override {
+ {
+ write(node._startOffset, "if ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.condition->accept(*this);
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " then ");
+ }
+ node.block1->accept(*this);
+ if (node.hasElse) {
+ write(node.block2->_startOffset, "else ", _state->_colors._keyword_color);
+ node.block2->accept(*this);
+ }
+ write(node._endOffset, "end if", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::TellStmtNode &node) override {
+ write(node._startOffset, "tell ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.window->accept(*this);
+ ImGui::NewLine();
+ node.block->accept(*this);
+ write(node._endOffset, "end tell", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::EndCaseNode &node) override {
+ write(node._endOffset, "end case", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::CaseLabelNode &node) override {
+ renderLine(node._startOffset);
+ renderIndentation();
+ bool parenValue = node.value->hasSpaces(_dot);
+ if (parenValue) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.value->accept(*this);
+ if (parenValue) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ if (node.nextOr) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ node.nextOr->accept(*this);
+ } else {
+ ImGui::Text(":");
+ node.block->accept(*this);
+ }
+ if (node.nextLabel) {
+ node.nextLabel->accept(*this);
+ }
+ }
+
+ virtual void visit(const LingoDec::ChunkExprNode &node) override {
+ ImGui::Text(LingoDec::StandardNames::chunkTypeNames[node.type]);
+ ImGui::SameLine();
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ node.first->accept(*this);
+ if (!(node.last->type == LingoDec::kLiteralNode && node.last->getValue()->type == LingoDec::kDatumInt && node.last->getValue()->i == 0)) {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " to ");
+ ImGui::SameLine();
+ node.last->accept(*this);
+ }
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
+ ImGui::SameLine();
+ node.string->accept(*this);
+ }
+
+ virtual void visit(const LingoDec::InverseOpNode &node) override {
+ ImGui::Text("-");
+ ImGui::SameLine();
+
+ bool parenOperand = node.operand->hasSpaces(_dot);
+ if (parenOperand) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.operand->accept(*this);
+ if (parenOperand) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::CaseStmtNode &node) override {
+ write(node._startOffset, "case ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.value->accept(*this);
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
+ indent();
+ if (node.firstLabel) {
+ node.firstLabel->accept(*this);
+ }
+ if (node.otherwise) {
+ node.otherwise->accept(*this);
+ }
+ unindent();
+ write(node._endOffset, "end case", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::ObjCallNode &node) override {
+ auto &rawArgs = node.argList->getValue()->l;
+
+ auto &obj = rawArgs[0];
+ bool parenObj = obj->hasSpaces(_dot);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::Text(".");
+ ImGui::SameLine();
+ ImGui::Text(node.name.c_str());
+ ImGui::SameLine();
+ ImGui::Text("(");
+ ImGui::SameLine();
+ for (size_t i = 1; i < rawArgs.size(); i++) {
+ if (i > 1) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ }
+ rawArgs[i]->accept(*this);
+ }
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ virtual void visit(const LingoDec::ObjPropExprNode &node) override {
+ if (_dot) {
+ bool parenObj = node.obj->hasSpaces(_dot);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::Text(".");
+ ImGui::SameLine();
+ ImGui::Text("%s", node.prop.c_str());
+ ImGui::SameLine();
+ } else {
+ ImGui::TextColored(_state->_colors._the_color, "the %s", node.prop.c_str());
+ ImGui::SameLine();
+ ImGui::TextColored(_state->_colors._keyword_color, " of ");
+ ImGui::SameLine();
+
+ bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+ }
+
+ virtual void visit(const LingoDec::BinaryOpNode &node) override {
+ unsigned int precedence = node.getPrecedence();
+ bool parenLeft = false;
+ bool parenRight = false;
+ if (precedence) {
+ if (node.left->type == LingoDec::kBinaryOpNode) {
+ auto leftBinaryOpNode = static_cast<LingoDec::BinaryOpNode *>(node.left.get());
+ parenLeft = (leftBinaryOpNode->getPrecedence() != precedence);
+ }
+ parenRight = (node.right->type == LingoDec::kBinaryOpNode);
+ }
+
+ if (parenLeft) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.left->accept(*this);
+ if (parenLeft) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ ImGui::Text(LingoDec::StandardNames::binaryOpNames[node.opcode]);
+ ImGui::SameLine();
+ ImGui::Text(" ");
+ ImGui::SameLine();
+
+ if (parenRight) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.right->accept(*this);
+ if (parenRight) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::OtherwiseNode &node) override {
+ write(node._startOffset, "otherwise:", _state->_colors._keyword_color);
+ node.block->accept(*this);
+ }
+
+ virtual void visit(const LingoDec::MemberExprNode &node) override {
+ bool hasCastID = node.castID && !(node.castID->type == LingoDec::kLiteralNode && node.castID->getValue()->type == LingoDec::kDatumInt && node.castID->getValue()->i == 0);
+ ImGui::Text(node.type.c_str());
+ ImGui::SameLine();
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ if (_dot) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ node.memberID->accept(*this);
+ if (hasCastID) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ node.castID->accept(*this);
+ }
+ ImGui::Text(")");
+ ImGui::SameLine();
+ } else {
+ bool parenMemberID = (node.memberID->type == LingoDec::kBinaryOpNode);
+ if (parenMemberID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.memberID->accept(*this);
+ if (parenMemberID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ if (hasCastID) {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), "of castLib");
+ ImGui::SameLine();
+
+ bool parenCastID = (node.castID->type == LingoDec::kBinaryOpNode);
+ if (parenCastID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.castID->accept(*this);
+ if (parenCastID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+ }
+ }
+
+ virtual void visit(const LingoDec::PlayCmdStmtNode &node) override {
+ auto &rawArgs = node.argList->getValue()->l;
+
+ write(node._startOffset, "play ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+
+ if (rawArgs.size() == 0) {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " done");
+ ImGui::SameLine();
+ return;
+ }
+
+ auto &frame = rawArgs[0];
+ if (rawArgs.size() == 1) {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " frame ");
+ ImGui::SameLine();
+ frame->accept(*this);
+ return;
+ }
+
+ auto &movie = rawArgs[1];
+ if (!(frame->type == LingoDec::kLiteralNode && frame->getValue()->type == LingoDec::kDatumInt && frame->getValue()->i == 1)) {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " frame ");
+ ImGui::SameLine();
+ frame->accept(*this);
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
+ ImGui::SameLine();
+ }
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " movie ");
+ ImGui::SameLine();
+ movie->accept(*this);
+ }
+
+ virtual void visit(const LingoDec::ThePropExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), "the ");
+ ImGui::SameLine();
+ ImGui::Text(node.prop.c_str());
+ ImGui::SameLine();
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of ");
+ ImGui::SameLine();
+
+ bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::MenuPropExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of menu ", LingoDec::StandardNames::menuPropertyNames[node.prop]);
+ ImGui::SameLine();
+
+ bool parenMenuID = (node.menuID->type == LingoDec::kBinaryOpNode);
+ if (parenMenuID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.menuID->accept(*this);
+ if (parenMenuID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::SoundCmdStmtNode &node) override {
+ write(node._startOffset, "sound ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ ImGui::Text(node.cmd.c_str());
+ ImGui::SameLine();
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ if (node.argList->getValue()->l.size() > 0) {
+ node.argList->accept(*this);
+ }
+ ImGui::NewLine();
+ }
+
+ virtual void visit(const LingoDec::SoundPropExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of sound ", LingoDec::StandardNames::soundPropertyNames[node.prop]);
+ ImGui::SameLine();
+
+ bool parenSoundID = (node.soundID->type == LingoDec::kBinaryOpNode);
+ if (parenSoundID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.soundID->accept(*this);
+ if (parenSoundID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::AssignmentStmtNode &node) override {
+ if (!_dot) {
+ write(node._startOffset, "set ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.variable->accept(*this);
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " to ");
+ ImGui::SameLine();
+ node.value->accept(*this);
+ } else {
+ node.variable->accept(*this);
+ ImGui::Text(" = ");
+ ImGui::SameLine();
+ node.value->accept(*this);
+ }
+ ImGui::NewLine();
+ }
+
+ virtual void visit(const LingoDec::ExitRepeatStmtNode &node) override {
+ write(node._startOffset, "exit repeat", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::NextRepeatStmtNode &node) override {
+ write(node._startOffset, "next repeat", _state->_colors._keyword_color);
+ }
+
+ virtual void visit(const LingoDec::ObjBracketExprNode &node) override {
+ bool parenObj = node.obj->hasSpaces(_dot);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::Text("[");
+ ImGui::SameLine();
+ node.prop->accept(*this);
+ ImGui::Text("]");
+ ImGui::SameLine();
+ }
+
+ virtual void visit(const LingoDec::SpritePropExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of sprite ", LingoDec::StandardNames::spritePropertyNames[node.prop]);
+ ImGui::SameLine();
+
+ bool parenSpriteID = (node.spriteID->type == LingoDec::kBinaryOpNode);
+ if (parenSpriteID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.spriteID->accept(*this);
+ if (parenSpriteID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::ChunkDeleteStmtNode &node) override {
+ write(node._startOffset, "delete", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.chunk->accept(*this);
+ }
+
+ virtual void visit(const LingoDec::ChunkHiliteStmtNode &node) override {
+ write(node._startOffset, "hilite", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ node.chunk->accept(*this);
+ }
+
+ virtual void visit(const LingoDec::MenuItemPropExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the %s of menuItem ", LingoDec::StandardNames::menuItemPropertyNames[node.prop]);
+ ImGui::SameLine();
+
+ bool parenItemID = (node.itemID->type == LingoDec::kBinaryOpNode);
+ if (parenItemID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.itemID->accept(*this);
+ if (parenItemID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " of menu ");
+ ImGui::SameLine();
+
+ bool parenMenuID = (node.menuID->type == LingoDec::kBinaryOpNode);
+ if (parenMenuID) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.menuID->accept(*this);
+ if (parenMenuID) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::ObjPropIndexExprNode &node) override {
+ bool parenObj = node.obj->hasSpaces(_dot);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::Text(".");
+ ImGui::SameLine();
+ ImGui::Text(node.prop.c_str());
+ ImGui::SameLine();
+ ImGui::Text("[");
+ ImGui::SameLine();
+ node.index->accept(*this);
+ if (node.index2) {
+ ImGui::Text("..");
+ ImGui::SameLine();
+ node.index2->accept(*this);
+ }
+ ImGui::Text("]");
+ ImGui::SameLine();
+ }
+
+ virtual void visit(const LingoDec::SpriteWithinExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), "sprite ");
+ ImGui::SameLine();
+
+ bool parenFirstSprite = (node.firstSprite->type == LingoDec::kBinaryOpNode);
+ if (parenFirstSprite) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.firstSprite->accept(*this);
+ if (parenFirstSprite) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " within ");
+ ImGui::SameLine();
+
+ bool parenSecondSprite = (node.secondSprite->type == LingoDec::kBinaryOpNode);
+ if (parenSecondSprite) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.secondSprite->accept(*this);
+ if (parenSecondSprite) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::LastStringChunkExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the last %s in ", LingoDec::StandardNames::chunkTypeNames[node.type]);
+ ImGui::SameLine();
+
+ bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::SpriteIntersectsExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), "sprite ");
+ ImGui::SameLine();
+
+ bool parenFirstSprite = (node.firstSprite->type == LingoDec::kBinaryOpNode);
+ if (parenFirstSprite) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.firstSprite->accept(*this);
+ if (parenFirstSprite) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+
+ ImGui::TextColored(ImColor(_state->_colors._keyword_color), " intersects ");
+ ImGui::SameLine();
+
+ bool parenSecondSprite = (node.secondSprite->type == LingoDec::kBinaryOpNode);
+ if (parenSecondSprite) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.secondSprite->accept(*this);
+ if (parenSecondSprite) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::StringChunkCountExprNode &node) override {
+ ImGui::TextColored(ImColor(_state->_colors._the_color), "the number of %ss in ", LingoDec::StandardNames::chunkTypeNames[node.type]);
+ ImGui::SameLine();
+
+ bool parenObj = (node.obj->type == LingoDec::kBinaryOpNode);
+ if (parenObj) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.obj->accept(*this);
+ if (parenObj) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void visit(const LingoDec::VarNode &node) override {
+ renderVar(node.varName);
+ }
+
+ virtual void visit(const LingoDec::NotOpNode &node) override {
+ ImGui::Text("not ");
+ ImGui::SameLine();
+
+ bool parenOperand = node.operand->hasSpaces(_dot);
+ if (parenOperand) {
+ ImGui::Text("(");
+ ImGui::SameLine();
+ }
+ node.operand->accept(*this);
+ if (parenOperand) {
+ ImGui::Text(")");
+ ImGui::SameLine();
+ }
+ }
+
+ virtual void defaultVisit(const LingoDec::Node &node) override {
+ LingoDec::CodeWriterVisitor code(_dot, false);
+ node.accept(code);
+ if (node.isStatement) {
+ renderLine(node._startOffset);
+ renderIndentation();
+ }
+ ImGui::Text("%s", code._str.c_str());
+ }
+
+private:
+ void write(LingoDec::Datum &datum) {
+ switch (datum.type) {
+ case LingoDec::kDatumVoid:
+ ImGui::TextColored(_state->_colors._keyword_color, "VOID");
+ ImGui::SameLine();
+ return;
+ case LingoDec::kDatumSymbol:
+ ImGui::Text("#%s", datum.s.c_str());
+ ImGui::SameLine();
+ return;
+ case LingoDec::kDatumVarRef:
+ ImGui::TextColored(_state->_colors._var_color, datum.s.c_str());
+ ImGui::SameLine();
+ return;
+ case LingoDec::kDatumString:
+ if (datum.s.empty()) {
+ ImGui::TextColored(_state->_colors._keyword_color, "EMPTY");
+ ImGui::SameLine();
+ return;
+ }
+ if (datum.s.size() == 1) {
+ switch (datum.s[0]) {
+ case '\x03':
+ ImGui::TextColored(_state->_colors._keyword_color, "ENTER");
+ ImGui::SameLine();
+ return;
+ case '\x08':
+ ImGui::TextColored(_state->_colors._keyword_color, "BACKSPACE");
+ ImGui::SameLine();
+ return;
+ case '\t':
+ ImGui::TextColored(_state->_colors._keyword_color, "TAB");
+ ImGui::SameLine();
+ return;
+ case '\r':
+ ImGui::TextColored(_state->_colors._keyword_color, "RETURN");
+ ImGui::SameLine();
+ return;
+ case '"':
+ ImGui::TextColored(_state->_colors._keyword_color, "QUOTE");
+ ImGui::SameLine();
+ return;
+ default:
+ break;
+ }
+ }
+ ImGui::Text("\"%s\"", datum.s.c_str());
+ ImGui::SameLine();
+ return;
+ case LingoDec::kDatumInt:
+ ImGui::TextColored(_state->_colors._literal_color, "%d", datum.i);
+ ImGui::SameLine();
+ return;
+ case LingoDec::kDatumFloat:
+ ImGui::TextColored(_state->_colors._literal_color, "%g", datum.f);
+ ImGui::SameLine();
+ return;
+ case LingoDec::kDatumList:
+ case LingoDec::kDatumArgList:
+ case LingoDec::kDatumArgListNoRet: {
+ if (datum.type == LingoDec::kDatumList) {
+ ImGui::Text("[");
+ ImGui::SameLine();
+ }
+ for (size_t ii = 0; ii < datum.l.size(); ii++) {
+ if (ii > 0) {
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ }
+ datum.l[ii]->accept(*this);
+ }
+ if (datum.type == LingoDec::kDatumList) {
+ ImGui::Text("]");
+ ImGui::SameLine();
+ }
+ }
+ return;
+ case LingoDec::kDatumPropList: {
+ ImGui::Text("[");
+ if (datum.l.size() == 0) {
+ ImGui::Text(":");
+ ImGui::SameLine();
+ } else {
+ for (size_t ii = 0; ii < datum.l.size(); ii += 2) {
+ if (ii > 0) {
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ }
+ datum.l[ii]->accept(*this);
+ ImGui::Text(": ");
+ ImGui::SameLine();
+ datum.l[ii + 1]->accept(*this);
+ }
+ }
+ ImGui::Text("]");
+ ImGui::SameLine();
+ }
+ return;
+ }
+ }
+
+ void renderVar(const Common::String &varName) {
+ ImGui::TextColored(_state->_colors._var_color, "%s", varName.c_str());
+ if (ImGui::IsItemHovered() && g_lingo->_globalvars.contains(varName)) {
+ const Datum &val = g_lingo->_globalvars.getVal(varName);
+ ImGui::BeginTooltip();
+ ImGui::Text("Click to add to watches.");
+ ImGui::Text("= %s", val.asString(true).c_str());
+ ImGui::EndTooltip();
+ }
+ if (ImGui::IsItemClicked()) {
+ _state->_variables[varName] = true;
+ }
+ ImGui::SameLine();
+ }
+
+ void lingoCode(const LingoDec::HandlerNode &node) {
+ if (_script.isGenericEvent) {
+ node.block->accept(*this);
+ return;
+ }
+
+ bool isMethod = _script.isMethod;
+ write(node._startOffset, isMethod ? "method " : "on ", _state->_colors._keyword_color);
+ ImGui::SameLine();
+ ImGui::TextColored(_state->_colors._call_color, "%s", _script.handlerId.c_str());
+ ImGui::SameLine();
+
+ if (!_script.argumentNames.empty()) {
+ ImGui::Text(" ");
+ ImGui::SameLine();
+ for (size_t i = 0; i < _script.argumentNames.size(); i++) {
+ if (i > 0) {
+ ImGui::Text(", ");
+ ImGui::SameLine();
+ }
+ ImGui::Text("%s", _script.argumentNames[i].c_str());
+ ImGui::SameLine();
+ }
+ }
+ indent();
+
+ if (isMethod && !_script.propertyNames.empty() && node.handler == &node.handler->script->handlers[0]) {
+ ImGui::NewLine();
+ write(node._startOffset, "instance ");
+ ImGui::SameLine();
+ for (size_t i = 0; i < _script.propertyNames.size(); i++) {
+ if (i > 0)
+ ImGui::Text(",");
+ ImGui::SameLine();
+ ImGui::TextColored(_state->_colors._var_color, "%s", _script.propertyNames[i].c_str());
+ ImGui::SameLine();
+ }
+ }
+
+ if (!_script.globalNames.empty()) {
+ ImGui::NewLine();
+ write(node._startOffset, "global ");
+ ImGui::SameLine();
+ for (size_t i = 0; i < _script.globalNames.size(); i++) {
+ if (i > 0) {
+ ImGui::Text(",");
+ ImGui::SameLine();
+ }
+ ImGui::TextColored(_state->_colors._var_color, "%s", _script.globalNames[i].c_str());
+ ImGui::SameLine();
+ }
+ }
+
+ ImGui::NewLine();
+ unindent();
+ node.block->accept(*this);
+
+ if (!isMethod) {
+ write(node._endOffset, "end", _state->_colors._keyword_color);
+ }
+ }
+
+ void byteCode(const LingoDec::HandlerNode &node) {
+ bool isMethod = _script.isMethod;
+ if (!_script.isGenericEvent) {
+ Common::String code;
+ if (isMethod) {
+ code += "method ";
+ } else {
+ code += "on ";
+ }
+ code += _script.handlerId;
+ if (_script.argumentNames.size() > 0) {
+ code += " ";
+ for (size_t i = 0; i < _script.argumentNames.size(); i++) {
+ if (i > 0)
+ code += ", ";
+ code += _script.argumentNames[i];
+ }
+ }
+ writeByteCode(0, code);
+ }
+ for (uint i = 0; i < _script.bytecodeArray.size(); i++) {
+ LingoDec::CodeWriterVisitor code(_dot, true);
+ code.indent();
+ auto &bytecode = _script.bytecodeArray[i];
+ code.write(LingoDec::StandardNames::getOpcodeName(bytecode.opID));
+ switch (bytecode.opcode) {
+ case LingoDec::kOpJmp:
+ case LingoDec::kOpJmpIfZ:
+ code.write(" ");
+ code.write(posToString(bytecode.pos + bytecode.obj));
+ break;
+ case LingoDec::kOpEndRepeat:
+ code.write(" ");
+ code.write(posToString(bytecode.pos - bytecode.obj));
+ break;
+ case LingoDec::kOpPushFloat32:
+ code.write(" ");
+ code.write(Common::String::format("%g", (*(const float *)(&bytecode.obj))));
+ break;
+ default:
+ if (bytecode.opID > 0x40) {
+ code.write(" ");
+ code.write(Common::String::format("%d", bytecode.obj));
+ }
+ break;
+ }
+ if (bytecode.translation) {
+ code.write(" ...");
+ while (code.lineWidth() < 49) {
+ code.write(".");
+ }
+ code.write(" ");
+ if (bytecode.translation->isExpression) {
+ code.write("<");
+ }
+ bytecode.translation->accept(code);
+ if (bytecode.translation->isExpression) {
+ code.write(">");
+ }
+ }
+ writeByteCode(bytecode.pos, code._str);
+ }
+ if (!_script.isGenericEvent) {
+ if (!isMethod) {
+ writeByteCode(node._endOffset, "end");
+ }
+ }
+ }
+
+ void write(uint32 offset, const Common::String &code, ImVec4 color = ImVec4(1, 1, 1, 1)) {
+ renderLine(offset);
+ renderIndentation();
+ ImGui::TextColored(color, "%s", code.c_str());
+ }
+
+ void writeByteCode(uint32 offset, const Common::String &code) {
+ renderLine(offset);
+ Common::String s;
+ for (int i = 0; i < _indent; i++) {
+ s += " ";
+ }
+ ImGui::Text("%s", (s + code).c_str());
+ }
+
+ void renderLine(uint p) {
+ bool showCurrentStatement = false;
+ p = MIN(p, _script.byteOffsets.size() - 1);
+ uint pc = _script.byteOffsets[p];
+ _script.startOffsets.push_back(pc);
+
+ if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
+ // check current statement
+ if (!_currentStatementDisplayed) {
+ if (g_lingo->_state->pc <= pc) {
+ showCurrentStatement = true;
+ _currentStatementDisplayed = true;
+ }
+ }
+ }
+
+ ImDrawList *dl = ImGui::GetWindowDrawList();
+ const ImVec2 pos = ImGui::GetCursorScreenPos();
+ const float width = ImGui::GetContentRegionAvail().x;
+ const ImVec2 mid(pos.x + 7, pos.y + 7);
+
+ ImVec4 color = _state->_colors._bp_color_disabled;
+ const Director::Breakpoint *bp = getBreakpoint(_script.handlerId, _script.id.member, pc);
+ if (bp)
+ color = _state->_colors._bp_color_enabled;
+
+ ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
+
+ // click on breakpoint column?
+ if (ImGui::IsItemClicked(0)) {
+ if (color == _state->_colors._bp_color_enabled) {
+ g_lingo->delBreakpoint(bp->id);
+ color = _state->_colors._bp_color_disabled;
+ } else {
+ Director::Breakpoint newBp;
+ newBp.type = kBreakpointFunction;
+ newBp.scriptId = _script.id.member;
+ newBp.funcName = _script.handlerId;
+ newBp.funcOffset = pc;
+ g_lingo->addBreakpoint(newBp);
+ color = _state->_colors._bp_color_enabled;
+ }
+ }
+
+ if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) {
+ color = _state->_colors._bp_color_hover;
+ }
+
+ // draw breakpoint
+ if (!bp || bp->enabled)
+ dl->AddCircleFilled(mid, 4.0f, ImColor(color));
+ else
+ dl->AddCircle(mid, 4.0f, ImColor(_state->_colors._line_color));
+
+ // draw current statement
+ if (showCurrentStatement) {
+ dl->AddQuadFilled(ImVec2(pos.x, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 4.f), ImVec2(pos.x + 9.f, pos.y + 10.f), ImVec2(pos.x, pos.y + 10.f), ImColor(_state->_colors._current_statement));
+ dl->AddTriangleFilled(ImVec2(pos.x + 8.f, pos.y), ImVec2(pos.x + 14.f, pos.y + 7.f), ImVec2(pos.x + 8.f, pos.y + 14.f), ImColor(_state->_colors._current_statement));
+ if (_state->_dbg._isScriptDirty && !ImGui::IsItemVisible()) {
+ ImGui::SetScrollHereY(0.5f);
+ }
+ dl->AddRectFilled(ImVec2(pos.x + 16.f, pos.y), ImVec2(pos.x + width, pos.y + 16.f), ImColor(IM_COL32(0xFF, 0xFF, 0x00, 0x20)), 0.4f);
+ }
+ // draw separator
+ dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color));
+
+ ImGui::SetItemTooltip("Click to add a breakpoint");
+ ImGui::SameLine();
+
+ // draw offset
+ 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);
+ }
+
+ void indent() {
+ _indent++;
+ }
+
+ void unindent() {
+ if (_indent > 0)
+ _indent--;
+ }
+
+ static Common::String posToString(int32 pos) {
+ return Common::String::format("[%3d]", pos);
+ }
+
+private:
+ ImGuiScript &_script;
+ bool _showByteCode = false;
+ bool _dot = false;
+ int _indent = 0;
+ bool _currentStatementDisplayed = false;
+ bool _isScriptInDebug = false;
+};
+
+void renderScriptAST(ImGuiScript &script, bool showByteCode) {
+ RenderScriptVisitor visitor(script, showByteCode);
+ script.root->accept(visitor);
+}
+
+
+} // namespace DT
+} // namespace Director
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 9ab58e6bdf5..9147fa130b3 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -160,6 +160,8 @@ ifdef USE_IMGUI
MODULE_OBJS += \
debugger/debugtools.o \
debugger/dt-logger.o \
+ debugger/dt-script-d2.o \
+ debugger/dt-script-d4.o
endif
Commit: 7d0a75e85a245cb088a0baf3cf5855ff802dba61
https://github.com/scummvm/scummvm/commit/7d0a75e85a245cb088a0baf3cf5855ff802dba61
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:01+02:00
Commit Message:
DIRECTOR: DT: Moved Score and Cast windows to dt-score.cpp
Changed paths:
A engines/director/debugger/dt-score.cpp
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-internal.h
engines/director/module.mk
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 86b53e4feb2..46da71320ea 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -29,9 +29,7 @@
#include "director/castmember/bitmap.h"
#include "director/castmember/text.h"
#include "director/castmember/script.h"
-#include "director/channel.h"
#include "director/debugger.h"
-#include "director/frame.h"
#include "director/movie.h"
#include "director/picture.h"
#include "director/score.h"
@@ -541,7 +539,7 @@ static const char *toString(CastType castType) {
return castTypes[(int)castType];
}
-static ImGuiImage getImageID(CastMember *castMember) {
+ImGuiImage getImageID(CastMember *castMember) {
if (castMember->_type != CastType::kCastBitmap)
return {};
@@ -571,7 +569,7 @@ static void setToolTipImage(const ImGuiImage &image, const char *name) {
}
}
-static void showImage(const ImGuiImage &image, const char *name, float thumbnailSize) {
+void showImage(const ImGuiImage &image, const char *name, float thumbnailSize) {
ImVec2 size;
if (image.width > image.height) {
size = {thumbnailSize - 2, (thumbnailSize - 2) * image.height / image.width};
@@ -589,7 +587,7 @@ static void showImage(const ImGuiImage &image, const char *name, float thumbnail
setToolTipImage(image, name);
}
-static Common::String getDisplayName(CastMember *castMember) {
+Common::String getDisplayName(CastMember *castMember) {
const CastMemberInfo *castMemberInfo = castMember->getInfo();
Common::String name(castMemberInfo ? castMemberInfo->name : "");
if (!name.empty())
@@ -869,7 +867,7 @@ static void showVars() {
ImGui::End();
}
-static ImVec4 convertColor(uint32 color) {
+ImVec4 convertColor(uint32 color) {
if (g_director->_colorDepth <= 8) {
float r = g_director->getPalette()[color * 3 + 0] * 1.0 / 255.0;
float g = g_director->getPalette()[color * 3 + 1] * 1.0 / 255.0;
@@ -897,7 +895,7 @@ void setScriptToDisplay(const ImGuiScript &script) {
_state->_functions._showScript = true;
}
-static void displayScriptRef(CastMemberID &scriptId) {
+void displayScriptRef(CastMemberID &scriptId) {
if (scriptId.member) {
ImGui::TextColored(ImVec4(0.5f, 0.5f, 1.0f, 1.0f), "%d", scriptId.member);
@@ -910,131 +908,6 @@ static void displayScriptRef(CastMemberID &scriptId) {
}
}
-static void showChannels() {
- if (!_state->_w.channels)
- return;
-
- ImVec2 pos(40, 40);
- ImGui::SetNextWindowPos(pos, ImGuiCond_FirstUseEver);
-
- ImVec2 windowSize = ImGui::GetMainViewport()->Size - pos - pos;
- ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
-
- if (ImGui::Begin("Channels", &_state->_w.channels)) {
- Score *score = g_director->getCurrentMovie()->getScore();
- Frame &frame = *score->_currentFrame;
-
- CastMemberID defaultPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
- ImGui::Text("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d, currentFPS: %d",
- frame._mainChannels.tempo, frame._mainChannels.skipFrameFlag, frame._mainChannels.blend, score->_currentFrameRate);
- if (!frame._mainChannels.palette.paletteId.isNull()) {
- ImGui::Text("PAL: paletteId: %s, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d, currentId: %s, defaultId: %s",
- frame._mainChannels.palette.paletteId.asString().c_str(), frame._mainChannels.palette.firstColor, frame._mainChannels.palette.lastColor, frame._mainChannels.palette.flags,
- frame._mainChannels.palette.cycleCount, frame._mainChannels.palette.speed, frame._mainChannels.palette.frameCount,
- frame._mainChannels.palette.fade, frame._mainChannels.palette.delay, frame._mainChannels.palette.style, g_director->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
- } else {
- ImGui::Text("PAL: paletteId: 000, currentId: %s, defaultId: %s\n", g_director->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
- }
- ImGui::Text("TRAN: transType: %d, transDuration: %d, transChunkSize: %d",
- frame._mainChannels.transType, frame._mainChannels.transDuration, frame._mainChannels.transChunkSize);
- ImGui::Text("SND: 1 sound1: %d, soundType1: %d", frame._mainChannels.sound1.member, frame._mainChannels.soundType1);
- ImGui::Text("SND: 2 sound2: %d, soundType2: %d", frame._mainChannels.sound2.member, frame._mainChannels.soundType2);
- ImGui::Text("LSCR: actionId: %d", frame._mainChannels.actionId.member);
-
- if (ImGui::BeginTable("Channels", 21, ImGuiTableFlags_Borders)) {
- ImGuiTableFlags flags = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_AngledHeader;
- ImGui::TableSetupColumn("CH", flags);
- ImGui::TableSetupColumn("castId", flags);
- ImGui::TableSetupColumn("vis", flags);
- ImGui::TableSetupColumn("inkData", flags);
- ImGui::TableSetupColumn("ink", flags);
- ImGui::TableSetupColumn("trails", flags);
- ImGui::TableSetupColumn("stretch", flags);
- ImGui::TableSetupColumn("line", flags);
- ImGui::TableSetupColumn("dims", flags);
- ImGui::TableSetupColumn("type", flags);
- ImGui::TableSetupColumn("fg", flags);
- ImGui::TableSetupColumn("bg", flags);
- ImGui::TableSetupColumn("script", flags);
- ImGui::TableSetupColumn("colorcode", flags);
- ImGui::TableSetupColumn("blendAmount", flags);
- ImGui::TableSetupColumn("unk3", flags);
- ImGui::TableSetupColumn("constraint", flags);
- ImGui::TableSetupColumn("puppet", flags);
- ImGui::TableSetupColumn("moveable", flags);
- ImGui::TableSetupColumn("movieRate", flags);
- ImGui::TableSetupColumn("movieTime", flags);
-
- ImGui::TableAngledHeadersRow();
- for (int i = 0; i < frame._numChannels; i++) {
- Channel &channel = *score->_channels[i + 1];
- Sprite &sprite = *channel._sprite;
-
- ImGui::TableNextRow();
-
- ImGui::TableNextColumn();
- ImGui::Text("%-3d", i + 1);
- ImGui::TableNextColumn();
-
- if (sprite._castId.member) {
- Common::Point position = channel.getPosition();
- ImGui::Text("%s", sprite._castId.asString().c_str());
- ImGui::TableNextColumn();
- ImGui::Checkbox("", &channel._visible);
- ImGui::TableNextColumn();
- ImGui::Text("0x%02x", sprite._inkData);
- ImGui::TableNextColumn();
- ImGui::Text("%d (%s)", sprite._ink, inkType2str(sprite._ink));
- ImGui::TableNextColumn();
- ImGui::Checkbox("", &sprite._trails);
- ImGui::TableNextColumn();
- ImGui::Checkbox("", &sprite._stretch);
- ImGui::TableNextColumn();
- ImGui::Text("%d", sprite._thickness);
- ImGui::TableNextColumn();
- ImGui::Text("%dx%d@%d,%d", channel.getWidth(), channel.getHeight(), position.x, position.y);
- ImGui::TableNextColumn();
- ImGui::Text("%d (%s)", sprite._spriteType, spriteType2str(sprite._spriteType));
- ImGui::TableNextColumn();
- ImGui::Text("%3d", sprite._foreColor); ImGui::SameLine();
- ImGui::ColorButton("foreColor", convertColor(sprite._foreColor));
- ImGui::TableNextColumn();
- ImGui::Text("%3d", sprite._backColor); ImGui::SameLine();
- ImGui::ColorButton("backColor", convertColor(sprite._backColor));
- ImGui::TableNextColumn();
- displayScriptRef(sprite._scriptId);
- ImGui::TableNextColumn();
- ImGui::Text("0x%x", sprite._colorcode);
- ImGui::TableNextColumn();
- ImGui::Text("0x%x", sprite._blendAmount);
- ImGui::TableNextColumn();
- ImGui::Text("0x%x", sprite._unk3);
- ImGui::TableNextColumn();
- ImGui::Text("%d", channel._constraint);
- ImGui::TableNextColumn();
- ImGui::Checkbox("", &sprite._puppet);
- ImGui::TableNextColumn();
- ImGui::Checkbox("", &sprite._moveable);
- ImGui::TableNextColumn();
- if (channel._movieRate)
- ImGui::Text("%f", channel._movieRate);
- else
- ImGui::Text("0");
- ImGui::TableNextColumn();
- if (channel._movieRate)
- ImGui::Text("%d (%f)", channel._movieTime, (float)(channel._movieTime/60.0f));
- else
- ImGui::Text("0");
- } else {
- ImGui::Text("000");
- }
- }
- ImGui::EndTable();
- }
- }
- ImGui::End();
-}
-
static void renderCastScript(Symbol &sym) {
if (sym.type != HANDLER)
return;
@@ -1476,486 +1349,6 @@ static void showBreakpointList() {
ImGui::End();
}
-enum { kModeMember, kModeBehavior, kModeLocation, kModeInk, kModeBlend, kModeExtended,
- kChTempo, kChPalette, kChTransition, kChSound1, kChSound2, kChScript };
-const char *modes[] = { "Member", "Behavior", "Location", "Ink", "Blend", "Extended" };
-const char *modes2[] = {
- "\ue425", "Tempo", // timer
- "\ue40a", "Palette", // palette
- "\uf50c", "Transition", // transition_fade
- "\ue0501","Sound 1", // volume_up
- "\ue0502","Sound 2", // volume_up
- "\uf0c8", "Script", // forms_apps_script
-};
-
-static void displayScoreChannel(int ch, int mode, int modeSel) {
- Score *score = g_director->getCurrentMovie()->getScore();
- uint numFrames = score->_scoreCache.size();
-
- const uint currentFrameNum = score->getCurrentFrameNum();
- const ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.0f, 0.65f));
-
- ImGui::TableNextRow();
-
- ImGui::PushFont(_state->_tinyFont);
-
- if (modeSel == kModeExtended && mode == kModeExtended)
- ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt));
-
- {
- ImGui::TableNextColumn();
-
- float indentSize = 17.0;
-
- if (mode < kChTempo && modeSel == kModeExtended)
- indentSize = 10.0;
-
- if (modeSel == kModeExtended && mode == kModeExtended)
- indentSize = 0.1;
-
- ImGui::Indent(indentSize);
-
- if (mode >= kChTempo) {
- ImGui::PushFont(ImGui::GetIO().FontDefault);
-
- ImGui::Text(modes2[(mode - kChTempo) * 2]);
- ImGui::SetItemTooltip(modes2[(mode - kChTempo) * 2 + 1]);
-
- ImGui::PopFont();
- } else if (modeSel != kModeExtended || mode == kModeExtended) {
- ImGui::Text("%3d", ch);
- } else {
- ImGui::Text(modes[mode]);
- }
-
- ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_TableHeaderBg));
-
- ImGui::Unindent(indentSize);
- }
-
- numFrames -= _state->_scoreFrameOffset - 1;
- numFrames = MIN<uint>(numFrames, kMaxColumnsInTable - 2);
-
- for (int f = 0; f < (int)numFrames; f++) {
- Frame &frame = *score->_scoreCache[f + _state->_scoreFrameOffset - 1];
- Sprite &sprite = *frame._sprites[ch];
-
- ImGui::TableNextColumn();
-
- if (f + _state->_scoreFrameOffset == (int)currentFrameNum)
- ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
-
- if (f == _state->_selectedScoreCast.frame + _state->_scoreFrameOffset - 1 &&
- ch == _state->_selectedScoreCast.channel && mode <= kModeExtended)
- ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(1.0f, 0.3f, 0.3f, 0.6f)));
-
- switch (mode) {
- case kModeMember:
- if (sprite._castId.member)
- ImGui::Selectable(Common::String::format("%d", sprite._castId.member).c_str());
- else if (sprite.isQDShape())
- ImGui::Selectable("Q");
- else
- ImGui::Selectable(" ");
- break;
-
- case kModeInk:
- ImGui::Selectable(Common::String::format("%s", inkType2str(sprite._ink)).c_str());
- break;
-
- case kModeLocation:
- ImGui::Selectable(Common::String::format("%d, %d", sprite._startPoint.x, sprite._startPoint.y).c_str());
- break;
-
- case kModeBlend:
- ImGui::Selectable(Common::String::format("%d", sprite._blendAmount).c_str());
- break;
-
- case kModeBehavior:
- displayScriptRef(sprite._scriptId);
- break;
-
- case kChTempo:
- if (frame._mainChannels.tempo)
- ImGui::Text(Common::String::format("%d", frame._mainChannels.tempo).c_str());
- break;
-
- case kChPalette:
- if (frame._mainChannels.palette.paletteId.member)
- ImGui::Text(frame._mainChannels.palette.paletteId.asString().c_str());
- break;
-
- case kChTransition:
- if (frame._mainChannels.transType)
- ImGui::Text(Common::String::format("%d", frame._mainChannels.transType).c_str());
- break;
-
- case kChSound1:
- if (frame._mainChannels.sound1.member)
- ImGui::Text(Common::String::format("%d", frame._mainChannels.sound1.member).c_str());
- break;
-
- case kChSound2:
- if (frame._mainChannels.sound2.member)
- ImGui::Text(Common::String::format("%d", frame._mainChannels.sound2.member).c_str());
- break;
-
- case kChScript:
- displayScriptRef(frame._mainChannels.actionId);
- break;
-
- case kModeExtended: // Render empty row
- default:
- ImGui::Selectable(" ");
- }
-
- if (ImGui::IsItemClicked(0)) {
- _state->_selectedScoreCast.frame = f + _state->_scoreFrameOffset - 1;
- _state->_selectedScoreCast.channel = ch;
- }
- }
-
- ImGui::PopFont();
-}
-
-static void showScore() {
- if (!_state->_w.score)
- return;
-
- ImVec2 pos(40, 40);
- ImGui::SetNextWindowPos(pos, ImGuiCond_FirstUseEver);
-
- ImVec2 windowSize = ImGui::GetMainViewport()->Size - pos - pos;
- ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
-
- if (ImGui::Begin("Score", &_state->_w.score)) {
- Score *score = g_director->getCurrentMovie()->getScore();
- uint numFrames = score->_scoreCache.size();
- Cast *cast = g_director->getCurrentMovie()->getCast();
-
- if (!numFrames) {
- ImGui::Text("No frames");
- ImGui::End();
-
- return;
- }
-
- if (_state->_selectedScoreCast.frame >= (int)numFrames)
- _state->_selectedScoreCast.frame = 0;
-
- if (!numFrames || _state->_selectedScoreCast.channel >= (int)score->_scoreCache[0]->_sprites.size())
- _state->_selectedScoreCast.channel = 0;
-
- if (_state->_scoreFrameOffset >= (int) numFrames)
- _state->_scoreFrameOffset = 1;
-
- { // Render sprite details
- Sprite *sprite = nullptr;
- CastMember *castMember = nullptr;
- bool shape = false;
-
- if (_state->_selectedScoreCast.frame != -1)
- sprite = score->_scoreCache[_state->_selectedScoreCast.frame]->_sprites[_state->_selectedScoreCast.channel];
-
- if (sprite) {
- castMember = cast->getCastMember(sprite->_castId.member, true);
-
- shape = sprite->isQDShape();
- }
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Image", ImVec2(200.0f, 70.0f));
-
- if (castMember || shape) {
- ImGuiImage imgID;
-
- if (castMember)
- imgID = getImageID(castMember);
-
- if (castMember && imgID.id) {
- Common::String name(getDisplayName(castMember));
- showImage(imgID, name.c_str(), 32.f);
- } else {
- ImGui::InvisibleButton("##canvas", ImVec2(32.f, 32.f));
- }
- ImGui::SameLine();
- ImGui::Text("%s", sprite->_castId.asString().c_str());
- ImGui::Text("%s", spriteType2str(sprite->_spriteType));
- }
-
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::SameLine();
- ImGui::BeginChild("Details", ImVec2(500.0f, 70.0f));
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Ink", ImVec2(150.0f, 20.0f));
-
- if (castMember || shape) {
- ImGui::Text("%s", inkType2str(sprite->_ink));
- ImGui::SameLine(70);
- ImGui::SetItemTooltip("Ink");
- ImGui::Text("|");
- ImGui::SameLine();
- ImGui::Text("%d", sprite->_blendAmount);
- ImGui::SameLine();
- ImGui::SetItemTooltip("Blend");
- }
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::SameLine();
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Range", ImVec2(100.0f, 20.0f));
-
- if (castMember || shape) {
- ImGui::Text("\uf816"); ImGui::SameLine(); // line_start_circle
- ImGui::Text(" ?"); ImGui::SameLine(50);
- ImGui::SetItemTooltip("Start Frame");
- ImGui::Text("\uf819"); ImGui::SameLine(); // line_end_square
- ImGui::Text(" ?"); ImGui::SameLine();
- ImGui::SetItemTooltip("End Frame");
- }
-
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::SameLine();
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Flags", ImVec2(200.0f, 20.0f));
-
- if (castMember || shape) {
- ImGui::Checkbox("\ue897", &sprite->_enabled); ImGui::SameLine(); // lock
- ImGui::SetItemTooltip("enabled");
- ImGui::Checkbox("\ue745", &sprite->_editable); ImGui::SameLine(); // edit_note
- ImGui::SetItemTooltip("editable");
- ImGui::Checkbox("\uf712", &sprite->_moveable); ImGui::SameLine(); // move_selection_right
- ImGui::SetItemTooltip("moveable");
- ImGui::Checkbox("\uea14", &sprite->_trails); // dynamic_feed
- ImGui::SetItemTooltip("trails");
- }
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Colors", ImVec2(150.0f, 50.0f));
-
- if (castMember || shape) {
- ImVec4 fg = convertColor(sprite->_foreColor);
-
- ImGui::ColorButton("foreColor", fg);
- ImGui::SameLine();
- ImGui::Text("#%02x%02x%02x", (int)(fg.x * 255), (int)(fg.y * 255), (int)(fg.z * 255));
- ImGui::SetItemTooltip("Foreground Color");
- ImVec4 bg = convertColor(sprite->_backColor);
- ImGui::ColorButton("backColor", bg);
- ImGui::SameLine();
- ImGui::Text("#%02x%02x%02x", (int)(bg.x * 255), (int)(bg.y * 255), (int)(bg.z * 255));
- ImGui::SameLine();
- ImGui::SetItemTooltip("Background Color");
- }
-
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::SameLine();
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Coordinates", ImVec2(150.0f, 50.0f));
-
- if (castMember || shape) {
- ImGui::Text("X:"); ImGui::SameLine();
- ImGui::Text("%d", sprite->_startPoint.x); ImGui::SameLine(75);
- ImGui::SetItemTooltip("Reg Point Horizontal");
- ImGui::Text("W:"); ImGui::SameLine();
- ImGui::Text("%d", sprite->getWidth());
- ImGui::SetItemTooltip("Width");
-
- ImGui::Text("Y:"); ImGui::SameLine();
- ImGui::Text("%d", sprite->_startPoint.y); ImGui::SameLine(75);
- ImGui::SetItemTooltip("Reg Point Vertical");
- ImGui::Text("H:"); ImGui::SameLine();
- ImGui::Text("%d", sprite->getHeight()); ImGui::SameLine();
- ImGui::SetItemTooltip("Height");
- }
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::SameLine();
-
- ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- ImGui::BeginChild("Bbox", ImVec2(150.0f, 50.0f));
-
- if (castMember || shape) {
- const Common::Rect &box = sprite->getBbox(true);
-
- ImGui::Text("l:"); ImGui::SameLine();
- ImGui::Text("%d", box.left); ImGui::SameLine(75);
- ImGui::SetItemTooltip("Left");
- ImGui::Text("r:"); ImGui::SameLine();
- ImGui::Text("%d", box.right);
- ImGui::SetItemTooltip("Right");
-
- ImGui::Text("t:"); ImGui::SameLine();
- ImGui::Text("%d", box.top); ImGui::SameLine(75);
- ImGui::SetItemTooltip("Top");
- ImGui::Text("b:"); ImGui::SameLine();
- ImGui::Text("%d", box.bottom);
- ImGui::SetItemTooltip("Bottom");
- }
- ImGui::PopStyleColor();
- ImGui::EndChild();
-
- ImGui::EndChild();
- }
-
- uint numChannels = score->_scoreCache[0]->_sprites.size();
- uint tableColumns = MAX(numFrames + 5, 25U); // Set minimal table width to 25
-
- { // Render pagination
- uint frame = 1;
-
- ImGui::Text(" Jump to frame: ");
-
- ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
-
- do {
- ImGui::SameLine(0, 20);
-
- if (ImGui::Selectable(Common::String::format("%d", frame).c_str(), (int) frame == _state->_scoreFrameOffset, 0, ImVec2(30, 10)))
- _state->_scoreFrameOffset = frame;
-
- frame += 300;
- } while (frame < numFrames);
-
- ImGui::PopStyleVar();
-
- ImGui::SameLine();
- ImGui::Text(" of %d", numFrames);
- }
-
- if (tableColumns > kMaxColumnsInTable - 2) // Current restriction of ImGui
- tableColumns = kMaxColumnsInTable - 2;
-
- ImGuiTableFlags addonFlags = _state->_scoreMode == kModeExtended ? 0 : ImGuiTableFlags_RowBg;
-
- if (ImGui::BeginTable("Score", tableColumns + 1,
- ImGuiTableFlags_Borders | ImGuiTableFlags_HighlightHoveredColumn |
- ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | addonFlags)) {
- ImGuiTableFlags flags = ImGuiTableColumnFlags_WidthFixed;
-
- ImGui::TableSetupScrollFreeze(1, 2);
-
- ImGui::PushFont(_state->_tinyFont);
-
- ImGui::TableSetupColumn("##", flags);
- for (uint i = 0; i < tableColumns; i++)
- ImGui::TableSetupColumn(((i + _state->_scoreFrameOffset) % 5 ? " " : Common::String::format("%-2d", i + _state->_scoreFrameOffset).c_str()), flags);
-
- ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
- ImGui::TableNextRow(0);
-
- ImGui::TableSetColumnIndex(0);
- ImGui::PushID(0);
-
- ImGui::SetNextItemWidth(50);
-
- const char *selMode = modes[_state->_scoreMode];
-
- if (ImGui::BeginCombo("##", selMode)) {
- for (int n = 0; n < ARRAYSIZE(modes); n++) {
- const bool selected = (_state->_scoreMode == n);
- if (ImGui::Selectable(modes[n], selected))
- _state->_scoreMode = n;
-
- if (selected)
- ImGui::SetItemDefaultFocus();
- }
- ImGui::EndCombo();
-
- ImGui::TableHeader("##");
- }
- ImGui::PopID();
-
- for (uint i = 0; i < tableColumns; i++) {
- ImGui::TableSetColumnIndex(i + 1);
- const char *column_name = ImGui::TableGetColumnName(i + 1);
-
- ImGui::SetNextItemWidth(20);
- ImGui::TableHeader(column_name);
- }
-
- ImGui::TableNextRow();
-
- ImGui::TableNextColumn();
-
- float indentSize = 10.0;
- ImGui::Indent(indentSize);
- ImGui::Text("Labels");
- ImGui::Unindent(indentSize);
-
- ImGui::PopFont();
-
- if (score->_labels && score->_labels->size()) {
- auto labels = *score->_labels;
- auto it = labels.begin();
-
- for (uint f = 0; f < tableColumns; f++) {
- ImGui::TableNextColumn();
-
- while (it != labels.end() && (*it)->number < f + _state->_scoreFrameOffset)
- it++;
-
- if (it == labels.end())
- continue;
-
- if ((*it)->number == f + _state->_scoreFrameOffset) {
- ImGui::Text("\ue52d"); // beenhere
- ImGui::SetItemTooltip((*it)->name.c_str());
- }
- }
- }
-
- {
- displayScoreChannel(0, kChTempo, 0);
- displayScoreChannel(0, kChPalette, 0);
- displayScoreChannel(0, kChTransition, 0);
- displayScoreChannel(0, kChSound1, 0);
- displayScoreChannel(0, kChSound2, 0);
- displayScoreChannel(0, kChScript, 0);
- }
- ImGui::TableNextRow();
-
- int mode = _state->_scoreMode;
-
- for (int ch = 0; ch < (int)numChannels - 1; ch++) {
- if (mode == kModeExtended) // This will render empty row
- displayScoreChannel(ch + 1, kModeExtended, _state->_scoreMode);
-
- if (mode == kModeMember || mode == kModeExtended)
- displayScoreChannel(ch + 1, kModeMember, _state->_scoreMode);
-
- if (mode == kModeBehavior || mode == kModeExtended)
- displayScoreChannel(ch + 1, kModeBehavior, _state->_scoreMode);
-
- if (mode == kModeInk || mode == kModeExtended)
- displayScoreChannel(ch + 1, kModeInk, _state->_scoreMode);
-
- if (mode == kModeBlend || mode == kModeExtended)
- displayScoreChannel(ch + 1, kModeBlend, _state->_scoreMode);
-
- if (mode == kModeLocation || mode == kModeExtended)
- displayScoreChannel(ch + 1, kModeLocation, _state->_scoreMode);
- }
- ImGui::EndTable();
- }
- }
- ImGui::End();
-}
-
static void showArchive() {
if (!_state->_w.archive)
return;
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 3cac86148ae..6090bfe2aa7 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -197,9 +197,16 @@ bool toggleButton(const char *label, bool *p_value, bool inverse = false);
ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId);
void setScriptToDisplay(const ImGuiScript &script);
Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 scriptId, uint pc);
+void displayScriptRef(CastMemberID &scriptId);
+ImGuiImage getImageID(CastMember *castMember);
+Common::String getDisplayName(CastMember *castMember);
+void showImage(const ImGuiImage &image, const char *name, float thumbnailSize);
+ImVec4 convertColor(uint32 color);
void renderOldScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d2.cpp
void renderScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d4.cpp
+void showScore(); // dt-score.cpp
+void showChannels(); // dt-score.cpp
extern ImGuiState *_state;
diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
new file mode 100644
index 00000000000..255136c05bf
--- /dev/null
+++ b/engines/director/debugger/dt-score.cpp
@@ -0,0 +1,641 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "director/director.h"
+#include "director/debugger/dt-internal.h"
+
+#include "director/cast.h"
+#include "director/channel.h"
+#include "director/frame.h"
+#include "director/movie.h"
+#include "director/score.h"
+#include "director/sprite.h"
+
+namespace Director {
+namespace DT {
+
+enum { kModeMember, kModeBehavior, kModeLocation, kModeInk, kModeBlend, kModeExtended,
+ kChTempo, kChPalette, kChTransition, kChSound1, kChSound2, kChScript };
+const char *modes[] = { "Member", "Behavior", "Location", "Ink", "Blend", "Extended" };
+const char *modes2[] = {
+ "\ue425", "Tempo", // timer
+ "\ue40a", "Palette", // palette
+ "\uf50c", "Transition", // transition_fade
+ "\ue0501","Sound 1", // volume_up
+ "\ue0502","Sound 2", // volume_up
+ "\uf0c8", "Script", // forms_apps_script
+};
+
+static void displayScoreChannel(int ch, int mode, int modeSel) {
+ Score *score = g_director->getCurrentMovie()->getScore();
+ uint numFrames = score->_scoreCache.size();
+
+ const uint currentFrameNum = score->getCurrentFrameNum();
+ const ImU32 cell_bg_color = ImGui::GetColorU32(ImVec4(0.7f, 0.7f, 0.0f, 0.65f));
+
+ ImGui::TableNextRow();
+
+ ImGui::PushFont(_state->_tinyFont);
+
+ if (modeSel == kModeExtended && mode == kModeExtended)
+ ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt));
+
+ {
+ ImGui::TableNextColumn();
+
+ float indentSize = 17.0;
+
+ if (mode < kChTempo && modeSel == kModeExtended)
+ indentSize = 10.0;
+
+ if (modeSel == kModeExtended && mode == kModeExtended)
+ indentSize = 0.1;
+
+ ImGui::Indent(indentSize);
+
+ if (mode >= kChTempo) {
+ ImGui::PushFont(ImGui::GetIO().FontDefault);
+
+ ImGui::Text(modes2[(mode - kChTempo) * 2]);
+ ImGui::SetItemTooltip(modes2[(mode - kChTempo) * 2 + 1]);
+
+ ImGui::PopFont();
+ } else if (modeSel != kModeExtended || mode == kModeExtended) {
+ ImGui::Text("%3d", ch);
+ } else {
+ ImGui::Text(modes[mode]);
+ }
+
+ ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImGuiCol_TableHeaderBg));
+
+ ImGui::Unindent(indentSize);
+ }
+
+ numFrames -= _state->_scoreFrameOffset - 1;
+ numFrames = MIN<uint>(numFrames, kMaxColumnsInTable - 2);
+
+ for (int f = 0; f < (int)numFrames; f++) {
+ Frame &frame = *score->_scoreCache[f + _state->_scoreFrameOffset - 1];
+ Sprite &sprite = *frame._sprites[ch];
+
+ ImGui::TableNextColumn();
+
+ if (f + _state->_scoreFrameOffset == (int)currentFrameNum)
+ ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, cell_bg_color);
+
+ if (f == _state->_selectedScoreCast.frame + _state->_scoreFrameOffset - 1 &&
+ ch == _state->_selectedScoreCast.channel && mode <= kModeExtended)
+ ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg, ImGui::GetColorU32(ImVec4(1.0f, 0.3f, 0.3f, 0.6f)));
+
+ switch (mode) {
+ case kModeMember:
+ if (sprite._castId.member)
+ ImGui::Selectable(Common::String::format("%d", sprite._castId.member).c_str());
+ else if (sprite.isQDShape())
+ ImGui::Selectable("Q");
+ else
+ ImGui::Selectable(" ");
+ break;
+
+ case kModeInk:
+ ImGui::Selectable(Common::String::format("%s", inkType2str(sprite._ink)).c_str());
+ break;
+
+ case kModeLocation:
+ ImGui::Selectable(Common::String::format("%d, %d", sprite._startPoint.x, sprite._startPoint.y).c_str());
+ break;
+
+ case kModeBlend:
+ ImGui::Selectable(Common::String::format("%d", sprite._blendAmount).c_str());
+ break;
+
+ case kModeBehavior:
+ displayScriptRef(sprite._scriptId);
+ break;
+
+ case kChTempo:
+ if (frame._mainChannels.tempo)
+ ImGui::Text(Common::String::format("%d", frame._mainChannels.tempo).c_str());
+ break;
+
+ case kChPalette:
+ if (frame._mainChannels.palette.paletteId.member)
+ ImGui::Text(frame._mainChannels.palette.paletteId.asString().c_str());
+ break;
+
+ case kChTransition:
+ if (frame._mainChannels.transType)
+ ImGui::Text(Common::String::format("%d", frame._mainChannels.transType).c_str());
+ break;
+
+ case kChSound1:
+ if (frame._mainChannels.sound1.member)
+ ImGui::Text(Common::String::format("%d", frame._mainChannels.sound1.member).c_str());
+ break;
+
+ case kChSound2:
+ if (frame._mainChannels.sound2.member)
+ ImGui::Text(Common::String::format("%d", frame._mainChannels.sound2.member).c_str());
+ break;
+
+ case kChScript:
+ displayScriptRef(frame._mainChannels.actionId);
+ break;
+
+ case kModeExtended: // Render empty row
+ default:
+ ImGui::Selectable(" ");
+ }
+
+ if (ImGui::IsItemClicked(0)) {
+ _state->_selectedScoreCast.frame = f + _state->_scoreFrameOffset - 1;
+ _state->_selectedScoreCast.channel = ch;
+ }
+ }
+
+ ImGui::PopFont();
+}
+
+void showScore() {
+ if (!_state->_w.score)
+ return;
+
+ ImVec2 pos(40, 40);
+ ImGui::SetNextWindowPos(pos, ImGuiCond_FirstUseEver);
+
+ ImVec2 windowSize = ImGui::GetMainViewport()->Size - pos - pos;
+ ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
+
+ if (ImGui::Begin("Score", &_state->_w.score)) {
+ Score *score = g_director->getCurrentMovie()->getScore();
+ uint numFrames = score->_scoreCache.size();
+ Cast *cast = g_director->getCurrentMovie()->getCast();
+
+ if (!numFrames) {
+ ImGui::Text("No frames");
+ ImGui::End();
+
+ return;
+ }
+
+ if (_state->_selectedScoreCast.frame >= (int)numFrames)
+ _state->_selectedScoreCast.frame = 0;
+
+ if (!numFrames || _state->_selectedScoreCast.channel >= (int)score->_scoreCache[0]->_sprites.size())
+ _state->_selectedScoreCast.channel = 0;
+
+ if (_state->_scoreFrameOffset >= (int) numFrames)
+ _state->_scoreFrameOffset = 1;
+
+ { // Render sprite details
+ Sprite *sprite = nullptr;
+ CastMember *castMember = nullptr;
+ bool shape = false;
+
+ if (_state->_selectedScoreCast.frame != -1)
+ sprite = score->_scoreCache[_state->_selectedScoreCast.frame]->_sprites[_state->_selectedScoreCast.channel];
+
+ if (sprite) {
+ castMember = cast->getCastMember(sprite->_castId.member, true);
+
+ shape = sprite->isQDShape();
+ }
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Image", ImVec2(200.0f, 70.0f));
+
+ if (castMember || shape) {
+ ImGuiImage imgID;
+
+ if (castMember)
+ imgID = getImageID(castMember);
+
+ if (castMember && imgID.id) {
+ Common::String name(getDisplayName(castMember));
+ showImage(imgID, name.c_str(), 32.f);
+ } else {
+ ImGui::InvisibleButton("##canvas", ImVec2(32.f, 32.f));
+ }
+ ImGui::SameLine();
+ ImGui::Text("%s", sprite->_castId.asString().c_str());
+ ImGui::Text("%s", spriteType2str(sprite->_spriteType));
+ }
+
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::SameLine();
+ ImGui::BeginChild("Details", ImVec2(500.0f, 70.0f));
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Ink", ImVec2(150.0f, 20.0f));
+
+ if (castMember || shape) {
+ ImGui::Text("%s", inkType2str(sprite->_ink));
+ ImGui::SameLine(70);
+ ImGui::SetItemTooltip("Ink");
+ ImGui::Text("|");
+ ImGui::SameLine();
+ ImGui::Text("%d", sprite->_blendAmount);
+ ImGui::SameLine();
+ ImGui::SetItemTooltip("Blend");
+ }
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::SameLine();
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Range", ImVec2(100.0f, 20.0f));
+
+ if (castMember || shape) {
+ ImGui::Text("\uf816"); ImGui::SameLine(); // line_start_circle
+ ImGui::Text(" ?"); ImGui::SameLine(50);
+ ImGui::SetItemTooltip("Start Frame");
+ ImGui::Text("\uf819"); ImGui::SameLine(); // line_end_square
+ ImGui::Text(" ?"); ImGui::SameLine();
+ ImGui::SetItemTooltip("End Frame");
+ }
+
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::SameLine();
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Flags", ImVec2(200.0f, 20.0f));
+
+ if (castMember || shape) {
+ ImGui::Checkbox("\ue897", &sprite->_enabled); ImGui::SameLine(); // lock
+ ImGui::SetItemTooltip("enabled");
+ ImGui::Checkbox("\ue745", &sprite->_editable); ImGui::SameLine(); // edit_note
+ ImGui::SetItemTooltip("editable");
+ ImGui::Checkbox("\uf712", &sprite->_moveable); ImGui::SameLine(); // move_selection_right
+ ImGui::SetItemTooltip("moveable");
+ ImGui::Checkbox("\uea14", &sprite->_trails); // dynamic_feed
+ ImGui::SetItemTooltip("trails");
+ }
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Colors", ImVec2(150.0f, 50.0f));
+
+ if (castMember || shape) {
+ ImVec4 fg = convertColor(sprite->_foreColor);
+
+ ImGui::ColorButton("foreColor", fg);
+ ImGui::SameLine();
+ ImGui::Text("#%02x%02x%02x", (int)(fg.x * 255), (int)(fg.y * 255), (int)(fg.z * 255));
+ ImGui::SetItemTooltip("Foreground Color");
+ ImVec4 bg = convertColor(sprite->_backColor);
+ ImGui::ColorButton("backColor", bg);
+ ImGui::SameLine();
+ ImGui::Text("#%02x%02x%02x", (int)(bg.x * 255), (int)(bg.y * 255), (int)(bg.z * 255));
+ ImGui::SameLine();
+ ImGui::SetItemTooltip("Background Color");
+ }
+
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::SameLine();
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Coordinates", ImVec2(150.0f, 50.0f));
+
+ if (castMember || shape) {
+ ImGui::Text("X:"); ImGui::SameLine();
+ ImGui::Text("%d", sprite->_startPoint.x); ImGui::SameLine(75);
+ ImGui::SetItemTooltip("Reg Point Horizontal");
+ ImGui::Text("W:"); ImGui::SameLine();
+ ImGui::Text("%d", sprite->getWidth());
+ ImGui::SetItemTooltip("Width");
+
+ ImGui::Text("Y:"); ImGui::SameLine();
+ ImGui::Text("%d", sprite->_startPoint.y); ImGui::SameLine(75);
+ ImGui::SetItemTooltip("Reg Point Vertical");
+ ImGui::Text("H:"); ImGui::SameLine();
+ ImGui::Text("%d", sprite->getHeight()); ImGui::SameLine();
+ ImGui::SetItemTooltip("Height");
+ }
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::SameLine();
+
+ ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
+ ImGui::BeginChild("Bbox", ImVec2(150.0f, 50.0f));
+
+ if (castMember || shape) {
+ const Common::Rect &box = sprite->getBbox(true);
+
+ ImGui::Text("l:"); ImGui::SameLine();
+ ImGui::Text("%d", box.left); ImGui::SameLine(75);
+ ImGui::SetItemTooltip("Left");
+ ImGui::Text("r:"); ImGui::SameLine();
+ ImGui::Text("%d", box.right);
+ ImGui::SetItemTooltip("Right");
+
+ ImGui::Text("t:"); ImGui::SameLine();
+ ImGui::Text("%d", box.top); ImGui::SameLine(75);
+ ImGui::SetItemTooltip("Top");
+ ImGui::Text("b:"); ImGui::SameLine();
+ ImGui::Text("%d", box.bottom);
+ ImGui::SetItemTooltip("Bottom");
+ }
+ ImGui::PopStyleColor();
+ ImGui::EndChild();
+
+ ImGui::EndChild();
+ }
+
+ uint numChannels = score->_scoreCache[0]->_sprites.size();
+ uint tableColumns = MAX(numFrames + 5, 25U); // Set minimal table width to 25
+
+ { // Render pagination
+ uint frame = 1;
+
+ ImGui::Text(" Jump to frame: ");
+
+ ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.5f));
+
+ do {
+ ImGui::SameLine(0, 20);
+
+ if (ImGui::Selectable(Common::String::format("%d", frame).c_str(), (int) frame == _state->_scoreFrameOffset, 0, ImVec2(30, 10)))
+ _state->_scoreFrameOffset = frame;
+
+ frame += 300;
+ } while (frame < numFrames);
+
+ ImGui::PopStyleVar();
+
+ ImGui::SameLine();
+ ImGui::Text(" of %d", numFrames);
+ }
+
+ if (tableColumns > kMaxColumnsInTable - 2) // Current restriction of ImGui
+ tableColumns = kMaxColumnsInTable - 2;
+
+ ImGuiTableFlags addonFlags = _state->_scoreMode == kModeExtended ? 0 : ImGuiTableFlags_RowBg;
+
+ if (ImGui::BeginTable("Score", tableColumns + 1,
+ ImGuiTableFlags_Borders | ImGuiTableFlags_HighlightHoveredColumn |
+ ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | addonFlags)) {
+ ImGuiTableFlags flags = ImGuiTableColumnFlags_WidthFixed;
+
+ ImGui::TableSetupScrollFreeze(1, 2);
+
+ ImGui::PushFont(_state->_tinyFont);
+
+ ImGui::TableSetupColumn("##", flags);
+ for (uint i = 0; i < tableColumns; i++)
+ ImGui::TableSetupColumn(((i + _state->_scoreFrameOffset) % 5 ? " " : Common::String::format("%-2d", i + _state->_scoreFrameOffset).c_str()), flags);
+
+ ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
+ ImGui::TableNextRow(0);
+
+ ImGui::TableSetColumnIndex(0);
+ ImGui::PushID(0);
+
+ ImGui::SetNextItemWidth(50);
+
+ const char *selMode = modes[_state->_scoreMode];
+
+ if (ImGui::BeginCombo("##", selMode)) {
+ for (int n = 0; n < ARRAYSIZE(modes); n++) {
+ const bool selected = (_state->_scoreMode == n);
+ if (ImGui::Selectable(modes[n], selected))
+ _state->_scoreMode = n;
+
+ if (selected)
+ ImGui::SetItemDefaultFocus();
+ }
+ ImGui::EndCombo();
+
+ ImGui::TableHeader("##");
+ }
+ ImGui::PopID();
+
+ for (uint i = 0; i < tableColumns; i++) {
+ ImGui::TableSetColumnIndex(i + 1);
+ const char *column_name = ImGui::TableGetColumnName(i + 1);
+
+ ImGui::SetNextItemWidth(20);
+ ImGui::TableHeader(column_name);
+ }
+
+ ImGui::TableNextRow();
+
+ ImGui::TableNextColumn();
+
+ float indentSize = 10.0;
+ ImGui::Indent(indentSize);
+ ImGui::Text("Labels");
+ ImGui::Unindent(indentSize);
+
+ ImGui::PopFont();
+
+ if (score->_labels && score->_labels->size()) {
+ auto labels = *score->_labels;
+ auto it = labels.begin();
+
+ for (uint f = 0; f < tableColumns; f++) {
+ ImGui::TableNextColumn();
+
+ while (it != labels.end() && (*it)->number < f + _state->_scoreFrameOffset)
+ it++;
+
+ if (it == labels.end())
+ continue;
+
+ if ((*it)->number == f + _state->_scoreFrameOffset) {
+ ImGui::Text("\ue52d"); // beenhere
+ ImGui::SetItemTooltip((*it)->name.c_str());
+ }
+ }
+ }
+
+ {
+ displayScoreChannel(0, kChTempo, 0);
+ displayScoreChannel(0, kChPalette, 0);
+ displayScoreChannel(0, kChTransition, 0);
+ displayScoreChannel(0, kChSound1, 0);
+ displayScoreChannel(0, kChSound2, 0);
+ displayScoreChannel(0, kChScript, 0);
+ }
+ ImGui::TableNextRow();
+
+ int mode = _state->_scoreMode;
+
+ for (int ch = 0; ch < (int)numChannels - 1; ch++) {
+ if (mode == kModeExtended) // This will render empty row
+ displayScoreChannel(ch + 1, kModeExtended, _state->_scoreMode);
+
+ if (mode == kModeMember || mode == kModeExtended)
+ displayScoreChannel(ch + 1, kModeMember, _state->_scoreMode);
+
+ if (mode == kModeBehavior || mode == kModeExtended)
+ displayScoreChannel(ch + 1, kModeBehavior, _state->_scoreMode);
+
+ if (mode == kModeInk || mode == kModeExtended)
+ displayScoreChannel(ch + 1, kModeInk, _state->_scoreMode);
+
+ if (mode == kModeBlend || mode == kModeExtended)
+ displayScoreChannel(ch + 1, kModeBlend, _state->_scoreMode);
+
+ if (mode == kModeLocation || mode == kModeExtended)
+ displayScoreChannel(ch + 1, kModeLocation, _state->_scoreMode);
+ }
+ ImGui::EndTable();
+ }
+ }
+ ImGui::End();
+}
+
+void showChannels() {
+ if (!_state->_w.channels)
+ return;
+
+ ImVec2 pos(40, 40);
+ ImGui::SetNextWindowPos(pos, ImGuiCond_FirstUseEver);
+
+ ImVec2 windowSize = ImGui::GetMainViewport()->Size - pos - pos;
+ ImGui::SetNextWindowSize(windowSize, ImGuiCond_FirstUseEver);
+
+ if (ImGui::Begin("Channels", &_state->_w.channels)) {
+ Score *score = g_director->getCurrentMovie()->getScore();
+ Frame &frame = *score->_currentFrame;
+
+ CastMemberID defaultPalette = g_director->getCurrentMovie()->getCast()->_defaultPalette;
+ ImGui::Text("TMPO: tempo: %d, skipFrameFlag: %d, blend: %d, currentFPS: %d",
+ frame._mainChannels.tempo, frame._mainChannels.skipFrameFlag, frame._mainChannels.blend, score->_currentFrameRate);
+ if (!frame._mainChannels.palette.paletteId.isNull()) {
+ ImGui::Text("PAL: paletteId: %s, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d, currentId: %s, defaultId: %s",
+ frame._mainChannels.palette.paletteId.asString().c_str(), frame._mainChannels.palette.firstColor, frame._mainChannels.palette.lastColor, frame._mainChannels.palette.flags,
+ frame._mainChannels.palette.cycleCount, frame._mainChannels.palette.speed, frame._mainChannels.palette.frameCount,
+ frame._mainChannels.palette.fade, frame._mainChannels.palette.delay, frame._mainChannels.palette.style, g_director->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
+ } else {
+ ImGui::Text("PAL: paletteId: 000, currentId: %s, defaultId: %s\n", g_director->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
+ }
+ ImGui::Text("TRAN: transType: %d, transDuration: %d, transChunkSize: %d",
+ frame._mainChannels.transType, frame._mainChannels.transDuration, frame._mainChannels.transChunkSize);
+ ImGui::Text("SND: 1 sound1: %d, soundType1: %d", frame._mainChannels.sound1.member, frame._mainChannels.soundType1);
+ ImGui::Text("SND: 2 sound2: %d, soundType2: %d", frame._mainChannels.sound2.member, frame._mainChannels.soundType2);
+ ImGui::Text("LSCR: actionId: %d", frame._mainChannels.actionId.member);
+
+ if (ImGui::BeginTable("Channels", 21, ImGuiTableFlags_Borders)) {
+ ImGuiTableFlags flags = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_AngledHeader;
+ ImGui::TableSetupColumn("CH", flags);
+ ImGui::TableSetupColumn("castId", flags);
+ ImGui::TableSetupColumn("vis", flags);
+ ImGui::TableSetupColumn("inkData", flags);
+ ImGui::TableSetupColumn("ink", flags);
+ ImGui::TableSetupColumn("trails", flags);
+ ImGui::TableSetupColumn("stretch", flags);
+ ImGui::TableSetupColumn("line", flags);
+ ImGui::TableSetupColumn("dims", flags);
+ ImGui::TableSetupColumn("type", flags);
+ ImGui::TableSetupColumn("fg", flags);
+ ImGui::TableSetupColumn("bg", flags);
+ ImGui::TableSetupColumn("script", flags);
+ ImGui::TableSetupColumn("colorcode", flags);
+ ImGui::TableSetupColumn("blendAmount", flags);
+ ImGui::TableSetupColumn("unk3", flags);
+ ImGui::TableSetupColumn("constraint", flags);
+ ImGui::TableSetupColumn("puppet", flags);
+ ImGui::TableSetupColumn("moveable", flags);
+ ImGui::TableSetupColumn("movieRate", flags);
+ ImGui::TableSetupColumn("movieTime", flags);
+
+ ImGui::TableAngledHeadersRow();
+ for (int i = 0; i < frame._numChannels; i++) {
+ Channel &channel = *score->_channels[i + 1];
+ Sprite &sprite = *channel._sprite;
+
+ ImGui::TableNextRow();
+
+ ImGui::TableNextColumn();
+ ImGui::Text("%-3d", i + 1);
+ ImGui::TableNextColumn();
+
+ if (sprite._castId.member) {
+ Common::Point position = channel.getPosition();
+ ImGui::Text("%s", sprite._castId.asString().c_str());
+ ImGui::TableNextColumn();
+ ImGui::Checkbox("", &channel._visible);
+ ImGui::TableNextColumn();
+ ImGui::Text("0x%02x", sprite._inkData);
+ ImGui::TableNextColumn();
+ ImGui::Text("%d (%s)", sprite._ink, inkType2str(sprite._ink));
+ ImGui::TableNextColumn();
+ ImGui::Checkbox("", &sprite._trails);
+ ImGui::TableNextColumn();
+ ImGui::Checkbox("", &sprite._stretch);
+ ImGui::TableNextColumn();
+ ImGui::Text("%d", sprite._thickness);
+ ImGui::TableNextColumn();
+ ImGui::Text("%dx%d@%d,%d", channel.getWidth(), channel.getHeight(), position.x, position.y);
+ ImGui::TableNextColumn();
+ ImGui::Text("%d (%s)", sprite._spriteType, spriteType2str(sprite._spriteType));
+ ImGui::TableNextColumn();
+ ImGui::Text("%3d", sprite._foreColor); ImGui::SameLine();
+ ImGui::ColorButton("foreColor", convertColor(sprite._foreColor));
+ ImGui::TableNextColumn();
+ ImGui::Text("%3d", sprite._backColor); ImGui::SameLine();
+ ImGui::ColorButton("backColor", convertColor(sprite._backColor));
+ ImGui::TableNextColumn();
+ displayScriptRef(sprite._scriptId);
+ ImGui::TableNextColumn();
+ ImGui::Text("0x%x", sprite._colorcode);
+ ImGui::TableNextColumn();
+ ImGui::Text("0x%x", sprite._blendAmount);
+ ImGui::TableNextColumn();
+ ImGui::Text("0x%x", sprite._unk3);
+ ImGui::TableNextColumn();
+ ImGui::Text("%d", channel._constraint);
+ ImGui::TableNextColumn();
+ ImGui::Checkbox("", &sprite._puppet);
+ ImGui::TableNextColumn();
+ ImGui::Checkbox("", &sprite._moveable);
+ ImGui::TableNextColumn();
+ if (channel._movieRate)
+ ImGui::Text("%f", channel._movieRate);
+ else
+ ImGui::Text("0");
+ ImGui::TableNextColumn();
+ if (channel._movieRate)
+ ImGui::Text("%d (%f)", channel._movieTime, (float)(channel._movieTime/60.0f));
+ else
+ ImGui::Text("0");
+ } else {
+ ImGui::Text("000");
+ }
+ }
+ ImGui::EndTable();
+ }
+ }
+ ImGui::End();
+}
+
+} // namespace DT
+} // namespace Director
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 9147fa130b3..26ecc28ca44 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -160,6 +160,7 @@ ifdef USE_IMGUI
MODULE_OBJS += \
debugger/debugtools.o \
debugger/dt-logger.o \
+ debugger/dt-score.o \
debugger/dt-script-d2.o \
debugger/dt-script-d4.o
Commit: 208c346ce2bbcee154a09e1b5a78674f023872b3
https://github.com/scummvm/scummvm/commit/208c346ce2bbcee154a09e1b5a78674f023872b3
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:01+02:00
Commit Message:
DIRECTOR: DT: Moved Control Panel window to a separate file
Changed paths:
A engines/director/debugger/dt-controlpanel.cpp
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-internal.h
engines/director/module.mk
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 46da71320ea..3abbdb6acdf 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -22,7 +22,6 @@
#include "graphics/opengl/shader.h"
#include "director/director.h"
-#include "director/lingo/lingo.h"
#include "director/lingo/lingodec/context.h"
#include "director/lingo/lingodec/script.h"
#include "director/cast.h"
@@ -32,7 +31,6 @@
#include "director/debugger.h"
#include "director/movie.h"
#include "director/picture.h"
-#include "director/score.h"
#include "director/debugger/debugtools.h"
#include "director/debugger/dt-internal.h"
@@ -135,314 +133,6 @@ Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 sc
return nullptr;
}
-static uint32 getLineFromPC() {
- const uint pc = g_lingo->_state->pc;
- if (_state->_functions._scripts.empty())
- return 0;
- const Common::Array<uint> &offsets = _state->_functions._scripts[_state->_functions._current].startOffsets;
- for (uint i = 0; i < offsets.size(); i++) {
- if (pc <= offsets[i])
- return i;
- }
- return 0;
-}
-
-static bool stepOverShouldPauseDebugger() {
- const uint32 line = getLineFromPC();
-
- // we stop when we are :
- // - in the same callstack level and the statement line is different
- // - OR we go up in the callstack
- if (((g_lingo->_state->callstack.size() == _state->_dbg._callstackSize) && (line != _state->_dbg._lastLinePC)) ||
- (g_lingo->_state->callstack.size() < _state->_dbg._callstackSize)) {
- _state->_dbg._lastLinePC = line;
- return true;
- }
-
- return false;
-}
-
-static bool stepInShouldPauseDebugger() {
- const uint32 line = getLineFromPC();
-
- // we stop when:
- // - the statement line is different
- // - OR when the callstack level change
- if ((g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) || (_state->_dbg._lastLinePC != line)) {
- _state->_dbg._lastLinePC = line;
- return true;
- }
- return false;
-}
-
-static bool stepOutShouldPause() {
- const uint32 line = getLineFromPC();
-
- // we stop when:
- // - the statement line is different
- // - OR we go up in the callstack
- if (g_lingo->_state->callstack.size() < _state->_dbg._callstackSize) {
- _state->_dbg._lastLinePC = line;
- return true;
- }
-
- return false;
-}
-
-static void dgbStop() {
- g_lingo->_exec._state = kPause;
- g_lingo->_exec._shouldPause = nullptr;
- _state->_dbg._isScriptDirty = true;
-}
-
-static void dbgStepOver() {
- g_lingo->_exec._state = kRunning;
- _state->_dbg._lastLinePC = getLineFromPC();
- _state->_dbg._callstackSize = g_lingo->_state->callstack.size();
- g_lingo->_exec._shouldPause = stepOverShouldPauseDebugger;
- _state->_dbg._isScriptDirty = true;
-}
-
-static void dbgStepInto() {
- g_lingo->_exec._state = kRunning;
- _state->_dbg._lastLinePC = getLineFromPC();
- _state->_dbg._callstackSize = g_lingo->_state->callstack.size();
- g_lingo->_exec._shouldPause = stepInShouldPauseDebugger;
- _state->_dbg._isScriptDirty = true;
-}
-
-static void dbgStepOut() {
- g_lingo->_exec._state = kRunning;
- _state->_dbg._lastLinePC = getLineFromPC();
- _state->_dbg._callstackSize = g_lingo->_state->callstack.size();
- g_lingo->_exec._shouldPause = stepOutShouldPause;
- _state->_dbg._isScriptDirty = true;
-}
-
-static void showControlPanel() {
- if (!_state->_w.controlPanel)
- return;
-
- ImVec2 vp(ImGui::GetMainViewport()->Size);
- ImGui::SetNextWindowPos(ImVec2(vp.x - 220.0f, 20.0f), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSize(ImVec2(200, 103), ImGuiCond_FirstUseEver);
-
- if (ImGui::Begin("Control Panel", &_state->_w.controlPanel)) {
- Movie *movie = g_director->getCurrentMovie();
- Score *score = movie->getScore();
- ImDrawList *dl = ImGui::GetWindowDrawList();
-
- ImU32 color = ImGui::GetColorU32(ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
- ImU32 color_red = ImGui::GetColorU32(ImVec4(1.0f, 0.6f, 0.6f, 1.0f));
- ImU32 active_color = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
- ImU32 bgcolor = ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 1.0f, 1.0f));
- ImVec2 p = ImGui::GetCursorScreenPos();
- ImVec2 buttonSize(20, 14);
- float bgX1 = -4.0f, bgX2 = 21.0f;
-
- int frameNum = score->getCurrentFrameNum();
-
- if (_state->_prevFrame != -1 && _state->_prevFrame != frameNum) {
- score->_playState = kPlayPaused;
- _state->_prevFrame = -1;
- }
-
- { // Rewind
- ImGui::InvisibleButton("Rewind", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
- score->setCurrentFrame(1);
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->AddTriangleFilled(ImVec2(p.x, p.y + 8), ImVec2(p.x + 8, p.y), ImVec2(p.x + 8, p.y + 16), color);
- dl->AddTriangleFilled(ImVec2(p.x + 8, p.y + 8), ImVec2(p.x + 16, p.y), ImVec2(p.x + 16, p.y + 16), color);
-
- ImGui::SetItemTooltip("Rewind");
- ImGui::SameLine();
- }
-
- { // Step Back
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Step Back", ImVec2(18, 16));
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
-
- score->setCurrentFrame(frameNum - 1);
- _state->_prevFrame = frameNum;
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->AddTriangleFilled(ImVec2(p.x, p.y + 8), ImVec2(p.x + 9, p.y), ImVec2(p.x + 9, p.y + 16), color);
- dl->AddRectFilled(ImVec2(p.x + 11, p.y), ImVec2(p.x + 17, p.y + 16), color);
-
- ImGui::SetItemTooltip("Step Back");
- ImGui::SameLine();
- }
-
- { // Stop
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Stop", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayPaused;
- g_lingo->_exec._state = kPause;
- g_lingo->_exec._shouldPause = nullptr;
- _state->_dbg._isScriptDirty = true;
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- ImU32 stopColor = (score->_playState == kPlayPaused) ? active_color : color;
- dl->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + 16, p.y + 16), stopColor);
-
- ImGui::SetItemTooltip("Stop");
- ImGui::SameLine();
- }
-
- { // Step
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Step", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
-
- score->setCurrentFrame(frameNum + 1);
- _state->_prevFrame = frameNum;
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + 6, p.y + 16), color);
- dl->AddTriangleFilled(ImVec2(p.x + 8, p.y + 2), ImVec2(p.x + 8, p.y + 14), ImVec2(p.x + 16, p.y + 8), color);
-
- ImGui::SetItemTooltip("Step");
- ImGui::SameLine();
- }
-
- { // Play
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Play", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
- g_lingo->_exec._state = kRunning;
- g_lingo->_exec._shouldPause = nullptr;
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->AddTriangleFilled(ImVec2(p.x, p.y), ImVec2(p.x, p.y + 16), ImVec2(p.x + 14, p.y + 8), color);
-
- ImGui::SetItemTooltip("Play");
- ImGui::SameLine();
- }
-
- char buf[6];
-
- snprintf(buf, 6, "%d", score->getCurrentFrameNum());
-
- ImGui::SetNextItemWidth(35);
- ImGui::InputText("##frame", buf, 5, ImGuiInputTextFlags_CharsDecimal);
- ImGui::SetItemTooltip("Frame");
-
- {
- ImGui::Separator();
- ImGui::TextColored(ImVec4(0.9f, 0.8f, 0.5f, 1.0f), movie->getArchive()->getPathName().toString().c_str());
- ImGui::SetItemTooltip(movie->getArchive()->getPathName().toString().c_str());
- }
-
- ImGui::Separator();
- ImGui::Separator();
- ImGui::Text("Lingo:");
- ImGui::SameLine();
- { // Step over
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Step Over", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
- if (g_lingo->_exec._state == kRunning) {
- dgbStop();
- } else {
- dbgStepOver();
- }
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->PathArcToFast(ImVec2(p.x + 9, p.y + 15), 10.0f, 7, 11);
- dl->PathStroke(color_red, 0, 2);
- dl->AddLine(ImVec2(p.x + 18, p.y + 5), ImVec2(p.x + 18, p.y + 10), color_red, 2);
- dl->AddLine(ImVec2(p.x + 14, p.y + 10), ImVec2(p.x + 18, p.y + 10), color_red, 2);
- dl->AddCircleFilled(ImVec2(p.x + 9, p.y + 15), 2.0f, color);
-
- ImGui::SetItemTooltip("Step Over");
- ImGui::SameLine();
- }
-
- { // Step into
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Step Into", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
- if (g_lingo->_exec._state == kRunning) {
- dgbStop();
- } else {
- dbgStepInto();
- }
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->AddLine(ImVec2(p.x + 8.5f, p.y + 1), ImVec2(p.x + 8.5f, p.y + 10), color_red, 2);
- dl->AddLine(ImVec2(p.x + 5.5f, p.y + 6), ImVec2(p.x + 8.5f, p.y + 9), color_red, 2);
- dl->AddLine(ImVec2(p.x + 12, p.y + 6), ImVec2(p.x + 8.5f, p.y + 9), color_red, 2);
- dl->AddCircleFilled(ImVec2(p.x + 9, p.y + 15), 2.0f, color);
-
- ImGui::SetItemTooltip("Step Into");
- ImGui::SameLine();
- }
-
- { // Step out
- p = ImGui::GetCursorScreenPos();
- ImGui::InvisibleButton("Step Out", buttonSize);
-
- if (ImGui::IsItemClicked(0)) {
- score->_playState = kPlayStarted;
- if (g_lingo->_exec._state == kRunning) {
- dgbStop();
- } else {
- dbgStepOut();
- }
- }
-
- if (ImGui::IsItemHovered())
- dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
-
- dl->AddLine(ImVec2(p.x + 8.5f, p.y + 1), ImVec2(p.x + 8.5f, p.y + 10), color_red, 2);
- dl->AddLine(ImVec2(p.x + 5.5f, p.y + 5), ImVec2(p.x + 8.5f, p.y + 1), color_red, 2);
- dl->AddLine(ImVec2(p.x + 12, p.y + 5), ImVec2(p.x + 8.5f, p.y + 1), color_red, 2);
- dl->AddCircleFilled(ImVec2(p.x + 9, p.y + 15), 2.0f, color);
-
- ImGui::SetItemTooltip("Step Out");
- }
- }
- ImGui::End();
-}
-
static void showCallStack() {
if (!_state->_w.callStack)
return;
diff --git a/engines/director/debugger/dt-controlpanel.cpp b/engines/director/debugger/dt-controlpanel.cpp
new file mode 100644
index 00000000000..d15080886d2
--- /dev/null
+++ b/engines/director/debugger/dt-controlpanel.cpp
@@ -0,0 +1,341 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "director/director.h"
+#include "director/debugger/dt-internal.h"
+
+#include "director/archive.h"
+#include "director/movie.h"
+#include "director/score.h"
+
+namespace Director {
+namespace DT {
+
+static uint32 getLineFromPC() {
+ const uint pc = g_lingo->_state->pc;
+ if (_state->_functions._scripts.empty())
+ return 0;
+ const Common::Array<uint> &offsets = _state->_functions._scripts[_state->_functions._current].startOffsets;
+ for (uint i = 0; i < offsets.size(); i++) {
+ if (pc <= offsets[i])
+ return i;
+ }
+ return 0;
+}
+
+static bool stepOverShouldPauseDebugger() {
+ const uint32 line = getLineFromPC();
+
+ // we stop when we are :
+ // - in the same callstack level and the statement line is different
+ // - OR we go up in the callstack
+ if (((g_lingo->_state->callstack.size() == _state->_dbg._callstackSize) && (line != _state->_dbg._lastLinePC)) ||
+ (g_lingo->_state->callstack.size() < _state->_dbg._callstackSize)) {
+ _state->_dbg._lastLinePC = line;
+ return true;
+ }
+
+ return false;
+}
+
+static bool stepInShouldPauseDebugger() {
+ const uint32 line = getLineFromPC();
+
+ // we stop when:
+ // - the statement line is different
+ // - OR when the callstack level change
+ if ((g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) || (_state->_dbg._lastLinePC != line)) {
+ _state->_dbg._lastLinePC = line;
+ return true;
+ }
+ return false;
+}
+
+static bool stepOutShouldPause() {
+ const uint32 line = getLineFromPC();
+
+ // we stop when:
+ // - the statement line is different
+ // - OR we go up in the callstack
+ if (g_lingo->_state->callstack.size() < _state->_dbg._callstackSize) {
+ _state->_dbg._lastLinePC = line;
+ return true;
+ }
+
+ return false;
+}
+
+static void dgbStop() {
+ g_lingo->_exec._state = kPause;
+ g_lingo->_exec._shouldPause = nullptr;
+ _state->_dbg._isScriptDirty = true;
+}
+
+static void dbgStepOver() {
+ g_lingo->_exec._state = kRunning;
+ _state->_dbg._lastLinePC = getLineFromPC();
+ _state->_dbg._callstackSize = g_lingo->_state->callstack.size();
+ g_lingo->_exec._shouldPause = stepOverShouldPauseDebugger;
+ _state->_dbg._isScriptDirty = true;
+}
+
+static void dbgStepInto() {
+ g_lingo->_exec._state = kRunning;
+ _state->_dbg._lastLinePC = getLineFromPC();
+ _state->_dbg._callstackSize = g_lingo->_state->callstack.size();
+ g_lingo->_exec._shouldPause = stepInShouldPauseDebugger;
+ _state->_dbg._isScriptDirty = true;
+}
+
+static void dbgStepOut() {
+ g_lingo->_exec._state = kRunning;
+ _state->_dbg._lastLinePC = getLineFromPC();
+ _state->_dbg._callstackSize = g_lingo->_state->callstack.size();
+ g_lingo->_exec._shouldPause = stepOutShouldPause;
+ _state->_dbg._isScriptDirty = true;
+}
+
+void showControlPanel() {
+ if (!_state->_w.controlPanel)
+ return;
+
+ ImVec2 vp(ImGui::GetMainViewport()->Size);
+ ImGui::SetNextWindowPos(ImVec2(vp.x - 220.0f, 20.0f), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(200, 103), ImGuiCond_FirstUseEver);
+
+ if (ImGui::Begin("Control Panel", &_state->_w.controlPanel)) {
+ Movie *movie = g_director->getCurrentMovie();
+ Score *score = movie->getScore();
+ ImDrawList *dl = ImGui::GetWindowDrawList();
+
+ ImU32 color = ImGui::GetColorU32(ImVec4(0.8f, 0.8f, 0.8f, 1.0f));
+ ImU32 color_red = ImGui::GetColorU32(ImVec4(1.0f, 0.6f, 0.6f, 1.0f));
+ ImU32 active_color = ImGui::GetColorU32(ImVec4(1.0f, 1.0f, 0.4f, 1.0f));
+ ImU32 bgcolor = ImGui::GetColorU32(ImVec4(0.2f, 0.2f, 1.0f, 1.0f));
+ ImVec2 p = ImGui::GetCursorScreenPos();
+ ImVec2 buttonSize(20, 14);
+ float bgX1 = -4.0f, bgX2 = 21.0f;
+
+ int frameNum = score->getCurrentFrameNum();
+
+ if (_state->_prevFrame != -1 && _state->_prevFrame != frameNum) {
+ score->_playState = kPlayPaused;
+ _state->_prevFrame = -1;
+ }
+
+ { // Rewind
+ ImGui::InvisibleButton("Rewind", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+ score->setCurrentFrame(1);
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->AddTriangleFilled(ImVec2(p.x, p.y + 8), ImVec2(p.x + 8, p.y), ImVec2(p.x + 8, p.y + 16), color);
+ dl->AddTriangleFilled(ImVec2(p.x + 8, p.y + 8), ImVec2(p.x + 16, p.y), ImVec2(p.x + 16, p.y + 16), color);
+
+ ImGui::SetItemTooltip("Rewind");
+ ImGui::SameLine();
+ }
+
+ { // Step Back
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Step Back", ImVec2(18, 16));
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+
+ score->setCurrentFrame(frameNum - 1);
+ _state->_prevFrame = frameNum;
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->AddTriangleFilled(ImVec2(p.x, p.y + 8), ImVec2(p.x + 9, p.y), ImVec2(p.x + 9, p.y + 16), color);
+ dl->AddRectFilled(ImVec2(p.x + 11, p.y), ImVec2(p.x + 17, p.y + 16), color);
+
+ ImGui::SetItemTooltip("Step Back");
+ ImGui::SameLine();
+ }
+
+ { // Stop
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Stop", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayPaused;
+ g_lingo->_exec._state = kPause;
+ g_lingo->_exec._shouldPause = nullptr;
+ _state->_dbg._isScriptDirty = true;
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ ImU32 stopColor = (score->_playState == kPlayPaused) ? active_color : color;
+ dl->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + 16, p.y + 16), stopColor);
+
+ ImGui::SetItemTooltip("Stop");
+ ImGui::SameLine();
+ }
+
+ { // Step
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Step", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+
+ score->setCurrentFrame(frameNum + 1);
+ _state->_prevFrame = frameNum;
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->AddRectFilled(ImVec2(p.x, p.y), ImVec2(p.x + 6, p.y + 16), color);
+ dl->AddTriangleFilled(ImVec2(p.x + 8, p.y + 2), ImVec2(p.x + 8, p.y + 14), ImVec2(p.x + 16, p.y + 8), color);
+
+ ImGui::SetItemTooltip("Step");
+ ImGui::SameLine();
+ }
+
+ { // Play
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Play", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+ g_lingo->_exec._state = kRunning;
+ g_lingo->_exec._shouldPause = nullptr;
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->AddTriangleFilled(ImVec2(p.x, p.y), ImVec2(p.x, p.y + 16), ImVec2(p.x + 14, p.y + 8), color);
+
+ ImGui::SetItemTooltip("Play");
+ ImGui::SameLine();
+ }
+
+ char buf[6];
+
+ snprintf(buf, 6, "%d", score->getCurrentFrameNum());
+
+ ImGui::SetNextItemWidth(35);
+ ImGui::InputText("##frame", buf, 5, ImGuiInputTextFlags_CharsDecimal);
+ ImGui::SetItemTooltip("Frame");
+
+ {
+ ImGui::Separator();
+ ImGui::TextColored(ImVec4(0.9f, 0.8f, 0.5f, 1.0f), movie->getArchive()->getPathName().toString().c_str());
+ ImGui::SetItemTooltip(movie->getArchive()->getPathName().toString().c_str());
+ }
+
+ ImGui::Separator();
+ ImGui::Separator();
+ ImGui::Text("Lingo:");
+ ImGui::SameLine();
+ { // Step over
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Step Over", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+ if (g_lingo->_exec._state == kRunning) {
+ dgbStop();
+ } else {
+ dbgStepOver();
+ }
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->PathArcToFast(ImVec2(p.x + 9, p.y + 15), 10.0f, 7, 11);
+ dl->PathStroke(color_red, 0, 2);
+ dl->AddLine(ImVec2(p.x + 18, p.y + 5), ImVec2(p.x + 18, p.y + 10), color_red, 2);
+ dl->AddLine(ImVec2(p.x + 14, p.y + 10), ImVec2(p.x + 18, p.y + 10), color_red, 2);
+ dl->AddCircleFilled(ImVec2(p.x + 9, p.y + 15), 2.0f, color);
+
+ ImGui::SetItemTooltip("Step Over");
+ ImGui::SameLine();
+ }
+
+ { // Step into
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Step Into", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+ if (g_lingo->_exec._state == kRunning) {
+ dgbStop();
+ } else {
+ dbgStepInto();
+ }
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->AddLine(ImVec2(p.x + 8.5f, p.y + 1), ImVec2(p.x + 8.5f, p.y + 10), color_red, 2);
+ dl->AddLine(ImVec2(p.x + 5.5f, p.y + 6), ImVec2(p.x + 8.5f, p.y + 9), color_red, 2);
+ dl->AddLine(ImVec2(p.x + 12, p.y + 6), ImVec2(p.x + 8.5f, p.y + 9), color_red, 2);
+ dl->AddCircleFilled(ImVec2(p.x + 9, p.y + 15), 2.0f, color);
+
+ ImGui::SetItemTooltip("Step Into");
+ ImGui::SameLine();
+ }
+
+ { // Step out
+ p = ImGui::GetCursorScreenPos();
+ ImGui::InvisibleButton("Step Out", buttonSize);
+
+ if (ImGui::IsItemClicked(0)) {
+ score->_playState = kPlayStarted;
+ if (g_lingo->_exec._state == kRunning) {
+ dgbStop();
+ } else {
+ dbgStepOut();
+ }
+ }
+
+ if (ImGui::IsItemHovered())
+ dl->AddRectFilled(ImVec2(p.x + bgX1, p.y + bgX1), ImVec2(p.x + bgX2, p.y + bgX2), bgcolor, 3.0f, ImDrawFlags_RoundCornersAll);
+
+ dl->AddLine(ImVec2(p.x + 8.5f, p.y + 1), ImVec2(p.x + 8.5f, p.y + 10), color_red, 2);
+ dl->AddLine(ImVec2(p.x + 5.5f, p.y + 5), ImVec2(p.x + 8.5f, p.y + 1), color_red, 2);
+ dl->AddLine(ImVec2(p.x + 12, p.y + 5), ImVec2(p.x + 8.5f, p.y + 1), color_red, 2);
+ dl->AddCircleFilled(ImVec2(p.x + 9, p.y + 15), 2.0f, color);
+
+ ImGui::SetItemTooltip("Step Out");
+ }
+ }
+ ImGui::End();
+}
+
+} // namespace DT
+} // namespace Director
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 6090bfe2aa7..b8c1186288b 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -171,7 +171,7 @@ typedef struct ImGuiState {
ImGuiLogger *_logger = nullptr;
} ImGuiState;
-
+// dt-logger.cpp
class ImGuiLogger {
char _inputBuf[256];
ImVector<char *> _items;
@@ -193,6 +193,7 @@ public:
void draw(const char *title, bool *p_open);
};
+// debugtools.cpp
bool toggleButton(const char *label, bool *p_value, bool inverse = false);
ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId);
void setScriptToDisplay(const ImGuiScript &script);
@@ -203,6 +204,7 @@ Common::String getDisplayName(CastMember *castMember);
void showImage(const ImGuiImage &image, const char *name, float thumbnailSize);
ImVec4 convertColor(uint32 color);
+void showControlPanel(); // dt-controlpanel.cpp
void renderOldScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d2.cpp
void renderScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d4.cpp
void showScore(); // dt-score.cpp
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 26ecc28ca44..9972214571f 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -159,6 +159,7 @@ MODULE_OBJS = \
ifdef USE_IMGUI
MODULE_OBJS += \
debugger/debugtools.o \
+ debugger/dt-controlpanel.o \
debugger/dt-logger.o \
debugger/dt-score.o \
debugger/dt-script-d2.o \
Commit: 2a908bb2dca062f0241ec5ed3436a2a2b1ab5406
https://github.com/scummvm/scummvm/commit/2a908bb2dca062f0241ec5ed3436a2a2b1ab5406
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:01+02:00
Commit Message:
DIRECTOR: DT: Moved script rendering windows to dt-scripts.cpp
Changed paths:
A engines/director/debugger/dt-scripts.cpp
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-internal.h
engines/director/module.mk
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 3abbdb6acdf..9fc16ccab80 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -598,322 +598,6 @@ void displayScriptRef(CastMemberID &scriptId) {
}
}
-static void renderCastScript(Symbol &sym) {
- if (sym.type != HANDLER)
- return;
-
- Director::Lingo *lingo = g_director->getLingo();
- Common::String handlerName;
-
- if (sym.ctx && sym.ctx->_id)
- handlerName = Common::String::format("%d:", sym.ctx->_id);
-
- handlerName += lingo->formatFunctionName(sym);
-
- ImGui::Text("%s", handlerName.c_str());
-
- ImDrawList *dl = ImGui::GetWindowDrawList();
-
- ImVec4 color;
-
- uint pc = 0;
- while (pc < sym.u.defn->size()) {
- ImVec2 pos = ImGui::GetCursorScreenPos();
- const ImVec2 mid(pos.x + 7, pos.y + 7);
- Common::String bpName = Common::String::format("%s-%d", handlerName.c_str(), pc);
-
- color = _state->_colors._bp_color_disabled;
-
- Director::Breakpoint *bp = getBreakpoint(handlerName, sym.ctx->_id, pc);
- if (bp)
- color = _state->_colors._bp_color_enabled;
-
- ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
- if (ImGui::IsItemClicked(0)) {
- if (bp) {
- g_lingo->delBreakpoint(bp->id);
- color = _state->_colors._bp_color_disabled;
- } else {
- Director::Breakpoint newBp;
- newBp.type = kBreakpointFunction;
- newBp.funcName = handlerName;
- newBp.funcOffset = pc;
- g_lingo->addBreakpoint(newBp);
- color = _state->_colors._bp_color_enabled;
- }
- }
-
- if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) {
- color = _state->_colors._bp_color_hover;
- }
-
- dl->AddCircleFilled(mid, 4.0f, ImColor(color));
- dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color));
-
- ImGui::SetItemTooltip("Click to add a breakpoint");
-
- ImGui::SameLine();
- ImGui::Text("[%5d] ", pc);
- ImGui::SameLine();
- ImGui::Text("%s", lingo->decodeInstruction(sym.u.defn, pc, &pc).c_str());
- }
-}
-
-static void renderScript(ImGuiScript &script, bool showByteCode) {
- if (script.oldAst) {
- renderOldScriptAST(script, showByteCode);
- _state->_dbg._isScriptDirty = false;
- return;
- }
-
- if (!script.root)
- return;
-
- renderScriptAST(script, showByteCode);
- _state->_dbg._isScriptDirty = false;
-}
-
-static bool showScriptCast(CastMemberID &id) {
- Common::String wName("Script ");
- wName += id.asString();
-
- ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSize(ImVec2(240, 240), ImGuiCond_FirstUseEver);
-
- bool closed = true;
-
- if (ImGui::Begin(wName.c_str(), &closed)) {
- Cast *cast = g_director->getCurrentMovie()->getCasts()->getVal(id.castLib);
- ScriptContext *ctx = g_director->getCurrentMovie()->getScriptContext(kScoreScript, id);
-
- if (ctx) {
- for (auto &handler : ctx->_functionHandlers)
- renderCastScript(handler._value);
- } else if (cast->_lingoArchive->factoryContexts.contains(id.member)) {
- for (auto &it : *cast->_lingoArchive->factoryContexts.getVal(id.member)) {
- for (auto &handler : it._value->_functionHandlers)
- renderCastScript(handler._value);
- }
- } else {
- ImGui::Text("[Nothing]");
- }
- }
- ImGui::End();
-
- if (!closed)
- return false;
-
- return true;
-}
-
-/**
- * Display all open scripts
- */
-static void displayScriptCasts() {
- if (_state->_scriptCasts.empty())
- return;
-
- for (Common::List<CastMemberID>::iterator scr = _state->_scriptCasts.begin(); scr != _state->_scriptCasts.end();) {
- if (!showScriptCast(*scr))
- scr = _state->_scriptCasts.erase(scr);
- else
- scr++;
- }
-}
-
-static void updateCurrentScript() {
- if ((g_lingo->_exec._state != kPause) || !_state->_dbg._isScriptDirty)
- return;
-
- Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
- if (callstack.empty())
- return;
-
- // show current script of the current stack frame
- CFrame *head = callstack[callstack.size() - 1];
- Director::Movie *movie = g_director->getCurrentMovie();
- ScriptContext *scriptContext = head->sp.ctx;
- int castLibID = movie->getCast()->_castLibID;
- ImGuiScript script = toImGuiScript(scriptContext->_scriptType, CastMemberID(head->sp.ctx->_id, castLibID), *head->sp.name);
- script.byteOffsets = scriptContext->_functionByteOffsets[script.handlerId];
- script.moviePath = movie->getArchive()->getPathName().toString();
- script.handlerName = head->sp.ctx->_id ? Common::String::format("%d:%s", head->sp.ctx->_id, script.handlerId.c_str()) : script.handlerId;
- setScriptToDisplay(script);
-}
-
-static void displayScripts() {
- updateCurrentScript();
-
- if (!_state->_functions._showScript)
- return;
-
- ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSize(ImVec2(240, 240), ImGuiCond_FirstUseEver);
-
- if (ImGui::Begin("Script", &_state->_functions._showScript)) {
- ImGui::BeginDisabled(_state->_functions._scripts.empty() || _state->_functions._current == 0);
- if (ImGui::Button("\ue5c4")) { // Backward // arrow_back
- _state->_functions._current--;
- }
- ImGui::EndDisabled();
- ImGui::SetItemTooltip("Backward");
- ImGui::SameLine();
-
- ImGui::BeginDisabled(_state->_functions._current >= _state->_functions._scripts.size() - 1);
- if (ImGui::Button("\ue5c8")) { // Forward // arrow_forward
- _state->_functions._current++;
- }
- ImGui::EndDisabled();
- ImGui::SetItemTooltip("Forward");
- ImGui::SameLine();
-
- const char *currentScript = nullptr;
- if (_state->_functions._current < _state->_functions._scripts.size()) {
- currentScript = _state->_functions._scripts[_state->_functions._current].handlerName.c_str();
- }
-
- if (ImGui::BeginCombo("##handlers", currentScript)) {
- for (uint i = 0; i < _state->_functions._scripts.size(); i++) {
- auto &script = _state->_functions._scripts[i];
- bool selected = i == _state->_functions._current;
- if (ImGui::Selectable(script.handlerName.c_str(), &selected)) {
- _state->_functions._current = i;
- }
- }
- ImGui::EndCombo();
- }
-
- if (!_state->_functions._scripts[_state->_functions._current].oldAst) {
- ImGui::SameLine(0, 20);
- toggleButton("\uf569", &_state->_functions._showByteCode, true); // Lingo // package_2
- ImGui::SetItemTooltip("Lingo");
- ImGui::SameLine();
-
- toggleButton("\uf500", &_state->_functions._showByteCode); // Bytecode // stacks
- ImGui::SetItemTooltip("Bytecode");
- }
-
- ImGui::Separator();
- const ImVec2 childsize = ImGui::GetContentRegionAvail();
- ImGui::BeginChild("##script", childsize);
- ImGuiScript &script = _state->_functions._scripts[_state->_functions._current];
- renderScript(script, _state->_functions._showByteCode);
- ImGui::EndChild();
- }
- ImGui::End();
-}
-
-static Common::String getHandlerName(Symbol &sym) {
- Common::String handlerName;
-
- if (sym.ctx && sym.ctx->_id)
- handlerName = Common::String::format("%d:", sym.ctx->_id);
- handlerName += g_lingo->formatFunctionName(sym);
-
- return handlerName;
-}
-
-static void showFuncList() {
- if (!_state->_w.funcList)
- return;
-
- ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSize(ImVec2(480, 240), ImGuiCond_FirstUseEver);
- if (ImGui::Begin("Functions", &_state->_w.funcList)) {
- _state->_functions._nameFilter.Draw();
- ImGui::Separator();
- const ImVec2 childSize = ImGui::GetContentRegionAvail();
- ImGui::BeginChild("##functions", ImVec2(childSize.x, childSize.y));
-
- if (ImGui::BeginTable("Functions", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
- ImGui::TableSetupColumn("Function", 0, 240.f);
- ImGui::TableSetupColumn("Movie", 0, 60.f);
- ImGui::TableSetupColumn("Cast", 0, 60.f);
- ImGui::TableSetupColumn("Type", 0, 80.f);
- ImGui::TableHeadersRow();
-
- Movie *movie = g_director->getCurrentMovie();
- for (auto &cast : *movie->getCasts()) {
- for (int i = 0; i <= kMaxScriptType; i++) {
- if (cast._value->_lingoArchive->scriptContexts[i].empty())
- continue;
- Common::String scriptType(scriptType2str((ScriptType)i));
- for (auto &scriptContext : cast._value->_lingoArchive->scriptContexts[i]) {
- Common::String name = Common::String::format("%d", scriptContext._key);
- CastMemberInfo *cmi = cast._value->getCastMemberInfo(scriptContext._key);
- if (cmi && !cmi->name.empty()) {
- name += Common::String::format(" \"%s\"", cmi->name.c_str());
- }
- for (auto &functionHandler : scriptContext._value->_functionHandlers) {
- Common::String function = Common::String::format("%s: %s", name.c_str(), g_lingo->formatFunctionName(functionHandler._value).c_str());
- if (!_state->_functions._nameFilter.PassFilter(function.c_str()))
- continue;
-
- ImGui::TableNextRow();
- ImGui::TableNextColumn();
- if (ImGui::Selectable(function.c_str())) {
- CastMemberID memberID(scriptContext._key, cast._key);
- ImGuiScript script = toImGuiScript(scriptContext._value->_scriptType, memberID, functionHandler._key);
- script.byteOffsets = scriptContext._value->_functionByteOffsets[script.handlerId];
- script.moviePath = movie->getArchive()->getPathName().toString();
- script.handlerName = getHandlerName(functionHandler._value);
- setScriptToDisplay(script);
- }
- ImGui::TableNextColumn();
- ImGui::Text("%s", movie->getArchive()->getPathName().toString().c_str());
- ImGui::TableNextColumn();
- ImGui::Text("%d", cast._key);
- ImGui::TableNextColumn();
- ImGui::Text("%s", scriptType.c_str());
- }
- }
- }
- }
-
- Cast *sharedCast = movie->getSharedCast();
- if (sharedCast && sharedCast->_lingoArchive) {
- for (int i = 0; i <= kMaxScriptType; i++) {
- if (sharedCast->_lingoArchive->scriptContexts[i].empty())
- continue;
- Common::String scriptType(scriptType2str((ScriptType)i));
- for (auto &scriptContext : sharedCast->_lingoArchive->scriptContexts[i]) {
- Common::String name = Common::String::format("%d", scriptContext._key);
- CastMemberInfo *cmi = sharedCast->getCastMemberInfo(scriptContext._key);
- if (cmi && !cmi->name.empty()) {
- name += Common::String::format(" \"%s\"", cmi->name.c_str());
- }
- for (auto &functionHandler : scriptContext._value->_functionHandlers) {
- Common::String function = Common::String::format("%s: %s", name.c_str(), g_lingo->formatFunctionName(functionHandler._value).c_str());
- if (!_state->_functions._nameFilter.PassFilter(function.c_str()))
- continue;
-
- ImGui::TableNextRow();
- ImGui::TableNextColumn();
- if (ImGui::Selectable(function.c_str())) {
- CastMemberID memberID(scriptContext._key, SHARED_CAST_LIB);
- ImGuiScript script = toImGuiScript(scriptContext._value->_scriptType, memberID, functionHandler._key);
- script.byteOffsets = scriptContext._value->_functionByteOffsets[script.handlerId];
- script.moviePath = movie->getArchive()->getPathName().toString();
- script.handlerName = getHandlerName(functionHandler._value);
- setScriptToDisplay(script);
- }
- ImGui::TableNextColumn();
- ImGui::Text("%s", movie->getArchive()->getPathName().toString().c_str());
- ImGui::TableNextColumn();
- ImGui::Text("SHARED");
- ImGui::TableNextColumn();
- ImGui::Text("%s", scriptType.c_str());
- }
- }
- }
- }
- ImGui::EndTable();
- }
- ImGui::EndChild();
- }
- ImGui::End();
-}
-
// Make the UI compact because there are so many fields
static void PushStyleCompact() {
ImGuiStyle &style = ImGui::GetStyle();
@@ -1248,8 +932,8 @@ void onImGuiRender() {
ImGui::EndMainMenuBar();
}
- displayScriptCasts();
- displayScripts();
+ showScriptCasts();
+ showScripts();
showControlPanel();
showVars();
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index b8c1186288b..c621b52bb5e 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -205,10 +205,13 @@ void showImage(const ImGuiImage &image, const char *name, float thumbnailSize);
ImVec4 convertColor(uint32 color);
void showControlPanel(); // dt-controlpanel.cpp
-void renderOldScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d2.cpp
-void renderScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d4.cpp
void showScore(); // dt-score.cpp
void showChannels(); // dt-score.cpp
+void renderOldScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d2.cpp
+void renderScriptAST(ImGuiScript &script, bool showByteCode); // dt-script-d4.cpp
+void showFuncList(); // dt-scripts.cpp
+void showScriptCasts(); // dt-scripts.cpp
+void showScripts(); // dt-scripts.cpp
extern ImGuiState *_state;
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
new file mode 100644
index 00000000000..dca76e64945
--- /dev/null
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -0,0 +1,353 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "director/director.h"
+#include "director/debugger/dt-internal.h"
+
+#include "director/archive.h"
+#include "director/cast.h"
+#include "director/debugger.h"
+#include "director/movie.h"
+#include "director/castmember/castmember.h"
+#include "director/lingo/lingo-object.h"
+
+
+namespace Director {
+namespace DT {
+
+static void renderCastScript(Symbol &sym) {
+ if (sym.type != HANDLER)
+ return;
+
+ Director::Lingo *lingo = g_director->getLingo();
+ Common::String handlerName;
+
+ if (sym.ctx && sym.ctx->_id)
+ handlerName = Common::String::format("%d:", sym.ctx->_id);
+
+ handlerName += lingo->formatFunctionName(sym);
+
+ ImGui::Text("%s", handlerName.c_str());
+
+ ImDrawList *dl = ImGui::GetWindowDrawList();
+
+ ImVec4 color;
+
+ uint pc = 0;
+ while (pc < sym.u.defn->size()) {
+ ImVec2 pos = ImGui::GetCursorScreenPos();
+ const ImVec2 mid(pos.x + 7, pos.y + 7);
+ Common::String bpName = Common::String::format("%s-%d", handlerName.c_str(), pc);
+
+ color = _state->_colors._bp_color_disabled;
+
+ Director::Breakpoint *bp = getBreakpoint(handlerName, sym.ctx->_id, pc);
+ if (bp)
+ color = _state->_colors._bp_color_enabled;
+
+ ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
+ if (ImGui::IsItemClicked(0)) {
+ if (bp) {
+ g_lingo->delBreakpoint(bp->id);
+ color = _state->_colors._bp_color_disabled;
+ } else {
+ Director::Breakpoint newBp;
+ newBp.type = kBreakpointFunction;
+ newBp.funcName = handlerName;
+ newBp.funcOffset = pc;
+ g_lingo->addBreakpoint(newBp);
+ color = _state->_colors._bp_color_enabled;
+ }
+ }
+
+ if (color == _state->_colors._bp_color_disabled && ImGui::IsItemHovered()) {
+ color = _state->_colors._bp_color_hover;
+ }
+
+ dl->AddCircleFilled(mid, 4.0f, ImColor(color));
+ dl->AddLine(ImVec2(pos.x + 16.0f, pos.y), ImVec2(pos.x + 16.0f, pos.y + 17), ImColor(_state->_colors._line_color));
+
+ ImGui::SetItemTooltip("Click to add a breakpoint");
+
+ ImGui::SameLine();
+ ImGui::Text("[%5d] ", pc);
+ ImGui::SameLine();
+ ImGui::Text("%s", lingo->decodeInstruction(sym.u.defn, pc, &pc).c_str());
+ }
+}
+
+static void renderScript(ImGuiScript &script, bool showByteCode) {
+ if (script.oldAst) {
+ renderOldScriptAST(script, showByteCode);
+ _state->_dbg._isScriptDirty = false;
+ return;
+ }
+
+ if (!script.root)
+ return;
+
+ renderScriptAST(script, showByteCode);
+ _state->_dbg._isScriptDirty = false;
+}
+
+static bool showScriptCast(CastMemberID &id) {
+ Common::String wName("Script ");
+ wName += id.asString();
+
+ ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(240, 240), ImGuiCond_FirstUseEver);
+
+ bool closed = true;
+
+ if (ImGui::Begin(wName.c_str(), &closed)) {
+ Cast *cast = g_director->getCurrentMovie()->getCasts()->getVal(id.castLib);
+ ScriptContext *ctx = g_director->getCurrentMovie()->getScriptContext(kScoreScript, id);
+
+ if (ctx) {
+ for (auto &handler : ctx->_functionHandlers)
+ renderCastScript(handler._value);
+ } else if (cast->_lingoArchive->factoryContexts.contains(id.member)) {
+ for (auto &it : *cast->_lingoArchive->factoryContexts.getVal(id.member)) {
+ for (auto &handler : it._value->_functionHandlers)
+ renderCastScript(handler._value);
+ }
+ } else {
+ ImGui::Text("[Nothing]");
+ }
+ }
+ ImGui::End();
+
+ if (!closed)
+ return false;
+
+ return true;
+}
+
+/**
+ * Display all open scripts
+ */
+void showScriptCasts() {
+ if (_state->_scriptCasts.empty())
+ return;
+
+ for (Common::List<CastMemberID>::iterator scr = _state->_scriptCasts.begin(); scr != _state->_scriptCasts.end();) {
+ if (!showScriptCast(*scr))
+ scr = _state->_scriptCasts.erase(scr);
+ else
+ scr++;
+ }
+}
+
+static void updateCurrentScript() {
+ if ((g_lingo->_exec._state != kPause) || !_state->_dbg._isScriptDirty)
+ return;
+
+ Common::Array<CFrame *> &callstack = g_lingo->_state->callstack;
+ if (callstack.empty())
+ return;
+
+ // show current script of the current stack frame
+ CFrame *head = callstack[callstack.size() - 1];
+ Director::Movie *movie = g_director->getCurrentMovie();
+ ScriptContext *scriptContext = head->sp.ctx;
+ int castLibID = movie->getCast()->_castLibID;
+ ImGuiScript script = toImGuiScript(scriptContext->_scriptType, CastMemberID(head->sp.ctx->_id, castLibID), *head->sp.name);
+ script.byteOffsets = scriptContext->_functionByteOffsets[script.handlerId];
+ script.moviePath = movie->getArchive()->getPathName().toString();
+ script.handlerName = head->sp.ctx->_id ? Common::String::format("%d:%s", head->sp.ctx->_id, script.handlerId.c_str()) : script.handlerId;
+ setScriptToDisplay(script);
+}
+
+void showScripts() {
+ updateCurrentScript();
+
+ if (!_state->_functions._showScript)
+ return;
+
+ ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(240, 240), ImGuiCond_FirstUseEver);
+
+ if (ImGui::Begin("Script", &_state->_functions._showScript)) {
+ ImGui::BeginDisabled(_state->_functions._scripts.empty() || _state->_functions._current == 0);
+ if (ImGui::Button("\ue5c4")) { // Backward // arrow_back
+ _state->_functions._current--;
+ }
+ ImGui::EndDisabled();
+ ImGui::SetItemTooltip("Backward");
+ ImGui::SameLine();
+
+ ImGui::BeginDisabled(_state->_functions._current >= _state->_functions._scripts.size() - 1);
+ if (ImGui::Button("\ue5c8")) { // Forward // arrow_forward
+ _state->_functions._current++;
+ }
+ ImGui::EndDisabled();
+ ImGui::SetItemTooltip("Forward");
+ ImGui::SameLine();
+
+ const char *currentScript = nullptr;
+ if (_state->_functions._current < _state->_functions._scripts.size()) {
+ currentScript = _state->_functions._scripts[_state->_functions._current].handlerName.c_str();
+ }
+
+ if (ImGui::BeginCombo("##handlers", currentScript)) {
+ for (uint i = 0; i < _state->_functions._scripts.size(); i++) {
+ auto &script = _state->_functions._scripts[i];
+ bool selected = i == _state->_functions._current;
+ if (ImGui::Selectable(script.handlerName.c_str(), &selected)) {
+ _state->_functions._current = i;
+ }
+ }
+ ImGui::EndCombo();
+ }
+
+ if (!_state->_functions._scripts[_state->_functions._current].oldAst) {
+ ImGui::SameLine(0, 20);
+ toggleButton("\uf569", &_state->_functions._showByteCode, true); // Lingo // package_2
+ ImGui::SetItemTooltip("Lingo");
+ ImGui::SameLine();
+
+ toggleButton("\uf500", &_state->_functions._showByteCode); // Bytecode // stacks
+ ImGui::SetItemTooltip("Bytecode");
+ }
+
+ ImGui::Separator();
+ const ImVec2 childsize = ImGui::GetContentRegionAvail();
+ ImGui::BeginChild("##script", childsize);
+ ImGuiScript &script = _state->_functions._scripts[_state->_functions._current];
+ renderScript(script, _state->_functions._showByteCode);
+ ImGui::EndChild();
+ }
+ ImGui::End();
+}
+
+static Common::String getHandlerName(Symbol &sym) {
+ Common::String handlerName;
+
+ if (sym.ctx && sym.ctx->_id)
+ handlerName = Common::String::format("%d:", sym.ctx->_id);
+ handlerName += g_lingo->formatFunctionName(sym);
+
+ return handlerName;
+}
+
+void showFuncList() {
+ if (!_state->_w.funcList)
+ return;
+
+ ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(480, 240), ImGuiCond_FirstUseEver);
+ if (ImGui::Begin("Functions", &_state->_w.funcList)) {
+ _state->_functions._nameFilter.Draw();
+ ImGui::Separator();
+ const ImVec2 childSize = ImGui::GetContentRegionAvail();
+ ImGui::BeginChild("##functions", ImVec2(childSize.x, childSize.y));
+
+ if (ImGui::BeginTable("Functions", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+ ImGui::TableSetupColumn("Function", 0, 240.f);
+ ImGui::TableSetupColumn("Movie", 0, 60.f);
+ ImGui::TableSetupColumn("Cast", 0, 60.f);
+ ImGui::TableSetupColumn("Type", 0, 80.f);
+ ImGui::TableHeadersRow();
+
+ Movie *movie = g_director->getCurrentMovie();
+ for (auto &cast : *movie->getCasts()) {
+ for (int i = 0; i <= kMaxScriptType; i++) {
+ if (cast._value->_lingoArchive->scriptContexts[i].empty())
+ continue;
+ Common::String scriptType(scriptType2str((ScriptType)i));
+ for (auto &scriptContext : cast._value->_lingoArchive->scriptContexts[i]) {
+ Common::String name = Common::String::format("%d", scriptContext._key);
+ CastMemberInfo *cmi = cast._value->getCastMemberInfo(scriptContext._key);
+ if (cmi && !cmi->name.empty()) {
+ name += Common::String::format(" \"%s\"", cmi->name.c_str());
+ }
+ for (auto &functionHandler : scriptContext._value->_functionHandlers) {
+ Common::String function = Common::String::format("%s: %s", name.c_str(), g_lingo->formatFunctionName(functionHandler._value).c_str());
+ if (!_state->_functions._nameFilter.PassFilter(function.c_str()))
+ continue;
+
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn();
+ if (ImGui::Selectable(function.c_str())) {
+ CastMemberID memberID(scriptContext._key, cast._key);
+ ImGuiScript script = toImGuiScript(scriptContext._value->_scriptType, memberID, functionHandler._key);
+ script.byteOffsets = scriptContext._value->_functionByteOffsets[script.handlerId];
+ script.moviePath = movie->getArchive()->getPathName().toString();
+ script.handlerName = getHandlerName(functionHandler._value);
+ setScriptToDisplay(script);
+ }
+ ImGui::TableNextColumn();
+ ImGui::Text("%s", movie->getArchive()->getPathName().toString().c_str());
+ ImGui::TableNextColumn();
+ ImGui::Text("%d", cast._key);
+ ImGui::TableNextColumn();
+ ImGui::Text("%s", scriptType.c_str());
+ }
+ }
+ }
+ }
+
+ Cast *sharedCast = movie->getSharedCast();
+ if (sharedCast && sharedCast->_lingoArchive) {
+ for (int i = 0; i <= kMaxScriptType; i++) {
+ if (sharedCast->_lingoArchive->scriptContexts[i].empty())
+ continue;
+ Common::String scriptType(scriptType2str((ScriptType)i));
+ for (auto &scriptContext : sharedCast->_lingoArchive->scriptContexts[i]) {
+ Common::String name = Common::String::format("%d", scriptContext._key);
+ CastMemberInfo *cmi = sharedCast->getCastMemberInfo(scriptContext._key);
+ if (cmi && !cmi->name.empty()) {
+ name += Common::String::format(" \"%s\"", cmi->name.c_str());
+ }
+ for (auto &functionHandler : scriptContext._value->_functionHandlers) {
+ Common::String function = Common::String::format("%s: %s", name.c_str(), g_lingo->formatFunctionName(functionHandler._value).c_str());
+ if (!_state->_functions._nameFilter.PassFilter(function.c_str()))
+ continue;
+
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn();
+ if (ImGui::Selectable(function.c_str())) {
+ CastMemberID memberID(scriptContext._key, SHARED_CAST_LIB);
+ ImGuiScript script = toImGuiScript(scriptContext._value->_scriptType, memberID, functionHandler._key);
+ script.byteOffsets = scriptContext._value->_functionByteOffsets[script.handlerId];
+ script.moviePath = movie->getArchive()->getPathName().toString();
+ script.handlerName = getHandlerName(functionHandler._value);
+ setScriptToDisplay(script);
+ }
+ ImGui::TableNextColumn();
+ ImGui::Text("%s", movie->getArchive()->getPathName().toString().c_str());
+ ImGui::TableNextColumn();
+ ImGui::Text("SHARED");
+ ImGui::TableNextColumn();
+ ImGui::Text("%s", scriptType.c_str());
+ }
+ }
+ }
+ }
+ ImGui::EndTable();
+ }
+ ImGui::EndChild();
+ }
+ ImGui::End();
+}
+
+} // namespace DT
+} // namespace Director
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 9972214571f..1f6dc67868e 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -163,7 +163,8 @@ MODULE_OBJS += \
debugger/dt-logger.o \
debugger/dt-score.o \
debugger/dt-script-d2.o \
- debugger/dt-script-d4.o
+ debugger/dt-script-d4.o \
+ debugger/dt-scripts.o
endif
Commit: 55eeb64759c3e00a07e578a8399c189a41c2c441
https://github.com/scummvm/scummvm/commit/55eeb64759c3e00a07e578a8399c189a41c2c441
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-06-01T20:44:01+02:00
Commit Message:
DIRECTOR: DT: Move Cast window to dt-cast.cpp
Changed paths:
A engines/director/debugger/dt-cast.cpp
engines/director/debugger/debugtools.cpp
engines/director/debugger/dt-internal.h
engines/director/module.mk
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 9fc16ccab80..233bbd42b6e 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -26,8 +26,6 @@
#include "director/lingo/lingodec/script.h"
#include "director/cast.h"
#include "director/castmember/bitmap.h"
-#include "director/castmember/text.h"
-#include "director/castmember/script.h"
#include "director/debugger.h"
#include "director/movie.h"
#include "director/picture.h"
@@ -169,66 +167,6 @@ static GLuint loadTextureFromSurface(Graphics::Surface *surface, const byte *pal
return image_texture;
}
-static const char *toString(ScriptType scriptType) {
- static const char *scriptTypes[] = {
- "Score",
- "Cast",
- "Movie",
- "Event",
- "Test",
- "???",
- "???",
- "Parent",
- };
- if (scriptType < 0 || scriptType > kMaxScriptType)
- return "???";
- return scriptTypes[(int)scriptType];
-}
-
-static const char *toIcon(CastType castType) {
- static const char *castTypes[] = {
- "", // Empty
- "\uf79e", // Bitmap // backround_dot_large
- "\ue8da", // FilmLoop // theaters
- "\uf6f1", // Text // match_case
- "\ue40a", // Palette // palette
- "\uefa2", // Picture // imagesmode
- "\ue050", // Sound // volume_up
- "\uf4ab", // Button // slab_serif
- "\ue602", // Shape // shapes
- "\ue02c", // Movie // movie
- "\uf49a", // DigitalVideo // animated_images
- "\uf0c8", // Script // forms_apps_script
- "\uf4f1", // RTE // brand_family
- "?", // ???
- "\uf50c"}; // Transition // transition_fade
- if (castType < 0 || castType > kCastTransition)
- return "";
- return castTypes[(int)castType];
-}
-
-static const char *toString(CastType castType) {
- static const char *castTypes[] = {
- "Empty",
- "Bitmap",
- "FilmLoop",
- "Text",
- "Palette",
- "Picture",
- "Sound",
- "Button",
- "Shape",
- "Movie",
- "DigitalVideo",
- "Script",
- "RTE",
- "???",
- "Transition"};
- if (castType < 0 || castType > kCastTransition)
- return "???";
- return castTypes[(int)castType];
-}
-
ImGuiImage getImageID(CastMember *castMember) {
if (castMember->_type != CastType::kCastBitmap)
return {};
@@ -277,175 +215,6 @@ void showImage(const ImGuiImage &image, const char *name, float thumbnailSize) {
setToolTipImage(image, name);
}
-Common::String getDisplayName(CastMember *castMember) {
- const CastMemberInfo *castMemberInfo = castMember->getInfo();
- Common::String name(castMemberInfo ? castMemberInfo->name : "");
- if (!name.empty())
- return name;
- if (castMember->_type == kCastText) {
- TextCastMember *textCastMember = (TextCastMember *)castMember;
- return textCastMember->getText();
- }
- return Common::String::format("%u", castMember->getID());
-}
-
-static void showCast() {
- if (!_state->_w.cast)
- return;
-
- ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
- ImGui::SetNextWindowSize(ImVec2(520, 240), ImGuiCond_FirstUseEver);
-
- if (ImGui::Begin("Cast", &_state->_w.cast)) {
- // display a toolbar with: grid/list/filters buttons + name filter
- toggleButton("\ue896", &_state->_cast._listView); // list
- ImGui::SetItemTooltip("List");
- ImGui::SameLine();
- toggleButton("\ue9b0", &_state->_cast._listView, true); // grid_view
- ImGui::SetItemTooltip("Grid");
- ImGui::SameLine();
-
- if (ImGui::Button("\uef4f")) { // filter_alt
- ImGui::OpenPopup("filters_popup");
- }
- ImGui::SameLine();
-
- if (ImGui::BeginPopup("filters_popup")) {
- ImGui::CheckboxFlags("All", &_state->_cast._typeFilter, 0x7FFF);
- ImGui::Separator();
- for (int i = 0; i <= 14; i++) {
- ImGui::PushID(i);
- Common::String option(Common::String::format("%s %s", toIcon((CastType)i), toString((CastType)i)));
- ImGui::CheckboxFlags(option.c_str(), &_state->_cast._typeFilter, 1 << i);
- ImGui::PopID();
- }
- ImGui::EndPopup();
- }
- _state->_cast._nameFilter.Draw();
- ImGui::Separator();
-
- // display a list or a grid
- const float sliderHeight = _state->_cast._listView ? 0.f : 38.f;
- const ImVec2 childsize = ImGui::GetContentRegionAvail();
- Movie *movie = g_director->getCurrentMovie();
- ImGui::BeginChild("##cast", ImVec2(childsize.x, childsize.y - sliderHeight));
- if (_state->_cast._listView) {
- if (ImGui::BeginTable("Resources", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
- ImGui::TableSetupColumn("Name", 0, 120.f);
- ImGui::TableSetupColumn("#", 0, 20.f);
- ImGui::TableSetupColumn("Script", 0, 80.f);
- ImGui::TableSetupColumn("Type", 0, 80.f);
- ImGui::TableSetupColumn("Preview", 0, 32.f);
- ImGui::TableHeadersRow();
-
- for (auto it : *movie->getCasts()) {
- Cast *cast = it._value;
- if (!cast->_loadedCast)
- continue;
-
- for (auto castMember : *cast->_loadedCast) {
- if (!castMember._value->isLoaded())
- continue;
-
- Common::String name(getDisplayName(castMember._value));
- if (!_state->_cast._nameFilter.PassFilter(name.c_str()))
- continue;
- if ((castMember._value->_type != kCastTypeAny) && !(_state->_cast._typeFilter & (1 << (int)castMember._value->_type)))
- continue;
-
- ImGui::TableNextRow();
- ImGui::TableNextColumn();
- ImGui::Text("%s %s", toIcon(castMember._value->_type), name.c_str());
-
- ImGui::TableNextColumn();
- ImGui::Text("%d", castMember._key);
-
- ImGui::TableNextColumn();
- if (castMember._value->_type == CastType::kCastLingoScript) {
- ScriptCastMember *scriptMember = (ScriptCastMember *)castMember._value;
- ImGui::Text("%s", toString(scriptMember->_scriptType));
- }
- ImGui::TableNextColumn();
- ImGui::Text("%s", toString(castMember._value->_type));
-
- ImGui::TableNextColumn();
- ImGuiImage imgID = getImageID(castMember._value);
- if (imgID.id) {
- showImage(imgID, name.c_str(), 32.f);
- }
- }
- }
-
- ImGui::EndTable();
- }
- } else {
- const float thumbnailSize = (float)_state->_cast._thumbnailSize;
- const float contentWidth = ImGui::GetContentRegionAvail().x;
- int columns = contentWidth / (thumbnailSize + 8.f);
- columns = columns < 1 ? 1 : columns;
- if (ImGui::BeginTable("Cast", columns)) {
- for (auto it : *movie->getCasts()) {
- const Cast *cast = it._value;
- if (!cast->_loadedCast)
- continue;
-
- for (auto castMember : *cast->_loadedCast) {
- if (!castMember._value->isLoaded())
- continue;
-
- Common::String name(getDisplayName(castMember._value));
- if (!_state->_cast._nameFilter.PassFilter(name.c_str()))
- continue;
- if ((castMember._value->_type != kCastTypeAny) && !(_state->_cast._typeFilter & (1 << (int)castMember._value->_type)))
- continue;
-
- ImGui::TableNextColumn();
-
- ImGui::BeginGroup();
- const ImVec2 textSize = ImGui::CalcTextSize(name.c_str());
- float textWidth = textSize.x;
- float textHeight = textSize.y;
- if (textWidth > thumbnailSize) {
- textWidth = thumbnailSize;
- textHeight *= (textSize.x / textWidth);
- }
-
- ImGuiImage imgID = getImageID(castMember._value);
- if (imgID.id) {
- showImage(imgID, name.c_str(), thumbnailSize);
- } else {
- ImGui::PushID(castMember._key);
- ImGui::InvisibleButton("##canvas", ImVec2(thumbnailSize, thumbnailSize));
- ImGui::PopID();
- const ImVec2 p0 = ImGui::GetItemRectMin();
- const ImVec2 p1 = ImGui::GetItemRectMax();
- ImGui::PushClipRect(p0, p1, true);
- ImDrawList *draw_list = ImGui::GetWindowDrawList();
- draw_list->AddRect(p0, p1, IM_COL32_WHITE);
- const ImVec2 pos = p0 + ImVec2((thumbnailSize - textWidth) * 0.5f, (thumbnailSize - textHeight) * 0.5f);
- draw_list->AddText(nullptr, 0.f, pos, IM_COL32_WHITE, name.c_str(), 0, thumbnailSize);
- draw_list->AddText(nullptr, 0.f, p1 - ImVec2(16, 16), IM_COL32_WHITE, toIcon(castMember._value->_type));
- ImGui::PopClipRect();
- }
- ImGui::EndGroup();
- }
- }
- ImGui::EndTable();
- }
- }
- ImGui::EndChild();
-
- // in the footer display a slider for the grid view: thumbnail size
- if (!_state->_cast._listView) {
- ImGui::Spacing();
- ImGui::Separator();
- ImGui::Spacing();
- ImGui::SliderInt("Thumbnail Size", &_state->_cast._thumbnailSize, 32, 256);
- }
- }
- ImGui::End();
-}
-
static void displayVariable(const Common::String &name) {
const ImU32 var_color = ImGui::GetColorU32(ImVec4(0.9f, 0.9f, 0.0f, 1.0f));
diff --git a/engines/director/debugger/dt-cast.cpp b/engines/director/debugger/dt-cast.cpp
new file mode 100644
index 00000000000..f7cc43a8c64
--- /dev/null
+++ b/engines/director/debugger/dt-cast.cpp
@@ -0,0 +1,265 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "director/director.h"
+#include "director/debugger/dt-internal.h"
+
+#include "director/cast.h"
+#include "director/castmember/bitmap.h"
+#include "director/castmember/text.h"
+#include "director/castmember/script.h"
+#include "director/movie.h"
+#include "director/types.h"
+
+namespace Director {
+namespace DT {
+
+static const char *toString(ScriptType scriptType) {
+ static const char *scriptTypes[] = {
+ "Score",
+ "Cast",
+ "Movie",
+ "Event",
+ "Test",
+ "???",
+ "???",
+ "Parent",
+ };
+ if (scriptType < 0 || scriptType > kMaxScriptType)
+ return "???";
+ return scriptTypes[(int)scriptType];
+}
+
+static const char *toIcon(CastType castType) {
+ static const char *castTypes[] = {
+ "", // Empty
+ "\uf79e", // Bitmap // backround_dot_large
+ "\ue8da", // FilmLoop // theaters
+ "\uf6f1", // Text // match_case
+ "\ue40a", // Palette // palette
+ "\uefa2", // Picture // imagesmode
+ "\ue050", // Sound // volume_up
+ "\uf4ab", // Button // slab_serif
+ "\ue602", // Shape // shapes
+ "\ue02c", // Movie // movie
+ "\uf49a", // DigitalVideo // animated_images
+ "\uf0c8", // Script // forms_apps_script
+ "\uf4f1", // RTE // brand_family
+ "?", // ???
+ "\uf50c"}; // Transition // transition_fade
+ if (castType < 0 || castType > kCastTransition)
+ return "";
+ return castTypes[(int)castType];
+}
+
+const char *toString(CastType castType) {
+ static const char *castTypes[] = {
+ "Empty",
+ "Bitmap",
+ "FilmLoop",
+ "Text",
+ "Palette",
+ "Picture",
+ "Sound",
+ "Button",
+ "Shape",
+ "Movie",
+ "DigitalVideo",
+ "Script",
+ "RTE",
+ "???",
+ "Transition"};
+ if (castType < 0 || castType > kCastTransition)
+ return "???";
+ return castTypes[(int)castType];
+}
+
+Common::String getDisplayName(CastMember *castMember) {
+ const CastMemberInfo *castMemberInfo = castMember->getInfo();
+ Common::String name(castMemberInfo ? castMemberInfo->name : "");
+ if (!name.empty())
+ return name;
+ if (castMember->_type == kCastText) {
+ TextCastMember *textCastMember = (TextCastMember *)castMember;
+ return textCastMember->getText();
+ }
+ return Common::String::format("%u", castMember->getID());
+}
+
+void showCast() {
+ if (!_state->_w.cast)
+ return;
+
+ ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(520, 240), ImGuiCond_FirstUseEver);
+
+ if (ImGui::Begin("Cast", &_state->_w.cast)) {
+ // display a toolbar with: grid/list/filters buttons + name filter
+ toggleButton("\ue896", &_state->_cast._listView); // list
+ ImGui::SetItemTooltip("List");
+ ImGui::SameLine();
+ toggleButton("\ue9b0", &_state->_cast._listView, true); // grid_view
+ ImGui::SetItemTooltip("Grid");
+ ImGui::SameLine();
+
+ if (ImGui::Button("\uef4f")) { // filter_alt
+ ImGui::OpenPopup("filters_popup");
+ }
+ ImGui::SameLine();
+
+ if (ImGui::BeginPopup("filters_popup")) {
+ ImGui::CheckboxFlags("All", &_state->_cast._typeFilter, 0x7FFF);
+ ImGui::Separator();
+ for (int i = 0; i <= 14; i++) {
+ ImGui::PushID(i);
+ Common::String option(Common::String::format("%s %s", toIcon((CastType)i), toString((CastType)i)));
+ ImGui::CheckboxFlags(option.c_str(), &_state->_cast._typeFilter, 1 << i);
+ ImGui::PopID();
+ }
+ ImGui::EndPopup();
+ }
+ _state->_cast._nameFilter.Draw();
+ ImGui::Separator();
+
+ // display a list or a grid
+ const float sliderHeight = _state->_cast._listView ? 0.f : 38.f;
+ const ImVec2 childsize = ImGui::GetContentRegionAvail();
+ Movie *movie = g_director->getCurrentMovie();
+ ImGui::BeginChild("##cast", ImVec2(childsize.x, childsize.y - sliderHeight));
+ if (_state->_cast._listView) {
+ if (ImGui::BeginTable("Resources", 5, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+ ImGui::TableSetupColumn("Name", 0, 120.f);
+ ImGui::TableSetupColumn("#", 0, 20.f);
+ ImGui::TableSetupColumn("Script", 0, 80.f);
+ ImGui::TableSetupColumn("Type", 0, 80.f);
+ ImGui::TableSetupColumn("Preview", 0, 32.f);
+ ImGui::TableHeadersRow();
+
+ for (auto it : *movie->getCasts()) {
+ Cast *cast = it._value;
+ if (!cast->_loadedCast)
+ continue;
+
+ for (auto castMember : *cast->_loadedCast) {
+ if (!castMember._value->isLoaded())
+ continue;
+
+ Common::String name(getDisplayName(castMember._value));
+ if (!_state->_cast._nameFilter.PassFilter(name.c_str()))
+ continue;
+ if ((castMember._value->_type != kCastTypeAny) && !(_state->_cast._typeFilter & (1 << (int)castMember._value->_type)))
+ continue;
+
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn();
+ ImGui::Text("%s %s", toIcon(castMember._value->_type), name.c_str());
+
+ ImGui::TableNextColumn();
+ ImGui::Text("%d", castMember._key);
+
+ ImGui::TableNextColumn();
+ if (castMember._value->_type == CastType::kCastLingoScript) {
+ ScriptCastMember *scriptMember = (ScriptCastMember *)castMember._value;
+ ImGui::Text("%s", toString(scriptMember->_scriptType));
+ }
+ ImGui::TableNextColumn();
+ ImGui::Text("%s", toString(castMember._value->_type));
+
+ ImGui::TableNextColumn();
+ ImGuiImage imgID = getImageID(castMember._value);
+ if (imgID.id) {
+ showImage(imgID, name.c_str(), 32.f);
+ }
+ }
+ }
+
+ ImGui::EndTable();
+ }
+ } else {
+ const float thumbnailSize = (float)_state->_cast._thumbnailSize;
+ const float contentWidth = ImGui::GetContentRegionAvail().x;
+ int columns = contentWidth / (thumbnailSize + 8.f);
+ columns = columns < 1 ? 1 : columns;
+ if (ImGui::BeginTable("Cast", columns)) {
+ for (auto it : *movie->getCasts()) {
+ const Cast *cast = it._value;
+ if (!cast->_loadedCast)
+ continue;
+
+ for (auto castMember : *cast->_loadedCast) {
+ if (!castMember._value->isLoaded())
+ continue;
+
+ Common::String name(getDisplayName(castMember._value));
+ if (!_state->_cast._nameFilter.PassFilter(name.c_str()))
+ continue;
+ if ((castMember._value->_type != kCastTypeAny) && !(_state->_cast._typeFilter & (1 << (int)castMember._value->_type)))
+ continue;
+
+ ImGui::TableNextColumn();
+
+ ImGui::BeginGroup();
+ const ImVec2 textSize = ImGui::CalcTextSize(name.c_str());
+ float textWidth = textSize.x;
+ float textHeight = textSize.y;
+ if (textWidth > thumbnailSize) {
+ textWidth = thumbnailSize;
+ textHeight *= (textSize.x / textWidth);
+ }
+
+ ImGuiImage imgID = getImageID(castMember._value);
+ if (imgID.id) {
+ showImage(imgID, name.c_str(), thumbnailSize);
+ } else {
+ ImGui::PushID(castMember._key);
+ ImGui::InvisibleButton("##canvas", ImVec2(thumbnailSize, thumbnailSize));
+ ImGui::PopID();
+ const ImVec2 p0 = ImGui::GetItemRectMin();
+ const ImVec2 p1 = ImGui::GetItemRectMax();
+ ImGui::PushClipRect(p0, p1, true);
+ ImDrawList *draw_list = ImGui::GetWindowDrawList();
+ draw_list->AddRect(p0, p1, IM_COL32_WHITE);
+ const ImVec2 pos = p0 + ImVec2((thumbnailSize - textWidth) * 0.5f, (thumbnailSize - textHeight) * 0.5f);
+ draw_list->AddText(nullptr, 0.f, pos, IM_COL32_WHITE, name.c_str(), 0, thumbnailSize);
+ draw_list->AddText(nullptr, 0.f, p1 - ImVec2(16, 16), IM_COL32_WHITE, toIcon(castMember._value->_type));
+ ImGui::PopClipRect();
+ }
+ ImGui::EndGroup();
+ }
+ }
+ ImGui::EndTable();
+ }
+ }
+ ImGui::EndChild();
+
+ // in the footer display a slider for the grid view: thumbnail size
+ if (!_state->_cast._listView) {
+ ImGui::Spacing();
+ ImGui::Separator();
+ ImGui::Spacing();
+ ImGui::SliderInt("Thumbnail Size", &_state->_cast._thumbnailSize, 32, 256);
+ }
+ }
+ ImGui::End();
+}
+
+} // namespace DT
+} // namespace Director
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index c621b52bb5e..09c7b48a786 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -204,6 +204,7 @@ Common::String getDisplayName(CastMember *castMember);
void showImage(const ImGuiImage &image, const char *name, float thumbnailSize);
ImVec4 convertColor(uint32 color);
+void showCast(); // dt-cast.cpp
void showControlPanel(); // dt-controlpanel.cpp
void showScore(); // dt-score.cpp
void showChannels(); // dt-score.cpp
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 1f6dc67868e..dee347b0549 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -159,6 +159,7 @@ MODULE_OBJS = \
ifdef USE_IMGUI
MODULE_OBJS += \
debugger/debugtools.o \
+ debugger/dt-cast.o \
debugger/dt-controlpanel.o \
debugger/dt-logger.o \
debugger/dt-score.o \
More information about the Scummvm-git-logs
mailing list