diff options
-rw-r--r-- | engines/agi/agi.h | 8 | ||||
-rw-r--r-- | engines/agi/cycle.cpp | 27 | ||||
-rw-r--r-- | engines/agi/keyboard.cpp | 240 | ||||
-rw-r--r-- | engines/agi/op_cmd.cpp | 11 | ||||
-rw-r--r-- | engines/agi/text.cpp | 29 | ||||
-rw-r--r-- | engines/agi/text.h | 7 |
6 files changed, 194 insertions, 128 deletions
diff --git a/engines/agi/agi.h b/engines/agi/agi.h index 1e6001dae3..9d220d2062 100644 --- a/engines/agi/agi.h +++ b/engines/agi/agi.h @@ -231,8 +231,7 @@ struct gameIdList { struct Mouse { int button; - int x; - int y; + Common::Point pos; }; // Used by AGI Mouse protocol 1.0 for v27 (i.e. button pressed -variable). @@ -942,7 +941,12 @@ public: void cleanKeyboard(); int16 getSpecialMenuControllerSlot(); + + bool handleMouseClicks(uint16 &key); bool handleController(uint16 key); + + bool showPredictiveDialog(); + uint16 agiGetKeypress(); int waitKey(); int waitAnyKey(); diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp index 6506ee29eb..67a238df08 100644 --- a/engines/agi/cycle.cpp +++ b/engines/agi/cycle.cpp @@ -206,8 +206,8 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) { // // We run AGIMOUSE always as a side effect //if (getFeatures() & GF_AGIMOUSE) { - setVar(VM_VAR_MOUSE_X, _mouse.x / 2); - setVar(VM_VAR_MOUSE_Y, _mouse.y); + setVar(VM_VAR_MOUSE_X, _mouse.pos.x / 2); + setVar(VM_VAR_MOUSE_Y, _mouse.pos.y); //} switch (_game.inputMode) { @@ -245,21 +245,27 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) { setVar(VM_VAR_KEY, keyAscii); } + handleMouseClicks(key); + if (!cycleInnerLoopIsActive()) { // no inner loop active at the moment, regular processing switch (_game.inputMode) { case INPUTMODE_NORMAL: - if (!handleController(key)) { - if (key == 0 || (!_text->promptIsEnabled())) - break; - - _text->promptCharPress(key); + if (key) { + if (!handleController(key)) { + if ((key) && (_text->promptIsEnabled())) { + _text->promptCharPress(key); + } + } } break; case INPUTMODE_NONE: - handleController(key); - if (key) - _game.keypress = key; + if (key) { + handleController(key); + if (key) { + _game.keypress = key; + } + } break; default: break; @@ -274,7 +280,6 @@ int AgiEngine::mainCycle(bool onlyCheckForEvents) { switch (_game.cycleInnerLoopType) { case CYCLE_INNERLOOP_GETSTRING: // loop called from TextMgr::stringEdit() case CYCLE_INNERLOOP_GETNUMBER: - //handleController(key); if (key) { _text->stringCharPress(key); } diff --git a/engines/agi/keyboard.cpp b/engines/agi/keyboard.cpp index 2a5f801a25..07aec985c8 100644 --- a/engines/agi/keyboard.cpp +++ b/engines/agi/keyboard.cpp @@ -68,52 +68,16 @@ void AgiEngine::processEvents() { while (_eventMan->pollEvent(event)) { switch (event.type) { - case Common::EVENT_PREDICTIVE_DIALOG: { - GUI::PredictiveDialog _predictiveDialog; - _predictiveDialog.runModal(); -#if 0 - strcpy(_predictiveResult, _predictiveDialog.getResult()); - if (strcmp(_predictiveResult, "")) { - if (_game.inputMode == INPUTMODE_NORMAL) { - //strcpy((char *)_game.inputBuffer, _predictiveResult); - //handleKeys(KEY_ENTER); - // TODO: repair predictive - } else if (_game.inputMode == INPUTMODE_GETSTRING) { - strcpy(_game.strings[_stringdata.str], _predictiveResult); - newInputMode(INPUTMODE_NORMAL); - //_gfx->printCharacter(_stringdata.x + strlen(_game.strings[_stringdata.str]) + 1, - // _stringdata.y, ' ', 15, 0); - } else if (_game.inputMode == INPUTMODE_NONE) { - for (int n = 0; _predictiveResult[n]; n++) - keyEnqueue(_predictiveResult[n]); - } - } -#endif - /* - if (predictiveDialog()) { - 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]); - } - } - */ - } + case Common::EVENT_PREDICTIVE_DIALOG: + showPredictiveDialog(); break; case Common::EVENT_LBUTTONDOWN: if (_game.mouseEnabled) { key = AGI_MOUSE_BUTTON_LEFT; _mouse.button = kAgiMouseButtonLeft; keyEnqueue(key); - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + _mouse.pos.x = event.mouse.x; + _mouse.pos.y = event.mouse.y; } break; case Common::EVENT_RBUTTONDOWN: @@ -121,8 +85,8 @@ void AgiEngine::processEvents() { key = AGI_MOUSE_BUTTON_RIGHT; _mouse.button = kAgiMouseButtonRight; keyEnqueue(key); - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + _mouse.pos.x = event.mouse.x; + _mouse.pos.y = event.mouse.y; } break; case Common::EVENT_WHEELUP: @@ -139,20 +103,20 @@ void AgiEngine::processEvents() { break; case Common::EVENT_MOUSEMOVE: if (_game.mouseEnabled) { - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + _mouse.pos.x = event.mouse.x; + _mouse.pos.y = event.mouse.y; if (!_game.mouseFence.isEmpty()) { - if (_mouse.x < _game.mouseFence.left) - _mouse.x = _game.mouseFence.left; - if (_mouse.x > _game.mouseFence.right) - _mouse.x = _game.mouseFence.right; - if (_mouse.y < _game.mouseFence.top) - _mouse.y = _game.mouseFence.top; - if (_mouse.y > _game.mouseFence.bottom) - _mouse.y = _game.mouseFence.bottom; - - g_system->warpMouse(_mouse.x, _mouse.y); + if (_mouse.pos.x < _game.mouseFence.left) + _mouse.pos.x = _game.mouseFence.left; + if (_mouse.pos.x > _game.mouseFence.right) + _mouse.pos.x = _game.mouseFence.right; + if (_mouse.pos.y < _game.mouseFence.top) + _mouse.pos.y = _game.mouseFence.top; + if (_mouse.pos.y > _game.mouseFence.bottom) + _mouse.pos.y = _game.mouseFence.bottom; + + g_system->warpMouse(_mouse.pos.x, _mouse.pos.y); } } @@ -161,8 +125,8 @@ void AgiEngine::processEvents() { case Common::EVENT_RBUTTONUP: if (_game.mouseEnabled) { _mouse.button = kAgiMouseButtonUp; - _mouse.x = event.mouse.x; - _mouse.y = event.mouse.y; + _mouse.pos.x = event.mouse.x; + _mouse.pos.y = event.mouse.y; } break; case Common::EVENT_KEYDOWN: @@ -347,6 +311,86 @@ int16 AgiEngine::getSpecialMenuControllerSlot() { return -1; } +bool AgiEngine::handleMouseClicks(uint16 &key) { + // No mouse click? -> exit + if (key != AGI_MOUSE_BUTTON_LEFT) + return false; + + Common::Rect displayLineRect(DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT); + int16 statusRow = _text->statusRow_Get(); + + displayLineRect.moveTo(0, statusRow * FONT_DISPLAY_HEIGHT); + + if (displayLineRect.contains(_mouse.pos)) { + if (getFlag(VM_FLAG_MENUS_WORK) && _menu->isAvailable()) { + warning("click on status line -> menu TODO"); + // TODO: menu + // This should be done in a better way as in simulate ESC key + // Sierra seems to have hardcoded it in some way, but we would have to verify, what flags + // they checked. The previous way wasn't accurate. Mouse support for menu is missing atm anyway. + //if ((getflag(VM_FLAG_MENUS_WORK) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) { + // newInputMode(INPUTMODE_MENU); + // return true; + //} + key = 0; // eat event + return true; + } + } + + if (_text->promptIsEnabled() && (!cycleInnerLoopIsActive()) ) { + // Prompt is currently enabled, but no inner loop is active + int16 promptRow = _text->promptRow_Get(); + + displayLineRect.moveTo(0, promptRow * FONT_DISPLAY_HEIGHT); + + if (displayLineRect.contains(_mouse.pos)) { + // and user clicked within the line of the prompt + showPredictiveDialog(); + + key = 0; // eat event + return true; + } + } + + if (cycleInnerLoopIsActive()) { + // inner loop active, check what kind of loop it is. Then process / forward it + switch (_game.cycleInnerLoopType) { + case CYCLE_INNERLOOP_GETSTRING: + case CYCLE_INNERLOOP_GETNUMBER: { + // process in here + int16 stringRow, stringColumn, stringMaxLen; + + _text->stringPos_Get(stringRow, stringColumn); + stringMaxLen = _text->stringGetMaxLen(); + + Common::Rect displayRect(stringMaxLen * FONT_DISPLAY_WIDTH, FONT_DISPLAY_HEIGHT); + displayRect.moveTo(stringColumn * FONT_DISPLAY_WIDTH, stringRow * FONT_DISPLAY_HEIGHT); + + if (displayRect.contains(_mouse.pos)) { + // user clicked inside the input space + showPredictiveDialog(); + + key = 0; // eat event + return true; + } + break; + } + case CYCLE_INNERLOOP_INVENTORY: + // TODO: forward + break; + case CYCLE_INNERLOOP_MENU: + // TODO: forward + break; + case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT: + // TODO: forward + break; + default: + break; + } + } + return false; +} + bool AgiEngine::handleController(uint16 key) { ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY]; @@ -407,51 +451,6 @@ bool AgiEngine::handleController(uint16 key) { } } - if (key == AGI_MOUSE_BUTTON_LEFT) { - // call mouse when click is done on status bar - // TODO - // This should be done in a better way as in simulate ESC key - // Sierra seems to have hardcoded it in some way, but we would have to verify, what flags - // they checked. The previous way wasn't accurate. Mouse support for menu is missing atm anyway. - //if ((getflag(VM_FLAG_MENUS_WORK) || (getFeatures() & GF_MENUS)) && _mouse.y <= CHAR_LINES) { - // newInputMode(INPUTMODE_MENU); - // return true; - //} - } - - // Show predictive dialog if the user clicks on input area - if (key == AGI_MOUSE_BUTTON_LEFT && - (int)_mouse.y >= _text->promptRow_Get() * FONT_DISPLAY_HEIGHT && - (int)_mouse.y <= (_text->promptRow_Get() + 1) * FONT_DISPLAY_HEIGHT) { - GUI::PredictiveDialog _predictiveDialog; - _predictiveDialog.runModal(); -#if 0 - strcpy(_predictiveResult, _predictiveDialog.getResult()); - if (strcmp(_predictiveResult, "")) { - if (_game.inputMode == INPUTMODE_NONE) { - for (int n = 0; _predictiveResult[n]; n++) - keyEnqueue(_predictiveResult[n]); - } else { - //strcpy((char *)_game.inputBuffer, _predictiveResult); - //handleKeys(KEY_ENTER); - // TODO - } - } -#endif - /* - if (predictiveDialog()) { - if (_game.inputMode == INPUT_NONE) { - for (int n = 0; _predictiveResult[n]; n++) - keyEnqueue(_predictiveResult[n]); - } else { - strcpy((char *)_game.inputBuffer, _predictiveResult); - handleKeys(KEY_ENTER); - } - } - */ - return true; - } - int16 newDirection = 0; switch (key) { @@ -498,8 +497,8 @@ bool AgiEngine::handleController(uint16 key) { //v->flags |= fAdjEgoXY; // setting fAdjEgoXY here will at least break "climbing the log" in SQ2 // in case you walked to the log by using the mouse, so don't!!! - int16 egoDestinationX = _mouse.x; - int16 egoDestinationY = _mouse.y; + int16 egoDestinationX = _mouse.pos.x; + int16 egoDestinationY = _mouse.pos.y; adjustPosToGameScreen(egoDestinationX, egoDestinationY); screenObjEgo->motionType = kMotionEgo; @@ -534,6 +533,41 @@ bool AgiEngine::handleController(uint16 key) { return false; } +bool AgiEngine::showPredictiveDialog() { + GUI::PredictiveDialog predictiveDialog; + + inGameTimerPause(); + predictiveDialog.runModal(); + inGameTimerResume(); + + Common::String predictiveResult(predictiveDialog.getResult()); + uint16 predictiveResultLen = predictiveResult.size(); + if (predictiveResult.size()) { + // User actually entered something + for (int16 resultPos = 0; resultPos < predictiveResultLen; resultPos++) { + keyEnqueue(predictiveResult[resultPos]); + } + if (!cycleInnerLoopIsActive()) { + if (_text->promptIsEnabled()) { + // add ENTER, when the input is probably meant for the prompt + keyEnqueue(AGI_KEY_ENTER); + } + } else { + switch (_game.cycleInnerLoopType) { + case CYCLE_INNERLOOP_GETSTRING: + case CYCLE_INNERLOOP_GETNUMBER: + // add ENTER, when the input is probably meant for GetString/GetNumber + keyEnqueue(AGI_KEY_ENTER); + break; + default: + break; + } + } + return true; + } + return false; +} + int AgiEngine::waitKey() { int key = 0; diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp index 4b82d2464a..f36090dafa 100644 --- a/engines/agi/op_cmd.cpp +++ b/engines/agi/op_cmd.cpp @@ -1851,8 +1851,7 @@ void cmdConfigureScreen(AgiGame *state, uint8 *parameter) { uint16 promptRow = parameter[1]; uint16 statusRow = parameter[2]; - state->_vm->_text->configureScreen(lineMinPrint); - + textMgr->configureScreen(lineMinPrint); textMgr->statusRow_Set(statusRow); textMgr->promptRow_Set(promptRow); } @@ -2256,8 +2255,8 @@ void cmdPushScript(AgiGame *state, uint8 *parameter) { // We run AGIMOUSE always as a side effect //if (getFeatures() & GF_AGIMOUSE || true) { vm->setVar(VM_VAR_MOUSE_BUTTONSTATE, state->_vm->_mouse.button); - vm->setVar(VM_VAR_MOUSE_X, state->_vm->_mouse.x / 2); - vm->setVar(VM_VAR_MOUSE_Y, state->_vm->_mouse.y); + vm->setVar(VM_VAR_MOUSE_X, vm->_mouse.pos.x / 2); + vm->setVar(VM_VAR_MOUSE_Y, vm->_mouse.pos.y); /*} else { if (getVersion() >= 0x2915) { debug(0, "push.script"); @@ -2277,8 +2276,8 @@ void cmdMousePosn(AgiGame *state, uint8 *parameter) { AgiEngine *vm = state->_vm; uint16 destVarNr1 = parameter[0]; uint16 destVarNr2 = parameter[1]; - int16 mouseX = state->_vm->_mouse.x; - int16 mouseY = state->_vm->_mouse.y; + int16 mouseX = vm->_mouse.pos.x; + int16 mouseY = vm->_mouse.pos.y; state->_vm->adjustPosToGameScreen(mouseX, mouseY); diff --git a/engines/agi/text.cpp b/engines/agi/text.cpp index 8806aeee28..c6c0f93651 100644 --- a/engines/agi/text.cpp +++ b/engines/agi/text.cpp @@ -64,6 +64,8 @@ TextMgr::TextMgr(AgiEngine *vm, Words *words, GfxMgr *gfx) { promptDisable(); promptReset(); + _inputStringRow = 0; + _inputStringColumn = 0; _inputStringMaxLen = 0; _inputStringCursorPos = 0; _inputString[0] = 0; @@ -107,16 +109,21 @@ void TextMgr::charPos_Set(int16 row, int16 column) { _textPos.column = column; } -void TextMgr::charPos_Get(TextPos_Struct *posPtr) { - posPtr->row = _textPos.row; - posPtr->column = _textPos.column; -} - void TextMgr::charPos_Set(TextPos_Struct *posPtr) { _textPos.row = posPtr->row; _textPos.column = posPtr->column; } +void TextMgr::charPos_Get(int16 &row, int16 &column) { + row = _textPos.row; + column = _textPos.column; +} + +void TextMgr::charPos_Get(TextPos_Struct *posPtr) { + posPtr->row = _textPos.row; + posPtr->column = _textPos.column; +} + void TextMgr::charPos_Push() { if (_textPosArrayCount < TEXTPOSARRAY_MAX) { charPos_Get(&_textPosArray[_textPosArrayCount]); @@ -735,9 +742,21 @@ void TextMgr::stringSet(const char *text) { _inputString[sizeof(_inputString) - 1] = 0; // terminator } +void TextMgr::stringPos_Get(int16 &row, int16 &column) { + row = _inputStringRow; + column = _inputStringColumn; +} +int16 TextMgr::stringGetMaxLen() { + return _inputStringMaxLen; +} + void TextMgr::stringEdit(int16 stringMaxLen) { int16 inputStringLen = strlen((const char *)_inputString); + // Remember current position for predictive dialog + _inputStringRow = _textPos.row; + _inputStringColumn = _textPos.column; + // Caller can set the input string _inputStringCursorPos = 0; while (_inputStringCursorPos < inputStringLen) { diff --git a/engines/agi/text.h b/engines/agi/text.h index b42f0982d5..febb50fcb9 100644 --- a/engines/agi/text.h +++ b/engines/agi/text.h @@ -107,8 +107,9 @@ public: void charPos_Clip(int16 &row, int16 &column); void charPos_Set(int16 row, int16 column); - void charPos_Get(TextPos_Struct *posPtr); void charPos_Set(TextPos_Struct *posPtr); + void charPos_Get(int16 &row, int16 &column); + void charPos_Get(TextPos_Struct *posPtr); void charPos_Push(); void charPos_Pop(); void charPos_SetInsideWindow(int16 windowRow, int16 windowColumn); @@ -181,12 +182,16 @@ public: void promptClear(); // for AGI1 void promptRememberForAutoComplete(bool entered = false); // for auto-completion + int16 _inputStringRow; + int16 _inputStringColumn; bool _inputStringEntered; int16 _inputStringMaxLen; int16 _inputStringCursorPos; byte _inputString[42]; bool stringWasEntered(); + void stringPos_Get(int16 &row, int16 &column); + int16 stringGetMaxLen(); void stringSet(const char *text); void stringEdit(int16 stringMaxLen); void stringCharPress(int16 newChar); |