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

sev- noreply at scummvm.org
Wed Feb 11 21:16:09 UTC 2026


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

Summary:
ebb1d87858 GUI: Implement scrollable game removal confirmation dialog


Commit: ebb1d87858b49812f0e76cbbff55eb1850bc72ef
    https://github.com/scummvm/scummvm/commit/ebb1d87858b49812f0e76cbbff55eb1850bc72ef
Author: Mohit Bankar (mohitbankar1212 at gmail.com)
Date: 2026-02-11T22:16:04+01:00

Commit Message:
GUI: Implement scrollable game removal confirmation dialog

Add RemovalConfirmationDialog with scrollable game list display.

Changed paths:
    gui/launcher.cpp
    gui/launcher.h


diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 1944108c5f7..dbd1de787fd 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -48,6 +48,8 @@
 #include "gui/unknown-game-dialog.h"
 #include "gui/widgets/edittext.h"
 #include "gui/widgets/groupedlist.h"
+#include "gui/widgets/scrollcontainer.h"
+#include "gui/widget.h"
 #include "gui/widgets/tab.h"
 #include "gui/widgets/popup.h"
 #include "gui/widgets/grid.h"
@@ -1834,29 +1836,20 @@ void LauncherDialog::confirmRemoveGames(const Common::Array<bool> &selectedItems
 		_("Do you really want to remove the following %d game configuration(s)?\n\n"),
 		selectedCount);
 
-	// Add games to message (max 10 items, then ellipsis)
-	int displayCount = 0;
+	// Build array of game titles to display
+	Common::StringArray gameTitles;
 	for (int i = 0; i < (int)selectedItems.size(); ++i) {
 		if (selectedItems[i]) {
 			// i is the index in _domains and _domainTitles
 			if (i >= 0 && i < (int)_domains.size()) {
-				Common::String domainName = _domains[i];
-				Common::String gameTitle = (i < (int)_domainTitles.size()) ? _domainTitles[i] : domainName;
-				message += Common::U32String(gameTitle) + "\n";
-				displayCount++;
-				if (displayCount >= 10)
-					break;
+				Common::String gameTitle = (i < (int)_domainTitles.size()) ? _domainTitles[i] : _domains[i];
+				gameTitles.push_back(gameTitle);
 			}
 		}
 	}
 
-	// Add ellipsis if more than 10 items are selected
-	if (selectedCount > 10) {
-		message += Common::U32String("...\n");
-	}
-
-	MessageDialog alert(message, Common::U32String(_("Yes")), Common::U32String(_("No")));
-	if (alert.runModal() == GUI::kMessageOK) {
+	RemovalConfirmationDialog alert(message, gameTitles);
+	if (alert.runModal() == RemovalConfirmationDialog::kRemovalYes) {
 		removeGames(selectedItems, getType() == kLauncherDisplayGrid);
 	}
 }
@@ -1893,4 +1886,117 @@ void LauncherDialog::removeGames(const Common::Array<bool> &selectedItems, bool
 	g_gui.scheduleTopDialogRedraw();
 }
 
