[Scummvm-git-logs] scummvm master -> b15e46d55c57b9c6016d842f5029110688c6b12a

sev- noreply at scummvm.org
Fri Aug 22 08:13:47 UTC 2025


This automated email contains information about 8 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
97113794f1 DIRECTOR: IMGUI: Sanity check context before accessing
eb7f968c95 DIRECTOR: IMGUI: Fix Execution Context navigation
436df3644b DIRECTOR: IMGUI: Fix Pop-up error message in `renderCastScript` window
d861260e08 DIRECTOR: IMGUI: Show functions in a separate window when clicked on
797533505a DIRECTOR: IMGUI: Add Script Context wise list to the Functions Window
c9874e2dc4 DIRECTOR: IMGUI: Rework the Functions window all handler list
297b892513 DIRECTOR: IMGUI: Make handlers in call stack Selectable for display
b15e46d55c DIRECTOR: ImGui: Set `byteOffsets` when `Go To Function` called


Commit: 97113794f127770b87e39c33d0b30e8510d4ff44
    https://github.com/scummvm/scummvm/commit/97113794f127770b87e39c33d0b30e8510d4ff44
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Sanity check context before accessing

Changed paths:
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index d73ca2b3878..95131815ec2 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -331,8 +331,11 @@ void showExecutionContext() {
 
 			// Get all the handlers from the script
 			ScriptContext* context = getScriptContext(current.id);
-			Common::String scriptInfo = Common::String::format("%d:%s type:%s", context->_id, context->getName().c_str(), scriptType2str(context->_scriptType));
-			ImGui::Text("%s", scriptInfo.c_str());
+
+			if (context) {
+				Common::String scriptInfo = Common::String::format("%d:%s type:%s", context->_id, context->getName().c_str(), scriptType2str(context->_scriptType));
+				ImGui::Text("%s", scriptInfo.c_str());
+			}
 
 			ImGui::BeginDisabled(scriptData->_scripts.empty() || scriptData->_current == 0);
 			if (ImGui::Button(ICON_MS_ARROW_BACK)) {
@@ -436,8 +439,11 @@ void showExecutionContext() {
 
 				// Get all the handlers from the script
 				ScriptContext* context = getScriptContext(current.id);
-				Common::String scriptInfo = Common::String::format("%d:%s type:%s", context->_id, context->getName().c_str(), scriptType2str(context->_scriptType));
-				ImGui::Text("%s", scriptInfo.c_str());
+
+				if (context) {
+					Common::String scriptInfo = Common::String::format("%d:%s type:%s", context->_id, context->getName().c_str(), scriptType2str(context->_scriptType));
+					ImGui::Text("%s", scriptInfo.c_str());
+				}
 
 				ImGui::BeginDisabled(scriptData->_scripts.empty() || scriptData->_current == 0);
 				if (ImGui::Button(ICON_MS_ARROW_BACK)) {


Commit: eb7f968c953b723b94aedd44b8cb42d7135184f4
    https://github.com/scummvm/scummvm/commit/eb7f968c953b723b94aedd44b8cb42d7135184f4
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Fix Execution Context navigation

Need to pass the current script by reference
Otherwise the `startOffsets` aren't stored
Also don't scroll to the current statement on every render
only scroll when the callstack level changes

Changed paths:
    engines/director/debugger/dt-controlpanel.cpp
    engines/director/debugger/dt-script-d2.cpp
    engines/director/debugger/dt-script-d4.cpp
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/dt-controlpanel.cpp b/engines/director/debugger/dt-controlpanel.cpp
index f2f1072578d..7be834a6823 100644
--- a/engines/director/debugger/dt-controlpanel.cpp
+++ b/engines/director/debugger/dt-controlpanel.cpp
@@ -69,6 +69,8 @@ static bool stepInShouldPauseDebugger() {
 		_state->_dbg._lastLinePC = line;
 		return true;
 	}
+
+	debug("I'm returning false for some reason, %d:%d", g_lingo->_state->callstack.size(), _state->_dbg._callstackSize);
 	return false;
 }
 
@@ -76,13 +78,13 @@ 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;
 	}
 
+	debug("I'm returning false for some reason, %d:%d", g_lingo->_state->callstack.size(), _state->_dbg._callstackSize);
 	return false;
 }
 
diff --git a/engines/director/debugger/dt-script-d2.cpp b/engines/director/debugger/dt-script-d2.cpp
index 1d632b57d50..fe440f62234 100644
--- a/engines/director/debugger/dt-script-d2.cpp
+++ b/engines/director/debugger/dt-script-d2.cpp
@@ -831,7 +831,7 @@ private:
 		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 && _scrollTo) {
+			if (_state->_dbg._isScriptDirty && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) {
 				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);
diff --git a/engines/director/debugger/dt-script-d4.cpp b/engines/director/debugger/dt-script-d4.cpp
index c83672049f0..8bd1114e258 100644
--- a/engines/director/debugger/dt-script-d4.cpp
+++ b/engines/director/debugger/dt-script-d4.cpp
@@ -1179,7 +1179,7 @@ private:
 		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 && _scrollTo) {
+			if (_state->_dbg._isScriptDirty && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) {
 				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);
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index 95131815ec2..c61d1fb7e7f 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -393,7 +393,8 @@ void showExecutionContext() {
 					script.byteOffsets = context->_functionByteOffsets[script.handlerId];
 					script.moviePath = movie->getArchive()->getPathName().toString();
 					script.handlerName = getHandlerName(functionHandler._value);
-					renderScript(script, scriptData->_showByteCode, script == current);
+					// Need to pass by reference in case of the current handler
+					renderScript(current == script ? current : script, scriptData->_showByteCode, script == current);
 					ImGui::NewLine();
 				}
 			}
@@ -501,7 +502,8 @@ void showExecutionContext() {
 						Movie *movie = g_director->getCurrentMovie();
 						script.moviePath = movie->getArchive()->getPathName().toString();
 						script.handlerName = getHandlerName(functionHandler._value);
-						renderScript(script, scriptData->_showByteCode, script == current);
+						// Need to pass by reference in case of the current handler
+						renderScript(current == script ? current : script, scriptData->_showByteCode, script == current);
 						ImGui::NewLine();
 					}
 				}


Commit: 436df3644b3d3fe6389dbae29334d6e8f12247e6
    https://github.com/scummvm/scummvm/commit/436df3644b3d3fe6389dbae29334d6e8f12247e6
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Fix Pop-up error message in `renderCastScript` window

Changed paths:
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index c61d1fb7e7f..d653dee99e7 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -66,6 +66,7 @@ static void renderCastScript(Symbol &sym) {
 		if (bp)
 			color = _state->_colors._bp_color_enabled;
 
+		ImGui::PushID(pc);
 		ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
 		if (ImGui::IsItemClicked(0)) {
 			if (bp) {
@@ -94,6 +95,7 @@ static void renderCastScript(Symbol &sym) {
 		ImGui::Text("[%5d] ", pc);
 		ImGui::SameLine();
 		ImGui::Text("%s", lingo->decodeInstruction(sym.u.defn, pc, &pc).c_str());
+		ImGui::PopID();
 	}
 }
 


Commit: d861260e08292e509057e29ed1472006e1a970db
    https://github.com/scummvm/scummvm/commit/d861260e08292e509057e29ed1472006e1a970db
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Show functions in a separate window when clicked on

Previously shown in Execution Context window
Also show all the handlers from the same script context

Changed paths:
    engines/director/debugger/debugtools.cpp
    engines/director/debugger/dt-internal.h
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 6c0b7350700..8a0cac6bcd8 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -534,6 +534,7 @@ void onImGuiRender() {
 
 	showScriptCasts();
 	showExecutionContext();
+	showHandlers();
 
 	showControlPanel();
 	showVars();
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index bf31d94ef50..630eab19164 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -166,6 +166,7 @@ typedef struct ImGuiState {
 	bool _wasHidden = false;
 
 	Common::List<CastMemberID> _scriptCasts;
+	Common::List<ImGuiScript> _openHandlers;
 	Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
 	int _prevFrame = -1;
 	struct {
@@ -229,6 +230,7 @@ void renderScriptAST(ImGuiScript &script, bool showByteCode, bool scrollTo);
 void showFuncList();
 void showScriptCasts();
 void showExecutionContext();
+void showHandlers();
 
 // dt-save-state.cpp
 void saveCurrentState();
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index d653dee99e7..155d98bbca6 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -159,6 +159,58 @@ void showScriptCasts() {
 	}
 }
 
+static void addToOpenHandlers(ImGuiScript handler) {
+	_state->_openHandlers.remove(handler);
+	_state->_openHandlers.push_back(handler);
+}
+
+static bool showHandler(ImGuiScript handler) {
+	ScriptContext *ctx = getScriptContext(handler.id);
+	Common::String wName(ctx->asString());
+
+	ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
+	ImGui::SetNextWindowSize(ImVec2(480, 540), ImGuiCond_FirstUseEver);
+
+	bool closed = true;
+
+	if (ImGui::Begin(wName.c_str(), &closed)) {
+		if (!ctx || ctx->_functionHandlers.size() <= 1) {
+			renderScript(handler, false, true);
+		} else {
+			for (auto &functionHandler : ctx->_functionHandlers) {
+				ImGuiScript script = toImGuiScript(ctx->_scriptType, handler.id, functionHandler._key);
+				script.byteOffsets = ctx->_functionByteOffsets[script.handlerId];
+				_state->_dbg._goToDefinition = true;
+				renderScript(script, false, script == handler);
+				ImGui::NewLine();
+			}
+		}
+	}
+	ImGui::End();
+
+	if (!closed)
+		return false;
+
+	return true;
+}
+
+/**
+ * Display all open handlers
+ */
+void showHandlers() {
+	if (_state->_openHandlers.empty()) {
+		return;
+	}
+
+	for (Common::List<ImGuiScript>::iterator handler = _state->_openHandlers.begin(); handler != _state->_openHandlers.end();) {
+		if (!showHandler(*handler)) {
+			handler = _state->_openHandlers.erase(handler);
+		} else {
+			handler++;
+		}
+	}
+}
+
 static void updateCurrentScript() {
 	if ((g_lingo->_exec._state != kPause) || !_state->_dbg._isScriptDirty)
 		return;
@@ -234,7 +286,8 @@ void showFuncList() {
 								script.byteOffsets = scriptContext._value->_functionByteOffsets[script.handlerId];
 								script.moviePath = movie->getArchive()->getPathName().toString();
 								script.handlerName = getHandlerName(functionHandler._value);
-								setScriptToDisplay(script);
+								addToOpenHandlers(script);
+								_state->_dbg._goToDefinition = true;
 							}
 							ImGui::TableNextColumn();
 							ImGui::Text("%s", movie->getArchive()->getPathName().toString().c_str());
@@ -272,7 +325,8 @@ void showFuncList() {
 								script.byteOffsets = scriptContext._value->_functionByteOffsets[script.handlerId];
 								script.moviePath = movie->getArchive()->getPathName().toString();
 								script.handlerName = getHandlerName(functionHandler._value);
-								setScriptToDisplay(script);
+								addToOpenHandlers(script);
+								_state->_dbg._goToDefinition = true;
 							}
 							ImGui::TableNextColumn();
 							ImGui::Text("%s", movie->getArchive()->getPathName().toString().c_str());


Commit: 797533505ae26df4b2fc0a8d0fa0851eb7f8b308
    https://github.com/scummvm/scummvm/commit/797533505ae26df4b2fc0a8d0fa0851eb7f8b308
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Add Script Context wise list to the Functions Window

This list will show all the handlers in a single 'Lscr' context
under one tree node

Changed paths:
    engines/director/debugger/dt-internal.h
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 630eab19164..39d4bbb3991 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -119,6 +119,7 @@ typedef struct ImGuiState {
 	} _cast;
 	struct {
 		ImGuiTextFilter _nameFilter;
+		bool _showScriptContexts;
 		Common::HashMap<Window *, ScriptData> _windowScriptData;
 	} _functions;
 
@@ -167,6 +168,8 @@ typedef struct ImGuiState {
 
 	Common::List<CastMemberID> _scriptCasts;
 	Common::List<ImGuiScript> _openHandlers;
+	bool _showCompleteScript = true;
+
 	Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
 	int _prevFrame = -1;
 	struct {
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index 155d98bbca6..e53eef72784 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -166,7 +166,12 @@ static void addToOpenHandlers(ImGuiScript handler) {
 
 static bool showHandler(ImGuiScript handler) {
 	ScriptContext *ctx = getScriptContext(handler.id);
-	Common::String wName(ctx->asString());
+	Common::String wName;
+	if (ctx) {
+		wName = Common::String(ctx->asString());
+	} else {
+		wName = Common::String();
+	}
 
 	ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
 	ImGui::SetNextWindowSize(ImVec2(480, 540), ImGuiCond_FirstUseEver);
@@ -174,13 +179,23 @@ static bool showHandler(ImGuiScript handler) {
 	bool closed = true;
 
 	if (ImGui::Begin(wName.c_str(), &closed)) {
-		if (!ctx || ctx->_functionHandlers.size() <= 1) {
+		ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &_state->_showCompleteScript, true); // Lingo
+		ImGui::SetItemTooltip("Show Handler");
+
+		ImGui::SameLine();
+		ImGuiEx::toggleButton(ICON_MS_STACKS, &_state->_showCompleteScript); // Bytecode
+		ImGui::SetItemTooltip("Show Script Context");
+
+		if (!ctx || ctx->_functionHandlers.size() <= 1 || !_state->_showCompleteScript) {
 			renderScript(handler, false, true);
 		} else {
 			for (auto &functionHandler : ctx->_functionHandlers) {
 				ImGuiScript script = toImGuiScript(ctx->_scriptType, handler.id, functionHandler._key);
 				script.byteOffsets = ctx->_functionByteOffsets[script.handlerId];
-				_state->_dbg._goToDefinition = true;
+
+				if (script == handler) {
+					_state->_dbg._goToDefinition = true;
+				}
 				renderScript(script, false, script == handler);
 				ImGui::NewLine();
 			}
@@ -247,98 +262,156 @@ void showFuncList() {
 		return;
 
 	ImGui::SetNextWindowPos(ImVec2(20, 20), ImGuiCond_FirstUseEver);
-	ImGui::SetNextWindowSize(ImVec2(480, 240), ImGuiCond_FirstUseEver);
+	ImGui::SetNextWindowSize(ImVec2(480, 640), ImGuiCond_FirstUseEver);
 	if (ImGui::Begin("Functions", &_state->_w.funcList)) {
 		_state->_functions._nameFilter.Draw();
 		ImGui::Separator();
+
+		// Show a script context wise handlers
+		ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &_state->_functions._showScriptContexts);
+		ImGui::SetItemTooltip("Script Contexts");
+
+		ImGui::SameLine();
+		// Show a list of all handlers
+		ImGuiEx::toggleButton(ICON_MS_STACKS, &_state->_functions._showScriptContexts, true);
+		ImGui::SetItemTooltip("All Handlers");
+
 		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());
+		Movie *movie = g_director->getCurrentMovie();
+		if (_state->_functions._showScriptContexts) {
+			if (ImGui::BeginTable("Functions", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+				ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 240.f);
+				ImGui::TableSetupColumn("Movie", 0, 60.f);
+				ImGui::TableSetupColumn("Cast", 0, 60.f);
+				ImGui::TableSetupColumn("Type", 0, 80.f);
+				ImGui::TableHeadersRow();
+
+				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);
+									addToOpenHandlers(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());
+							}
 						}
-						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);
-								addToOpenHandlers(script);
-								_state->_dbg._goToDefinition = true;
+					}
+				}
+
+				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);
+									addToOpenHandlers(script);
+									_state->_dbg._goToDefinition = true;
+								}
+								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::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());
 						}
 					}
 				}
+				ImGui::EndTable();
 			}
+		} else {
+			for (auto cast : *movie->getCasts()) {
+				Common::String castName = Common::String::format("%d", cast._key);
+				if (cast._value->getCastName().size()) {
+					castName += Common::String::format(": %s ", cast._value->getCastName().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());
+				if (ImGui::TreeNode(castName.c_str())) {
+					for (auto context : cast._value->_lingoArchive->lctxContexts) {
+						CastMemberInfo *cmi = cast._value->getCastMemberInfo(context._value->_id);
+						Common::String contextName = Common::String::format("%d", context._value->_id);
+						if (cmi && cmi->name.size()) {
+							contextName += 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);
-								addToOpenHandlers(script);
-								_state->_dbg._goToDefinition = true;
+
+						contextName += Common::String::format(": %s", scriptType2str(context._value->_scriptType));
+						if (!context._value || !context._value->_functionHandlers.size() || !_state->_functions._nameFilter.PassFilter(contextName.c_str())) {
+							continue;
+						}
+
+						ImGui::PushID(context._key);
+						if (ImGui::TreeNode(contextName.c_str())) {
+							if (ImGui::BeginTable("Functions", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+								ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 240.f);
+								for (auto &functionHandler : context._value->_functionHandlers) {
+									Common::String function = Common::String::format("%s", g_lingo->formatFunctionName(functionHandler._value).c_str());
+
+									ImGui::TableNextRow();
+									ImGui::TableNextColumn();
+									if (ImGui::Selectable(function.c_str())) {
+										CastMemberID memberID(cast._value->getCastIdByScriptId(context._key), cast._key);
+										ImGuiScript script = toImGuiScript(context._value->_scriptType, memberID, functionHandler._key);
+										script.byteOffsets = context._value->_functionByteOffsets[script.handlerId];
+										script.moviePath = movie->getArchive()->getPathName().toString();
+										script.handlerName = g_lingo->formatFunctionName(functionHandler._value);
+										addToOpenHandlers(script);
+									}
+								}
+								ImGui::EndTable();
 							}
-							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::TreePop();
 						}
+						ImGui::PopID();
 					}
+					ImGui::TreePop();
 				}
 			}
-			ImGui::EndTable();
 		}
 		ImGui::EndChild();
 	}


