[Scummvm-git-logs] scummvm master -> 6c2c8e9303037f37afaa13ea8d6d49743ddd59b9

sev- noreply at scummvm.org
Sun Mar 8 19:00:40 UTC 2026


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

Summary:
b6eaad36c5 DIRECTOR: DT: Fix frame navigation in Control Panel UI
fb9911d559 DIRECTOR: DT: Add ignore-mouse option to debugger UI
00e92e1873 DIRECTOR: Support ignoring mouse events when debugging
08d3fe121e DIRECTOR: DT: Select channel in debugger on stage click
e46d732d84 DIRECTOR: DT: Select channel when clicking active sprite span in Score
15d47cec93 DIRECTOR: DT: Add Multi-Viewport toggle to debugger settings
87e4a555f2 DIRECTOR: DT: Double-click Score cells to jump to frame
18672e375c DIRECTOR: DT: Fix channel hiding in debugger UI
a9afc765be DIRECTOR: DT: Fix channel selection blocking clicks and row height
6c2c8e9303 DIRECTOR: DT: Fix ImGui crash when updating UI with paused submovies


Commit: b6eaad36c5dd12ce0af0344a0f5921f948c6994d
    https://github.com/scummvm/scummvm/commit/b6eaad36c5dd12ce0af0344a0f5921f948c6994d
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Fix frame navigation in Control Panel UI

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


