Logo Search packages:      
Sourcecode: scummvm version File versions

virtual-keyboard-gui.cpp

/* 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: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-13-0/backends/vkeybd/virtual-keyboard-gui.cpp $
* $Id: virtual-keyboard-gui.cpp 35813 2009-01-11 00:20:27Z sev $
*
*/

#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

Generated by  Doxygen 1.6.0   Back to index