+RemovalConfirmationDialog::RemovalConfirmationDialog(const Common::U32String &message, const Common::StringArray &gameTitles)
+	: Dialog(""),
+	  _message(message),
+	  _gameTitles(gameTitles),
+	  _scrollContainer(nullptr),
+	  _buttonWidth(g_gui.xmlEval()->getVar("Globals.Button.Width", 0)),
+	  _buttonHeight(g_gui.xmlEval()->getVar("Globals.Button.Height", 0)),
+	  _scrollbarWidth(g_gui.xmlEval()->getVar("Globals.Scrollbar.Width", 0)) {
+
+	// Create scroll container with bogus size (will be sized in reflowLayout)
+	_scrollContainer = new ScrollContainerWidget(this, 10, 10, 20, 20);
+	_scrollContainer->setBackgroundType(ThemeEngine::kWidgetBackgroundPlain);
+
+	// Create Game Widgets with bogus size (will be sized in reflowLayout)
+	for (uint i = 0; i < _gameTitles.size(); ++i) {
+		_gameNameWidgets.push_back(new StaticTextWidget(_scrollContainer, 0, 0, 0, 0, _gameTitles[i], Graphics::kTextAlignLeft));
+	}
+
+	// Create Button Widgets with bogus size (will be sized in reflowLayout)
+	_buttons.push_back(new ButtonWidget(this, 0, 0, 0, 0, Common::U32String(_("Yes")), Common::U32String(), kRemovalYes, 'y'));
+	_buttons.push_back(new ButtonWidget(this, 0, 0, 0, 0, Common::U32String(_("No")), Common::U32String(), kRemovalNo, 'n'));
+
+	reflowLayout();
+}
+
+RemovalConfirmationDialog::~RemovalConfirmationDialog() {
+}
+
+void RemovalConfirmationDialog::reflowLayout() {
+	int16 screenW, screenH;
+	const Common::Rect safeArea = g_system->getSafeOverlayArea(&screenW, &screenH);
+
+	const int buttonCount = _buttons.size();
+	const int buttonsTotalWidth = buttonCount * _buttonWidth + (buttonCount - 1) * kButtonSpacing;
+
+	_maxlineWidth = g_gui.getFont().wordWrapText(_message, safeArea.width() - 2 * kHorizontalMargin, _messageLines);
+
+	// Calculate desired dialog size
+	_w = MAX(_maxlineWidth, buttonsTotalWidth) + 2 * kHorizontalMargin;
+	_w = MIN((uint16)_w, (uint16)safeArea.width());
+
+	int curY = 10;
+
+	// restrict the overall container height to max of 18 lines
+	_h = MIN((int)safeArea.height(), (int)(kLineHeight * (18 + 2) + curY + 5 + _buttonHeight));
+
+	// Center the dialog
+	_x = (screenW - _w) / 2;
+	_y = (screenH - _h) / 2;
+
+	safeArea.constrain(_x, _y, _w, _h);
+
+	int gameListHeight = _h;
+	gameListHeight -= curY;
+	gameListHeight -= (int)_messageWidgets.size() * kLineHeight;
+	gameListHeight -= 5;
+	gameListHeight -= kLineHeight;
+	gameListHeight -= _buttonHeight;
+
+	// Cleanup message line widgets
+	if (_messageWidgets.size() > 0) {
+		for (uint i = 0; i < _messageWidgets.size(); ++i) {
+			removeWidget(_messageWidgets[i]);
+			delete _messageWidgets[i];
+		}
+	}
+	_messageWidgets.clear();
+
+	for (uint i = 0; i < _messageLines.size(); ++i) {
+		_messageWidgets.push_back(new StaticTextWidget(this, kHorizontalMargin, curY, _w - 2 * kHorizontalMargin, kLineHeight, _messageLines[i], Graphics::kTextAlignCenter));
+		curY += kLineHeight;
+	}
+	_messageLines.clear();
+
+	curY -= kLineHeight;
+	curY += 5;
+
+	// Position scroll container
+	_scrollContainer->setPos(kHorizontalMargin, curY);
+	_scrollContainer->setSize(_w - 2 * kHorizontalMargin - _scrollbarWidth, gameListHeight);
+
+	// Size and Position game line widgets
+	int gameY = kGamePadding;
+	for (uint i = 0; i < _gameNameWidgets.size(); ++i) {
+		_gameNameWidgets[i]->setPos(kGamePadding, gameY);
+		_gameNameWidgets[i]->setSize(_scrollContainer->getWidth() - 2 * kGamePadding - _scrollbarWidth, kLineHeight);
+		gameY += kLineHeight;
+	}
+
+	curY += gameListHeight + kLineHeight;
+
+	// Size and Position button widgets
+	if (buttonCount) {
+		int buttonPos = (_w - buttonsTotalWidth) / 2;
+		for (int i = 0; i < buttonCount; ++i) {
+			_buttons[i]->setPos(buttonPos, curY);
+			_buttons[i]->setSize(_buttonWidth, _buttonHeight);
+			buttonPos += _buttonWidth + kButtonSpacing;
+		}
+	}
+
+	Dialog::reflowLayout();
+}
+
+void RemovalConfirmationDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
+	if (cmd == kRemovalYes || cmd == kRemovalNo) {
+		setResult(cmd);
+		close();
+	} else {
+		Dialog::handleCommand(sender, cmd, data);
+	}
+}
+
 } // End of namespace GUI
diff --git a/gui/launcher.h b/gui/launcher.h
index 5d1d8dc54d3..0c3b6295e2e 100644
--- a/gui/launcher.h
+++ b/gui/launcher.h
@@ -89,6 +89,7 @@ class StaticTextWidget;
 class EditTextWidget;
 class SaveLoadChooser;
 class PopUpWidget;
+class ScrollContainerWidget;
 
 struct LauncherEntry {
 	Common::String key;
@@ -252,6 +253,41 @@ private:
 	bool checkModifier(int modifier);
 };
 
+/**
+ * Removal confirmation dialog with scrollable content.
+ * Used by LauncherDialog to display game list for removal confirmation.
+ */
+class RemovalConfirmationDialog : public Dialog {
+public:
+	RemovalConfirmationDialog(const Common::U32String &message, const Common::StringArray &gameTitles);
+	~RemovalConfirmationDialog() override;
+
+	void reflowLayout() override;
+	void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) override;
+
+	static const uint32 kRemovalYes = 1;
+	static const uint32 kRemovalNo = 2;
+
+private:
+	static const int kHorizontalMargin = 10;
+	static const int kButtonSpacing = 10;
+	static const int kGamePadding = 10;
+
+	// Pre-calculated values
+	const int _buttonWidth;
+	const int _buttonHeight;
+	const int _scrollbarWidth;
+
+	Common::U32String _message;
+	Common::StringArray _gameTitles;
+	ScrollContainerWidget *_scrollContainer;
+	Common::Array<StaticTextWidget *> _messageWidgets;
+	Common::Array<StaticTextWidget *> _gameNameWidgets;
+	Common::Array<ButtonWidget *> _buttons;
+	Common::Array<Common::U32String> _messageLines;
+	int _maxlineWidth;
+};
+
 class LauncherChooser {
 protected:
 	LauncherDialog *_impl;




More information about the Scummvm-git-logs mailing list