From 0d3ad2dc8ad49c684e8a74285ec832335d7675e7 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 21 Oct 2018 22:53:35 -0700 Subject: GLK: Added TextGridWindow methods and support --- engines/gargoyle/draw.cpp | 32 ++ engines/gargoyle/draw.h | 38 ++ engines/gargoyle/events.cpp | 4 + engines/gargoyle/events.h | 2 + engines/gargoyle/glk_types.h | 14 + engines/gargoyle/module.mk | 2 + engines/gargoyle/window_mask.cpp | 336 ++++++++++++++ engines/gargoyle/window_mask.h | 67 +++ engines/gargoyle/windows.cpp | 944 ++++++++++++++++++++++++++++++++++----- engines/gargoyle/windows.h | 330 ++++++++++++-- 10 files changed, 1622 insertions(+), 147 deletions(-) create mode 100644 engines/gargoyle/draw.cpp create mode 100644 engines/gargoyle/draw.h create mode 100644 engines/gargoyle/window_mask.cpp create mode 100644 engines/gargoyle/window_mask.h (limited to 'engines') diff --git a/engines/gargoyle/draw.cpp b/engines/gargoyle/draw.cpp new file mode 100644 index 0000000000..86d5fb0f92 --- /dev/null +++ b/engines/gargoyle/draw.cpp @@ -0,0 +1,32 @@ +/* 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. + * + */ + +#include "gargoyle/draw.h" + +namespace Gargoyle { + +int Draw::drawStringUni(int x, int y, int fidx, byte *rgb, glui32 *s, int n, int spw) { + // TODO + return 0; +} + +} // End of namespace Gargoyle diff --git a/engines/gargoyle/draw.h b/engines/gargoyle/draw.h new file mode 100644 index 0000000000..61dfe1891a --- /dev/null +++ b/engines/gargoyle/draw.h @@ -0,0 +1,38 @@ +/* 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. + * + */ + +#ifndef GARGOYLE_DRAW_H +#define GARGOYLE_DRAW_H + +#include "common/events.h" +#include "gargoyle/glk_types.h" + +namespace Gargoyle { + +class Draw { +protected: + int drawStringUni(int x, int y, int fidx, byte *rgb, glui32 *s, int n, int spw); +}; + +} // End of namespace Gargoyle + +#endif diff --git a/engines/gargoyle/events.cpp b/engines/gargoyle/events.cpp index 1f7cc6a236..3373628a1e 100644 --- a/engines/gargoyle/events.cpp +++ b/engines/gargoyle/events.cpp @@ -32,4 +32,8 @@ void Events::clearEvent(Event *ev) { // TODO } +void Events::eventStore(EvType type, Window *win, uint32 val1, uint32 val2) { + // TODO +} + } // End of namespace Gargoyle diff --git a/engines/gargoyle/events.h b/engines/gargoyle/events.h index 476be40181..4ee94707ea 100644 --- a/engines/gargoyle/events.h +++ b/engines/gargoyle/events.h @@ -118,6 +118,8 @@ public: void pollEvents(); void clearEvent(Event *ev); + + void eventStore(EvType type, Window *win, uint32 val1 = 0, uint32 val2 = 0); }; } // End of namespace Gargoyle diff --git a/engines/gargoyle/glk_types.h b/engines/gargoyle/glk_types.h index 8f84cbe6a6..eaebb6f929 100644 --- a/engines/gargoyle/glk_types.h +++ b/engines/gargoyle/glk_types.h @@ -165,6 +165,20 @@ enum StyleHint { stylehint_just_RightFlush = 3, }; +/** + * These constants define the classes of opaque objects. It's a bit ugly to put + * them in this header file, since more classes may be added in the future. + * But if you find yourself stuck with an obsolete version of this file, + * adding new class definitions will be easy enough -- they will be numbered + * sequentially, and the numeric constants can be found in the Glk specification. + */ +enum giDisp { + gidisp_Class_Window = 0, + gidisp_Class_Stream = 1, + gidisp_Class_Fileref = 2, + gidisp_Class_Schannel = 3, +}; + #ifdef GLK_MODULE_IMAGE enum ImageAlign { diff --git a/engines/gargoyle/module.mk b/engines/gargoyle/module.mk index 925c66d359..46f2d31722 100644 --- a/engines/gargoyle/module.mk +++ b/engines/gargoyle/module.mk @@ -3,6 +3,7 @@ MODULE := engines/gargoyle MODULE_OBJS := \ conf.o \ detection.o \ + draw.o \ events.o \ fonts.o \ gargoyle.o \ @@ -10,6 +11,7 @@ MODULE_OBJS := \ picture.o \ streams.o \ string.o \ + window_mask.o \ windows.o \ scott/detection.o \ scott/scott.o diff --git a/engines/gargoyle/window_mask.cpp b/engines/gargoyle/window_mask.cpp new file mode 100644 index 0000000000..f0f6aa36bf --- /dev/null +++ b/engines/gargoyle/window_mask.cpp @@ -0,0 +1,336 @@ +/* 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. + * + */ + +#include "gargoyle/window_mask.h" +#include "gargoyle/conf.h" +#include "gargoyle/gargoyle.h" +#include "gargoyle/windows.h" + +namespace Gargoyle { + +int WindowMask::_lastX; +int WindowMask::_lastY; + +WindowMask::WindowMask() : _hor(0), _ver(0), _links(nullptr) { + _lastX = _lastY = 0; +} + +void WindowMask::resize(size_t x, size_t y) { + // Deallocate old storage + for (size_t i = 0; i < _hor; i++) { + if (_links[i]) + delete _links[i]; + } + + delete _links; + + _hor = x + 1; + _ver = y + 1; + + // allocate new storage + _links = new glui32 *[_hor]; + if (!_links) { + warning("resize_mask: out of memory"); + _hor = _ver = 0; + return; + } + + for (size_t i = 0; i < _hor; i++) { + _links[i] = new glui32[_ver]; + if (!_links[i]) { + warning("resize_mask: could not allocate new memory"); + return; + } + } + + _select.left = 0; + _select.top = 0; + _select.right = 0; + _select.bottom = 0; +} + +void WindowMask::putHyperlink(glui32 linkval, uint x0, uint y0, uint x1, uint y1) { + uint i, k; + size_t tx0 = x0 < x1 ? x0 : x1; + size_t tx1 = x0 < x1 ? x1 : x0; + size_t ty0 = y0 < y1 ? y0 : y1; + size_t ty1 = y0 < y1 ? y1 : y0; + + if (!_hor || !_ver) { + warning("putHyperlink: struct not initialized"); + return; + } + + if (tx0 >= _hor + || tx1 >= _hor + || ty0 >= _ver || ty1 >= _ver + || !_links[tx0] || !_links[tx1]) { + warning("putHyperlink: invalid range given"); + return; + } + + for (i = tx0; i < tx1; i++) { + for (k = ty0; k < ty1; k++) + _links[i][k] = linkval; + } +} + +glui32 WindowMask::getHyperlink(const Common::Point &pos) { + if (!_hor || !_ver) { + warning("getHyperlink: struct not initialized"); + return 0; + } + + if (pos.x >= (int16)_hor + || pos.y >= (int16)_ver + || !_links[pos.x]) { + warning("getHyperlink: invalid range given"); + return 0; + } + + return _links[pos.x][pos.y]; +} + +void WindowMask::startSelection(const Common::Point &pos) { + int tx, ty; + + if (!_hor || !_ver) { + warning("startSelection: mask not initialized"); + return; + } + + tx = MIN(pos.x, (int16)_hor); + ty = MIN(pos.y, (int16)_ver); + + _select.left = _lastX = tx; + _select.top = _lastY = ty; + _select.right = 0; + _select.bottom = 0; + + g_vm->_windows->selectionChanged(); +} + +void WindowMask::moveSelection(const Common::Point &pos) { + int tx, ty; + + if (ABS(pos.x - _lastX) < 5 && abs(pos.y - _lastY) < 5) + return; + + if (!_hor || !_ver) { + warning("moveSelection: mask not initialized"); + return; + } + + tx = MIN(pos.x, (int16)_hor); + ty = MIN(pos.y, (int16)_ver); + + _select.right = _lastX = tx; + _select.bottom = _lastY = ty; + + g_vm->_windows->selectionChanged(); +} + +void WindowMask::clearSelection() { + if (_select.left || _select.right + || _select.top || _select.bottom) + Windows::_forceRedraw = true; + + _select.left = 0; + _select.top = 0; + _select.right = 0; + _select.bottom = 0; + g_vm->_windows->clearClaimSelect(); +} + +int WindowMask::checkSelection(uint x0, uint y0, uint x1, uint y1) { + uint cx0, cx1, cy0, cy1; + + cx0 = _select.left < _select.right + ? _select.left + : _select.right; + + cx1 = _select.left < _select.right + ? _select.right + : _select.left; + + cy0 = _select.top < _select.bottom + ? _select.top + : _select.bottom; + + cy1 = _select.top < _select.bottom + ? _select.bottom + : _select.top; + + if (!cx0 || !cx1 || !cy0 || !cy1) + return false; + + if (cx0 >= x0 && cx0 <= x1 + && cy0 >= y0 && cy0 <= y1) + return true; + + if (cx0 >= x0 && cx0 <= x1 + && cy1 >= y0 && cy1 <= y1) + return true; + + if (cx1 >= x0 && cx1 <= x1 + && cy0 >= y0 && cy0 <= y1) + return true; + + if (cx1 >= x0 && cx1 <= x1 + && cy1 >= y0 && cy1 <= y1) + return true; + + return false; +} + +int WindowMask::getSelection(uint x0, uint y0, uint x1, uint y1, uint *rx0, uint *rx1) { + uint row, upper, lower, above, below; + int row_selected, found_left, found_right; + int from_right, from_below, is_above, is_below; + uint cx0, cx1, cy0, cy1; + + row = (y0 + y1) / 2; + upper = row - (row - y0) / 2; + lower = row + (y1 - row) / 2; + above = upper - (g_conf->_leading) / 2; + below = lower + (g_conf->_leading) / 2; + + cx0 = _select.left < _select.right + ? _select.left + : _select.right; + + cx1 = _select.left < _select.right + ? _select.right + : _select.left; + + cy0 = _select.top < _select.bottom + ? _select.top + : _select.bottom; + + cy1 = _select.top < _select.bottom + ? _select.bottom + : _select.top; + + row_selected = false; + + if ((cy0 >= upper && cy0 <= lower) + || (cy1 >= upper && cy1 <= lower)) + row_selected = true; + + if (row >= cy0 && row <= cy1) + row_selected = true; + + if (!row_selected) + return false; + + from_right = (_select.left != (int16)cx0); + from_below = (_select.top != (int16)cy0); + is_above = (above >= cy0 && above <= cy1); + is_below = (below >= cy0 && below <= cy1); + + *rx0 = 0; + *rx1 = 0; + + found_left = false; + found_right = false; + + if (is_above && is_below) { + *rx0 = x0; + *rx1 = x1; + found_left = true; + found_right = true; + } else if (!is_above && is_below) { + if (from_below) { + if (from_right) { + *rx0 = cx0; + *rx1 = x1; + found_left = true; + found_right = true; + } else { + *rx0 = cx1; + *rx1 = x1; + found_left = true; + found_right = true; + } + } else { + if (from_right) { + *rx0 = cx1; + *rx1 = x1; + found_left = true; + found_right = true; + } else { + *rx1 = x1; + found_right = true; + } + } + } else if (is_above && !is_below) { + if (from_below) { + if (from_right) { + *rx0 = x0; + *rx1 = cx1; + found_left = true; + found_right = true; + } else { + *rx0 = x0; + *rx1 = cx0; + found_left = true; + found_right = true; + } + } else { + if (from_right) { + if (x0 > cx0) + return false; + *rx0 = x0; + *rx1 = cx0; + found_left = true; + found_right = true; + } else { + *rx0 = x0; + found_left = true; + } + } + } + + if (found_left && found_right) + return true; + + for (uint i = x0; i <= x1; i++) { + if (i >= cx0 && i <= cx1) { + if (!found_left) { + *rx0 = i; + found_left = true; + if (found_right) + return true; + } else { + if (!found_right) + *rx1 = i; + } + } + } + + if (rx0 && !rx1) + *rx1 = x1; + + return (rx0 && rx1); +} + +} // End of namespace Gargoyle diff --git a/engines/gargoyle/window_mask.h b/engines/gargoyle/window_mask.h new file mode 100644 index 0000000000..db0d7e655d --- /dev/null +++ b/engines/gargoyle/window_mask.h @@ -0,0 +1,67 @@ +/* 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. + * + */ + +#ifndef GARGOYLE_WINDOW_MASK_H +#define GARGOYLE_WINDOW_MASK_H + +#include "common/rect.h" +#include "gargoyle/glk_types.h" + +namespace Gargoyle { + +class Window; + +struct WindowMask { + size_t _hor, _ver; + glui32 **_links; + Common::Rect _select; + + static int _lastX, _lastY; + + /** + * Constructor + */ + WindowMask(); + + /** + * Resize the links array + */ + void resize(size_t x, size_t y); + + void putHyperlink(glui32 linkval, uint x0, uint y0, uint x1, uint y1); + + glui32 getHyperlink(const Common::Point &pos); + + void startSelection(const Common::Point &pos); + + void moveSelection(const Common::Point &pos); + + void clearSelection(); + + int checkSelection(uint x0, uint y0, uint x1, uint y1); + + int getSelection(uint x0, uint y0, uint x1, uint y1, uint *rx0, uint *rx1); +}; + +} // End of namespace Gargoyle + +#endif diff --git a/engines/gargoyle/windows.cpp b/engines/gargoyle/windows.cpp index ac16471b37..a625040f8d 100644 --- a/engines/gargoyle/windows.cpp +++ b/engines/gargoyle/windows.cpp @@ -35,8 +35,15 @@ namespace Gargoyle { bool Windows::_overrideReverse; bool Windows::_overrideFgSet; bool Windows::_overrideBgSet; +bool Windows::_forceRedraw; int Windows::_overrideFgVal; int Windows::_overrideBgVal; +int Windows::_zcolor_fg; +int Windows::_zcolor_bg; +byte Windows::_zcolor_LightGrey[3]; +byte Windows::_zcolor_Foreground[3]; +byte Windows::_zcolor_Background[3]; +byte Windows::_zcolor_Bright[3]; /*--------------------------------------------------------------------------*/ @@ -76,13 +83,25 @@ Windows::iterator &Windows::iterator::operator++() { /*--------------------------------------------------------------------------*/ Windows::Windows(Graphics::Screen *screen) : - _screen(screen), _forceRedraw(true), _moreFocus(false), _windowList(nullptr), + _screen(screen), _moreFocus(false), _windowList(nullptr), _rootWin(nullptr), _focusWin(nullptr), _mask(nullptr), _claimSelect(0) { + _mask = new WindowMask(); _overrideReverse = false; _overrideFgSet = false; _overrideBgSet = false; + _forceRedraw = true; _overrideFgVal = 0; _overrideBgVal = 0; + _zcolor_fg = _zcolor_bg = 0; + + _zcolor_LightGrey[0] = _zcolor_LightGrey[1] = _zcolor_LightGrey[2] = 181; + _zcolor_Foreground[0] = _zcolor_Foreground[1] = _zcolor_Foreground[2] = 0; + _zcolor_Background[0] = _zcolor_Background[1] = _zcolor_Background[2] = 0; + _zcolor_Bright[0] = _zcolor_Bright[1] = _zcolor_Bright[2] = 0; +} + +Windows::~Windows() { + delete _mask; } Window *Windows::windowOpen(Window *splitwin, glui32 method, glui32 size, @@ -235,31 +254,43 @@ void Windows::rearrange() { } } -void Windows::clearSelection() { - if (!_mask) { - warning("clear_selection: mask not initialized"); - return; - } +void Windows::selectionChanged() { + _claimSelect = false; + _forceRedraw = true; + redraw(); +} - if (_mask->select.left || _mask->select.right - || _mask->select.top || _mask->select.bottom) - _forceRedraw = true; +void Windows::clearSelection() { + _mask->clearSelection(); +} - _mask->select = Common::Rect(); - _claimSelect = false; +void Windows::redraw() { + // TODO: gli_windows_redraw } void Windows::repaint(const Common::Rect &box) { // TODO } +void Windows::drawRect(int x0, int y0, int w, int h, const byte *rgb) { + // TODO +} + +byte *Windows::rgbShift(byte *rgb) { + _zcolor_Bright[0] = (rgb[0] + 0x30) < 0xff ? (rgb[0] + 0x30) : 0xff; + _zcolor_Bright[1] = (rgb[1] + 0x30) < 0xff ? (rgb[1] + 0x30) : 0xff; + _zcolor_Bright[2] = (rgb[2] + 0x30) < 0xff ? (rgb[2] + 0x30) : 0xff; + + return _zcolor_Bright; +} + /*--------------------------------------------------------------------------*/ Window::Window(Windows *windows, glui32 rock) : _magicnum(MAGIC_WINDOW_NUM), _windows(windows), _rock(rock), _type(0), _parent(nullptr), _next(nullptr), _prev(nullptr), - yadj(0), _lineRequest(0), _lineRequestUni(0), _charRequest(0), _charRequestUni(0), + _yAdj(0), _lineRequest(0), _lineRequestUni(0), _charRequest(0), _charRequestUni(0), _mouseRequest(0), _hyperRequest(0), _moreRequest(0), _scrollRequest(0), _imageLoaded(0), - _echoLineInput(true), _lineTerminators(nullptr), _termCt(0), _echoStream(nullptr) { + _echoLineInput(true), _lineTerminatorsBase(nullptr), _termCt(0), _echoStream(nullptr) { _attr.fgset = 0; _attr.bgset = 0; _attr.reverse = 0; @@ -276,6 +307,27 @@ Window::Window(Windows *windows, glui32 rock) : _magicnum(MAGIC_WINDOW_NUM), _stream = streams.addWindowStream(this); } +Window::~Window() { + if (g_vm->gli_unregister_obj) + (*g_vm->gli_unregister_obj)(this, gidisp_Class_Window, _dispRock); + + + _echoStream = nullptr; + delete _stream; + + delete[] _lineTerminatorsBase; + + Window *prev = _prev; + Window *next = _next; + + if (prev) + prev->_next = next; + else + _windows->_windowList = next; + if (next) + next->_prev = prev; +} + void Window::cancelLineEvent(Event *ev) { Event dummyEv; if (!ev) @@ -284,6 +336,31 @@ void Window::cancelLineEvent(Event *ev) { g_vm->_events->clearEvent(ev); } +void Window::requestLineEvent(char *buf, glui32 maxlen, glui32 initlen) { + warning("requestLineEvent: window does not support keyboard input"); +} + +void Window::requestLineEventUni(glui32 *buf, glui32 maxlen, glui32 initlen) { + warning("requestLineEventUni: window does not support keyboard input"); +} + +void Window::redraw() { + if (Windows::_forceRedraw) { + unsigned char *color = Windows::_overrideBgSet ? g_conf->_windowColor : _bgColor; + int y0 = _yAdj ? _bbox.top - _yAdj : _bbox.top; + _windows->drawRect(_bbox.left, y0, _bbox.width(), _bbox.bottom - y0, color); + } +} + +bool Window::checkTerminator(glui32 ch) { + if (ch == keycode_Escape) + return true; + else if (ch >= keycode_Func12 && ch <= keycode_Func1) + return true; + else + return false; +} + /*--------------------------------------------------------------------------*/ BlankWindow::BlankWindow(Windows *windows, uint32 rock) : Window(windows, rock) { @@ -338,9 +415,9 @@ void TextGridWindow::rearrange(const Common::Rect &box) { } void TextGridWindow::touch(int line) { - int y = bbox.top + line * g_conf->_leading; + int y = _bbox.top + line * g_conf->_leading; _lines[line].dirty = true; - _windows->repaint(Common::Rect(bbox.left, y, bbox.right, y + g_conf->_leading)); + _windows->repaint(Common::Rect(_bbox.left, y, _bbox.right, y + g_conf->_leading)); } glui32 TextGridWindow::getSplit(glui32 size, bool vertical) const { @@ -348,6 +425,251 @@ glui32 TextGridWindow::getSplit(glui32 size, bool vertical) const { size * g_conf->_cellH + g_conf->_tMarginY * 2; } +void TextGridWindow::putChar(unsigned char ch) { + +} + +void TextGridWindow::putCharUni(uint32 ch) { + TextGridRow *ln; + + // Canonicalize the cursor position. That is, the cursor may have been + // left outside the window area; wrap it if necessary. + if (_curX < 0) { + _curX = 0; + } else if (_curX >= _width) { + _curX = 0; + _curY++; + } + if (_curY < 0) + _curY = 0; + else if (_curY >= _height) + return; /* outside the window */ + + if (ch == '\n') { + /* a newline just moves the cursor. */ + _curY++; + _curX = 0; + return; + } + + touch(_curY); + + ln = &(_lines[_curY]); + ln->_chars[_curX] = ch; + ln->_attrs[_curX] = _attr; + + _curX++; + // We can leave the cursor outside the window, since it will be + // canonicalized next time a character is printed. +} + +bool TextGridWindow::unputCharUni(uint32 ch) { + TextGridRow *ln; + int oldx = _curX, oldy = _curY; + + /* Move the cursor back. */ + if (_curX >= _width) + _curX = _width - 1; + else + _curX--; + + /* Canonicalize the cursor position. That is, the cursor may have been + left outside the window area; wrap it if necessary. */ + if (_curX < 0) { + _curX = _width - 1; + _curY--; + } + if (_curY < 0) + _curY = 0; + else if (_curY >= _height) + return false; // outside the window + + if (ch == '\n') { + // a newline just moves the cursor. + if (_curX == _width - 1) + return 1; // deleted a newline + _curX = oldx; + _curY = oldy; + return 0; // it wasn't there */ + } + + ln = &(_lines[_curY]); + if (ln->_chars[_curX] == ch) { + ln->_chars[_curX] = ' '; + ln->_attrs[_curX].clear(); + touch(_curY); + return true; // deleted the char + } else { + _curX = oldx; + _curY = oldy; + return false; // it wasn't there + } +} + +void TextGridWindow::putBuffer(const unsigned char *buf, size_t len) { + // TODO +} + +void TextGridWindow::putBufferUni(const uint32 *buf, size_t len) { + // TODO +} + +void TextGridWindow::moveCursor(const Common::Point &pos) { + // If the values are negative, they're really huge positive numbers -- + // remember that they were cast from glui32. So set them huge and + // let canonicalization take its course. + _curX = (pos.x < 0) ? 32767 : pos.x; + _curY = (pos.y < 0) ? 32767 : pos.y; +} + +void TextGridWindow::clear() { + _attr.fgset = Windows::_overrideFgSet; + _attr.bgset = Windows::_overrideBgSet; + _attr.fgcolor = Windows::_overrideFgSet ? Windows::_overrideFgVal : 0; + _attr.bgcolor = Windows::_overrideBgSet ? Windows::_overrideBgVal : 0; + _attr.reverse = false; + + for (int k = 0; k < _height; k++) { + TextGridRow &ln = _lines[k]; + touch(k); + for (uint j = 0; j < ln._attrs.size(); ++j) { + ln._chars[j] = ' '; + ln._attrs[j].clear(); + } + } + + _curX = 0; + _curY = 0; +} + +void TextGridWindow::click(const Common::Point &newPos) { + int x = newPos.x - _bbox.left; + int y = newPos.y - _bbox.top; + + if (_lineRequest || _charRequest || _lineRequestUni || _charRequestUni + || _moreRequest || _scrollRequest) + _windows->setFocus(this); + + if (_mouseRequest) { + g_vm->_events->eventStore(evtype_MouseInput, this, x / g_conf->_cellW, y / g_conf->_leading); + _mouseRequest = false; + if (g_conf->_safeClicks) + g_vm->_events->_forceClick = true; + } + + if (_hyperRequest) { + glui32 linkval = _windows->getHyperlink(newPos); + if (linkval) + { + g_vm->_events->eventStore(evtype_Hyperlink, this, linkval, 0); + _hyperRequest = false; + if (g_conf->_safeClicks) + g_vm->_events->_forceClick = true; + } + } +} + +void TextGridWindow::requestLineEvent(char *buf, glui32 maxlen, glui32 initlen) { + if (_charRequest || _lineRequest || _charRequestUni || _lineRequestUni) + { + warning("request_line_event: window already has keyboard request"); + return; + } + + if ((int)maxlen > (_width - _curX)) + maxlen = (_width - _curX); + + _inBuf = buf; + _inMax = maxlen; + _inLen = 0; + _inCurs = 0; + _inOrgX = _curX; + _inOrgY = _curY; + _origAttr = _attr; + _attr.set(style_Input); + + if (initlen > maxlen) + initlen = maxlen; + + if (initlen) { + TextGridRow *ln = &_lines[_inOrgY]; + + for (glui32 ix = 0; ix < initlen; ix++) { + ln->_attrs[_inOrgX + ix].set(style_Input); + ln->_chars[_inOrgX + ix] = buf[ix]; + } + + _inCurs += initlen; + _inLen += initlen; + _curX = _inOrgX + _inCurs; + _curY = _inOrgY; + + touch(_inOrgY); + } + + if (_lineTerminatorsBase && _termCt) { + _lineTerminators = new glui32[_termCt + 1]; + + if (_lineTerminators) { + memcpy(_lineTerminators, _lineTerminatorsBase, _termCt * sizeof(glui32)); + _lineTerminators[_termCt] = 0; + } + } + + if (g_vm->gli_register_arr) + _inArrayRock = (*g_vm->gli_register_arr)(buf, maxlen, "&+#!Cn"); +} + +void TextGridWindow::requestLineEventUni(glui32 *buf, glui32 maxlen, glui32 initlen) { + if (_charRequest || _lineRequest || _charRequestUni || _lineRequestUni) { + warning("requestLineEventUni: window already has keyboard request"); + return; + } + + if ((int)maxlen > (_width - _curX)) + maxlen = (_width - _curX); + + _inBuf = buf; + _inMax = maxlen; + _inLen = 0; + _inCurs = 0; + _inOrgX = _curX; + _inOrgY = _curY; + _origAttr = _attr; + _attr.set(style_Input); + + if (initlen > maxlen) + initlen = maxlen; + + if (initlen) { + TextGridRow *ln = &(_lines[_inOrgY]); + + for (glui32 ix = 0; ix_attrs[_inOrgX + ix].set(style_Input); + ln->_chars[_inOrgX + ix] = buf[ix]; + } + + _inCurs += initlen; + _inLen += initlen; + _curX = _inOrgX + _inCurs; + _curY = _inOrgY; + + touch(_inOrgY); + } + + if (_lineTerminatorsBase && _termCt) { + _lineTerminators = new glui32[_termCt + 1]; + + if (_lineTerminators) { + memcpy(_lineTerminators, _lineTerminatorsBase, _termCt * sizeof(glui32)); + _lineTerminators[_termCt] = 0; + } + } + + if (g_vm->gli_register_arr) + _inArrayRock = (*g_vm->gli_register_arr)(buf, maxlen, "&+#!Iu"); +} + void TextGridWindow::cancelLineEvent(Event *ev) { int ix; void *inbuf; @@ -373,7 +695,7 @@ void TextGridWindow::cancelLineEvent(Event *ev) { if (!unicode) { for (ix = 0; ix<_inLen; ix++) { - glui32 ch = ln->chars[_inOrgX + ix]; + glui32 ch = ln->_chars[_inOrgX + ix]; if (ch > 0xff) ch = '?'; ((char *)inbuf)[ix] = (char)ch; @@ -382,7 +704,7 @@ void TextGridWindow::cancelLineEvent(Event *ev) { _echoStream->echoLine((char *)_inBuf, _inLen); } else { for (ix = 0; ix<_inLen; ix++) - ((glui32 *)inbuf)[ix] = ln->chars[_inOrgX + ix]; + ((glui32 *)inbuf)[ix] = ln->_chars[_inOrgX + ix]; if (_echoStream) _echoStream->echoLineUni((glui32 *)inbuf, _inLen); } @@ -413,14 +735,274 @@ void TextGridWindow::cancelLineEvent(Event *ev) { (*g_vm->gli_unregister_arr)(inbuf, inmax, unicode ? "&+#!Iu" : "&+#!Cn", inarrayrock); } +void TextGridWindow::acceptReadChar(glui32 arg) { + glui32 key; + + switch (arg) + { + case keycode_Erase: + key = keycode_Delete; + break; + case keycode_MouseWheelUp: + case keycode_MouseWheelDown: + return; + default: + key = arg; + } + + if (key > 0xff && key < (0xffffffff - keycode_MAXVAL + 1)) + { + if (!(_charRequestUni) || key > 0x10ffff) + key = keycode_Unknown; + } + + _charRequest = false; + _charRequestUni = false; + g_vm->_events->eventStore(evtype_CharInput, this, key, 0); +} + +void TextGridWindow::acceptLine(glui32 keycode) { + int ix; + void *inbuf; + int inmax; + gidispatch_rock_t inarrayrock; + TextGridRow *ln = &(_lines[_inOrgY]); + int unicode = _lineRequestUni; + + if (!_inBuf) + return; + + inbuf = _inBuf; + inmax = _inMax; + inarrayrock = _inArrayRock; + + if (!unicode) { + for (ix = 0; ix<_inLen; ix++) + ((char *)inbuf)[ix] = (char)ln->_chars[_inOrgX + ix]; + if (_echoStream) + _echoStream->echoLine((char *)inbuf, _inLen); + } else { + for (ix = 0; ix<_inLen; ix++) + ((glui32 *)inbuf)[ix] = ln->_chars[_inOrgX + ix]; + if (_echoStream) + _echoStream->echoLineUni((glui32 *)inbuf, _inLen); + } + + _curY = _inOrgY + 1; + _curX = 0; + _attr = _origAttr; + + if (_lineTerminators) + { + glui32 val2 = keycode; + if (val2 == keycode_Return) + val2 = 0; + g_vm->_events->eventStore(evtype_LineInput, this, _inLen, val2); + free(_lineTerminators); + _lineTerminators = NULL; + } else { + g_vm->_events->eventStore(evtype_LineInput, this, _inLen, 0); + } + _lineRequest = false; + _lineRequestUni = false; + _inBuf = NULL; + _inMax = 0; + _inOrgX = 0; + _inOrgY = 0; + + if (g_vm->gli_unregister_arr) + (*g_vm->gli_unregister_arr)(inbuf, inmax, unicode ? "&+#!Iu" : "&+#!Cn", inarrayrock); +} + +void TextGridWindow::acceptReadLine(glui32 arg) { + int ix; + TextGridRow *ln = &(_lines[_inOrgY]); + + if (!_inBuf) + return; + + if (_lineTerminators && checkTerminator(arg)) { + glui32 *cx; + for (cx = _lineTerminators; *cx; cx++) { + if (*cx == arg) { + acceptLine(arg); + return; + } + } + } + + switch (arg) { + + /* Delete keys, during line input. */ + + case keycode_Delete: + if (_inLen <= 0) + return; + if (_inCurs <= 0) + return; + for (ix = _inCurs; ix<_inLen; ix++) + ln->_chars[_inOrgX + ix - 1] = ln->_chars[_inOrgX + ix]; + ln->_chars[_inOrgX + _inLen - 1] = ' '; + _inCurs--; + _inLen--; + break; + + case keycode_Erase: + if (_inLen <= 0) + return; + if (_inCurs >= _inLen) + return; + for (ix = _inCurs; ix<_inLen - 1; ix++) + ln->_chars[_inOrgX + ix] = ln->_chars[_inOrgX + ix + 1]; + ln->_chars[_inOrgX + _inLen - 1] = ' '; + _inLen--; + break; + + case keycode_Escape: + if (_inLen <= 0) + return; + for (ix = 0; ix<_inLen; ix++) + ln->_chars[_inOrgX + ix] = ' '; + _inLen = 0; + _inCurs = 0; + break; + + /* Cursor movement keys, during line input. */ + + case keycode_Left: + if (_inCurs <= 0) + return; + _inCurs--; + break; + + case keycode_Right: + if (_inCurs >= _inLen) + return; + _inCurs++; + break; + + case keycode_Home: + if (_inCurs <= 0) + return; + _inCurs = 0; + break; + + case keycode_End: + if (_inCurs >= _inLen) + return; + _inCurs = _inLen; + break; + + case keycode_Return: + acceptLine(arg); + break; + + default: + if (_inLen >= _inMax) + return; + + if (arg < 32 || arg > 0xff) + return; + + if (g_conf->_caps && (arg > 0x60 && arg < 0x7b)) + arg -= 0x20; + + for (ix = _inLen; ix>_inCurs; ix--) + ln->_chars[_inOrgX + ix] = ln->_chars[_inOrgX + ix - 1]; + ln->_attrs[_inOrgX + _inLen].set(style_Input); + ln->_chars[_inOrgX + _inCurs] = arg; + + _inCurs++; + _inLen++; + } + + _curX = _inOrgX + _inCurs; + _curY = _inOrgY; + + touch(_inOrgY); +} + +void TextGridWindow::redraw() { + TextGridRow *ln; + int x0, y0; + int x, y, w; + int i, a, b, k, o; + glui32 link; + int font; + byte *fgcolor, *bgcolor; + + x0 = _bbox.left; + y0 = _bbox.top; + + for (i = 0; i < _height; i++) { + ln = &_lines[i]; + if (ln->dirty || Windows::_forceRedraw) { + ln->dirty = 0; + + x = x0; + y = y0 + i * g_conf->_leading; + + /* clear any stored hyperlink coordinates */ + _windows->setHyperlink(0, x0, y, x0 + g_conf->_cellW * _width, y + g_conf->_leading); + + a = 0; + for (b = 0; b < _width; b++) { + if (ln->_attrs[a] == ln->_attrs[b]) { + link = ln->_attrs[a].hyper; + font = ln->_attrs[a].attrFont(styles); + fgcolor = link ? g_conf->_linkColor : ln->_attrs[a].attrFg(styles); + bgcolor = ln->_attrs[a].attrBg(styles); + w = (b - a) * g_conf->_cellW; + _windows->drawRect(x, y, w, g_conf->_leading, bgcolor); + o = x; + + for (k = a; k < b; k++) { + drawStringUni(o * GLI_SUBPIX, + y + g_conf->_baseLine, font, fgcolor, + &ln->_chars[k], 1, -1); + o += g_conf->_cellW; + } + if (link) { + _windows->drawRect(x, y + g_conf->_baseLine + 1, w, + g_conf->_linkStyle, g_conf->_linkColor); + _windows->setHyperlink(link, x, y, x + w, y + g_conf->_leading); + } + x += w; + a = b; + } + } + link = ln->_attrs[a].hyper; + font = ln->_attrs[a].attrFont(styles); + fgcolor = link ? g_conf->_linkColor : ln->_attrs[a].attrFg(styles); + bgcolor = ln->_attrs[a].attrBg(styles); + w = (b - a) * g_conf->_cellW; + w += _bbox.right - (x + w); + _windows->drawRect(x, y, w, g_conf->_leading, bgcolor); + + o = x; + for (k = a; k < b; k++) { + drawStringUni(o * GLI_SUBPIX, + y + g_conf->_baseLine, font, fgcolor, + &ln->_chars[k], 1, -1); + o += g_conf->_cellW; + } + if (link) { + _windows->drawRect(x, y + g_conf->_baseLine + 1, w, + g_conf->_linkStyle, g_conf->_linkColor); + _windows->setHyperlink(link, x, y, x + w, y + g_conf->_leading); + } + } + } +} + /*--------------------------------------------------------------------------*/ void TextGridWindow::TextGridRow::resize(size_t newSize) { - chars.clear(); - attr.clear(); - chars.resize(newSize); - attr.resize(newSize); - Common::fill(&chars[0], &chars[0] + newSize, ' '); + _chars.clear(); + _attrs.clear(); + _chars.resize(newSize); + _attrs.resize(newSize); + Common::fill(&_chars[0], &_chars[0] + newSize, ' '); } /*--------------------------------------------------------------------------*/ @@ -465,8 +1047,8 @@ void TextBufferWindow::rearrange(const Common::Rect &box) { /* align text with bottom */ rnd = newhgt * g_conf->_cellH + g_conf->_tMarginY * 2; - yadj = (box.height() - rnd); - bbox.top += (box.height() - rnd); + _yAdj = (box.height() - rnd); + _bbox.top += (box.height() - rnd); if (newwid != _width) { _width = newwid; @@ -601,7 +1183,7 @@ void TextBufferWindow::reflow() { if (inputbyte != -1) { _inFence = _numChars; - putTextUnit(charbuf + inputbyte, p - inputbyte, _numChars, 0); + putTextUni(charbuf + inputbyte, p - inputbyte, _numChars, 0); _inCurs = _numChars; } @@ -620,54 +1202,12 @@ void TextBufferWindow::reflow() { void TextBufferWindow::touchScroll() { _windows->clearSelection(); - _windows->repaint(bbox); + _windows->repaint(_bbox); for (int i = 0; i < _scrollMax; i++) _lines[i].dirty = true; } -void TextBufferWindow::clear() { - int i; - - _attr.fgset = Windows::_overrideFgSet; - _attr.bgset = Windows::_overrideBgSet; - _attr.fgcolor = Windows::_overrideFgSet ? Windows::_overrideFgVal : 0; - _attr.bgcolor = Windows::_overrideBgSet ? Windows::_overrideBgVal : 0; - _attr.reverse = false; - - _ladjw = _radjw = 0; - _ladjn = _radjn = 0; - - _spaced = 0; - _dashed = 0; - - _numChars = 0; - - for (i = 0; i < _scrollBack; i++) { - _lines[i].len = 0; - - if (_lines[i].lpic) _lines[i].lpic->decrement(); - _lines[i].lpic = nullptr; - if (_lines[i].rpic) _lines[i].rpic->decrement(); - _lines[i].rpic = nullptr; - - _lines[i].lhyper = 0; - _lines[i].rhyper = 0; - _lines[i].lm = 0; - _lines[i].rm = 0; - _lines[i].newline = 0; - _lines[i].dirty = true; - _lines[i].repaint = false; - } - - _lastSeen = 0; - _scrollPos = 0; - _scrollMax = 0; - - for (i = 0; i < _height; i++) - touch(i); -} - bool TextBufferWindow::putPicture(Picture *pic, glui32 align, glui32 linkval) { if (align == imagealign_MarginRight) { @@ -696,7 +1236,29 @@ bool TextBufferWindow::putPicture(Picture *pic, glui32 align, glui32 linkval) { flowBreak(); } - return true ; + return true; +} + +void TextBufferWindow::flowBreak() { + // TODO +} + +void TextBufferWindow::putTextUni(const glui32 *buf, int len, int pos, int oldlen) { + // TODO +} + +void TextBufferWindow::touch(int line) { + int y = _bbox.top + g_conf->_tMarginY + (_height - line - 1) * g_conf->_leading; + _lines[line].dirty = 1; + _windows->clearSelection(); + _windows->repaint(Common::Rect(_bbox.left, y - 2, _bbox.right, y + g_conf->_leading + 2)); +} + +glui32 TextBufferWindow::getSplit(glui32 size, bool vertical) const { + return (vertical) ? size * g_conf->_cellW : size * g_conf->_cellH; +} + +void TextBufferWindow::putChar(unsigned char ch) { } void TextBufferWindow::putCharUni(glui32 ch) { @@ -712,10 +1274,10 @@ void TextBufferWindow::putCharUni(glui32 ch) { gli_tts_speak(&ch, 1); - pw = (bbox.right - bbox.left - g_conf->_tMarginX * 2 - gli_scroll_width) * GLI_SUBPIX; + pw = (_bbox.right - _bbox.left - g_conf->_tMarginX * 2 - gli_scroll_width) * GLI_SUBPIX; pw = pw - 2 * SLOP - radjw - ladjw; - color = gli_override_bg_set ? gli_window_color : bgcolor; + color = Windows::_overrideBgSet ? gli_window_color : bgcolor; // oops ... overflow if (numchars + 1 >= TBLINELEN) @@ -730,7 +1292,7 @@ void TextBufferWindow::putCharUni(glui32 ch) { // fails for 'tis a wonderful day in the '80s if (gli_conf_quotes > 1 && ch == '\'') { - if (numchars == 0 || leftquote(chars[numchars - 1])) + if (numchars == 0 || leftquote(_chars[numchars - 1])) ch = UNI_LSQUO; } @@ -742,7 +1304,7 @@ void TextBufferWindow::putCharUni(glui32 ch) { if (ch == '"') { - if (numchars == 0 || leftquote(chars[numchars - 1])) + if (numchars == 0 || leftquote(_chars[numchars - 1])) ch = UNI_LDQUO; else ch = UNI_RDQUO; @@ -810,23 +1372,23 @@ void TextBufferWindow::putCharUni(glui32 ch) { } } - chars[numchars] = ch; + _chars[numchars] = ch; attrs[numchars] = attr; numchars++; // kill spaces at the end for line width calculation linelen = numchars; - while (linelen > 1 && chars[linelen - 1] == ' ' + while (linelen > 1 && _chars[linelen - 1] == ' ' && styles[attrs[linelen - 1].style].bg == color && !styles[attrs[linelen - 1].style].reverse) linelen--; - if (calcwidth(dwin, chars, attrs, 0, linelen, -1) >= pw) + if (calcwidth(dwin, _chars, attrs, 0, linelen, -1) >= pw) { bpoint = numchars; for (i = numchars - 1; i > 0; i--) - if (chars[i] == ' ') + if (_chars[i] == ' ') { bpoint = i + 1; // skip space break; @@ -834,13 +1396,13 @@ void TextBufferWindow::putCharUni(glui32 ch) { saved = numchars - bpoint; - memcpy(bchars, chars + bpoint, saved * 4); + memcpy(bchars, _chars + bpoint, saved * 4); memcpy(battrs, attrs + bpoint, saved * sizeof(attr_t)); numchars = bpoint; scrolloneline(dwin, 0); - memcpy(chars, bchars, saved * 4); + memcpy(_chars, bchars, saved * 4); memcpy(attrs, battrs, saved * sizeof(attr_t)); numchars = saved; } @@ -849,23 +1411,83 @@ void TextBufferWindow::putCharUni(glui32 ch) { */ } -void TextBufferWindow::putTextUnit(const glui32 *buf, int len, int pos, int oldlen) { +bool TextBufferWindow::unputCharUni(uint32 ch) { // TODO + return false; } -void TextBufferWindow::flowBreak() { +void TextBufferWindow::putBuffer(const unsigned char *buf, size_t len) { // TODO } -void TextBufferWindow::touch(int line) { - int y = bbox.top + g_conf->_tMarginY + (_height - line - 1) * g_conf->_leading; - _lines[line].dirty = 1; - _windows->clearSelection(); - _windows->repaint(Common::Rect(bbox.left, y - 2, bbox.right, y + g_conf->_leading + 2)); +void TextBufferWindow::putBufferUni(const uint32 *buf, size_t len) { + // TODO } -glui32 TextBufferWindow::getSplit(glui32 size, bool vertical) const { - return (vertical) ? size * g_conf->_cellW : size * g_conf->_cellH; +void TextBufferWindow::moveCursor(const Common::Point &newPos) { + // TODO +} + +void TextBufferWindow::clear() { + int i; + + _attr.fgset = Windows::_overrideFgSet; + _attr.bgset = Windows::_overrideBgSet; + _attr.fgcolor = Windows::_overrideFgSet ? Windows::_overrideFgVal : 0; + _attr.bgcolor = Windows::_overrideBgSet ? Windows::_overrideBgVal : 0; + _attr.reverse = false; + + _ladjw = _radjw = 0; + _ladjn = _radjn = 0; + + _spaced = 0; + _dashed = 0; + + _numChars = 0; + + for (i = 0; i < _scrollBack; i++) { + _lines[i].len = 0; + + if (_lines[i].lpic) _lines[i].lpic->decrement(); + _lines[i].lpic = nullptr; + if (_lines[i].rpic) _lines[i].rpic->decrement(); + _lines[i].rpic = nullptr; + + _lines[i].lhyper = 0; + _lines[i].rhyper = 0; + _lines[i].lm = 0; + _lines[i].rm = 0; + _lines[i].newline = 0; + _lines[i].dirty = true; + _lines[i].repaint = false; + } + + _lastSeen = 0; + _scrollPos = 0; + _scrollMax = 0; + + for (i = 0; i < _height; i++) + touch(i); +} + +void TextBufferWindow::requestLineEvent(char *buf, glui32 maxlen, glui32 initlen) { + if (_charRequest || _lineRequest || _charRequestUni || _lineRequestUni) + { + warning("request_line_event: window already has keyboard request"); + return; + } + + // TODO +} + +void TextBufferWindow::requestLineEventUni(glui32 *buf, glui32 maxlen, glui32 initlen) { + if (_charRequest || _lineRequest || _charRequestUni || _lineRequestUni) + { + warning("request_line_event_uni: window already has keyboard request"); + return; + } + + // TODO } void TextBufferWindow::cancelLineEvent(Event *ev) { @@ -899,18 +1521,15 @@ void TextBufferWindow::cancelLineEvent(Event *ev) { if (len > inmax) len = inmax; - if (!unicode) - { - for (ix = 0; ix 0xff) ch = '?'; ((char *)inbuf)[ix] = (char)ch; } } - else - { + else { for (ix = 0; ixgli_unregister_arr)(inbuf, inmax, unicode ? "&+#!Iu" : "&+#!Cn", inarrayrock); } +void TextBufferWindow::redraw() { + // TODO +} + /*--------------------------------------------------------------------------*/ TextBufferWindow::TextBufferRow::TextBufferRow() : len(0), newline(0), dirty(false), repaint(false), @@ -974,7 +1598,7 @@ void GraphicsWindow::rearrange(const Common::Rect &box) { int oldw, oldh; Graphics::ManagedSurface *newSurface; - bbox = box; + _bbox = box; newwid = box.width(); newhgt = box.height(); @@ -1013,7 +1637,11 @@ void GraphicsWindow::rearrange(const Common::Rect &box) { void GraphicsWindow::touch() { _dirty = true; - _windows->repaint(bbox); + _windows->repaint(_bbox); +} + +void GraphicsWindow::redraw() { + // TODO } /*--------------------------------------------------------------------------*/ @@ -1034,14 +1662,14 @@ void PairWindow::rearrange(const Common::Rect &box) { int min, diff, split, splitwid, max; Window *ch1, *ch2; - bbox = box; + _bbox = box; if (_vertical) { - min = bbox.left; - max = bbox.right; + min = _bbox.left; + max = _bbox.right; } else { - min = bbox.top; - max = bbox.bottom; + min = _bbox.top; + max = _bbox.bottom; } diff = max - min; @@ -1080,23 +1708,23 @@ void PairWindow::rearrange(const Common::Rect &box) { } if (_vertical) { - box1.left = bbox.left; + box1.left = _bbox.left; box1.right = split; box2.left = split + splitwid; - box2.right = bbox.right; - box1.top = bbox.top; - box1.bottom = bbox.bottom; - box2.top = bbox.top; - box2.bottom = bbox.bottom; + box2.right = _bbox.right; + box1.top = _bbox.top; + box1.bottom = _bbox.bottom; + box2.top = _bbox.top; + box2.bottom = _bbox.bottom; } else { - box1.top = bbox.top; + box1.top = _bbox.top; box1.bottom = split; box2.top = split + splitwid; - box2.bottom = bbox.bottom; - box1.left = bbox.left; - box1.right = bbox.right; - box2.left = bbox.left; - box2.right = bbox.right; + box2.bottom = _bbox.bottom; + box1.left = _bbox.left; + box1.right = _bbox.right; + box2.left = _bbox.left; + box2.right = _bbox.right; } if (!_backward) { @@ -1111,6 +1739,10 @@ void PairWindow::rearrange(const Common::Rect &box) { ch2->rearrange(box2); } +void PairWindow::redraw() { + // TODO +} + /*--------------------------------------------------------------------------*/ void Attributes::clear() { @@ -1123,4 +1755,88 @@ void Attributes::clear() { style = 0; } +byte *Attributes::attrBg(WindowStyle *styles) { + int revset = reverse || (styles[style].reverse && !Windows::_overrideReverse); + + int zfset = fgset ? fgset : Windows::_overrideFgSet; + int zbset = bgset ? bgset : Windows::_overrideBgSet; + + int zfore = fgset ? fgcolor : Windows::_overrideFgVal; + int zback = bgset ? bgcolor : Windows::_overrideBgVal; + + if (zfset && zfore != Windows::_zcolor_fg) { + Windows::_zcolor_Foreground[0] = (zfore >> 16) & 0xff; + Windows::_zcolor_Foreground[1] = (zfore >> 8) & 0xff; + Windows::_zcolor_Foreground[2] = (zfore)& 0xff; + Windows::_zcolor_fg = zfore; + } + + if (zbset && zback != Windows::_zcolor_bg) { + Windows::_zcolor_Background[0] = (zback >> 16) & 0xff; + Windows::_zcolor_Background[1] = (zback >> 8) & 0xff; + Windows::_zcolor_Background[2] = (zback)& 0xff; + Windows::_zcolor_bg = zback; + } + + if (!revset) { + if (zbset) + return Windows::_zcolor_Background; + else + return styles[style].bg; + } else { + if (zfset) + if (zfore == zback) + return Windows::rgbShift(Windows::_zcolor_Foreground); + else + return Windows::_zcolor_Foreground; + else + if (zbset && !memcmp(styles[style].fg, Windows::_zcolor_Background, 3)) + return Windows::_zcolor_LightGrey; + else + return styles[style].fg; + } +} + +byte *Attributes::attrFg(WindowStyle *styles) { + int revset = reverse || (styles[style].reverse && !Windows::_overrideReverse); + + int zfset = fgset ? fgset : Windows::_overrideFgSet; + int zbset = bgset ? bgset : Windows::_overrideBgSet; + + int zfore = fgset ? fgcolor : Windows::_overrideFgVal; + int zback = bgset ? bgcolor : Windows::_overrideBgVal; + + if (zfset && zfore != Windows::_zcolor_fg) { + Windows::_zcolor_Foreground[0] = (zfore >> 16) & 0xff; + Windows::_zcolor_Foreground[1] = (zfore >> 8) & 0xff; + Windows::_zcolor_Foreground[2] = (zfore)& 0xff; + Windows::_zcolor_fg = zfore; + } + + if (zbset && zback != Windows::_zcolor_bg) { + Windows::_zcolor_Background[0] = (zback >> 16) & 0xff; + Windows::_zcolor_Background[1] = (zback >> 8) & 0xff; + Windows::_zcolor_Background[2] = (zback)& 0xff; + Windows::_zcolor_bg = zback; + } + + if (!revset) { + if (zfset) + if (zfore == zback) + return Windows::rgbShift(Windows::_zcolor_Foreground); + else + return Windows::_zcolor_Foreground; + else + if (zbset && !memcmp(styles[style].fg, Windows::_zcolor_Background, 3)) + return Windows::_zcolor_LightGrey; + else + return styles[style].fg; + } else { + if (zbset) + return Windows::_zcolor_Background; + else + return styles[style].bg; + } +} + } // End of namespace Gargoyle diff --git a/engines/gargoyle/windows.h b/engines/gargoyle/windows.h index 24043c6548..9a09641ca8 100644 --- a/engines/gargoyle/windows.h +++ b/engines/gargoyle/windows.h @@ -27,17 +27,18 @@ #include "common/list.h" #include "common/rect.h" #include "graphics/screen.h" +#include "gargoyle/draw.h" #include "gargoyle/events.h" #include "gargoyle/glk_types.h" #include "gargoyle/fonts.h" #include "gargoyle/picture.h" #include "gargoyle/streams.h" +#include "gargoyle/window_mask.h" namespace Gargoyle { class Window; class PairWindow; -struct WindowMask; #define HISTORYLEN 100 #define SCROLLBACK 512 @@ -47,6 +48,7 @@ struct WindowMask; * Main windows manager */ class Windows { + friend class Window; public: class iterator { private: @@ -82,7 +84,6 @@ private: Window * _windowList; ///< List of all windows Window *_rootWin; ///< The topmost window Window *_focusWin; ///< The window selected by the player - bool _forceRedraw; bool _moreFocus; bool _claimSelect; WindowMask *_mask; @@ -105,14 +106,27 @@ public: static bool _overrideReverse; static bool _overrideFgSet; static bool _overrideBgSet; + static bool _forceRedraw; static int _overrideFgVal; static int _overrideBgVal; + static int _zcolor_fg, _zcolor_bg; + static byte _zcolor_LightGrey[3]; + static byte _zcolor_Foreground[3]; + static byte _zcolor_Background[3]; + static byte _zcolor_Bright[3]; + + static byte *rgbShift(byte *rgb); public: /** * Constructor */ Windows(Graphics::Screen *screen); + /** + * Destructor + */ + ~Windows(); + /** * Open a new window */ @@ -124,13 +138,34 @@ public: */ Window *getRoot() const { return _rootWin; } + /** + * Gets the focused window + */ + Window *getFocusWindow() const { return _focusWin; } + + /** + * Setst the focused window + */ + void setFocus(Window *win) { _focusWin = win; } + void clearSelection(); + void selectionChanged(); + + void clearClaimSelect() { _claimSelect = false; } + + void redraw(); + /** * Repaint an area of the windows */ void repaint(const Common::Rect &box); + /** + * Draw an area of the windows + */ + void drawRect(int x0, int y0, int w, int h, const byte *rgb); + /** * Get an iterator that will move over the tree */ @@ -140,6 +175,18 @@ public: * Returns the end point of window iteration */ iterator end() { return iterator(nullptr); } + + /** + * Gets a hyperlink + */ + glui32 getHyperlink(const Common::Point &pos) { return _mask->getHyperlink(pos); } + + /** + * Sets a hyperlink + */ + void setHyperlink(glui32 linkval, uint x0, uint y0, uint x1, uint y1) { + return _mask->putHyperlink(linkval, x0, y0, x1, y1); + } }; /** @@ -176,21 +223,37 @@ struct Attributes { * Clear */ void clear(); -}; -struct WindowMask { - int hor; - int ver; - glui32 **links; - Common::Rect select; + /** + * Set the style + */ + void set(glui32 s) { + clear(); + style = s; + } + + /** + * Equality comparison + */ + bool operator==(const Attributes &src) { + return fgset == src.fgset && bgset == src.bgset && reverse == src.reverse + && style == src.style && fgcolor == src.fgcolor && bgcolor == src.bgcolor + && hyper == src.hyper; + } + + byte *attrBg(WindowStyle *styles); + byte *attrFg(WindowStyle *styles); - WindowMask() : hor(0), ver(0), links(nullptr) {} + /** + * Get the font from the attribute's style + */ + FACES attrFont(WindowStyle *styles) const { return styles[style].font; } }; /** * Window definition */ -class Window { +class Window : public Draw { public: Windows *_windows; glui32 _magicnum; @@ -199,8 +262,8 @@ public: Window *_parent; ///< pair window which contains this one Window *_next, *_prev; ///< in the big linked list of windows - Common::Rect bbox; - int yadj; + Common::Rect _bbox; + int _yAdj; Stream *_stream; ///< the window stream. Stream *_echoStream; ///< the window's echo stream, if any. @@ -216,7 +279,7 @@ public: int _imageLoaded; glui32 _echoLineInput; - glui32 *_lineTerminators; + glui32 *_lineTerminatorsBase; glui32 _termCt; Attributes _attr; @@ -224,6 +287,8 @@ public: byte _fgColor[3]; gidispatch_rock_t _dispRock; +protected: + bool checkTerminator(glui32 ch); public: /** * Constructor @@ -233,12 +298,12 @@ public: /** * Destructor */ - virtual ~Window() {} + virtual ~Window(); /** * Rearranges the window */ - virtual void rearrange(const Common::Rect &box) { bbox = box; } + virtual void rearrange(const Common::Rect &box) { _bbox = box; } /** * Get window split size within parent pair window @@ -246,29 +311,74 @@ public: virtual glui32 getSplit(glui32 size, bool vertical) const { return 0; } /** - * Cancel a line event + * Write a character */ - virtual void cancelLineEvent(Event *ev); + virtual void putChar(unsigned char ch) {} /** - * Write a character + * Write a unicode character */ - virtual void putChar(unsigned char ch) { /* TODO */ } + virtual void putCharUni(uint32 ch) {} /** - * Write a unicode character + * Unput a unicode character */ - virtual void putCharUni(uint32 ch) { /* TODO */ } + virtual bool unputCharUni(uint32 ch) { return false; } /** * Write a buffer */ - virtual void putBuffer(const unsigned char *buf, size_t len) { /* TODO */ } + virtual void putBuffer(const unsigned char *buf, size_t len) {} /** * Write a unicode character */ - virtual void putBufferUni(const uint32 *buf, size_t len) { /* TODO */ } + virtual void putBufferUni(const uint32 *buf, size_t len) {} + + /** + * Move the cursor + */ + virtual void moveCursor(const Common::Point &newPos) {} + + /** + * Clear the window + */ + virtual void clear() {} + + /** + * Click the window + */ + virtual void click(const Common::Point &newPos) {} + + /** + * Prepare for inputing a line + */ + virtual void requestLineEvent(char *buf, glui32 maxlen, glui32 initlen); + + /** + * Prepare for inputing a line + */ + virtual void requestLineEventUni(glui32 *buf, glui32 maxlen, glui32 initlen); + + /** + * Cancel an input line event + */ + virtual void cancelLineEvent(Event *ev); + + /** + * Cancel a mouse event + */ + virtual void cancelMouseEvent() {} + + /** + * Cancel a hyperlink event + */ + virtual void cancelHyperlinkEvent() {} + + /** + * Redraw the window + */ + virtual void redraw(); }; typedef Window *winid_t; @@ -291,8 +401,8 @@ class TextGridWindow : public Window { * Structure for a row within the grid window */ struct TextGridRow { - Common::Array chars; - Common::Array attr; + Common::Array _chars; + Common::Array _attrs; bool dirty; /** @@ -311,13 +421,25 @@ private: * Mark a given text row as modified */ void touch(int line); + + void acceptReadChar(glui32 arg); + + /** + * Return or enter, during line input. Ends line input. + */ + void acceptLine(glui32 keycode); + + /** + * Any regular key, during line input. + */ + void acceptReadLine(glui32 arg); public: int _width, _height; TextGridRows _lines; int _curX, _curY; ///< the window cursor position - ///< for line input + ///< for line input void *_inBuf; ///< unsigned char* for latin1, glui32* for unicode int _inOrgX, _inOrgY; int _inMax; @@ -349,9 +471,74 @@ public: virtual glui32 getSplit(glui32 size, bool vertical) const override; /** - * Cancel a line event + * Write a character + */ + virtual void putChar(unsigned char ch) override; + + /** + * Write a unicode character + */ + virtual void putCharUni(uint32 ch) override; + + /** + * Unput a unicode character + */ + virtual bool unputCharUni(uint32 ch) override; + + /** + * Write a buffer + */ + virtual void putBuffer(const unsigned char *buf, size_t len) override; + + /** + * Write a unicode character + */ + virtual void putBufferUni(const uint32 *buf, size_t len) override; + + /** + * Move the cursor + */ + virtual void moveCursor(const Common::Point &newPos) override; + + /** + * Clear the window + */ + virtual void clear() override; + + /** + * Click the window + */ + virtual void click(const Common::Point &newPos) override; + + /** + * Prepare for inputing a line + */ + virtual void requestLineEvent(char *buf, glui32 maxlen, glui32 initlen) override; + + /** + * Prepare for inputing a line + */ + virtual void requestLineEventUni(glui32 *buf, glui32 maxlen, glui32 initlen) override; + + /** + * Cancel an input line event */ virtual void cancelLineEvent(Event *ev) override; + + /** + * Cancel a mouse event + */ + virtual void cancelMouseEvent() override { _mouseRequest = false; } + + /** + * Cancel a hyperlink event + */ + virtual void cancelHyperlinkEvent() override { _hyperRequest = false; } + + /** + * Redraw the window + */ + virtual void redraw() override; }; /** @@ -385,8 +572,7 @@ private: void reflow(); void touchScroll(); bool putPicture(Picture *pic, glui32 align, glui32 linkval); - void putCharUni(glui32 ch); - void putTextUnit(const glui32 *buf, int len, int pos, int oldlen); + void putTextUni(const glui32 *buf, int len, int pos, int oldlen); void flowBreak(); /** @@ -460,14 +646,64 @@ public: virtual glui32 getSplit(glui32 size, bool vertical) const override; /** - * Cancel a line event + * Write a character */ - virtual void cancelLineEvent(Event *ev) override; + virtual void putChar(unsigned char ch) override; + + /** + * Write a unicode character + */ + virtual void putCharUni(uint32 ch) override; + + /** + * Unput a unicode character + */ + virtual bool unputCharUni(uint32 ch) override; + + /** + * Write a buffer + */ + virtual void putBuffer(const unsigned char *buf, size_t len) override; + + /** + * Write a unicode character + */ + virtual void putBufferUni(const uint32 *buf, size_t len) override; + + /** + * Move the cursor + */ + virtual void moveCursor(const Common::Point &newPos) override; /** * Clear the window */ - void clear(); + virtual void clear() override; + + /** + * Prepare for inputing a line + */ + virtual void requestLineEvent(char *buf, glui32 maxlen, glui32 initlen) override; + + /** + * Prepare for inputing a line + */ + virtual void requestLineEventUni(glui32 *buf, glui32 maxlen, glui32 initlen) override; + + /** + * Cancel an input line event + */ + virtual void cancelLineEvent(Event *ev) override; + + /** + * Cancel a hyperlink event + */ + virtual void cancelHyperlinkEvent() override { _hyperRequest = false; } + + /** + * Redraw the window + */ + virtual void redraw() override; }; /** @@ -479,7 +715,7 @@ private: public: unsigned char _bgnd[3]; bool _dirty; - int _w, _h; + glui32 _w, _h; Graphics::ManagedSurface *_surface; public: /** @@ -503,6 +739,29 @@ public: virtual glui32 getSplit(glui32 size, bool vertical) const override { return size; } + + /** + * Cancel a mouse event + */ + virtual void cancelMouseEvent() override { _mouseRequest = false; } + + /** + * Cancel a hyperlink event + */ + virtual void cancelHyperlinkEvent() override { _hyperRequest = false; } + + /** + * Redraw the window + */ + virtual void redraw() override; + + /** + * Get the window dimensions + */ + void getSize(glui32 *w, glui32 *h) { + *w = _w; + *h = _h; + } }; /** @@ -530,6 +789,11 @@ public: * Rearranges the window */ virtual void rearrange(const Common::Rect &box) override; + + /** + * Redraw the window + */ + virtual void redraw() override; }; } // End of namespace Gargoyle -- cgit v1.2.3