[Scummvm-git-logs] scummvm master -> 0886091f7d23734b779538dc7a2946421f877d4e

sev- sev at scummvm.org
Wed Jun 10 13:43:06 UTC 2020


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

Summary:
f099b6a073 GRAPHICS: MACGUI: Generalize pixel inversion plotproc
b49f3f6cd3 GRAPHICS: MACGUI: MacEditableText: Stay sane
9f06150a36 GRAPHICS: MACGUI: MacEditableText: Add text features
c38ad8bd5e GRAPHICS: MACGUI: MacText: Add shadow
d64e41eca2 GRAPHICS: MACGUI: Add MacButton widget
ecb0df0620 GRAPHICS: MACGUI: Ensure proper cursor change
dcb0bded11 GRAPHICS: MACGUI: Delete unnecessary helper functions
67bc0b0e88 GRAPHICS: MACGUI: MacEditableText: Properly handle cursor state change
4160ce4f86 GRAPHICS: MACGUI: MacEditableText: Start off inert
2eecd518b1 GRAPHICS: MACGUI: MacWidget: Make non-abstract
033e025365 GRAPHICS: MACGUI: MacWindowManager: Deactivate widget when mouse leaves
a2e230803d DIRECTOR: Render texts and buttons with widgets
bd216b237c DIRECTOR: Fix previous rendering typos
f112b2b564 DIRECTOR: Implement kTheHilite
d6176f8ed1 DIRECTOR: Implement kTheStageColor
5711e4399a DIRECTOR: Use WM button activation styles
d6f87f22df DIRECTOR: Make puppetSprite version-sensitive
3095637e60 DIRECTOR: Convert texts to buttons if necessary
c3bfd99d50 DIRECTOR: Render bitmaps with widgets
0886091f7d DIRECTOR: Fix puppetSprite de-activation


Commit: f099b6a073ac7d7d9fcf9070f370a6d07cec2c56
    https://github.com/scummvm/scummvm/commit/f099b6a073ac7d7d9fcf9070f370a6d07cec2c56
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: Generalize pixel inversion plotproc

Changed paths:
    graphics/macgui/macwindow.cpp
    graphics/macgui/macwindowmanager.cpp
    graphics/macgui/macwindowmanager.h


diff --git a/graphics/macgui/macwindow.cpp b/graphics/macgui/macwindow.cpp
index f9913a9bc8..36ad8eded6 100644
--- a/graphics/macgui/macwindow.cpp
+++ b/graphics/macgui/macwindow.cpp
@@ -195,18 +195,6 @@ const int arrowPixels[ARROW_H][ARROW_W] = {
 		{0,1,1,1,1,1,1,1,1,1,1,0},
 		{1,1,1,1,1,1,1,1,1,1,1,1}};
 
-int localColorWhite, localColorBlack;
-
-static void drawPixelInverted(int x, int y, int color, void *data) {
-	ManagedSurface *surface = (ManagedSurface *)data;
-
-	if (x >= 0 && x < surface->w && y >= 0 && y < surface->h) {
-		byte *p = (byte *)surface->getBasePtr(x, y);
-
-		*p = *p == localColorWhite ? localColorBlack : localColorWhite;
-	}
-}
-
 void MacWindow::updateInnerDims() {
 	if (_dims.isEmpty())
 		return;
@@ -304,10 +292,7 @@ void MacWindow::drawSimpleBorder(ManagedSurface *g) {
 				int ry2 = ry1 + _dims.height() * _scrollSize;
 				Common::Rect rr(rx1, ry1, rx2, ry2);
 
-				localColorWhite = _wm->_colorWhite;
-				localColorBlack = _wm->_colorBlack;
-
-				Graphics::drawFilledRect(rr, _wm->_colorBlack, drawPixelInverted, g);
+				Graphics::drawFilledRect(rr, _wm->_colorBlack, Graphics::macInvertPixel, g);
 			}
 		}
 		if (closeable) {
diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
index 526f8b17c0..462517cf8b 100644
--- a/graphics/macgui/macwindowmanager.cpp
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -359,6 +359,17 @@ void macDrawPixel(int x, int y, int color, void *data) {
 	}
 }
 
