synced with scummvm svn rev 53000

This commit is contained in:
Pawel Kolodziejski 2011-04-11 15:40:01 +02:00
parent 886c17d130
commit 241c7a8c6e
116 changed files with 104334 additions and 1926 deletions

View file

@ -34,14 +34,24 @@ ifeq "$(HAVE_GCC)" "1"
# being helpful.
#CXXFLAGS+= -Wmissing-format-attribute
# Disable exceptions, and enable checking of pointers returned by "new"
CXXFLAGS+= -fno-exceptions -fcheck-new
# Disable RTTI and exceptions
CXXFLAGS+= -fno-rtti -fno-exceptions
ifneq "$(HAVE_CLANG)" "1"
# enable checking of pointers returned by "new", but only when we do not
# build with clang
CXXFLAGS+= -fcheck-new
endif
endif
ifeq "$(HAVE_CLANG)" "1"
CXXFLAGS+= -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-compare -Wno-four-char-constants
endif
# Warn if global constructors are used. Only available in GCC with LLVM backend
# (and maybe clang?), hence off by default.
#CXXFLAGS+= -Wglobal-constructors
#######################################################################
# Default commands - put the necessary replacements in config.mk #
#######################################################################

View file

@ -172,7 +172,7 @@ SVNROOT := https://resisual.svn.sourceforge.net/svnroot/residual/residual/trunk/
endif
# Define the Subversion revision if available, either autodetected or
# specified by the user
# specified by the user, but only for base/version.cpp.
ifneq ($(origin VER_SVNREV), undefined)
CXXFLAGS+= -DRESIDUAL_SVN_REVISION=\"$(VER_SVNREV)\"
endif
@ -227,7 +227,11 @@ dist-src: \
DIST_FILES_DOCS:=$(addprefix $(srcdir)/,AUTHORS COPYING COPYING.LGPL NEWS README)
# Themes files
DIST_FILES_THEMES:=$(addprefix $(srcdir)/gui/themes/,modern.zip)
DIST_FILES_THEMES=modern.zip
ifdef USE_TRANSLATION
DIST_FILES_THEMES+=translations.dat
endif
DIST_FILES_THEMES:=$(addprefix $(srcdir)/gui/themes/,$(DIST_FILES_THEMES))
# Engine data files
DIST_FILES_ENGINEDATA=

View file

@ -169,6 +169,7 @@ bool DefaultEventManager::pollEvent(Common::Event &event) {
// key pressed. A better fix would be for engines to stop
// making invalid assumptions about ascii values.
event.kbd.ascii = Common::KEYCODE_BACKSPACE;
_currentKeyDown.ascii = Common::KEYCODE_BACKSPACE;
}
break;

View file

@ -24,7 +24,7 @@
#include "common/sys.h"
#if defined(UNIX) && defined(USE_ALSA)
#if defined(USE_ALSA)
#include "common/config-manager.h"
#include "common/util.h"
@ -48,6 +48,17 @@
#define my_snd_seq_open(seqp) snd_seq_open(seqp, SND_SEQ_OPEN)
#endif
#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
static int check_permission(snd_seq_port_info_t *pinfo)
{
if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) {
if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT))
return 1;
}
return 0;
}
/*
* parse address string
*/
@ -56,7 +67,7 @@
class MidiDriver_ALSA:public MidiDriver_MPU401 {
public:
MidiDriver_ALSA();
MidiDriver_ALSA(int client, int port);
int open();
void close();
void send(uint32 b);
@ -69,48 +80,38 @@ private:
snd_seq_t *seq_handle;
int seq_client, seq_port;
int my_client, my_port;
static int parse_addr(const char *arg, int *client, int *port);
};
MidiDriver_ALSA::MidiDriver_ALSA()
: _isOpen(false), seq_handle(0), seq_client(0), seq_port(0), my_client(0), my_port(0)
MidiDriver_ALSA::MidiDriver_ALSA(int client, int port)
: _isOpen(false), seq_handle(0), seq_client(client), seq_port(port), my_client(0), my_port(0)
{
memset(&ev, 0, sizeof(ev));
}
int MidiDriver_ALSA::open() {
const char *var = NULL;
if (_isOpen)
return MERR_ALREADY_OPEN;
_isOpen = true;
var = getenv("SCUMMVM_PORT");
if (!var && ConfMan.hasKey("alsa_port")) {
var = ConfMan.get("alsa_port").c_str();
}
if (var) {
if (parse_addr(var, &seq_client, &seq_port) < 0) {
error("Invalid port %s", var);
return -1;
}
}
if (my_snd_seq_open(&seq_handle) < 0) {
error("Can't open sequencer");
return -1;
}
my_client = snd_seq_client_id(seq_handle);
if (snd_seq_set_client_name(seq_handle, "SCUMMVM") < 0) {
if (snd_seq_set_client_name(seq_handle, "RESIDUAL") < 0) {
error("Can't set sequencer client name");
}
snd_seq_set_client_group(seq_handle, "input");
my_port = snd_seq_create_simple_port(seq_handle, "SCUMMVM port 0",
SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE |
SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC);
// According to http://www.alsa-project.org/~tiwai/alsa-subs.html
// you can set read or write capabilities to allow other clients to
// read or write the port. I don't think we need that, unless maybe
// to be able to record the sound, but I can't get that to work even
// with those capabilities.
my_port = snd_seq_create_simple_port(seq_handle, "RESIDUAL port 0", 0,
SND_SEQ_PORT_TYPE_MIDI_GENERIC | SND_SEQ_PORT_TYPE_APPLICATION);
if (my_port < 0) {
snd_seq_close(seq_handle);
@ -118,30 +119,46 @@ int MidiDriver_ALSA::open() {
return -1;
}
if (var) {
if (seq_client != SND_SEQ_ADDRESS_SUBSCRIBERS) {
// subscribe to MIDI port
// Subscribe to MIDI port. Prefer one that doesn't already have
// any connections, unless we've forced a port number already.
if (seq_port == -1) {
snd_seq_client_info_t *cinfo;
snd_seq_port_info_t *pinfo;
snd_seq_client_info_alloca(&cinfo);
snd_seq_port_info_alloca(&pinfo);
snd_seq_get_any_client_info(seq_handle, seq_client, cinfo);
int first_port = -1;
int found_port = -1;
snd_seq_port_info_set_client(pinfo, seq_client);
snd_seq_port_info_set_port(pinfo, -1);
while (found_port == -1 && snd_seq_query_next_port(seq_handle, pinfo) >= 0) {
if (check_permission(pinfo)) {
if (first_port == -1)
first_port = snd_seq_port_info_get_port(pinfo);
if (found_port == -1 && snd_seq_port_info_get_write_use(pinfo) == 0)
found_port = snd_seq_port_info_get_port(pinfo);
}
}
if (found_port == -1) {
// Should we abort here? For now, use the first
// available port.
seq_port = first_port;
warning("MidiDriver_ALSA: All ports on client %d (%s) are already in use", seq_client, snd_seq_client_info_get_name(cinfo));
} else {
seq_port = found_port;
}
}
if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) < 0) {
error("Can't subscribe to MIDI port (%d:%d) see README for help", seq_client, seq_port);
}
}
} else {
int defaultPorts[] = {
65, 0,
17, 0
};
int i;
for (i = 0; i < ARRAYSIZE(defaultPorts); i += 2) {
seq_client = defaultPorts[i];
seq_port = defaultPorts[i + 1];
if (snd_seq_connect_to(seq_handle, my_port, seq_client, seq_port) >= 0)
break;
}
if (i >= ARRAYSIZE(defaultPorts))
error("Can't subscribe to MIDI port (65:0) or (17:0)");
}
printf("Connected to Alsa sequencer client [%d:%d]\n", seq_client, seq_port);
printf("ALSA client initialised [%d:0]\n", my_client);
@ -230,7 +247,203 @@ void MidiDriver_ALSA::sysEx(const byte *msg, uint16 length) {
send_event(1);
}
int MidiDriver_ALSA::parse_addr(const char *arg, int *client, int *port) {
void MidiDriver_ALSA::send_event(int do_flush) {
snd_seq_ev_set_direct(&ev);
snd_seq_ev_set_source(&ev, my_port);
snd_seq_ev_set_dest(&ev, seq_client, seq_port);
snd_seq_event_output(seq_handle, &ev);
if (do_flush)
snd_seq_flush_output(seq_handle);
}
// Plugin interface
class AlsaDevice {
public:
AlsaDevice(Common::String name, MusicType mt, int client);
Common::String getName();
MusicType getType();
int getClient();
private:
Common::String _name;
MusicType _type;
int _client;
};
typedef Common::List<AlsaDevice> AlsaDevices;
AlsaDevice::AlsaDevice(Common::String name, MusicType mt, int client)
: _name(name), _type(mt), _client(client) {
}
Common::String AlsaDevice::getName() {
return _name;
}
MusicType AlsaDevice::getType() {
return _type;
}
int AlsaDevice::getClient() {
return _client;
}
class AlsaMusicPlugin : public MusicPluginObject {
public:
const char *getName() const {
return "ALSA";
}
const char *getId() const {
return "alsa";
}
AlsaDevices getAlsaDevices() const;
MusicDevices getDevices() const;
Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
private:
static int parse_addr(const char *arg, int *client, int *port);
};
AlsaDevices AlsaMusicPlugin::getAlsaDevices() const {
AlsaDevices devices;
snd_seq_t *seq_handle;
if (my_snd_seq_open(&seq_handle) < 0)
return devices; // can't open sequencer
snd_seq_client_info_t *cinfo;
snd_seq_client_info_alloca(&cinfo);
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca(&pinfo);
snd_seq_client_info_set_client(cinfo, -1);
while (snd_seq_query_next_client(seq_handle, cinfo) >= 0) {
bool found_valid_port = false;
/* reset query info */
snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
snd_seq_port_info_set_port(pinfo, -1);
while (!found_valid_port && snd_seq_query_next_port(seq_handle, pinfo) >= 0) {
if (check_permission(pinfo)) {
found_valid_port = true;
const char *name = snd_seq_client_info_get_name(cinfo);
// TODO: Can we figure out the appropriate music type?
MusicType type = MT_GM;
int client = snd_seq_client_info_get_client(cinfo);
devices.push_back(AlsaDevice(name, type, client));
}
}
}
snd_seq_close(seq_handle);
return devices;
}
MusicDevices AlsaMusicPlugin::getDevices() const {
MusicDevices devices;
AlsaDevices::iterator d;
AlsaDevices alsaDevices = getAlsaDevices();
// Since the default behaviour is to use the first device in the list,
// try to put something sensible there. We used to have 17:0 and 65:0
// as defaults.
for (d = alsaDevices.begin(); d != alsaDevices.end();) {
const int client = d->getClient();
if (client == 17 || client == 65) {
devices.push_back(MusicDevice(this, d->getName(), d->getType()));
d = alsaDevices.erase(d);
} else {
++d;
}
}
// 128:0 is probably TiMidity, or something like that, so that's
// probably a good second choice.
for (d = alsaDevices.begin(); d != alsaDevices.end();) {
if (d->getClient() == 128) {
devices.push_back(MusicDevice(this, d->getName(), d->getType()));
d = alsaDevices.erase(d);
} else {
++d;
}
}
// Add the remaining devices in the order they were found.
for (d = alsaDevices.begin(); d != alsaDevices.end(); ++d)
devices.push_back(MusicDevice(this, d->getName(), d->getType()));
return devices;
}
Common::Error AlsaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle dev) const {
bool found = false;
int seq_client, seq_port;
const char *var = NULL;
// TODO: Upgrade from old alsa_port setting. This probably isn't the
// right place to do that, though.
if (ConfMan.hasKey("alsa_port")) {
warning("AlsaMusicPlugin: Found old 'alsa_port' setting, which will be ignored");
}
// The SCUMMVM_PORT environment variable can still be used to override
// any config setting.
var = getenv("RESIDUAL_PORT");
if (var) {
warning("AlsaMusicPlugin: RESIDUAL_PORT environment variable overrides config settings");
if (parse_addr(var, &seq_client, &seq_port) >= 0) {
found = true;
} else {
warning("AlsaMusicPlugin: Invalid port %s, using config settings instead", var);
}
}
// Try to match the setting to an available ALSA device.
if (!found && dev) {
AlsaDevices alsaDevices = getAlsaDevices();
for (AlsaDevices::iterator d = alsaDevices.begin(); d != alsaDevices.end(); ++d) {
MusicDevice device(this, d->getName(), d->getType());
if (device.getCompleteId().equals(MidiDriver::getDeviceString(dev, MidiDriver::kDeviceId))) {
found = true;
seq_client = d->getClient();
seq_port = -1;
break;
}
}
}
// Still nothing? Try a sensible default.
if (!found) {
// TODO: What's a sensible default anyway? And exactly when do
// we get to this case?
warning("AlsaMusicPlugin: Using 17:0 as default ALSA port");
seq_client = 17;
seq_port = 0;
}
*mididriver = new MidiDriver_ALSA(seq_client, seq_port);
return Common::kNoError;
}
int AlsaMusicPlugin::parse_addr(const char *arg, int *client, int *port) {
const char *p;
if (isdigit(*arg)) {
@ -248,82 +461,6 @@ int MidiDriver_ALSA::parse_addr(const char *arg, int *client, int *port) {
return 0;
}
void MidiDriver_ALSA::send_event(int do_flush) {
snd_seq_ev_set_direct(&ev);
snd_seq_ev_set_source(&ev, my_port);
snd_seq_ev_set_dest(&ev, seq_client, seq_port);
snd_seq_event_output(seq_handle, &ev);
if (do_flush)
snd_seq_flush_output(seq_handle);
}
// Plugin interface
class AlsaMusicPlugin : public MusicPluginObject {
public:
const char *getName() const {
return "ALSA";
}
const char *getId() const {
return "alsa";
}
MusicDevices getDevices() const;
Common::Error createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle = 0) const;
};
#define perm_ok(pinfo,bits) ((snd_seq_port_info_get_capability(pinfo) & (bits)) == (bits))
static int check_permission(snd_seq_port_info_t *pinfo)
{
if (perm_ok(pinfo, SND_SEQ_PORT_CAP_WRITE|SND_SEQ_PORT_CAP_SUBS_WRITE)) {
if (!(snd_seq_port_info_get_capability(pinfo) & SND_SEQ_PORT_CAP_NO_EXPORT))
return 1;
}
return 0;
}
MusicDevices AlsaMusicPlugin::getDevices() const {
MusicDevices devices;
snd_seq_t *seq;
if (snd_seq_open(&seq, "default", SND_SEQ_OPEN_DUPLEX, 0) < 0)
return devices; // can't open sequencer
snd_seq_client_info_t *cinfo;
snd_seq_client_info_alloca(&cinfo);
snd_seq_port_info_t *pinfo;
snd_seq_port_info_alloca(&pinfo);
snd_seq_client_info_set_client(cinfo, -1);
while (snd_seq_query_next_client(seq, cinfo) >= 0) {
bool found_valid_port = false;
/* reset query info */
snd_seq_port_info_set_client(pinfo, snd_seq_client_info_get_client(cinfo));
snd_seq_port_info_set_port(pinfo, -1);
while (!found_valid_port && snd_seq_query_next_port(seq, pinfo) >= 0) {
if (check_permission(pinfo)) {
found_valid_port = true;
// TODO: Return a different music type depending on the configuration
devices.push_back(MusicDevice(this, snd_seq_client_info_get_name(cinfo), MT_GM));
//snd_seq_client_info_get_client(cinfo) : snd_seq_port_info_get_port(pinfo)
}
}
}
snd_seq_close(seq);
return devices;
}
Common::Error AlsaMusicPlugin::createInstance(MidiDriver **mididriver, MidiDriver::DeviceHandle) const {
*mididriver = new MidiDriver_ALSA();
return Common::kNoError;
}
//#if PLUGIN_ENABLED_DYNAMIC(ALSA)
//REGISTER_PLUGIN_DYNAMIC(ALSA, PLUGIN_TYPE_MUSIC, AlsaMusicPlugin);
//#else

View file

@ -28,7 +28,9 @@
* both the QuickTime support and (vkeybd http://www.alsa-project.org/~iwai/alsa.html)
*/
#if defined(UNIX) && !defined(__BEOS__) && !defined(__MAEMO__) && !defined(__MINT__) && !defined(__ANDROID__)
#include "common/sys.h"
#if defined(USE_SEQ_MIDI)
#include "common/util.h"
#include "sound/musicplugin.h"

View file

@ -106,7 +106,7 @@ void MidiDriver_WIN::sysEx(const byte *msg, uint16 length) {
return;
if (WaitForSingleObject (_streamEvent, 2000) == WAIT_TIMEOUT) {
warning ("Could not send SysEx - MMSYSTEM is still trying to send data.");
warning ("Could not send SysEx - MMSYSTEM is still trying to send data");
return;
}

View file

@ -21,7 +21,6 @@ MODULE_OBJS := \
midi/timidity.o \
midi/dmedia.o \
midi/windows.o \
plugins/dc/dc-provider.o \
plugins/posix/posix-provider.o \
plugins/sdl/sdl-provider.o \
plugins/win32/win32-provider.o \
@ -35,5 +34,41 @@ MODULE_OBJS := \
vkeybd/virtual-keyboard-gui.o \
vkeybd/virtual-keyboard-parser.o
ifeq ($(BACKEND),dc)
MODULE_OBJS += \
plugins/dc/dc-provider.o
endif
ifeq ($(BACKEND),ds)
MODULE_OBJS += \
fs/ds/ds-fs-factory.o \
fs/ds/ds-fs.o
endif
ifeq ($(BACKEND),n64)
MODULE_OBJS += \
fs/n64/n64-fs-factory.o \
fs/n64/romfsstream.o
endif
ifeq ($(BACKEND),ps2)
MODULE_OBJS += \
fs/ps2/ps2-fs-factory.o
endif
ifeq ($(BACKEND),psp)
MODULE_OBJS += \
fs/psp/psp-fs-factory.o \
fs/psp/psp-stream.o \
plugins/psp/psp-provider.o \
saves/psp/psp-saves.o \
timer/psp/timer.o
endif
ifeq ($(BACKEND),wii)
MODULE_OBJS += \
fs/wii/wii-fs-factory.o
endif
# Include common rules
include $(srcdir)/rules.mk

View file

@ -38,7 +38,7 @@
// Several SDL based ports use a custom main, and hence do not want to compile
// of this file. The following "#if" ensures that.
#if !defined(__MAEMO__) && !defined(_WIN32_WCE) && !defined(GP2XWIZ)&& !defined(LINUXMOTO) && !defined(__SYMBIAN32__)
#if !defined(__MAEMO__) && !defined(_WIN32_WCE) && !defined(CAANOO) && !defined(GP2XWIZ) && !defined(LINUXMOTO) && !defined(OPENPANDORA) && !defined(__SYMBIAN32__) && !defined(DINGUX)
#include "backends/platform/sdl/sdl.h"

View file

@ -7,8 +7,7 @@ MODULE_OBJS := \
main.o \
sdl.o
MODULE_DIRS += \
backends/platform/sdl/
# We don't use the rules.mk here on purpose
OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS)) $(OBJS)
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
OBJS := $(MODULE_OBJS) $(OBJS)
MODULE_DIRS += $(sort $(dir $(MODULE_OBJS)))

View file

@ -766,7 +766,7 @@ Common::Error processSettings(Common::String &command, Common::StringMap &settin
// environment variable. This is weaker than a --savepath on the
// command line, but overrides the default savepath, hence it is
// handled here, just before the command line gets parsed.
#if !defined(MACOS_CARBON) && !defined(_WIN32_WCE) && !defined(PALMOS_MODE) && !defined(__GP32__) && !defined(ANDROID)
#if !defined(_WIN32_WCE) && !defined(__GP32__) && !defined(ANDROID)
if (!settings.contains("savepath")) {
const char *dir = getenv("RESIDUAL_SAVEPATH");
if (dir && *dir && strlen(dir) < MAXPATHLEN) {

View file

@ -1,5 +1,14 @@
#ifndef INCLUDED_FROM_BASE_VERSION_CPP
#error This file may only be included by base/version.cpp
#endif
#ifndef RESIDUAL_SVN_REVISION
#define RESIDUAL_SVN_REVISION
#endif
#ifdef RELEASE_BUILD
#undef RESIDUAL_SVN_REVISION
#define RESIDUAL_SVN_REVISION
#endif
#define RESIDUAL_VERSION "0.0.6svn" RESIDUAL_SVN_REVISION

View file

@ -1,5 +1,14 @@
#ifndef INCLUDED_FROM_BASE_VERSION_CPP
#error This file may only be included by base/version.cpp
#endif
#ifndef RESIDUAL_SVN_REVISION
#define RESIDUAL_SVN_REVISION
#endif
#ifdef RELEASE_BUILD
#undef RESIDUAL_SVN_REVISION
#define RESIDUAL_SVN_REVISION
#endif
#define RESIDUAL_VERSION "@VERSION@" RESIDUAL_SVN_REVISION

View file

@ -307,9 +307,6 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
// Update the config file
ConfMan.set("versioninfo", gResidualVersion, Common::ConfigManager::kApplicationDomain);
// Enable translation
TransMan.setLanguage(ConfMan.get("gui_language").c_str());
// Load and setup the debuglevel and the debug flags. We do this at the
// soonest possible moment to ensure debug output starts early on, if
// requested.
@ -333,7 +330,7 @@ extern "C" int residual_main(int argc, const char * const argv[]) {
// On the other hand we cannot load the plugins before we know the file paths (in case of external plugins).
if (settings.contains("music-driver")) {
if (MidiDriver::getMusicType(MidiDriver::getDeviceHandle(settings["music-driver"])) == MT_INVALID) {
warning("Unrecognized music driver '%s'. Switching to default device.", settings["music-driver"].c_str());
warning("Unrecognized music driver '%s'. Switching to default device", settings["music-driver"].c_str());
settings["music-driver"] = "auto";
}
}

View file

@ -24,9 +24,11 @@
*/
#include "common/sys.h"
#include "base/internal_version.h"
#include "base/version.h"
#define INCLUDED_FROM_BASE_VERSION_CPP
#include "base/internal_version.h"
/*
* Version string and build date string. These can be used by anything that
* wants to display this information to the user (e.g. about dialog).
@ -86,6 +88,10 @@ const char *gResidualFeatures = ""
"ALSA "
#endif
#ifdef USE_SEQ_MIDI
"SEQ "
#endif
#ifdef USE_RGB_COLOR
"RGB "
#endif
@ -94,6 +100,10 @@ const char *gResidualFeatures = ""
"zLib "
#endif
#ifdef USE_MPEG2
"MPEG2 "
#endif
#ifdef USE_FLUIDSYNTH
"FluidSynth "
#endif

View file

@ -197,6 +197,21 @@ T sortPartition(T first, T last, T pivot, StrictWeakOrdering &comp) {
/**
* Simple sort function, modeled after std::sort.
* It compares data with the given comparator object comp.
*
* Like std::sort this is not guaranteed to be stable.
*
* Two small quotes from wikipedia about stability:
*
* Stable sorting algorithms maintain the relative order of records with
* equal keys.
*
* Unstable sorting algorithms may change the relative order of records with
* equal keys, but stable sorting algorithms never do so.
*
* For more information on that topic check out:
* http://en.wikipedia.org/wiki/Sorting_algorithm#Stability
*
* NOTE: Actually as the time of writing our implementation is unstable.
*/
template<typename T, class StrictWeakOrdering>
void sort(T first, T last, StrictWeakOrdering comp) {

View file

@ -79,7 +79,8 @@ public:
/**
* Archive allows searches of (file)names into an arbitrary container.
* Archive allows managing of member of arbitrary containers in a uniform
* fashion, allowing lookup by (file)names.
* It also supports opening a file and returning an usable input stream.
*/
class Archive {
@ -87,24 +88,23 @@ public:
virtual ~Archive() { }
/**
* Check if a name is present in the Archive. Patterns are not allowed,
* as this is meant to be a quick File::exists() replacement.
* Check if a member with the given name is present in the Archive.
* Patterns are not allowed, as this is meant to be a quick File::exists()
* replacement.
*/
virtual bool hasFile(const String &name) = 0;
/**
* Add all the names present in the Archive which match pattern to
* list. Returned names can be used as parameters to createReadStreamForMember.
* Must not remove elements from the list.
* Add all members of the Archive matching the specified pattern to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of names added to list
* @return the number of members added to list
*/
virtual int listMatchingMembers(ArchiveMemberList &list, const String &pattern);
/**
* Add all the names present in the Archive to list. Returned
* names can be used as parameters to createReadStreamForMember.
* Must not remove elements from the list.
* Add all members of the Archive to list.
* Must only append to list, and not remove elements from it.
*
* @return the number of names added to list
*/
@ -116,8 +116,8 @@ public:
virtual ArchiveMemberPtr getMember(const String &name) = 0;
/**
* Create a stream bound to a member in the archive. If no member with the
* specified name exists, then 0 is returned.
* Create a stream bound to a member with the specified name in the
* archive. If no member with this name exists, 0 is returned.
* @return the newly created input stream
*/
virtual SeekableReadStream *createReadStreamForMember(const String &name) const = 0;

View file

@ -150,6 +150,12 @@ public:
insert_aux(_storage + idx, &element, &element + 1);
}
void insert_at(int idx, const Array<T> &array) {
assert(idx >= 0 && (uint)idx <= _size);
insert_aux(_storage + idx, array.begin(), array.end());
}
T remove_at(int idx) {
assert(idx >= 0 && (uint)idx < _size);
T tmp = _storage[idx];

View file

@ -223,32 +223,27 @@ void ConfigManager::flushToDisk() {
stream = dump;
}
// Write the application domain
writeDomain(*stream, kApplicationDomain, _appDomain);
#ifdef ENABLE_KEYMAPPER
// Write the keymapper domain
writeDomain(*stream, kKeymapperDomain, _keymapperDomain);
#endif
// First write the domains in _domainSaveOrder, in that order.
// Note: It's possible for _domainSaveOrder to list domains which
// are not present anymore.
// are not present anymore, so we validate each name.
Array<String>::const_iterator i;
for (i = _domainSaveOrder.begin(); i != _domainSaveOrder.end(); ++i) {
if (kApplicationDomain == *i) {
writeDomain(*stream, *i, _appDomain);
#ifdef ENABLE_KEYMAPPER
} else if (kKeymapperDomain == *i) {
writeDomain(*stream, *i, _keymapperDomain);
#endif
} else if (_gameDomains.contains(*i)) {
if (_gameDomains.contains(*i)) {
writeDomain(*stream, *i, _gameDomains[*i]);
}
}
DomainMap::const_iterator d;
// Now write the domains which haven't been written yet
if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), kApplicationDomain) == _domainSaveOrder.end())
writeDomain(*stream, kApplicationDomain, _appDomain);
#ifdef ENABLE_KEYMAPPER
if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), kKeymapperDomain) == _domainSaveOrder.end())
writeDomain(*stream, kKeymapperDomain, _keymapperDomain);
#endif
for (d = _gameDomains.begin(); d != _gameDomains.end(); ++d) {
if (find(_domainSaveOrder.begin(), _domainSaveOrder.end(), d->_key) == _domainSaveOrder.end())
writeDomain(*stream, d->_key, d->_value);

View file

@ -189,22 +189,22 @@
#elif defined(__GNUC__) && (__GNUC__ >= 4)
FORCEINLINE uint16 READ_UINT16(const void *ptr) {
struct Unaligned16 { uint16 val; } __attribute__ ((__packed__));
struct Unaligned16 { uint16 val; } __attribute__ ((__packed__, __may_alias__));
return ((const Unaligned16 *)ptr)->val;
}
FORCEINLINE uint32 READ_UINT32(const void *ptr) {
struct Unaligned32 { uint32 val; } __attribute__ ((__packed__));
struct Unaligned32 { uint32 val; } __attribute__ ((__packed__, __may_alias__));
return ((const Unaligned32 *)ptr)->val;
}
FORCEINLINE void WRITE_UINT16(void *ptr, uint16 value) {
struct Unaligned16 { uint16 val; } __attribute__ ((__packed__));
struct Unaligned16 { uint16 val; } __attribute__ ((__packed__, __may_alias__));
((Unaligned16 *)ptr)->val = value;
}
FORCEINLINE void WRITE_UINT32(void *ptr, uint32 value) {
struct Unaligned32 { uint32 val; } __attribute__ ((__packed__));
struct Unaligned32 { uint32 val; } __attribute__ ((__packed__, __may_alias__));
((Unaligned32 *)ptr)->val = value;
}

View file

@ -110,6 +110,7 @@ bool MacResManager::open(Common::String filename) {
_baseFileName = filename;
return true;
}
delete macResForkRawStream;
#endif
@ -169,6 +170,7 @@ bool MacResManager::open(Common::FSNode path, Common::String filename) {
_baseFileName = filename;
return true;
}
delete macResForkRawStream;
#endif
@ -466,6 +468,28 @@ Common::SeekableReadStream *MacResManager::getResource(const Common::String &fil
return 0;
}
Common::SeekableReadStream *MacResManager::getResource(uint32 typeID, const Common::String &filename) {
for (uint32 i = 0; i < _resMap.numTypes; i++) {
if (_resTypes[i].id != typeID)
continue;
for (uint32 j = 0; j < _resTypes[i].items; j++) {
if (_resLists[i][j].nameOffset != -1 && filename.equalsIgnoreCase(_resLists[i][j].name)) {
_stream->seek(_dataOffset + _resLists[i][j].dataOffset);
uint32 len = _stream->readUint32BE();
// Ignore resources with 0 length
if (!len)
return 0;
return _stream->readStream(len);
}
}
}
return 0;
}
void MacResManager::readMap() {
_stream->seek(_mapOffset + 22);
@ -557,6 +581,7 @@ void MacResManager::convertCrsrCursor(byte *data, int datasize, byte **cursor, i
*hotspot_y = dis.readUint16BE();
*hotspot_x = dis.readUint16BE();
*w = *h = 16;
*keycolor = 0xff;
// Use b/w cursor on backends which don't support cursor palettes
if (!colored)

View file

@ -57,7 +57,7 @@ public:
/**
* Read resource from the Mac Binary file
* @param typeID FourCC with type ID
* @param typeID FourCC of the type
* @param resID Resource ID to fetch
* @return Pointer to a SeekableReadStream with loaded resource
*/
@ -65,11 +65,20 @@ public:
/**
* Read resource from the Mac Binary file
* @note This will take the first resource that matches this name, regardless of type
* @param filename filename of the resource
* @return Pointer to a SeekableReadStream with loaded resource
*/
Common::SeekableReadStream *getResource(const Common::String &filename);
/**
* Read resource from the Mac Binary file
* @param typeID FourCC of the type
* @param filename filename of the resource
* @return Pointer to a SeekableReadStream with loaded resource
*/
Common::SeekableReadStream *getResource(uint32 typeID, const Common::String &filename);
Common::SeekableReadStream *getDataFork();
Common::String getResName(uint32 typeID, uint16 resID);
uint32 getResForkSize();
@ -94,7 +103,7 @@ public:
* The memory will be malloc()'ed
* @param palSize Pointer to integer where the palette size will be stored.
*/
void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
static void convertCrsrCursor(byte *data, int datasize, byte **cursor, int *w, int *h,
int *hotspot_x, int *hotspot_y, int *keycolor, bool colored, byte **palette, int *palSize);
/**

View file

@ -90,6 +90,9 @@ struct Rect {
Rect(int16 x1, int16 y1, int16 x2, int16 y2) : top(y1), left(x1), bottom(y2), right(x2) {
assert(isValidRect());
}
bool operator==(const Rect &rhs) const { return equals(rhs); }
bool operator!=(const Rect &rhs) const { return !equals(rhs); }
int16 width() const { return right - left; }
int16 height() const { return bottom - top; }

View file

@ -30,11 +30,6 @@
#include <stdarg.h>
#if !defined(__SYMBIAN32__)
#include <new>
#endif
namespace Common {
MemoryPool *g_refCountPool = 0; // FIXME: This is never freed right now
@ -421,7 +416,7 @@ void String::trim() {
// Trim leading whitespace
char *t = _str;
while (isspace(*t))
while (isspace((unsigned char)*t))
t++;
if (t != _str) {
@ -626,7 +621,7 @@ Common::String lastPathComponent(const Common::String &path, const char sep) {
// Now scan the whole component
const char *first = last - 1;
while (first >= str && *first != sep)
while (first > str && *first != sep)
--first;
if (*first == sep)
@ -696,9 +691,18 @@ bool matchString(const char *str, const char *pat, bool ignoreCase, bool pathMod
switch (*pat) {
case '*':
if (*str) {
// Record pattern / string position for backtracking
p = ++pat;
q = str;
} else {
// If we've reached the end of str, we can't backtrack further
// NB: We can't simply check if pat also ended here, because
// the pattern might end with any number of *s.
++pat;
p = 0;
q = 0;
}
// If pattern ended with * -> match
if (!*pat)
return true;

View file

@ -226,6 +226,7 @@ BufferedReadStream::BufferedReadStream(ReadStream *parentStream, uint32 bufSize,
: _parentStream(parentStream),
_disposeParentStream(disposeParentStream),
_pos(0),
_eos(false),
_bufSize(0),
_realBufSize(bufSize) {
@ -259,8 +260,12 @@ uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
// At this point the buffer is empty. Now if the read request
// exceeds the buffer size, just satisfy it directly.
if (dataSize > _bufSize)
return alreadyRead + _parentStream->read(dataPtr, dataSize);
if (dataSize > _realBufSize) {
uint32 n = _parentStream->read(dataPtr, dataSize);
if (_parentStream->eos())
_eos = true;
return alreadyRead + n;
}
// Refill the buffer.
// If we didn't read as many bytes as requested, the reason
@ -269,13 +274,19 @@ uint32 BufferedReadStream::read(void *dataPtr, uint32 dataSize) {
// return to the caller.
_bufSize = _parentStream->read(_buf, _realBufSize);
_pos = 0;
if (dataSize > _bufSize)
if (_bufSize < dataSize) {
// we didn't get enough data from parent
if (_parentStream->eos())
_eos = true;
dataSize = _bufSize;
}
}
if (dataSize) {
// Satisfy the request from the buffer
memcpy(dataPtr, _buf + _pos, dataSize);
_pos += dataSize;
}
return alreadyRead + dataSize;
}
@ -289,18 +300,76 @@ bool BufferedSeekableReadStream::seek(int32 offset, int whence) {
// in the buffer only.
// Note: We could try to handle SEEK_END and SEEK_SET, too, but
// since they are rarely used, it seems not worth the effort.
_eos = false; // seeking always cancels EOS
if (whence == SEEK_CUR && (int)_pos + offset >= 0 && _pos + offset <= _bufSize) {
_pos += offset;
// Note: we do not need to reset parent's eos flag here. It is
// sufficient that it is reset when actually seeking in the parent.
} else {
// Seek was not local enough, so we reset the buffer and
// just seeks normally in the parent stream.
// just seek normally in the parent stream.
if (whence == SEEK_CUR)
offset -= (_bufSize - _pos);
_pos = _bufSize;
_parentStream->seek(offset, whence);
}
return true; // FIXME: STREAM REWRITE
return true;
}
BufferedWriteStream::BufferedWriteStream(WriteStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream)
: _parentStream(parentStream),
_disposeParentStream(disposeParentStream),
_pos(0),
_bufSize(bufSize) {
assert(parentStream);
_buf = new byte[bufSize];
assert(_buf);
}
BufferedWriteStream::~BufferedWriteStream() {
assert(flush());
if (_disposeParentStream)
delete _parentStream;
delete[] _buf;
}
uint32 BufferedWriteStream::write(const void *dataPtr, uint32 dataSize) {
// check if we have enough space for writing to the buffer
if (_bufSize - _pos >= dataSize) {
memcpy(_buf + _pos, dataPtr, dataSize);
_pos += dataSize;
} else if (_bufSize >= dataSize) { // check if we can flush the buffer and load the data
// flush the buffer
assert(flushBuffer());
memcpy(_buf, dataPtr, dataSize);
_pos += dataSize;
} else { // too big for our buffer
// flush the buffer
assert(flushBuffer());
return _parentStream->write(dataPtr, dataSize);
}
return dataSize;
}
bool BufferedWriteStream::flushBuffer() {
uint32 bytesToWrite = _pos;
if (bytesToWrite) {
_pos = 0;
if (_parentStream->write(_buf, bytesToWrite) != bytesToWrite)
return false;
}
return true;
}
bool BufferedWriteStream::flush() {
return flushBuffer();
}
bool MemoryWriteStreamDynamic::seek(int32 offs, int whence) {

View file

@ -149,7 +149,6 @@ public:
void writeString(const String &str);
};
/**
* Generic interface for a readable data stream.
*/
@ -495,16 +494,17 @@ protected:
DisposeAfterUse::Flag _disposeParentStream;
byte *_buf;
uint32 _pos;
bool _eos; // end of stream
uint32 _bufSize;
uint32 _realBufSize;
public:
BufferedReadStream(ReadStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO);
~BufferedReadStream();
virtual ~BufferedReadStream();
virtual bool eos() const { return (_pos == _bufSize) && _parentStream->eos(); }
virtual bool eos() const { return _eos; }
virtual bool err() const { return _parentStream->err(); }
virtual void clearErr() { _parentStream->clearErr(); }
virtual void clearErr() { _eos = false; _parentStream->clearErr(); }
virtual uint32 read(void *dataPtr, uint32 dataSize);
};
@ -525,7 +525,25 @@ public:
virtual bool seek(int32 offset, int whence = SEEK_SET);
};
/**
* Wrapper class which adds buffering to any WriteStream.
*/
class BufferedWriteStream : public WriteStream {
protected:
WriteStream *_parentStream;
DisposeAfterUse::Flag _disposeParentStream;
byte *_buf;
uint32 _pos;
uint32 _bufSize;
bool flushBuffer(); // write out the data in the buffer
public:
BufferedWriteStream(WriteStream *parentStream, uint32 bufSize, DisposeAfterUse::Flag disposeParentStream = DisposeAfterUse::NO);
virtual ~BufferedWriteStream();
virtual uint32 write(const void *dataPtr, uint32 dataSize);
virtual bool flush();
};
/**
* Simple memory based 'stream', which implements the ReadStream interface for

View file

@ -29,7 +29,11 @@
#undef ARRAYSIZE
#endif
#define TRANSLATIONS_DAT_VER 2
#include "translation.h"
#include "common/archive.h"
#include "common/config-manager.h"
DECLARE_SINGLETON(Common::TranslationManager)
@ -39,18 +43,19 @@ DECLARE_SINGLETON(Common::TranslationManager)
#endif // !WIN32
#endif
#ifdef USE_TRANSLATION
#include "messages.cpp"
#endif
namespace Common {
bool operator<(const TLanguage &l, const TLanguage &r) {
return strcmp(l.name, r.name) < 0;
}
#ifdef USE_TRANSLATION
// Translation enabled
TranslationManager::TranslationManager() {
TranslationManager::TranslationManager() : _currentLang(-1) {
loadTranslationsInfoDat();
#ifdef USE_DETECTLANG
#ifdef WIN32
// We can not use "setlocale" (at least not for MSVC builds), since it
@ -112,11 +117,6 @@ TranslationManager::TranslationManager() {
_syslang = "C";
#endif // USE_DETECTLANG
#ifdef USE_TERMCONV
_convmsg = NULL;
_conversion = NULL;
#endif // USE_TERMCONV
// Set the default language
setLanguage("");
}
@ -125,50 +125,130 @@ TranslationManager::~TranslationManager() {
}
void TranslationManager::setLanguage(const char *lang) {
if (*lang == '\0')
po2c_setlang(_syslang.c_str());
else
po2c_setlang(lang);
// Get lang index
int langIndex = -1;
String langStr(lang);
if (langStr.empty())
langStr = _syslang;
// Searching for a valid language
for (unsigned int i = 0; i < _langs.size() && langIndex == -1; ++i) {
if (langStr == _langs[i])
langIndex = i;
}
// Try partial match
for (unsigned int i = 0; i < _langs.size() && langIndex == -1; ++i) {
if (strncmp(langStr.c_str(), _langs[i].c_str(), 2) == 0)
langIndex = i;
}
// Load messages for that lang
// Call it even if the index is -1 to unload previously loaded translations
if (langIndex != _currentLang) {
loadLanguageDat(langIndex);
_currentLang = langIndex;
}
}
const char *TranslationManager::getTranslation(const char *message) {
return po2c_gettext(message);
return getTranslation(message, NULL);
}
const char *TranslationManager::getTranslation(const char *message, const char *context) {
// if no language is set or message is empty, return msgid as is
if (_currentTranslationMessages.empty() || *message == '\0')
return message;
// binary-search for the msgid
int leftIndex = 0;
int rightIndex = _currentTranslationMessages.size() - 1;
while (rightIndex >= leftIndex) {
const int midIndex = (leftIndex + rightIndex) / 2;
const PoMessageEntry *const m = &_currentTranslationMessages[midIndex];
int compareResult = strcmp(message, _messageIds[m->msgid].c_str());
if (compareResult == 0) {
// Get the range of messages with the same ID (but different context)
leftIndex = rightIndex = midIndex;
while (
leftIndex > 0 &&
_currentTranslationMessages[leftIndex - 1].msgid == m->msgid
) {
--leftIndex;
}
while (
rightIndex < (int)_currentTranslationMessages.size() - 1 &&
_currentTranslationMessages[rightIndex + 1].msgid == m->msgid
) {
++rightIndex;
}
// Find the context we want
if (context == NULL || *context == '\0' || leftIndex == rightIndex)
return _currentTranslationMessages[leftIndex].msgstr.c_str();
// We could use again binary search, but there should be only a small number of contexts.
while (rightIndex > leftIndex) {
compareResult = strcmp(context, _currentTranslationMessages[rightIndex].msgctxt.c_str());
if (compareResult == 0)
return _currentTranslationMessages[rightIndex].msgstr.c_str();
else if (compareResult > 0)
break;
--rightIndex;
}
return _currentTranslationMessages[leftIndex].msgstr.c_str();
} else if (compareResult < 0)
rightIndex = midIndex - 1;
else
leftIndex = midIndex + 1;
}
return message;
}
const char *TranslationManager::getCurrentCharset() {
return po2c_getcharset();
if (_currentCharset.empty())
return "ASCII";
return _currentCharset.c_str();
}
const char *TranslationManager::getCurrentLanguage() {
if (_currentLang == -1)
return "C";
return _langs[_currentLang].c_str();
}
String TranslationManager::getTranslation(const String &message) {
return po2c_gettext(message.c_str());
return getTranslation(message.c_str());
}
const TLangArray TranslationManager::getSupportedLanguages() const {
String TranslationManager::getTranslation(const String &message, const String &context) {
return getTranslation(message.c_str(), context.c_str());
}
const TLangArray TranslationManager::getSupportedLanguageNames() const {
TLangArray languages;
int total = po2c_getnumlangs();
for (int i = 0; i < total; i++) {
TLanguage lng(po2c_getlang(i), i + 1);
for (unsigned int i = 0; i < _langNames.size(); i++) {
TLanguage lng(_langNames[i].c_str(), i + 1);
languages.push_back(lng);
}
//sort(languages.begin(), languages.end());
sort(languages.begin(), languages.end());
return languages;
}
int TranslationManager::parseLanguage(const String lang) {
int total = po2c_getnumlangs();
for (int i = 0; i < total; i++) {
if (lang == po2c_getlang(i))
for (unsigned int i = 0; i < _langs.size(); i++) {
if (lang == _langs[i])
return i + 1;
}
return kTranslationBuiltinId;
}
const char *TranslationManager::getLangById(int id) {
switch (id) {
case kTranslationAutodetectId:
@ -176,8 +256,8 @@ const char *TranslationManager::getLangById(int id) {
case kTranslationBuiltinId:
return "C";
default:
if (id >= 0 && id - 1 < po2c_getnumlangs())
return po2c_getlang(id - 1);
if (id >= 0 && id - 1 < (int)_langs.size())
return _langs[id - 1].c_str();
}
// In case an invalid ID was specified, we will output a warning
@ -186,6 +266,175 @@ const char *TranslationManager::getLangById(int id) {
return "";
}
bool TranslationManager::openTranslationsFile(File& inFile) {
// First try to open it directly (i.e. using the SearchMan).
if (inFile.open("translations.dat"))
return true;
// Then look in the Themepath if we can find the file.
if (ConfMan.hasKey("themepath"))
return openTranslationsFile(FSNode(ConfMan.get("themepath")), inFile);
return false;
}
bool TranslationManager::openTranslationsFile(const FSNode &node, File& inFile, int depth) {
if (!node.exists() || !node.isReadable() || !node.isDirectory())
return false;
// Check if we can find the file in this directory
// Since File::open(FSNode) makes all the needed tests, it is not really
// necessary to make them here. But it avoid printing warnings.
FSNode fileNode = node.getChild("translations.dat");
if (fileNode.exists() && fileNode.isReadable() && !fileNode.isDirectory()) {
if (inFile.open(fileNode))
return true;
}
// Check if we exceeded the given recursion depth
if (depth - 1 == -1)
return false;
// Otherwise look for it in sub-directories
FSList fileList;
if (!node.getChildren(fileList, FSNode::kListDirectoriesOnly))
return false;
for (FSList::iterator i = fileList.begin(); i != fileList.end(); ++i) {
if (openTranslationsFile(*i, inFile, depth == -1 ? - 1 : depth - 1))
return true;
}
// Not found in this directory or its sub-directories
return false;
}
void TranslationManager::loadTranslationsInfoDat() {
File in;
if (!openTranslationsFile(in)) {
warning("You are missing the 'translations.dat' file. GUI translation will not be available");
return;
}
if (!checkHeader(in))
return;
char buf[256];
int len;
// Get number of translations
int nbTranslations = in.readUint16BE();
// Skip all the block sizes
for (int i = 0; i < nbTranslations + 2; ++i)
in.readUint16BE();
// Read list of languages
_langs.resize(nbTranslations);
_langNames.resize(nbTranslations);
for (int i = 0; i < nbTranslations; ++i) {
len = in.readUint16BE();
in.read(buf, len);
_langs[i] = String(buf, len);
len = in.readUint16BE();
in.read(buf, len);
_langNames[i] = String(buf, len);
}
// Read messages
int numMessages = in.readUint16BE();
_messageIds.resize(numMessages);
for (int i = 0; i < numMessages; ++i) {
len = in.readUint16BE();
in.read(buf, len);
_messageIds[i] = String(buf, len);
}
}
void TranslationManager::loadLanguageDat(int index) {
_currentTranslationMessages.clear();
_currentCharset.clear();
// Sanity check
if (index < 0 || index >= (int)_langs.size()) {
if (index != -1)
warning("Invalid language index %d passed to TranslationManager::loadLanguageDat", index);
return;
}
File in;
if (!openTranslationsFile(in))
return;
if (!checkHeader(in))
return;
char buf[1024];
int len;
// Get number of translations
int nbTranslations = in.readUint16BE();
if (nbTranslations != (int)_langs.size()) {
warning("The 'translations.dat' file has changed since starting ScummVM. GUI translation will not be available");
return;
}
// Get size of blocks to skip.
int skipSize = 0;
for (int i = 0; i < index + 2; ++i)
skipSize += in.readUint16BE();
// We also need to skip the remaining block sizes
skipSize += 2 * (nbTranslations - index);
// Seek to start of block we want to read
in.seek(skipSize, SEEK_CUR);
// Read number of translated messages
int nbMessages = in.readUint16BE();
_currentTranslationMessages.resize(nbMessages);
// Read charset
len = in.readUint16BE();
in.read(buf, len);
_currentCharset = String(buf, len);
// Read messages
for (int i = 0; i < nbMessages; ++i) {
_currentTranslationMessages[i].msgid = in.readUint16BE();
len = in.readUint16BE();
in.read(buf, len);
_currentTranslationMessages[i].msgstr = String(buf, len);
len = in.readUint16BE();
if (len > 0) {
in.read(buf, len);
_currentTranslationMessages[i].msgctxt = String(buf, len);
}
}
}
bool TranslationManager::checkHeader(File &in) {
char buf[13];
int ver;
in.read(buf, 12);
buf[12] = '\0';
// Check header
if (strcmp(buf, "TRANSLATIONS")) {
warning("Your 'translations.dat' file is corrupt. GUI translation will not be available");
return false;
}
// Check version
ver = in.readByte();
if (ver != TRANSLATIONS_DAT_VER) {
warning("Your 'translations.dat' file has a mismatching version, expected was %d but you got %d. GUI translation will not be available", TRANSLATIONS_DAT_VER, ver);
return false;
}
return true;
}
#else // USE_TRANSLATION
// Translation disabled
@ -213,10 +462,27 @@ String TranslationManager::getTranslation(const String &message) {
return message;
}
const TLangArray TranslationManager::getSupportedLanguages() const {
const char *TranslationManager::getTranslation(const char *message, const char *) {
return message;
}
String TranslationManager::getTranslation(const String &message, const String &) {
return message;
}
const TLangArray TranslationManager::getSupportedLanguageNames() const {
return TLangArray();
}
const char *TranslationManager::getCurrentCharset() {
return "ASCII";
}
const char *TranslationManager::getCurrentLanguage() {
return "C";
}
#endif // USE_TRANSLATION
} // End of namespace Common

View file

@ -27,6 +27,8 @@
#include "common/singleton.h"
#include "common/str-array.h"
#include "common/file.h"
#include "common/fs.h"
namespace Common {
@ -39,19 +41,20 @@ struct TLanguage {
const char *name;
int id;
TLanguage() {
name = 0;
id = 0;
}
TLanguage(const char *n, int i) {
name = n;
id = i;
}
TLanguage() : name(0), id(0) {}
TLanguage(const char *n, int i) : name(n), id(i) {}
};
bool operator<(const TLanguage &l, const TLanguage &r);
typedef Array<TLanguage> TLangArray;
struct PoMessageEntry {
int msgid;
String msgctxt;
String msgstr;
};
/**
* Message translation manager.
*/
@ -114,20 +117,86 @@ public:
*/
String getTranslation(const String &message);
/**
* Returns the translation into the current language of the parameter
* message. In case the message isn't found in the translation catalog,
* it returns the original untranslated message.
*
* If a translation is found for the given context it will return that
* translation, otherwise it will look for a translation for the same
* massage without a context or with a different context.
*/
const char *getTranslation(const char *message, const char *context);
/**
* Returns the translation into the current language of the parameter
* message. In case the message isn't found in the translation catalog,
* it returns the original untranslated message.
*
* If a translation is found for the given context it will return that
* translation, otherwise it will look for a translation for the same
* massage without a context or with a different context.
*/
String getTranslation(const String &message, const String &context);
/**
* Returns a list of supported languages.
*
* @return The list of supported languages.
* @return The list of supported languages in a user readable form.
*/
const TLangArray getSupportedLanguages() const;
const TLangArray getSupportedLanguageNames() const;
/**
* Returns charset specified by selected translation language
*/
const char *getCurrentCharset();
/**
* Returns currently selected translation language
*/
const char *getCurrentLanguage();
private:
Common::String _syslang;
#ifdef USE_TRANSLATION
/**
* Find the translations.dat file. It looks first using the SearchMan and
* then if needed using the Themepath. If found it opens the given File
* to read the translations.dat file.
*/
bool openTranslationsFile(File&);
/**
* Find the translations.dat file in the given directory node.
* If found it opens the given File to read the translations.dat file.
*/
bool openTranslationsFile(const FSNode &node, File&, int depth = -1);
/**
* Load the list of languages from the translations.dat file
*/
void loadTranslationsInfoDat();
/**
* Load the translation for the given language from the translations.dat file
*
* @param index of the language in the list of languages
*/
void loadLanguageDat(int index);
/**
* Check the header of the given file to make sure it is a valid translations data file.
*/
bool checkHeader(File &in);
String _syslang;
StringArray _langs;
StringArray _langNames;
StringArray _messageIds;
Array<PoMessageEntry> _currentTranslationMessages;
String _currentCharset;
int _currentLang;
#endif
};
} // End of namespace Common
@ -136,10 +205,14 @@ private:
#ifdef USE_TRANSLATION
#define _(str) TransMan.getTranslation(str)
#define _c(str, context) TransMan.getTranslation(str, context)
#else
#define _(str) str
#define _c(str, context) str
#endif
#define _s(str) str
#define _sc(str, ctxt) str
#define DECLARE_TRANSLATION_ADDITIONAL_CONTEXT(str, ctxt)
#endif

View file

@ -107,6 +107,9 @@ typedef struct {
#include "common/unzip.h"
#include "common/file.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
@ -362,6 +365,16 @@ typedef struct {
uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
} file_in_zip_read_info_s;
typedef struct {
uLong num_file; /* number of the current file in the zipfile*/
uLong pos_in_central_dir; /* pos of the current file in the central dir*/
uLong current_file_ok; /* flag about the usability of the current file*/
unz_file_info cur_file_info; /* public info about the current file in zip*/
unz_file_info_internal cur_file_info_internal; /* private info about it*/
} cached_file_in_zip;
typedef Common::HashMap<Common::String, cached_file_in_zip, Common::IgnoreCase_Hash,
Common::IgnoreCase_EqualTo> ZipHash;
/* unz_s contain internal information about the zipfile
*/
@ -382,6 +395,7 @@ typedef struct {
unz_file_info_internal cur_file_info_internal; /* private info about it*/
file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
file if we are decompressing it */
ZipHash _hash;
} unz_s;
/* ===========================================================================
@ -589,7 +603,27 @@ unzFile unzOpen(Common::SeekableReadStream *stream) {
us->central_pos = central_pos;
us->pfile_in_zip_read = NULL;
unzGoToFirstFile((unzFile)us);
err = unzGoToFirstFile((unzFile)us);
while (err == UNZ_OK) {
// Get the file details
char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
unzGetCurrentFileInfo(us, NULL, szCurrentFileName, sizeof(szCurrentFileName) - 1,
NULL, 0, NULL, 0);
// Save details into the hash
cached_file_in_zip fe;
fe.num_file = us->num_file;
fe.pos_in_central_dir = us->pos_in_central_dir;
fe.current_file_ok = us->current_file_ok;
fe.cur_file_info = us->cur_file_info;
fe.cur_file_info_internal = us->cur_file_info_internal;
us->_hash[Common::String(szCurrentFileName)] = fe;
// Move to the next file
err = unzGoToNextFile((unzFile)us);
}
return (unzFile)us;
}
@ -870,7 +904,6 @@ int unzGoToNextFile(unzFile file) {
return err;
}
/*
Try locate the file szFileName in the zipfile.
For the iCaseSensitivity signification, see unzipStringFileNameCompare
@ -881,12 +914,6 @@ int unzGoToNextFile(unzFile file) {
*/
int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
unz_s* s;
int err;
uLong num_fileSaved;
uLong pos_in_central_dirSaved;
if (file==NULL)
return UNZ_PARAMERROR;
@ -898,25 +925,20 @@ int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
if (!s->current_file_ok)
return UNZ_END_OF_LIST_OF_FILE;
num_fileSaved = s->num_file;
pos_in_central_dirSaved = s->pos_in_central_dir;
// Check to see if the entry exists
ZipHash::iterator i = s->_hash.find(Common::String(szFileName));
if (i == s->_hash.end())
return UNZ_END_OF_LIST_OF_FILE;
err = unzGoToFirstFile(file);
// Found it, so reset the details in the main structure
cached_file_in_zip &fe = i->_value;
s->num_file = fe.num_file;
s->pos_in_central_dir = fe.pos_in_central_dir;
s->current_file_ok = fe.current_file_ok;
s->cur_file_info = fe.cur_file_info;
s->cur_file_info_internal = fe.cur_file_info_internal;
while (err == UNZ_OK) {
char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
unzGetCurrentFileInfo(file,NULL,
szCurrentFileName,sizeof(szCurrentFileName)-1,
NULL,0,NULL,0);
if (unzStringFileNameCompare(szCurrentFileName,
szFileName,iCaseSensitivity)==0)
return UNZ_OK;
err = unzGoToNextFile(file);
}
s->num_file = num_fileSaved ;
s->pos_in_central_dir = pos_in_central_dirSaved ;
return err;
}

View file

@ -259,6 +259,9 @@ const RenderModeDescription g_renderModes[] = {
{0, 0, kRenderDefault}
};
DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Hercules Green", "lowres")
DECLARE_TRANSLATION_ADDITIONAL_CONTEXT("Hercules Amber", "lowres")
RenderMode parseRenderMode(const String &str) {
if (str.empty())
return kRenderDefault;
@ -306,6 +309,9 @@ const struct GameOpt {
{ GUIO_MIDICMS, "midiCMS" },
{ GUIO_MIDIPCJR, "midiPCJr" },
{ GUIO_MIDIADLIB, "midiAdLib" },
{ GUIO_MIDIC64, "midiC64" },
{ GUIO_MIDIAMIGA, "midiAmiga" },
{ GUIO_MIDIAPPLEIIGS,"midiAppleIIgs" },
{ GUIO_MIDITOWNS, "midiTowns" },
{ GUIO_MIDIPC98, "midiPC98" },
{ GUIO_MIDIMT32, "midiMt32" },

View file

@ -226,10 +226,13 @@ enum GameGUIOption {
GUIO_MIDICMS = (1 << 7),
GUIO_MIDIPCJR = (1 << 8),
GUIO_MIDIADLIB = (1 << 9),
GUIO_MIDITOWNS = (1 << 10),
GUIO_MIDIPC98 = (1 << 11),
GUIO_MIDIMT32 = (1 << 12),
GUIO_MIDIGM = (1 << 13)
GUIO_MIDIC64 = (1 << 10),
GUIO_MIDIAMIGA = (1 << 11),
GUIO_MIDIAPPLEIIGS = (1 << 12),
GUIO_MIDITOWNS = (1 << 13),
GUIO_MIDIPC98 = (1 << 14),
GUIO_MIDIMT32 = (1 << 15),
GUIO_MIDIGM = (1 << 16)
};
bool checkGameGUIOption(GameGUIOption option, const String &str);

767
configure vendored

File diff suppressed because it is too large Load diff

View file

@ -209,12 +209,41 @@ static void updateGameDescriptor(GameDescriptor &desc, const ADGameDescription *
desc.setGUIOptions(realDesc->guioptions | params.guioptions);
desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(realDesc->language));
if (realDesc->flags & ADGF_ADDENGLISH)
desc.appendGUIOptions(getGameGUIOptionsDescriptionLanguage(Common::EN_ANY));
}
bool cleanupPirated(ADGameDescList &matched) {
// OKay, now let's sense presense of pirated games
if (!matched.empty()) {
for (uint j = 0; j < matched.size();) {
if (matched[j]->flags & ADGF_PIRATED)
matched.remove_at(j);
else
++j;
}
// We ruled out all variants and now have nothing
if (matched.empty()) {
warning("Illegitimate copy of the game detected. We give no support in such cases %d", matched.size());
return true;
}
}
return false;
}
GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
ADGameDescList matches = detectGame(fslist, params, Common::UNK_LANG, Common::kPlatformUnknown, "");
GameList detectedGames;
if (cleanupPirated(matches))
return detectedGames;
// Use fallback detector if there were no matches by other means
if (matches.empty()) {
const ADGameDescription *fallbackDesc = fallbackDetect(fslist);
@ -279,6 +308,9 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
ADGameDescList matches = detectGame(files, params, language, platform, extra);
if (cleanupPirated(matches))
return Common::kNoGameDataFoundError;
if (params.singleid == NULL) {
for (uint i = 0; i < matches.size(); i++) {
if (matches[i]->gameid == gameid) {
@ -306,7 +338,12 @@ Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine)
// If the GUI options were updated, we catch this here and update them in the users config
// file transparently.
Common::updateGameGUIOptions(agdDesc->guioptions | params.guioptions, getGameGUIOptionsDescriptionLanguage(agdDesc->language));
Common::String lang = getGameGUIOptionsDescriptionLanguage(agdDesc->language);
if (agdDesc->flags & ADGF_ADDENGLISH)
lang += " " + getGameGUIOptionsDescriptionLanguage(Common::EN_ANY);
Common::updateGameGUIOptions(agdDesc->guioptions | params.guioptions, lang);
debug(2, "Running %s", toGameDescriptor(*agdDesc, params.list).description().c_str());
if (!createInstance(syst, engine, agdDesc))
@ -334,14 +371,14 @@ static void reportUnknown(const Common::FSNode &path, const SizeMD5Map &filesSiz
printf("of the game you tried to add and its version/language/etc.:\n");
for (SizeMD5Map::const_iterator file = filesSizeMD5.begin(); file != filesSizeMD5.end(); ++file)
printf(" \"%s\", \"%s\", %d\n", file->_key.c_str(), file->_value.md5, file->_value.size);
printf(" {\"%s\", 0, \"%s\", %d},\n", file->_key.c_str(), file->_value.md5, file->_value.size);
printf("\n");
}
static ADGameDescList detectGameFilebased(const FileMap &allFiles, const ADParams &params);
static void composeFileHashMap(const Common::FSList &fslist, FileMap &allFiles, int depth, const char **directoryGlobs) {
static void composeFileHashMap(const Common::FSList &fslist, FileMap &allFiles, int depth, const char * const *directoryGlobs) {
if (depth <= 0)
return;
@ -358,8 +395,8 @@ static void composeFileHashMap(const Common::FSList &fslist, FileMap &allFiles,
continue;
bool matched = false;
for (const char *glob = *directoryGlobs; *glob; glob++)
if (file->getName().matchString(glob, true)) {
for (const char * const *glob = directoryGlobs; *glob; glob++)
if (file->getName().matchString(*glob, true)) {
matched = true;
break;
}
@ -455,7 +492,8 @@ static ADGameDescList detectGame(const Common::FSList &fslist, const ADParams &p
// Do not even bother to look at entries which do not have matching
// language and platform (if specified).
if ((language != Common::UNK_LANG && g->language != Common::UNK_LANG && g->language != language) ||
if ((language != Common::UNK_LANG && g->language != Common::UNK_LANG && g->language != language
&& !(language == Common::EN_ANY && (g->flags & ADGF_ADDENGLISH))) ||
(platform != Common::kPlatformUnknown && g->platform != Common::kPlatformUnknown && g->platform != platform)) {
continue;
}

View file

@ -38,11 +38,15 @@ struct ADGameFileDescription {
int32 fileSize; // Optional. Set to -1 to ignore.
};
#define AD_ENTRY1(f, x) {{ f, 0, x, -1}, {NULL, 0, NULL, 0}}
#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, {NULL, 0, NULL, 0}}
#define AD_LISTEND {NULL, 0, NULL, 0}
#define AD_ENTRY1(f, x) {{ f, 0, x, -1}, AD_LISTEND}
#define AD_ENTRY1s(f, x, s) {{ f, 0, x, s}, AD_LISTEND}
enum ADGameFlags {
ADGF_NO_FLAGS = 0,
ADGF_PIRATED = (1 << 23), // flag to designate well known pirated versions with cracks
ADGF_ADDENGLISH = (1 << 24), // always add English as language option
ADGF_MACRESFORK = (1 << 25), // the md5 for this entry will be calculated from the resource fork
ADGF_USEEXTRAASTITLE = (1 << 26), // Extra field value will be used as main game title, not gameid
ADGF_KEEPMATCH = (1 << 27), // this entry is kept even when there are matched entries with more files
@ -204,7 +208,7 @@ struct ADParams {
*
* @note Last item must be 0
*/
const char **directoryGlobs;
const char * const *directoryGlobs;
};

View file

@ -75,11 +75,11 @@ MainMenuDialog::MainMenuDialog(Engine *engine)
_logo->useThemeTransparency(true);
_logo->setGfx(g_gui.theme()->getImageSurface(GUI::ThemeEngine::kImageLogoSmall));
} else {
StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "Residual");
title->setAlign(Graphics::kTextAlignCenter);
}
#else
StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "ScummVM");
StaticTextWidget *title = new StaticTextWidget(this, "GlobalMenu.Title", "Residual");
title->setAlign(Graphics::kTextAlignCenter);
#endif
@ -106,7 +106,10 @@ MainMenuDialog::MainMenuDialog(Engine *engine)
new GUI::ButtonWidget(this, "GlobalMenu.About", _("~A~bout"), 0, kAboutCmd);
if (g_system->getOverlayWidth() > 320)
_rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", _("~R~eturn to Launcher"), 0, kRTLCmd);
else
_rtlButton = new GUI::ButtonWidget(this, "GlobalMenu.RTL", _c("~R~eturn to Launcher", "lowres"), 0, kRTLCmd);
_rtlButton->setEnabled(_engine->hasFeature(Engine::kSupportsRTL));

View file

@ -110,7 +110,7 @@ Engine::Engine(OSystem *syst)
// heaps of (sound) memory get allocated but never freed. Of course,
// there still would be problems with many games...
if (!_mixer->isReady())
warning("Sound initialization failed. This may cause severe problems in some games.");
warning("Sound initialization failed. This may cause severe problems in some games");
}
Engine::~Engine() {

View file

@ -102,7 +102,7 @@ void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect &
break;
default:
error("Vertical alignment in horizontal data.");
error("Vertical alignment in horizontal data");
}
} else {
in_x = area.left;
@ -131,7 +131,7 @@ void VectorRenderer::stepGetPositions(const DrawStep &step, const Common::Rect &
break;
default:
error("Horizontal alignment in vertical data.");
error("Horizontal alignment in vertical data");
}
} else {
in_y = area.top;

View file

@ -164,7 +164,7 @@ inline frac_t fp_sqroot(uint32 x) {
x--; px -= pitch; \
} \
a2 = (T >> 8); \
a1 = ~a2; \
a1 = ~a2 >> 4; \
}

View file

@ -166,6 +166,30 @@ struct ColorMasks<1555> {
};
};
template<>
struct ColorMasks<5551> {
enum {
kBytesPerPixel = 2,
kAlphaBits = 1,
kRedBits = 5,
kGreenBits = 5,
kBlueBits = 5,
kAlphaShift = 0,
kRedShift = kGreenBits+kBlueBits+kAlphaBits,
kGreenShift = kBlueBits+kAlphaBits,
kBlueShift = kAlphaBits,
kAlphaMask = ((1 << kAlphaBits) - 1) << kAlphaShift,
kRedMask = ((1 << kRedBits) - 1) << kRedShift,
kGreenMask = ((1 << kGreenBits) - 1) << kGreenShift,
kBlueMask = ((1 << kBlueBits) - 1) << kBlueShift,
kRedBlueMask = kRedMask | kBlueMask
};
};
template<>
struct ColorMasks<4444> {
enum {

View file

@ -609,8 +609,8 @@ bool NewFont::cacheFontData(const NewFont &font, const Common::String &filename)
cacheFile.writeUint16BE(font.desc.height);
cacheFile.writeUint16BE(font.desc.fbbw);
cacheFile.writeUint16BE(font.desc.fbbh);
cacheFile.writeUint16BE(font.desc.fbbx);
cacheFile.writeUint16BE(font.desc.fbby);
cacheFile.writeSint16BE(font.desc.fbbx);
cacheFile.writeSint16BE(font.desc.fbby);
cacheFile.writeUint16BE(font.desc.ascent);
cacheFile.writeUint16BE(font.desc.firstchar);
cacheFile.writeUint16BE(font.desc.size);
@ -667,8 +667,8 @@ NewFont *NewFont::loadFromCache(Common::SeekableReadStream &stream) {
data->height = stream.readUint16BE();
data->fbbw = stream.readUint16BE();
data->fbbh = stream.readUint16BE();
data->fbbx = stream.readUint16BE();
data->fbby = stream.readUint16BE();
data->fbbx = stream.readSint16BE();
data->fbby = stream.readSint16BE();
data->ascent = stream.readUint16BE();
data->firstchar = stream.readUint16BE();
data->size = stream.readUint16BE();

View file

@ -24,6 +24,7 @@
#include "common/algorithm.h"
#include "common/util.h"
#include "common/endian.h"
#include "graphics/primitives.h"
#include "graphics/surface.h"
@ -143,8 +144,10 @@ void Surface::fillRect(Common::Rect r, uint32 color) {
lineLen *= 2;
if ((uint16)color != ((color & 0xff) | (color & 0xff) << 8))
useMemset = false;
} else if (bytesPerPixel == 4) {
useMemset = false;
} else if (bytesPerPixel != 1) {
error("Surface::fillRect: bytesPerPixel must be 1 or 2");
error("Surface::fillRect: bytesPerPixel must be 1, 2 or 4");
}
if (useMemset) {
@ -154,11 +157,19 @@ void Surface::fillRect(Common::Rect r, uint32 color) {
ptr += pitch;
}
} else {
if (bytesPerPixel == 2) {
uint16 *ptr = (uint16 *)getBasePtr(r.left, r.top);
while (height--) {
Common::set_to(ptr, ptr + width, (uint16)color);
ptr += pitch/2;
}
} else {
uint32 *ptr = (uint32 *)getBasePtr(r.left, r.top);
while (height--) {
Common::set_to(ptr, ptr + width, color);
ptr += pitch / 4;
}
}
}
}
@ -169,65 +180,72 @@ void Surface::frameRect(const Common::Rect &r, uint32 color) {
vLine(r.right-1, r.top, r.bottom-1, color);
}
// FIXME: LordHoto asks why is this in Surface, since this
// just supports 8bpp surfaces. Looks like someone wants
// to subclass Surface to add this or it should be extended
// to support 16bpp (or marked as just working for 8bpp
// surfaces).
void Surface::move(int dx, int dy, int height) {
// This function currently just works with 8bpp surfaces
assert(bytesPerPixel == 1);
// Short circuit check - do we have to do anything anyway?
if ((dx == 0 && dy == 0) || height <= 0)
return;
if (bytesPerPixel != 1 && bytesPerPixel != 2)
error("Surface::move: bytesPerPixel must be 1 or 2");
byte *src, *dst;
int x, y;
// vertical movement
if (dy > 0) {
// move down - copy from bottom to top
dst = (byte *)pixels + (height - 1) * w;
src = dst - dy * w;
dst = (byte *)pixels + (height - 1) * pitch;
src = dst - dy * pitch;
for (y = dy; y < height; y++) {
memcpy(dst, src, w);
src -= w;
dst -= w;
memcpy(dst, src, pitch);
src -= pitch;
dst -= pitch;
}
} else if (dy < 0) {
// move up - copy from top to bottom
dst = (byte *)pixels;
src = dst - dy * w;
src = dst - dy * pitch;
for (y = -dy; y < height; y++) {
memcpy(dst, src, w);
src += w;
dst += w;
memcpy(dst, src, pitch);
src += pitch;
dst += pitch;
}
}
// horizontal movement
if (dx > 0) {
// move right - copy from right to left
dst = (byte *)pixels + (w - 1);
src = dst - dx;
dst = (byte *)pixels + (pitch - bytesPerPixel);
src = dst - (dx * bytesPerPixel);
for (y = 0; y < height; y++) {
for (x = dx; x < w; x++) {
if (bytesPerPixel == 1) {
*dst-- = *src--;
} else if (bytesPerPixel == 2) {
*(uint16 *)dst = *(const uint16 *)src;
src -= 2;
dst -= 2;
}
src += w + (w - dx);
dst += w + (w - dx);
}
src += pitch + (pitch - dx * bytesPerPixel);
dst += pitch + (pitch - dx * bytesPerPixel);
}
} else if (dx < 0) {
// move left - copy from left to right
dst = (byte *)pixels;
src = dst - dx;
src = dst - (dx * bytesPerPixel);
for (y = 0; y < height; y++) {
for (x = -dx; x < w; x++) {
if (bytesPerPixel == 1) {
*dst++ = *src++;
} else if (bytesPerPixel == 2) {
*(uint16 *)dst = *(const uint16 *)src;
src += 2;
dst += 2;
}
src += w - (w + dx);
dst += w - (w + dx);
}
src += pitch - (pitch + dx * bytesPerPixel);
dst += pitch - (pitch + dx * bytesPerPixel);
}
}
}

View file

@ -82,7 +82,7 @@ bool checkThumbnailHeader(Common::SeekableReadStream &in) {
return hasHeader;
}
bool skipThumbnailHeader(Common::SeekableReadStream &in) {
bool skipThumbnail(Common::SeekableReadStream &in) {
uint32 position = in.pos();
ThumbnailHeader header;

View file

@ -39,14 +39,14 @@ namespace Graphics {
bool checkThumbnailHeader(Common::SeekableReadStream &in);
/**
* Skips a thumbnail header, if present.
* Skips a thumbnail, if present.
*
* @param in stream to process
*/
bool skipThumbnailHeader(Common::SeekableReadStream &in);
bool skipThumbnail(Common::SeekableReadStream &in);
/**
* Lodas a thumbnail from the given input stream.
* Loads a thumbnail from the given input stream.
* The loaded thumbnail will be automatically converted to the
* current overlay pixelformat.
*/

View file

@ -88,7 +88,7 @@ void EditTextWidget::drawWidget() {
}
Common::Rect EditTextWidget::getEditRect() const {
Common::Rect r(2 + _leftPadding, 1, _w - 2 - _leftPadding - _rightPadding, _h-1);
Common::Rect r(2 + _leftPadding, 2, _w - 2 - _leftPadding - _rightPadding, _h-1);
return r;
}

View file

@ -45,11 +45,12 @@ namespace GUI {
enum {
kDoubleClickDelay = 500, // milliseconds
kCursorAnimateDelay = 250
kCursorAnimateDelay = 250,
kTooltipDelay = 1250
};
// Constructor
GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled), _tooltipCheck(false),
_stateIsSaved(false), _cursorAnimateCounter(0), _cursorAnimateTimer(0) {
_theme = 0;
_useStdCursor = false;
@ -62,6 +63,9 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
// Clear the cursor
memset(_cursor, 0xFF, sizeof(_cursor));
// Enable translation
TransMan.setLanguage(ConfMan.get("gui_language").c_str());
ConfMan.registerDefault("gui_theme", "modern");
Common::String themefile(ConfMan.get("gui_theme"));
@ -77,7 +81,7 @@ GuiManager::GuiManager() : _redrawStatus(kRedrawDisabled),
}
}
_tooltip = new Tooltip(this);
_tooltip = 0;
}
GuiManager::~GuiManager() {
@ -224,13 +228,6 @@ Dialog *GuiManager::getTopDialog() const {
return _dialogStack.top();
}
static void tooltipCallback(void *ref) {
GuiManager *guiManager = (GuiManager *)ref;
guiManager->getTooltip()->setVisible(true);
g_system->getTimerManager()->removeTimerProc(&tooltipCallback);
}
void GuiManager::runLoop() {
Dialog *activeDialog = getTopDialog();
bool didSaveState = false;
@ -255,6 +252,9 @@ void GuiManager::runLoop() {
redraw();
}
_lastMousePosition.x = _lastMousePosition.y = -1;
_lastMousePosition.time = 0;
Common::EventManager *eventMan = _system->getEventManager();
uint32 lastRedraw = 0;
const uint32 waitTime = 1000 / 45;
@ -321,7 +321,14 @@ void GuiManager::runLoop() {
break;
case Common::EVENT_MOUSEMOVE:
activeDialog->handleMouseMoved(mouse.x, mouse.y, 0);
_tooltip->setMouseXY(mouse.x, mouse.y);
if (mouse.x != _lastMousePosition.x || mouse.y != _lastMousePosition.y) {
_lastMousePosition.x = mouse.x;
_lastMousePosition.y = mouse.y;
_lastMousePosition.time = _system->getMillis();
}
_tooltipCheck = true;
eventTookplace = true;
break;
// We don't distinguish between mousebuttons (for now at least)
@ -367,11 +374,16 @@ void GuiManager::runLoop() {
}
}
if (eventTookplace) {
_tooltip->setVisible(false);
if (_tooltipCheck && _lastMousePosition.time + kTooltipDelay < _system->getMillis()) {
if (_tooltip == 0)
_tooltip = new Tooltip();
_system->getTimerManager()->removeTimerProc(&tooltipCallback);
_system->getTimerManager()->installTimerProc(&tooltipCallback, 2*1000000, this);
_tooltipCheck = false;
_tooltip->tooltipModal(_lastMousePosition.x, _lastMousePosition.y);
}
if (eventTookplace && _tooltip) {
_tooltip->mustClose();
}
// Delay for a moment

View file

@ -33,6 +33,7 @@
#include "graphics/font.h"
#include "gui/widget.h"
#include "gui/Tooltip.h"
#include "gui/ThemeEngine.h"
class OSystem;
@ -93,8 +94,6 @@ public:
*/
bool checkScreenChange();
Tooltip *getTooltip() { return _tooltip; }
protected:
enum RedrawStatus {
kRedrawDisabled = 0,
@ -119,13 +118,14 @@ protected:
bool _useStdCursor;
Tooltip *_tooltip;
bool _tooltipCheck;
// position and time of last mouse click (used to detect double clicks)
struct {
int16 x, y; // Position of mouse when the click occurred
uint32 time; // Time
int count; // How often was it already pressed?
} _lastClick;
} _lastClick, _lastMousePosition;
// mouse cursor state
int _cursorAnimateCounter;

View file

@ -30,12 +30,13 @@
#include "gui/dialog.h"
#include "gui/ListWidget.h"
#include "common/str.h"
#include "common/translation.h"
namespace GUI {
class KeysDialog : public GUI::Dialog {
public:
KeysDialog(const Common::String &title = "Choose an action to map");
KeysDialog(const Common::String &title = _("Choose an action to map"));
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
virtual void handleKeyUp(Common::KeyState state);

View file

@ -449,11 +449,15 @@ bool ListWidget::handleKeyUp(Common::KeyState state) {
}
void ListWidget::receivedFocusWidget() {
_inversion = ThemeEngine::kTextInversionFocus;
// Redraw the widget so the selection color will change
draw();
}
void ListWidget::lostFocusWidget() {
_inversion = ThemeEngine::kTextInversion;
// If we lose focus, we simply forget the user changes
_editMode = false;
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
@ -491,12 +495,8 @@ void ListWidget::drawWidget() {
ThemeEngine::TextInversionState inverted = ThemeEngine::kTextInversionNone;
// Draw the selected item inverted, on a highlighted background.
if (_selectedItem == pos) {
if (_hasFocus)
inverted = ThemeEngine::kTextInversionFocus;
else
inverted = ThemeEngine::kTextInversion;
}
if (_selectedItem == pos)
inverted = _inversion;
Common::Rect r(getEditRect());
int pad = _leftPadding;

View file

@ -44,12 +44,6 @@
#include "gui/ThemeEval.h"
#include "gui/ThemeParser.h"
#if defined(MACOSX) || defined(IPHONE)
#include <CoreFoundation/CoreFoundation.h>
#endif
#define GUI_ENABLE_BUILTIN_THEME
namespace GUI {
const char * const ThemeEngine::kImageLogo = "logo.bmp";
@ -169,6 +163,7 @@ static const DrawDataInfo kDrawDataDefaults[] = {
{kDDMainDialogBackground, "mainmenu_bg", true, kDDNone},
{kDDSpecialColorBackground, "special_bg", true, kDDNone},
{kDDPlainColorBackground, "plain_bg", true, kDDNone},
{kDDTooltipBackground, "tooltip_bg", true, kDDNone},
{kDDDefaultBackground, "default_bg", true, kDDNone},
{kDDTextSelectionBackground, "text_selection", false, kDDNone},
{kDDTextSelectionFocusBackground, "text_selection_focus", false, kDDNone},
@ -334,10 +329,10 @@ ThemeEngine::~ThemeEngine() {
* Rendering mode management
*********************************************************/
const ThemeEngine::Renderer ThemeEngine::_rendererModes[] = {
{ _s("Disabled GFX"), "none", kGfxDisabled },
{ _s("Standard Renderer (16bpp)"), "normal_16bpp", kGfxStandard16bit },
{ _s("Disabled GFX"), _sc("Disabled GFX", "lowres"), "none", kGfxDisabled },
{ _s("Standard Renderer (16bpp)"), _s("Standard (16bpp)"), "normal_16bpp", kGfxStandard16bit },
#ifndef DISABLE_FANCY_THEMES
{ _s("Antialiased Renderer (16bpp)"), "aa_16bpp", kGfxAntialias16bit }
{ _s("Antialiased Renderer (16bpp)"), _s("Antialiased (16bpp)"), "aa_16bpp", kGfxAntialias16bit }
#endif
};
@ -396,15 +391,23 @@ bool ThemeEngine::init() {
// Try to create a Common::Archive with the files of the theme.
if (!_themeArchive && !_themeFile.empty()) {
Common::FSNode node(_themeFile);
if (node.getName().hasSuffix(".zip") && !node.isDirectory()) {
Common::Archive *zipArchive = Common::makeZipArchive(node);
if (!zipArchive) {
if (node.isDirectory()) {
_themeArchive = new Common::FSDirectory(node);
} else if (_themeFile.hasSuffix(".zip")) {
// TODO: Also use "node" directly?
// Look for the zip file via SearchMan
Common::ArchiveMemberPtr member = SearchMan.getMember(_themeFile);
if (member) {
_themeArchive = Common::makeZipArchive(member->createReadStream());
if (!_themeArchive) {
warning("Failed to open Zip archive '%s'.", member->getDisplayName().c_str());
}
} else {
_themeArchive = Common::makeZipArchive(node);
if (!_themeArchive) {
warning("Failed to open Zip archive '%s'.", node.getPath().c_str());
}
_themeArchive = zipArchive;
} else if (node.isDirectory()) {
_themeArchive = new Common::FSDirectory(node);
}
}
}
@ -571,8 +574,16 @@ bool ThemeEngine::addFont(TextData textId, const Common::String &file) {
// First try to load localized font
_texts[textId]->_fontPtr = loadFont(localized);
// Fallback to non-localized font
if (!_texts[textId]->_fontPtr)
if (_texts[textId]->_fontPtr)
FontMan.assignFontToName(file, _texts[textId]->_fontPtr);
// Fallback to non-localized font and default translation
else {
// Try built-in fonts
_texts[textId]->_fontPtr = FontMan.getFontByName(file);
// Try to load it
if (!_texts[textId]->_fontPtr) {
_texts[textId]->_fontPtr = loadFont(file);
if (!_texts[textId]->_fontPtr)
@ -580,6 +591,10 @@ bool ThemeEngine::addFont(TextData textId, const Common::String &file) {
FontMan.assignFontToName(file, _texts[textId]->_fontPtr);
}
TransMan.setLanguage("C");
warning("Failed to load localized font '%s'. Using non-localized font and default GUI language instead", file.c_str());
}
}
}
return true;
@ -697,7 +712,7 @@ bool ThemeEngine::loadDefaultXML() {
// file inside the themes directory.
// Use the Python script "makedeftheme.py" to convert a normal XML theme
// into the "default.inc" file, which is ready to be included in the code.
#ifdef GUI_ENABLE_BUILTIN_THEME
#ifndef DISABLE_GUI_BUILTIN_THEME
const char *defaultXML =
#include "themes/default.inc"
;
@ -980,6 +995,10 @@ void ThemeEngine::drawDialogBackground(const Common::Rect &r, DialogBackground b
queueDD(kDDPlainColorBackground, r);
break;
case kDialogBackgroundTooltip:
queueDD(kDDTooltipBackground, r);
break;
case kDialogBackgroundDefault:
queueDD(kDDDefaultBackground, r);
break;
@ -1058,12 +1077,16 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, co
if (i == active)
continue;
if (r.left + i * tabWidth > r.right || r.left + (i + 1) * tabWidth > r.right)
continue;
Common::Rect tabRect(r.left + i * tabWidth, r.top, r.left + (i + 1) * tabWidth, r.top + tabHeight);
queueDD(kDDTabInactive, tabRect);
queueDDText(getTextData(kDDTabInactive), getTextColor(kDDTabInactive), tabRect, tabs[i], false, false, _widgets[kDDTabInactive]->_textAlignH, _widgets[kDDTabInactive]->_textAlignV);
}
if (active >= 0) {
if (active >= 0 &&
(r.left + active * tabWidth < r.right) && (r.left + (active + 1) * tabWidth < r.right)) {
Common::Rect tabRect(r.left + active * tabWidth, r.top, r.left + (active + 1) * tabWidth, r.top + tabHeight);
const uint16 tabLeft = active * tabWidth;
const uint16 tabRight = MAX(r.right - tabRect.right, 0);
@ -1165,70 +1188,6 @@ void ThemeEngine::debugWidgetPosition(const char *name, const Common::Rect &r) {
_screen.vLine(r.right, r.top, r.bottom, 0xFFFF);
}
ThemeEngine::StoredState *ThemeEngine::storeState(const Common::Rect &r) {
StoredState *state = new StoredState;
byte *dst;
byte *src;
state->r.top = r.top;
state->r.bottom = r.bottom;
state->r.left = r.left;
state->r.right = r.right;
state->r.clip(_screen.w, _screen.h);
state->screen.create(state->r.width(), state->r.height(), _screen.bytesPerPixel);
state->backBuffer.create(state->r.width(), state->r.height(), _backBuffer.bytesPerPixel);
src = (byte *)_screen.getBasePtr(state->r.left, state->r.top);
dst = (byte *)state->screen.getBasePtr(0, 0);
for (int i = state->r.height(); i > 0; i--) {
memcpy(dst, src, state->r.width() * _screen.bytesPerPixel);
src += _screen.pitch;
dst += state->screen.pitch;
}
src = (byte *)_backBuffer.getBasePtr(state->r.left, state->r.top);
dst = (byte *)state->backBuffer.getBasePtr(0, 0);
for (int i = state->r.height(); i > 0; i--) {
memcpy(dst, src, state->r.width() * _backBuffer.bytesPerPixel);
src += _backBuffer.pitch;
dst += state->backBuffer.pitch;
}
return state;
}
void ThemeEngine::restoreState(StoredState *state) {
byte *dst;
byte *src;
if (!state)
return;
src = (byte *)state->screen.getBasePtr(0, 0);
dst = (byte *)_screen.getBasePtr(state->r.left, state->r.top);
for (int i = state->r.height(); i > 0; i--) {
memcpy(dst, src, state->r.width() * _screen.bytesPerPixel);
src += state->screen.pitch;
dst += _screen.pitch;
}
src = (byte *)state->backBuffer.getBasePtr(0, 0);
dst = (byte *)_backBuffer.getBasePtr(state->r.left, state->r.top);
for (int i = state->r.height(); i > 0; i--) {
memcpy(dst, src, state->r.width() * _backBuffer.bytesPerPixel);
src += state->backBuffer.pitch;
dst += _backBuffer.pitch;
}
addDirtyRect(state->r);
}
/**********************************************************
* Screen/overlay management
*********************************************************/
@ -1434,6 +1393,20 @@ const Graphics::Font *ThemeEngine::loadFontFromArchive(const Common::String &fil
Common::SeekableReadStream *stream = 0;
const Graphics::Font *font = 0;
if (_themeArchive)
stream = _themeArchive->createReadStreamForMember(filename);
if (stream) {
font = Graphics::NewFont::loadFont(*stream);
delete stream;
}
return font;
}
const Graphics::Font *ThemeEngine::loadCachedFontFromArchive(const Common::String &filename) {
Common::SeekableReadStream *stream = 0;
const Graphics::Font *font = 0;
if (_themeArchive)
stream = _themeArchive->createReadStreamForMember(filename);
if (stream) {
@ -1450,13 +1423,14 @@ const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename) {
Common::File fontFile;
if (!cacheFilename.empty()) {
if (fontFile.open(cacheFilename))
if (fontFile.open(cacheFilename)) {
font = Graphics::NewFont::loadFromCache(fontFile);
}
if (font)
return font;
if ((font = loadFontFromArchive(cacheFilename)))
if ((font = loadCachedFontFromArchive(cacheFilename)))
return font;
}
@ -1471,7 +1445,7 @@ const Graphics::Font *ThemeEngine::loadFont(const Common::String &filename) {
if (font) {
if (!cacheFilename.empty()) {
if (!Graphics::NewFont::cacheFontData(*(const Graphics::NewFont*)font, cacheFilename)) {
if (!Graphics::NewFont::cacheFontData(*(const Graphics::NewFont *)font, cacheFilename)) {
warning("Couldn't create cache file for font '%s'", filename.c_str());
}
}
@ -1552,6 +1526,28 @@ bool ThemeEngine::themeConfigParseHeader(Common::String header, Common::String &
return tok.empty();
}
bool ThemeEngine::themeConfigUsable(const Common::ArchiveMember &member, Common::String &themeName) {
Common::File stream;
bool foundHeader = false;
if (member.getName().hasSuffix(".zip")) {
Common::Archive *zipArchive = Common::makeZipArchive(member.createReadStream());
if (zipArchive && zipArchive->hasFile("THEMERC")) {
stream.open("THEMERC", *zipArchive);
}
delete zipArchive;
}
if (stream.isOpen()) {
Common::String stxHeader = stream.readLine();
foundHeader = themeConfigParseHeader(stxHeader, themeName);
}
return foundHeader;
}
bool ThemeEngine::themeConfigUsable(const Common::FSNode &node, Common::String &themeName) {
Common::File stream;
bool foundHeader = false;
@ -1596,7 +1592,7 @@ struct TDComparator {
} // end of anonymous namespace
void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
#ifdef GUI_ENABLE_BUILTIN_THEME
#ifndef DISABLE_GUI_BUILTIN_THEME
ThemeDescriptor th;
th.name = "ScummVM Classic Theme (Builtin Version)";
th.id = "builtin";
@ -1607,26 +1603,7 @@ void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
if (ConfMan.hasKey("themepath"))
listUsableThemes(Common::FSNode(ConfMan.get("themepath")), list);
#ifdef DATA_PATH
listUsableThemes(Common::FSNode(DATA_PATH), list);
#endif
#if defined(MACOSX) || defined(IPHONE)
CFURLRef resourceUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle());
if (resourceUrl) {
char buf[256];
if (CFURLGetFileSystemRepresentation(resourceUrl, true, (UInt8 *)buf, 256)) {
Common::FSNode resourcePath(buf);
listUsableThemes(resourcePath, list);
}
CFRelease(resourceUrl);
}
#endif
if (ConfMan.hasKey("extrapath"))
listUsableThemes(Common::FSNode(ConfMan.get("extrapath")), list);
listUsableThemes(Common::FSNode("."), list, 1);
listUsableThemes(SearchMan, list);
// Now we need to strip all duplicates
// TODO: It might not be the best idea to strip duplicates. The user might
@ -1645,6 +1622,32 @@ void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
output.clear();
}
void ThemeEngine::listUsableThemes(Common::Archive &archive, Common::List<ThemeDescriptor> &list) {
ThemeDescriptor td;
Common::ArchiveMemberList fileList;
archive.listMatchingMembers(fileList, "*.zip");
for (Common::ArchiveMemberList::iterator i = fileList.begin();
i != fileList.end(); ++i) {
td.name.clear();
if (themeConfigUsable(**i, td.name)) {
td.filename = (*i)->getName();
td.id = (*i)->getDisplayName();
// If the name of the node object also contains
// the ".zip" suffix, we will strip it.
if (td.id.hasSuffix(".zip")) {
for (int j = 0; j < 4; ++j)
td.id.deleteLastChar();
}
list.push_back(td);
}
}
fileList.clear();
}
void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth) {
if (!node.exists() || !node.isReadable() || !node.isDirectory())
return;

View file

@ -61,6 +61,7 @@ enum DrawData {
kDDMainDialogBackground,
kDDSpecialColorBackground,
kDDPlainColorBackground,
kDDTooltipBackground,
kDDDefaultBackground,
kDDTextSelectionBackground,
kDDTextSelectionFocusBackground,
@ -162,6 +163,7 @@ public:
kDialogBackgroundMain,
kDialogBackgroundSpecial,
kDialogBackgroundPlain,
kDialogBackgroundTooltip,
kDialogBackgroundDefault
};
@ -236,6 +238,7 @@ public:
struct Renderer {
const char *name;
const char *shortname;
const char *cfg;
GraphicsMode mode;
};
@ -261,17 +264,6 @@ public:
void enable();
void disable();
struct StoredState {
Common::Rect r;
Graphics::Surface screen;
Graphics::Surface backBuffer;
StoredState() {}
};
StoredState *storeState(const Common::Rect &r);
void restoreState(StoredState *state);
/**
* Implementation of the GUI::Theme API. Called when a
* new dialog is opened. Note that the boolean parameter
@ -538,6 +530,7 @@ protected:
const Graphics::Font *loadFont(const Common::String &filename);
const Graphics::Font *loadFontFromArchive(const Common::String &filename);
const Graphics::Font *loadCachedFontFromArchive(const Common::String &filename);
Common::String genCacheFilename(const char *filename);
Common::String genLocalizedFontFilename(const char *filename);
@ -583,11 +576,13 @@ public:
static void listUsableThemes(Common::List<ThemeDescriptor> &list);
private:
static bool themeConfigUsable(const Common::FSNode &node, Common::String &themeName);
static bool themeConfigUsable(const Common::ArchiveMember &member, Common::String &themeName);
static bool themeConfigParseHeader(Common::String header, Common::String &themeName);
static Common::String getThemeFile(const Common::String &id);
static Common::String getThemeId(const Common::String &filename);
static void listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth = -1);
static void listUsableThemes(Common::Archive &archive, Common::List<ThemeDescriptor> &list);
protected:
OSystem *_system; /** Global system object. */

View file

@ -23,8 +23,8 @@
*
*/
#ifndef GUI_THEME_EVAL
#define GUI_THEME_EVAL
#ifndef GUI_THEME_EVAL_H
#define GUI_THEME_EVAL_H
#include "common/sys.h"
#include "common/hashmap.h"

101
gui/Tooltip.cpp Normal file
View file

@ -0,0 +1,101 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*/
#include "common/util.h"
#include "graphics/fontman.h"
#include "gui/widget.h"
#include "gui/dialog.h"
#include "gui/GuiManager.h"
#include "gui/Tooltip.h"
#include "gui/ThemeEval.h"
namespace GUI {
Tooltip::Tooltip() :
Dialog(-1, -1, -1, -1), _maxWidth(-1) {
_backgroundType = GUI::ThemeEngine::kDialogBackgroundTooltip;
}
void Tooltip::mustClose() {
if (isVisible())
Dialog::close();
}
bool Tooltip::tooltipModal(int x, int y) {
Widget *wdg;
if (!g_gui.getTopDialog())
return false;
wdg = g_gui.getTopDialog()->findWidget(x, y);
if (!wdg || !wdg->getTooltip())
return false;
if (_maxWidth == -1) {
_maxWidth = g_gui.xmlEval()->getVar("Globals.Tooltip.MaxWidth", 100);
_xdelta = g_gui.xmlEval()->getVar("Globals.Tooltip.XDelta", 0);
_ydelta = g_gui.xmlEval()->getVar("Globals.Tooltip.YDelta", 0);
}
const Graphics::Font *tooltipFont = g_gui.theme()->getFont(ThemeEngine::kFontStyleTooltip);
_wrappedLines.clear();
_w = tooltipFont->wordWrapText(wdg->getTooltip(), _maxWidth - 4, _wrappedLines);
_h = (tooltipFont->getFontHeight() + 2) * _wrappedLines.size();
_x = MIN<int16>(g_gui.getTopDialog()->_x + x + _xdelta, g_gui.getWidth() - _w - 3);
_y = MIN<int16>(g_gui.getTopDialog()->_y + y + _ydelta, g_gui.getHeight() - _h - 3);
open();
g_gui.runLoop();
return true;
}
void Tooltip::drawDialog() {
int num = 0;
int h = g_gui.theme()->getFontHeight(ThemeEngine::kFontStyleTooltip) + 2;
Dialog::drawDialog();
for (Common::StringArray::const_iterator i = _wrappedLines.begin(); i != _wrappedLines.end(); ++i, ++num) {
g_gui.theme()->drawText(
Common::Rect(_x + 1, _y + 1 + num * h, _x + 1 +_w, _y + 1+ (num + 1) * h), *i,
ThemeEngine::kStateEnabled,
Graphics::kTextAlignLeft,
ThemeEngine::kTextInversionNone,
0,
false,
ThemeEngine::kFontStyleTooltip,
ThemeEngine::kFontColorNormal,
false
);
}
}
}

50
gui/Tooltip.h Normal file
View file

@ -0,0 +1,50 @@
/* Residual - A 3D game interpreter
*
* Residual is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the AUTHORS
* 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.
*
* $URL$
* $Id$
*/
#ifndef GUI_TOOLTIP_H
#define GUI_TOOLTIP_H
#include "gui/dialog.h"
namespace GUI {
class Tooltip : public Dialog {
public:
Tooltip();
~Tooltip() {}
void drawDialog();
bool tooltipModal(int x, int y);
void mustClose();
protected:
Common::String _text;
int _maxWidth;
int _xdelta, _ydelta;
Common::StringArray _wrappedLines;
};
}
#endif

View file

@ -66,7 +66,10 @@ BrowserDialog::BrowserDialog(const char *title, bool dirBrowser)
_backgroundType = GUI::ThemeEngine::kDialogBackgroundPlain;
// Buttons
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(this, "Browser.Up", _("Go up"), _("Go to previous directory level"), kGoUpCmd);
else
new ButtonWidget(this, "Browser.Up", _c("Go up", "lowres"), _("Go to previous directory level"), kGoUpCmd);
new ButtonWidget(this, "Browser.Cancel", _("Cancel"), 0, kCloseCmd);
new ButtonWidget(this, "Browser.Choose", _("Choose"), 0, kChooseCmd);
}

View file

@ -48,6 +48,7 @@ void EditableWidget::init() {
_editScrollOffset = 0;
_font = ThemeEngine::kFontStyleBold;
_inversion = ThemeEngine::kTextInversionNone;
}
EditableWidget::~EditableWidget() {
@ -237,7 +238,7 @@ void EditableWidget::drawCaret(bool erase) {
Common::Rect editRect = getEditRect();
int x = editRect.left;
int y = editRect.top + 1;
int y = editRect.top;
x += getCaretOffset();
@ -253,7 +254,7 @@ void EditableWidget::drawCaret(bool erase) {
if ((uint)_caretPos < _editString.size()) {
GUI::EditableWidget::String chr(_editString[_caretPos]);
int chrWidth = g_gui.getCharWidth(_editString[_caretPos], _font);
g_gui.theme()->drawText(Common::Rect(x, y, x + chrWidth, y + editRect.height() - 2), chr, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, 0, false, _font);
g_gui.theme()->drawText(Common::Rect(x, y, x + chrWidth, y + editRect.height() - 2), chr, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font);
}
}

View file

@ -54,6 +54,8 @@ protected:
ThemeEngine::FontStyle _font;
ThemeEngine::TextInversionState _inversion;
public:
EditableWidget(GuiObject *boss, int x, int y, int w, int h, const char *tooltip = 0, uint32 cmd = 0);
EditableWidget(GuiObject *boss, const String &name, const char *tooltip = 0, uint32 cmd = 0);

View file

@ -72,6 +72,7 @@ enum {
kCmdGlobalGraphicsOverride = 'OGFX',
kCmdGlobalAudioOverride = 'OSFX',
kCmdGlobalMIDIOverride = 'OMID',
kCmdGlobalMT32Override = 'OM32',
kCmdGlobalVolumeOverride = 'OVOL',
kCmdChooseSoundFontCmd = 'chsf',
@ -144,6 +145,7 @@ protected:
CheckboxWidget *_globalGraphicsOverride;
CheckboxWidget *_globalAudioOverride;
CheckboxWidget *_globalMIDIOverride;
CheckboxWidget *_globalMT32Override;
CheckboxWidget *_globalVolumeOverride;
};
@ -170,11 +172,17 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
tab->addTab(_("Game"));
// GUI: Label & edit widget for the game ID
if (g_system->getOverlayWidth() > 320)
new StaticTextWidget(tab, "GameOptions_Game.Id", _("ID:"), _("Short game identifier used for referring to savegames and running the game from the command line"));
else
new StaticTextWidget(tab, "GameOptions_Game.Id", _c("ID:", "lowres"), _("Short game identifier used for referring to savegames and running the game from the command line"));
_domainWidget = new DomainEditTextWidget(tab, "GameOptions_Game.Domain", _domain, _("Short game identifier used for referring to savegames and running the game from the command line"));
// GUI: Label & edit widget for the description
if (g_system->getOverlayWidth() > 320)
new StaticTextWidget(tab, "GameOptions_Game.Name", _("Name:"), _("Full title of the game"));
else
new StaticTextWidget(tab, "GameOptions_Game.Name", _c("Name:", "lowres"), _("Full title of the game"));
_descriptionWidget = new EditTextWidget(tab, "GameOptions_Game.Desc", description, _("Full title of the game"));
// Language popup
@ -189,7 +197,10 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
}
// Platform popup
if (g_system->getOverlayWidth() > 320)
_platformPopUpDesc = new StaticTextWidget(tab, "GameOptions_Game.PlatformPopupDesc", _("Platform:"), _("Platform the game was originally designed for"));
else
_platformPopUpDesc = new StaticTextWidget(tab, "GameOptions_Game.PlatformPopupDesc", _c("Platform:", "lowres"), _("Platform the game was originally designed for"));
_platformPopUp = new PopUpWidget(tab, "GameOptions_Game.PlatformPopup", _("Platform the game was originally designed for"));
_platformPopUp->appendEntry(_("<default>"));
_platformPopUp->appendEntry("");
@ -199,39 +210,54 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
}
//
// 3) The graphics tab
// 2) The graphics tab
//
_graphicsTabId = tab->addTab(g_system->getOverlayWidth() > 320 ? _("Graphics") : _("GFX"));
if (g_system->getOverlayWidth() > 320)
_globalGraphicsOverride = new CheckboxWidget(tab, "GameOptions_Graphics.EnableTabCheckbox", _("Override global graphic settings"), 0, kCmdGlobalGraphicsOverride);
else
_globalGraphicsOverride = new CheckboxWidget(tab, "GameOptions_Graphics.EnableTabCheckbox", _c("Override global graphic settings", "lowres"), 0, kCmdGlobalGraphicsOverride);
addGraphicControls(tab, "GameOptions_Graphics.");
//
// 4) The audio tab
// 3) The audio tab
//
tab->addTab(_("Audio"));
if (g_system->getOverlayWidth() > 320)
_globalAudioOverride = new CheckboxWidget(tab, "GameOptions_Audio.EnableTabCheckbox", _("Override global audio settings"), 0, kCmdGlobalAudioOverride);
else
_globalAudioOverride = new CheckboxWidget(tab, "GameOptions_Audio.EnableTabCheckbox", _c("Override global audio settings", "lowres"), 0, kCmdGlobalAudioOverride);
addAudioControls(tab, "GameOptions_Audio.");
addSubtitleControls(tab, "GameOptions_Audio.");
//
// 5) The volume tab
// 4) The volume tab
//
if (g_system->getOverlayWidth() > 320)
tab->addTab(_("Volume"));
else
tab->addTab(_c("Volume", "lowres"));
if (g_system->getOverlayWidth() > 320)
_globalVolumeOverride = new CheckboxWidget(tab, "GameOptions_Volume.EnableTabCheckbox", _("Override global volume settings"), 0, kCmdGlobalVolumeOverride);
else
_globalVolumeOverride = new CheckboxWidget(tab, "GameOptions_Volume.EnableTabCheckbox", _c("Override global volume settings", "lowres"), 0, kCmdGlobalVolumeOverride);
addVolumeControls(tab, "GameOptions_Volume.");
//
// 6) The MIDI tab
// 5) The MIDI tab
//
tab->addTab(_("MIDI"));
if (g_system->getOverlayWidth() > 320)
_globalMIDIOverride = new CheckboxWidget(tab, "GameOptions_MIDI.EnableTabCheckbox", _("Override global MIDI settings"), 0, kCmdGlobalMIDIOverride);
else
_globalMIDIOverride = new CheckboxWidget(tab, "GameOptions_MIDI.EnableTabCheckbox", _c("Override global MIDI settings", "lowres"), 0, kCmdGlobalMIDIOverride);
if (_guioptions & Common::GUIO_NOMIDI)
_globalMIDIOverride->setEnabled(false);
@ -239,23 +265,50 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
addMIDIControls(tab, "GameOptions_MIDI.");
//
// 2) The 'Path' tab
// 6) The MT-32 tab
//
tab->addTab(_("MT-32"));
if (g_system->getOverlayWidth() > 320)
_globalMT32Override = new CheckboxWidget(tab, "GameOptions_MT32.EnableTabCheckbox", _("Override global MT-32 settings"), 0, kCmdGlobalMT32Override);
else
_globalMT32Override = new CheckboxWidget(tab, "GameOptions_MT32.EnableTabCheckbox", _c("Override global MT-32 settings", "lowres"), 0, kCmdGlobalMT32Override);
//if (_guioptions & Common::GUIO_NOMIDI)
// _globalMT32Override->setEnabled(false);
addMT32Controls(tab, "GameOptions_MT32.");
//
// 7) The Paths tab
//
if (g_system->getOverlayWidth() > 320)
tab->addTab(_("Paths"));
else
tab->addTab(_c("Paths", "lowres"));
// These buttons have to be extra wide, or the text will be truncated
// in the small version of the GUI.
// GUI: Button + Label for the game path
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GameOptions_Paths.Gamepath", _("Game Path:"), 0, kCmdGameBrowser);
else
new ButtonWidget(tab, "GameOptions_Paths.Gamepath", _c("Game Path:", "context"), 0, kCmdGameBrowser);
_gamePathWidget = new StaticTextWidget(tab, "GameOptions_Paths.GamepathText", gamePath);
// GUI: Button + Label for the additional path
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GameOptions_Paths.Extrapath", _("Extra Path:"), _("Specifies path to additional data used the game"), kCmdExtraBrowser);
else
new ButtonWidget(tab, "GameOptions_Paths.Extrapath", _c("Extra Path:", "lowres"), _("Specifies path to additional data used the game"), kCmdExtraBrowser);
_extraPathWidget = new StaticTextWidget(tab, "GameOptions_Paths.ExtrapathText", extraPath, _("Specifies path to additional data used the game"));
// GUI: Button + Label for the save path
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GameOptions_Paths.Savepath", _("Save Path:"), _("Specifies where your savegames are put"), kCmdSaveBrowser);
else
new ButtonWidget(tab, "GameOptions_Paths.Savepath", _c("Save Path:", "lowres"), _("Specifies where your savegames are put"), kCmdSaveBrowser);
_savePathWidget = new StaticTextWidget(tab, "GameOptions_Paths.SavepathText", savePath, _("Specifies where your savegames are put"));
// Activate the first tab
@ -272,7 +325,7 @@ void EditGameDialog::open() {
String extraPath(ConfMan.get("extrapath", _domain));
if (extraPath.empty() || !ConfMan.hasKey("extrapath", _domain)) {
_extraPathWidget->setLabel(_("None"));
_extraPathWidget->setLabel(_c("None", "path"));
}
String savePath(ConfMan.get("savepath", _domain));
@ -305,11 +358,13 @@ void EditGameDialog::open() {
e = ConfMan.hasKey("soundfont", _domain) ||
ConfMan.hasKey("multi_midi", _domain) ||
ConfMan.hasKey("native_mt32", _domain) ||
ConfMan.hasKey("enable_gs", _domain) ||
ConfMan.hasKey("midi_gain", _domain);
_globalMIDIOverride->setState(e);
e = ConfMan.hasKey("native_mt32", _domain) ||
ConfMan.hasKey("enable_gs", _domain);
_globalMT32Override->setState(e);
// TODO: game path
const Common::Language lang = Common::parseLanguage(ConfMan.get("language", _domain));
@ -350,7 +405,7 @@ void EditGameDialog::close() {
ConfMan.set("path", gamePath, _domain);
String extraPath(_extraPathWidget->getLabel());
if (!extraPath.empty() && (extraPath != _("None")))
if (!extraPath.empty() && (extraPath != _c("None", "path")))
ConfMan.set("extrapath", extraPath, _domain);
String savePath(_savePathWidget->getLabel());
@ -382,6 +437,10 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
setMIDISettingsState(data != 0);
draw();
break;
case kCmdGlobalMT32Override:
setMT32SettingsState(data != 0);
draw();
break;
case kCmdGlobalVolumeOverride:
setVolumeSettingsState(data != 0);
draw();
@ -394,7 +453,7 @@ void EditGameDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 dat
Common::FSNode file(browser.getResult());
_soundFont->setLabel(file.getPath());
if (!file.getPath().empty() && (file.getPath() != _("None")))
if (!file.getPath().empty() && (file.getPath() != _c("None", "path")))
_soundFontClearButton->setEnabled(true);
else
_soundFontClearButton->setEnabled(false);
@ -506,12 +565,21 @@ LauncherDialog::LauncherDialog()
new ButtonWidget(this, "Launcher.LoadGameButton", _("~L~oad..."), _("Load savegame for selected game"), kLoadGameCmd);
// Above the lowest button rows: two more buttons (directly below the list box)
if (g_system->getOverlayWidth() > 320) {
_addButton =
new ButtonWidget(this, "Launcher.AddGameButton", _("~A~dd Game..."), _("Hold Shift for Mass Add"), kAddGameCmd);
_editButton =
new ButtonWidget(this, "Launcher.EditGameButton", _("~E~dit Game..."), _("Change game options"), kEditGameCmd);
_removeButton =
new ButtonWidget(this, "Launcher.RemoveGameButton", _("~R~emove Game"), _("Remove game from the list. The game data files stay intact"), kRemoveGameCmd);
} else {
_addButton =
new ButtonWidget(this, "Launcher.AddGameButton", _c("~A~dd Game...", "lowres"), _("Hold Shift for Mass Add"), kAddGameCmd);
_editButton =
new ButtonWidget(this, "Launcher.EditGameButton", _c("~E~dit Game...", "lowres"), _("Change game options"), kEditGameCmd);
_removeButton =
new ButtonWidget(this, "Launcher.RemoveGameButton", _c("~R~emove Game", "lowres"), _("Remove game from the list. The game data files stay intact"), kRemoveGameCmd);
}
// Search box
_searchDesc = 0;
@ -984,9 +1052,11 @@ void LauncherDialog::updateButtons() {
// Update the label of the "Add" button depending on whether shift is pressed or not
int modifiers = g_system->getEventManager()->getModifierState();
const bool massAdd = (modifiers & Common::KBD_SHIFT) != 0;
const bool lowRes = g_system->getOverlayWidth() <= 320;
const char *newAddButtonLabel = massAdd
? _("Mass Add...")
: _("Add Game...");
? (lowRes ? _c("Mass Add...", "lowres") : _("Mass Add..."))
: (lowRes ? _c("Add Game...", "lowres") : _("Add Game..."));
if (_addButton->getLabel() != newAddButtonLabel)
_addButton->setLabel(newAddButtonLabel);

View file

@ -25,6 +25,7 @@ MODULE_OBJS := \
ThemeEval.o \
ThemeLayout.o \
ThemeParser.o \
Tooltip.o \
widget.o
ifdef MACOSX

View file

@ -100,13 +100,14 @@ void OptionsDialog::init() {
_aspectCheckbox = 0;
_enableAudioSettings = false;
_midiPopUp = 0;
_mt32DevicePopUp = 0;
_gmDevicePopUp = 0;
_oplPopUp = 0;
_outputRatePopUp = 0;
_enableMIDISettings = false;
_gmDevicePopUp = 0;
_multiMidiCheckbox = 0;
_enableMT32Settings = false;
_mt32Checkbox = 0;
_mt32DevicePopUp = 0;
_enableGSCheckbox = 0;
_enableVolumeSettings = false;
_musicVolumeDesc = 0;
@ -153,24 +154,6 @@ void OptionsDialog::open() {
if (!loadMusicDeviceSetting(_midiPopUp, "music_driver"))
_midiPopUp->setSelected(0);
if (!loadMusicDeviceSetting(_mt32DevicePopUp, "mt32_device")) {
if (_domain.equals(Common::ConfigManager::kApplicationDomain)) {
if (!loadMusicDeviceSetting(_mt32DevicePopUp, Common::String(), MT_MT32))
_mt32DevicePopUp->setSelected(0);
} else {
_mt32DevicePopUp->setSelected(0);
}
}
if (!loadMusicDeviceSetting(_gmDevicePopUp, "gm_device")) {
if (_domain.equals(Common::ConfigManager::kApplicationDomain)) {
if (!loadMusicDeviceSetting(_gmDevicePopUp, Common::String(), MT_GM))
_gmDevicePopUp->setSelected(0);
} else {
_gmDevicePopUp->setSelected(0);
}
}
if (_oplPopUp) {
OPL::Config::DriverId id = MAX<OPL::Config::DriverId>(OPL::Config::parse(ConfMan.get("opl_driver", _domain)), 0);
_oplPopUp->setSelectedTag(id);
@ -186,19 +169,21 @@ void OptionsDialog::open() {
}
if (_multiMidiCheckbox) {
if (!loadMusicDeviceSetting(_gmDevicePopUp, "gm_device")) {
if (_domain.equals(Common::ConfigManager::kApplicationDomain)) {
if (!loadMusicDeviceSetting(_gmDevicePopUp, Common::String(), MT_GM))
_gmDevicePopUp->setSelected(0);
} else {
_gmDevicePopUp->setSelected(0);
}
}
// Multi midi setting
_multiMidiCheckbox->setState(ConfMan.getBool("multi_midi", _domain));
// Native mt32 setting
_mt32Checkbox->setState(ConfMan.getBool("native_mt32", _domain));
// GS extensions setting
_enableGSCheckbox->setState(ConfMan.getBool("enable_gs", _domain));
Common::String soundFont(ConfMan.get("soundfont", _domain));
if (soundFont.empty() || !ConfMan.hasKey("soundfont", _domain)) {
_soundFont->setLabel(_("None"));
_soundFont->setLabel(_c("None", "soundfont"));
_soundFontClearButton->setEnabled(false);
} else {
_soundFont->setLabel(soundFont);
@ -213,6 +198,24 @@ void OptionsDialog::open() {
_midiGainLabel->setLabel(buf);
}
// MT-32 options
if (_mt32DevicePopUp) {
if (!loadMusicDeviceSetting(_mt32DevicePopUp, "mt32_device")) {
if (_domain.equals(Common::ConfigManager::kApplicationDomain)) {
if (!loadMusicDeviceSetting(_mt32DevicePopUp, Common::String(), MT_MT32))
_mt32DevicePopUp->setSelected(0);
} else {
_mt32DevicePopUp->setSelected(0);
}
}
// Native mt32 setting
_mt32Checkbox->setState(ConfMan.getBool("native_mt32", _domain));
// GS extensions setting
_enableGSCheckbox->setState(ConfMan.getBool("enable_gs", _domain));
}
// Volume options
if (_musicVolumeSlider) {
int vol;
@ -250,12 +253,8 @@ void OptionsDialog::close() {
if (_midiPopUp) {
if (_enableAudioSettings) {
saveMusicDeviceSetting(_midiPopUp, "music_driver");
saveMusicDeviceSetting(_mt32DevicePopUp, "mt32_device");
saveMusicDeviceSetting(_gmDevicePopUp, "gm_device");
} else {
ConfMan.removeKey("music_driver", _domain);
ConfMan.removeKey("mt32_device", _domain);
ConfMan.removeKey("gm_device", _domain);
}
}
@ -288,24 +287,36 @@ void OptionsDialog::close() {
// MIDI options
if (_multiMidiCheckbox) {
if (_enableMIDISettings) {
saveMusicDeviceSetting(_gmDevicePopUp, "gm_device");
ConfMan.setBool("multi_midi", _multiMidiCheckbox->getState(), _domain);
ConfMan.setBool("native_mt32", _mt32Checkbox->getState(), _domain);
ConfMan.setBool("enable_gs", _enableGSCheckbox->getState(), _domain);
ConfMan.setInt("midi_gain", _midiGainSlider->getValue(), _domain);
Common::String soundFont(_soundFont->getLabel());
if (!soundFont.empty() && (soundFont != _("None")))
if (!soundFont.empty() && (soundFont != _c("None", "soundfont")))
ConfMan.set("soundfont", soundFont, _domain);
else
ConfMan.removeKey("soundfont", _domain);
} else {
ConfMan.removeKey("gm_device", _domain);
ConfMan.removeKey("multi_midi", _domain);
ConfMan.removeKey("native_mt32", _domain);
ConfMan.removeKey("enable_gs", _domain);
ConfMan.removeKey("midi_gain", _domain);
ConfMan.removeKey("soundfont", _domain);
}
}
// MT-32 options
if (_mt32DevicePopUp) {
if (_enableMT32Settings) {
saveMusicDeviceSetting(_mt32DevicePopUp, "mt32_device");
ConfMan.setBool("native_mt32", _mt32Checkbox->getState(), _domain);
ConfMan.setBool("enable_gs", _enableGSCheckbox->getState(), _domain);
} else {
ConfMan.removeKey("mt32_device", _domain);
ConfMan.removeKey("native_mt32", _domain);
ConfMan.removeKey("enable_gs", _domain);
}
}
// Save config file
ConfMan.flushToDisk();
}
@ -340,7 +351,7 @@ void OptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data
_subSpeedLabel->draw();
break;
case kClearSoundFontCmd:
_soundFont->setLabel(_("None"));
_soundFont->setLabel(_c("None", "soundfont"));
_soundFontClearButton->setEnabled(false);
draw();
break;
@ -364,10 +375,6 @@ void OptionsDialog::setAudioSettingsState(bool enabled) {
_enableAudioSettings = enabled;
_midiPopUpDesc->setEnabled(enabled);
_midiPopUp->setEnabled(enabled);
_mt32DevicePopUpDesc->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_mt32DevicePopUp->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_gmDevicePopUpDesc->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_gmDevicePopUp->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
uint32 allFlags = MidiDriver::musicType2GUIO((uint32)-1);
@ -388,24 +395,35 @@ void OptionsDialog::setMIDISettingsState(bool enabled) {
if (_guioptions & Common::GUIO_NOMIDI)
enabled = false;
_gmDevicePopUpDesc->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_gmDevicePopUp->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_enableMIDISettings = enabled;
_soundFontButton->setEnabled(enabled);
_soundFont->setEnabled(enabled);
if (enabled && !_soundFont->getLabel().empty() && (_soundFont->getLabel() != _("None")))
if (enabled && !_soundFont->getLabel().empty() && (_soundFont->getLabel() != _c("None", "soundfont")))
_soundFontClearButton->setEnabled(enabled);
else
_soundFontClearButton->setEnabled(false);
_multiMidiCheckbox->setEnabled(enabled);
_mt32Checkbox->setEnabled(enabled);
_enableGSCheckbox->setEnabled(enabled);
_midiGainDesc->setEnabled(enabled);
_midiGainSlider->setEnabled(enabled);
_midiGainLabel->setEnabled(enabled);
}
void OptionsDialog::setMT32SettingsState(bool enabled) {
_enableMT32Settings = enabled;
_mt32DevicePopUpDesc->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_mt32DevicePopUp->setEnabled(_domain.equals(Common::ConfigManager::kApplicationDomain) ? enabled : false);
_mt32Checkbox->setEnabled(enabled);
_enableGSCheckbox->setEnabled(enabled);
}
void OptionsDialog::setVolumeSettingsState(bool enabled) {
bool ena;
@ -463,14 +481,12 @@ void OptionsDialog::addGraphicControls(GuiObject *boss, const Common::String &pr
void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &prefix) {
// The MIDI mode popup & a label
if (g_system->getOverlayWidth() > 320)
_midiPopUpDesc = new StaticTextWidget(boss, prefix + "auMidiPopupDesc", _domain == Common::ConfigManager::kApplicationDomain ? _("Preferred Device:") : _("Music Device:"), _domain == Common::ConfigManager::kApplicationDomain ? _("Specifies preferred sound device or sound card emulator") : _("Specifies output sound device or sound card emulator"));
else
_midiPopUpDesc = new StaticTextWidget(boss, prefix + "auMidiPopupDesc", _domain == Common::ConfigManager::kApplicationDomain ? _c("Preferred Device:", "lowres") : _c("Music Device:", "lowres"), _domain == Common::ConfigManager::kApplicationDomain ? _("Specifies preferred sound device or sound card emulator") : _("Specifies output sound device or sound card emulator"));
_midiPopUp = new PopUpWidget(boss, prefix + "auMidiPopup", _("Specifies output sound device or sound card emulator"));
_mt32DevicePopUpDesc = new StaticTextWidget(boss, prefix + "auPrefMt32PopupDesc", _("MT-32 Device:"), _("Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"));
_mt32DevicePopUp = new PopUpWidget(boss, prefix + "auPrefMt32Popup");
_gmDevicePopUpDesc = new StaticTextWidget(boss, prefix + "auPrefGmPopupDesc", _("GM Device:"), _("Specifies default sound device for General MIDI output"));
_gmDevicePopUp = new PopUpWidget(boss, prefix + "auPrefGmPopup");
// Populate it
uint32 allFlags = MidiDriver::musicType2GUIO((uint32)-1);
@ -478,26 +494,20 @@ void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &pref
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
if ((_domain == Common::ConfigManager::kApplicationDomain && d->getMusicType() != MT_TOWNS) // global dialog - skip useless FM-Towns option there
const uint32 deviceGuiOption = MidiDriver::musicType2GUIO(d->getMusicType());
if ((_domain == Common::ConfigManager::kApplicationDomain && d->getMusicType() != MT_TOWNS // global dialog - skip useless FM-Towns, C64, Amiga, AppleIIGS options there
&& d->getMusicType() != MT_C64 && d->getMusicType() != MT_AMIGA && d->getMusicType() != MT_APPLEIIGS)
|| (_domain != Common::ConfigManager::kApplicationDomain && !(_guioptions & allFlags)) // No flags are specified
|| _guioptions & (MidiDriver::musicType2GUIO(d->getMusicType())) // flag is present
|| (_guioptions & deviceGuiOption) // flag is present
// HACK/FIXME: For now we have to show GM devices, even when the game only has GUIO_MIDIMT32 set,
// else we would not show for example external devices connected via ALSA, since they are always
// marked as General MIDI device.
|| (deviceGuiOption == Common::GUIO_MIDIGM && (_guioptions & Common::GUIO_MIDIMT32))
|| d->getMusicDriverId() == "auto" || d->getMusicDriverId() == "null") // always add default and null device
_midiPopUp->appendEntry(d->getCompleteName(), d->getHandle());
if (d->getMusicType() >= MT_GM || d->getMusicDriverId() == "auto") {
_mt32DevicePopUp->appendEntry(d->getCompleteName(), d->getHandle());
if (d->getMusicType() != MT_MT32)
_gmDevicePopUp->appendEntry(d->getCompleteName(), d->getHandle());
}
}
}
if (!_domain.equals(Common::ConfigManager::kApplicationDomain)) {
_mt32DevicePopUpDesc->setEnabled(false);
_mt32DevicePopUp->setEnabled(false);
_gmDevicePopUpDesc->setEnabled(false);
_gmDevicePopUp->setEnabled(false);
}
// The OPL emulator popup & a label
_oplPopUpDesc = new StaticTextWidget(boss, prefix + "auOPLPopupDesc", _("AdLib emulator:"), _("AdLib is used for music in many games"));
@ -522,20 +532,37 @@ void OptionsDialog::addAudioControls(GuiObject *boss, const Common::String &pref
}
void OptionsDialog::addMIDIControls(GuiObject *boss, const Common::String &prefix) {
_gmDevicePopUpDesc = new StaticTextWidget(boss, prefix + "auPrefGmPopupDesc", _("GM Device:"), _("Specifies default sound device for General MIDI output"));
_gmDevicePopUp = new PopUpWidget(boss, prefix + "auPrefGmPopup");
// Populate
const MusicPlugin::List p = MusicMan.getPlugins();
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
if (d->getMusicType() >= MT_GM || d->getMusicDriverId() == "auto") {
if (d->getMusicType() != MT_MT32)
_gmDevicePopUp->appendEntry(d->getCompleteName(), d->getHandle());
}
}
}
if (!_domain.equals(Common::ConfigManager::kApplicationDomain)) {
_gmDevicePopUpDesc->setEnabled(false);
_gmDevicePopUp->setEnabled(false);
}
// SoundFont
if (g_system->getOverlayWidth() > 320)
_soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _("SoundFont:"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"), kChooseSoundFontCmd);
_soundFont = new StaticTextWidget(boss, prefix + "mcFontPath", _("None"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"));
else
_soundFontButton = new ButtonWidget(boss, prefix + "mcFontButton", _c("SoundFont:", "lowres"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"), kChooseSoundFontCmd);
_soundFont = new StaticTextWidget(boss, prefix + "mcFontPath", _c("None", "soundfont"), _("SoundFont is supported by some audio cards, Fluidsynth and Timidity"));
_soundFontClearButton = new ButtonWidget(boss, prefix + "mcFontClearButton", "C", _("Clear value"), kClearSoundFontCmd);
// Multi midi setting
_multiMidiCheckbox = new CheckboxWidget(boss, prefix + "mcMixedCheckbox", _("Mixed AdLib/MIDI mode"), _("Use both MIDI and AdLib sound generation"));
// Native mt32 setting
_mt32Checkbox = new CheckboxWidget(boss, prefix + "mcMt32Checkbox", _("True Roland MT-32 (disable GM emulation)"), _("Check if you want to use your real hardware Roland-compatible sound device connected to your computer"));
// GS Extensions setting
_enableGSCheckbox = new CheckboxWidget(boss, prefix + "mcGSCheckbox", _("Enable Roland GS Mode"), _("Turns off General MIDI mapping for games with Roland MT-32 soundtrack"));
// MIDI gain setting (FluidSynth uses this)
_midiGainDesc = new StaticTextWidget(boss, prefix + "mcMidiGainText", _("MIDI gain:"));
_midiGainSlider = new SliderWidget(boss, prefix + "mcMidiGainSlider", 0, kMidiGainChanged);
@ -546,28 +573,64 @@ void OptionsDialog::addMIDIControls(GuiObject *boss, const Common::String &prefi
_enableMIDISettings = true;
}
void OptionsDialog::addMT32Controls(GuiObject *boss, const Common::String &prefix) {
_mt32DevicePopUpDesc = new StaticTextWidget(boss, prefix + "auPrefMt32PopupDesc", _("MT-32 Device:"), _("Specifies default sound device for Roland MT-32/LAPC1/CM32l/CM64 output"));
_mt32DevicePopUp = new PopUpWidget(boss, prefix + "auPrefMt32Popup");
// Native mt32 setting
if (g_system->getOverlayWidth() > 320)
_mt32Checkbox = new CheckboxWidget(boss, prefix + "mcMt32Checkbox", _("True Roland MT-32 (disable GM emulation)"), _("Check if you want to use your real hardware Roland-compatible sound device connected to your computer"));
else
_mt32Checkbox = new CheckboxWidget(boss, prefix + "mcMt32Checkbox", _c("True Roland MT-32 (disable GM emulation)", "lowres"), _("Check if you want to use your real hardware Roland-compatible sound device connected to your computer"));
// GS Extensions setting
_enableGSCheckbox = new CheckboxWidget(boss, prefix + "mcGSCheckbox", _("Enable Roland GS Mode"), _("Turns off General MIDI mapping for games with Roland MT-32 soundtrack"));
const MusicPlugin::List p = MusicMan.getPlugins();
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); ++m) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); ++d) {
if (d->getMusicType() >= MT_GM || d->getMusicDriverId() == "auto") {
_mt32DevicePopUp->appendEntry(d->getCompleteName(), d->getHandle());
}
}
}
if (!_domain.equals(Common::ConfigManager::kApplicationDomain)) {
_mt32DevicePopUpDesc->setEnabled(false);
_mt32DevicePopUp->setEnabled(false);
}
_enableMT32Settings = true;
}
// The function has an extra slider range parameter, since both the launcher and SCUMM engine
// make use of the widgets. The launcher range is 0-255. SCUMM's 0-9
void OptionsDialog::addSubtitleControls(GuiObject *boss, const Common::String &prefix, int maxSliderVal) {
if (g_system->getOverlayWidth() > 320) {
_subToggleDesc = new StaticTextWidget(boss, prefix + "subToggleDesc", _("Text and Speech:"));
if (g_system->getOverlayWidth() > 320) {
_subToggleGroup = new RadiobuttonGroup(boss, kSubtitleToggle);
_subToggleSpeechOnly = new RadiobuttonWidget(boss, prefix + "subToggleSpeechOnly", _subToggleGroup, kSubtitlesSpeech, _("Speech"));
_subToggleSubOnly = new RadiobuttonWidget(boss, prefix + "subToggleSubOnly", _subToggleGroup, kSubtitlesSubs, _("Subtitles"));
_subToggleSubBoth = new RadiobuttonWidget(boss, prefix + "subToggleSubBoth", _subToggleGroup, kSubtitlesBoth, _("Both"));
_subSpeedDesc = new StaticTextWidget(boss, prefix + "subSubtitleSpeedDesc", _("Subtitle speed:"));
} else {
_subToggleDesc = new StaticTextWidget(boss, prefix + "subToggleDesc", _c("Text and Speech:", "lowres"));
_subToggleGroup = new RadiobuttonGroup(boss, kSubtitleToggle);
_subToggleSpeechOnly = new RadiobuttonWidget(boss, prefix + "subToggleSpeechOnly", _subToggleGroup, kSubtitlesSpeech, _("Spch"), _("Speech"));
_subToggleSubOnly = new RadiobuttonWidget(boss, prefix + "subToggleSubOnly", _subToggleGroup, kSubtitlesSubs, _("Subs"), _("Subtitles"));
_subToggleSubBoth = new RadiobuttonWidget(boss, prefix + "subToggleSubBoth", _subToggleGroup, kSubtitlesBoth, _("Both"), _("Show subtitles and play speech"));
_subToggleSubBoth = new RadiobuttonWidget(boss, prefix + "subToggleSubBoth", _subToggleGroup, kSubtitlesBoth, _c("Both", "lowres"), _("Show subtitles and play speech"));
_subSpeedDesc = new StaticTextWidget(boss, prefix + "subSubtitleSpeedDesc", _c("Subtitle speed:", "lowres"));
}
// Subtitle speed
_subSpeedDesc = new StaticTextWidget(boss, prefix + "subSubtitleSpeedDesc", _("Subtitle speed:"));
_subSpeedSlider = new SliderWidget(boss, prefix + "subSubtitleSpeedSlider", 0, kSubtitleSpeedChanged);
_subSpeedLabel = new StaticTextWidget(boss, prefix + "subSubtitleSpeedLabel", "100%");
_subSpeedSlider->setMinValue(0); _subSpeedSlider->setMaxValue(maxSliderVal);
@ -579,21 +642,30 @@ void OptionsDialog::addSubtitleControls(GuiObject *boss, const Common::String &p
void OptionsDialog::addVolumeControls(GuiObject *boss, const Common::String &prefix) {
// Volume controllers
if (g_system->getOverlayWidth() > 320)
_musicVolumeDesc = new StaticTextWidget(boss, prefix + "vcMusicText", _("Music volume:"));
else
_musicVolumeDesc = new StaticTextWidget(boss, prefix + "vcMusicText", _c("Music volume:", "lowres"));
_musicVolumeSlider = new SliderWidget(boss, prefix + "vcMusicSlider", 0, kMusicVolumeChanged);
_musicVolumeLabel = new StaticTextWidget(boss, prefix + "vcMusicLabel", "100%");
_musicVolumeSlider->setMinValue(0);
_musicVolumeSlider->setMaxValue(Audio::Mixer::kMaxMixerVolume);
_musicVolumeLabel->setFlags(WIDGET_CLEARBG);
if (g_system->getOverlayWidth() > 320)
_sfxVolumeDesc = new StaticTextWidget(boss, prefix + "vcSfxText", _("SFX volume:"), _("Special sound effects volume"));
else
_sfxVolumeDesc = new StaticTextWidget(boss, prefix + "vcSfxText", _c("SFX volume:", "lowres"), _("Special sound effects volume"));
_sfxVolumeSlider = new SliderWidget(boss, prefix + "vcSfxSlider", _("Special sound effects volume"), kSfxVolumeChanged);
_sfxVolumeLabel = new StaticTextWidget(boss, prefix + "vcSfxLabel", "100%");
_sfxVolumeSlider->setMinValue(0);
_sfxVolumeSlider->setMaxValue(Audio::Mixer::kMaxMixerVolume);
_sfxVolumeLabel->setFlags(WIDGET_CLEARBG);
if (g_system->getOverlayWidth() > 320)
_speechVolumeDesc = new StaticTextWidget(boss, prefix + "vcSpeechText" , _("Speech volume:"));
else
_speechVolumeDesc = new StaticTextWidget(boss, prefix + "vcSpeechText" , _c("Speech volume:", "lowres"));
_speechVolumeSlider = new SliderWidget(boss, prefix + "vcSpeechSlider", 0, kSpeechVolumeChanged);
_speechVolumeLabel = new StaticTextWidget(boss, prefix + "vcSpeechLabel", "100%");
_speechVolumeSlider->setMinValue(0);
@ -692,7 +764,10 @@ GlobalOptionsDialog::GlobalOptionsDialog()
addAudioControls(tab, "GlobalOptions_Audio.");
addSubtitleControls(tab, "GlobalOptions_Audio.");
if (g_system->getOverlayWidth() > 320)
tab->addTab(_("Volume"));
else
tab->addTab(_c("Volume", "lowres"));
addVolumeControls(tab, "GlobalOptions_Volume.");
// TODO: cd drive setting
@ -704,31 +779,58 @@ GlobalOptionsDialog::GlobalOptionsDialog()
addMIDIControls(tab, "GlobalOptions_MIDI.");
//
// 4) The miscellaneous tab
// 4) The MT-32 tab
//
tab->addTab(_("MT-32"));
addMT32Controls(tab, "GlobalOptions_MT32.");
//
// 5) The Paths tab
//
if (g_system->getOverlayWidth() > 320)
tab->addTab(_("Paths"));
else
tab->addTab(_c("Paths", "lowres"));
#if !( defined(__DC__) || defined(__GP32__) )
// These two buttons have to be extra wide, or the text will be
// truncated in the small version of the GUI.
// Save game path
new ButtonWidget(tab, "GlobalOptions_Paths.SaveButton", _("Save Path: "), _("Specifies where your savegames are put"), kChooseSaveDirCmd);
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GlobalOptions_Paths.SaveButton", _("Save Path:"), _("Specifies where your savegames are put"), kChooseSaveDirCmd);
else
new ButtonWidget(tab, "GlobalOptions_Paths.SaveButton", _c("Save Path:", "lowres"), _("Specifies where your savegames are put"), kChooseSaveDirCmd);
_savePath = new StaticTextWidget(tab, "GlobalOptions_Paths.SavePath", "/foo/bar", _("Specifies where your savegames are put"));
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GlobalOptions_Paths.ThemeButton", _("Theme Path:"), 0, kChooseThemeDirCmd);
_themePath = new StaticTextWidget(tab, "GlobalOptions_Paths.ThemePath", _("None"));
else
new ButtonWidget(tab, "GlobalOptions_Paths.ThemeButton", _c("Theme Path:", "lowres"), 0, kChooseThemeDirCmd);
_themePath = new StaticTextWidget(tab, "GlobalOptions_Paths.ThemePath", _c("None", "path"));
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GlobalOptions_Paths.ExtraButton", _("Extra Path:"), _("Specifies path to additional data used by all games or ScummVM"), kChooseExtraDirCmd);
_extraPath = new StaticTextWidget(tab, "GlobalOptions_Paths.ExtraPath", _("None"), _("Specifies path to additional data used by all games or ScummVM"));
else
new ButtonWidget(tab, "GlobalOptions_Paths.ExtraButton", _c("Extra Path:", "lowres"), _("Specifies path to additional data used by all games or ScummVM"), kChooseExtraDirCmd);
_extraPath = new StaticTextWidget(tab, "GlobalOptions_Paths.ExtraPath", _c("None", "path"), _("Specifies path to additional data used by all games or ScummVM"));
#ifdef DYNAMIC_MODULES
if (g_system->getOverlayWidth() > 320)
new ButtonWidget(tab, "GlobalOptions_Paths.PluginsButton", _("Plugins Path:"), 0, kChoosePluginsDirCmd);
_pluginsPath = new StaticTextWidget(tab, "GlobalOptions_Paths.PluginsPath", _("None"));
else
new ButtonWidget(tab, "GlobalOptions_Paths.PluginsButton", _c("Plugins Path:", "lowres"), 0, kChoosePluginsDirCmd);
_pluginsPath = new StaticTextWidget(tab, "GlobalOptions_Paths.PluginsPath", _c("None", "path"));
#endif
#endif
//
// 6) The miscellaneous tab
//
if (g_system->getOverlayWidth() > 320)
tab->addTab(_("Misc"));
else
tab->addTab(_c("Misc", "lowres"));
new ButtonWidget(tab, "GlobalOptions_Misc.ThemeButton", _("Theme:"), 0, kChooseThemeCmd);
_curTheme = new StaticTextWidget(tab, "GlobalOptions_Misc.CurTheme", g_gui.theme()->getThemeName());
@ -737,10 +839,18 @@ GlobalOptionsDialog::GlobalOptionsDialog()
_rendererPopUpDesc = new StaticTextWidget(tab, "GlobalOptions_Misc.RendererPopupDesc", _("GUI Renderer:"));
_rendererPopUp = new PopUpWidget(tab, "GlobalOptions_Misc.RendererPopup");
if (g_system->getOverlayWidth() > 320) {
for (uint i = 1; i < GUI::ThemeEngine::_rendererModesSize; ++i)
_rendererPopUp->appendEntry(_(GUI::ThemeEngine::_rendererModes[i].name), GUI::ThemeEngine::_rendererModes[i].mode);
} else {
for (uint i = 1; i < GUI::ThemeEngine::_rendererModesSize; ++i)
_rendererPopUp->appendEntry(_(GUI::ThemeEngine::_rendererModes[i].shortname), GUI::ThemeEngine::_rendererModes[i].mode);
}
if (g_system->getOverlayWidth() > 320)
_autosavePeriodPopUpDesc = new StaticTextWidget(tab, "GlobalOptions_Misc.AutosavePeriodPopupDesc", _("Autosave:"));
else
_autosavePeriodPopUpDesc = new StaticTextWidget(tab, "GlobalOptions_Misc.AutosavePeriodPopupDesc", _c("Autosave:", "lowres"));
_autosavePeriodPopUp = new PopUpWidget(tab, "GlobalOptions_Misc.AutosavePeriodPopup");
for (int i = 0; savePeriodLabels[i]; i++) {
@ -760,9 +870,9 @@ GlobalOptionsDialog::GlobalOptionsDialog()
#ifdef USE_DETECTLANG
_guiLanguagePopUp->appendEntry(_("<default>"), Common::kTranslationAutodetectId);
#endif // USE_DETECTLANG
_guiLanguagePopUp->appendEntry(_("English"), Common::kTranslationBuiltinId);
_guiLanguagePopUp->appendEntry("English", Common::kTranslationBuiltinId);
_guiLanguagePopUp->appendEntry("", 0);
Common::TLangArray languages = TransMan.getSupportedLanguages();
Common::TLangArray languages = TransMan.getSupportedLanguageNames();
Common::TLangArray::iterator lang = languages.begin();
while (lang != languages.end()) {
_guiLanguagePopUp->appendEntry(lang->name, lang->id);
@ -811,19 +921,19 @@ void GlobalOptionsDialog::open() {
Common::String extraPath(ConfMan.get("extrapath", _domain));
if (savePath.empty() || !ConfMan.hasKey("savepath", _domain)) {
_savePath->setLabel(_("None"));
_savePath->setLabel(_c("None", "path"));
} else {
_savePath->setLabel(savePath);
}
if (themePath.empty() || !ConfMan.hasKey("themepath", _domain)) {
_themePath->setLabel(_("None"));
_themePath->setLabel(_c("None", "path"));
} else {
_themePath->setLabel(themePath);
}
if (extraPath.empty() || !ConfMan.hasKey("extrapath", _domain)) {
_extraPath->setLabel(_("None"));
_extraPath->setLabel(_c("None", "path"));
} else {
_extraPath->setLabel(extraPath);
}
@ -831,7 +941,7 @@ void GlobalOptionsDialog::open() {
#ifdef DYNAMIC_MODULES
Common::String pluginsPath(ConfMan.get("pluginspath", _domain));
if (pluginsPath.empty() || !ConfMan.hasKey("pluginspath", _domain)) {
_pluginsPath->setLabel(_("None"));
_pluginsPath->setLabel(_c("None", "path"));
} else {
_pluginsPath->setLabel(pluginsPath);
}
@ -855,24 +965,24 @@ void GlobalOptionsDialog::open() {
void GlobalOptionsDialog::close() {
if (getResult()) {
Common::String savePath(_savePath->getLabel());
if (!savePath.empty() && (savePath != _("None")))
if (!savePath.empty() && (savePath != _c("None", "path")))
ConfMan.set("savepath", savePath, _domain);
Common::String themePath(_themePath->getLabel());
if (!themePath.empty() && (themePath != _("None")))
if (!themePath.empty() && (themePath != _c("None", "path")))
ConfMan.set("themepath", themePath, _domain);
else
ConfMan.removeKey("themepath", _domain);
Common::String extraPath(_extraPath->getLabel());
if (!extraPath.empty() && (extraPath != _("None")))
if (!extraPath.empty() && (extraPath != _c("None", "path")))
ConfMan.set("extrapath", extraPath, _domain);
else
ConfMan.removeKey("extrapath", _domain);
#ifdef DYNAMIC_MODULES
Common::String pluginsPath(_pluginsPath->getLabel());
if (!pluginsPath.empty() && (pluginsPath != _("None")))
if (!pluginsPath.empty() && (pluginsPath != _c("None", "path")))
ConfMan.set("pluginspath", pluginsPath, _domain);
else
ConfMan.removeKey("pluginspath", _domain);
@ -971,7 +1081,7 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
Common::FSNode file(browser.getResult());
_soundFont->setLabel(file.getPath());
if (!file.getPath().empty() && (file.getPath() != _("None")))
if (!file.getPath().empty() && (file.getPath() != _c("None", "path")))
_soundFontClearButton->setEnabled(true);
else
_soundFontClearButton->setEnabled(false);
@ -987,10 +1097,22 @@ void GlobalOptionsDialog::handleCommand(CommandSender *sender, uint32 cmd, uint3
Common::String theme = browser.getSelected();
// FIXME: Actually, any changes (including the theme change) should
// only become active *after* the options dialog has closed.
Common::String lang = TransMan.getCurrentLanguage();
Common::String oldTheme = g_gui.theme()->getThemeId();
if (g_gui.loadNewTheme(theme)) {
// If the charset has changed, it means the font were not found for the
// new theme. Since for the moment we do not support change of translation
// language without restarting, we let the user know about this.
if (lang != TransMan.getCurrentLanguage()) {
TransMan.setLanguage(lang.c_str());
g_gui.loadNewTheme(oldTheme);
MessageDialog error(_("The theme you selected does not support your current language. If you want to use this theme you need to switch to another language first."));
error.runModal();
} else {
_curTheme->setLabel(g_gui.theme()->getThemeName());
ConfMan.set("gui_theme", theme);
}
}
draw();
}
break;

View file

@ -68,6 +68,7 @@ protected:
void addGraphicControls(GuiObject *boss, const Common::String &prefix);
void addAudioControls(GuiObject *boss, const Common::String &prefix);
void addMIDIControls(GuiObject *boss, const Common::String &prefix);
void addMT32Controls(GuiObject *boss, const Common::String &prefix);
void addVolumeControls(GuiObject *boss, const Common::String &prefix);
// The default value is the launcher's non-scaled talkspeed value. When SCUMM uses the widget,
// it uses its own scale
@ -76,6 +77,7 @@ protected:
void setGraphicSettingsState(bool enabled);
void setAudioSettingsState(bool enabled);
void setMIDISettingsState(bool enabled);
void setMT32SettingsState(bool enabled);
void setVolumeSettingsState(bool enabled);
void setSubtitleSettingsState(bool enabled);
@ -120,12 +122,17 @@ private:
//
bool _enableMIDISettings;
CheckboxWidget *_multiMidiCheckbox;
CheckboxWidget *_mt32Checkbox;
CheckboxWidget *_enableGSCheckbox;
StaticTextWidget *_midiGainDesc;
SliderWidget *_midiGainSlider;
StaticTextWidget *_midiGainLabel;
//
// MT-32 controls
//
bool _enableMT32Settings;
CheckboxWidget *_mt32Checkbox;
CheckboxWidget *_enableGSCheckbox;
//
// Subtitle controls
//

View file

@ -179,7 +179,7 @@ void SaveLoadChooser::reflowLayout() {
uint16 w, h;
if (!g_gui.xmlEval()->getWidgetData("SaveLoadChooser.Thumbnail", x, y, w, h))
error("Error when loading position data for Save/Load Thumbnails.");
error("Error when loading position data for Save/Load Thumbnails");
int thumbW = kThumbnailWidth;
int thumbH = kThumbnailHeight2;

File diff suppressed because it is too large Load diff

1537
gui/themes/fonts/Arial.bdf Normal file

File diff suppressed because it is too large Load diff

7119
gui/themes/fonts/Arial12.bdf Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

3
gui/themes/fonts/README Normal file
View file

@ -0,0 +1,3 @@
These are fonts used in ScummVM. Most of them come from Xorg.
Also other potentially usable fonts are stored here as well.

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

22736
gui/themes/fonts/clR6x12.bdf Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

12708
gui/themes/fonts/helvB12.bdf Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

12195
gui/themes/fonts/helvBO12.bdf Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

12688
gui/themes/fonts/helvR12.bdf Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,4 @@
This package is a remake of Amiga built-in Topaz font for use with Lithuanian keyboards.
You will find detailed information in topazLT.readme.

Binary file not shown.

View file

@ -0,0 +1,63 @@
Short: Topaz with Lithuanian characters
Uploader: r.ulozas@kaunas.omnitel.net (Ricardas Ulozas)
Author: r.ulozas@kaunas.omnitel.net (Ricardas Ulozas)
Type: text/font
Version: 1.0
WHAT IS IT?
This font has BalticRim layout standard for Lithuanian, Latvian,
Estonian, Finnish, Polish, Czech and other Central European
countries. It is very useful when browsing through different
Lithuanian or Latvian Web sites as you may see the special
diacritic signs, or when typing in the aforementioned languages.
WHAT DO YOU NEED?
To type in Lithuanian, please download BalticRimLT.lha on
Aminet.
HOW TO RUN IT?
First, extract: lha x topazLT.lha fonts:
Second, select it on your famous text editor or DTP program.
WHOM I WANT TO THANK?
Commodore-Amiga,Inc. - Steve Beats and Andy Finkel for FED
CygnusSoft for CED
Phase5 for PPC card (when will I get it?...)
Duckman, Smartie, Beavis and others for being so smart.
HOW YOU MAY DISTRIBUTE IT?
Anyone, anywhere, anytime, anyway, anywise, etc. as long as you
don't make money on it (if you do, write me, I'd like to know
how ;) )
WHAT IF YOU WANT TO KEEP IT?
If you liked it I ask you to send me a postcard with your city
sights. Those lazy-bones, tramps and other poor creatures may
write me an e-mail.
WHAT IF YOU WANT TO CONTACT ME?
OK, for bug reports, excited or disappointed letters, requests
for other versions (Hmm..), ideas please write to:
r.ulozas@kaunas.omnitel.net
If you are a female, have sexy voice and want to have a good
chat with a guy thousand miles away, make a call:
370-7-223859
And if you want to send me a postcard, money, a PPC board, a
monitor or a stone brick, better try the slow medieval way:
Ricardas Ulozas
POB 2133
LT-3000 Kaunas
Lithuania
WHAT IS IN THE FUTURE?
Some new characters to make it fully BalticRim-compatible.
Sizes 9 and 11 - fixed width.
Vector font - huge MAYBE.
Improved documentation.
That's it. Enjoy the font and support Amiga!

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -516,6 +516,15 @@
/>
</drawdata>
<!-- Tooltip -->
<drawdata id = 'tooltip_bg' cache = 'false'>
<drawstep func = 'square'
fill = 'foreground'
fg_color = 'blandyellow'
shadow = '3'
/>
</drawdata>
<!-- Idle button -->
<drawdata id = 'button_idle' cache = 'false'>
<text font = 'text_button'

View file

@ -23,7 +23,7 @@
- $Id$
-
-->
<layout_info resolution = '-320xY, -256x240, -Xx272'>
<layout_info resolution = '-320xY, -256x240, -Xx272, -Xx350'>
<globals>
<def var = 'Line.Height' value = '16' />
<def var = 'Font.Height' value = '16' />
@ -53,7 +53,7 @@
<def var = 'Tooltip.YDelta' value = '32'/>
<widget name = 'OptionsLabel'
size = '110, Globals.Line.Height'
size = '115, Globals.Line.Height'
textalign = 'right'
/>
<widget name = 'SmallLabel'
@ -246,22 +246,6 @@
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'auPrefMt32PopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefMt32Popup'
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'auPrefGmPopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefGmPopup'
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'auOPLPopupDesc'
type = 'OptionsLabel'
@ -353,6 +337,14 @@
<dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'auPrefGmPopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefGmPopup'
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'mcFontButton'
type = 'Button'
@ -368,12 +360,6 @@
<widget name = 'mcMixedCheckbox'
type = 'Checkbox'
/>
<widget name = 'mcMt32Checkbox'
type = 'Checkbox'
/>
<widget name = 'mcGSCheckbox'
type = 'Checkbox'
/>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'mcMidiGainText'
type = 'OptionsLabel'
@ -389,6 +375,25 @@
</layout>
</dialog>
<dialog name = 'GlobalOptions_MT32' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
<widget name = 'auPrefMt32PopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefMt32Popup'
type = 'PopUp'
/>
</layout>
<widget name = 'mcMt32Checkbox'
type = 'Checkbox'
/>
<widget name = 'mcGSCheckbox'
type = 'Checkbox'
/>
</layout>
</dialog>
<dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '10' center = 'true'>
@ -533,6 +538,15 @@
</layout>
</dialog>
<dialog name = 'GameOptions_MT32' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<widget name = 'EnableTabCheckbox'
type = 'Checkbox'
/>
<import layout = 'Dialog.GlobalOptions_MT32' />
</layout>
</dialog>
<dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<widget name = 'EnableTabCheckbox'
@ -698,7 +712,7 @@
<layout type = 'vertical' padding = '24, 24, 24, 24' center = 'true'>
<widget name = 'vcMuteCheckbox'
type = 'Checkbox'
width = '80' <!-- FIXME: Why this is needed? -->
width = '120' <!-- FIXME: Why this is needed? -->
/>
</layout>
</layout>

View file

@ -23,7 +23,7 @@
- $Id$
-
-->
<layout_info resolution = "320xY, 256x240, Xx272">
<layout_info resolution = "320xY, 256x240, Xx272, Xx350">
<globals>
<def var = 'Line.Height' value = '12' />
<def var = 'Font.Height' value = '10' />
@ -88,11 +88,11 @@
padding = '0, 0, 2, 0'
/>
<widget name = 'TabWidget.Body'
padding = '0, 0, 0, 0'
padding = '0, 0, 0, -8'
/>
<widget name = 'TabWidget.NavButton'
size = '32, 18'
padding = '0, 3, 4, 0'
padding = '0, 0, 2, 0'
/>
</globals>
@ -227,22 +227,6 @@
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'auPrefMt32PopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefMt32Popup'
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'auPrefGmPopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefGmPopup'
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'auOPLPopupDesc'
type = 'OptionsLabel'
@ -333,6 +317,14 @@
<dialog name = 'GlobalOptions_MIDI' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'auPrefGmPopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefGmPopup'
type = 'PopUp'
/>
</layout>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
<widget name = 'mcFontButton'
type = 'Button'
@ -348,12 +340,6 @@
<widget name = 'mcMixedCheckbox'
type = 'Checkbox'
/>
<widget name = 'mcMt32Checkbox'
type = 'Checkbox'
/>
<widget name = 'mcGSCheckbox'
type = 'Checkbox'
/>
<layout type = 'horizontal' padding = '0, 0, 0, 0' center = 'true'>
<widget name = 'mcMidiGainText'
type = 'OptionsLabel'
@ -369,6 +355,25 @@
</layout>
</dialog>
<dialog name = 'GlobalOptions_MT32' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '6' center = 'true'>
<widget name = 'auPrefMt32PopupDesc'
type = 'OptionsLabel'
/>
<widget name = 'auPrefMt32Popup'
type = 'PopUp'
/>
</layout>
<widget name = 'mcMt32Checkbox'
type = 'Checkbox'
/>
<widget name = 'mcGSCheckbox'
type = 'Checkbox'
/>
</layout>
</dialog>
<dialog name = 'GlobalOptions_Paths' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '16, 16, 16, 16' spacing = '8'>
<layout type = 'horizontal' padding = '0, 0, 0, 0' spacing = '16' center = 'true'>
@ -478,7 +483,7 @@
</dialog>
<dialog name = 'GameOptions' overlays = 'screen' inset = '16' shading = 'dim'>
<layout type = 'vertical' padding = '0, 0, 0, 0' spacing = '16'>
<layout type = 'vertical' padding = '0, 0, 0, 0'>
<widget name = 'TabWidget'/>
<layout type = 'horizontal' padding = '8, 8, 8, 8'>
<space/>
@ -519,6 +524,15 @@
</layout>
</dialog>
<dialog name = 'GameOptions_MT32' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'>
<widget name = 'EnableTabCheckbox'
type = 'Checkbox'
/>
<import layout = 'Dialog.GlobalOptions_MT32' />
</layout>
</dialog>
<dialog name = 'GameOptions_Volume' overlays = 'Dialog.GlobalOptions.TabWidget'>
<layout type = 'vertical' padding = '8, 8, 8, 8' spacing = '6'>
<widget name = 'EnableTabCheckbox'

View file

@ -224,83 +224,6 @@ Common::String Widget::cleanupHotkey(const Common::String &label) {
#pragma mark -
Tooltip::Tooltip(GuiManager *guiManager) : GuiObject(0, 0, 0, 0) {
_guiManager = guiManager;
_visible = false;
_maxWidth = -1;
_storedState = 0;
}
void Tooltip::draw() {
int num = 0;
int h = g_gui.theme()->getFontHeight(ThemeEngine::kFontStyleTooltip) + 2;
// Make Rect bigger for compensating the shadow
_storedState = g_gui.theme()->storeState(Common::Rect(_x - 5, _y - 5, _x + _w + 5, _y + _h + 5));
g_gui.theme()->startBuffering();
g_gui.theme()->drawWidgetBackground(Common::Rect(_x, _y, _x + _w, _y + _h), 0, ThemeEngine::kWidgetBackgroundBorderSmall);
for (Common::StringArray::const_iterator i = _wrappedLines.begin(); i != _wrappedLines.end(); ++i, ++num) {
g_gui.theme()->drawText(Common::Rect(_x + 1, _y + 1 + num * h, _x + 1 +_w, _y + 1+ (num + 1) * h), *i, ThemeEngine::kStateEnabled, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleTooltip, ThemeEngine::kFontColorNormal, false);
}
g_gui.theme()->finishBuffering();
}
void Tooltip::reflowLayout() {
}
void Tooltip::setMouseXY(int x, int y) {
_mouseX = x;
_mouseY = y;
}
void Tooltip::setVisible(bool state) {
if (state == _visible)
return;
if (state) {
if (!_guiManager->getTopDialog())
return;
Widget *wdg = _guiManager->getTopDialog()->findWidget(_mouseX, _mouseY);
if (!wdg)
return;
if (wdg->getTooltip()) {
_visible = state;
// Cache config values.
// NOTE: we cannot do it in the consturctor
if (_maxWidth == -1) {
_maxWidth = g_gui.xmlEval()->getVar("Globals.Tooltip.MaxWidth", 100);
_xdelta = g_gui.xmlEval()->getVar("Globals.Tooltip.XDelta", 0);
_ydelta = g_gui.xmlEval()->getVar("Globals.Tooltip.YDelta", 0);
}
const Graphics::Font *tooltipFont = g_gui.theme()->getFont(ThemeEngine::kFontStyleTooltip);
_wrappedLines.clear();
_w = tooltipFont->wordWrapText(wdg->getTooltip(), _maxWidth - 4, _wrappedLines);
_h = (tooltipFont->getFontHeight() + 2) * _wrappedLines.size();
_x = MIN<int16>(_guiManager->getTopDialog()->_x + _mouseX + _xdelta, g_gui.getWidth() - _w - 3);
_y = MIN<int16>(_guiManager->getTopDialog()->_y + _mouseY + _ydelta, g_gui.getHeight() - _h - 3);
draw();
}
} else {
_visible = state;
g_gui.theme()->restoreState(_storedState);
delete _storedState;
}
}
#pragma mark -
StaticTextWidget::StaticTextWidget(GuiObject *boss, int x, int y, int w, int h, const Common::String &text, Graphics::TextAlign align, const char *tooltip)
: Widget(boss, x, y, w, h, tooltip), _align(align) {
setFlags(WIDGET_ENABLED);
@ -351,7 +274,7 @@ 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) {
_cmd(cmd), _hotkey(hotkey) {
if (hotkey == 0)
_hotkey = parseHotkey(label);

View file

@ -159,31 +159,6 @@ protected:
void handleCommand(CommandSender *sender, uint32 cmd, uint32 data) { assert(_boss); _boss->handleCommand(sender, cmd, data); }
};
class GuiManager;
class Tooltip : public GuiObject {
public:
Tooltip(GuiManager *guiManager);
bool isVisible() const { return _visible; }
void draw();
void reflowLayout();
void releaseFocus() {}
void setVisible(bool state);
void setMouseXY(int x, int y);
protected:
Common::String _text;
GuiManager *_guiManager;
bool _visible;
int _mouseX, _mouseY;
int _maxWidth;
int _xdelta, _ydelta;
Common::StringArray _wrappedLines;
ThemeEngine::StoredState *_storedState;
};
/* StaticTextWidget */
class StaticTextWidget : public Widget {
protected:

View file

@ -5,6 +5,7 @@ gui/browser.cpp
gui/chooser.cpp
gui/error.cpp
gui/GuiManager.cpp
gui/KeysDialog.h
gui/KeysDialog.cpp
gui/launcher.cpp
gui/massadd.cpp
@ -25,9 +26,12 @@ sound/musicplugin.cpp
sound/null.h
sound/null.cpp
sound/softsynth/adlib.cpp
sound/softsynth/appleiigs.cpp
sound/softsynth/sid.cpp
sound/softsynth/mt32.cpp
sound/softsynth/pcspk.cpp
sound/softsynth/ym2612.cpp
backends/keymapper/remap-dialog.cpp
backends/midi/windows.cpp
backends/platform/sdl/graphics.cpp

View file

@ -3,6 +3,7 @@ POFILES := $(wildcard $(srcdir)/po/*.po)
updatepot:
xgettext -f $(srcdir)/po/POTFILES -D $(srcdir) -d residual --c++ -k_ -k_t -k_s -o $(POTFILE) \
-kDECLARE_TRANSLATION_ADDITIONAL_CONTEXT:1,2c -o $(POTFILE) \
"--copyright-holder=Residual Team" --package-name=Residual \
--package-version=$(VERSION) --msgid-bugs-address=residual-devel@lists.sf.net -o $(POTFILE)_
@ -35,9 +36,14 @@ updatepot:
#$(srcdir)/common/messages.cpp: $(POFILES)
# perl $(srcdir)/tools/po2c $^ > $(srcdir)/common/messages.cpp
translations-dat: tools/create_translations
tools/create_translations/create_translations $(POFILES)
mv translations.dat $(srcdir)/gui/themes/
update-translations: updatepot $(POFILES) translations-dat
update-translations: updatepot $(POFILES)
@$(foreach file, $(POFILES), echo -n $(notdir $(basename $(file)))": ";msgfmt --statistic $(file);)
@rm -f messages.mo
perl $(srcdir)/tools/po2c $(POFILES) > $(srcdir)/common/messages.cpp
.PHONY: updatepot update-translations
.PHONY: updatepot translations-dat update-translations

View file

@ -72,8 +72,9 @@ endif
ldid -S residual
chmod 755 residual
cp residual $(bundle_name)/Residual
cp $(srcdir)/dists/iphone/icon.png $(bundle_name)/icon.png
cp $(srcdir)/dists/iphone/Default.png $(bundle_name)/Default.png
cp $(srcdir)/dists/iphone/icon.png $(bundle_name)/
cp $(srcdir)/dists/iphone/icon-72.png $(bundle_name)/
cp $(srcdir)/dists/iphone/Default.png $(bundle_name)/
# Location of static libs for the iPhone
ifneq ($(BACKEND), iphone)

View file

@ -42,6 +42,8 @@ AudioCDManager::AudioCDManager() {
_cd.start = 0;
_cd.duration = 0;
_cd.numLoops = 0;
_cd.volume = Mixer::kMaxChannelVolume;
_cd.balance = 0;
_mixer = g_system->getMixer();
_emulating = false;
assert(_mixer);
@ -79,7 +81,8 @@ void AudioCDManager::play(int track, int numLoops, int startFrame, int duration,
*/
_emulating = true;
_mixer->playStream(Mixer::kMusicSoundType, &_handle,
makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops));
makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
} else {
_emulating = false;
if (!only_emulate)
@ -109,6 +112,38 @@ bool AudioCDManager::isPlaying() const {
}
}
void AudioCDManager::setVolume(byte volume) {
_cd.volume = volume;
if (_emulating) {
// Audio CD emulation
if (_mixer->isSoundHandleActive(_handle))
_mixer->setChannelVolume(_handle, _cd.volume);
} else {
// Real Audio CD
// Unfortunately I can't implement this atm
// since SDL doesn't seem to offer an interface method for this.
// g_system->setVolumeCD(_cd.volume);
}
}
void AudioCDManager::setBalance(int8 balance) {
_cd.balance = balance;
if (_emulating) {
// Audio CD emulation
if (isPlaying())
_mixer->setChannelBalance(_handle, _cd.balance);
} else {
// Real Audio CD
// Unfortunately I can't implement this atm
// since SDL doesn't seem to offer an interface method for this.
// g_system->setBalanceCD(_cd.balance);
}
}
void AudioCDManager::updateCD() {
if (_emulating) {
// Check whether the audio track stopped playback

View file

@ -42,6 +42,8 @@ public:
int start;
int duration;
int numLoops;
int volume;
int balance;
};
/**
@ -59,6 +61,9 @@ public:
void stop();
bool isPlaying() const;
void setVolume(byte volume);
void setBalance(int8 balance);
void updateCD();
Status getStatus() const;

View file

@ -233,6 +233,8 @@ bool MP3Stream::seek(const Timestamp &where) {
while (mad_timer_compare(destination, _totalTime) > 0 && _state != MP3_STATE_EOS)
readHeader();
decodeMP3Data();
return (_state != MP3_STATE_EOS);
}

View file

@ -42,7 +42,7 @@ enum OplEmulator {
OPL::OPL() {
if (_hasInstance)
error("There are multiple OPL output instances running.");
error("There are multiple OPL output instances running");
_hasInstance = true;
}
@ -91,7 +91,7 @@ Config::DriverId Config::detect(OplType type) {
} else {
// Else we will output a warning and just
// return that no valid driver is found.
warning("Your selected OPL driver \"%s\" does not support type %d emulation, which is requested by your game.", _drivers[drv].description, type);
warning("Your selected OPL driver \"%s\" does not support type %d emulation, which is requested by your game", _drivers[drv].description, type);
return -1;
}
}
@ -138,7 +138,7 @@ OPL *Config::create(DriverId driver, OplType type) {
if (type == kOpl2)
return new MAME::OPL();
else
warning("MAME OPL emulator only supports OPL2 emulation.");
warning("MAME OPL emulator only supports OPL2 emulation");
return 0;
#ifndef DISABLE_DOSBOX_OPL

View file

@ -58,10 +58,14 @@ const byte MidiDriver::_gmToMt32[128] = {
static const uint32 GUIOMapping[] = {
MT_PCSPK, Common::GUIO_MIDIPCSPK,
/*MDT_CMS, Common::GUIO_MIDICMS,*/
MT_CMS, Common::GUIO_MIDICMS,
MT_PCJR, Common::GUIO_MIDIPCJR,
MT_ADLIB, Common::GUIO_MIDIADLIB,
MT_C64, Common::GUIO_MIDIC64,
MT_AMIGA, Common::GUIO_MIDIAMIGA,
MT_APPLEIIGS, Common::GUIO_MIDIAPPLEIIGS,
MT_TOWNS, Common::GUIO_MIDITOWNS,
MT_PC98, Common::GUIO_MIDIPC98,
MT_GM, Common::GUIO_MIDIGM,
MT_MT32, Common::GUIO_MIDIMT32,
0, 0
@ -150,6 +154,21 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
return hdl;
break;
case MT_C64:
if (flags & MDT_C64)
return hdl;
break;
case MT_AMIGA:
if (flags & MDT_AMIGA)
return hdl;
break;
case MT_APPLEIIGS:
if (flags & MDT_APPLEIIGS)
return hdl;
break;
case MT_TOWNS:
if (flags & MDT_TOWNS)
return hdl;
@ -224,10 +243,20 @@ MidiDriver::DeviceHandle MidiDriver::detectDevice(int flags) {
MusicType tp = MT_AUTO;
if (flags & MDT_TOWNS)
tp = MT_TOWNS;
else if (flags & MDT_PC98)
tp = MT_PC98;
else if (flags & MDT_ADLIB)
tp = MT_ADLIB;
else if (flags & MDT_PCSPK)
tp = MT_PCSPK;
else if (flags & MDT_PCJR)
tp = MT_PCJR;
else if (flags & MDT_C64)
tp = MT_C64;
else if (flags & MDT_AMIGA)
tp = MT_AMIGA;
else if (flags & MDT_APPLEIIGS)
tp = MT_APPLEIIGS;
else if (l == 0)
// if we haven't tried to find a MIDI device yet we do this now.
continue;
@ -261,12 +290,15 @@ MidiDriver::DeviceHandle MidiDriver::getDeviceHandle(const Common::String &ident
const MusicPlugin::List p = MusicMan.getPlugins();
if (p.begin() == p.end())
error("Music plugins must be loaded prior to calling this method.");
error("Music plugins must be loaded prior to calling this method");
for (MusicPlugin::List::const_iterator m = p.begin(); m != p.end(); m++) {
MusicDevices i = (**m)->getDevices();
for (MusicDevices::iterator d = i.begin(); d != i.end(); d++) {
if (identifier.equals(d->getCompleteId()) || identifier.equals(d->getCompleteName())) {
// The music driver id isn't unique, but it will match
// driver's first device. This is useful when selecting
// the driver from the command line.
if (identifier.equals(d->getMusicDriverId()) || identifier.equals(d->getCompleteId()) || identifier.equals(d->getCompleteName())) {
return d->getHandle();
}
}
@ -274,3 +306,16 @@ MidiDriver::DeviceHandle MidiDriver::getDeviceHandle(const Common::String &ident
return 0;
}
void MidiDriver::sendMT32Reset() {
static const byte resetSysEx[] = { 0x41, 0x10, 0x16, 0x12, 0x7F, 0x00, 0x00, 0x01, 0x00 };
sysEx(resetSysEx, sizeof(resetSysEx));
g_system->delayMillis(100);
}
void MidiDriver::sendGMReset() {
static const byte resetSysEx[] = { 0x7E, 0x7F, 0x09, 0x01 };
sysEx(resetSysEx, sizeof(resetSysEx));
g_system->delayMillis(100);
}

Some files were not shown because too many files have changed in this diff Show more