[Scummvm-git-logs] scummvm master -> 7494441d8603f640fcb4d8fce63d5c15f4ab8200

sev- noreply at scummvm.org
Mon Jun 15 23:33:34 UTC 2026


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

Summary:
824b057902 DIRECTOR: DT: Improve cast details panel and unify script display
f318fc13ae DIRECTOR: DT: Add browser navigation to scripts window, decouple from execution context
7494441d86 DIRECTOR: DT: Add Ctrl+2/3/4 shortcuts for Control Panel, Cast, Score


Commit: 824b0579026a88879916d1c062973efb54b70cd3
    https://github.com/scummvm/scummvm/commit/824b0579026a88879916d1c062973efb54b70cd3
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-06-16T01:33:29+02:00

Commit Message:
DIRECTOR: DT: Improve cast details panel and unify script display

Show actual data in the cast details panel instead of placeholder ellipses.
scriptText displays as "(hover)" with a multiline tooltip preview; clicking
opens the script in the handlers window via addToOpenHandlers. modifiedBy and
comments show "N/A" when absent.

Removes the old showScriptCasts/addScriptCastToDisplay/renderCastScript
pipeline entirely. all script display now goes through renderScript. Fixes
a bug where the Lingo/Bytecode toggle in the script viewer was a single
global flag shared across all open handlers.

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


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index eac525112e0..e121297d662 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -524,11 +524,6 @@ ImVec4 convertColor(uint32 color) {
 	return ImGui::ColorConvertU32ToFloat4(color);
 }
 
