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

bgK bastien.bouclet at gmail.com
Sat Jan 27 18:18:47 CET 2018


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

Summary:
3b50b57f54 GUI: Rework the frame limiter to actually reach the target framerate
0496ede62f GUI: Implement dirty-checking for widget redraws
fc37918130 GUI: Remove explicit redraw when scrolling the ScrollContainer
5878c618c9 GUI: Remove Dialog::markAsDirty to expose full GUI redraws
7dc602f352 GUI: Fix the caret drawing over the scroll bar in the list widget
21552fb4e6 GUI: Remove the parent from the button_idle DrawData
d26aa8255d GRAPHICS: Fix drawing clipped key colored bitmaps


Commit: 3b50b57f544cb7c719a5f02f061853e10885ae6c
    https://github.com/scummvm/scummvm/commit/3b50b57f544cb7c719a5f02f061853e10885ae6c
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:12:34+01:00

Commit Message:
GUI: Rework the frame limiter to actually reach the target framerate

The previous combination of a fixed 10 milliseconds delay and time since
last update checks meant that in most cases 20 milliseconds elapsed
between two calls to updateScreen resulting in a 50 fps framerate. On
systems with wait for vsync enabled that meant that some frames were
missed.

The new frame limiter waits for a variable delay equal to the non
consumed time in the slot allocated to the frame.

Changed paths:
    gui/gui-manager.cpp


diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 76f5577..2e947c6 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -299,10 +299,11 @@ void GuiManager::runLoop() {
 	}
 
 	Common::EventManager *eventMan = _system->getEventManager();
-	uint32 lastRedraw = 0;
-	const uint32 waitTime = 1000 / 60;
+	const uint32 targetFrameDuration = 1000 / 60;
 
 	while (!_dialogStack.empty() && activeDialog == getTopDialog() && !eventMan->shouldQuit()) {
+		uint32 frameStartTime = _system->getMillis(true);
+
 		redraw();
 
 		// Don't "tickle" the dialog until the theme has had a chance
@@ -312,14 +313,6 @@ void GuiManager::runLoop() {
 
 		if (_useStdCursor)
 			animateCursor();
-//		_theme->updateScreen();
-//		_system->updateScreen();
-
-		if (lastRedraw + waitTime < _system->getMillis(true)) {
-			lastRedraw = _system->getMillis(true);
-			_theme->updateScreen();
-			_system->updateScreen();
-		}
 
 		Common::Event event;
 
@@ -349,13 +342,6 @@ void GuiManager::runLoop() {
 			}
 
 			processEvent(event, activeDialog);
-
-
-			if (lastRedraw + waitTime < _system->getMillis(true)) {
-				lastRedraw = _system->getMillis(true);
-				_theme->updateScreen();
-				_system->updateScreen();
-			}
 		}
 
 		// Delete GuiObject that have been added to the trash for a delayed deletion
@@ -379,8 +365,14 @@ void GuiManager::runLoop() {
 			}
 		}
 
-		// Delay for a moment
-		_system->delayMillis(10);
+		_theme->updateScreen();
+
+		// Delay until the allocated frame time is elapsed to match the target frame rate
+		uint32 actualFrameDuration = _system->getMillis(true) - frameStartTime;
+		if (actualFrameDuration < targetFrameDuration) {
+			_system->delayMillis(targetFrameDuration - actualFrameDuration);
+		}
+		_system->updateScreen();
 	}
 
 	// WORKAROUND: When quitting we might not properly close the dialogs on


Commit: 0496ede62f8b86e1885d594e3aa5320c96b708eb
    https://github.com/scummvm/scummvm/commit/0496ede62f8b86e1885d594e3aa5320c96b708eb
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:12:34+01:00

Commit Message:
GUI: Implement dirty-checking for widget redraws

Changed paths:
    backends/keymapper/remap-dialog.cpp
    gui/KeysDialog.cpp
    gui/browser.cpp
    gui/chooser.cpp
    gui/console.cpp
    gui/dialog.cpp
    gui/dialog.h
    gui/downloaddialog.cpp
    gui/editgamedialog.cpp
    gui/filebrowser-dialog.cpp
    gui/fluidsynth-dialog.cpp
    gui/gui-manager.cpp
    gui/launcher.cpp
    gui/object.cpp
    gui/object.h
    gui/options.cpp
    gui/predictivedialog.cpp
    gui/recorderdialog.cpp
    gui/remotebrowser.cpp
    gui/saveload-dialog.cpp
    gui/storagewizarddialog.cpp
    gui/themebrowser.cpp
    gui/widget.cpp
    gui/widget.h
    gui/widgets/editable.cpp
    gui/widgets/edittext.cpp
    gui/widgets/list.cpp
    gui/widgets/popup.cpp
    gui/widgets/popup.h
    gui/widgets/scrollbar.cpp
    gui/widgets/scrollbar.h
    gui/widgets/scrollcontainer.cpp
    gui/widgets/tab.cpp
    gui/widgets/tab.h


diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index 3aa3647..78a9520 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -267,7 +267,7 @@ void RemapDialog::startRemapping(uint i) {
 	_remapTimeout = g_system->getMillis() + kRemapTimeoutDelay;
 	Action *activeRemapAction = _currentActions[_topAction + i].action;
 	_keymapWidgets[i].keyButton->setLabel("...");
-	_keymapWidgets[i].keyButton->draw();
+	_keymapWidgets[i].keyButton->markAsDirty();
 	_keymapper->startRemappingMode(activeRemapAction);
 
 }
@@ -414,8 +414,8 @@ void RemapDialog::refreshKeymap() {
 
 	_topAction = newTopAction;
 
-	//_container->draw();
-	_scrollBar->draw();
+	//_container->markAsDirty();
+	_scrollBar->markAsDirty();
 
 	uint actionI = _topAction;
 
@@ -446,12 +446,12 @@ void RemapDialog::refreshKeymap() {
 			widg.keyButton->setVisible(false);
 			widg.clearButton->setVisible(false);
 		}
-		//widg.actionText->draw();
-		//widg.keyButton->draw();
+		//widg.actionText->markAsDirty();
+		//widg.keyButton->markAsDirty();
 	}
 	// need to redraw entire Dialog so that invisible
 	// widgets disappear
-	draw();
+	markAsDirty();
 }
 
 
diff --git a/gui/KeysDialog.cpp b/gui/KeysDialog.cpp
index fcf9201..68e9bd8 100644
--- a/gui/KeysDialog.cpp
+++ b/gui/KeysDialog.cpp
@@ -82,7 +82,7 @@ void KeysDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
 				selection = Common::String::format(_("Associated key : none"));
 
 			_keyMapping->setLabel(selection);
-			_keyMapping->draw();
+			_keyMapping->markAsDirty();
 		}
 		break;
 	case kMapCmd:
@@ -105,11 +105,11 @@ void KeysDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
 
 			_actionTitle->setLabel(_("Press the key to associate"));
 			_keyMapping->setLabel(selection);
-			_keyMapping->draw();
+			_keyMapping->markAsDirty();
 			Actions::Instance()->beginMapping(true);
 			_actionsList->setEnabled(false);
 		}
-		_actionTitle->draw();
+		_actionTitle->markAsDirty();
 		break;
 	case kOKCmd:
 		Actions::Instance()->saveMapping();
@@ -144,8 +144,8 @@ void KeysDialog::handleKeyUp(Common::KeyState state) {
 
 		_actionTitle->setLabel(_("Choose an action to map"));
 		_keyMapping->setLabel(selection);
-		_keyMapping->draw();
-		_actionTitle->draw();
+		_keyMapping->markAsDirty();
+		_actionTitle->markAsDirty();
 		_actionSelected = -1;
 		_actionsList->setEnabled(true);
 		Actions::Instance()->beginMapping(false);
diff --git a/gui/browser.cpp b/gui/browser.cpp
index 19fa791..bbfe485 100644
--- a/gui/browser.cpp
+++ b/gui/browser.cpp
@@ -191,7 +191,7 @@ void BrowserDialog::updateListing() {
 	_fileList->scrollTo(0);
 
 	// Finally, redraw
-	draw();
+	markAsDirty();
 }
 
 } // End of namespace GUI
diff --git a/gui/chooser.cpp b/gui/chooser.cpp
index 61af3de..1351263 100644
--- a/gui/chooser.cpp
+++ b/gui/chooser.cpp
@@ -64,7 +64,7 @@ void ChooserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		break;
 	case kListSelectionChangedCmd:
 		_chooseButton->setEnabled(item >= 0);
-		_chooseButton->draw();
+		_chooseButton->markAsDirty();
 		break;
 	case kCloseCmd:
 		setResult(-1);
diff --git a/gui/console.cpp b/gui/console.cpp
index f99197c..5d28f5a 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -173,6 +173,7 @@ void ConsoleDialog::drawDialog() {
 		drawLine(line, false);
 
 	// Draw the scrollbar
+	_scrollBar->markAsDirty();
 	_scrollBar->draw();
 }
 
@@ -213,7 +214,7 @@ void ConsoleDialog::reflowLayout() {
 	updateScrollBuffer();
 
 	Dialog::reflowLayout();
-	draw();
+	markAsDirty();
 }
 
 void ConsoleDialog::handleTickle() {
@@ -236,13 +237,13 @@ void ConsoleDialog::handleTickle() {
 			// End the slide
 			_slideMode = kNoSlideMode;
 			_y = 0;
-			draw();
+			markAsDirty();
 		} else if (_slideMode == kUpSlideMode && _y <= -_h) {
 			// End the slide
 			//_slideMode = kNoSlideMode;
 			close();
 		} else
-			draw();
+			markAsDirty();
 	}
 
 	_scrollBar->handleTickle();
@@ -291,7 +292,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 		print(PROMPT);
 		_promptStartPos = _promptEndPos = _currentPos;
 
-		draw();
+		markAsDirty();
 		if (!keepRunning)
 			slideUpAndClose();
 		break;
@@ -376,7 +377,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 		} else {
 			_currentPos = _promptEndPos;
 		}
-		draw();
+		markAsDirty();
 		break;
 
 	case Common::KEYCODE_KP2:
@@ -404,7 +405,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 					_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
 			}
 			updateScrollBuffer();
-			draw();
+			markAsDirty();
 		}
 		break;
 
@@ -445,7 +446,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 		} else {
 			_currentPos = _promptStartPos;
 		}
-		draw();
+		markAsDirty();
 		break;
 
 	case Common::KEYCODE_KP8:
@@ -470,7 +471,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 			if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
 				_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
 			updateScrollBuffer();
-			draw();
+			markAsDirty();
 		}
 		break;
 
