GUI: Move predictive dialog to common gui
This commit is contained in:
parent
3b57dc9164
commit
ec32ccb6d6
22 changed files with 2549 additions and 1503 deletions
|
@ -46,6 +46,8 @@
|
||||||
#include "agi/keyboard.h"
|
#include "agi/keyboard.h"
|
||||||
#include "agi/menu.h"
|
#include "agi/menu.h"
|
||||||
|
|
||||||
|
#include "gui/predictivedialog.h"
|
||||||
|
|
||||||
namespace Agi {
|
namespace Agi {
|
||||||
|
|
||||||
void AgiEngine::allowSynthetic(bool allow) {
|
void AgiEngine::allowSynthetic(bool allow) {
|
||||||
|
@ -58,9 +60,25 @@ void AgiEngine::processEvents() {
|
||||||
|
|
||||||
while (_eventMan->pollEvent(event)) {
|
while (_eventMan->pollEvent(event)) {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case Common::EVENT_PREDICTIVE_DIALOG:
|
case Common::EVENT_PREDICTIVE_DIALOG: {
|
||||||
if (_predictiveDialogRunning)
|
GUI::PredictiveDialog _predictiveDialog;
|
||||||
break;
|
_predictiveDialog.runModal();
|
||||||
|
strcpy(_predictiveResult, _predictiveDialog.getResult());
|
||||||
|
if (strcmp(_predictiveResult, "")) {
|
||||||
|
if (_game.inputMode == INPUT_NORMAL) {
|
||||||
|
strcpy((char *)_game.inputBuffer, _predictiveResult);
|
||||||
|
handleKeys(KEY_ENTER);
|
||||||
|
} else if (_game.inputMode == INPUT_GETSTRING) {
|
||||||
|
strcpy(_game.strings[_stringdata.str], _predictiveResult);
|
||||||
|
newInputMode(INPUT_NORMAL);
|
||||||
|
_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
|
||||||
|
_stringdata.y, ' ', _game.colorFg, _game.colorBg);
|
||||||
|
} else if (_game.inputMode == INPUT_NONE) {
|
||||||
|
for (int n = 0; _predictiveResult[n]; n++)
|
||||||
|
keyEnqueue(_predictiveResult[n]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
if (predictiveDialog()) {
|
if (predictiveDialog()) {
|
||||||
if (_game.inputMode == INPUT_NORMAL) {
|
if (_game.inputMode == INPUT_NORMAL) {
|
||||||
strcpy((char *)_game.inputBuffer, _predictiveResult);
|
strcpy((char *)_game.inputBuffer, _predictiveResult);
|
||||||
|
@ -75,6 +93,8 @@ void AgiEngine::processEvents() {
|
||||||
keyEnqueue(_predictiveResult[n]);
|
keyEnqueue(_predictiveResult[n]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case Common::EVENT_LBUTTONDOWN:
|
case Common::EVENT_LBUTTONDOWN:
|
||||||
key = BUTTON_LEFT;
|
key = BUTTON_LEFT;
|
||||||
|
@ -131,65 +151,46 @@ void AgiEngine::processEvents() {
|
||||||
switch (key = event.kbd.keycode) {
|
switch (key = event.kbd.keycode) {
|
||||||
case Common::KEYCODE_LEFT:
|
case Common::KEYCODE_LEFT:
|
||||||
case Common::KEYCODE_KP4:
|
case Common::KEYCODE_KP4:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP4)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_LEFT;
|
key = KEY_LEFT;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_RIGHT:
|
case Common::KEYCODE_RIGHT:
|
||||||
case Common::KEYCODE_KP6:
|
case Common::KEYCODE_KP6:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP6)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_RIGHT;
|
key = KEY_RIGHT;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_UP:
|
case Common::KEYCODE_UP:
|
||||||
case Common::KEYCODE_KP8:
|
case Common::KEYCODE_KP8:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP8)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_UP;
|
key = KEY_UP;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_DOWN:
|
case Common::KEYCODE_DOWN:
|
||||||
case Common::KEYCODE_KP2:
|
case Common::KEYCODE_KP2:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP2)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_DOWN;
|
key = KEY_DOWN;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_PAGEUP:
|
case Common::KEYCODE_PAGEUP:
|
||||||
case Common::KEYCODE_KP9:
|
case Common::KEYCODE_KP9:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP9)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_UP_RIGHT;
|
key = KEY_UP_RIGHT;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_PAGEDOWN:
|
case Common::KEYCODE_PAGEDOWN:
|
||||||
case Common::KEYCODE_KP3:
|
case Common::KEYCODE_KP3:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP3)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_DOWN_RIGHT;
|
key = KEY_DOWN_RIGHT;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_HOME:
|
case Common::KEYCODE_HOME:
|
||||||
case Common::KEYCODE_KP7:
|
case Common::KEYCODE_KP7:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP7)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_UP_LEFT;
|
key = KEY_UP_LEFT;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_END:
|
case Common::KEYCODE_END:
|
||||||
case Common::KEYCODE_KP1:
|
case Common::KEYCODE_KP1:
|
||||||
if (_predictiveDialogRunning && key == Common::KEYCODE_KP1)
|
if (_allowSynthetic || !event.synthetic)
|
||||||
key = event.kbd.ascii;
|
|
||||||
else if (_allowSynthetic || !event.synthetic)
|
|
||||||
key = KEY_DOWN_LEFT;
|
key = KEY_DOWN_LEFT;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_KP5:
|
case Common::KEYCODE_KP5:
|
||||||
if (_predictiveDialogRunning)
|
key = KEY_STATIONARY;
|
||||||
key = event.kbd.ascii;
|
|
||||||
else
|
|
||||||
key = KEY_STATIONARY;
|
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_PLUS:
|
case Common::KEYCODE_PLUS:
|
||||||
key = '+';
|
key = '+';
|
||||||
|
@ -218,7 +219,7 @@ void AgiEngine::processEvents() {
|
||||||
case Common::KEYCODE_F6:
|
case Common::KEYCODE_F6:
|
||||||
key = 0x4000;
|
key = 0x4000;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_F7:
|
case Common::KEYCODE_F7:
|
||||||
key = 0x4100;
|
key = 0x4100;
|
||||||
break;
|
break;
|
||||||
case Common::KEYCODE_F8:
|
case Common::KEYCODE_F8:
|
||||||
|
@ -575,10 +576,6 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
|
||||||
|
|
||||||
_oldMode = INPUT_NONE;
|
_oldMode = INPUT_NONE;
|
||||||
|
|
||||||
_predictiveDialogRunning = false;
|
|
||||||
_predictiveDictText = NULL;
|
|
||||||
_predictiveDictLine = NULL;
|
|
||||||
_predictiveDictLineCount = 0;
|
|
||||||
_firstSlot = 0;
|
_firstSlot = 0;
|
||||||
|
|
||||||
resetControllers();
|
resetControllers();
|
||||||
|
@ -684,9 +681,6 @@ AgiEngine::~AgiEngine() {
|
||||||
_gfx->deinitMachine();
|
_gfx->deinitMachine();
|
||||||
delete _gfx;
|
delete _gfx;
|
||||||
delete _console;
|
delete _console;
|
||||||
|
|
||||||
free(_predictiveDictLine);
|
|
||||||
free(_predictiveDictText);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::Error AgiBase::init() {
|
Common::Error AgiBase::init() {
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "agi/logic.h"
|
#include "agi/logic.h"
|
||||||
#include "agi/sound.h"
|
#include "agi/sound.h"
|
||||||
|
|
||||||
|
#include "gui/predictivedialog.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
class RandomSource;
|
class RandomSource;
|
||||||
|
@ -1078,7 +1079,6 @@ public:
|
||||||
void clearPrompt(bool useBlackBg = false);
|
void clearPrompt(bool useBlackBg = false);
|
||||||
void clearLines(int, int, int);
|
void clearLines(int, int, int);
|
||||||
void flushLines(int, int);
|
void flushLines(int, int);
|
||||||
bool predictiveDialog();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void printStatus(const char *message, ...) GCC_PRINTF(2, 3);
|
void printStatus(const char *message, ...) GCC_PRINTF(2, 3);
|
||||||
|
@ -1088,16 +1088,6 @@ private:
|
||||||
void loadDict();
|
void loadDict();
|
||||||
bool matchWord();
|
bool matchWord();
|
||||||
|
|
||||||
// Predictive dialog
|
|
||||||
// TODO: Move this to a separate class
|
|
||||||
char *_predictiveDictText;
|
|
||||||
char **_predictiveDictLine;
|
|
||||||
int32 _predictiveDictLineCount;
|
|
||||||
char *_predictiveDictActLine;
|
|
||||||
Common::String _currentCode;
|
|
||||||
Common::String _currentWord;
|
|
||||||
int _wordNumber;
|
|
||||||
bool _predictiveDialogRunning;
|
|
||||||
public:
|
public:
|
||||||
char _predictiveResult[40];
|
char _predictiveResult[40];
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,19 @@ int AgiEngine::handleController(int key) {
|
||||||
if (key == BUTTON_LEFT &&
|
if (key == BUTTON_LEFT &&
|
||||||
(int)_mouse.y >= _game.lineUserInput * CHAR_LINES &&
|
(int)_mouse.y >= _game.lineUserInput * CHAR_LINES &&
|
||||||
(int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) {
|
(int)_mouse.y <= (_game.lineUserInput + 1) * CHAR_LINES) {
|
||||||
|
GUI::PredictiveDialog _predictiveDialog;
|
||||||
|
_predictiveDialog.runModal();
|
||||||
|
strcpy(_predictiveResult, _predictiveDialog.getResult());
|
||||||
|
if (strcmp(_predictiveResult, "")) {
|
||||||
|
if (_game.inputMode == INPUT_NONE) {
|
||||||
|
for (int n = 0; _predictiveResult[n]; n++)
|
||||||
|
keyEnqueue(_predictiveResult[n]);
|
||||||
|
} else {
|
||||||
|
strcpy((char *)_game.inputBuffer, _predictiveResult);
|
||||||
|
handleKeys(KEY_ENTER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
if (predictiveDialog()) {
|
if (predictiveDialog()) {
|
||||||
if (_game.inputMode == INPUT_NONE) {
|
if (_game.inputMode == INPUT_NONE) {
|
||||||
for (int n = 0; _predictiveResult[n]; n++)
|
for (int n = 0; _predictiveResult[n]; n++)
|
||||||
|
@ -142,6 +155,7 @@ int AgiEngine::handleController(int key) {
|
||||||
handleKeys(KEY_ENTER);
|
handleKeys(KEY_ENTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,6 +231,17 @@ void AgiEngine::handleGetstring(int key) {
|
||||||
case BUTTON_LEFT:
|
case BUTTON_LEFT:
|
||||||
if ((int)_mouse.y >= _stringdata.y * CHAR_LINES &&
|
if ((int)_mouse.y >= _stringdata.y * CHAR_LINES &&
|
||||||
(int)_mouse.y <= (_stringdata.y + 1) * CHAR_LINES) {
|
(int)_mouse.y <= (_stringdata.y + 1) * CHAR_LINES) {
|
||||||
|
GUI::PredictiveDialog _predictiveDialog;
|
||||||
|
_predictiveDialog.runModal();
|
||||||
|
strcpy(_predictiveResult, _predictiveDialog.getResult());
|
||||||
|
if (strcmp(_predictiveResult, "")) {
|
||||||
|
strcpy(_game.strings[_stringdata.str], _predictiveResult);
|
||||||
|
newInputMode(INPUT_NORMAL);
|
||||||
|
_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1,
|
||||||
|
_stringdata.y, ' ', _game.colorFg, _game.colorBg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
if (predictiveDialog()) {
|
if (predictiveDialog()) {
|
||||||
strcpy(_game.strings[_stringdata.str], _predictiveResult);
|
strcpy(_game.strings[_stringdata.str], _predictiveResult);
|
||||||
newInputMode(INPUT_NORMAL);
|
newInputMode(INPUT_NORMAL);
|
||||||
|
@ -224,6 +249,7 @@ void AgiEngine::handleGetstring(int key) {
|
||||||
_stringdata.y, ' ', _game.colorFg, _game.colorBg);
|
_stringdata.y, ' ', _game.colorFg, _game.colorBg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case KEY_ENTER:
|
case KEY_ENTER:
|
||||||
|
|
|
@ -28,7 +28,6 @@ MODULE_OBJS := \
|
||||||
preagi_mickey.o \
|
preagi_mickey.o \
|
||||||
preagi_troll.o \
|
preagi_troll.o \
|
||||||
preagi_winnie.o \
|
preagi_winnie.o \
|
||||||
predictive.o \
|
|
||||||
saveload.o \
|
saveload.o \
|
||||||
sound.o \
|
sound.o \
|
||||||
sound_2gs.o \
|
sound_2gs.o \
|
||||||
|
|
|
@ -1,617 +0,0 @@
|
||||||
/* 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 "agi/agi.h"
|
|
||||||
#include "agi/graphics.h"
|
|
||||||
#include "agi/keyboard.h"
|
|
||||||
|
|
||||||
#include "common/config-manager.h"
|
|
||||||
#include "common/textconsole.h"
|
|
||||||
|
|
||||||
#ifdef __DS__
|
|
||||||
#include "wordcompletion.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Agi {
|
|
||||||
|
|
||||||
enum {
|
|
||||||
kModePre = 0,
|
|
||||||
kModeNum = 1,
|
|
||||||
kModeAbc = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
MAXLINELEN = 80,
|
|
||||||
MAXWORDLEN = 24
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8 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("Invalid dictionary line");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 num = 1;
|
|
||||||
ptr++;
|
|
||||||
while ((ptr = strchr(ptr, ' '))) {
|
|
||||||
ptr++;
|
|
||||||
num++;
|
|
||||||
}
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
void 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("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));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AgiEngine::predictiveDialog() {
|
|
||||||
uint8 x;
|
|
||||||
int y;
|
|
||||||
int bx[17], by[17];
|
|
||||||
Common::String prefix;
|
|
||||||
char temp[MAXWORDLEN + 1], repeatcount[MAXWORDLEN];
|
|
||||||
AgiBlock tmpwindow;
|
|
||||||
bool navigationwithkeys = false;
|
|
||||||
|
|
||||||
const char *buttonStr[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0" };
|
|
||||||
const char *buttons[] = {
|
|
||||||
"(1)'-.&", "(2)abc", "(3)def",
|
|
||||||
"(4)ghi", "(5)jkl", "(6)mno",
|
|
||||||
"(7)pqrs", "(8)tuv", "(9)wxyz",
|
|
||||||
"(#)next", "add",
|
|
||||||
"<",
|
|
||||||
"Cancel", "OK",
|
|
||||||
"(*)Pre", "(0) ", NULL
|
|
||||||
};
|
|
||||||
const int colors[] = {
|
|
||||||
15, 0, 15, 0, 15, 0,
|
|
||||||
15, 0, 15, 0, 15, 0,
|
|
||||||
15, 0, 15, 0, 15, 0,
|
|
||||||
15, 12, 15, 12,
|
|
||||||
15, 0,
|
|
||||||
15, 0, 15, 0,
|
|
||||||
14, 0, 15, 0, 0, 0
|
|
||||||
};
|
|
||||||
const char *modes[] = { "(*)Pre", "(*)123", "(*)Abc" };
|
|
||||||
|
|
||||||
// FIXME: Move this to a more appropriate place.
|
|
||||||
if (!_predictiveDictText) {
|
|
||||||
loadDict();
|
|
||||||
if (!_predictiveDictText)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_predictiveDictActLine = NULL;
|
|
||||||
uint8 numMatchingWords = 0;
|
|
||||||
|
|
||||||
_predictiveDialogRunning = true;
|
|
||||||
_system->setFeatureState(OSystem::kFeatureDisableKeyFiltering, true);
|
|
||||||
|
|
||||||
memset(repeatcount, 0, sizeof(repeatcount));
|
|
||||||
|
|
||||||
// show the predictive dialog.
|
|
||||||
// if another window is already in display, save its state into tmpwindow
|
|
||||||
memset(&tmpwindow, 0, sizeof(tmpwindow));
|
|
||||||
tmpwindow.active = false;
|
|
||||||
if (_game.window.active)
|
|
||||||
memcpy(&tmpwindow, &(_game.window), sizeof(AgiBlock));
|
|
||||||
drawWindow(50, 40, 269, 159);
|
|
||||||
_gfx->drawRectangle(62, 54, 249, 66, MSG_BOX_TEXT);
|
|
||||||
_gfx->flushBlock(62, 54, 249, 66);
|
|
||||||
|
|
||||||
bx[15] = 73; // Zero/space
|
|
||||||
by[15] = 120;
|
|
||||||
bx[9] = 110; // next
|
|
||||||
by[9] = 120;
|
|
||||||
bx[10] = 172; // add
|
|
||||||
by[10] = 120;
|
|
||||||
bx[14] = 200; // Mode
|
|
||||||
by[14] = 120;
|
|
||||||
bx[11] = 252; // Backspace
|
|
||||||
by[11] = 57;
|
|
||||||
bx[12] = 180; // Cancel
|
|
||||||
by[12] = 140;
|
|
||||||
bx[13] = 240; // OK
|
|
||||||
by[13] = 140;
|
|
||||||
|
|
||||||
x = 73;
|
|
||||||
y = 75;
|
|
||||||
for (int i = 0; i < 9; i++) {
|
|
||||||
bx[i] = x;
|
|
||||||
by[i] = y;
|
|
||||||
x += 60;
|
|
||||||
if (i % 3 == 2) {
|
|
||||||
y += 15;
|
|
||||||
x = 73;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
clearKeyQueue();
|
|
||||||
|
|
||||||
prefix.clear();
|
|
||||||
_currentCode.clear();
|
|
||||||
_currentWord.clear();
|
|
||||||
_wordNumber = 0;
|
|
||||||
|
|
||||||
int mode = kModePre;
|
|
||||||
|
|
||||||
bool needRefresh = true;
|
|
||||||
int active = -1, lastactive = 0;
|
|
||||||
bool rc = false;
|
|
||||||
bool closeDialog = false;
|
|
||||||
bool enterPredictiveResult = false;
|
|
||||||
while (!closeDialog && !shouldQuit()) {
|
|
||||||
if (needRefresh) {
|
|
||||||
for (int i = 0; buttons[i]; i++) {
|
|
||||||
int color1 = colors[i * 2];
|
|
||||||
int color2 = colors[i * 2 + 1];
|
|
||||||
|
|
||||||
if (i == 9 && !((mode != kModeAbc && _predictiveDictActLine && numMatchingWords > 1)
|
|
||||||
|| (mode == kModeAbc && _currentWord.size() && _currentWord.lastChar() != ' '))) { // Next
|
|
||||||
color2 = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
// needs fixing, or remove it!
|
|
||||||
bool _addIsActive = false; // FIXME: word adding is not implemented
|
|
||||||
if (i == 10 && !_addIsActive) { // Add
|
|
||||||
color2 = 7;
|
|
||||||
}
|
|
||||||
if (i == 14) {
|
|
||||||
_gfx->drawDefaultStyleButton(bx[i], by[i], modes[mode], i == active, 0, color1, color2);
|
|
||||||
} else {
|
|
||||||
_gfx->drawDefaultStyleButton(bx[i], by[i], buttons[i], i == active, 0, color1, color2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Common::strlcpy(temp, prefix.c_str(), sizeof(temp));
|
|
||||||
Common::strlcat(temp, _currentWord.c_str(), sizeof(temp));
|
|
||||||
|
|
||||||
for (int i = prefix.size() + _currentCode.size(); i < MAXWORDLEN; i++)
|
|
||||||
temp[i] = ' ';
|
|
||||||
temp[MAXWORDLEN] = 0;
|
|
||||||
|
|
||||||
printText(temp, 0, 8, 7, MAXWORDLEN, 15, 0);
|
|
||||||
_gfx->flushBlock(62, 54, 249, 66);
|
|
||||||
|
|
||||||
if (active >= 0 && !navigationwithkeys) {
|
|
||||||
// provide visual feedback only when not navigating with the arrows
|
|
||||||
// so that the user can see the active button.
|
|
||||||
active = -1;
|
|
||||||
needRefresh = true;
|
|
||||||
} else
|
|
||||||
needRefresh = false;
|
|
||||||
|
|
||||||
_gfx->doUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool processkey = false;
|
|
||||||
|
|
||||||
pollTimer();
|
|
||||||
int key = doPollKeyboard();
|
|
||||||
switch (key) {
|
|
||||||
case KEY_ENTER:
|
|
||||||
if (navigationwithkeys) {
|
|
||||||
// when the user has utilized arrow key navigation,
|
|
||||||
// interpret enter as 'click' on the active button
|
|
||||||
active = lastactive;
|
|
||||||
} else {
|
|
||||||
// else it is a shortcut for 'Ok'
|
|
||||||
active = 13;
|
|
||||||
}
|
|
||||||
processkey = true;
|
|
||||||
break;
|
|
||||||
case KEY_ESCAPE:
|
|
||||||
rc = false;
|
|
||||||
closeDialog = true;
|
|
||||||
break;
|
|
||||||
case BUTTON_LEFT:
|
|
||||||
navigationwithkeys = false;
|
|
||||||
for (int i = 0; buttons[i]; i++) {
|
|
||||||
if (_gfx->testButton(bx[i], by[i], buttons[i])) {
|
|
||||||
active = i;
|
|
||||||
processkey = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case KEY_BACKSPACE:
|
|
||||||
active = 11;
|
|
||||||
processkey = true;
|
|
||||||
break;
|
|
||||||
case '#':
|
|
||||||
active = 9;
|
|
||||||
processkey = true;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
active = 14;
|
|
||||||
processkey = true;
|
|
||||||
break;
|
|
||||||
case 0x09: // Tab
|
|
||||||
navigationwithkeys = true;
|
|
||||||
debugC(3, kDebugLevelText, "Focus change");
|
|
||||||
lastactive = active = lastactive + 1;
|
|
||||||
active %= ARRAYSIZE(buttons) - 1;
|
|
||||||
needRefresh = true;
|
|
||||||
break;
|
|
||||||
case KEY_LEFT:
|
|
||||||
navigationwithkeys = true;
|
|
||||||
if (lastactive == 0 || lastactive == 3 || lastactive == 6)
|
|
||||||
active = lastactive + 2;
|
|
||||||
else if (lastactive == 9)
|
|
||||||
active = 15;
|
|
||||||
else if (lastactive == 11)
|
|
||||||
active = 11;
|
|
||||||
else if (lastactive == 12)
|
|
||||||
active = 13;
|
|
||||||
else if (lastactive == 14)
|
|
||||||
active = 10;
|
|
||||||
else
|
|
||||||
active = lastactive - 1;
|
|
||||||
lastactive = active;
|
|
||||||
needRefresh = true;
|
|
||||||
break;
|
|
||||||
case KEY_RIGHT:
|
|
||||||
navigationwithkeys = true;
|
|
||||||
if (lastactive == 2 || lastactive == 5 || lastactive == 8)
|
|
||||||
active = lastactive - 2;
|
|
||||||
else if (lastactive == 10)
|
|
||||||
active = 14;
|
|
||||||
else if (lastactive == 11)
|
|
||||||
active = 11;
|
|
||||||
else if (lastactive == 13)
|
|
||||||
active = 12;
|
|
||||||
else if (lastactive == 15)
|
|
||||||
active = 9;
|
|
||||||
else
|
|
||||||
active = lastactive + 1;
|
|
||||||
lastactive = active;
|
|
||||||
needRefresh = true;
|
|
||||||
break;
|
|
||||||
case KEY_UP:
|
|
||||||
navigationwithkeys = true;
|
|
||||||
if (lastactive <= 2)
|
|
||||||
active = 11;
|
|
||||||
else if (lastactive == 9 || lastactive == 10)
|
|
||||||
active = lastactive - 2;
|
|
||||||
else if (lastactive == 11)
|
|
||||||
active = 13;
|
|
||||||
else if (lastactive == 14)
|
|
||||||
active = 8;
|
|
||||||
else if (lastactive == 15)
|
|
||||||
active = 6;
|
|
||||||
else
|
|
||||||
active = lastactive - 3;
|
|
||||||
lastactive = active;
|
|
||||||
needRefresh = true;
|
|
||||||
break;
|
|
||||||
case KEY_DOWN:
|
|
||||||
navigationwithkeys = true;
|
|
||||||
if (lastactive == 6)
|
|
||||||
active = 15;
|
|
||||||
else if (lastactive == 7 || lastactive == 8)
|
|
||||||
active = lastactive + 2;
|
|
||||||
else if (lastactive == 11)
|
|
||||||
active = 0;
|
|
||||||
else if (lastactive == 12 || lastactive == 13)
|
|
||||||
active = 11;
|
|
||||||
else if (lastactive == 14 || lastactive == 15)
|
|
||||||
active = lastactive - 2;
|
|
||||||
else
|
|
||||||
active = lastactive + 3;
|
|
||||||
lastactive = active;
|
|
||||||
needRefresh = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// handle numeric buttons
|
|
||||||
if (key >= '1' && key <= '9') {
|
|
||||||
active = key - '1';
|
|
||||||
processkey = true;
|
|
||||||
} else if (key == '0') {
|
|
||||||
active = 15;
|
|
||||||
processkey = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (processkey && !closeDialog) {
|
|
||||||
if (active >= 0) {
|
|
||||||
needRefresh = true;
|
|
||||||
lastactive = active;
|
|
||||||
if (active == 15 && mode != kModeNum) { // Space
|
|
||||||
// bring MRU word at the top of the list when changing words
|
|
||||||
if (mode == kModePre && _predictiveDictActLine && numMatchingWords > 1 && _wordNumber != 0)
|
|
||||||
bringWordtoTop(_predictiveDictActLine, _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));
|
|
||||||
} else if (active < 9 || active == 11 || active == 15) { // number or backspace
|
|
||||||
if (active == 11) { // backspace
|
|
||||||
if (_currentCode.size()) {
|
|
||||||
repeatcount[_currentCode.size() - 1] = 0;
|
|
||||||
_currentCode.deleteLastChar();
|
|
||||||
} else {
|
|
||||||
if (prefix.size())
|
|
||||||
prefix.deleteLastChar();
|
|
||||||
}
|
|
||||||
} else if (prefix.size() + _currentCode.size() < MAXWORDLEN - 1) { // don't overflow the dialog line
|
|
||||||
if (active == 15) { // zero
|
|
||||||
_currentCode += buttonStr[9];
|
|
||||||
} else {
|
|
||||||
_currentCode += buttonStr[active];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (mode) {
|
|
||||||
case kModeNum:
|
|
||||||
_currentWord = _currentCode;
|
|
||||||
break;
|
|
||||||
case kModePre:
|
|
||||||
if (!matchWord() && _currentCode.size()) {
|
|
||||||
_currentCode.deleteLastChar();
|
|
||||||
matchWord();
|
|
||||||
}
|
|
||||||
numMatchingWords = countWordsInString(_predictiveDictActLine);
|
|
||||||
break;
|
|
||||||
case kModeAbc:
|
|
||||||
for (x = 0; x < _currentCode.size(); x++)
|
|
||||||
if (_currentCode[x] >= '1')
|
|
||||||
temp[x] = buttons[_currentCode[x] - '1'][3 + repeatcount[x]];
|
|
||||||
temp[_currentCode.size()] = 0;
|
|
||||||
_currentWord = temp;
|
|
||||||
}
|
|
||||||
} else if (active == 9) { // next
|
|
||||||
if (mode == kModePre) {
|
|
||||||
if (_predictiveDictActLine && numMatchingWords > 1) {
|
|
||||||
_wordNumber = (_wordNumber + 1) % numMatchingWords;
|
|
||||||
char tmp[MAXLINELEN];
|
|
||||||
strncpy(tmp, _predictiveDictActLine, 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'][3 + repeatcount[x - 1]], x-1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (active == 10) { // add
|
|
||||||
debug(0, "add");
|
|
||||||
} else if (active == 13) { // Ok
|
|
||||||
// bring MRU word at the top of the list when ok'ed out of the dialog
|
|
||||||
if (mode == kModePre && _predictiveDictActLine && numMatchingWords > 1 && _wordNumber != 0)
|
|
||||||
bringWordtoTop(_predictiveDictActLine, _wordNumber);
|
|
||||||
rc = true;
|
|
||||||
enterPredictiveResult = true;
|
|
||||||
closeDialog = true;
|
|
||||||
} else if (active == 14) { // Mode
|
|
||||||
mode++;
|
|
||||||
if (mode > kModeAbc)
|
|
||||||
mode = kModePre;
|
|
||||||
|
|
||||||
// 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));
|
|
||||||
_predictiveDictActLine = NULL;
|
|
||||||
} else {
|
|
||||||
enterPredictiveResult = true;
|
|
||||||
closeDialog = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enterPredictiveResult) {
|
|
||||||
Common::strlcpy(_predictiveResult, prefix.c_str(), sizeof(_predictiveResult));
|
|
||||||
Common::strlcat(_predictiveResult, _currentWord.c_str(), sizeof(_predictiveResult));
|
|
||||||
}
|
|
||||||
|
|
||||||
// if another window was shown, bring it up again
|
|
||||||
if (!tmpwindow.active)
|
|
||||||
closeWindow();
|
|
||||||
else {
|
|
||||||
_gfx->restoreBlock(_game.window.x1, _game.window.y1,
|
|
||||||
_game.window.x2, _game.window.y2, _game.window.buffer);
|
|
||||||
|
|
||||||
free(_game.window.buffer);
|
|
||||||
memcpy(&(_game.window), &tmpwindow, sizeof(AgiBlock));
|
|
||||||
_gfx->doUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
_system->setFeatureState(OSystem::kFeatureDisableKeyFiltering, false);
|
|
||||||
_predictiveDialogRunning = false;
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AgiEngine::loadDict() {
|
|
||||||
Common::File inFile;
|
|
||||||
int lines = 0;
|
|
||||||
|
|
||||||
ConfMan.registerDefault("predictive_dictionary", "pred.dic");
|
|
||||||
|
|
||||||
uint32 time1 = _system->getMillis();
|
|
||||||
Common::String inFileName(ConfMan.get("predictive_dictionary"));
|
|
||||||
if (!inFile.open(inFileName))
|
|
||||||
return;
|
|
||||||
|
|
||||||
char *ptr;
|
|
||||||
int size = inFile.size();
|
|
||||||
|
|
||||||
_predictiveDictText = (char *)malloc(size + 1);
|
|
||||||
if (!_predictiveDictText) {
|
|
||||||
warning("Not enough memory to load the predictive dictionary");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
inFile.read(_predictiveDictText, size);
|
|
||||||
_predictiveDictText[size] = 0;
|
|
||||||
uint32 time2 = _system->getMillis();
|
|
||||||
debug("Time to read %s: %d bytes, %d ms", inFileName.c_str(), size, time2-time1);
|
|
||||||
inFile.close();
|
|
||||||
|
|
||||||
ptr = _predictiveDictText;
|
|
||||||
lines = 1;
|
|
||||||
while ((ptr = strchr(ptr, '\n'))) {
|
|
||||||
lines++;
|
|
||||||
ptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_predictiveDictLine = (char **)calloc(1, sizeof(char *) * lines);
|
|
||||||
if (_predictiveDictLine == NULL) {
|
|
||||||
warning("Cannot allocate memory for line index buffer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_predictiveDictLine[0] = _predictiveDictText;
|
|
||||||
ptr = _predictiveDictText;
|
|
||||||
int i = 1;
|
|
||||||
while ((ptr = strchr(ptr, '\n'))) {
|
|
||||||
*ptr = 0;
|
|
||||||
ptr++;
|
|
||||||
#ifdef __DS__
|
|
||||||
// Pass the line on to the DS word list
|
|
||||||
DS::addAutoCompleteLine(_predictiveDictLine[i - 1]);
|
|
||||||
#endif
|
|
||||||
_predictiveDictLine[i++] = ptr;
|
|
||||||
}
|
|
||||||
if (_predictiveDictLine[lines - 1][0] == 0)
|
|
||||||
lines--;
|
|
||||||
|
|
||||||
_predictiveDictLineCount = lines;
|
|
||||||
debug("Loaded %d lines", _predictiveDictLineCount);
|
|
||||||
|
|
||||||
// FIXME: We use binary search on _predictiveDictLine, yet we make no attempt
|
|
||||||
// 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 = _system->getMillis();
|
|
||||||
debug("Time to parse pred.dic: %d, total: %d", time3-time2, time3-time1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AgiEngine::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 + " ";
|
|
||||||
|
|
||||||
// Perform a binary search on the dictionary.
|
|
||||||
int hi = _predictiveDictLineCount - 1;
|
|
||||||
int lo = 0;
|
|
||||||
int line = 0;
|
|
||||||
while (lo <= hi) {
|
|
||||||
line = (lo + hi) / 2;
|
|
||||||
int cmpVal = strncmp(_predictiveDictLine[line], code.c_str(), code.size());
|
|
||||||
if (cmpVal > 0)
|
|
||||||
hi = line - 1;
|
|
||||||
else if (cmpVal < 0)
|
|
||||||
lo = line + 1;
|
|
||||||
else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool partial = hi < lo;
|
|
||||||
if (partial) {
|
|
||||||
// Didn't find an exact match, but 'lo' now points to the first entry
|
|
||||||
// lexicographically greater than the current code, so that will
|
|
||||||
// be the first entry with the current code as a prefix, if it exists.
|
|
||||||
line = lo;
|
|
||||||
_predictiveDictActLine = NULL;
|
|
||||||
} else {
|
|
||||||
_predictiveDictActLine = _predictiveDictLine[line];
|
|
||||||
}
|
|
||||||
|
|
||||||
_currentWord.clear();
|
|
||||||
_wordNumber = 0;
|
|
||||||
if (0 == strncmp(_predictiveDictLine[line], _currentCode.c_str(), _currentCode.size())) {
|
|
||||||
char tmp[MAXLINELEN];
|
|
||||||
strncpy(tmp, _predictiveDictLine[line], MAXLINELEN);
|
|
||||||
tmp[MAXLINELEN - 1] = 0;
|
|
||||||
char *tok = strtok(tmp, " ");
|
|
||||||
tok = strtok(NULL, " ");
|
|
||||||
_currentWord = Common::String(tok, _currentCode.size());
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // End of namespace Agi
|
|
|
@ -47,6 +47,7 @@ const char * const ThemeEngine::kImageLogo = "logo.bmp";
|
||||||
const char * const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
|
const char * const ThemeEngine::kImageLogoSmall = "logo_small.bmp";
|
||||||
const char * const ThemeEngine::kImageSearch = "search.bmp";
|
const char * const ThemeEngine::kImageSearch = "search.bmp";
|
||||||
const char * const ThemeEngine::kImageEraser = "eraser.bmp";
|
const char * const ThemeEngine::kImageEraser = "eraser.bmp";
|
||||||
|
const char * const ThemeEngine::kImageDelbtn = "delbtn.bmp";
|
||||||
|
|
||||||
struct TextDrawData {
|
struct TextDrawData {
|
||||||
const Graphics::Font *_fontPtr;
|
const Graphics::Font *_fontPtr;
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
#include "graphics/pixelformat.h"
|
#include "graphics/pixelformat.h"
|
||||||
|
|
||||||
|
|
||||||
#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.9"
|
#define SCUMMVM_THEME_VERSION_STR "SCUMMVM_STX0.8.10"
|
||||||
|
|
||||||
class OSystem;
|
class OSystem;
|
||||||
|
|
||||||
|
@ -229,6 +229,7 @@ public:
|
||||||
static const char *const kImageLogoSmall; ///< ScummVM logo used in the GMM
|
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 kImageSearch; ///< Search tool image used in the launcher
|
||||||
static const char *const kImageEraser; ///< Clear input 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.
|
* Graphics mode enumeration.
|
||||||
|
|
|
@ -13,6 +13,7 @@ MODULE_OBJS := \
|
||||||
message.o \
|
message.o \
|
||||||
object.o \
|
object.o \
|
||||||
options.o \
|
options.o \
|
||||||
|
predictivedialog.o \
|
||||||
saveload.o \
|
saveload.o \
|
||||||
themebrowser.o \
|
themebrowser.o \
|
||||||
ThemeEngine.o \
|
ThemeEngine.o \
|
||||||
|
|
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.9:ScummVM Classic Theme:No Author]
|
[SCUMMVM_STX0.8.10:ScummVM Classic Theme:No Author]
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
<def var = 'Tooltip.XDelta' value = '16'/> <!-- basically cursor size -->
|
<def var = 'Tooltip.XDelta' value = '16'/> <!-- basically cursor size -->
|
||||||
<def var = 'Tooltip.YDelta' value = '16'/>
|
<def var = 'Tooltip.YDelta' value = '16'/>
|
||||||
|
|
||||||
|
<def var = 'Predictive.Button.Width' value = '60' />
|
||||||
|
|
||||||
<widget name = 'OptionsLabel'
|
<widget name = 'OptionsLabel'
|
||||||
size = '110, Globals.Line.Height'
|
size = '110, Globals.Line.Height'
|
||||||
textalign = 'right'
|
textalign = 'right'
|
||||||
|
@ -911,4 +913,98 @@
|
||||||
/>
|
/>
|
||||||
</layout>
|
</layout>
|
||||||
</dialog>
|
</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>
|
</layout_info>
|
||||||
|
|
|
@ -43,6 +43,9 @@
|
||||||
<def var = 'Tooltip.XDelta' value = '8'/> <!-- basically cursor size -->
|
<def var = 'Tooltip.XDelta' value = '8'/> <!-- basically cursor size -->
|
||||||
<def var = 'Tooltip.YDelta' value = '8'/>
|
<def var = 'Tooltip.YDelta' value = '8'/>
|
||||||
|
|
||||||
|
<def var = 'Predictive.Button.Width' value = '45' />
|
||||||
|
<def var = 'Predictive.Button.Height' value = '15' />
|
||||||
|
|
||||||
<widget name = 'Button'
|
<widget name = 'Button'
|
||||||
size = '72, 16'
|
size = '72, 16'
|
||||||
/>
|
/>
|
||||||
|
@ -913,4 +916,97 @@
|
||||||
/>
|
/>
|
||||||
</layout>
|
</layout>
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
||||||
|
<dialog name = 'Predictive' overlays = 'screen_center'>
|
||||||
|
<layout type = 'vertical' padding = '1, 1, 1, 1' center = 'true'>
|
||||||
|
<widget name = 'Headline'
|
||||||
|
height = 'Globals.Line.Height'
|
||||||
|
width = '150'
|
||||||
|
textalign = 'center'
|
||||||
|
/>
|
||||||
|
<layout type = 'horizontal' padding = '3, 3, 3, 3'>
|
||||||
|
<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 = '3, 3, 3, 3'>
|
||||||
|
<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 = '3, 3, 3, 3'>
|
||||||
|
<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 = '3, 3, 3, 3'>
|
||||||
|
<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 = '3, 3, 3, 0'>
|
||||||
|
<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 = '3' />
|
||||||
|
<layout type = 'horizontal' padding = '3, 3, 0, 3'>
|
||||||
|
<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>
|
</layout_info>
|
||||||
|
|
Binary file not shown.
|
@ -1 +1 @@
|
||||||
[SCUMMVM_STX0.8.9:ScummVM Modern Theme:No Author]
|
[SCUMMVM_STX0.8.10:ScummVM Modern Theme:No Author]
|
||||||
|
|
BIN
gui/themes/scummmodern/delbtn.bmp
Normal file
BIN
gui/themes/scummmodern/delbtn.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 890 B |
|
@ -100,6 +100,7 @@
|
||||||
<bitmap filename = 'logo_small.bmp'/>
|
<bitmap filename = 'logo_small.bmp'/>
|
||||||
<bitmap filename = 'search.bmp'/>
|
<bitmap filename = 'search.bmp'/>
|
||||||
<bitmap filename = 'eraser.bmp'/>
|
<bitmap filename = 'eraser.bmp'/>
|
||||||
|
<bitmap filename = 'delbtn.bmp'/>
|
||||||
</bitmaps>
|
</bitmaps>
|
||||||
|
|
||||||
<fonts>
|
<fonts>
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
<def var = 'Tooltip.XDelta' value = '16'/> <!-- basically cursor size -->
|
<def var = 'Tooltip.XDelta' value = '16'/> <!-- basically cursor size -->
|
||||||
<def var = 'Tooltip.YDelta' value = '32'/>
|
<def var = 'Tooltip.YDelta' value = '32'/>
|
||||||
|
|
||||||
|
<def var = 'Predictive.Button.Width' value = '60' />
|
||||||
|
|
||||||
<widget name = 'OptionsLabel'
|
<widget name = 'OptionsLabel'
|
||||||
size = '115, Globals.Line.Height'
|
size = '115, Globals.Line.Height'
|
||||||
textalign = 'right'
|
textalign = 'right'
|
||||||
|
@ -59,8 +61,7 @@
|
||||||
|
|
||||||
<widget name = 'Button'
|
<widget name = 'Button'
|
||||||
size = '108, 24'
|
size = '108, 24'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
||||||
<widget name = 'Slider'
|
<widget name = 'Slider'
|
||||||
size = '128, 18'
|
size = '128, 18'
|
||||||
|
@ -925,5 +926,99 @@
|
||||||
type = 'Button'
|
type = 'Button'
|
||||||
/>
|
/>
|
||||||
</layout>
|
</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>
|
</dialog>
|
||||||
|
|
||||||
</layout_info>
|
</layout_info>
|
||||||
|
|
|
@ -33,6 +33,9 @@
|
||||||
|
|
||||||
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/>
|
<def var = 'SaveLoadChooser.ExtInfo.Visible' value = '0'/>
|
||||||
|
|
||||||
|
<def var = 'Predictive.Button.Width' value = '45' />
|
||||||
|
<def var = 'Predictive.Button.Height' value = '15' />
|
||||||
|
|
||||||
<widget name = 'Button'
|
<widget name = 'Button'
|
||||||
size = '72, 16'
|
size = '72, 16'
|
||||||
/>
|
/>
|
||||||
|
@ -911,4 +914,96 @@
|
||||||
/>
|
/>
|
||||||
</layout>
|
</layout>
|
||||||
</dialog>
|
</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>
|
</layout_info>
|
||||||
|
|
|
@ -70,18 +70,17 @@ public:
|
||||||
|
|
||||||
virtual void handleTickle();
|
virtual void handleTickle();
|
||||||
virtual bool handleKeyDown(Common::KeyState state);
|
virtual bool handleKeyDown(Common::KeyState state);
|
||||||
|
|
||||||
virtual void reflowLayout();
|
virtual void reflowLayout();
|
||||||
|
|
||||||
|
bool setCaretPos(int newPos);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void startEditMode() = 0;
|
virtual void startEditMode() = 0;
|
||||||
virtual void endEditMode() = 0;
|
virtual void endEditMode() = 0;
|
||||||
virtual void abortEditMode() = 0;
|
virtual void abortEditMode() = 0;
|
||||||
|
|
||||||
virtual Common::Rect getEditRect() const = 0;
|
virtual Common::Rect getEditRect() const = 0;
|
||||||
virtual int getCaretOffset() const;
|
virtual int getCaretOffset() const;
|
||||||
void drawCaret(bool erase);
|
void drawCaret(bool erase);
|
||||||
bool setCaretPos(int newPos);
|
|
||||||
bool adjustOffset();
|
bool adjustOffset();
|
||||||
void makeCaretVisible();
|
void makeCaretVisible();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue