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/selection.h"
24 #include "glk/conf.h"
25 #include "glk/glk.h"
26 #include "glk/windows.h"
27 #include "common/system.h"
28 
29 namespace Glk {
30 
clipboardStore(const Common::U32String & text)31 void Clipboard::clipboardStore(const Common::U32String &text) {
32 	_text = text;
33 }
34 
clipboardSend(ClipSource source)35 void Clipboard::clipboardSend(ClipSource source) {
36 	g_system->setTextInClipboard(_text);
37 }
38 
clipboardReceive(ClipSource source)39 void Clipboard::clipboardReceive(ClipSource source) {
40 	Windows &windows = *g_vm->_windows;
41 
42 	if (g_system->hasTextInClipboard()) {
43 		Common::U32String text = g_system->getTextFromClipboard();
44 		for (uint idx = 0; idx < text.size(); ++idx) {
45 			uint c = text[idx];
46 			if (c != '\r' && c != '\n' && c != '\b' && c != '\t')
47 				windows.inputHandleKey(c);
48 		}
49 	}
50 }
51 
52 /*--------------------------------------------------------------------------*/
53 
WindowMask()54 WindowMask::WindowMask() : _hor(0), _ver(0), _links(nullptr) {
55 	_last.x = _last.y = 0;
56 	resize(g_system->getWidth(), g_system->getHeight());
57 }
58 
~WindowMask()59 WindowMask::~WindowMask() {
60 	clear();
61 }
62 
clear()63 void WindowMask::clear() {
64 	for (size_t i = 0; i < _hor; i++) {
65 		if (_links[i])
66 			delete[] _links[i];
67 	}
68 
69 	delete[] _links;
70 }
71 
resize(size_t x,size_t y)72 void WindowMask::resize(size_t x, size_t y) {
73 	clear();
74 
75 	_hor = x + 1;
76 	_ver = y + 1;
77 
78 	// allocate new storage
79 	_links = new uint *[_hor];
80 	if (!_links) {
81 		warning("resize_mask: out of memory");
82 		_hor = _ver = 0;
83 		return;
84 	}
85 
86 	for (size_t i = 0; i < _hor; i++) {
87 		_links[i] = new uint[_ver];
88 		if (!_links[i]) {
89 			warning("resize_mask: could not allocate new memory");
90 			return;
91 		}
92 	}
93 
94 	_select.left = 0;
95 	_select.top = 0;
96 	_select.right = 0;
97 	_select.bottom = 0;
98 }
99 
putHyperlink(uint linkval,uint x0,uint y0,uint x1,uint y1)100 void WindowMask::putHyperlink(uint linkval, uint x0, uint y0, uint x1, uint y1) {
101 	uint i, k;
102 	size_t tx0 = x0 < x1 ? x0 : x1;
103 	size_t tx1 = x0 < x1 ? x1 : x0;
104 	size_t ty0 = y0 < y1 ? y0 : y1;
105 	size_t ty1 = y0 < y1 ? y1 : y0;
106 
107 	if (!_hor || !_ver) {
108 		warning("putHyperlink: struct not initialized");
109 		return;
110 	}
111 
112 	if (tx0 >= _hor
113 			|| tx1 >= _hor
114 			|| ty0 >= _ver || ty1 >= _ver
115 			|| !_links[tx0] || !_links[tx1]) {
116 		warning("putHyperlink: invalid range given");
117 		return;
118 	}
119 
120 	for (i = tx0; i < tx1; i++) {
121 		for (k = ty0; k < ty1; k++)
122 			_links[i][k] = linkval;
123 	}
124 }
125 
getHyperlink(const Point & pos) const126 uint WindowMask::getHyperlink(const Point &pos) const {
127 	if (!_hor || !_ver) {
128 		warning("getHyperlink: struct not initialized");
129 		return 0;
130 	}
131 
132 	if (pos.x >= (int16)_hor || pos.y >= (int16)_ver || !_links[pos.x]) {
133 		warning("getHyperlink: invalid range given");
134 		return 0;
135 	}
136 
137 	return _links[pos.x][pos.y];
138 }
139 
140 /*--------------------------------------------------------------------------*/
141 
startSelection(const Point & pos)142 void Selection::startSelection(const Point &pos) {
143 	int tx, ty;
144 
145 	if (!_hor || !_ver) {
146 		warning("startSelection: mask not initialized");
147 		return;
148 	}
149 
150 	tx = MIN(pos.x, (int16)_hor);
151 	ty = MIN(pos.y, (int16)_ver);
152 
153 	_select.left = _select.right = _last.x = tx;
154 	_select.top = _select.bottom = _last.y = ty;
155 
156 	g_vm->_windows->selectionChanged();
157 }
158 
moveSelection(const Point & pos)159 void Selection::moveSelection(const Point &pos) {
160 	int tx, ty;
161 
162 	if (ABS(pos.x - _last.x) < 5 && ABS(pos.y - _last.y) < 5)
163 		return;
164 
165 	if (!_hor || !_ver) {
166 		warning("moveSelection: mask not initialized");
167 		return;
168 	}
169 
170 	tx = MIN(pos.x, (int16)_hor);
171 	ty = MIN(pos.y, (int16)_ver);
172 
173 	_select.right = _last.x = tx;
174 	_select.bottom = _last.y = ty;
175 
176 	g_vm->_windows->selectionChanged();
177 }
178 
clearSelection()179 void Selection::clearSelection() {
180 	if (!_select.isEmpty())
181 		Windows::_forceRedraw = true;
182 
183 	_select = Rect();
184 	g_vm->_windows->clearClaimSelect();
185 }
186 
checkSelection(const Rect & r) const187 bool Selection::checkSelection(const Rect &r) const {
188 	Rect select(MIN(_select.left, _select.right), MIN(_select.top, _select.bottom),
189 		MAX(_select.left, _select.right), MAX(_select.top, _select.bottom));
190 	if (select.isEmpty())
191 		return false;
192 
193 	return select.intersects(r);
194 }
195 
getSelection(const Rect & r,int * rx0,int * rx1) const196 bool Selection::getSelection(const Rect &r, int *rx0, int *rx1) const {
197 	uint row, upper, lower, above, below;
198 	bool row_selected, found_left, found_right;
199 	int from_right, from_below, is_above, is_below;
200 	uint cx0, cx1, cy0, cy1;
201 	uint x0 = r.left, y0 = r.top, x1 = r.right, y1 = r.bottom;
202 
203 	row = (y0 + y1) / 2;
204 	upper = row - (row - y0) / 2;
205 	lower = row + (y1 - row) / 2;
206 	above = upper - (g_conf->_propInfo._leading) / 2;
207 	below = lower + (g_conf->_propInfo._leading) / 2;
208 
209 	cx0 = MIN(_select.left, _select.right);
210 	cx1 = MAX(_select.left, _select.right);
211 	cy0 = MIN(_select.top, _select.bottom);
212 	cy1 = MAX(_select.top, _select.bottom);
213 
214 	row_selected = false;
215 
216 	if ((cy0 >= upper && cy0 <= lower)
217 			|| (cy1 >= upper && cy1 <= lower))
218 		row_selected = true;
219 
220 	if (row >= cy0 && row <= cy1)
221 		row_selected = true;
222 
223 	if (!row_selected)
224 		return false;
225 
226 	from_right = (_select.left != (int16)cx0);
227 	from_below = (_select.top != (int16)cy0);
228 	is_above = (above >= cy0 && above <= cy1);
229 	is_below = (below >= cy0 && below <= cy1);
230 
231 	*rx0 = 0;
232 	*rx1 = 0;
233 
234 	found_left = false;
235 	found_right = false;
236 
237 	if (is_above && is_below) {
238 		*rx0 = x0;
239 		*rx1 = x1;
240 		found_left = true;
241 		found_right = true;
242 	} else if (!is_above && is_below) {
243 		if (from_below) {
244 			if (from_right) {
245 				*rx0 = cx0;
246 				*rx1 = x1;
247 				found_left = true;
248 				found_right = true;
249 			} else {
250 				*rx0 = cx1;
251 				*rx1 = x1;
252 				found_left = true;
253 				found_right = true;
254 			}
255 		} else {
256 			if (from_right) {
257 				*rx0 = cx1;
258 				*rx1 = x1;
259 				found_left = true;
260 				found_right = true;
261 			} else {
262 				*rx1 = x1;
263 				found_right = true;
264 			}
265 		}
266 	} else if (is_above && !is_below) {
267 		if (from_below) {
268 			if (from_right) {
269 				*rx0 = x0;
270 				*rx1 = cx1;
271 				found_left = true;
272 				found_right = true;
273 			} else {
274 				*rx0 = x0;
275 				*rx1 = cx0;
276 				found_left = true;
277 				found_right = true;
278 			}
279 		} else {
280 			if (from_right) {
281 				if (x0 > cx0)
282 					return false;
283 				*rx0 = x0;
284 				*rx1 = cx0;
285 				found_left = true;
286 				found_right = true;
287 			} else {
288 				*rx0 = x0;
289 				found_left = true;
290 			}
291 		}
292 	}
293 
294 	if (found_left && found_right)
295 		return true;
296 
297 	for (uint i = x0; i <= x1; i++) {
298 		if (i >= cx0 && i <= cx1) {
299 			if (!found_left) {
300 				*rx0 = i;
301 				found_left = true;
302 				if (found_right)
303 					return true;
304 			} else {
305 				if (!found_right)
306 					*rx1 = i;
307 			}
308 		}
309 	}
310 
311 	if (rx0 && !rx1)
312 		*rx1 = x1;
313 
314 	return (rx0 && rx1);
315 }
316 
317 } // End of namespace Glk
318