aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS10
-rw-r--r--audio/decoders/quicktime.cpp2
-rw-r--r--backends/graphics/opengl/opengl-graphics.cpp5
-rw-r--r--base/main.cpp14
-rw-r--r--common/unzip.cpp20
-rwxr-xr-xconfigure10
-rw-r--r--devtools/create_project/create_project.cpp8
-rw-r--r--devtools/scumm-md5.txt1
-rw-r--r--engines/agi/saveload.cpp3
-rw-r--r--engines/configure.engines4
-rw-r--r--engines/cruise/cruise_main.cpp107
-rw-r--r--engines/dreamweb/detection_tables.h16
-rw-r--r--engines/dreamweb/dreamweb.cpp20
-rw-r--r--engines/dreamweb/module.mk1
-rw-r--r--engines/dreamweb/mouse.cpp171
-rw-r--r--engines/dreamweb/stubs.cpp142
-rw-r--r--engines/kyra/screen.cpp19
-rw-r--r--engines/sci/detection_tables.h13
-rw-r--r--engines/sci/engine/features.cpp3
-rw-r--r--engines/sci/engine/features.h7
-rw-r--r--engines/sci/graphics/cursor.cpp8
-rw-r--r--engines/sci/sound/music.cpp6
-rw-r--r--engines/scumm/detection.cpp10
-rw-r--r--engines/scumm/scumm-md5.h3
-rw-r--r--engines/sword25/script/luabindhelper.cpp2
-rw-r--r--engines/tinsel/detection_tables.h2
-rw-r--r--engines/tinsel/music.cpp94
-rw-r--r--engines/tinsel/music.h6
-rw-r--r--engines/tinsel/tinlib.cpp2
-rw-r--r--graphics/decoders/bmp.h2
-rw-r--r--graphics/decoders/pict.cpp25
-rw-r--r--graphics/fontman.cpp36
-rw-r--r--graphics/fontman.h5
-rw-r--r--graphics/fonts/bdf.h2
-rw-r--r--graphics/fonts/ttf.cpp8
-rw-r--r--graphics/fonts/ttf.h2
-rw-r--r--gui/ThemeEngine.cpp5
-rw-r--r--gui/ThemeEngine.h6
-rw-r--r--gui/dialog.cpp13
-rw-r--r--gui/dialog.h7
-rw-r--r--gui/gui-manager.cpp13
-rw-r--r--gui/launcher.cpp1
-rw-r--r--gui/predictivedialog.cpp288
-rw-r--r--gui/predictivedialog.h9
-rw-r--r--gui/themes/default.inc11
-rw-r--r--gui/themes/scummclassic.zipbin93076 -> 93390 bytes
-rw-r--r--gui/themes/scummclassic/THEMERC2
-rw-r--r--gui/themes/scummclassic/classic_gfx.stx13
-rw-r--r--gui/themes/scummmodern.zipbin1449403 -> 1449894 bytes
-rw-r--r--gui/themes/scummmodern/THEMERC2
-rw-r--r--gui/themes/scummmodern/scummmodern_gfx.stx21
-rw-r--r--gui/widget.cpp58
-rw-r--r--gui/widget.h18
53 files changed, 840 insertions, 416 deletions
diff --git a/NEWS b/NEWS
index b208646d74..0a48ccab9a 100644
--- a/NEWS
+++ b/NEWS
@@ -3,7 +3,17 @@ For a more comprehensive changelog of the latest experimental code, see:
1.5.0 (????-??-??)
New Games:
+ - Added support for Blue Force.
+ - Added support for Darby the Dragon.
+ - Added support for Dreamweb.
+ - Added support for Gregory and the Hot Air Balloon.
+ - Added support for Magic Tales: Baba Yaga and the Magic Geese.
+ - Added support for Magic Tales: Imo and the King.
+ - Added support for Magic Tales: Liam Finds a Story.
+ - Added support for Magic Tales: The Little Samurai.
+ - Added support for Sleeping Cub's Test of Courage.
- Added support for Soltys.
+ - Added support for The Princess and the Crab.
General:
- Updated MT-32 emulation code to latest munt project snapshot. The emulation
diff --git a/audio/decoders/quicktime.cpp b/audio/decoders/quicktime.cpp
index 48e76a94da..99c1527a71 100644
--- a/audio/decoders/quicktime.cpp
+++ b/audio/decoders/quicktime.cpp
@@ -449,7 +449,7 @@ void QuickTimeAudioDecoder::QuickTimeAudioTrack::skipSamples(const Timestamp &le
}
void QuickTimeAudioDecoder::QuickTimeAudioTrack::findEdit(const Timestamp &position) {
- for (_curEdit = 0; _curEdit < _parentTrack->editCount && position < Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale); _curEdit++)
+ for (_curEdit = 0; _curEdit < _parentTrack->editCount - 1 && position > Timestamp(0, _parentTrack->editList[_curEdit].timeOffset, _decoder->_timeScale); _curEdit++)
;
enterNewEdit(position);
diff --git a/backends/graphics/opengl/opengl-graphics.cpp b/backends/graphics/opengl/opengl-graphics.cpp
index 45804b5d6e..cd820ae3b2 100644
--- a/backends/graphics/opengl/opengl-graphics.cpp
+++ b/backends/graphics/opengl/opengl-graphics.cpp
@@ -70,6 +70,11 @@ OpenGLGraphicsManager::~OpenGLGraphicsManager() {
free(_gamePalette);
free(_cursorPalette);
+ _screenData.free();
+ _overlayData.free();
+ _cursorData.free();
+ _osdSurface.free();
+
delete _gameTexture;
delete _overlayTexture;
delete _cursorTexture;
diff --git a/base/main.cpp b/base/main.cpp
index c657488758..25e1b881cc 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)
@@ -493,10 +499,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/common/unzip.cpp b/common/unzip.cpp
index 8cfcd605fa..ab659343a2 100644
--- a/common/unzip.cpp
+++ b/common/unzip.cpp
@@ -1463,22 +1463,16 @@ bool ZipArchive::hasFile(const String &name) const {
}
int ZipArchive::listMembers(ArchiveMemberList &list) const {
- int matches = 0;
- int err = unzGoToFirstFile(_zipFile);
+ int members = 0;
- while (err == UNZ_OK) {
- char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
- if (unzGetCurrentFileInfo(_zipFile, NULL,
- szCurrentFileName, sizeof(szCurrentFileName)-1,
- NULL, 0, NULL, 0) == UNZ_OK) {
- list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(szCurrentFileName, this)));
- matches++;
- }
-
- err = unzGoToNextFile(_zipFile);
+ const unz_s *const archive = (const unz_s *)_zipFile;
+ for (ZipHash::const_iterator i = archive->_hash.begin(), end = archive->_hash.end();
+ i != end; ++i) {
+ list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(i->_key, this)));
+ ++members;
}
- return matches;
+ return members;
}
const ArchiveMemberPtr ZipArchive::getMember(const String &name) const {
diff --git a/configure b/configure
index cdc44a8c01..88dc161595 100755
--- a/configure
+++ b/configure
@@ -840,7 +840,7 @@ Optional Libraries:
--with-sdl-prefix=DIR Prefix where the sdl-config script is
installed (optional)
- --with-freetype-prefix=DIR Prefix where the freetype-config script is
+ --with-freetype2-prefix=DIR Prefix where the freetype-config script is
installed (optional)
--with-nasm-prefix=DIR Prefix where nasm executable is installed (optional)
@@ -1403,6 +1403,10 @@ ps3)
echo "Please set PS3DEV in your environment. export PS3DEV=<path to ps3 toolchain>"
exit 1
fi
+ if test -z "$PSL1GHT"; then
+ echo "Please set PSL1GHT in your environment. export PSL1GHT=<path to psl1ght>"
+ exit 1
+ fi
;;
psp)
if test -z "$PSPDEV"; then
@@ -2068,8 +2072,8 @@ case $_host_os in
_sdlpath="$PS3DEV/portlibs/ppu:$PS3DEV/portlibs/ppu/bin"
DEFINES="$DEFINES -DPLAYSTATION3"
- CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PS3DEV/psl1ght/ppu/include -I$PS3DEV/portlibs/ppu/include"
- LDFLAGS="$LDFLAGS -L$PS3DEV/psl1ght/ppu/lib -L$PS3DEV/portlibs/ppu/lib"
+ CXXFLAGS="$CXXFLAGS -mcpu=cell -mminimal-toc -I$PSL1GHT/ppu/include -I$PS3DEV/portlibs/ppu/include"
+ LDFLAGS="$LDFLAGS -L$PSL1GHT/ppu/lib -L$PS3DEV/portlibs/ppu/lib"
add_line_to_config_mk 'PLAYSTATION3 = 1'
add_line_to_config_h "#define PREFIX \"${prefix}\""
;;
diff --git a/devtools/create_project/create_project.cpp b/devtools/create_project/create_project.cpp
index 293cc0b2de..df220f0934 100644
--- a/devtools/create_project/create_project.cpp
+++ b/devtools/create_project/create_project.cpp
@@ -654,14 +654,14 @@ void displayHelp(const char *exe) {
"\n"
"Engines settings:\n"
" --list-engines list all available engines and their default state\n"
- " --enable-engine enable building of the engine with the name \"engine\"\n"
- " --disable-engine disable building of the engine with the name \"engine\"\n"
+ " --enable-engine=<name> enable building of the engine with the name \"name\"\n"
+ " --disable-engine=<name> disable building of the engine with the name \"name\"\n"
" --enable-all-engines enable building of all engines\n"
" --disable-all-engines disable building of all engines\n"
"\n"
"Optional features settings:\n"
- " --enable-name enable inclusion of the feature \"name\"\n"
- " --disable-name disable inclusion of the feature \"name\"\n"
+ " --enable-<name> enable inclusion of the feature \"name\"\n"
+ " --disable-<name> disable inclusion of the feature \"name\"\n"
"\n"
" There are the following features available:\n"
"\n";
diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt
index 01d806a484..7d2ea94f10 100644
--- a/devtools/scumm-md5.txt
+++ b/devtools/scumm-md5.txt
@@ -590,6 +590,7 @@ FreddisFunShop Freddi Fish's One-Stop Fun Shop
catalog Humongous Interactive Catalog
11e6e244078ff09b0f3832e35420e0a7 -1 en Windows - Demo - khalek, sev
037385a953789190298494d92b89b3d0 -1 en Windows HE 72 Demo - khalek, sev
+ f7635a0e2ab82c9a0f9ace5f232a488f -1 en Windows HE 72 Demo - Kirben
a56e8d9d4281c53c3f63c9bd22a59e21 10978342 en All HE CUP Preview George Kormendi
74da3494fbe1a7d20213b0afe0954755 10841544 fr All HE CUP Preview - George Kormendi
4c4820518e16e1a0e3616a3b021a04f3 10927456 de All HE CUP Preview - Kirben
diff --git a/engines/agi/saveload.cpp b/engines/agi/saveload.cpp
index 8e524c8d9a..d58e55a6b9 100644
--- a/engines/agi/saveload.cpp
+++ b/engines/agi/saveload.cpp
@@ -831,6 +831,9 @@ int AgiEngine::scummVMSaveLoadDialog(bool isSave) {
delete dialog;
+ if (slot < 0)
+ return true;
+
if (isSave)
return doSave(slot, desc);
else
diff --git a/engines/configure.engines b/engines/configure.engines
index 93c349378d..91e5e82506 100644
--- a/engines/configure.engines
+++ b/engines/configure.engines
@@ -7,11 +7,11 @@ add_engine agos "AGOS" yes "agos2"
add_engine agos2 "AGOS 2 games" yes
add_engine cge "CGE" yes
add_engine cine "Cinematique evo 1" yes
-add_engine composer "Magic Composer" no
+add_engine composer "Magic Composer" yes
add_engine cruise "Cinematique evo 2" yes
add_engine draci "Dragon History" yes
add_engine drascula "Drascula: The Vampire Strikes Back" yes
-add_engine dreamweb "Dreamweb" no
+add_engine dreamweb "Dreamweb" yes
add_engine gob "Gobli*ns" yes
add_engine groovie "Groovie" yes "groovie2"
add_engine groovie2 "Groovie 2 games" no
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index 6e2847d6d7..911041c1a4 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -1799,32 +1799,60 @@ void CruiseEngine::mainLoop() {
// Handle frame delay
uint32 currentTick = g_system->getMillis();
- if (!bFastMode) {
- // Delay for the specified amount of time, but still respond to events
- bool skipEvents = false;
+ // Delay for the specified amount of time, but still respond to events
+ bool skipEvents = false;
- do {
- g_system->updateScreen();
+ do {
+ if (userEnabled && !userWait && !autoTrack) {
+ if (currentActiveMenu == -1) {
+ static int16 oldMouseX = -1;
+ static int16 oldMouseY = -1;
- g_system->delayMillis(10);
- currentTick = g_system->getMillis();
+ getMouseStatus(&main10, &mouseX, &mouseButton, &mouseY);
- if (!skipEvents)
- skipEvents = manageEvents();
+ if (mouseX != oldMouseX || mouseY != oldMouseY) {
+ int objectType;
+ int newCursor1;
+ int newCursor2;
- if (playerDontAskQuit)
- break;
+ oldMouseX = mouseX;
+ oldMouseY = mouseY;
- _vm->getDebugger()->onFrame();
- } while (currentTick < lastTick + _gameSpeed);
- } else {
- manageEvents();
+ objectType = findObject(mouseX, mouseY, &newCursor1, &newCursor2);
- if (currentTick >= (lastTickDebug + 10)) {
- lastTickDebug = currentTick;
- _vm->getDebugger()->onFrame();
+ if (objectType == 9) {
+ changeCursor(CURSOR_EXIT);
+ } else if (objectType != -1) {
+ changeCursor(CURSOR_MAGNIFYING_GLASS);
+ } else {
+ changeCursor(CURSOR_WALK);
+ }
+ }
+ } else {
+ changeCursor(CURSOR_NORMAL);
+ }
+ } else {
+ changeCursor(CURSOR_NORMAL);
}
- }
+
+ g_system->updateScreen();
+
+ if (!skipEvents || bFastMode)
+ skipEvents = manageEvents();
+
+ if (bFastMode) {
+ if (currentTick >= (lastTickDebug + 10))
+ lastTickDebug = currentTick;
+ } else {
+ g_system->delayMillis(10);
+ currentTick = g_system->getMillis();
+ }
+
+ if (playerDontAskQuit)
+ break;
+
+ _vm->getDebugger()->onFrame();
+ } while (currentTick < lastTick + _gameSpeed && !bFastMode);
if (playerDontAskQuit)
break;
@@ -1844,6 +1872,14 @@ void CruiseEngine::mainLoop() {
// readKeyboard();
bool isUserWait = userWait != 0;
+ // WORKAROUND: This prevents hotspots responding during
+ // delays i.e. Menu opening if you click fast on another
+ // hotspot after trying to open a locked door, which
+ // occurred with the original interpreter.
+ if (userDelay) {
+ currentMouseButton = 0;
+ }
+
playerDontAskQuit = processInput();
if (playerDontAskQuit)
break;
@@ -1855,7 +1891,6 @@ void CruiseEngine::mainLoop() {
if (userDelay && !userWait) {
userDelay--;
- continue;
}
if (isUserWait & !userWait) {
@@ -1918,38 +1953,6 @@ void CruiseEngine::mainLoop() {
mainDraw(userWait);
flipScreen();
- if (userEnabled && !userWait && !autoTrack) {
- if (currentActiveMenu == -1) {
- static int16 oldMouseX = -1;
- static int16 oldMouseY = -1;
-
- getMouseStatus(&main10, &mouseX, &mouseButton, &mouseY);
-
- if (mouseX != oldMouseX || mouseY != oldMouseY) {
- int objectType;
- int newCursor1;
- int newCursor2;
-
- oldMouseX = mouseX;
- oldMouseY = mouseY;
-
- objectType = findObject(mouseX, mouseY, &newCursor1, &newCursor2);
-
- if (objectType == 9) {
- changeCursor(CURSOR_EXIT);
- } else if (objectType != -1) {
- changeCursor(CURSOR_MAGNIFYING_GLASS);
- } else {
- changeCursor(CURSOR_WALK);
- }
- }
- } else {
- changeCursor(CURSOR_NORMAL);
- }
- } else {
- changeCursor(CURSOR_NORMAL);
- }
-
if (userWait == 1) {
// Waiting for press - original wait loop has been integrated into the
// main event loop
diff --git a/engines/dreamweb/detection_tables.h b/engines/dreamweb/detection_tables.h
index 8ca24d1724..d54b2402c8 100644
--- a/engines/dreamweb/detection_tables.h
+++ b/engines/dreamweb/detection_tables.h
@@ -45,7 +45,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_UNSTABLE,
+ ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -62,7 +62,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::EN_ANY,
Common::kPlatformPC,
- ADGF_CD | ADGF_UNSTABLE,
+ ADGF_CD | ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -96,7 +96,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::FR_FRA,
Common::kPlatformPC,
- ADGF_CD | ADGF_UNSTABLE,
+ ADGF_CD | ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -113,7 +113,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_UNSTABLE,
+ ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -130,7 +130,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::DE_DEU,
Common::kPlatformPC,
- ADGF_CD | ADGF_UNSTABLE,
+ ADGF_CD | ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -147,7 +147,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_UNSTABLE,
+ ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -164,7 +164,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::ES_ESP,
Common::kPlatformPC,
- ADGF_CD | ADGF_UNSTABLE,
+ ADGF_CD | ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
@@ -181,7 +181,7 @@ static const DreamWebGameDescription gameDescriptions[] = {
},
Common::IT_ITA,
Common::kPlatformPC,
- ADGF_UNSTABLE,
+ ADGF_TESTING,
GUIO2(GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_BRIGHTPALETTE)
},
},
diff --git a/engines/dreamweb/dreamweb.cpp b/engines/dreamweb/dreamweb.cpp
index 2e9c7bb2b8..299dd74b53 100644
--- a/engines/dreamweb/dreamweb.cpp
+++ b/engines/dreamweb/dreamweb.cpp
@@ -422,25 +422,6 @@ void DreamWebEngine::keyPressed(uint16 ascii) {
DreamWeb::g_keyBuffer[in] = ascii;
}
-void DreamWebEngine::mouseCall(uint16 *x, uint16 *y, uint16 *state) {
- processEvents();
- Common::Point pos = _eventMan->getMousePos();
- if (pos.x > 298)
- pos.x = 298;
- if (pos.x < 15)
- pos.x = 15;
- if (pos.y < 15)
- pos.y = 15;
- if (pos.y > 184)
- pos.y = 184;
- *x = pos.x;
- *y = pos.y;
-
- unsigned newState = _eventMan->getButtonState();
- *state = (newState == _oldMouseState? 0 : newState);
- _oldMouseState = newState;
-}
-
void DreamWebEngine::getPalette(uint8 *data, uint start, uint count) {
_system->getPaletteManager()->grabPalette(data, start, count);
while (count--)
@@ -541,6 +522,7 @@ uint8 DreamWebEngine::modifyChar(uint8 c) const {
return c;
}
case Common::FR_FRA:
+ case Common::IT_ITA:
switch(c) {
case 133:
return 'Z' + 1;
diff --git a/engines/dreamweb/module.mk b/engines/dreamweb/module.mk
index 6bc4f8728e..3e367c6fdf 100644
--- a/engines/dreamweb/module.mk
+++ b/engines/dreamweb/module.mk
@@ -7,6 +7,7 @@ MODULE_OBJS := \
dreamweb.o \
keypad.o \
monitor.o \
+ mouse.o \
newplace.o \
object.o \
pathfind.o \
diff --git a/engines/dreamweb/mouse.cpp b/engines/dreamweb/mouse.cpp
new file mode 100644
index 0000000000..77d907611d
--- /dev/null
+++ b/engines/dreamweb/mouse.cpp
@@ -0,0 +1,171 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/events.h"
+#include "dreamweb/dreamweb.h"
+
+namespace DreamWeb {
+
+void DreamWebEngine::mouseCall(uint16 *x, uint16 *y, uint16 *state) {
+ processEvents();
+ Common::Point pos = _eventMan->getMousePos();
+ *x = CLIP<int16>(pos.x, 15, 298);
+ *y = CLIP<int16>(pos.y, 15, 184);
+
+ unsigned newState = _eventMan->getButtonState();
+ *state = (newState == _oldMouseState ? 0 : newState);
+ _oldMouseState = newState;
+}
+
+void DreamWebEngine::readMouse() {
+ _oldButton = _mouseButton;
+ _mouseButton = readMouseState();
+}
+
+uint16 DreamWebEngine::readMouseState() {
+ _oldX = _mouseX;
+ _oldY = _mouseY;
+ uint16 x, y, state;
+ mouseCall(&x, &y, &state);
+ _mouseX = x;
+ _mouseY = y;
+ return state;
+}
+
+void DreamWebEngine::dumpPointer() {
+ dumpBlink();
+ multiDump(_delHereX, _delHereY, _delXS, _delYS);
+ if ((_oldPointerX != _delHereX) || (_oldPointerY != _delHereY))
+ multiDump(_oldPointerX, _oldPointerY, _pointerXS, _pointerYS);
+}
+
+void DreamWebEngine::showPointer() {
+ showBlink();
+ uint16 x = _mouseX;
+ _oldPointerX = _mouseX;
+ uint16 y = _mouseY;
+ _oldPointerY = _mouseY;
+ if (_pickUp == 1) {
+ const GraphicsFile *frames;
+ if (_objectType != kExObjectType)
+ frames = &_freeFrames;
+ else
+ frames = &_exFrames;
+ const Frame *frame = &frames->_frames[(3 * _itemFrame + 1)];
+
+ uint8 width = MAX<uint8>(frame->width, 12);
+ uint8 height = MAX<uint8>(frame->height, 12);
+ _pointerXS = width;
+ _pointerYS = height;
+ uint16 xMin = (x >= width / 2) ? x - width / 2 : 0;
+ uint16 yMin = (y >= height / 2) ? y - height / 2 : 0;
+ _oldPointerX = xMin;
+ _oldPointerY = yMin;
+ multiGet(_pointerBack, xMin, yMin, width, height);
+ showFrame(*frames, x, y, 3 * _itemFrame + 1, 128);
+ showFrame(_icons1, x, y, 3, 128);
+ } else {
+ const Frame *frame = &_icons1._frames[_pointerFrame + 20];
+ uint8 width = MAX<uint8>(frame->width, 12);
+ uint8 height = MAX<uint8>(frame->height, 12);
+ _pointerXS = width;
+ _pointerYS = height;
+ multiGet(_pointerBack, x, y, width, height);
+ showFrame(_icons1, x, y, _pointerFrame + 20, 0);
+ }
+}
+
+void DreamWebEngine::delPointer() {
+ if (_oldPointerX == 0xffff)
+ return;
+ _delHereX = _oldPointerX;
+ _delHereY = _oldPointerY;
+ _delXS = _pointerXS;
+ _delYS = _pointerYS;
+ multiPut(_pointerBack, _delHereX, _delHereY, _pointerXS, _pointerYS);
+}
+
+void DreamWebEngine::animPointer() {
+ if (_pointerMode == 2) {
+ _pointerFrame = 0;
+ if ((_realLocation == 14) && (_commandType == 211))
+ _pointerFrame = 5;
+ return;
+ } else if (_pointerMode == 3) {
+ if (_pointerSpeed != 0) {
+ --_pointerSpeed;
+ } else {
+ _pointerSpeed = 5;
+ ++_pointerCount;
+ if (_pointerCount == 16)
+ _pointerCount = 0;
+ }
+ _pointerFrame = (_pointerCount <= 8) ? 1 : 2;
+ return;
+ }
+ if (_vars._watchingTime != 0) {
+ _pointerFrame = 11;
+ return;
+ }
+ _pointerFrame = 0;
+ if (_inMapArea == 0)
+ return;
+ if (_pointerFirstPath == 0)
+ return;
+ uint8 flag, flagEx;
+ getFlagUnderP(&flag, &flagEx);
+ if (flag < 2)
+ return;
+ if (flag >= 128)
+ return;
+ if (flag & 4) {
+ _pointerFrame = 3;
+ return;
+ }
+ if (flag & 16) {
+ _pointerFrame = 4;
+ return;
+ }
+ if (flag & 2) {
+ _pointerFrame = 5;
+ return;
+ }
+ if (flag & 8) {
+ _pointerFrame = 6;
+ return;
+ }
+ _pointerFrame = 8;
+}
+
+void DreamWebEngine::checkCoords(const RectWithCallback *rectWithCallbacks) {
+ if (_newLocation != 0xff)
+ return;
+ const RectWithCallback *r;
+ for (r = rectWithCallbacks; r->_xMin != 0xffff; ++r) {
+ if (r->contains(_mouseX, _mouseY)) {
+ (this->*(r->_callback))();
+ return;
+ }
+ }
+}
+
+} // End of namespace DreamWeb
diff --git a/engines/dreamweb/stubs.cpp b/engines/dreamweb/stubs.cpp
index 5a53b82510..750dafe7b4 100644
--- a/engines/dreamweb/stubs.cpp
+++ b/engines/dreamweb/stubs.cpp
@@ -876,22 +876,6 @@ void DreamWebEngine::hangOnCurs(uint16 frameCount) {
}
}
-void DreamWebEngine::readMouse() {
- _oldButton = _mouseButton;
- uint16 state = readMouseState();
- _mouseButton = state;
-}
-
-uint16 DreamWebEngine::readMouseState() {
- _oldX = _mouseX;
- _oldY = _mouseY;
- uint16 x, y, state;
- mouseCall(&x, &y, &state);
- _mouseX = x;
- _mouseY = y;
- return state;
-}
-
void DreamWebEngine::dumpTextLine() {
if (_newTextLine != 1)
return;
@@ -1513,16 +1497,6 @@ void DreamWebEngine::obName(uint8 command, uint8 commandType) {
}
}
-void DreamWebEngine::delPointer() {
- if (_oldPointerX == 0xffff)
- return;
- _delHereX = _oldPointerX;
- _delHereY = _oldPointerY;
- _delXS = _pointerXS;
- _delYS = _pointerYS;
- multiPut(_pointerBack, _delHereX, _delHereY, _pointerXS, _pointerYS);
-}
-
void DreamWebEngine::showBlink() {
if (_manIsOffScreen == 1)
return;
@@ -1554,110 +1528,6 @@ void DreamWebEngine::dumpBlink() {
multiDump(44, 32, 16, 12);
}
-void DreamWebEngine::dumpPointer() {
- dumpBlink();
- multiDump(_delHereX, _delHereY, _delXS, _delYS);
- if ((_oldPointerX != _delHereX) || (_oldPointerY != _delHereY))
- multiDump(_oldPointerX, _oldPointerY, _pointerXS, _pointerYS);
-}
-
-void DreamWebEngine::showPointer() {
- showBlink();
- uint16 x = _mouseX;
- _oldPointerX = _mouseX;
- uint16 y = _mouseY;
- _oldPointerY = _mouseY;
- if (_pickUp == 1) {
- const GraphicsFile *frames;
- if (_objectType != kExObjectType)
- frames = &_freeFrames;
- else
- frames = &_exFrames;
- const Frame *frame = &frames->_frames[(3 * _itemFrame + 1)];
-
- uint8 width = frame->width;
- uint8 height = frame->height;
- if (width < 12)
- width = 12;
- if (height < 12)
- height = 12;
- _pointerXS = width;
- _pointerYS = height;
- uint16 xMin = (x >= width / 2) ? x - width / 2 : 0;
- uint16 yMin = (y >= height / 2) ? y - height / 2 : 0;
- _oldPointerX = xMin;
- _oldPointerY = yMin;
- multiGet(_pointerBack, xMin, yMin, width, height);
- showFrame(*frames, x, y, 3 * _itemFrame + 1, 128);
- showFrame(_icons1, x, y, 3, 128);
- } else {
- const Frame *frame = &_icons1._frames[_pointerFrame + 20];
- uint8 width = frame->width;
- uint8 height = frame->height;
- if (width < 12)
- width = 12;
- if (height < 12)
- height = 12;
- _pointerXS = width;
- _pointerYS = height;
- multiGet(_pointerBack, x, y, width, height);
- showFrame(_icons1, x, y, _pointerFrame + 20, 0);
- }
-}
-
-void DreamWebEngine::animPointer() {
-
- if (_pointerMode == 2) {
- _pointerFrame = 0;
- if ((_realLocation == 14) && (_commandType == 211))
- _pointerFrame = 5;
- return;
- } else if (_pointerMode == 3) {
- if (_pointerSpeed != 0) {
- --_pointerSpeed;
- } else {
- _pointerSpeed = 5;
- ++_pointerCount;
- if (_pointerCount == 16)
- _pointerCount = 0;
- }
- _pointerFrame = (_pointerCount <= 8) ? 1 : 2;
- return;
- }
- if (_vars._watchingTime != 0) {
- _pointerFrame = 11;
- return;
- }
- _pointerFrame = 0;
- if (_inMapArea == 0)
- return;
- if (_pointerFirstPath == 0)
- return;
- uint8 flag, flagEx;
- getFlagUnderP(&flag, &flagEx);
- if (flag < 2)
- return;
- if (flag >= 128)
- return;
- if (flag & 4) {
- _pointerFrame = 3;
- return;
- }
- if (flag & 16) {
- _pointerFrame = 4;
- return;
- }
- if (flag & 2) {
- _pointerFrame = 5;
- return;
- }
- if (flag & 8) {
- _pointerFrame = 6;
- return;
- }
- _pointerFrame = 8;
-}
-
void DreamWebEngine::printMessage(uint16 x, uint16 y, uint8 index, uint8 maxWidth, bool centered) {
const uint8 *string = (const uint8 *)_commandText.getString(index);
printDirect(string, x, y, maxWidth, centered);
@@ -3183,16 +3053,4 @@ void DreamWebEngine::purgeAnItem() {
}
}
-void DreamWebEngine::checkCoords(const RectWithCallback *rectWithCallbacks) {
- if (_newLocation != 0xff)
- return;
- const RectWithCallback *r;
- for (r = rectWithCallbacks; r->_xMin != 0xffff; ++r) {
- if (r->contains(_mouseX, _mouseY)) {
- (this->*(r->_callback))();
- return;
- }
- }
-}
-
} // End of namespace DreamWeb
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index d3b4d6f943..711fe15348 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -95,8 +95,23 @@ bool Screen::init() {
_use16ColorMode = _vm->gameFlags().use16ColorMode;
_isAmiga = (_vm->gameFlags().platform == Common::kPlatformAmiga);
- if (ConfMan.hasKey("render_mode"))
- _renderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
+ // We only check the "render_mode" setting for both Eye of the Beholder
+ // games here, since all the other games do not support the render_mode
+ // setting or handle it differently, like Kyra 1 PC-98. This avoids
+ // graphics glitches and crashes in other games, when the user sets his
+ // global render_mode setting to EGA for example.
+ // TODO/FIXME: It would be nice not to hardcode this. But there is no
+ // trivial/non annoying way to do mode checks in an easy fashion right
+ // now.
+ // In a more general sense, we might want to think about a way to only
+ // pass valid config values, as in values which the engine can work with,
+ // to the engines. We already limit the selection via our GUIO flags in
+ // the game specific settings, but this is not enough due to global
+ // settings allowing everything.
+ if (_vm->game() == GI_EOB1 || _vm->game() == GI_EOB2) {
+ if (ConfMan.hasKey("render_mode"))
+ _renderMode = Common::parseRenderMode(ConfMan.get("render_mode"));
+ }
// CGA and EGA modes use additional pages to do the CGA/EGA specific graphics conversions.
if (_renderMode == Common::kRenderCGA || _renderMode == Common::kRenderEGA) {
diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h
index d741bb801f..ff78d4f18b 100644
--- a/engines/sci/detection_tables.h
+++ b/engines/sci/detection_tables.h
@@ -3445,6 +3445,19 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+ // Space Quest 4 1.000 - French DOS Floppy (supplied by misterhands in bug report #3515247)
+ {"sq4", "", {
+
+ {"resource.map", 0, "1fd6f356f6a59ad2057686ce6573caeb", 6159},
+ {"resource.000", 0, "8000a55aebc50a68b7cce07a8c33758c", 205287},
+ {"resource.001", 0, "99a6df6d366b3f061271ff3450ac0d32", 1269850},
+ {"resource.002", 0, "a6a8d7a24dbb7a266a26b084e7275e89", 1242668},
+ {"resource.003", 0, "482a99c8103b4bcb5706e5969d1c1193", 1323083},
+ {"resource.004", 0, "b2cca3afcf2e013b8ce86b64155af766", 1254353},
+ {"resource.005", 0, "9e520577e035547c4b5149a6d12ef85b", 1098814},
+ AD_LISTEND},
+ Common::FR_FRA, Common::kPlatformPC, 0, GUIO4(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
+
// Space Quest 4 1.000 - English DOS Floppy (from abevi, bug report #2612718)
{"sq4", "", {
{"resource.map", 0, "8f08b97ca093f370c56d99715b015554", 6153},
diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp
index cad95b1c18..8a932232f8 100644
--- a/engines/sci/engine/features.cpp
+++ b/engines/sci/engine/features.cpp
@@ -45,6 +45,7 @@ GameFeatures::GameFeatures(SegManager *segMan, Kernel *kernel) : _segMan(segMan)
_usesCdTrack = Common::File::exists("cdaudio.map");
if (!ConfMan.getBool("use_cdaudio"))
_usesCdTrack = false;
+ _forceDOSTracks = false;
}
reg_t GameFeatures::getDetectionAddr(const Common::String &objName, Selector slc, int methodNum) {
@@ -642,7 +643,7 @@ MoveCountType GameFeatures::detectMoveCountType() {
}
bool GameFeatures::useAltWinGMSound() {
- if (g_sci && g_sci->getPlatform() == Common::kPlatformWindows && g_sci->isCD()) {
+ if (g_sci && g_sci->getPlatform() == Common::kPlatformWindows && g_sci->isCD() && !_forceDOSTracks) {
SciGameId id = g_sci->getGameId();
return (id == GID_ECOQUEST ||
id == GID_JONES ||
diff --git a/engines/sci/engine/features.h b/engines/sci/engine/features.h
index 4592c5be9c..f6bb0b5759 100644
--- a/engines/sci/engine/features.h
+++ b/engines/sci/engine/features.h
@@ -117,6 +117,12 @@ public:
*/
bool useAltWinGMSound();
+ /**
+ * Forces DOS soundtracks in Windows CD versions when the user hasn't
+ * selected a MIDI output device
+ */
+ void forceDOSTracks() { _forceDOSTracks = true; }
+
private:
reg_t getDetectionAddr(const Common::String &objName, Selector slc, int methodNum = -1);
@@ -137,6 +143,7 @@ private:
MoveCountType _moveCountType;
bool _usesCdTrack;
+ bool _forceDOSTracks;
SegManager *_segMan;
Kernel *_kernel;
diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp
index 71f4598afc..14ffa69f91 100644
--- a/engines/sci/graphics/cursor.cpp
+++ b/engines/sci/graphics/cursor.cpp
@@ -148,11 +148,13 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) {
colorMapping[1] = _screen->getColorWhite(); // White is also hardcoded
colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR;
colorMapping[3] = _palette->matchColor(170, 170, 170); // Grey
- // Special case for the magnifier cursor in LB1 (bug #3487092).
- // No other SCI0 game has a cursor resource of 1, so this is handled
- // specifically for LB1.
+ // TODO: Figure out if the grey color is hardcoded
+ // HACK for the magnifier cursor in LB1, fixes its color (bug #3487092)
if (g_sci->getGameId() == GID_LAURABOW && resourceId == 1)
colorMapping[3] = _screen->getColorWhite();
+ // HACK for Longbow cursors, fixes the shade of grey they're using (bug #3489101)
+ if (g_sci->getGameId() == GID_LONGBOW)
+ colorMapping[3] = _palette->matchColor(223, 223, 223); // Light Grey
// Seek to actual data
resourceData += 4;
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index 09cab75c39..918b045cb9 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -88,6 +88,12 @@ void SciMusic::init() {
uint32 dev = MidiDriver::detectDevice(deviceFlags);
_musicType = MidiDriver::getMusicType(dev);
+ if (g_sci->_features->useAltWinGMSound() && _musicType != MT_GM) {
+ warning("A Windows CD version with an alternate MIDI soundtrack has been chosen, "
+ "but no MIDI music device has been selected. Reverting to the DOS soundtrack");
+ g_sci->_features->forceDOSTracks();
+ }
+
switch (_musicType) {
case MT_ADLIB:
// FIXME: There's no Amiga sound option, so we hook it up to AdLib
diff --git a/engines/scumm/detection.cpp b/engines/scumm/detection.cpp
index b47982af00..2da0abb5df 100644
--- a/engines/scumm/detection.cpp
+++ b/engines/scumm/detection.cpp
@@ -589,11 +589,11 @@ static void detectGames(const Common::FSList &fslist, Common::List<DetectorResul
file.c_str(), md5str.c_str(), filesize);
// Sanity check: We *should* have found a matching gameid / variant at this point.
- // If not, then there's a bug in our data tables...
- assert(dr.game.gameid != 0);
-
- // Add it to the list of detected games
- results.push_back(dr);
+ // If not, we may have #ifdef'ed the entry out in our detection_tables.h because we
+ // don't have the required stuff compiled in, or there's a bug in our data tables...
+ if (dr.game.gameid != 0)
+ // Add it to the list of detected games
+ results.push_back(dr);
}
}
diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h
index c25c875616..3957c7c42d 100644
--- a/engines/scumm/scumm-md5.h
+++ b/engines/scumm/scumm-md5.h
@@ -1,5 +1,5 @@
/*
- This file was generated by the md5table tool on Mon Apr 9 12:23:48 2012
+ This file was generated by the md5table tool on Tue Apr 24 03:50:58 2012
DO NOT EDIT MANUALLY!
*/
@@ -621,6 +621,7 @@ static const MD5Table md5table[] = {
{ "f40a7f495f59188ca57a9d1d50301bb6", "puttputt", "HE 60", "Demo", -1, Common::EN_ANY, Common::kPlatformMacintosh },
{ "f5228b0cc1c19e6ea8268ba2eeb61f60", "freddi", "HE 73", "Demo", -1, Common::FR_FRA, Common::kPlatformWindows },
{ "f73883f13b5a302749a5bad31d909780", "tentacle", "", "CD", -1, Common::DE_DEU, Common::kPlatformMacintosh },
+ { "f7635a0e2ab82c9a0f9ace5f232a488f", "catalog", "HE 72", "Demo", -1, Common::EN_ANY, Common::kPlatformWindows },
{ "f7711f9264d4d43c2a1518ec7c10a607", "pajama3", "", "", 79382, Common::EN_USA, Common::kPlatformUnknown },
{ "f79e60c17cca601e411f1f75e8ee9b5a", "spyfox2", "", "", 51286, Common::UNK_LANG, Common::kPlatformUnknown },
{ "f8be685007a8b425ba2a455da732f59f", "pajama2", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformMacintosh },
diff --git a/engines/sword25/script/luabindhelper.cpp b/engines/sword25/script/luabindhelper.cpp
index 8fbbe7e272..6900305f5c 100644
--- a/engines/sword25/script/luabindhelper.cpp
+++ b/engines/sword25/script/luabindhelper.cpp
@@ -412,7 +412,7 @@ Common::String LuaBindhelper::stackDump(lua_State *L) {
oss += "------------------- Stack Dump -------------------\n";
while (i) {
- oss += i + ": " + getLuaValueInfo(L, i) + "\n";
+ oss += Common::String::format("%d: ", i) + getLuaValueInfo(L, i) + "\n";
i--;
}
diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h
index be44b1c462..b6b19f6ee7 100644
--- a/engines/tinsel/detection_tables.h
+++ b/engines/tinsel/detection_tables.h
@@ -397,7 +397,7 @@ static const TinselGameDescription gameDescriptions[] = {
{ // multilanguage PSX demo
{
"dw",
- "CD demo",
+ "CD Demo",
{
{"french.txt", 0, "e7020d35f58d0d187052ac406d86cc87", 273914},
{"german.txt", 0, "52f0a01e0ff0d340b02a36fd5109d705", 263942},
diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp
index 781a378f13..fa5334a033 100644
--- a/engines/tinsel/music.cpp
+++ b/engines/tinsel/music.cpp
@@ -131,11 +131,6 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
g_currentMidi = dwFileOffset;
g_currentLoop = bLoop;
- // Tinsel V1 PSX uses a different music format, so i
- // disable it here.
- // TODO: Maybe this should be moved to a better place...
- if (TinselV1PSX) return false;
-
if (_vm->_config->_musicVolume != 0) {
bool mute = false;
if (ConfMan.hasKey("mute"))
@@ -231,14 +226,14 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
_vm->_midiMusic->send(0x7F07B0 | 13);
}
- _vm->_midiMusic->playXMIDI(g_midiBuffer.pDat, dwSeqLen, bLoop);
+ _vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
// Store the length
//dwLastSeqLen = dwSeqLen;
} else {
// dwFileOffset == dwLastMidiIndex
_vm->_midiMusic->stop();
- _vm->_midiMusic->playXMIDI(g_midiBuffer.pDat, dwSeqLen, bLoop);
+ _vm->_midiMusic->playMIDI(dwSeqLen, bLoop);
}
return true;
@@ -314,8 +309,7 @@ void OpenMidiFiles() {
Common::File midiStream;
// Demo version has no midi file
- // Also, Discworld PSX uses still unsupported psx SEQ format for music...
- if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2) || TinselV1PSX)
+ if ((_vm->getFeatures() & GF_DEMO) || (TinselVersion == TINSEL_V2))
return;
if (g_midiBuffer.pDat)
@@ -412,7 +406,7 @@ void MidiMusicPlayer::send(uint32 b) {
}
}
-void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
+void MidiMusicPlayer::playMIDI(uint32 size, bool loop) {
Common::StackLock lock(_mutex);
if (_isPlaying)
@@ -420,6 +414,13 @@ void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
stop();
+ if (TinselV1PSX)
+ playSEQ(size, loop);
+ else
+ playXMIDI(size, loop);
+}
+
+void MidiMusicPlayer::playXMIDI(uint32 size, bool loop) {
// It seems like not all music (the main menu music, for instance) set
// all the instruments explicitly. That means the music will sound
// different, depending on which music played before it. This appears
@@ -433,7 +434,78 @@ void MidiMusicPlayer::playXMIDI(byte *midiData, uint32 size, bool loop) {
// Load XMID resource data
MidiParser *parser = MidiParser::createParser_XMIDI();
- if (parser->loadMusic(midiData, size)) {
+ if (parser->loadMusic(g_midiBuffer.pDat, size)) {
+ parser->setTrack(0);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(getBaseTempo());
+ parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
+ parser->property(MidiParser::mpSendSustainOffOnNotesOff, 1);
+
+ _parser = parser;
+
+ _isLooping = loop;
+ _isPlaying = true;
+ } else {
+ delete parser;
+ }
+}
+
+void MidiMusicPlayer::playSEQ(uint32 size, bool loop) {
+ // MIDI.DAT holds the file names in DW1 PSX
+ Common::String baseName((char *)g_midiBuffer.pDat, size);
+ Common::String seqName = baseName + ".SEQ";
+
+ // TODO: Load the instrument bank (<baseName>.VB and <baseName>.VH)
+
+ Common::File seqFile;
+ if (!seqFile.open(seqName))
+ error("Failed to open SEQ file '%s'", seqName.c_str());
+
+ if (seqFile.readUint32LE() != MKTAG('S', 'E', 'Q', 'p'))
+ error("Failed to find SEQp tag");
+
+ // Make sure we don't have a SEP file (with multiple SEQ's inside)
+ if (seqFile.readUint32BE() != 1)
+ error("Can only play SEQ files, not SEP");
+
+ uint16 ppqn = seqFile.readUint16BE();
+ uint32 tempo = seqFile.readUint16BE() << 8;
+ tempo |= seqFile.readByte();
+ /* uint16 beat = */ seqFile.readUint16BE();
+
+ // SEQ is directly based on SMF and we'll use that to our advantage here
+ // and convert to SMF and then use the SMF MidiParser.
+
+ // Calculate the SMF size we'll need
+ uint32 dataSize = seqFile.size() - 15;
+ uint32 actualSize = dataSize + 7 + 22;
+
+ // Resize the buffer if necessary
+ if (g_midiBuffer.size < actualSize) {
+ g_midiBuffer.pDat = (byte *)realloc(g_midiBuffer.pDat, actualSize);
+ assert(g_midiBuffer.pDat);
+ }
+
+ // Now construct the header
+ WRITE_BE_UINT32(g_midiBuffer.pDat, MKTAG('M', 'T', 'h', 'd'));
+ WRITE_BE_UINT32(g_midiBuffer.pDat + 4, 6); // header size
+ WRITE_BE_UINT16(g_midiBuffer.pDat + 8, 0); // type 0
+ WRITE_BE_UINT16(g_midiBuffer.pDat + 10, 1); // one track
+ WRITE_BE_UINT16(g_midiBuffer.pDat + 12, ppqn);
+ WRITE_BE_UINT32(g_midiBuffer.pDat + 14, MKTAG('M', 'T', 'r', 'k'));
+ WRITE_BE_UINT32(g_midiBuffer.pDat + 18, dataSize + 7); // SEQ data size + tempo change event size
+
+ // Add in a fake tempo change event
+ WRITE_BE_UINT32(g_midiBuffer.pDat + 22, 0x00FF5103); // no delta, meta event, tempo change, param size = 3
+ WRITE_BE_UINT16(g_midiBuffer.pDat + 26, tempo >> 8);
+ g_midiBuffer.pDat[28] = tempo & 0xFF;
+
+ // Now copy in the rest of the events
+ seqFile.read(g_midiBuffer.pDat + 29, dataSize);
+ seqFile.close();
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ if (parser->loadMusic(g_midiBuffer.pDat, actualSize)) {
parser->setTrack(0);
parser->setMidiDriver(this);
parser->setTimerRate(getBaseTempo());
diff --git a/engines/tinsel/music.h b/engines/tinsel/music.h
index d43fed268d..121bf3d79b 100644
--- a/engines/tinsel/music.h
+++ b/engines/tinsel/music.h
@@ -64,7 +64,7 @@ public:
virtual void setVolume(int volume);
- void playXMIDI(byte *midiData, uint32 size, bool loop);
+ void playMIDI(uint32 size, bool loop);
// void stop();
void pause();
@@ -76,6 +76,10 @@ public:
// The original sets the "sequence timing" to 109 Hz, whatever that
// means. The default is 120.
uint32 getBaseTempo() { return _driver ? (109 * _driver->getBaseTempo()) / 120 : 0; }
+
+private:
+ void playXMIDI(uint32 size, bool loop);
+ void playSEQ(uint32 size, bool loop);
};
class PCMMusicPlayer : public Audio::AudioStream {
diff --git a/engines/tinsel/tinlib.cpp b/engines/tinsel/tinlib.cpp
index c652abca25..cd65a4ec32 100644
--- a/engines/tinsel/tinlib.cpp
+++ b/engines/tinsel/tinlib.cpp
@@ -1626,7 +1626,7 @@ static void Play(CORO_PARAM, SCNHANDLE hFilm, int x, int y, bool bComplete, int
*/
static void PlayMidi(CORO_PARAM, SCNHANDLE hMidi, int loop, bool complete) {
// FIXME: This is a workaround for the FIXME below
- if (GetMidiVolume() == 0 || TinselV1PSX)
+ if (GetMidiVolume() == 0)
return;
CORO_BEGIN_CONTEXT;
diff --git a/graphics/decoders/bmp.h b/graphics/decoders/bmp.h
index 6360aa81c9..8a37538ee1 100644
--- a/graphics/decoders/bmp.h
+++ b/graphics/decoders/bmp.h
@@ -51,7 +51,7 @@ public:
void destroy();
virtual bool loadStream(Common::SeekableReadStream &stream);
virtual const Surface *getSurface() const { return _surface; }
- virtual const byte *getPalette() { return _palette; }
+ const byte *getPalette() const { return _palette; }
private:
Surface *_surface;
diff --git a/graphics/decoders/pict.cpp b/graphics/decoders/pict.cpp
index 957342084e..bdb733a87d 100644
--- a/graphics/decoders/pict.cpp
+++ b/graphics/decoders/pict.cpp
@@ -361,14 +361,14 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPal
memcpy(_outputSurface->pixels, buffer, _outputSurface->w * _outputSurface->h);
break;
case 2:
- // Convert from 16-bit to whatever surface we need
+ // We have a 16-bit surface
_outputSurface->create(width, height, PixelFormat(2, 5, 5, 5, 0, 10, 5, 0, 0));
for (uint16 y = 0; y < _outputSurface->h; y++)
for (uint16 x = 0; x < _outputSurface->w; x++)
WRITE_UINT16(_outputSurface->getBasePtr(x, y), READ_UINT16(buffer + (y * _outputSurface->w + x) * 2));
break;
case 3:
- // Convert from 24-bit (planar!) to whatever surface we need
+ // We have a planar 24-bit surface
_outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
for (uint16 y = 0; y < _outputSurface->h; y++) {
for (uint16 x = 0; x < _outputSurface->w; x++) {
@@ -380,15 +380,18 @@ void PICTDecoder::unpackBitsRect(Common::SeekableReadStream &stream, bool hasPal
}
break;
case 4:
- // Convert from 32-bit (planar!) to whatever surface we need
+ // We have a planar 32-bit surface
+ // Note that we ignore the alpha channel since it seems to not be correct
+ // Mac OS X does not ignore it, but then displays it incorrectly. Photoshop
+ // does ignore it and displays it correctly.
_outputSurface->create(width, height, Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0));
for (uint16 y = 0; y < _outputSurface->h; y++) {
for (uint16 x = 0; x < _outputSurface->w; x++) {
- byte r = *(buffer + y * _outputSurface->w * 4 + x);
- byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x);
- byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x);
- byte a = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x);
- *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.ARGBToColor(r, g, b, a);
+ byte a = 0xFF;
+ byte r = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w + x);
+ byte g = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 2 + x);
+ byte b = *(buffer + y * _outputSurface->w * 4 + _outputSurface->w * 3 + x);
+ *((uint32 *)_outputSurface->getBasePtr(x, y)) = _outputSurface->format.ARGBToColor(a, r, g, b);
}
}
break;
@@ -541,10 +544,14 @@ void PICTDecoder::decodeCompressedQuickTime(Common::SeekableReadStream &stream)
// Now we've reached the image descriptor, so read the relevant data from that
uint32 idStart = stream.pos();
uint32 idSize = stream.readUint32BE();
- stream.skip(40); // miscellaneous stuff
+ uint32 codec = stream.readUint32BE();
+ stream.skip(36); // miscellaneous stuff
uint32 jpegSize = stream.readUint32BE();
stream.skip(idSize - (stream.pos() - idStart)); // more useless stuff
+ if (codec != MKTAG('j', 'p', 'e', 'g'))
+ error("Unhandled CompressedQuickTime format '%s'", tag2str(codec));
+
Common::SeekableSubReadStream jpegStream(&stream, stream.pos(), stream.pos() + jpegSize);
JPEGDecoder jpeg;
diff --git a/graphics/fontman.cpp b/graphics/fontman.cpp
index 8d967d595f..99dd3d664f 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<Common::String, const Font *>::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 42f7d856fa..b06ddea860 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<Common::String, const Font *> _fontMap;
+ Common::Array<const Font *> _ownedFonts;
Common::String _localizedFontName;
};
diff --git a/graphics/fonts/bdf.h b/graphics/fonts/bdf.h
index 5b615cc043..b0166a2095 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 7505f7913e..96241e923c 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 7222d6e112..ec7dbe04ef 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/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index fdd7750af9..be0a5db601 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},
@@ -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;
}
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 0495a85c88..acded085f5 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.12"
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;
diff --git a/gui/dialog.cpp b/gui/dialog.cpp
index 2201e83ca5..ffca15bbc8 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 f5a5f94a68..1773c6633e 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 ffecd928bc..abd781e1a3 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 a86a98f819..c8ed3126c4 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();
diff --git a/gui/predictivedialog.cpp b/gui/predictivedialog.cpp
index 9cd18b81ba..b827d49416 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);
-
-#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 = (ButtonWidget **)calloc(1, sizeof(ButtonWidget *) * 16);
+
+ _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);
+ _currBtn = ButtonId(_lastbutton + 2);
+ else if (_lastbutton == kDelAct)
+ _currBtn = kBtn1Act;
+ else if (_lastbutton == kModeAct)
+ _currBtn = kNextAct;
else if (_lastbutton == kNextAct)
- act = kBtn0Act;
- else if (_lastbutton == kDelAct)
- act = kDelAct;
+ _currBtn = kBtn0Act;
+ else if (_lastbutton == kAddAct)
+ _currBtn = kOkAct;
else if (_lastbutton == kCancelAct)
- act = kOkAct;
- else if (_lastbutton == kModeAct)
- act = kAddAct;
+ _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);
+ if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act || _lastbutton == kOkAct)
+ _currBtn = ButtonId(_lastbutton - 2);
+ else if (_lastbutton == kDelAct)
+ _currBtn = kBtn3Act;
+ else if (_lastbutton == kBtn0Act)
+ _currBtn = kNextAct;
+ else if (_lastbutton == kNextAct)
+ _currBtn = kModeAct;
else if (_lastbutton == kAddAct)
- act = kModeAct;
- else if (_lastbutton == kDelAct)
- act = kDelAct;
+ _currBtn = kCancelAct;
else if (_lastbutton == kOkAct)
- act = kCancelAct;
- else if (_lastbutton == kBtn0Act)
- act = kNextAct;
+ _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 32de36d5f2..0e3d2967c0 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/themes/default.inc b/gui/themes/default.inc
index 542f776dbd..5ee9b9202a 100644
--- a/gui/themes/default.inc
+++ b/gui/themes/default.inc
@@ -460,6 +460,17 @@
"bevel='2' "
"/> "
"</drawdata> "
+"<drawdata id='button_pressed' cache='false'> "
+"<text font='text_button' "
+"text_color='color_alternative_inverted' "
+"vertical_align='center' "
+"horizontal_align='center' "
+"/> "
+"<drawstep func='square' "
+"fill='foreground' "
+"fg_color='green' "
+"/> "
+"</drawdata> "
"<drawdata id='button_idle' cache='false'> "
"<text font='text_button' "
"text_color='color_button' "
diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip
index eb5ac2d9f7..ec1728b778 100644
--- a/gui/themes/scummclassic.zip
+++ b/gui/themes/scummclassic.zip
Binary files differ
diff --git a/gui/themes/scummclassic/THEMERC b/gui/themes/scummclassic/THEMERC
index b808aee32f..7cbed97e40 100644
--- a/gui/themes/scummclassic/THEMERC
+++ b/gui/themes/scummclassic/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.11:ScummVM Classic Theme:No Author]
+[SCUMMVM_STX0.8.12:ScummVM Classic Theme:No Author]
diff --git a/gui/themes/scummclassic/classic_gfx.stx b/gui/themes/scummclassic/classic_gfx.stx
index f07499ce79..49ecea2e11 100644
--- a/gui/themes/scummclassic/classic_gfx.stx
+++ b/gui/themes/scummclassic/classic_gfx.stx
@@ -541,6 +541,19 @@
/>
</drawdata>
+ <!-- Pressed button -->
+ <drawdata id = 'button_pressed' cache = 'false'>
+ <text font = 'text_button'
+ text_color = 'color_alternative_inverted'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'square'
+ fill = 'foreground'
+ fg_color = 'green'
+ />
+ </drawdata>
+
<drawdata id = 'button_idle' cache = 'false'>
<text font = 'text_button'
text_color = 'color_button'
diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip
index 94f7cd8f6e..deae315e30 100644
--- a/gui/themes/scummmodern.zip
+++ b/gui/themes/scummmodern.zip
Binary files differ
diff --git a/gui/themes/scummmodern/THEMERC b/gui/themes/scummmodern/THEMERC
index e6c441d543..326993e98d 100644
--- a/gui/themes/scummmodern/THEMERC
+++ b/gui/themes/scummmodern/THEMERC
@@ -1 +1 @@
-[SCUMMVM_STX0.8.11:ScummVM Modern Theme:No Author]
+[SCUMMVM_STX0.8.12:ScummVM Modern Theme:No Author]
diff --git a/gui/themes/scummmodern/scummmodern_gfx.stx b/gui/themes/scummmodern/scummmodern_gfx.stx
index 403f636fd0..970d78a5ae 100644
--- a/gui/themes/scummmodern/scummmodern_gfx.stx
+++ b/gui/themes/scummmodern/scummmodern_gfx.stx
@@ -740,6 +740,27 @@
/>
</drawdata>
+ <!-- Pressed button -->
+ <drawdata id = 'button_pressed' cache = 'false'>
+ <text font = 'text_button'
+ text_color = 'color_button'
+ vertical_align = 'center'
+ horizontal_align = 'center'
+ />
+ <drawstep func = 'roundedsq'
+ radius = '5'
+ stroke = '1'
+ fill = 'foreground'
+ shadow = '0'
+ factor = '0'
+ fg_color = '120, 40, 16'
+ gradient_start = '255, 0, 0'
+ gradient_end = '255, 0, 0'
+ bevel = '1'
+ bevel_color = 'black'
+ />
+ </drawdata>
+
<!-- Idle button -->
<drawdata id = 'button_idle' cache = 'false'>
<text font = 'text_button'
diff --git a/gui/widget.cpp b/gui/widget.cpp
index 0e2fd248b1..6ae4e5cee5 100644
--- a/gui/widget.cpp
+++ b/gui/widget.cpp
@@ -30,6 +30,8 @@
#include "gui/ThemeEval.h"
+#include "gui/dialog.h"
+
namespace GUI {
Widget::Widget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip)
@@ -77,6 +79,8 @@ void Widget::updateState(int oldFlags, int newFlags) {
_state = ThemeEngine::kStateEnabled;
if (newFlags & WIDGET_HILITED)
_state = ThemeEngine::kStateHighlight;
+ if (newFlags & WIDGET_PRESSED)
+ _state = ThemeEngine::kStatePressed;
} else {
_state = ThemeEngine::kStateDisabled;
}
@@ -272,27 +276,33 @@ void StaticTextWidget::drawWidget() {
ButtonWidget::ButtonWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &label, const char *tooltip, uint32 cmd, uint8 hotkey)
: StaticTextWidget(boss, x, y, w, h, cleanupHotkey(label), Graphics::kTextAlignCenter, tooltip), CommandSender(boss),
- _cmd(cmd), _hotkey(hotkey) {
+ _cmd(cmd), _hotkey(hotkey), _lastTime(0) {
if (hotkey == 0)
_hotkey = parseHotkey(label);
- setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
+ setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG | WIDGET_WANT_TICKLE);
_type = kButtonWidget;
}
ButtonWidget::ButtonWidget(GuiObject *boss, const Common::String &name, const Common::String &label, const char *tooltip, uint32 cmd, uint8 hotkey)
: StaticTextWidget(boss, name, cleanupHotkey(label), tooltip), CommandSender(boss),
- _cmd(cmd) {
+ _cmd(cmd), _lastTime(0) {
if (hotkey == 0)
_hotkey = parseHotkey(label);
- setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG);
+ setFlags(WIDGET_ENABLED/* | WIDGET_BORDER*/ | WIDGET_CLEARBG | WIDGET_WANT_TICKLE);
_type = kButtonWidget;
}
void ButtonWidget::handleMouseUp(int x, int y, int button, int clickCount) {
- if (isEnabled() && x >= 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,6 +334,44 @@ 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)
diff --git a/gui/widget.h b/gui/widget.h
index 789fc09231..6a6c67ced9 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 */