-static void addScriptCastToDisplay(CastMemberID &id) {
-	_state->_scriptCasts.remove(id);
-	_state->_scriptCasts.push_back(id);
-}
-
 void addToOpenHandlers(ImGuiScript handler) {
 	_state->_openHandlers.erase(handler.id.member);
 	_state->_openHandlers[handler.id.member] = handler;
@@ -553,8 +548,19 @@ void displayScriptRef(CastMemberID &scriptId) {
 
 		ImGui::SetItemTooltip(scriptId.asString().c_str());
 
-		if (ImGui::IsItemClicked(0))
-			addScriptCastToDisplay(scriptId);
+		if (ImGui::IsItemClicked(0)) {
+			ScriptContext *ctx = getScriptContext(scriptId);
+			if (ctx) {
+				Common::String moviePath = g_director->getCurrentMovie()->getArchive()->getPathName().toString();
+				for (auto &handler : ctx->_functionHandlers) {
+					ImGuiScript script = toImGuiScript(ctx->_scriptType, scriptId, handler._key);
+					script.byteOffsets = ctx->_functionByteOffsets[script.handlerId];
+					script.moviePath = moviePath;
+					script.handlerName = formatHandlerName(ctx->_scriptId, scriptId.member, script.handlerId, ctx->_scriptType, false);
+					addToOpenHandlers(script);
+				}
+			}
+		}
 	} else {
 		ImGui::Selectable("  ");
 	}
@@ -934,7 +940,6 @@ void onImGuiRender() {
 		ImGui::EndMainMenuBar();
 	}
 
-	showScriptCasts();
 	showExecutionContext();
 	showHandlers();
 
diff --git a/engines/director/debugger/dt-castdetails.cpp b/engines/director/debugger/dt-castdetails.cpp
index 1999dddddfa..4546709984a 100644
--- a/engines/director/debugger/dt-castdetails.cpp
+++ b/engines/director/debugger/dt-castdetails.cpp
@@ -44,6 +44,7 @@
 namespace Director {
 namespace DT {
 
+
 template<typename... Args>
 void showProperty(const Common::String &title,
 				  const ImVec4 *color,
@@ -448,9 +449,9 @@ void drawRichTextCMprops(RichTextCastMember *member) {
 				for (int i = 7; i >= 0; i--) {
 					bool bitSet = (member->_cropFlags & (1 << i)) != 0;
 					if (bitSet) {
-						ImGui::TextColored(ImVec4(0.4f, 1.0f, 0.4f, 1.0f), "1");
+						ImGui::TextColored(_state->theme->var_color, "1");
 					} else {
-						ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "0");
+						ImGui::TextDisabled("0");
 					}
 					if (i > 0) {
 						ImGui::SameLine();
@@ -521,8 +522,8 @@ void drawBaseCMprops(CastMember *member) {
 				if (info) {
 					showProperty("name", "%s", info->name.c_str());
 				} else {
-					ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("name", &grayColor, "No Info");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("name", &disabledColor, "No Info");
 				}
 
 				showProperty("number", "%d", member->getID());
@@ -532,8 +533,8 @@ void drawBaseCMprops(CastMember *member) {
 				if (info && !info->fileName.empty()) {
 					showProperty("fileName", "%s", info->fileName.c_str());
 				} else {
-					ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("fileName", &grayColor, "...");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("fileName", &disabledColor, "...");
 				}
 
 				showProperty("type", "#%s", castType2str(member->_type));
@@ -544,47 +545,73 @@ void drawBaseCMprops(CastMember *member) {
 				ImGui::TableSetColumnIndex(0);
 				ImGui::Text("scriptText");
 				ImGui::TableSetColumnIndex(1);
-				if (info && !info->script.empty()) {
+				{
 					CastMemberID scriptCastId(member->getID(), cast->_castLibID);
+					ScriptContext *scriptCtx = getScriptContext(scriptCastId);
+					bool hasScript = scriptCtx != nullptr || (info && !info->script.empty());
 					bool hasCastScript = g_director->getCurrentMovie()->getScriptContext(kCastScript, scriptCastId) != nullptr;
-					ImGui::TextColored(hasCastScript ? ImVec4(0.4f, 0.8f, 0.4f, 1.0f) : ImVec4(0.7f, 0.7f, 1.0f, 1.0f), "...");
-					if (ImGui::IsItemHovered()) {
-						ImGui::SetTooltip(hasCastScript ? "%s\n\n(click to open script)" : "%s", info->script.c_str());
-						if (hasCastScript)
+					if (hasScript) {
+						ImGui::TextColored(hasCastScript ? _state->theme->var_color : _state->theme->script_ref, "(hover)");
+						if (ImGui::IsItemHovered()) {
 							ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
+							if (ImGui::BeginTooltip()) {
+								ImGui::PushTextWrapPos(400.0f);
+								if (info && !info->script.empty()) {
+									Common::String tip = info->script;
+									tip.replace('\r', '\n');
+									if (tip.size() > 500)
+										tip = tip.substr(0, 500) + "\n...";
+									ImGui::TextUnformatted(tip.c_str());
+									ImGui::Separator();
+								}
+								ImGui::TextDisabled("(click to open script)");
+								ImGui::PopTextWrapPos();
+								ImGui::EndTooltip();
+							}
+						}
+						if (ImGui::IsItemClicked(0)) {
+							if (scriptCtx) {
+								Common::String moviePath = g_director->getCurrentMovie()->getArchive()->getPathName().toString();
+								for (auto &handler : scriptCtx->_functionHandlers) {
+									ImGuiScript script = toImGuiScript(scriptCtx->_scriptType, scriptCastId, handler._key);
+									script.byteOffsets = scriptCtx->_functionByteOffsets[script.handlerId];
+									script.moviePath = moviePath;
+									script.handlerName = formatHandlerName(scriptCtx->_scriptId, scriptCastId.member, script.handlerId, scriptCtx->_scriptType, false);
+									addToOpenHandlers(script);
+								}
+							}
+						}
+					} else {
+						ImGui::TextDisabled("...");
 					}
-					if (hasCastScript && ImGui::IsItemClicked(0))
-						displayScriptRef(scriptCastId);
-				} else {
-					ImGui::TextColored(ImVec4(0.5f, 0.5f, 0.5f, 1.0f), "...");
 				}
 
 				if (info && info->creationTime != 0) {
 					showProperty("creationDate", "%u", info->creationTime);
 				} else {
-					ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("creationDate", &grayColor, "...");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("creationDate", &disabledColor, "N/A");
 				}
 
 				if (info && info->modifiedTime != 0) {
 					showProperty("modifiedDate", "%u", info->modifiedTime);
 				} else {
-					ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("modifiedDate", &grayColor, "...");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("modifiedDate", &disabledColor, "N/A");
 				}
 
 				if (info && !info->modifiedBy.empty()) {
 					showProperty("modifiedBy", "%s", info->modifiedBy.c_str());
 				} else {
-					ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("modifiedBy", &grayColor, "...");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("modifiedBy", &disabledColor, "N/A");
 				}
 
 				if (info && !info->comments.empty()) {
 					showProperty("comments", "%s", info->comments.c_str());
 				} else {
-					ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("comments", &grayColor, "...");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("comments", &disabledColor, "N/A");
 				}
 
 				showProperty("purgePriority", "%d", member->_purgePriority);
@@ -604,8 +631,8 @@ void drawBaseCMprops(CastMember *member) {
 
 				ImGuiImage media = getImageID(member);
 
-				ImVec4 grayColor = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-				showProperty("media", &grayColor, "%s", media.id == 0 ? "empty" : "...");
+				ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+				showProperty("media", &disabledColor, "%s", media.id == 0 ? "empty" : "...");
 
 				// Not using showProperty() here because we want to show a
 				// thumbnail of the media instead of text.
@@ -933,10 +960,10 @@ void drawSoundCMprops(SoundCastMember *member) {
 					showProperty("sampleSize", "%d bit", member->_audio->getSampleSize());
 					showProperty("channels", "%d", member->_audio->getChannelCount());
 				} else {
-					ImVec4 gray = ImVec4(0.5f, 0.5f, 0.5f, 1.0f);
-					showProperty("sampleRate", &gray, "N/A");
-					showProperty("sampleSize", &gray, "N/A");
-					showProperty("channels", &gray, "N/A");
+					ImVec4 disabledColor = ImGui::GetStyleColorVec4(ImGuiCol_TextDisabled);
+					showProperty("sampleRate", &disabledColor, "N/A");
+					showProperty("sampleSize", &disabledColor, "N/A");
+					showProperty("channels", &disabledColor, "N/A");
 				}
 				ImGui::EndTable();
 			}
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 1372e834365..673791dde7e 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -57,6 +57,7 @@ typedef struct ImGuiScriptCodeLine {
 
 typedef struct ImGuiScript {
 	bool score = false;
+	bool showByteCode = false;
 	CastMemberID id;
 	ScriptType type;
 	Common::String handlerId;
@@ -276,7 +277,6 @@ typedef struct ImGuiState {
 	ImGuiWindows _savedW;
 	bool _wasHidden = false;
 
-	Common::List<CastMemberID> _scriptCasts;
 	Common::HashMap<int, ImGuiScript> _openHandlers;
 	bool _showCompleteScript = true;
 
@@ -385,7 +385,6 @@ void renderScriptAST(ImGuiScript &script, bool showByteCode, bool scrollTo);
 
 // dt-scripts.cpp
 void showFuncList();
-void showScriptCasts();
 void showExecutionContext();
 void showHandlers();
 
diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index fcc05364f08..2f66701c6e6 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -959,12 +959,6 @@ static void drawMainChannelGrid(ImDrawList *dl, ImVec2 startPos, Score *score) {
 				case kChPalette: // open cast window focused on palette member
 					if (mc.palette.paletteId.member) {
 						_state->_w.cast = true;
-						// select it in the cast so showCast() highlights it
-						for (auto &scriptCast : _state->_scriptCasts) {
-							if (scriptCast == mc.palette.paletteId) {
-								break;
-							}
-						}
 					}
 					break;
 				case kChTransition:
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index 402f96376cf..c44bf27c76b 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -36,69 +36,6 @@
 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->theme->bp_color_disabled;
-
-		Director::Breakpoint *bp = getBreakpoint(handlerName, sym.ctx->_id, pc);
-		if (bp)
-			color = _state->theme->bp_color_enabled;
-
-		ImGui::PushID(pc);
-		ImGui::InvisibleButton("Line", ImVec2(16, ImGui::GetFontSize()));
-		if (ImGui::IsItemClicked(0)) {
-			if (bp) {
-				g_lingo->delBreakpoint(bp->id);
-				color = _state->theme->bp_color_disabled;
-			} else {
-				Director::Breakpoint newBp;
-				newBp.type = kBreakpointFunction;
-				newBp.funcName = handlerName;
-				newBp.funcOffset = pc;
-				g_lingo->addBreakpoint(newBp);
-				color = _state->theme->bp_color_enabled;
-			}
-		}
-
-		if (color == _state->theme->bp_color_disabled && ImGui::IsItemHovered()) {
-			color = _state->theme->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->theme->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());
-		ImGui::PopID();
-	}
-}
-
 static void renderScript(ImGuiScript &script, bool showByteCode, bool scrollTo) {
 	if (script.oldAst) {
 		renderOldScriptAST(script, showByteCode, scrollTo);
@@ -176,55 +113,7 @@ static void renderCallStack(uint pc) {
 	}
 }
 
-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()->getValOrDefault(id.castLib, nullptr);
-		ScriptContext *ctx = g_director->getCurrentMovie()->getScriptContext(kScoreScript, id);
-
-		if (ctx) {
-			for (auto &handler : ctx->_functionHandlers)
-				renderCastScript(handler._value);
-		} else if (cast && 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 bool showHandler(ImGuiScript handler) {
+static bool showHandler(ImGuiScript &handler) {
 	ScriptContext *ctx = getScriptContext(handler.id);
 	Common::String wName;
 	if (ctx) {
@@ -237,27 +126,14 @@ static bool showHandler(ImGuiScript handler) {
 	bool closed = true;
 
 	if (ImGui::Begin(wName.c_str(), &closed)) {
-		ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &_state->_showCompleteScript, true); // Lingo
-		ImGui::SetItemTooltip("Show Handler");
+		ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &handler.showByteCode, true); // Lingo
+		ImGui::SetItemTooltip("Show Lingo");
 
 		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];
+		ImGuiEx::toggleButton(ICON_MS_STACKS, &handler.showByteCode); // Bytecode
+		ImGui::SetItemTooltip("Show Bytecode");
 
-				if (script == handler) {
-					_state->_dbg._goToDefinition = true;
-				}
-				renderScript(script, false, script == handler);
-				ImGui::NewLine();
-			}
-		}
+		renderScript(handler, handler.showByteCode, true);
 	}
 	ImGui::End();
 
@@ -276,7 +152,7 @@ void showHandlers() {
 	}
 
 	Common::Array<uint32> toClose;
-	for (auto handler : _state->_openHandlers) {
+	for (auto &handler : _state->_openHandlers) {
 		if (!showHandler(handler._value))
 			toClose.push_back(handler._value.id.member);
 	}


Commit: f318fc13ae404b1e857d61a239307eec4c75cf76
    https://github.com/scummvm/scummvm/commit/f318fc13ae404b1e857d61a239307eec4c75cf76
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-06-16T01:33:29+02:00

Commit Message:
DIRECTOR: DT: Add browser navigation to scripts window, decouple from execution context

Replace the per-handler floating windows with a single "Scripts" window
backed by browser-style history (back/forward buttons + dropdown combo).
Extract renderScriptNavBar() and renderScriptContext() as shared helpers
used by both the Scripts window and Execution Context, removing ~80 lines
of duplicated code.

addToOpenHandlers() now pushes into ScriptData _openScripts with forward-
history truncation, replacing HashMap<int, ImGuiScript> _openHandlers which
had a collision bug (two scripts from different cast libs with the same
member number would overwrite each other).

Also fixes: closing the Scripts window and clicking the same script now
reopens it; back/forward in the non-stage execution context window now sets
_goToDefinition; combo entries now use PushID(); getScriptContext() falls
back to lctxContexts so Movie/parent scripts are found by cast member ID.

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 e121297d662..3d4b3ef210b 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -133,7 +133,7 @@ ImGuiScript toImGuiScript(ScriptType scriptType, CastMemberID id, const Common::
 }
 
 ScriptContext *getScriptContext(CastMemberID id) {
-	const Director::Movie *movie = g_director->getCurrentMovie();;
+	const Director::Movie *movie = g_director->getCurrentMovie();
 	const Cast *cast;
 
 	if (id.castLib == SHARED_CAST_LIB)
@@ -141,12 +141,20 @@ ScriptContext *getScriptContext(CastMemberID id) {
 	else
 		cast = movie->getCasts()->getVal(id.castLib);
 
-	if (!cast) {
+	if (!cast)
 		return nullptr;
-	}
 
 	ScriptContext *ctx = cast->_lingoArchive->findScriptContext(id.member);
-	return ctx;
+	if (ctx)
+		return ctx;
+
+	// Some scripts are only in lctxContexts (keyed by lctx index, not cast member ID).
+	// Do a reverse lookup: find the lctx entry whose cast ID maps to id.member.
+	for (auto &entry : cast->_lingoArchive->lctxContexts) {
+		if (cast->getCastIdByScriptId(entry._key) == id.member)
+			return entry._value;
+	}
+	return nullptr;
 }
 
 ScriptContext *getScriptContext(uint32 nameIndex, CastMemberID id, Common::String handlerName) {
@@ -525,8 +533,17 @@ ImVec4 convertColor(uint32 color) {
 }
 
 void addToOpenHandlers(ImGuiScript handler) {
-	_state->_openHandlers.erase(handler.id.member);
-	_state->_openHandlers[handler.id.member] = handler;
+	ScriptData &data = _state->_openScripts;
+	_state->_w.scripts = true;  // always (re)open the window
+	// Truncate forward history when navigating to a new script
+	if (data._current + 1 < data._scripts.size())
+		data._scripts.resize(data._current + 1);
+	// Don't add a duplicate at the current position
+	if (!data._scripts.empty() && data._scripts.back() == handler)
+		return;
+	data._scripts.push_back(handler);
+	data._current = data._scripts.size() - 1;
+	data._showScript = true;
 }
 
 void setScriptToDisplay(const ImGuiScript &script) {
@@ -941,7 +958,7 @@ void onImGuiRender() {
 	}
 
 	showExecutionContext();
-	showHandlers();
+	showScriptsWindow();
 
 	showControlPanel();
 	showVars();
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 673791dde7e..24d21b061d5 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -98,6 +98,7 @@ typedef struct ImGuiWindows {
 	bool archive = false;
 	bool watchedVars = false;
 	bool executionContext = false;
+	bool scripts = false;
 	bool search = false;
 	bool imageViewer = false;
 	bool windows = false;
@@ -277,7 +278,7 @@ typedef struct ImGuiState {
 	ImGuiWindows _savedW;
 	bool _wasHidden = false;
 
-	Common::HashMap<int, ImGuiScript> _openHandlers;
+	ScriptData _openScripts;
 	bool _showCompleteScript = true;
 
 	Common::HashMap<Common::String, bool, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> _variables;
@@ -386,7 +387,7 @@ void renderScriptAST(ImGuiScript &script, bool showByteCode, bool scrollTo);
 // dt-scripts.cpp
 void showFuncList();
 void showExecutionContext();
-void showHandlers();
+void showScriptsWindow();
 
 // dt-save-state.cpp
 void saveCurrentState();
diff --git a/engines/director/debugger/dt-scripts.cpp b/engines/director/debugger/dt-scripts.cpp
index c44bf27c76b..562b24ddaaf 100644
--- a/engines/director/debugger/dt-scripts.cpp
+++ b/engines/director/debugger/dt-scripts.cpp
@@ -113,51 +113,112 @@ static void renderCallStack(uint pc) {
 	}
 }
 
-static bool showHandler(ImGuiScript &handler) {
-	ScriptContext *ctx = getScriptContext(handler.id);
-	Common::String wName;
-	if (ctx) {
-		wName = Common::String(ctx->asString());
-	}
-
-	ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
-	ImGui::SetNextWindowSize(ImVec2(480, 540), ImGuiCond_FirstUseEver);
+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;
+}
 
-	bool closed = true;
+// Renders back/forward navigation, handler dropdown, and Lingo/Bytecode toggle for a ScriptData.
+// Returns true when there is a script to render.
+static bool renderScriptNavBar(ScriptData &data) {
+	if (data._scripts.empty())
+		return false;
 
-	if (ImGui::Begin(wName.c_str(), &closed)) {
-		ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &handler.showByteCode, true); // Lingo
-		ImGui::SetItemTooltip("Show Lingo");
+	ImGui::BeginDisabled(data._current == 0);
+	if (ImGui::Button(ICON_MS_ARROW_BACK)) {
+		data._current--;
+		_state->_dbg._goToDefinition = true;
+	}
+	ImGui::EndDisabled();
+	ImGui::SetItemTooltip("Backward");
+	ImGui::SameLine();
+
+	ImGui::BeginDisabled(data._current >= data._scripts.size() - 1);
+	if (ImGui::Button(ICON_MS_ARROW_FORWARD)) {
+		data._current++;
+		_state->_dbg._goToDefinition = true;
+	}
+	ImGui::EndDisabled();
+	ImGui::SetItemTooltip("Forward");
+	ImGui::SameLine();
+
+	const char *currentName = data._scripts[data._current].handlerName.c_str();
+	if (ImGui::BeginCombo("##handlers", currentName)) {
+		for (uint i = 0; i < data._scripts.size(); i++) {
+			bool selected = (i == data._current);
+			ImGui::PushID(i);
+			if (ImGui::Selectable(data._scripts[i].handlerName.c_str(), &selected)) {
+				data._current = i;
+				_state->_dbg._goToDefinition = true;
+			}
+			ImGui::PopID();
+		}
+		ImGui::EndCombo();
+	}
 
+	if (!data._scripts[data._current].oldAst) {
+		ImGui::SameLine(0, 20);
+		ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &data._showByteCode, true);
+		ImGui::SetItemTooltip("Lingo");
 		ImGui::SameLine();
-		ImGuiEx::toggleButton(ICON_MS_STACKS, &handler.showByteCode); // Bytecode
-		ImGui::SetItemTooltip("Show Bytecode");
-
-		renderScript(handler, handler.showByteCode, true);
+		ImGuiEx::toggleButton(ICON_MS_STACKS, &data._showByteCode);
+		ImGui::SetItemTooltip("Bytecode");
 	}
-	ImGui::End();
-
-	if (!closed)
-		return false;
 
 	return true;
 }
 
-/**
- * Display all open handlers
- */
-void showHandlers() {
-	if (_state->_openHandlers.empty()) {
+// Renders all handlers in the context, scrolling to the selected one.
+static void renderScriptContext(ScriptData &data, const Movie *movie) {
+	ImGuiScript &current = data._scripts[data._current];
+	ScriptContext *context = getScriptContext(current.id);
+	bool scrollTo = _state->_dbg._goToDefinition;
+
+	if (!context || context->_functionHandlers.size() == 1) {
+		renderScript(current, data._showByteCode, scrollTo);
 		return;
 	}
 
-	Common::Array<uint32> toClose;
-	for (auto &handler : _state->_openHandlers) {
-		if (!showHandler(handler._value))
-			toClose.push_back(handler._value.id.member);
+	for (auto &functionHandler : context->_functionHandlers) {
+		if (current.handlerId == functionHandler._key) {
+			renderScript(current, data._showByteCode, scrollTo);
+		} 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);
+			renderScript(script, data._showByteCode, false);
+		}
+		ImGui::NewLine();
 	}
-	for (uint32 key : toClose)
-		_state->_openHandlers.erase(key);
+}
+
+void showScriptsWindow() {
+	ScriptData &data = _state->_openScripts;
+	if (!_state->_w.scripts || !data._showScript || data._scripts.empty())
+		return;
+
+	ImGui::SetNextWindowPos(ImVec2(20, 160), ImGuiCond_FirstUseEver);
+	ImGui::SetNextWindowSize(ImVec2(480, 540), ImGuiCond_FirstUseEver);
+
+	if (ImGui::Begin("Scripts", &_state->_w.scripts)) {
+		ScriptContext *ctx = getScriptContext(data._scripts[data._current].id);
+		if (ctx)
+			ImGui::Text("%s", ctx->asString().c_str());
+
+		if (renderScriptNavBar(data)) {
+			ImGui::Separator();
+			ImVec2 childSize = ImGui::GetContentRegionAvail();
+			ImGui::BeginChild("##script", childSize);
+			renderScriptContext(data, g_director->getCurrentMovie());
+			ImGui::EndChild();
+		}
+	}
+	ImGui::End();
+	_state->_dbg._goToDefinition = false;
 }
 
 static void updateCurrentScript() {
@@ -190,16 +251,6 @@ static void updateCurrentScript() {
 	setScriptToDisplay(script);
 }
 
-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;
@@ -456,91 +507,23 @@ void showExecutionContext() {
 		ScriptData *scriptData = &_state->_functions._windowScriptData.getOrCreateVal(stage);
 		updateCurrentScript();
 
-		if (scriptData->_showScript && !scriptData->_scripts.empty() && scriptData->_current < scriptData->_scripts.size()) {
-			// disable highlighting while rendering scripts in Execution Context
+		if (scriptData->_showScript && !scriptData->_scripts.empty()) {
 			bool oldSuppress = _state->_dbg._suppressHighlight;
 			_state->_dbg._suppressHighlight = true;
 
-			ImGuiScript &current = scriptData->_scripts[scriptData->_current];
-
-			// Get all the handlers from the script
-			ScriptContext* context = getScriptContext(current.id);
-
-			if (context) {
+			ScriptContext *context = getScriptContext(scriptData->_scripts[scriptData->_current].id);
+			if (context)
 				ImGui::Text("%d:%s type:%s", context->_id, context->getName().c_str(), scriptType2str(context->_scriptType));
-			}
 
-			ImGui::BeginDisabled(scriptData->_scripts.empty() || scriptData->_current == 0);
-			if (ImGui::Button(ICON_MS_ARROW_BACK)) {
-				scriptData->_current--;
-				_state->_dbg._goToDefinition = true;
-			}
-			ImGui::EndDisabled();
-			ImGui::SetItemTooltip("Backward");
-			ImGui::SameLine();
-
-			ImGui::BeginDisabled(scriptData->_current >= scriptData->_scripts.size() - 1);
-			if (ImGui::Button(ICON_MS_ARROW_FORWARD)) {
-				scriptData->_current++;
-				_state->_dbg._goToDefinition = true;
-			}
-			ImGui::EndDisabled();
-			ImGui::SetItemTooltip("Forward");
-			ImGui::SameLine();
-
-			const char *currentScript = nullptr;
-
-			if (scriptData->_current < scriptData->_scripts.size()) {
-				currentScript = scriptData->_scripts[scriptData->_current].handlerName.c_str();
-			}
-
-			if (ImGui::BeginCombo("##handlers", currentScript)) {
-				for (uint i = 0; i < scriptData->_scripts.size(); i++) {
-					auto &script = scriptData->_scripts[i];
-					bool selected = i == scriptData->_current;
-					ImGui::PushID(i);
-					if (ImGui::Selectable(script.handlerName.c_str(), &selected)) {
-						scriptData->_current = i;
-					}
-					ImGui::PopID();
-				}
-				ImGui::EndCombo();
-			}
-
-			if (!scriptData->_scripts[scriptData->_current].oldAst) {
-				ImGui::SameLine(0, 20);
-				ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &scriptData->_showByteCode, true); // Lingo
-				ImGui::SetItemTooltip("Lingo");
-				ImGui::SameLine();
-
-				ImGuiEx::toggleButton(ICON_MS_STACKS, &scriptData->_showByteCode); // Bytecode
-				ImGui::SetItemTooltip("Bytecode");
-			}
-
-			ImGui::Separator();
-			childSize = ImGui::GetContentRegionAvail();
-			ImGui::BeginChild("##script", childSize);
-
-			if (!context || context->_functionHandlers.size() == 1) {
-				renderScript(current, scriptData->_showByteCode, true);
-			} else {
-				for (auto &functionHandler : context->_functionHandlers) {
-					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();
-				}
+			if (renderScriptNavBar(*scriptData)) {
+				ImGui::Separator();
+				childSize = ImGui::GetContentRegionAvail();
+				ImGui::BeginChild("##script", childSize);
+				renderScriptContext(*scriptData, movie);
+				ImGui::EndChild();
+				scriptsRendered = true;
 			}
-			scriptsRendered = true;
 
-			ImGui::EndChild();
 			_state->_dbg._suppressHighlight = oldSuppress;
 		}
 
@@ -576,90 +559,23 @@ void showExecutionContext() {
 			scriptData = &_state->_functions._windowScriptData.getOrCreateVal(window);
 			updateCurrentScript();
 
-			if (scriptData->_showScript && !scriptData->_scripts.empty() && scriptData->_current < scriptData->_scripts.size()) {
+			if (scriptData->_showScript && !scriptData->_scripts.empty()) {
 				bool oldSuppress = _state->_dbg._suppressHighlight;
 				_state->_dbg._suppressHighlight = true;
-				ImGuiScript &current = scriptData->_scripts[scriptData->_current];
-
-				// Get all the handlers from the script
-				ScriptContext* context = getScriptContext(current.id);
-
-				if (context) {
-					int castId = context->_id;
-					if (castId == -1) {
-						castId = movie->getCast()->getCastIdByScriptId(context->_parentNumber);
-					}
-					Common::String scriptInfo = Common::String::format("%d:%s type:%s", castId, 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)) {
-					scriptData->_current--;
-				}
-				ImGui::EndDisabled();
-				ImGui::SetItemTooltip("Backward");
-				ImGui::SameLine();
 
-				ImGui::BeginDisabled(scriptData->_current >= scriptData->_scripts.size() - 1);
-				if (ImGui::Button(ICON_MS_ARROW_FORWARD)) {
-					scriptData->_current++;
-				}
-				ImGui::EndDisabled();
-				ImGui::SetItemTooltip("Forward");
-				ImGui::SameLine();
-
-				const char *currentScript = nullptr;
-
-				if (scriptData->_current < scriptData->_scripts.size()) {
-					currentScript = scriptData->_scripts[scriptData->_current].handlerName.c_str();
-				}
-
-				if (ImGui::BeginCombo("##handlers", currentScript)) {
-					for (uint i = 0; i < scriptData->_scripts.size(); i++) {
-						auto &script = scriptData->_scripts[i];
-						bool selected = i == scriptData->_current;
-						if (ImGui::Selectable(script.handlerName.c_str(), &selected)) {
-							scriptData->_current = i;
-						}
-					}
-					ImGui::EndCombo();
+				ScriptContext *context = getScriptContext(scriptData->_scripts[scriptData->_current].id);
+				if (context)
+					ImGui::Text("%d:%s type:%s", context->_id, context->getName().c_str(), scriptType2str(context->_scriptType));
+
+				if (renderScriptNavBar(*scriptData)) {
+					ImGui::Separator();
+					childSize = ImGui::GetContentRegionAvail();
+					ImGui::BeginChild("##script", childSize);
+					renderScriptContext(*scriptData, movie);
+					ImGui::EndChild();
+					scriptsRendered = true;
 				}
 
-				if (!scriptData->_scripts[scriptData->_current].oldAst) {
-					ImGui::SameLine(0, 20);
-					ImGuiEx::toggleButton(ICON_MS_PACKAGE_2, &scriptData->_showByteCode, true); // Lingo
-					ImGui::SetItemTooltip("Lingo");
-					ImGui::SameLine();
-
-					ImGuiEx::toggleButton(ICON_MS_STACKS, &scriptData->_showByteCode); // Bytecode
-					ImGui::SetItemTooltip("Bytecode");
-				}
-
-				ImGui::Separator();
-				childSize = ImGui::GetContentRegionAvail();
-				ImGui::BeginChild("##script", childSize);
-
-				if (!context || context->_functionHandlers.size() == 1) {
-					renderScript(current, scriptData->_showByteCode, true);
-				} else {
-					for (auto &functionHandler : context->_functionHandlers) {
-						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();
-					}
-				}
-
-				scriptsRendered = true;
-				ImGui::EndChild();
 				_state->_dbg._suppressHighlight = oldSuppress;
 			}
 
@@ -670,6 +586,7 @@ void showExecutionContext() {
 
 		// Mark the scripts not dirty after all the handlers have been rendered
 		_state->_dbg._isScriptDirty = !scriptsRendered;
+		_state->_dbg._goToDefinition = false;
 
 		g_director->setCurrentWindow(currentWindow);
 		g_lingo->switchStateFromWindow();


Commit: 7494441d8603f640fcb4d8fce63d5c15f4ab8200
    https://github.com/scummvm/scummvm/commit/7494441d8603f640fcb4d8fce63d5c15f4ab8200
Author: ramyak-sharma (ramyaksharma1 at gmail.com)
Date: 2026-06-16T01:33:29+02:00

Commit Message:
DIRECTOR: DT: Add Ctrl+2/3/4 shortcuts for Control Panel, Cast, Score

Use ImGui::Shortcut() with RouteGlobal | RouteOverFocused inside
BeginMainMenuBar() to register global shortcuts for toggling the
Control Panel (Ctrl+2), Cast (Ctrl+3), and Score (Ctrl+4) windows.

Since MacOS overrides ctrl, use cmd instead.:wq

Changed paths:
    engines/director/debugger/debugtools.cpp


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 3d4b3ef210b..f9c32539a1d 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -908,6 +908,12 @@ void onImGuiRender() {
 	ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
 
 	if (ImGui::BeginMainMenuBar()) {
+		if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_2, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused))
+			_state->_w.controlPanel = !_state->_w.controlPanel;
+		if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_3, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused))
+			_state->_w.cast = !_state->_w.cast;
+		if (ImGui::Shortcut(ImGuiMod_Ctrl | ImGuiKey_4, ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused))
+			_state->_w.score = !_state->_w.score;
 		if (ImGui::BeginMenu("View")) {
 			ImGui::SeparatorText("Windows");
 




More information about the Scummvm-git-logs mailing list