diff options
author | Paul Gilbert | 2018-10-21 23:14:50 -0700 |
---|---|---|
committer | Paul Gilbert | 2018-12-08 19:05:59 -0800 |
commit | 8708ed4f9aead0876d09dd9b6bb9096407cd961c (patch) | |
tree | 734e0a0e3f48f267df060a9eed45313dd86781f6 /engines/gargoyle | |
parent | 0d3ad2dc8ad49c684e8a74285ec832335d7675e7 (diff) | |
download | scummvm-rg350-8708ed4f9aead0876d09dd9b6bb9096407cd961c.tar.gz scummvm-rg350-8708ed4f9aead0876d09dd9b6bb9096407cd961c.tar.bz2 scummvm-rg350-8708ed4f9aead0876d09dd9b6bb9096407cd961c.zip |
GLK: Split the windows.cpp file into separate files for each window class
Diffstat (limited to 'engines/gargoyle')
-rw-r--r-- | engines/gargoyle/module.mk | 6 | ||||
-rw-r--r-- | engines/gargoyle/window_graphics.cpp | 89 | ||||
-rw-r--r-- | engines/gargoyle/window_graphics.h | 91 | ||||
-rw-r--r-- | engines/gargoyle/window_pair.cpp | 125 | ||||
-rw-r--r-- | engines/gargoyle/window_pair.h | 64 | ||||
-rw-r--r-- | engines/gargoyle/window_text_buffer.cpp | 602 | ||||
-rw-r--r-- | engines/gargoyle/window_text_buffer.h | 198 | ||||
-rw-r--r-- | engines/gargoyle/window_text_grid.cpp | 665 | ||||
-rw-r--r-- | engines/gargoyle/window_text_grid.h | 180 | ||||
-rw-r--r-- | engines/gargoyle/windows.cpp | 1459 | ||||
-rw-r--r-- | engines/gargoyle/windows.h | 407 |
11 files changed, 2063 insertions, 1823 deletions
diff --git a/engines/gargoyle/module.mk b/engines/gargoyle/module.mk index 46f2d31722..e684ff998b 100644 --- a/engines/gargoyle/module.mk +++ b/engines/gargoyle/module.mk @@ -11,8 +11,12 @@ MODULE_OBJS := \ picture.o \ streams.o \ string.o \ - window_mask.o \ windows.o \ + window_mask.o \ + window_graphics.o \ + window_pair.o \ + window_text_buffer.o \ + window_text_grid.o \ scott/detection.o \ scott/scott.o diff --git a/engines/gargoyle/window_graphics.cpp b/engines/gargoyle/window_graphics.cpp new file mode 100644 index 0000000000..cc9a5dd19e --- /dev/null +++ b/engines/gargoyle/window_graphics.cpp @@ -0,0 +1,89 @@ +/* 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_graphics.h" + +namespace Gargoyle { + +GraphicsWindow::GraphicsWindow(Windows *windows, uint32 rock) : Window(windows, rock), +_w(0), _h(0), _dirty(false), _surface(nullptr) { + _type = wintype_Graphics; + Common::copy(&_bgColor[0], &_bgColor[3], _bgnd); +} + +GraphicsWindow::~GraphicsWindow() { + delete _surface; +} + +void GraphicsWindow::rearrange(const Common::Rect &box) { + int newwid, newhgt; + int bothwid, bothhgt; + int oldw, oldh; + Graphics::ManagedSurface *newSurface; + + _bbox = box; + + newwid = box.width(); + newhgt = box.height(); + oldw = _w; + oldh = _h; + + if (newwid <= 0 || newhgt <= 0) { + _w = 0; + _h = 0; + delete _surface; + _surface = NULL; + return; + } + + bothwid = _w; + if (newwid < bothwid) + bothwid = newwid; + bothhgt = _h; + if (newhgt < bothhgt) + bothhgt = newhgt; + + newSurface = new Graphics::ManagedSurface(newwid, newhgt, + Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)); + + // If the new surface is equal or bigger than the old one, copy it over + if (_surface && bothwid && bothhgt) + newSurface->blitFrom(*_surface); + + delete _surface; + _surface = newSurface; + _w = newwid; + _h = newhgt; + + touch(); +} + +void GraphicsWindow::touch() { + _dirty = true; + _windows->repaint(_bbox); +} + +void GraphicsWindow::redraw() { + // TODO +} + +} // End of namespace Gargoyle diff --git a/engines/gargoyle/window_graphics.h b/engines/gargoyle/window_graphics.h new file mode 100644 index 0000000000..77e49105b2 --- /dev/null +++ b/engines/gargoyle/window_graphics.h @@ -0,0 +1,91 @@ +/* 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_GRAPHICS_H +#define GARGOYLE_WINDOW_GRAPHICS_H + +#include "gargoyle/windows.h" +#include "gargoyle/picture.h" + +namespace Gargoyle { + +/** + * Graphics window + */ +class GraphicsWindow : public Window { +private: + void touch(); +public: + unsigned char _bgnd[3]; + bool _dirty; + glui32 _w, _h; + Graphics::ManagedSurface *_surface; +public: + /** + * Constructor + */ + GraphicsWindow(Windows *windows, uint32 rock); + + /** + * Destructor + */ + virtual ~GraphicsWindow(); + + /** + * Rearranges the window + */ + virtual void rearrange(const Common::Rect &box) override; + + /** + * Get window split size within parent pair window + */ + 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; + } +}; + +} // End of namespace Gargoyle + +#endif diff --git a/engines/gargoyle/window_pair.cpp b/engines/gargoyle/window_pair.cpp new file mode 100644 index 0000000000..af3ed4ca38 --- /dev/null +++ b/engines/gargoyle/window_pair.cpp @@ -0,0 +1,125 @@ +/* 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_pair.h" +#include "gargoyle/conf.h" + +namespace Gargoyle { + +PairWindow::PairWindow(Windows *windows, glui32 method, Window *key, glui32 size) : + Window(windows, 0), + _dir(method & winmethod_DirMask), + _division(method & winmethod_DivisionMask), + _wBorder((method & winmethod_BorderMask) == winmethod_Border), + _vertical(_dir == winmethod_Left || _dir == winmethod_Right), + _backward(_dir == winmethod_Left || _dir == winmethod_Above), + _key(key), _size(size), _keyDamage(0), _child1(nullptr), _child2(nullptr) { + _type = wintype_Pair; +} + +void PairWindow::rearrange(const Common::Rect &box) { + Common::Rect box1, box2; + int min, diff, split, splitwid, max; + Window *ch1, *ch2; + + _bbox = box; + + if (_vertical) { + min = _bbox.left; + max = _bbox.right; + } else { + min = _bbox.top; + max = _bbox.bottom; + } + diff = max - min; + + // We now figure split. + if (_vertical) + splitwid = g_conf->_wPaddingX; // want border? + else + splitwid = g_conf->_wPaddingY; // want border? + + switch (_division) { + case winmethod_Proportional: + split = (diff * _size) / 100; + break; + + case winmethod_Fixed: + split = !_key ? 0 : _key->getSplit(_size, _vertical); + break; + + default: + split = diff / 2; + break; + } + + if (!_backward) + split = max - split - splitwid; + else + split = min + split; + + if (min >= max) { + split = min; + } else { + if (split < min) + split = min; + else if (split > max - splitwid) + split = max - splitwid; + } + + if (_vertical) { + 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; + } else { + 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; + } + + if (!_backward) { + ch1 = _child1; + ch2 = _child2; + } else { + ch1 = _child2; + ch2 = _child1; + } + + ch1->rearrange(box1); + ch2->rearrange(box2); +} + +void PairWindow::redraw() { + // TODO +} + +} // End of namespace Gargoyle diff --git a/engines/gargoyle/window_pair.h b/engines/gargoyle/window_pair.h new file mode 100644 index 0000000000..b25b324199 --- /dev/null +++ b/engines/gargoyle/window_pair.h @@ -0,0 +1,64 @@ +/* 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_PAIR_H +#define GARGOYLE_WINDOW_PAIR_H + +#include "gargoyle/windows.h" + +namespace Gargoyle { + +/** + * Pair window + */ +class PairWindow : public Window { +public: + Window *_child1, *_child2; + + /* split info... */ + glui32 _dir; ///< winmethod_Left, Right, Above, or Below + bool _vertical, _backward; ///< flags + glui32 _division; ///< winmethod_Fixed or winmethod_Proportional + Window *_key; ///< NULL or a leaf-descendant (not a Pair) + int _keyDamage; ///< used as scratch space in window closing + glui32 _size; ///< size value + glui32 _wBorder; ///< winMethod_Border, NoBorder +public: + /** + * Constructor + */ + PairWindow(Windows *windows, glui32 method, Window *key, glui32 size); + + /** + * Rearranges the window + */ + virtual void rearrange(const Common::Rect &box) override; + + /** + * Redraw the window + */ + virtual void redraw() override; +}; + +} // End of namespace Gargoyle + +#endif diff --git a/engines/gargoyle/window_text_buffer.cpp b/engines/gargoyle/window_text_buffer.cpp new file mode 100644 index 0000000000..1e85a24f8d --- /dev/null +++ b/engines/gargoyle/window_text_buffer.cpp @@ -0,0 +1,602 @@ +/* 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_text_buffer.h" +#include "gargoyle/conf.h" +#include "gargoyle/gargoyle.h" + +namespace Gargoyle { + +TextBufferWindow::TextBufferWindow(Windows *windows, uint32 rock) : Window(windows, rock), + _historyPos(0), _historyFirst(0), _historyPresent(0), _lastSeen(0), _scrollPos(0), + _scrollMax(0), _scrollBack(SCROLLBACK), _width(-1), _height(-1), _inBuf(nullptr), + _lineTerminators(nullptr), _echoLineInput(true), _ladjw(0), _radjw(0), _ladjn(0), + _radjn(0), _numChars(0), _chars(nullptr), _attrs(nullptr), + _spaced(0), _dashed(0), _copyBuf(0), _copyPos(0) { + _type = wintype_TextBuffer; + Common::fill(&_history[0], &_history[HISTORYLEN], nullptr); + + Common::copy(&g_conf->_tStyles[0], &g_conf->_tStyles[style_NUMSTYLES], styles); +} + +TextBufferWindow::~TextBufferWindow() { + if (_inBuf) { + if (g_vm->gli_unregister_arr) + (*g_vm->gli_unregister_arr)(_inBuf, _inMax, "&+#!Cn", _inArrayRock); + _inBuf = nullptr; + } + + delete[] _copyBuf; + delete[] _lineTerminators; + + for (int i = 0; i < _scrollBack; i++) { + if (_lines[i].lpic) + _lines[i].lpic->decrement(); + if (_lines[i].rpic) + _lines[i].rpic->decrement(); + } +} + +void TextBufferWindow::rearrange(const Common::Rect &box) { + Window::rearrange(box); + int newwid, newhgt; + int rnd; + + newwid = (box.width() - g_conf->_tMarginX * 2 - g_conf->_scrollWidth) / g_conf->_cellW; + newhgt = (box.height() - g_conf->_tMarginY * 2) / g_conf->_cellH; + + /* align text with bottom */ + rnd = newhgt * g_conf->_cellH + g_conf->_tMarginY * 2; + _yAdj = (box.height() - rnd); + _bbox.top += (box.height() - rnd); + + if (newwid != _width) { + _width = newwid; + reflow(); + } + + if (newhgt != _height) { + /* scroll up if we obscure new lines */ + if (_lastSeen >= newhgt - 1) + _scrollPos += (_height - newhgt); + + _height = newhgt; + + /* keep window within 'valid' lines */ + if (_scrollPos > _scrollMax - _height + 1) + _scrollPos = _scrollMax - _height + 1; + if (_scrollPos < 0) + _scrollPos = 0; + touchScroll(); + + /* allocate copy buffer */ + if (_copyBuf) + delete[] _copyBuf; + _copyBuf = new glui32[_height * TBLINELEN]; + + for (int i = 0; i < (_height * TBLINELEN); i++) + _copyBuf[i] = 0; + + _copyPos = 0; + } +} + +void TextBufferWindow::reflow() { + int inputbyte = -1; + Attributes curattr, oldattr; + int i, k, p, s; + int x; + + if (_height < 4 || _width < 20) + return; + + _lines[0].len = _numChars; + + /* allocate temp buffers */ + Attributes *attrbuf = new Attributes[SCROLLBACK * TBLINELEN]; + glui32 *charbuf = new glui32[SCROLLBACK * TBLINELEN]; + int *alignbuf = new int[SCROLLBACK]; + Picture **pictbuf = new Picture *[SCROLLBACK]; + glui32 *hyperbuf = new glui32[SCROLLBACK]; + int *offsetbuf = new int[SCROLLBACK]; + + if (!attrbuf || !charbuf || !alignbuf || !pictbuf || !hyperbuf || !offsetbuf) { + delete[] attrbuf; + delete[] charbuf; + delete[] alignbuf; + delete[] pictbuf; + delete[] hyperbuf; + delete[] offsetbuf; + return; + } + + /* copy text to temp buffers */ + + oldattr = _attr; + curattr.clear(); + + x = 0; + p = 0; + s = _scrollMax < SCROLLBACK ? _scrollMax : SCROLLBACK - 1; + + for (k = s; k >= 0; k--) { + if (k == 0 && _lineRequest) + inputbyte = p + _inFence; + + if (_lines[k].lpic) { + offsetbuf[x] = p; + alignbuf[x] = imagealign_MarginLeft; + pictbuf[x] = _lines[k].lpic; + + if (pictbuf[x]) pictbuf[x]->increment(); + hyperbuf[x] = _lines[k].lhyper; + x++; + } + + if (_lines[k].rpic) { + offsetbuf[x] = p; + alignbuf[x] = imagealign_MarginRight; + pictbuf[x] = _lines[k].rpic; + if (pictbuf[x]) pictbuf[x]->increment(); + hyperbuf[x] = _lines[k].rhyper; + x++; + } + + for (i = 0; i < _lines[k].len; i++) { + attrbuf[p] = curattr = _lines[k].attr[i]; + charbuf[p] = _lines[k].chars[i]; + p++; + } + + if (_lines[k].newline) { + attrbuf[p] = curattr; + charbuf[p] = '\n'; + p++; + } + } + + offsetbuf[x] = -1; + + /* clear window */ + + clear(); + + /* and dump text back */ + + x = 0; + for (i = 0; i < p; i++) { + if (i == inputbyte) + break; + _attr = attrbuf[i]; + + if (offsetbuf[x] == i) { + putPicture(pictbuf[x], alignbuf[x], hyperbuf[x]); + x++; + } + + putCharUni(charbuf[i]); + } + + /* terribly sorry about this... */ + _lastSeen = 0; + _scrollPos = 0; + + if (inputbyte != -1) { + _inFence = _numChars; + putTextUni(charbuf + inputbyte, p - inputbyte, _numChars, 0); + _inCurs = _numChars; + } + + // free temp buffers + delete[] attrbuf; + delete[] charbuf; + delete[] alignbuf; + delete[] pictbuf; + delete[] hyperbuf; + delete[] offsetbuf; + + _attr = oldattr; + + touchScroll(); +} + +void TextBufferWindow::touchScroll() { + _windows->clearSelection(); + _windows->repaint(_bbox); + + for (int i = 0; i < _scrollMax; i++) + _lines[i].dirty = true; +} + +bool TextBufferWindow::putPicture(Picture *pic, glui32 align, glui32 linkval) { + if (align == imagealign_MarginRight) + { + if (_lines[0].rpic || _numChars) + return false; + + _radjw = (pic->w + g_conf->_tMarginX) * GLI_SUBPIX; + _radjn = (pic->h + g_conf->_cellH - 1) / g_conf->_cellH; + _lines[0].rpic = pic; + _lines[0].rm = _radjw; + _lines[0].rhyper = linkval; + } else { + if (align != imagealign_MarginLeft && _numChars) + putCharUni('\n'); + + if (_lines[0].lpic || _numChars) + return false; + + _ladjw = (pic->w + g_conf->_tMarginX) * GLI_SUBPIX; + _ladjn = (pic->h + g_conf->_cellH - 1) / g_conf->_cellH; + _lines[0].lpic = pic; + _lines[0].lm = _ladjw; + _lines[0].lhyper = linkval; + + if (align != imagealign_MarginLeft) + flowBreak(); + } + + 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) { + /* + glui32 bchars[TBLINELEN]; + Attributes battrs[TBLINELEN]; + int pw; + int bpoint; + int saved; + int i; + int linelen; + unsigned char *color; + + gli_tts_speak(&ch, 1); + + pw = (_bbox.right - _bbox.left - g_conf->_tMarginX * 2 - gli_scroll_width) * GLI_SUBPIX; + pw = pw - 2 * SLOP - radjw - ladjw; + + color = Windows::_overrideBgSet ? gli_window_color : bgcolor; + + // oops ... overflow + if (numchars + 1 >= TBLINELEN) + scrolloneline(dwin, 0); + + if (ch == '\n') { + scrolloneline(dwin, 1); + return; + } + + if (gli_conf_quotes) { + // fails for 'tis a wonderful day in the '80s + if (gli_conf_quotes > 1 && ch == '\'') + { + if (numchars == 0 || leftquote(_chars[numchars - 1])) + ch = UNI_LSQUO; + } + + if (ch == '`') + ch = UNI_LSQUO; + + if (ch == '\'') + ch = UNI_RSQUO; + + if (ch == '"') + { + if (numchars == 0 || leftquote(_chars[numchars - 1])) + ch = UNI_LDQUO; + else + ch = UNI_RDQUO; + } + } + + if (gli_conf_dashes && attr.style != style_Preformatted) + { + if (ch == '-') + { + dashed++; + if (dashed == 2) + { + numchars--; + if (gli_conf_dashes == 2) + ch = UNI_NDASH; + else + ch = UNI_MDASH; + } + if (dashed == 3) + { + numchars--; + ch = UNI_MDASH; + dashed = 0; + } + } + else + dashed = 0; + } + + if (gli_conf_spaces && attr.style != style_Preformatted + && styles[attr.style].bg == color + && !styles[attr.style].reverse) + { + // turn (period space space) into (period space) + if (gli_conf_spaces == 1) + { + if (ch == '.') + spaced = 1; + else if (ch == ' ' && spaced == 1) + spaced = 2; + else if (ch == ' ' && spaced == 2) + { + spaced = 0; + return; + } + else + spaced = 0; + } + + // Turn (per sp x) into (per sp sp x) + if (gli_conf_spaces == 2) + { + if (ch == '.') + spaced = 1; + else if (ch == ' ' && spaced == 1) + spaced = 2; + else if (ch != ' ' && spaced == 2) + { + spaced = 0; + win_textbuffer_putchar_uni(win, ' '); + } + else + spaced = 0; + } + } + + _chars[numchars] = ch; + attrs[numchars] = attr; + numchars++; + + // kill spaces at the end for line width calculation + linelen = numchars; + 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) + { + bpoint = numchars; + + for (i = numchars - 1; i > 0; i--) + if (_chars[i] == ' ') + { + bpoint = i + 1; // skip space + break; + } + + saved = numchars - bpoint; + + 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(attrs, battrs, saved * sizeof(attr_t)); + numchars = saved; + } + + touch(0); + */ +} + +bool TextBufferWindow::unputCharUni(uint32 ch) { + // TODO + return false; +} + +void TextBufferWindow::putBuffer(const unsigned char *buf, size_t len) { + // TODO +} + +void TextBufferWindow::putBufferUni(const uint32 *buf, size_t len) { + // TODO +} + +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) { + gidispatch_rock_t inarrayrock; + int ix; + int len; + void *inbuf; + int inmax; + int unicode = _lineRequestUni; + Event dummyEv; + + if (!ev) + ev = &dummyEv; + + g_vm->_events->clearEvent(ev); + + if (!_lineRequest && !_lineRequestUni) + return; + + if (!_inBuf) + return; + + inbuf = _inBuf; + inmax = _inMax; + inarrayrock = _inArrayRock; + + len = _numChars - _inFence; + if (_echoStream) + _echoStream->echoLineUni(_chars + _inFence, len); + + if (len > inmax) + len = inmax; + + if (!unicode) { + for (ix = 0; ix<len; ix++) { + glui32 ch = _chars[_inFence + ix]; + if (ch > 0xff) + ch = '?'; + ((char *)inbuf)[ix] = (char)ch; + } + } + else { + for (ix = 0; ix<len; ix++) + ((glui32 *)inbuf)[ix] = _chars[_inFence + ix]; + } + + _attr = _origAttr; + + ev->_type = evtype_LineInput; + ev->_window = this; + ev->_val1 = len; + ev->_val2 = 0; + + _lineRequest = false; + _lineRequestUni = false; + if (_lineTerminators) { + free(_lineTerminators); + _lineTerminators = nullptr; + } + _inBuf = nullptr; + _inMax = 0; + + if (_echoLineInput) { + putCharUni('\n'); + } + else { + _numChars = _inFence; + touch(0); + } + + if (g_vm->gli_unregister_arr) + (*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), + lpic(nullptr), rpic(nullptr), lhyper(0), rhyper(0), lm(0), rm(0) { +} + +void TextBufferWindow::TextBufferRow::resize(size_t newSize) { + chars.clear(); + attr.clear(); + chars.resize(newSize); + attr.resize(newSize); + Common::fill(&chars[0], &chars[0] + newSize, ' '); +} + +} // End of namespace Gargoyle diff --git a/engines/gargoyle/window_text_buffer.h b/engines/gargoyle/window_text_buffer.h new file mode 100644 index 0000000000..f7427d7320 --- /dev/null +++ b/engines/gargoyle/window_text_buffer.h @@ -0,0 +1,198 @@ +/* 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_TEXT_BUFFER_H +#define GARGOYLE_WINDOW_TEXT_BUFFER_H + +#include "gargoyle/windows.h" +#include "gargoyle/picture.h" + +namespace Gargoyle { + +/** + * Text Buffer window + */ +class TextBufferWindow : public Window { + /** + * Structure for a row within the window + */ + struct TextBufferRow { + Common::Array<uint32> chars; + Common::Array<Attributes> attr; + int len, newline; + bool dirty, repaint; + Picture *lpic, *rpic; + glui32 lhyper, rhyper; + int lm, rm; + + /** + * Constructor + */ + TextBufferRow(); + + /** + * Resize the row + */ + void resize(size_t newSize); + }; + typedef Common::Array<TextBufferRow> TextBufferRows; +private: + void reflow(); + void touchScroll(); + bool putPicture(Picture *pic, glui32 align, glui32 linkval); + void putTextUni(const glui32 *buf, int len, int pos, int oldlen); + void flowBreak(); + + /** + * Mark a given text row as modified + */ + void touch(int line); +public: + int _width, _height; + int _spaced; + int _dashed; + + TextBufferRows _lines; + int _scrollBack; + + int _numChars; ///< number of chars in last line: lines[0] + glui32 *_chars; ///< alias to lines[0].chars + Attributes *_attrs; ///< alias to lines[0].attrs + + ///< adjust margins temporarily for images + int _ladjw; + int _ladjn; + int _radjw; + int _radjn; + + /* Command history. */ + glui32 *_history[HISTORYLEN]; + int _historyPos; + int _historyFirst, _historyPresent; + + /* for paging */ + int _lastSeen; + int _scrollPos; + int _scrollMax; + + /* for line input */ + void *_inBuf; ///< unsigned char* for latin1, glui32* for unicode + int _inMax; + long _inFence; + long _inCurs; + Attributes _origAttr; + gidispatch_rock_t _inArrayRock; + + glui32 _echoLineInput; + glui32 *_lineTerminators; + + /* style hints and settings */ + WindowStyle styles[style_NUMSTYLES]; + + /* for copy selection */ + glui32 *_copyBuf; + int _copyPos; +public: + /** + * Constructor + */ + TextBufferWindow(Windows *windows, uint32 rock); + + /** + * Destructor + */ + virtual ~TextBufferWindow(); + + /** + * Rearranges the window + */ + virtual void rearrange(const Common::Rect &box) override; + + /** + * Get window split size within parent pair window + */ + virtual glui32 getSplit(glui32 size, bool vertical) const override; + + /** + * 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; + + /** + * 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; +}; + +} // End of namespace Gargoyle + +#endif diff --git a/engines/gargoyle/window_text_grid.cpp b/engines/gargoyle/window_text_grid.cpp new file mode 100644 index 0000000000..41444ed33c --- /dev/null +++ b/engines/gargoyle/window_text_grid.cpp @@ -0,0 +1,665 @@ +/* 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_text_grid.h" +#include "gargoyle/conf.h" +#include "gargoyle/gargoyle.h" + +namespace Gargoyle { + +TextGridWindow::TextGridWindow(Windows *windows, uint32 rock) : Window(windows, rock) { + _type = wintype_TextGrid; + _width = _height = 0; + _curX = _curY = 0; + _inBuf = nullptr; + _inOrgX = _inOrgY = 0; + _inMax = 0; + _inCurs = _inLen = 0; + _inArrayRock.num = 0; + _lineTerminators = nullptr; + + Common::copy(&g_conf->_gStyles[0], &g_conf->_gStyles[style_NUMSTYLES], styles); +} + +TextGridWindow::~TextGridWindow() { + if (_inBuf) { + if (g_vm->gli_unregister_arr) + (*g_vm->gli_unregister_arr)(_inBuf, _inMax, "&+#!Cn", _inArrayRock); + _inBuf = nullptr; + } + + delete[] _lineTerminators; +} + +void TextGridWindow::rearrange(const Common::Rect &box) { + Window::rearrange(box); + int newwid, newhgt; + + newwid = box.width() / g_conf->_cellW; + newhgt = box.height() / g_conf->_cellH; + + if (newwid == _width && newhgt == _height) + return; + + _lines.resize(newhgt); + for (int y = 0; y < newhgt; ++y) { + _lines[y].resize(newwid); + touch(y); + } + + _attr.clear(); + _width = newwid; + _height = newhgt; +} + +void TextGridWindow::touch(int line) { + 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)); +} + +glui32 TextGridWindow::getSplit(glui32 size, bool vertical) const { + return vertical ? size * g_conf->_cellW + g_conf->_tMarginX * 2 : + 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; + int inmax; + int unicode = _lineRequestUni; + gidispatch_rock_t inarrayrock; + TextGridRow *ln = &_lines[_inOrgY]; + Event dummyEv; + + if (!ev) + ev = &dummyEv; + + g_vm->_events->clearEvent(ev); + + if (!_lineRequest && !_lineRequestUni) + return; + + + inbuf = _inBuf; + inmax = _inMax; + inarrayrock = _inArrayRock; + + if (!unicode) { + for (ix = 0; ix<_inLen; ix++) + { + glui32 ch = ln->_chars[_inOrgX + ix]; + if (ch > 0xff) + ch = '?'; + ((char *)inbuf)[ix] = (char)ch; + } + 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; + + ev->_type = evtype_LineInput; + ev->_window = this; + ev->_val1 = _inLen; + ev->_val2 = 0; + + _lineRequest = false; + _lineRequestUni = false; + + if (_lineTerminators) { + free(_lineTerminators); + _lineTerminators = nullptr; + } + + _inBuf = nullptr; + _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::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(); + _attrs.clear(); + _chars.resize(newSize); + _attrs.resize(newSize); + Common::fill(&_chars[0], &_chars[0] + newSize, ' '); +} + +} // End of namespace Gargoyle diff --git a/engines/gargoyle/window_text_grid.h b/engines/gargoyle/window_text_grid.h new file mode 100644 index 0000000000..2c72dde458 --- /dev/null +++ b/engines/gargoyle/window_text_grid.h @@ -0,0 +1,180 @@ +/* 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_TEXT_GRID_H +#define GARGOYLE_WINDOW_TEXT_GRID_H + +#include "gargoyle/windows.h" + +namespace Gargoyle { + +/** + * Text Grid window + */ +class TextGridWindow : public Window { + /** + * Structure for a row within the grid window + */ + struct TextGridRow { + Common::Array<uint32> _chars; + Common::Array<Attributes> _attrs; + bool dirty; + + /** + * Constructor + */ + TextGridRow() : dirty(false) {} + + /** + * Resize the row + */ + void resize(size_t newSize); + }; + typedef Common::Array<TextGridRow> TextGridRows; +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 + void *_inBuf; ///< unsigned char* for latin1, glui32* for unicode + int _inOrgX, _inOrgY; + int _inMax; + int _inCurs, _inLen; + Attributes _origAttr; + gidispatch_rock_t _inArrayRock; + glui32 *_lineTerminators; + + WindowStyle styles[style_NUMSTYLES]; ///< style hints and settings +public: + /** + * Constructor + */ + TextGridWindow(Windows *windows, uint32 rock); + + /** + * Destructor + */ + virtual ~TextGridWindow(); + + /** + * Rearranges the window + */ + virtual void rearrange(const Common::Rect &box) override; + + /** + * Get window split size within parent pair window + */ + virtual glui32 getSplit(glui32 size, bool vertical) const override; + + /** + * 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; +}; + +} // End of namespace Gargoyle + +#endif diff --git a/engines/gargoyle/windows.cpp b/engines/gargoyle/windows.cpp index a625040f8d..cf9b7de77d 100644 --- a/engines/gargoyle/windows.cpp +++ b/engines/gargoyle/windows.cpp @@ -21,6 +21,10 @@ */ #include "gargoyle/windows.h" +#include "gargoyle/window_graphics.h" +#include "gargoyle/window_pair.h" +#include "gargoyle/window_text_buffer.h" +#include "gargoyle/window_text_grid.h" #include "gargoyle/conf.h" #include "gargoyle/gargoyle.h" #include "gargoyle/streams.h" @@ -29,9 +33,6 @@ namespace Gargoyle { -#define MAGIC_WINDOW_NUM (9876) -#define GLI_SUBPIX 8 - bool Windows::_overrideReverse; bool Windows::_overrideFgSet; bool Windows::_overrideBgSet; @@ -47,41 +48,6 @@ byte Windows::_zcolor_Bright[3]; /*--------------------------------------------------------------------------*/ -Windows::iterator &Windows::iterator::operator++() { - if (!_current) - return *this; - - PairWindow *pairWin = dynamic_cast<PairWindow *>(_current); - - if (pairWin) { - _current = !pairWin->_backward ? pairWin->_child1 : pairWin->_child2; - } else { - while (_current->_parent) { - pairWin = dynamic_cast<PairWindow *>(_current->_parent); - - if (!pairWin->_backward) { - if (_current == pairWin->_child1) { - _current = pairWin->_child2; - return *this; - } - } else { - if (_current == pairWin->_child2) { - _current = pairWin->_child1; - return *this; - } - } - - _current = pairWin; - } - - _current = nullptr; - } - - return *this; -} - -/*--------------------------------------------------------------------------*/ - Windows::Windows(Graphics::Screen *screen) : _screen(screen), _moreFocus(false), _windowList(nullptr), _rootWin(nullptr), _focusWin(nullptr), _mask(nullptr), _claimSelect(0) { @@ -286,9 +252,44 @@ byte *Windows::rgbShift(byte *rgb) { /*--------------------------------------------------------------------------*/ -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), +Windows::iterator &Windows::iterator::operator++() { + if (!_current) + return *this; + + PairWindow *pairWin = dynamic_cast<PairWindow *>(_current); + + if (pairWin) { + _current = !pairWin->_backward ? pairWin->_child1 : pairWin->_child2; + } else { + while (_current->_parent) { + pairWin = dynamic_cast<PairWindow *>(_current->_parent); + + if (!pairWin->_backward) { + if (_current == pairWin->_child1) { + _current = pairWin->_child2; + return *this; + } + } else { + if (_current == pairWin->_child2) { + _current = pairWin->_child1; + return *this; + } + } + + _current = pairWin; + } + + _current = nullptr; + } + + return *this; +} + +/*--------------------------------------------------------------------------*/ + +Window::Window(Windows *windows, glui32 rock) : _windows(windows), _rock(rock), + _type(0), _parent(nullptr), _next(nullptr), _prev(nullptr), _yAdj(0), + _lineRequest(0), _lineRequestUni(0), _charRequest(0), _charRequestUni(0), _mouseRequest(0), _hyperRequest(0), _moreRequest(0), _scrollRequest(0), _imageLoaded(0), _echoLineInput(true), _lineTerminatorsBase(nullptr), _termCt(0), _echoStream(nullptr) { _attr.fgset = 0; @@ -369,1382 +370,6 @@ BlankWindow::BlankWindow(Windows *windows, uint32 rock) : Window(windows, rock) /*--------------------------------------------------------------------------*/ -TextGridWindow::TextGridWindow(Windows *windows, uint32 rock) : Window(windows, rock) { - _type = wintype_TextGrid; - _width = _height = 0; - _curX = _curY = 0; - _inBuf = nullptr; - _inOrgX = _inOrgY = 0; - _inMax = 0; - _inCurs = _inLen = 0; - _inArrayRock.num = 0; - _lineTerminators = nullptr; - - Common::copy(&g_conf->_gStyles[0], &g_conf->_gStyles[style_NUMSTYLES], styles); -} - -TextGridWindow::~TextGridWindow() { - if (_inBuf) { - if (g_vm->gli_unregister_arr) - (*g_vm->gli_unregister_arr)(_inBuf, _inMax, "&+#!Cn", _inArrayRock); - _inBuf = nullptr; - } - - delete[] _lineTerminators; -} - -void TextGridWindow::rearrange(const Common::Rect &box) { - Window::rearrange(box); - int newwid, newhgt; - - newwid = box.width() / g_conf->_cellW; - newhgt = box.height() / g_conf->_cellH; - - if (newwid == _width && newhgt == _height) - return; - - _lines.resize(newhgt); - for (int y = 0; y < newhgt; ++y) { - _lines[y].resize(newwid); - touch(y); - } - - _attr.clear(); - _width = newwid; - _height = newhgt; -} - -void TextGridWindow::touch(int line) { - 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)); -} - -glui32 TextGridWindow::getSplit(glui32 size, bool vertical) const { - return vertical ? size * g_conf->_cellW + g_conf->_tMarginX * 2 : - 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; - int inmax; - int unicode = _lineRequestUni; - gidispatch_rock_t inarrayrock; - TextGridRow *ln = &_lines[_inOrgY]; - Event dummyEv; - - if (!ev) - ev = &dummyEv; - - g_vm->_events->clearEvent(ev); - - if (!_lineRequest && !_lineRequestUni) - return; - - - inbuf = _inBuf; - inmax = _inMax; - inarrayrock = _inArrayRock; - - if (!unicode) { - for (ix = 0; ix<_inLen; ix++) - { - glui32 ch = ln->_chars[_inOrgX + ix]; - if (ch > 0xff) - ch = '?'; - ((char *)inbuf)[ix] = (char)ch; - } - 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; - - ev->_type = evtype_LineInput; - ev->_window = this; - ev->_val1 = _inLen; - ev->_val2 = 0; - - _lineRequest = false; - _lineRequestUni = false; - - if (_lineTerminators) { - free(_lineTerminators); - _lineTerminators = nullptr; - } - - _inBuf = nullptr; - _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::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(); - _attrs.clear(); - _chars.resize(newSize); - _attrs.resize(newSize); - Common::fill(&_chars[0], &_chars[0] + newSize, ' '); -} - -/*--------------------------------------------------------------------------*/ - -TextBufferWindow::TextBufferWindow(Windows *windows, uint32 rock) : Window(windows, rock), - _historyPos(0), _historyFirst(0), _historyPresent(0), _lastSeen(0), _scrollPos(0), - _scrollMax(0), _scrollBack(SCROLLBACK), _width(-1), _height(-1), _inBuf(nullptr), - _lineTerminators(nullptr), _echoLineInput(true), _ladjw(0), _radjw(0), _ladjn(0), - _radjn(0), _numChars(0), _chars(nullptr), _attrs(nullptr), - _spaced(0), _dashed(0), _copyBuf(0), _copyPos(0) { - _type = wintype_TextBuffer; - Common::fill(&_history[0], &_history[HISTORYLEN], nullptr); - - Common::copy(&g_conf->_tStyles[0], &g_conf->_tStyles[style_NUMSTYLES], styles); -} - -TextBufferWindow::~TextBufferWindow() { - if (_inBuf) { - if (g_vm->gli_unregister_arr) - (*g_vm->gli_unregister_arr)(_inBuf, _inMax, "&+#!Cn", _inArrayRock); - _inBuf = nullptr; - } - - delete[] _copyBuf; - delete[] _lineTerminators; - - for (int i = 0; i < _scrollBack; i++) { - if (_lines[i].lpic) - _lines[i].lpic->decrement(); - if (_lines[i].rpic) - _lines[i].rpic->decrement(); - } -} - -void TextBufferWindow::rearrange(const Common::Rect &box) { - Window::rearrange(box); - int newwid, newhgt; - int rnd; - - newwid = (box.width() - g_conf->_tMarginX * 2 - g_conf->_scrollWidth) / g_conf->_cellW; - newhgt = (box.height() - g_conf->_tMarginY * 2) / g_conf->_cellH; - - /* align text with bottom */ - rnd = newhgt * g_conf->_cellH + g_conf->_tMarginY * 2; - _yAdj = (box.height() - rnd); - _bbox.top += (box.height() - rnd); - - if (newwid != _width) { - _width = newwid; - reflow(); - } - - if (newhgt != _height) { - /* scroll up if we obscure new lines */ - if (_lastSeen >= newhgt - 1) - _scrollPos += (_height - newhgt); - - _height = newhgt; - - /* keep window within 'valid' lines */ - if (_scrollPos > _scrollMax - _height + 1) - _scrollPos = _scrollMax - _height + 1; - if (_scrollPos < 0) - _scrollPos = 0; - touchScroll(); - - /* allocate copy buffer */ - if (_copyBuf) - delete[] _copyBuf; - _copyBuf = new glui32[_height * TBLINELEN]; - - for (int i = 0; i < (_height * TBLINELEN); i++) - _copyBuf[i] = 0; - - _copyPos = 0; - } -} - -void TextBufferWindow::reflow() { - int inputbyte = -1; - Attributes curattr, oldattr; - int i, k, p, s; - int x; - - if (_height < 4 || _width < 20) - return; - - _lines[0].len = _numChars; - - /* allocate temp buffers */ - Attributes *attrbuf = new Attributes[SCROLLBACK * TBLINELEN]; - glui32 *charbuf = new glui32[SCROLLBACK * TBLINELEN]; - int *alignbuf = new int[SCROLLBACK]; - Picture **pictbuf = new Picture *[SCROLLBACK]; - glui32 *hyperbuf = new glui32[SCROLLBACK]; - int *offsetbuf = new int[SCROLLBACK]; - - if (!attrbuf || !charbuf || !alignbuf || !pictbuf || !hyperbuf || !offsetbuf) { - delete[] attrbuf; - delete[] charbuf; - delete[] alignbuf; - delete[] pictbuf; - delete[] hyperbuf; - delete[] offsetbuf; - return; - } - - /* copy text to temp buffers */ - - oldattr = _attr; - curattr.clear(); - - x = 0; - p = 0; - s = _scrollMax < SCROLLBACK ? _scrollMax : SCROLLBACK - 1; - - for (k = s; k >= 0; k--) { - if (k == 0 && _lineRequest) - inputbyte = p + _inFence; - - if (_lines[k].lpic) { - offsetbuf[x] = p; - alignbuf[x] = imagealign_MarginLeft; - pictbuf[x] = _lines[k].lpic; - - if (pictbuf[x]) pictbuf[x]->increment(); - hyperbuf[x] = _lines[k].lhyper; - x++; - } - - if (_lines[k].rpic) { - offsetbuf[x] = p; - alignbuf[x] = imagealign_MarginRight; - pictbuf[x] = _lines[k].rpic; - if (pictbuf[x]) pictbuf[x]->increment(); - hyperbuf[x] = _lines[k].rhyper; - x++; - } - - for (i = 0; i < _lines[k].len; i++) { - attrbuf[p] = curattr = _lines[k].attr[i]; - charbuf[p] = _lines[k].chars[i]; - p++; - } - - if (_lines[k].newline) { - attrbuf[p] = curattr; - charbuf[p] = '\n'; - p++; - } - } - - offsetbuf[x] = -1; - - /* clear window */ - - clear(); - - /* and dump text back */ - - x = 0; - for (i = 0; i < p; i++) { - if (i == inputbyte) - break; - _attr = attrbuf[i]; - - if (offsetbuf[x] == i) { - putPicture(pictbuf[x], alignbuf[x], hyperbuf[x]); - x++; - } - - putCharUni(charbuf[i]); - } - - /* terribly sorry about this... */ - _lastSeen = 0; - _scrollPos = 0; - - if (inputbyte != -1) { - _inFence = _numChars; - putTextUni(charbuf + inputbyte, p - inputbyte, _numChars, 0); - _inCurs = _numChars; - } - - // free temp buffers - delete[] attrbuf; - delete[] charbuf; - delete[] alignbuf; - delete[] pictbuf; - delete[] hyperbuf; - delete[] offsetbuf; - - _attr = oldattr; - - touchScroll(); -} - -void TextBufferWindow::touchScroll() { - _windows->clearSelection(); - _windows->repaint(_bbox); - - for (int i = 0; i < _scrollMax; i++) - _lines[i].dirty = true; -} - -bool TextBufferWindow::putPicture(Picture *pic, glui32 align, glui32 linkval) { - if (align == imagealign_MarginRight) - { - if (_lines[0].rpic || _numChars) - return false; - - _radjw = (pic->w + g_conf->_tMarginX) * GLI_SUBPIX; - _radjn = (pic->h + g_conf->_cellH - 1) / g_conf->_cellH; - _lines[0].rpic = pic; - _lines[0].rm = _radjw; - _lines[0].rhyper = linkval; - } else { - if (align != imagealign_MarginLeft && _numChars) - putCharUni('\n'); - - if (_lines[0].lpic || _numChars) - return false; - - _ladjw = (pic->w + g_conf->_tMarginX) * GLI_SUBPIX; - _ladjn = (pic->h + g_conf->_cellH - 1) / g_conf->_cellH; - _lines[0].lpic = pic; - _lines[0].lm = _ladjw; - _lines[0].lhyper = linkval; - - if (align != imagealign_MarginLeft) - flowBreak(); - } - - 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) { - /* - glui32 bchars[TBLINELEN]; - Attributes battrs[TBLINELEN]; - int pw; - int bpoint; - int saved; - int i; - int linelen; - unsigned char *color; - - gli_tts_speak(&ch, 1); - - pw = (_bbox.right - _bbox.left - g_conf->_tMarginX * 2 - gli_scroll_width) * GLI_SUBPIX; - pw = pw - 2 * SLOP - radjw - ladjw; - - color = Windows::_overrideBgSet ? gli_window_color : bgcolor; - - // oops ... overflow - if (numchars + 1 >= TBLINELEN) - scrolloneline(dwin, 0); - - if (ch == '\n') { - scrolloneline(dwin, 1); - return; - } - - if (gli_conf_quotes) { - // fails for 'tis a wonderful day in the '80s - if (gli_conf_quotes > 1 && ch == '\'') - { - if (numchars == 0 || leftquote(_chars[numchars - 1])) - ch = UNI_LSQUO; - } - - if (ch == '`') - ch = UNI_LSQUO; - - if (ch == '\'') - ch = UNI_RSQUO; - - if (ch == '"') - { - if (numchars == 0 || leftquote(_chars[numchars - 1])) - ch = UNI_LDQUO; - else - ch = UNI_RDQUO; - } - } - - if (gli_conf_dashes && attr.style != style_Preformatted) - { - if (ch == '-') - { - dashed++; - if (dashed == 2) - { - numchars--; - if (gli_conf_dashes == 2) - ch = UNI_NDASH; - else - ch = UNI_MDASH; - } - if (dashed == 3) - { - numchars--; - ch = UNI_MDASH; - dashed = 0; - } - } - else - dashed = 0; - } - - if (gli_conf_spaces && attr.style != style_Preformatted - && styles[attr.style].bg == color - && !styles[attr.style].reverse) - { - // turn (period space space) into (period space) - if (gli_conf_spaces == 1) - { - if (ch == '.') - spaced = 1; - else if (ch == ' ' && spaced == 1) - spaced = 2; - else if (ch == ' ' && spaced == 2) - { - spaced = 0; - return; - } - else - spaced = 0; - } - - // Turn (per sp x) into (per sp sp x) - if (gli_conf_spaces == 2) - { - if (ch == '.') - spaced = 1; - else if (ch == ' ' && spaced == 1) - spaced = 2; - else if (ch != ' ' && spaced == 2) - { - spaced = 0; - win_textbuffer_putchar_uni(win, ' '); - } - else - spaced = 0; - } - } - - _chars[numchars] = ch; - attrs[numchars] = attr; - numchars++; - - // kill spaces at the end for line width calculation - linelen = numchars; - 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) - { - bpoint = numchars; - - for (i = numchars - 1; i > 0; i--) - if (_chars[i] == ' ') - { - bpoint = i + 1; // skip space - break; - } - - saved = numchars - bpoint; - - 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(attrs, battrs, saved * sizeof(attr_t)); - numchars = saved; - } - - touch(0); - */ -} - -bool TextBufferWindow::unputCharUni(uint32 ch) { - // TODO - return false; -} - -void TextBufferWindow::putBuffer(const unsigned char *buf, size_t len) { - // TODO -} - -void TextBufferWindow::putBufferUni(const uint32 *buf, size_t len) { - // TODO -} - -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) { - gidispatch_rock_t inarrayrock; - int ix; - int len; - void *inbuf; - int inmax; - int unicode = _lineRequestUni; - Event dummyEv; - - if (!ev) - ev = &dummyEv; - - g_vm->_events->clearEvent(ev); - - if (!_lineRequest && !_lineRequestUni) - return; - - if (!_inBuf) - return; - - inbuf = _inBuf; - inmax = _inMax; - inarrayrock = _inArrayRock; - - len = _numChars - _inFence; - if (_echoStream) - _echoStream->echoLineUni(_chars + _inFence, len); - - if (len > inmax) - len = inmax; - - if (!unicode) { - for (ix = 0; ix<len; ix++) { - glui32 ch = _chars[_inFence + ix]; - if (ch > 0xff) - ch = '?'; - ((char *)inbuf)[ix] = (char)ch; - } - } - else { - for (ix = 0; ix<len; ix++) - ((glui32 *)inbuf)[ix] = _chars[_inFence + ix]; - } - - _attr = _origAttr; - - ev->_type = evtype_LineInput; - ev->_window = this; - ev->_val1 = len; - ev->_val2 = 0; - - _lineRequest = false; - _lineRequestUni = false; - if (_lineTerminators) { - free(_lineTerminators); - _lineTerminators = nullptr; - } - _inBuf = nullptr; - _inMax = 0; - - if (_echoLineInput) { - putCharUni('\n'); - } - else { - _numChars = _inFence; - touch(0); - } - - if (g_vm->gli_unregister_arr) - (*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), - lpic(nullptr), rpic(nullptr), lhyper(0), rhyper(0), lm(0), rm(0) { -} - -void TextBufferWindow::TextBufferRow::resize(size_t newSize) { - chars.clear(); - attr.clear(); - chars.resize(newSize); - attr.resize(newSize); - Common::fill(&chars[0], &chars[0] + newSize, ' '); -} - -/*--------------------------------------------------------------------------*/ - -GraphicsWindow::GraphicsWindow(Windows *windows, uint32 rock) : Window(windows, rock), -_w(0), _h(0), _dirty(false), _surface(nullptr) { - _type = wintype_Graphics; - Common::copy(&_bgColor[0], &_bgColor[3], _bgnd); -} - -GraphicsWindow::~GraphicsWindow() { - delete _surface; -} - -void GraphicsWindow::rearrange(const Common::Rect &box) { - int newwid, newhgt; - int bothwid, bothhgt; - int oldw, oldh; - Graphics::ManagedSurface *newSurface; - - _bbox = box; - - newwid = box.width(); - newhgt = box.height(); - oldw = _w; - oldh = _h; - - if (newwid <= 0 || newhgt <= 0) { - _w = 0; - _h = 0; - delete _surface; - _surface = NULL; - return; - } - - bothwid = _w; - if (newwid < bothwid) - bothwid = newwid; - bothhgt = _h; - if (newhgt < bothhgt) - bothhgt = newhgt; - - newSurface = new Graphics::ManagedSurface(newwid, newhgt, - Graphics::PixelFormat(3, 8, 8, 8, 0, 16, 8, 0, 0)); - - // If the new surface is equal or bigger than the old one, copy it over - if (_surface && bothwid && bothhgt) - newSurface->blitFrom(*_surface); - - delete _surface; - _surface = newSurface; - _w = newwid; - _h = newhgt; - - touch(); -} - -void GraphicsWindow::touch() { - _dirty = true; - _windows->repaint(_bbox); -} - -void GraphicsWindow::redraw() { - // TODO -} - -/*--------------------------------------------------------------------------*/ - -PairWindow::PairWindow(Windows *windows, glui32 method, Window *key, glui32 size) : - Window(windows, 0), - _dir(method & winmethod_DirMask), - _division(method & winmethod_DivisionMask), - _wBorder((method & winmethod_BorderMask) == winmethod_Border), - _vertical(_dir == winmethod_Left || _dir == winmethod_Right), - _backward(_dir == winmethod_Left || _dir == winmethod_Above), - _key(key), _size(size), _keyDamage(0), _child1(nullptr), _child2(nullptr) { - _type = wintype_Pair; -} - -void PairWindow::rearrange(const Common::Rect &box) { - Common::Rect box1, box2; - int min, diff, split, splitwid, max; - Window *ch1, *ch2; - - _bbox = box; - - if (_vertical) { - min = _bbox.left; - max = _bbox.right; - } else { - min = _bbox.top; - max = _bbox.bottom; - } - diff = max - min; - - // We now figure split. - if (_vertical) - splitwid = g_conf->_wPaddingX; // want border? - else - splitwid = g_conf->_wPaddingY; // want border? - - switch (_division) { - case winmethod_Proportional: - split = (diff * _size) / 100; - break; - - case winmethod_Fixed: - split = !_key ? 0 : _key->getSplit(_size, _vertical); - break; - - default: - split = diff / 2; - break; - } - - if (!_backward) - split = max - split - splitwid; - else - split = min + split; - - if (min >= max) { - split = min; - } else { - if (split < min) - split = min; - else if (split > max - splitwid) - split = max - splitwid; - } - - if (_vertical) { - 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; - } else { - 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; - } - - if (!_backward) { - ch1 = _child1; - ch2 = _child2; - } else { - ch1 = _child2; - ch2 = _child1; - } - - ch1->rearrange(box1); - ch2->rearrange(box2); -} - -void PairWindow::redraw() { - // TODO -} - -/*--------------------------------------------------------------------------*/ - void Attributes::clear() { fgset = 0; bgset = 0; diff --git a/engines/gargoyle/windows.h b/engines/gargoyle/windows.h index 9a09641ca8..a5bc2f43f9 100644 --- a/engines/gargoyle/windows.h +++ b/engines/gargoyle/windows.h @@ -31,7 +31,6 @@ #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" @@ -43,6 +42,8 @@ class PairWindow; #define HISTORYLEN 100 #define SCROLLBACK 512 #define TBLINELEN 300 +#define GLI_SUBPIX 8 + /** * Main windows manager @@ -256,7 +257,6 @@ struct Attributes { class Window : public Draw { public: Windows *_windows; - glui32 _magicnum; glui32 _rock; glui32 _type; @@ -393,409 +393,6 @@ public: BlankWindow(Windows *windows, uint32 rock); }; -/** - * Text Grid window - */ -class TextGridWindow : public Window { - /** - * Structure for a row within the grid window - */ - struct TextGridRow { - Common::Array<uint32> _chars; - Common::Array<Attributes> _attrs; - bool dirty; - - /** - * Constructor - */ - TextGridRow() : dirty(false) {} - - /** - * Resize the row - */ - void resize(size_t newSize); - }; - typedef Common::Array<TextGridRow> TextGridRows; -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 - void *_inBuf; ///< unsigned char* for latin1, glui32* for unicode - int _inOrgX, _inOrgY; - int _inMax; - int _inCurs, _inLen; - Attributes _origAttr; - gidispatch_rock_t _inArrayRock; - glui32 *_lineTerminators; - - WindowStyle styles[style_NUMSTYLES]; ///< style hints and settings -public: - /** - * Constructor - */ - TextGridWindow(Windows *windows, uint32 rock); - - /** - * Destructor - */ - virtual ~TextGridWindow(); - - /** - * Rearranges the window - */ - virtual void rearrange(const Common::Rect &box) override; - - /** - * Get window split size within parent pair window - */ - virtual glui32 getSplit(glui32 size, bool vertical) const override; - - /** - * 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; -}; - -/** - * Text Buffer window - */ -class TextBufferWindow : public Window { - /** - * Structure for a row within the window - */ - struct TextBufferRow { - Common::Array<uint32> chars; - Common::Array<Attributes> attr; - int len, newline; - bool dirty, repaint; - Picture *lpic, *rpic; - glui32 lhyper, rhyper; - int lm, rm; - - /** - * Constructor - */ - TextBufferRow(); - - /** - * Resize the row - */ - void resize(size_t newSize); - }; - typedef Common::Array<TextBufferRow> TextBufferRows; -private: - void reflow(); - void touchScroll(); - bool putPicture(Picture *pic, glui32 align, glui32 linkval); - void putTextUni(const glui32 *buf, int len, int pos, int oldlen); - void flowBreak(); - - /** - * Mark a given text row as modified - */ - void touch(int line); -public: - int _width, _height; - int _spaced; - int _dashed; - - TextBufferRows _lines; - int _scrollBack; - - int _numChars; ///< number of chars in last line: lines[0] - glui32 *_chars; ///< alias to lines[0].chars - Attributes *_attrs; ///< alias to lines[0].attrs - - ///< adjust margins temporarily for images - int _ladjw; - int _ladjn; - int _radjw; - int _radjn; - - /* Command history. */ - glui32 *_history[HISTORYLEN]; - int _historyPos; - int _historyFirst, _historyPresent; - - /* for paging */ - int _lastSeen; - int _scrollPos; - int _scrollMax; - - /* for line input */ - void *_inBuf; ///< unsigned char* for latin1, glui32* for unicode - int _inMax; - long _inFence; - long _inCurs; - Attributes _origAttr; - gidispatch_rock_t _inArrayRock; - - glui32 _echoLineInput; - glui32 *_lineTerminators; - - /* style hints and settings */ - WindowStyle styles[style_NUMSTYLES]; - - /* for copy selection */ - glui32 *_copyBuf; - int _copyPos; -public: - /** - * Constructor - */ - TextBufferWindow(Windows *windows, uint32 rock); - - /** - * Destructor - */ - virtual ~TextBufferWindow(); - - /** - * Rearranges the window - */ - virtual void rearrange(const Common::Rect &box) override; - - /** - * Get window split size within parent pair window - */ - virtual glui32 getSplit(glui32 size, bool vertical) const override; - - /** - * 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; - - /** - * 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; -}; - -/** - * Graphics window - */ -class GraphicsWindow : public Window { -private: - void touch(); -public: - unsigned char _bgnd[3]; - bool _dirty; - glui32 _w, _h; - Graphics::ManagedSurface *_surface; -public: - /** - * Constructor - */ - GraphicsWindow(Windows *windows, uint32 rock); - - /** - * Destructor - */ - virtual ~GraphicsWindow(); - - /** - * Rearranges the window - */ - virtual void rearrange(const Common::Rect &box) override; - - /** - * Get window split size within parent pair window - */ - 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; - } -}; - -/** - * Pair window - */ -class PairWindow : public Window { -public: - Window *_child1, *_child2; - - /* split info... */ - glui32 _dir; ///< winmethod_Left, Right, Above, or Below - bool _vertical, _backward; ///< flags - glui32 _division; ///< winmethod_Fixed or winmethod_Proportional - Window *_key; ///< NULL or a leaf-descendant (not a Pair) - int _keyDamage; ///< used as scratch space in window closing - glui32 _size; ///< size value - glui32 _wBorder; ///< winMethod_Border, NoBorder -public: - /** - * Constructor - */ - PairWindow(Windows *windows, glui32 method, Window *key, glui32 size); - - /** - * Rearranges the window - */ - virtual void rearrange(const Common::Rect &box) override; - - /** - * Redraw the window - */ - virtual void redraw() override; -}; - } // End of namespace Gargoyle #endif |