mirror of
https://github.com/libretro/scummvm.git
synced 2025-04-02 14:51:40 +00:00
ALL: synced with scummvm
This commit is contained in:
parent
522885137f
commit
0517f256d7
@ -510,7 +510,7 @@ Common::String parseCommandLine(Common::StringMap &settings, int argc, const cha
|
||||
END_OPTION
|
||||
#endif
|
||||
|
||||
#if defined (WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
|
||||
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__SYMBIAN32__)
|
||||
// Optional console window on Windows (default: enabled)
|
||||
DO_LONG_OPTION_BOOL("console")
|
||||
END_OPTION
|
||||
|
@ -195,7 +195,7 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
|
||||
}
|
||||
|
||||
// On creation the engine should have set up all debug levels so we can use
|
||||
// the command line arugments here
|
||||
// the command line arguments here
|
||||
Common::StringTokenizer tokenizer(edebuglevels, " ,");
|
||||
while (!tokenizer.empty()) {
|
||||
Common::String token = tokenizer.nextToken();
|
||||
@ -206,6 +206,12 @@ static Common::Error runGame(const EnginePlugin *plugin, OSystem &system, const
|
||||
// Initialize any game-specific keymaps
|
||||
engine->initKeymap();
|
||||
|
||||
// Set default values to the custom engine options
|
||||
const ExtraGuiOptions engineOptions = (*plugin)->getExtraGuiOptions(ConfMan.getActiveDomainName());
|
||||
for (uint i = 0; i < engineOptions.size(); i++) {
|
||||
ConfMan.registerDefault(engineOptions[i].configOption, engineOptions[i].defaultState);
|
||||
}
|
||||
|
||||
// Inform backend that the engine is about to be run
|
||||
system.engineInit();
|
||||
|
||||
|
@ -64,6 +64,14 @@ const struct GameOpt {
|
||||
{ GUIO_RENDERPC9821, "pc9821" },
|
||||
{ GUIO_RENDERPC9801, "pc9801" },
|
||||
|
||||
{ GUIO_GAMEOPTIONS1, "gameOption1" },
|
||||
{ GUIO_GAMEOPTIONS2, "gameOption2" },
|
||||
{ GUIO_GAMEOPTIONS3, "gameOption3" },
|
||||
{ GUIO_GAMEOPTIONS4, "gameOption4" },
|
||||
{ GUIO_GAMEOPTIONS5, "gameOption5" },
|
||||
{ GUIO_GAMEOPTIONS6, "gameOption6" },
|
||||
{ GUIO_GAMEOPTIONS7, "gameOption7" },
|
||||
|
||||
{ GUIO_NONE, 0 }
|
||||
};
|
||||
|
||||
|
@ -56,6 +56,16 @@
|
||||
#define GUIO_RENDERPC9821 "\037"
|
||||
#define GUIO_RENDERPC9801 "\040"
|
||||
|
||||
// Special GUIO flags for the AdvancedDetector's caching of game specific
|
||||
// options.
|
||||
#define GUIO_GAMEOPTIONS1 "\041"
|
||||
#define GUIO_GAMEOPTIONS2 "\042"
|
||||
#define GUIO_GAMEOPTIONS3 "\043"
|
||||
#define GUIO_GAMEOPTIONS4 "\044"
|
||||
#define GUIO_GAMEOPTIONS5 "\045"
|
||||
#define GUIO_GAMEOPTIONS6 "\046"
|
||||
#define GUIO_GAMEOPTIONS7 "\047"
|
||||
|
||||
#define GUIO0() (GUIO_NONE)
|
||||
#define GUIO1(a) (a)
|
||||
#define GUIO2(a,b) (a b)
|
||||
@ -63,6 +73,8 @@
|
||||
#define GUIO4(a,b,c,d) (a b c d)
|
||||
#define GUIO5(a,b,c,d,e) (a b c d e)
|
||||
#define GUIO6(a,b,c,d,e,f) (a b c d e f)
|
||||
#define GUIO7(a,b,c,d,e,f,g) (a b c d e f g)
|
||||
#define GUIO8(a,b,c,d,e,f,g,h) (a b c d e f g h)
|
||||
|
||||
namespace Common {
|
||||
|
||||
|
@ -167,6 +167,25 @@ GameList AdvancedMetaEngine::detectGames(const Common::FSList &fslist) const {
|
||||
return detectedGames;
|
||||
}
|
||||
|
||||
const ExtraGuiOptions AdvancedMetaEngine::getExtraGuiOptions(const Common::String &target) const {
|
||||
if (!_extraGuiOptions)
|
||||
return ExtraGuiOptions();
|
||||
|
||||
// Query the GUI options
|
||||
const Common::String guiOptionsString = ConfMan.get("guioptions", target);
|
||||
const Common::String guiOptions = parseGameGUIOptions(guiOptionsString);
|
||||
|
||||
ExtraGuiOptions options;
|
||||
|
||||
// Add all the applying extra GUI options.
|
||||
for (const ADExtraGuiOptionsMap *entry = _extraGuiOptions; entry->guioFlag; ++entry) {
|
||||
if (guiOptions.contains(entry->guioFlag))
|
||||
options.push_back(entry->option);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
Common::Error AdvancedMetaEngine::createInstance(OSystem *syst, Engine **engine) const {
|
||||
assert(engine);
|
||||
|
||||
@ -562,8 +581,9 @@ GameDescriptor AdvancedMetaEngine::findGame(const char *gameid) const {
|
||||
return GameDescriptor();
|
||||
}
|
||||
|
||||
AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids)
|
||||
: _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameids(gameids) {
|
||||
AdvancedMetaEngine::AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions)
|
||||
: _gameDescriptors((const byte *)descs), _descItemSize(descItemSize), _gameids(gameids),
|
||||
_extraGuiOptions(extraGuiOptions) {
|
||||
|
||||
_md5Bytes = 5000;
|
||||
_singleid = NULL;
|
||||
|
@ -133,6 +133,24 @@ enum ADFlags {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Map entry for mapping GUIO_GAMEOPTIONS* to their ExtraGuiOption
|
||||
* description.
|
||||
*/
|
||||
struct ADExtraGuiOptionsMap {
|
||||
/**
|
||||
* GUIO_GAMEOPTION* string.
|
||||
*/
|
||||
const char *guioFlag;
|
||||
|
||||
/**
|
||||
* The associated option.
|
||||
*/
|
||||
ExtraGuiOption option;
|
||||
};
|
||||
|
||||
#define AD_EXTRA_GUI_OPTIONS_TERMINATOR { 0, { 0, 0, 0, 0 } }
|
||||
|
||||
/**
|
||||
* A MetaEngine implementation based around the advanced detector code.
|
||||
*/
|
||||
@ -158,6 +176,11 @@ protected:
|
||||
*/
|
||||
const PlainGameDescriptor *_gameids;
|
||||
|
||||
/**
|
||||
* A map containing all the extra game GUI options the engine supports.
|
||||
*/
|
||||
const ADExtraGuiOptionsMap * const _extraGuiOptions;
|
||||
|
||||
/**
|
||||
* The number of bytes to compute MD5 sum for. The AdvancedDetector
|
||||
* is primarily based on computing and matching MD5 checksums of files.
|
||||
@ -211,7 +234,7 @@ protected:
|
||||
const char * const *_directoryGlobs;
|
||||
|
||||
public:
|
||||
AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids);
|
||||
AdvancedMetaEngine(const void *descs, uint descItemSize, const PlainGameDescriptor *gameids, const ADExtraGuiOptionsMap *extraGuiOptions = 0);
|
||||
|
||||
/**
|
||||
* Returns list of targets supported by the engine.
|
||||
@ -225,6 +248,8 @@ public:
|
||||
|
||||
virtual Common::Error createInstance(OSystem *syst, Engine **engine) const;
|
||||
|
||||
virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const;
|
||||
|
||||
protected:
|
||||
// To be implemented by subclasses
|
||||
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const = 0;
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/error.h"
|
||||
#include "common/array.h"
|
||||
|
||||
#include "engines/game.h"
|
||||
#include "engines/savestate.h"
|
||||
@ -38,6 +39,19 @@ class FSList;
|
||||
class String;
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-game extra GUI options structure.
|
||||
* Currently, this can only be used for options with checkboxes.
|
||||
*/
|
||||
struct ExtraGuiOption {
|
||||
const char *label; // option label, e.g. "Fullscreen mode"
|
||||
const char *tooltip; // option tooltip (when the mouse hovers above it)
|
||||
const char *configOption; // confMan key, e.g. "fullscreen"
|
||||
bool defaultState; // the detault state of the checkbox (checked or not)
|
||||
};
|
||||
|
||||
typedef Common::Array<ExtraGuiOption> ExtraGuiOptions;
|
||||
|
||||
/**
|
||||
* A meta engine is essentially a factory for Engine instances with the
|
||||
* added ability of listing and detecting supported games.
|
||||
@ -97,6 +111,16 @@ public:
|
||||
return SaveStateList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of extra GUI options.
|
||||
* Currently, this only supports options with checkboxes.
|
||||
*
|
||||
* The default implementation returns an empty list.
|
||||
*/
|
||||
virtual const ExtraGuiOptions getExtraGuiOptions(const Common::String &target) const {
|
||||
return ExtraGuiOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum save slot that the engine supports.
|
||||
*
|
||||
|
@ -47,6 +47,7 @@ const char * const ThemeEngine::kImageLogo = "logo.bmp";
|
||||
const char * const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
|
||||
const char * const ThemeEngine::kImageSearch = "search.bmp";
|
||||
const char * const ThemeEngine::kImageEraser = "eraser.bmp";
|
||||
const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp";
|
||||
|
||||
struct TextDrawData {
|
||||
const Graphics::Font *_fontPtr;
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include "graphics/pixelformat.h"
|
||||
|
||||
|
||||
#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.8"
|
||||
#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.10"
|
||||
|
||||
class OSystem;
|
||||
|
||||
@ -229,6 +229,7 @@ public:
|
||||
static const char *const kImageLogoSmall; ///< ScummVM logo used in the GMM
|
||||
static const char *const kImageSearch; ///< Search tool image used in the launcher
|
||||
static const char *const kImageEraser; ///< Clear input image used in the launcher
|
||||
static const char *const kImageDelbtn; ///< Delete characters in the predictive dialog
|
||||
|
||||
/**
|
||||
* Graphics mode enumeration.
|
||||
|
@ -145,11 +145,28 @@ protected:
|
||||
CheckboxWidget *_globalMIDIOverride;
|
||||
CheckboxWidget *_globalMT32Override;
|
||||
CheckboxWidget *_globalVolumeOverride;
|
||||
|
||||
ExtraGuiOptions _engineOptions;
|
||||
};
|
||||
|
||||
EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
: OptionsDialog(domain, "GameOptions") {
|
||||
|
||||
// Retrieve all game specific options.
|
||||
const EnginePlugin *plugin = 0;
|
||||
// To allow for game domains without a gameid.
|
||||
// TODO: Is it intentional that this is still supported?
|
||||
String gameId(ConfMan.get("gameid", domain));
|
||||
if (gameId.empty())
|
||||
gameId = domain;
|
||||
// Retrieve the plugin, since we need to access the engine's MetaEngine
|
||||
// implementation.
|
||||
EngineMan.findGame(gameId, &plugin);
|
||||
if (plugin) {
|
||||
_engineOptions = (*plugin)->getExtraGuiOptions(domain);
|
||||
} else {
|
||||
warning("Plugin for target \"%s\" not found! Game specific settings might be missing", domain.c_str());
|
||||
}
|
||||
|
||||
// GAME: Path to game data (r/o), extra data (r/o), and save data (r/w)
|
||||
String gamePath(ConfMan.get("path", _domain));
|
||||
String extraPath(ConfMan.get("extrapath", _domain));
|
||||
@ -208,7 +225,16 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
}
|
||||
|
||||
//
|
||||
// 2) The graphics tab
|
||||
// 2) The engine tab (shown only if there are custom engine options)
|
||||
//
|
||||
if (_engineOptions.size() > 0) {
|
||||
tab->addTab(_("Engine"));
|
||||
|
||||
addEngineControls(tab, "GameOptions_Engine.", _engineOptions);
|
||||
}
|
||||
|
||||
//
|
||||
// 3) The graphics tab
|
||||
//
|
||||
_graphicsTabId = tab->addTab(g_system->getOverlayWidth() > 320 ? _("Graphics") : _("GFX"));
|
||||
|
||||
@ -220,7 +246,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
addGraphicControls(tab, "GameOptions_Graphics.");
|
||||
|
||||
//
|
||||
// 3) The audio tab
|
||||
// 4) The audio tab
|
||||
//
|
||||
tab->addTab(_("Audio"));
|
||||
|
||||
@ -233,7 +259,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
addSubtitleControls(tab, "GameOptions_Audio.");
|
||||
|
||||
//
|
||||
// 4) The volume tab
|
||||
// 5) The volume tab
|
||||
//
|
||||
if (g_system->getOverlayWidth() > 320)
|
||||
tab->addTab(_("Volume"));
|
||||
@ -248,7 +274,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
addVolumeControls(tab, "GameOptions_Volume.");
|
||||
/* ResidualVM: do not enable midi
|
||||
//
|
||||
// 5) The MIDI tab
|
||||
// 6) The MIDI tab
|
||||
//
|
||||
if (!_guioptions.contains(GUIO_NOMIDI)) {
|
||||
tab->addTab(_("MIDI"));
|
||||
@ -262,7 +288,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
}
|
||||
|
||||
//
|
||||
// 6) The MT-32 tab
|
||||
// 7) The MT-32 tab
|
||||
//
|
||||
if (!_guioptions.contains(GUIO_NOMIDI)) {
|
||||
tab->addTab(_("MT-32"));
|
||||
@ -276,7 +302,7 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
}*/
|
||||
|
||||
//
|
||||
// 7) The Paths tab
|
||||
// 8) The Paths tab
|
||||
//
|
||||
if (g_system->getOverlayWidth() > 320)
|
||||
tab->addTab(_("Paths"));
|
||||
@ -311,7 +337,6 @@ EditGameDialog::EditGameDialog(const String &domain, const String &desc)
|
||||
|
||||
_savePathClearButton = addClearButton(tab, "GameOptions_Paths.SavePathClearButton", kCmdSavePathClear);
|
||||
|
||||
|
||||
// Activate the first tab
|
||||
tab->setActiveTab(0);
|
||||
_tabWidget = tab;
|
||||
@ -386,6 +411,19 @@ void EditGameDialog::open() {
|
||||
_langPopUp->setEnabled(false);
|
||||
}
|
||||
|
||||
// Set the state of engine-specific checkboxes
|
||||
for (uint j = 0; j < _engineOptions.size(); ++j) {
|
||||
// The default values for engine-specific checkboxes are not set when
|
||||
// ScummVM starts, as this would require us to load and poll all of the
|
||||
// engine plugins on startup. Thus, we set the state of each custom
|
||||
// option checkbox to what is specified by the engine plugin, and
|
||||
// update it only if a value has been set in the configuration of the
|
||||
// currently selected game.
|
||||
bool isChecked = _engineOptions[j].defaultState;
|
||||
if (ConfMan.hasKey(_engineOptions[j].configOption, _domain))
|
||||
isChecked = ConfMan.getBool(_engineOptions[j].configOption, _domain);
|
||||
_engineCheckboxes[j]->setState(isChecked);
|
||||
}
|
||||
|
||||
const Common::PlatformDescription *p = Common::g_platforms;
|
||||
const Common::Platform platform = Common::parsePlatform(ConfMan.get("platform", _domain));
|
||||
@ -429,6 +467,11 @@ void EditGameDialog::close() {
|
||||
ConfMan.removeKey("platform", _domain);
|
||||
else
|
||||
ConfMan.set("platform", Common::getPlatformCode(platform), _domain);
|
||||
|
||||
// Set the state of engine-specific checkboxes
|
||||
for (uint i = 0; i < _engineOptions.size(); i++) {
|
||||
ConfMan.setBool(_engineOptions[i].configOption, _engineCheckboxes[i]->getState(), _domain);
|
||||
}
|
||||
}
|
||||
OptionsDialog::close();
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ MODULE_OBJS := \
|
||||
message.o \
|
||||
object.o \
|
||||
options.o \
|
||||
predictivedialog.o \
|
||||
saveload.o \
|
||||
themebrowser.o \
|
||||
ThemeEngine.o \
|
||||
|
@ -890,6 +890,22 @@ void OptionsDialog::addVolumeControls(GuiObject *boss, const Common::String &pre
|
||||
_enableVolumeSettings = true;
|
||||
}
|
||||
|
||||
void OptionsDialog::addEngineControls(GuiObject *boss, const Common::String &prefix, const ExtraGuiOptions &engineOptions) {
|
||||
// Note: up to 7 engine options can currently fit on screen (the most that
|
||||
// can fit in a 320x200 screen with the classic theme).
|
||||
// TODO: Increase this number by including the checkboxes inside a scroll
|
||||
// widget. The appropriate number of checkboxes will need to be added to
|
||||
// the theme files.
|
||||
|
||||
uint i = 1;
|
||||
ExtraGuiOptions::const_iterator iter;
|
||||
for (iter = engineOptions.begin(); iter != engineOptions.end(); ++iter, ++i) {
|
||||
Common::String id = Common::String::format("%d", i);
|
||||
_engineCheckboxes.push_back(new CheckboxWidget(boss,
|
||||
prefix + "customOption" + id + "Checkbox", _(iter->label), _(iter->tooltip)));
|
||||
}
|
||||
}
|
||||
|
||||
bool OptionsDialog::loadMusicDeviceSetting(PopUpWidget *popup, Common::String setting, MusicType preferredType) {
|
||||
if (!popup || !popup->isEnabled())
|
||||
return true;
|
||||
@ -1369,11 +1385,11 @@ void GlobalOptionsDialog::reflowLayout() {
|
||||
|
||||
if (_midiTabId != -1) {
|
||||
_tabWidget->setActiveTab(_midiTabId);
|
||||
|
||||
/* Residual do not use it
|
||||
_tabWidget->removeWidget(_soundFontClearButton);
|
||||
_soundFontClearButton->setNext(0);
|
||||
delete _soundFontClearButton;
|
||||
_soundFontClearButton = addClearButton(_tabWidget, "GlobalOptions_MIDI.mcFontClearButton", kClearSoundFontCmd);
|
||||
_soundFontClearButton = addClearButton(_tabWidget, "GlobalOptions_MIDI.mcFontClearButton", kClearSoundFontCmd);*/
|
||||
}
|
||||
|
||||
if (_pathsTabId != -1) {
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef OPTIONS_DIALOG_H
|
||||
#define OPTIONS_DIALOG_H
|
||||
|
||||
#include "engines/metaengine.h"
|
||||
|
||||
#include "gui/dialog.h"
|
||||
#include "common/str.h"
|
||||
#include "audio/mididrv.h"
|
||||
@ -44,6 +46,8 @@ class RadiobuttonGroup;
|
||||
class RadiobuttonWidget;
|
||||
|
||||
class OptionsDialog : public Dialog {
|
||||
typedef Common::Array<CheckboxWidget *> CheckboxWidgetList;
|
||||
|
||||
public:
|
||||
OptionsDialog(const Common::String &domain, int x, int y, int w, int h);
|
||||
OptionsDialog(const Common::String &domain, const Common::String &name);
|
||||
@ -74,6 +78,7 @@ protected:
|
||||
// The default value is the launcher's non-scaled talkspeed value. When SCUMM uses the widget,
|
||||
// it uses its own scale
|
||||
void addSubtitleControls(GuiObject *boss, const Common::String &prefix, int maxSliderVal = 255);
|
||||
void addEngineControls(GuiObject *boss, const Common::String &prefix, const ExtraGuiOptions &engineOptions);
|
||||
|
||||
void setGraphicSettingsState(bool enabled);
|
||||
void setAudioSettingsState(bool enabled);
|
||||
@ -181,6 +186,11 @@ protected:
|
||||
//Theme Options
|
||||
//
|
||||
Common::String _oldTheme;
|
||||
|
||||
//
|
||||
// Engine-specific controls
|
||||
//
|
||||
CheckboxWidgetList _engineCheckboxes;
|
||||
};
|
||||
|
||||
|
||||
|
917
gui/predictivedialog.cpp
Normal file
917
gui/predictivedialog.cpp
Normal file
@ -0,0 +1,917 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gui/predictivedialog.h"
|
||||
#include "gui/widget.h"
|
||||
#include "gui/widgets/edittext.h"
|
||||
#include "gui/gui-manager.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/translation.h"
|
||||
#include "common/events.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/system.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/file.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
using namespace Common;
|
||||
|
||||
namespace GUI {
|
||||
|
||||
enum {
|
||||
kCancelCmd = 'CNCL',
|
||||
kOkCmd = '__OK',
|
||||
kBut1Cmd = 'BUT1',
|
||||
kBut2Cmd = 'BUT2',
|
||||
kBut3Cmd = 'BUT3',
|
||||
kBut4Cmd = 'BUT4',
|
||||
kBut5Cmd = 'BUT5',
|
||||
kBut6Cmd = 'BUT6',
|
||||
kBut7Cmd = 'BUT7',
|
||||
kBut8Cmd = 'BUT8',
|
||||
kBut9Cmd = 'BUT9',
|
||||
kBut0Cmd = 'BUT0',
|
||||
kNextCmd = 'NEXT',
|
||||
kAddCmd = '_ADD',
|
||||
kModeCmd = 'MODE',
|
||||
kDelCmd = '_DEL',
|
||||
kTestCmd = 'TEST'
|
||||
};
|
||||
|
||||
enum {
|
||||
kModePre = 0,
|
||||
kModeNum = 1,
|
||||
kModeAbc = 2
|
||||
};
|
||||
|
||||
PredictiveDialog::PredictiveDialog() : Dialog("Predictive") {
|
||||
new StaticTextWidget(this, "Predictive.Headline", "Enter Text");
|
||||
|
||||
new ButtonWidget(this, "Predictive.Cancel" , _("Cancel") , 0, kCancelCmd);
|
||||
new ButtonWidget(this, "Predictive.OK" , _("Ok") , 0, kOkCmd);
|
||||
new ButtonWidget(this, "Predictive.Button1", "1 `-.&" , 0, kBut1Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button2", "2 abc" , 0, kBut2Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button3", "3 def" , 0, kBut3Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button4", "4 ghi" , 0, kBut4Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button5", "5 jkl" , 0, kBut5Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button6", "6 mno" , 0, kBut6Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button7", "7 pqrs" , 0, kBut7Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button8", "8 tuv" , 0, kBut8Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button9", "9 wxyz" , 0, kBut9Cmd);
|
||||
new ButtonWidget(this, "Predictive.Button0", "0" , 0, kBut0Cmd);
|
||||
// I18N: You must leave "#" as is, only word 'next' is translatable
|
||||
new ButtonWidget(this, "Predictive.Next" , _("# next") , 0, kNextCmd);
|
||||
_addBtn = new ButtonWidget(this, "Predictive.Add", _("add") , 0, kAddCmd);
|
||||
_addBtn->setEnabled(false);
|
||||
|
||||
#ifndef DISABLE_FANCY_THEMES
|
||||
_delbtn = new PicButtonWidget(this, "Predictive.Delete", _("Delete char"), kDelCmd);
|
||||
((PicButtonWidget *)_delbtn)->useThemeTransparency(true);
|
||||
((PicButtonWidget *)_delbtn)->setGfx(g_gui.theme()->getImageSurface(ThemeEngine::kImageDelbtn));
|
||||
#endif
|
||||
_delbtn = new ButtonWidget(this, "Predictive.Delete" , _("<") , 0, kDelCmd);
|
||||
// I18N: Pre means 'Predictive', leave '*' as is
|
||||
_modebutton = new ButtonWidget(this, "Predictive.Pre", _("* Pre"), 0, kModeCmd);
|
||||
_edittext = new EditTextWidget(this, "Predictive.Word", _search, 0, 0, 0);
|
||||
|
||||
_userDictHasChanged = false;
|
||||
|
||||
_predictiveDict.nameDict = "predictive_dictionary";
|
||||
_predictiveDict.fnameDict = "pred.dic";
|
||||
_predictiveDict.dictActLine = NULL;
|
||||
|
||||
_userDict.nameDict = "user_dictionary";
|
||||
_userDict.fnameDict = "user.dic";
|
||||
_userDict.dictActLine = NULL;
|
||||
|
||||
_unitedDict.nameDict = "";
|
||||
_unitedDict.fnameDict = "";
|
||||
|
||||
_predictiveDict.dictLine = NULL;
|
||||
_predictiveDict.dictText = NULL;
|
||||
_predictiveDict.dictLineCount = 0;
|
||||
|
||||
if (!_predictiveDict.dictText) {
|
||||
loadAllDictionary(_predictiveDict);
|
||||
if (!_predictiveDict.dictText)
|
||||
debug("Predictive Dialog: pred.dic not loaded");
|
||||
}
|
||||
|
||||
_userDict.dictLine = NULL;
|
||||
_userDict.dictText = NULL;
|
||||
_userDict.dictTextSize = 0;
|
||||
_userDict.dictLineCount = 0;
|
||||
|
||||
if (!_userDict.dictText) {
|
||||
loadAllDictionary(_userDict);
|
||||
if (!_userDict.dictText)
|
||||
debug("Predictive Dialog: user.dic not loaded");
|
||||
}
|
||||
|
||||
mergeDicts();
|
||||
|
||||
_unitedDict.dictActLine = NULL;
|
||||
_unitedDict.dictText = NULL;
|
||||
|
||||
memset(_repeatcount, 0, sizeof(_repeatcount));
|
||||
|
||||
_prefix.clear();
|
||||
_currentCode.clear();
|
||||
_currentWord.clear();
|
||||
_wordNumber = 0;
|
||||
_numMatchingWords = 0;
|
||||
|
||||
_lastbutton = kNoAct;
|
||||
_mode = kModePre;
|
||||
|
||||
_lastTime = 0;
|
||||
_curTime = 0;
|
||||
_lastPressBtn = kNoAct;
|
||||
|
||||
_memoryList[0] = _predictiveDict.dictText;
|
||||
_memoryList[1] = _userDict.dictText;
|
||||
_numMemory = 0;
|
||||
|
||||
_navigationwithkeys = false;
|
||||
}
|
||||
|
||||
PredictiveDialog::~PredictiveDialog() {
|
||||
for (int i = 0; i < _numMemory; i++) {
|
||||
free(_memoryList[i]);
|
||||
}
|
||||
free(_userDict.dictLine);
|
||||
free(_predictiveDict.dictLine);
|
||||
free(_unitedDict.dictLine);
|
||||
}
|
||||
|
||||
void PredictiveDialog::saveUserDictToFile() {
|
||||
if (_userDictHasChanged) {
|
||||
ConfMan.registerDefault("user_dictionary", "user.dic");
|
||||
|
||||
Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(ConfMan.get("user_dictionary"));
|
||||
|
||||
for (int i = 0; i < _userDict.dictLineCount; i++) {
|
||||
file->writeString(_userDict.dictLine[i]);
|
||||
file->writeString("\n");
|
||||
}
|
||||
|
||||
file->finalize();
|
||||
delete file;
|
||||
}
|
||||
}
|
||||
|
||||
void PredictiveDialog::handleKeyDown(Common::KeyState state) {
|
||||
ButtonId act = kNoAct;
|
||||
|
||||
if (getFocusWidget() == _edittext) {
|
||||
setFocusWidget(_addBtn);
|
||||
}
|
||||
|
||||
switch (state.keycode) {
|
||||
case Common::KEYCODE_ESCAPE:
|
||||
saveUserDictToFile();
|
||||
close();
|
||||
return;
|
||||
case Common::KEYCODE_LEFT:
|
||||
_navigationwithkeys = true;
|
||||
if (_lastbutton == kBtn1Act || _lastbutton == kBtn4Act || _lastbutton == kBtn7Act)
|
||||
act = ButtonId(_lastbutton + 2);
|
||||
else if (_lastbutton == kNextAct)
|
||||
act = kBtn0Act;
|
||||
else if (_lastbutton == kDelAct)
|
||||
act = kDelAct;
|
||||
else if (_lastbutton == kCancelAct)
|
||||
act = kOkAct;
|
||||
else if (_lastbutton == kModeAct)
|
||||
act = kAddAct;
|
||||
else
|
||||
act = ButtonId(_lastbutton - 1);
|
||||
_lastbutton = act;
|
||||
//needRefresh = true;
|
||||
break;
|
||||
case Common::KEYCODE_RIGHT:
|
||||
_navigationwithkeys = true;
|
||||
if (_lastbutton == kBtn3Act || _lastbutton == kBtn6Act || _lastbutton == kBtn9Act)
|
||||
act = ButtonId(_lastbutton - 2);
|
||||
else if (_lastbutton == kAddAct)
|
||||
act = kModeAct;
|
||||
else if (_lastbutton == kDelAct)
|
||||
act = kDelAct;
|
||||
else if (_lastbutton == kOkAct)
|
||||
act = kCancelAct;
|
||||
else if (_lastbutton == kBtn0Act)
|
||||
act = kNextAct;
|
||||
else
|
||||
act = ButtonId(_lastbutton + 1);
|
||||
_lastbutton = act;
|
||||
//needRefresh = true;
|
||||
break;
|
||||
case Common::KEYCODE_UP:
|
||||
_navigationwithkeys = true;
|
||||
if (_lastbutton <= kBtn3Act)
|
||||
act = kDelAct;
|
||||
else if (_lastbutton == kNextAct || _lastbutton == kAddAct)
|
||||
act = ButtonId(_lastbutton - 2);
|
||||
else if (_lastbutton == kDelAct)
|
||||
act = kOkAct;
|
||||
else if (_lastbutton == kModeAct)
|
||||
act = kBtn9Act;
|
||||
else if (_lastbutton == kBtn0Act)
|
||||
act = kBtn7Act;
|
||||
else
|
||||
act = ButtonId(_lastbutton - 3);
|
||||
_lastbutton = act;
|
||||
//needRefresh = true;
|
||||
break;
|
||||
case Common::KEYCODE_DOWN:
|
||||
_navigationwithkeys = true;
|
||||
if (_lastbutton == kBtn7Act)
|
||||
act = kBtn0Act;
|
||||
else if (_lastbutton == kBtn8Act || _lastbutton == kBtn9Act)
|
||||
act = ButtonId(_lastbutton + 2);
|
||||
else if (_lastbutton == kDelAct)
|
||||
act = kBtn1Act;
|
||||
else if (_lastbutton == kCancelAct || _lastbutton == kOkAct)
|
||||
act = kDelAct;
|
||||
else if (_lastbutton == kModeAct || _lastbutton == kBtn0Act)
|
||||
act = ButtonId(_lastbutton - 2);
|
||||
else
|
||||
act = ButtonId(_lastbutton + 3);
|
||||
_lastbutton = act;
|
||||
//needRefresh = true;
|
||||
break;
|
||||
case Common::KEYCODE_KP_ENTER:
|
||||
if (_navigationwithkeys) {
|
||||
// when the user has utilized arrow key navigation,
|
||||
// interpret enter as 'click' on the act button
|
||||
act = _lastbutton;
|
||||
} else {
|
||||
// else it is a shortcut for 'Ok'
|
||||
act = kOkAct;
|
||||
}
|
||||
break;
|
||||
case Common::KEYCODE_KP_PLUS:
|
||||
act = kAddAct;
|
||||
break;
|
||||
case Common::KEYCODE_BACKSPACE:
|
||||
case Common::KEYCODE_KP_MINUS:
|
||||
act = kDelAct;
|
||||
break;
|
||||
case Common::KEYCODE_KP_DIVIDE:
|
||||
act = kNextAct;
|
||||
break;
|
||||
case Common::KEYCODE_KP_MULTIPLY:
|
||||
act = kModeAct;
|
||||
break;
|
||||
case Common::KEYCODE_KP0:
|
||||
act = kBtn0Act;
|
||||
break;
|
||||
case Common::KEYCODE_KP1:
|
||||
case Common::KEYCODE_KP2:
|
||||
case Common::KEYCODE_KP3:
|
||||
case Common::KEYCODE_KP4:
|
||||
case Common::KEYCODE_KP5:
|
||||
case Common::KEYCODE_KP6:
|
||||
case Common::KEYCODE_KP7:
|
||||
case Common::KEYCODE_KP8:
|
||||
case Common::KEYCODE_KP9:
|
||||
act = ButtonId(state.keycode - Common::KEYCODE_KP1);
|
||||
break;
|
||||
default:
|
||||
Dialog::handleKeyDown(state);
|
||||
}
|
||||
|
||||
if (act != kNoAct) {
|
||||
processBtnActive(act);
|
||||
}
|
||||
}
|
||||
|
||||
void PredictiveDialog::handleCommand(CommandSender *sender, uint32 cmd, uint32 data) {
|
||||
ButtonId act = kNoAct;
|
||||
|
||||
_navigationwithkeys = false;
|
||||
|
||||
switch (cmd) {
|
||||
case kDelCmd:
|
||||
act = kDelAct;
|
||||
break;
|
||||
case kNextCmd:
|
||||
act = kNextAct;
|
||||
break;
|
||||
case kAddCmd:
|
||||
act = kAddAct;
|
||||
break;
|
||||
case kModeCmd:
|
||||
act = kModeAct;
|
||||
break;
|
||||
case kBut1Cmd:
|
||||
act = kBtn1Act;
|
||||
break;
|
||||
case kBut2Cmd:
|
||||
act = kBtn2Act;
|
||||
break;
|
||||
case kBut3Cmd:
|
||||
act = kBtn3Act;
|
||||
break;
|
||||
case kBut4Cmd:
|
||||
act = kBtn4Act;
|
||||
break;
|
||||
case kBut5Cmd:
|
||||
act = kBtn5Act;
|
||||
break;
|
||||
case kBut6Cmd:
|
||||
act = kBtn6Act;
|
||||
break;
|
||||
case kBut7Cmd:
|
||||
act = kBtn7Act;
|
||||
break;
|
||||
case kBut8Cmd:
|
||||
act = kBtn8Act;
|
||||
break;
|
||||
case kBut9Cmd:
|
||||
act = kBtn9Act;
|
||||
break;
|
||||
case kBut0Cmd:
|
||||
act = kBtn0Act;
|
||||
break;
|
||||
case kCancelCmd:
|
||||
saveUserDictToFile();
|
||||
close();
|
||||
return;
|
||||
case kOkCmd:
|
||||
act = kOkAct;
|
||||
break;
|
||||
default:
|
||||
Dialog::handleCommand(sender, cmd, data);
|
||||
}
|
||||
|
||||
if (act != kNoAct) {
|
||||
processBtnActive(act);
|
||||
}
|
||||
}
|
||||
|
||||
void PredictiveDialog::processBtnActive(ButtonId button) {
|
||||
uint8 x;
|
||||
const char *buttonStr[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };
|
||||
const char *buttons[] = {
|
||||
"'-.&", "abc", "def",
|
||||
"ghi", "jkl", "mno",
|
||||
"pqrs", "tuv", "wxyz",
|
||||
"next", "add",
|
||||
"<",
|
||||
"Cancel", "OK",
|
||||
"Pre", "(0) ", NULL
|
||||
};
|
||||
|
||||
if (_mode == kModeAbc) {
|
||||
if (button >= kBtn1Act && button <= kBtn9Act ) {
|
||||
if (!_lastTime)
|
||||
_lastTime = g_system->getMillis();
|
||||
if (_lastPressBtn == button) {
|
||||
_curTime = g_system->getMillis();
|
||||
if((_curTime - _lastTime) < kRepeatDelay) {
|
||||
button = kNextAct;
|
||||
_lastTime = _curTime;
|
||||
} else {
|
||||
_lastTime = 0;
|
||||
}
|
||||
} else {
|
||||
_lastPressBtn = button;
|
||||
_lastTime = g_system->getMillis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (button >= kBtn1Act) {
|
||||
_lastbutton = button;
|
||||
if (button == kBtn0Act && _mode != kModeNum) { // Space
|
||||
// bring MRU word at the top of the list when changing words
|
||||
if (_mode == kModePre && _unitedDict.dictActLine && _numMatchingWords > 1 && _wordNumber != 0)
|
||||
bringWordtoTop(_unitedDict.dictActLine, _wordNumber);
|
||||
|
||||
strncpy(_temp, _currentWord.c_str(), _currentCode.size());
|
||||
_temp[_currentCode.size()] = 0;
|
||||
_prefix += _temp;
|
||||
_prefix += " ";
|
||||
_currentCode.clear();
|
||||
_currentWord.clear();
|
||||
_numMatchingWords = 0;
|
||||
memset(_repeatcount, 0, sizeof(_repeatcount));
|
||||
_lastTime = 0;
|
||||
_lastPressBtn = kNoAct;
|
||||
_curTime = 0;
|
||||
} else if (button < kNextAct || button == kDelAct || button == kBtn0Act) { // number or backspace
|
||||
if (button == kDelAct) { // backspace
|
||||
if (_currentCode.size()) {
|
||||
_repeatcount[_currentCode.size() - 1] = 0;
|
||||
_currentCode.deleteLastChar();
|
||||
if(_currentCode == Common::String(""))
|
||||
_currentWord.clear();
|
||||
} else {
|
||||
if (_prefix.size())
|
||||
_prefix.deleteLastChar();
|
||||
}
|
||||
} else if (_prefix.size() + _currentCode.size() < MAXWORDLEN - 1) { // don't overflow the dialog line
|
||||
if (button == kBtn0Act) { // zero
|
||||
_currentCode += buttonStr[9];
|
||||
} else {
|
||||
_currentCode += buttonStr[button];
|
||||
}
|
||||
}
|
||||
|
||||
switch (_mode) {
|
||||
case kModeNum:
|
||||
_currentWord = _currentCode;
|
||||
break;
|
||||
case kModePre:
|
||||
if (!matchWord() && _currentCode.size()) {
|
||||
_currentCode.deleteLastChar();
|
||||
matchWord();
|
||||
}
|
||||
_numMatchingWords = countWordsInString(_unitedDict.dictActLine);
|
||||
break;
|
||||
case kModeAbc:
|
||||
for (x = 0; x < _currentCode.size(); x++)
|
||||
if (_currentCode[x] >= '1')
|
||||
_temp[x] = buttons[_currentCode[x] - '1'][_repeatcount[x]];
|
||||
_temp[_currentCode.size()] = 0;
|
||||
_currentWord = _temp;
|
||||
}
|
||||
} else if (button == kNextAct) { // next
|
||||
if (_mode == kModePre) {
|
||||
if (_unitedDict.dictActLine && _numMatchingWords > 1) {
|
||||
_wordNumber = (_wordNumber + 1) % _numMatchingWords;
|
||||
char tmp[MAXLINELEN];
|
||||
strncpy(tmp, _unitedDict.dictActLine, MAXLINELEN);
|
||||
tmp[MAXLINELEN - 1] = 0;
|
||||
char *tok = strtok(tmp, " ");
|
||||
for (uint8 i = 0; i <= _wordNumber; i++)
|
||||
tok = strtok(NULL, " ");
|
||||
_currentWord = Common::String(tok, _currentCode.size());
|
||||
}
|
||||
} else if (_mode == kModeAbc) {
|
||||
x = _currentCode.size();
|
||||
if (x) {
|
||||
if (_currentCode.lastChar() == '1' || _currentCode.lastChar() == '7' || _currentCode.lastChar() == '9')
|
||||
_repeatcount[x - 1] = (_repeatcount[x - 1] + 1) % 4;
|
||||
else
|
||||
_repeatcount[x - 1] = (_repeatcount[x - 1] + 1) % 3;
|
||||
|
||||
if (_currentCode.lastChar() >= '1')
|
||||
_currentWord.setChar(buttons[_currentCode[x - 1] - '1'][_repeatcount[x - 1]], x-1);
|
||||
}
|
||||
}
|
||||
} else if (button == kAddAct) { // add
|
||||
if (_mode == kModeAbc)
|
||||
addWordToDict();
|
||||
else
|
||||
debug("Predictive Dialog: button Add doesn't work in this mode");
|
||||
} else if (button == kOkAct) { // Ok
|
||||
// bring MRU word at the top of the list when ok'ed out of the dialog
|
||||
if (_mode == kModePre && _unitedDict.dictActLine && _numMatchingWords > 1 && _wordNumber != 0)
|
||||
bringWordtoTop(_unitedDict.dictActLine, _wordNumber);
|
||||
|
||||
goto press;
|
||||
} else if (button == kModeAct) { // Mode
|
||||
_mode++;
|
||||
_addBtn->setEnabled(false);
|
||||
if (_mode > kModeAbc) {
|
||||
_mode = kModePre;
|
||||
// I18N: Pre means 'Predictive', leave '*' as is
|
||||
_modebutton->setLabel("* Pre");
|
||||
// I18N: 'Num' means Numbers, 'Abc' means Latin alphabet input
|
||||
} else (_mode == kModeNum) ? _modebutton->setLabel("* Num") : (_modebutton->setLabel("* Abc"), _addBtn->setEnabled(true));
|
||||
|
||||
// truncate current input at mode change
|
||||
strncpy(_temp, _currentWord.c_str(), _currentCode.size());
|
||||
_temp[_currentCode.size()] = 0;
|
||||
_prefix += _temp;
|
||||
_currentCode.clear();
|
||||
_currentWord.clear();
|
||||
memset(_repeatcount, 0, sizeof(_repeatcount));
|
||||
|
||||
_lastTime = 0;
|
||||
_lastPressBtn = kNoAct;
|
||||
_curTime = 0;
|
||||
} else {
|
||||
goto press;
|
||||
}
|
||||
}
|
||||
|
||||
press:
|
||||
pressEditText();
|
||||
|
||||
if (button == kOkAct) close();
|
||||
}
|
||||
|
||||
void PredictiveDialog::handleTickle() {
|
||||
if (!_lastTime)
|
||||
if ((_curTime - _lastTime) > kRepeatDelay) {
|
||||
_lastTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void PredictiveDialog::mergeDicts() {
|
||||
_unitedDict.dictLineCount = _predictiveDict.dictLineCount + _userDict.dictLineCount;
|
||||
_unitedDict.dictLine = (char **)calloc(1, sizeof(char *) * _unitedDict.dictLineCount);
|
||||
|
||||
if (!_unitedDict.dictLine) {
|
||||
debug("Predictive Dialog: cannot allocate memory for united dic");
|
||||
return;
|
||||
}
|
||||
|
||||
int lenUserDictCode, lenPredictiveDictCode, lenCode;
|
||||
int i, j, k;
|
||||
i = j = k = 0;
|
||||
|
||||
while ((i < _userDict.dictLineCount) && (j < _predictiveDict.dictLineCount)) {
|
||||
lenUserDictCode = strchr(_userDict.dictLine[i], ' ') - _userDict.dictLine[i];
|
||||
lenPredictiveDictCode = strchr(_predictiveDict.dictLine[j], ' ') - _predictiveDict.dictLine[j];
|
||||
lenCode = (lenUserDictCode >= lenPredictiveDictCode) ? lenUserDictCode : lenPredictiveDictCode;
|
||||
if (strncmp(_userDict.dictLine[i], _predictiveDict.dictLine[j], lenCode) >= 0) {
|
||||
_unitedDict.dictLine[k++] = _predictiveDict.dictLine[j++];
|
||||
} else {
|
||||
_unitedDict.dictLine[k++] = _userDict.dictLine[i++];
|
||||
}
|
||||
}
|
||||
|
||||
while (i < _userDict.dictLineCount) {
|
||||
_unitedDict.dictLine[k++] = _userDict.dictLine[i++];
|
||||
}
|
||||
|
||||
while (j < _predictiveDict.dictLineCount) {
|
||||
_unitedDict.dictLine[k++] = _predictiveDict.dictLine[j++];
|
||||
}
|
||||
}
|
||||
|
||||
uint8 PredictiveDialog::countWordsInString(char *str) {
|
||||
// Count the number of (space separated) words in the given string.
|
||||
char *ptr;
|
||||
|
||||
if (!str)
|
||||
return 0;
|
||||
|
||||
ptr = strchr(str, ' ');
|
||||
if (!ptr) {
|
||||
debug("Predictive Dialog: Invalid dictionary line");
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8 num = 1;
|
||||
ptr++;
|
||||
while ((ptr = strchr(ptr, ' '))) {
|
||||
ptr++;
|
||||
num++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
void PredictiveDialog::bringWordtoTop(char *str, int wordnum) {
|
||||
// This function reorders the words on the given pred.dic line
|
||||
// by moving the word at position 'wordnum' to the front (that is, right behind
|
||||
// right behind the numerical code word at the start of the line).
|
||||
Common::Array<Common::String> words;
|
||||
char buf[MAXLINELEN];
|
||||
|
||||
if (!str)
|
||||
return;
|
||||
strncpy(buf, str, MAXLINELEN);
|
||||
buf[MAXLINELEN - 1] = 0;
|
||||
char *word = strtok(buf, " ");
|
||||
if (!word) {
|
||||
debug("Predictive Dialog: Invalid dictionary line");
|
||||
return;
|
||||
}
|
||||
|
||||
words.push_back(word);
|
||||
while ((word = strtok(NULL, " ")) != NULL)
|
||||
words.push_back(word);
|
||||
words.insert_at(1, words.remove_at(wordnum + 1));
|
||||
|
||||
Common::String tmp;
|
||||
for (uint8 i = 0; i < words.size(); i++)
|
||||
tmp += words[i] + " ";
|
||||
tmp.deleteLastChar();
|
||||
memcpy(str, tmp.c_str(), strlen(str));
|
||||
}
|
||||
|
||||
int PredictiveDialog::binarySearch(char **dictLine, const String &code, int dictLineCount) {
|
||||
int hi = dictLineCount - 1;
|
||||
int lo = 0;
|
||||
int line = 0;
|
||||
while (lo <= hi) {
|
||||
line = (lo + hi) / 2;
|
||||
int cmpVal = strncmp(dictLine[line], code.c_str(), code.size());
|
||||
if (cmpVal > 0)
|
||||
hi = line - 1;
|
||||
else if (cmpVal < 0)
|
||||
lo = line + 1;
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (hi < lo) {
|
||||
return -(lo + 1);
|
||||
} else {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
bool PredictiveDialog::matchWord() {
|
||||
// If no text has been entered, then there is no match.
|
||||
if (_currentCode.empty())
|
||||
return false;
|
||||
|
||||
// If the currently entered text is too long, it cannot match anything.
|
||||
if (_currentCode.size() > MAXWORDLEN)
|
||||
return false;
|
||||
|
||||
// The entries in the dictionary consist of a code, a space, and then
|
||||
// a space-separated list of words matching this code.
|
||||
// To exactly match a code, we therefore match the code plus the trailing
|
||||
// space in the dictionary.
|
||||
Common::String code = _currentCode + " ";
|
||||
|
||||
int line = binarySearch(_unitedDict.dictLine, code, _unitedDict.dictLineCount);
|
||||
if (line < 0) {
|
||||
line = -(line + 1);
|
||||
_unitedDict.dictActLine = NULL;
|
||||
} else {
|
||||
_unitedDict.dictActLine = _unitedDict.dictLine[line];
|
||||
}
|
||||
|
||||
_currentWord.clear();
|
||||
_wordNumber = 0;
|
||||
if (0 == strncmp(_unitedDict.dictLine[line], _currentCode.c_str(), _currentCode.size())) {
|
||||
char tmp[MAXLINELEN];
|
||||
strncpy(tmp, _unitedDict.dictLine[line], MAXLINELEN);
|
||||
tmp[MAXLINELEN - 1] = 0;
|
||||
char *tok = strtok(tmp, " ");
|
||||
tok = strtok(NULL, " ");
|
||||
_currentWord = Common::String(tok, _currentCode.size());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool PredictiveDialog::searchWord(char *where, const String &whatCode) {
|
||||
char *ptr = where;
|
||||
ptr += whatCode.size();
|
||||
|
||||
char *newPtr;
|
||||
bool is = false;
|
||||
while((newPtr = strchr(ptr, ' '))) {
|
||||
if (0 == strncmp(ptr, _currentWord.c_str(), newPtr - ptr)) {
|
||||
is = true;
|
||||
break;
|
||||
}
|
||||
ptr = newPtr + 1;
|
||||
}
|
||||
if (!is) {
|
||||
if (0 == strcmp(ptr, _currentWord.c_str())) {
|
||||
is = true;
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
void PredictiveDialog::addWord(Dict &dict, const String &word, const String &code) {
|
||||
char *newLine;
|
||||
Common::String tmpCode = code + ' ';
|
||||
int line = binarySearch(dict.dictLine, tmpCode, dict.dictLineCount);
|
||||
if (line >= 0) {
|
||||
if (searchWord(dict.dictLine[line], tmpCode)) {
|
||||
// if we found code and word, we should not insert/expands any word
|
||||
return;
|
||||
} else {
|
||||
// if we found the code, but did not find a word, we must
|
||||
// EXPANDS the currnent line with new word
|
||||
int oldLineSize = strlen(dict.dictLine[line]);
|
||||
int newLineSize = oldLineSize + word.size() + 1;
|
||||
|
||||
newLine = (char *)malloc(newLineSize + 1);
|
||||
|
||||
char *ptr = newLine;
|
||||
strncpy(ptr, dict.dictLine[line], oldLineSize);
|
||||
ptr += oldLineSize;
|
||||
Common::String tmp = ' ' + word + '\0';
|
||||
strncpy(ptr, tmp.c_str(), tmp.size());
|
||||
|
||||
dict.dictLine[line] = newLine;
|
||||
_memoryList[_numMemory++] = newLine;
|
||||
|
||||
if (dict.nameDict == "user_dictionary")
|
||||
_userDictHasChanged = true;
|
||||
|
||||
return;
|
||||
}
|
||||
} else { // if we didn't find the code, we need to INSERT new line with code and word
|
||||
if (dict.nameDict == "user_dictionary") {
|
||||
// if we must INSERT new line(code and word) to user_dictionary, we need to
|
||||
// check if there is a line that we want to INSERT in predictive dictionay
|
||||
int predictLine = binarySearch(_predictiveDict.dictLine, tmpCode, _predictiveDict.dictLineCount);
|
||||
if (predictLine >= 0) {
|
||||
if (searchWord(_predictiveDict.dictLine[predictLine], tmpCode)) {
|
||||
// if code and word is in predictive dictionary, we need to copy
|
||||
// this line to user dictionary
|
||||
int len = (predictLine == _predictiveDict.dictLineCount - 1) ? &_predictiveDict.dictText[_predictiveDict.dictTextSize] - _predictiveDict.dictLine[predictLine] :
|
||||
_predictiveDict.dictLine[predictLine + 1] - _predictiveDict.dictLine[predictLine];
|
||||
newLine = (char *)malloc(len);
|
||||
strncpy(newLine, _predictiveDict.dictLine[predictLine], len);
|
||||
} else {
|
||||
// if there is no word in predictive dictionary, we need to copy to
|
||||
// user dictionary mathed line + new word.
|
||||
int len = (predictLine == _predictiveDict.dictLineCount - 1) ? &_predictiveDict.dictText[_predictiveDict.dictTextSize] - _predictiveDict.dictLine[predictLine] :
|
||||
_predictiveDict.dictLine[predictLine + 1] - _predictiveDict.dictLine[predictLine];
|
||||
newLine = (char *)malloc(len + word.size() + 1);
|
||||
char *ptr = newLine;
|
||||
strncpy(ptr, _predictiveDict.dictLine[predictLine], len);
|
||||
ptr[len - 1] = ' ';
|
||||
ptr += len;
|
||||
strncpy(ptr, word.c_str(), word.size());
|
||||
ptr[len + word.size()] = '\0';
|
||||
}
|
||||
} else {
|
||||
// if we didnt find line in predictive dialog, we should copy to user dictionary
|
||||
// code + word
|
||||
Common::String tmp;
|
||||
tmp = tmpCode + word + '\0';
|
||||
newLine = (char *)malloc(tmp.size());
|
||||
strncpy(newLine, tmp.c_str(), tmp.size());
|
||||
}
|
||||
} else {
|
||||
// if want to insert line to different from user dictionary, we should copy to this
|
||||
// dictionary code + word
|
||||
Common::String tmp;
|
||||
tmp = tmpCode + word + '\0';
|
||||
newLine = (char *)malloc(tmp.size());
|
||||
strncpy(newLine, tmp.c_str(), tmp.size());
|
||||
}
|
||||
}
|
||||
|
||||
// start from here are INSERTING new line to dictionaty ( dict )
|
||||
char **newDictLine = (char **)calloc(1, sizeof(char *) * (dict.dictLineCount + 1));
|
||||
if (!newDictLine) {
|
||||
warning("Predictive Dialog: cannot allocate memory for index buffer");
|
||||
return;
|
||||
}
|
||||
newDictLine[dict.dictLineCount] = '\0';
|
||||
|
||||
int k = 0;
|
||||
bool inserted = false;
|
||||
for (int i = 0; i < dict.dictLineCount; i++) {
|
||||
uint lenPredictiveDictCode = strchr(dict.dictLine[i], ' ') - dict.dictLine[i];
|
||||
uint lenCode = (lenPredictiveDictCode >= (code.size() - 1)) ? lenPredictiveDictCode : code.size() - 1;
|
||||
if ((strncmp(dict.dictLine[i], code.c_str(), lenCode) > 0) && !inserted) {
|
||||
newDictLine[k++] = newLine;
|
||||
inserted = true;
|
||||
}
|
||||
if (k != (dict.dictLineCount + 1)) {
|
||||
newDictLine[k++] = dict.dictLine[i];
|
||||
}
|
||||
}
|
||||
if (!inserted)
|
||||
newDictLine[k] = newLine;
|
||||
|
||||
_memoryList[_numMemory++] = newLine;
|
||||
|
||||
free(dict.dictLine);
|
||||
dict.dictLineCount += 1;
|
||||
dict.dictLine = (char **)calloc(1, sizeof(char *) * dict.dictLineCount);
|
||||
if (!dict.dictLine) {
|
||||
warning("Predictive Dialog: cannot allocate memory for index buffer");
|
||||
free(newDictLine);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < dict.dictLineCount; i++) {
|
||||
dict.dictLine[i] = newDictLine[i];
|
||||
}
|
||||
|
||||
if (dict.nameDict == "user_dictionary")
|
||||
_userDictHasChanged = true;
|
||||
|
||||
free(newDictLine);
|
||||
}
|
||||
|
||||
void PredictiveDialog::addWordToDict() {
|
||||
if (_numMemory < MAXWORD) {
|
||||
addWord(_unitedDict, _currentWord, _currentCode);
|
||||
addWord(_userDict, _currentWord, _currentCode);
|
||||
} else {
|
||||
warning("Predictive Dialog: You cannot add word to user dictionary...");
|
||||
}
|
||||
}
|
||||
|
||||
void PredictiveDialog::loadDictionary(Common::SeekableReadStream *in, Dict &dict) {
|
||||
int lines = 0;
|
||||
|
||||
uint32 time1 = g_system->getMillis();
|
||||
|
||||
dict.dictTextSize = in->size();
|
||||
dict.dictText = (char *)malloc(dict.dictTextSize + 1);
|
||||
|
||||
if (!dict.dictText) {
|
||||
warning("Predictive Dialog: Not enough memory to load the file user.dic");
|
||||
return;
|
||||
}
|
||||
|
||||
in->read(dict.dictText, dict.dictTextSize);
|
||||
dict.dictText[dict.dictTextSize] = 0;
|
||||
uint32 time2 = g_system->getMillis();
|
||||
debug("Predictive Dialog: Time to read %s: %d bytes, %d ms", ConfMan.get(dict.nameDict).c_str(), dict.dictTextSize, time2-time1);
|
||||
delete in;
|
||||
|
||||
char *ptr = dict.dictText;
|
||||
lines = 1;
|
||||
while ((ptr = strchr(ptr, '\n'))) {
|
||||
lines++;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
dict.dictLine = (char **)calloc(1, sizeof(char *) * lines);
|
||||
if (dict.dictLine == NULL) {
|
||||
warning("Predictive Dialog: Cannot allocate memory for line index buffer");
|
||||
return;
|
||||
}
|
||||
dict.dictLine[0] = dict.dictText;
|
||||
ptr = dict.dictText;
|
||||
int i = 1;
|
||||
while ((ptr = strchr(ptr, '\n'))) {
|
||||
*ptr = 0;
|
||||
ptr++;
|
||||
#ifdef __DS__
|
||||
// Pass the line on to the DS word list
|
||||
DS::addAutoCompleteLine(dict.dictLine[i - 1]);
|
||||
#endif
|
||||
dict.dictLine[i++] = ptr;
|
||||
}
|
||||
if (dict.dictLine[lines - 1][0] == 0)
|
||||
lines--;
|
||||
|
||||
dict.dictLineCount = lines;
|
||||
debug("Predictive Dialog: Loaded %d lines", dict.dictLineCount);
|
||||
|
||||
// FIXME: We use binary search on _predictiveDict.dictLine, yet we make no at_tempt
|
||||
// to ever sort this array (except for the DS port). That seems risky, doesn't it?
|
||||
|
||||
#ifdef __DS__
|
||||
// Sort the DS word completion list, to allow for a binary chop later (in the ds backend)
|
||||
DS::sortAutoCompleteWordList();
|
||||
#endif
|
||||
|
||||
uint32 time3 = g_system->getMillis();
|
||||
debug("Predictive Dialog: Time to parse %s: %d, total: %d", ConfMan.get(dict.nameDict).c_str(), time3-time2, time3-time1);
|
||||
}
|
||||
|
||||
void PredictiveDialog::loadAllDictionary(Dict &dict) {
|
||||
ConfMan.registerDefault(dict.nameDict, dict.fnameDict);
|
||||
|
||||
if (dict.nameDict == "predictive_dictionary") {
|
||||
Common::File *inFile = new File();
|
||||
if (!inFile->open(ConfMan.get(dict.nameDict))) {
|
||||
warning("Predictive Dialog: cannot read file: %s", dict.fnameDict.c_str());
|
||||
return;
|
||||
}
|
||||
loadDictionary(inFile, dict);
|
||||
} else {
|
||||
Common::InSaveFile *inFile = g_system->getSavefileManager()->openForLoading(ConfMan.get(dict.nameDict));
|
||||
if (!inFile) {
|
||||
warning("Predictive Dialog: cannot read file: %s", dict.fnameDict.c_str());
|
||||
return;
|
||||
}
|
||||
loadDictionary(inFile, dict);
|
||||
}
|
||||
}
|
||||
|
||||
void PredictiveDialog::pressEditText() {
|
||||
Common::strlcpy(_predictiveResult, _prefix.c_str(), sizeof(_predictiveResult));
|
||||
Common::strlcat(_predictiveResult, _currentWord.c_str(), sizeof(_predictiveResult));
|
||||
_edittext->setEditString(_predictiveResult);
|
||||
//_edittext->setCaretPos(_prefix.size() + _currentWord.size());
|
||||
_edittext->draw();
|
||||
}
|
||||
|
||||
} // namespace GUI
|
142
gui/predictivedialog.h
Normal file
142
gui/predictivedialog.h
Normal file
@ -0,0 +1,142 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef GLOBAL_DIALOGS_H
|
||||
#define GLOBAL_DIALOGS_H
|
||||
|
||||
#include "gui/dialog.h"
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class EditTextWidget;
|
||||
class ButtonWidget;
|
||||
class PicButtonWidget;
|
||||
|
||||
enum ButtonId {
|
||||
kBtn1Act = 0,
|
||||
kBtn2Act = 1,
|
||||
kBtn3Act = 2,
|
||||
kBtn4Act = 3,
|
||||
kBtn5Act = 4,
|
||||
kBtn6Act = 5,
|
||||
kBtn7Act = 6,
|
||||
kBtn8Act = 7,
|
||||
kBtn9Act = 8,
|
||||
kNextAct = 9,
|
||||
kAddAct = 10,
|
||||
kDelAct = 11,
|
||||
kCancelAct = 12,
|
||||
kOkAct = 13,
|
||||
kModeAct = 14,
|
||||
kBtn0Act = 15,
|
||||
kNoAct = -1
|
||||
};
|
||||
|
||||
enum {
|
||||
kRepeatDelay = 500
|
||||
};
|
||||
|
||||
enum {
|
||||
MAXLINELEN = 80,
|
||||
MAXWORDLEN = 24,
|
||||
MAXWORD = 50
|
||||
};
|
||||
|
||||
class PredictiveDialog : public GUI::Dialog {
|
||||
typedef Common::String String;
|
||||
|
||||
public:
|
||||
PredictiveDialog();
|
||||
~PredictiveDialog();
|
||||
|
||||
virtual void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data);
|
||||
virtual void handleKeyDown(Common::KeyState state);
|
||||
virtual void handleTickle();
|
||||
|
||||
char * getResult() { return _predictiveResult; }
|
||||
private:
|
||||
struct Dict {
|
||||
char **dictLine;
|
||||
char *dictText;
|
||||
char *dictActLine; // using only for united dict...
|
||||
int32 dictLineCount;
|
||||
int32 dictTextSize;
|
||||
String nameDict;
|
||||
String fnameDict;
|
||||
};
|
||||
|
||||
uint8 countWordsInString(char *str);
|
||||
void bringWordtoTop(char *str, int wordnum);
|
||||
void loadDictionary(Common::SeekableReadStream *in, Dict &dict);
|
||||
void loadAllDictionary(Dict &dict);
|
||||
void addWordToDict();
|
||||
void addWord(Dict &dict, const String &word, const String &code);
|
||||
bool searchWord(char *where, const String &whatCode);
|
||||
int binarySearch(char **dictLine, const String &code, int dictLineCount);
|
||||
bool matchWord();
|
||||
void processBtnActive(ButtonId active);
|
||||
void pressEditText();
|
||||
|
||||
void saveUserDictToFile();
|
||||
|
||||
void mergeDicts();
|
||||
private:
|
||||
Dict _unitedDict;
|
||||
Dict _predictiveDict;
|
||||
Dict _userDict;
|
||||
|
||||
int _mode;
|
||||
ButtonId _lastbutton;
|
||||
|
||||
bool _userDictHasChanged;
|
||||
|
||||
int _wordNumber;
|
||||
uint8 _numMatchingWords;
|
||||
char _predictiveResult[40];
|
||||
|
||||
String _currentCode;
|
||||
String _currentWord;
|
||||
String _prefix;
|
||||
|
||||
uint32 _curTime, _lastTime;
|
||||
ButtonId _lastPressBtn;
|
||||
|
||||
char _temp[MAXWORDLEN + 1];
|
||||
int _repeatcount[MAXWORDLEN];
|
||||
|
||||
char *_memoryList[MAXWORD];
|
||||
int _numMemory;
|
||||
|
||||
String _search;
|
||||
|
||||
bool _navigationwithkeys;
|
||||
private:
|
||||
EditTextWidget *_edittext;
|
||||
ButtonWidget *_modebutton;
|
||||
ButtonWidget *_delbtn;
|
||||
ButtonWidget *_addBtn;
|
||||
};
|
||||
|
||||
} // namespace GUI
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -1 +1 @@
|
||||
[SCUMMVM_STX0.8.8:ResidualVM Modern Theme:No Author]
|
||||
[SCUMMVM_STX0.8.10:ResidualVM Modern Theme:No Author]
|
||||
|
BIN
gui/themes/modern/delbtn.bmp
Normal file
BIN
gui/themes/modern/delbtn.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 822 B |
@ -100,6 +100,7 @@
|
||||
<bitmap filename = 'logo_small.bmp'/>
|
||||
<bitmap filename = 'search.bmp'/>
|
||||
<bitmap filename = 'eraser.bmp'/>
|
||||
<bitmap filename = 'delbtn.bmp'/>
|
||||
</bitmaps>
|
||||
|
||||
<fonts>
|
||||
|
@ -49,6 +49,8 @@
|
||||
<def var = 'Tooltip.XDelta' value = '16'/> <!-- basically cursor size -->
|
||||
<def var = 'Tooltip.YDelta' value = '32'/>
|
||||
|
||||
<def var = 'Predictive.Button.Width' value = '60' />
|
||||
|
||||
<widget name = 'OptionsLabel'
|
||||
size = '115, Globals.Line.Height'
|
||||
textalign = 'right'
|
||||
@ -59,8 +61,7 @@
|
||||
|
||||
<widget name = 'Button'
|
||||
size = '108, 24'
|
||||
/>
|
||||
|
||||
/>
|
||||
|
||||
<widget name = 'Slider'
|
||||
size = '128, 18'
|
||||
@ -642,6 +643,32 @@
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GameOptions_Engine' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
|
||||
<layout type = 'vertical' padding = '16, 16, 16, 16'>
|
||||
<widget name = 'customOption1Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption2Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption3Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption4Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption5Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption6Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption7Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
|
||||
<layout type = 'vertical' padding = '16, 16, 16, 16' center = 'true'>
|
||||
<widget name = 'Logo'
|
||||
@ -899,5 +926,99 @@
|
||||
type = 'Button'
|
||||
/>
|
||||
</layout>
|
||||
</dialog>
|
||||
<dialog name = 'Predictive' overlays = 'screen_center'>
|
||||
<layout type = 'vertical' padding = '5, 5, 5, 5' center = 'true'>
|
||||
<widget name = 'Headline'
|
||||
height = 'Globals.Line.Height'
|
||||
width = '210'
|
||||
textalign = 'center'
|
||||
/>
|
||||
|
||||
<layout type = 'horizontal' padding = '5, 5, 5, 5'>
|
||||
<widget name = 'Word'
|
||||
width = '190'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Delete'
|
||||
width = '20'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<space size = '5' />
|
||||
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
|
||||
<widget name = 'Button1'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button2'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button3'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
|
||||
<widget name = 'Button4'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button5'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button6'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
|
||||
<widget name = 'Button7'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button8'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button9'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
|
||||
<widget name = 'Pre'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button0'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Next'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<space size = '5' />
|
||||
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
|
||||
<widget name = 'Add'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<space size = '22'/>
|
||||
<widget name = 'Cancel'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'OK'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
</layout_info>
|
||||
|
@ -33,6 +33,9 @@
|
||||
|
||||
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/>
|
||||
|
||||
<def var = 'Predictive.Button.Width' value = '45' />
|
||||
<def var = 'Predictive.Button.Height' value = '15' />
|
||||
|
||||
<widget name = 'Button'
|
||||
size = '72, 16'
|
||||
/>
|
||||
@ -637,6 +640,32 @@
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GameOptions_Engine' overlays = 'Dialog.GameOptions.TabWidget' shading = 'dim'>
|
||||
<layout type = 'vertical' padding = '8, 8, 8, 8'>
|
||||
<widget name = 'customOption1Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption2Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption3Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption4Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption5Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption6Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
<widget name = 'customOption7Checkbox'
|
||||
type = 'Checkbox'
|
||||
/>
|
||||
</layout>
|
||||
</dialog>
|
||||
|
||||
<dialog name = 'GlobalMenu' overlays = 'screen_center'>
|
||||
<layout type = 'vertical' padding = '4, 4, 4, 4' center = 'true' spacing='2'>
|
||||
<widget name = 'Title'
|
||||
@ -885,4 +914,96 @@
|
||||
/>
|
||||
</layout>
|
||||
</dialog>
|
||||
<dialog name = 'Predictive' overlays = 'screen_center'>
|
||||
<layout type = 'vertical' center = 'true'>
|
||||
<widget name = 'Headline'
|
||||
height = 'Globals.Line.Height'
|
||||
width = '150'
|
||||
textalign = 'center'
|
||||
/>
|
||||
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
|
||||
<widget name = 'Word'
|
||||
width = '120'
|
||||
height = 'Globals.Button.Height'
|
||||
/>
|
||||
<widget name = 'Delete'
|
||||
width = '20'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<!-- <space size = '3' /> -->
|
||||
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
|
||||
<widget name = 'Button1'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button2'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button3'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
|
||||
<widget name = 'Button4'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button5'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button6'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
|
||||
<widget name = 'Button7'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button8'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button9'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
|
||||
<widget name = 'Pre'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Button0'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'Next'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
<space size = '2' />
|
||||
<layout type = 'horizontal' padding = '0, 0, 2, 2'>
|
||||
<widget name = 'Add'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<!-- <space size = '22'/> -->
|
||||
<widget name = 'Cancel'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
<widget name = 'OK'
|
||||
width = 'Globals.Predictive.Button.Width'
|
||||
height = 'Globals.Predictive.Button.Height'
|
||||
/>
|
||||
</layout>
|
||||
</layout>
|
||||
</dialog>
|
||||
</layout_info>
|
||||
|
@ -70,18 +70,17 @@ public:
|
||||
|
||||
virtual void handleTickle();
|
||||
virtual bool handleKeyDown(Common::KeyState state);
|
||||
|
||||
virtual void reflowLayout();
|
||||
|
||||
bool setCaretPos(int newPos);
|
||||
|
||||
protected:
|
||||
virtual void startEditMode() = 0;
|
||||
virtual void endEditMode() = 0;
|
||||
virtual void abortEditMode() = 0;
|
||||
|
||||
virtual void abortEditMode() = 0;
|
||||
virtual Common::Rect getEditRect() const = 0;
|
||||
virtual int getCaretOffset() const;
|
||||
void drawCaret(bool erase);
|
||||
bool setCaretPos(int newPos);
|
||||
void drawCaret(bool erase);
|
||||
bool adjustOffset();
|
||||
void makeCaretVisible();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user