diff options
| author | Paul Gilbert | 2018-10-21 22:53:35 -0700 | 
|---|---|---|
| committer | Paul Gilbert | 2018-12-08 19:05:59 -0800 | 
| commit | 0d3ad2dc8ad49c684e8a74285ec832335d7675e7 (patch) | |
| tree | 94d4172819151b5e95952aee2cfd55418fe0000c | |
| parent | 71389c2dd2b0af525c8f458cee723b61dcfeb614 (diff) | |
| download | scummvm-rg350-0d3ad2dc8ad49c684e8a74285ec832335d7675e7.tar.gz scummvm-rg350-0d3ad2dc8ad49c684e8a74285ec832335d7675e7.tar.bz2 scummvm-rg350-0d3ad2dc8ad49c684e8a74285ec832335d7675e7.zip | |
GLK: Added TextGridWindow methods and support
| -rw-r--r-- | engines/gargoyle/draw.cpp | 32 | ||||
| -rw-r--r-- | engines/gargoyle/draw.h | 38 | ||||
| -rw-r--r-- | engines/gargoyle/events.cpp | 4 | ||||
| -rw-r--r-- | engines/gargoyle/events.h | 2 | ||||
| -rw-r--r-- | engines/gargoyle/glk_types.h | 14 | ||||
| -rw-r--r-- | engines/gargoyle/module.mk | 2 | ||||
| -rw-r--r-- | engines/gargoyle/window_mask.cpp | 336 | ||||
| -rw-r--r-- | engines/gargoyle/window_mask.h | 67 | ||||
| -rw-r--r-- | engines/gargoyle/windows.cpp | 944 | ||||
| -rw-r--r-- | engines/gargoyle/windows.h | 330 | 
10 files changed, 1622 insertions, 147 deletions
| 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<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, "&+#!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<len; ix++) -		{ +	if (!unicode) { +		for (ix = 0; ix<len; ix++) {  			glui32 ch = _chars[_inFence + ix];  			if (ch > 0xff)  				ch = '?';  			((char *)inbuf)[ix] = (char)ch;  		}  	} -	else -	{ +	else {  		for (ix = 0; ix<len; ix++)  			((glui32 *)inbuf)[ix] = _chars[_inFence + ix];  	} @@ -933,7 +1552,8 @@ void TextBufferWindow::cancelLineEvent(Event *ev) {  	if (_echoLineInput) {  		putCharUni('\n'); -	} else { +	} +	else {  		_numChars = _inFence;  		touch(0);  	} @@ -942,6 +1562,10 @@ void TextBufferWindow::cancelLineEvent(Event *ev) {  		(*g_vm->gli_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,8 +106,16 @@ 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 @@ -114,6 +123,11 @@ public:  	Windows(Graphics::Screen *screen);  	/** +	 * Destructor +	 */ +	~Windows(); + +	/**  	 * Open a new window  	 */  	Window *windowOpen(Window *splitwin, glui32 method, glui32 size, @@ -124,14 +138,35 @@ 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  	 */  	iterator begin() { return iterator(_windowList); } @@ -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<uint32> chars; -		Common::Array<Attributes> attr; +		Common::Array<uint32> _chars; +		Common::Array<Attributes> _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 | 
