mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-01 15:09:47 +00:00
40f9506163
This makes sense as a default for CLUT8 modes, but not really for anything else. As part of the gsoc2009-16bit merge, the default was changed to "all ones", with extra code in the SDL backend to truncate this to the depth of the mode. However, "all ones" (white) still isn't a very useful default for RGB modes. So rather than jumping through hoops to provide a bad default, it's better to remove the default altogether. Engines which relied on the old default of 255 have been updated to specify it explicitly. svn-id: r47118
476 lines
12 KiB
C++
476 lines
12 KiB
C++
/* 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$
|
|
*
|
|
*/
|
|
|
|
#ifdef ENABLE_VKEYBD
|
|
|
|
#include "backends/vkeybd/virtual-keyboard-gui.h"
|
|
|
|
#include "graphics/cursorman.h"
|
|
#include "graphics/fontman.h"
|
|
#include "gui/GuiManager.h"
|
|
|
|
namespace Common {
|
|
|
|
static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, OverlayColor transparent) {
|
|
if (surf_dst->bytesPerPixel != sizeof(OverlayColor) || surf_src->bytesPerPixel != sizeof(OverlayColor))
|
|
return;
|
|
|
|
const OverlayColor *src = (const OverlayColor *)surf_src->pixels;
|
|
int blitW = surf_src->w;
|
|
int blitH = surf_src->h;
|
|
|
|
// clip co-ordinates
|
|
if (x < 0) {
|
|
blitW += x;
|
|
src -= x;
|
|
x = 0;
|
|
}
|
|
if (y < 0) {
|
|
blitH += y;
|
|
src -= y * surf_src->w;
|
|
y = 0;
|
|
}
|
|
if (blitW > surf_dst->w - x)
|
|
blitW = surf_dst->w - x;
|
|
if (blitH > surf_dst->h - y)
|
|
blitH = surf_dst->h - y;
|
|
if (blitW <= 0 || blitH <= 0)
|
|
return;
|
|
|
|
OverlayColor *dst = (OverlayColor *)surf_dst->getBasePtr(x, y);
|
|
int dstAdd = surf_dst->w - blitW;
|
|
int srcAdd = surf_src->w - blitW;
|
|
|
|
for (int i = 0; i < blitH; ++i) {
|
|
for (int j = 0; j < blitW; ++j, ++dst, ++src) {
|
|
OverlayColor col = *src;
|
|
if (col != transparent)
|
|
*dst = col;
|
|
}
|
|
dst += dstAdd;
|
|
src += srcAdd;
|
|
}
|
|
}
|
|
|
|
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) {
|
|
assert(mode->image);
|
|
|
|
_kbdSurface = mode->image;
|
|
_kbdTransparentColor = mode->transparentColor;
|
|
_kbdBound.setWidth(_kbdSurface->w);
|
|
_kbdBound.setHeight(_kbdSurface->h);
|
|
|
|
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)) {
|
|
/* FIXME: We 'ab'use the kConsoleFont to get a font that fits in a small display_area on 320*240 keyboard images */
|
|
_dispFont = FontMan.getFontByUsage(Graphics::FontManager::kConsoleFont);
|
|
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() {
|
|
g_gui.checkScreenChange();
|
|
|
|
_lastScreenChanged = _system->getScreenChangeID();
|
|
int16 newScreenW = _system->getOverlayWidth();
|
|
int16 newScreenH = _system->getOverlayHeight();
|
|
|
|
if (_screenW != newScreenW || _screenH != newScreenH) {
|
|
_screenW = newScreenW;
|
|
_screenH = newScreenH;
|
|
|
|
_overlayBackup.create(_screenW, _screenH, sizeof(OverlayColor));
|
|
_system->grabOverlay((OverlayColor*)_overlayBackup.pixels, _overlayBackup.w);
|
|
|
|
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::Surface 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;
|
|
}
|
|
|
|
blit(&surf, _kbdSurface, _kbdBound.left - _dirtyRect.left,
|
|
_kbdBound.top - _dirtyRect.top, _kbdTransparentColor);
|
|
if (_displayEnabled) {
|
|
blit(&surf, &_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, 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, 255);
|
|
|
|
_cursorAnimateTimer = time;
|
|
_cursorAnimateCounter = (_cursorAnimateCounter + 1) % 4;
|
|
}
|
|
}
|
|
|
|
void VirtualKeyboardGUI::removeCursor() {
|
|
CursorMan.popCursor();
|
|
CursorMan.popCursorPalette();
|
|
}
|
|
|
|
} // End of namespace Common
|
|
|
|
#endif // #ifdef ENABLE_VKEYBD
|