Commit: c9874e2dc4b2a127225bfd0d0303fc17610cfa16
    https://github.com/scummvm/scummvm/commit/c9874e2dc4b2a127225bfd0d0303fc17610cfa16
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Rework the Functions window all handler list

Change the way the function names are shown

Changed paths:
    engines/director/debugger/dt-internal.h
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 39d4bbb3991..f9c4e0474ce 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -119,7 +119,7 @@ typedef struct ImGuiState {
 	} _cast;
 	struct {
 		ImGuiTextFilter _nameFilter;
-		bool _showScriptContexts;
+		bool _showScriptContexts = true;
 		Common::HashMap<Window *, ScriptData> _windowScriptData;
 	} _functions;
 
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index e53eef72784..6c336ac6633 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -281,11 +281,104 @@ void showFuncList() {
 
 		Movie *movie = g_director->getCurrentMovie();
 		if (_state->_functions._showScriptContexts) {
-			if (ImGui::BeginTable("Functions", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
-				ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 240.f);
-				ImGui::TableSetupColumn("Movie", 0, 60.f);
-				ImGui::TableSetupColumn("Cast", 0, 60.f);
-				ImGui::TableSetupColumn("Type", 0, 80.f);
+			for (auto cast : *movie->getCasts()) {
+				Common::String castName = Common::String::format("%d", cast._key);
+				if (cast._value->getCastName().size()) {
+					castName += Common::String::format(": %s ", cast._value->getCastName().c_str());
+				}
+
+				if (ImGui::TreeNodeEx(castName.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
+					for (auto context : cast._value->_lingoArchive->lctxContexts) {
+						CastMemberInfo *cmi = cast._value->getCastMemberInfo(context._value->_id);
+						Common::String contextName = Common::String::format("%d", context._value->_id);
+						if (cmi && cmi->name.size()) {
+							contextName += Common::String::format(": %s", cmi->name.c_str());
+						}
+
+						contextName += Common::String::format(": %s", scriptType2str(context._value->_scriptType));
+						if (!context._value || !context._value->_functionHandlers.size() || !_state->_functions._nameFilter.PassFilter(contextName.c_str())) {
+							continue;
+						}
+
+						ImGui::PushID(context._key);
+						if (ImGui::TreeNode(contextName.c_str())) {
+							if (ImGui::BeginTable("Functions", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+								ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 240.f);
+								for (auto &functionHandler : context._value->_functionHandlers) {
+									Common::String function = Common::String::format("%s", g_lingo->formatFunctionName(functionHandler._value).c_str());
+
+									ImGui::TableNextRow();
+									ImGui::TableNextColumn();
+									if (ImGui::Selectable(function.c_str())) {
+										CastMemberID memberID(cast._value->getCastIdByScriptId(context._key), cast._key);
+										ImGuiScript script = toImGuiScript(context._value->_scriptType, memberID, functionHandler._key);
+										script.byteOffsets = context._value->_functionByteOffsets[script.handlerId];
+										script.moviePath = movie->getArchive()->getPathName().toString();
+										script.handlerName = g_lingo->formatFunctionName(functionHandler._value);
+										addToOpenHandlers(script);
+									}
+								}
+								ImGui::EndTable();
+							}
+							ImGui::TreePop();
+						}
+						ImGui::PopID();
+					}
+					ImGui::TreePop();
+				}
+			}
+
+			Cast *sharedCast = movie->getSharedCast();
+			if (sharedCast && sharedCast->_lingoArchive) {
+				Common::String castName = Common::String::format("%s", "SHARED");
+				if (sharedCast->getCastName().size()) {
+					castName += Common::String::format(": %s ", sharedCast->getCastName().c_str());
+				}
+
+				if (ImGui::TreeNode(castName.c_str())) {
+					for (auto context : sharedCast->_lingoArchive->lctxContexts) {
+						CastMemberInfo *cmi = sharedCast->getCastMemberInfo(context._value->_id);
+						Common::String contextName = Common::String::format("%d", context._value->_id);
+						if (cmi && cmi->name.size()) {
+							contextName += Common::String::format(": %s", cmi->name.c_str());
+						}
+
+						contextName += Common::String::format(": %s", scriptType2str(context._value->_scriptType));
+						if (!context._value || !context._value->_functionHandlers.size() || !_state->_functions._nameFilter.PassFilter(contextName.c_str())) {
+							continue;
+						}
+
+						ImGui::PushID(context._key);
+						if (ImGui::TreeNode(contextName.c_str())) {
+							if (ImGui::BeginTable("Functions", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+								ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 240.f);
+								for (auto &functionHandler : context._value->_functionHandlers) {
+									Common::String function = Common::String::format("%s", g_lingo->formatFunctionName(functionHandler._value).c_str());
+
+									ImGui::TableNextRow();
+									ImGui::TableNextColumn();
+									if (ImGui::Selectable(function.c_str())) {
+										CastMemberID memberID(sharedCast->getCastIdByScriptId(context._key), SHARED_CAST_LIB);
+										ImGuiScript script = toImGuiScript(context._value->_scriptType, memberID, functionHandler._key);
+										script.byteOffsets = context._value->_functionByteOffsets[script.handlerId];
+										script.moviePath = movie->getArchive()->getPathName().toString();
+										script.handlerName = g_lingo->formatFunctionName(functionHandler._value);
+										addToOpenHandlers(script);
+									}
+								}
+								ImGui::EndTable();
+							}
+							ImGui::TreePop();
+						}
+						ImGui::PopID();
+					}
+					ImGui::TreePop();
+				}
+			}
+		} else {
+			if (ImGui::BeginTable("Functions", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
+				ImGui::TableSetupColumn("Function", 0, 240.f);
+				ImGui::TableSetupColumn("Cast Name", ImGuiTableColumnFlags_WidthStretch, 240.f);
 				ImGui::TableHeadersRow();
 
 				for (auto &cast : *movie->getCasts()) {
@@ -296,11 +389,13 @@ void showFuncList() {
 						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());
-							}
+							CastMember *castMember = cast._value->getCastMember(scriptContext._key);
+
 							for (auto &functionHandler : scriptContext._value->_functionHandlers) {
-								Common::String function = Common::String::format("%s: %s", name.c_str(), g_lingo->formatFunctionName(functionHandler._value).c_str());
+								Common::String function = Common::String::format("%s-%s (%d lib %d)",
+									castMember ? castType2str(castMember->_type) : "any", g_lingo->formatFunctionName(functionHandler._value).c_str(),
+									scriptContext._key, cast._key
+								);
 								if (!_state->_functions._nameFilter.PassFilter(function.c_str()))
 									continue;
 
@@ -314,12 +409,9 @@ void showFuncList() {
 									script.handlerName = getHandlerName(functionHandler._value);
 									addToOpenHandlers(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());
+								ImGui::Text("%s", (cmi && cmi->name.size()) ? cmi->name.c_str() : "unnamed");
 							}
 						}
 					}
@@ -334,11 +426,13 @@ void showFuncList() {
 						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());
-							}
+							CastMember *castMember = sharedCast->getCastMember(scriptContext._key);
+
 							for (auto &functionHandler : scriptContext._value->_functionHandlers) {
-								Common::String function = Common::String::format("%s: %s", name.c_str(), g_lingo->formatFunctionName(functionHandler._value).c_str());
+								Common::String function = Common::String::format("%s-%s (%d lib %d)",
+									castMember ? castType2str(castMember->_type) : "any", g_lingo->formatFunctionName(functionHandler._value).c_str(),
+									scriptContext._key, SHARED_CAST_LIB
+								);
 								if (!_state->_functions._nameFilter.PassFilter(function.c_str()))
 									continue;
 
@@ -351,67 +445,16 @@ void showFuncList() {
 									script.moviePath = movie->getArchive()->getPathName().toString();
 									script.handlerName = getHandlerName(functionHandler._value);
 									addToOpenHandlers(script);
-									_state->_dbg._goToDefinition = true;
 								}
+
 								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::Text("%s", (cmi && cmi->name.size()) ? cmi->name.c_str() : "unnamed");
 							}
 						}
 					}
 				}
 				ImGui::EndTable();
 			}
