synced with scummvm svn rev 53000
This commit is contained in:
parent
886c17d130
commit
241c7a8c6e
116 changed files with 104334 additions and 1926 deletions
14
Makefile
14
Makefile
|
@ -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 #
|
||||
#######################################################################
|
||||
|
|
|
@ -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=
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)))
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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" },
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ¶ms);
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -164,7 +164,7 @@ inline frac_t fp_sqroot(uint32 x) {
|
|||
x--; px -= pitch; \
|
||||
} \
|
||||
a2 = (T >> 8); \
|
||||
a1 = ~a2; \
|
||||
a1 = ~a2 >> 4; \
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
101
gui/Tooltip.cpp
Normal 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
50
gui/Tooltip.h
Normal 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
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -25,6 +25,7 @@ MODULE_OBJS := \
|
|||
ThemeEval.o \
|
||||
ThemeLayout.o \
|
||||
ThemeParser.o \
|
||||
Tooltip.o \
|
||||
widget.o
|
||||
|
||||
ifdef MACOSX
|
||||
|
|
300
gui/options.cpp
300
gui/options.cpp
|
@ -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
|
||||
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;
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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
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
7119
gui/themes/fonts/Arial12.bdf
Normal file
File diff suppressed because it is too large
Load diff
1538
gui/themes/fonts/ArialBold.bdf
Normal file
1538
gui/themes/fonts/ArialBold.bdf
Normal file
File diff suppressed because it is too large
Load diff
3
gui/themes/fonts/README
Normal file
3
gui/themes/fonts/README
Normal 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.
|
4290
gui/themes/fonts/clR6x12-iso-8859-1.bdf
Normal file
4290
gui/themes/fonts/clR6x12-iso-8859-1.bdf
Normal file
File diff suppressed because it is too large
Load diff
4291
gui/themes/fonts/clR6x12-iso-8859-5.bdf
Normal file
4291
gui/themes/fonts/clR6x12-iso-8859-5.bdf
Normal file
File diff suppressed because it is too large
Load diff
22736
gui/themes/fonts/clR6x12.bdf
Normal file
22736
gui/themes/fonts/clR6x12.bdf
Normal file
File diff suppressed because it is too large
Load diff
2926
gui/themes/fonts/courr12-iso-8859-1.bdf
Normal file
2926
gui/themes/fonts/courr12-iso-8859-1.bdf
Normal file
File diff suppressed because it is too large
Load diff
3380
gui/themes/fonts/fixed5x8-iso-8859-1.bdf
Normal file
3380
gui/themes/fonts/fixed5x8-iso-8859-1.bdf
Normal file
File diff suppressed because it is too large
Load diff
2309
gui/themes/fonts/fixed5x8-iso-8859-5.bdf
Normal file
2309
gui/themes/fonts/fixed5x8-iso-8859-5.bdf
Normal file
File diff suppressed because it is too large
Load diff
3059
gui/themes/fonts/helvB12-iso-8859-1.bdf
Normal file
3059
gui/themes/fonts/helvB12-iso-8859-1.bdf
Normal file
File diff suppressed because it is too large
Load diff
2763
gui/themes/fonts/helvB12-iso-8859-5.bdf
Normal file
2763
gui/themes/fonts/helvB12-iso-8859-5.bdf
Normal file
File diff suppressed because it is too large
Load diff
12708
gui/themes/fonts/helvB12.bdf
Normal file
12708
gui/themes/fonts/helvB12.bdf
Normal file
File diff suppressed because it is too large
Load diff
3058
gui/themes/fonts/helvBO12-iso-8859-1.bdf
Normal file
3058
gui/themes/fonts/helvBO12-iso-8859-1.bdf
Normal file
File diff suppressed because it is too large
Load diff
12195
gui/themes/fonts/helvBO12.bdf
Normal file
12195
gui/themes/fonts/helvBO12.bdf
Normal file
File diff suppressed because it is too large
Load diff
3048
gui/themes/fonts/helvR12-iso-8859-1.bdf
Normal file
3048
gui/themes/fonts/helvR12-iso-8859-1.bdf
Normal file
File diff suppressed because it is too large
Load diff
12688
gui/themes/fonts/helvR12.bdf
Normal file
12688
gui/themes/fonts/helvR12.bdf
Normal file
File diff suppressed because it is too large
Load diff
4
gui/themes/fonts/topaz/README
Normal file
4
gui/themes/fonts/topaz/README
Normal 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.
|
||||
|
||||
|
BIN
gui/themes/fonts/topaz/topazLT.font
Normal file
BIN
gui/themes/fonts/topaz/topazLT.font
Normal file
Binary file not shown.
63
gui/themes/fonts/topaz/topazLT.readme
Normal file
63
gui/themes/fonts/topaz/topazLT.readme
Normal 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!
|
BIN
gui/themes/fonts/topaz/topazlt/8
Normal file
BIN
gui/themes/fonts/topaz/topazlt/8
Normal file
Binary file not shown.
Binary file not shown.
BIN
gui/themes/modern/clR6x12-iso-8859-5.fcc
Normal file
BIN
gui/themes/modern/clR6x12-iso-8859-5.fcc
Normal file
Binary file not shown.
BIN
gui/themes/modern/fixed5x8-iso-8859-5.fcc
Normal file
BIN
gui/themes/modern/fixed5x8-iso-8859-5.fcc
Normal file
Binary file not shown.
BIN
gui/themes/modern/helvb12-iso-8859-5.fcc
Normal file
BIN
gui/themes/modern/helvb12-iso-8859-5.fcc
Normal file
Binary file not shown.
|
@ -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'
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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);
|
||||
|
|
25
gui/widget.h
25
gui/widget.h
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
10
po/module.mk
10
po/module.mk
|
@ -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
|
||||
|
|
5
ports.mk
5
ports.mk
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue