aboutsummaryrefslogtreecommitdiff
path: root/engines/glk/selection.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/glk/selection.cpp')
-rw-r--r--engines/glk/selection.cpp321
1 files changed, 321 insertions, 0 deletions
diff --git a/engines/glk/selection.cpp b/engines/glk/selection.cpp
new file mode 100644
index 0000000000..f1c5bb86dc
--- /dev/null
+++ b/engines/glk/selection.cpp
@@ -0,0 +1,321 @@
+/* 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 "glk/selection.h"
+#include "glk/conf.h"
+#include "glk/gargoyle.h"
+#include "glk/windows.h"
+#include "common/system.h"
+
+namespace Gargoyle {
+
+void Clipboard::clipboardStore(const Common::U32String &text) {
+ _text = text;
+}
+
+void Clipboard::clipboardSend(ClipSource source) {
+ if (g_system->hasFeature(OSystem::kFeatureClipboardSupport)) {
+ // Convert unicode string to standard string, since that's all ScummVM supports
+ Common::String text;
+ for (uint idx = 0; idx < _text.size(); ++idx)
+ text += (_text[idx] <= 0x7f) ? (char)_text[idx] : '?';
+
+ g_system->setTextInClipboard(text);
+ }
+}
+
+void Clipboard::clipboardReceive(ClipSource source) {
+ if (g_system->hasFeature(OSystem::kFeatureClipboardSupport)) {
+ Windows &windows = *g_vm->_windows;
+
+ if (g_system->hasTextInClipboard()) {
+ Common::String text = g_system->getTextFromClipboard();
+ for (uint idx = 0; idx < text.size(); ++idx) {
+ uint c = text[idx];
+ if (c != '\r' && c != '\n' && c != '\b' && c != '\t')
+ windows.inputHandleKey(c);
+ }
+ }
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+WindowMask::WindowMask() : _hor(0), _ver(0), _links(nullptr) {
+ _last.x = _last.y = 0;
+ resize(g_system->getWidth(), g_system->getHeight());
+}
+
+void WindowMask::resize(size_t x, size_t y) {
+ // Deallocate old storage
+ for (size_t i = 0; i < _hor; i++) {
+ if (_links[i])
+ delete _links[i];
+ }
+
+ delete _links;
+
+ _hor = x + 1;
+ _ver = y + 1;
+
+ // allocate new storage
+ _links = new glui32 *[_hor];
+ if (!_links) {
+ warning("resize_mask: out of memory");
+ _hor = _ver = 0;
+ return;
+ }
+
+ for (size_t i = 0; i < _hor; i++) {
+ _links[i] = new glui32[_ver];
+ if (!_links[i]) {
+ warning("resize_mask: could not allocate new memory");
+ return;
+ }
+ }
+
+ _select.left = 0;
+ _select.top = 0;
+ _select.right = 0;
+ _select.bottom = 0;
+}
+
+void WindowMask::putHyperlink(glui32 linkval, uint x0, uint y0, uint x1, uint y1) {
+ uint i, k;
+ size_t tx0 = x0 < x1 ? x0 : x1;
+ size_t tx1 = x0 < x1 ? x1 : x0;
+ size_t ty0 = y0 < y1 ? y0 : y1;
+ size_t ty1 = y0 < y1 ? y1 : y0;
+
+ if (!_hor || !_ver) {
+ warning("putHyperlink: struct not initialized");
+ return;
+ }
+
+ if (tx0 >= _hor
+ || tx1 >= _hor
+ || ty0 >= _ver || ty1 >= _ver
+ || !_links[tx0] || !_links[tx1]) {
+ warning("putHyperlink: invalid range given");
+ return;
+ }
+
+ for (i = tx0; i < tx1; i++) {
+ for (k = ty0; k < ty1; k++)
+ _links[i][k] = linkval;
+ }
+}
+
+glui32 WindowMask::getHyperlink(const Point &pos) const {
+ if (!_hor || !_ver) {
+ warning("getHyperlink: struct not initialized");
+ return 0;
+ }
+
+ if (pos.x >= (int16)_hor || pos.y >= (int16)_ver || !_links[pos.x]) {
+ warning("getHyperlink: invalid range given");
+ return 0;
+ }
+
+ return _links[pos.x][pos.y];
+}
+
+/*--------------------------------------------------------------------------*/
+
+void Selection::startSelection(const Point &pos) {
+ int tx, ty;
+
+ if (!_hor || !_ver) {
+ warning("startSelection: mask not initialized");
+ return;
+ }
+
+ tx = MIN(pos.x, (int16)_hor);
+ ty = MIN(pos.y, (int16)_ver);
+
+ _select.left = _last.x = tx;
+ _select.top = _last.y = ty;
+ _select.right = 0;
+ _select.bottom = 0;
+
+ g_vm->_windows->selectionChanged();
+}
+
+void Selection::moveSelection(const Point &pos) {
+ int tx, ty;
+
+ if (ABS(pos.x - _last.x) < 5 && ABS(pos.y - _last.y) < 5)
+ return;
+
+ if (!_hor || !_ver) {
+ warning("moveSelection: mask not initialized");
+ return;
+ }
+
+ tx = MIN(pos.x, (int16)_hor);
+ ty = MIN(pos.y, (int16)_ver);
+
+ _select.right = _last.x = tx;
+ _select.bottom = _last.y = ty;
+
+ g_vm->_windows->selectionChanged();
+}
+
+void Selection::clearSelection() {
+ if (!_select.isEmpty())
+ Windows::_forceRedraw = true;
+
+ _select = Rect();
+ g_vm->_windows->clearClaimSelect();
+}
+
+bool Selection::checkSelection(const Rect &r) const {
+ Rect select(MIN(_select.left, _select.right), MAX(_select.left, _select.right),
+ MIN(_select.top, _select.bottom), MAX(_select.top, _select.bottom));
+ if (select.isEmpty())
+ return false;
+
+ return select.intersects(r);
+}
+
+bool Selection::getSelection(const Rect &r, int *rx0, int *rx1) const {
+ uint row, upper, lower, above, below;
+ bool row_selected, found_left, found_right;
+ int from_right, from_below, is_above, is_below;
+ uint cx0, cx1, cy0, cy1;
+ uint x0 = r.left, y0 = r.top, x1 = r.right, y1 = r.bottom;
+
+ row = (y0 + y1) / 2;
+ upper = row - (row - y0) / 2;
+ lower = row + (y1 - row) / 2;
+ above = upper - (g_conf->_leading) / 2;
+ below = lower + (g_conf->_leading) / 2;
+
+ cx0 = MIN(_select.left, _select.right);
+ cx1 = MAX(_select.left, _select.right);
+ cy0 = MIN(_select.top, _select.bottom);
+ cy1 = MAX(_select.top, _select.bottom);
+
+ row_selected = false;
+
+ if ((cy0 >= upper && cy0 <= lower)
+ || (cy1 >= upper && cy1 <= lower))
+ row_selected = true;
+
+ if (row >= cy0 && row <= cy1)
+ row_selected = true;
+
+ if (!row_selected)
+ return false;
+
+ from_right = (_select.left != (int16)cx0);
+ from_below = (_select.top != (int16)cy0);
+ is_above = (above >= cy0 && above <= cy1);
+ is_below = (below >= cy0 && below <= cy1);
+
+ *rx0 = 0;
+ *rx1 = 0;
+
+ found_left = false;
+ found_right = false;
+
+ if (is_above && is_below) {
+ *rx0 = x0;
+ *rx1 = x1;
+ found_left = true;
+ found_right = true;
+ } else if (!is_above && is_below) {
+ if (from_below) {
+ if (from_right) {
+ *rx0 = cx0;
+ *rx1 = x1;
+ found_left = true;
+ found_right = true;
+ } else {
+ *rx0 = cx1;
+ *rx1 = x1;
+ found_left = true;
+ found_right = true;
+ }
+ } else {
+ if (from_right) {
+ *rx0 = cx1;
+ *rx1 = x1;
+ found_left = true;
+ found_right = true;
+ } else {
+ *rx1 = x1;
+ found_right = true;
+ }
+ }
+ } else if (is_above && !is_below) {
+ if (from_below) {
+ if (from_right) {
+ *rx0 = x0;
+ *rx1 = cx1;
+ found_left = true;
+ found_right = true;
+ } else {
+ *rx0 = x0;
+ *rx1 = cx0;
+ found_left = true;
+ found_right = true;
+ }
+ } else {
+ if (from_right) {
+ if (x0 > cx0)
+ return false;
+ *rx0 = x0;
+ *rx1 = cx0;
+ found_left = true;
+ found_right = true;
+ } else {
+ *rx0 = x0;
+ found_left = true;
+ }
+ }
+ }
+
+ if (found_left && found_right)
+ return true;
+
+ for (uint i = x0; i <= x1; i++) {
+ if (i >= cx0 && i <= cx1) {
+ if (!found_left) {
+ *rx0 = i;
+ found_left = true;
+ if (found_right)
+ return true;
+ } else {
+ if (!found_right)
+ *rx1 = i;
+ }
+ }
+ }
+
+ if (rx0 && !rx1)
+ *rx1 = x1;
+
+ return (rx0 && rx1);
+}
+
+} // End of namespace Gargoyle