@@ -507,7 +508,7 @@ void ConsoleDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		int newPos = (int)data + _linesPerPage - 1 + _firstLineInBuffer;
 		if (newPos != _scrollLine) {
 			_scrollLine = newPos;
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -517,25 +518,25 @@ void ConsoleDialog::specialKeys(int keycode) {
 	switch (keycode) {
 	case Common::KEYCODE_a:
 		_currentPos = _promptStartPos;
-		draw();
+		markAsDirty();
 		break;
 	case Common::KEYCODE_d:
 		if (_currentPos < _promptEndPos) {
 			killChar();
-			draw();
+			markAsDirty();
 		}
 		break;
 	case Common::KEYCODE_e:
 		_currentPos = _promptEndPos;
-		draw();
+		markAsDirty();
 		break;
 	case Common::KEYCODE_k:
 		killLine();
-		draw();
+		markAsDirty();
 		break;
 	case Common::KEYCODE_w:
 		killLastWord();
-		draw();
+		markAsDirty();
 		break;
 	}
 }
@@ -625,7 +626,7 @@ void ConsoleDialog::historyScroll(int direction) {
 	// Ensure once more the caret is visible (in case of very long history entries)
 	scrollToCurrent();
 
-	draw();
+	markAsDirty();
 }
 
 void ConsoleDialog::nextLine() {
@@ -703,7 +704,7 @@ void ConsoleDialog::print(const char *str) {
 	while (*str)
 		printCharIntern(*str++);
 
-	draw();
+	markAsDirty();
 }
 
 void ConsoleDialog::drawCaret(bool erase) {
@@ -732,7 +733,7 @@ void ConsoleDialog::scrollToCurrent() {
 	} else if (line > _scrollLine) {
 		_scrollLine = line;
 		updateScrollBuffer();
-		draw();
+		markAsDirty();
 	}
 }
 
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index 24b3db4..7434118 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -153,7 +153,7 @@ void Dialog::releaseFocus() {
 	}
 }
 
-void Dialog::draw() {
+void Dialog::markAsDirty() {
 	//TANOKU - FIXME when is this enabled? what does this do?
 	// Update: called on tab drawing, mainly...
 	// we can pass this as open a new dialog or something
@@ -161,6 +161,14 @@ void Dialog::draw() {
 	g_gui._redrawStatus = GUI::GuiManager::kRedrawTopDialog;
 }
 
+void Dialog::markWidgetsAsDirty() {
+	Widget *w = _firstWidget;
+	while (w) {
+		w->markAsDirty();
+		w = w->_next;
+	}
+}
+
 void Dialog::drawDialog() {
 
 	if (!isVisible())
@@ -168,6 +176,15 @@ void Dialog::drawDialog() {
 
 	g_gui.theme()->drawDialogBackground(Common::Rect(_x, _y, _x+_w, _y+_h), _backgroundType);
 
+	markWidgetsAsDirty();
+	drawWidgets();
+}
+
+void Dialog::drawWidgets() {
+
+	if (!isVisible())
+		return;
+
 	// Draw all children
 	Widget *w = _firstWidget;
 	while (w) {
diff --git a/gui/dialog.h b/gui/dialog.h
index cf734a8..cb6e13f 100644
--- a/gui/dialog.h
+++ b/gui/dialog.h
@@ -88,9 +88,16 @@ protected:
 	virtual void open();
 	virtual void close();
 
-	virtual void draw();
+	void markAsDirty() override;
+	/** Recursively mark all the widgets in this dialog as dirty so they are redrawn */
+	void markWidgetsAsDirty();
+
+	/** Draw the dialog in its entirety (background and widgets) */
 	virtual void drawDialog();
 
+	/** Draw only the dialog's widgets */
+	void drawWidgets();
+
 	virtual void handleTickle(); // Called periodically (in every guiloop() )
 	virtual void handleMouseDown(int x, int y, int button, int clickCount);
 	virtual void handleMouseUp(int x, int y, int button, int clickCount);
diff --git a/gui/downloaddialog.cpp b/gui/downloaddialog.cpp
index bcbe956..dc6d7ff 100644
--- a/gui/downloaddialog.cpp
+++ b/gui/downloaddialog.cpp
@@ -81,7 +81,7 @@ void DownloadDialog::open() {
 		if (!selectDirectories())
 			close();
 	reflowLayout();
-	draw();
+	markAsDirty();
 }
 
 void DownloadDialog::close() {
@@ -101,7 +101,7 @@ void DownloadDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 	case kDownloadProgressCmd:
 		if (!_close) {
 			refreshWidgets();
-			draw();
+			markAsDirty();
 		}
 		break;
 	case kDownloadEndedCmd:
@@ -196,7 +196,7 @@ void DownloadDialog::handleTickle() {
 	int32 progress = (int32)(100 * CloudMan.getDownloadingProgress());
 	if (_progressBar->getValue() != progress) {
 		refreshWidgets();
-		draw();
+		markAsDirty();
 	}
 
 	Dialog::handleTickle();
diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp
index 348ba5c..b99b53c 100644
--- a/gui/editgamedialog.cpp
+++ b/gui/editgamedialog.cpp
@@ -424,26 +424,26 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 	switch (cmd) {
 	case kCmdGlobalGraphicsOverride:
 		setGraphicSettingsState(data != 0);
-		draw();
+		markAsDirty();
 		break;
 	case kCmdGlobalAudioOverride:
 		setAudioSettingsState(data != 0);
 		setSubtitleSettingsState(data != 0);
 		if (_globalVolumeOverride == NULL)
 			setVolumeSettingsState(data != 0);
-		draw();
+		markAsDirty();
 		break;
 	case kCmdGlobalMIDIOverride:
 		setMIDISettingsState(data != 0);
-		draw();
+		markAsDirty();
 		break;
 	case kCmdGlobalMT32Override:
 		setMT32SettingsState(data != 0);
-		draw();
+		markAsDirty();
 		break;
 	case kCmdGlobalVolumeOverride:
 		setVolumeSettingsState(data != 0);
-		draw();
+		markAsDirty();
 		break;
 	case kCmdChooseSoundFontCmd:
 	{
@@ -459,7 +459,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			else
 				_soundFontClearButton->setEnabled(false);
 
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -477,9 +477,9 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			// FSList files = dir.listDir(FSNode::kListFilesOnly);
 
 			_gamePathWidget->setLabel(dir.getPath());
-			draw();
+			markAsDirty();
 		}
-		draw();
+		markAsDirty();
 		break;
 	}
 
@@ -491,9 +491,9 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_extraPathWidget->setLabel(dir.getPath());
-			draw();
+			markAsDirty();
 		}
-		draw();
+		markAsDirty();
 		break;
 	}
 	// Change path for stored save game (perm and temp) data
@@ -508,9 +508,9 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			MessageDialog warningMessage(_("Saved games sync feature doesn't work with non-default directories. If you want your saved games to sync, use default directory."));
 			warningMessage.runModal();
 #endif
-			draw();
+			markAsDirty();
 		}
-		draw();
+		markAsDirty();
 		break;
 	}
 
diff --git a/gui/filebrowser-dialog.cpp b/gui/filebrowser-dialog.cpp
index 93395ba..95fc4d9 100644
--- a/gui/filebrowser-dialog.cpp
+++ b/gui/filebrowser-dialog.cpp
@@ -88,7 +88,7 @@ void FileBrowserDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32
 		break;
 	case kListSelectionChangedCmd:
 		_fileName->setEditString(_fileList->getList().operator[](_fileList->getSelected()).c_str());
-		_fileName->draw();
+		_fileName->markAsDirty();
 		break;
 	case kListItemActivatedCmd:
 	case kListItemDoubleClickedCmd:
@@ -154,7 +154,7 @@ void FileBrowserDialog::updateListing() {
 	_fileList->scrollTo(0);
 
 	// Finally, redraw
-	draw();
+	markAsDirty();
 }
 
 } // End of namespace GUI
diff --git a/gui/fluidsynth-dialog.cpp b/gui/fluidsynth-dialog.cpp
index af5ee6f..fb72997 100644
--- a/gui/fluidsynth-dialog.cpp
+++ b/gui/fluidsynth-dialog.cpp
@@ -180,45 +180,45 @@ void FluidSynthSettingsDialog::handleCommand(CommandSender *sender, uint32 cmd,
 		break;
 	case kChorusVoiceCountChangedCmd:
 		_chorusVoiceCountLabel->setLabel(Common::String::format("%d", _chorusVoiceCountSlider->getValue()));
-		_chorusVoiceCountLabel->draw();
+		_chorusVoiceCountLabel->markAsDirty();
 		break;
 	case kChorusLevelChangedCmd:
 		_chorusLevelLabel->setLabel(Common::String::format("%d", _chorusLevelSlider->getValue()));
-		_chorusLevelLabel->draw();
+		_chorusLevelLabel->markAsDirty();
 		break;
 	case kChorusSpeedChangedCmd:
 		_chorusSpeedLabel->setLabel(Common::String::format("%d", _chorusSpeedSlider->getValue()));
-		_chorusSpeedLabel->draw();
+		_chorusSpeedLabel->markAsDirty();
 		break;
 	case kChorusDepthChangedCmd:
 		_chorusDepthLabel->setLabel(Common::String::format("%d", _chorusDepthSlider->getValue()));
-		_chorusDepthLabel->draw();
+		_chorusDepthLabel->markAsDirty();
 		break;
 	case kActivateReverbCmd:
 		setReverbSettingsState(data);
 		break;
 	case kReverbRoomSizeChangedCmd:
 		_reverbRoomSizeLabel->setLabel(Common::String::format("%d", _reverbRoomSizeSlider->getValue()));
-		_reverbRoomSizeLabel->draw();
+		_reverbRoomSizeLabel->markAsDirty();
 		break;
 	case kReverbDampingChangedCmd:
 		_reverbDampingLabel->setLabel(Common::String::format("%d", _reverbDampingSlider->getValue()));
-		_reverbDampingLabel->draw();
+		_reverbDampingLabel->markAsDirty();
 		break;
 	case kReverbWidthChangedCmd:
 		_reverbWidthLabel->setLabel(Common::String::format("%d", _reverbWidthSlider->getValue()));
-		_reverbWidthLabel->draw();
+		_reverbWidthLabel->markAsDirty();
 		break;
 	case kReverbLevelChangedCmd:
 		_reverbLevelLabel->setLabel(Common::String::format("%d", _reverbLevelSlider->getValue()));
-		_reverbLevelLabel->draw();
+		_reverbLevelLabel->markAsDirty();
 		break;
 	case kResetSettingsCmd: {
 		MessageDialog alert(_("Do you really want to reset all FluidSynth settings to their default values?"), _("Yes"), _("No"));
 		if (alert.runModal() == GUI::kMessageOK) {
 			resetSettings();
 			readSettings();
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 2e947c6..4b91019 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -208,7 +208,7 @@ bool GuiManager::loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx,
 void GuiManager::redraw() {
 	ThemeEngine::ShadingStyle shading;
 
-	if (_redrawStatus == kRedrawDisabled || _dialogStack.empty())
+	if (_dialogStack.empty())
 		return;
 
 	shading = (ThemeEngine::ShadingStyle)xmlEval()->getVar("Dialog." + _dialogStack.top()->_name + ".Shading", 0);
@@ -241,9 +241,12 @@ void GuiManager::redraw() {
 			break;
 
 		default:
-			return;
+			break;
 	}
 
+	// Redraw the widgets that are marked as dirty
+	_dialogStack.top()->drawWidgets();
+
 	_theme->updateScreen();
 	_redrawStatus = kRedrawDisabled;
 }
@@ -304,8 +307,6 @@ void GuiManager::runLoop() {
 	while (!_dialogStack.empty() && activeDialog == getTopDialog() && !eventMan->shouldQuit()) {
 		uint32 frameStartTime = _system->getMillis(true);
 
-		redraw();
-
 		// Don't "tickle" the dialog until the theme has had a chance
 		// to re-allocate buffers in case of a scaler change.
 
@@ -365,7 +366,7 @@ void GuiManager::runLoop() {
 			}
 		}
 
-		_theme->updateScreen();
+		redraw();
 
 		// Delay until the allocated frame time is elapsed to match the target frame rate
 		uint32 actualFrameDuration = _system->getMillis(true) - frameStartTime;
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index fd75674..5f73776 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -323,7 +323,7 @@ void LauncherDialog::addGame() {
 				selectTarget(newTarget);
 			}
 
-			draw();
+			markAsDirty();
 		}
 
 		// We need to update the buttons here, so "Mass add" will revert to "Add game"
@@ -427,7 +427,7 @@ void LauncherDialog::removeGame(int item) {
 
 		// Update the ListWidget and force a redraw
 		updateListing();
-		draw();
+		markAsDirty();
 	}
 }
 
@@ -452,7 +452,7 @@ void LauncherDialog::editGame(int item) {
 		// Update the ListWidget, reselect the edited game and force a redraw
 		updateListing();
 		selectTarget(editDialog.getDomain());
-		draw();
+		markAsDirty();
 	}
 }
 
@@ -614,7 +614,7 @@ bool LauncherDialog::doGameDetection(const Common::String &path) {
 			// Update the ListWidget, select the new item, and force a redraw
 			updateListing();
 			selectTarget(editDialog.getDomain());
-			draw();
+			markAsDirty();
 		} else {
 			// User aborted, remove the the new domain again
 			ConfMan.removeGameDomain(domain);
@@ -688,15 +688,15 @@ void LauncherDialog::updateButtons() {
 	bool enable = (_list->getSelected() >= 0);
 	if (enable != _startButton->isEnabled()) {
 		_startButton->setEnabled(enable);
-		_startButton->draw();
+		_startButton->markAsDirty();
 	}
 	if (enable != _editButton->isEnabled()) {
 		_editButton->setEnabled(enable);
-		_editButton->draw();
+		_editButton->markAsDirty();
 	}
 	if (enable != _removeButton->isEnabled()) {
 		_removeButton->setEnabled(enable);
-		_removeButton->draw();
+		_removeButton->markAsDirty();
 	}
 
 	int item = _list->getSelected();
@@ -707,7 +707,7 @@ void LauncherDialog::updateButtons() {
 
 	if (en != _loadButton->isEnabled()) {
 		_loadButton->setEnabled(en);
-		_loadButton->draw();
+		_loadButton->markAsDirty();
 	}
 	switchButtonsText(_addButton, "~A~dd Game...", _s("Mass Add..."));
 #ifdef ENABLE_EVENTRECORDER
diff --git a/gui/object.cpp b/gui/object.cpp
index de66d95..327bc27 100644
--- a/gui/object.cpp
+++ b/gui/object.cpp
@@ -30,7 +30,7 @@
 namespace GUI {
 
 GuiObject::GuiObject(const Common::String &name)
-	: _x(-1000), _y(-1000), _w(0), _h(0), _name(name), _firstWidget(0), _textDrawableArea(Common::Rect(0, 0, 0, 0)) {
+	: _x(-1000), _y(-1000), _w(0), _h(0), _name(name), _firstWidget(nullptr) {
 	reflowLayout();
 }
 
diff --git a/gui/object.h b/gui/object.h
index 1541c35..af64697 100644
--- a/gui/object.h
+++ b/gui/object.h
@@ -70,7 +70,7 @@ protected:
 	Widget		*_firstWidget;
 
 public:
-	GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _firstWidget(0), _textDrawableArea(Common::Rect(0, 0, 0, 0)) { }
+	GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _firstWidget(nullptr) { }
 	GuiObject(const Common::String &name);
 	~GuiObject();
 
@@ -87,7 +87,7 @@ public:
 
 	virtual bool	isVisible() const = 0;
 
-	virtual void	draw() = 0;
+	virtual void    markAsDirty() = 0;
 
 	virtual void	reflowLayout();
 
diff --git a/gui/options.cpp b/gui/options.cpp
index d1e2be1..38ad185 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -709,12 +709,12 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 	switch (cmd) {
 	case kMidiGainChanged:
 		_midiGainLabel->setLabel(Common::String::format("%.2f", (double)_midiGainSlider->getValue() / 100.0));
-		_midiGainLabel->draw();
+		_midiGainLabel->markAsDirty();
 		break;
 	case kMusicVolumeChanged: {
 		const int newValue = _musicVolumeSlider->getValue();
 		_musicVolumeLabel->setValue(newValue);
-		_musicVolumeLabel->draw();
+		_musicVolumeLabel->markAsDirty();
 
 		if (_guioptions.contains(GUIO_LINKMUSICTOSFX)) {
 			updateSfxVolume(newValue);
@@ -729,7 +729,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 	case kSfxVolumeChanged: {
 		const int newValue = _sfxVolumeSlider->getValue();
 		_sfxVolumeLabel->setValue(_sfxVolumeSlider->getValue());
-		_sfxVolumeLabel->draw();
+		_sfxVolumeLabel->markAsDirty();
 
 		if (_guioptions.contains(GUIO_LINKMUSICTOSFX)) {
 			updateMusicVolume(newValue);
@@ -744,7 +744,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 	case kSpeechVolumeChanged: {
 		const int newValue = _speechVolumeSlider->getValue();
 		_speechVolumeLabel->setValue(newValue);
-		_speechVolumeLabel->draw();
+		_speechVolumeLabel->markAsDirty();
 
 		if (_guioptions.contains(GUIO_LINKSPEECHTOSFX)) {
 			updateSfxVolume(newValue);
@@ -768,20 +768,20 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		break;
 	case kSubtitleSpeedChanged:
 		_subSpeedLabel->setValue(_subSpeedSlider->getValue());
-		_subSpeedLabel->draw();
+		_subSpeedLabel->markAsDirty();
 		break;
 	case kClearSoundFontCmd:
 		_soundFont->setLabel(_c("None", "soundfont"));
 		_soundFontClearButton->setEnabled(false);
-		draw();
+		markAsDirty();
 		break;
 	case kKbdMouseSpeedChanged:
 		_kbdMouseSpeedLabel->setLabel(_(kbdMouseSpeedLabels[_kbdMouseSpeedSlider->getValue()]));
-		_kbdMouseSpeedLabel->draw();
+		_kbdMouseSpeedLabel->markAsDirty();
 		break;
 	case kJoystickDeadzoneChanged:
 		_joystickDeadzoneLabel->setValue(_joystickDeadzoneSlider->getValue());
-		_joystickDeadzoneLabel->draw();
+		_joystickDeadzoneLabel->markAsDirty();
 		break;
 	case kApplyCmd:
 		apply();
@@ -1320,22 +1320,22 @@ int OptionsDialog::getSubtitleMode(bool subtitles, bool speech_mute) {
 void OptionsDialog::updateMusicVolume(const int newValue) const {
 	_musicVolumeLabel->setValue(newValue);
 	_musicVolumeSlider->setValue(newValue);
-	_musicVolumeLabel->draw();
-	_musicVolumeSlider->draw();
+	_musicVolumeLabel->markAsDirty();
+	_musicVolumeSlider->markAsDirty();
 }
 
 void OptionsDialog::updateSfxVolume(const int newValue) const {
 	_sfxVolumeLabel->setValue(newValue);
 	_sfxVolumeSlider->setValue(newValue);
-	_sfxVolumeLabel->draw();
-	_sfxVolumeSlider->draw();
+	_sfxVolumeLabel->markAsDirty();
+	_sfxVolumeSlider->markAsDirty();
 }
 
 void OptionsDialog::updateSpeechVolume(const int newValue) const {
 	_speechVolumeLabel->setValue(newValue);
 	_speechVolumeSlider->setValue(newValue);
-	_speechVolumeLabel->draw();
-	_speechVolumeSlider->draw();
+	_speechVolumeLabel->markAsDirty();
+	_speechVolumeSlider->markAsDirty();
 }
 
 void OptionsDialog::reflowLayout() {
@@ -1936,7 +1936,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 				error.runModal();
 				return;
 			}
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -1946,7 +1946,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_themePath->setLabel(dir.getPath());
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -1956,7 +1956,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_extraPath->setLabel(dir.getPath());
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -1967,7 +1967,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_pluginsPath->setLabel(dir.getPath());
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -1982,7 +1982,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			if (path.empty())
 				path = "/"; // absolute root
 			_rootPath->setLabel(path);
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -2013,7 +2013,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			else
 				_soundFontClearButton->setEnabled(false);
 
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
@@ -2107,7 +2107,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 		if (_serverPort) {
 			_serverPort->setEditString(Common::String::format("%u", Networking::LocalWebserver::DEFAULT_SERVER_PORT));
 		}
-		draw();
+		markAsDirty();
 		break;
 	}
 #endif // USE_SDL_NET
@@ -2144,7 +2144,7 @@ void GlobalOptionsDialog::handleTickle() {
 #endif
 	if (_redrawCloudTab) {
 		setupCloudTab();
-		draw();
+		markAsDirty();
 		_redrawCloudTab = false;
 	}
 #endif
diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp
index 9336671..5650fd8 100644
--- a/gui/predictivedialog.cpp
+++ b/gui/predictivedialog.cpp
@@ -995,7 +995,7 @@ void PredictiveDialog::pressEditText() {
 	Common::strlcat(_predictiveResult, _currentWord.c_str(), sizeof(_predictiveResult));
 	_editText->setEditString(_predictiveResult);
 	//_editText->setCaretPos(_prefix.size() + _currentWord.size());
-	_editText->draw();
+	_editText->markAsDirty();
 }
 
 } // namespace GUI
diff --git a/gui/recorderdialog.cpp b/gui/recorderdialog.cpp
index 7e8e12b..cd89b58 100644
--- a/gui/recorderdialog.cpp
+++ b/gui/recorderdialog.cpp
@@ -211,7 +211,7 @@ void RecorderDialog::updateList() {
 		file.close();
 	}
 	_list->setList(namesList);
-	_list->draw();
+	_list->markAsDirty();
 }
 
 int RecorderDialog::runModal(Common::String &target) {
@@ -253,7 +253,7 @@ void RecorderDialog::updateSelection(bool redraw) {
 		_screenShotsCount = -1;
 		_currentScreenshot = 0;
 		_gfxWidget->setGfx(-1, -1, 0, 0, 0);
-		_gfxWidget->draw();
+		_gfxWidget->markAsDirty();
 		updateScreenShotsText();
 	}
 }
@@ -283,7 +283,7 @@ void RecorderDialog::updateScreenshot() {
 	} else {
 		_gfxWidget->setGfx(-1, -1, 0, 0, 0);
 	}
-	_gfxWidget->draw();
+	_gfxWidget->markAsDirty();
 }
 
 void RecorderDialog::updateScreenShotsText() {
diff --git a/gui/remotebrowser.cpp b/gui/remotebrowser.cpp
index 0293205..1d50300 100644
--- a/gui/remotebrowser.cpp
+++ b/gui/remotebrowser.cpp
@@ -162,7 +162,7 @@ void RemoteBrowserDialog::updateListing() {
 	_fileList->setEnabled(!_navigationLocked);
 
 	// Finally, redraw
-	draw();
+	markAsDirty();
 }
 
 void RemoteBrowserDialog::goUp() {
diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp
index 189760b..6d2a43b 100644
--- a/gui/saveload-dialog.cpp
+++ b/gui/saveload-dialog.cpp
@@ -60,7 +60,7 @@ SaveLoadCloudSyncProgressDialog::SaveLoadCloudSyncProgressDialog(bool canRunInBa
 	new ButtonWidget(this, "SaveLoadCloudSyncProgress.Cancel", "Cancel", 0, kCancelSyncCmd, Common::ASCII_ESCAPE);	// Cancel dialog
 	ButtonWidget *backgroundButton = new ButtonWidget(this, "SaveLoadCloudSyncProgress.Background", "Run in background", 0, kBackgroundSyncCmd, Common::ASCII_RETURN);	// Confirm dialog
 	backgroundButton->setEnabled(canRunInBackground);
-	draw();
+	markAsDirty();
 }
 
 SaveLoadCloudSyncProgressDialog::~SaveLoadCloudSyncProgressDialog() {
@@ -72,7 +72,7 @@ void SaveLoadCloudSyncProgressDialog::handleCommand(CommandSender *sender, uint3
 	case kSavesSyncProgressCmd:
 		_percentLabel->setLabel(Common::String::format("%u%%", data));
 		_progressBar->setValue(data);
-		_progressBar->draw();
+		_progressBar->markAsDirty();
 		break;
 
 	case kCancelSyncCmd:
@@ -594,14 +594,14 @@ void SaveLoadChooserSimple::updateSelection(bool redraw) {
 	_deleteButton->setEnabled(isDeletable && !isLocked && (selItem >= 0) && (!_list->getSelectedString().empty()));
 
 	if (redraw) {
-		_gfxWidget->draw();
-		_date->draw();
-		_time->draw();
-		_playtime->draw();
-		_chooseButton->draw();
-		_deleteButton->draw();
-
-		draw();
+		_gfxWidget->markAsDirty();
+		_date->markAsDirty();
+		_time->markAsDirty();
+		_playtime->markAsDirty();
+		_chooseButton->markAsDirty();
+		_deleteButton->markAsDirty();
+
+		markAsDirty();
 	}
 }
 
@@ -703,7 +703,7 @@ void SaveLoadChooserSimple::updateSaveList() {
 	else
 		_chooseButton->setEnabled(false);
 
-	draw();
+	markAsDirty();
 }
 
 // SaveLoadChooserGrid implementation
@@ -761,13 +761,13 @@ void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint3
 	case kNextCmd:
 		++_curPage;
 		updateSaves();
-		draw();
+		markAsDirty();
 		break;
 
 	case kPrevCmd:
 		--_curPage;
 		updateSaves();
-		draw();
+		markAsDirty();
 		break;
 
 	case kNewSaveCmd:
@@ -788,13 +788,13 @@ void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
 		if (_nextButton->isEnabled()) {
 			++_curPage;
 			updateSaves();
-			draw();
+			markAsDirty();
 		}
 	} else {
 		if (_prevButton->isEnabled()) {
 			--_curPage;
 			updateSaves();
-			draw();
+			markAsDirty();
 		}
 	}
 }
@@ -802,7 +802,7 @@ void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
 void SaveLoadChooserGrid::updateSaveList() {
 	SaveLoadChooserDialog::updateSaveList();
 	updateSaves();
-	draw();
+	markAsDirty();
 }
 
 void SaveLoadChooserGrid::open() {
diff --git a/gui/storagewizarddialog.cpp b/gui/storagewizarddialog.cpp
index 085f901..e7a684c 100644
--- a/gui/storagewizarddialog.cpp
+++ b/gui/storagewizarddialog.cpp
@@ -231,7 +231,7 @@ void StorageWizardDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 				_codeWidget[i]->setEditString(subcode);
 			}
 			handleCommand(sender, kCodeBoxCmd, data);
-			draw();
+			markAsDirty();
 		}
 		break;
 	}
diff --git a/gui/themebrowser.cpp b/gui/themebrowser.cpp
index 75be555..d21979c 100644
--- a/gui/themebrowser.cpp
+++ b/gui/themebrowser.cpp
@@ -115,7 +115,7 @@ void ThemeBrowser::updateListing() {
 	_fileList->setSelected(currentThemeIndex);
 
 	// Finally, redraw
-	draw();
+	markAsDirty();
 }
 
 } // End of namespace GUI
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 4b84e19..fa3767b 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -51,6 +51,7 @@ void Widget::init() {
 	// Insert into the widget list of the boss
 	_next = _boss->_firstWidget;
 	_boss->_firstWidget = this;
+	_needsRedraw = true;
 }
 
 Common::Rect Widget::getBossClipRect() const {
@@ -112,38 +113,52 @@ void Widget::updateState(int oldFlags, int newFlags) {
 	}
 }
 
+void Widget::markAsDirty() {
+	_needsRedraw = true;
+
+	Widget *w = _firstWidget;
+	while (w) {
+		w->markAsDirty();
+		w = w->next();
+	}
+}
+
 void Widget::draw() {
 	if (!isVisible() || !_boss->isVisible())
 		return;
 
-	int oldX = _x, oldY = _y;
+	if (_needsRedraw) {
+		int oldX = _x, oldY = _y;
 
-	// Account for our relative position in the dialog
-	_x = getAbsX();
-	_y = getAbsY();
+		// Account for our relative position in the dialog
+		_x = getAbsX();
+		_y = getAbsY();
 
-	// Draw border
-	if (_flags & WIDGET_BORDER) {
-		g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder);
-		_x += 4;
-		_y += 4;
-		_w -= 8;
-		_h -= 8;
-	}
+		// Draw border
+		if (_flags & WIDGET_BORDER) {
+			g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x+_w, _y+_h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder);
+			_x += 4;
+			_y += 4;
+			_w -= 8;
+			_h -= 8;
+		}
 
-	// Now perform the actual widget draw
-	drawWidget();
+		// Now perform the actual widget draw
+		drawWidget();
 
-	// Restore x/y
-	if (_flags & WIDGET_BORDER) {
-		_x -= 4;
-		_y -= 4;
-		_w += 8;
-		_h += 8;
-	}
+		// Restore x/y
+		if (_flags & WIDGET_BORDER) {
+			_x -= 4;
+			_y -= 4;
+			_w += 8;
+			_h += 8;
+		}
 
-	_x = oldX;
-	_y = oldY;
+		_x = oldX;
+		_y = oldY;
+
+		_needsRedraw = false;
+	}
 
 	// Draw all children
 	Widget *w = _firstWidget;
@@ -191,7 +206,7 @@ void Widget::setEnabled(bool e) {
 		else
 			clearFlags(WIDGET_ENABLED);
 
-		_boss->draw();
+		_boss->markAsDirty();
 	}
 }
 
@@ -273,7 +288,7 @@ StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h,
 
 StaticTextWidget::StaticTextWidget(GuiObject *boss, const Common::String &name, const Common::String &text, const char *tooltip, ThemeEngine::FontStyle font)
 	: Widget(boss, name, tooltip) {
-	setFlags(WIDGET_ENABLED);
+	setFlags(WIDGET_ENABLED | WIDGET_CLEARBG);
 	_type = kStaticTextWidget;
 	_label = text;
 
@@ -289,12 +304,7 @@ void StaticTextWidget::setLabel(const Common::String &label) {
 	if (_label != label) {
 		_label = label;
 
-		// when changing the label, add the CLEARBG flag
-		// so the widget is completely redrawn, otherwise
-		// the new text is drawn on top of the old one.
-		setFlags(WIDGET_CLEARBG);
-		draw();
-		clearFlags(WIDGET_CLEARBG);
+		markAsDirty();
 	}
 }
 
@@ -302,14 +312,8 @@ void StaticTextWidget::setAlign(Graphics::TextAlign align) {
 	if (_align != align){
 		_align = align;
 
-		// same as setLabel() actually, the text
-		// would be redrawn on top of the old one so
-		// we add the CLEARBG flag
-		setFlags(WIDGET_CLEARBG);
-		draw();
-		clearFlags(WIDGET_CLEARBG);
+		markAsDirty();
 	}
-
 }
 
 
@@ -389,18 +393,18 @@ ButtonWidget *addClearButton(GuiObject *boss, const Common::String &name, uint32
 
 void ButtonWidget::setHighLighted(bool enable) {
 	(enable) ? setFlags(WIDGET_HILITED) : clearFlags(WIDGET_HILITED);
-	draw();
+	markAsDirty();
 }
 
 void ButtonWidget::setPressedState() {
 	setFlags(WIDGET_PRESSED);
 	clearFlags(WIDGET_HILITED);
-	draw();
+	markAsDirty();
 }
 
 void ButtonWidget::setUnpressedState() {
 	clearFlags(WIDGET_PRESSED);
-	draw();
+	markAsDirty();
 }
 
 #pragma mark -
@@ -563,7 +567,7 @@ void CheckboxWidget::setState(bool state) {
 	if (_state != state) {
 		_state = state;
 		//_flags ^= WIDGET_INV_BORDER;
-		draw();
+		markAsDirty();
 	}
 	sendCommand(_cmd, _state);
 }
@@ -632,7 +636,7 @@ void RadiobuttonWidget::setState(bool state, bool setGroup) {
 	if (_state != state) {
 		_state = state;
 		//_flags ^= WIDGET_INV_BORDER;
-		draw();
+		markAsDirty();
 	}
 	sendCommand(_cmd, _state);
 }
@@ -667,7 +671,7 @@ void SliderWidget::handleMouseMoved(int x, int y, int button) {
 
 		if (newValue != _value) {
 			_value = newValue;
-			draw();
+			markAsDirty();
 			sendCommand(_cmd, _value);	// FIXME - hack to allow for "live update" in sound dialog
 		}
 	}
@@ -699,7 +703,7 @@ void SliderWidget::handleMouseWheel(int x, int y, int direction) {
 
 		if (newValue != _value) {
 			_value = newValue;
-			draw();
+			markAsDirty();
 			sendCommand(_cmd, _value);	// FIXME - hack to allow for "live update" in sound dialog
 		}
 	}
diff --git a/gui/widget.h b/gui/widget.h
index 0da071e..e57f3cd 100644
--- a/gui/widget.h
+++ b/gui/widget.h
@@ -103,6 +103,7 @@ protected:
 
 private:
 	uint16		_flags;
+	bool		_needsRedraw;
 
 public:
 	static Widget *findWidgetInChain(Widget *start, int x, int y);
@@ -137,7 +138,12 @@ public:
 	virtual bool handleKeyUp(Common::KeyState state) { return false; }	// Return true if the event was handled
 	virtual void handleTickle() {}
 
-	void draw();
+	/** Mark the widget and its children as dirty so they are redrawn on the next screen update */
+	virtual void markAsDirty();
+
+	/** Redraw the widget if it was marked as dirty, and recursively proceed with its children */
+	virtual void draw();
+
 	void receivedFocus() { _hasFocus = true; receivedFocusWidget(); }
 	void lostFocus() { _hasFocus = false; lostFocusWidget(); }
 	virtual bool wantsFocus() { return false; }
@@ -213,8 +219,8 @@ public:
 
 	void handleMouseUp(int x, int y, int button, int clickCount);
 	void handleMouseDown(int x, int y, int button, int clickCount);
-	void handleMouseEntered(int button)	{ if (_duringPress) { setFlags(WIDGET_PRESSED); } else { setFlags(WIDGET_HILITED); } draw(); }
-	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED | WIDGET_PRESSED); draw(); }
+	void handleMouseEntered(int button)	{ if (_duringPress) { setFlags(WIDGET_PRESSED); } else { setFlags(WIDGET_HILITED); } markAsDirty(); }
+	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED | WIDGET_PRESSED); markAsDirty(); }
 
 	void setHighLighted(bool enable);
 	void setPressedState();
@@ -262,8 +268,8 @@ public:
 	CheckboxWidget(GuiObject *boss, const Common::String &name, const Common::String &label, const char *tooltip = 0, uint32 cmd = 0, uint8 hotkey = 0);
 
 	void handleMouseUp(int x, int y, int button, int clickCount);
-	virtual void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); draw(); }
-	virtual void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); draw(); }
+	virtual void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); markAsDirty(); }
+	virtual void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); markAsDirty(); }
 
 	void setState(bool state);
 	void toggleState()			{ setState(!_state); }
@@ -308,8 +314,8 @@ public:
 	RadiobuttonWidget(GuiObject *boss, const Common::String &name, RadiobuttonGroup *group, int value, const Common::String &label, const char *tooltip = 0, uint8 hotkey = 0);
 
 	void handleMouseUp(int x, int y, int button, int clickCount);
-	virtual void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); draw(); }
-	virtual void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); draw(); }
+	virtual void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); markAsDirty(); }
+	virtual void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); markAsDirty(); }
 
 	void setState(bool state, bool setGroup = true);
 	void toggleState()			{ setState(!_state); }
