diff --git a/Makefile b/Makefile index f9471579c5d..1c5b2c57039 100644 --- a/Makefile +++ b/Makefile @@ -75,7 +75,7 @@ EXECUTABLE := $(EXEPRE)residualvm$(EXEEXT) include $(srcdir)/Makefile.common # check if configure has been run or has been changed since last run -config.h config.mk: $(srcdir)/configure +config.h config.mk: $(srcdir)/configure $(srcdir)/engines/configure.engines ifeq "$(findstring config.mk,$(MAKEFILE_LIST))" "config.mk" @echo "Running $(srcdir)/configure with the last specified parameters" @sleep 2 diff --git a/audio/mixer.h b/audio/mixer.h index e38e052bef5..a0060f2e1a4 100644 --- a/audio/mixer.h +++ b/audio/mixer.h @@ -97,7 +97,7 @@ public: * @param stream the actual AudioStream to be played * @param id a unique id assigned to this stream * @param volume the volume with which to play the sound, ranging from 0 to 255 - * @param balance the balance with which to play the sound, ranging from -128 to 127 + * @param balance the balance with which to play the sound, ranging from -127 to 127 (full left to full right), 0 is balanced, -128 is invalid * @param autofreeStream a flag indicating whether the stream should be * freed after playback finished * @param permanent a flag indicating whether a plain stopAll call should diff --git a/backends/graphics/graphics.h b/backends/graphics/graphics.h index 9d6f0213891..fec4c940d2c 100644 --- a/backends/graphics/graphics.h +++ b/backends/graphics/graphics.h @@ -65,7 +65,7 @@ public: virtual int16 getWidth() = 0; virtual void setPalette(const byte *colors, uint start, uint num) = 0; virtual void grabPalette(byte *colors, uint start, uint num) = 0; - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) = 0; + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) = 0; virtual Graphics::Surface *lockScreen() = 0; virtual void unlockScreen() = 0; virtual void fillScreen(uint32 col) = 0; @@ -78,14 +78,14 @@ public: virtual void hideOverlay() = 0; virtual Graphics::PixelFormat getOverlayFormat() const = 0; virtual void clearOverlay() = 0; - virtual void grabOverlay(OverlayColor *buf, int pitch) = 0; - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h)= 0; + virtual void grabOverlay(void *buf, int pitch) = 0; + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h)= 0; virtual int16 getOverlayHeight() = 0; virtual int16 getOverlayWidth() = 0; virtual bool showMouse(bool visible) = 0; virtual void warpMouse(int x, int y) = 0; - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL) = 0; + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) = 0; virtual void setCursorPalette(const byte *colors, uint start, uint num) = 0; // ResidualVM specific method diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp index ce7c4df6153..31aa2e221a9 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.cpp +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.cpp @@ -431,7 +431,7 @@ void SurfaceSdlGraphicsManager::updateScreen() { } } -void SurfaceSdlGraphicsManager::copyRectToScreen(const byte *src, int pitch, int x, int y, int w, int h) { +void SurfaceSdlGraphicsManager::copyRectToScreen(const void *src, int pitch, int x, int y, int w, int h) { // ResidualVM: not use it } @@ -555,7 +555,7 @@ void SurfaceSdlGraphicsManager::clearOverlay() { _overlayDirty = true; } -void SurfaceSdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) { +void SurfaceSdlGraphicsManager::grabOverlay(void *buf, int pitch) { if (_overlayscreen == NULL) return; @@ -563,30 +563,33 @@ void SurfaceSdlGraphicsManager::grabOverlay(OverlayColor *buf, int pitch) { error("SDL_LockSurface failed: %s", SDL_GetError()); byte *src = (byte *)_overlayscreen->pixels; + byte *dst = (byte *)buf; int h = _overlayHeight; do { - memcpy(buf, src, _overlayWidth * _overlayscreen->format->BytesPerPixel); + memcpy(dst, src, _overlayWidth * _overlayscreen->format->BytesPerPixel); src += _overlayscreen->pitch; - buf += pitch; + dst += pitch; } while (--h); SDL_UnlockSurface(_overlayscreen); } -void SurfaceSdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { +void SurfaceSdlGraphicsManager::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { if (_overlayscreen == NULL) return; + const byte *src = (const byte*)buf; + // Clip the coordinates if (x < 0) { w += x; - buf -= x; + src -= x * 2; x = 0; } if (y < 0) { h += y; - buf -= y * pitch; + src -= y * pitch; y = 0; } @@ -606,9 +609,9 @@ void SurfaceSdlGraphicsManager::copyRectToOverlay(const OverlayColor *buf, int p byte *dst = (byte *)_overlayscreen->pixels + y * _overlayscreen->pitch + x * _overlayscreen->format->BytesPerPixel; do { - memcpy(dst, buf, w * _overlayscreen->format->BytesPerPixel); + memcpy(dst, src, w * _overlayscreen->format->BytesPerPixel); dst += _overlayscreen->pitch; - buf += pitch; + src += pitch; } while (--h); SDL_UnlockSurface(_overlayscreen); @@ -651,7 +654,7 @@ void SurfaceSdlGraphicsManager::warpMouse(int x, int y) { SDL_WarpMouse(x, y); } -void SurfaceSdlGraphicsManager::setMouseCursor(const byte *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { +void SurfaceSdlGraphicsManager::setMouseCursor(const void *buf, uint w, uint h, int hotspot_x, int hotspot_y, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { // ResidualVM: not use it } diff --git a/backends/graphics/surfacesdl/surfacesdl-graphics.h b/backends/graphics/surfacesdl/surfacesdl-graphics.h index b0499f7efe9..3b8d4d4be3d 100644 --- a/backends/graphics/surfacesdl/surfacesdl-graphics.h +++ b/backends/graphics/surfacesdl/surfacesdl-graphics.h @@ -85,7 +85,7 @@ protected: virtual void grabPalette(byte *colors, uint start, uint num); public: - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); virtual Graphics::Surface *lockScreen(); virtual void unlockScreen(); virtual void fillScreen(uint32 col); @@ -98,8 +98,8 @@ public: virtual void hideOverlay(); virtual Graphics::PixelFormat getOverlayFormat() const { return _overlayFormat; } virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); //ResidualVM specific implemention: virtual int16 getOverlayHeight() { return _overlayHeight; } virtual int16 getOverlayWidth() { return _overlayWidth; } @@ -107,7 +107,7 @@ public: virtual bool showMouse(bool visible); virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL); + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); virtual void setCursorPalette(const byte *colors, uint start, uint num); // ResidualVM specific method virtual bool lockMouse(bool lock); diff --git a/backends/midi/sndio.cpp b/backends/midi/sndio.cpp new file mode 100644 index 00000000000..21c9ea4feca --- /dev/null +++ b/backends/midi/sndio.cpp @@ -0,0 +1,152 @@ +/* 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. + */ + +// Disable symbol overrides so that we can use system headers. +#define FORBIDDEN_SYMBOL_ALLOW_ALL + +#include "common/scummsys.h" + +#if defined(USE_SNDIO) + +#include "common/error.h" +#include "common/textconsole.h" +#include "common/util.h" +#include "audio/musicplugin.h" +#include "audio/mpu401.h" + +#include + +//////////////////////////////////////// +// +// sndio MIDI driver +// +//////////////////////////////////////// + +class MidiDriver_Sndio : public MidiDriver_MPU401 { +public: + MidiDriver_Sndio(); + int open(); + bool isOpen() const { return hdl != NULL; } + void close(); + void send(uint32 b); + void sysEx(const byte *msg, uint16 length); + +private: + struct mio_hdl *hdl; +}; + +MidiDriver_Sndio::MidiDriver_Sndio() { + hdl = NULL; +} + +int MidiDriver_Sndio::open() { + if (hdl != NULL) + return MERR_ALREADY_OPEN; + + hdl = ::mio_open(NULL, MIO_OUT, 0); + if (hdl == NULL) + warning("Could open MIDI port (no music)"); + return 0; +} + +void MidiDriver_Sndio::close() { + MidiDriver_MPU401::close(); + if (!hdl) + return; + mio_close(hdl); + hdl = NULL; +} + +void MidiDriver_Sndio::send(uint32 b) { + unsigned char buf[4]; + unsigned int len; + + if (!hdl) + return; + buf[0] = b & 0xff; + buf[1] = (b >> 8) & 0xff; + buf[2] = (b >> 16) & 0xff; + buf[3] = (b >> 24) & 0xff; + switch (buf[0] & 0xf0) { + case 0xf0: + return; + case 0xc0: + case 0xd0: + len = 2; + break; + default: + len = 3; + } + mio_write(hdl, buf, len); +} + +void MidiDriver_Sndio::sysEx(const byte *msg, uint16 length) { + if (!hdl) + return; + + unsigned char buf[266]; + + assert(length + 2 <= ARRAYSIZE(buf)); + + // Add SysEx frame + buf[0] = 0xF0; + memcpy(buf + 1, msg, length); + buf[length + 1] = 0xF7; + + mio_write(hdl, buf, length + 2); +} + + +// Plugin interface + +class SndioMusicPlugin : public MusicPluginObject { +public: + const char *getName() const { + return "Sndio"; + } + + const char *getId() const { + return "sndio"; + } + + MusicDevices getDevices() const; + Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const; +}; + +MusicDevices SndioMusicPlugin::getDevices() const { + MusicDevices devices; + devices.push_back(MusicDevice(this, "", MT_GM)); + return devices; +} + +Common::Error SndioMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const { + *mididriver = new MidiDriver_Sndio(); + + return Common::kNoError; +} + +//#if PLUGIN_ENABLED_DYNAMIC(Sndio) + //REGISTER_PLUGIN_DYNAMIC(SNDIO, PLUGIN_TYPE_MUSIC, SndioMusicPlugin); +//#else + REGISTER_PLUGIN_STATIC(SNDIO, PLUGIN_TYPE_MUSIC, SndioMusicPlugin); +//#endif + +#endif diff --git a/backends/modular-backend.cpp b/backends/modular-backend.cpp index 893a11ecd1c..45e6bb86c56 100644 --- a/backends/modular-backend.cpp +++ b/backends/modular-backend.cpp @@ -136,7 +136,7 @@ PaletteManager *ModularBackend::getPaletteManager() { return _graphicsManager; } -void ModularBackend::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { +void ModularBackend::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { _graphicsManager->copyRectToScreen(buf, pitch, x, y, w, h); } @@ -183,11 +183,11 @@ void ModularBackend::clearOverlay() { _graphicsManager->clearOverlay(); } -void ModularBackend::grabOverlay(OverlayColor *buf, int pitch) { +void ModularBackend::grabOverlay(void *buf, int pitch) { _graphicsManager->grabOverlay(buf, pitch); } -void ModularBackend::copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) { +void ModularBackend::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { _graphicsManager->copyRectToOverlay(buf, pitch, x, y, w, h); } @@ -212,8 +212,8 @@ void ModularBackend::warpMouse(int x, int y) { _graphicsManager->warpMouse(x, y); } -void ModularBackend::setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale, const Graphics::PixelFormat *format) { - _graphicsManager->setMouseCursor(buf, w, h, hotspotX, hotspotY, keycolor, cursorTargetScale, format); +void ModularBackend::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + _graphicsManager->setMouseCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); } void ModularBackend::setCursorPalette(const byte *colors, uint start, uint num) { diff --git a/backends/modular-backend.h b/backends/modular-backend.h index f60bbb2b2eb..3209261ca47 100644 --- a/backends/modular-backend.h +++ b/backends/modular-backend.h @@ -84,7 +84,7 @@ public: virtual int16 getHeight(); virtual int16 getWidth(); virtual PaletteManager *getPaletteManager(); - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); virtual Graphics::Surface *lockScreen(); virtual void unlockScreen(); virtual void fillScreen(uint32 col); @@ -97,14 +97,14 @@ public: virtual void hideOverlay(); virtual Graphics::PixelFormat getOverlayFormat() const; virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h); + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); virtual int16 getOverlayHeight(); virtual int16 getOverlayWidth(); virtual bool showMouse(bool visible); virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL); + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); virtual void setCursorPalette(const byte *colors, uint start, uint num); // ResidualVM specific method virtual bool lockMouse(bool lock); diff --git a/backends/module.mk b/backends/module.mk index aaf419da1c9..5e33313876a 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -11,6 +11,7 @@ MODULE_OBJS := \ midi/alsa.o \ midi/dmedia.o \ midi/seq.o \ + midi/sndio.o \ midi/stmidi.o \ midi/timidity.o \ saves/savefile.o \ diff --git a/backends/platform/android/android.cpp b/backends/platform/android/android.cpp index 0ffc26ef83a..08e2d9c5162 100644 --- a/backends/platform/android/android.cpp +++ b/backends/platform/android/android.cpp @@ -560,6 +560,7 @@ void OSystem_Android::getTimeAndDate(TimeDate &td) const { td.tm_mday = tm.tm_mday; td.tm_mon = tm.tm_mon; td.tm_year = tm.tm_year; + td.tm_wday = tm.tm_wday; } void OSystem_Android::addSysArchivesToSearchSet(Common::SearchSet &s, diff --git a/backends/platform/android/android.h b/backends/platform/android/android.h index f8d65def2fa..37ebb0d0613 100644 --- a/backends/platform/android/android.h +++ b/backends/platform/android/android.h @@ -256,7 +256,7 @@ protected: virtual void grabPalette(byte *colors, uint start, uint num); public: - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h); virtual void updateScreen(); virtual Graphics::Surface *lockScreen(); @@ -269,8 +269,8 @@ public: virtual void showOverlay(); virtual void hideOverlay(); virtual void clearOverlay(); - virtual void grabOverlay(OverlayColor *buf, int pitch); - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, + virtual void grabOverlay(void *buf, int pitch); + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h); virtual int16 getOverlayHeight(); virtual int16 getOverlayWidth(); @@ -279,9 +279,9 @@ public: virtual bool showMouse(bool visible); virtual void warpMouse(int x, int y); - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, - int cursorTargetScale, + bool dontScale, const Graphics::PixelFormat *format); virtual void setCursorPalette(const byte *colors, uint start, uint num); diff --git a/backends/platform/android/gfx.cpp b/backends/platform/android/gfx.cpp index b3b8c0966cc..7194099837c 100644 --- a/backends/platform/android/gfx.cpp +++ b/backends/platform/android/gfx.cpp @@ -449,7 +449,7 @@ void OSystem_Android::grabPalette(byte *colors, uint start, uint num) { pf.colorToRGB(READ_UINT16(p), colors[0], colors[1], colors[2]); } -void OSystem_Android::copyRectToScreen(const byte *buf, int pitch, +void OSystem_Android::copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) { ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); @@ -694,33 +694,32 @@ void OSystem_Android::clearOverlay() { _overlay_texture->fillBuffer(0); } -void OSystem_Android::grabOverlay(OverlayColor *buf, int pitch) { +void OSystem_Android::grabOverlay(void *buf, int pitch) { ENTER("%p, %d", buf, pitch); GLTHREADCHECK; const Graphics::Surface *surface = _overlay_texture->surface_const(); - assert(surface->format.bytesPerPixel == sizeof(buf[0])); + assert(surface->format.bytesPerPixel == sizeof(uint16)); + byte *dst = (byte *)buf; const byte *src = (const byte *)surface->pixels; uint h = surface->h; do { - memcpy(buf, src, surface->w * surface->format.bytesPerPixel); + memcpy(dst, src, surface->w * surface->format.bytesPerPixel); src += surface->pitch; - // This 'pitch' is pixels not bytes - buf += pitch; + dst += pitch; } while (--h); } -void OSystem_Android::copyRectToOverlay(const OverlayColor *buf, int pitch, +void OSystem_Android::copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) { ENTER("%p, %d, %d, %d, %d, %d", buf, pitch, x, y, w, h); GLTHREADCHECK; - // This 'pitch' is pixels not bytes - _overlay_texture->updateBuffer(x, y, w, h, buf, pitch * sizeof(buf[0])); + _overlay_texture->updateBuffer(x, y, w, h, buf, pitch); } int16 OSystem_Android::getOverlayHeight() { @@ -743,12 +742,12 @@ bool OSystem_Android::showMouse(bool visible) { return true; } -void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, +void OSystem_Android::setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, - uint32 keycolor, int cursorTargetScale, + uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { ENTER("%p, %u, %u, %d, %d, %u, %d, %p", buf, w, h, hotspotX, hotspotY, - keycolor, cursorTargetScale, format); + keycolor, dontScale, format); GLTHREADCHECK; @@ -799,7 +798,7 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, byte *tmp = new byte[pitch * h]; // meh, a 16bit cursor without alpha bits... this is so silly - if (!crossBlit(tmp, buf, pitch, w * 2, w, h, + if (!crossBlit(tmp, (const byte *)buf, pitch, w * 2, w, h, _mouse_texture->getPixelFormat(), *format)) { LOGE("crossblit failed"); @@ -824,7 +823,8 @@ void OSystem_Android::setMouseCursor(const byte *buf, uint w, uint h, } _mouse_hotspot = Common::Point(hotspotX, hotspotY); - _mouse_targetscale = cursorTargetScale; + // TODO: Adapt to the new "do not scale" cursor logic. + _mouse_targetscale = 1; } void OSystem_Android::setCursorPaletteInternal(const byte *colors, diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 5ab71ad1029..33e7692d6a1 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -439,6 +439,7 @@ void OSystem_SDL::getTimeAndDate(TimeDate &td) const { td.tm_mday = t.tm_mday; td.tm_mon = t.tm_mon; td.tm_year = t.tm_year; + td.tm_wday = t.tm_wday; } Audio::Mixer *OSystem_SDL::getMixer() { diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp index 237c50a1ba7..64e7e778b60 100644 --- a/backends/saves/default/default-saves.cpp +++ b/backends/saves/default/default-saves.cpp @@ -97,7 +97,7 @@ Common::InSaveFile *DefaultSaveFileManager::openForLoading(const Common::String return Common::wrapCompressedReadStream(sf); } -Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename) { +Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String &filename, bool compress) { // Ensure that the savepath is valid. If not, generate an appropriate error. Common::String savePathName = getSavePath(); checkPath(Common::FSNode(savePathName)); @@ -112,7 +112,7 @@ Common::OutSaveFile *DefaultSaveFileManager::openForSaving(const Common::String // Open the file for saving Common::WriteStream *sf = file.createWriteStream(); - return Common::wrapCompressedWriteStream(sf); + return compress ? Common::wrapCompressedWriteStream(sf) : sf; } bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) { diff --git a/backends/saves/default/default-saves.h b/backends/saves/default/default-saves.h index 1ea87efc675..c7fca279bc5 100644 --- a/backends/saves/default/default-saves.h +++ b/backends/saves/default/default-saves.h @@ -38,7 +38,7 @@ public: virtual Common::StringArray listSavefiles(const Common::String &pattern); virtual Common::InSaveFile *openForLoading(const Common::String &filename); - virtual Common::OutSaveFile *openForSaving(const Common::String &filename); + virtual Common::OutSaveFile *openForSaving(const Common::String &filename, bool compress = true); virtual bool removeSavefile(const Common::String &filename); protected: diff --git a/backends/timer/default/default-timer.cpp b/backends/timer/default/default-timer.cpp index 8681102cd0b..9cd803f1481 100644 --- a/backends/timer/default/default-timer.cpp +++ b/backends/timer/default/default-timer.cpp @@ -59,7 +59,6 @@ void insertPrioQueue(TimerSlot *head, TimerSlot *newSlot) { DefaultTimerManager::DefaultTimerManager() : - _timerHandler(0), _head(0) { _head = new TimerSlot(); diff --git a/backends/timer/default/default-timer.h b/backends/timer/default/default-timer.h index e5a9dada792..5884979da05 100644 --- a/backends/timer/default/default-timer.h +++ b/backends/timer/default/default-timer.h @@ -34,7 +34,6 @@ private: typedef Common::HashMap TimerSlotMap; Common::Mutex _mutex; - void *_timerHandler; TimerSlot *_head; TimerSlotMap _callbacks; diff --git a/backends/vkeybd/virtual-keyboard-gui.cpp b/backends/vkeybd/virtual-keyboard-gui.cpp index 42f9707ddc3..75de86472f0 100644 --- a/backends/vkeybd/virtual-keyboard-gui.cpp +++ b/backends/vkeybd/virtual-keyboard-gui.cpp @@ -161,7 +161,7 @@ void VirtualKeyboardGUI::run() { _system->clearOverlay(); } _overlayBackup.create(_screenW, _screenH, _system->getOverlayFormat()); - _system->grabOverlay((OverlayColor *)_overlayBackup.pixels, _overlayBackup.w); + _system->grabOverlay(_overlayBackup.pixels, _overlayBackup.pitch); setupCursor(); @@ -171,7 +171,7 @@ void VirtualKeyboardGUI::run() { removeCursor(); - _system->copyRectToOverlay((OverlayColor *)_overlayBackup.pixels, _overlayBackup.w, 0, 0, _overlayBackup.w, _overlayBackup.h); + _system->copyRectToOverlay(_overlayBackup.pixels, _overlayBackup.pitch, 0, 0, _overlayBackup.w, _overlayBackup.h); if (!g_gui.isActive()) _system->hideOverlay(); _overlayBackup.free(); @@ -262,7 +262,7 @@ void VirtualKeyboardGUI::screenChanged() { _screenH = newScreenH; _overlayBackup.create(_screenW, _screenH, _system->getOverlayFormat()); - _system->grabOverlay((OverlayColor *)_overlayBackup.pixels, _overlayBackup.w); + _system->grabOverlay(_overlayBackup.pixels, _overlayBackup.pitch); if (!_kbd->checkModeResolutions()) { _displaying = false; @@ -371,7 +371,7 @@ void VirtualKeyboardGUI::redraw() { blit(&surf, &_dispSurface, _dispX - _dirtyRect.left, _dispY - _dirtyRect.top, _dispBackColor); } - _system->copyRectToOverlay((OverlayColor *)surf.pixels, surf.w, + _system->copyRectToOverlay(surf.pixels, surf.pitch, _dirtyRect.left, _dirtyRect.top, surf.w, surf.h); surf.free(); diff --git a/base/main.cpp b/base/main.cpp index ebce9ca83d4..c852aa4a467 100644 --- a/base/main.cpp +++ b/base/main.cpp @@ -55,6 +55,12 @@ #include "audio/mididrv.h" #include "audio/musicplugin.h" /* for music manager */ +#include "graphics/cursorman.h" +#include "graphics/fontman.h" +#ifdef USE_FREETYPE2 +#include "graphics/fonts/ttf.h" +#endif + #include "backends/keymapper/keymapper.h" #if defined(_WIN32_WCE) @@ -494,10 +500,18 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) { PluginManager::destroy(); GUI::GuiManager::destroy(); Common::ConfigManager::destroy(); + Common::DebugManager::destroy(); + Common::EventRecorder::destroy(); Common::SearchManager::destroy(); #ifdef USE_TRANSLATION Common::TranslationManager::destroy(); #endif + MusicManager::destroy(); + Graphics::CursorManager::destroy(); + Graphics::FontManager::destroy(); +#ifdef USE_FREETYPE2 + Graphics::shutdownTTF(); +#endif return 0; } diff --git a/base/plugins.cpp b/base/plugins.cpp index 7a13c6f8d5f..5a3b687a864 100644 --- a/base/plugins.cpp +++ b/base/plugins.cpp @@ -101,6 +101,9 @@ public: #if defined(USE_SEQ_MIDI) LINK_PLUGIN(SEQ) #endif + #if defined(USE_SNDIO) + LINK_PLUGIN(SNDIO) + #endif #if defined(__MINT__) LINK_PLUGIN(STMIDI) #endif diff --git a/base/version.cpp b/base/version.cpp index 7d85c27bbae..75f39fa5840 100644 --- a/base/version.cpp +++ b/base/version.cpp @@ -94,6 +94,10 @@ const char *gScummVMFeatures = "" "SEQ " #endif +#ifdef USE_SNDIO + "sndio " +#endif + #ifdef USE_TIMIDITY "TiMidity " #endif diff --git a/common/keyboard.h b/common/keyboard.h index e6db086598f..f9e94e66564 100644 --- a/common/keyboard.h +++ b/common/keyboard.h @@ -248,7 +248,10 @@ struct KeyState { * ASCII-value of the pressed key (if any). * This depends on modifiers, i.e. pressing the 'A' key results in * different values here depending on the status of shift, alt and - * caps lock. + * caps lock. This should be used rather than keycode for text input + * to avoid keyboard layout issues. For example you cannot assume that + * KEYCODE_0 without a modifier will be '0' (on AZERTY keyboards it is + * not). */ uint16 ascii; diff --git a/common/savefile.h b/common/savefile.h index 03a7b52add4..da787289ee1 100644 --- a/common/savefile.h +++ b/common/savefile.h @@ -104,11 +104,23 @@ public: virtual String popErrorDesc(); /** - * Open the savefile with the specified name in the given directory for saving. - * @param name the name of the savefile + * Open the savefile with the specified name in the given directory for + * saving. + * + * Saved games are compressed by default, and engines are expected to + * always write compressed saves. + * + * A notable exception is if uncompressed files are needed for + * compatibility with games not supported by ScummVM, such as character + * exports from the Quest for Glory series. QfG5 is a 3D game and won't be + * supported by ScummVM. + * + * @param name the name of the savefile + * @param compress toggles whether to compress the resulting save file + * (default) or not. * @return pointer to an OutSaveFile, or NULL if an error occurred. */ - virtual OutSaveFile *openForSaving(const String &name) = 0; + virtual OutSaveFile *openForSaving(const String &name, bool compress = true) = 0; /** * Open the file with the specified name in the given directory for loading. diff --git a/common/system.h b/common/system.h index bcb4fed307d..38636fa616d 100644 --- a/common/system.h +++ b/common/system.h @@ -80,6 +80,7 @@ struct TimeDate { int tm_mday; ///< day of month (1 - 31) int tm_mon; ///< month of year (0 - 11) int tm_year; ///< year - 1900 + int tm_wday; ///< days since Sunday (0 - 6) }; namespace LogMessageType { @@ -386,33 +387,22 @@ public: * * * The next layer is the overlay. It is composed over the game - * graphics. By default, it has exactly the same size and - * resolution as the game graphics. However, client code can - * specify an overlay scale (as an additional parameter to - * initSize()). This is meant to increase the resolution of the - * overlay while keeping its size the same as that of the game - * graphics. For example, if the overlay scale is 2, and the game - * graphics have a resolution of 320x200; then the overlay shall - * have a resolution of 640x400, but it still has the same - * physical size as the game graphics. - * The overlay usually uses 16bpp, but on some ports, only 8bpp - * are availble, so that is supported, too, via a compile time - * switch (see also the OverlayColor typedef in scummsys.h). - * + * graphics. Historically the overlay size had always been a + * multiple of the game resolution, for example when the game + * resolution was 320x200 and the user selected a 2x scaler and did + * not enable aspect ratio correction it had a size of 640x400. + * An exception was the aspect ratio correction, which did allow + * for non multiples of the vertical resolution of the game screen. + * Nowadays the overlay size does not need to have any relation to + * the game resolution though, for example the overlay resolution + * might be the same as the physical screen resolution. + * The overlay is forced to a 16bpp mode right now. * * Finally, there is the mouse layer. This layer doesn't have to * actually exist within the backend -- it all depends on how a * backend chooses to implement mouse cursors, but in the default * SDL backend, it really is a separate layer. The mouse can * have a palette of its own, if the backend supports it. - * The scale of the mouse cursor is called 'cursorTargetScale'. - * This is meant as a hint to the backend. For example, let us - * assume the overlay is not visible, and the game graphics are - * displayed using a 2x scaler. If a mouse cursor with a - * cursorTargetScale of 1 is set, then it should be scaled by - * factor 2x, too, just like the game graphics. But if it has a - * cursorTargetScale of 2, then it shouldn't be scaled again by - * the game graphics scaler. * * On a note for OSystem users here. We do not require our graphics * to be thread safe and in fact most/all backends using OpenGL are @@ -725,7 +715,7 @@ public: * @see updateScreen * @see getScreenFormat */ - virtual void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) = 0; + virtual void copyRectToScreen(const void *buf, int pitch, int x, int y, int w, int h) = 0; /** * !!! Not used in ResidualVM !!! @@ -821,14 +811,12 @@ public: * @name Overlay * In order to be able to display dialogs atop the game graphics, backends * must provide an overlay mode. - * !!! Not valid for ResidualVM !!! - * The overlay can be 8 or 16 bpp. Depending on which it is, OverlayColor - * is 8 or 16 bit. + * + * The overlay is currently forced at 16 bpp. * * For 'coolness' we usually want to have an overlay which is blended over * the game graphics. On backends which support alpha blending, this is - * no issue; but on other systems (in particular those which only support - * 8bpp), this needs some trickery. + * no issue; but on other systems this needs some trickery. * * Essentially, we fake (alpha) blending on these systems by copying the * current game graphics into the overlay buffer when activating the overlay, @@ -867,20 +855,14 @@ public: * Copy the content of the overlay into a buffer provided by the caller. * This is only used to implement fake alpha blending. */ - virtual void grabOverlay(OverlayColor *buf, int pitch) = 0; + virtual void grabOverlay(void *buf, int pitch) = 0; /** * Blit a graphics buffer to the overlay. * In a sense, this is the reverse of grabOverlay. * - * @note The pitch parameter actually contains the 'pixel pitch', i.e., - * the number of pixels per scanline, and not as usual the number of bytes - * per scanline. - * - * @todo Change 'pitch' to be byte and not pixel based - * * @param buf the buffer containing the graphics data source - * @param pitch the pixel pitch of the buffer (number of pixels in a scanline) + * @param pitch the pitch of the buffer (number of bytes in a scanline) * @param x the x coordinate of the destination rectangle * @param y the y coordinate of the destination rectangle * @param w the width of the destination rectangle @@ -889,7 +871,7 @@ public: * @see copyRectToScreen * @see grabOverlay */ - virtual void copyRectToOverlay(const OverlayColor *buf, int pitch, int x, int y, int w, int h) = 0; + virtual void copyRectToOverlay(const void *buf, int pitch, int x, int y, int w, int h) = 0; /** * Return the height of the overlay. @@ -956,10 +938,11 @@ public: * @param keycolor transparency color value. This should not exceed the maximum color value of the specified format. * In case it does the behavior is undefined. The backend might just error out or simply ignore the * value. (The SDL backend will just assert to prevent abuse of this). - * @param cursorTargetScale scale factor which cursor is designed for + * @param dontScale Whether the cursor should never be scaled. An exception are high ppi displays, where the cursor + * would be too small to notice otherwise, these are allowed to scale the cursor anyway. * @param format pointer to the pixel format which cursor graphic uses (0 means CLUT8) */ - virtual void setMouseCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int cursorTargetScale = 1, const Graphics::PixelFormat *format = NULL) = 0; + virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) = 0; /** * !!! Not used in ResidualVM !!! diff --git a/common/taskbar.h b/common/taskbar.h index ba99d4e4875..6f28028e746 100644 --- a/common/taskbar.h +++ b/common/taskbar.h @@ -34,7 +34,7 @@ namespace Common { * The TaskbarManager allows interaction with the ScummVM application icon: * - in the taskbar on Windows 7 and later * - in the launcher for Unity - * - in the dock on MacOSX + * - in the dock on Mac OS X * - ... * * This allows GUI code and engines to display a progress bar, an overlay icon and/or count diff --git a/common/updates.h b/common/updates.h index 1e0babdf6dc..4d58a216fb5 100644 --- a/common/updates.h +++ b/common/updates.h @@ -30,7 +30,7 @@ namespace Common { /** * The UpdateManager allows configuring of the automatic update checking * for systems that support it: - * - using Sparkle on MacOSX + * - using Sparkle on Mac OS X * - using WinSparkle on Windows * * Most of the update checking is completely automated and this class only diff --git a/configure b/configure index f65b5fb164d..3044b149fa8 100755 --- a/configure +++ b/configure @@ -816,8 +816,8 @@ Optional Libraries: installed (optional) --disable-fluidsynth disable fluidsynth MIDI driver [autodetect] - --with-sparkle-prefix=DIR Prefix where sparkle is installed (MacOSX only - optional) - --disable-sparkle disable sparkle automatic update support [MacOSX only - autodetect] + --with-sparkle-prefix=DIR Prefix where sparkle is installed (Mac OS X only - optional) + --disable-sparkle disable sparkle automatic update support [Mac OS X only - autodetect] --with-sdl-prefix=DIR Prefix where the sdl-config script is installed (optional) @@ -834,6 +834,9 @@ Optional Libraries: --with-libunity-prefix=DIR Prefix where libunity is installed (optional) --disable-libunity disable Unity launcher integration [autodetect] + --with-sndio-prefix=DIR Prefix where sndio is installed (optional) + --disable-sndio disable sndio MIDI driver [autodetect] + Some influential environment variables: LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory @@ -856,6 +859,8 @@ for ac_option in $@; do --disable-alsa) _alsa=no ;; --enable-seq-midi) _seq_midi=yes ;; --disable-seq-midi) _seq_midi=no ;; + --enable-sndio) _sndio=yes ;; + --disable-sndio) _sndio=no ;; --enable-timidity) _timidity=yes ;; --disable-timidity) _timidity=no ;; --enable-vorbis) _vorbis=yes ;; @@ -925,6 +930,11 @@ for ac_option in $@; do ALSA_CFLAGS="-I$arg/include" ALSA_LIBS="-L$arg/lib" ;; + --with-sndio-prefix=*) + arg=`echo $ac_option | cut -d '=' -f 2` + SNDIO_CFLAGS="-I$arg/include" + SNDIO_LIBS="-L$arg/lib" + ;; --with-ogg-prefix=*) arg=`echo $ac_option | cut -d '=' -f 2` OGG_CFLAGS="-I$arg/include" @@ -2211,6 +2221,9 @@ if test -n "$_host"; then CXXFLAGS="$CXXFLAGS -mips32" _backend="dingux" _mt32emu=no + _optimization_level=-O3 + # Disable alsa midi to get the port build on OpenDingux toolchain + _alsa=no _vkeybd=yes _build_hq_scalers=no _keymapper=no @@ -3242,6 +3255,25 @@ fi define_in_config_h_if_yes "$_seq_midi" 'USE_SEQ_MIDI' echo "$_seq_midi" +# +# Check for sndio +# +echocheck "sndio" +if test "$_sndio" = auto ; then + _sndio=no + cat > $TMPC << EOF +#include +int main(void) { struct sio_par par; sio_initpar(&par); return 0; } +EOF + cc_check $SNDIO_CFLAGS $SNDIO_LIBS -lsndio && _sndio=yes +fi +if test "$_sndio" = yes ; then + LIBS="$LIBS $SNDIO_LIBS -lsndio" + INCLUDES="$INCLUDES $SNDIO_CFLAGS" +fi +define_in_config_h_if_yes "$_sndio" 'USE_SNDIO' +echo "$_sndio" + # # Check for TiMidity(++) # diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp index e5e0676304e..a585c8022d5 100644 --- a/devtools/create_project/msbuild.cpp +++ b/devtools/create_project/msbuild.cpp @@ -250,7 +250,7 @@ void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::s if (setup.devTools || name == setup.projectName || name == "sword25" || name == "grim" || name == "myst3") { project << "\t\t\tfalse\n"; } else { - if (name == "tinsel" && !isRelease) + if (name == "residualvm" && !isRelease) project << "\t\t\tProgramDatabase\n"; if (warningsIterator != _projectWarnings.end()) diff --git a/devtools/create_project/visualstudio.cpp b/devtools/create_project/visualstudio.cpp index 2ebb408e013..2c58178e1e2 100644 --- a/devtools/create_project/visualstudio.cpp +++ b/devtools/create_project/visualstudio.cpp @@ -110,7 +110,7 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: std::string toolConfig; toolConfig = (!warnings.empty() ? "DisableSpecificWarnings=\"" + warnings + "\"" : ""); - toolConfig += (name == "tinsel" ? "DebugInformationFormat=\"3\" " : ""); + toolConfig += (name == "residualvm" ? "DebugInformationFormat=\"3\" " : ""); toolConfig += (name == "sword25" ? "DisableLanguageExtensions=\"false\" " : ""); toolConfig += (name == "grim" ? "DisableLanguageExtensions=\"false\" " : ""); toolConfig += (name == "myst3" ? "DisableLanguageExtensions=\"false\" " : ""); @@ -145,7 +145,7 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: void VisualStudioProvider::outputConfiguration(std::ostream &project, const BuildSetup &setup, const std::string &libraries, const std::string &config, const std::string &platform, const std::string &props, const bool isWin32) { project << "\t\t\n" - "\t\t\t\n" + "\t\t\t\n" "\t\t\t\n"; diff --git a/devtools/create_project/xcode.cpp b/devtools/create_project/xcode.cpp index 39470f4e19d..9784bb0bf57 100644 --- a/devtools/create_project/xcode.cpp +++ b/devtools/create_project/xcode.cpp @@ -871,7 +871,9 @@ std::string XCodeProvider::writeProperty(const std::string &variable, Property & std::string XCodeProvider::writeSetting(const std::string &variable, std::string value, std::string comment, int flags, int indent) const { return writeSetting(variable, Setting(value, comment, flags, indent)); } -// Heavily modified (not in a good way) function, imported from QMake XCode project generator (licensed under the QT license) + +// Heavily modified (not in a good way) function, imported from the QMake +// XCode project generator pbuilder_pbx.cpp, writeSettings() (under LGPL 2.1) std::string XCodeProvider::writeSetting(const std::string &variable, const Setting &setting) const { std::string output; const std::string quote = (setting.flags & SettingsNoQuote) ? "" : "\""; diff --git a/engines/dialogs.cpp b/engines/dialogs.cpp index b659c361559..84adbe6e8ca 100644 --- a/engines/dialogs.cpp +++ b/engines/dialogs.cpp @@ -111,10 +111,8 @@ MainMenuDialog::MainMenuDialog(Engine *engine) _aboutDialog = new GUI::AboutDialog(); _optionsDialog = new ConfigDialog(_engine->hasFeature(Engine::kSupportsSubtitleOptions)); - _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load")); - _loadDialog->setSaveMode(false); - _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save")); - _saveDialog->setSaveMode(true); + _loadDialog = new GUI::SaveLoadChooser(_("Load game:"), _("Load"), false); + _saveDialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); } MainMenuDialog::~MainMenuDialog() { @@ -216,26 +214,13 @@ void MainMenuDialog::reflowLayout() { } void MainMenuDialog::save() { - const Common::String gameId = ConfMan.get("gameid"); - - const EnginePlugin *plugin = 0; - EngineMan.findGame(gameId, &plugin); - - int slot = _saveDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int slot = _saveDialog->runModalWithCurrentTarget(); if (slot >= 0) { Common::String result(_saveDialog->getResultString()); if (result.empty()) { // If the user was lazy and entered no save name, come up with a default name. - #if defined(USE_SAVEGAME_TIMESTAMP) - TimeDate curTime; - g_system->getTimeAndDate(curTime); - curTime.tm_year += 1900; // fixup year - curTime.tm_mon++; // fixup month - result = Common::String::format("%04d.%02d.%02d / %02d:%02d:%02d", curTime.tm_year, curTime.tm_mon, curTime.tm_mday, curTime.tm_hour, curTime.tm_min, curTime.tm_sec); - #else - result = Common::String::format("Save %d", slot + 1); - #endif + result = _saveDialog->createDefaultSaveDescription(slot); } Common::Error status = _engine->saveGameState(slot, result); @@ -252,12 +237,7 @@ void MainMenuDialog::save() { } void MainMenuDialog::load() { - const Common::String gameId = ConfMan.get("gameid"); - - const EnginePlugin *plugin = 0; - EngineMan.findGame(gameId, &plugin); - - int slot = _loadDialog->runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); + int slot = _loadDialog->runModalWithCurrentTarget(); _engine->setGameToLoadSlot(slot); diff --git a/engines/grim/movie/codecs/smush_decoder.cpp b/engines/grim/movie/codecs/smush_decoder.cpp index df7226975f5..ea2be91b2eb 100644 --- a/engines/grim/movie/codecs/smush_decoder.cpp +++ b/engines/grim/movie/codecs/smush_decoder.cpp @@ -500,7 +500,7 @@ void SmushDecoder::setMsPerFrame(int ms) { _frameRate = Common::Rational(1000000, ms); } -void SmushDecoder::seekToTime(Audio::Timestamp time) { // FIXME: This will be off by a second or two right now. +void SmushDecoder::seekToTime(const Audio::Timestamp &time) { // FIXME: This will be off by a second or two right now. int32 wantedFrame = (uint32) ((time.msecs() / 1000.0f) * getFrameRate().toDouble()); warning("Seek to time: %d, frame: %d", time.msecs(), wantedFrame); warning("Current frame: %d", _curFrame); @@ -546,7 +546,7 @@ uint32 SmushDecoder::getDuration() const { uint32 SmushDecoder::getTimeToNextFrame() const { if (endOfVideo()) { //handle looping - uint32 elapsedTime = getElapsedTime(); + uint32 elapsedTime = getTime(); Common::Rational beginTime = (_curFrame + 1) * 1000; beginTime /= getFrameRate(); diff --git a/engines/grim/movie/codecs/smush_decoder.h b/engines/grim/movie/codecs/smush_decoder.h index b05f0fd32ff..2ba37d4a431 100644 --- a/engines/grim/movie/codecs/smush_decoder.h +++ b/engines/grim/movie/codecs/smush_decoder.h @@ -89,7 +89,7 @@ public: void close(); // Seekable - void seekToTime(Audio::Timestamp time); + void seekToTime(const Audio::Timestamp &time); uint32 getDuration() const; uint32 getTimeToNextFrame() const; diff --git a/engines/grim/movie/movie.cpp b/engines/grim/movie/movie.cpp index 7338a9857a8..56b518cb5db 100644 --- a/engines/grim/movie/movie.cpp +++ b/engines/grim/movie/movie.cpp @@ -105,7 +105,7 @@ bool MoviePlayer::prepareFrame() { _internalSurface = _videoDecoder->decodeNextFrame(); _updateNeeded = true; - _movieTime = _videoDecoder->getElapsedTime(); + _movieTime = _videoDecoder->getTime(); _frame = _videoDecoder->getCurFrame(); return true; diff --git a/engines/savestate.h b/engines/savestate.h index 6cbdb22edf1..c2335546574 100644 --- a/engines/savestate.h +++ b/engines/savestate.h @@ -40,6 +40,8 @@ struct Surface; * * Further possibilites are a thumbnail, play time, creation date, * creation time, delete protected, write protection. + * + * Saves are writable and deletable by default. */ class SaveStateDescriptor { public: diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index 78177256645..1ed5a3308ae 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -422,8 +422,8 @@ void VectorRendererSpec:: copyFrame(OSystem *sys, const Common::Rect &r) { sys->copyRectToOverlay( - (const OverlayColor *)_activeSurface->getBasePtr(r.left, r.top), - _activeSurface->pitch / _activeSurface->format.bytesPerPixel, + _activeSurface->getBasePtr(r.left, r.top), + _activeSurface->pitch, r.left, r.top, r.width(), r.height() ); } diff --git a/graphics/cursorman.cpp b/graphics/cursorman.cpp index 425714ea348..c8181016456 100644 --- a/graphics/cursorman.cpp +++ b/graphics/cursorman.cpp @@ -55,14 +55,14 @@ bool CursorManager::showMouse(bool visible) { return g_system->showMouse(visible); } -void CursorManager::pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { - Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format); +void CursorManager::pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { + Cursor *cur = new Cursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); cur->_visible = isVisible(); _cursorStack.push(cur); if (buf) { - g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format); + g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format); } } @@ -75,7 +75,7 @@ void CursorManager::popCursor() { if (!_cursorStack.empty()) { cur = _cursorStack.top(); - g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_targetScale, &cur->_format); + g_system->setMouseCursor(cur->_data, cur->_width, cur->_height, cur->_hotspotX, cur->_hotspotY, cur->_keycolor, cur->_dontScale, &cur->_format); } g_system->showMouse(isVisible()); @@ -98,10 +98,10 @@ void CursorManager::popAllCursors() { g_system->showMouse(isVisible()); } -void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { +void CursorManager::replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { if (_cursorStack.empty()) { - pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, targetScale, format); + pushCursor(buf, w, h, hotspotX, hotspotY, keycolor, dontScale, format); return; } @@ -131,7 +131,7 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, cur->_hotspotX = hotspotX; cur->_hotspotY = hotspotY; cur->_keycolor = keycolor; - cur->_targetScale = targetScale; + cur->_dontScale = dontScale; #ifdef USE_RGB_COLOR if (format) cur->_format = *format; @@ -139,7 +139,7 @@ void CursorManager::replaceCursor(const byte *buf, uint w, uint h, int hotspotX, cur->_format = Graphics::PixelFormat::createFormatCLUT8(); #endif - g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, targetScale, format); + g_system->setMouseCursor(cur->_data, w, h, hotspotX, hotspotY, keycolor, dontScale, format); } bool CursorManager::supportsCursorPalettes() { @@ -225,7 +225,7 @@ void CursorManager::replaceCursorPalette(const byte *colors, uint start, uint nu } } -CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale, const Graphics::PixelFormat *format) { +CursorManager::Cursor::Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale, const Graphics::PixelFormat *format) { #ifdef USE_RGB_COLOR if (!format) _format = Graphics::PixelFormat::createFormatCLUT8(); @@ -245,7 +245,7 @@ CursorManager::Cursor::Cursor(const byte *data, uint w, uint h, int hotspotX, in _height = h; _hotspotX = hotspotX; _hotspotY = hotspotY; - _targetScale = targetScale; + _dontScale = dontScale; } CursorManager::Cursor::~Cursor() { diff --git a/graphics/cursorman.h b/graphics/cursorman.h index 543a5d0a5c3..66e8d1ba56c 100644 --- a/graphics/cursorman.h +++ b/graphics/cursorman.h @@ -63,14 +63,15 @@ public: * @param hotspotY the hotspot Y coordinate * @param keycolor the color value for the transparent color. This may not exceed * the maximum color value as defined by format. - * @param targetScale the scale for which the cursor is designed + * @param dontScale Whether the cursor should never be scaled. An exception are high ppi displays, where the cursor + * would be too small to notice otherwise, these are allowed to scale the cursor anyway. * @param format a pointer to the pixel format which the cursor graphic uses, * CLUT8 will be used if this is NULL or not specified. * @note It is ok for the buffer to be a NULL pointer. It is sometimes * useful to push a "dummy" cursor and modify it later. The * cursor will be added to the stack, but not to the backend. */ - void pushCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale = 1, const Graphics::PixelFormat *format = NULL); + void pushCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); /** * Pop a cursor from the stack, and restore the previous one to the @@ -90,11 +91,12 @@ public: * @param hotspotY the hotspot Y coordinate * @param keycolor the color value for the transparent color. This may not exceed * the maximum color value as defined by format. - * @param targetScale the scale for which the cursor is designed + * @param dontScale Whether the cursor should never be scaled. An exception are high ppi displays, where the cursor + * would be too small to notice otherwise, these are allowed to scale the cursor anyway. * @param format a pointer to the pixel format which the cursor graphic uses, * CLUT8 will be used if this is NULL or not specified. */ - void replaceCursor(const byte *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale = 1, const Graphics::PixelFormat *format = NULL); + void replaceCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); /** * Pop all of the cursors and cursor palettes from their respective stacks. @@ -175,11 +177,11 @@ private: int _hotspotY; uint32 _keycolor; Graphics::PixelFormat _format; - int _targetScale; + bool _dontScale; uint _size; - Cursor(const byte *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, int targetScale = 1, const Graphics::PixelFormat *format = NULL); + Cursor(const void *data, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL); ~Cursor(); }; diff --git a/graphics/decoders/bmp.cpp b/graphics/decoders/bmp.cpp index 0d44881d7ce..5f764e1bd37 100644 --- a/graphics/decoders/bmp.cpp +++ b/graphics/decoders/bmp.cpp @@ -31,6 +31,7 @@ namespace Graphics { BitmapDecoder::BitmapDecoder() { _surface = 0; _palette = 0; + _paletteColorCount = 0; } BitmapDecoder::~BitmapDecoder() { @@ -44,6 +45,7 @@ void BitmapDecoder::destroy() { } delete[] _palette; _palette = 0; + _paletteColorCount = 0; } bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { @@ -95,16 +97,16 @@ bool BitmapDecoder::loadStream(Common::SeekableReadStream &stream) { /* uint32 imageSize = */ stream.readUint32LE(); /* uint32 pixelsPerMeterX = */ stream.readUint32LE(); /* uint32 pixelsPerMeterY = */ stream.readUint32LE(); - uint32 colorsUsed = stream.readUint32LE(); + _paletteColorCount = stream.readUint32LE(); /* uint32 colorsImportant = */ stream.readUint32LE(); - if (colorsUsed == 0) - colorsUsed = 256; + if (_paletteColorCount == 0) + _paletteColorCount = 256; if (bitsPerPixel == 8) { // Read the palette - _palette = new byte[colorsUsed * 3]; - for (uint16 i = 0; i < colorsUsed; i++) { + _palette = new byte[_paletteColorCount * 3]; + for (uint16 i = 0; i < _paletteColorCount; i++) { _palette[i * 3 + 2] = stream.readByte(); _palette[i * 3 + 1] = stream.readByte(); _palette[i * 3 + 0] = stream.readByte(); diff --git a/graphics/decoders/bmp.h b/graphics/decoders/bmp.h index 8a37538ee1a..59da682e4de 100644 --- a/graphics/decoders/bmp.h +++ b/graphics/decoders/bmp.h @@ -52,10 +52,12 @@ public: virtual bool loadStream(Common::SeekableReadStream &stream); virtual const Surface *getSurface() const { return _surface; } const byte *getPalette() const { return _palette; } + uint16 getPaletteColorCount() const { return _paletteColorCount; } private: Surface *_surface; byte *_palette; + uint16 _paletteColorCount; }; } // End of namespace Graphics diff --git a/graphics/decoders/image_decoder.h b/graphics/decoders/image_decoder.h index e768f7f9a20..7fa00749ffe 100644 --- a/graphics/decoders/image_decoder.h +++ b/graphics/decoders/image_decoder.h @@ -78,6 +78,11 @@ public: * @return the decoded palette, or 0 if no palette is present */ virtual const byte *getPalette() const { return 0; } + + /** Return the starting index of the palette. */ + virtual byte getPaletteStartIndex() const { return 0; } + /** Return the number of colors in the palette. */ + virtual uint16 getPaletteColorCount() const { return 0; } }; } // End of namespace Graphics diff --git a/graphics/fontman.cpp b/graphics/fontman.cpp index 8d967d595fa..99dd3d664f8 100644 --- a/graphics/fontman.cpp +++ b/graphics/fontman.cpp @@ -47,6 +47,13 @@ FontManager::FontManager() { } FontManager::~FontManager() { + for (uint i = 0; i < _ownedFonts.size(); ++i) { + const Font *font = _ownedFonts[i]; + if (font == g_sysfont || font == g_sysfont_big || font == g_consolefont) + continue; + delete font; + } + delete g_sysfont; g_sysfont = 0; delete g_sysfont_big; @@ -90,6 +97,8 @@ bool FontManager::assignFontToName(const Common::String &name, const Font *font) Common::String lowercaseName = name; lowercaseName.toLowercase(); _fontMap[lowercaseName] = font; + if (Common::find(_ownedFonts.begin(), _ownedFonts.end(), font) == _ownedFonts.end()) + _ownedFonts.push_back(font); return true; } @@ -116,8 +125,35 @@ bool FontManager::setFont(FontUsage usage, const BdfFont *font) { void FontManager::removeFontName(const Common::String &name) { Common::String lowercaseName = name; lowercaseName.toLowercase(); + if (!_fontMap.contains(lowercaseName)) + return; + + const Font *font = _fontMap[lowercaseName]; _fontMap.erase(lowercaseName); + // Check if we still have a copy of this font in the map. + bool stillHasFont = false; + for (Common::HashMap::iterator i = _fontMap.begin(); i != _fontMap.end(); ++i) { + if (i->_value != font) + continue; + stillHasFont = true; + break; + } + + if (!stillHasFont) { + // We don't have a copy of the font, so remove it from our list and delete it. + stillHasFont = true; + for (uint i = 0; i < _ownedFonts.size(); ++i) { + if (_ownedFonts[i] != font) + continue; + stillHasFont = false; + _ownedFonts.remove_at(i); + break; + } + assert(!stillHasFont); + delete font; + } + // In case the current localized font is removed, we fall back to the // default font again. if (_localizedFontName == lowercaseName) diff --git a/graphics/fontman.h b/graphics/fontman.h index 42f7d856fa5..b06ddea8602 100644 --- a/graphics/fontman.h +++ b/graphics/fontman.h @@ -60,7 +60,9 @@ public: const Font *getFontByName(const Common::String &name) const; /** - * Associates a font object with an 'name' + * Associates a font object with an 'name'. + * The FontManager takes ownership of the provided font object + * and will delete it when necesssary. * * @param name the name of the font * @param font the font object @@ -111,6 +113,7 @@ private: ~FontManager(); Common::HashMap _fontMap; + Common::Array _ownedFonts; Common::String _localizedFontName; }; diff --git a/graphics/fonts/bdf.h b/graphics/fonts/bdf.h index 5b615cc043b..b0166a2095b 100644 --- a/graphics/fonts/bdf.h +++ b/graphics/fonts/bdf.h @@ -77,7 +77,7 @@ private: #define DEFINE_FONT(n) \ const BdfFont *n = 0; \ void create_##n() { \ - n = new BdfFont(desc, DisposeAfterUse::YES); \ + n = new BdfFont(desc, DisposeAfterUse::NO); \ } #define FORWARD_DECLARE_FONT(n) \ diff --git a/graphics/fonts/ttf.cpp b/graphics/fonts/ttf.cpp index 7505f7913e4..96241e923cb 100644 --- a/graphics/fonts/ttf.cpp +++ b/graphics/fonts/ttf.cpp @@ -43,10 +43,6 @@ namespace Graphics { namespace { -inline int ftFloor26_6(FT_Pos x) { - return x / 64; -} - inline int ftCeil26_6(FT_Pos x) { return (x + 63) / 64; } @@ -70,6 +66,10 @@ private: bool _initialized; }; +void shutdownTTF() { + TTFLibrary::destroy(); +} + #define g_ttf ::Graphics::TTFLibrary::instance() TTFLibrary::TTFLibrary() : _library(), _initialized(false) { diff --git a/graphics/fonts/ttf.h b/graphics/fonts/ttf.h index 7222d6e112e..ec7dbe04ef1 100644 --- a/graphics/fonts/ttf.h +++ b/graphics/fonts/ttf.h @@ -34,6 +34,8 @@ namespace Graphics { class Font; Font *loadTTFFont(Common::SeekableReadStream &stream, int size, bool monochrome = false, const uint32 *mapping = 0); +void shutdownTTF(); + } // End of namespace Graphics #endif diff --git a/graphics/pixelformat.h b/graphics/pixelformat.h index e0cf6ce4016..ca4ef11c171 100644 --- a/graphics/pixelformat.h +++ b/graphics/pixelformat.h @@ -97,7 +97,7 @@ struct PixelFormat { } inline void colorToARGB(uint32 color, uint8 &a, uint8 &r, uint8 &g, uint8 &b) const { - a = ((color >> aShift) << aLoss) & 0xFF; + a = (aBits() == 0) ? 0xFF : (((color >> aShift) << aLoss) & 0xFF); r = ((color >> rShift) << rLoss) & 0xFF; g = ((color >> gShift) << gLoss) & 0xFF; b = ((color >> bShift) << bLoss) & 0xFF; diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index d9d91c1e9ea..0f37ca041ed 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -175,6 +175,7 @@ static const DrawDataInfo kDrawDataDefaults[] = { {kDDButtonIdle, "button_idle", true, kDDWidgetBackgroundSlider}, {kDDButtonHover, "button_hover", false, kDDButtonIdle}, {kDDButtonDisabled, "button_disabled", true, kDDNone}, + {kDDButtonPressed, "button_pressed", false, kDDButtonIdle}, {kDDSliderFull, "slider_full", false, kDDNone}, {kDDSliderHover, "slider_hover", false, kDDNone}, @@ -428,7 +429,7 @@ bool ThemeEngine::init() { void ThemeEngine::clearAll() { if (_initOk) { _system->clearOverlay(); - _system->grabOverlay((OverlayColor *)_screen.pixels, _screen.w); + _system->grabOverlay(_screen.pixels, _screen.pitch); } } @@ -453,7 +454,7 @@ void ThemeEngine::refresh() { if (_useCursor) { CursorMan.replaceCursorPalette(_cursorPal, 0, _cursorPalSize); - CursorMan.replaceCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, _cursorTargetScale); + CursorMan.replaceCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true); } } } @@ -464,7 +465,7 @@ void ThemeEngine::enable() { if (_useCursor) { CursorMan.pushCursorPalette(_cursorPal, 0, _cursorPalSize); - CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, _cursorTargetScale); + CursorMan.pushCursor(_cursor, _cursorWidth, _cursorHeight, _cursorHotspotX, _cursorHotspotY, 255, true); CursorMan.showMouse(true); } @@ -877,6 +878,8 @@ void ThemeEngine::drawButton(const Common::Rect &r, const Common::String &str, W dd = kDDButtonHover; else if (state == kStateDisabled) dd = kDDButtonDisabled; + else if (state == kStatePressed) + dd = kDDButtonPressed; queueDD(dd, r, 0, hints & WIDGET_CLEARBG); queueDDText(getTextData(dd), getTextColor(dd), r, str, false, true, _widgets[dd]->_textAlignH, _widgets[dd]->_textAlignV); @@ -1125,6 +1128,7 @@ void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, Wid break; case kStateEnabled: + case kStatePressed: colorId = kTextColorNormal; break; } @@ -1145,6 +1149,7 @@ void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, Wid break; case kStateEnabled: + case kStatePressed: colorId = kTextColorAlternative; break; } @@ -1282,7 +1287,7 @@ void ThemeEngine::openDialog(bool doBuffer, ShadingStyle style) { _vectorRenderer->setSurface(&_screen); } -bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale) { +bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int hotspotY) { if (!_system->hasFeature(OSystem::kFeatureCursorPalette)) return true; @@ -1300,7 +1305,6 @@ bool ThemeEngine::createCursor(const Common::String &filename, int hotspotX, int // Set up the cursor parameters _cursorHotspotX = hotspotX; _cursorHotspotY = hotspotY; - _cursorTargetScale = scale; _cursorWidth = cursor->w; _cursorHeight = cursor->h; diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index 0495a85c88c..21711e29557 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -35,7 +35,7 @@ #include "graphics/pixelformat.h" -#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.11" +#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.13" class OSystem; @@ -81,6 +81,7 @@ enum DrawData { kDDButtonIdle, kDDButtonHover, kDDButtonDisabled, + kDDButtonPressed, kDDSliderFull, kDDSliderHover, @@ -178,7 +179,8 @@ public: enum State { kStateDisabled, ///< Indicates that the widget is disabled, that does NOT include that it is invisible kStateEnabled, ///< Indicates that the widget is enabled - kStateHighlight ///< Indicates that the widget is highlighted by the user + kStateHighlight, ///< Indicates that the widget is highlighted by the user + kStatePressed ///< Indicates that the widget is pressed, currently works for buttons }; typedef State WidgetStateInfo; @@ -273,6 +275,11 @@ public: void enable(); void disable(); + /** + * Query the set up pixel format. + */ + const Graphics::PixelFormat getPixelFormat() const { return _overlayFormat; } + /** * Implementation of the GUI::Theme API. Called when a * new dialog is opened. Note that the boolean parameter @@ -493,9 +500,8 @@ public: * @param filename File name of the bitmap to load. * @param hotspotX X Coordinate of the bitmap which does the cursor click. * @param hotspotY Y Coordinate of the bitmap which does the cursor click. - * @param scale Scale at which the bitmap is supposed to be used. */ - bool createCursor(const Common::String &filename, int hotspotX, int hotspotY, int scale); + bool createCursor(const Common::String &filename, int hotspotX, int hotspotY); /** * Wrapper for restoring data from the Back Buffer to the screen. @@ -667,7 +673,6 @@ protected: bool _useCursor; int _cursorHotspotX, _cursorHotspotY; - int _cursorTargetScale; enum { MAX_CURS_COLORS = 255 }; diff --git a/gui/ThemeParser.cpp b/gui/ThemeParser.cpp index 9ccdedd5645..9a85399ed1b 100644 --- a/gui/ThemeParser.cpp +++ b/gui/ThemeParser.cpp @@ -218,15 +218,12 @@ bool ThemeParser::parserCallback_cursor(ParserNode *node) { return true; } - int spotx, spoty, scale; + int spotx, spoty; if (!parseIntegerKey(node->values["hotspot"], 2, &spotx, &spoty)) return parserError("Error parsing cursor Hot Spot coordinates."); - if (!parseIntegerKey(node->values["scale"], 1, &scale)) - return parserError("Error parsing cursor scale."); - - if (!_theme->createCursor(node->values["file"], spotx, spoty, scale)) + if (!_theme->createCursor(node->values["file"], spotx, spoty)) return parserError("Error creating Bitmap Cursor."); return true; diff --git a/gui/ThemeParser.h b/gui/ThemeParser.h index 4b7e88cbf37..82f774b8030 100644 --- a/gui/ThemeParser.h +++ b/gui/ThemeParser.h @@ -85,7 +85,6 @@ protected: XML_KEY(cursor) XML_PROP(file, true) XML_PROP(hotspot, true) - XML_PROP(scale, true) XML_PROP(resolution, false) KEY_END() diff --git a/gui/dialog.cpp b/gui/dialog.cpp index 2201e83ca54..ffca15bbc82 100644 --- a/gui/dialog.cpp +++ b/gui/dialog.cpp @@ -42,7 +42,7 @@ namespace GUI { Dialog::Dialog(int x, int y, int w, int h) : GuiObject(x, y, w, h), - _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false), + _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _tickleWidget(0), _visible(false), _backgroundType(GUI::ThemeEngine::kDialogBackgroundDefault) { // Some dialogs like LauncherDialog use internally a fixed size, even though // their widgets rely on the layout to be initialized correctly by the theme. @@ -54,7 +54,7 @@ Dialog::Dialog(int x, int y, int w, int h) Dialog::Dialog(const Common::String &name) : GuiObject(name), - _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _visible(false), + _mouseWidget(0), _focusedWidget(0), _dragWidget(0), _tickleWidget(0), _visible(false), _backgroundType(GUI::ThemeEngine::kDialogBackgroundDefault) { // It may happen that we have 3x scaler in launcher (960xY) and then 640x480 @@ -117,6 +117,12 @@ void Dialog::reflowLayout() { GuiObject::reflowLayout(); } +void Dialog::lostFocus() { + if (_tickleWidget) { + _tickleWidget->lostFocus(); + } +} + void Dialog::setFocusWidget(Widget *widget) { // The focus will change. Tell the old focused widget (if any) // that it lost the focus. @@ -308,6 +314,9 @@ void Dialog::handleTickle() { // Focused widget receives tickle notifications if (_focusedWidget && _focusedWidget->getFlags() & WIDGET_WANT_TICKLE) _focusedWidget->handleTickle(); + + if (_tickleWidget && _tickleWidget->getFlags() & WIDGET_WANT_TICKLE) + _tickleWidget->handleTickle(); } void Dialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { diff --git a/gui/dialog.h b/gui/dialog.h index f5a5f94a68b..1773c6633ea 100644 --- a/gui/dialog.h +++ b/gui/dialog.h @@ -52,6 +52,7 @@ protected: Widget *_mouseWidget; Widget *_focusedWidget; Widget *_dragWidget; + Widget *_tickleWidget; bool _visible; ThemeEngine::DialogBackground _backgroundType; @@ -71,7 +72,13 @@ public: void setFocusWidget(Widget *widget); Widget *getFocusWidget() { return _focusedWidget; } + void setTickleWidget(Widget *widget) { _tickleWidget = widget; } + void unSetTickleWidget() { _tickleWidget = NULL; } + Widget *getTickleWidget() { return _tickleWidget; } + virtual void reflowLayout(); + virtual void lostFocus(); + virtual void receivedFocus() {} protected: virtual void open(); diff --git a/gui/gui-manager.cpp b/gui/gui-manager.cpp index 15ff0c84741..84e43bab3c2 100644 --- a/gui/gui-manager.cpp +++ b/gui/gui-manager.cpp @@ -381,7 +381,7 @@ void GuiManager::runLoop() { if (tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) { Widget *wdg = activeDialog->findWidget(_lastMousePosition.x, _lastMousePosition.y); - if (wdg && wdg->getTooltip()) { + if (wdg && wdg->getTooltip() && !(wdg->getFlags() & WIDGET_PRESSED)) { Tooltip *tooltip = new Tooltip(); tooltip->setup(activeDialog, wdg, _lastMousePosition.x, _lastMousePosition.y); tooltip->runModal(); @@ -441,6 +441,11 @@ void GuiManager::restoreState() { } void GuiManager::openDialog(Dialog *dialog) { + dialog->receivedFocus(); + + if (!_dialogStack.empty()) + getTopDialog()->lostFocus(); + _dialogStack.push(dialog); if (_redrawStatus != kRedrawFull) _redrawStatus = kRedrawOpenDialog; @@ -458,7 +463,11 @@ void GuiManager::closeTopDialog() { return; // Remove the dialog from the stack - _dialogStack.pop(); + _dialogStack.pop()->lostFocus(); + + if (!_dialogStack.empty()) + getTopDialog()->receivedFocus(); + if (_redrawStatus != kRedrawFull) _redrawStatus = kRedrawCloseDialog; diff --git a/gui/launcher.cpp b/gui/launcher.cpp index 7bbfeccbd89..52b4be9fa3e 100644 --- a/gui/launcher.cpp +++ b/gui/launcher.cpp @@ -663,7 +663,6 @@ LauncherDialog::LauncherDialog() _list->setEditable(false); _list->setNumberingMode(kListNumberingOff); - // Populate the list updateListing(); @@ -678,7 +677,7 @@ LauncherDialog::LauncherDialog() _browser = new BrowserDialog(_("Select directory with game data"), true); // Create Load dialog - _loadDialog = new SaveLoadChooser(_("Load game:"), _("Load")); + _loadDialog = new SaveLoadChooser(_("Load game:"), _("Load"), false); } void LauncherDialog::selectTarget(const String &target) { diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp index 9cd18b81ba3..b827d494165 100644 --- a/gui/predictivedialog.cpp +++ b/gui/predictivedialog.cpp @@ -69,31 +69,33 @@ enum { PredictiveDialog::PredictiveDialog() : Dialog("Predictive") { new StaticTextWidget(this, "Predictive.Headline", "Enter Text"); - new ButtonWidget(this, "Predictive.Cancel" , _("Cancel"), 0, kCancelCmd); - new ButtonWidget(this, "Predictive.OK" , _("Ok") , 0, kOkCmd); - new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd); - new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd); - new ButtonWidget(this, "Predictive.Button3", "3 def" , 0, kBut3Cmd); - new ButtonWidget(this, "Predictive.Button4", "4 ghi" , 0, kBut4Cmd); - new ButtonWidget(this, "Predictive.Button5", "5 jkl" , 0, kBut5Cmd); - new ButtonWidget(this, "Predictive.Button6", "6 mno" , 0, kBut6Cmd); - new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , 0, kBut7Cmd); - new ButtonWidget(this, "Predictive.Button8", "8 tuv" , 0, kBut8Cmd); - new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd); - new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd); - // I18N: You must leave "#" as is, only word 'next' is translatable - new ButtonWidget(this, "Predictive.Next" , _("# next"), 0, kNextCmd); - _addBtn = new ButtonWidget(this, "Predictive.Add", _("add"), 0, kAddCmd); - _addBtn->setEnabled(false); + _btns = (ButtonWidget **)calloc(1, sizeof(ButtonWidget *) * 16); -#ifndef DISABLE_FANCY_THEMES - _delbtn = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd); - ((PicButtonWidget *)_delbtn)->useThemeTransparency(true); - ((PicButtonWidget *)_delbtn)->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageDelbtn)); -#endif - _delbtn = new ButtonWidget(this, "Predictive.Delete" , _("<"), 0, kDelCmd); - // I18N: Pre means 'Predictive', leave '*' as is - _modebutton = new ButtonWidget(this, "Predictive.Pre", _("* Pre"), 0, kModeCmd); + _btns[kCancelAct] = new ButtonWidget(this, "Predictive.Cancel", _("Cancel") , 0, kCancelCmd); + _btns[kOkAct] = new ButtonWidget(this, "Predictive.OK", _("Ok") , 0, kOkCmd); + _btns[kBtn1Act] = new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd); + _btns[kBtn2Act] = new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd); + _btns[kBtn3Act] = new ButtonWidget(this, "Predictive.Button3", "3 def" , 0, kBut3Cmd); + _btns[kBtn4Act] = new ButtonWidget(this, "Predictive.Button4", "4 ghi" , 0, kBut4Cmd); + _btns[kBtn5Act] = new ButtonWidget(this, "Predictive.Button5", "5 jkl" , 0, kBut5Cmd); + _btns[kBtn6Act] = new ButtonWidget(this, "Predictive.Button6", "6 mno" , 0, kBut6Cmd); + _btns[kBtn7Act] = new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , 0, kBut7Cmd); + _btns[kBtn8Act] = new ButtonWidget(this, "Predictive.Button8", "8 tuv" , 0, kBut8Cmd); + _btns[kBtn9Act] = new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd); + _btns[kBtn0Act] = new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd); + // I18N: You must leave "#" as is, only word 'next' is translatable + _btns[kNextAct] = new ButtonWidget(this, "Predictive.Next", _("# next") , 0, kNextCmd); + _btns[kAddAct] = new ButtonWidget(this, "Predictive.Add", _("add") , 0, kAddCmd); + _btns[kAddAct]->setEnabled(false); + + #ifndef DISABLE_FANCY_THEMES + _btns[kDelAct] = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd); + ((PicButtonWidget *)_btns[kDelAct])->useThemeTransparency(true); + ((PicButtonWidget *)_btns[kDelAct])->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageDelbtn)); + #endif + _btns[kDelAct] = new ButtonWidget(this, "Predictive.Delete" , _("<") , 0, kDelCmd); + // I18N: Pre means 'Predictive', leave '*' as is + _btns[kModeAct] = new ButtonWidget(this, "Predictive.Pre", _("* Pre"), 0, kModeCmd); _edittext = new EditTextWidget(this, "Predictive.Word", _search, 0, 0, 0); _userDictHasChanged = false; @@ -164,6 +166,8 @@ PredictiveDialog::~PredictiveDialog() { free(_userDict.dictLine); free(_predictiveDict.dictLine); free(_unitedDict.dictLine); + + free(_btns); } void PredictiveDialog::saveUserDictToFile() { @@ -182,11 +186,23 @@ void PredictiveDialog::saveUserDictToFile() { } } +void PredictiveDialog::handleKeyUp(Common::KeyState state) { + if (_currBtn != kNoAct && !_needRefresh) { + _btns[_currBtn]->startAnimatePressedState(); + processBtnActive(_currBtn); + } +} + void PredictiveDialog::handleKeyDown(Common::KeyState state) { - ButtonId act = kNoAct; + _currBtn = kNoAct; + _needRefresh = false; if (getFocusWidget() == _edittext) { - setFocusWidget(_addBtn); + setFocusWidget(_btns[kAddAct]); + } + + if (_lastbutton == kNoAct) { + _lastbutton = kBtn5Act; } switch (state.keycode) { @@ -197,96 +213,126 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) { case Common::KEYCODE_LEFT: _navigationwithkeys = true; if (_lastbutton == kBtn1Act || _lastbutton == kBtn4Act || _lastbutton == kBtn7Act) - act = ButtonId(_lastbutton + 2); - else if (_lastbutton == kNextAct) - act = kBtn0Act; - else if (_lastbutton == kDelAct) - act = kDelAct; - else if (_lastbutton == kCancelAct) - act = kOkAct; + _currBtn = ButtonId(_lastbutton + 2); + else if (_lastbutton == kDelAct) + _currBtn = kBtn1Act; else if (_lastbutton == kModeAct) - act = kAddAct; + _currBtn = kNextAct; + else if (_lastbutton == kNextAct) + _currBtn = kBtn0Act; + else if (_lastbutton == kAddAct) + _currBtn = kOkAct; + else if (_lastbutton == kCancelAct) + _currBtn = kAddAct; else - act = ButtonId(_lastbutton - 1); - _lastbutton = act; - //needRefresh = true; + _currBtn = ButtonId(_lastbutton - 1); + + + if (_mode != kModeAbc && _lastbutton == kCancelAct) + _currBtn = kOkAct; + + _needRefresh = true; break; case Common::KEYCODE_RIGHT: _navigationwithkeys = true; - if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act) - act = ButtonId(_lastbutton - 2); - else if (_lastbutton == kAddAct) - act = kModeAct; - else if (_lastbutton == kDelAct) - act = kDelAct; - else if (_lastbutton == kOkAct) - act = kCancelAct; + if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act || _lastbutton == kOkAct) + _currBtn = ButtonId(_lastbutton - 2); + else if (_lastbutton == kDelAct) + _currBtn = kBtn3Act; else if (_lastbutton == kBtn0Act) - act = kNextAct; + _currBtn = kNextAct; + else if (_lastbutton == kNextAct) + _currBtn = kModeAct; + else if (_lastbutton == kAddAct) + _currBtn = kCancelAct; + else if (_lastbutton == kOkAct) + _currBtn = kAddAct; else - act = ButtonId(_lastbutton + 1); - _lastbutton = act; - //needRefresh = true; + _currBtn = ButtonId(_lastbutton + 1); + + if (_mode != kModeAbc && _lastbutton == kOkAct) + _currBtn = kCancelAct; + _needRefresh = true; break; case Common::KEYCODE_UP: _navigationwithkeys = true; if (_lastbutton <= kBtn3Act) - act = kDelAct; - else if (_lastbutton == kNextAct || _lastbutton == kAddAct) - act = ButtonId(_lastbutton - 2); + _currBtn = kDelAct; else if (_lastbutton == kDelAct) - act = kOkAct; - else if (_lastbutton == kModeAct) - act = kBtn9Act; + _currBtn = kOkAct; + else if (_lastbutton == kModeAct) + _currBtn = kBtn7Act; else if (_lastbutton == kBtn0Act) - act = kBtn7Act; + _currBtn = kBtn8Act; + else if (_lastbutton == kNextAct) + _currBtn = kBtn9Act; + else if (_lastbutton == kAddAct) + _currBtn = kModeAct; + else if (_lastbutton == kCancelAct) + _currBtn = kBtn0Act; + else if (_lastbutton == kOkAct) + _currBtn = kNextAct; else - act = ButtonId(_lastbutton - 3); - _lastbutton = act; - //needRefresh = true; + _currBtn = ButtonId(_lastbutton - 3); + _needRefresh = true; break; case Common::KEYCODE_DOWN: _navigationwithkeys = true; - if (_lastbutton == kBtn7Act) - act = kBtn0Act; - else if (_lastbutton == kBtn8Act || _lastbutton == kBtn9Act) - act = ButtonId(_lastbutton + 2); - else if (_lastbutton == kDelAct) - act = kBtn1Act; - else if (_lastbutton == kCancelAct || _lastbutton == kOkAct) - act = kDelAct; - else if (_lastbutton == kModeAct || _lastbutton == kBtn0Act) - act = ButtonId(_lastbutton - 2); + if (_lastbutton == kDelAct) + _currBtn = kBtn3Act; + else if (_lastbutton == kBtn7Act) + _currBtn = kModeAct; + else if (_lastbutton == kBtn8Act) + _currBtn = kBtn0Act; + else if (_lastbutton == kBtn9Act) + _currBtn = kNextAct; + else if (_lastbutton == kModeAct) + _currBtn = kAddAct; + else if (_lastbutton == kBtn0Act) + _currBtn = kCancelAct; + else if (_lastbutton == kNextAct) + _currBtn = kOkAct; + else if (_lastbutton == kAddAct || _lastbutton == kCancelAct || _lastbutton == kOkAct) + _currBtn = kDelAct; else - act = ButtonId(_lastbutton + 3); - _lastbutton = act; - //needRefresh = true; + _currBtn = ButtonId(_lastbutton + 3); + + if (_mode != kModeAbc && _lastbutton == kModeAct) + _currBtn = kCancelAct; + + _needRefresh = true; break; case Common::KEYCODE_KP_ENTER: + case Common::KEYCODE_RETURN: + if (state.flags & Common::KBD_CTRL) { + _currBtn = kOkAct; + break; + } if (_navigationwithkeys) { // when the user has utilized arrow key navigation, - // interpret enter as 'click' on the act button - act = _lastbutton; + // interpret enter as 'click' on the _currBtn button + _currBtn = _lastbutton; + _needRefresh = false; } else { // else it is a shortcut for 'Ok' - act = kOkAct; + _currBtn = kOkAct; } break; case Common::KEYCODE_KP_PLUS: - act = kAddAct; + _currBtn = kAddAct; break; case Common::KEYCODE_BACKSPACE: case Common::KEYCODE_KP_MINUS: - act = kDelAct; + _currBtn = kDelAct; break; case Common::KEYCODE_KP_DIVIDE: - act = kNextAct; + _currBtn = kNextAct; break; case Common::KEYCODE_KP_MULTIPLY: - act = kModeAct; + _currBtn = kModeAct; break; case Common::KEYCODE_KP0: - act = kBtn0Act; + _currBtn = kBtn0Act; break; case Common::KEYCODE_KP1: case Common::KEYCODE_KP2: @@ -297,78 +343,93 @@ void PredictiveDialog::handleKeyDown(Common::KeyState state) { case Common::KEYCODE_KP7: case Common::KEYCODE_KP8: case Common::KEYCODE_KP9: - act = ButtonId(state.keycode - Common::KEYCODE_KP1); + _currBtn = ButtonId(state.keycode - Common::KEYCODE_KP1); break; default: Dialog::handleKeyDown(state); } - if (act != kNoAct) { - processBtnActive(act); + if (_lastbutton != _currBtn) + _btns[_lastbutton]->stopAnimatePressedState(); + + if (_currBtn != kNoAct && !_needRefresh) + _btns[_currBtn]->setPressedState(); + else + updateHighLightedButton(_currBtn); +} + +void PredictiveDialog::updateHighLightedButton(ButtonId act) { + if (_currBtn != kNoAct) { + _btns[_lastbutton]->setHighLighted(false); + _lastbutton = act; + _btns[_lastbutton]->setHighLighted(true); } } void PredictiveDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { - ButtonId act = kNoAct; + _currBtn = kNoAct; _navigationwithkeys = false; + if (_lastbutton != kNoAct) + _btns[_lastbutton]->setHighLighted(false); + switch (cmd) { case kDelCmd: - act = kDelAct; + _currBtn = kDelAct; break; case kNextCmd: - act = kNextAct; + _currBtn = kNextAct; break; case kAddCmd: - act = kAddAct; + _currBtn = kAddAct; break; case kModeCmd: - act = kModeAct; + _currBtn = kModeAct; break; case kBut1Cmd: - act = kBtn1Act; + _currBtn = kBtn1Act; break; case kBut2Cmd: - act = kBtn2Act; + _currBtn = kBtn2Act; break; case kBut3Cmd: - act = kBtn3Act; + _currBtn = kBtn3Act; break; case kBut4Cmd: - act = kBtn4Act; + _currBtn = kBtn4Act; break; case kBut5Cmd: - act = kBtn5Act; + _currBtn = kBtn5Act; break; case kBut6Cmd: - act = kBtn6Act; + _currBtn = kBtn6Act; break; case kBut7Cmd: - act = kBtn7Act; + _currBtn = kBtn7Act; break; case kBut8Cmd: - act = kBtn8Act; + _currBtn = kBtn8Act; break; case kBut9Cmd: - act = kBtn9Act; + _currBtn = kBtn9Act; break; case kBut0Cmd: - act = kBtn0Act; + _currBtn = kBtn0Act; break; case kCancelCmd: saveUserDictToFile(); close(); return; case kOkCmd: - act = kOkAct; + _currBtn = kOkAct; break; default: Dialog::handleCommand(sender, cmd, data); } - if (act != kNoAct) { - processBtnActive(act); + if (_currBtn != kNoAct) { + processBtnActive(_currBtn); } } @@ -500,18 +561,18 @@ void PredictiveDialog::processBtnActive(ButtonId button) { bringWordtoTop(_unitedDict.dictActLine, _wordNumber); } else if (button == kModeAct) { // Mode _mode++; - _addBtn->setEnabled(false); + _btns[kAddAct]->setEnabled(false); if (_mode > kModeAbc) { _mode = kModePre; // I18N: Pre means 'Predictive', leave '*' as is - _modebutton->setLabel("* Pre"); + _btns[kModeAct]->setLabel("* Pre"); } else if (_mode == kModeNum) { // I18N: 'Num' means Numbers - _modebutton->setLabel("* Num"); + _btns[kModeAct]->setLabel("* Num"); } else { // I18N: 'Abc' means Latin alphabet input - _modebutton->setLabel("* Abc"); - _addBtn->setEnabled(true); + _btns[kModeAct]->setLabel("* Abc"); + _btns[kAddAct]->setEnabled(true); } // truncate current input at mode change @@ -532,18 +593,23 @@ void PredictiveDialog::processBtnActive(ButtonId button) { if (button == kOkAct) close(); + + if (button == kCancelAct) { + saveUserDictToFile(); + close(); + } } void PredictiveDialog::handleTickle() { - // TODO/FIXME: This code does not seem to make any sense. It is only - // triggered when _lastTime is zero and sets _lastTime to zero again - // under some condition. This should really be a nop. Probably this - // code intends to check "_lastTime" instead of "!_lastTime". - if (!_lastTime) { + if (_lastTime) { if ((_curTime - _lastTime) > kRepeatDelay) { _lastTime = 0; } } + + if (getTickleWidget()) { + getTickleWidget()->handleTickle(); + } } void PredictiveDialog::mergeDicts() { @@ -664,7 +730,7 @@ bool PredictiveDialog::matchWord() { // The entries in the dictionary consist of a code, a space, and then // a space-separated list of words matching this code. - // To exactly match a code, we therefore match the code plus the trailing + // To ex_currBtnly match a code, we therefore match the code plus the trailing // space in the dictionary. Common::String code = _currentCode + " "; diff --git a/gui/predictivedialog.h b/gui/predictivedialog.h index 32de36d5f28..0e3d2967c07 100644 --- a/gui/predictivedialog.h +++ b/gui/predictivedialog.h @@ -68,6 +68,7 @@ public: ~PredictiveDialog(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); + virtual void handleKeyUp(Common::KeyState state); virtual void handleKeyDown(Common::KeyState state); virtual void handleTickle(); @@ -98,6 +99,8 @@ private: void saveUserDictToFile(); void mergeDicts(); + + void updateHighLightedButton(ButtonId active); private: Dict _unitedDict; Dict _predictiveDict; @@ -118,6 +121,7 @@ private: uint32 _curTime, _lastTime; ButtonId _lastPressBtn; + ButtonId _currBtn; char _temp[kMaxWordLen + 1]; int _repeatcount[kMaxWordLen]; @@ -128,11 +132,10 @@ private: Common::String _search; bool _navigationwithkeys; + bool _needRefresh; private: EditTextWidget *_edittext; - ButtonWidget *_modebutton; - ButtonWidget *_delbtn; - ButtonWidget *_addBtn; + ButtonWidget **_btns; }; } // namespace GUI diff --git a/gui/saveload.cpp b/gui/saveload.cpp index 3dc99619068..67d871e1332 100644 --- a/gui/saveload.cpp +++ b/gui/saveload.cpp @@ -21,6 +21,7 @@ #include "common/config-manager.h" #include "common/translation.h" +#include "common/system.h" #include "gui/widgets/list.h" #include "gui/message.h" @@ -40,7 +41,7 @@ enum { }; -SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel) +SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode) : Dialog("SaveLoadChooser"), _delSupport(0), _list(0), _chooseButton(0), _deleteButton(0), _gfxWidget(0) { _delSupport = _metaInfoSupport = _thumbnailSupport = _saveDateSupport = _playTimeSupport = false; @@ -51,7 +52,7 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel) // Add choice list _list = new GUI::ListWidget(this, "SaveLoadChooser.List"); _list->setNumberingMode(GUI::kListNumberingZero); - setSaveMode(false); + _list->setEditable(saveMode); _gfxWidget = new GUI::GraphicsWidget(this, 0, 0, 10, 10); @@ -76,6 +77,15 @@ SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel) SaveLoadChooser::~SaveLoadChooser() { } +int SaveLoadChooser::runModalWithCurrentTarget() { + const Common::String gameId = ConfMan.get("gameid"); + + const EnginePlugin *plugin = 0; + EngineMan.findGame(gameId, &plugin); + + return runModalWithPluginAndTarget(plugin, ConfMan.getActiveDomainName()); +} + int SaveLoadChooser::runModalWithPluginAndTarget(const EnginePlugin *plugin, const String &target) { if (_gfxWidget) _gfxWidget->setGfx(0); @@ -117,8 +127,16 @@ const Common::String &SaveLoadChooser::getResultString() const { return (selItem >= 0) ? _list->getSelectedString() : _resultString; } -void SaveLoadChooser::setSaveMode(bool saveMode) { - _list->setEditable(saveMode); +Common::String SaveLoadChooser::createDefaultSaveDescription(const int slot) const { +#if defined(USE_SAVEGAME_TIMESTAMP) + TimeDate curTime; + g_system->getTimeAndDate(curTime); + curTime.tm_year += 1900; // fixup year + curTime.tm_mon++; // fixup month + return Common::String::format("%04d.%02d.%02d / %02d:%02d:%02d", curTime.tm_year, curTime.tm_mon, curTime.tm_mday, curTime.tm_hour, curTime.tm_min, curTime.tm_sec); +#else + return Common::String::format("Save %d", slot + 1); +#endif } void SaveLoadChooser::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { diff --git a/gui/saveload.h b/gui/saveload.h index adaf311fd21..a19f5ab0839 100644 --- a/gui/saveload.h +++ b/gui/saveload.h @@ -62,16 +62,37 @@ protected: void updateSaveList(); void updateSelection(bool redraw); public: - SaveLoadChooser(const String &title, const String &buttonLabel); + SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode); ~SaveLoadChooser(); virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data); - void setList(const StringArray& list); + + /** + * Runs the save/load chooser with the currently active config manager + * domain as target. + * + * @return The selcted save slot. -1 in case none is selected. + */ + int runModalWithCurrentTarget(); int runModalWithPluginAndTarget(const EnginePlugin *plugin, const String &target); void open(); const Common::String &getResultString() const; - void setSaveMode(bool saveMode); + + /** + * Creates a default save description for the specified slot. Depending + * on the ScummVM configuration this might be a simple "Slot #" description + * or the current date and time. + * + * TODO: This might not be the best place to put this, since engines not + * using this class might want to mimic the same behavior. Check whether + * moving this to a better place makes sense and find what this place would + * be. + * + * @param slot The slot number (must be >= 0). + * @return The slot description. + */ + Common::String createDefaultSaveDescription(const int slot) const; virtual void reflowLayout(); diff --git a/gui/themes/default.inc b/gui/themes/default.inc index 46a3f689b2a..be3dd10f84f 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -460,6 +460,17 @@ "bevel='2' " "/> " " " +" " +" " +" " +" " " " " " " " " " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " -" " " " " " " " @@ -2495,3 +1558,948 @@ " " " " " " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " +" " diff --git a/gui/themes/modern.zip b/gui/themes/modern.zip index 206b50bae33..43575d982c2 100644 Binary files a/gui/themes/modern.zip and b/gui/themes/modern.zip differ diff --git a/gui/themes/modern/THEMERC b/gui/themes/modern/THEMERC index 6e7fff41ea4..d23dfd29ada 100644 --- a/gui/themes/modern/THEMERC +++ b/gui/themes/modern/THEMERC @@ -1 +1 @@ -[SCUMMVM_STX0.8.11:ResidualVM Modern Theme:No Author] +[SCUMMVM_STX0.8.13:ResidualVM Modern Theme:No Author] diff --git a/gui/themes/modern/modern_gfx.stx b/gui/themes/modern/modern_gfx.stx index 284f1e10741..e650c6650e1 100644 --- a/gui/themes/modern/modern_gfx.stx +++ b/gui/themes/modern/modern_gfx.stx @@ -187,8 +187,8 @@ - - + + @@ -740,6 +740,27 @@ /> + + + + + + = 0 && x < _w && y >= 0 && y < _h) + if (isEnabled() && x >= 0 && x < _w && y >= 0 && y < _h) { sendCommand(_cmd, 0); + startAnimatePressedState(); + } +} + +void ButtonWidget::handleMouseDown(int x, int y, int button, int clickCount) { + setPressedState(); } void ButtonWidget::drawWidget() { @@ -324,11 +334,49 @@ ButtonWidget *addClearButton(GuiObject *boss, const Common::String &name, uint32 return button; } +void ButtonWidget::setHighLighted(bool enable) { + (enable) ? setFlags(WIDGET_HILITED) : clearFlags(WIDGET_HILITED); + draw(); +} + +void ButtonWidget::handleTickle() { + if (_lastTime) { + uint32 curTime = g_system->getMillis(); + if (curTime - _lastTime > kPressedButtonTime) { + stopAnimatePressedState(); + } + } +} + +void ButtonWidget::setPressedState() { + wantTickle(true); + setFlags(WIDGET_PRESSED); + draw(); +} + +void ButtonWidget::stopAnimatePressedState() { + wantTickle(false); + _lastTime = 0; + clearFlags(WIDGET_PRESSED); + draw(); +} + +void ButtonWidget::startAnimatePressedState() { + _lastTime = g_system->getMillis(); +} + +void ButtonWidget::wantTickle(bool tickled) { + if (tickled) + ((GUI::Dialog *)_boss)->setTickleWidget(this); + else + ((GUI::Dialog *)_boss)->unSetTickleWidget(); +} + #pragma mark - PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip, uint32 cmd, uint8 hotkey) : ButtonWidget(boss, x, y, w, h, "", tooltip, cmd, hotkey), - _gfx(), _alpha(256), _transparency(false) { + _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) { setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG); _type = kButtonWidget; @@ -336,38 +384,54 @@ PicButtonWidget::PicButtonWidget(GuiObject *boss, int x, int y, int w, int h, co PicButtonWidget::PicButtonWidget(GuiObject *boss, const Common::String &name, const char *tooltip, uint32 cmd, uint8 hotkey) : ButtonWidget(boss, name, "", tooltip, cmd, hotkey), - _alpha(256), _transparency(false) { + _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) { setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG); _type = kButtonWidget; } PicButtonWidget::~PicButtonWidget() { - _gfx.free(); + _gfx->free(); + delete _gfx; } void PicButtonWidget::setGfx(const Graphics::Surface *gfx) { - _gfx.free(); + _gfx->free(); if (!gfx || !gfx->pixels) return; + if (gfx->format.bytesPerPixel == 1) { + warning("PicButtonWidget::setGfx got paletted surface passed"); + return; + } + + if (gfx->w > _w || gfx->h > _h) { warning("PicButtonWidget has size %dx%d, but a surface with %dx%d is to be set", _w, _h, gfx->w, gfx->h); return; } - // TODO: add conversion to OverlayColor - _gfx.copyFrom(*gfx); + _gfx->copyFrom(*gfx); } void PicButtonWidget::drawWidget() { g_gui.theme()->drawButton(Common::Rect(_x, _y, _x+_w, _y+_h), "", _state, getFlags()); - if (sizeof(OverlayColor) == _gfx.format.bytesPerPixel && _gfx.pixels) { - const int x = _x + (_w - _gfx.w) / 2; - const int y = _y + (_h - _gfx.h) / 2; + if (_gfx->pixels) { + // Check whether the set up surface needs to be converted to the GUI + // color format. + const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat(); + if (_gfx->format != requiredFormat) { + Graphics::Surface *converted = _gfx->convertTo(requiredFormat); + _gfx->free(); + delete _gfx; + _gfx = converted; + } - g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency); + const int x = _x + (_w - _gfx->w) / 2; + const int y = _y + (_h - _gfx->h) / 2; + + g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx->w, y + _gfx->h), *_gfx, _state, _alpha, _transparency); } } @@ -555,34 +619,39 @@ int SliderWidget::posToValue(int pos) { #pragma mark - GraphicsWidget::GraphicsWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip) - : Widget(boss, x, y, w, h, tooltip), _gfx(), _alpha(256), _transparency(false) { + : Widget(boss, x, y, w, h, tooltip), _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) { setFlags(WIDGET_ENABLED | WIDGET_CLEARBG); _type = kGraphicsWidget; } GraphicsWidget::GraphicsWidget(GuiObject *boss, const Common::String &name, const char *tooltip) - : Widget(boss, name, tooltip), _gfx(), _alpha(256), _transparency(false) { + : Widget(boss, name, tooltip), _gfx(new Graphics::Surface()), _alpha(256), _transparency(false) { setFlags(WIDGET_ENABLED | WIDGET_CLEARBG); _type = kGraphicsWidget; } GraphicsWidget::~GraphicsWidget() { - _gfx.free(); + _gfx->free(); + delete _gfx; } void GraphicsWidget::setGfx(const Graphics::Surface *gfx) { - _gfx.free(); + _gfx->free(); if (!gfx || !gfx->pixels) return; + if (gfx->format.bytesPerPixel == 1) { + warning("GraphicsWidget::setGfx got paletted surface passed"); + return; + } + if (gfx->w > _w || gfx->h > _h) { warning("GraphicsWidget has size %dx%d, but a surface with %dx%d is to be set", _w, _h, gfx->w, gfx->h); return; } - // TODO: add conversion to OverlayColor - _gfx.copyFrom(*gfx); + _gfx->copyFrom(*gfx); } void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) { @@ -591,26 +660,29 @@ void GraphicsWidget::setGfx(int w, int h, int r, int g, int b) { if (h == -1) h = _h; - Graphics::PixelFormat overlayFormat = g_system->getOverlayFormat(); + const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat(); - _gfx.free(); - _gfx.create(w, h, overlayFormat); - - OverlayColor *dst = (OverlayColor *)_gfx.pixels; - OverlayColor fillCol = overlayFormat.RGBToColor(r, g, b); - while (h--) { - for (int i = 0; i < w; ++i) { - *dst++ = fillCol; - } - } + _gfx->free(); + _gfx->create(w, h, requiredFormat); + _gfx->fillRect(Common::Rect(0, 0, w, h), _gfx->format.RGBToColor(r, g, b)); } void GraphicsWidget::drawWidget() { - if (sizeof(OverlayColor) == _gfx.format.bytesPerPixel && _gfx.pixels) { - const int x = _x + (_w - _gfx.w) / 2; - const int y = _y + (_h - _gfx.h) / 2; + if (_gfx->pixels) { + // Check whether the set up surface needs to be converted to the GUI + // color format. + const Graphics::PixelFormat &requiredFormat = g_gui.theme()->getPixelFormat(); + if (_gfx->format != requiredFormat) { + Graphics::Surface *converted = _gfx->convertTo(requiredFormat); + _gfx->free(); + delete _gfx; + _gfx = converted; + } - g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx.w, y + _gfx.h), _gfx, _state, _alpha, _transparency); + const int x = _x + (_w - _gfx->w) / 2; + const int y = _y + (_h - _gfx->h) / 2; + + g_gui.theme()->drawSurface(Common::Rect(x, y, x + _gfx->w, y + _gfx->h), *_gfx, _state, _alpha, _transparency); } } diff --git a/gui/widget.h b/gui/widget.h index 789fc092315..6de56862c3d 100644 --- a/gui/widget.h +++ b/gui/widget.h @@ -38,6 +38,7 @@ enum { WIDGET_INVISIBLE = 1 << 1, WIDGET_HILITED = 1 << 2, WIDGET_BORDER = 1 << 3, + WIDGET_PRESSED = 1 << 4, //WIDGET_INV_BORDER = 1 << 4, WIDGET_CLEARBG = 1 << 5, WIDGET_WANT_TICKLE = 1 << 7, @@ -73,6 +74,10 @@ enum { kCaretBlinkTime = 300 }; +enum { + kPressedButtonTime = 200 +}; + /* Widget */ class Widget : public GuiObject { friend class Dialog; @@ -189,11 +194,22 @@ public: void setLabel(const Common::String &label); void handleMouseUp(int x, int y, int button, int clickCount); + void handleMouseDown(int x, int y, int button, int clickCount); void handleMouseEntered(int button) { setFlags(WIDGET_HILITED); draw(); } - void handleMouseLeft(int button) { clearFlags(WIDGET_HILITED); draw(); } + void handleMouseLeft(int button) { clearFlags(WIDGET_HILITED | WIDGET_PRESSED); draw(); } + void handleTickle(); + void setHighLighted(bool enable); + void setPressedState(); + void startAnimatePressedState(); + void stopAnimatePressedState(); + + void lostFocusWidget() { stopAnimatePressedState(); } protected: void drawWidget(); + void wantTickle(bool tickled); +private: + uint32 _lastTime; }; /* PicButtonWidget */ @@ -211,7 +227,7 @@ public: protected: void drawWidget(); - Graphics::Surface _gfx; + Graphics::Surface *_gfx; int _alpha; bool _transparency; }; @@ -339,7 +355,7 @@ public: protected: void drawWidget(); - Graphics::Surface _gfx; + Graphics::Surface *_gfx; int _alpha; bool _transparency; }; diff --git a/video/bink_decoder.cpp b/video/bink_decoder.cpp index a1cc6ed1f42..5b4905970d9 100644 --- a/video/bink_decoder.cpp +++ b/video/bink_decoder.cpp @@ -120,7 +120,7 @@ void BinkDecoder::startAudio() { const AudioTrack &audio = _audioTracks[_audioTrack]; _audioStream = Audio::makeQueuingAudioStream(audio.outSampleRate, audio.outChannels == 2); - g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandle, _audioStream); + g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_audioHandle, _audioStream, -1, getVolume(), getBalance()); } // else no audio } @@ -181,7 +181,7 @@ void BinkDecoder::close() { _frames.clear(); } -uint32 BinkDecoder::getElapsedTime() const { +uint32 BinkDecoder::getTime() const { if (_audioStream && g_system->getMixer()->isSoundHandleActive(_audioHandle)) return g_system->getMixer()->getSoundElapsedTime(_audioHandle) + _audioStartOffset; @@ -1647,4 +1647,14 @@ void BinkDecoder::IDCTPut(DecodeContext &ctx, int16 *block) { } } +void BinkDecoder::updateVolume() { + if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) + g_system->getMixer()->setChannelVolume(_audioHandle, getVolume()); +} + +void BinkDecoder::updateBalance() { + if (g_system->getMixer()->isSoundHandleActive(_audioHandle)) + g_system->getMixer()->setChannelBalance(_audioHandle, getBalance()); +} + } // End of namespace Video diff --git a/video/bink_decoder.h b/video/bink_decoder.h index 3d5e882dd7f..a5e1b102709 100644 --- a/video/bink_decoder.h +++ b/video/bink_decoder.h @@ -70,7 +70,7 @@ public: uint16 getHeight() const { return _surface.h; } Graphics::PixelFormat getPixelFormat() const { return _surface.format; } uint32 getFrameCount() const { return _frames.size(); } - uint32 getElapsedTime() const; + uint32 getTime() const; const Graphics::Surface *decodeNextFrame(); // FixedRateVideoDecoder @@ -78,7 +78,12 @@ public: // Bink specific bool loadStream(Common::SeekableReadStream *stream, const Graphics::PixelFormat &format); + protected: + // VideoDecoder API + void updateVolume(); + void updateBalance(); + static const int kAudioChannelsMax = 2; static const int kAudioBlockSizeMax = (kAudioChannelsMax << 11); diff --git a/video/bink_decoder_seek.cpp b/video/bink_decoder_seek.cpp index 7c068d32814..dcf0ebf4f6b 100644 --- a/video/bink_decoder_seek.cpp +++ b/video/bink_decoder_seek.cpp @@ -112,7 +112,7 @@ void SeekableBinkDecoder::seekToFrame(uint32 frame) { startAudio(); } -void SeekableBinkDecoder::seekToTime(Audio::Timestamp time) { +void SeekableBinkDecoder::seekToTime(const Audio::Timestamp &time) { // Try to find the last frame that should have been decoded Common::Rational frame = time.msecs() * getFrameRate() / 1000; seekToFrame(frame.toInt()); diff --git a/video/bink_decoder_seek.h b/video/bink_decoder_seek.h index 6d72a501635..dbee7134715 100644 --- a/video/bink_decoder_seek.h +++ b/video/bink_decoder_seek.h @@ -34,7 +34,7 @@ class SeekableBinkDecoder: public Video::BinkDecoder, public: // SeekableVideoDecoder API void seekToFrame(uint32 frame); - void seekToTime(Audio::Timestamp time); + void seekToTime(const Audio::Timestamp &time); uint32 getDuration() const; // Bink seek specific diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index e1122132a8f..44d79176524 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -22,6 +22,8 @@ #include "video/video_decoder.h" +#include "audio/mixer.h" // for kMaxChannelVolume + #include "common/rational.h" #include "common/file.h" #include "common/system.h" @@ -45,7 +47,7 @@ bool VideoDecoder::loadFile(const Common::String &filename) { return loadStream(file); } -uint32 VideoDecoder::getElapsedTime() const { +uint32 VideoDecoder::getTime() const { return g_system->getMillis() - _startTime; } @@ -61,6 +63,8 @@ void VideoDecoder::reset() { _curFrame = -1; _startTime = 0; _pauseLevel = 0; + _audioVolume = Audio::Mixer::kMaxChannelVolume; + _audioBalance = 0; } bool VideoDecoder::endOfVideo() const { @@ -94,11 +98,21 @@ void VideoDecoder::resetPauseStartTime() { _pauseStartTime = g_system->getMillis(); } +void VideoDecoder::setVolume(byte volume) { + _audioVolume = volume; + updateVolume(); +} + +void VideoDecoder::setBalance(int8 balance) { + _audioBalance = balance; + updateBalance(); +} + uint32 FixedRateVideoDecoder::getTimeToNextFrame() const { if (endOfVideo() || _curFrame < 0) return 0; - uint32 elapsedTime = getElapsedTime(); + uint32 elapsedTime = getTime(); uint32 nextFrameStartTime = getFrameBeginTime(_curFrame + 1); // If the time that the next frame should be shown has past diff --git a/video/video_decoder.h b/video/video_decoder.h index 52ced4777c7..3bb75ade09d 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -125,15 +125,20 @@ public: virtual uint32 getFrameCount() const = 0; /** - * Returns the time (in ms) that the video has been running. - * This is based on the "wall clock" time as determined by - * OSystem::getMillis, and takes pausing the video into account. + * Returns the time position (in ms) of the current video. + * This can be based on the "wall clock" time as determined by + * OSystem::getMillis() or the current time of any audio track + * running in the video, and takes pausing the video into account. * - * As such, it can differ from what multiplying getCurFrame() by + * As such, it will differ from what multiplying getCurFrame() by * some constant would yield, e.g. for a video with non-constant * frame rate. + * + * Due to the nature of the timing, this value may not always be + * completely accurate (since our mixer does not have precise + * timing). */ - virtual uint32 getElapsedTime() const; + virtual uint32 getTime() const; /** * Return the time (in ms) until the next frame should be displayed. @@ -180,6 +185,40 @@ public: */ bool isPaused() const { return _pauseLevel != 0; } + /** + * Get the current volume at which the audio in the video is being played + * @return the current volume at which the audio in the video is being played + */ + virtual byte getVolume() const { return _audioVolume; } + + /** + * Set the volume at which the audio in the video should be played. + * This setting remains until reset() is called (which may be called + * from loadStream() or close()). The default volume is the maximum. + * + * @note This function calls updateVolume() by default. + * + * @param volume The volume at which to play the audio in the video + */ + virtual void setVolume(byte volume); + + /** + * Get the current balance at which the audio in the video is being played + * @return the current balance at which the audio in the video is being played + */ + virtual int8 getBalance() const { return _audioBalance; } + + /** + * Set the balance at which the audio in the video should be played. + * This setting remains until reset() is called (which may be called + * from loadStream() or close()). The default balance is 0. + * + * @note This function calls updateBalance() by default. + * + * @param balance The balance at which to play the audio in the video + */ + virtual void setBalance(int8 balance); + protected: /** * Resets _curFrame and _startTime. Should be called from every close() function. @@ -202,12 +241,24 @@ protected: */ void resetPauseStartTime(); + /** + * Update currently playing audio tracks with the new volume setting + */ + virtual void updateVolume() {} + + /** + * Update currently playing audio tracks with the new balance setting + */ + virtual void updateBalance() {} + int32 _curFrame; int32 _startTime; private: uint32 _pauseLevel; uint32 _pauseStartTime; + byte _audioVolume; + int8 _audioBalance; }; /** @@ -247,13 +298,8 @@ class SeekableVideoDecoder : public virtual RewindableVideoDecoder { public: /** * Seek to the specified time. - * - * This will round to the previous frame showing. If the time would happen to - * land while a frame is showing, this function will seek to the beginning of that - * frame. In other words, there is *no* subframe accuracy. This may change in a - * later revision of the API. */ - virtual void seekToTime(Audio::Timestamp time) = 0; + virtual void seekToTime(const Audio::Timestamp &time) = 0; /** * Seek to the specified time (in ms).