1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "glk/windows.h"
24 #include "glk/window_graphics.h"
25 #include "glk/window_pair.h"
26 #include "glk/window_text_buffer.h"
27 #include "glk/window_text_grid.h"
28 #include "glk/conf.h"
29 #include "glk/glk.h"
30 #include "glk/screen.h"
31 #include "glk/streams.h"
32 #include "common/algorithm.h"
33 #include "common/textconsole.h"
34 
35 namespace Glk {
36 
37 bool Windows::_overrideReverse;
38 bool Windows::_overrideFgSet;
39 bool Windows::_overrideBgSet;
40 bool Windows::_forceRedraw;
41 bool Windows::_claimSelect;
42 bool Windows::_moreFocus;
43 uint Windows::_overrideFgVal;
44 uint Windows::_overrideBgVal;
45 uint Windows::_zcolor_fg;
46 uint Windows::_zcolor_bg;
47 uint Windows::_zcolor_LightGrey;
48 uint Windows::_zcolor_Foreground;
49 uint Windows::_zcolor_Background;
50 uint Windows::_zcolor_Bright;
51 
52 /*--------------------------------------------------------------------------*/
53 
Windows(Graphics::Screen * screen)54 Windows::Windows(Graphics::Screen *screen) : _screen(screen), _windowList(nullptr),
55 	_rootWin(nullptr), _focusWin(nullptr) {
56 	_overrideReverse = false;
57 	_overrideFgSet = false;
58 	_overrideBgSet = false;
59 	_forceRedraw = true;
60 	_claimSelect = false;
61 	_moreFocus = false;
62 	_overrideFgVal = 0;
63 	_overrideBgVal = 0;
64 	_zcolor_fg = _zcolor_bg = 0;
65 	_drawSelect = false;
66 
67 	_zcolor_LightGrey = g_system->getScreenFormat().RGBToColor(181, 181, 181);
68 	_zcolor_Foreground = _zcolor_Background = 0;
69 	_zcolor_Bright = 0;
70 }
71 
~Windows()72 Windows::~Windows() {
73 	delete _rootWin;
74 }
75 
windowOpen(Window * splitwin,uint method,uint size,uint wintype,uint rock)76 Window *Windows::windowOpen(Window *splitwin, uint method, uint size,
77 							uint wintype, uint rock) {
78 	Window *newwin, *oldparent = nullptr;
79 	PairWindow *pairWin;
80 	uint val;
81 
82 	_forceRedraw = true;
83 
84 	if (!_rootWin) {
85 		if (splitwin) {
86 			warning("window_open: ref must be nullptr");
87 			return nullptr;
88 		}
89 
90 		// ignore method and size now
91 		oldparent = nullptr;
92 	} else {
93 		if (!splitwin) {
94 			warning("window_open: ref must not be nullptr");
95 			return nullptr;
96 		}
97 
98 		val = (method & winmethod_DivisionMask);
99 		if (val != winmethod_Fixed && val != winmethod_Proportional) {
100 			warning("window_open: invalid method (not fixed or proportional)");
101 			return nullptr;
102 		}
103 
104 		val = (method & winmethod_DirMask);
105 		if (val != winmethod_Above && val != winmethod_Below && val != winmethod_Left
106 				&& val != winmethod_Right && val != winmethod_Arbitrary) {
107 			warning("window_open: invalid method (bad direction)");
108 			return nullptr;
109 		}
110 
111 		oldparent = splitwin->_parent;
112 		if (oldparent && oldparent->_type != wintype_Pair) {
113 			warning("window_open: parent window is not Pair");
114 			return nullptr;
115 		}
116 	}
117 
118 	assert(wintype != wintype_Pair);
119 	newwin = newWindow(wintype, rock);
120 	if (!newwin) {
121 		warning("window_open: unable to create window");
122 		return nullptr;
123 	}
124 
125 	if (!splitwin) {
126 		_rootWin = newwin;
127 	} else if (splitwin->_type == wintype_Pair) {
128 		pairWin = static_cast<PairWindow *>(splitwin);
129 		pairWin->_dir = winmethod_Arbitrary;
130 		pairWin->_children.push_back(newwin);
131 		newwin->_parent = pairWin;
132 	} else {
133 		// create pairWin, with newwin as the key
134 		pairWin = newPairWindow(method, newwin, size);
135 		pairWin->_children.push_back(splitwin);
136 		pairWin->_children.push_back(newwin);
137 
138 		splitwin->_parent = pairWin;
139 		newwin->_parent = pairWin;
140 		pairWin->_parent = oldparent;
141 
142 		if (oldparent) {
143 			PairWindow *parentWin = dynamic_cast<PairWindow *>(oldparent);
144 			assert(parentWin);
145 
146 			for (uint idx = 0; idx < parentWin->_children.size(); ++idx) {
147 				if (parentWin->_children[idx] == splitwin)
148 					parentWin->_children[idx] = pairWin;
149 			}
150 		} else {
151 			_rootWin = pairWin;
152 		}
153 	}
154 
155 	rearrange();
156 
157 	return newwin;
158 }
159 
windowClose(Window * win,StreamResult * result)160 void Windows::windowClose(Window *win, StreamResult *result) {
161 	_forceRedraw = true;
162 
163 	if (win == _rootWin || win->_parent == nullptr) {
164 		// Close the root window, which means all windows.
165 		_rootWin = nullptr;
166 
167 		// Begin (simpler) closation
168 		win->_stream->fillResult(result);
169 		win->close(true);
170 	} else {
171 		// Have to jigger parent
172 		Window *sibWin;
173 		PairWindow *pairWin = dynamic_cast<PairWindow *>(win->_parent);
174 		PairWindow *grandparWin;
175 
176 		if (pairWin) {
177 			int index = pairWin->_children.indexOf(win);
178 			if (index == -1) {
179 				warning("windowClose: window tree is corrupted");
180 				return;
181 			}
182 
183 			// Detach window being closed from parent pair window
184 			pairWin->_children.remove_at(index);
185 			win->_parent = nullptr;
186 
187 			if (!(pairWin->_dir & winmethod_Arbitrary)) {
188 				// Get the remaining child window
189 				assert(pairWin->_children.size() == 1);
190 				sibWin = pairWin->_children.front();
191 
192 				// Detach it from the pair window
193 				index = pairWin->_children.indexOf(sibWin);
194 				assert(index >= 0);
195 				pairWin->_children.remove_at(index);
196 
197 				// Set up window as either the singular root, or grandparent pair window if one exists
198 				grandparWin = dynamic_cast<PairWindow *>(pairWin->_parent);
199 				if (!grandparWin) {
200 					_rootWin = sibWin;
201 					sibWin->_parent = nullptr;
202 				} else {
203 					index = grandparWin->_children.indexOf(pairWin);
204 					grandparWin->_children[index] = sibWin;
205 					sibWin->_parent = grandparWin;
206 				}
207 			}
208 		}
209 
210 		// Begin closation
211 		win->_stream->fillResult(result);
212 
213 		// Close the child window (and descendants), so that key-deletion can
214 		// crawl up the tree to the root window.
215 		win->close(true);
216 
217 		if (pairWin && !(pairWin->_dir & winmethod_Arbitrary))
218 			// Now we can delete the parent pair.
219 			pairWin->close(false);
220 
221 		// Sort out the arrangements
222 		rearrange();
223 	}
224 }
225 
newWindow(uint type,uint rock)226 Window *Windows::newWindow(uint type, uint rock) {
227 	Window *win;
228 
229 	switch (type) {
230 	case wintype_Blank:
231 		win = new BlankWindow(this, rock);
232 		break;
233 	case wintype_TextGrid:
234 		win = new TextGridWindow(this, rock);
235 		break;
236 	case wintype_TextBuffer:
237 		win = new TextBufferWindow(this, rock);
238 		break;
239 	case wintype_Graphics:
240 		win = new GraphicsWindow(this, rock);
241 		break;
242 	case wintype_Pair:
243 		error("Pair windows cannot be created directly");
244 	default:
245 		error("Unknown window type");
246 	}
247 
248 	win->_next = _windowList;
249 	_windowList = win;
250 	if (win->_next)
251 		win->_next->_prev = win;
252 
253 	return win;
254 }
255 
newPairWindow(uint method,Window * key,uint size)256 PairWindow *Windows::newPairWindow(uint method, Window *key, uint size) {
257 	PairWindow *pwin = new PairWindow(this, method, key, size);
258 	pwin->_next = _windowList;
259 	_windowList = pwin;
260 	if (pwin->_next)
261 		pwin->_next->_prev = pwin;
262 
263 	return pwin;
264 }
265 
rearrange()266 void Windows::rearrange() {
267 	if (_rootWin) {
268 		Rect box;
269 		Point cell(g_conf->_monoInfo._cellW, g_conf->_monoInfo._cellH);
270 
271 		if (g_conf->_lockCols) {
272 			int desired_width = g_conf->_wMarginSaveX * 2 + cell.x * g_conf->_cols;
273 			if (desired_width > g_conf->_imageW)
274 				g_conf->_wMarginX = g_conf->_wMarginSaveX;
275 			else
276 				g_conf->_wMarginX = (g_conf->_imageW - cell.x * g_conf->_cols) / 2;
277 		}
278 
279 		if (g_conf->_lockRows) {
280 			int desired_height = g_conf->_wMarginSaveY * 2 + cell.y * g_conf->_rows;
281 			if (desired_height > g_conf->_imageH)
282 				g_conf->_wMarginY = g_conf->_wMarginSaveY;
283 			else
284 				g_conf->_wMarginY = (g_conf->_imageH - cell.y * g_conf->_rows) / 2;
285 		}
286 
287 		box.left = g_conf->_wMarginX;
288 		box.top = g_conf->_wMarginY;
289 		box.right = g_conf->_imageW - g_conf->_wMarginX;
290 		box.bottom = g_conf->_imageH - g_conf->_wMarginY;
291 
292 		_rootWin->rearrange(box);
293 	}
294 }
295 
inputGuessFocus()296 void Windows::inputGuessFocus() {
297 	Window *altWin = _focusWin;
298 
299 	do {
300 		if (altWin
301 				&& (altWin->_lineRequest || altWin->_charRequest ||
302 					altWin->_lineRequestUni || altWin->_charRequestUni))
303 			break;
304 		altWin = iterateTreeOrder(altWin);
305 	} while (altWin != _focusWin);
306 
307 	if (_focusWin != altWin) {
308 		_focusWin = altWin;
309 		_forceRedraw = true;
310 		redraw();
311 	}
312 }
313 
inputMoreFocus()314 void Windows::inputMoreFocus() {
315 	Window *altWin = _focusWin;
316 
317 	do {
318 		if (altWin && altWin->_moreRequest)
319 			break;
320 		altWin = iterateTreeOrder(altWin);
321 	} while (altWin != _focusWin);
322 
323 	_focusWin = altWin;
324 }
325 
inputNextFocus()326 void Windows::inputNextFocus() {
327 	Window *altWin = _focusWin;
328 
329 	do {
330 		altWin = iterateTreeOrder(altWin);
331 		if (altWin
332 				&& (altWin->_lineRequest || altWin->_charRequest ||
333 					altWin->_lineRequestUni || altWin->_charRequestUni))
334 			break;
335 	} while (altWin != _focusWin);
336 
337 	if (_focusWin  != altWin) {
338 		_focusWin = altWin;
339 		_forceRedraw = true;
340 		redraw();
341 	}
342 }
343 
inputScrollFocus()344 void Windows::inputScrollFocus() {
345 	Window *altWin = _focusWin;
346 
347 	do {
348 		if (altWin && altWin->_scrollRequest)
349 			break;
350 		altWin = iterateTreeOrder(altWin);
351 	} while (altWin != _focusWin);
352 
353 	_focusWin = altWin;
354 }
355 
inputHandleKey(uint key)356 void Windows::inputHandleKey(uint key) {
357 	if (_moreFocus) {
358 		inputMoreFocus();
359 	} else if (_focusWin && (_focusWin->_lineRequest || _focusWin->_lineRequestUni) &&
360 			_focusWin->checkTerminators(key)) {
361 		// WORKAROUND: Do line terminators checking first. This was first needed for Beyond Zork,
362 		// since it needs the Page Up/Down keys to scroll the description area rathern than the buffer area
363 	} else {
364 		switch (key) {
365 		case keycode_Tab:
366 			inputNextFocus();
367 			return;
368 		case keycode_PageUp:
369 		case keycode_PageDown:
370 		case keycode_MouseWheelUp:
371 		case keycode_MouseWheelDown:
372 			inputScrollFocus();
373 			break;
374 		default:
375 			inputGuessFocus();
376 			break;
377 		}
378 	}
379 
380 	Window *win = _focusWin;
381 	if (!win)
382 		return;
383 
384 	bool deferExit = false;
385 
386 	TextGridWindow *gridWindow = dynamic_cast<TextGridWindow *>(win);
387 	TextBufferWindow *bufWindow = dynamic_cast<TextBufferWindow *>(win);
388 
389 	if (gridWindow) {
390 		if (gridWindow->_charRequest || gridWindow->_charRequestUni)
391 			gridWindow->acceptReadChar(key);
392 		else if (gridWindow->_lineRequest || gridWindow->_lineRequestUni)
393 			gridWindow->acceptReadLine(key);
394 	} else if (bufWindow) {
395 		if (bufWindow->_charRequest || bufWindow->_charRequestUni)
396 			bufWindow->acceptReadChar(key);
397 		else if (bufWindow->_lineRequest || bufWindow->_lineRequestUni)
398 			bufWindow->acceptReadLine(key);
399 		else if (bufWindow->_moreRequest || bufWindow->_scrollRequest)
400 			deferExit = bufWindow->acceptScroll(key);
401 	}
402 
403 	if (!deferExit && g_vm->_terminated)
404 		g_vm->quitGame();
405 }
406 
inputHandleClick(const Point & pos)407 void Windows::inputHandleClick(const Point &pos) {
408 	if (_rootWin)
409 		_rootWin->click(pos);
410 }
411 
selectionChanged()412 void Windows::selectionChanged() {
413 	_claimSelect = false;
414 	_forceRedraw = true;
415 	redraw();
416 }
417 
redraw()418 void Windows::redraw() {
419 	_claimSelect = false;
420 
421 	if (_forceRedraw) {
422 		repaint(Rect(0, 0, g_conf->_imageW, g_conf->_imageH));
423 		g_vm->_screen->fill(g_conf->_windowColor);
424 	}
425 
426 	if (_rootWin)
427 		_rootWin->redraw();
428 
429 	if (_moreFocus)
430 		refocus(_focusWin);
431 
432 	_forceRedraw = false;
433 }
434 
redrawRect(const Rect & r)435 void Windows::redrawRect(const Rect &r) {
436 	_drawSelect = true;
437 	repaint(r);
438 }
439 
repaint(const Rect & box)440 void Windows::repaint(const Rect &box) {
441 	g_vm->_events->redraw();
442 }
443 
rgbShift(uint color)444 uint Windows::rgbShift(uint color) {
445 	uint8 r, g, b;
446 	Graphics::PixelFormat pf = g_system->getScreenFormat();
447 	pf.colorToRGB(color, r, g, b);
448 
449 	r = ((uint)r + 0x30) < 0xff ? ((uint)r + 0x30) : 0xff;
450 	g = ((uint)g + 0x30) < 0xff ? ((uint)g + 0x30) : 0xff;
451 	b = ((uint)b + 0x30) < 0xff ? ((uint)b + 0x30) : 0xff;
452 
453 	_zcolor_Bright = pf.RGBToColor(r, g, b);
454 	return _zcolor_Bright;
455 }
456 
457 /*--------------------------------------------------------------------------*/
458 
operator ++()459 Windows::iterator &Windows::iterator::operator++() {
460 	_current = _current->_next;
461 	return *this;
462 }
463 
operator --()464 Windows::iterator &Windows::iterator::operator--() {
465 	_current = _current->_prev;
466 	return *this;
467 }
468 
refocus(Window * win)469 void Windows::refocus(Window *win) {
470 	Window *focus = win;
471 	do {
472 		if (focus && focus->_moreRequest) {
473 			_focusWin = focus;
474 			return;
475 		}
476 
477 		focus = iterateTreeOrder(focus);
478 	} while (focus != win);
479 
480 	_moreFocus = false;
481 }
482 
iterateTreeOrder(Window * win)483 Window *Windows::iterateTreeOrder(Window *win) {
484 	if (!win)
485 		return _rootWin;
486 
487 	PairWindow *pairWin = dynamic_cast<PairWindow *>(win);
488 	if (pairWin) {
489 		return pairWin->_backward ? pairWin->_children.back() : pairWin->_children.front();
490 	} else {
491 		while (win->_parent) {
492 			pairWin = dynamic_cast<PairWindow *>(win->_parent);
493 			assert(pairWin);
494 			int index = pairWin->_children.indexOf(win);
495 			assert(index != -1);
496 
497 			if (!pairWin->_backward) {
498 				if (index < ((int)pairWin->_children.size() - 1))
499 					return pairWin->_children[index + 1];
500 			} else {
501 				if (index > 0)
502 					return pairWin->_children[index - 1];
503 			}
504 
505 			win = pairWin;
506 		}
507 
508 		return nullptr;
509 	}
510 }
511 
512 /*--------------------------------------------------------------------------*/
513 
Window(Windows * windows,uint rock)514 Window::Window(Windows *windows, uint rock) : _windows(windows), _rock(rock),
515 	_type(0), _parent(nullptr), _next(nullptr), _prev(nullptr), _yAdj(0),
516 	_lineRequest(false), _lineRequestUni(false), _charRequest(false),
517 	_charRequestUni(false), _mouseRequest(false), _hyperRequest(false),
518 	_moreRequest(false), _scrollRequest(false), _imageLoaded(false),
519 	_echoLineInputBase(true), _lineTerminatorsBase(nullptr), _termCt(0), _echoStream(nullptr) {
520 	_attr.fgset = false;
521 	_attr.bgset = false;
522 	_attr.reverse = false;
523 	_attr.style = 0;
524 	_attr.fgcolor = 0;
525 	_attr.bgcolor = 0;
526 	_attr.hyper = 0;
527 
528 	_bgColor = g_conf->_windowColor;
529 	_fgColor = g_conf->_propInfo._moreColor;
530 
531 	Streams &streams = *g_vm->_streams;
532 	_stream = streams.openWindowStream(this);
533 
534 	if (g_vm->gli_register_obj)
535 		_dispRock = (*g_vm->gli_register_obj)(this, gidisp_Class_Window);
536 }
537 
~Window()538 Window::~Window() {
539 	if (g_vm->gli_unregister_obj)
540 		(*g_vm->gli_unregister_obj)(this, gidisp_Class_Window, _dispRock);
541 
542 	// Remove the window from the parent's children list
543 	PairWindow *parent = dynamic_cast<PairWindow *>(_parent);
544 	if (parent) {
545 		int index = parent->_children.indexOf(this);
546 		if (index != -1)
547 			parent->_children.remove_at(index);
548 	}
549 
550 	delete[] _lineTerminatorsBase;
551 
552 	// Remove the window from the master list of windows
553 	Window *prev = _prev;
554 	Window *next = _next;
555 
556 	if (prev)
557 		prev->_next = next;
558 	else
559 		_windows->_windowList = next;
560 	if (next)
561 		next->_prev = prev;
562 
563 	// Delete any attached window stream
564 	_echoStream = nullptr;
565 	delete _stream;
566 }
567 
close(bool recurse)568 void Window::close(bool recurse) {
569 	if (_windows->getFocusWindow() == this)
570 		// Focused window is being removed
571 		_windows->setFocus(nullptr);
572 
573 	for (Window *wx = _parent; wx; wx = wx->_parent) {
574 		PairWindow *pairWin = dynamic_cast<PairWindow *>(wx);
575 
576 		if (pairWin && pairWin->_key == this) {
577 			pairWin->_key = nullptr;
578 			pairWin->_keyDamage = true;
579 		}
580 	}
581 
582 	PairWindow *pairWin = dynamic_cast<PairWindow *>(this);
583 	if (pairWin) {
584 		for (uint idx = 0; idx < pairWin->_children.size(); ++idx)
585 			pairWin->_children[idx]->close();
586 	}
587 
588 	// Finally, delete the window
589 	delete this;
590 }
591 
getFontInfo()592 FontInfo *Window::getFontInfo() {
593 	error("Tried to get font info for a non-text window");
594 }
595 
cancelLineEvent(Event * ev)596 void Window::cancelLineEvent(Event *ev) {
597 	Event dummyEv;
598 	if (!ev)
599 		ev = &dummyEv;
600 
601 	ev->clear();
602 }
603 
moveCursor(const Point & newPos)604 void Window::moveCursor(const Point &newPos) {
605 	warning("moveCursor: not a TextGrid window");
606 }
607 
requestLineEvent(char * buf,uint maxlen,uint initlen)608 void Window::requestLineEvent(char *buf, uint maxlen, uint initlen) {
609 	warning("requestLineEvent: window does not support keyboard input");
610 }
611 
requestLineEventUni(uint32 * buf,uint maxlen,uint initlen)612 void Window::requestLineEventUni(uint32 *buf, uint maxlen, uint initlen) {
613 	warning("requestLineEventUni: window does not support keyboard input");
614 }
615 
redraw()616 void Window::redraw() {
617 	if (Windows::_forceRedraw) {
618 		uint color = Windows::_overrideBgSet ? g_conf->_windowColor : _bgColor;
619 		int y0 = _yAdj ? _bbox.top - _yAdj : _bbox.top;
620 		g_vm->_screen->fillRect(Rect(_bbox.left, y0, _bbox.right, _bbox.bottom), color);
621 	}
622 }
623 
acceptReadLine(uint32 arg)624 void Window::acceptReadLine(uint32 arg) {
625 	warning("acceptReadLine:: window does not support keyboard input");
626 }
627 
acceptReadChar(uint arg)628 void Window::acceptReadChar(uint arg) {
629 	warning("acceptReadChar:: window does not support keyboard input");
630 }
631 
getArrangement(uint * method,uint * size,Window ** keyWin)632 void Window::getArrangement(uint *method, uint *size, Window **keyWin) {
633 	warning("getArrangement: not a Pair window");
634 }
635 
setArrangement(uint method,uint size,Window * keyWin)636 void Window::setArrangement(uint method, uint size, Window *keyWin) {
637 	warning("setArrangement: not a Pair window");
638 }
639 
requestCharEvent()640 void Window::requestCharEvent() {
641 	warning("requestCharEvent: window does not support keyboard input");
642 }
643 
requestCharEventUni()644 void Window::requestCharEventUni() {
645 	warning("requestCharEventUni: window does not support keyboard input");
646 }
647 
flowBreak()648 void Window::flowBreak() {
649 	warning("flowBreak: not a text buffer window");
650 }
651 
eraseRect(bool whole,const Rect & box)652 void Window::eraseRect(bool whole, const Rect &box) {
653 	warning("eraseRect: not a graphics window");
654 }
655 
fillRect(uint color,const Rect & box)656 void Window::fillRect(uint color, const Rect &box) {
657 	warning("fillRect: not a graphics window");
658 }
659 
setBackgroundColor(uint color)660 void Window::setBackgroundColor(uint color) {
661 	warning("setBackgroundColor: not a graphics window");
662 }
663 
getStyles() const664 const WindowStyle *Window::getStyles() const {
665 	warning("getStyles: not a text window");
666 	return nullptr;
667 }
668 
setTerminatorsLineEvent(const uint32 * keycodes,uint count)669 void Window::setTerminatorsLineEvent(const uint32 *keycodes, uint count) {
670 	if (dynamic_cast<TextBufferWindow *>(this) || dynamic_cast<TextGridWindow *>(this)) {
671 		delete[] _lineTerminatorsBase;
672 		_lineTerminatorsBase = nullptr;
673 
674 		if (!keycodes || count == 0) {
675 			_termCt = 0;
676 		} else {
677 			_lineTerminatorsBase = new uint[count + 1];
678 			if (_lineTerminatorsBase) {
679 				memcpy(_lineTerminatorsBase, keycodes, count * sizeof(uint));
680 				_lineTerminatorsBase[count] = 0;
681 				_termCt = count;
682 			}
683 		}
684 	} else {
685 		warning("setTerminatorsLineEvent: window does not support keyboard input");
686 	}
687 }
688 
checkBasicTerminators(uint32 ch)689 bool Window::checkBasicTerminators(uint32 ch) {
690 	if (ch == keycode_Escape)
691 		return true;
692 	else if (ch >= keycode_Func12 && ch <= keycode_Func1)
693 		return true;
694 	else
695 		return false;
696 }
697 
checkTerminators(uint32 ch)698 bool Window::checkTerminators(uint32 ch) {
699 	if (checkBasicTerminators(ch))
700 		return true;
701 
702 	for (uint idx = 0; idx < _termCt; ++idx) {
703 		if (_lineTerminatorsBase[idx] == ch)
704 			return true;
705 	}
706 
707 	return false;
708 }
709 
imageDraw(uint image,uint align,int val1,int val2)710 bool Window::imageDraw(uint image, uint align, int val1, int val2) {
711 	return imageDraw(Common::String::format("%u", image),
712 		align, val1, val2);
713 }
714 
imageDraw(const Common::String & image,uint align,int val1,int val2)715 bool Window::imageDraw(const Common::String & image, uint align, int val1, int val2) {
716 	if (!g_conf->_graphics)
717 		return false;
718 
719 	TextBufferWindow *bufWin = dynamic_cast<TextBufferWindow *>(this);
720 	GraphicsWindow *graWin = dynamic_cast<GraphicsWindow *>(this);
721 
722 	if (bufWin)
723 		return bufWin->drawPicture(image, val1, false, 0, 0);
724 	if (graWin)
725 		return graWin->drawPicture(image, val1, val2, false, 0, 0);
726 
727 	return false;
728 }
729 
getSize(uint * width,uint * height) const730 void Window::getSize(uint *width, uint *height) const {
731 	if (width)
732 		*width = 0;
733 	if (height)
734 		*height = 0;
735 }
736 
bringToFront()737 void Window::bringToFront() {
738 	PairWindow *pairWin = dynamic_cast<PairWindow *>(_parent);
739 
740 	if (pairWin && pairWin->_dir == winmethod_Arbitrary && pairWin->_children.back() != this) {
741 		pairWin->_children.remove(this);
742 		pairWin->_children.push_back(this);
743 		Windows::_forceRedraw = true;
744 	}
745 }
746 
sendToBack()747 void Window::sendToBack() {
748 	PairWindow *pairWin = dynamic_cast<PairWindow *>(_parent);
749 
750 	if (pairWin && pairWin->_dir == winmethod_Arbitrary && pairWin->_children.front() != this) {
751 		pairWin->_children.remove(this);
752 		pairWin->_children.insert_at(0, this);
753 		Windows::_forceRedraw = true;
754 	}
755 }
756 
757 /*--------------------------------------------------------------------------*/
758 
BlankWindow(Windows * windows,uint rock)759 BlankWindow::BlankWindow(Windows *windows, uint rock) : Window(windows, rock) {
760 	_type = wintype_Blank;
761 }
762 
763 /*--------------------------------------------------------------------------*/
764 
WindowStyle(const WindowStyleStatic & src)765 WindowStyle::WindowStyle(const WindowStyleStatic &src) : font(src.font), reverse(src.reverse) {
766 	Graphics::PixelFormat pf = g_system->getScreenFormat();
767 	fg = pf.RGBToColor(src.fg[0], src.fg[1], src.fg[2]);
768 	bg = pf.RGBToColor(src.bg[0], src.bg[1], src.bg[1]);
769 }
770 
771 /*--------------------------------------------------------------------------*/
772 
clear()773 void Attributes::clear() {
774 	fgset = false;
775 	bgset = false;
776 	reverse = false;
777 	unused = false;
778 	style = 0;
779 	fgcolor = 0;
780 	bgcolor = 0;
781 	hyper = 0;
782 }
783 
attrBg(const WindowStyle * styles)784 uint Attributes::attrBg(const WindowStyle *styles) {
785 	int revset = reverse || (styles[style].reverse && !Windows::_overrideReverse);
786 
787 	bool zfset = fgset ? fgset : Windows::_overrideFgSet;
788 	bool zbset = bgset ? bgset : Windows::_overrideBgSet;
789 
790 	uint zfore = fgset ? fgcolor : Windows::_overrideFgVal;
791 	uint zback = bgset ? bgcolor : Windows::_overrideBgVal;
792 
793 	if (zfset && zfore != Windows::_zcolor_fg) {
794 		Windows::_zcolor_Foreground = zfore;
795 		Windows::_zcolor_fg = zfore;
796 	}
797 
798 	if (zbset && zback != Windows::_zcolor_bg) {
799 		Windows::_zcolor_Background = zback;
800 		Windows::_zcolor_bg = zback;
801 	}
802 
803 	if (!revset) {
804 		if (zbset)
805 			return Windows::_zcolor_Background;
806 		else
807 			return styles[style].bg;
808 	} else {
809 		if (zfset)
810 			if (zfore == zback)
811 				return Windows::rgbShift(Windows::_zcolor_Foreground);
812 			else
813 				return Windows::_zcolor_Foreground;
814 		else if (zbset && styles[style].fg == Windows::_zcolor_Background)
815 			return Windows::_zcolor_LightGrey;
816 		else
817 			return styles[style].fg;
818 	}
819 }
820 
attrFg(const WindowStyle * styles)821 uint Attributes::attrFg(const WindowStyle *styles) {
822 	int revset = reverse || (styles[style].reverse && !Windows::_overrideReverse);
823 
824 	bool zfset = fgset ? fgset : Windows::_overrideFgSet;
825 	bool zbset = bgset ? bgset : Windows::_overrideBgSet;
826 
827 	uint zfore = fgset ? fgcolor : Windows::_overrideFgVal;
828 	uint zback = bgset ? bgcolor : Windows::_overrideBgVal;
829 
830 	if (zfset && zfore != Windows::_zcolor_fg) {
831 		Windows::_zcolor_Foreground = zfore;
832 		Windows::_zcolor_fg = zfore;
833 	}
834 
835 	if (zbset && zback != Windows::_zcolor_bg) {
836 		Windows::_zcolor_Background = zback;
837 		Windows::_zcolor_bg = zback;
838 	}
839 
840 	if (!revset) {
841 		if (zfset)
842 			if (zfore == zback)
843 				return Windows::rgbShift(Windows::_zcolor_Foreground);
844 			else
845 				return Windows::_zcolor_Foreground;
846 		else if (zbset && styles[style].fg == Windows::_zcolor_Background)
847 			return Windows::_zcolor_LightGrey;
848 		else
849 			return styles[style].fg;
850 	} else {
851 		if (zbset)
852 			return Windows::_zcolor_Background;
853 		else
854 			return styles[style].bg;
855 	}
856 }
857 
858 } // End of namespace Glk
859