aboutsummaryrefslogtreecommitdiff
path: root/backends/vkeybd/virtual-keyboard-gui.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backends/vkeybd/virtual-keyboard-gui.cpp')
-rw-r--r--backends/vkeybd/virtual-keyboard-gui.cpp421
1 files changed, 421 insertions, 0 deletions
diff --git a/backends/vkeybd/virtual-keyboard-gui.cpp b/backends/vkeybd/virtual-keyboard-gui.cpp
new file mode 100644
index 0000000000..d6abd537c1
--- /dev/null
+++ b/backends/vkeybd/virtual-keyboard-gui.cpp
@@ -0,0 +1,421 @@
+/* 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.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "backends/vkeybd/virtual-keyboard-gui.h"
+
+#ifdef ENABLE_VKEYBD
+
+#include "graphics/cursorman.h"
+#include "gui/newgui.h"
+
+namespace Common {
+
+VirtualKeyboardGUI::VirtualKeyboardGUI(VirtualKeyboard *kbd)
+ : _kbd(kbd), _displaying(false), _drag(false),
+ _drawCaret(false), _displayEnabled(false), _firstRun(true),
+ _cursorAnimateTimer(0), _cursorAnimateCounter(0) {
+
+ assert(_kbd);
+ assert(g_system);
+ _system = g_system;
+
+ _lastScreenChanged = _system->getScreenChangeID();
+ _screenW = _system->getOverlayWidth();
+ _screenH = _system->getOverlayHeight();
+
+
+ memset(_cursor, 0xFF, sizeof(_cursor));
+}
+
+VirtualKeyboardGUI::~VirtualKeyboardGUI() {
+ _overlayBackup.free();
+ _dispSurface.free();
+}
+
+void VirtualKeyboardGUI::initMode(VirtualKeyboard::Mode *mode) {
+ _kbdSurface = mode->image;
+ _kbdTransparentColor = mode->transparentColor;
+ _kbdBound.setWidth(_kbdSurface->w);
+ _kbdBound.setHeight(_kbdSurface->h);
+
+ if (mode->displayArea)
+ setupDisplayArea(*(mode->displayArea), mode->displayFontColor);
+
+ if (_displaying) {
+ extendDirtyRect(_kbdBound);
+ redraw();
+ }
+}
+
+void VirtualKeyboardGUI::setupDisplayArea(Rect& r, OverlayColor forecolor) {
+
+ _dispFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont);
+ if (!fontIsSuitable(_dispFont, r)) {
+ _dispFont = FontMan.getFontByUsage(Graphics::FontManager::kGUIFont);
+ if (!fontIsSuitable(_dispFont, r)) {
+ _displayEnabled = false;
+ return;
+ }
+ }
+ _dispX = _kbdBound.left + r.left;
+ _dispY = _kbdBound.top + r.top + (r.height() - _dispFont->getFontHeight()) / 2;
+ _dispI = 0;
+ _dispForeColor = forecolor;
+ _dispBackColor = _dispForeColor + 0xFF;
+ _dispSurface.create(r.width(), _dispFont->getFontHeight(), sizeof(OverlayColor));
+ _dispSurface.fillRect(Rect(_dispSurface.w, _dispSurface.h), _dispBackColor);
+ _displayEnabled = true;
+}
+
+bool VirtualKeyboardGUI::fontIsSuitable(const Graphics::Font *font, const Rect& rect) {
+ return (font->getMaxCharWidth() < rect.width() &&
+ font->getFontHeight() < rect.height());
+}
+
+void VirtualKeyboardGUI::checkScreenChanged() {
+ if (_lastScreenChanged != _system->getScreenChangeID())
+ screenChanged();
+}
+
+void VirtualKeyboardGUI::initSize(int16 w, int16 h) {
+ _screenW = w;
+ _screenH = h;
+}
+
+void VirtualKeyboardGUI::run() {
+ if (_firstRun) {
+ _firstRun = false;
+ moveToDefaultPosition();
+ }
+
+ if (!g_gui.isActive()) {
+ _system->showOverlay();
+ _system->clearOverlay();
+ }
+ _overlayBackup.create(_screenW, _screenH, sizeof(OverlayColor));
+ _system->grabOverlay((OverlayColor*)_overlayBackup.pixels, _overlayBackup.w);
+
+ setupCursor();
+
+ forceRedraw();
+ _displaying = true;
+ mainLoop();
+
+ removeCursor();
+
+ _system->copyRectToOverlay((OverlayColor*)_overlayBackup.pixels, _overlayBackup.w, 0, 0, _overlayBackup.w, _overlayBackup.h);
+ if (!g_gui.isActive()) _system->hideOverlay();
+
+ _overlayBackup.free();
+ _dispSurface.free();
+}
+
+void VirtualKeyboardGUI::close() {
+ _displaying = false;
+}
+
+void VirtualKeyboardGUI::reset() {
+ _kbdBound.left = _kbdBound.top
+ = _kbdBound.right = _kbdBound.bottom = 0;
+ _displaying = _drag = false;
+ _firstRun = true;
+ _lastScreenChanged = _system->getScreenChangeID();
+ _kbdSurface = 0;
+}
+
+void VirtualKeyboardGUI::moveToDefaultPosition()
+{
+ int16 kbdW = _kbdBound.width(), kbdH = _kbdBound.height();
+ int16 x = 0, y = 0;
+ if (_screenW != kbdW) {
+ switch (_kbd->_hAlignment) {
+ case VirtualKeyboard::kAlignLeft:
+ x = 0;
+ break;
+ case VirtualKeyboard::kAlignCentre:
+ x = (_screenW - kbdW) / 2;
+ break;
+ case VirtualKeyboard::kAlignRight:
+ x = _screenW - kbdW;
+ break;
+ }
+ }
+ if (_screenH != kbdH) {
+ switch (_kbd->_vAlignment) {
+ case VirtualKeyboard::kAlignTop:
+ y = 0;
+ break;
+ case VirtualKeyboard::kAlignMiddle:
+ y = (_screenH - kbdH) / 2;
+ break;
+ case VirtualKeyboard::kAlignBottom:
+ y = _screenH - kbdH;
+ break;
+ }
+ }
+ move(x, y);
+}
+
+void VirtualKeyboardGUI::move(int16 x, int16 y) {
+ // add old position to dirty area
+ if (_displaying) extendDirtyRect(_kbdBound);
+
+ // snap to edge of screen
+ if (ABS(x) < SNAP_WIDTH)
+ x = 0;
+ int16 x2 = _screenW - _kbdBound.width();
+ if (ABS(x - x2) < SNAP_WIDTH)
+ x = x2;
+ if (ABS(y) < SNAP_WIDTH)
+ y = 0;
+ int16 y2 = _screenH - _kbdBound.height();
+ if (ABS(y - y2) < SNAP_WIDTH)
+ y = y2;
+
+ _dispX += x - _kbdBound.left;
+ _dispY += y - _kbdBound.top;
+ _kbdBound.moveTo(x, y);
+
+ if (_displaying) {
+ // add new position to dirty area
+ extendDirtyRect(_kbdBound);
+ redraw();
+ }
+}
+
+void VirtualKeyboardGUI::screenChanged() {
+ _lastScreenChanged = _system->getScreenChangeID();
+ int16 newScreenW = _system->getOverlayWidth();
+ int16 newScreenH = _system->getOverlayHeight();
+ if (_screenW != newScreenW || _screenH != newScreenH) {
+ _screenW = newScreenW;
+ _screenH = newScreenH;
+ if (!_kbd->checkModeResolutions()) {
+ _displaying = false;
+ return;
+ }
+ moveToDefaultPosition();
+ }
+}
+
+
+void VirtualKeyboardGUI::mainLoop() {
+ Common::EventManager *eventMan = _system->getEventManager();
+
+ while (_displaying) {
+ if (_kbd->_keyQueue.hasStringChanged())
+ updateDisplay();
+ animateCaret();
+ animateCursor();
+ redraw();
+ _system->updateScreen();
+ Common::Event event;
+ while (eventMan->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_LBUTTONDOWN:
+ if (_kbdBound.contains(event.mouse)) {
+ _kbd->handleMouseDown(event.mouse.x - _kbdBound.left,
+ event.mouse.y - _kbdBound.top);
+ }
+ break;
+ case Common::EVENT_LBUTTONUP:
+ if (_kbdBound.contains(event.mouse)) {
+ _kbd->handleMouseUp(event.mouse.x - _kbdBound.left,
+ event.mouse.y - _kbdBound.top);
+ }
+ break;
+ case Common::EVENT_MOUSEMOVE:
+ if (_drag)
+ move(event.mouse.x - _dragPoint.x,
+ event.mouse.y - _dragPoint.y);
+ break;
+ case Common::EVENT_SCREEN_CHANGED:
+ screenChanged();
+ break;
+ case Common::EVENT_QUIT:
+ _system->quit();
+ return;
+ default:
+ break;
+ }
+ }
+ // Delay for a moment
+ _system->delayMillis(10);
+ }
+}
+
+void VirtualKeyboardGUI::startDrag(int16 x, int16 y) {
+ _drag = true;
+ _dragPoint.x = x;
+ _dragPoint.y = y;
+}
+
+void VirtualKeyboardGUI::endDrag() {
+ _drag = false;
+}
+
+void VirtualKeyboardGUI::extendDirtyRect(const Rect &r) {
+ if (_dirtyRect.isValidRect()) {
+ _dirtyRect.extend(r);
+ } else {
+ _dirtyRect = r;
+ }
+ _dirtyRect.clip(Rect(_overlayBackup.w, _overlayBackup.h));
+}
+
+void VirtualKeyboardGUI::resetDirtyRect() {
+ _dirtyRect.setWidth(-1);
+}
+
+void VirtualKeyboardGUI::forceRedraw() {
+ updateDisplay();
+ extendDirtyRect(Rect(_overlayBackup.w, _overlayBackup.h));
+ redraw();
+}
+
+void VirtualKeyboardGUI::redraw() {
+ assert(_kbdSurface);
+ int16 w = _dirtyRect.width();
+ int16 h = _dirtyRect.height();
+ if (w <= 0 || h <= 0) return;
+
+ Graphics::SurfaceKeyColored surf;
+ surf.create(w, h, sizeof(OverlayColor));
+
+ OverlayColor *dst = (OverlayColor *)surf.pixels;
+ const OverlayColor *src = (OverlayColor *) _overlayBackup.getBasePtr(_dirtyRect.left, _dirtyRect.top);
+
+ while (h--) {
+ memcpy(dst, src, surf.w * sizeof(OverlayColor));
+ dst += surf.w;
+ src += _overlayBackup.w;
+ }
+
+ surf.blit(_kbdSurface, _kbdBound.left - _dirtyRect.left,
+ _kbdBound.top - _dirtyRect.top, _kbdTransparentColor);
+ if (_displayEnabled) {
+ surf.blit(&_dispSurface, _dispX - _dirtyRect.left,
+ _dispY - _dirtyRect.top, _dispBackColor);
+ }
+ _system->copyRectToOverlay((OverlayColor*)surf.pixels, surf.w,
+ _dirtyRect.left, _dirtyRect.top, surf.w, surf.h);
+
+ surf.free();
+
+ resetDirtyRect();
+}
+
+uint VirtualKeyboardGUI::calculateEndIndex(const String& str, uint startIndex) {
+ int16 w = 0;
+ while (w <= _dispSurface.w && startIndex < str.size()) {
+ w += _dispFont->getCharWidth(str[startIndex++]);
+ }
+ if (w > _dispSurface.w) startIndex--;
+ return startIndex;
+}
+
+void VirtualKeyboardGUI::animateCaret() {
+ if (!_displayEnabled) return;
+
+ if (_system->getMillis() % kCaretBlinkTime < kCaretBlinkTime / 2) {
+ if (!_drawCaret) {
+ _drawCaret = true;
+ _dispSurface.drawLine(_caretX, 0, _caretX, _dispSurface.h, _dispForeColor);
+ extendDirtyRect(Rect(_dispX + _caretX, _dispY, _dispX + _caretX + 1, _dispY + _dispSurface.h));
+ }
+ } else {
+ if (_drawCaret) {
+ _drawCaret = false;
+ _dispSurface.drawLine(_caretX, 0, _caretX, _dispSurface.h, _dispBackColor);
+ extendDirtyRect(Rect(_dispX + _caretX, _dispY, _dispX + _caretX + 1, _dispY + _dispSurface.h));
+ }
+ }
+}
+
+void VirtualKeyboardGUI::updateDisplay() {
+ if (!_displayEnabled) return;
+
+ // calculate the text to display
+ uint cursorPos = _kbd->_keyQueue.getInsertIndex();
+ String wholeText = _kbd->_keyQueue.getString();
+ uint dispTextEnd;
+ if (_dispI > cursorPos)
+ _dispI = cursorPos;
+
+ dispTextEnd = calculateEndIndex(wholeText, _dispI);
+ while (cursorPos > dispTextEnd)
+ dispTextEnd = calculateEndIndex(wholeText, ++_dispI);
+
+ String dispText = String(wholeText.c_str() + _dispI, wholeText.c_str() + dispTextEnd);
+
+ // draw to display surface
+ _dispSurface.fillRect(Rect(_dispSurface.w, _dispSurface.h), _dispBackColor);
+ _dispFont->drawString(&_dispSurface, dispText, 0, 0, _dispSurface.w, _dispForeColor);
+
+ String beforeCaret(wholeText.c_str() + _dispI, wholeText.c_str() + cursorPos);
+ _caretX = _dispFont->getStringWidth(beforeCaret);
+ if (_drawCaret) _dispSurface.drawLine(_caretX, 0, _caretX, _dispSurface.h, _dispForeColor);
+
+ extendDirtyRect(Rect(_dispX, _dispY, _dispX + _dispSurface.w, _dispY + _dispSurface.h));
+}
+
+void VirtualKeyboardGUI::setupCursor() {
+ const byte palette[] = {
+ 255, 255, 255, 0,
+ 255, 255, 255, 0,
+ 171, 171, 171, 0,
+ 87, 87, 87, 0
+ };
+
+ CursorMan.pushCursorPalette(palette, 0, 4);
+ CursorMan.pushCursor(NULL, 0, 0, 0, 0);
+ CursorMan.showMouse(true);
+}
+
+void VirtualKeyboardGUI::animateCursor() {
+ int time = _system->getMillis();
+ if (time > _cursorAnimateTimer + kCursorAnimateDelay) {
+ for (int i = 0; i < 15; i++) {
+ if ((i < 6) || (i > 8)) {
+ _cursor[16 * 7 + i] = _cursorAnimateCounter;
+ _cursor[16 * i + 7] = _cursorAnimateCounter;
+ }
+ }
+
+ CursorMan.replaceCursor(_cursor, 16, 16, 7, 7);
+
+ _cursorAnimateTimer = time;
+ _cursorAnimateCounter = (_cursorAnimateCounter + 1) % 4;
+ }
+}
+
+void VirtualKeyboardGUI::removeCursor() {
+ CursorMan.popCursor();
+ CursorMan.popCursorPalette();
+}
+
+} // end of namespace Common
+
+#endif // #ifdef ENABLE_VKEYBD