[Scummvm-git-logs] scummvm master -> 4bfffc43a76a9d4446237c15642f0f3c7b2e548c

moralrecordings code at moral.net.au
Sun Jul 26 04:32:33 UTC 2020


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

Summary:
4bfffc43a7 DIRECTOR: Move widgets from cast members to channels (#2372)


Commit: 4bfffc43a76a9d4446237c15642f0f3c7b2e548c
    https://github.com/scummvm/scummvm/commit/4bfffc43a76a9d4446237c15642f0f3c7b2e548c
Author: Scott Percival (code at moral.net.au)
Date: 2020-07-26T04:32:29Z

Commit Message:
DIRECTOR: Move widgets from cast members to channels (#2372)

This change is required to support copies of the same cast member running in different channels.

* DIRECTOR: Move widget ownership from cast member to channel

* DIRECTOR: Cache cast dimensions from createWidget

* DIRECTOR: Add null checks for createWidget

* GRAPHICS: MACGUI: Clear active/hover WM references if the widget is destroyed

* DIRECTOR: LINGO: Re-add null check for kTheEditableText

* DIRECTOR: Avoid destroying widgets if the channel isn't dirty

* DIRECTOR: Fix dirty test

* DIRECTOR: Fix text field writeback

* DIRECTOR: Fix null cast check

* DIRECTOR: Add bbox as argument to createWidget

* DIRECTOR: Add setCast method to Channel

* DIRECTOR: Fix use-after-free in Channel::getMask

* DIRECTOR: Fix bounding box for Button sprites

* DIRECTOR: Cache widget dimensions in cast member

* DIRECTOR: Remove widget from channel if nextSprite is empty

* GRAPHICS: MACGUI: Fix MacText::splitString for empty string case

* DIRECTOR: Add null checks for movie and score in processEvents

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/castmember.cpp
    engines/director/castmember.h
    engines/director/channel.cpp
    engines/director/channel.h
    engines/director/cursor.cpp
    engines/director/events.cpp
    engines/director/lingo/lingo-the.cpp
    engines/director/score.cpp
    engines/director/sprite.cpp
    graphics/macgui/macbutton.cpp
    graphics/macgui/mactext.cpp
    graphics/macgui/macwidget.cpp
    graphics/macgui/macwindowmanager.cpp
    graphics/macgui/macwindowmanager.h


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index f654398fb9..21f73043d3 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -345,7 +345,6 @@ bool Cast::loadArchive() {
 
 	loadSpriteImages();
 	loadSpriteSounds();
-	createCastWidgets();
 
 	return true;
 }
@@ -433,15 +432,6 @@ void Cast::copyCastStxts() {
 	}
 }
 
-void Cast::createCastWidgets() {
-	for (Common::HashMap<int, CastMember *>::iterator c = _loadedCast->begin(); c != _loadedCast->end(); ++c) {
-		if (!c->_value)
-			continue;
-
-		c->_value->createWidget();
-	}
-}
-
 void Cast::loadSpriteImages() {
 	debugC(1, kDebugLoading, "****** Preloading sprite images");
 
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 14e2914b7f..3b599c336c 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -67,7 +67,6 @@ public:
 	void loadSpriteSounds();
 
 	void copyCastStxts();
-	void createCastWidgets();
 	Common::Rect getCastMemberInitialRect(int castId);
 	void setCastMemberModified(int castId);
 	CastMember *getCastMember(int castId);
diff --git a/engines/director/castmember.cpp b/engines/director/castmember.cpp
index 069472c418..5c9415327c 100644
--- a/engines/director/castmember.cpp
+++ b/engines/director/castmember.cpp
@@ -35,7 +35,6 @@ CastMember::CastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndi
 	_type = kCastTypeNull;
 	_cast = cast;
 	_castId = castId;
-	_widget = nullptr;
 	_hilite = false;
 	_autoHilite = false;
 	_purgePriority = 3;
@@ -46,7 +45,7 @@ CastMember::CastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndi
 }
 
 BitmapCastMember::BitmapCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint32 castTag, uint16 version, uint8 flags1)
