diff options
| author | Eugene Sandulenko | 2013-05-17 00:18:09 +0300 | 
|---|---|---|
| committer | Eugene Sandulenko | 2013-05-17 00:18:09 +0300 | 
| commit | f59512c47ea21c851535eeabf822aabdfde9167f (patch) | |
| tree | 19c58c54c897dde0188e28951f0827a20ef3c4a0 /gui | |
| parent | 4a62d6c25a4994a72c59ca3b8f2913ead565a173 (diff) | |
| download | scummvm-rg350-f59512c47ea21c851535eeabf822aabdfde9167f.tar.gz scummvm-rg350-f59512c47ea21c851535eeabf822aabdfde9167f.tar.bz2 scummvm-rg350-f59512c47ea21c851535eeabf822aabdfde9167f.zip  | |
RECORDER: Implement Events Recorder
Diffstat (limited to 'gui')
32 files changed, 3152 insertions, 498 deletions
diff --git a/gui/EventRecorder.cpp b/gui/EventRecorder.cpp new file mode 100644 index 0000000000..94b955cb22 --- /dev/null +++ b/gui/EventRecorder.cpp @@ -0,0 +1,699 @@ +/* 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 "gui/EventRecorder.h" + +namespace Common { +DECLARE_SINGLETON(GUI::EventRecorder); +} + +#ifdef ENABLE_EVENTRECORDER + +#include "common/debug-channels.h" +#include "backends/timer/sdl/sdl-timer.h" +#include "backends/mixer/sdl/sdl-mixer.h" +#include "common/config-manager.h" +#include "common/md5.h" +#include "gui/gui-manager.h" +#include "gui/widget.h" +#include "gui/onscreendialog.h" +#include "common/random.h" +#include "common/savefile.h" +#include "common/textconsole.h" +#include "graphics/thumbnail.h" +#include "graphics/surface.h" +#include "graphics/scaler.h" + +namespace GUI { + + +const int kMaxRecordsNames = 0x64; +const int kDefaultScreenshotPeriod = 60000; +const int kDefaultBPP = 2; + +uint32 readTime(Common::ReadStream *inFile) { +	uint32 d = inFile->readByte(); +	if (d == 0xff) { +		d = inFile->readUint32LE(); +	} + +	return d; +} + +void writeTime(Common::WriteStream *outFile, uint32 d) { +		//Simple RLE compression +	if (d >= 0xff) { +		outFile->writeByte(0xff); +		outFile->writeUint32LE(d); +	} else { +		outFile->writeByte(d); +	} +} + +EventRecorder::EventRecorder() { +	_timerManager = NULL; +	_recordMode = kPassthrough; +	_fakeMixerManager = NULL; +	_initialized = false; +	_needRedraw = false; +	_fastPlayback = false; +	DebugMan.addDebugChannel(kDebugLevelEventRec, "EventRec", "Event recorder debug level"); +} + +EventRecorder::~EventRecorder() { +	if (_timerManager != NULL) { +		delete _timerManager; +	} +} + +void EventRecorder::deinit() { +	if (!_initialized) { +		return; +	} +	setFileHeader(); +	_needRedraw = false; +	_initialized = false; +	_recordMode = kPassthrough; +	delete _fakeMixerManager; +	_fakeMixerManager = NULL; +	controlPanel->close(); +	delete controlPanel; +	debugC(1, kDebugLevelEventRec, "playback:action=stopplayback"); +	g_system->getEventManager()->getEventDispatcher()->unregisterSource(this); +	_recordMode = kPassthrough; +	_playbackFile->close(); +	delete _playbackFile; +	switchMixer(); +	switchTimerManagers(); +	DebugMan.disableDebugChannel("EventRec"); +} + +void EventRecorder::processMillis(uint32 &millis, bool skipRecord) { +	if (!_initialized) { +		return; +	} +	if (skipRecord) { +		millis = _fakeTimer; +		return; +	} +	if (_recordMode == kRecorderPlaybackPause) { +		millis = _fakeTimer; +	} +	uint32 millisDelay; +	Common::RecorderEvent timerEvent; +	switch (_recordMode) { +	case kRecorderRecord: +		updateSubsystems(); +		millisDelay = millis - _lastMillis; +		_lastMillis = millis; +		_fakeTimer += millisDelay; +		controlPanel->setReplayedTime(_fakeTimer); +		timerEvent.recordedtype = Common::kRecorderEventTypeTimer; +		timerEvent.time = _fakeTimer; +		_playbackFile->writeEvent(timerEvent); +		takeScreenshot(); +		_timerManager->handler(); +		break; +	case kRecorderPlayback: +		updateSubsystems(); +		if (_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) { +			_fakeTimer = _nextEvent.time; +			_nextEvent = _playbackFile->getNextEvent(); +			_timerManager->handler(); +		} else { +			if (_nextEvent.type == Common::EVENT_RTL) { +				error("playback:action=stopplayback"); +			} else { +				uint32 seconds = _fakeTimer / 1000; +				Common::String screenTime = Common::String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60); +				error("playback:action=error reason=\"synchronization error\" time = %s", screenTime.c_str()); +			} +		} +		millis = _fakeTimer; +		controlPanel->setReplayedTime(_fakeTimer); +		break; +	case kRecorderPlaybackPause: +		millis = _fakeTimer; +		break; +	default: +		break; +	} +} + +bool EventRecorder::processDelayMillis() { +	return _fastPlayback; +} + +void EventRecorder::checkForKeyCode(const Common::Event &event) { +	if ((event.type == Common::EVENT_KEYDOWN) && (event.kbd.flags & Common::KBD_CTRL) && (event.kbd.keycode == Common::KEYCODE_p) && (!event.synthetic)) { +		togglePause(); +	} +} + +bool EventRecorder::pollEvent(Common::Event &ev) { +	if ((_recordMode != kRecorderPlayback) || !_initialized) +		return false; +	 +	if ((_nextEvent.recordedtype == Common::kRecorderEventTypeTimer) || (_nextEvent.type ==  Common::EVENT_INVALID)) { +		return false; +	} + +	switch (_nextEvent.type) { +	case Common::EVENT_MOUSEMOVE: +	case Common::EVENT_LBUTTONDOWN: +	case Common::EVENT_LBUTTONUP: +	case Common::EVENT_RBUTTONDOWN: +	case Common::EVENT_RBUTTONUP: +	case Common::EVENT_WHEELUP: +	case Common::EVENT_WHEELDOWN: +		g_system->warpMouse(_nextEvent.mouse.x, _nextEvent.mouse.y); +		break; +	default: +		break; +	} +	ev = _nextEvent; +	_nextEvent = _playbackFile->getNextEvent(); +	return true; +} + +void EventRecorder::switchFastMode() { +	if (_recordMode == kRecorderPlaybackPause) { +		_fastPlayback = !_fastPlayback; +	} +} + +void EventRecorder::togglePause() { +	RecordMode oldState; +	switch (_recordMode) { +	case kRecorderPlayback: +	case kRecorderRecord: +		oldState = _recordMode; +		_recordMode = kRecorderPlaybackPause; +		controlPanel->runModal(); +		_recordMode = oldState; +		_initialized = true; +		break; +	case kRecorderPlaybackPause: +		controlPanel->close(); +		break; +	default: +		break; +	} +} + +void EventRecorder::RegisterEventSource() { +	g_system->getEventManager()->getEventDispatcher()->registerMapper(this, false); +} + +uint32 EventRecorder::getRandomSeed(const Common::String &name) { +	uint32 result = g_system->getMillis(); +	if (_recordMode == kRecorderRecord) { +		_playbackFile->getHeader().randomSourceRecords[name] = result; +	} else if (_recordMode == kRecorderPlayback) { +		result = _playbackFile->getHeader().randomSourceRecords[name]; +	} +	return result; +} + +Common::String EventRecorder::generateRecordFileName(const Common::String &target) { +	Common::String pattern(target+".r??"); +	Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern); +	for (int i = 0; i < kMaxRecordsNames; ++i) { +		Common::String recordName = Common::String::format("%s.r%02d", target.c_str(), i); +		if (find(files.begin(), files.end(), recordName) != files.end()) { +			continue; +		} +		return recordName; +	} +	return ""; +} + + +void EventRecorder::init(Common::String recordFileName, RecordMode mode) { +	_fakeMixerManager = new NullSdlMixerManager(); +	_fakeMixerManager->init(); +	_fakeMixerManager->suspendAudio(); +	_fakeTimer = 0; +	_lastMillis = g_system->getMillis(); +	_playbackFile = new Common::PlaybackFile(); +	_lastScreenshotTime = 0; +	_recordMode = mode; +	_needcontinueGame = false; +	if (ConfMan.hasKey("disable_display")) { +		DebugMan.enableDebugChannel("EventRec"); +		gDebugLevel = 1; +	} +	if (_recordMode == kRecorderPlayback) { +		debugC(1, kDebugLevelEventRec, "playback:action=\"Load file\" filename=%s", recordFileName.c_str()); +	} +	g_system->getEventManager()->getEventDispatcher()->registerSource(this, false); +	_screenshotPeriod = ConfMan.getInt("screenshot_period"); +	if (_screenshotPeriod == 0) { +		_screenshotPeriod = kDefaultScreenshotPeriod; +	} +	if (!openRecordFile(recordFileName)) { +		deinit(); +		error("playback:action=error reason=\"Record file loading error\""); +		return; +	} +	if (_recordMode != kPassthrough) { +		controlPanel = new GUI::OnScreenDialog(_recordMode == kRecorderRecord); +	} +	if (_recordMode == kRecorderPlayback) { +		applyPlaybackSettings(); +		_nextEvent = _playbackFile->getNextEvent(); +	} +	if (_recordMode == kRecorderRecord) { +		getConfig(); +	} + +	switchMixer(); +	switchTimerManagers(); +	_needRedraw = true; +	_initialized = true; +} + + +/** + * Opens or creates file depend of recording mode. + * + *@param id of recording or playing back game + *@return true in case of success, false in case of error + * + */ +bool EventRecorder::openRecordFile(const Common::String &fileName) { +	bool result; +	switch (_recordMode) { +	case kRecorderRecord: +		return _playbackFile->openWrite(fileName); +	case kRecorderPlayback: +		_recordMode = kPassthrough; +		result = _playbackFile->openRead(fileName); +		_recordMode = kRecorderPlayback; +		return result; +	default: +		return false; +	} +	return true; +} + +bool EventRecorder::checkGameHash(const ADGameDescription *gameDesc) { +	if ((gameDesc == NULL) && (_playbackFile->getHeader().hashRecords.size() != 0)) { +		warning("Engine doesn't contain description table"); +		return false; +	} +	for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) { +		if (_playbackFile->getHeader().hashRecords.find(fileDesc->fileName) == _playbackFile->getHeader().hashRecords.end()) { +			warning("MD5 hash for file %s not found in record file", fileDesc->fileName); +			debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=\"\" result=different", fileDesc->fileName, fileDesc->md5); +			return false; +		} +		if (_playbackFile->getHeader().hashRecords[fileDesc->fileName] != fileDesc->md5) { +			warning("Incorrect version of game file %s. Stored MD5 is %s. MD5 of loaded game is %s", fileDesc->fileName, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str(), fileDesc->md5); +			debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=%s result=different", fileDesc->fileName, fileDesc->md5, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str()); +			return false; +		} +		debugC(1, kDebugLevelEventRec, "playback:action=\"Check game hash\" filename=%s filehash=%s storedhash=%s result=equal", fileDesc->fileName, fileDesc->md5, _playbackFile->getHeader().hashRecords[fileDesc->fileName].c_str()); +	} +	return true; +} + +void EventRecorder::registerMixerManager(SdlMixerManager *mixerManager) { +	_realMixerManager = mixerManager; +} + +void EventRecorder::switchMixer() { +	if (_recordMode == kPassthrough) { +		_realMixerManager->resumeAudio(); +	} else { +		_realMixerManager->suspendAudio(); +		_fakeMixerManager->resumeAudio(); +	} +} + +SdlMixerManager *EventRecorder::getMixerManager() { +	if (_recordMode == kPassthrough) { +		return _realMixerManager; +	} else { +		return _fakeMixerManager; +	} +} + +void EventRecorder::getConfigFromDomain(Common::ConfigManager::Domain *domain) { +	for (Common::ConfigManager::Domain::iterator entry = domain->begin(); entry!= domain->end(); ++entry) { +		_playbackFile->getHeader().settingsRecords[entry->_key] = entry->_value; +	} +} + +void EventRecorder::getConfig() { +	getConfigFromDomain(ConfMan.getDomain(ConfMan.kApplicationDomain)); +	getConfigFromDomain(ConfMan.getActiveDomain()); +	_playbackFile->getHeader().settingsRecords["save_slot"] = ConfMan.get("save_slot"); +} + + +void EventRecorder::applyPlaybackSettings() { +	for (Common::StringMap::iterator i = _playbackFile->getHeader().settingsRecords.begin(); i != _playbackFile->getHeader().settingsRecords.end(); ++i) { +		Common::String currentValue = ConfMan.get(i->_key); +		if (currentValue != i->_value) { +			ConfMan.set(i->_key, i->_value, ConfMan.kTransientDomain); +			debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" key=%s storedvalue=%s currentvalue=%s result=different", i->_key.c_str(), i->_value.c_str(), currentValue.c_str()); +		} else { +			debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" key=%s storedvalue=%s currentvalue=%s result=equal", i->_key.c_str(), i->_value.c_str(), currentValue.c_str()); +		} +	} +	removeDifferentEntriesInDomain(ConfMan.getDomain(ConfMan.kApplicationDomain)); +	removeDifferentEntriesInDomain(ConfMan.getActiveDomain()); +} + +void EventRecorder::removeDifferentEntriesInDomain(Common::ConfigManager::Domain *domain) { +	for (Common::ConfigManager::Domain::iterator entry = domain->begin(); entry!= domain->end(); ++entry) { +		if (_playbackFile->getHeader().settingsRecords.find(entry->_key) == _playbackFile->getHeader().settingsRecords.end()) { +			debugC(1, kDebugLevelEventRec, "playback:action=\"Apply settings\" checksettings:key=%s storedvalue=%s currentvalue="" result=different", entry->_key.c_str(), entry->_value.c_str()); +			domain->erase(entry->_key); +		} +	} +} + +DefaultTimerManager *EventRecorder::getTimerManager() { +	return _timerManager; +} + +void EventRecorder::registerTimerManager(DefaultTimerManager *timerManager) { +	_timerManager = timerManager; +} + +void EventRecorder::switchTimerManagers() { +	delete _timerManager; +	if (_recordMode == kPassthrough) { +		_timerManager = new SdlTimerManager(); +	} else { +		_timerManager = new DefaultTimerManager(); +	} +} + +void EventRecorder::updateSubsystems() { +	if (_recordMode == kPassthrough) { +		return; +	} +	RecordMode oldRecordMode = _recordMode; +	_recordMode = kPassthrough; +	_fakeMixerManager->update(); +	_recordMode = oldRecordMode; +} + +Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Common::EventSource *source) { +	if ((!_initialized) && (_recordMode != kRecorderPlaybackPause)) { +		return DefaultEventMapper::mapEvent(ev, source); +	} + +	checkForKeyCode(ev); +	Common::Event evt = ev; +	evt.mouse.x = evt.mouse.x * (g_system->getOverlayWidth() / g_system->getWidth()); +	evt.mouse.y = evt.mouse.y * (g_system->getOverlayHeight() / g_system->getHeight()); +	switch (_recordMode) { +	case kRecorderPlayback: +		if (ev.synthetic != true) { +			return Common::List<Common::Event>(); +		} +		return Common::DefaultEventMapper::mapEvent(ev, source); +		break; +	case kRecorderRecord: +		g_gui.processEvent(evt, controlPanel); +		if (((evt.type == Common::EVENT_LBUTTONDOWN) || (evt.type == Common::EVENT_LBUTTONUP) || (evt.type == Common::EVENT_MOUSEMOVE)) && controlPanel->isMouseOver()) { +			return Common::List<Common::Event>(); +		} else { +			Common::RecorderEvent e; +			memcpy(&e, &ev, sizeof(ev)); +			e.recordedtype = Common::kRecorderEventTypeNormal; +			e.time = _fakeTimer; +			_playbackFile->writeEvent(e); +			return DefaultEventMapper::mapEvent(ev, source); +		} +		break; +	case kRecorderPlaybackPause: { +		Common::Event dialogEvent; +		if (controlPanel->isEditDlgVisible()) { +			dialogEvent = ev; +		} else { +			dialogEvent = evt; +		} +		g_gui.processEvent(dialogEvent, controlPanel->getActiveDlg()); +		if (((dialogEvent.type == Common::EVENT_LBUTTONDOWN) || (dialogEvent.type == Common::EVENT_LBUTTONUP) || (dialogEvent.type == Common::EVENT_MOUSEMOVE)) && controlPanel->isMouseOver()) { +			return Common::List<Common::Event>(); +		} +		return Common::DefaultEventMapper::mapEvent(dialogEvent, source); +	} +		break; +	default: +		return Common::DefaultEventMapper::mapEvent(ev, source); +	} +} + +void EventRecorder::setGameMd5(const ADGameDescription *gameDesc) { +	for (const ADGameFileDescription *fileDesc = gameDesc->filesDescriptions; fileDesc->fileName; fileDesc++) { +		if (fileDesc->md5 != NULL) { +			_playbackFile->getHeader().hashRecords[fileDesc->fileName] = fileDesc->md5; +		} +	} +} + +void EventRecorder::processGameDescription(const ADGameDescription *desc) { +	if (_recordMode == kRecorderRecord) { +		setGameMd5(desc); +	} +	if ((_recordMode == kRecorderPlayback) && !checkGameHash(desc)) { +		deinit(); +		error("playback:action=error reason=\"\""); +	} +} + +void EventRecorder::deleteRecord(const Common::String& fileName) { +	g_system->getSavefileManager()->removeSavefile(fileName); +} + +void EventRecorder::takeScreenshot() { +	if ((_fakeTimer - _lastScreenshotTime) > _screenshotPeriod) { +		Graphics::Surface screen; +		uint8 md5[16]; +		if (grabScreenAndComputeMD5(screen, md5)) { +			_lastScreenshotTime = _fakeTimer; +			_playbackFile->saveScreenShot(screen, md5); +			screen.free(); +		} +	} +} + +bool EventRecorder::grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]) { +	if (!createScreenShot(screen)) { +		warning("Can't save screenshot"); +		return false; +	} +	Common::MemoryReadStream bitmapStream((const byte*)screen.pixels, screen.w * screen.h * screen.format.bytesPerPixel); +	computeStreamMD5(bitmapStream, md5); +	return true; +} + +Common::SeekableReadStream *EventRecorder::processSaveStream(const Common::String &fileName) { +	Common::InSaveFile *saveFile; +	switch (_recordMode) { +	case kRecorderPlayback: +		debugC(1, kDebugLevelEventRec, "playback:action=\"Process save file\" filename=%s len=%d", fileName.c_str(), _playbackFile->getHeader().saveFiles[fileName].size); +		return new Common::MemoryReadStream(_playbackFile->getHeader().saveFiles[fileName].buffer, _playbackFile->getHeader().saveFiles[fileName].size); +	case kRecorderRecord: +		saveFile = _realSaveManager->openForLoading(fileName); +		if (saveFile != NULL) { +			_playbackFile->addSaveFile(fileName, saveFile); +			saveFile->seek(0); +		} +		return saveFile; +	default: +		return NULL; +		break; +	} +} + +Common::SaveFileManager *EventRecorder::getSaveManager(Common::SaveFileManager *realSaveManager) { +	_realSaveManager = realSaveManager; +	if (_recordMode != kPassthrough) { +		return &_fakeSaveManager; +	} else { +		return realSaveManager; +	} +} + +void EventRecorder::preDrawOverlayGui() { +    if ((_initialized) || (_needRedraw)) { +		RecordMode oldMode = _recordMode; +		_recordMode = kPassthrough; +		g_system->showOverlay(); +		g_gui.theme()->clearAll(); +		g_gui.theme()->openDialog(true, GUI::ThemeEngine::kShadingNone); +		controlPanel->drawDialog(); +		g_gui.theme()->finishBuffering(); +		g_gui.theme()->updateScreen(); +		_recordMode = oldMode; +   } +} + +void EventRecorder::postDrawOverlayGui() { +    if ((_initialized) || (_needRedraw)) { +		RecordMode oldMode = _recordMode; +		_recordMode = kPassthrough; +	    g_system->hideOverlay(); +		_recordMode = oldMode; +	} +} + +Common::StringArray EventRecorder::listSaveFiles(const Common::String &pattern) { +	if (_recordMode == kRecorderPlayback) { +		Common::StringArray result; +		for (Common::HashMap<Common::String, Common::PlaybackFile::SaveFileBuffer>::iterator  i = _playbackFile->getHeader().saveFiles.begin(); i != _playbackFile->getHeader().saveFiles.end(); ++i) { +			if (i->_key.matchString(pattern, false, true)) { +				result.push_back(i->_key); +			} +		} +		return result; +	} else { +		return _realSaveManager->listSavefiles(pattern); +	} +} + +void EventRecorder::setFileHeader() { +	if (_recordMode != kRecorderRecord) { +		return; +	} +	TimeDate t; +	const EnginePlugin *plugin = 0; +	GameDescriptor desc = EngineMan.findGame(ConfMan.getActiveDomainName(), &plugin); +	g_system->getTimeAndDate(t); +	if (_author.empty()) { +		setAuthor("Unknown Author"); +	} +	if (_name.empty()) { +		g_eventRec.setName(Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description()); +	} +	_playbackFile->getHeader().author = _author; +	_playbackFile->getHeader().notes = _desc; +	_playbackFile->getHeader().name = _name; +} + +SDL_Surface *EventRecorder::getSurface(int width, int height) { +	SDL_Surface *surface = new SDL_Surface(); +	surface->format = new SDL_PixelFormat(); +	surface->flags = 0; +	surface->format->palette = NULL; +	surface->format->BitsPerPixel = 16; +	surface->format->BytesPerPixel = 2; +	surface->format->Rloss = 3; +	surface->format->Gloss = 2; +	surface->format->Bloss = 3; +	surface->format->Aloss = 8; +	surface->format->Rshift = 11; +	surface->format->Gshift = 5; +	surface->format->Bshift = 0; +	surface->format->Ashift = 0; +	surface->format->Rmask = 63488; +	surface->format->Gmask = 2016; +	surface->format->Bmask = 31; +	surface->format->Amask = 0; +	surface->format->colorkey = 0; +	surface->format->alpha = 255; +	surface->w = width; +	surface->h = height; +	surface->pitch = width * 2; +	surface->pixels = (char *)malloc(surface->pitch * surface->h); +	surface->offset = 0; +	surface->hwdata = NULL; +	surface->clip_rect.x = 0; +	surface->clip_rect.y = 0; +	surface->clip_rect.w = width; +	surface->clip_rect.h = height; +	surface->unused1 = 0; +	surface->locked = 0; +	surface->map = NULL; +	surface->format_version = 4; +	surface->refcount = 1; +	return surface; +} + +bool EventRecorder::switchMode() { +	const Common::String gameId = ConfMan.get("gameid"); +	const EnginePlugin *plugin = 0; +	EngineMan.findGame(gameId, &plugin); +	bool metaInfoSupport = (*plugin)->hasFeature(MetaEngine::kSavesSupportMetaInfo); +	bool featuresSupport = metaInfoSupport && +						  g_engine->canSaveGameStateCurrently() && +						  (*plugin)->hasFeature(MetaEngine::kSupportsListSaves) && +						  (*plugin)->hasFeature(MetaEngine::kSupportsDeleteSave); +	if (!featuresSupport) { +		return false; +	} + +	int emptySlot = 1; +	SaveStateList saveList = (*plugin)->listSaves(gameId.c_str()); +	for (SaveStateList::const_iterator x = saveList.begin(); x != saveList.end(); ++x) { +		int saveSlot = x->getSaveSlot(); +		if (saveSlot == 0) { +			continue; +		} +		if (emptySlot != saveSlot) { +			break; +		} +		emptySlot++; +	} +	Common::String saveName; +	if (emptySlot >= 0) { +		saveName = Common::String::format("Save %d", emptySlot + 1); +		Common::Error status = g_engine->saveGameState(emptySlot, saveName); +		if (status.getCode() == Common::kNoError) { +			Common::Event eventRTL; +			eventRTL.type = Common::EVENT_RTL; +			g_system->getEventManager()->pushEvent(eventRTL); +		} +	} +	ConfMan.set("record_mode", "", Common::ConfigManager::kTransientDomain); +	ConfMan.setInt("save_slot", emptySlot, Common::ConfigManager::kTransientDomain); +	_needcontinueGame = true; +	return true; +} + +bool EventRecorder::checkForContinueGame() { +	bool result = _needcontinueGame; +	_needcontinueGame = false; +	return result; +} + +void EventRecorder::deleteTemporarySave() { +	if (_temporarySlot == -1) return; +	const Common::String gameId = ConfMan.get("gameid"); +	const EnginePlugin *plugin = 0; +	EngineMan.findGame(gameId, &plugin); +	 (*plugin)->removeSaveState(gameId.c_str(), _temporarySlot); +	_temporarySlot = -1; +} + +} // End of namespace GUI + +#endif // ENABLE_EVENTRECORDER + diff --git a/gui/EventRecorder.h b/gui/EventRecorder.h new file mode 100644 index 0000000000..3e32d89232 --- /dev/null +++ b/gui/EventRecorder.h @@ -0,0 +1,293 @@ +/* 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 GUI_EVENTRECORDER_H +#define GUI_EVENTRECORDER_H + +#include "common/system.h" + +#include "common/events.h" +#include "common/savefile.h" +#include "common/singleton.h" + +#include "engines/advancedDetector.h" + +#ifdef ENABLE_EVENTRECORDER + +#include "common/mutex.h" +#include "common/array.h" +#include "common/memstream.h" +#include "backends/keymapper/keymapper.h" +#include "backends/mixer/sdl/sdl-mixer.h" +#include "common/hashmap.h" +#include "common/hash-str.h" +#include "backends/timer/sdl/sdl-timer.h" +#include "common/config-manager.h" +#include "common/recorderfile.h" +#include "backends/saves/recorder/recorder-saves.h" +#include "backends/mixer/nullmixer/nullsdl-mixer.h" +#include "backends/saves/default/default-saves.h" + + +#define g_eventRec (GUI::EventRecorder::instance()) + +namespace GUI { +	class OnScreenDialog; +} + +namespace GUI { +class RandomSource; +class SeekableReadStream; +class WriteStream; + + +/** + * Our generic event recorder. + * + * TODO: Add more documentation. + */ +class EventRecorder : private Common::EventSource, public Common::Singleton<EventRecorder>, private Common::DefaultEventMapper { +	friend class Common::Singleton<SingletonBaseType>; +	EventRecorder(); +	~EventRecorder(); +public: +	/** Specify operation mode of Event Recorder */ +	enum RecordMode { +		kPassthrough = 0,		/**< kPassthrough, do nothing */ +		kRecorderRecord = 1,		/**< kRecorderRecord, do the recording */ +		kRecorderPlayback = 2,		/**< kRecorderPlayback, playback existing recording */ +		kRecorderPlaybackPause = 3	/**< kRecordetPlaybackPause, interal state when user pauses the playback */ +	}; + +	void init(Common::String recordFileName, RecordMode mode); +	void deinit(); +	bool processDelayMillis(); +	uint32 getRandomSeed(const Common::String &name); +	void processMillis(uint32 &millis, bool skipRecord); +	bool processAudio(uint32 &samples, bool paused); +	void processGameDescription(const ADGameDescription *desc); +	Common::SeekableReadStream *processSaveStream(const Common::String & fileName); + +	/** Hooks for intercepting into GUI processing, so required events could be shoot +	 *  or filtered out */ +	void preDrawOverlayGui(); +	void postDrawOverlayGui(); + +	/** Set recording author +	 * +	 *  @see getAuthor +	 */ +	void setAuthor(const Common::String &author) { +		_author = author; +	} + +	/** Set recording notes +	 * +	 *  @see getNotes +	 */ +	void setNotes(const Common::String &desc){ +		_desc = desc; +	} + +	/** Set descriptive name of the recording +	 * +	 *  @see getName +	 */ +	void setName(const Common::String &name) { +		_name = name; +	} + +	/** Get recording author +	 * +	 *  @see getAuthor +	 */ +	const Common::String getAuthor() { +		return _author; +	} + +	/** Get recording notes +	 * +	 *  @see setNotes +	 */ +	const Common::String getNotes() { +		return _desc; +	} + +	/** Get recording name +	 * +	 *  @see setName +	 */ +	const Common::String getName() { +		return _name; +	} +	void setRedraw(bool redraw) { +		_needRedraw = redraw; +	} + +	void registerMixerManager(SdlMixerManager *mixerManager); +	void registerTimerManager(DefaultTimerManager *timerManager); + +	SdlMixerManager *getMixerManager(); +	DefaultTimerManager *getTimerManager(); + +	void deleteRecord(const Common::String& fileName); +	bool checkForContinueGame(); + +	void suspendRecording() { +		_savedState = _initialized; +		_initialized = false; +	} + +	void resumeRecording() { +		_initialized = _savedState; +	} + +	Common::StringArray listSaveFiles(const Common::String &pattern); +	Common::String generateRecordFileName(const Common::String &target); + +	Common::SaveFileManager *getSaveManager(Common::SaveFileManager *realSaveManager); +	SDL_Surface *getSurface(int width, int height); +	void RegisterEventSource(); + +	/** Retrieve game screenshot and compute its checksum for comparison */ +	bool grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]); + +	void updateSubsystems(); +	bool switchMode(); +	void switchFastMode(); + +private: +	virtual Common::List<Common::Event> mapEvent(const Common::Event &ev, Common::EventSource *source); +	bool notifyPoll(); +	bool pollEvent(Common::Event &ev); +	bool _initialized; +	volatile uint32 _fakeTimer; +	bool _savedState; +	bool _needcontinueGame; +	int _temporarySlot; +	Common::String _author; +	Common::String _desc; +	Common::String _name; + +	Common::SaveFileManager *_realSaveManager; +	SdlMixerManager *_realMixerManager; +	DefaultTimerManager *_timerManager; +	RecorderSaveFileManager _fakeSaveManager; +	NullSdlMixerManager *_fakeMixerManager; +	GUI::OnScreenDialog *controlPanel; +	Common::RecorderEvent _nextEvent; + +	void setFileHeader(); +	void setGameMd5(const ADGameDescription *gameDesc); +	void getConfig(); +	void getConfigFromDomain(Common::ConfigManager::Domain *domain); +	void removeDifferentEntriesInDomain(Common::ConfigManager::Domain *domain); +	void applyPlaybackSettings(); + +	void switchMixer(); +	void switchTimerManagers(); + +	void togglePause(); + +	void takeScreenshot(); + +	bool openRecordFile(const Common::String &fileName); + +	bool checkGameHash(const ADGameDescription *desc); + +	void checkForKeyCode(const Common::Event &event); +	bool allowMapping() const { return false; } + +	volatile uint32 _lastMillis; +	uint32 _lastScreenshotTime; +	uint32 _screenshotPeriod; +	Common::PlaybackFile *_playbackFile; + +	void saveScreenShot(); +	void checkRecordedMD5(); +	void deleteTemporarySave(); +	volatile RecordMode _recordMode; +	Common::String _recordFileName; +	bool _fastPlayback; +	bool _needRedraw; +}; + +} // End of namespace GUI + +#else + +#ifdef SDL_BACKEND +#include "backends/timer/default/default-timer.h" +#include "backends/mixer/sdl/sdl-mixer.h" +#endif + +#define g_eventRec (GUI::EventRecorder::instance()) + +namespace GUI { + +class EventRecorder : private Common::EventSource, public Common::Singleton<EventRecorder>, private Common::DefaultEventMapper { +	friend class Common::Singleton<SingletonBaseType>; + +  public: +	EventRecorder() { +#ifdef SDL_BACKEND +	  _timerManager = NULL; +	  _realMixerManager = NULL; +#endif +	} +	~EventRecorder() {} + +	bool pollEvent(Common::Event &ev) { return false; } +	void RegisterEventSource() {} +	void deinit() {} +	void suspendRecording() {} +	void resumeRecording() {} +	void preDrawOverlayGui() {} +	void postDrawOverlayGui() {} +	void processGameDescription(const ADGameDescription *desc) {} +	void updateSubsystems() {} +	uint32 getRandomSeed(const Common::String &name) { return g_system->getMillis(); } +	Common::SaveFileManager *getSaveManager(Common::SaveFileManager *realSaveManager) { return realSaveManager; } + +#ifdef SDL_BACKEND +  private: +	DefaultTimerManager *_timerManager; +	SdlMixerManager *_realMixerManager; + +  public: +	DefaultTimerManager *getTimerManager() { return _timerManager; } +	void registerTimerManager(DefaultTimerManager *timerManager) { _timerManager = timerManager; } + +	SdlMixerManager *getMixerManager() { return _realMixerManager; } +	void registerMixerManager(SdlMixerManager *mixerManager) { _realMixerManager = mixerManager; } + +	void processMillis(uint32 &millis, bool skipRecord) {} +	bool processDelayMillis() { return false; } +#endif + +}; + +} // namespace GUI + +#endif // ENABLE_EVENTRECORDER + +#endif diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index e2fa2580f5..3ce043cb39 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -50,6 +50,14 @@ const char * const ThemeEngine::kImageEraser = "eraser.bmp";  const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp";  const char * const ThemeEngine::kImageList = "list.bmp";  const char * const ThemeEngine::kImageGrid = "grid.bmp"; +const char * const ThemeEngine::kImageStopbtn = "stopbtn.bmp"; +const char * const ThemeEngine::kImageEditbtn = "editbtn.bmp"; +const char * const ThemeEngine::kImageSwitchModebtn = "switchbtn.bmp"; +const char * const ThemeEngine::kImageFastReplaybtn = "fastreplay.bmp"; +const char * const ThemeEngine::kImageStopSmallbtn = "stopbtn_small.bmp"; +const char * const ThemeEngine::kImageEditSmallbtn = "editbtn_small.bmp"; +const char * const ThemeEngine::kImageSwitchModeSmallbtn = "switchbtn_small.bmp"; +const char * const ThemeEngine::kImageFastReplaySmallbtn = "fastreplay_small.bmp";  struct TextDrawData {  	const Graphics::Font *_fontPtr; @@ -465,11 +473,7 @@ void ThemeEngine::enable() {  	if (_enabled)  		return; -	if (_useCursor) { -		CursorMan.pushCursorPalette(_cursorPal, 0, _cursorPalSize); -		CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true); -		CursorMan.showMouse(true); -	} +	showCursor();  	_system->showOverlay();  	clearAll(); @@ -482,10 +486,8 @@ void ThemeEngine::disable() {  	_system->hideOverlay(); -	if (_useCursor) { -		CursorMan.popCursorPalette(); -		CursorMan.popCursor(); -	} +	hideCursor(); +  	_enabled = false;  } @@ -1787,5 +1789,20 @@ Common::String ThemeEngine::getThemeId(const Common::String &filename) {  	}  } +void ThemeEngine::showCursor() { +	if (_useCursor) { +		CursorMan.pushCursorPalette(_cursorPal, 0, _cursorPalSize); +		CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true); +		CursorMan.showMouse(true); +	} +} + +void ThemeEngine::hideCursor() { +	if (_useCursor) { +		CursorMan.popCursorPalette(); +		CursorMan.popCursor(); +	} +} +  } // End of namespace GUI. diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 6e5fd291b7..160ceb3259 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -234,6 +234,14 @@ public:  	static const char *const kImageDelbtn; ///< Delete characters in the predictive dialog  	static const char *const kImageList;      ///< List image used in save/load chooser selection  	static const char *const kImageGrid;      ///< Grid image used in save/load chooser selection +	static const char *const kImageStopbtn; ///< Stop recording button in recorder onscreen dialog +	static const char *const kImageEditbtn; ///< Edit recording metadata in recorder onscreen dialog +	static const char *const kImageSwitchModebtn; ///< Switch mode button in recorder onscreen dialog +	static const char *const kImageFastReplaybtn; ///< Fast playback mode button in recorder onscreen dialog +	static const char *const kImageStopSmallbtn; ///< Stop recording button in recorder onscreen dialog (for 320xY) +	static const char *const kImageEditSmallbtn; ///< Edit recording metadata in recorder onscreen dialog (for 320xY) +	static const char *const kImageSwitchModeSmallbtn; ///< Switch mode button in recorder onscreen dialog (for 320xY) +	static const char *const kImageFastReplaySmallbtn; ///< Fast playback mode button in recorder onscreen dialog (for 320xY)  	/**  	 * Graphics mode enumeration. @@ -275,8 +283,13 @@ public:  	void refresh();  	void enable(); + +	void showCursor(); +	void hideCursor(); +  	void disable(); +  	/**  	 * Query the set up pixel format.  	 */ diff --git a/gui/dialog.h b/gui/dialog.h index 1773c6633e..d269a2f645 100644 --- a/gui/dialog.h +++ b/gui/dialog.h @@ -37,6 +37,8 @@ struct Event;  namespace GUI { +class EventRecorder; +  class Widget;  // Some "common" commands sent to handleCommand() @@ -47,6 +49,7 @@ enum {  class Dialog : public GuiObject {  	friend class GuiManager; +	friend class EventRecorder;  	friend class Tooltip;  protected:  	Widget	*_mouseWidget; diff --git a/gui/editrecorddialog.cpp b/gui/editrecorddialog.cpp new file mode 100644 index 0000000000..a6a7a2560e --- /dev/null +++ b/gui/editrecorddialog.cpp @@ -0,0 +1,87 @@ +/* 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 "editrecorddialog.h" +#include "gui/widgets/edittext.h" +#include "common/translation.h" + + +namespace GUI { + +const Common::String EditRecordDialog::getAuthor() { +	return _authorEdit->getEditString(); +} + +void EditRecordDialog::setAuthor(const Common::String &author) { +	_authorEdit->setEditString(author); +} + +const Common::String EditRecordDialog::getNotes() { +	return _notesEdit->getEditString(); +}  + +void EditRecordDialog::setNotes(const Common::String &desc) { +	_notesEdit->setEditString(desc); +} + +const Common::String EditRecordDialog::getName() { +	return _nameEdit->getEditString(); +} + +void EditRecordDialog::setName(const Common::String &name) { +	_nameEdit->setEditString(name); +} + +EditRecordDialog::~EditRecordDialog() { +} + +EditRecordDialog::EditRecordDialog(const Common::String author, const Common::String name, const Common::String notes) : Dialog("EditRecordDialog") { +	new StaticTextWidget(this,"EditRecordDialog.AuthorLabel",_("Author:")); +	new StaticTextWidget(this,"EditRecordDialog.NameLabel",_("Name:")); +	new StaticTextWidget(this,"EditRecordDialog.NotesLabel",_("Notes:")); +	_authorEdit = new EditTextWidget(this, "EditRecordDialog.AuthorEdit",""); +	_notesEdit = new EditTextWidget(this, "EditRecordDialog.NotesEdit",""); +	_nameEdit = new EditTextWidget(this, "EditRecordDialog.NameEdit",""); +	_authorEdit->setEditString(author); +	_notesEdit->setEditString(notes); +	_nameEdit->setEditString(name); +	new GUI::ButtonWidget(this, "EditRecordDialog.Cancel", _("Cancel"), 0, kCloseCmd); +	new GUI::ButtonWidget(this, "EditRecordDialog.OK", _("Ok"), 0, kOKCmd); +} + +void EditRecordDialog::handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) { +	switch(cmd) { +	case kCloseCmd: +		setResult(kCloseCmd); +		close(); +		break; +	case kOKCmd: +		setResult(kOKCmd); +		close(); +		break; +	default: +		Dialog::handleCommand(sender, cmd, data); +		break; +	} +} + +} diff --git a/gui/editrecorddialog.h b/gui/editrecorddialog.h new file mode 100644 index 0000000000..c8da4521ca --- /dev/null +++ b/gui/editrecorddialog.h @@ -0,0 +1,56 @@ +/* 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 GUI_EDITRECORDDIALOG_H +#define GUI_EDITRECORDDIALOG_H + +#include "gui/dialog.h" + +namespace GUI { + +class EditTextWidget; +class StaticTextWidget; + +class EditRecordDialog : public Dialog { +private: +	EditTextWidget *_notesEdit; +	EditTextWidget *_nameEdit; +	EditTextWidget *_authorEdit; +	EditRecordDialog() : Dialog("EditRecordDialog") {}; +public: +	EditRecordDialog(const Common::String author, const Common::String name, const Common::String notes); +	~EditRecordDialog(); + +	const Common::String getAuthor(); +	const Common::String getNotes(); +	const Common::String getName(); + +	void setAuthor(const Common::String &author); +	void setNotes(const Common::String &desc); +	void setName(const Common::String &name); + +	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); +}; + +}// End of namespace GUI + +#endif diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp index a0ef4216aa..78b40a46ce 100644 --- a/gui/gui-manager.cpp +++ b/gui/gui-manager.cpp @@ -27,6 +27,7 @@  #include "common/rect.h"  #include "common/textconsole.h"  #include "common/translation.h" +#include "gui/EventRecorder.h"  #include "backends/keymapper/keymapper.h" @@ -253,12 +254,13 @@ Dialog *GuiManager::getTopDialog() const {  void GuiManager::runLoop() {  	Dialog * const activeDialog = getTopDialog();  	bool didSaveState = false; -	int button; -	uint32 time;  	if (activeDialog == 0)  		return; +	// Suspend recording while GUI is shown +	g_eventRec.suspendRecording(); +  	if (!_stateIsSaved) {  		saveState();  		_theme->enable(); @@ -296,10 +298,10 @@ void GuiManager::runLoop() {  //		_theme->updateScreen();  //		_system->updateScreen(); -		if (lastRedraw + waitTime < _system->getMillis()) { +		if (lastRedraw + waitTime < _system->getMillis(true)) {  			_theme->updateScreen();  			_system->updateScreen(); -			lastRedraw = _system->getMillis(); +			lastRedraw = _system->getMillis(true);  		}  		Common::Event event; @@ -314,72 +316,21 @@ void GuiManager::runLoop() {  			if (activeDialog != getTopDialog() && event.type != Common::EVENT_SCREEN_CHANGED)  				continue; -			Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); - -			switch (event.type) { -			case Common::EVENT_KEYDOWN: -				activeDialog->handleKeyDown(event.kbd); -				break; -			case Common::EVENT_KEYUP: -				activeDialog->handleKeyUp(event.kbd); -				break; -			case Common::EVENT_MOUSEMOVE: -				activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); - -				if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) { -					_lastMousePosition.x = mouse.x; -					_lastMousePosition.y = mouse.y; -					_lastMousePosition.time = _system->getMillis(); -				} +			processEvent(event, activeDialog); +			if (event.type == Common::EVENT_MOUSEMOVE) {  				tooltipCheck = true; -				break; -			// We don't distinguish between mousebuttons (for now at least) -			case Common::EVENT_LBUTTONDOWN: -			case Common::EVENT_RBUTTONDOWN: -				button = (event.type == Common::EVENT_LBUTTONDOWN ? 1 : 2); -				time = _system->getMillis(); -				if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) -							&& ABS(_lastClick.x - event.mouse.x) < 3 -							&& ABS(_lastClick.y - event.mouse.y) < 3) { -					_lastClick.count++; -				} else { -					_lastClick.x = event.mouse.x; -					_lastClick.y = event.mouse.y; -					_lastClick.count = 1; -				} -				_lastClick.time = time; -				activeDialog->handleMouseDown(mouse.x, mouse.y, button, _lastClick.count); -				break; -			case Common::EVENT_LBUTTONUP: -			case Common::EVENT_RBUTTONUP: -				button = (event.type == Common::EVENT_LBUTTONUP ? 1 : 2); -				activeDialog->handleMouseUp(mouse.x, mouse.y, button, _lastClick.count); -				break; -			case Common::EVENT_WHEELUP: -				activeDialog->handleMouseWheel(mouse.x, mouse.y, -1); -				break; -			case Common::EVENT_WHEELDOWN: -				activeDialog->handleMouseWheel(mouse.x, mouse.y, 1); -				break; -			case Common::EVENT_SCREEN_CHANGED: -				screenChange(); -				break; -			default: -#ifdef ENABLE_KEYMAPPER -				activeDialog->handleOtherEvent(event); -#endif -				break;  			} -			if (lastRedraw + waitTime < _system->getMillis()) { + +			if (lastRedraw + waitTime < _system->getMillis(true)) {  				_theme->updateScreen();  				_system->updateScreen(); -				lastRedraw = _system->getMillis(); +				lastRedraw = _system->getMillis(true);  			}  		} -		if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) { +		if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis(true)) {  			Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y);  			if (wdg && wdg->hasTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) {  				Tooltip *tooltip = new Tooltip(); @@ -409,6 +360,9 @@ void GuiManager::runLoop() {  		restoreState();  		_useStdCursor = false;  	} + +	// Resume recording once GUI is shown +	g_eventRec.resumeRecording();  }  #pragma mark - @@ -492,7 +446,7 @@ void GuiManager::setupCursor() {  // very much. We could plug in a different cursor here if we like to.  void GuiManager::animateCursor() { -	int time = _system->getMillis(); +	int time = _system->getMillis(true);  	if (time > _cursorAnimateTimer + kCursorAnimateDelay) {  		for (int i = 0; i < 15; i++) {  			if ((i < 6) || (i > 8)) { @@ -537,4 +491,64 @@ void GuiManager::screenChange() {  	_system->updateScreen();  } +void GuiManager::processEvent(const Common::Event &event, Dialog *const activeDialog) { +	int button; +	uint32 time; +	Common::Point mouse(event.mouse.x - activeDialog->_x, event.mouse.y - activeDialog->_y); +	switch (event.type) { +	case Common::EVENT_KEYDOWN: +		activeDialog->handleKeyDown(event.kbd); +		break; +	case Common::EVENT_KEYUP: +		activeDialog->handleKeyUp(event.kbd); +		break; +	case Common::EVENT_MOUSEMOVE: +		activeDialog->handleMouseMoved(mouse.x, mouse.y, 0); + +		if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) { +			_lastMousePosition.x = mouse.x; +			_lastMousePosition.y = mouse.y; +			_lastMousePosition.time = _system->getMillis(true); +		} + +		break; +		// We don't distinguish between mousebuttons (for now at least) +	case Common::EVENT_LBUTTONDOWN: +	case Common::EVENT_RBUTTONDOWN: +		button = (event.type == Common::EVENT_LBUTTONDOWN ? 1 : 2); +		time = _system->getMillis(true); +		if (_lastClick.count && (time < _lastClick.time + kDoubleClickDelay) +			&& ABS(_lastClick.x - event.mouse.x) < 3 +			&& ABS(_lastClick.y - event.mouse.y) < 3) { +				_lastClick.count++; +		} else { +			_lastClick.x = event.mouse.x; +			_lastClick.y = event.mouse.y; +			_lastClick.count = 1; +		} +		_lastClick.time = time; +		activeDialog->handleMouseDown(mouse.x, mouse.y, button, _lastClick.count); +		break; +	case Common::EVENT_LBUTTONUP: +	case Common::EVENT_RBUTTONUP: +		button = (event.type == Common::EVENT_LBUTTONUP ? 1 : 2); +		activeDialog->handleMouseUp(mouse.x, mouse.y, button, _lastClick.count); +		break; +	case Common::EVENT_WHEELUP: +		activeDialog->handleMouseWheel(mouse.x, mouse.y, -1); +		break; +	case Common::EVENT_WHEELDOWN: +		activeDialog->handleMouseWheel(mouse.x, mouse.y, 1); +		break; +	case Common::EVENT_SCREEN_CHANGED: +		screenChange(); +		break; +	default: +	#ifdef ENABLE_KEYMAPPER +		activeDialog->handleOtherEvent(event); +	#endif +		break; +	} +} +  } // End of namespace GUI diff --git a/gui/gui-manager.h b/gui/gui-manager.h index 49542fd001..b52d91ba08 100644 --- a/gui/gui-manager.h +++ b/gui/gui-manager.h @@ -35,6 +35,10 @@ namespace Graphics {  class Font;  } +namespace Common { +	struct Event; +} +  namespace GUI {  class Dialog; @@ -67,6 +71,8 @@ public:  	// until no dialogs are active anymore.  	void runLoop(); +	void processEvent(const Common::Event &event, Dialog *const activeDialog); +  	bool isActive() const	{ return ! _dialogStack.empty(); }  	bool loadNewTheme(Common::String id, ThemeEngine::GraphicsMode gfx = ThemeEngine::kGfxDisabled, bool force = false); diff --git a/gui/launcher.cpp b/gui/launcher.cpp index 4e35b54db8..77d4cce794 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -37,6 +37,11 @@  #include "gui/message.h"  #include "gui/gui-manager.h"  #include "gui/options.h" +#ifdef ENABLE_EVENTRECORDER +#include "gui/onscreendialog.h" +#include "gui/recorderdialog.h" +#include "gui/EventRecorder.h" +#endif  #include "gui/saveload.h"  #include "gui/widgets/edittext.h"  #include "gui/widgets/list.h" @@ -596,7 +601,6 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat  LauncherDialog::LauncherDialog()  	: Dialog(0, 0, 320, 200) {  	_backgroundType = GUI::ThemeEngine::kDialogBackgroundMain; -  	const int screenW = g_system->getOverlayWidth();  	const int screenH = g_system->getOverlayHeight(); @@ -779,10 +783,9 @@ void LauncherDialog::updateListing() {  }  void LauncherDialog::addGame() { -	int modifiers = g_system->getEventManager()->getModifierState();  #ifndef DISABLE_MASS_ADD -	const bool massAdd = (modifiers & Common::KBD_SHIFT) != 0; +	const bool massAdd = checkModifier(Common::KBD_SHIFT);  	if (massAdd) {  		MessageDialog alert(_("Do you really want to run the mass game detector? " @@ -975,6 +978,49 @@ void LauncherDialog::editGame(int item) {  	}  } +void LauncherDialog::loadGameButtonPressed(int item) { +#ifdef ENABLE_EVENTRECORDER +	const bool shiftPressed = checkModifier(Common::KBD_SHIFT); +	if (shiftPressed) { +		recordGame(item); +	} else { +		loadGame(item); +	} +	updateButtons(); +#else +	loadGame(item); +#endif +} + +#ifdef ENABLE_EVENTRECORDER +void LauncherDialog::recordGame(int item) { +	RecorderDialog recorderDialog; +	MessageDialog alert(_("Do you want to load savegame?"), +		_("Yes"), _("No")); +	switch(recorderDialog.runModal(_domains[item])) { +	case RecorderDialog::kRecordDialogClose: +		break; +	case RecorderDialog::kRecordDialogPlayback: +		ConfMan.setActiveDomain(_domains[item]); +		close(); +		ConfMan.set("record_mode", "playback", ConfigManager::kTransientDomain); +		ConfMan.set("record_file_name", recorderDialog.getFileName(), ConfigManager::kTransientDomain); +		break; +	case RecorderDialog::kRecordDialogRecord: +		ConfMan.setActiveDomain(_domains[item]); +		if (alert.runModal() == GUI::kMessageOK) { +			loadGame(item); +		} +		close(); +		g_eventRec.setAuthor(recorderDialog._author); +		g_eventRec.setName(recorderDialog._name); +		g_eventRec.setNotes(recorderDialog._notes); +		ConfMan.set("record_mode", "record", ConfigManager::kTransientDomain); +		break; +	} +} +#endif +  void LauncherDialog::loadGame(int item) {  	String gameId = ConfMan.get("gameid", _domains[item]);  	if (gameId.empty()) @@ -1039,7 +1085,7 @@ void LauncherDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat  		editGame(item);  		break;  	case kLoadGameCmd: -		loadGame(item); +		loadGameButtonPressed(item);  		break;  	case kOptionsCmd: {  		GlobalOptionsDialog options; @@ -1109,20 +1155,28 @@ void LauncherDialog::updateButtons() {  		_loadButton->setEnabled(en);  		_loadButton->draw();  	} +	switchButtonsText(_addButton, "~A~dd Game...", "Mass Add..."); +#ifdef ENABLE_EVENTRECORDER +	switchButtonsText(_loadButton, "~L~oad...", "Record..."); +#endif +} -	// Update the label of the "Add" button depending on whether shift is pressed or not -	int modifiers = g_system->getEventManager()->getModifierState(); -	const bool massAdd = (modifiers & Common::KBD_SHIFT) != 0; +// Update the label of the button depending on whether shift is pressed or not +void LauncherDialog::switchButtonsText(ButtonWidget *button, const char *normalText, const char *shiftedText) { +	const bool shiftPressed = checkModifier(Common::KBD_SHIFT);  	const bool lowRes = g_system->getOverlayWidth() <= 320; -	const char *newAddButtonLabel = massAdd -		? (lowRes ? _c("Mass Add...", "lowres") : _("Mass Add...")) -		: (lowRes ? _c("~A~dd Game...", "lowres") : _("~A~dd Game...")); +	const char *newAddButtonLabel = shiftPressed +		? (lowRes ? _c(shiftedText, "lowres") : _(shiftedText)) +		: (lowRes ? _c(normalText, "lowres") : _(normalText)); -	if (_addButton->getLabel() != newAddButtonLabel) -		_addButton->setLabel(newAddButtonLabel); +	if (button->getLabel() != newAddButtonLabel) +		button->setLabel(newAddButtonLabel);  } + + +  void LauncherDialog::reflowLayout() {  #ifndef DISABLE_FANCY_THEMES  	if (g_gui.xmlEval()->getVar("Globals.ShowLauncherLogo") == 1 && g_gui.theme()->supportsImages()) { @@ -1186,4 +1240,9 @@ void LauncherDialog::reflowLayout() {  	Dialog::reflowLayout();  } +bool LauncherDialog::checkModifier(int checkedModifier) { +	int modifiers = g_system->getEventManager()->getModifierState(); +	return (modifiers & checkedModifier) != 0; +} +  } // End of namespace GUI diff --git a/gui/launcher.h b/gui/launcher.h index fc0484350a..2ab47be98d 100644 --- a/gui/launcher.h +++ b/gui/launcher.h @@ -56,7 +56,7 @@ protected:  	ListWidget		*_list;  	ButtonWidget	*_addButton;  	Widget			*_startButton; -	Widget			*_loadButton; +	ButtonWidget	*_loadButton;  	Widget			*_editButton;  	Widget			*_removeButton;  #ifndef DISABLE_FANCY_THEMES @@ -80,6 +80,7 @@ protected:  	void updateListing();  	void updateButtons(); +	void switchButtonsText(ButtonWidget *button, const char *normalText, const char *shiftedText);  	void open();  	void close(); @@ -100,6 +101,16 @@ protected:  	void editGame(int item);  	/** +	 * Facade for "Load..."/"Record..." buttons. +	 */ +	void loadGameButtonPressed(int item); + +	/** +	 * Handle "Record..." button. +	 */ +	void recordGame(int item); + +	/**  	 * Handle "Load..." button.  	 */  	void loadGame(int item); @@ -111,6 +122,8 @@ protected:  	 * @target	name of target to select  	 */  	void selectTarget(const String &target); +private: +	bool checkModifier(int modifier);  };  } // End of namespace GUI diff --git a/gui/module.mk b/gui/module.mk index bda3c88cd5..338e43c6a4 100644 --- a/gui/module.mk +++ b/gui/module.mk @@ -7,6 +7,7 @@ MODULE_OBJS := \  	debugger.o \  	dialog.o \  	error.o \ +	EventRecorder.o \  	gui-manager.o \  	launcher.o \  	massadd.o \ @@ -38,6 +39,13 @@ MODULE_OBJS += \  	browser.o  endif +ifdef ENABLE_EVENTRECORDER +MODULE_OBJS += \ +	editrecorddialog.o \ +	onscreendialog.o \ +	recorderdialog.o +endif +  ifdef USE_FLUIDSYNTH  MODULE_OBJS += \  	fluidsynth-dialog.o diff --git a/gui/onscreendialog.cpp b/gui/onscreendialog.cpp new file mode 100644 index 0000000000..efe8038e68 --- /dev/null +++ b/gui/onscreendialog.cpp @@ -0,0 +1,231 @@ +/* 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/system.h" + +#include "gui/gui-manager.h" + +#include "gui/EventRecorder.h" + +#include "common/events.h" +#include "common/rect.h" +#include "common/translation.h" + +#include "graphics/cursorman.h" + +#include "gui/editrecorddialog.h" +#include "gui/ThemeEval.h" + +#include "gui/onscreendialog.h" + +namespace GUI { + +bool OnScreenDialog::isVisible() const { +	return true; +} + +enum { +	kStopCmd = 'STOP', +	kEditCmd = 'EDIT', +	kSwitchModeCmd = 'MODE', +	kFastModeCmd = 'FAST' +}; + +void OnScreenDialog::reflowLayout() { +	GuiObject::reflowLayout(); +} + +void OnScreenDialog::releaseFocus() { +} + +OnScreenDialog::OnScreenDialog(bool isRecord) : Dialog("OnScreenDialog") { +	_x = _y = 0; + +#ifndef DISABLE_FANCY_THEMES +	if (g_gui.xmlEval()->getVar("Globals.OnScreenDialog.ShowPics") == 1 && g_gui.theme()->supportsImages()) { +		GUI::PicButtonWidget *btn; +		btn = new PicButtonWidget(this, "OnScreenDialog.StopButton", 0, kStopCmd, 0); +		btn->useThemeTransparency(true); + +		if (g_system->getOverlayWidth() > 320) +			btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopbtn)); +		else +			btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageStopSmallbtn)); + +		if (isRecord) { +			btn = new PicButtonWidget(this, "OnScreenDialog.EditButton", 0, kEditCmd, 0); +			btn->useThemeTransparency(true); + +			if (g_system->getOverlayWidth() > 320) +				btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditbtn)); +			else +				btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageEditSmallbtn)); +		} else { +			btn = new PicButtonWidget(this, "OnScreenDialog.SwitchModeButton", 0, kSwitchModeCmd, 0); +			btn->useThemeTransparency(true); +			if (g_system->getOverlayWidth() > 320) +				btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModebtn)); +			else +				btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageSwitchModeSmallbtn)); + +			btn = new PicButtonWidget(this, "OnScreenDialog.FastReplayButton", 0, kFastModeCmd, 0); +			btn->useThemeTransparency(true); +			if (g_system->getOverlayWidth() > 320) +				btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaybtn)); +			else +				btn->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageFastReplaySmallbtn)); +		} +	} else +#endif +	{ +		GUI::ButtonWidget *btn; +		if (g_system->getOverlayWidth() > 320) +			btn = new ButtonWidget(this, "OnScreenDialog.StopButton", "[ ]", _("Stop"), kStopCmd); +		else +			btn = new ButtonWidget(this, "OnScreenDialog.StopButton", "[]", _("Stop"), kStopCmd); + +		if (isRecord) { +			btn = new ButtonWidget(this, "OnScreenDialog.EditButton", "E", _("Edit record description"), kEditCmd); +		} else { +			btn = new ButtonWidget(this, "OnScreenDialog.SwitchModeButton", "G", _("Switch to Game"), kSwitchModeCmd); + +			btn = new ButtonWidget(this, "OnScreenDialog.FastReplayButton", ">>", _("Fast replay"), kFastModeCmd); +		} +	} + + +	text = new GUI::StaticTextWidget(this, "OnScreenDialog.TimeLabel", "00:00:00"); +	_enableDrag = false; +	_mouseOver = false; +	_editDlgShown = false; +} + +void OnScreenDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +	Common::Event eventRTL; +	switch (cmd) { +	case kStopCmd: +		eventRTL.type = Common::EVENT_RTL; +		g_system->getEventManager()->pushEvent(eventRTL); +		close(); +		break; +	case kEditCmd: +		dlg = new EditRecordDialog(g_eventRec.getAuthor(), g_eventRec.getName(), g_eventRec.getNotes()); +		CursorMan.lock(false); +		g_eventRec.setRedraw(false); +		g_system->showOverlay(); +		_editDlgShown = true; +		dlg->runModal(); +		_editDlgShown = false; +		g_system->hideOverlay(); +		g_eventRec.setRedraw(true); +		CursorMan.lock(true); +		g_eventRec.setAuthor(((EditRecordDialog *)dlg)->getAuthor()); +		g_eventRec.setName(((EditRecordDialog *)dlg)->getName()); +		g_eventRec.setNotes(((EditRecordDialog *)dlg)->getNotes()); +		delete dlg; +		break; +	case kSwitchModeCmd: +		if (g_eventRec.switchMode()) { +			close(); +		} +		break; +	case kFastModeCmd: +		g_eventRec.switchFastMode(); +		break; +	} +} + +void OnScreenDialog::setReplayedTime(uint32 newTime) { +	if (newTime - lastTime > 1000) { +		uint32 seconds = newTime / 1000; +		text->setLabel(Common::String::format("%.2d:%.2d:%.2d", seconds / 3600 % 24, seconds / 60 % 60, seconds % 60)); +		lastTime = newTime; +	} +} + +OnScreenDialog::~OnScreenDialog() { +} + +void OnScreenDialog::handleMouseMoved(int x, int y, int button) { +	if (_enableDrag) { +		_x = _x + x - _dragPoint.x; +		_y = _y + y - _dragPoint.y; +	} +	Dialog::handleMouseMoved(x, y, button); +	if (isMouseOver(x, y)) { +		if (_mouseOver == false) { +			g_gui.theme()->showCursor(); +			CursorMan.lock(true); +		} +		_mouseOver = true; +	} else { +		if (_mouseOver == true) { +			CursorMan.lock(false); +			g_gui.theme()->hideCursor(); +		} +		_mouseOver = false; +	} +} + +void OnScreenDialog::handleMouseDown(int x, int y, int button, int clickCount) { +	if (isMouseOver(x, y)) { +		_dragPoint.x = x; +		_dragPoint.y = y; +		_enableDrag = true; +	} +	Dialog::handleMouseDown(x, y, button, clickCount); +} + +void OnScreenDialog::handleMouseUp(int x, int y, int button, int clickCount) { +	if (isMouseOver(x, y)) { + +	} +	_enableDrag = false; +	Dialog::handleMouseUp(x, y, button, clickCount); +} + +bool OnScreenDialog::isMouseOver(int x, int y) { +	return (x >= 0 && x < _w && y >= 0 && y < _h); +} + +bool OnScreenDialog::isMouseOver() { +	return _mouseOver; +} + +void OnScreenDialog::close() { +	CursorMan.lock(false); +	Dialog::close(); +} + +Dialog *OnScreenDialog::getActiveDlg() { +	if (_editDlgShown) { +		return dlg; +	} else { +		return this; +	} +} + +bool OnScreenDialog::isEditDlgVisible() { +	return _editDlgShown; +} + +} diff --git a/gui/onscreendialog.h b/gui/onscreendialog.h new file mode 100644 index 0000000000..4f3839acb6 --- /dev/null +++ b/gui/onscreendialog.h @@ -0,0 +1,64 @@ +/* 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 GUI_ONSCREENDIALOG_H +#define GUI_ONSCREENDIALOG_H + +#include "gui/dialog.h" +#include "gui/widget.h" + +namespace GUI { + +class OnScreenDialog : public Dialog { +private: +	uint32 lastTime; +	bool _enableDrag; +	bool _mouseOver; +	bool _editDlgShown; +	Common::Point _dragPoint; +	GUI::StaticTextWidget *text; +	Dialog *dlg; +	bool isMouseOver(int x, int y); +public: +	OnScreenDialog(bool recordingMode); +	~OnScreenDialog(); +	virtual void close(); +	virtual bool isVisible() const; +	virtual void reflowLayout(); + +	void setReplayedTime(uint32 newTime); + +	virtual void handleMouseMoved(int x, int y, int button); +	virtual void handleMouseDown(int x, int y, int button, int clickCount); +	virtual void handleMouseUp(int x, int y, int button, int clickCount); +	void handleCommand(CommandSender *sender, uint32 cmd, uint32 data); + +	bool isMouseOver(); +	bool isEditDlgVisible(); +	Dialog *getActiveDlg(); +protected: +	virtual void	releaseFocus(); +}; + +} // End of namespace GUI + +#endif diff --git a/gui/recorderdialog.cpp b/gui/recorderdialog.cpp new file mode 100644 index 0000000000..55f342d4a1 --- /dev/null +++ b/gui/recorderdialog.cpp @@ -0,0 +1,291 @@ +/* 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/algorithm.h" +#include "common/bufferedstream.h" +#include "common/savefile.h" +#include "common/system.h" +#include "graphics/colormasks.h" +#include "graphics/palette.h" +#include "graphics/scaler.h" +#include "graphics/thumbnail.h" +#include "common/translation.h" +#include "gui/widgets/list.h" +#include "gui/editrecorddialog.h" +#include "gui/EventRecorder.h" +#include "gui/message.h" +#include "gui/saveload.h" +#include "common/system.h" +#include "gui/ThemeEval.h" +#include "gui/gui-manager.h" +#include "recorderdialog.h" + +#define MAX_RECORDS_NAMES 0xFF + +namespace GUI { + +enum { +	kRecordCmd = 'RCRD', +	kPlaybackCmd = 'PBCK', +	kDeleteCmd = 'DEL ', +	kNextScreenshotCmd = 'NEXT', +	kPrevScreenshotCmd = 'PREV', +	kEditRecordCmd = 'EDIT' +}; + +RecorderDialog::RecorderDialog() : Dialog("RecorderDialog"), _list(0), _currentScreenshot(0) { +	_backgroundType = ThemeEngine::kDialogBackgroundSpecial; + +	new StaticTextWidget(this, "SaveLoadChooser.Title", _("Recorder or Playback Gameplay")); + +	_list = new GUI::ListWidget(this, "RecorderDialog.List"); +	_list->setNumberingMode(GUI::kListNumberingOff); + +	_deleteButton = new GUI::ButtonWidget(this, "RecorderDialog.Delete", _("Delete"), 0, kDeleteCmd); +	new GUI::ButtonWidget(this, "RecorderDialog.Cancel", _("Cancel"), 0, kCloseCmd); +	new GUI::ButtonWidget(this, "RecorderDialog.Record", _("Record"), 0, kRecordCmd); +	_playbackButton = new GUI::ButtonWidget(this, "RecorderDialog.Playback", _("Playback"), 0, kPlaybackCmd); +	 +	_editButton = new GUI::ButtonWidget(this, "RecorderDialog.Edit", _("Edit"), 0, kEditRecordCmd); + +	_editButton->setEnabled(false); +	_deleteButton->setEnabled(false); +	_playbackButton->setEnabled(false); + +	_gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10); +	_container = new GUI::ContainerWidget(this, 0, 0, 10, 10); +	if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") == 1) { +		new GUI::ButtonWidget(this,"RecorderDialog.NextScreenShotButton", "<", 0, kPrevScreenshotCmd); +		new GUI::ButtonWidget(this, "RecorderDialog.PreviousScreenShotButton", ">", 0, kNextScreenshotCmd);	 +		_currentScreenshotText = new StaticTextWidget(this, "RecorderDialog.currentScreenshot", "0/0"); +		_authorText = new StaticTextWidget(this, "RecorderDialog.Author", _("Author: ")); +		_notesText = new StaticTextWidget(this, "RecorderDialog.Notes", _("Notes: ")); +	} +	if (_gfxWidget) +		_gfxWidget->setGfx(0); +} + + +void RecorderDialog::reflowLayout() { +	if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") == 1) { +		int16 x, y; +		uint16 w, h; + +		if (!g_gui.xmlEval()->getWidgetData("RecorderDialog.Thumbnail", x, y, w, h)) { +			error("Error when loading position data for Recorder Thumbnails"); +		} + +		int thumbW = kThumbnailWidth; +		int thumbH = kThumbnailHeight2; +		int thumbX = x + (w >> 1) - (thumbW >> 1); +		int thumbY = y + kLineHeight; + +		_container->resize(x, y, w, h); +		_gfxWidget->resize(thumbX, thumbY, thumbW, thumbH); + +		_container->setVisible(true); +		_gfxWidget->setVisible(true); +		updateSelection(false); +	} else { +		_container->setVisible(false); +		_gfxWidget->setVisible(false); +	} +	Dialog::reflowLayout(); +} + + + +void RecorderDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { +	switch(cmd) { +	case kEditRecordCmd: { +		if (_list->getSelected() >= 0) { +			EditRecordDialog editDlg(_fileHeaders[_list->getSelected()].author, _fileHeaders[_list->getSelected()].name, _fileHeaders[_list->getSelected()].notes); +			if (editDlg.runModal() != kOKCmd) { +				return; +			} +			_playbackFile.openRead(_fileHeaders[_list->getSelected()].fileName); +			_playbackFile.getHeader().author = editDlg.getAuthor(); +			_playbackFile.getHeader().name = editDlg.getName(); +			_playbackFile.getHeader().notes = editDlg.getNotes(); +			_playbackFile.updateHeader(); +			_fileHeaders[_list->getSelected()] = _playbackFile.getHeader(); +			int oldselection = _list->getSelected(); +			updateList(); +			_list->setSelected(oldselection); +			updateSelection(true); +			_playbackFile.close(); +		} +	} +		break; +	case kNextScreenshotCmd: +		++_currentScreenshot; +		updateScreenshot(); +		break; +	case kPrevScreenshotCmd: +		--_currentScreenshot; +		updateScreenshot(); +		break; +	case kDeleteCmd: +		if (_list->getSelected() >= 0) { +			MessageDialog alert(_("Do you really want to delete this record?"), +				_("Delete"), _("Cancel")); +			if (alert.runModal() == GUI::kMessageOK) { +				_playbackFile.close(); +				g_eventRec.deleteRecord(_fileHeaders[_list->getSelected()].fileName); +				_list->setSelected(-1); +				updateList(); +			} +		} +		break; +	case GUI::kListSelectionChangedCmd: +		updateSelection(true); +		break; +	case kRecordCmd: { +		TimeDate t; +		Common::String gameId = ConfMan.get("gameid", _target); +		const EnginePlugin *plugin = 0; +		GameDescriptor desc = EngineMan.findGame(gameId, &plugin); +		g_system->getTimeAndDate(t); +		EditRecordDialog editDlg("Unknown Author", Common::String::format("%.2d.%.2d.%.4d ", t.tm_mday, t.tm_mon, 1900 + t.tm_year) + desc.description(), ""); +		if (editDlg.runModal() != kOKCmd) { +			return; +		} +		_author = editDlg.getAuthor(); +		_name = editDlg.getName(); +		_notes = editDlg.getNotes(); +		_filename = g_eventRec.generateRecordFileName(_target); +		setResult(kRecordDialogRecord); +		close(); +		} +		break; +	case kPlaybackCmd: +		if (_list->getSelected() >= 0) { +			_filename = _fileHeaders[_list->getSelected()].fileName; +			setResult(kRecordDialogPlayback); +			close(); +		} +		break; +	case kCloseCmd: +		setResult(kRecordDialogClose); +	default: +		Dialog::handleCommand(sender, cmd, data); +		} +	} + +void RecorderDialog::updateList() { +	Common::SaveFileManager *saveFileMan = g_system->getSavefileManager(); +	Common::String pattern(_target+".r??"); +	Common::StringArray files = saveFileMan->listSavefiles(pattern); +	Common::PlaybackFile file; +	Common::StringArray namesList; +	_fileHeaders.clear(); +	for (Common::StringArray::iterator i = files.begin(); i != files.end(); ++i) { +		if (file.openRead(*i)) { +			namesList.push_back(file.getHeader().name); +			_fileHeaders.push_back(file.getHeader()); +		} +		file.close(); +	} +	_list->setList(namesList); +	_list->draw(); +} + +int RecorderDialog::runModal(Common::String &target) { +	_target = target; +	updateList(); +	return Dialog::runModal(); +} + +RecorderDialog::~RecorderDialog() { +} + +void RecorderDialog::updateSelection(bool redraw) { +	if (_list->getSelected() >= 0) { +		_editButton->setEnabled(true); +		_deleteButton->setEnabled(true); +		_playbackButton->setEnabled(true); +	} + +	if (g_gui.xmlEval()->getVar("Globals.RecorderDialog.ExtInfo.Visible") != 1) +		return; + +	_gfxWidget->setGfx(-1, -1, 0, 0, 0); +	_screenShotsCount = 0; +	_currentScreenshot = 0; +	updateScreenShotsText(); +	if (_list->getSelected() >= 0) { +		_authorText->setLabel(_("Author: ") + _fileHeaders[_list->getSelected()].author); +		_notesText->setLabel(_("Notes: ") + _fileHeaders[_list->getSelected()].notes); + +		_firstScreenshotUpdate = true; +		updateScreenshot(); +		if ((_screenShotsCount) > 0) { +			_currentScreenshot = 1; +		} +		updateScreenshot(); +	} else { +		_authorText->setLabel(_("Author: ")); +		_notesText->setLabel(_("Notes: ")); +		_screenShotsCount = -1; +		_currentScreenshot = 0; +		_gfxWidget->setGfx(-1, -1, 0, 0, 0); +		_gfxWidget->draw(); +		updateScreenShotsText(); +	} +} + +void RecorderDialog::updateScreenshot() { +	if (_list->getSelected() == -1) { +		return; +	} +	if (_currentScreenshot < 1) { +		_currentScreenshot = _screenShotsCount; +	} +	if (_currentScreenshot > _screenShotsCount) { +		_currentScreenshot = 1; +	} +	if (_firstScreenshotUpdate) { +		_playbackFile.openRead(_fileHeaders[_list->getSelected()].fileName); +		_screenShotsCount = _playbackFile.getScreensCount(); +		_firstScreenshotUpdate = false; +	} +	Graphics::Surface *srcsf = _playbackFile.getScreenShot(_currentScreenshot); +	if (srcsf != NULL) { +		Graphics::Surface *destsf = Graphics::scale(*srcsf, _gfxWidget->getWidth(), _gfxWidget->getHeight()); +		_gfxWidget->setGfx(destsf); +		updateScreenShotsText(); +		delete destsf; +		delete srcsf; +	} else { +		_gfxWidget->setGfx(-1, -1, 0, 0, 0); +	} +	_gfxWidget->draw(); +} + +void RecorderDialog::updateScreenShotsText() { +	if (_screenShotsCount == -1) { +		_currentScreenshotText->setLabel(Common::String::format("%d / ?", _currentScreenshot)); +	} else { +		_currentScreenshotText->setLabel(Common::String::format("%d / %d", _currentScreenshot, _screenShotsCount)); +	} +} + +} // End of namespace GUI diff --git a/gui/recorderdialog.h b/gui/recorderdialog.h new file mode 100644 index 0000000000..eb690a4f38 --- /dev/null +++ b/gui/recorderdialog.h @@ -0,0 +1,81 @@ +/* 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 GUI_RECORDER_DIALOG_H +#define GUI_RECORDER_DIALOG_H +#include "common/stream.h" +#include "common/recorderfile.h" +#include "gui/dialog.h" +namespace GUI { + +class ListWidget; +class GraphicsWidget; +class ButtonWidget; +class CommandSender; +class ContainerWidget; +class StaticTextWidget; + +class RecorderDialog : public GUI::Dialog { +private: +	bool _firstScreenshotUpdate; +	Common::PlaybackFile _playbackFile; +	Common::String _target; +	Common::String _filename; +	int _currentScreenshot; +	int _screenShotsCount; +	Common::Array<Common::PlaybackFile::PlaybackFileHeader> _fileHeaders; +	GUI::ListWidget *_list; +	GUI::ContainerWidget *_container; +	GUI::GraphicsWidget *_gfxWidget; +	GUI::StaticTextWidget *_currentScreenshotText; +	GUI::StaticTextWidget *_authorText; +	GUI::StaticTextWidget *_notesText; +	GUI::ButtonWidget *_editButton; +	GUI::ButtonWidget *_deleteButton; +	GUI::ButtonWidget *_playbackButton; + +	void updateList(); +	void updateScreenShotsText(); +	void updateSelection(bool redraw); +	void updateScreenshot(); +public: +	Common::String _author; +	Common::String _name; +	Common::String _notes; +	enum DialogResult { +		kRecordDialogClose, +		kRecordDialogRecord, +		kRecordDialogPlayback +	}; +	RecorderDialog(); +	~RecorderDialog(); + +	virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); +	virtual void reflowLayout(); + +	int runModal(Common::String &target); +	const Common::String getFileName() {return _filename;} +}; + +}  // End of namespace GUI + + +#endif diff --git a/gui/themes/default.inc b/gui/themes/default.inc index 6d8e6baac7..1b6ae3ec27 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -610,50 +610,54 @@  "/> "  "</drawdata> "  "</render_info> " -"<layout_info resolution='y<400'> " +"<layout_info resolution='y>399'> "  "<globals> " -"<def var='Line.Height' value='12' /> " -"<def var='Font.Height' value='10' /> " -"<def var='About.OuterBorder' value='10'/> " -"<def var='Layout.Spacing' value='8'/> " +"<def var='Line.Height' value='16' /> " +"<def var='Font.Height' value='16' /> " +"<def var='About.OuterBorder' value='80'/> " +"<def var='Layout.Spacing' value='8' /> "  "<def var='ShowLauncherLogo' value='0'/> "  "<def var='ShowGlobalMenuLogo' value='0'/> "  "<def var='ShowSearchPic' value='0'/> "  "<def var='ShowChooserPics' value='0'/> " -"<def var='ShowChooserPageDisplay' value='0'/> " -"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> " -"<def var='KeyMapper.Spacing' value='5'/> " -"<def var='KeyMapper.LabelWidth' value='80'/> " -"<def var='KeyMapper.ButtonWidth' value='60'/> " -"<def var='Tooltip.MaxWidth' value='70'/> " -"<def var='Tooltip.XDelta' value='8'/> " -"<def var='Tooltip.YDelta' value='8'/> " -"<def var='Predictive.Button.Width' value='45' /> " -"<def var='Predictive.Button.Height' value='15' /> " -"<widget name='Button' " -"size='72,16' " -"/> " -"<widget name='Slider' " -"size='85,12' " -"/> " +"<def var='ShowChooserPageDisplay' value='1'/> " +"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> " +"<def var='RecorderDialog.ExtInfo.Visible' value='1'/> " +"<def var='OnScreenDialog.ShowPics' value='0'/> " +"<def var='KeyMapper.Spacing' value='10'/> " +"<def var='KeyMapper.LabelWidth' value='100'/> " +"<def var='KeyMapper.ButtonWidth' value='80'/> " +"<def var='Tooltip.MaxWidth' value='200'/> " +"<def var='Tooltip.XDelta' value='16'/> " +"<def var='Tooltip.YDelta' value='16'/> " +"<def var='Predictive.Button.Width' value='60' /> "  "<widget name='OptionsLabel' "  "size='110,Globals.Line.Height' "  "textalign='right' "  "/> "  "<widget name='SmallLabel' " -"size='18,Globals.Line.Height' " +"size='24,Globals.Line.Height' " +"/> " +"<widget name='ShortOptionsLabel' " +"size='60,Globals.Line.Height' " +"/> " +"<widget name='Button' " +"size='108,24' " +"/> " +"<widget name='Slider' " +"size='128,18' "  "/> "  "<widget name='PopUp' " -"size='-1,15' " +"size='-1,19' "  "/> "  "<widget name='Checkbox' " -"size='-1,Globals.Line.Height' " +"size='-1,14' "  "/> "  "<widget name='Radiobutton' "  "size='-1,Globals.Line.Height' "  "/> "  "<widget name='ListWidget' " -"padding='5,0,0,0' " +"padding='5,0,8,0' "  "/> "  "<widget name='PopUpWidget' "  "padding='7,5,0,0' " @@ -665,29 +669,35 @@  "padding='7,5,5,5' "  "/> "  "<widget name='Scrollbar' " -"size='9,0' " +"size='15,0' "  "/> "  "<widget name='TabWidget.Tab' " -"size='45,16' " -"padding='0,0,2,0' " +"size='75,27' " +"padding='0,0,8,0' "  "/> "  "<widget name='TabWidget.Body' " -"padding='0,0,0,-8' " +"padding='0,0,0,0' "  "/> "  "<widget name='TabWidget.NavButton' " -"size='32,18' " -"padding='0,0,1,0' " +"size='15,18' " +"padding='0,3,4,0' " +"/> " +"<widget name='EditRecordLabel' " +"size='60,25' " +"/> " +"<widget name='EditRecord' " +"size='240,25' "  "/> "  "</globals> "  "<dialog name='Launcher' overlays='screen'> " -"<layout type='vertical' center='true' padding='6,6,2,2'> " +"<layout type='vertical' center='true' padding='16,16,8,8'> "  "<widget name='Version' "  "height='Globals.Line.Height' "  "textalign='center' "  "/> " -"<layout type='horizontal' spacing='5' padding='0,0,0,0'> " +"<layout type='horizontal' spacing='5' padding='10,0,0,0'> "  "<widget name='SearchDesc' " -"width='50' " +"width='60' "  "height='Globals.Line.Height' "  "textalign='right' "  "/> " @@ -702,38 +712,39 @@  "<space /> "  "</layout> "  "<widget name='GameList'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='LoadGameButton' " -"height='12' " +"height='20' "  "/> "  "<widget name='AddGameButton' " -"height='12' " +"height='20' "  "/> "  "<widget name='EditGameButton' " -"height='12' " +"height='20' "  "/> "  "<widget name='RemoveGameButton' " -"height='12' " +"height='20' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"<space size='4'/> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='QuitButton' " -"height='12' " +"height='20' "  "/> "  "<widget name='AboutButton' " -"height='12' " +"height='20' "  "/> "  "<widget name='OptionsButton' " -"height='12' " +"height='20' "  "/> "  "<widget name='StartButton' " -"height='12' " +"height='20' "  "/> "  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='Browser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,0,4'> " +"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'> " +"<layout type='vertical' padding='8,8,8,8'> "  "<widget name='Headline' "  "height='Globals.Line.Height' "  "/> " @@ -741,7 +752,7 @@  "height='Globals.Line.Height' "  "/> "  "<widget name='List'/> " -"<layout type='vertical' padding='0,0,8,0'> " +"<layout type='vertical' padding='0,0,16,0'> "  "<widget name='Hidden' "  "type='Checkbox' "  "/> " @@ -760,10 +771,10 @@  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'> " +"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'> "  "<layout type='vertical' padding='0,0,0,0'> "  "<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " +"<layout type='horizontal' padding='16,16,16,16'> "  "<space/> "  "<widget name='Cancel' "  "type='Button' " @@ -776,7 +787,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='grModePopupDesc' "  "type='OptionsLabel' "  "/> " @@ -784,7 +795,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='grRenderPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -802,7 +813,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='auMidiPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -810,7 +821,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='auOPLPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -818,7 +829,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='auSampleRatePopupDesc' "  "type='OptionsLabel' "  "/> " @@ -826,7 +837,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='3' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='subToggleDesc' "  "type='OptionsLabel' "  "/> " @@ -840,7 +851,7 @@  "type='Radiobutton' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='subSubtitleSpeedDesc' "  "type='OptionsLabel' "  "/> " @@ -854,8 +865,9 @@  "</layout> "  "</dialog> "  "<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='0,0,0,0' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0'> "  "<widget name='vcMusicText' "  "type='OptionsLabel' "  "/> " @@ -866,7 +878,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0'> "  "<widget name='vcSfxText' "  "type='OptionsLabel' "  "/> " @@ -877,7 +889,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0'> "  "<widget name='vcSpeechText' "  "type='OptionsLabel' "  "/> " @@ -888,8 +900,8 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " -"<space size='110' /> " +"</layout> " +"<layout type='vertical' padding='24,0,24,0' center='true'> "  "<widget name='vcMuteCheckbox' "  "type='Checkbox' "  "/> " @@ -897,8 +909,8 @@  "</layout> "  "</dialog> "  "<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='6'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='auPrefGmPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -906,7 +918,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='mcFontButton' "  "type='Button' "  "/> " @@ -921,7 +933,7 @@  "<widget name='mcMixedCheckbox' "  "type='Checkbox' "  "/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0'> "  "<widget name='mcMidiGainText' "  "type='OptionsLabel' "  "/> " @@ -934,14 +946,14 @@  "/> "  "</layout> "  "<widget name='mcFluidSynthSettings' " -"width='150' " +"width='200' "  "height='Globals.Button.Height' "  "/> "  "</layout> "  "</dialog> "  "<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='auPrefMt32PopupDesc' "  "type='OptionsLabel' "  "/> " @@ -959,7 +971,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='SaveButton' "  "type='Button' "  "/> " @@ -971,7 +983,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='ThemeButton' "  "type='Button' "  "/> " @@ -983,7 +995,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='ExtraButton' "  "type='Button' "  "/> " @@ -1007,7 +1019,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='ThemeButton' "  "type='Button' "  "/> " @@ -1015,31 +1027,25 @@  "height='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='RendererPopupDesc' " -"width='80' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='RendererPopup' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='AutosavePeriodPopupDesc' " -"width='80' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='AutosavePeriodPopup' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='GuiLanguagePopupDesc' " -"width='80' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='GuiLanguagePopup' "  "type='PopUp' " @@ -1074,10 +1080,10 @@  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'> " +"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'> "  "<layout type='vertical' padding='0,0,0,0' spacing='16'> "  "<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " +"<layout type='horizontal' padding='16,16,16,4'> "  "<space/> "  "<widget name='Cancel' "  "type='Button' " @@ -1089,7 +1095,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1097,7 +1103,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1105,7 +1111,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1113,7 +1119,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1121,7 +1127,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1129,43 +1135,34 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='vertical' padding='16,16,16,16'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='Id' " -"width='35' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='Domain' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='Name' " -"width='35' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='Desc' "  "type='PopUp' "  "/> "  "</layout> " -"<space size='8'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='LangPopupDesc' " -"width='60' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='LangPopup' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='PlatformPopupDesc' " -"width='60' " -"height='Globals.Line.Height' " -"textalign='right' " +"type='OptionsLabel' "  "/> "  "<widget name='PlatformPopup' "  "type='PopUp' " @@ -1174,8 +1171,8 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"<layout type='vertical' padding='16,16,16,16'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='Savepath' "  "type='Button' "  "/> " @@ -1187,7 +1184,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='Extrapath' "  "type='Button' "  "/> " @@ -1199,7 +1196,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='Gamepath' "  "type='Button' "  "/> " @@ -1210,7 +1207,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " +"<layout type='vertical' padding='16,16,16,16'> "  "<widget name='customOption1Checkbox' "  "type='Checkbox' "  "/> " @@ -1235,55 +1232,57 @@  "</layout> "  "</dialog> "  "<dialog name='GlobalMenu' overlays='screen_center'> " -"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' center='true'> "  "<widget name='Title' " -"width='160' " -"height='4' " +"width='210' " +"height='Globals.Line.Height' "  "/> "  "<widget name='Version' " -"width='160' " -"height='4' " +"width='210' " +"height='Globals.Line.Height' "  "/> " -"<space size='1'/> " +"<widget name='Resume' " +"width='150' " +"height='Globals.Button.Height' " +"/> " +"<space size='10'/> "  "<widget name='Load' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Save' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> " -"<space size='1'/> " +"<space size='10'/> "  "<widget name='Options' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Help' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> "  "<widget name='About' " -"width='120' " -"height='12' " -"/> " -"<space size='1'/> " -"<widget name='Resume' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> " +"<space size='10'/> "  "<widget name='RTL' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Quit' " -"width='120' " -"height='12' " +"width='150' " +"height='Globals.Button.Height' "  "/> "  "</layout> "  "</dialog> "  "<dialog name='GlobalConfig' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='vertical' padding='0,0,0,0' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "  "<widget name='vcMusicText' "  "type='OptionsLabel' "  "/> " @@ -1294,7 +1293,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "  "<widget name='vcSfxText' "  "type='OptionsLabel' "  "/> " @@ -1305,7 +1304,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "  "<widget name='vcSpeechText' "  "type='OptionsLabel' "  "/> " @@ -1316,34 +1315,33 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " -"<space size='110' /> " +"</layout> " +"<layout type='vertical' padding='24,24,24,24' center='true'> "  "<widget name='vcMuteCheckbox' "  "type='Checkbox' " -"width='80' " +"width='80'  "  "/> "  "</layout> " -"<layout type='vertical' padding='0,0,0,0' spacing='1' center='true'> " +"</layout> " +"<space size='8' /> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='subToggleDesc' "  "type='OptionsLabel' "  "/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='subToggleSpeechOnly' "  "type='Radiobutton' " -"width='90' " +"width='100' "  "/> "  "<widget name='subToggleSubOnly' "  "type='Radiobutton' " -"width='90' " +"width='100' "  "/> "  "<widget name='subToggleSubBoth' "  "type='Radiobutton' " -"width='90' " +"width='100' "  "/> "  "</layout> " -"</layout> " -"<space size='2' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='subSubtitleSpeedDesc' "  "type='OptionsLabel' "  "/> " @@ -1354,8 +1352,8 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<space size='16'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='4'> " +"<space size='60'/> " +"<layout type='horizontal' padding='0,0,0,0' spacing='10'> "  "<widget name='Keys' "  "type='Button' "  "/> " @@ -1372,7 +1370,7 @@  "<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'> "  "<layout type='vertical' padding='0,0,0,0'> "  "<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " +"<layout type='horizontal' padding='16,16,16,16'> "  "<space/> "  "<widget name='ResetSettings' "  "type='Button' " @@ -1387,7 +1385,7 @@  "</layout> "  "</dialog> "  "<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1450,7 +1448,7 @@  "</layout> "  "</dialog> "  "<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -1505,7 +1503,7 @@  "</layout> "  "</dialog> "  "<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> "  "<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='InterpolationText' "  "type='OptionsLabel' " @@ -1517,10 +1515,25 @@  "</layout> "  "</dialog> "  "<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " -"<widget name='Title' height='Globals.Line.Height'/> " +"<layout type='vertical' padding='8,8,8,32' center='true'> " +"<layout type='horizontal' padding='0,0,0,0'> " +"<widget name='Title' " +"height='Globals.Line.Height' " +"/> " +"<space/> " +"<widget name='PageDisplay' " +"width='200' " +"height='Globals.Line.Height' " +"/> " +"</layout> " +"<layout type='horizontal' padding='0,0,0,16' spacing='16'> "  "<widget name='List' /> " -"<layout type='horizontal' padding='0,0,16,0'> " +"<widget name='Thumbnail' " +"width='180' " +"height='200' " +"/> " +"</layout> " +"<layout type='horizontal' padding='0,0,0,0'> "  "<widget name='ListSwitch' "  "height='Globals.Line.Height' "  "width='Globals.Line.Height' " @@ -1533,7 +1546,7 @@  "<widget name='Delete' "  "type='Button' "  "/> " -"<space size='16'/> " +"<space size='32'/> "  "<widget name='Cancel' "  "type='Button' "  "/> " @@ -1546,7 +1559,7 @@  "<dialog name='SavenameDialog' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8'> "  "<widget name='DescriptionText' " -"width='180' " +"width='320' "  "height='Globals.Line.Height' "  "/> "  "<widget name='Description' " @@ -1556,22 +1569,139 @@  "<widget name='Cancel' "  "type='Button' "  "/> " +"<space size='96'/> "  "<widget name='Ok' "  "type='Button' "  "/> "  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='ScummHelp' overlays='screen'> " -"<layout type='vertical' padding='8,8,8,8'> " +"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'> " +"<layout type='vertical' padding='8,8,8,32' center='true'> "  "<widget name='Title' " +"height='Globals.Line.Height' " +"/> " +"<layout type='horizontal' padding='0,0,0,16' spacing='16'> " +"<widget name='List' /> " +"<layout type='vertical' padding='0,0,0,0'> " +"<widget name='Thumbnail' "  "width='180' " +"height='170' " +"/> " +"<layout type='horizontal' padding='0,0,0,0'> " +"<widget name='NextScreenShotButton' " +"width='25' " +"height='25' " +"/> " +"<widget name='currentScreenshot' " +"width='125' " +"height='25' " +"textalign='center' " +"/> " +"<widget name='PreviousScreenShotButton' " +"width='25' " +"height='25' " +"/> " +"</layout> " +"<widget name='Author' height='Globals.Line.Height' /> " +"<widget name='Notes' height='Globals.Line.Height' /> " +"</layout> " +"</layout> " +"<layout type='horizontal' padding='0,0,0,0'> " +"<widget name='Delete' " +"type='Button' " +"/> " +"<space size='16'/> " +"<widget name='Cancel' " +"type='Button' " +"/> " +"<space size='16'/> " +"<widget name='Edit' " +"type='Button' " +"/> " +"<widget name='Record' " +"type='Button' " +"/> " +"<widget name='Playback' " +"type='Button' " +"/> " +"</layout> " +"</layout> " +"</dialog> " +"<dialog name='OnScreenDialog' overlays='screen_center'> " +"<layout type='horizontal' spacing='5' padding='5,3,5,3' center='true'> " +"<widget name='StopButton' " +"width='32' " +"height='32' " +"/> " +"<widget name='EditButton' " +"width='32' " +"height='32' " +"/> " +"<widget name='SwitchModeButton' " +"width='32' " +"height='32' " +"/> " +"<widget name='FastReplayButton' " +"width='32' " +"height='32' " +"/> " +"<widget name='TimeLabel' " +"width='50' " +"height='30' " +"/> " +"</layout> " +"</dialog> " +"<dialog name='EditRecordDialog' overlays='screen_center'> " +"<layout type='vertical' padding='8,8,8,8' center='true'> " +"<widget name='Title' " +"width='320' " +"height='Globals.Line.Height' " +"/> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='AuthorLabel' " +"type='EditRecordLabel' " +"/> " +"<widget name='AuthorEdit' " +"type='EditRecord' " +"/> " +"</layout> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='NameLabel' " +"type='EditRecordLabel' " +"/> " +"<widget name='NameEdit' " +"type='EditRecord' " +"/> " +"</layout> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='NotesLabel' " +"type='EditRecordLabel' " +"/> " +"<widget name='NotesEdit' " +"type='EditRecord' " +"/> " +"</layout> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='Cancel' " +"type='Button' " +"/> " +"<widget name='OK' " +"type='Button' " +"/> " +"</layout> " +"</layout> " +"</dialog> " +"<dialog name='ScummHelp' overlays='screen_center'> " +"<layout type='vertical' padding='8,8,8,8' center='true'> " +"<widget name='Title' " +"width='320' "  "height='Globals.Line.Height' "  "/> "  "<widget name='HelpText' " -"height='140' " +"height='200' "  "/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='horizontal' padding='0,0,16,0'> "  "<widget name='Prev' "  "type='Button' "  "/> " @@ -1588,7 +1718,7 @@  "<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8' center='true'> "  "<widget name='Description1' " -"width='280' " +"width='320' "  "height='Globals.Line.Height' "  "/> "  "<widget name='Description2' " @@ -1606,20 +1736,20 @@  "</layout> "  "</dialog> "  "<dialog name='MassAdd' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='4,4,16,4' center='true'> " +"<layout type='vertical' padding='8,8,32,8' center='true'> "  "<widget name='DirProgressText' " -"width='280' " +"width='480' "  "height='Globals.Line.Height' "  "/> "  "<widget name='GameProgressText' " -"width='280' " +"width='480' "  "height='Globals.Line.Height' "  "/> "  "<widget name='GameList' " -"width='280' " -"height='100' " +"width='480' " +"height='250' "  "/> " -"<layout type='horizontal' padding='4,4,4,4'> " +"<layout type='horizontal' padding='8,8,8,8'> "  "<widget name='Ok' "  "type='Button' "  "/> " @@ -1630,20 +1760,20 @@  "</layout> "  "</dialog> "  "<dialog name='KeyMapper' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'> " +"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'> "  "<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='PopupDesc' "  "type='OptionsLabel' "  "/> "  "<widget name='Popup' "  "type='PopUp' " -"width='150' " +"width='400' "  "height='Globals.Line.Height' "  "/> "  "</layout> "  "<widget name='KeymapArea' " -"width='300' " -"height='120' " +"width='600' " +"height='280' "  "/> "  "<widget name='Close' "  "type='Button' " @@ -1651,142 +1781,144 @@  "</layout> "  "</dialog> "  "<dialog name='Predictive' overlays='screen_center'> " -"<layout type='vertical' padding='1,1,1,1' center='true'> " +"<layout type='vertical' padding='5,5,5,5' center='true'> "  "<widget name='Headline' "  "height='Globals.Line.Height' " -"width='150' " +"width='210' "  "textalign='center' "  "/> " -"<layout type='horizontal' padding='3,3,3,3'> " +"<layout type='horizontal' padding='5,5,5,5'> "  "<widget name='Word' " -"width='120' " +"width='190' "  "height='Globals.Button.Height' "  "/> "  "<widget name='Delete' "  "width='20' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "</layout> " +"<space size='5' /> "  "<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Button1' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button2' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button3' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "</layout> "  "<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Button4' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button5' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button6' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "</layout> "  "<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Button7' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button8' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button9' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='3,3,3,0'> " +"<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Pre' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Button0' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='Next' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "</layout> " -"<space size='3' /> " -"<layout type='horizontal' padding='3,3,0,3'> " +"<space size='5' /> " +"<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Add' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> " +"<space size='22'/> "  "<widget name='Cancel' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "<widget name='OK' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Predictive.Button.Height' " +"height='Globals.Button.Height' "  "/> "  "</layout> "  "</layout> "  "</dialog> "  "</layout_info> " -"<layout_info resolution='y>399'> " +"<layout_info resolution='y<400'> "  "<globals> " -"<def var='Line.Height' value='16' /> " -"<def var='Font.Height' value='16' /> " -"<def var='About.OuterBorder' value='80'/> " -"<def var='Layout.Spacing' value='8' /> " +"<def var='Line.Height' value='12' /> " +"<def var='Font.Height' value='10' /> " +"<def var='About.OuterBorder' value='10'/> " +"<def var='Layout.Spacing' value='8'/> "  "<def var='ShowLauncherLogo' value='0'/> "  "<def var='ShowGlobalMenuLogo' value='0'/> "  "<def var='ShowSearchPic' value='0'/> "  "<def var='ShowChooserPics' value='0'/> " -"<def var='ShowChooserPageDisplay' value='1'/> " -"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> " -"<def var='KeyMapper.Spacing' value='10'/> " -"<def var='KeyMapper.LabelWidth' value='100'/> " -"<def var='KeyMapper.ButtonWidth' value='80'/> " -"<def var='Tooltip.MaxWidth' value='200'/> " -"<def var='Tooltip.XDelta' value='16'/> " -"<def var='Tooltip.YDelta' value='16'/> " -"<def var='Predictive.Button.Width' value='60' /> " +"<def var='ShowChooserPageDisplay' value='0'/> " +"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> " +"<def var='RecorderDialog.ExtInfo.Visible' value='0'/> " +"<def var='OnScreenDialog.ShowPics' value='0'/> " +"<def var='KeyMapper.Spacing' value='5'/> " +"<def var='KeyMapper.LabelWidth' value='80'/> " +"<def var='KeyMapper.ButtonWidth' value='60'/> " +"<def var='Tooltip.MaxWidth' value='70'/> " +"<def var='Tooltip.XDelta' value='8'/> " +"<def var='Tooltip.YDelta' value='8'/> " +"<def var='Predictive.Button.Width' value='45' /> " +"<def var='Predictive.Button.Height' value='15' /> " +"<widget name='Button' " +"size='72,16' " +"/> " +"<widget name='Slider' " +"size='85,12' " +"/> "  "<widget name='OptionsLabel' "  "size='110,Globals.Line.Height' "  "textalign='right' "  "/> "  "<widget name='SmallLabel' " -"size='24,Globals.Line.Height' " -"/> " -"<widget name='ShortOptionsLabel' " -"size='60,Globals.Line.Height' " -"/> " -"<widget name='Button' " -"size='108,24' " -"/> " -"<widget name='Slider' " -"size='128,18' " +"size='18,Globals.Line.Height' "  "/> "  "<widget name='PopUp' " -"size='-1,19' " +"size='-1,15' "  "/> "  "<widget name='Checkbox' " -"size='-1,14' " +"size='-1,Globals.Line.Height' "  "/> "  "<widget name='Radiobutton' "  "size='-1,Globals.Line.Height' "  "/> "  "<widget name='ListWidget' " -"padding='5,0,8,0' " +"padding='5,0,0,0' "  "/> "  "<widget name='PopUpWidget' "  "padding='7,5,0,0' " @@ -1798,29 +1930,35 @@  "padding='7,5,5,5' "  "/> "  "<widget name='Scrollbar' " -"size='15,0' " +"size='9,0' "  "/> "  "<widget name='TabWidget.Tab' " -"size='75,27' " -"padding='0,0,8,0' " +"size='45,16' " +"padding='0,0,2,0' "  "/> "  "<widget name='TabWidget.Body' " -"padding='0,0,0,0' " +"padding='0,0,0,-8' "  "/> "  "<widget name='TabWidget.NavButton' " -"size='15,18' " -"padding='0,3,4,0' " +"size='32,18' " +"padding='0,0,1,0' " +"/> " +"<widget name='EditRecordLabel' " +"size='60,Globals.Line.Height' " +"/> " +"<widget name='EditRecord' " +"size='120,15' "  "/> "  "</globals> "  "<dialog name='Launcher' overlays='screen'> " -"<layout type='vertical' center='true' padding='16,16,8,8'> " +"<layout type='vertical' center='true' padding='6,6,2,2'> "  "<widget name='Version' "  "height='Globals.Line.Height' "  "textalign='center' "  "/> " -"<layout type='horizontal' spacing='5' padding='10,0,0,0'> " +"<layout type='horizontal' spacing='5' padding='0,0,0,0'> "  "<widget name='SearchDesc' " -"width='60' " +"width='50' "  "height='Globals.Line.Height' "  "textalign='right' "  "/> " @@ -1835,39 +1973,38 @@  "<space /> "  "</layout> "  "<widget name='GameList'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "  "<widget name='LoadGameButton' " -"height='20' " +"height='12' "  "/> "  "<widget name='AddGameButton' " -"height='20' " +"height='12' "  "/> "  "<widget name='EditGameButton' " -"height='20' " +"height='12' "  "/> "  "<widget name='RemoveGameButton' " -"height='20' " +"height='12' "  "/> "  "</layout> " -"<space size='4'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='8'> "  "<widget name='QuitButton' " -"height='20' " +"height='12' "  "/> "  "<widget name='AboutButton' " -"height='20' " +"height='12' "  "/> "  "<widget name='OptionsButton' " -"height='20' " +"height='12' "  "/> "  "<widget name='StartButton' " -"height='20' " +"height='12' "  "/> "  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " +"<dialog name='Browser' overlays='screen' inset='8' shading='dim'> " +"<layout type='vertical' padding='8,8,0,4'> "  "<widget name='Headline' "  "height='Globals.Line.Height' "  "/> " @@ -1875,7 +2012,7 @@  "height='Globals.Line.Height' "  "/> "  "<widget name='List'/> " -"<layout type='vertical' padding='0,0,16,0'> " +"<layout type='vertical' padding='0,0,8,0'> "  "<widget name='Hidden' "  "type='Checkbox' "  "/> " @@ -1894,10 +2031,10 @@  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'> " +"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'> "  "<layout type='vertical' padding='0,0,0,0'> "  "<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,16'> " +"<layout type='horizontal' padding='8,8,8,8'> "  "<space/> "  "<widget name='Cancel' "  "type='Button' " @@ -1910,7 +2047,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='grModePopupDesc' "  "type='OptionsLabel' "  "/> " @@ -1918,7 +2055,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='grRenderPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -1936,7 +2073,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='auMidiPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -1944,7 +2081,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='auOPLPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -1952,7 +2089,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='auSampleRatePopupDesc' "  "type='OptionsLabel' "  "/> " @@ -1960,7 +2097,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='3' center='true'> "  "<widget name='subToggleDesc' "  "type='OptionsLabel' "  "/> " @@ -1974,7 +2111,7 @@  "type='Radiobutton' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='subSubtitleSpeedDesc' "  "type='OptionsLabel' "  "/> " @@ -1988,9 +2125,8 @@  "</layout> "  "</dialog> "  "<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='horizontal' padding='16,16,16,16' spacing='8'> " -"<layout type='vertical' padding='0,0,0,0' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='vcMusicText' "  "type='OptionsLabel' "  "/> " @@ -2001,7 +2137,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='vcSfxText' "  "type='OptionsLabel' "  "/> " @@ -2012,7 +2148,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='vcSpeechText' "  "type='OptionsLabel' "  "/> " @@ -2023,8 +2159,8 @@  "type='SmallLabel' "  "/> "  "</layout> " -"</layout> " -"<layout type='vertical' padding='24,0,24,0' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<space size='110' /> "  "<widget name='vcMuteCheckbox' "  "type='Checkbox' "  "/> " @@ -2032,8 +2168,8 @@  "</layout> "  "</dialog> "  "<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='vertical' padding='16,16,16,16' spacing='6'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='auPrefGmPopupDesc' "  "type='OptionsLabel' "  "/> " @@ -2041,7 +2177,7 @@  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "  "<widget name='mcFontButton' "  "type='Button' "  "/> " @@ -2056,7 +2192,7 @@  "<widget name='mcMixedCheckbox' "  "type='Checkbox' "  "/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='mcMidiGainText' "  "type='OptionsLabel' "  "/> " @@ -2069,14 +2205,14 @@  "/> "  "</layout> "  "<widget name='mcFluidSynthSettings' " -"width='200' " +"width='150' "  "height='Globals.Button.Height' "  "/> "  "</layout> "  "</dialog> "  "<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='auPrefMt32PopupDesc' "  "type='OptionsLabel' "  "/> " @@ -2094,7 +2230,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "  "<widget name='SaveButton' "  "type='Button' "  "/> " @@ -2106,7 +2242,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "  "<widget name='ThemeButton' "  "type='Button' "  "/> " @@ -2118,7 +2254,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "  "<widget name='ExtraButton' "  "type='Button' "  "/> " @@ -2142,7 +2278,7 @@  "</dialog> "  "<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> "  "<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16'> "  "<widget name='ThemeButton' "  "type='Button' "  "/> " @@ -2150,25 +2286,31 @@  "height='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='RendererPopupDesc' " -"type='OptionsLabel' " +"width='80' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='RendererPopup' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='AutosavePeriodPopupDesc' " -"type='OptionsLabel' " +"width='80' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='AutosavePeriodPopup' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='GuiLanguagePopupDesc' " -"type='OptionsLabel' " +"width='80' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='GuiLanguagePopup' "  "type='PopUp' " @@ -2203,10 +2345,10 @@  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'> " +"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'> "  "<layout type='vertical' padding='0,0,0,0' spacing='16'> "  "<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,4'> " +"<layout type='horizontal' padding='8,8,8,8'> "  "<space/> "  "<widget name='Cancel' "  "type='Button' " @@ -2218,7 +2360,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2226,7 +2368,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2234,7 +2376,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2242,7 +2384,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2250,7 +2392,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2258,34 +2400,43 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='vertical' padding='8,8,8,8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='Id' " -"type='OptionsLabel' " +"width='35' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='Domain' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='Name' " -"type='OptionsLabel' " +"width='35' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='Desc' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<space size='8'/> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='LangPopupDesc' " -"type='OptionsLabel' " +"width='60' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='LangPopup' "  "type='PopUp' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='PlatformPopupDesc' " -"type='OptionsLabel' " +"width='60' " +"height='Globals.Line.Height' " +"textalign='right' "  "/> "  "<widget name='PlatformPopup' "  "type='PopUp' " @@ -2294,8 +2445,8 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='vertical' padding='8,8,8,8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "  "<widget name='Savepath' "  "type='Button' "  "/> " @@ -2307,7 +2458,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "  "<widget name='Extrapath' "  "type='Button' "  "/> " @@ -2319,7 +2470,7 @@  "width='Globals.Line.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> "  "<widget name='Gamepath' "  "type='Button' "  "/> " @@ -2330,7 +2481,7 @@  "</layout> "  "</dialog> "  "<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " +"<layout type='vertical' padding='8,8,8,8'> "  "<widget name='customOption1Checkbox' "  "type='Checkbox' "  "/> " @@ -2355,57 +2506,55 @@  "</layout> "  "</dialog> "  "<dialog name='GlobalMenu' overlays='screen_center'> " -"<layout type='vertical' padding='16,16,16,16' center='true'> " +"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'> "  "<widget name='Title' " -"width='210' " -"height='Globals.Line.Height' " +"width='160' " +"height='4' "  "/> "  "<widget name='Version' " -"width='210' " -"height='Globals.Line.Height' " -"/> " -"<widget name='Resume' " -"width='150' " -"height='Globals.Button.Height' " +"width='160' " +"height='4' "  "/> " -"<space size='10'/> " +"<space size='1'/> "  "<widget name='Load' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' "  "/> "  "<widget name='Save' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' "  "/> " -"<space size='10'/> " +"<space size='1'/> "  "<widget name='Options' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' "  "/> "  "<widget name='Help' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' "  "/> "  "<widget name='About' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' " +"/> " +"<space size='1'/> " +"<widget name='Resume' " +"width='120' " +"height='12' "  "/> " -"<space size='10'/> "  "<widget name='RTL' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' "  "/> "  "<widget name='Quit' " -"width='150' " -"height='Globals.Button.Height' " +"width='120' " +"height='12' "  "/> "  "</layout> "  "</dialog> "  "<dialog name='GlobalConfig' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0'> " -"<layout type='vertical' padding='0,0,0,0' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='vcMusicText' "  "type='OptionsLabel' "  "/> " @@ -2416,7 +2565,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='vcSfxText' "  "type='OptionsLabel' "  "/> " @@ -2427,7 +2576,7 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='vcSpeechText' "  "type='OptionsLabel' "  "/> " @@ -2438,33 +2587,34 @@  "type='SmallLabel' "  "/> "  "</layout> " -"</layout> " -"<layout type='vertical' padding='24,24,24,24' center='true'> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"<space size='110' /> "  "<widget name='vcMuteCheckbox' "  "type='Checkbox' " -"width='80'  " +"width='80' "  "/> "  "</layout> " -"</layout> " -"<space size='8' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"<layout type='vertical' padding='0,0,0,0' spacing='1' center='true'> "  "<widget name='subToggleDesc' "  "type='OptionsLabel' "  "/> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='subToggleSpeechOnly' "  "type='Radiobutton' " -"width='100' " +"width='90' "  "/> "  "<widget name='subToggleSubOnly' "  "type='Radiobutton' " -"width='100' " +"width='90' "  "/> "  "<widget name='subToggleSubBoth' "  "type='Radiobutton' " -"width='100' " +"width='90' "  "/> "  "</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"</layout> " +"<space size='2' /> " +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> "  "<widget name='subSubtitleSpeedDesc' "  "type='OptionsLabel' "  "/> " @@ -2475,8 +2625,8 @@  "type='SmallLabel' "  "/> "  "</layout> " -"<space size='60'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"<space size='16'/> " +"<layout type='horizontal' padding='0,0,0,0' spacing='4'> "  "<widget name='Keys' "  "type='Button' "  "/> " @@ -2493,7 +2643,7 @@  "<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'> "  "<layout type='vertical' padding='0,0,0,0'> "  "<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,16'> " +"<layout type='horizontal' padding='8,8,8,8'> "  "<space/> "  "<widget name='ResetSettings' "  "type='Button' " @@ -2508,7 +2658,7 @@  "</layout> "  "</dialog> "  "<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2571,7 +2721,7 @@  "</layout> "  "</dialog> "  "<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<widget name='EnableTabCheckbox' "  "type='Checkbox' "  "/> " @@ -2626,7 +2776,7 @@  "</layout> "  "</dialog> "  "<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"<layout type='vertical' padding='8,8,8,8' spacing='6'> "  "<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='InterpolationText' "  "type='OptionsLabel' " @@ -2638,25 +2788,10 @@  "</layout> "  "</dialog> "  "<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,32' center='true'> " -"<layout type='horizontal' padding='0,0,0,0'> " -"<widget name='Title' " -"height='Globals.Line.Height' " -"/> " -"<space/> " -"<widget name='PageDisplay' " -"width='200' " -"height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,16' spacing='16'> " +"<layout type='vertical' padding='8,8,8,8' center='true'> " +"<widget name='Title' height='Globals.Line.Height'/> "  "<widget name='List' /> " -"<widget name='Thumbnail' " -"width='180' " -"height='200' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"<layout type='horizontal' padding='0,0,16,0'> "  "<widget name='ListSwitch' "  "height='Globals.Line.Height' "  "width='Globals.Line.Height' " @@ -2669,7 +2804,7 @@  "<widget name='Delete' "  "type='Button' "  "/> " -"<space size='32'/> " +"<space size='16'/> "  "<widget name='Cancel' "  "type='Button' "  "/> " @@ -2682,7 +2817,7 @@  "<dialog name='SavenameDialog' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8'> "  "<widget name='DescriptionText' " -"width='320' " +"width='180' "  "height='Globals.Line.Height' "  "/> "  "<widget name='Description' " @@ -2692,23 +2827,114 @@  "<widget name='Cancel' "  "type='Button' "  "/> " -"<space size='96'/> "  "<widget name='Ok' "  "type='Button' "  "/> "  "</layout> "  "</layout> "  "</dialog> " -"<dialog name='ScummHelp' overlays='screen_center'> " +"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'> " +"<layout type='vertical' padding='8,8,8,4' center='true'> " +"<widget name='Title' " +"height='Globals.Line.Height' " +"/> " +"<widget name='List' /> " +"<layout type='horizontal' padding='0,0,0,0' spacing='2'> " +"<widget name='Edit' " +"type='Button' " +"/> " +"<space /> " +"<widget name='Record' " +"type='Button' " +"/> " +"</layout> " +"<layout type='horizontal' padding='0,0,0,0' spacing='2'> " +"<widget name='Delete' " +"type='Button' " +"/> " +"<space /> " +"<widget name='Cancel' " +"type='Button' " +"/> " +"<widget name='Playback' " +"type='Button' " +"/> " +"</layout> " +"</layout> " +"</dialog> " +"<dialog name='OnScreenDialog' overlays='screen_center'> " +"<layout type='horizontal' spacing='5' padding='3,2,3,2' center='true'> " +"<widget name='StopButton' " +"width='16' " +"height='16' " +"/> " +"<widget name='EditButton' " +"width='16' " +"height='16' " +"/> " +"<widget name='SwitchModeButton' " +"width='16' " +"height='16' " +"/> " +"<widget name='FastReplayButton' " +"width='16' " +"height='16' " +"/> " +"<widget name='TimeLabel' " +"width='50' " +"height='16' " +"/> " +"</layout> " +"</dialog> " +"<dialog name='EditRecordDialog' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8' center='true'> "  "<widget name='Title' " -"width='320' " +"height='Globals.Line.Height' " +"/> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='AuthorLabel' " +"type='EditRecordLabel' " +"/> " +"<widget name='AuthorEdit' " +"type='EditRecord' " +"/> " +"</layout> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='NameLabel' " +"type='EditRecordLabel' " +"/> " +"<widget name='NameEdit' " +"type='EditRecord' " +"/> " +"</layout> " +"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"<widget name='NotesLabel' " +"type='EditRecordLabel' " +"/> " +"<widget name='NotesEdit' " +"type='EditRecord' " +"/> " +"</layout> " +"<layout type='horizontal' spacing='5' padding='0,0,0,0'> " +"<widget name='Cancel' " +"type='Button' " +"/> " +"<widget name='OK' " +"type='Button' " +"/> " +"</layout> " +"</layout> " +"</dialog> " +"<dialog name='ScummHelp' overlays='screen'> " +"<layout type='vertical' padding='8,8,8,8'> " +"<widget name='Title' " +"width='180' "  "height='Globals.Line.Height' "  "/> "  "<widget name='HelpText' " -"height='200' " +"height='140' "  "/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"<layout type='horizontal' padding='0,0,0,0'> "  "<widget name='Prev' "  "type='Button' "  "/> " @@ -2725,7 +2951,7 @@  "<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'> "  "<layout type='vertical' padding='8,8,8,8' center='true'> "  "<widget name='Description1' " -"width='320' " +"width='280' "  "height='Globals.Line.Height' "  "/> "  "<widget name='Description2' " @@ -2743,20 +2969,20 @@  "</layout> "  "</dialog> "  "<dialog name='MassAdd' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,32,8' center='true'> " +"<layout type='vertical' padding='4,4,16,4' center='true'> "  "<widget name='DirProgressText' " -"width='480' " +"width='280' "  "height='Globals.Line.Height' "  "/> "  "<widget name='GameProgressText' " -"width='480' " +"width='280' "  "height='Globals.Line.Height' "  "/> "  "<widget name='GameList' " -"width='480' " -"height='250' " +"width='280' " +"height='100' "  "/> " -"<layout type='horizontal' padding='8,8,8,8'> " +"<layout type='horizontal' padding='4,4,4,4'> "  "<widget name='Ok' "  "type='Button' "  "/> " @@ -2767,20 +2993,20 @@  "</layout> "  "</dialog> "  "<dialog name='KeyMapper' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'> " +"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'> "  "<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> "  "<widget name='PopupDesc' "  "type='OptionsLabel' "  "/> "  "<widget name='Popup' "  "type='PopUp' " -"width='400' " +"width='150' "  "height='Globals.Line.Height' "  "/> "  "</layout> "  "<widget name='KeymapArea' " -"width='600' " -"height='280' " +"width='300' " +"height='120' "  "/> "  "<widget name='Close' "  "type='Button' " @@ -2788,93 +3014,91 @@  "</layout> "  "</dialog> "  "<dialog name='Predictive' overlays='screen_center'> " -"<layout type='vertical' padding='5,5,5,5' center='true'> " +"<layout type='vertical' padding='1,1,1,1' center='true'> "  "<widget name='Headline' "  "height='Globals.Line.Height' " -"width='210' " +"width='150' "  "textalign='center' "  "/> " -"<layout type='horizontal' padding='5,5,5,5'> " +"<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Word' " -"width='190' " +"width='120' "  "height='Globals.Button.Height' "  "/> "  "<widget name='Delete' "  "width='20' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "</layout> " -"<space size='5' /> "  "<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Button1' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button2' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button3' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "</layout> "  "<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Button4' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button5' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button6' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "</layout> "  "<layout type='horizontal' padding='3,3,3,3'> "  "<widget name='Button7' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button8' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button9' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"<layout type='horizontal' padding='3,3,3,0'> "  "<widget name='Pre' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Button0' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='Next' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "</layout> " -"<space size='5' /> " -"<layout type='horizontal' padding='3,3,3,3'> " +"<space size='3' /> " +"<layout type='horizontal' padding='3,3,0,3'> "  "<widget name='Add' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> " -"<space size='22'/> "  "<widget name='Cancel' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "<widget name='OK' "  "width='Globals.Predictive.Button.Width' " -"height='Globals.Button.Height' " +"height='Globals.Predictive.Button.Height' "  "/> "  "</layout> "  "</layout> " diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differindex 297ff20344..4154c6c33a 100644 --- a/gui/themes/scummclassic.zip +++ b/gui/themes/scummclassic.zip diff --git a/gui/themes/scummclassic/classic_layout.stx b/gui/themes/scummclassic/classic_layout.stx index 180e8fba74..5fd2d6f835 100644 --- a/gui/themes/scummclassic/classic_layout.stx +++ b/gui/themes/scummclassic/classic_layout.stx @@ -36,6 +36,9 @@  		<def var = 'ShowChooserPageDisplay' value = '1'/>  		<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '1'/> +		<def var = 'RecorderDialog.ExtInfo.Visible' value = '1'/> + +		<def var = 'OnScreenDialog.ShowPics' value = '0'/>  		<def var = 'KeyMapper.Spacing' value = '10'/>  		<def var = 'KeyMapper.LabelWidth' value = '100'/> @@ -101,6 +104,12 @@  				size = '15, 18'  				padding = '0, 3, 4, 0'  		/> +		<widget name = 'EditRecordLabel' +				size = '60, 25' +		/> +		<widget name = 'EditRecord' +				size = '240, 25' +		/>  	</globals>  	<dialog name = 'Launcher' overlays = 'screen'> @@ -1019,6 +1028,125 @@  		</layout>  	</dialog> +	<dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> +		<layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'> +			<widget name = 'Title' +					height = 'Globals.Line.Height' +			/> +			<layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'> +				<widget name = 'List' /> +				<layout type = 'vertical' padding = '0, 0, 0, 0'> +					<widget name = 'Thumbnail' +							width = '180' +							height = '170' +					/> +					<layout type = 'horizontal' padding = '0, 0, 0, 0'>	 +						<widget name = 'NextScreenShotButton' +								width = '25' +								height = '25' +						/> +						<widget name = 'currentScreenshot' +								width = '125' +								height = '25' +								textalign = 'center' +						/> +						<widget name = 'PreviousScreenShotButton' +								width = '25' +								height = '25' +						/> +					</layout> +					<widget name = 'Author' height = 'Globals.Line.Height' /> +					<widget name = 'Notes' height = 'Globals.Line.Height' /> +				</layout> +			</layout> +			<layout type = 'horizontal' padding = '0, 0, 0, 0'> +				<widget name = 'Delete' +						type = 'Button' +				/> +				<space size = '16'/> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<space size = '16'/> +				<widget name = 'Edit' +						type = 'Button' +				/> +				<widget name = 'Record' +						type = 'Button' +				/> +				<widget name = 'Playback' +						type = 'Button' +				/> +			</layout> +		</layout> +	</dialog> + +	<dialog name = 'OnScreenDialog' overlays = 'screen_center'> +		<layout type = 'horizontal'  spacing = '5' padding = '5, 3, 5, 3' center = 'true'> +			<widget name = 'StopButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'EditButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'SwitchModeButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'FastReplayButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'TimeLabel' +				width = '50' +				height = '30' +			/> +		</layout> +	</dialog> + +	<dialog name = 'EditRecordDialog' overlays = 'screen_center'> +		<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> +			<widget name = 'Title' +					width = '320' +					height = 'Globals.Line.Height' +			/> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'AuthorLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'AuthorEdit' +						type = 'EditRecord' +				/>		 +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NameLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'NameEdit' +						type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NotesLabel' +						type = 'EditRecordLabel' +				/> +				<widget name = 'NotesEdit' +						type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<widget name = 'OK' +						type = 'Button' +				/>			 +			</layout> +		</layout> +	</dialog> +	  	<dialog name = 'ScummHelp' overlays = 'screen_center'>  		<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>  			<widget name = 'Title' diff --git a/gui/themes/scummclassic/classic_layout_lowres.stx b/gui/themes/scummclassic/classic_layout_lowres.stx index 8bb03dea17..802998df3c 100644 --- a/gui/themes/scummclassic/classic_layout_lowres.stx +++ b/gui/themes/scummclassic/classic_layout_lowres.stx @@ -37,6 +37,9 @@  		<def var = 'ShowChooserPageDisplay' value = '0'/>  		<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/> +		<def var = 'RecorderDialog.ExtInfo.Visible' value = '0'/> + +		<def var = 'OnScreenDialog.ShowPics' value = '0'/>  		<def var = 'KeyMapper.Spacing' value = '5'/>  		<def var = 'KeyMapper.LabelWidth' value = '80'/> @@ -99,6 +102,12 @@  				size = '32, 18'  				padding = '0, 0, 1, 0'  		/> +		<widget name = 'EditRecordLabel' +				size = '60, Globals.Line.Height' +		/> +		<widget name = 'EditRecord' +				size = '120, 15' +		/>  	</globals>  	<dialog name = 'Launcher' overlays = 'screen'> @@ -1013,6 +1022,101 @@  		</layout>  	</dialog> +	<dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> +		<layout type = 'vertical' padding = '8, 8, 8, 4' center = 'true'> +			<widget name = 'Title' +					height = 'Globals.Line.Height' +			/> +			<widget name = 'List' /> +			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> +			  <widget name = 'Edit' +					  type = 'Button' +					  /> +			  <space /> +			  <widget name = 'Record' +					  type = 'Button' +					  /> +			</layout> +			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> +			  <widget name = 'Delete' +					  type = 'Button' +					  /> +			  <space /> +			  <widget name = 'Cancel' +					  type = 'Button' +					  /> +			  <widget name = 'Playback' +					  type = 'Button' +					  /> +			</layout> +		</layout> +	</dialog> + +	<dialog name = 'OnScreenDialog' overlays = 'screen_center'> +		<layout type = 'horizontal'  spacing = '5' padding = '3, 2, 3, 2' center = 'true'> +			<widget name = 'StopButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'EditButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'SwitchModeButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'FastReplayButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'TimeLabel' +				width = '50' +				height = '16' +			/> +		</layout> +	</dialog> + +	<dialog name = 'EditRecordDialog' overlays = 'screen_center'> +		<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> +			<widget name = 'Title' +					height = 'Globals.Line.Height' +			/> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'AuthorLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'AuthorEdit' +						type = 'EditRecord' +				/>		 +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NameLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'NameEdit' +							type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NotesLabel' +						type = 'EditRecordLabel' +				/> +				<widget name = 'NotesEdit' +							type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 0'> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<widget name = 'OK' +						type = 'Button' +				/>			 +			</layout> +		</layout> +	</dialog> +  	<dialog name = 'ScummHelp' overlays = 'screen'>  		<layout type = 'vertical' padding = '8, 8, 8, 8'>  			<widget name = 'Title' diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip Binary files differindex dbd84992e6..3925c67121 100644 --- a/gui/themes/scummmodern.zip +++ b/gui/themes/scummmodern.zip diff --git a/gui/themes/scummmodern/editbtn.bmp b/gui/themes/scummmodern/editbtn.bmp Binary files differnew file mode 100644 index 0000000000..49eb4035b5 --- /dev/null +++ b/gui/themes/scummmodern/editbtn.bmp diff --git a/gui/themes/scummmodern/editbtn_small.bmp b/gui/themes/scummmodern/editbtn_small.bmp Binary files differnew file mode 100644 index 0000000000..8a0357fc2e --- /dev/null +++ b/gui/themes/scummmodern/editbtn_small.bmp diff --git a/gui/themes/scummmodern/fastreplay.bmp b/gui/themes/scummmodern/fastreplay.bmp Binary files differnew file mode 100644 index 0000000000..35ad2b4444 --- /dev/null +++ b/gui/themes/scummmodern/fastreplay.bmp diff --git a/gui/themes/scummmodern/fastreplay_small.bmp b/gui/themes/scummmodern/fastreplay_small.bmp Binary files differnew file mode 100644 index 0000000000..8ef004c3bf --- /dev/null +++ b/gui/themes/scummmodern/fastreplay_small.bmp diff --git a/gui/themes/scummmodern/scummmodern_gfx.stx b/gui/themes/scummmodern/scummmodern_gfx.stx index 4d449f50ec..1b3bcea0d6 100644 --- a/gui/themes/scummmodern/scummmodern_gfx.stx +++ b/gui/themes/scummmodern/scummmodern_gfx.stx @@ -103,6 +103,14 @@  		<bitmap filename = 'delbtn.bmp'/>  		<bitmap filename = 'list.bmp'/>  		<bitmap filename = 'grid.bmp'/> +		<bitmap filename = 'stopbtn.bmp'/> +		<bitmap filename = 'editbtn.bmp'/> +		<bitmap filename = 'switchbtn.bmp'/> +		<bitmap filename = 'fastreplay.bmp'/> +		<bitmap filename = 'stopbtn_small.bmp'/> +		<bitmap filename = 'editbtn_small.bmp'/> +		<bitmap filename = 'switchbtn_small.bmp'/> +		<bitmap filename = 'fastreplay_small.bmp'/>  	</bitmaps>  	<fonts> diff --git a/gui/themes/scummmodern/scummmodern_layout.stx b/gui/themes/scummmodern/scummmodern_layout.stx index 49c13cf1b0..4fd6ae6eba 100644 --- a/gui/themes/scummmodern/scummmodern_layout.stx +++ b/gui/themes/scummmodern/scummmodern_layout.stx @@ -43,6 +43,9 @@  		<def var = 'ShowChooserPageDisplay' value = '1'/>  		<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '1'/> +		<def var = 'RecorderDialog.ExtInfo.Visible' value = '1'/> + +		<def var = 'OnScreenDialog.ShowPics' value = '1'/>  		<def var = 'KeyMapper.Spacing' value = '10'/>  		<def var = 'KeyMapper.LabelWidth' value = '100'/> @@ -106,6 +109,13 @@  				size = '15, 18'  				padding = '0, 3, 4, 0'  		/> + +		<widget name = 'EditRecordLabel' +				size = '60, 25' +		/> +		<widget name = 'EditRecord' +				size = '240, 25' +		/>  	</globals>  	<dialog name = 'Launcher' overlays = 'screen'> @@ -1032,6 +1042,126 @@  		</layout>  	</dialog> +	<dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> +		<layout type = 'vertical' padding = '8, 8, 8, 32' center = 'true'> +			<widget name = 'Title' +					height = 'Globals.Line.Height' +			/> +			<layout type = 'horizontal' padding = '0, 0, 0, 16' spacing = '16'> +				<widget name = 'List' /> +				<layout type = 'vertical' padding = '0, 0, 0, 0'> +					<widget name = 'Thumbnail' +							width = '180' +							height = '170' +					/> +					<layout type = 'horizontal' padding = '0, 0, 0, 0'>	 +						<widget name = 'NextScreenShotButton' +								width = '25' +								height = '25' +						/> +						<widget name = 'currentScreenshot' +								width = '125' +								height = '25' +								textalign = 'center' +						/> +						<widget name = 'PreviousScreenShotButton' +								width = '25' +								height = '25' +						/> +					</layout> +					<widget name = 'Author' height = 'Globals.Line.Height' /> +					<widget name = 'Notes' height = 'Globals.Line.Height' /> +				</layout> +			</layout> +			<layout type = 'horizontal' padding = '0, 0, 0, 0'> +				<space/> +				<widget name = 'Delete' +						type = 'Button' +				/> +				<space size = '16'/> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<space size = '16'/> +				<widget name = 'Edit' +						type = 'Button' +				/> +				<widget name = 'Record' +						type = 'Button' +				/> +				<widget name = 'Playback' +						type = 'Button' +				/> +			</layout> +		</layout> +	</dialog> + +	<dialog name = 'OnScreenDialog' overlays = 'screen_center'> +		<layout type = 'horizontal'  spacing = '5' padding = '5, 3, 5, 3' center = 'true'> +			<widget name = 'StopButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'EditButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'SwitchModeButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'FastReplayButton' +				width = '32' +				height = '32' +			/> +			<widget name = 'TimeLabel' +				width = '50' +				height = '30' +			/> +		</layout> +	</dialog> + +	<dialog name = 'EditRecordDialog' overlays = 'screen_center'> +		<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> +			<widget name = 'Title' +					width = '320' +					height = 'Globals.Line.Height' +			/> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'AuthorLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'AuthorEdit' +						type = 'EditRecord' +				/>		 +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NameLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'NameEdit' +						type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NotesLabel' +						type = 'EditRecordLabel' +				/> +				<widget name = 'NotesEdit' +						type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<widget name = 'OK' +						type = 'Button' +				/>			 +			</layout> +		</layout> +	</dialog> +	  	<dialog name = 'ScummHelp' overlays = 'screen_center'>  		<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'>  			<widget name = 'Title' diff --git a/gui/themes/scummmodern/scummmodern_layout_lowres.stx b/gui/themes/scummmodern/scummmodern_layout_lowres.stx index 9658402f82..cee1e4af2b 100644 --- a/gui/themes/scummmodern/scummmodern_layout_lowres.stx +++ b/gui/themes/scummmodern/scummmodern_layout_lowres.stx @@ -35,6 +35,9 @@  		<def var = 'ShowChooserPageDisplay' value = '0'/>  		<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/> +		<def var = 'RecorderDialog.ExtInfo.Visible' value = '0'/> + +		<def var = 'OnScreenDialog.ShowPics' value = '1'/>  		<def var = 'Predictive.Button.Width' value = '45' />  		<def var = 'Predictive.Button.Height' value = '15' /> @@ -97,6 +100,12 @@  				size = '32, 18'  				padding = '0, 0, 2, 0'  		/> +		<widget name = 'EditRecordLabel' +				size = '60, Globals.Line.Height' +		/> +		<widget name = 'EditRecord' +				size = '120, 15' +		/>  	</globals>  	<dialog name = 'Launcher' overlays = 'screen'> @@ -1012,6 +1021,122 @@  		</layout>  	</dialog> +	<dialog name = 'SavenameDialog' overlays = 'screen_center'> +		<layout type = 'vertical' padding = '8, 8, 8, 8'> +			<widget name = 'DescriptionText' +					width = '320' +					height = 'Globals.Line.Height' +			/> +			<widget name = 'Description' +					height = '19' +			/> +			<layout type = 'horizontal' padding = '0, 0, 16, 0'> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<space size = '96'/> +				<widget name = 'Ok' +						type = 'Button' +				/> +			</layout> +		</layout> +	</dialog> + +	<dialog name = 'RecorderDialog' overlays = 'screen' inset = '8' shading = 'dim'> +		<layout type = 'vertical' padding = '8, 8, 8, 4' center = 'true'> +			<widget name = 'Title' +					height = 'Globals.Line.Height' +			/> +			<widget name = 'List' /> +			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> +			  <widget name = 'Edit' +					  type = 'Button' +					  /> +			  <space /> +			  <widget name = 'Record' +					  type = 'Button' +					  /> +			</layout> +			<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '2'> +			  <widget name = 'Delete' +					  type = 'Button' +					  /> +			  <space /> +			  <widget name = 'Cancel' +					  type = 'Button' +					  /> +			  <widget name = 'Playback' +					  type = 'Button' +					  /> +			</layout> +		</layout> +	</dialog> + +	<dialog name = 'OnScreenDialog' overlays = 'screen_center'> +		<layout type = 'horizontal'  spacing = '5' padding = '3, 2, 3, 2' center = 'true'> +			<widget name = 'StopButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'EditButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'SwitchModeButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'FastReplayButton' +				width = '16' +				height = '16' +			/> +			<widget name = 'TimeLabel' +				width = '50' +				height = '16' +			/> +		</layout> +	</dialog> + +	<dialog name = 'EditRecordDialog' overlays = 'screen_center'> +		<layout type = 'vertical' padding = '8, 8, 8, 8' center = 'true'> +			<widget name = 'Title' +					height = 'Globals.Line.Height' +			/> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'AuthorLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'AuthorEdit' +						type = 'EditRecord' +				/>		 +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NameLabel' +						type = 'EditRecordLabel' +				/>		 +				<widget name = 'NameEdit' +							type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 10'> +				<widget name = 'NotesLabel' +						type = 'EditRecordLabel' +				/> +				<widget name = 'NotesEdit' +							type = 'EditRecord' +				/> +			</layout> +			<layout type = 'horizontal'  spacing = '5' padding = '0, 0, 0, 0'> +				<widget name = 'Cancel' +						type = 'Button' +				/> +				<widget name = 'OK' +						type = 'Button' +				/>			 +			</layout> +		</layout> +	</dialog> +	  	<dialog name = 'ScummHelp' overlays = 'screen' inset = '8'>  		<layout type = 'vertical' padding = '8, 8, 8, 8'>  			<widget name = 'Title' diff --git a/gui/themes/scummmodern/stopbtn.bmp b/gui/themes/scummmodern/stopbtn.bmp Binary files differnew file mode 100644 index 0000000000..3575956694 --- /dev/null +++ b/gui/themes/scummmodern/stopbtn.bmp diff --git a/gui/themes/scummmodern/stopbtn_small.bmp b/gui/themes/scummmodern/stopbtn_small.bmp Binary files differnew file mode 100644 index 0000000000..ffd5025279 --- /dev/null +++ b/gui/themes/scummmodern/stopbtn_small.bmp diff --git a/gui/themes/scummmodern/switchbtn.bmp b/gui/themes/scummmodern/switchbtn.bmp Binary files differnew file mode 100644 index 0000000000..6bafa4a998 --- /dev/null +++ b/gui/themes/scummmodern/switchbtn.bmp diff --git a/gui/themes/scummmodern/switchbtn_small.bmp b/gui/themes/scummmodern/switchbtn_small.bmp Binary files differnew file mode 100644 index 0000000000..929b128884 --- /dev/null +++ b/gui/themes/scummmodern/switchbtn_small.bmp  | 
