From f412328181baaac3ec6726de3bd9b914731cc551 Mon Sep 17 00:00:00 2001 From: Matthew Stewart Date: Fri, 27 Jul 2018 01:59:01 -0400 Subject: STARTREK: Implement text input boxes Needed for SINS mission with the keypads --- engines/startrek/font.cpp | 37 ++++- engines/startrek/font.h | 6 +- engines/startrek/graphics.cpp | 6 +- engines/startrek/graphics.h | 6 +- engines/startrek/room.cpp | 20 ++- engines/startrek/room.h | 6 +- engines/startrek/rooms/sins1.cpp | 13 +- engines/startrek/sprite.cpp | 4 +- engines/startrek/sprite.h | 2 +- engines/startrek/startrek.h | 26 ++++ engines/startrek/text.cpp | 309 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 416 insertions(+), 19 deletions(-) (limited to 'engines') diff --git a/engines/startrek/font.cpp b/engines/startrek/font.cpp index 7cba71196e..6cd3f1b416 100644 --- a/engines/startrek/font.cpp +++ b/engines/startrek/font.cpp @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://scummvm-startrek.googlecode.com/svn/trunk/font.cpp $ - * $Id: font.cpp 2 2009-09-12 20:13:40Z clone2727 $ - * */ #include "startrek/font.h" @@ -47,4 +44,38 @@ byte *Font::getCharData(int i) { return _characters[i].data; } +bool Font::isDisplayableCharacter(char c) { + // True if lowercase, uppercase, a digit, punctuation, or space + return _fontProperties[c & 0xff] & 0x57; +} + + +// Bit 0 set for lowercase characters; +// Bit 1 set for uppercase characters; +// Bit 2 set for digits; +// Bit 3 set for certain control characters (nl, tab, cr?); +// Bit 4 set for punctuation, also &, @, etc; +// Bit 5 set for "undrawable" characters (?); +// Bit 6 set for space only (?); +// Bit 7 set for hexadecimal characters. +// NOTE: May need to update this for French, German languages? +const byte Font::_fontProperties[] = { + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x48, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x84, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x10, 0x10, 0x10, 0x10, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + } diff --git a/engines/startrek/font.h b/engines/startrek/font.h index 1353acc2e5..184d5abcd5 100644 --- a/engines/startrek/font.h +++ b/engines/startrek/font.h @@ -18,9 +18,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - * $URL: https://scummvm-startrek.googlecode.com/svn/trunk/font.h $ - * $Id: font.h 2 2009-09-12 20:13:40Z clone2727 $ - * */ #ifndef STARTREK_FONT_H @@ -38,6 +35,7 @@ public: ~Font(); byte *getCharData(int i); + bool isDisplayableCharacter(char c); private: StarTrekEngine *_vm; @@ -45,6 +43,8 @@ private: struct Character { byte data[0x40]; } *_characters; + + const static byte _fontProperties[256]; }; diff --git a/engines/startrek/graphics.cpp b/engines/startrek/graphics.cpp index cce9861934..5d484edbc6 100644 --- a/engines/startrek/graphics.cpp +++ b/engines/startrek/graphics.cpp @@ -658,7 +658,7 @@ void Graphics::addSprite(Sprite *sprite) { // Initialize some fields sprite->drawMode = 0; - sprite->field8 = 0; + sprite->field8 = ""; sprite->field16 = false; sprite->bitmapChanged = true; // FIXME (delete this later?) @@ -701,6 +701,10 @@ void Graphics::popSprites() { _pushedNumSprites = -1; } +byte *Graphics::getFontGfx(char c) { + return _font->getCharData(c & 0xff); +} + void Graphics::copyBackgroundScreen() { drawDirectToScreen(_backgroundImage); diff --git a/engines/startrek/graphics.h b/engines/startrek/graphics.h index bd5784e3a2..627b5bec47 100644 --- a/engines/startrek/graphics.h +++ b/engines/startrek/graphics.h @@ -143,14 +143,18 @@ public: void pushSprites(); void popSprites(); + byte *getFontGfx(char c); + void copyBackgroundScreen(); void drawDirectToScreen(SharedPtr bitmap); void loadEGAData(const char *egaFile); void drawBackgroundImage(const char *filename); +public: + Font *_font; + private: StarTrekEngine *_vm; - Font *_font; bool _egaMode; byte *_egaData; diff --git a/engines/startrek/room.cpp b/engines/startrek/room.cpp index b5149b5ecf..a8a4b490f4 100644 --- a/engines/startrek/room.cpp +++ b/engines/startrek/room.cpp @@ -475,9 +475,23 @@ void Room::showGameOverMenu() { // TODO: takes an optional parameter? // TODO: finish. Shouldn't do this within a room due to deletion of current room? } -int Room::showKeypad(const Common::String &code) { - // TODO - return 3; +int Room::showCodeInputBox(const char * const *codes) { + Common::String inputString = _vm->showCodeInputBox(); + + // ENHANCEMENT: Extra condition for "nothing entered" + if (inputString.empty()) + return -1; + + int retval = 0; + int code = 0; + + while (codes[code] != nullptr) { + if (strcmp(codes[code], inputString.c_str()) == 0) + retval = code + 1; + code++; + } + + return retval; } void Room::playVoc(Common::String filename) { diff --git a/engines/startrek/room.h b/engines/startrek/room.h index bb1c8f1d5c..dff0bcaad1 100644 --- a/engines/startrek/room.h +++ b/engines/startrek/room.h @@ -236,9 +236,11 @@ private: */ void showGameOverMenu(); /** - * Cmd 0x13: Keypad used in "Than Old Devil Moon" (SINS mission) + * Cmd 0x13: Text input used in "Than Old Devil Moon" (SINS mission) + * Takes a list of codes (ending with nullptr) and returns the index of the matched + * code (plus one), or 0 if no code was matched. */ - int showKeypad(const Common::String &code); + int showCodeInputBox(const char * const *codes); /** * Cmd 0x15 */ diff --git a/engines/startrek/rooms/sins1.cpp b/engines/startrek/rooms/sins1.cpp index 8d94b4aea5..8f44840667 100644 --- a/engines/startrek/rooms/sins1.cpp +++ b/engines/startrek/rooms/sins1.cpp @@ -197,9 +197,16 @@ void Room::sins1UseSpockOnKeypad() { } void Room::sins1SpockReachedKeypad() { - int ans = showKeypad("01210"); - - if (ans == 1 || ans == 2) { + const char * const codes[] = { + "01210", "1210", "10200", nullptr + }; + int ans = showCodeInputBox(codes); + + if (ans == -1) { + // ENHANCEMENT: Do nothing if no code was entered. + _vm->_awayMission.crewDirectionsAfterWalk[OBJECT_SPOCK] = DIR_W; + walkCrewman(OBJECT_SPOCK, 0xf3, 0xad); + } else if (ans == 1 || ans == 2) { playVoc("EFX14S"); loadActorAnimC(OBJECT_SPOCK, "susehn", -1, -1, &Room::sins1EnteredSacredSofNumber); } else if (ans == 3) { diff --git a/engines/startrek/sprite.cpp b/engines/startrek/sprite.cpp index 821a78ed00..dc01a917c9 100644 --- a/engines/startrek/sprite.cpp +++ b/engines/startrek/sprite.cpp @@ -26,7 +26,7 @@ namespace StarTrek { Sprite::Sprite() : - pos(), drawPriority(0), drawPriority2(0), field8(0), + pos(), drawPriority(0), drawPriority2(0), field8(""), bitmap(), drawMode(0), textColor(0), bitmapChanged(false), rect2Valid(false), isOnScreen(false), field16(false), lastDrawRect(), drawRect(), rectangle2(), drawX(0), drawY(0) @@ -60,7 +60,7 @@ void Sprite::saveLoadWithSerializer(Common::Serializer &ser) { ser.syncAsSint16LE(pos.y); ser.syncAsUint16LE(drawPriority); ser.syncAsUint16LE(drawPriority2); - ser.syncAsUint16LE(field8); + ser.syncString(field8); // Note: bitmap must be reloaded ser.syncAsUint16LE(drawMode); ser.syncAsUint16LE(textColor); diff --git a/engines/startrek/sprite.h b/engines/startrek/sprite.h index b91e2f2c21..d8cfc0b334 100644 --- a/engines/startrek/sprite.h +++ b/engines/startrek/sprite.h @@ -46,7 +46,7 @@ struct Sprite : Common::Serializable { Common::Point pos; uint16 drawPriority; uint16 drawPriority2; // If two sprites' drawPriorities are equal, this is checked. - uint16 field8; + Common::String field8; SharedPtr bitmap; uint16 drawMode; uint16 textColor; diff --git a/engines/startrek/startrek.h b/engines/startrek/startrek.h index ef2ddf195b..386abd186f 100644 --- a/engines/startrek/startrek.h +++ b/engines/startrek/startrek.h @@ -107,6 +107,9 @@ const int TEXTBOX_WIDTH = 26; const int TEXT_CHARS_PER_LINE = TEXTBOX_WIDTH - 2; const int MAX_TEXTBOX_LINES = 12; +const int TEXT_INPUT_BUFFER_SIZE = 134; +const int MAX_TEXT_INPUT_LEN = 20; + const int MAX_BUFFERED_WALK_ACTIONS = 32; const int MAX_BAN_FILES = 16; @@ -466,6 +469,11 @@ public: * Returns position of text to continue from, or nullptr if done. */ const char *getNextTextLine(const char *text, char *line, int lineWidth); + /** + * Draw a line of text to a standard bitmap (NOT a "TextBitmap", whose pixel array is + * an array of characters, but an actual standard bitmap). + */ + void drawTextLineToBitmap(const char *text, int textLen, int x, int y, SharedPtr bitmap); String centerTextboxHeader(String headerText); void getTextboxHeader(String *headerTextOutput, String speakerText, int choiceIndex); @@ -523,6 +531,24 @@ public: */ String readTextFromArrayWithChoices(int choiceIndex, uintptr data, String *headerTextOutput); + Common::String showCodeInputBox(); + void redrawTextInput(); + void addCharToTextInputBuffer(char c); + /** + * Shows a textbox that the player can type a string into. + */ + Common::String showTextInputBox(int16 arg0, int16 arg2, const Common::String &headerText); + void initTextInputSprite(int16 arg0, int16 arg2, const Common::String &headerText); + void cleanupTextInputSprite(); + +private: + char _textInputBuffer[TEXT_INPUT_BUFFER_SIZE]; + int16 _textInputCursorPos; + char _textInputCursorChar; + SharedPtr _textInputBitmapSkeleton; + SharedPtr _textInputBitmap; + Sprite _textInputSprite; + // menu.cpp public: /** diff --git a/engines/startrek/text.cpp b/engines/startrek/text.cpp index e2f271548c..1a05ecc1e8 100644 --- a/engines/startrek/text.cpp +++ b/engines/startrek/text.cpp @@ -80,6 +80,62 @@ const char *StarTrekEngine::getNextTextLine(const char *text, char *lineOutput, return lastSpaceInput + 1; } +void StarTrekEngine::drawTextLineToBitmap(const char *text, int textLen, int x, int y, SharedPtr bitmap) { + const int charWidth = 8; + + int textOffset = 0; + + while (textOffset < textLen) { + Common::Rect destRect(x, y, x + 8, y + 8); + Common::Rect bitmapRect(bitmap->width, bitmap->height); + + if (destRect.intersects(bitmapRect)) { + // drawRect = the rectangle within the 8x8 font character that will be drawn + // (part of it may be clipped) + Common::Rect drawRect; + drawRect.left = bitmapRect.left - destRect.left; + if (drawRect.left < destRect.left - destRect.left) + drawRect.left = destRect.left - destRect.left; + + drawRect.right = bitmapRect.right - destRect.left; + if (drawRect.right > destRect.right - destRect.left) + drawRect.right = destRect.right - destRect.left; + + drawRect.top = bitmapRect.top - destRect.top; + if (drawRect.top < destRect.top - destRect.top) + drawRect.top = destRect.top - destRect.top; + + drawRect.bottom = bitmapRect.bottom - destRect.top; + if (drawRect.bottom > destRect.bottom - destRect.top) + drawRect.bottom = destRect.bottom - destRect.top; + + + int16 destX = destRect.left - bitmapRect.left; + if (destX < bitmapRect.right - bitmapRect.right) + destX = bitmapRect.right - bitmapRect.right; + + int16 destY = destRect.top - bitmapRect.top; + if (destY < bitmapRect.top - bitmapRect.top) + destY = bitmapRect.top - bitmapRect.top; + + int16 srcRowDiff = charWidth - drawRect.width(); + int16 destRowDiff = bitmapRect.width() - drawRect.width(); + + byte *srcPixels = _gfx->getFontGfx(text[textOffset]) + drawRect.top * charWidth + drawRect.left; + byte *destPixels = bitmap->pixels + destY * bitmapRect.width() + destX; + + for (int i = 0; i < drawRect.height(); i++) { + memcpy(destPixels, srcPixels, drawRect.width()); + destPixels += destRowDiff + drawRect.width(); + srcPixels += srcRowDiff + drawRect.width(); + } + } + + x += charWidth; + textOffset++; + } +} + String StarTrekEngine::centerTextboxHeader(String headerText) { char text[TEXT_CHARS_PER_LINE + 1]; memset(text, ' ', sizeof(text)); @@ -621,4 +677,257 @@ String StarTrekEngine::readTextFromArrayWithChoices(int choiceIndex, uintptr dat return String(mainText); } +Common::String StarTrekEngine::showCodeInputBox() { + memset(_textInputBuffer, 0, TEXT_INPUT_BUFFER_SIZE - 1); + return showTextInputBox(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, "Code:\n "); +} + +void StarTrekEngine::redrawTextInput() { + char buf[MAX_TEXT_INPUT_LEN * 2 + 2]; + memset(buf, 0, MAX_TEXT_INPUT_LEN * 2); + strcpy(buf, _textInputBuffer); + + if (_textInputCursorChar != 0) + buf[_textInputCursorPos] = _textInputCursorChar; + + memcpy(_textInputBitmap->pixels, _textInputBitmapSkeleton->pixels, _textInputBitmapSkeleton->width * _textInputBitmapSkeleton->height); + + drawTextLineToBitmap(buf, MAX_TEXT_INPUT_LEN, 4, 12, _textInputBitmap); + _textInputSprite.bitmapChanged = true; + _gfx->drawAllSprites(); +} + +void StarTrekEngine::addCharToTextInputBuffer(char c) { + Common::String str(_textInputBuffer); + while ((int)str.size() < _textInputCursorPos) { + str += " "; + } + + str.insertChar(c, _textInputCursorPos); + + strncpy(_textInputBuffer, str.c_str(), MAX_TEXT_INPUT_LEN); + _textInputBuffer[MAX_TEXT_INPUT_LEN] = '\0'; +} + +Common::String StarTrekEngine::showTextInputBox(int16 x, int16 y, const Common::String &headerText) { + bool validInput = false; + + _keyboardControlsMouse = false; + _textInputCursorPos = 0; + + initTextInputSprite(x, y, headerText); + + bool loop = true; + + while (loop) { + TrekEvent event; + if (!popNextEvent(&event)) + continue; + + switch (event.type) { + case TREKEVENT_TICK: + _gfx->incPaletteFadeLevel(); + _frameIndex++; + _textInputCursorChar = (_frameIndex & 2 ? 1 : 0); + redrawTextInput(); + break; + + case TREKEVENT_LBUTTONDOWN: + redrawTextInput(); + validInput = true; + loop = false; + break; + + case TREKEVENT_RBUTTONDOWN: + loop = false; + break; + + case TREKEVENT_KEYDOWN: + switch (event.kbd.keycode) { + case Common::KEYCODE_BACKSPACE: + if (_textInputCursorPos > 0) { + _textInputCursorPos--; + Common::String str(_textInputBuffer); + str.deleteChar(_textInputCursorPos); + strcpy(_textInputBuffer, str.c_str()); + } + redrawTextInput(); + break; + + case Common::KEYCODE_DELETE: { // ENHANCEMENT: Support delete key + Common::String str(_textInputBuffer); + if (_textInputCursorPos < (int)str.size()) { + str.deleteChar(_textInputCursorPos); + strcpy(_textInputBuffer, str.c_str()); + redrawTextInput(); + } + break; + } + + case Common::KEYCODE_RETURN: + case Common::KEYCODE_KP_ENTER: + case Common::KEYCODE_F1: + redrawTextInput(); + loop = false; + validInput = true; + break; + + case Common::KEYCODE_ESCAPE: + case Common::KEYCODE_F2: + loop = false; + break; + + case Common::KEYCODE_HOME: + case Common::KEYCODE_KP7: + _textInputCursorPos = 0; + break; + + case Common::KEYCODE_LEFT: + case Common::KEYCODE_KP4: + if (_textInputCursorPos > 0) + _textInputCursorPos--; + redrawTextInput(); + break; + + case Common::KEYCODE_RIGHT: + case Common::KEYCODE_KP6: + if (_textInputCursorPos < MAX_TEXT_INPUT_LEN - 1) + _textInputCursorPos++; + redrawTextInput(); + break; + + case Common::KEYCODE_END: + case Common::KEYCODE_KP1: + _textInputCursorPos = strlen(_textInputBuffer); + // BUGFIX: Check that it doesn't exceed the buffer length. + // Original game had a bug where you could crash the game by pressing + // "end", writing a character, pressing "end" again, etc. + if (_textInputCursorPos >= MAX_TEXT_INPUT_LEN) + _textInputCursorPos = MAX_TEXT_INPUT_LEN - 1; + break; + + default: // Typed any other character + if (_gfx->_font->isDisplayableCharacter(event.kbd.ascii)) { + addCharToTextInputBuffer(event.kbd.ascii); + if (_textInputCursorPos < MAX_TEXT_INPUT_LEN - 1) + _textInputCursorPos++; + redrawTextInput(); + } + break; + } + break; + + default: + break; + } + } + + cleanupTextInputSprite(); + _keyboardControlsMouse = true; + + if (validInput) + return _textInputBuffer; + else + return ""; +} + +void StarTrekEngine::initTextInputSprite(int16 textboxX, int16 textboxY, const Common::String &headerText) { + int headerLen = headerText.size(); + + if (headerLen > 25) + headerLen = 25; + + char textBuf[TEXTBOX_WIDTH * 11 + 1]; + const char *headerPos = headerText.c_str(); + int row = 0; + + /* + // TODO: investigate this (might be unused...) + if (word_53100 != 0) { + // ... + } + */ + + do { + headerPos = getNextTextLine(headerPos, textBuf + row * TEXTBOX_WIDTH, headerLen); + row++; + } while (headerPos != 0 && row < 11); + + int16 width = headerLen * 8 + 8; + int16 height = row * 8 + 8; + + _textInputBitmapSkeleton = SharedPtr(new Bitmap(width, height)); + _textInputBitmap = SharedPtr(new Bitmap(width, height)); + + _textInputBitmapSkeleton->xoffset = width / 2; + if (textboxX + width / 2 >= SCREEN_WIDTH) + _textInputBitmapSkeleton->xoffset += width / 2 + textboxX - (SCREEN_WIDTH - 1); + if (textboxX - width / 2 < 0) + _textInputBitmapSkeleton->xoffset -= 0 - (textboxX - width / 2); + + _textInputBitmapSkeleton->yoffset = height + 20; + memset(_textInputBitmapSkeleton->pixels, 0, width * height); + + // Top border + int16 xPos = 1; + int16 yPos = 1; + while (xPos < width - 1) { + _textInputBitmapSkeleton->pixels[yPos * width + xPos] = 0x78; + xPos++; + } + + // Bottom border + xPos = 1; + yPos = height - 2; + while (xPos < width - 1) { + _textInputBitmapSkeleton->pixels[yPos * width + xPos] = 0x78; + xPos++; + } + + // Left border + xPos = 1; + yPos = 1; + while (yPos < height - 1) { + _textInputBitmapSkeleton->pixels[yPos * width + xPos] = 0x78; + yPos++; + } + + // Right border + xPos = width - 2; + yPos = 1; + while (yPos < height - 1) { + _textInputBitmapSkeleton->pixels[yPos * width + xPos] = 0x78; + yPos++; + } + + // Draw header text + for (int r = 0; r < row; r++) { + char *text = textBuf + r * TEXTBOX_WIDTH; + drawTextLineToBitmap(text, strlen(text), 4, r * 8 + 4, _textInputBitmapSkeleton); + } + + // Copy skeleton bitmap to actual used bitmap + _textInputBitmap->xoffset = _textInputBitmapSkeleton->xoffset; + _textInputBitmap->yoffset = _textInputBitmapSkeleton->yoffset; + memcpy(_textInputBitmap->pixels, _textInputBitmapSkeleton->pixels, width * height); + + _gfx->addSprite(&_textInputSprite); + _textInputSprite.drawMode = 2; + _textInputSprite.field8 = "System"; + _textInputSprite.bitmap = _textInputBitmap; + _textInputSprite.setXYAndPriority(textboxX, textboxY, 15); + _textInputSprite.drawPriority2 = 8; + _gfx->drawAllSprites(); +} + +void StarTrekEngine::cleanupTextInputSprite() { + _textInputSprite.dontDrawNextFrame(); + _gfx->drawAllSprites(); + _gfx->delSprite(&_textInputSprite); + + _textInputSprite.bitmap.reset(); + _textInputBitmapSkeleton.reset(); + _textInputBitmap.reset(); +} + } -- cgit v1.2.3