+void macInvertPixel(int x, int y, int color, void *data) {
+	// Argument color is unused; we just invert the colors as they are in the surface.
+	Graphics::ManagedSurface *surface = (Graphics::ManagedSurface *)data;
+
+	if (x >= 0 && x < surface->w && y >= 0 && y < surface->h) {
+		byte *p = (byte *)surface->getBasePtr(x, y);
+
+		*p = abs(255 - *p);
+	}
+}
+
 void MacWindowManager::drawDesktop() {
 	Common::Rect r(_screen->getBounds());
 
diff --git a/graphics/macgui/macwindowmanager.h b/graphics/macgui/macwindowmanager.h
index 70cd0de4aa..e962a3827a 100644
--- a/graphics/macgui/macwindowmanager.h
+++ b/graphics/macgui/macwindowmanager.h
@@ -102,6 +102,7 @@ struct MacPlotData {
 };
 
 void macDrawPixel(int x, int y, int color, void *data);
+void macInvertPixel(int x, int y, int color, void *data);
 
 /**
  * A manager class to handle window creation, destruction,


Commit: b49f3f6cd3ff94d459a782205eb38412782d9545
    https://github.com/scummvm/scummvm/commit/b49f3f6cd3ff94d459a782205eb38412782d9545
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacEditableText: Stay sane

Changed paths:
    graphics/macgui/maceditabletext.cpp


diff --git a/graphics/macgui/maceditabletext.cpp b/graphics/macgui/maceditabletext.cpp
index 4a6ae664da..c83c4f5871 100644
--- a/graphics/macgui/maceditabletext.cpp
+++ b/graphics/macgui/maceditabletext.cpp
@@ -108,10 +108,9 @@ void MacEditableText::setActive(bool active) {
 
 	MacWidget::setActive(active);
 
+	g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler);
 	if (_active) {
 		g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "macEditableText");
-	} else {
-		g_system->getTimerManager()->removeTimerProc(&cursorTimerHandler);
 	}
 
 	if (!_cursorOff && _cursorState == true) {
@@ -161,6 +160,11 @@ bool MacEditableText::draw(bool forceRedraw) {
 	if (!_contentIsDirty && !_cursorDirty && !forceRedraw)
 		return false;
 
+	if (!_surface) {
+		warning("MacEditableText::draw: Null surface");
+		return false;
+	}
+
 	_composeSurface->clear(_bgcolor);
 
 	_contentIsDirty = false;
@@ -179,7 +183,7 @@ bool MacEditableText::draw(bool forceRedraw) {
 }
 
 bool MacEditableText::draw(ManagedSurface *g, bool forceRedraw) {
-	if (!draw(forceRedraw))
+	if (!MacEditableText::draw(forceRedraw))
 		return false;
 
 	g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), Common::Point(_dims.left - 2, _dims.top - 2), kColorGreen2);


Commit: 9f06150a36984174e831bbeaf752ac7e75faff1f
    https://github.com/scummvm/scummvm/commit/9f06150a36984174e831bbeaf752ac7e75faff1f
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacEditableText: Add text features

 Border, gutter, box shadow, text alignment

Changed paths:
    graphics/macgui/maceditabletext.cpp
    graphics/macgui/maceditabletext.h
    graphics/macgui/macwidget.cpp
    graphics/macgui/macwidget.h


diff --git a/graphics/macgui/maceditabletext.cpp b/graphics/macgui/maceditabletext.cpp
index c83c4f5871..167a595797 100644
--- a/graphics/macgui/maceditabletext.cpp
+++ b/graphics/macgui/maceditabletext.cpp
@@ -40,8 +40,8 @@ enum {
 
 static void cursorTimerHandler(void *refCon);
 
-MacEditableText::MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear) :
-		MacWidget(parent, x, y, w, h, true), MacText(s, wm, macFont, fgcolor, bgcolor, maxWidth, textAlignment, interlinear) {
+MacEditableText::MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear, uint16 border, uint16 gutter, uint16 boxShadow, uint16 textShadow) :
+	MacWidget(parent, x, y, w, h, true, border, gutter, boxShadow), MacText(s, wm, macFont, fgcolor, bgcolor, maxWidth, textAlignment, interlinear, textShadow) {
 
 	_maxWidth = maxWidth;
 
@@ -50,10 +50,12 @@ MacEditableText::MacEditableText(MacWidget *parent, int x, int y, int w, int h,
 	setDefaultFormatting(macFont->getId(), macFont->getSlant(), macFont->getSize(), 0, 0, 0);
 
 	MacText::render();
+	setAlignOffset(_textAlignment);
+	updateCursorPos();
 }
 
-MacEditableText::MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::String &s, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear) :
-		MacWidget(parent, x, y, w, h, true), MacText(s, wm, macFont, fgcolor, bgcolor, maxWidth, textAlignment, interlinear) {
+MacEditableText::MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::String &s, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear, uint16 border, uint16 gutter, uint16 boxShadow, uint16 textShadow) :
+	MacWidget(parent, x, y, w, h, true, border, gutter, boxShadow), MacText(s, wm, macFont, fgcolor, bgcolor, maxWidth, textAlignment, interlinear, textShadow) {
 
 	_maxWidth = maxWidth;
 
@@ -62,6 +64,8 @@ MacEditableText::MacEditableText(MacWidget *parent, int x, int y, int w, int h,
 	setDefaultFormatting(macFont->getId(), macFont->getSlant(), macFont->getSize(), 0, 0, 0);
 
 	MacText::render();
+	setAlignOffset(_textAlignment);
+	updateCursorPos();
 }
 
 void MacEditableText::init() {
@@ -83,8 +87,6 @@ void MacEditableText::init() {
 	_cursorRow = getLineCount() - 1;
 	_cursorCol = getLineCharWidth(_cursorRow);
 
-	updateCursorPos();
-
 	_cursorRect = new Common::Rect(0, 0, 1, kCursorHeight);
 
 	_cursorSurface = new ManagedSurface(1, kCursorHeight);
@@ -102,6 +104,25 @@ MacEditableText::~MacEditableText() {
 	delete _composeSurface;
 }
 
+void MacEditableText::setAlignOffset(TextAlign align) {
+	switch(align) {
+	case kTextAlignLeft:
+	default:
+		_alignOffset = Common::Point(0, 0);
+		break;
+	case kTextAlignCenter:
+		_alignOffset = Common::Point((_maxWidth / 2) - (_surface->w / 2), 0);
+		break;
+	case kTextAlignRight:
+		_alignOffset = Common::Point(_maxWidth - (_surface->w + 1), 0);
+		break;
+	}
+}
+
+Common::Point MacEditableText::calculateOffset() {
+	return Common::Point(_alignOffset.x + _border + _gutter + 1, _alignOffset.y + _border + _gutter/2);
+}
+
 void MacEditableText::setActive(bool active) {
 	if (_active == active)
 		return;
@@ -171,10 +192,21 @@ bool MacEditableText::draw(bool forceRedraw) {
 	_cursorDirty = false;
 
 	// Compose
-	MacText::draw(_composeSurface, 0, _scrollPos, _surface->w, _scrollPos + _surface->h, 0, 0);
+	for (int bb = 0; bb < _shadow; bb ++) {
+		_composeSurface->hLine(_shadow, _composeSurface->h - _shadow + bb, _composeSurface->w, 0);
+		_composeSurface->vLine(_composeSurface->w - _shadow + bb, _shadow, _composeSurface->h - _shadow, 0);
+	}
+
+	for (int bb = 0; bb < _border; bb++) {
+		Common::Rect borderRect(bb, bb, _composeSurface->w - _shadow - bb, _composeSurface->h - _shadow - bb);
+		_composeSurface->frameRect(borderRect, 0);
+	}
+
+	Common::Point offset(calculateOffset());
+	MacText::draw(_composeSurface, 0, _scrollPos, _surface->w, _scrollPos + _surface->h, offset.x, offset.y);
 
 	if (_cursorState)
-		_composeSurface->blitFrom(*_cursorSurface, *_cursorRect, Common::Point(_cursorX, _cursorY));
+		_composeSurface->blitFrom(*_cursorSurface, *_cursorRect, Common::Point(_cursorX, _cursorY + offset.y + 1));
 
 	if (_selectedText.endY != -1)
 		drawSelection();
@@ -524,8 +556,16 @@ void MacEditableText::updateCursorPos() {
 	} else {
 		_cursorRow = MIN<int>(_cursorRow, _textLines.size() - 1);
 
-		_cursorY = _textLines[_cursorRow].y;
-		_cursorX = getLineWidth(_cursorRow, false, _cursorCol);
+		Common::Point offset(calculateOffset());
+
+		int alignOffset = 0;
+		if (_textAlignment == kTextAlignRight)
+			alignOffset = _textMaxWidth - getLineWidth(_cursorRow);
+		else if (_textAlignment == kTextAlignCenter)
+			alignOffset = (_textMaxWidth / 2) - (getLineWidth(_cursorRow) / 2);
+
+		_cursorY = _textLines[_cursorRow].y + offset.y - 2;
+		_cursorX = getLineWidth(_cursorRow, false, _cursorCol) + alignOffset + offset.x - 1;
 	}
 
 	_cursorDirty = true;
diff --git a/graphics/macgui/maceditabletext.h b/graphics/macgui/maceditabletext.h
index cdde33620c..f61a7587f8 100644
--- a/graphics/macgui/maceditabletext.h
+++ b/graphics/macgui/maceditabletext.h
@@ -53,10 +53,8 @@ struct SelectedText {
 
 class MacEditableText : public MacText, public MacWidget {
 public:
-	MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *font, int fgcolor, int bgcolor,
-			int maxWidth, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0);
-	MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::String &s, const MacFont *font, int fgcolor, int bgcolor,
-			int maxWidth, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0);
+	MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0, uint16 border = 0, uint16 gutter = 0, uint16 boxShadow = 0, uint16 textShadow = 0);
+	MacEditableText(MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::String &s, const MacFont *font, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0, uint16 border = 0, uint16 gutter = 0, uint16 boxShadow = 0, uint16 textShadow = 0);
 			// 0 pixels between the lines by default
 	virtual ~MacEditableText();
 
@@ -68,6 +66,8 @@ public:
 	virtual bool draw(bool forceRedraw = false) override;
 	virtual void blit(ManagedSurface *g, Common::Rect &dest) override;
 
+	void setAlignOffset(TextAlign align);
+	Common::Point calculateOffset();
 	virtual void setActive(bool active) override;
 
 	void appendText(const Common::U32String &str, const MacFont *macFont, bool skipAdd = false);
@@ -110,6 +110,9 @@ public:
 
 	int _scrollPos;
 
+protected:
+	Common::Point _alignOffset;
+
 private:
 	ManagedSurface *_cursorSurface;
 
diff --git a/graphics/macgui/macwidget.cpp b/graphics/macgui/macwidget.cpp
index 051c45839d..5cd8e0df84 100644
--- a/graphics/macgui/macwidget.cpp
+++ b/graphics/macgui/macwidget.cpp
@@ -26,14 +26,14 @@
 
 namespace Graphics {
 
-MacWidget::MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusable) :
-		_focusable(focusable), _parent(parent) {
+MacWidget::MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusable, uint16 border, uint16 gutter, uint16 shadow) :
+	_focusable(focusable), _parent(parent), _border(border), _gutter(gutter), _shadow(shadow) {
 	_contentIsDirty = true;
 
 	_dims.left = x;
-	_dims.right = x + w;
+	_dims.right = x + w + 2 * border + 2 * gutter + shadow + 1;
 	_dims.top = y;
-	_dims.bottom = y + h;
+	_dims.bottom = y + h + 2 * border + gutter + shadow;
 
 	if (parent)
 		parent->_children.push_back(this);
diff --git a/graphics/macgui/macwidget.h b/graphics/macgui/macwidget.h
index e919568be0..ca9322b2d0 100644
--- a/graphics/macgui/macwidget.h
+++ b/graphics/macgui/macwidget.h
@@ -39,7 +39,7 @@ class MacWidget {
 	friend class MacEditableText;
 
 public:
-	MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusable);
+	MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusable, uint16 border = 0, uint16 gutter = 0, uint16 shadow = 0);
 	virtual ~MacWidget();
 
 	/**
@@ -87,6 +87,10 @@ protected:
 	bool _active;
 	bool _editable;
 
+	uint16 _border;
+	uint16 _gutter;
+	uint16 _shadow;
+
 	Common::Rect _dims;
 
 	Graphics::ManagedSurface *_composeSurface;


Commit: c38ad8bd5ecd826142fdcbbd3a8dc70967fd9e5c
    https://github.com/scummvm/scummvm/commit/c38ad8bd5ecd826142fdcbbd3a8dc70967fd9e5c
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacText: Add shadow

Changed paths:
    graphics/macgui/mactext.cpp
    graphics/macgui/mactext.h


diff --git a/graphics/macgui/mactext.cpp b/graphics/macgui/mactext.cpp
index 8675b12f74..54908256e9 100644
--- a/graphics/macgui/mactext.cpp
+++ b/graphics/macgui/mactext.cpp
@@ -83,7 +83,7 @@ MacText::~MacText() {
 	delete _surface;
 }
 
-MacText::MacText(const Common::U32String &s, MacWindowManager *wm, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear) {
+MacText::MacText(const Common::U32String &s, MacWindowManager *wm, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear, uint16 textShadow) {
 	_str = s;
 	_wm = wm;
 	_macFont = macFont;
@@ -95,6 +95,7 @@ MacText::MacText(const Common::U32String &s, MacWindowManager *wm, const MacFont
 	_surface = nullptr;
 	_textAlignment = textAlignment;
 	_interLinear = interlinear;
+	_textShadow = textShadow;
 
 	if (macFont) {
 		_defaultFormatting = MacFontRun(_wm, macFont->getId(), macFont->getSlant(), macFont->getSize(), 0, 0, 0);
@@ -114,7 +115,7 @@ MacText::MacText(const Common::U32String &s, MacWindowManager *wm, const MacFont
 	_fullRefresh = true;
 }
 
-MacText::MacText(const Common::String &s, MacWindowManager *wm, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear) {
+MacText::MacText(const Common::String &s, MacWindowManager *wm, const MacFont *macFont, int fgcolor, int bgcolor, int maxWidth, TextAlign textAlignment, int interlinear, uint16 textShadow) {
 	_str = Common::U32String(s);
 	_wm = wm;
 	_macFont = macFont;
@@ -126,6 +127,7 @@ MacText::MacText(const Common::String &s, MacWindowManager *wm, const MacFont *m
 	_surface = nullptr;
 	_textAlignment = textAlignment;
 	_interLinear = interlinear;
+	_textShadow = textShadow;
 
 	if (macFont) {
 		_defaultFormatting = MacFontRun(_wm, macFont->getId(), macFont->getSlant(), macFont->getSize(), 0, 0, 0);
@@ -592,6 +594,12 @@ void MacText::draw(ManagedSurface *g, int x, int y, int w, int h, int xoff, int
 	g->blitFrom(*_surface, Common::Rect(MIN<int>(_surface->w, x), MIN<int>(_surface->h, y),
 										MIN<int>(_surface->w, x + w), MIN<int>(_surface->h, y + h)),
 										Common::Point(xoff, yoff));
+
+	if (_textShadow)
+		g->transBlitFrom(*_surface, Common::Rect(MIN<int>(_surface->w, x), MIN<int>(_surface->h, y),
+																				MIN<int>(_surface->w, x + w), MIN<int>(_surface->h, y + h)),
+										 Common::Point(xoff + _textShadow, yoff + _textShadow), 0xff);
+
 }
 
 void MacText::drawToPoint(ManagedSurface *g, Common::Rect srcRect, Common::Point dstPoint) {
diff --git a/graphics/macgui/mactext.h b/graphics/macgui/mactext.h
index 9df142c6bd..5567459fe8 100644
--- a/graphics/macgui/mactext.h
+++ b/graphics/macgui/mactext.h
@@ -109,9 +109,9 @@ class MacText {
 
 public:
 	MacText(const Common::U32String &s, MacWindowManager *wm, const MacFont *font, int fgcolor, int bgcolor,
-			int maxWidth = -1, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0);
+			int maxWidth = -1, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0, uint16 textShadow = 0);
 	MacText(const Common::String &s, MacWindowManager *wm, const MacFont *font, int fgcolor, int bgcolor,
-			int maxWidth = -1, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0);
+			int maxWidth = -1, TextAlign textAlignment = kTextAlignLeft, int interlinear = 0, uint16 textShadow = 0);
 			// 0 pixels between the lines by default
 	~MacText();
 
@@ -182,6 +182,7 @@ protected:
 
 	int _maxWidth;
 	int _interLinear;
+	int _textShadow;
 
 	int _textMaxWidth;
 	int _textMaxHeight;


Commit: d64e41eca240aefe24ab1664c9b24485afc33c23
    https://github.com/scummvm/scummvm/commit/d64e41eca240aefe24ab1664c9b24485afc33c23
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: Add MacButton widget

Changed paths:
  A graphics/macgui/macbutton.cpp
  A graphics/macgui/macbutton.h
    graphics/module.mk


diff --git a/graphics/macgui/macbutton.cpp b/graphics/macgui/macbutton.cpp
new file mode 100644
index 0000000000..54b5934ee5
--- /dev/null
+++ b/graphics/macgui/macbutton.cpp
@@ -0,0 +1,165 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/timer.h"
+#include "common/system.h"
+
+#include "graphics/primitives.h"
+#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/macgui/macfontmanager.h"
+#include "graphics/macgui/maceditabletext.h"
+#include "graphics/macgui/macmenu.h"
+#include "graphics/macgui/macbutton.h"
+#include "graphics/macgui/macwidget.h"
+#include "graphics/macgui/macwindow.h"
+
+namespace Graphics {
+
+MacButton::MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *macFont, int fgcolor, int bgcolor) :
+	MacEditableText(parent, x, y, w, h, wm, s, macFont, fgcolor, bgcolor, w, textAlignment) {
+
+	_buttonType = buttonType;
+	delete _composeSurface;
+
+	int offset;
+	switch (buttonType) {
+	case kCheckBox:
+		offset = 16;
+		break;
+	case kRound:
+		offset = 4;
+		_dims.top -= 2;
+		_dims.bottom += 2;
+		_alignOffset.y += 2;
+		break;
+	case kRadio:
+		offset = 16;
+		break;
+	}
+
+	_alignOffset.x += offset;
+	_dims.right += offset;
+	_composeSurface = new ManagedSurface(_dims.width(), _dims.height());
+}
+
+void MacButton::setActive(bool active) {
+	if (active == _active)
+		return;
+
+	MacWidget::setActive(active);
+	if (_composeSurface)
+		invertOuter();
+}
+
+void MacButton::invertOuter() {
+	Common::Rect r(_dims.width() - 1, _dims.height() - 1);
+
+	switch (_buttonType) {
+	case kCheckBox: {
+		Common::Rect c = Common::Rect(r.left + 1, r.top + 3, r.left + 9, r.top + 11);
+		Graphics::drawRect(c, 0, Graphics::macInvertPixel, _composeSurface);
+	}
+		break;
+	case kRound:
+		Graphics::drawRoundRect(r, 4, 0, true, Graphics::macInvertPixel, _composeSurface);
+		break;
+	case kRadio:
+		Graphics::drawEllipse(r.left + 1, r.top + 3, r.left + 10, r.top + 12, 0, false, Graphics::macInvertPixel, _composeSurface);
+		break;
+	}
+}
+
+void MacButton::invertInner() {
+	Common::Rect r(_dims.width() - 1, _dims.height() - 1);
+
+	switch (_buttonType) {
+	case kCheckBox:
+		Graphics::drawLine(r.left + 1, r.top + 3, r.left + 9, r.top + 11, 0, Graphics::macInvertPixel, _composeSurface);
+		Graphics::drawLine(r.left + 1, r.top + 11, r.left + 9, r.top + 3, 0, Graphics::macInvertPixel, _composeSurface);
+		Graphics::macInvertPixel(5, 7, 0, _composeSurface);
+		break;
+	case kRound:
+		break;
+	case kRadio:
+		Graphics::drawEllipse(r.left + 3, r.top + 5, r.left + 8, r.top + 10, 0, true, Graphics::macInvertPixel, _composeSurface);
+		break;
+	}
+}
+
+bool MacButton::draw(bool forceRedraw) {
+	if (!_contentIsDirty && !forceRedraw)
+		return false;
+
+	MacEditableText::draw();
+
+	Common::Rect r(_dims.width() - 1, _dims.height() - 1);
+	Graphics::MacPlotData pd(_composeSurface, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, 0);
+
+	switch (_buttonType) {
+	case kCheckBox: {
+		Common::Rect c = Common::Rect(r.left, r.top + 2, r.left + 10, r.top + 2 + 10);
+		Graphics::drawRect(c, 0, Graphics::macDrawPixel, &pd);
+		break;
+	}
+	case kRound:
+		Graphics::drawRoundRect(r, 4, 0, _active, Graphics::macDrawPixel, &pd);
+		break;
+	case kRadio:
+		Graphics::drawEllipse(r.left, r.top + 2, r.left + 11, r.top + 13, 0, false, Graphics::macDrawPixel, &pd);
+		break;
+	}
+
+	_contentIsDirty = false;
+	return true;
+}
+
+bool MacButton::draw(ManagedSurface *g, bool forceRedraw) {
+	if (!MacButton::draw(forceRedraw))
+		return false;
+
+	g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), Common::Point(_dims.left - 2, _dims.top - 2), kColorGreen2);
+
+	return true;
+}
+
+void MacButton::blit(ManagedSurface *g, Common::Rect &dest) {
+	g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, kColorGreen2);
+}
+
+bool MacButton::processEvent(Common::Event &event) {
+	switch (event.type) {
+	case Common::EVENT_MOUSEMOVE:
+		break;
+	case Common::EVENT_LBUTTONDOWN:
+		setActive(true);
+		break;
+	case Common::EVENT_LBUTTONUP:
+		setActive(false);
+		invertInner();
+		break;
+	default:
+		warning("MacButton:: processEvent: Event not handled");
+	}
+	return false;
+}
+
+} // End of namespace Graphics
diff --git a/graphics/macgui/macbutton.h b/graphics/macgui/macbutton.h
new file mode 100644
index 0000000000..c1302a5e60
--- /dev/null
+++ b/graphics/macgui/macbutton.h
@@ -0,0 +1,60 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef GRAPHICS_MACGUI_MACBUTTON_H
+#define GRAPHICS_MACGUI_MACBUTTON_H
+
+#include "graphics/macgui/mactext.h"
+#include "graphics/macgui/maceditabletext.h"
+#include "graphics/macgui/macwidget.h"
+
+namespace Graphics {
+
+class MacWidget;
+class MacText;
+
+enum MacButtonType {
+	kRound,
+	kCheckBox,
+	kRadio
+};
+
+class MacButton : public MacEditableText {
+public:
+	MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidget *parent, int x, int y, int w, int h, MacWindowManager *wm, const Common::U32String &s, const MacFont *macFont, int fgcolor, int bgcolor);
+
+	virtual void setActive(bool active) override;
+
+	void invertOuter();
+	void invertInner();
+	virtual bool draw(ManagedSurface *g, bool forceRedraw = false) override;
+	virtual bool draw(bool forceRedraw = false) override;
+	virtual void blit(ManagedSurface *g, Common::Rect &dest) override;
+	virtual bool processEvent(Common::Event &event) override;
+
+private:
+	MacButtonType _buttonType;
+};
+
+} // End of namespace Graphics
+
+#endif
diff --git a/graphics/module.mk b/graphics/module.mk
index f2a0a52364..8068b389be 100644
--- a/graphics/module.mk
+++ b/graphics/module.mk
@@ -14,6 +14,7 @@ MODULE_OBJS := \
 	fonts/winfont.o \
 	larryScale.o \
 	maccursor.o \
+	macgui/macbutton.o \
 	macgui/maceditabletext.o \
 	macgui/macfontmanager.o \
 	macgui/macmenu.o \


Commit: ecb0df0620e7856aaa8d07567b5d962fc24e7a26
    https://github.com/scummvm/scummvm/commit/ecb0df0620e7856aaa8d07567b5d962fc24e7a26
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: Ensure proper cursor change

Changed paths:
    graphics/macgui/macwindowmanager.cpp


diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
index 462517cf8b..204abcbab0 100644
--- a/graphics/macgui/macwindowmanager.cpp
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -446,8 +446,9 @@ bool MacWindowManager::processEvent(Common::Event &event) {
 
 	if (_activeWindow != -1) {
 		if ((_windows[_activeWindow]->isEditable() && _windows[_activeWindow]->getType() == kWindowWindow &&
-				((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y))
-				|| (_activeWidget && _activeWidget->isEditable())) {
+				 ((MacWindow *)_windows[_activeWindow])->getInnerDimensions().contains(event.mouse.x, event.mouse.y)) ||
+				(_activeWidget && _activeWidget->isEditable() &&
+				 _activeWidget->getDimensions().contains(event.mouse.x, event.mouse.y))) {
 			if (_cursorIsArrow) {
 				CursorMan.replaceCursor(macCursorBeam, 11, 16, 3, 8, 3);
 				_cursorIsArrow = false;


Commit: dcb0bded11fbb923e854e2fb1aa75d53ecbaf916
    https://github.com/scummvm/scummvm/commit/dcb0bded11fbb923e854e2fb1aa75d53ecbaf916
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: Delete unnecessary helper functions

Changed paths:
    graphics/macgui/maceditabletext.h
    graphics/macgui/macwidget.h


diff --git a/graphics/macgui/maceditabletext.h b/graphics/macgui/maceditabletext.h
index f61a7587f8..2ec58129f3 100644
--- a/graphics/macgui/maceditabletext.h
+++ b/graphics/macgui/maceditabletext.h
@@ -74,9 +74,6 @@ public:
 	void appendText(const Common::String &str, const MacFont *macFont, bool skipAdd = false);
 	void clearText();
 
-	void setEditable(bool editable) { _editable = editable; }
-	void setSelectable(bool selectable) { _selectable = selectable; }
-
 	void undrawCursor();
 
 	Common::U32String getSelection(bool formatted = false, bool newlines = true);
diff --git a/graphics/macgui/macwidget.h b/graphics/macgui/macwidget.h
index ca9322b2d0..f59492af1d 100644
--- a/graphics/macgui/macwidget.h
+++ b/graphics/macgui/macwidget.h
@@ -48,8 +48,6 @@ public:
 	 */
 	const Common::Rect &getDimensions() { return _dims; }
 
-	bool isFocusable() { return _focusable; }
-
 	/**
 	 * Method for indicating whether the widget is active or inactive.
 	 * Used by the WM to handle focus on windows, etc.
@@ -82,20 +80,20 @@ public:
 	Graphics::ManagedSurface *getSurface() { return _composeSurface; }
 
 protected:
-	bool _focusable;
-	bool _contentIsDirty;
-	bool _active;
-	bool _editable;
-
 	uint16 _border;
 	uint16 _gutter;
 	uint16 _shadow;
 
-	Common::Rect _dims;
-
 	Graphics::ManagedSurface *_composeSurface;
 
 public:
+	bool _focusable;
+	bool _contentIsDirty;
+	bool _active;
+	bool _editable;
+
+	Common::Rect _dims;
+
 	MacWidget *_parent;
 	Common::Array<MacWidget *> _children;
 };


Commit: 67bc0b0e88a0e4030a3db7531419f865fbc0488e
    https://github.com/scummvm/scummvm/commit/67bc0b0e88a0e4030a3db7531419f865fbc0488e
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacEditableText: Properly handle cursor state change

Changed paths:
    graphics/macgui/maceditabletext.cpp
    graphics/macgui/maceditabletext.h


diff --git a/graphics/macgui/maceditabletext.cpp b/graphics/macgui/maceditabletext.cpp
index 167a595797..875fad4537 100644
--- a/graphics/macgui/maceditabletext.cpp
+++ b/graphics/macgui/maceditabletext.cpp
@@ -134,9 +134,24 @@ void MacEditableText::setActive(bool active) {
 		g_system->getTimerManager()->installTimerProc(&cursorTimerHandler, 200000, this, "macEditableText");
 	}
 
-	if (!_cursorOff && _cursorState == true) {
-		_cursorState = false;
-		_cursorDirty = true;
+	if (!_cursorOff && _cursorState == true)
+		undrawCursor();
+}
+
+void MacEditableText::setEditable(bool editable) {
+	if (editable == _editable)
+		return;
+
+	_editable = editable;
+	_cursorOff = !editable;
+
+	if (editable) {
+		// TODO: Select whole region. This is done every time the text is set from
+		// uneditable to editable.
+		setActive(editable);
+		_wm->setActiveWidget(this);
+	} else {
+		undrawCursor();
 	}
 }
 
diff --git a/graphics/macgui/maceditabletext.h b/graphics/macgui/maceditabletext.h
index 2ec58129f3..d97b4184b4 100644
--- a/graphics/macgui/maceditabletext.h
+++ b/graphics/macgui/maceditabletext.h
@@ -69,6 +69,7 @@ public:
 	void setAlignOffset(TextAlign align);
 	Common::Point calculateOffset();
 	virtual void setActive(bool active) override;
+	void setEditable(bool editable);
 
 	void appendText(const Common::U32String &str, const MacFont *macFont, bool skipAdd = false);
 	void appendText(const Common::String &str, const MacFont *macFont, bool skipAdd = false);


Commit: 4160ce4f86fa80bb6304490a634cb16629237038
    https://github.com/scummvm/scummvm/commit/4160ce4f86fa80bb6304490a634cb16629237038
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacEditableText: Start off inert

Changed paths:
    graphics/macgui/maceditabletext.cpp


diff --git a/graphics/macgui/maceditabletext.cpp b/graphics/macgui/maceditabletext.cpp
index 875fad4537..89773b63aa 100644
--- a/graphics/macgui/maceditabletext.cpp
+++ b/graphics/macgui/maceditabletext.cpp
@@ -72,8 +72,8 @@ void MacEditableText::init() {
 	_inTextSelection = false;
 
 	_scrollPos = 0;
-	_editable = true;
-	_selectable = true;
+	_editable = false;
+	_selectable = false;
 
 	_editableRow = 0;
 


Commit: 2eecd518b169a9d40dc403eaf18998563bbf88a0
    https://github.com/scummvm/scummvm/commit/2eecd518b169a9d40dc403eaf18998563bbf88a0
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacWidget: Make non-abstract

Changed paths:
    graphics/macgui/macbutton.cpp
    graphics/macgui/macbutton.h
    graphics/macgui/maceditabletext.cpp
    graphics/macgui/maceditabletext.h
    graphics/macgui/macwidget.cpp
    graphics/macgui/macwidget.h


diff --git a/graphics/macgui/macbutton.cpp b/graphics/macgui/macbutton.cpp
index 54b5934ee5..cc2c9cb871 100644
--- a/graphics/macgui/macbutton.cpp
+++ b/graphics/macgui/macbutton.cpp
@@ -38,7 +38,6 @@ MacButton::MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidge
 	MacEditableText(parent, x, y, w, h, wm, s, macFont, fgcolor, bgcolor, w, textAlignment) {
 
 	_buttonType = buttonType;
-	delete _composeSurface;
 
 	int offset;
 	switch (buttonType) {
@@ -58,7 +57,8 @@ MacButton::MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidge
 
 	_alignOffset.x += offset;
 	_dims.right += offset;
-	_composeSurface = new ManagedSurface(_dims.width(), _dims.height());
+	_composeSurface->create(_dims.width(), _dims.height());
+	_maskSurface->create(_dims.width(), _dims.height());
 }
 
 void MacButton::setActive(bool active) {
@@ -109,10 +109,11 @@ bool MacButton::draw(bool forceRedraw) {
 	if (!_contentIsDirty && !forceRedraw)
 		return false;
 
+	_maskSurface->clear(0);
 	MacEditableText::draw();
 
 	Common::Rect r(_dims.width() - 1, _dims.height() - 1);
-	Graphics::MacPlotData pd(_composeSurface, nullptr, &_wm->getPatterns(), 1, 0, 0, 1, 0);
+	Graphics::MacPlotData pd(_composeSurface, _maskSurface, &_wm->getPatterns(), 1, 0, 0, 1, 0);
 
 	switch (_buttonType) {
 	case kCheckBox: {
@@ -141,10 +142,6 @@ bool MacButton::draw(ManagedSurface *g, bool forceRedraw) {
 	return true;
 }
 
-void MacButton::blit(ManagedSurface *g, Common::Rect &dest) {
-	g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, kColorGreen2);
-}
-
 bool MacButton::processEvent(Common::Event &event) {
 	switch (event.type) {
 	case Common::EVENT_MOUSEMOVE:
diff --git a/graphics/macgui/macbutton.h b/graphics/macgui/macbutton.h
index c1302a5e60..fead5fee37 100644
--- a/graphics/macgui/macbutton.h
+++ b/graphics/macgui/macbutton.h
@@ -48,7 +48,6 @@ public:
 	void invertInner();
 	virtual bool draw(ManagedSurface *g, bool forceRedraw = false) override;
 	virtual bool draw(bool forceRedraw = false) override;
-	virtual void blit(ManagedSurface *g, Common::Rect &dest) override;
 	virtual bool processEvent(Common::Event &event) override;
 
 private:
diff --git a/graphics/macgui/maceditabletext.cpp b/graphics/macgui/maceditabletext.cpp
index 89773b63aa..c0dadba278 100644
--- a/graphics/macgui/maceditabletext.cpp
+++ b/graphics/macgui/maceditabletext.cpp
@@ -91,9 +91,6 @@ void MacEditableText::init() {
 
 	_cursorSurface = new ManagedSurface(1, kCursorHeight);
 	_cursorSurface->clear(_wm->_colorBlack);
-
-	_composeSurface = new ManagedSurface(_dims.width(), _dims.height());
-	_composeSurface->clear(_bgcolor);
 }
 
 MacEditableText::~MacEditableText() {
@@ -238,10 +235,6 @@ bool MacEditableText::draw(ManagedSurface *g, bool forceRedraw) {
 	return true;
 }
 
-void MacEditableText::blit(ManagedSurface *g, Common::Rect &dest) {
-	g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, kColorGreen2);
-}
-
 void MacEditableText::drawSelection() {
 	if (_selectedText.endY == -1)
 		return;
diff --git a/graphics/macgui/maceditabletext.h b/graphics/macgui/maceditabletext.h
index d97b4184b4..62ef25fd19 100644
--- a/graphics/macgui/maceditabletext.h
+++ b/graphics/macgui/maceditabletext.h
@@ -64,7 +64,6 @@ public:
 
 	virtual bool draw(ManagedSurface *g, bool forceRedraw = false) override;
 	virtual bool draw(bool forceRedraw = false) override;
-	virtual void blit(ManagedSurface *g, Common::Rect &dest) override;
 
 	void setAlignOffset(TextAlign align);
 	Common::Point calculateOffset();
diff --git a/graphics/macgui/macwidget.cpp b/graphics/macgui/macwidget.cpp
index 5cd8e0df84..a98f25480d 100644
--- a/graphics/macgui/macwidget.cpp
+++ b/graphics/macgui/macwidget.cpp
@@ -22,11 +22,12 @@
 
 #include "common/system.h"
 
+#include "graphics/macgui/macwindowmanager.h"
 #include "graphics/macgui/macwidget.h"
 
 namespace Graphics {
 
-MacWidget::MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusable, uint16 border, uint16 gutter, uint16 shadow) :
+	MacWidget::MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusable, uint16 border, uint16 gutter, uint16 shadow) :
 	_focusable(focusable), _parent(parent), _border(border), _gutter(gutter), _shadow(shadow) {
 	_contentIsDirty = true;
 
@@ -39,6 +40,13 @@ MacWidget::MacWidget(MacWidget *parent, int x, int y, int w, int h, bool focusab
 		parent->_children.push_back(this);
 
 	_composeSurface = nullptr;
+	_maskSurface = nullptr;
+
+	_composeSurface = new ManagedSurface(_dims.width(), _dims.height());
+	_composeSurface->clear(255);
+
+	_maskSurface = new ManagedSurface(_dims.width(), _dims.height());
+	_maskSurface->clear(0);
 
 	_active = false;
 	_editable = false;
@@ -59,6 +67,23 @@ void MacWidget::setActive(bool active) {
 	_active = active;
 }
 
+bool MacWidget::draw(bool forceRedraw) {
+	return false;
+}
+
+bool MacWidget::draw(ManagedSurface *g, bool forceRedraw) {
+	return false;
+}
+
+void MacWidget::blit(ManagedSurface *g, Common::Rect &dest) {
+	g->transBlitFrom(*_composeSurface, _composeSurface->getBounds(), dest, kColorGreen2);
+}
+
+bool MacWidget::processEvent(Common::Event &event) {
+	warning("MacWidget::processEvent");
+	return false;
+}
+
 void MacWidget::removeWidget(MacWidget *child, bool del) {
 	for (uint i = 0; i < _children.size(); i++) {
 		if (_children[i] == child) {
diff --git a/graphics/macgui/macwidget.h b/graphics/macgui/macwidget.h
index f59492af1d..8fbada8977 100644
--- a/graphics/macgui/macwidget.h
+++ b/graphics/macgui/macwidget.h
@@ -26,6 +26,7 @@
 #include "common/array.h"
 #include "common/events.h"
 #include "common/rect.h"
+#include "graphics/managed_surface.h"
 
 namespace Common {
 	struct Event;
@@ -34,6 +35,7 @@ namespace Common {
 namespace Graphics {
 
 class ManagedSurface;
+class MacWindowManager;
 
 class MacWidget {
 	friend class MacEditableText;
@@ -61,10 +63,10 @@ public:
 	 */
 	void setDirty(bool dirty) { _contentIsDirty = dirty; }
 
-	virtual bool draw(ManagedSurface *g, bool forceRedraw = false) = 0;
-	virtual bool draw(bool forceRedraw = false) = 0;
-	virtual void blit(ManagedSurface *g, Common::Rect &dest) = 0;
-	virtual bool processEvent(Common::Event &event) = 0;
+	virtual bool draw(ManagedSurface *g, bool forceRedraw = false);
+	virtual bool draw(bool forceRedraw = false);
+	virtual void blit(ManagedSurface *g, Common::Rect &dest);
+	virtual bool processEvent(Common::Event &event);
 	virtual bool hasAllFocus() { return _active; }
 	virtual bool isEditable() { return _editable; }
 
@@ -78,6 +80,7 @@ public:
 	void removeWidget(MacWidget *child, bool del = true);
 
 	Graphics::ManagedSurface *getSurface() { return _composeSurface; }
+	Graphics::ManagedSurface *getMask() { return _maskSurface; }
 
 protected:
 	uint16 _border;
@@ -85,6 +88,7 @@ protected:
 	uint16 _shadow;
 
 	Graphics::ManagedSurface *_composeSurface;
+	Graphics::ManagedSurface *_maskSurface;
 
 public:
 	bool _focusable;


Commit: 033e02536568f479d5715e60c67719238eb6c246
    https://github.com/scummvm/scummvm/commit/033e02536568f479d5715e60c67719238eb6c246
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
GRAPHICS: MACGUI: MacWindowManager: Deactivate widget when mouse leaves

Changed paths:
    graphics/macgui/macbutton.cpp
    graphics/macgui/macwidget.cpp
    graphics/macgui/macwindow.cpp
    graphics/macgui/macwindowmanager.cpp
    graphics/macgui/macwindowmanager.h


diff --git a/graphics/macgui/macbutton.cpp b/graphics/macgui/macbutton.cpp
index cc2c9cb871..4b77b12800 100644
--- a/graphics/macgui/macbutton.cpp
+++ b/graphics/macgui/macbutton.cpp
@@ -145,6 +145,12 @@ bool MacButton::draw(ManagedSurface *g, bool forceRedraw) {
 bool MacButton::processEvent(Common::Event &event) {
 	switch (event.type) {
 	case Common::EVENT_MOUSEMOVE:
+		if (_wm->_mouseDown) {
+			if (_wm->_mode & kWMModeButtonDialogStyle)
+				return true;
+
+			setActive(true);
+		}
 		break;
 	case Common::EVENT_LBUTTONDOWN:
 		setActive(true);
diff --git a/graphics/macgui/macwidget.cpp b/graphics/macgui/macwidget.cpp
index a98f25480d..400ffd8e0d 100644
--- a/graphics/macgui/macwidget.cpp
+++ b/graphics/macgui/macwidget.cpp
@@ -80,11 +80,13 @@ void MacWidget::blit(ManagedSurface *g, Common::Rect &dest) {
 }
 
 bool MacWidget::processEvent(Common::Event &event) {
-	warning("MacWidget::processEvent");
 	return false;
 }
 
 void MacWidget::removeWidget(MacWidget *child, bool del) {
+	if (_children.size() == 0)
+		return;
+
 	for (uint i = 0; i < _children.size(); i++) {
 		if (_children[i] == child) {
 			if (del)
diff --git a/graphics/macgui/macwindow.cpp b/graphics/macgui/macwindow.cpp
index 36ad8eded6..a71bcbb7e8 100644
--- a/graphics/macgui/macwindow.cpp
+++ b/graphics/macgui/macwindow.cpp
@@ -479,6 +479,11 @@ bool MacWindow::processEvent(Common::Event &event) {
 
 	switch (event.type) {
 	case Common::EVENT_MOUSEMOVE:
+		if (_wm->_mouseDown && _wm->_hoveredWidget && !_wm->_hoveredWidget->_dims.contains(event.mouse.x, event.mouse.y)) {
+			_wm->_hoveredWidget->setActive(false);
+			_wm->_hoveredWidget = nullptr;
+		}
+
 		if (_beingDragged) {
 			_dims.translate(event.mouse.x - _draggedX, event.mouse.y - _draggedY);
 			updateInnerDims();
@@ -527,6 +532,7 @@ bool MacWindow::processEvent(Common::Event &event) {
 	case Common::EVENT_LBUTTONUP:
 		_beingDragged = false;
 		_beingResized = false;
+		_wm->_mouseDownWidget = nullptr;
 
 		setHighlight(kBorderNone);
 		break;
@@ -544,9 +550,16 @@ bool MacWindow::processEvent(Common::Event &event) {
 		return false;
 	}
 
-	MacWidget *w = findEventHandler(event, _dims.left, _dims.top);
-	if (w && w != this && w->processEvent(event))
-		return true;
+	MacWidget *w = _wm->_mouseDownWidget ? _wm->_mouseDownWidget : findEventHandler(event, _dims.left, _dims.top);
+	if (w && w != this) {
+		_wm->_hoveredWidget = w;
+
+		if (event.type == Common::EVENT_LBUTTONDOWN)
+			_wm->_mouseDownWidget = w;
+
+		if (w->processEvent(event))
+			return true;
+	}
 
 	if (_callback)
 		return (*_callback)(click, event, _dataPtr);
diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
index 204abcbab0..2bf4528b88 100644
--- a/graphics/macgui/macwindowmanager.cpp
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -159,6 +159,9 @@ MacWindowManager::MacWindowManager(uint32 mode) {
 	_needsRemoval = false;
 
 	_activeWidget = nullptr;
+	_mouseDown = false;
+	_hoveredWidget = nullptr;
+	_mouseDownWidget = nullptr;
 
 	_mode = mode;
 
@@ -313,6 +316,8 @@ void MacWindowManager::setActiveWindow(int id) {
 void MacWindowManager::removeWindow(MacWindow *target) {
 	_windowsToRemove.push_back(target);
 	_needsRemoval = true;
+	_hoveredWidget = nullptr;
+	_mouseDownWidget = nullptr;
 
 	if (target->getId() == _activeWindow)
 		_activeWindow = -1;
@@ -427,8 +432,19 @@ static void menuTimerHandler(void *refCon) {
 }
 
 bool MacWindowManager::processEvent(Common::Event &event) {
-	if (event.type == Common::EVENT_MOUSEMOVE)
+	switch (event.type) {
+	case Common::EVENT_MOUSEMOVE:
 		_lastMousePos = event.mouse;
+		break;
+	case Common::EVENT_LBUTTONDOWN:
+		_mouseDown = true;
+		break;
+	case Common::EVENT_LBUTTONUP:
+		_mouseDown = false;
+		break;
+	default:
+		break;
+	}
 
 	if (_menu && !_menu->isVisible()) {
 		if ((_mode & kWMModeAutohideMenu) && event.type == Common::EVENT_MOUSEMOVE) {
diff --git a/graphics/macgui/macwindowmanager.h b/graphics/macgui/macwindowmanager.h
index e962a3827a..158428704d 100644
--- a/graphics/macgui/macwindowmanager.h
+++ b/graphics/macgui/macwindowmanager.h
@@ -66,7 +66,8 @@ enum {
 	kWMModeForceBuiltinFonts= (1 << 3),
 	kWMModeUnicode			= (1 << 4),
 	kWMModeManualDrawWidgets= (1 << 5),
-	kWMModeFullscreen       = (1 << 6)
+	kWMModeFullscreen       = (1 << 6),
+	kWMModeButtonDialogStyle= (1 << 7)
 };
 
 }
@@ -256,9 +257,13 @@ public:
 	Common::Rect _menuHotzone;
 
 	bool _menuTimerActive;
+	bool _mouseDown;
 
 	int _colorBlack, _colorWhite;
 
+	MacWidget *_hoveredWidget;
+	MacWidget *_mouseDownWidget;
+
 private:
 	void drawDesktop();
 


Commit: a2e230803df0e84bdd1aeb0bd4af8778537c2f16
    https://github.com/scummvm/scummvm/commit/a2e230803df0e84bdd1aeb0bd4af8778537c2f16
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Render texts and buttons with widgets

Changed paths:
  R engines/director/cachedmactext.cpp
  R engines/director/cachedmactext.h
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/events.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/module.mk
    engines/director/score-loading.cpp
    engines/director/score.cpp
    engines/director/score.h
    engines/director/sprite.cpp
    engines/director/sprite.h


diff --git a/engines/director/cachedmactext.cpp b/engines/director/cachedmactext.cpp
deleted file mode 100644
index 4d690f828e..0000000000
--- a/engines/director/cachedmactext.cpp
+++ /dev/null
@@ -1,122 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#include "graphics/macgui/macfontmanager.h"
-#include "graphics/macgui/macwindowmanager.h"
-#include "graphics/macgui/mactext.h"
-
-#include "director/director.h"
-#include "director/cast.h"
-#include "director/cachedmactext.h"
-
-namespace Director {
-
-void CachedMacText::makeMacText() {
-	assert(_width != -1);
-	assert(_wm != NULL);
-
-	delete _macText;
-	_macText = nullptr;
-
-	if ((int)_textCast->_textAlign == -1)
-		_align = (Graphics::TextAlign)3;
-	else
-		_align = (Graphics::TextAlign)((int)_textCast->_textAlign + 1);
-
-	Graphics::MacFont *macFont = new Graphics::MacFont(_textCast->_fontId,
-										_textCast->_fontSize,
-										_textCast->_textSlant);
-
-	debugC(5, kDebugText, "CachedMacText::makeMacText(): font id: %d size: %d slant: %d name: %s '%s'",
-		_textCast->_fontId, _textCast->_fontSize, _textCast->_textSlant, macFont->getName().c_str(),
-		Common::toPrintable(_textCast->_ftext).c_str());
-
-	uint color = _wm->findBestColor(_textCast->_palinfo1 & 0xff, _textCast->_palinfo2 & 0xff, _textCast->_palinfo3 & 0xff);
-
-	_macText = new Graphics::MacText(_textCast->_ftext, _wm, macFont, color, _bgcolor, _width, _align, 1);
-
-	delete macFont;
-}
-
-CachedMacText::~CachedMacText() {
-	delete _macText;
-}
-
-CachedMacText::CachedMacText(TextCast *const textCast, int32 bgcolor, int version, int defaultWidth,
-								Graphics::MacWindowManager *const wm) :
-		_surface(NULL), _macText(NULL), _width(defaultWidth), _dirty(true),
-		_textCast(textCast), _wm(wm), _bgcolor(bgcolor), _align(Graphics::kTextAlignLeft) {
-
-	debugC(5, kDebugText, "CachedMacText::CachedMacText(): font id: %d '%s'", _textCast->_fontId, Common::toPrintable(_textCast->_ftext).c_str());
-
-	if (_width == -1)  {
-		if (version >= 4) {
-			// This came from frame.cpp
-			_width = _textCast->_initialRect.right;
-		} else {
-			_width = _textCast->_initialRect.width();
-		}
-	}
-
-	if (_wm != NULL)
-		makeMacText();
-}
-
-void CachedMacText::setWm(Graphics::MacWindowManager *wm) {
-	if (wm != _wm) {
-		_dirty = true;
-		_wm = wm;
-		makeMacText();
-	}
-}
-
-void CachedMacText::clip(int width) {
-	if (width != _width) {
-		_dirty = true;
-		_width = width;
-		if (_wm != NULL)
-			makeMacText();
-	}
-}
-
-void CachedMacText::forceDirty() {
-	_dirty = true;
-
-	makeMacText();
-}
-
-const Graphics::ManagedSurface *CachedMacText::getSurface() {
-	assert(_wm != NULL);
-	if (_dirty) {
-		_macText->render();
-		_surface = _macText->getSurface();
-		_dirty = false;
-	}
-	return _surface;
-}
-
-int CachedMacText::getLineCount() {
-	assert(_macText != NULL);
-	return _macText->getLineCount();
-}
-
-} // End of namespace Director
diff --git a/engines/director/cachedmactext.h b/engines/director/cachedmactext.h
deleted file mode 100644
index 2b4c3a27ca..0000000000
--- a/engines/director/cachedmactext.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef DIRECTOR_CACHEDMACTEXT_H
-#define DIRECTOR_CACHEDMACTEXT_H
-
-#include "graphics/font.h"
-
-namespace Graphics {
-class ManagedSurface;
-class MacText;
-class MacWindowManager;
-}
-
-namespace Director {
-
-class TextCast;
-
-class CachedMacText {
-private:
-	int _width;
-	const TextCast *_textCast;
-	Graphics::MacWindowManager *_wm;
-	Graphics::MacText *_macText;
-	Graphics::TextAlign _align;
-	bool _dirty;
-	Graphics::ManagedSurface *_surface;
-	void makeMacText();
-	int32 _bgcolor;
-
-public:
-	CachedMacText(TextCast *const textCast, int32 bgcolor, int version, int defaultWidth = -1,
-			Graphics::MacWindowManager *const wm = NULL);
-	~CachedMacText();
-
-	void setWm(Graphics::MacWindowManager *wm);
-	void clip(int width);
-	void setBgColor(int color) { _bgcolor = color; }
-	void forceDirty();
-	const Graphics::ManagedSurface *getSurface();
-	int getLineCount();
-
-	void setStxt(const TextCast *stxt) { _textCast = stxt; forceDirty(); }
-};
-
-} // End of namespace Director
-
-#endif
diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 7264fb9c42..fa557f70d6 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -22,11 +22,12 @@
 
 #include "common/substream.h"
 #include "graphics/surface.h"
+#include "graphics/macgui/macwindowmanager.h"
 #include "graphics/macgui/maceditabletext.h"
+#include "graphics/macgui/macbutton.h"
 #include "image/image_decoder.h"
 
 #include "director/director.h"
-#include "director/cachedmactext.h"
 #include "director/cast.h"
 #include "director/score.h"
 #include "director/sound.h"
@@ -47,6 +48,18 @@ Cast::Cast() {
 Cast::~Cast() {
 	if (_img)
 		delete _img;
+
+	if (_widget)
+		delete _widget;
+}
+
+bool Cast::isEditable() {
+	return false;
+}
+
+bool Cast::setEditable(bool editable) {
+	warning("Cast::setEditable: Attempted to set editable of non-editable cast");
+	return false;
 }
 
 BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint32 castTag, uint16 version) {
@@ -255,13 +268,22 @@ TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcol
 		stream.readUint16();
 	}
 
-	_cachedMacText = new CachedMacText(this, _bgcolor, version, -1, g_director->_wm);
-
 	_modified = false;
 }
 
-TextCast::~TextCast() {
-	delete _cachedMacText;
+Graphics::TextAlign TextCast::getAlignment() {
+	switch (_textAlign) {
+	case kTextAlignRight:
+		return Graphics::kTextAlignRight;
+		break;
+	case kTextAlignCenter:
+		return Graphics::kTextAlignCenter;
+		break;
+	case kTextAlignLeft:
+	default:
+		return Graphics::kTextAlignLeft;
+		break;
+	}
 }
 
 void TextCast::importStxt(const Stxt *stxt) {
@@ -273,11 +295,21 @@ void TextCast::importStxt(const Stxt *stxt) {
 	_palinfo3 = stxt->_palinfo3;
 	_ftext = stxt->_ftext;
 	_ptext = stxt->_ptext;
+}
+
+void TextCast::createWidget() {
+	uint fgcolor = g_director->_wm->findBestColor(_palinfo1 & 0xff, _palinfo2 & 0xff, _palinfo3 & 0xff);
+	warning("TextCast::createWidget: bgcolor: %d, fgcolor: %d", _bgcolor, fgcolor);
+
+	Graphics::MacFont *macFont = new Graphics::MacFont(_fontId, _fontSize, _textSlant);
+
+	_widget = new Graphics::MacEditableText(g_director->getCurrentScore()->_window, 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, fgcolor, _bgcolor, _initialRect.width(), getAlignment(), 1, _borderSize, _gutterSize, _boxShadow, _textShadow);
 
-	_cachedMacText->setStxt(this);
+	((Graphics::MacEditableText *)_widget)->draw();
+	delete macFont;
 }
 
-void TextCast::importRTE(byte *text) 	{
+void TextCast::importRTE(byte *text) {
 	//assert(rteList.size() == 3);
 	//child0 is probably font data.
 	//child1 is the raw text.
@@ -292,12 +324,14 @@ void TextCast::setText(const char *text) {
 
 	_ptext = _ftext = text;
 
-	_cachedMacText->forceDirty();
-
 	if (_widget) {
-		((Graphics::MacEditableText *)_widget)->clearText();
-		((Graphics::MacEditableText *)_widget)->appendTextDefault(_ftext);
+		Graphics::MacEditableText *wtext = (Graphics::MacEditableText *)_widget;
+		wtext->clearText();
+		wtext->appendTextDefault(_ftext);
+		wtext->draw();
 	}
+
+	_modified = true;
 }
 
 Common::String TextCast::getText() {
@@ -307,6 +341,34 @@ Common::String TextCast::getText() {
 	return _ptext;
 }
 
+bool TextCast::isModified() {
+	return _modified || (_widget ? ((Graphics::MacEditableText *)_widget)->_contentIsDirty : false);
+}
+
+bool TextCast::isEditable() {
+	if (!_widget) {
+		warning("TextCast::setEditable: Attempt to set editable of null widget");
+		return false;
+	}
+
+	return (Graphics::MacEditableText *)_widget->_editable;
+}
+
+bool TextCast::setEditable(bool editable) {
+	if (!_widget) {
+		warning("TextCast::setEditable: Attempt to set editable of null widget");
+		return false;
+	}
+
+	Graphics::MacEditableText *text = (Graphics::MacEditableText *)_widget;
+	text->_focusable = editable;
+	text->setEditable(editable);
+	text->_selectable = editable;
+	// text->setActive(editable);
+
+	return true;
+}
+
 ShapeCast::ShapeCast(Common::ReadStreamEndian &stream, uint16 version) {
 	_type = kCastShape;
 
@@ -379,6 +441,19 @@ ButtonCast::ButtonCast(Common::ReadStreamEndian &stream, uint16 version) : TextC
 	}
 }
 
+void ButtonCast::createWidget() {
+	uint fgcolor = g_director->_wm->findBestColor(_palinfo1 & 0xff, _palinfo2 & 0xff, _palinfo3 & 0xff);
+
+	Graphics::MacFont *macFont = new Graphics::MacFont(_fontId, _fontSize, _textSlant);
+
+	_widget = new Graphics::MacButton(Graphics::MacButtonType(_buttonType), getAlignment(), g_director->getCurrentScore()->_window, 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, fgcolor, _bgcolor);
+
+	_widget->_focusable = true;
+
+	((Graphics::MacButton *)(_widget))->draw();
+	delete macFont;
+}
+
 ScriptCast::ScriptCast(Common::ReadStreamEndian &stream, uint16 version) {
 	_type = kCastLingoScript;
 	_scriptType = kNoneScript;
diff --git a/engines/director/cast.h b/engines/director/cast.h
index c3bac04fc7..2c8c94823a 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -26,8 +26,13 @@
 #include "director/archive.h"
 #include "director/types.h"
 
+#include "graphics/font.h"
+
 namespace Graphics {
 struct Surface;
+class MacEditableText;
+class MacWindowManager;
+class MacButton;
 class MacWidget;
 }
 
@@ -43,13 +48,15 @@ class ImageDecoder;
 namespace Director {
 
 class Stxt;
-class CachedMacText;
 class SNDDecoder;
 
 class Cast {
 public:
 	Cast();
 	virtual ~Cast();
+	virtual bool isEditable();
+	virtual bool setEditable(bool editable);
+	virtual bool isModified() { return _modified; }
 
 	CastType _type;
 	Common::Rect _initialRect;
@@ -105,9 +112,14 @@ public:
 class TextCast : public Cast {
 public:
 	TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor);
-	virtual ~TextCast();
 
 	void setText(const char *text);
+	virtual void createWidget();
+
+	virtual bool isModified() override;
+	virtual bool isEditable() override;
+	virtual bool setEditable(bool editable) override;
+	Graphics::TextAlign getAlignment();
 
 	SizeType _borderSize;
 	SizeType _gutterSize;
@@ -128,7 +140,6 @@ public:
 	Common::String _ptext;
 	void importStxt(const Stxt *stxt);
 	void importRTE(byte* text);
-	CachedMacText *_cachedMacText;
 
 	Common::String getText();
 };
@@ -136,6 +147,7 @@ public:
 class ButtonCast : public TextCast {
 public:
 	ButtonCast(Common::ReadStreamEndian &stream, uint16 version);
+	virtual void createWidget() override;
 
 	ButtonType _buttonType;
 };
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 0571c34140..e37522ab28 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -85,9 +85,7 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 					if (draggedSprite->_moveable) {
 						pos = g_system->getEventManager()->getMousePos();
 						Common::Point delta = pos - _draggingSpritePos;
-						draggedSprite->_currentPoint.x += delta.x;
-						draggedSprite->_currentPoint.y += delta.y;
-						draggedSprite->_dirty = true;
+						draggedSprite->translate(delta);
 						_draggingSpritePos = pos;
 					} else {
 						releaseDraggedSprite();
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 806f926bc8..4b7d3576e6 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -683,7 +683,7 @@ Datum Lingo::getTheSprite(Datum &id1, int field) {
 		d.u.i = sprite->_constraint;
 		break;
 	case kTheEditableText:
-		d = Datum(sprite->_editableText);
+		d.u.i = sprite->_cast ? sprite->_cast->isEditable() : 0;
 		break;
 	case kTheForeColor:
 		d.u.i = sprite->_foreColor;
@@ -798,7 +798,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		sprite->_constraint = d.asInt();
 		break;
 	case kTheEditableText:
-		sprite->_editableText = d.asString();
+		sprite->_cast ? sprite->_cast->setEditable(d.asInt()) : false;
 		break;
 	case kTheForeColor:
 		sprite->_foreColor = d.asInt();
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 914a5c0e51..6b6c755bf7 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -3,7 +3,6 @@ MODULE := engines/director
 MODULE_OBJS = \
 	archive.o \
 	cast.o \
-	cachedmactext.o \
 	detection.o \
 	director.o \
 	events.o \
diff --git a/engines/director/score-loading.cpp b/engines/director/score-loading.cpp
index 1ecf0eebd0..840affb61a 100644
--- a/engines/director/score-loading.cpp
+++ b/engines/director/score-loading.cpp
@@ -119,6 +119,10 @@ bool Score::loadArchive() {
 		_stageColor = 1;
 	}
 
+	_window = _vm->_wm->addWindow(false, false, false);
+	_window->disableBorder();
+	_window->resize(_movieRect.width(), _movieRect.height());
+
 	// Cast Information Array
 	if (_movieArchive->hasResource(MKTAG('V', 'W', 'C', 'R'), -1)) {
 		_castIDoffset = _movieArchive->getResourceIDList(MKTAG('V', 'W', 'C', 'R'))[0];
@@ -224,11 +228,6 @@ bool Score::loadArchive() {
 		debug("STUB: Unhandled 'SCVW' resource");
 	}
 
-	setSpriteCasts();
-	setSpriteBboxes();
-	loadSpriteImages(false);
-	loadSpriteSounds(false);
-
 	// Now process STXTs
 	Common::Array<uint16> stxt = _movieArchive->getResourceIDList(MKTAG('S','T','X','T'));
 	debugC(2, kDebugLoading, "****** Loading %d STXT resources", stxt.size());
@@ -250,6 +249,11 @@ bool Score::loadArchive() {
 	}
 	copyCastStxts();
 
+	setSpriteCasts();
+	setSpriteBboxes();
+	loadSpriteImages(false);
+	loadSpriteSounds(false);
+
 	return true;
 }
 
@@ -267,7 +271,9 @@ void Score::copyCastStxts() {
 		if (_loadedStxts->getVal(stxtid)) {
 			const Stxt *stxt = _loadedStxts->getVal(stxtid);
 			TextCast *tc = (TextCast *)c->_value;
+
 			tc->importStxt(stxt);
+			tc->createWidget();
 		}
 	}
 }
@@ -673,6 +679,12 @@ void Score::setSpriteBboxes() {
 	for (uint16 i = 0; i < _frames.size(); i++) {
 		for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
 			Sprite *sp = _frames[i]->_sprites[j];
+			if (i == 1)
+			// Only call updateCast on the first frame sprites, because renderSprite
+			// calls updateCast for us after that. We need to get widget bounding info here.
+			// if (i == 1)
+				sp->updateCast();
+
 			sp->_startBbox = sp->getBbox();
 			sp->_currentBbox = sp->_startBbox;
 		}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 197b91c521..721bf5e105 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -26,7 +26,6 @@
 #include "graphics/primitives.h"
 #include "graphics/macgui/macwindowmanager.h"
 #include "graphics/macgui/maceditabletext.h"
-#include "director/cachedmactext.h"
 
 #include "director/director.h"
 #include "director/cast.h"
@@ -296,10 +295,6 @@ void Score::startLoop() {
 
 	initGraphics(_movieRect.width(), _movieRect.height());
 
-	_window = _vm->_wm->addWindow(false, false, false);
-	_window->disableBorder();
-	_window->resize(_movieRect.width(), _movieRect.height());
-
 	_surface = _window->getWindowSurface();
 	_maskSurface = new Graphics::ManagedSurface;
 	_backSurface = new Graphics::ManagedSurface;
@@ -324,6 +319,7 @@ void Score::startLoop() {
 	_vm->_backSurface.create(_movieRect.width(), _movieRect.height());
 
 	_vm->_wm->setScreen(_surface);
+	_vm->_wm->_lastWidget = nullptr;
 
 	_surface->clear(_stageColor);
 
@@ -434,9 +430,6 @@ void Score::update() {
 
 	_vm->_newMovieStarted = false;
 
-	// _surface->clear(_stageColor);
-	// _surface->copyFrom(*_trailSurface);
-
 	_lingo->executeImmediateScripts(_frames[_currentFrame]);
 
 	if (_vm->getVersion() >= 6) {
@@ -509,7 +502,7 @@ void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly)
 		// - The cast member ID of the sprite has changed (_dirty flag set)
 		// - The sprite slot from the current frame is different (cast member ID or bounding box) from the cached sprite slot
 		// (maybe we have to compare all the sprite attributes, not just these two?)
-		bool needsUpdate = currentSprite->_dirty || currentSprite->_castId != nextSprite->_castId || currentSprite->_currentBbox != nextSprite->_currentBbox;
+		bool needsUpdate = currentSprite->isDirty() || currentSprite->_castId != nextSprite->_castId || currentSprite->_currentBbox != nextSprite->_currentBbox;
 
 		if (needsUpdate || forceUpdate)
 			unrenderSprite(i);
@@ -551,11 +544,15 @@ void Score::unrenderSprite(uint16 spriteId) {
 
 	currentSprite->_currentBbox = currentSprite->getBbox();
 	currentSprite->_dirty = false;
+
+	if (currentSprite->_cast)
+		currentSprite->_cast->_modified = false;
 }
 
 void Score::renderSprite(uint16 id) {
 	Sprite *sprite = _sprites[id];
 
+	sprite->updateCast();
 	if (!sprite || !sprite->_enabled)
 		return;
 
@@ -573,7 +570,7 @@ void Score::renderSprite(uint16 id) {
 	if (castType == kCastShape) {
 		renderShape(id);
 	} else if (castType == kCastText || castType == kCastRTE) {
-		renderText(id, NULL);
+		renderText(id);
 	} else if (castType == kCastButton) {
 		renderButton(id);
 	} else {
@@ -588,6 +585,8 @@ void Score::renderSprite(uint16 id) {
 
 		renderBitmap(id);
 	}
+
+	sprite->setClean();
 }
 
 void Score::renderShape(uint16 spriteId) {
@@ -708,7 +707,6 @@ void Score::renderShape(uint16 spriteId) {
 	inkBasedBlit(&maskSurface, tmpSurface, ink, shapeRect, spriteId);
 }
 
-
 void Score::renderButton(uint16 spriteId) {
 	uint16 castId = _sprites[spriteId]->_castId;
 
@@ -723,241 +721,31 @@ void Score::renderButton(uint16 spriteId) {
 	}
 	ButtonCast *button = (ButtonCast *)member;
 
-	// Sometimes, at least in the D3 Workshop Examples, these buttons are just TextCast.
-	// If they are, then we just want to use the spriteType as the button type.
-	// If they are full-bown Cast members, then use the actual cast member type.
-	int buttonType = _sprites[spriteId]->_spriteType;
-	if (buttonType == kCastMemberSprite) {
-		switch (button->_buttonType) {
-		case kTypeCheckBox:
-			buttonType = kCheckboxSprite;
-			break;
-		case kTypeButton:
-			buttonType = kButtonSprite;
-			break;
-		case kTypeRadio:
-			buttonType = kRadioButtonSprite;
-			break;
-		}
-	}
-
-	bool invert = spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId;
-
 	// TODO: review all cases to confirm if we should use text height.
 	// height = textRect.height();
 
-	Common::Rect _rect = _sprites[spriteId]->_currentBbox;
-	int16 x = _rect.left;
-	int16 y = _rect.top;
-
-	Common::Rect textRect(0, 0, _rect.width(), _rect.height());
-
-	// WORKAROUND, HACK
-	// Because we're not drawing text with transparency
-	// We swap drawing depending on whether the button is
-	// inverted or not, to prevent destroying the border
-	if (!invert)
-		renderText(spriteId, &textRect);
-
-	Graphics::MacPlotData plotStroke(_surface, nullptr, &_vm->getPatterns(), 1, 0, 0, 1, 0);
-
-	switch (buttonType) {
-	case kCheckboxSprite:
-		_surface->frameRect(_rect, 0);
-		break;
-	case kButtonSprite: {
-			Graphics::MacPlotData pd(_surface, nullptr, &_vm->getMacWindowManager()->getPatterns(), Graphics::MacGUIConstants::kPatternSolid, 0, 0, 1, invert ? Graphics::kColorBlack : Graphics::kColorWhite);
+	Common::Rect bbox = _sprites[spriteId]->_currentBbox;
 
-			Graphics::drawRoundRect(_rect, 4, 0, invert, Graphics::macDrawPixel, &pd);
-		}
-		break;
-	case kRadioButtonSprite:
-		Graphics::drawEllipse(x, y + 2, x + 11, y + 13, 0, false, Graphics::macDrawPixel, &plotStroke);
-		break;
-	default:
-		warning("renderButton: Unknown buttonType");
-		break;
-	}
-
-	if (invert)
-		renderText(spriteId, &textRect);
+	inkBasedBlit(nullptr, button->_widget->getSurface()->rawSurface(),  _sprites[spriteId]->_ink, bbox, spriteId);
 }
 
-void Score::renderText(uint16 spriteId, Common::Rect *textRect) {
-	TextCast *textCast = (TextCast*)_sprites[spriteId]->_cast;
-	if (textCast == nullptr) {
+void Score::renderText(uint16 spriteId) {
+	TextCast *text = (TextCast*)_sprites[spriteId]->_cast;
+	if (text == nullptr) {
 		warning("Score::renderText(): TextCast #%d is a nullptr", spriteId);
 		return;
 	}
 
-	Score *score = _vm->getCurrentScore();
-	Sprite *sprite = _sprites[spriteId];
-
-	Common::Rect bbox = sprite->_currentBbox;
-	int width = bbox.width();
-	int height = bbox.height();
-	int x = bbox.left;
-	int y = bbox.top;
+	Common::Rect bbox = _sprites[spriteId]->_currentBbox;
+	text->_widget->draw();
 
-	if (_vm->getCurrentScore()->_fontMap.contains(textCast->_fontId)) {
+	if (_fontMap.contains(text->_fontId)) {
 		// We need to make sure that the Shared Cast fonts have been loaded in?
 		// might need a mapping table here of our own.
 		// textCast->fontId = _vm->_wm->_fontMan->getFontIdByName(_vm->getCurrentScore()->_fontMap[textCast->fontId]);
 	}
 
-	if (width == 0 || height == 0) {
-		warning("Score::renderText(): Requested to draw on an empty surface: %d x %d", width, height);
-		return;
-	}
-
-	if (sprite->_editable) {
-		if (!textCast->_widget) {
-			warning("Creating MacEditableText with '%s'", toPrintable(textCast->_ftext).c_str());
-			textCast->_widget = new Graphics::MacEditableText(score->_window, x, y, width, height, g_director->_wm, textCast->_ftext, new Graphics::MacFont(), 0, 255, width);
-			warning("Finished creating MacEditableText");
-		}
-
-		textCast->_widget->draw();
-
-		InkType ink = sprite->_ink;
-
-		// if (spriteId == score->_currentMouseDownSpriteId)
-		// 	ink = kInkTypeReverse;
-
-		inkBasedBlit(nullptr, textCast->_widget->getSurface()->rawSurface(), ink, Common::Rect(x, y, x + width, y + height), spriteId);
-
-		return;
-	}
-
-	debugC(3, kDebugText, "renderText: sprite: %d x: %d y: %d w: %d h: %d fontId: '%d' text: '%s'", spriteId, x, y, width, height, textCast->_fontId, Common::toPrintable(textCast->_ftext).c_str());
-
-	uint16 boxShadow = (uint16)textCast->_boxShadow;
-	uint16 borderSize = (uint16)textCast->_borderSize;
-	if (textRect != NULL)
-		borderSize = 0;
-	uint16 padding = (uint16)textCast->_gutterSize;
-	uint16 textShadow = (uint16)textCast->_textShadow;
-
-	//uint32 rectLeft = textCast->initialRect.left;
-	//uint32 rectTop = textCast->initialRect.top;
-
-	textCast->_cachedMacText->clip(width);
-	const Graphics::ManagedSurface *textSurface = textCast->_cachedMacText->getSurface();
-
-	if (!textSurface)
-		return;
-
-	height = textSurface->h;
-	if (textRect != NULL) {
-		// TODO: this offset could be due to incorrect fonts loaded!
-		textRect->bottom = height + textCast->_cachedMacText->getLineCount();
-	}
-
-	uint16 textX = 0, textY = 0;
-
-	if (textRect == NULL) {
-		if (borderSize > 0) {
-			if (_vm->getVersion() <= 3) {
-				height += (borderSize * 2);
-				textX += (borderSize + 2);
-			} else {
-				height += borderSize;
-				textX += (borderSize + 1);
-			}
-			textY += borderSize;
-		} else {
-			x += 1;
-		}
-
-		if (padding > 0) {
-			width += padding * 2;
-			height += padding;
-			textY += padding / 2;
-		}
-
-		if (textCast->_textAlign == kTextAlignRight)
-			textX -= 1;
-
-		if (textShadow > 0)
-			textX--;
-	} else {
-		x++;
-		if (width % 2 != 0)
-			x++;
-
-		if (sprite->_spriteType != kCastMemberSprite) {
-			y += 2;
-			switch (sprite->_spriteType) {
-			case kCheckboxSprite:
-				textX += 16;
-				break;
-			case kRadioButtonSprite:
-				textX += 17;
-				break;
-			default:
-				break;
-			}
-		} else {
-			ButtonType buttonType = ((ButtonCast*)textCast)->_buttonType;
-			switch (buttonType) {
-			case kTypeCheckBox:
-				width += 4;
-				textX += 16;
-				break;
-			case kTypeRadio:
-				width += 4;
-				textX += 17;
-				break;
-			case kTypeButton:
-				width += 4;
-				y += 2;
-				break;
-			default:
-				warning("Score::renderText(): Expected button but got unexpected button type: %d", buttonType);
-				y += 2;
-				break;
-			}
-		}
-	}
-
-	switch (textCast->_textAlign) {
-	case kTextAlignLeft:
-	default:
-		break;
-	case kTextAlignCenter:
-		textX = (width / 2) - (textSurface->w / 2) + (padding / 2) + borderSize;
-		break;
-	case kTextAlignRight:
-		textX = width - (textSurface->w + 1) + (borderSize * 2) - (textShadow * 2) - (padding);
-		break;
-	}
-
-	Graphics::ManagedSurface textWithFeatures(width + (borderSize * 2) + boxShadow + textShadow, height + borderSize + boxShadow + textShadow);
-	textWithFeatures.fillRect(Common::Rect(textWithFeatures.w, textWithFeatures.h), score->getStageColor());
-
-	if (textRect == NULL && boxShadow > 0) {
-		textWithFeatures.fillRect(Common::Rect(boxShadow, boxShadow, textWithFeatures.w + boxShadow, textWithFeatures.h), 0);
-	}
-
-	if (textRect == NULL && borderSize != kSizeNone) {
-		for (int bb = 0; bb < borderSize; bb++) {
-			Common::Rect borderRect(bb, bb, textWithFeatures.w - bb - boxShadow - textShadow, textWithFeatures.h - bb - boxShadow - textShadow);
-			textWithFeatures.fillRect(borderRect, 0xff);
-			textWithFeatures.frameRect(borderRect, 0);
-		}
-	}
-
-	if (textShadow > 0)
-		textWithFeatures.transBlitFrom(textSurface->rawSurface(), Common::Point(textX + textShadow, textY + textShadow), 0xff);
-
-	textWithFeatures.transBlitFrom(textSurface->rawSurface(), Common::Point(textX, textY), 0xff);
-
-	InkType ink = sprite->_ink;
-
-	// if (spriteId == score->_currentMouseDownSpriteId)
-	// 	ink = kInkTypeReverse;
-
-	inkBasedBlit(nullptr, textWithFeatures, ink, Common::Rect(x, y, x + width, y + height), spriteId);
+	inkBasedBlit(nullptr, text->_widget->getSurface()->rawSurface(), _sprites[spriteId]->_ink, bbox, spriteId);
 }
 
 void Score::renderBitmap(uint16 spriteId) {
diff --git a/engines/director/score.h b/engines/director/score.h
index 22c438e015..48dc4d2119 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -149,7 +149,7 @@ public:
 
 private:
 	void update();
-	void renderText(uint16 spriteId, Common::Rect *textSize);
+	void renderText(uint16 spriteId);
 	void renderShape(uint16 spriteId);
 	void renderButton(uint16 spriteId);
 	void renderBitmap(uint16 spriteId);
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 0b1da06a03..d99eaef0b7 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -24,6 +24,8 @@
 #include "director/cast.h"
 #include "director/sprite.h"
 
+#include "graphics/macgui/macwidget.h"
+
 namespace Director {
 
 Sprite::Sprite() {
@@ -69,6 +71,37 @@ Sprite::Sprite() {
 Sprite::~Sprite() {
 }
 
+void Sprite::updateCast() {
+	if (_cast && _cast->_widget) {
+		if (_cast->isEditable() != _editable && !_puppet)
+			_cast->setEditable(_editable);
+		_cast->_widget->_dims.moveTo(_currentPoint.x, _currentPoint.y);
+	}
+}
+
+void Sprite::translate(Common::Point delta, bool moveTo) {
+	_currentPoint += delta;
+
+	if (_cast && _cast->_widget) {
+		if (moveTo)
+			_cast->_widget->_dims.translate(delta.x, delta.y);
+		else
+			_cast->_widget->_dims.moveTo(delta.x, delta.y);
+	}
+
+	_dirty = true;
+}
+
+bool Sprite::isDirty() {
+	return _dirty || (_cast && _cast->isModified());
+}
+
+void Sprite::setClean() {
+	_dirty = false;
+	if (_cast)
+		_cast->_modified = false;
+}
+
 uint16 Sprite::getPattern() {
 	switch (_spriteType) {
 	case kRectangleSprite:
@@ -196,89 +229,15 @@ Common::Rect Sprite::getBbox() {
 								_currentPoint.y + _height);
 		break;
 	case kCastRTE:
-	case kCastText: {
-		if (!_cast)
-			return result;
-
-		TextCast *textCast = (TextCast*)_cast;
-		int x = _currentPoint.x; // +rectLeft;
-		int y = _currentPoint.y; // +rectTop;
-		int height = textCast->_initialRect.height(); //_sprites[spriteId]->_height;
-		int width;
-		Common::Rect *textRect = NULL;
-
-		if (g_director->getVersion() >= 4) {
-			// where does textRect come from?
-			if (textRect == NULL) {
-				width = textCast->_initialRect.right;
-			} else {
-				width = textRect->width();
-			}
-		} else {
-			width = textCast->_initialRect.width(); //_sprites[spriteId]->_width;
-		}
+	case kCastText:
+	case kCastButton:
+		{
+			if (!_cast)
+				return result;
 
-		result = Common::Rect(x, y, x + width, y + height);
-		break;
-	}
-	case kCastButton: {
-		// This may not be a button cast. It could be a textcast with the
-		// channel forcing it to be a checkbox or radio button!
-		if (!_cast)
-			return result;
-
-		ButtonCast *button = (ButtonCast *)_cast;
-
-		// Sometimes, at least in the D3 Workshop Examples, these buttons are
-		// just TextCast. If they are, then we just want to use the spriteType
-		// as the button type. If they are full-bown Cast members, then use the
-		// actual cast member type.
-		int buttonType = _spriteType;
-		if (buttonType == kCastMemberSprite) {
-			switch (button->_buttonType) {
-			case kTypeCheckBox:
-				buttonType = kCheckboxSprite;
-				break;
-			case kTypeButton:
-				buttonType = kButtonSprite;
-				break;
-			case kTypeRadio:
-				buttonType = kRadioButtonSprite;
-				break;
-			}
-		}
-
-		uint32 rectLeft = button->_initialRect.left;
-		uint32 rectTop = button->_initialRect.top;
-
-		int x = _currentPoint.x;
-		int y = _currentPoint.y;
-
-		if (g_director->getVersion() > 3) {
-			x += rectLeft;
-			y += rectTop;
-		}
-
-		int height = button->_initialRect.height();
-		int width = button->_initialRect.width() + 3;
-
-		switch (buttonType) {
-		case kCheckboxSprite:
-			// Magic numbers: checkbox square need to move left about 5px from
-			// text and 12px side size (D4)
-			result = Common::Rect(x, y + 2, x + 12, y + 14);
-			break;
-		case kButtonSprite:
-			result = Common::Rect(x, y, x + width, y + height + 3);
+			result = _cast->_widget->getDimensions();
 			break;
-		case kRadioButtonSprite:
-			result = Common::Rect(x, y + 2, x + 12, y + 14);
-			break;
-		default:
-			warning("Score::getBbox(): Unknown buttonType");
 		}
-		break;
-	}
 	case kCastBitmap: {
 		if (!_cast)
 			return result;
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index e97e73d87f..58e28a900b 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -62,6 +62,10 @@ public:
 	Sprite();
 	~Sprite();
 
+	void updateCast();
+	void translate(Common::Point delta, bool moveTo = false);
+	bool isDirty();
+	void setClean();
 	uint16 getPattern();
 	void setPattern(uint16 pattern);
 
@@ -113,9 +117,6 @@ public:
 	uint16 _stopTime;
 	byte _volume;
 	byte _stretch;
-
-	// Using in text sprites
-	Common::String _editableText;
 };
 
 } // End of namespace Director


Commit: bd216b237c40a0b87fa5954adc1485fb978abc9a
    https://github.com/scummvm/scummvm/commit/bd216b237c40a0b87fa5954adc1485fb978abc9a
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Fix previous rendering typos

Changed paths:
    engines/director/ink.cpp
    engines/director/score.cpp


diff --git a/engines/director/ink.cpp b/engines/director/ink.cpp
index 1b7fb2bd00..f12310af5b 100644
--- a/engines/director/ink.cpp
+++ b/engines/director/ink.cpp
@@ -55,10 +55,7 @@ void Score::inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::
 
 	switch (ink) {
 	case kInkTypeCopy:
-		if (maskSurface)
 			_surface->transBlitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top), *maskSurface);
-		else
-			_surface->blitFrom(spriteSurface, Common::Point(drawRect.left, drawRect.top));
 		break;
 	case kInkTypeTransparent:
 		// FIXME: is it always white (last entry in pallette)?
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 721bf5e105..1cc5437da3 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -304,8 +304,6 @@ void Score::startLoop() {
 	_backSurface->create(_movieRect.width(), _movieRect.height());
 	_backSurface2->create(_movieRect.width(), _movieRect.height());
 
-	_sprites.resize(_frames[0]->_sprites.size());
-
 	if (_vm->_backSurface.w > 0) {
 		// Persist screen between the movies
 		// TODO: this is a workaround until the rendering pipeline is reworked
@@ -330,7 +328,6 @@ void Score::startLoop() {
 	_sprites = _frames[_currentFrame]->_sprites;
 	_lingo->processEvent(kEventStartMovie);
 
-	_sprites = _frames[_currentFrame]->_sprites;
 	renderFrame(_currentFrame, true);
 
 	if (_frames.size() <= 1) {	// We added one empty sprite
@@ -507,6 +504,7 @@ void Score::renderFrame(uint16 frameId, bool forceUpdate, bool updateStageOnly)
 		if (needsUpdate || forceUpdate)
 			unrenderSprite(i);
 
+		_maskSurface->fillRect(nextSprite->_currentBbox, 1);
 		_sprites[i] = nextSprite;
 	}
 
@@ -558,8 +556,6 @@ void Score::renderSprite(uint16 id) {
 
 	CastType castType = sprite->_castType;
 
-	_maskSurface->fillRect(sprite->_currentBbox, 1);
-
 	if (castType == kCastTypeNull)
 		return;
 


Commit: f112b2b564fe3a09f34aa34a234eca9638f44fd3
    https://github.com/scummvm/scummvm/commit/f112b2b564fe3a09f34aa34a234eca9638f44fd3
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Implement kTheHilite

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/events.cpp
    engines/director/lingo/lingo-the.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index fa557f70d6..9c17dd244f 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -39,6 +39,7 @@ Cast::Cast() {
 	_type = kCastTypeNull;
 	_surface = nullptr;
 	_widget = nullptr;
+	_hilite = false;
 
 	_img = nullptr;
 
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 2c8c94823a..9a0ff5fc42 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -67,6 +67,7 @@ public:
 	Image::ImageDecoder *_img;
 
 	bool _modified;
+	bool _hilite;
 
 	Graphics::MacWidget *_widget;
 };
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index e37522ab28..36220d1ba4 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -28,6 +28,7 @@
 #include "director/frame.h"
 #include "director/score.h"
 #include "director/sprite.h"
+#include "director/cast.h"
 #include "director/lingo/lingo.h"
 
 namespace Director {
@@ -125,6 +126,12 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 				sc->_mouseIsDown = false;
 				releaseDraggedSprite();
 
+				{
+					Cast *cast = g_director->getCastMember(sc->_sprites[spriteId]->_castId);
+					if (cast && cast->_type == kCastButton)
+						cast->_hilite = !cast->_hilite;
+				}
+
 				_lingo->registerEvent(kEventMouseUp);
 				sc->_currentMouseDownSpriteId = 0;
 				break;
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 4b7d3576e6..34cc8295ce 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -23,6 +23,9 @@
 #include "common/system.h"
 #include "common/events.h"
 
+#include "graphics/macgui/macwindowmanager.h"
+#include "graphics/macgui/macbutton.h"
+
 #include "director/director.h"
 #include "director/cast.h"
 #include "director/frame.h"
@@ -896,6 +899,11 @@ Datum Lingo::getTheCast(Datum &id1, int field) {
 		return d;
 	}
 
+	if (field == kTheHilite) {
+		d.u.i = member->_hilite;
+		return d;
+	}
+
 	CastType castType = member->_type;
 	CastInfo *castInfo = nullptr;
 	if (score->_castsInfo.contains(id)) {
@@ -1047,6 +1055,18 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		score->getCastMemberInitialRect(id).setHeight(d.asInt());
 		score->setCastMemberModified(id);
 		break;
+	case kTheHilite:
+		// TODO: Understand how texts can be selected programmatically as well.
+		if (member->_type == kCastButton) {
+			TextCast *button = (TextCast *)member;
+			if ((bool)d.asInt() !=  member->_hilite) {
+				((Graphics::MacButton *) button->_widget)->invertInner();
+				button->_hilite = !!d.asInt();
+			}
+		} else {
+			warning("Lingo::setTheCast: Attempted to set hilite of unsupported cast type");
+		}
+		break;
 	case kTheName:
 		if (!castInfo) {
 			warning("Lingo::setTheCast(): The cast %d not found. type: %d", id, castType);


Commit: d6176f8ed156321e179ca8c55a9510e563cd876f
    https://github.com/scummvm/scummvm/commit/d6176f8ed156321e179ca8c55a9510e563cd876f
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Implement kTheStageColor

Changed paths:
    engines/director/ink.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/score.cpp
    engines/director/score.h


diff --git a/engines/director/ink.cpp b/engines/director/ink.cpp
index f12310af5b..9d228de5d3 100644
--- a/engines/director/ink.cpp
+++ b/engines/director/ink.cpp
@@ -85,6 +85,10 @@ void Score::inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::
 
 void Score::drawBackgndTransSprite(const Graphics::Surface &sprite, Common::Rect &drawRect, int spriteId) {
 	byte skipColor = _sprites[spriteId]->_backColor;
+	if (_sprites[spriteId]->_castType == kCastText && _sprites[spriteId]->_cast) {
+		skipColor = ((TextCast *)_sprites[spriteId]->_cast)->_bgcolor;
+	}
+
 	Common::Rect srcRect(sprite.w, sprite.h);
 
 	if (!_surface->clip(srcRect, drawRect))
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 34cc8295ce..9eb0ee52f6 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -622,6 +622,13 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 			}
 		}
 		break;
+	case kTheStageColor: {
+		Score *score = _vm->getCurrentScore();
+		score->_stageColor = d.asInt();
+		score->_surface->clear(score->_stageColor);
+		score->renderFrame(score->getCurrentFrame(), true);
+	}
+		break;
 	case kTheSprite:
 		setTheSprite(id, field, d);
 		break;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 1cc5437da3..dfa301c073 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -72,7 +72,6 @@ Score::Score(DirectorEngine *vm) {
 	_nextFrameTime = 0;
 	_flags = 0;
 	_stopPlay = false;
-	_stageColor = 0;
 
 	_castIDoffset = 0;
 
diff --git a/engines/director/score.h b/engines/director/score.h
index 48dc4d2119..97a20850ef 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -140,8 +140,6 @@ public:
 	void renderZoomBox(bool redraw = false);
 	bool haveZoomBox() { return !_zoomBoxes.empty(); }
 
-	int32 getStageColor() { return _stageColor; }
-
 	Cast *getCastMember(int castId);
 	void renderFrame(uint16 frameId, bool forceUpdate = false, bool updateStageOnly = false);
 	void renderSprite(uint16 id);
@@ -211,6 +209,7 @@ public:
 	uint32 _lastClickTime;
 	uint32 _lastKeyTime;
 	uint32 _lastTimerReset;
+	uint16 _stageColor;
 
 	bool _stopPlay;
 	uint32 _nextFrameTime;
@@ -243,7 +242,6 @@ private:
 	uint32 _flags;
 	uint16 _castArrayEnd;
 	uint16 _movieScriptCount;
-	uint16 _stageColor;
 	Lingo *_lingo;
 	DirectorSound *_soundManager;
 	DirectorEngine *_vm;


Commit: 5711e4399aed80f82772e8f3cf6e425cc7a96743
    https://github.com/scummvm/scummvm/commit/5711e4399aed80f82772e8f3cf6e425cc7a96743
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Use WM button activation styles

Changed paths:
    engines/director/director.cpp
    engines/director/director.h
    engines/director/events.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/score.cpp
    engines/director/score.h


diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index 0ef6a2867d..a47bde07f1 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -40,6 +40,9 @@
 
 namespace Director {
 
+const uint32 wmMode = Graphics::kWMModalMenuMode | Graphics::kWMModeNoDesktop
+	| Graphics::kWMModeManualDrawWidgets | Graphics::kWMModeFullscreen;
+
 DirectorEngine *g_director;
 
 DirectorEngine::DirectorEngine(OSystem *syst, const DirectorGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc),
@@ -135,8 +138,7 @@ Common::Error DirectorEngine::run() {
 	_macBinary = nullptr;
 	_soundManager = nullptr;
 
-	_wm = new Graphics::MacWindowManager(Graphics::kWMModalMenuMode | Graphics::kWMModeNoDesktop
-																			 | Graphics::kWMModeManualDrawWidgets | Graphics::kWMModeFullscreen);
+	_wm = new Graphics::MacWindowManager(wmMode);
 	_wm->setEngine(this);
 
 	_lingo = new Lingo(this);
diff --git a/engines/director/director.h b/engines/director/director.h
index af98ebbd66..2cb867a5a6 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -208,6 +208,7 @@ private:
 };
 
 extern DirectorEngine *g_director;
+extern const uint32 wmMode;
 
 } // End of namespace Director
 
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index 36220d1ba4..4222ab2a5a 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -104,7 +104,6 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 				if (sc->_sprites[spriteId]->_scriptId)
 					sc->_currentClickOnSpriteId = spriteId;
 
-				sc->_mouseIsDown = true;
 				sc->_lastEventTime = g_director->getMacTicks();
 				sc->_lastClickTime = sc->_lastEventTime;
 
@@ -121,9 +120,14 @@ void DirectorEngine::processEvents(bool bufferLingoEvents) {
 
 				spriteId = sc->getSpriteIDFromPos(pos);
 
+				if (!sc->_sprites[sc->_currentMouseDownSpriteId]->_currentBbox.contains(pos))
+					sc->_currentMouseDownSpriteId = 0;
+
+				if (!(g_director->_wm->_mode & Graphics::kWMModeButtonDialogStyle))
+					sc->_currentMouseDownSpriteId = spriteId;
+
 				debugC(3, kDebugEvents, "event: Button Up @(%d, %d), sprite id: %d", pos.x, pos.y, spriteId);
 
-				sc->_mouseIsDown = false;
 				releaseDraggedSprite();
 
 				{
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 9eb0ee52f6..1984aeca9a 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -549,7 +549,7 @@ Datum Lingo::getTheEntity(int entity, Datum &id, int field) {
 		break;
 	case kTheStillDown:
 		d.type = INT;
-		d.u.i = _vm->getCurrentScore()->_mouseIsDown;
+		d.u.i = _vm->_wm->_mouseDown;
 		break;
 	case kTheTimer:
 		d.type = INT;
@@ -576,6 +576,12 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 	}
 
 	switch (entity) {
+	case kTheButtonStyle:
+		if (d.asInt())
+			g_director->_wm->_mode = Director::wmMode | Graphics::kWMModeButtonDialogStyle;
+		else
+			g_director->_wm->_mode = Director::wmMode;
+		break;
 	case kTheCast:
 		setTheCast(id, field, d);
 		break;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index dfa301c073..1d326be718 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -48,7 +48,6 @@ Score::Score(DirectorEngine *vm) {
 	_soundManager = _vm->getSoundManager();
 	_currentMouseDownSpriteId = 0;
 	_currentClickOnSpriteId = 0;
-	_mouseIsDown = false;
 	_lastEventTime = _vm->getMacTicks();
 	_lastKeyTime = _lastEventTime;
 	_lastClickTime = _lastEventTime;
diff --git a/engines/director/score.h b/engines/director/score.h
index 97a20850ef..a95a0fc763 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -203,7 +203,6 @@ public:
 	Common::Rect _movieRect;
 	uint16 _currentMouseDownSpriteId;
 	uint16 _currentClickOnSpriteId;
-	bool _mouseIsDown;
 	uint32 _lastEventTime;
 	uint32 _lastRollTime;
 	uint32 _lastClickTime;


Commit: d6f87f22dfa369dfc8a29dd50ca3658120788d2a
    https://github.com/scummvm/scummvm/commit/d6f87f22dfa369dfc8a29dd50ca3658120788d2a
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Make puppetSprite version-sensitive

Changed paths:
    engines/director/lingo/lingo-builtins.cpp


diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index b1f0fbd626..4f098e4fda 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1682,19 +1682,33 @@ void LB::b_puppetSound(int nargs) {
 }
 
 void LB::b_puppetSprite(int nargs) {
-	if (!g_director->getCurrentScore()) {
+	Score *sc = g_director->getCurrentScore();
+	if (!sc) {
 		warning("b_puppetSprite: no score");
-
+		g_lingo->dropStack(nargs);
 		return;
 	}
 
-	Frame *frame = g_director->getCurrentScore()->_frames[g_director->getCurrentScore()->getCurrentFrame()];
+	if (nargs == 2 && g_director->getVersion() >= 4) {
+		Datum state = g_lingo->pop();
+		Datum sprite = g_lingo->pop();
+		if ((uint)sprite.asInt() < sc->_sprites.size()) {
+			sc->_sprites[sprite.asInt()]->_puppet = state.asInt();
+		} else {
+			warning("b_puppetSprite: sprite index out of bounds");
+		}
+	} else if (nargs == 0 && g_director->getVersion() < 4) {
+		g_lingo->dropStack(nargs);
 
-	if (g_lingo->_currentChannelId == -1) {
-		warning("b_puppetSprite: channel Id is missing");
-		return;
+		if (g_lingo->_currentChannelId == -1) {
+			warning("b_puppetSprite: channel Id is missing");
+			return;
+		}
+		sc->_sprites[g_lingo->_currentChannelId]->_puppet = true;
+	} else {
+		warning("b_puppetSprite: unexpectedly received %d arguments", nargs);
+		g_lingo->dropStack(nargs);
 	}
-	frame->_sprites[g_lingo->_currentChannelId]->_puppet = true;
 }
 
 void LB::b_puppetTempo(int nargs) {


Commit: 3095637e601ae7bb7f7c8aaf0280eb6e68ceacd7
    https://github.com/scummvm/scummvm/commit/3095637e601ae7bb7f7c8aaf0280eb6e68ceacd7
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Convert texts to buttons if necessary

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/score-loading.cpp
    engines/director/score.cpp
    engines/director/score.h
    engines/director/sprite.cpp
    engines/director/sprite.h


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 9c17dd244f..24cff1b433 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -155,13 +155,14 @@ SoundCast::SoundCast(Common::ReadStreamEndian &stream, uint16 version) {
 	}
 }
 
-TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor) {
+TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor, bool asButton) {
 	_type = kCastText;
 
 	_bgcolor = bgcolor;
 	_borderSize = kSizeNone;
 	_gutterSize = kSizeNone;
 	_boxShadow = kSizeNone;
+	_buttonType = kTypeButton;
 
 	_flags = 0;
 	_textFlags = 0;
@@ -269,7 +270,24 @@ TextCast::TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcol
 		stream.readUint16();
 	}
 
-	_modified = false;
+	if (asButton) {
+		_type = kCastButton;
+
+		if (version < 4) {
+			_buttonType = static_cast<ButtonType>(stream.readUint16BE() - 1);
+		} else {
+			stream.readByte();
+			stream.readByte();
+
+			// This has already been populated in the super TextCast constructor
+			//initialRect = Score::readRect(stream);
+			//boundingRect = Score::readRect(stream);
+
+			_buttonType = static_cast<ButtonType>(stream.readUint16BE());
+		}
+	}
+
+	_modified = true;
 }
 
 Graphics::TextAlign TextCast::getAlignment() {
@@ -299,14 +317,34 @@ void TextCast::importStxt(const Stxt *stxt) {
 }
 
 void TextCast::createWidget() {
+	if (g_director->getCurrentScore()->_window)
+		g_director->getCurrentScore()->_window->removeWidget(_widget);
+	else if (_widget)
+		delete _widget;
+
 	uint fgcolor = g_director->_wm->findBestColor(_palinfo1 & 0xff, _palinfo2 & 0xff, _palinfo3 & 0xff);
-	warning("TextCast::createWidget: bgcolor: %d, fgcolor: %d", _bgcolor, fgcolor);
 
 	Graphics::MacFont *macFont = new Graphics::MacFont(_fontId, _fontSize, _textSlant);
 
-	_widget = new Graphics::MacEditableText(g_director->getCurrentScore()->_window, 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, fgcolor, _bgcolor, _initialRect.width(), getAlignment(), 1, _borderSize, _gutterSize, _boxShadow, _textShadow);
+	switch (_type) {
+	case kCastText:
+		_widget = new Graphics::MacEditableText(g_director->getCurrentScore()->_window, 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, fgcolor, _bgcolor, _initialRect.width(), getAlignment(), 1, _borderSize, _gutterSize, _boxShadow, _textShadow);
+
+		((Graphics::MacEditableText *)_widget)->draw();
+		break;
+
+	case kCastButton:
+		_widget = new Graphics::MacButton(Graphics::MacButtonType(_buttonType), getAlignment(), g_director->getCurrentScore()->_window, 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, fgcolor, _bgcolor);
+		((Graphics::MacButton *)_widget)->draw();
+		_widget->_focusable = true;
+
+		((Graphics::MacButton *)(_widget))->draw();
+		break;
+
+	default:
+		break;
+	}
 
-	((Graphics::MacEditableText *)_widget)->draw();
 	delete macFont;
 }
 
@@ -425,36 +463,6 @@ ShapeCast::ShapeCast(Common::ReadStreamEndian &stream, uint16 version) {
 		_initialRect.debugPrint(0, "ShapeCast: rect:");
 }
 
-ButtonCast::ButtonCast(Common::ReadStreamEndian &stream, uint16 version) : TextCast(stream, version, 0xff) {
-	_type = kCastButton;
-
-	if (version < 4) {
-		_buttonType = static_cast<ButtonType>(stream.readUint16BE() - 1);
-	} else {
-		stream.readByte();
-		stream.readByte();
-
-		// This has already been populated in the super TextCast constructor
-		//initialRect = Score::readRect(stream);
-		//boundingRect = Score::readRect(stream);
-
-		_buttonType = static_cast<ButtonType>(stream.readUint16BE());
-	}
-}
-
-void ButtonCast::createWidget() {
-	uint fgcolor = g_director->_wm->findBestColor(_palinfo1 & 0xff, _palinfo2 & 0xff, _palinfo3 & 0xff);
-
-	Graphics::MacFont *macFont = new Graphics::MacFont(_fontId, _fontSize, _textSlant);
-
-	_widget = new Graphics::MacButton(Graphics::MacButtonType(_buttonType), getAlignment(), g_director->getCurrentScore()->_window, 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, fgcolor, _bgcolor);
-
-	_widget->_focusable = true;
-
-	((Graphics::MacButton *)(_widget))->draw();
-	delete macFont;
-}
-
 ScriptCast::ScriptCast(Common::ReadStreamEndian &stream, uint16 version) {
 	_type = kCastLingoScript;
 	_scriptType = kNoneScript;
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 9a0ff5fc42..4f19364671 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -112,7 +112,7 @@ public:
 
 class TextCast : public Cast {
 public:
-	TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor);
+	TextCast(Common::ReadStreamEndian &stream, uint16 version, int32 bgcolor, bool asButton = false);
 
 	void setText(const char *text);
 	virtual void createWidget();
@@ -136,6 +136,7 @@ public:
 	byte _textFlags;
 	uint16 _palinfo1, _palinfo2, _palinfo3;
 	int32 _bgcolor;
+	ButtonType _buttonType;
 
 	Common::String _ftext;
 	Common::String _ptext;
@@ -145,14 +146,6 @@ public:
 	Common::String getText();
 };
 
-class ButtonCast : public TextCast {
-public:
-	ButtonCast(Common::ReadStreamEndian &stream, uint16 version);
-	virtual void createWidget() override;
-
-	ButtonType _buttonType;
-};
-
 class ScriptCast : public Cast {
 public:
 	ScriptCast(Common::ReadStreamEndian &stream, uint16 version);
diff --git a/engines/director/score-loading.cpp b/engines/director/score-loading.cpp
index 840affb61a..bbfd8d4850 100644
--- a/engines/director/score-loading.cpp
+++ b/engines/director/score-loading.cpp
@@ -273,7 +273,6 @@ void Score::copyCastStxts() {
 			TextCast *tc = (TextCast *)c->_value;
 
 			tc->importStxt(stxt);
-			tc->createWidget();
 		}
 	}
 }
@@ -654,7 +653,7 @@ void Score::loadCastDataVWCR(Common::SeekableSubReadStreamEndian &stream) {
 			break;
 		case kCastButton:
 			debugC(3, kDebugLoading, "Score::loadCastDataVWCR(): CastTypes id: %d(%s) ButtonCast", id, numToCastNum(id));
-			_loadedCast->setVal(id, new ButtonCast(stream, _vm->getVersion()));
+			_loadedCast->setVal(id, new TextCast(stream, _vm->getVersion(), 0xff, true));
 			break;
 		default:
 			warning("Score::loadCastDataVWCR(): Unhandled cast id: %d(%s), type: %d, %d bytes", id, numToCastNum(id), castType, size);
@@ -679,7 +678,6 @@ void Score::setSpriteBboxes() {
 	for (uint16 i = 0; i < _frames.size(); i++) {
 		for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
 			Sprite *sp = _frames[i]->_sprites[j];
-			if (i == 1)
 			// Only call updateCast on the first frame sprites, because renderSprite
 			// calls updateCast for us after that. We need to get widget bounding info here.
 			// if (i == 1)
@@ -774,7 +772,7 @@ void Score::loadCastData(Common::SeekableSubReadStreamEndian &stream, uint16 id,
 		break;
 	case kCastButton:
 		debugC(3, kDebugLoading, "Score::loadCastData(): loading kCastButton (%d children)", res->children.size());
-		_loadedCast->setVal(id, new ButtonCast(castStream, _vm->getVersion()));
+		_loadedCast->setVal(id, new TextCast(castStream, _vm->getVersion(), 0xff, true));
 		break;
 	case kCastLingoScript:
 		debugC(3, kDebugLoading, "Score::loadCastData(): loading kCastLingoScript");
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index 1d326be718..ef8e9a5cbd 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -713,7 +713,7 @@ void Score::renderButton(uint16 spriteId) {
 		warning("renderButton: cast id %d not of type kCastButton", castId);
 		return;
 	}
-	ButtonCast *button = (ButtonCast *)member;
+	TextCast *button = (TextCast *)member;
 
 	// TODO: review all cases to confirm if we should use text height.
 	// height = textRect.height();
diff --git a/engines/director/score.h b/engines/director/score.h
index a95a0fc763..f31c38191a 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -49,7 +49,6 @@ struct Resource;
 class Sprite;
 class Stxt;
 class BitmapCast;
-class ButtonCast;
 class ScriptCast;
 class ShapeCast;
 class TextCast;
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index d99eaef0b7..3a761132c1 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -72,11 +72,23 @@ Sprite::~Sprite() {
 }
 
 void Sprite::updateCast() {
-	if (_cast && _cast->_widget) {
-		if (_cast->isEditable() != _editable && !_puppet)
-			_cast->setEditable(_editable);
-		_cast->_widget->_dims.moveTo(_currentPoint.x, _currentPoint.y);
+	if (!_cast)
+		return;
+
+	if (!_cast->_widget) {
+		if (_cast->_type == kCastText && _spriteType != kTextSprite) {
+			_cast->_type = kCastButton;
+			((TextCast *)_cast)->_buttonType = (ButtonType)(_spriteType - 8);
+		}
+
+		if (_cast->_type == kCastText || _cast->_type == kCastButton) {
+			((TextCast *)_cast)->createWidget();
+			_cast->_widget->_dims.moveTo(_currentPoint.x, _currentPoint.y);
+		}
 	}
+
+	if (_cast->isEditable() != _editable && !_puppet)
+		_cast->setEditable(_editable);
 }
 
 void Sprite::translate(Common::Point delta, bool moveTo) {
@@ -199,6 +211,7 @@ void Sprite::setCast(uint16 castId) {
 		case kCheckboxSprite:
 		case kRadioButtonSprite:
 			_castType = kCastButton;
+
 			break;
 		default:
 			warning("Sprite::setCast(): Unhandled sprite type %d", _spriteType);
diff --git a/engines/director/sprite.h b/engines/director/sprite.h
index 58e28a900b..d966740e8e 100644
--- a/engines/director/sprite.h
+++ b/engines/director/sprite.h
@@ -26,7 +26,6 @@
 namespace Director {
 
 class BitmapCast;
-class ButtonCast;
 class ShapeCast;
 class TextCast;
 


Commit: c3bfd99d509316c87980ddaabc35b2c54670accb
    https://github.com/scummvm/scummvm/commit/c3bfd99d509316c87980ddaabc35b2c54670accb
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Render bitmaps with widgets

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/ink.cpp
    engines/director/lingo/lingo-funcs.cpp
    engines/director/score-loading.cpp
    engines/director/score.cpp
    engines/director/score.h
    engines/director/sprite.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 24cff1b433..be44a9d725 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -37,34 +37,25 @@ namespace Director {
 
 Cast::Cast() {
 	_type = kCastTypeNull;
-	_surface = nullptr;
 	_widget = nullptr;
 	_hilite = false;
 
-	_img = nullptr;
-
 	_modified = true;
 }
 
 Cast::~Cast() {
-	if (_img)
-		delete _img;
-
 	if (_widget)
 		delete _widget;
 }
 
-bool Cast::isEditable() {
-	return false;
-}
-
-bool Cast::setEditable(bool editable) {
-	warning("Cast::setEditable: Attempted to set editable of non-editable cast");
-	return false;
+void Cast::createWidget() {
+	if (_widget)
+		error("TextCast::createWidget: Attempted to create widget twice");
 }
 
 BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint32 castTag, uint16 version) {
 	_type = kCastBitmap;
+	_img = nullptr;
 
 	if (version < 4) {
 		_pitch = 0;
@@ -142,6 +133,23 @@ BitmapCast::BitmapCast(Common::ReadStreamEndian &stream, uint32 castTag, uint16
 	_tag = castTag;
 }
 
+BitmapCast::~BitmapCast() {
+	if (_img)
+		delete _img;
+}
+
+void BitmapCast::createWidget() {
+	Cast::createWidget();
+
+	if (!_img) {
+		warning("BitmapCast::createWidget: No image decoder");
+		return;
+	}
+
+	_widget = new Graphics::MacWidget(g_director->getCurrentScore()->_window, 0, 0, _initialRect.width() - 1, _initialRect.height() - 1, false);
+	_widget->getSurface()->blitFrom(*_img->getSurface());
+}
+
 SoundCast::SoundCast(Common::ReadStreamEndian &stream, uint16 version) {
 	_type = kCastSound;
 	_audio = nullptr;
@@ -294,14 +302,11 @@ Graphics::TextAlign TextCast::getAlignment() {
 	switch (_textAlign) {
 	case kTextAlignRight:
 		return Graphics::kTextAlignRight;
-		break;
 	case kTextAlignCenter:
 		return Graphics::kTextAlignCenter;
-		break;
 	case kTextAlignLeft:
 	default:
 		return Graphics::kTextAlignLeft;
-		break;
 	}
 }
 
@@ -317,10 +322,7 @@ void TextCast::importStxt(const Stxt *stxt) {
 }
 
 void TextCast::createWidget() {
-	if (g_director->getCurrentScore()->_window)
-		g_director->getCurrentScore()->_window->removeWidget(_widget);
-	else if (_widget)
-		delete _widget;
+	Cast::createWidget();
 
 	uint fgcolor = g_director->_wm->findBestColor(_palinfo1 & 0xff, _palinfo2 & 0xff, _palinfo3 & 0xff);
 
@@ -463,6 +465,17 @@ ShapeCast::ShapeCast(Common::ReadStreamEndian &stream, uint16 version) {
 		_initialRect.debugPrint(0, "ShapeCast: rect:");
 }
 
+ShapeCast::ShapeCast() {
+	_shapeType = kShapeRectangle;
+	_pattern = 0;
+	_fgCol = 0;
+	_bgCol = 0;
+	_fillType = 0;
+	_lineThickness = 0;
+	_lineDirection = 0;
+	_ink = kInkTypeCopy;
+}
+
 ScriptCast::ScriptCast(Common::ReadStreamEndian &stream, uint16 version) {
 	_type = kCastLingoScript;
 	_scriptType = kNoneScript;
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 4f19364671..bbc2e576cd 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -54,18 +54,16 @@ class Cast {
 public:
 	Cast();
 	virtual ~Cast();
-	virtual bool isEditable();
-	virtual bool setEditable(bool editable);
+	virtual bool isEditable() { return false; }
+	virtual bool setEditable(bool editable) { return false; }
 	virtual bool isModified() { return _modified; }
+	virtual void createWidget();
 
 	CastType _type;
 	Common::Rect _initialRect;
 	Common::Rect _boundingRect;
 	Common::Array<Resource> _children;
 
-	const Graphics::Surface *_surface;
-	Image::ImageDecoder *_img;
-
 	bool _modified;
 	bool _hilite;
 
@@ -75,6 +73,10 @@ public:
 class BitmapCast : public Cast {
 public:
 	BitmapCast(Common::ReadStreamEndian &stream, uint32 castTag, uint16 version);
+	~BitmapCast();
+	virtual void createWidget() override;
+
+	Image::ImageDecoder *_img;
 
 	uint16 _pitch;
 	uint16 _regX;
@@ -99,6 +101,7 @@ public:
 class ShapeCast : public Cast {
 public:
 	ShapeCast(Common::ReadStreamEndian &stream, uint16 version);
+	ShapeCast();
 
 	ShapeType _shapeType;
 	uint16 _pattern;
diff --git a/engines/director/ink.cpp b/engines/director/ink.cpp
index 9d228de5d3..a329ff9623 100644
--- a/engines/director/ink.cpp
+++ b/engines/director/ink.cpp
@@ -33,23 +33,12 @@ void Score::inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::
 	t.moveTo(drawRect.left, drawRect.top);
 	bool nullMask = false;
 
-	// combine the given mask with the maskSurface
-	if (!maskSurface) {
-		nullMask = true;
-		maskSurface = new Graphics::ManagedSurface;
-		maskSurface->create(spriteSurface.w, spriteSurface.h, Graphics::PixelFormat::createFormatCLUT8());
-		maskSurface->clear(0);
-	}
-
 	drawRect.clip(Common::Rect(_maskSurface->w, _maskSurface->h));
-
-
-	if (drawRect.isEmpty()) {
-		warning("Score::inkBasedBlit(): empty drawRect");
-		return;
+	if (maskSurface->w != drawRect.width() || maskSurface->h != drawRect.height()) {
+		warning("Score::inkBasedBlit: Mismatched dimensions of mask surface and drawRect: %d", spriteId);
 	}
 
-	maskSurface->blitFrom(*_maskSurface, drawRect, Common::Point(0, 0));
+	maskSurface->transBlitFrom(*_maskSurface, drawRect, Common::Point(0, 0), _stageColor);
 
 	drawRect.clip(t);
 
diff --git a/engines/director/lingo/lingo-funcs.cpp b/engines/director/lingo/lingo-funcs.cpp
index 63f6d9e975..9d4702e48c 100644
--- a/engines/director/lingo/lingo-funcs.cpp
+++ b/engines/director/lingo/lingo-funcs.cpp
@@ -346,30 +346,21 @@ void Lingo::func_cursor(int cursorId, int maskId) {
 			return;
 		}
 
-		if (cursorCast->_surface == nullptr) {
-			warning("func_cursor(): empty surface for bitmap cast %d", cursorId);
-			return;
-		}
-		if (maskCast->_surface == nullptr) {
-			warning("func_cursor(): empty surface for bitmap cast %d", maskId);
-			return;
-		}
-
 		byte *assembly = (byte *)malloc(16 * 16);
 		byte *dst = assembly;
 
 		for (int y = 0; y < 16; y++) {
 			const byte *cursor = nullptr, *mask = nullptr;
 
-			if (y < cursorCast->_surface->h &&
-					y < maskCast->_surface->h) {
-				cursor = (const byte *)cursorCast->_surface->getBasePtr(0, y);
-				mask = (const byte *)maskCast->_surface->getBasePtr(0, y);
+			if (y < cursorCast->_widget->getSurface()->h &&
+					y < maskCast->_widget->getSurface()->h) {
+				cursor = (const byte *)cursorCast->_widget->getSurface()->getBasePtr(0, y);
+				mask = (const byte *)maskCast->_widget->getSurface()->getBasePtr(0, y);
 			}
 
 			for (int x = 0; x < 16; x++) {
-				if (x >= cursorCast->_surface->w ||
-						x >= maskCast->_surface->w) {
+				if (x >= cursorCast->_widget->getSurface()->w ||
+						x >= maskCast->_widget->getSurface()->w) {
 					cursor = mask = nullptr;
 				}
 
diff --git a/engines/director/score-loading.cpp b/engines/director/score-loading.cpp
index bbfd8d4850..2ceb96735a 100644
--- a/engines/director/score-loading.cpp
+++ b/engines/director/score-loading.cpp
@@ -250,9 +250,9 @@ bool Score::loadArchive() {
 	copyCastStxts();
 
 	setSpriteCasts();
-	setSpriteBboxes();
 	loadSpriteImages(false);
 	loadSpriteSounds(false);
+	setSpriteBboxes();
 
 	return true;
 }
@@ -358,8 +358,8 @@ void Score::loadSpriteImages(bool isSharedCast) {
 
 		delete pic;
 
-		bitmapCast->_surface = img->getSurface();
 		bitmapCast->_img = img;
+		bitmapCast->createWidget();
 
 		debugC(4, kDebugImages, "Score::loadSpriteImages(): id: %d, w: %d, h: %d, flags: %x, bytes: %x, bpp: %d clut: %x",
 			imgId, w, h, bitmapCast->_flags, bitmapCast->_bytes, bitmapCast->_bitsPerPixel, bitmapCast->_clut);
@@ -678,10 +678,7 @@ void Score::setSpriteBboxes() {
 	for (uint16 i = 0; i < _frames.size(); i++) {
 		for (uint16 j = 0; j < _frames[i]->_sprites.size(); j++) {
 			Sprite *sp = _frames[i]->_sprites[j];
-			// Only call updateCast on the first frame sprites, because renderSprite
-			// calls updateCast for us after that. We need to get widget bounding info here.
-			// if (i == 1)
-				sp->updateCast();
+			sp->updateCast();
 
 			sp->_startBbox = sp->getBbox();
 			sp->_currentBbox = sp->_startBbox;
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index ef8e9a5cbd..38c5b5e0aa 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -315,7 +315,6 @@ void Score::startLoop() {
 	_vm->_backSurface.create(_movieRect.width(), _movieRect.height());
 
 	_vm->_wm->setScreen(_surface);
-	_vm->_wm->_lastWidget = nullptr;
 
 	_surface->clear(_stageColor);
 
@@ -539,45 +538,27 @@ void Score::unrenderSprite(uint16 spriteId) {
 	}
 
 	currentSprite->_currentBbox = currentSprite->getBbox();
-	currentSprite->_dirty = false;
-
-	if (currentSprite->_cast)
-		currentSprite->_cast->_modified = false;
 }
 
 void Score::renderSprite(uint16 id) {
 	Sprite *sprite = _sprites[id];
 
-	sprite->updateCast();
-	if (!sprite || !sprite->_enabled)
+	if (!sprite || !sprite->_enabled || !sprite->_castType)
 		return;
 
-	CastType castType = sprite->_castType;
-
-	if (castType == kCastTypeNull)
-		return;
+	sprite->updateCast();
 
-	debugC(1, kDebugImages, "Score::renderFrame(): channel: %d,  castType: %d", id, castType);
-	// this needs precedence to be hit first... D3 does something really tricky
-	// with cast IDs for shapes. I don't like this implementation 100% as the
-	// 'cast' above might not actually hit a member and be null?
-	if (castType == kCastShape) {
+	debugC(1, kDebugImages, "Score::renderFrame(): channel: %d,  castType: %d", id, sprite->_castType);
+	if (sprite->_castType == kCastShape) {
 		renderShape(id);
-	} else if (castType == kCastText || castType == kCastRTE) {
-		renderText(id);
-	} else if (castType == kCastButton) {
-		renderButton(id);
 	} else {
-		if (!sprite->_cast || sprite->_cast->_type != kCastBitmap) {
-			warning("Score::renderFrame(): No cast ID for sprite %d", id);
-			return;
-		}
-		if (sprite->_cast->_surface == nullptr) {
-			warning("Score::renderFrame(): No cast surface for sprite %d", id);
-			return;
+		Cast *cast = _sprites[id]->_cast;
+		if (cast && cast->_widget) {
+			cast->_widget->draw();
+			inkBasedBlit(cast->_widget->getMask(), cast->_widget->getSurface()->rawSurface(), _sprites[id]->_ink, _sprites[id]->_currentBbox, id);
+		} else {
+			warning("Score::renderSprite: No widget for channel ID %d", id);
 		}
-
-		renderBitmap(id);
 	}
 
 	sprite->setClean();
@@ -701,62 +682,6 @@ void Score::renderShape(uint16 spriteId) {
 	inkBasedBlit(&maskSurface, tmpSurface, ink, shapeRect, spriteId);
 }
 
-void Score::renderButton(uint16 spriteId) {
-	uint16 castId = _sprites[spriteId]->_castId;
-
-	// This may not be a button cast. It could be a textcast with the channel forcing it
-	// to be a checkbox or radio button!
-	Cast *member = _vm->getCastMember(castId);
-	if (!member) {
-		warning("renderButton: unknown cast id %d", castId);
-	} else if (member->_type != kCastButton) {
-		warning("renderButton: cast id %d not of type kCastButton", castId);
-		return;
-	}
-	TextCast *button = (TextCast *)member;
-
-	// TODO: review all cases to confirm if we should use text height.
-	// height = textRect.height();
-
-	Common::Rect bbox = _sprites[spriteId]->_currentBbox;
-
-	inkBasedBlit(nullptr, button->_widget->getSurface()->rawSurface(),  _sprites[spriteId]->_ink, bbox, spriteId);
-}
-
-void Score::renderText(uint16 spriteId) {
-	TextCast *text = (TextCast*)_sprites[spriteId]->_cast;
-	if (text == nullptr) {
-		warning("Score::renderText(): TextCast #%d is a nullptr", spriteId);
-		return;
-	}
-
-	Common::Rect bbox = _sprites[spriteId]->_currentBbox;
-	text->_widget->draw();
-
-	if (_fontMap.contains(text->_fontId)) {
-		// We need to make sure that the Shared Cast fonts have been loaded in?
-		// might need a mapping table here of our own.
-		// textCast->fontId = _vm->_wm->_fontMan->getFontIdByName(_vm->getCurrentScore()->_fontMap[textCast->fontId]);
-	}
-
-	inkBasedBlit(nullptr, text->_widget->getSurface()->rawSurface(), _sprites[spriteId]->_ink, bbox, spriteId);
-}
-
-void Score::renderBitmap(uint16 spriteId) {
-	InkType ink;
-	Sprite *sprite = _sprites[spriteId];
-
-	// if (spriteId == _vm->getCurrentScore()->_currentMouseDownSpriteId)
-	// 	ink = kInkTypeReverse;
-	// else
-		ink = sprite->_ink;
-
-	BitmapCast *bc = (BitmapCast *)sprite->_cast;
-	Common::Rect drawRect = sprite->_currentBbox;
-
-	inkBasedBlit(nullptr, *(bc->_surface), ink, drawRect, spriteId);
-}
-
 uint16 Score::getSpriteIDFromPos(Common::Point pos) {
 	for (int i = _sprites.size() - 1; i >= 0; i--)
 		if (_sprites[i]->_currentBbox.contains(pos))
diff --git a/engines/director/score.h b/engines/director/score.h
index f31c38191a..dea4df24f1 100644
--- a/engines/director/score.h
+++ b/engines/director/score.h
@@ -146,10 +146,7 @@ public:
 
 private:
 	void update();
-	void renderText(uint16 spriteId);
 	void renderShape(uint16 spriteId);
-	void renderButton(uint16 spriteId);
-	void renderBitmap(uint16 spriteId);
 
 	// ink.cpp
 	void inkBasedBlit(Graphics::ManagedSurface *maskSurface, const Graphics::Surface &spriteSurface, InkType ink, Common::Rect drawRect, uint spriteId);
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 3a761132c1..6ff186520a 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -24,6 +24,8 @@
 #include "director/cast.h"
 #include "director/sprite.h"
 
+#include "director/score.h"
+
 #include "graphics/macgui/macwidget.h"
 
 namespace Director {
@@ -76,17 +78,27 @@ void Sprite::updateCast() {
 		return;
 
 	if (!_cast->_widget) {
-		if (_cast->_type == kCastText && _spriteType != kTextSprite) {
+		if (_cast->_type == kCastText && (_spriteType == kButtonSprite || _spriteType == kCheckboxSprite || _spriteType == kRadioButtonSprite)) {
+			// WORKAROUND: In D2/D3 there can be text casts that have button
+			// information set in the sprite.
+			warning("Sprite::updateCast: Working around D2/3 button glitch");
 			_cast->_type = kCastButton;
 			((TextCast *)_cast)->_buttonType = (ButtonType)(_spriteType - 8);
 		}
 
-		if (_cast->_type == kCastText || _cast->_type == kCastButton) {
-			((TextCast *)_cast)->createWidget();
-			_cast->_widget->_dims.moveTo(_currentPoint.x, _currentPoint.y);
-		}
+		_cast->createWidget();
+	}
+
+	int offsetx, offsety = 0;
+	if (_cast->_type == kCastBitmap) {
+		BitmapCast *bc = (BitmapCast *)_cast;
+		offsety = bc->_initialRect.top - bc->_regY;
+		offsetx = bc->_initialRect.left - bc->_regX;
 	}
 
+	if (_cast && _cast->_widget)
+		_cast->_widget->_dims.moveTo(_currentPoint.x + offsetx, _currentPoint.y + offsety);
+
 	if (_cast->isEditable() != _editable && !_puppet)
 		_cast->setEditable(_editable);
 }
@@ -174,8 +186,9 @@ void Sprite::setCast(uint16 castId) {
 
 	if (member)
 		_cast = member;
-	else
+	else {
 		warning("Sprite::setCast: Cast id %d has null member", castId);
+	}
 
 	if (g_director->getVersion() < 4) {
 		switch (_spriteType) {
@@ -191,7 +204,7 @@ void Sprite::setCast(uint16 castId) {
 		case kOutlinedRoundedRectangleSprite:
 		case kOutlinedOvalSprite:
 		case kCastMemberSprite:
-			if (_cast != nullptr) {
+			if (_cast) {
 				switch (_cast->_type) {
 				case kCastButton:
 					_castType = kCastButton;
@@ -202,6 +215,8 @@ void Sprite::setCast(uint16 castId) {
 				}
 			} else {
 				_castType = kCastShape;
+
+				g_director->getCurrentScore()->_loadedCast->setVal(_castId, new ShapeCast());
 			}
 			break;
 		case kTextSprite:
@@ -225,6 +240,7 @@ void Sprite::setCast(uint16 castId) {
 		}
 	}
 
+
 	_dirty = true;
 }
 
@@ -234,49 +250,22 @@ Common::Rect Sprite::getBbox() {
 		return result;
 	}
 
-	switch (_castType) {
-	case kCastShape:
-		result = Common::Rect(_currentPoint.x,
-								_currentPoint.y,
-								_currentPoint.x + _width,
-								_currentPoint.y + _height);
-		break;
-	case kCastRTE:
-	case kCastText:
-	case kCastButton:
-		{
-			if (!_cast)
-				return result;
-
-			result = _cast->_widget->getDimensions();
-			break;
-		}
-	case kCastBitmap: {
-		if (!_cast)
-			return result;
-
-		BitmapCast *bc = (BitmapCast *)_cast;
-
-		int32 regX = bc->_regX;
-		int32 regY = bc->_regY;
-		int32 rectLeft = bc->_initialRect.left;
-		int32 rectTop = bc->_initialRect.top;
-
-		int x = _currentPoint.x - regX + rectLeft;
-		int y = _currentPoint.y - regY + rectTop;
-		int height = _height;
-		int width = g_director->getVersion() > 4 ? bc->_initialRect.width() : _width;
+	if (_castType == kCastShape) {
+		// WORKAROUND: Shape widgets not fully implemented.
+		result = Common::Rect(_currentPoint.x, _currentPoint.y, _currentPoint.x + _width, _currentPoint.y + _height);
+	} else {
+		result = _cast ? _cast->_widget->getDimensions() : Common::Rect(0, 0, _width, _height);
+	}
 
-		// If one of the dimensions is invalid, invalidate whole thing
-		if (width == 0 || height == 0)
-			width = height = 0;
+	result.moveTo(_currentPoint.x, _currentPoint.y);
 
-		result = Common::Rect(x, y, x + width, y + height);
-		break;
-	}
-	default:
-		warning("Sprite::getBbox(): Unhandled cast type: %d : castId: %d", _castType, _castId);
+	if (_cast && _castType == kCastBitmap) {
+		BitmapCast *bc = (BitmapCast *)_cast;
+		int offsety = bc->_initialRect.top - bc->_regY;
+		int offsetx = bc->_initialRect.left - bc->_regX;
+		result.translate(offsetx, offsety);
 	}
+
 	return result;
 }
 


Commit: 0886091f7d23734b779538dc7a2946421f877d4e
    https://github.com/scummvm/scummvm/commit/0886091f7d23734b779538dc7a2946421f877d4e
Author: Nathanael Gentry (nathanael.gentrydb8 at gmail.com)
Date: 2020-06-10T15:42:49+02:00

Commit Message:
DIRECTOR: Fix puppetSprite de-activation

Changed paths:
    engines/director/lingo/lingo-the.cpp


diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index 1984aeca9a..390880c531 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -853,9 +853,13 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		sprite->setPattern(d.asInt());
 		break;
 	case kThePuppet:
+		warning("kThePuppet: %d", d.asInt());
 		sprite->_puppet = d.asInt();
-		if (!d.u.i) {
+		if (!d.asInt()) {
 			sprite->_currentPoint = sprite->_startPoint;
+
+			// TODO: Properly reset sprite properties after puppet disabled.
+			sprite->_moveable = false;
 		}
 		break;
 	case kTheStartTime:




More information about the Scummvm-git-logs mailing list