@@ -348,8 +354,8 @@ public:
 	void handleMouseMoved(int x, int y, int button);
 	void handleMouseDown(int x, int y, int button, int clickCount);
 	void handleMouseUp(int x, int y, int button, int clickCount);
-	void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); draw(); }
-	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); draw(); }
+	void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); markAsDirty(); }
+	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); markAsDirty(); }
 	void handleMouseWheel(int x, int y, int direction);
 
 protected:
diff --git a/gui/widgets/editable.cpp b/gui/widgets/editable.cpp
index 02defe9..5e7c94b 100644
--- a/gui/widgets/editable.cpp
+++ b/gui/widgets/editable.cpp
@@ -235,7 +235,7 @@ bool EditableWidget::handleKeyDown(Common::KeyState state) {
 	}
 
 	if (dirty)
-		draw();
+		markAsDirty();
 
 	if (forcecaret)
 		makeCaretVisible();
diff --git a/gui/widgets/edittext.cpp b/gui/widgets/edittext.cpp
index 0a8725a..9736674 100644
--- a/gui/widgets/edittext.cpp
+++ b/gui/widgets/edittext.cpp
@@ -87,7 +87,7 @@ void EditTextWidget::handleMouseDown(int x, int y, int button, int clickCount) {
 		last = cur;
 	}
 	if (setCaretPos(i))