-		} else {
-			for (auto cast : *movie->getCasts()) {
-				Common::String castName = Common::String::format("%d", cast._key);
-				if (cast._value->getCastName().size()) {
-					castName += Common::String::format(": %s ", cast._value->getCastName().c_str());
-				}
-
-				if (ImGui::TreeNode(castName.c_str())) {
-					for (auto context : cast._value->_lingoArchive->lctxContexts) {
-						CastMemberInfo *cmi = cast._value->getCastMemberInfo(context._value->_id);
-						Common::String contextName = Common::String::format("%d", context._value->_id);
-						if (cmi && cmi->name.size()) {
-							contextName += Common::String::format(": %s", cmi->name.c_str());
-						}
-
-						contextName += Common::String::format(": %s", scriptType2str(context._value->_scriptType));
-						if (!context._value || !context._value->_functionHandlers.size() || !_state->_functions._nameFilter.PassFilter(contextName.c_str())) {
-							continue;
-						}
-
-						ImGui::PushID(context._key);
-						if (ImGui::TreeNode(contextName.c_str())) {
-							if (ImGui::BeginTable("Functions", 1, ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg)) {
-								ImGui::TableSetupColumn("Function", ImGuiTableColumnFlags_WidthStretch, 240.f);
-								for (auto &functionHandler : context._value->_functionHandlers) {
-									Common::String function = Common::String::format("%s", g_lingo->formatFunctionName(functionHandler._value).c_str());
-
-									ImGui::TableNextRow();
-									ImGui::TableNextColumn();
-									if (ImGui::Selectable(function.c_str())) {
-										CastMemberID memberID(cast._value->getCastIdByScriptId(context._key), cast._key);
-										ImGuiScript script = toImGuiScript(context._value->_scriptType, memberID, functionHandler._key);
-										script.byteOffsets = context._value->_functionByteOffsets[script.handlerId];
-										script.moviePath = movie->getArchive()->getPathName().toString();
-										script.handlerName = g_lingo->formatFunctionName(functionHandler._value);
-										addToOpenHandlers(script);
-									}
-								}
-								ImGui::EndTable();
-							}
-							ImGui::TreePop();
-						}
-						ImGui::PopID();
-					}
-					ImGui::TreePop();
-				}
-			}
 		}
 		ImGui::EndChild();
 	}


