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