-		draw();
+		markAsDirty();
 
 #ifdef TIZEN
 	// Display the virtual keypad to allow text entry. Samsung app-store testers expected
diff --git a/gui/widgets/list.cpp b/gui/widgets/list.cpp
index e5690fb..16d91f9 100644
--- a/gui/widgets/list.cpp
+++ b/gui/widgets/list.cpp
@@ -145,7 +145,7 @@ void ListWidget::setSelected(int item) {
 
 		_currentPos = _selectedItem - _entriesPerPage / 2;
 		scrollToCurrent();
-		draw();
+		markAsDirty();
 	}
 }
 
@@ -251,7 +251,7 @@ void ListWidget::handleMouseDown(int x, int y, int button, int clickCount) {
 	// TODO: Determine where inside the string the user clicked and place the
 	// caret accordingly.
 	// See _editScrollOffset and EditTextWidget::handleMouseDown.
-	draw();
+	markAsDirty();
 
 }
 
@@ -446,12 +446,12 @@ bool ListWidget::handleKeyDown(Common::KeyState state) {
 	}
 
 	if (dirty || _selectedItem != oldSelectedItem)
-		draw();
+		markAsDirty();
 
 	if (_selectedItem != oldSelectedItem) {
 		sendCommand(kListSelectionChangedCmd, _selectedItem);
 		// also draw scrollbar
-		_scrollBar->draw();
+		_scrollBar->markAsDirty();
 	}
 
 	return handled;