-	: CastMember(cast, castId, stream) {
+		: CastMember(cast, castId, stream) {
 	_type = kCastBitmap;
 	_img = nullptr;
 	_matte = nullptr;
@@ -163,16 +162,15 @@ BitmapCastMember::~BitmapCastMember() {
 		delete _matte;
 }
 
-void BitmapCastMember::createWidget() {
-	CastMember::createWidget();
-
+Graphics::MacWidget *BitmapCastMember::createWidget(Common::Rect &bbox) {
 	if (!_img) {
 		warning("BitmapCastMember::createWidget: No image decoder");
-		return;
+		return nullptr;
 	}
 
-	_widget = new Graphics::MacWidget(g_director->getCurrentStage(), 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, false);
-	_widget->getSurface()->blitFrom(*_img->getSurface());
+	Graphics::MacWidget *widget = new Graphics::MacWidget(g_director->getCurrentStage(), bbox.left, bbox.top, bbox.width(), bbox.height(), g_director->_wm, false);
+	widget->getSurface()->blitFrom(*_img->getSurface());
+	return widget;
 }
 
 void BitmapCastMember::createMatte() {
@@ -297,6 +295,7 @@ TextCastMember::TextCastMember(Cast *cast, uint16 castId, Common::SeekableReadSt
 	_gutterSize = kSizeNone;
 	_boxShadow = kSizeNone;
 	_buttonType = kTypeButton;
+	_editable = false;
 	_maxHeight = _textHeight = 0;
 
 	_bgcolor = 0;
@@ -423,17 +422,11 @@ TextCastMember::TextCastMember(Cast *cast, uint16 castId, Common::SeekableReadSt
 }
 
 void TextCastMember::setColors(int *fgcolor, int *bgcolor) {
-	if (!_widget)
-		return;
-
 	if (fgcolor)
 		_fgcolor = *fgcolor;
 
 	if (bgcolor)
 		_bgcolor = *bgcolor;
-
-	_widget->setColors(_fgcolor, _bgcolor);
-	((Graphics::MacText *)_widget)->_fullRefresh = true;
 }
 
 Graphics::TextAlign TextCastMember::getAlignment() {
@@ -459,24 +452,27 @@ void TextCastMember::importStxt(const Stxt *stxt) {
 	_ptext = stxt->_ptext;
 }
 
-void TextCastMember::createWidget() {
-	CastMember::createWidget();
-
+Graphics::MacWidget *TextCastMember::createWidget(Common::Rect &bbox) {
 	Graphics::MacFont *macFont = new Graphics::MacFont(_fontId, _fontSize, _textSlant);
+	Graphics::MacWidget *widget = nullptr;
 
 	switch (_type) {
 	case kCastText:
-		_widget = new Graphics::MacText(g_director->getCurrentStage(), 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, getForeColor(), getBackColor(), _initialRect.width(), getAlignment(), 0, _borderSize, _gutterSize, _boxShadow, _textShadow);
-
-		((Graphics::MacText *)_widget)->draw();
+		widget = new Graphics::MacText(g_director->getCurrentStage(), bbox.left, bbox.top, bbox.width(), bbox.height(), g_director->_wm, _ftext, macFont, getForeColor(), getBackColor(), bbox.width(), getAlignment(), 0, _borderSize, _gutterSize, _boxShadow, _textShadow);
+		((Graphics::MacText *)widget)->draw();
+		((Graphics::MacText *)widget)->_focusable = _editable;
+		((Graphics::MacText *)widget)->setEditable(_editable);
+		((Graphics::MacText *)widget)->_selectable = _editable;
 		break;
 
 	case kCastButton:
-		_widget = new Graphics::MacButton(Graphics::MacButtonType(_buttonType), getAlignment(), g_director->getCurrentStage(), 0, 0, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, getForeColor(), 0xff);
-		((Graphics::MacButton *)_widget)->draw();
-		_widget->_focusable = true;
+		// note that we use _initialRect for the dimensions of the button;
+		// the values provided in the sprite bounding box are ignored
+		widget = new Graphics::MacButton(Graphics::MacButtonType(_buttonType), getAlignment(), g_director->getCurrentStage(), bbox.left, bbox.top, _initialRect.width(), _initialRect.height(), g_director->_wm, _ftext, macFont, getForeColor(), 0xff);
+		((Graphics::MacButton *)widget)->draw();
+		widget->_focusable = true;
 
-		((Graphics::MacButton *)(_widget))->draw();
+		((Graphics::MacButton *)widget)->draw();
 		break;
 
 	default:
@@ -484,6 +480,17 @@ void TextCastMember::createWidget() {
 	}
 
 	delete macFont;
+	return widget;
+}
+
+Common::Rect TextCastMember::getWidgetRect() {
+	Graphics::MacWidget *widget = createWidget(_initialRect);
+	Common::Rect result = _initialRect;
+	if (widget) {
+		result = widget->_dims;
+		delete widget;
+	}
+	return result;
 }
 
 void TextCastMember::importRTE(byte *text) {
@@ -500,50 +507,29 @@ void TextCastMember::setText(const char *text) {
 		return;
 
 	_ptext = _ftext = text;
-
-	if (_widget) {
-		Graphics::MacText *wtext = (Graphics::MacText *)_widget;
-		wtext->clearText();
-		wtext->appendTextDefault(_ftext);
-		wtext->draw();
-	}
-
 	_modified = true;
 }
 
 Common::String TextCastMember::getText() {
-	if (_widget)
-		_ptext = ((Graphics::MacText *)_widget)->getEditedString().encode();
-
 	return _ptext;
 }
 
 bool TextCastMember::isModified() {
-	return _modified || (_widget ? ((Graphics::MacText *)_widget)->_contentIsDirty || ((Graphics::MacText *)_widget)->_cursorDirty: false);
+	return _modified;
 }
 
 bool TextCastMember::isEditable() {
-	if (!_widget) {
-		warning("TextCastMember::setEditable: Attempt to set editable of null widget");
-		return false;
-	}
+	return _editable;
+}
 
-	return (Graphics::MacText *)_widget->_editable;
+void TextCastMember::setEditable(bool editable) {
+	_editable = editable;
 }
 
-bool TextCastMember::setEditable(bool editable) {
-	if (!_widget) {
-		warning("TextCastMember::setEditable: Attempt to set editable of null widget");
-		return false;
+void TextCastMember::updateFromWidget(Graphics::MacWidget *widget) {
+	if (widget && _type == kCastText) {
+		_ptext = ((Graphics::MacText *)widget)->getEditedString().encode();
 	}
-
-	Graphics::MacText *text = (Graphics::MacText *)_widget;
-	text->setEditable(editable);
-	text->_focusable = editable;
-	text->_selectable = editable;
-	// text->setActive(editable);
-
-	return true;
 }
 
 ShapeCastMember::ShapeCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint16 version)
diff --git a/engines/director/castmember.h b/engines/director/castmember.h
index c28c5b2d37..b1d53e45a0 100644
--- a/engines/director/castmember.h
+++ b/engines/director/castmember.h
@@ -61,9 +61,11 @@ public:
 	uint16 getID() { return _castId; }
 
 	virtual bool isEditable() { return false; }
-	virtual bool setEditable(bool editable) { return false; }
+	virtual void setEditable(bool editable) {}
 	virtual bool isModified() { return _modified; }
-	virtual void createWidget() {}
+	virtual Graphics::MacWidget *createWidget(Common::Rect &bbox) { return nullptr; }
+	virtual void updateFromWidget(Graphics::MacWidget *widget) {}
+	virtual Common::Rect getWidgetRect() { return _initialRect; }
 
 	virtual void setColors(int *fgcolor, int *bgcolor) { return; }
 	virtual uint getForeColor() { return 0; }
@@ -81,8 +83,6 @@ public:
 	uint32 _size;
 	uint8 _flags1;
 
-	Graphics::MacWidget *_widget;
-
 private:
 	Cast *_cast;
 	uint16 _castId;
@@ -92,7 +92,7 @@ class BitmapCastMember : public CastMember {
 public:
 	BitmapCastMember(Cast *cast, uint16 castId, Common::SeekableReadStreamEndian &stream, uint32 castTag, uint16 version, uint8 flags1 = 0);
 	~BitmapCastMember();
-	virtual void createWidget() override;
+	virtual Graphics::MacWidget *createWidget(Common::Rect &bbox) override;
 
 	void createMatte();
 	Graphics::Surface *getMatte();
@@ -164,11 +164,13 @@ public:
 	virtual void setColors(int *fgcolor, int *bgcolor) override;
 
 	void setText(const char *text);
-	virtual void createWidget() override;
+	virtual Graphics::MacWidget *createWidget(Common::Rect &bbox) override;
+	virtual Common::Rect getWidgetRect() override;
 
 	virtual bool isModified() override;
 	virtual bool isEditable() override;
-	virtual bool setEditable(bool editable) override;
+	virtual void setEditable(bool editable) override;
+	virtual void updateFromWidget(Graphics::MacWidget *widget);
 	Graphics::TextAlign getAlignment();
 
 	virtual uint getBackColor() override { return _bgcolor; }
@@ -191,6 +193,7 @@ public:
 	uint16 _bgpalinfo1, _bgpalinfo2, _bgpalinfo3;
 	uint16 _fgpalinfo1, _fgpalinfo2, _fgpalinfo3;
 	ButtonType _buttonType;
+	bool _editable;
 
 	Common::String _ftext;
 	Common::String _ptext;
diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index b849c51073..0eed8530a4 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -32,12 +32,15 @@
 
 namespace Director {
 
-Channel::Channel(Sprite *sp) {
+Channel::Channel(Sprite *sp, int priority) {
 	_sprite = sp;
+	_widget = nullptr;
 	_currentPoint = sp->_startPoint;
 	_delta = Common::Point(0, 0);
 	_constraint = 0;
+	_mask = nullptr;
 
+	_priority = priority;
 	_width = _sprite->_width;
 	_height = _sprite->_height;
 
@@ -47,6 +50,13 @@ Channel::Channel(Sprite *sp) {
 	_sprite->updateCast();
 }
 
+Channel::~Channel() {
+	if (_widget)
+		delete _widget;
+	if (_mask)
+		delete _mask;
+}
+
 DirectorPlotData Channel::getPlotData() {
 	DirectorPlotData pd(g_director->_wm, _sprite->_spriteType, _sprite->_ink, getBackColor(), getForeColor());
 	pd.colorWhite = pd._wm->_colorWhite;
@@ -66,8 +76,8 @@ DirectorPlotData Channel::getPlotData() {
 }
 
 Graphics::ManagedSurface *Channel::getSurface() {
-	if (_sprite->_cast && _sprite->_cast->_widget) {
-		return  _sprite->_cast->_widget->getSurface();
+	if (_widget) {
+		return _widget->getSurface();
 	} else {
 		return nullptr;
 	}
@@ -96,7 +106,14 @@ const Graphics::Surface *Channel::getMask(bool forceMatte) {
 		CastMember *member = g_director->getCurrentMovie()->getCastMember(_sprite->_castId + 1);
 
 		if (member && member->_initialRect == _sprite->_cast->_initialRect) {
-			return &member->_widget->getSurface()->rawSurface();
+			Common::Rect bbox(getBbox());
+			Graphics::MacWidget *widget = member->createWidget(bbox);
+			if (_mask)
+				delete _mask;
+			_mask = new Graphics::ManagedSurface();
+			_mask->copyFrom(*widget->getSurface());
+			delete widget;
+			return &_mask->rawSurface();
 		} else {
 			warning("Channel::getMask(): Requested cast mask, but no matching mask was found");
 			return nullptr;
@@ -144,7 +161,7 @@ bool Channel::isActiveText() {
 	if (_sprite->_spriteType != kTextSprite)
 		return false;
 
-	if (_sprite->_cast && _sprite->_cast->_widget && _sprite->_cast->_widget->hasAllFocus())
+	if (_widget && _widget->hasAllFocus())
 		return true;
 
 	return false;
@@ -228,12 +245,19 @@ Common::Rect Channel::getBbox(bool unstretched) {
 	return result;
 }
 
+void Channel::setCast(uint16 castId) {
+	_sprite->setCast(castId);
+	_width = _sprite->_width;
+	_height = _sprite->_height;
+	replaceWidget();
+}
+
 void Channel::setClean(Sprite *nextSprite, int spriteId, bool partial) {
 	if (!nextSprite)
 		return;
 
 	bool newSprite = (_sprite->_spriteType == kInactiveSprite && nextSprite->_spriteType != kInactiveSprite);
-	_dirty = false;
+	bool replace = isDirty(nextSprite);
 
 	if (nextSprite) {
 		if (!_sprite->_puppet) {
@@ -259,16 +283,11 @@ void Channel::setClean(Sprite *nextSprite, int spriteId, bool partial) {
 		_delta = Common::Point(0, 0);
 	}
 
-	if (_sprite->_cast && _sprite->_cast->_widget) {
+	if (replace) {
 		_sprite->updateCast();
-		Common::Point p(getPosition());
-		_sprite->_cast->_modified = false;
-		_sprite->_cast->_widget->_dims.moveTo(p.x, p.y);
-
-		_sprite->_cast->_widget->_priority = spriteId;
-		_sprite->_cast->_widget->draw();
-		_sprite->_cast->_widget->_contentIsDirty = false;
+		replaceWidget();
 	}
+	_dirty = false;
 }
 
 void Channel::setWidth(int w) {
@@ -295,6 +314,37 @@ void Channel::setBbox(int l, int t, int r, int b) {
 	}
 }
 
+void Channel::replaceWidget() {
+	if (_widget) {
+		delete _widget;
+		_widget = nullptr;
+	}
+
+	if (_sprite && _sprite->_cast) {
+		Common::Rect bbox(getBbox());
+		_sprite->_cast->_modified = false;
+
+		_widget = _sprite->_cast->createWidget(bbox);
+		if (_widget) {
+			_widget->_priority = _priority;
+			_widget->draw();
+			_widget->_contentIsDirty = false;
+		}
+	}
+}
+
+bool Channel::updateWidget() {
+	if (_widget && _widget->_contentIsDirty) {
+		if (_sprite->_cast) {
+			_sprite->_cast->updateFromWidget(_widget);
+		}
+		_widget->draw();
+		return true;
+	}
+
+	return false;
+}
+
 void Channel::addRegistrationOffset(Common::Point &pos, bool subtract) {
 	if (_sprite->_cast && _sprite->_cast->_type == kCastBitmap) {
 		BitmapCastMember *bc = (BitmapCastMember *)(_sprite->_cast);
diff --git a/engines/director/channel.h b/engines/director/channel.h
index 15506c1924..413006bd53 100644
--- a/engines/director/channel.h
+++ b/engines/director/channel.h
@@ -26,6 +26,7 @@
 namespace Graphics {
 	struct Surface;
 	class ManagedSurface;
+	class MacWidget;
 }
 
 namespace Director {
@@ -35,7 +36,8 @@ class Cursor;
 
 class Channel {
 public:
-	Channel(Sprite *sp);
+	Channel(Sprite *sp, int priority = 0);
+	~Channel();
 
 	DirectorPlotData getPlotData();
 	const Graphics::Surface *getMask(bool forceMatte = false);
@@ -52,20 +54,26 @@ public:
 	void setWidth(int w);
 	void setHeight(int h);
 	void setBbox(int l, int t, int r, int b);
+	void setCast(uint16 castId);
 	void setClean(Sprite *nextSprite, int spriteId, bool partial = false);
+	void replaceWidget();
+	bool updateWidget();
 
 	void addDelta(Common::Point pos);
 
 public:
 	Sprite *_sprite;
 	Cursor _cursor;
+	Graphics::MacWidget *_widget;
 
 	bool _dirty;
 	bool _visible;
 	uint _constraint;
 	Common::Point _currentPoint;
 	Common::Point _delta;
+	Graphics::ManagedSurface *_mask;
 
+	int _priority;
 	int _width;
 	int _height;
 
diff --git a/engines/director/cursor.cpp b/engines/director/cursor.cpp
index 00e947e197..ed90be9d70 100644
--- a/engines/director/cursor.cpp
+++ b/engines/director/cursor.cpp
@@ -19,6 +19,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
+#include "image/image_decoder.h"
+
 #include "director/director.h"
 #include "director/cursor.h"
 #include "director/movie.h"
@@ -52,10 +54,10 @@ void Cursor::readFromCast(uint cursorId, uint maskId) {
 	CastMember *cursorCast = g_director->getCurrentMovie()->getCastMember(cursorId);
 	CastMember *maskCast = g_director->getCurrentMovie()->getCastMember(maskId);
 
-	if (!cursorCast || !cursorCast->_widget || cursorCast->_type != kCastBitmap) {
+	if (!cursorCast || cursorCast->_type != kCastBitmap) {
 		warning("Cursor::readFromCast: No bitmap cast for cursor");
 		return;
-	} else if (!maskCast || !maskCast->_widget || maskCast->_type != kCastBitmap) {
+	} else if (!maskCast || maskCast->_type != kCastBitmap) {
 		warning("Cursor::readFromCast: No bitmap mask for cursor");
 		return;
 	}
@@ -65,21 +67,24 @@ void Cursor::readFromCast(uint cursorId, uint maskId) {
 
 	resetCursor(Graphics::kMacCursorCustom, true, 0, cursorId, maskId);
 
+	BitmapCastMember *cursorBitmap = (BitmapCastMember *)cursorCast;
+	BitmapCastMember *maskBitmap = (BitmapCastMember *)maskCast;
+
 	_surface = new byte[getWidth() * getHeight()];
 	byte *dst = _surface;
 
 	for (int y = 0; y < 16; y++) {
 		const byte *cursor = nullptr, *mask = nullptr;
 
-		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);
+		if (y < cursorBitmap->_img->getSurface()->h &&
+				y < maskBitmap->_img->getSurface()->h) {
+			cursor = (const byte *)cursorBitmap->_img->getSurface()->getBasePtr(0, y);
+			mask = (const byte *)maskBitmap->_img->getSurface()->getBasePtr(0, y);
 		}
 
 		for (int x = 0; x < 16; x++) {
-			if (x >= cursorCast->_widget->getSurface()->w ||
-					x >= maskCast->_widget->getSurface()->w) {
+			if (x >= cursorBitmap->_img->getSurface()->w ||
+					x >= maskBitmap->_img->getSurface()->w) {
 				cursor = mask = nullptr;
 			}
 
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index bf7b6f4d89..960019f735 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -65,10 +65,26 @@ void DirectorEngine::processEvents() {
 
 	uint endTime = g_system->getMillis() + 10;
 
+	Movie *m = getCurrentMovie();
+	if (m) {
+		Score *sc = m->getScore();
+
+		if (sc && sc->getCurrentFrame() >= sc->_frames.size()) {
+			warning("processEvents: request to access frame %d of %d", sc->getCurrentFrame(), sc->_frames.size() - 1);
+			return;
+		}
+	}
+
+	uint16 spriteId = 0;
+
+	Common::Point pos;
+
 	while (g_system->getMillis() < endTime) {
 		while (g_system->getEventManager()->pollEvent(event)) {
-			if (_wm->processEvent(event))
+			if (_wm->processEvent(event)) {
+				// window manager has done something! update the channels
 				continue;
+			}
 
 			switch (event.type) {
 			case Common::EVENT_QUIT:
diff --git a/engines/director/lingo/lingo-the.cpp b/engines/director/lingo/lingo-the.cpp
index a85f6bfccf..571e4454cb 100644
--- a/engines/director/lingo/lingo-the.cpp
+++ b/engines/director/lingo/lingo-the.cpp
@@ -919,16 +919,16 @@ void Lingo::setTheEntity(int entity, Datum &id, int field, Datum &d) {
 		if (_vm->getCurrentMovie()->_currentEditableTextChannel != 0) {
 			Channel *channel = _vm->getCurrentMovie()->getScore()->getChannelById(_vm->getCurrentMovie()->_currentEditableTextChannel);
 
-			if (channel->_sprite->_cast->_widget)
-				(((Graphics::MacText *)channel->_sprite->_cast->_widget)->setSelection(d.asInt(), false));
+			if (channel->_widget)
+				(((Graphics::MacText *)channel->_widget)->setSelection(d.asInt(), false));
 		}
 		break;
 	case kTheSelStart:
 		if (_vm->getCurrentMovie()->_currentEditableTextChannel != 0) {
 			Channel *channel = _vm->getCurrentMovie()->getScore()->getChannelById(_vm->getCurrentMovie()->_currentEditableTextChannel);
 
-			if (channel->_sprite->_cast->_widget)
-				(((Graphics::MacText *)channel->_sprite->_cast->_widget)->setSelection(d.asInt(), true));
+			if (channel->_widget)
+				(((Graphics::MacText *)channel->_widget)->setSelection(d.asInt(), true));
 		}
 		break;
 	case kTheSoundEnabled:
@@ -1218,9 +1218,7 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		if (d.asInt() != sprite->_castId) {
 			g_director->getCurrentStage()->addDirtyRect(channel->getBbox());
 
-			sprite->setCast(d.asInt());
-			channel->_width = sprite->_width;
-			channel->_height = sprite->_height;
+			channel->setCast(d.asInt());
 		} else {
 			channel->_dirty = false;
 		}
@@ -1244,7 +1242,8 @@ void Lingo::setTheSprite(Datum &id1, int field, Datum &d) {
 		}
 		break;
 	case kTheEditableText:
-		sprite->_cast ? sprite->_cast->setEditable(d.asInt()) : false;
+		if (sprite->_cast)
+			sprite->_cast->setEditable(d.asInt());
 		break;
 	case kTheForeColor:
 		if (d.asInt() != sprite->_foreColor) {
@@ -1649,7 +1648,6 @@ void Lingo::setTheCast(Datum &id1, int field, Datum &d) {
 		if (member->_type == kCastButton) {
 			TextCastMember *button = (TextCastMember *)member;
 			if ((bool)d.asInt() !=  member->_hilite) {
-				((Graphics::MacButton *) button->_widget)->invertInner();
 				button->_hilite = !!d.asInt();
 			}
 		} else {
@@ -1761,17 +1759,16 @@ Datum Lingo::getTheField(Datum &id1, int field) {
 		break;
 	case kTheTextAlign:
 		d.type = STRING;
-		switch (((Graphics::MacText *)member->_widget)->getAlign()) {
-		case Graphics::kTextAlignLeft:
+		switch (((TextCastMember *)member)->_textAlign) {
+		case kTextAlignLeft:
 			d.u.s = new Common::String("left");
 			break;
-		case Graphics::kTextAlignCenter:
+		case kTextAlignCenter:
 			d.u.s = new Common::String("center");
 			break;
-		case Graphics::kTextAlignRight:
+		case kTextAlignRight:
 			d.u.s = new Common::String("right");
 			break;
-		case Graphics::kTextAlignInvalid:
 		default:
 			warning("Lingo::getTheField: Invalid text align spec");
 			break;
@@ -1823,20 +1820,19 @@ void Lingo::setTheField(Datum &id1, int field, Datum &d) {
 			Common::String select = d.asString(true);
 			select.toLowercase();
 
-			Graphics::TextAlign align;
+			TextAlignType align;
 			if (select == "\"left\"") {
-				align = Graphics::kTextAlignLeft;
+				align = kTextAlignLeft;
 			} else if (select == "\"center\"") {
-				align = Graphics::kTextAlignCenter;
+				align = kTextAlignCenter;
 			} else if (select == "\"right\"") {
-				align = Graphics::kTextAlignRight;
+				align = kTextAlignRight;
 			} else {
 				warning("Lingo::setTheField: Unknown text align spec: %s", d.asString(true).c_str());
 				break;
 			}
 
-			((Graphics::MacText *)member->_widget)->setAlignOffset(align);
-			((Graphics::MacText *)member->_widget)->draw();
+			((TextCastMember *)member)->_textAlign = align;
 			member->_modified = true;
 			break;
 		}
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index fce329da49..af799189d8 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -230,7 +230,7 @@ void Score::startPlay() {
 	// All frames in the same movie have the same number of channels
 	if (_playState != kPlayStopped)
 		for (uint i = 0; i < _frames[1]->_sprites.size(); i++)
-			_channels.push_back(new Channel(_frames[1]->_sprites[i]));
+			_channels.push_back(new Channel(_frames[1]->_sprites[i], i));
 
 	if (_vm->getVersion() >= 3)
 		_movie->processEvent(kEventStartMovie);
@@ -438,10 +438,14 @@ void Score::renderSprites(uint16 frameId, RenderMode mode) {
 		Sprite *currentSprite = channel->_sprite;
 		Sprite *nextSprite = _frames[frameId]->_sprites[i];
 
+		// widget content has changed and needs a redraw.
+		// this doesn't include changes in dimension or position!
+		bool widgetRedrawn = channel->updateWidget();
+
 		if (channel->isActiveText())
 			_movie->_currentEditableTextChannel = i;
 
-		if (channel->isDirty(nextSprite) || mode == kRenderForceUpdate) {
+		if (channel->isDirty(nextSprite) || widgetRedrawn || mode == kRenderForceUpdate) {
 			if (!currentSprite->_trails)
 				_stage->addDirtyRect(channel->getBbox());
 
diff --git a/engines/director/sprite.cpp b/engines/director/sprite.cpp
index 4dbbb839ff..a9e187b763 100644
--- a/engines/director/sprite.cpp
+++ b/engines/director/sprite.cpp
@@ -166,16 +166,13 @@ void Sprite::setCast(uint16 castId) {
 			// information set in the sprite.
 			warning("Sprite::setCast(): Working around D2/3 button glitch");
 
-			delete _cast->_widget;
 			_cast->_type = kCastButton;
 			((TextCastMember *)_cast)->_buttonType = (ButtonType)(_spriteType - 8);
-			((TextCastMember *)_cast)->createWidget();
 		}
 
-		if (_cast->_widget) {
-			_width = _cast->_widget->_dims.width();
-			_height = _cast->_widget->_dims.height();
-		}
+		Common::Rect dims = _cast->getWidgetRect();
+		_width = dims.width();
+		_height = dims.height();
 	} else {
 		warning("Sprite::setCast(): CastMember id %d has null member", castId);
 	}
diff --git a/graphics/macgui/macbutton.cpp b/graphics/macgui/macbutton.cpp
index a63431877b..92a5b558e4 100644
--- a/graphics/macgui/macbutton.cpp
+++ b/graphics/macgui/macbutton.cpp
@@ -38,24 +38,23 @@ MacButton::MacButton(MacButtonType buttonType, TextAlign textAlignment, MacWidge
 
 	_buttonType = buttonType;
 
-	int offset = 0;
 	switch (buttonType) {
 	case kCheckBox:
-		offset = 16;
+		_alignOffset.x += 16;
+		_dims.right += 16;
 		break;
 	case kRound:
-		offset = 4;
-		_dims.top -= 2;
-		_dims.bottom += 2;
+		_alignOffset.x += 2;
 		_alignOffset.y += 2;
+		_dims.right += 2;
+		_dims.bottom += 4;
 		break;
 	case kRadio:
-		offset = 16;
+		_alignOffset.x += 16;
+		_dims.right += 16;
 		break;
 	}
 
-	_alignOffset.x += offset;
-	_dims.right += offset;
 	_composeSurface->create(_dims.width(), _dims.height());
 	_composeSurface->clear(_bgcolor);
 }
diff --git a/graphics/macgui/mactext.cpp b/graphics/macgui/mactext.cpp
index a87aa32cc9..805336c51b 100644
--- a/graphics/macgui/mactext.cpp
+++ b/graphics/macgui/mactext.cpp
@@ -357,13 +357,6 @@ void MacText::splitString(const Common::U32String &str, int curLine) {
 
 	D(9, "** splitString(\"%s\")", toPrintable(str.encode()).c_str());
 
-	if (str.empty()) {
-		debug(9, "** splitString, empty line");
-		return;
-	}
-
-	Common::U32String paragraph, tmp;
-
 	if (_textLines.empty()) {
 		_textLines.resize(1);
 		_textLines[0].chunks.push_back(_defaultFormatting);
@@ -372,6 +365,13 @@ void MacText::splitString(const Common::U32String &str, int curLine) {
 		D(9, "** splitString, continuing, %d lines", _textLines.size());
 	}
 
+	if (str.empty()) {
+		debug(9, "** splitString, empty line");
+		return;
+	}
+
+	Common::U32String paragraph, tmp;
+
 	if (curLine == -1)
 		curLine = _textLines.size() - 1;
 
@@ -395,7 +395,7 @@ void MacText::splitString(const Common::U32String &str, int curLine) {
 			paragraph += *l++;
 		}
 
-		D(9, "** splitString, paragraph: \"%s\"", Common::toPrintable(line.encode()).c_str());
+		D(9, "** splitString, paragraph: \"%s\"", Common::toPrintable(paragraph.encode()).c_str());
 
 		// Now process whole paragraph
 		const Common::U32String::value_type *s = paragraph.c_str();
diff --git a/graphics/macgui/macwidget.cpp b/graphics/macgui/macwidget.cpp
index 9440b4541c..090948abe5 100644
--- a/graphics/macgui/macwidget.cpp
+++ b/graphics/macgui/macwidget.cpp
@@ -54,6 +54,9 @@ MacWidget::~MacWidget() {
 	if (_parent)
 		_parent->removeWidget(this, false);
 
+	if (_wm)
+		_wm->clearWidgetRefs(this);
+
 	if (_composeSurface) {
 		_composeSurface->free();
 		delete _composeSurface;
diff --git a/graphics/macgui/macwindowmanager.cpp b/graphics/macgui/macwindowmanager.cpp
index 9f1c3c029f..729235688a 100644
--- a/graphics/macgui/macwindowmanager.cpp
+++ b/graphics/macgui/macwindowmanager.cpp
@@ -228,6 +228,14 @@ void MacWindowManager::setActiveWidget(MacWidget *widget) {
 		_activeWidget->setActive(true);
 }
 
+void MacWindowManager::clearWidgetRefs(MacWidget *widget) {
+	if (widget == _hoveredWidget)
+		_hoveredWidget = nullptr;
+
+	if (widget == _activeWidget)
+		_activeWidget = nullptr;
+}
+
 MacWindow *MacWindowManager::addWindow(bool scrollable, bool resizable, bool editable) {
 	MacWindow *w = new MacWindow(_lastId, scrollable, resizable, editable, this);
 
diff --git a/graphics/macgui/macwindowmanager.h b/graphics/macgui/macwindowmanager.h
index 075221255c..e4b56aefca 100644
--- a/graphics/macgui/macwindowmanager.h
+++ b/graphics/macgui/macwindowmanager.h
@@ -252,6 +252,8 @@ public:
 
 	MacWidget *getActiveWidget() { return _activeWidget; }
 
+	void clearWidgetRefs(MacWidget *widget);
+
 	void pushCursor(MacCursorType type, Cursor *cursor = nullptr);
 	void replaceCursor(MacCursorType type, Cursor *cursor = nullptr);
 




More information about the Scummvm-git-logs mailing list