Commit: 297b892513f35d03b1559f52b26f108a0166144f
    https://github.com/scummvm/scummvm/commit/297b892513f35d03b1559f52b26f108a0166144f
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: IMGUI: Make handlers in call stack Selectable for display

Pressing on it will display the script down in the Scripts window

Changed paths:
    engines/director/debugger/dt-internal.h
    engines/director/debugger/dt-script-d2.cpp
    engines/director/debugger/dt-script-d4.cpp
    engines/director/debugger/dt-scripts.cpp


diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index f9c4e0474ce..9540619c234 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -63,6 +63,7 @@ typedef struct ImGuiScript {
 	Common::String handlerName;
 	Common::String moviePath;
 	Common::Array<uint32> byteOffsets;
+	uint pc = 0;
 
 	bool isMethod = false;
 	bool isGenericEvent = false;
diff --git a/engines/director/debugger/dt-script-d2.cpp b/engines/director/debugger/dt-script-d2.cpp
index fe440f62234..e7d5cf276d3 100644
--- a/engines/director/debugger/dt-script-d2.cpp
+++ b/engines/director/debugger/dt-script-d2.cpp
@@ -39,6 +39,7 @@ private:
 	bool _isScriptInDebug = false;
 	bool _currentStatementDisplayed = false;
 	bool _scrollTo = false;
+	bool _scrollDone = true;
 
 public:
 	explicit RenderOldScriptVisitor(ImGuiScript &script, bool scrollTo) : _script(script), _scrollTo(scrollTo) {
@@ -779,7 +780,12 @@ private:
 		bool showCurrentStatement = false;
 		_script.startOffsets.push_back(pc);
 
-		if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
+		if (_script.pc != 0 && pc >= _script.pc) {
+			if (!_currentStatementDisplayed) {
+				showCurrentStatement = true;
+				_currentStatementDisplayed = true;
+			}
+		} else if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
 			// check current statement
 			if (!_currentStatementDisplayed) {
 				if (g_lingo->_state->pc <= pc) {
@@ -831,8 +837,9 @@ private:
 		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 && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) {
+			if (!_scrollDone && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) {
 				ImGui::SetScrollHereY(0.5f);
+				_scrollDone = true;
 			}
 			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);
 		}
diff --git a/engines/director/debugger/dt-script-d4.cpp b/engines/director/debugger/dt-script-d4.cpp
index 8bd1114e258..6faea7005ae 100644
--- a/engines/director/debugger/dt-script-d4.cpp
+++ b/engines/director/debugger/dt-script-d4.cpp
@@ -1122,7 +1122,12 @@ private:
 		uint pc = _script.byteOffsets[p];
 		_script.startOffsets.push_back(pc);
 
-		if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
+		if (_script.pc != 0 && pc >= _script.pc) {
+			if (!_currentStatementDisplayed) {
+				showCurrentStatement = true;
+				_currentStatementDisplayed = true;
+			}
+		} else if (_isScriptInDebug && g_lingo->_exec._state == kPause) {
 			// check current statement
 			if (!_currentStatementDisplayed) {
 				if (g_lingo->_state->pc <= pc) {
@@ -1179,8 +1184,9 @@ private:
 		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 && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) {
+			if (!_scrollDone && _scrollTo && g_lingo->_state->callstack.size() != _state->_dbg._callstackSize) {
 				ImGui::SetScrollHereY(0.5f);
+				_scrollDone = true;
 			}
 			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);
 		}
@@ -1228,6 +1234,7 @@ private:
 	bool _isScriptInDebug = false;
 	int _renderLineID = 1;
 	bool _scrollTo = false;
+	bool _scrollDone = false;
 };
 
 void renderScriptAST(ImGuiScript &script, bool showByteCode, bool scrollTo) {
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index 6c336ac6633..3a6ef326e59 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -111,6 +111,54 @@ static void renderScript(ImGuiScript &script, bool showByteCode, bool scrollTo)
 	renderScriptAST(script, showByteCode, scrollTo);
 }
 
+static void renderCallStack(uint pc) {
+	Common::Array<CFrame *> callstack = g_lingo->_state->callstack;
+	if (callstack.size() == 0) {
+		ImGui::Text("End of execution\n");
+		return;
+	}
+
+	ImGui::Text("Call stack:\n");
+	for (int i = 0; i < (int)callstack.size(); i++) {
+		Common::String stackFrame;
+		CFrame *frame = callstack[callstack.size() - i - 1];
+		uint framePc = pc;
+		if (i > 0)
+			framePc = callstack[callstack.size() - i]->retPC;
+
+		if (frame->sp.type != VOIDSYM) {
+			stackFrame = Common::String::format("#%d ", i);
+			if (frame->sp.ctx && frame->sp.ctx->_id) {
+				stackFrame += Common::String::format("%d:", frame->sp.ctx->_id);
+			}
+			if (frame->sp.ctx && frame->sp.ctx->isFactory()) {
+				stackFrame += Common::String::format("%s:", frame->sp.ctx->getName().c_str());
+			}
+			stackFrame += Common::String::format("%s at [%5d]\n",
+				frame->sp.name->c_str(),
+				framePc
+			);
+		} else {
+			stackFrame = Common::String::format("#%d [unknown] at [%5d]\n", i,
+				framePc
+			);
+		}
+
+		if (ImGui::Selectable(stackFrame.c_str())) {
+			Director::Movie *movie = g_director->getCurrentMovie();
+			CFrame *head = callstack[callstack.size() - i - 1];
+			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 = head->sp.ctx->_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;
+			script.pc = framePc;
+			setScriptToDisplay(script);
+		}
+	}
+}
+
 static bool showScriptCast(CastMemberID &id) {
 	Common::String wName("Script ");
 	wName += id.asString();
@@ -230,7 +278,6 @@ 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;
@@ -244,6 +291,7 @@ static void updateCurrentScript() {
 	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;
+	script.pc = 0;
 	setScriptToDisplay(script);
 }
 
@@ -490,7 +538,7 @@ void showExecutionContext() {
 		ImVec2 childSize = ImGui::GetContentRegionAvail();
 		childSize.y /= 3;
 		ImGui::BeginChild("##backtrace", childSize);
-		ImGui::Text("%s", lingo->formatCallStack(lingo->_state->pc).c_str());
+		renderCallStack(lingo->_state->pc);
 		ImGui::EndChild();
 
 		ImGui::SeparatorText("Scripts");
@@ -561,12 +609,16 @@ void showExecutionContext() {
 			} else {
 				Movie *movie = g_director->getCurrentMovie();
 				for (auto &functionHandler : context->_functionHandlers) {
-					ImGuiScript script = toImGuiScript(context->_scriptType, current.id, functionHandler._key);
-					script.byteOffsets = context->_functionByteOffsets[script.handlerId];
-					script.moviePath = movie->getArchive()->getPathName().toString();
-					script.handlerName = getHandlerName(functionHandler._value);
-					// Need to pass by reference in case of the current handler
-					renderScript(current == script ? current : script, scriptData->_showByteCode, script == current);
+					if (current.handlerId == functionHandler._key) {
+						renderScript(current, scriptData->_showByteCode, true);
+					} else {
+						ImGuiScript script = toImGuiScript(context->_scriptType, current.id, functionHandler._key);
+						script.byteOffsets = context->_functionByteOffsets[script.handlerId];
+						script.moviePath = movie->getArchive()->getPathName().toString();
+						script.handlerName = getHandlerName(functionHandler._value);
+						// Need to pass by reference in case of the current handler
+						renderScript(script, scriptData->_showByteCode, false);
+					}
 					ImGui::NewLine();
 				}
 			}
@@ -600,7 +652,7 @@ void showExecutionContext() {
 			childSize = ImGui::GetContentRegionAvail();
 			childSize.y /= 3;
 			ImGui::BeginChild("##backtrace", childSize);
-			ImGui::Text("%s", lingo->formatCallStack(lingo->_state->pc).c_str());
+			renderCallStack(lingo->_state->pc);
 			ImGui::EndChild();
 
 			ImGui::SeparatorText("Scripts");
@@ -668,14 +720,18 @@ void showExecutionContext() {
 				if (!context || context->_functionHandlers.size() == 1) {
 					renderScript(current, scriptData->_showByteCode, true);
 				} else {
+					Movie *movie = g_director->getCurrentMovie();
 					for (auto &functionHandler : context->_functionHandlers) {
-						ImGuiScript script = toImGuiScript(context->_scriptType, current.id, functionHandler._key);
-						script.byteOffsets = context->_functionByteOffsets[script.handlerId];
-						Movie *movie = g_director->getCurrentMovie();
-						script.moviePath = movie->getArchive()->getPathName().toString();
-						script.handlerName = getHandlerName(functionHandler._value);
-						// Need to pass by reference in case of the current handler
-						renderScript(current == script ? current : script, scriptData->_showByteCode, script == current);
+						if (current.handlerId == functionHandler._key) {
+							renderScript(current, scriptData->_showByteCode, true);
+						} else {
+							ImGuiScript script = toImGuiScript(context->_scriptType, current.id, functionHandler._key);
+							script.byteOffsets = context->_functionByteOffsets[script.handlerId];
+							script.moviePath = movie->getArchive()->getPathName().toString();
+							script.handlerName = getHandlerName(functionHandler._value);
+							// Need to pass by reference in case of the current handler
+							renderScript(script, scriptData->_showByteCode, false);
+						}
 						ImGui::NewLine();
 					}
 				}


Commit: b15e46d55c57b9c6016d842f5029110688c6b12a
    https://github.com/scummvm/scummvm/commit/b15e46d55c57b9c6016d842f5029110688c6b12a
Author: Malhar (themalharbdv2046 at gmail.com)
Date: 2025-08-22T10:13:40+02:00

Commit Message:
DIRECTOR: ImGui: Set `byteOffsets` when `Go To Function` called

Solves a segmentation fault caused by accessing `byteOffsets` array
which wasn't being set when called `Go To Function` in Script window
Had to rewrite `getCastIdFromScriptId` to fetch context instead of
only castId

Changed paths:
    engines/director/debugger/debugtools.cpp
    engines/director/debugger/dt-controlpanel.cpp
    engines/director/debugger/dt-internal.h
    engines/director/debugger/dt-script-d2.cpp
    engines/director/debugger/dt-script-d4.cpp


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 8a0cac6bcd8..1f7cee04839 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -127,22 +127,22 @@ ScriptContext *getScriptContext(CastMemberID id) {
 	return ctx;
 }
 
-int16 getCastIdFromScriptNameIndex(uint32 nameIndex, CastMemberID id, Common::String handlerName) {
+ScriptContext *getScriptContext(uint32 nameIndex, CastMemberID id, Common::String handlerName) {
 	Movie *movie = g_director->getCurrentMovie();
 	Cast *cast = movie->getCasts()->getVal(id.castLib);
 
-	// If the name at nameIndex is not the same as handler name, means its a local script
-	if (cast->_lingoArchive->names[nameIndex] != handlerName) {
-		return id.member;
+	// If the name at nameIndex is not the same as handler name, means its a local script (in the same Lscr resource)
+	if (cast && cast->_lingoArchive->names[nameIndex] != handlerName) {
+		return cast->_lingoArchive->findScriptContext(id.member);
 	}
 
 	for (auto it : cast->_lingoArchive->scriptContexts[kMovieScript]) {
 		if (it._value->_functionHandlers.contains(handlerName)) {
-			return it._key;
+			return it._value;
 		}
 	}
 
-	return -1;
+	return nullptr;
 }
 
 Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 scriptId, uint pc) {
diff --git a/engines/director/debugger/dt-controlpanel.cpp b/engines/director/debugger/dt-controlpanel.cpp
index 7be834a6823..8f1afdeba67 100644
--- a/engines/director/debugger/dt-controlpanel.cpp
+++ b/engines/director/debugger/dt-controlpanel.cpp
@@ -70,7 +70,6 @@ static bool stepInShouldPauseDebugger() {
 		return true;
 	}
 
-	debug("I'm returning false for some reason, %d:%d", g_lingo->_state->callstack.size(), _state->_dbg._callstackSize);
 	return false;
 }
 
@@ -84,7 +83,6 @@ static bool stepOutShouldPause() {
 		return true;
 	}
 
-	debug("I'm returning false for some reason, %d:%d", g_lingo->_state->callstack.size(), _state->_dbg._callstackSize);
 	return false;
 }
 
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 9540619c234..517ad9dce14 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -202,7 +202,7 @@ typedef struct ImGuiState {
 // debugtools.cpp
 ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::String &handlerId);
 ScriptContext *getScriptContext(CastMemberID id);
-int16 getCastIdFromScriptNameIndex(uint32 nameIndex, CastMemberID castId, Common::String handler);
+ScriptContext *getScriptContext(uint32 nameIndex, CastMemberID castId, Common::String handler);
 void setScriptToDisplay(const ImGuiScript &script);
 Director::Breakpoint *getBreakpoint(const Common::String &handlerName, uint16 scriptId, uint pc);
 void displayScriptRef(CastMemberID &scriptId);
diff --git a/engines/director/debugger/dt-script-d2.cpp b/engines/director/debugger/dt-script-d2.cpp
index e7d5cf276d3..dc4b2461a7b 100644
--- a/engines/director/debugger/dt-script-d2.cpp
+++ b/engines/director/debugger/dt-script-d2.cpp
@@ -503,8 +503,9 @@ public:
 				}
 			}
 
-			int16 castId = getCastIdFromScriptNameIndex(obj, _script.id, *node->name);
-			ImGuiScript script = toImGuiScript(_script.type, CastMemberID(castId, _script.id.castLib), *node->name);
+			ScriptContext *context = getScriptContext(obj, _script.id, *node->name);
+			ImGuiScript script = toImGuiScript(_script.type, CastMemberID(context->_id, _script.id.castLib), *node->name);
+			script.byteOffsets = context->_functionByteOffsets[script.handlerId];
 			script.moviePath = _script.moviePath;
 			script.handlerName = *node->name;
 			setScriptToDisplay(script);
diff --git a/engines/director/debugger/dt-script-d4.cpp b/engines/director/debugger/dt-script-d4.cpp
index 6faea7005ae..22933f73123 100644
--- a/engines/director/debugger/dt-script-d4.cpp
+++ b/engines/director/debugger/dt-script-d4.cpp
@@ -118,8 +118,9 @@ public:
 					break;
 				}
 			}
-			int16 castId = getCastIdFromScriptNameIndex(obj, _script.id, node.name);
-			ImGuiScript script = toImGuiScript(_script.type, CastMemberID(castId, _script.id.castLib), node.name);
+			ScriptContext *context = getScriptContext(obj, _script.id, node.name);
+			ImGuiScript script = toImGuiScript(_script.type, CastMemberID(context->_id, _script.id.castLib), node.name);
+			script.byteOffsets = context->_functionByteOffsets[script.handlerId];
 			script.moviePath = _script.moviePath;
 			script.handlerName = node.name;
 			setScriptToDisplay(script);




More information about the Scummvm-git-logs mailing list