@@ -467,7 +467,7 @@ void ListWidget::receivedFocusWidget() {
 	_inversion = ThemeEngine::kTextInversionFocus;
 
 	// Redraw the widget so the selection color will change
-	draw();
+	markAsDirty();
 }
 
 void ListWidget::lostFocusWidget() {
@@ -477,7 +477,7 @@ void ListWidget::lostFocusWidget() {
 	_editMode = false;
 	g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
 	drawCaret(true);
-	draw();
+	markAsDirty();
 }
 
 void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
@@ -486,7 +486,7 @@ void ListWidget::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
 		if (_currentPos != (int)data) {
 			_currentPos = data;
 			checkBounds();
-			draw();
+			markAsDirty();
 
 			// Scrollbar actions cause list focus (which triggers a redraw)
 			// NOTE: ListWidget's boss is always GUI::Dialog
@@ -600,7 +600,7 @@ void ListWidget::scrollToEnd() {
 
 	_scrollBar->_currentPos = _currentPos;
 	_scrollBar->recalc();
-	_scrollBar->draw();
+	_scrollBar->markAsDirty();
 }
 
 void ListWidget::startEditMode() {
@@ -616,7 +616,7 @@ void ListWidget::startEditMode() {
 			else
 				_editColor = _listColors[_listIndex[_selectedItem]];
 		}
-		draw();
+		markAsDirty();
 		g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
 	}
 }
@@ -636,7 +636,7 @@ void ListWidget::abortEditMode() {
 	assert(_selectedItem >= 0);
 	_editMode = false;
 	//drawCaret(true);
-	//draw();
+	//markAsDirty();
 	g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
 }
 
@@ -744,7 +744,7 @@ void ListWidget::setFilter(const String &filter, bool redraw) {
 		// Such a widget could also (optionally) draw a border (or even different
 		// kinds of borders) around the objects it groups; and also a 'title'
 		// (I am borrowing these "ideas" from the NSBox class in Cocoa :).
-		_boss->draw();
+		_boss->markAsDirty();
 	}
 }
 
diff --git a/gui/widgets/popup.cpp b/gui/widgets/popup.cpp
index 74fbc44..f59a89e 100644
--- a/gui/widgets/popup.cpp
+++ b/gui/widgets/popup.cpp
@@ -409,7 +409,7 @@ void PopUpWidget::handleMouseDown(int x, int y, int button, int clickCount) {
 		if (newSel != -1 && _selectedItem != newSel) {
 			_selectedItem = newSel;
 			sendCommand(kPopUpItemSelectedCmd, _entries[_selectedItem].tag);
-			draw();
+			markAsDirty();
 		}
 	}
 }
@@ -429,7 +429,7 @@ void PopUpWidget::handleMouseWheel(int x, int y, int direction) {
 			(newSelection != _selectedItem)) {
 			_selectedItem = newSelection;
 			sendCommand(kPopUpItemSelectedCmd, _entries[_selectedItem].tag);
-			draw();
+			markAsDirty();
 		}
 	}
 }
diff --git a/gui/widgets/popup.h b/gui/widgets/popup.h
index 37ddc27..d2b1f1c 100644
--- a/gui/widgets/popup.h
+++ b/gui/widgets/popup.h
@@ -77,8 +77,8 @@ public:
 	uint32 getSelectedTag() const				{ return (_selectedItem >= 0) ? _entries[_selectedItem].tag : (uint32)-1; }
 //	const String& getSelectedString() const		{ return (_selectedItem >= 0) ? _entries[_selectedItem].name : String::emptyString; }
 
-	void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); draw(); }
-	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); draw(); }
+	void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); markAsDirty(); }
+	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); markAsDirty(); }
 
 	virtual void reflowLayout();
 protected:
diff --git a/gui/widgets/scrollbar.cpp b/gui/widgets/scrollbar.cpp
index d8bcb18..b0e2576 100644
--- a/gui/widgets/scrollbar.cpp
+++ b/gui/widgets/scrollbar.cpp
@@ -135,7 +135,7 @@ void ScrollBarWidget::handleMouseMoved(int x, int y, int button) {
 			_part = kSliderPart;
 
 		if (old_part != _part)
-			draw();
+			markAsDirty();
 	}
 }
 
@@ -165,7 +165,7 @@ void ScrollBarWidget::checkBounds(int old_pos) {
 
 	if (old_pos != _currentPos) {
 		recalc();
-		draw();
+		markAsDirty();
 		sendCommand(kSetPositionCmd, _currentPos);
 	}
 }
diff --git a/gui/widgets/scrollbar.h b/gui/widgets/scrollbar.h
index de7c13c..a1181b9 100644
--- a/gui/widgets/scrollbar.h
+++ b/gui/widgets/scrollbar.h
@@ -69,7 +69,7 @@ public:
 	void handleMouseWheel(int x, int y, int direction);
 	void handleMouseMoved(int x, int y, int button);
 	void handleMouseEntered(int button)	{ setFlags(WIDGET_HILITED); }
-	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); _part = kNoPart; draw(); }
+	void handleMouseLeft(int button)	{ clearFlags(WIDGET_HILITED); _part = kNoPart; markAsDirty(); }
 	void handleTickle();
 
 	// FIXME - this should be private, but then we also have to add accessors
diff --git a/gui/widgets/scrollcontainer.cpp b/gui/widgets/scrollcontainer.cpp
index 7c5ab61..0f3c96d 100644
--- a/gui/widgets/scrollcontainer.cpp
+++ b/gui/widgets/scrollcontainer.cpp
@@ -102,7 +102,7 @@ void ScrollContainerWidget::handleCommand(CommandSender *sender, uint32 cmd, uin
 	case kSetPositionCmd:
 		_scrolledY = _verticalScroll->_currentPos;
 		reflowLayout();
-		draw();
+		markAsDirty();
 		g_gui.doFullRedraw();
 		break;
 	}
diff --git a/gui/widgets/tab.cpp b/gui/widgets/tab.cpp
index e2e3e72..9b045da 100644
--- a/gui/widgets/tab.cpp
+++ b/gui/widgets/tab.cpp
@@ -154,7 +154,7 @@ void TabWidget::removeTab(int tabID) {
 	}
 
 	// Finally trigger a redraw
-	_boss->draw();
+	_boss->markAsDirty();
 }
 
 void TabWidget::setActiveTab(int tabID) {
@@ -174,7 +174,7 @@ void TabWidget::setActiveTab(int tabID) {
 		while (_lastVisibleTab < tabID)
 			setFirstVisible(_firstVisibleTab + 1, false);
 
-		_boss->draw();
+		_boss->markAsDirty();
 	}
 }
 
@@ -246,7 +246,7 @@ void TabWidget::setFirstVisible(int tabID, bool adjustIfRoom) {
 
 	computeLastVisibleTab(adjustIfRoom);
 
-	_boss->draw(); // TODO: Necessary?
+	_boss->markAsDirty(); // TODO: Necessary?
 }
 
 void TabWidget::reflowLayout() {
@@ -334,6 +334,15 @@ void TabWidget::draw() {
 	}
 }
 