diff --git a/engines/director/debugger/dt-controlpanel.cpp b/engines/director/debugger/dt-controlpanel.cpp
index 305dcc05fba..d0fd862aec2 100644
--- a/engines/director/debugger/dt-controlpanel.cpp
+++ b/engines/director/debugger/dt-controlpanel.cpp
@@ -141,6 +141,7 @@ void showControlPanel() {
 		float bgX1 = -4.0f, bgX2 = 21.0f;
 
 		int frameNum = score->getCurrentFrameNum();
+		int maxFrame = score->getFramesNum() - 1;
 
 		if (_state->_prevFrame != -1 && _state->_prevFrame != frameNum) {
 			score->_playState = kPlayPaused;
@@ -152,7 +153,9 @@ void showControlPanel() {
 
 			if (ImGui::IsItemClicked(0)) {
 				score->_playState = kPlayStarted;
-				score->setCurrentFrame(1);
+				Datum frameDatum(1);
+				Datum movieDatum;
+				g_lingo->func_goto(frameDatum, movieDatum, true);
 			}
 
 			if (ImGui::IsItemHovered())
@@ -172,7 +175,11 @@ void showControlPanel() {
 			if (ImGui::IsItemClicked(0)) {
 				score->_playState = kPlayStarted;
 
-				score->setCurrentFrame(frameNum - 1);
+				int targetFrame = (frameNum <= 1) ? maxFrame : (frameNum - 1);
+				Datum frameDatum(targetFrame);
+				Datum movieDatum;
+				g_lingo->func_goto(frameDatum, movieDatum, true);
+
 				_state->_prevFrame = frameNum;
 			}
 
@@ -216,7 +223,11 @@ void showControlPanel() {
 			if (ImGui::IsItemClicked(0)) {
 				score->_playState = kPlayStarted;
 
-				score->setCurrentFrame(frameNum + 1);
+				int targetFrame = (frameNum >= maxFrame) ? 1 : (frameNum + 1);
+				Datum frameDatum(targetFrame);
+				Datum movieDatum;
+				g_lingo->func_goto(frameDatum, movieDatum, true);
+
 				_state->_prevFrame = frameNum;
 			}
 
@@ -261,7 +272,20 @@ void showControlPanel() {
 		snprintf(buf, 6, "%d", score->getCurrentFrameNum());
 
 		ImGui::SetNextItemWidth(35);
-		ImGui::InputText("##frame", buf, 5, ImGuiInputTextFlags_CharsDecimal);
+		if (ImGui::InputText("##frame", buf, 5, ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_EnterReturnsTrue)) {
+			int newFrame = atoi(buf);
+			newFrame = (newFrame < 1) ? 1 : (newFrame > maxFrame ? maxFrame : newFrame);
+
+			if (newFrame != frameNum) {
+				score->_playState = kPlayStarted;
+
+				Datum frameDatum(newFrame);
+				Datum movieDatum;
+				g_lingo->func_goto(frameDatum, movieDatum, true);
+
+				_state->_prevFrame = frameNum;
+			}
+		}
 		ImGui::SetItemTooltip("Frame");
 
 		{


Commit: fb9911d559039e127678b8888b08c26c7cbce462
    https://github.com/scummvm/scummvm/commit/fb9911d559039e127678b8888b08c26c7cbce462
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Add ignore-mouse option to debugger UI

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


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index dcff9c3be01..d8a3f5532bd 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -649,6 +649,10 @@ static void showSettings() {
 		}
 
 		_state->_logger->drawColorOptions();
+
+		ImGui::SeparatorText("Debugger Behavior");
+		ImGui::Checkbox("Ignore Mouse Events", &_state->_ignoreMouse);
+		ImGui::SetItemTooltip("Block mouse events from reaching Director.\nHold SHIFT to temporarily allow them.\nPress Ctrl+F1 to toggle this setting.");
 	}
 	ImGui::End();
 }
@@ -709,6 +713,13 @@ void onImGuiRender() {
 	ImGuiIO &io = ImGui::GetIO();
 	io.ConfigFlags &= ~(ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse);
 
+	if (ImGui::IsKeyChordPressed(ImGuiMod_Ctrl | ImGuiKey_F1)) {
+		_state->_ignoreMouse = !_state->_ignoreMouse;
+
+		Common::String msg = Common::String::format("Debug Mouse Ignore: %s", _state->_ignoreMouse ? "ON" : "OFF");
+		g_system->displayMessageOnOSD(Common::U32String(msg));
+	}
+
 	ImGui::DockSpaceOverViewport(0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode);
 
 	if (ImGui::BeginMainMenuBar()) {
@@ -793,6 +804,18 @@ int getSelectedChannel(){
 	return _state ? _state->_selectedChannel : -1;
 }
 
+bool isMouseInputIgnored() {
+	if (!_state || !_state->_ignoreMouse)
+		return false;
+
+	// Holding Shift temporarily allows mouse events to pass to the engine
+	ImGuiIO &io = ImGui::GetIO();
+	if (io.KeyShift)
+		return false;
+
+	return true;
+}
+
 Common::String formatHandlerName(int scriptId, int castId, Common::String handlerName, ScriptType scriptType, bool childScript) {
 	Common::String formatted = Common::String();
 	// Naming convention: <script id> (<cast id/cast id of parent script>): name of handler: script type
diff --git a/engines/director/debugger/debugtools.h b/engines/director/debugger/debugtools.h
index 68e18857d8e..df4e5f6f48e 100644
--- a/engines/director/debugger/debugtools.h
+++ b/engines/director/debugger/debugtools.h
@@ -28,6 +28,7 @@ void onImGuiInit();
 void onImGuiRender();
 void onImGuiCleanup();
 int getSelectedChannel();
+bool isMouseInputIgnored();
 } // namespace DT
 } // namespace Director
 
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 37be478c097..80ccbcd5274 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -287,6 +287,7 @@ typedef struct ImGuiState {
 	} _archive;
 
 	ImGuiEx::ImGuiLogger *_logger = nullptr;
+	bool _ignoreMouse = false;
 } ImGuiState;
 
 // debugtools.cpp


Commit: 00e92e18732c56948e90913b2594e7bb62959edc
    https://github.com/scummvm/scummvm/commit/00e92e18732c56948e90913b2594e7bb62959edc
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: Support ignoring mouse events when debugging

Changed paths:
    engines/director/debugger/dt-save-state.cpp
    engines/director/events.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/movie.cpp
    engines/director/movie.h
    engines/director/score.cpp
    engines/director/window.cpp


diff --git a/engines/director/debugger/dt-save-state.cpp b/engines/director/debugger/dt-save-state.cpp
index 4bab8cc1f96..c614e768e32 100644
--- a/engines/director/debugger/dt-save-state.cpp
+++ b/engines/director/debugger/dt-save-state.cpp
@@ -94,6 +94,7 @@ void saveCurrentState() {
 	json["ScoreWindow"] = new Common::JSONValue(_state->_scoreWindow);
 	json["ChannelsWindow"] = new Common::JSONValue(_state->_channelsWindow);
 	json["CastWindow"] = new Common::JSONValue(_state->_castWindow);
+	json["IgnoreMouse"] = new Common::JSONValue(_state->_ignoreMouse);
 
 	// Save the JSON
 	Common::JSONValue save(json);
@@ -177,6 +178,7 @@ void loadSavedState() {
 	_state->_scoreWindow = saved->asObject()["ScoreWindow"]->asString();
 	_state->_channelsWindow = saved->asObject()["ChannelsWindow"]->asString();
 	_state->_castWindow = saved->asObject()["CastWindow"]->asString();
+	_state->_ignoreMouse = saved->asObject()["IgnoreMouse"]->asBool();
 
 	free(data);
 	delete saved;
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 94d1578624a..c8733199068 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -37,6 +37,7 @@
 #include "director/sprite.h"
 #include "director/window.h"
 #include "director/castmember/castmember.h"
+#include "director/debugger/debugtools.h"
 
 namespace Director {
 
@@ -58,6 +59,12 @@ bool DirectorEngine::processEvents(bool captureClick, bool skipWindowManager) {
 
 	Common::Event event;
 	while (pollEvent(event)) {
+		if (Director::DT::isMouseInputIgnored()) {
+			if (Common::isMouseEvent(event)) {
+				continue;
+			}
+		}
+
 		if (skipWindowManager || !_wm->processEvent(event)) {
 			// We only want to handle these events if the event
 			// wasn't handled by the window manager.
@@ -143,6 +150,7 @@ bool Movie::processEvent(Common::Event &event) {
 			spriteId = _score->getMouseSpriteIDFromPos(event.mouse);
 
 		_currentHoveredSpriteId = spriteId;
+		_lastMousePos = event.mouse;
 	}
 
 	Common::Point pos;
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 14f0b894fe7..3e128d824de 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -42,6 +42,7 @@
 #include "director/lingo/lingo-builtins.h"
 #include "director/lingo/lingo-code.h"
 #include "director/lingo/lingo-the.h"
+#include "director/debugger/debugtools.h"
 
 namespace Director {
 
@@ -856,7 +857,11 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		}
 		break;
 	case kTheMouseDown:
-		d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_LEFT | 1 << Common::MOUSE_BUTTON_RIGHT) ? 1 : 0;
+		if (Director::DT::isMouseInputIgnored()) {
+			d = 0;
+		} else {
+			d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_LEFT | 1 << Common::MOUSE_BUTTON_RIGHT) ? 1 : 0;
+		}
 		break;
 	case kTheMouseDownScript:
 		d.type = STRING;
@@ -896,7 +901,11 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		}
 		break;
 	case kTheMouseUp:
-		d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_LEFT | 1 << Common::MOUSE_BUTTON_RIGHT) ? 0 : 1;
+		if (Director::DT::isMouseInputIgnored()) {
+			d = 1;
+		} else {
+			d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_LEFT | 1 << Common::MOUSE_BUTTON_RIGHT) ? 0 : 1;
+		}
 		break;
 	case kTheMouseUpScript:
 		d.type = STRING;
@@ -1003,10 +1012,18 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		d = g_lingo->_theResult;
 		break;
 	case kTheRightMouseDown:
-		d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_RIGHT) ? 1 : 0;
+		if (Director::DT::isMouseInputIgnored()) {
+			d = 0;
+		} else {
+			d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_RIGHT) ? 1 : 0;
+		}
 		break;
 	case kTheRightMouseUp:
-		d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_RIGHT) ? 0 : 1;
+		if (Director::DT::isMouseInputIgnored()) {
+			d = 1;
+		} else {
+			d = g_system->getEventManager()->getButtonState() & (1 << Common::MOUSE_BUTTON_RIGHT) ? 0 : 1;
+		}
 		break;
 	case kTheRollOver:
 		d = score->getSpriteIDFromPos(g_director->getCurrentWindow()->getMousePos());
@@ -1119,7 +1136,11 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		}
 		break;
 	case kTheStillDown:
-		d = _vm->_wm->_mouseDown;
+		if (Director::DT::isMouseInputIgnored()) {
+			d = 0;
+		} else {
+			d = _vm->_wm->_mouseDown;
+		}
 		break;
 	case kTheSwitchColorDepth:
 		getTheEntitySTUB(kTheSwitchColorDepth);
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 2bdf3e672d0..b840a3a4770 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -55,6 +55,7 @@ Movie::Movie(Window *window) {
 	_lastKeyTime = _lastEventTime;
 	_lastClickTime = _lastEventTime;
 	_lastClickTime2 = 0;
+	_lastMousePos = Common::Point(0, 0);
 	_lastRollTime = _lastEventTime;
 	_lastTimerReset = _lastEventTime;
 	_nextEventId = 0;
diff --git a/engines/director/movie.h b/engines/director/movie.h
index a463a1d6b6e..3388b320a56 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -167,6 +167,7 @@ public:
 	uint32 _lastClickTime;
 	uint32 _lastClickTime2;
 	Common::Point _lastClickPos;
+	Common::Point _lastMousePos;
 	uint32 _lastKeyTime;
 	uint32 _lastTimerReset;
 	uint32 _stageColor;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index db9bb484895..1dd509dff5e 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -49,6 +49,7 @@
 #include "director/castmember/castmember.h"
 #include "director/castmember/filmloop.h"
 #include "director/castmember/transition.h"
+#include "director/debugger/debugtools.h"
 
 namespace Director {
 
@@ -363,7 +364,8 @@ void Score::step() {
 			_soundManager->processCuePoints();
 		} else 	if (_version >= kFileVer500) {
 			// In D5, these events are only generated if a mouse button is pressed
-			if (_movie->_currentHoveredSpriteId && g_system->getEventManager()->getButtonState() != 0) {
+			bool isButtonDown = !Director::DT::isMouseInputIgnored() && (g_system->getEventManager()->getButtonState() != 0);
+			if (_movie->_currentHoveredSpriteId && isButtonDown) {
 				_movie->processEvent(kEventMouseWithin, _movie->_currentHoveredSpriteId);
 			}
 		}
@@ -1398,6 +1400,10 @@ void Score::renderPaletteCycle(RenderMode mode) {
 }
 
 void Score::renderCursor(Common::Point pos, bool forceUpdate) {
+	if (Director::DT::isMouseInputIgnored()) {
+		pos = _movie->_lastMousePos;
+	}
+
 	if (_window != _vm->getCursorWindow()) {
 		// The cursor is outside of this window.
 		return;
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 3834bace3b2..5e9437b9389 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -413,6 +413,10 @@ void Window::inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::Mana
 }
 
 Common::Point Window::getMousePos() {
+	if (Director::DT::isMouseInputIgnored() && _currentMovie) {
+		return _currentMovie->_lastMousePos;
+	}
+
 	Common::Rect innerDims = _window->getInnerDimensions();
 	return g_system->getEventManager()->getMousePos() - Common::Point(innerDims.left, innerDims.top);
 }


Commit: 08d3fe121e7b48f01dd1e0315b3be3f77dac1b5d
    https://github.com/scummvm/scummvm/commit/08d3fe121e7b48f01dd1e0315b3be3f77dac1b5d
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Select channel in debugger on stage click

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


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index d8a3f5532bd..12beacad8f8 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -804,6 +804,17 @@ int getSelectedChannel(){
 	return _state ? _state->_selectedChannel : -1;
 }
 
+void setSelectedChannel(int channel) {
+	if (_state) {
+		_state->_selectedChannel = channel;
+
+		if (channel > 0) {
+			_state->_scrollToChannel = true; 
+			_state->_w.channels = true;
+		}
+	}
+}
+
 bool isMouseInputIgnored() {
 	if (!_state || !_state->_ignoreMouse)
 		return false;
diff --git a/engines/director/debugger/debugtools.h b/engines/director/debugger/debugtools.h
index df4e5f6f48e..dd554659144 100644
--- a/engines/director/debugger/debugtools.h
+++ b/engines/director/debugger/debugtools.h
@@ -28,6 +28,7 @@ void onImGuiInit();
 void onImGuiRender();
 void onImGuiCleanup();
 int getSelectedChannel();
+void setSelectedChannel(int channel);
 bool isMouseInputIgnored();
 } // namespace DT
 } // namespace Director
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 80ccbcd5274..3d825b03396 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -269,6 +269,7 @@ typedef struct ImGuiState {
 	int _scoreFrameOffset = 1;
 	int _scorePageSlider = 0;
 	int _selectedChannel = -1;
+	bool _scrollToChannel = false;
 
 	ImFont *_tinyFont = nullptr;
 
diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index 59ca362c027..8638b21a8a9 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -1217,6 +1217,11 @@ void showChannels() {
 
 				ImGui::TableNextRow();
 
+				if (_state->_selectedChannel == i + 1 && _state->_scrollToChannel) {
+					ImGui::SetScrollHereY(0.5f);
+					_state->_scrollToChannel = false;
+				}
+
 				{ // Playback toggle
 					ImGui::TableNextColumn();
 
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index c8733199068..21b1d987bda 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -61,6 +61,19 @@ bool DirectorEngine::processEvents(bool captureClick, bool skipWindowManager) {
 	while (pollEvent(event)) {
 		if (Director::DT::isMouseInputIgnored()) {
 			if (Common::isMouseEvent(event)) {
+				if (event.type == Common::EVENT_LBUTTONDOWN) {
+					Window *window = g_director->getCurrentWindow();
+					Score *score = window->getCurrentMovie()->getScore();
+					uint16 spriteId = 0;
+
+					if (g_director->getVersion() < 400)
+						spriteId = score->getActiveSpriteIDFromPos(event.mouse);
+					else
+						spriteId = score->getMouseSpriteIDFromPos(event.mouse);
+
+					Director::DT::setSelectedChannel(spriteId);
+					window->render(true);
+				}
 				continue;
 			}
 		}


Commit: e46d732d8427b9b91119f0fc78c09e34e60e2d68
    https://github.com/scummvm/scummvm/commit/e46d732d8427b9b91119f0fc78c09e34e60e2d68
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Select channel when clicking active sprite span in Score

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


diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index 8638b21a8a9..6b6a4573c7a 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -24,6 +24,7 @@
 #include "backends/imgui/IconsMaterialSymbols.h"
 #include "director/director.h"
 #include "director/debugger/dt-internal.h"
+#include "director/debugger/debugtools.h"
 
 #include "director/cast.h"
 #include "director/castmember/castmember.h"
@@ -730,6 +731,12 @@ static void drawSpriteGrid(ImDrawList *dl, ImVec2 startPos, Score *score, Cast *
 					_state->_selectedScoreCast.frame = rf;
 					_state->_selectedScoreCast.channel = ch;
 					_state->_selectedScoreCast.isMainChannel = false;
+
+					int playheadIdx = score->getCurrentFrameNum() - 1;
+					if (playheadIdx >= spanStart && playheadIdx <= spanEnd) {
+						Director::DT::setSelectedChannel(ch);
+						window->render(true);
+					}
 				}
 
 				if (ImGui::IsItemHovered()) {


Commit: 15d47cec93aa42e05e40d274e40773640b48c3ec
    https://github.com/scummvm/scummvm/commit/15d47cec93aa42e05e40d274e40773640b48c3ec
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Add Multi-Viewport toggle to debugger settings

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


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index 12beacad8f8..cac3485c667 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -653,6 +653,16 @@ static void showSettings() {
 		ImGui::SeparatorText("Debugger Behavior");
 		ImGui::Checkbox("Ignore Mouse Events", &_state->_ignoreMouse);
 		ImGui::SetItemTooltip("Block mouse events from reaching Director.\nHold SHIFT to temporarily allow them.\nPress Ctrl+F1 to toggle this setting.");
+
+		ImGuiIO &io = ImGui::GetIO();
+		if (ImGui::Checkbox("Enable Multi-Viewport", &_state->_enableMultiViewport)) {
+			if (_state->_enableMultiViewport) {
+				io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
+			} else {
+				io.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
+			}
+		}
+		ImGui::SetItemTooltip("When disabled, all debugger windows are forced to stay inside the main ScummVM window.");
 	}
 	ImGui::End();
 }
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 3d825b03396..fd2e1ea8832 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -289,6 +289,7 @@ typedef struct ImGuiState {
 
 	ImGuiEx::ImGuiLogger *_logger = nullptr;
 	bool _ignoreMouse = false;
+	bool _enableMultiViewport = true;
 } ImGuiState;
 
 // debugtools.cpp
diff --git a/engines/director/debugger/dt-save-state.cpp b/engines/director/debugger/dt-save-state.cpp
index c614e768e32..0180968d6ee 100644
--- a/engines/director/debugger/dt-save-state.cpp
+++ b/engines/director/debugger/dt-save-state.cpp
@@ -95,6 +95,7 @@ void saveCurrentState() {
 	json["ChannelsWindow"] = new Common::JSONValue(_state->_channelsWindow);
 	json["CastWindow"] = new Common::JSONValue(_state->_castWindow);
 	json["IgnoreMouse"] = new Common::JSONValue(_state->_ignoreMouse);
+	json["EnableMultiViewport"] = new Common::JSONValue(_state->_enableMultiViewport);
 
 	// Save the JSON
 	Common::JSONValue save(json);
@@ -179,6 +180,14 @@ void loadSavedState() {
 	_state->_channelsWindow = saved->asObject()["ChannelsWindow"]->asString();
 	_state->_castWindow = saved->asObject()["CastWindow"]->asString();
 	_state->_ignoreMouse = saved->asObject()["IgnoreMouse"]->asBool();
+	_state->_enableMultiViewport = saved->asObject()["EnableMultiViewport"]->asBool();
+
+	ImGuiIO &io = ImGui::GetIO();
+	if (_state->_enableMultiViewport) {
+		io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
+	} else {
+		io.ConfigFlags &= ~ImGuiConfigFlags_ViewportsEnable;
+	}
 
 	free(data);
 	delete saved;


Commit: 87e4a555f2149333a7da6a2aa39b6be43a560cf6
    https://github.com/scummvm/scummvm/commit/87e4a555f2149333a7da6a2aa39b6be43a560cf6
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Double-click Score cells to jump to frame

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


diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index 6b6a4573c7a..63809e503d9 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -739,6 +739,19 @@ static void drawSpriteGrid(ImDrawList *dl, ImVec2 startPos, Score *score, Cast *
 					}
 				}
 
+				if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
+					score->_playState = kPlayStarted;
+
+					Datum frameDatum(rf + 1);
+					Datum movieDatum;
+					g_lingo->func_goto(frameDatum, movieDatum, true);
+
+					_state->_prevFrame = score->getCurrentFrameNum();
+
+					Director::DT::setSelectedChannel(ch);
+					window->render(true);
+				}
+
 				if (ImGui::IsItemHovered()) {
 					_state->_hoveredScoreCast.frame = rf;
 					_state->_hoveredScoreCast.channel = ch;


Commit: 18672e375c6e2e09eb9fecb998bfa8af14442a3c
    https://github.com/scummvm/scummvm/commit/18672e375c6e2e09eb9fecb998bfa8af14442a3c
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Fix channel hiding in debugger UI

Changed paths:
    engines/director/channel.cpp
    engines/director/channel.h
    engines/director/debugger/debugtools.cpp
    engines/director/debugger/dt-internal.h
    engines/director/debugger/dt-score.cpp
    engines/director/window.cpp


diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index 0909843da10..916038bba78 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -62,6 +62,7 @@ Channel::Channel(Score *sc, Sprite *sp, int priority) {
 
 	_visible = true;
 	_dirty = true;
+	_hideFromStage = false;
 
 	if (sp) {
 		_startFrame = sp->_spriteInfo.startFrame;
@@ -95,6 +96,7 @@ Channel& Channel::operator=(const Channel &channel) {
 
 	_visible = channel._visible;
 	_dirty = channel._dirty;
+	_hideFromStage = channel._hideFromStage;
 
 	_startFrame = channel._startFrame;
 	_endFrame = channel._endFrame;
diff --git a/engines/director/channel.h b/engines/director/channel.h
index 3e50aaeb6c8..69bde1c55ce 100644
--- a/engines/director/channel.h
+++ b/engines/director/channel.h
@@ -107,6 +107,7 @@ public:
 
 	bool _dirty;
 	bool _visible;
+	bool _hideFromStage; // Used in DT for hiding the channel from rendering
 	uint _constraint;
 	Graphics::ManagedSurface *_mask;
 
diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index cac3485c667..f07deac74b9 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -499,6 +499,7 @@ static const DebuggerTheme themes[kThemeCount] = {
 		IM_COL32(0xC8, 0x32, 0x00, 0xFF), // playhead_color
 		IM_COL32(0xFF, 0xFF, 0x00, 0x20), // current_statement_bg
 		IM_COL32(0x30, 0x30, 0xFF, 0xFF), // channel_toggle
+		IM_COL32(0xB4, 0x32, 0x32, 0xC8), // channel_hide_bg
 		IM_COL32(0x94, 0x00, 0xD3, 0xFF), // channelSelectedCol
 		IM_COL32(0xFF, 0xFF, 0x00, 0x3C), // channelHoveredCol
 		{                                 // contColors
@@ -556,6 +557,7 @@ static const DebuggerTheme themes[kThemeCount] = {
 		IM_COL32(0xC8, 0x32, 0x00, 0xFF), // playhead_color
 		IM_COL32(0xFF, 0xFF, 0x00, 0x60), // current_statement_bg
 		IM_COL32(0x00, 0x00, 0xB0, 0xFF), // channel_toggle
+		IM_COL32(0xDC, 0x3C, 0x3C, 0xC8), // channel_hide_bg
 		IM_COL32(0x94, 0x00, 0xD3, 0xFF), // channelSelectedCol
 		IM_COL32(0xD0, 0x90, 0x00, 0x50), // channelHoveredCol
 		{                                 // contColors
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index fd2e1ea8832..2501aac6e72 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -125,6 +125,7 @@ struct DebuggerTheme {
 	ImU32 playhead_color;
 	ImU32 current_statement_bg;
 	ImU32 channel_toggle;
+	ImU32 channel_hide_bg;
 	ImU32 channelSelectedCol;
 	ImU32 channelHoveredCol;
 	ImU32 contColors[6];
diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index 63809e503d9..f96a8d037ed 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -297,7 +297,17 @@ static void drawSidebar2(ImDrawList *dl, ImVec2 startPos, Score *score) {
 
 		ImVec2 center(rowMin.x + pad + radius, rowMax.y - pad - radius);
 
-		if (score->_channels[ch]->_visible)
+		bool isEngineVis = score->_channels[ch]->_visible;
+		bool isHiddenFromStage = score->_channels[ch]->_hideFromStage;
+
+		if (isHiddenFromStage) {
+			float offset = 6.0f;
+			ImVec2 boxMin(center.x - offset, center.y - offset);
+			ImVec2 boxMax(center.x + offset, center.y + offset);
+			dl->AddRectFilled(boxMin, boxMax, _state->theme->channel_hide_bg);
+		}
+
+		if (isEngineVis)
 			dl->AddCircleFilled(center, radius, _state->theme->channel_toggle);
 		else
 			dl->AddCircle(center, radius, _state->theme->channel_toggle);
@@ -307,7 +317,7 @@ static void drawSidebar2(ImDrawList *dl, ImVec2 startPos, Score *score) {
 		if (ImGui::IsItemHovered())
 			setTooltip("Playback toggle");
 		if (ImGui::IsItemClicked()) { // determines what happens on toggle of the button
-			score->_channels[ch]->_visible = !score->_channels[ch]->_visible;
+			score->_channels[ch]->_hideFromStage = !isHiddenFromStage;
 		}
 
 		// channel num and extra stuff if extended mode
@@ -1242,6 +1252,9 @@ void showChannels() {
 					_state->_scrollToChannel = false;
 				}
 
+				bool isEngineVis = channel._visible;
+				bool isHiddenFromStage = channel._hideFromStage;
+
 				{ // Playback toggle
 					ImGui::TableNextColumn();
 
@@ -1254,12 +1267,18 @@ void showChannels() {
 					ImGui::SetItemTooltip("Playback toggle");
 
 					if (ImGui::IsItemClicked(0)) {
-						score->_channels[i]->_visible = !score->_channels[i]->_visible;
-
+						channel._hideFromStage = !isHiddenFromStage;
 						selectedWindow->render(true);
 					}
 
-					if (score->_channels[i]->_visible)
+					if (isHiddenFromStage) {
+						float offset = 6.0f;
+						ImVec2 boxMin(mid.x - offset, mid.y - offset);
+						ImVec2 boxMax(mid.x + offset, mid.y + offset);
+						dl->AddRectFilled(boxMin, boxMax, _state->theme->channel_hide_bg);
+					}
+
+					if (isEngineVis)
 						dl->AddCircleFilled(mid, 4.0f, _state->theme->channel_toggle);
 					else
 						dl->AddCircle(mid, 4.0f, _state->theme->channel_toggle);
@@ -1290,7 +1309,9 @@ void showChannels() {
 					ImGui::Text("%s", sprite._castId.asString().c_str());
 					ImGui::TableNextColumn();
 					colN = "##vis" + chNum;
-					ImGui::Checkbox(colN.c_str(), &channel._visible);
+					if (ImGui::Checkbox(colN.c_str(), &channel._visible)) {
+						selectedWindow->render(true);
+					}
 					ImGui::TableNextColumn();
 					ImGui::Text("0x%02x", sprite._inkData);
 					ImGui::TableNextColumn();
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 5e9437b9389..fb588074cdb 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -202,7 +202,9 @@ bool Window::render(bool forceRedraw, Graphics::ManagedSurface *blitTo) {
 		bool shouldClear = true;
 		Channel *trailChannel = nullptr;
 		for (auto &j : _dirtyChannels) {
-			if (j->_visible && r == j->getBbox() && j->isTrail()) {
+			bool isHidden = false;
+			isHidden = j->_hideFromStage;
+			if (j->_visible && !isHidden && r == j->getBbox() && j->isTrail()) {
 				shouldClear = false;
 				trailChannel = j;
 				break;
@@ -227,6 +229,9 @@ bool Window::render(bool forceRedraw, Graphics::ManagedSurface *blitTo) {
 						continue;
 				}
 
+				if (j->_hideFromStage)
+					continue;
+
 				if (j->_visible) {
 					if (j->hasSubChannels()) {
 						Common::Array<Channel> *list = j->getSubChannels();


Commit: a9afc765bec1f2e51fbe2444a175457365a20b21
    https://github.com/scummvm/scummvm/commit/a9afc765bec1f2e51fbe2444a175457365a20b21
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Fix channel selection blocking clicks and row height

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


diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index f96a8d037ed..4f78cf3a9f8 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -1289,7 +1289,9 @@ void showChannels() {
 				ImGui::TableNextColumn();
 
 				bool isSelected = (_state->_selectedChannel == i + 1);
-				if (ImGui::Selectable(Common::String::format("%-3d", i + 1).c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns)) {
+				int numLines = (score->_version >= kFileVer600) ? MAX<int>(1, sprite._behaviors.size()) : 1;
+				float rowHeight = (ImGui::GetTextLineHeightWithSpacing() * numLines) + (ImGui::GetStyle().CellPadding.y * 2);
+				if (ImGui::Selectable(Common::String::format("%-3d", i + 1).c_str(), isSelected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap, ImVec2(0, rowHeight))) {
 					if (isSelected) {
 						_state->_selectedChannel = -1;
 					 } else {


Commit: 6c2c8e9303037f37afaa13ea8d6d49743ddd59b9
    https://github.com/scummvm/scummvm/commit/6c2c8e9303037f37afaa13ea8d6d49743ddd59b9
Author: Krish Ganatra (ganatrakrish2882005 at gmail.com)
Date: 2026-03-08T20:00:26+01:00

Commit Message:
DIRECTOR: DT: Fix ImGui crash when updating UI with paused submovies

Problem: Calling window->render(true) directly from UI clicks crashes the engine if it's paused and a submovie is active.

Fix: Instead of forcing an immediate render, push a full-screen dirty rect at the end of onImGuiRender().

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


diff --git a/engines/director/debugger/debugtools.cpp b/engines/director/debugger/debugtools.cpp
index f07deac74b9..ee94369c17c 100644
--- a/engines/director/debugger/debugtools.cpp
+++ b/engines/director/debugger/debugtools.cpp
@@ -722,6 +722,18 @@ void onImGuiRender() {
 	if (!_state)
 		return;
 
+	if (_state->_windowToRedraw) {
+		Graphics::ManagedSurface *surface = _state->_windowToRedraw->getSurface();
+		if (surface) {
+			Common::Rect fullScreen(0, 0, surface->w, surface->h);
+
+			_state->_windowToRedraw->addDirtyRect(fullScreen);
+			_state->_windowToRedraw->setDirty(true);
+		}
+
+		_state->_windowToRedraw = nullptr;
+	}
+
 	ImGuiIO &io = ImGui::GetIO();
 	io.ConfigFlags &= ~(ImGuiConfigFlags_NoMouseCursorChange | ImGuiConfigFlags_NoMouse);
 
diff --git a/engines/director/debugger/dt-internal.h b/engines/director/debugger/dt-internal.h
index 2501aac6e72..a3056963860 100644
--- a/engines/director/debugger/dt-internal.h
+++ b/engines/director/debugger/dt-internal.h
@@ -34,6 +34,7 @@
 #include "backends/imgui/components/imgui_memory_editor.h"
 
 #include "director/types.h"
+#include "director/window.h"
 #include "director/lingo/lingo.h"
 #include "director/lingo/lingodec/ast.h"
 #include "director/lingo/lingodec/handler.h"
@@ -291,6 +292,8 @@ typedef struct ImGuiState {
 	ImGuiEx::ImGuiLogger *_logger = nullptr;
 	bool _ignoreMouse = false;
 	bool _enableMultiViewport = true;
+
+	Window *_windowToRedraw = nullptr;
 } ImGuiState;
 
 // debugtools.cpp
diff --git a/engines/director/debugger/dt-score.cpp b/engines/director/debugger/dt-score.cpp
index 4f78cf3a9f8..5eb3deb928f 100644
--- a/engines/director/debugger/dt-score.cpp
+++ b/engines/director/debugger/dt-score.cpp
@@ -745,7 +745,7 @@ static void drawSpriteGrid(ImDrawList *dl, ImVec2 startPos, Score *score, Cast *
 					int playheadIdx = score->getCurrentFrameNum() - 1;
 					if (playheadIdx >= spanStart && playheadIdx <= spanEnd) {
 						Director::DT::setSelectedChannel(ch);
-						window->render(true);
+						_state->_windowToRedraw = window;
 					}
 				}
 
@@ -759,7 +759,7 @@ static void drawSpriteGrid(ImDrawList *dl, ImVec2 startPos, Score *score, Cast *
 					_state->_prevFrame = score->getCurrentFrameNum();
 
 					Director::DT::setSelectedChannel(ch);
-					window->render(true);
+					_state->_windowToRedraw = window;
 				}
 
 				if (ImGui::IsItemHovered()) {
@@ -1268,7 +1268,7 @@ void showChannels() {
 
 					if (ImGui::IsItemClicked(0)) {
 						channel._hideFromStage = !isHiddenFromStage;
-						selectedWindow->render(true);
+						_state->_windowToRedraw = selectedWindow;
 					}
 
 					if (isHiddenFromStage) {
@@ -1298,7 +1298,7 @@ void showChannels() {
 						_state->_selectedChannel = i + 1;
 					 }
 
-					selectedWindow->render(true);
+					_state->_windowToRedraw = selectedWindow;
 				}
 
 				ImGui::TableNextColumn();
@@ -1312,7 +1312,7 @@ void showChannels() {
 					ImGui::TableNextColumn();
 					colN = "##vis" + chNum;
 					if (ImGui::Checkbox(colN.c_str(), &channel._visible)) {
-						selectedWindow->render(true);
+						_state->_windowToRedraw = selectedWindow;
 					}
 					ImGui::TableNextColumn();
 					ImGui::Text("0x%02x", sprite._inkData);




More information about the Scummvm-git-logs mailing list