+void TabWidget::markAsDirty() {
+	Widget::markAsDirty();
+
+	if (_navButtonsVisible) {
+		_navLeft->markAsDirty();
+		_navRight->markAsDirty();
+	}
+}
+
 bool TabWidget::containsWidget(Widget *w) const {
 	if (w == _navLeft || w == _navRight || _navLeft->containsWidget(w) || _navRight->containsWidget(w))
 		return true;
diff --git a/gui/widgets/tab.h b/gui/widgets/tab.h
index fe5e4d8..bdd3e56 100644
--- a/gui/widgets/tab.h
+++ b/gui/widgets/tab.h
@@ -111,7 +111,8 @@ public:
 
 	virtual void reflowLayout();
 
-	virtual void draw();
+	void draw() override;
+	void markAsDirty() override;
 
 protected:
 	// We overload getChildY to make sure child widgets are positioned correctly.


Commit: fc37918130d8539ee57be014108729e8aca6e3f8
    https://github.com/scummvm/scummvm/commit/fc37918130d8539ee57be014108729e8aca6e3f8
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:12:34+01:00

Commit Message:
GUI: Remove explicit redraw when scrolling the ScrollContainer

The redraw is already handled by the GUI main loop

Changed paths:
    gui/gui-manager.cpp
    gui/widgets/scrollcontainer.cpp


diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 4b91019..08417c3 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -592,8 +592,6 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi
 
 void GuiManager::doFullRedraw() {
 	_redrawStatus = kRedrawFull;
-	redraw();
-	_system->updateScreen();
 }
 
 void GuiManager::giveFocusToDialog(Dialog *dialog) {
diff --git a/gui/widgets/scrollcontainer.cpp b/gui/widgets/scrollcontainer.cpp
index 0f3c96d..00eadff 100644
--- a/gui/widgets/scrollcontainer.cpp
+++ b/gui/widgets/scrollcontainer.cpp
@@ -102,7 +102,6 @@ void ScrollContainerWidget::handleCommand(CommandSender *sender, uint32 cmd, uin
 	case kSetPositionCmd:
 		_scrolledY = _verticalScroll->_currentPos;
 		reflowLayout();
-		markAsDirty();
 		g_gui.doFullRedraw();
 		break;
 	}


Commit: 5878c618c931f6c600dda0b156d96f909013779b
    https://github.com/scummvm/scummvm/commit/5878c618c931f6c600dda0b156d96f909013779b
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:12:34+01:00

Commit Message:
GUI: Remove Dialog::markAsDirty to expose full GUI redraws

Changed paths:
    backends/keymapper/remap-dialog.cpp
    engines/scumm/dialogs.cpp
    gui/browser.cpp
    gui/console.cpp
    gui/dialog.cpp
    gui/dialog.h
    gui/downloaddialog.cpp
    gui/editgamedialog.cpp
    gui/filebrowser-dialog.cpp
    gui/fluidsynth-dialog.cpp
    gui/gui-manager.cpp
    gui/gui-manager.h
    gui/launcher.cpp
    gui/object.h
    gui/options.cpp
    gui/remotebrowser.cpp
    gui/saveload-dialog.cpp
    gui/storagewizarddialog.cpp
    gui/themebrowser.cpp
    gui/widget.cpp
    gui/widgets/list.cpp
    gui/widgets/scrollcontainer.cpp
    gui/widgets/tab.cpp


diff --git a/backends/keymapper/remap-dialog.cpp b/backends/keymapper/remap-dialog.cpp
index 78a9520..9c52a92 100644
--- a/backends/keymapper/remap-dialog.cpp
+++ b/backends/keymapper/remap-dialog.cpp
@@ -451,7 +451,7 @@ void RemapDialog::refreshKeymap() {
 	}
 	// need to redraw entire Dialog so that invisible
 	// widgets disappear
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 
diff --git a/engines/scumm/dialogs.cpp b/engines/scumm/dialogs.cpp
index 8acb6eb..1af7523 100644
--- a/engines/scumm/dialogs.cpp
+++ b/engines/scumm/dialogs.cpp
@@ -358,7 +358,7 @@ void HelpDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 da
 			_prevButton->setFlags(WIDGET_ENABLED);
 		}
 		displayKeyBindings();
-		draw();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kPrevCmd:
 		_page--;
@@ -369,7 +369,7 @@ void HelpDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 da
 			_prevButton->clearFlags(WIDGET_ENABLED);
 		}
 		displayKeyBindings();
-		draw();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	default:
 		ScummDialog::handleCommand(sender, cmd, data);
@@ -553,7 +553,7 @@ void ValueDisplayDialog::handleKeyDown(Common::KeyState state) {
 
 		setResult(_value);
 		_timer = g_system->getMillis() + kDisplayDelay;
-		draw();
+		g_gui.scheduleTopDialogRedraw();
 	} else {
 		close();
 	}
@@ -581,7 +581,7 @@ void SubtitleSettingsDialog::handleKeyDown(Common::KeyState state) {
 		cycleValue();
 
 		reflowLayout();
-		draw();
+		g_gui.scheduleTopDialogRedraw();
 	} else {
 		close();
 	}
@@ -634,7 +634,7 @@ void DebugInputDialog::handleKeyDown(Common::KeyState state) {
 		buffer.deleteLastChar();
 		Common::String total = mainText + ' ' + buffer;
 		setInfoText(total);
-		draw();
+		g_gui.scheduleTopDialogRedraw();
 		reflowLayout();
 	} else if (state.keycode == Common::KEYCODE_RETURN) {
 		done = 1;
@@ -643,7 +643,7 @@ void DebugInputDialog::handleKeyDown(Common::KeyState state) {
 	} else if ((state.ascii >= '0' && state.ascii <= '9') || (state.ascii >= 'A' && state.ascii <= 'Z') || (state.ascii >= 'a' && state.ascii <= 'z') || state.ascii == '.' || state.ascii == ' ') {
 		buffer += state.ascii;
 		Common::String total = mainText + ' ' + buffer;
-		draw();
+		g_gui.scheduleTopDialogRedraw();
 		reflowLayout();
 		setInfoText(total);
 	}
diff --git a/gui/browser.cpp b/gui/browser.cpp
index bbfe485..67b0dd9 100644
--- a/gui/browser.cpp
+++ b/gui/browser.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "gui/browser.h"
+#include "gui/gui-manager.h"
 #include "gui/widgets/list.h"
 
 #include "common/config-manager.h"
@@ -191,7 +192,7 @@ void BrowserDialog::updateListing() {
 	_fileList->scrollTo(0);
 
 	// Finally, redraw
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 } // End of namespace GUI
diff --git a/gui/console.cpp b/gui/console.cpp
index 5d28f5a..942ef61 100644
--- a/gui/console.cpp
+++ b/gui/console.cpp
@@ -214,7 +214,7 @@ void ConsoleDialog::reflowLayout() {
 	updateScrollBuffer();
 
 	Dialog::reflowLayout();
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void ConsoleDialog::handleTickle() {
@@ -237,13 +237,13 @@ void ConsoleDialog::handleTickle() {
 			// End the slide
 			_slideMode = kNoSlideMode;
 			_y = 0;
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		} else if (_slideMode == kUpSlideMode && _y <= -_h) {
 			// End the slide
 			//_slideMode = kNoSlideMode;
 			close();
 		} else
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 	}
 
 	_scrollBar->handleTickle();
@@ -292,7 +292,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 		print(PROMPT);
 		_promptStartPos = _promptEndPos = _currentPos;
 
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		if (!keepRunning)
 			slideUpAndClose();
 		break;
@@ -377,7 +377,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 		} else {
 			_currentPos = _promptEndPos;
 		}
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 
 	case Common::KEYCODE_KP2:
@@ -405,7 +405,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 					_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
 			}
 			updateScrollBuffer();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 
@@ -446,7 +446,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 		} else {
 			_currentPos = _promptStartPos;
 		}
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 
 	case Common::KEYCODE_KP8:
@@ -471,7 +471,7 @@ void ConsoleDialog::handleKeyDown(Common::KeyState state) {
 			if (_scrollLine < _firstLineInBuffer + _linesPerPage - 1)
 				_scrollLine = _firstLineInBuffer + _linesPerPage - 1;
 			updateScrollBuffer();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 
@@ -508,7 +508,7 @@ void ConsoleDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 		int newPos = (int)data + _linesPerPage - 1 + _firstLineInBuffer;
 		if (newPos != _scrollLine) {
 			_scrollLine = newPos;
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -518,25 +518,25 @@ void ConsoleDialog::specialKeys(int keycode) {
 	switch (keycode) {
 	case Common::KEYCODE_a:
 		_currentPos = _promptStartPos;
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case Common::KEYCODE_d:
 		if (_currentPos < _promptEndPos) {
 			killChar();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	case Common::KEYCODE_e:
 		_currentPos = _promptEndPos;
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case Common::KEYCODE_k:
 		killLine();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case Common::KEYCODE_w:
 		killLastWord();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	}
 }
@@ -626,7 +626,7 @@ void ConsoleDialog::historyScroll(int direction) {
 	// Ensure once more the caret is visible (in case of very long history entries)
 	scrollToCurrent();
 
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void ConsoleDialog::nextLine() {
@@ -704,7 +704,7 @@ void ConsoleDialog::print(const char *str) {
 	while (*str)
 		printCharIntern(*str++);
 
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void ConsoleDialog::drawCaret(bool erase) {
@@ -733,7 +733,7 @@ void ConsoleDialog::scrollToCurrent() {
 	} else if (line > _scrollLine) {
 		_scrollLine = line;
 		updateScrollBuffer();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index 7434118..408387b 100644
--- a/gui/dialog.cpp
+++ b/gui/dialog.cpp
@@ -153,14 +153,6 @@ void Dialog::releaseFocus() {
 	}
 }
 
-void Dialog::markAsDirty() {
-	//TANOKU - FIXME when is this enabled? what does this do?
-	// Update: called on tab drawing, mainly...
-	// we can pass this as open a new dialog or something
-//	g_gui._needRedraw = true;
-	g_gui._redrawStatus = GUI::GuiManager::kRedrawTopDialog;
-}
-
 void Dialog::markWidgetsAsDirty() {
 	Widget *w = _firstWidget;
 	while (w) {
diff --git a/gui/dialog.h b/gui/dialog.h
index cb6e13f..8f3b234 100644
--- a/gui/dialog.h
+++ b/gui/dialog.h
@@ -88,7 +88,6 @@ protected:
 	virtual void open();
 	virtual void close();
 
-	void markAsDirty() override;
 	/** Recursively mark all the widgets in this dialog as dirty so they are redrawn */
 	void markWidgetsAsDirty();
 
diff --git a/gui/downloaddialog.cpp b/gui/downloaddialog.cpp
index dc6d7ff..4df7dc7 100644
--- a/gui/downloaddialog.cpp
+++ b/gui/downloaddialog.cpp
@@ -29,6 +29,7 @@
 #include "gui/browser.h"
 #include "gui/chooser.h"
 #include "gui/editgamedialog.h"
+#include "gui/gui-manager.h"
 #include "gui/launcher.h"
 #include "gui/message.h"
 #include "gui/remotebrowser.h"
@@ -81,7 +82,7 @@ void DownloadDialog::open() {
 		if (!selectDirectories())
 			close();
 	reflowLayout();
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void DownloadDialog::close() {
@@ -101,7 +102,7 @@ void DownloadDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 	case kDownloadProgressCmd:
 		if (!_close) {
 			refreshWidgets();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	case kDownloadEndedCmd:
@@ -196,7 +197,7 @@ void DownloadDialog::handleTickle() {
 	int32 progress = (int32)(100 * CloudMan.getDownloadingProgress());
 	if (_progressBar->getValue() != progress) {
 		refreshWidgets();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 
 	Dialog::handleTickle();
diff --git a/gui/editgamedialog.cpp b/gui/editgamedialog.cpp
index b99b53c..4192c40 100644
--- a/gui/editgamedialog.cpp
+++ b/gui/editgamedialog.cpp
@@ -28,6 +28,7 @@
 #include "common/system.h"
 
 #include "gui/browser.h"
+#include "gui/gui-manager.h"
 #include "gui/message.h"
 #ifdef ENABLE_EVENTRECORDER
 #include "gui/onscreendialog.h"
@@ -424,26 +425,26 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 	switch (cmd) {
 	case kCmdGlobalGraphicsOverride:
 		setGraphicSettingsState(data != 0);
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kCmdGlobalAudioOverride:
 		setAudioSettingsState(data != 0);
 		setSubtitleSettingsState(data != 0);
 		if (_globalVolumeOverride == NULL)
 			setVolumeSettingsState(data != 0);
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kCmdGlobalMIDIOverride:
 		setMIDISettingsState(data != 0);
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kCmdGlobalMT32Override:
 		setMT32SettingsState(data != 0);
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kCmdGlobalVolumeOverride:
 		setVolumeSettingsState(data != 0);
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kCmdChooseSoundFontCmd:
 	{
@@ -459,7 +460,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			else
 				_soundFontClearButton->setEnabled(false);
 
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -477,9 +478,9 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			// FSList files = dir.listDir(FSNode::kListFilesOnly);
 
 			_gamePathWidget->setLabel(dir.getPath());
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	}
 
@@ -491,9 +492,9 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_extraPathWidget->setLabel(dir.getPath());
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	}
 	// Change path for stored save game (perm and temp) data
@@ -508,9 +509,9 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
 			MessageDialog warningMessage(_("Saved games sync feature doesn't work with non-default directories. If you want your saved games to sync, use default directory."));
 			warningMessage.runModal();
 #endif
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	}
 
diff --git a/gui/filebrowser-dialog.cpp b/gui/filebrowser-dialog.cpp
index 95fc4d9..0c7f55a 100644
--- a/gui/filebrowser-dialog.cpp
+++ b/gui/filebrowser-dialog.cpp
@@ -30,6 +30,7 @@
 #include "common/translation.h"
 
 #include "gui/widgets/list.h"
+#include "gui/gui-manager.h"
 #include "gui/message.h"
 
 namespace GUI {
@@ -154,7 +155,7 @@ void FileBrowserDialog::updateListing() {
 	_fileList->scrollTo(0);
 
 	// Finally, redraw
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 } // End of namespace GUI
diff --git a/gui/fluidsynth-dialog.cpp b/gui/fluidsynth-dialog.cpp
index fb72997..921449e 100644
--- a/gui/fluidsynth-dialog.cpp
+++ b/gui/fluidsynth-dialog.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "gui/fluidsynth-dialog.h"
+#include "gui/gui-manager.h"
 #include "gui/message.h"
 #include "gui/widgets/tab.h"
 #include "gui/widgets/popup.h"
@@ -218,7 +219,7 @@ void FluidSynthSettingsDialog::handleCommand(CommandSender *sender, uint32 cmd,
 		if (alert.runModal() == GUI::kMessageOK) {
 			resetSettings();
 			readSettings();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp
index 08417c3..7c00c68 100644
--- a/gui/gui-manager.cpp
+++ b/gui/gui-manager.cpp
@@ -590,8 +590,8 @@ void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDi
 	}
 }
 
-void GuiManager::doFullRedraw() {
-	_redrawStatus = kRedrawFull;
+void GuiManager::scheduleTopDialogRedraw() {
+	_redrawStatus = kRedrawTopDialog;
 }
 
 void GuiManager::giveFocusToDialog(Dialog *dialog) {
diff --git a/gui/gui-manager.h b/gui/gui-manager.h
index 82a8aa9..07ea474 100644
--- a/gui/gui-manager.h
+++ b/gui/gui-manager.h
@@ -75,7 +75,7 @@ public:
 	void runLoop();
 
 	void processEvent(const Common::Event &event, Dialog *const activeDialog);
-	void doFullRedraw();
+	void scheduleTopDialogRedraw();
 
 	bool isActive() const	{ return ! _dialogStack.empty(); }
 
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index 5f73776..4fe1ae7 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -323,7 +323,7 @@ void LauncherDialog::addGame() {
 				selectTarget(newTarget);
 			}
 
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 
 		// We need to update the buttons here, so "Mass add" will revert to "Add game"
@@ -427,7 +427,7 @@ void LauncherDialog::removeGame(int item) {
 
 		// Update the ListWidget and force a redraw
 		updateListing();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
@@ -452,7 +452,7 @@ void LauncherDialog::editGame(int item) {
 		// Update the ListWidget, reselect the edited game and force a redraw
 		updateListing();
 		selectTarget(editDialog.getDomain());
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
@@ -614,7 +614,7 @@ bool LauncherDialog::doGameDetection(const Common::String &path) {
 			// Update the ListWidget, select the new item, and force a redraw
 			updateListing();
 			selectTarget(editDialog.getDomain());
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		} else {
 			// User aborted, remove the the new domain again
 			ConfMan.removeGameDomain(domain);
diff --git a/gui/object.h b/gui/object.h
index af64697..40ea2da 100644
--- a/gui/object.h
+++ b/gui/object.h
@@ -87,8 +87,6 @@ public:
 
 	virtual bool	isVisible() const = 0;
 
-	virtual void    markAsDirty() = 0;
-
 	virtual void	reflowLayout();
 
 	virtual void	removeWidget(Widget *widget);
diff --git a/gui/options.cpp b/gui/options.cpp
index 38ad185..6083a2c 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -773,7 +773,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
 	case kClearSoundFontCmd:
 		_soundFont->setLabel(_c("None", "soundfont"));
 		_soundFontClearButton->setEnabled(false);
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	case kKbdMouseSpeedChanged:
 		_kbdMouseSpeedLabel->setLabel(_(kbdMouseSpeedLabels[_kbdMouseSpeedSlider->getValue()]));
@@ -1936,7 +1936,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 				error.runModal();
 				return;
 			}
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -1946,7 +1946,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_themePath->setLabel(dir.getPath());
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -1956,7 +1956,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_extraPath->setLabel(dir.getPath());
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -1967,7 +1967,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			// User made his choice...
 			Common::FSNode dir(browser.getResult());
 			_pluginsPath->setLabel(dir.getPath());
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -1982,7 +1982,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			if (path.empty())
 				path = "/"; // absolute root
 			_rootPath->setLabel(path);
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -2013,7 +2013,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 			else
 				_soundFontClearButton->setEnabled(false);
 
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
@@ -2107,7 +2107,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 		if (_serverPort) {
 			_serverPort->setEditString(Common::String::format("%u", Networking::LocalWebserver::DEFAULT_SERVER_PORT));
 		}
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	}
 #endif // USE_SDL_NET
@@ -2144,7 +2144,7 @@ void GlobalOptionsDialog::handleTickle() {
 #endif
 	if (_redrawCloudTab) {
 		setupCloudTab();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		_redrawCloudTab = false;
 	}
 #endif
diff --git a/gui/remotebrowser.cpp b/gui/remotebrowser.cpp
index 1d50300..0bbc21d 100644
--- a/gui/remotebrowser.cpp
+++ b/gui/remotebrowser.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "gui/remotebrowser.h"
+#include "gui/gui-manager.h"
 #include "gui/widgets/list.h"
 
 #include "common/config-manager.h"
@@ -28,9 +29,9 @@
 #include "common/algorithm.h"
 
 #include "common/translation.h"
-#include <backends/networking/curl/request.h>
-#include <backends/cloud/storage.h>
-#include <backends/cloud/cloudmanager.h>
+#include "backends/networking/curl/request.h"
+#include "backends/cloud/storage.h"
+#include "backends/cloud/cloudmanager.h"
 #include "message.h"
 
 namespace GUI {
@@ -162,7 +163,7 @@ void RemoteBrowserDialog::updateListing() {
 	_fileList->setEnabled(!_navigationLocked);
 
 	// Finally, redraw
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void RemoteBrowserDialog::goUp() {
diff --git a/gui/saveload-dialog.cpp b/gui/saveload-dialog.cpp
index 6d2a43b..8d59a63 100644
--- a/gui/saveload-dialog.cpp
+++ b/gui/saveload-dialog.cpp
@@ -60,7 +60,7 @@ SaveLoadCloudSyncProgressDialog::SaveLoadCloudSyncProgressDialog(bool canRunInBa
 	new ButtonWidget(this, "SaveLoadCloudSyncProgress.Cancel", "Cancel", 0, kCancelSyncCmd, Common::ASCII_ESCAPE);	// Cancel dialog
 	ButtonWidget *backgroundButton = new ButtonWidget(this, "SaveLoadCloudSyncProgress.Background", "Run in background", 0, kBackgroundSyncCmd, Common::ASCII_RETURN);	// Confirm dialog
 	backgroundButton->setEnabled(canRunInBackground);
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 SaveLoadCloudSyncProgressDialog::~SaveLoadCloudSyncProgressDialog() {
@@ -601,7 +601,7 @@ void SaveLoadChooserSimple::updateSelection(bool redraw) {
 		_chooseButton->markAsDirty();
 		_deleteButton->markAsDirty();
 
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
@@ -703,7 +703,7 @@ void SaveLoadChooserSimple::updateSaveList() {
 	else
 		_chooseButton->setEnabled(false);
 
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 // SaveLoadChooserGrid implementation
@@ -761,13 +761,13 @@ void SaveLoadChooserGrid::handleCommand(CommandSender *sender, uint32 cmd, uint3
 	case kNextCmd:
 		++_curPage;
 		updateSaves();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 
 	case kPrevCmd:
 		--_curPage;
 		updateSaves();
-		markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 
 	case kNewSaveCmd:
@@ -788,13 +788,13 @@ void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
 		if (_nextButton->isEnabled()) {
 			++_curPage;
 			updateSaves();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 	} else {
 		if (_prevButton->isEnabled()) {
 			--_curPage;
 			updateSaves();
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 	}
 }
@@ -802,7 +802,7 @@ void SaveLoadChooserGrid::handleMouseWheel(int x, int y, int direction) {
 void SaveLoadChooserGrid::updateSaveList() {
 	SaveLoadChooserDialog::updateSaveList();
 	updateSaves();
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void SaveLoadChooserGrid::open() {
diff --git a/gui/storagewizarddialog.cpp b/gui/storagewizarddialog.cpp
index e7a684c..fe5a109 100644
--- a/gui/storagewizarddialog.cpp
+++ b/gui/storagewizarddialog.cpp
@@ -231,7 +231,7 @@ void StorageWizardDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
 				_codeWidget[i]->setEditString(subcode);
 			}
 			handleCommand(sender, kCodeBoxCmd, data);
-			markAsDirty();
+			g_gui.scheduleTopDialogRedraw();
 		}
 		break;
 	}
diff --git a/gui/themebrowser.cpp b/gui/themebrowser.cpp
index d21979c..6705c07 100644
--- a/gui/themebrowser.cpp
+++ b/gui/themebrowser.cpp
@@ -115,7 +115,7 @@ void ThemeBrowser::updateListing() {
 	_fileList->setSelected(currentThemeIndex);
 
 	// Finally, redraw
-	markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 } // End of namespace GUI
diff --git a/gui/widget.cpp b/gui/widget.cpp
index fa3767b..9993d64 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -206,7 +206,7 @@ void Widget::setEnabled(bool e) {
 		else
 			clearFlags(WIDGET_ENABLED);
 
-		_boss->markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
diff --git a/gui/widgets/list.cpp b/gui/widgets/list.cpp
index 16d91f9..b4a5f4b 100644
--- a/gui/widgets/list.cpp
+++ b/gui/widgets/list.cpp
@@ -744,7 +744,7 @@ void ListWidget::setFilter(const String &filter, bool redraw) {
 		// Such a widget could also (optionally) draw a border (or even different
 		// kinds of borders) around the objects it groups; and also a 'title'
 		// (I am borrowing these "ideas" from the NSBox class in Cocoa :).
-		_boss->markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
diff --git a/gui/widgets/scrollcontainer.cpp b/gui/widgets/scrollcontainer.cpp
index 00eadff..d6b1b74 100644
--- a/gui/widgets/scrollcontainer.cpp
+++ b/gui/widgets/scrollcontainer.cpp
@@ -102,7 +102,7 @@ void ScrollContainerWidget::handleCommand(CommandSender *sender, uint32 cmd, uin
 	case kSetPositionCmd:
 		_scrolledY = _verticalScroll->_currentPos;
 		reflowLayout();
-		g_gui.doFullRedraw();
+		g_gui.scheduleTopDialogRedraw();
 		break;
 	}
 }
diff --git a/gui/widgets/tab.cpp b/gui/widgets/tab.cpp
index 9b045da..dfcb919 100644
--- a/gui/widgets/tab.cpp
+++ b/gui/widgets/tab.cpp
@@ -154,7 +154,7 @@ void TabWidget::removeTab(int tabID) {
 	}
 
 	// Finally trigger a redraw
-	_boss->markAsDirty();
+	g_gui.scheduleTopDialogRedraw();
 }
 
 void TabWidget::setActiveTab(int tabID) {
@@ -174,7 +174,7 @@ void TabWidget::setActiveTab(int tabID) {
 		while (_lastVisibleTab < tabID)
 			setFirstVisible(_firstVisibleTab + 1, false);
 
-		_boss->markAsDirty();
+		g_gui.scheduleTopDialogRedraw();
 	}
 }
 
@@ -246,7 +246,7 @@ void TabWidget::setFirstVisible(int tabID, bool adjustIfRoom) {
 
 	computeLastVisibleTab(adjustIfRoom);
 
-	_boss->markAsDirty(); // TODO: Necessary?
+	g_gui.scheduleTopDialogRedraw(); // TODO: Necessary?
 }
 
 void TabWidget::reflowLayout() {


Commit: 7dc602f35287223f9a335d5f19d92b4f8951c04d
    https://github.com/scummvm/scummvm/commit/7dc602f35287223f9a335d5f19d92b4f8951c04d
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:12:53+01:00

Commit Message:
GUI: Fix the caret drawing over the scroll bar in the list widget

Also remove the unused linesWidth variable and fix the hlLeftPadding and
hlRightPadding widget attributes to actually work.

There are still issues remaining with the caret in the list widget due
to the ellipsis being used to shorten long text. Ellipsis is accounted
for when drawing the text but not when computing the caret position.

Changed paths:
    gui/widgets/list.cpp
    gui/widgets/list.h


diff --git a/gui/widgets/list.cpp b/gui/widgets/list.cpp
index b4a5f4b..df12d6f 100644
--- a/gui/widgets/list.cpp
+++ b/gui/widgets/list.cpp
@@ -37,7 +37,6 @@ ListWidget::ListWidget(Dialog *boss, const String &name, const char *tooltip, ui
 	: EditableWidget(boss, name, tooltip), _cmd(cmd) {
 
 	_scrollBar = NULL;
-	_textWidth = NULL;
 
 	// This ensures that _entriesPerPage is properly initialized.
 	reflowLayout();
@@ -69,7 +68,6 @@ ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h, const char *too
 	: EditableWidget(boss, x, y, w, h, tooltip), _cmd(cmd) {
 
 	_scrollBar = NULL;
-	_textWidth = NULL;
 
 	// This ensures that _entriesPerPage is properly initialized.
 	reflowLayout();
@@ -97,10 +95,6 @@ ListWidget::ListWidget(Dialog *boss, int x, int y, int w, int h, const char *too
 	_editColor = ThemeEngine::kFontColorNormal;
 }
 
-ListWidget::~ListWidget() {
-	delete[] _textWidth;
-}
-
 bool ListWidget::containsWidget(Widget *w) const {
 	if (w == _scrollBar || _scrollBar->containsWidget(w))
 		return true;
@@ -502,7 +496,6 @@ void ListWidget::drawWidget() {
 
 	// Draw a thin frame around the list.
 	g_gui.theme()->drawWidgetBackgroundClip(Common::Rect(_x, _y, _x + _w, _y + _h), getBossClipRect(), 0, ThemeEngine::kWidgetBackgroundBorder);
-	const int scrollbarW = (_scrollBar && _scrollBar->isVisible()) ? _scrollBarWidth : 0;
 
 	// Draw the list items
 	for (i = 0, pos = _currentPos; i < _entriesPerPage && pos < len; i++, pos++) {
@@ -520,13 +513,11 @@ void ListWidget::drawWidget() {
 		// If in numbering mode, we first print a number prefix
 		if (_numberingMode != kListNumberingOff) {
 			buffer = Common::String::format("%2d. ", (pos + _numberingMode));
-			g_gui.theme()->drawTextClip(Common::Rect(_x, y, _x + r.left + _leftPadding, y + fontHeight - 2), getBossClipRect(),
-									buffer, _state, Graphics::kTextAlignLeft, inverted, _leftPadding, true);
+			g_gui.theme()->drawTextClip(Common::Rect(_x + _hlLeftPadding, y, _x + r.left + _leftPadding, y + fontHeight - 2),
+			                            getBossClipRect(), buffer, _state, Graphics::kTextAlignLeft, inverted, _leftPadding, true);
 			pad = 0;
 		}
 
-		int width;
-
 		ThemeEngine::FontColor color = ThemeEngine::kFontColorNormal;
 
 		if (!_listColors.empty()) {
@@ -540,22 +531,21 @@ void ListWidget::drawWidget() {
 			buffer = _editString;
 			color = _editColor;
 			adjustOffset();
-			width = _w - r.left - _hlRightPadding - _leftPadding - scrollbarW;
-			g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), getBossClipRect(), buffer, _state,
-									Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
+			g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.right, y + fontHeight - 2),
+			                            getBossClipRect(), buffer, _state,
+			                            Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
 		} else {
 			buffer = _list[pos];
-			width = _w - r.left - scrollbarW;
-			g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.left + width, y + fontHeight - 2), getBossClipRect(), buffer, _state,
-									Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
+			g_gui.theme()->drawTextClip(Common::Rect(_x + r.left, y, _x + r.right, y + fontHeight - 2),
+			                            getBossClipRect(), buffer, _state,
+			                            Graphics::kTextAlignLeft, inverted, pad, true, ThemeEngine::kFontStyleBold, color);
 		}
-
-		_textWidth[i] = width;
 	}
 }
 
 Common::Rect ListWidget::getEditRect() const {
-	Common::Rect r(_hlLeftPadding, 0, _w - _hlLeftPadding - _hlRightPadding, kLineHeight - 2);
+	const int scrollbarW = (_scrollBar && _scrollBar->isVisible()) ? _scrollBarWidth : 0;
+	Common::Rect r(_hlLeftPadding, 0, _w - _hlRightPadding - scrollbarW, kLineHeight - 2);
 	const int offset = (_selectedItem - _currentPos) * kLineHeight + _topPadding;
 	r.top += offset;
 	r.bottom += offset;
@@ -668,12 +658,6 @@ void ListWidget::reflowLayout() {
 	_entriesPerPage = fracToInt(entriesPerPage);
 	assert(_entriesPerPage > 0);
 
-	delete[] _textWidth;
-	_textWidth = new int[_entriesPerPage];
-
-	for (int i = 0; i < _entriesPerPage; i++)
-		_textWidth[i] = 0;
-
 	if (_scrollBar) {
 		_scrollBar->resize(_w - _scrollBarWidth + 1, 0, _scrollBarWidth, _h);
 		scrollBarRecalc();
diff --git a/gui/widgets/list.h b/gui/widgets/list.h
index 44366be..57e677e 100644
--- a/gui/widgets/list.h
+++ b/gui/widgets/list.h
@@ -87,7 +87,6 @@ protected:
 public:
 	ListWidget(Dialog *boss, const String &name, const char *tooltip = 0, uint32 cmd = 0);
 	ListWidget(Dialog *boss, int x, int y, int w, int h, const char *tooltip = 0, uint32 cmd = 0);
-	virtual ~ListWidget();
 
 	virtual bool containsWidget(Widget *) const;
 	virtual Widget *findWidget(int x, int y);
@@ -149,8 +148,6 @@ protected:
 	void lostFocusWidget();
 	void checkBounds();
 	void scrollToCurrent();
-
-	int *_textWidth;
 };
 
 } // End of namespace GUI


Commit: 21552fb4e6eaf7c59920055b65ae8f401426fad1
    https://github.com/scummvm/scummvm/commit/21552fb4e6eaf7c59920055b65ae8f401426fad1
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:16:08+01:00

Commit Message:
GUI: Remove the parent from the button_idle DrawData

Removing it does not result in any visible difference. It was likeliy
set by mistake.

Changed paths:
    gui/ThemeEngine.cpp


diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index 5c0b232..cff0947 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -227,7 +227,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
 	{kDDWidgetBackgroundEditText,   "widget_textedit",  true,   kDDNone},
 	{kDDWidgetBackgroundSlider,     "widget_slider",    true,   kDDNone},
 
-	{kDDButtonIdle,                 "button_idle",      true,   kDDWidgetBackgroundSlider},
+	{kDDButtonIdle,                 "button_idle",      true,   kDDNone},
 	{kDDButtonHover,                "button_hover",     false,  kDDButtonIdle},
 	{kDDButtonDisabled,             "button_disabled",  true,   kDDNone},
 	{kDDButtonPressed,              "button_pressed",   false,  kDDButtonIdle},


Commit: d26aa8255d83a1a5dd94d3f013cc9a71a589ffe1
    https://github.com/scummvm/scummvm/commit/d26aa8255d83a1a5dd94d3f013cc9a71a589ffe1
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2018-01-27T18:16:08+01:00

Commit Message:
GRAPHICS: Fix drawing clipped key colored bitmaps

The previous implementation was not clipping the bottom part of the
bitmap.

Changed paths:
    graphics/VectorRendererSpec.cpp


diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp
index 68e7a0c..1d6b258 100644
--- a/graphics/VectorRendererSpec.cpp
+++ b/graphics/VectorRendererSpec.cpp
@@ -936,34 +936,26 @@ blitKeyBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const
 	if (r.height() > source->h)
 		y = y + (r.height() >> 1) - (source->h >> 1);
 
-	int w = source->w, h = source->h;
-	int usedW = w, usedH = h;
-	int offsetX = 0, offsetY = 0;
+	Common::Rect drawRect(x, y, x + source->w, y + source->h);
+	drawRect.clip(clipping);
 
-	if (x > clipping.right || x + w < clipping.left) return;
-	if (y > clipping.bottom || y + h < clipping.top) return;
-	if (x < clipping.left) {
-		offsetX = clipping.left - x;
-		usedW -= offsetX;
-		x = clipping.left;
-	}
-	if (y < clipping.top) {
-		offsetY = clipping.top - y;
-		usedH -= offsetY;
-		y = clipping.top;
+	if (drawRect.isEmpty()) {
+		return;
 	}
-	if (usedW > clipping.width()) usedW = clipping.width();
-	if (usedH > clipping.height()) usedH = clipping.height();
 
-	PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(x, y);
-	const PixelType *src_ptr = (const PixelType *)source->getBasePtr(offsetX, offsetY);
+	int sourceOffsetX = drawRect.left - x;
+	int sourceOffsetY = drawRect.top - y;
+
+	PixelType *dst_ptr = (PixelType *)_activeSurface->getBasePtr(drawRect.left, drawRect.top);
+	const PixelType *src_ptr = (const PixelType *)source->getBasePtr(sourceOffsetX, sourceOffsetY);
 
 	int dst_pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel;
 	int src_pitch = source->pitch / source->format.bytesPerPixel;
 
-	h = usedH;
+	int w, h = drawRect.height();
+
 	while (h--) {
-		w = usedW;
+		w = drawRect.width();
 
 		while (w--) {
 			if (*src_ptr != _bitmapAlphaColor)
@@ -973,8 +965,8 @@ blitKeyBitmapClip(const Graphics::Surface *source, const Common::Rect &r, const
 			src_ptr++;
 		}
 
-		dst_ptr = dst_ptr - usedW + dst_pitch;
-		src_ptr = src_ptr - usedW + src_pitch;
+		dst_ptr = dst_ptr - drawRect.width() + dst_pitch;
+		src_ptr = src_ptr - drawRect.width() + src_pitch;
 	}
 }
 





More information about the Scummvm-git-logs mailing list