aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2019-01-02 18:18:11 -0800
committerPaul Gilbert2019-01-02 18:18:11 -0800
commitf1d9722f3bd58f7883f3e76c19d4a0133da73489 (patch)
tree26986b085d83e597b10c3851fde9b49574c10586
parent3ed48e3de223259dd58f0c613c2d68d69848e5a2 (diff)
downloadscummvm-rg350-f1d9722f3bd58f7883f3e76c19d4a0133da73489.tar.gz
scummvm-rg350-f1d9722f3bd58f7883f3e76c19d4a0133da73489.tar.bz2
scummvm-rg350-f1d9722f3bd58f7883f3e76c19d4a0133da73489.zip
GLK: FROTZ: Add support for pair windows to have more than 2 children
This is primarily for the V6 games, which have up to 8 windows on-screen at the same time in arbitray positions ext
-rw-r--r--engines/glk/frotz/windows.cpp18
-rw-r--r--engines/glk/frotz/windows.h5
-rw-r--r--engines/glk/glk_api.cpp9
-rw-r--r--engines/glk/glk_types.h12
-rw-r--r--engines/glk/utils.h25
-rw-r--r--engines/glk/window_pair.cpp57
-rw-r--r--engines/glk/window_pair.h6
-rw-r--r--engines/glk/windows.cpp85
8 files changed, 138 insertions, 79 deletions
diff --git a/engines/glk/frotz/windows.cpp b/engines/glk/frotz/windows.cpp
index 1863e68032..ffee6392c7 100644
--- a/engines/glk/frotz/windows.cpp
+++ b/engines/glk/frotz/windows.cpp
@@ -22,6 +22,7 @@
#include "glk/frotz/windows.h"
#include "glk/frotz/frotz.h"
+#include "glk/window_pair.h"
namespace Glk {
namespace Frotz {
@@ -51,7 +52,8 @@ winid_t Window::getWindow() {
// TODO: For now I'm assuming all the extra created windows will be graphics, since Glk requires
// us to specify it at creation time. Not sure if it's true or not for all V6 games
winid_t parent = _windows->_lower;
- _win = g_vm->glk_window_open(parent, winmethod_OnTop | winmethod_Fixed, 0, wintype_Graphics, 0);
+ _win = g_vm->glk_window_open(g_vm->glk_window_get_root(), winmethod_Arbitrary | winmethod_Fixed,
+ 0, wintype_Graphics, 0);
}
return _win;
@@ -59,6 +61,7 @@ winid_t Window::getWindow() {
void Window::setSize(const Point &newSize) {
winid_t win = getWindow();
+ checkRepositionLower();
win->setSize(newSize);
/* TODO
@@ -73,6 +76,7 @@ void Window::setSize(const Point &newSize) {
void Window::setPosition(const Point &newPos) {
winid_t win = getWindow();
+ checkRepositionLower();
win->setPosition(newPos);
}
@@ -113,5 +117,17 @@ void Window::setProperty(WindowProperty propType, uint16 value) {
// TODO
}
+void Window::checkRepositionLower() {
+ if (&_windows->_lower == this) {
+ PairWindow *parent = dynamic_cast<PairWindow *>(_win->_parent);
+ if (!parent)
+ error("Parent was not a pair window");
+
+ // Ensure the parent pair window is flagged as having children at arbitrary positions,
+ // just in case it isn't already
+ parent->_dir = winmethod_Arbitrary;
+ }
+}
+
} // End of namespace Frotz
} // End of namespace Glk
diff --git a/engines/glk/frotz/windows.h b/engines/glk/frotz/windows.h
index ba277d57dc..43358665b2 100644
--- a/engines/glk/frotz/windows.h
+++ b/engines/glk/frotz/windows.h
@@ -64,6 +64,11 @@ private:
* Set a property value
*/
void setProperty(WindowProperty propType, uint16 value);
+
+ /**
+ * Called when trying to reposition or resize windows. Does special handling for the lower window
+ */
+ void checkRepositionLower();
public:
/**
* Constructor
diff --git a/engines/glk/glk_api.cpp b/engines/glk/glk_api.cpp
index e2da31706a..6e0f33ea56 100644
--- a/engines/glk/glk_api.cpp
+++ b/engines/glk/glk_api.cpp
@@ -258,10 +258,11 @@ winid_t GlkAPI::glk_window_get_sibling(winid_t win) {
if (!parentWin)
return nullptr;
- if (parentWin->_child1 == win)
- return parentWin->_child2;
- else if (parentWin->_child2 == win)
- return parentWin->_child1;
+ int index = parentWin->_children.indexOf(win);
+ if (index == ((int)parentWin->_children.size() - 1))
+ return parentWin->_children.front();
+ else if (index >= 0)
+ return parentWin->_children[index + 1];
return nullptr;
}
diff --git a/engines/glk/glk_types.h b/engines/glk/glk_types.h
index 2e23aec018..4a29b15abf 100644
--- a/engines/glk/glk_types.h
+++ b/engines/glk/glk_types.h
@@ -150,12 +150,12 @@ enum WinType {
};
enum WinMethod {
- winmethod_Left = 0x00,
- winmethod_Right = 0x01,
- winmethod_Above = 0x02,
- winmethod_Below = 0x03,
- winmethod_OnTop = 0x04, ///< Newly introduced for ScummGlk
- winmethod_DirMask = 0x0f,
+ winmethod_Left = 0x00,
+ winmethod_Right = 0x01,
+ winmethod_Above = 0x02,
+ winmethod_Below = 0x03,
+ winmethod_Arbitrary = 0x04, ///< Newly introduced for ScummGlk
+ winmethod_DirMask = 0x0f,
winmethod_Fixed = 0x10,
winmethod_Proportional = 0x20,
diff --git a/engines/glk/utils.h b/engines/glk/utils.h
index 3655f57c33..2532f270a5 100644
--- a/engines/glk/utils.h
+++ b/engines/glk/utils.h
@@ -23,13 +23,20 @@
#ifndef GLK_UTILS_H
#define GLK_UTILS_H
+#include "common/array.h"
#include "common/rect.h"
#include "glk/glk_types.h"
namespace Glk {
+/**
+ * Two dimensional point
+ */
typedef Common::Point Point;
+/**
+ * Contains a square box/rect area
+ */
struct Rect : public Common::Rect {
public:
static Rect fromXYWH(int x, int y, int w, int h) {
@@ -42,6 +49,24 @@ public:
};
/**
+ * Derived array class
+ */
+template<class T>class Array : public Common::Array<T> {
+public:
+ /**
+ * Return the index in the array of a passed item
+ */
+ int indexOf(T val) {
+ for (size_t idx = 0; idx < this->size(); ++idx) {
+ if ((*this).operator[](idx) == val)
+ return idx;
+ }
+
+ return -1;
+ }
+};
+
+/**
* Converts a decimal or hexadecimal string into a number
*/
int strToInt(const char *s);
diff --git a/engines/glk/window_pair.cpp b/engines/glk/window_pair.cpp
index c90f389eac..7ddd57b23c 100644
--- a/engines/glk/window_pair.cpp
+++ b/engines/glk/window_pair.cpp
@@ -34,13 +34,13 @@ PairWindow::PairWindow(Windows *windows, uint method, Window *key, uint size) :
_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) {
+ _key(key), _size(size), _keyDamage(0) {
_type = wintype_Pair;
}
PairWindow::~PairWindow() {
- delete _child1;
- delete _child2;
+ for (uint idx = 0; idx < _children.size(); ++idx)
+ delete _children[idx];
}
void PairWindow::rearrange(const Rect &box) {
@@ -51,24 +51,23 @@ void PairWindow::rearrange(const Rect &box) {
_bbox = box;
if (!_backward) {
- ch1 = _child1;
- ch2 = _child2;
+ ch1 = _children[0];
+ ch2 = _children[1];
} else {
- ch1 = _child2;
- ch2 = _child1;
+ ch1 = _children[1];
+ ch2 = _children[0];
}
-
- if (_dir == winmethod_OnTop) {
- // ch2 is on top of ch1
- ch1->rearrange(box1);
- if (!ch2->_bbox.isEmpty() && !ch2->_bbox.contains(box)) {
- // ch2 is outside new bounds, so clip it to the new dimensions
- Rect subRect = ch2->_bbox;
- subRect.clip(box);
- ch2->rearrange(subRect);
+ if (_dir == winmethod_Arbitrary) {
+ // When a pair window is in "arbitrary" mode, each child window has it's own independant positioning,
+ // so thre's no need to be readjusting it
+ /*
+ for (int ctr = 0, idx = (_backward ? (int)_children.size() - 1 : 0); ctr < (int)_children.size();
+ ++ctr, idx += (_backward ? -1 : 1)) {
+ Window *w = _children[idx];
+ w->rearrange();
}
-
+ */
return;
}
@@ -142,10 +141,12 @@ void PairWindow::rearrange(const Rect &box) {
void PairWindow::redraw() {
Window::redraw();
- _child1->redraw();
- _child2->redraw();
+ for (int ctr = 0, idx = (_backward ? (int)_children.size() - 1 : 0); ctr < (int)_children.size();
+ ++ctr, idx += (_backward ? -1 : 1)) {
+ _children[idx]->redraw();
+ }
- Window *child = !_backward ? _child1 : _child2;
+ Window *child = !_backward ? _children.front() : _children.back();
Rect box(child->_bbox.left, child->_yAdj ? child->_bbox.top - child->_yAdj : child->_bbox.top,
child->_bbox.right, child->_bbox.bottom);
@@ -184,6 +185,7 @@ void PairWindow::getArrangement(uint *method, uint *size, Window **keyWin) {
void PairWindow::setArrangement(uint method, uint size, Window *keyWin) {
uint newDir;
bool newVertical, newBackward;
+ assert((method & winmethod_DirMask) != winmethod_Arbitrary && _dir != winmethod_Arbitrary);
if (_key) {
Window *wx;
@@ -226,9 +228,7 @@ void PairWindow::setArrangement(uint method, uint size, Window *keyWin) {
if ((newBackward && !_backward) || (!newBackward && _backward)) {
// switch the children
- Window *tmpWin = _child1;
- _child1 = _child2;
- _child2 = tmpWin;
+ SWAP(_children[0], _children[1]);
}
// set up everything else
@@ -245,11 +245,12 @@ void PairWindow::setArrangement(uint method, uint size, Window *keyWin) {
}
void PairWindow::click(const Point &newPos) {
- if (_child1->_bbox.contains(newPos))
- _child1->click(newPos);
-
- if (_child2->_bbox.contains(newPos))
- _child2->click(newPos);
+ for (int ctr = 0, idx = (!_backward ? (int)_children.size() - 1 : 0); ctr < (int)_children.size();
+ ++ctr, idx += (_backward ? -1 : 1)) {
+ Window *w = _children[idx];
+ if (w->_bbox.contains(newPos))
+ w->click(newPos);
+ }
}
} // End of namespace Glk
diff --git a/engines/glk/window_pair.h b/engines/glk/window_pair.h
index 83cbcc884a..10d92648d0 100644
--- a/engines/glk/window_pair.h
+++ b/engines/glk/window_pair.h
@@ -24,15 +24,17 @@
#define GLK_WINDOW_PAIR_H
#include "glk/windows.h"
+#include "glk/utils.h"
namespace Glk {
/**
- * Pair window
+ * Acts as a container of child windows. Under most cases there will be exactly two children,
+ * though in a special new "OnTop" mode, there can be more than two
*/
class PairWindow : public Window {
public:
- Window *_child1, *_child2;
+ Array<Window *> _children;
// split info...
uint _dir; ///< winmethod_Left, Right, Above, Below, or OnTop
diff --git a/engines/glk/windows.cpp b/engines/glk/windows.cpp
index de8fa52385..d75ba1f6e5 100644
--- a/engines/glk/windows.cpp
+++ b/engines/glk/windows.cpp
@@ -104,15 +104,22 @@ Window *Windows::windowOpen(Window *splitwin, uint method, uint size,
val = (method & winmethod_DirMask);
if (val != winmethod_Above && val != winmethod_Below && val != winmethod_Left
- && val != winmethod_Right && val != winmethod_OnTop) {
+ && val != winmethod_Right && val != winmethod_Arbitrary) {
warning("window_open: invalid method (bad direction)");
return nullptr;
}
- oldparent = splitwin->_parent;
- if (oldparent && oldparent->_type != wintype_Pair) {
- warning("window_open: parent window is not Pair");
- return nullptr;
+ if (splitwin->_type == wintype_Pair) {
+ if ((method & winmethod_DirMask) != winmethod_Arbitrary) {
+ warning("window_open: Can only add windows to a Pair window in arbitrary mode");
+ return nullptr;
+ }
+ } else {
+ oldparent = splitwin->_parent;
+ if (oldparent && oldparent->_type != wintype_Pair) {
+ warning("window_open: parent window is not Pair");
+ return nullptr;
+ }
}
}
@@ -125,11 +132,16 @@ Window *Windows::windowOpen(Window *splitwin, uint method, uint size,
if (!splitwin) {
_rootWin = newwin;
+ } else if (splitwin->_type == wintype_Pair) {
+ pairWin = static_cast<PairWindow *>(splitwin);
+ pairWin->_dir = winmethod_Arbitrary;
+ pairWin->_children.push_back(newwin);
+ newwin->_parent = pairWin;
} else {
// create pairWin, with newwin as the key
pairWin = newPairWindow(method, newwin, size);
- pairWin->_child1 = splitwin;
- pairWin->_child2 = newwin;
+ pairWin->_children.push_back(splitwin);
+ pairWin->_children.push_back(newwin);
splitwin->_parent = pairWin;
newwin->_parent = pairWin;
@@ -138,10 +150,11 @@ Window *Windows::windowOpen(Window *splitwin, uint method, uint size,
if (oldparent) {
PairWindow *parentWin = dynamic_cast<PairWindow *>(oldparent);
assert(parentWin);
- if (parentWin->_child1 == splitwin)
- parentWin->_child1 = pairWin;
- else
- parentWin->_child2 = pairWin;
+
+ for (uint idx = 0; idx < parentWin->_children.size(); ++idx) {
+ if (parentWin->_children[idx] == splitwin)
+ parentWin->_children[idx] = pairWin;
+ }
} else {
_rootWin = pairWin;
}
@@ -168,24 +181,22 @@ void Windows::windowClose(Window *win, StreamResult *result) {
PairWindow *pairWin = dynamic_cast<PairWindow *>(win->_parent);
PairWindow *grandparWin;
- if (win == pairWin->_child1) {
- sibWin = pairWin->_child2;
- } else if (win == pairWin->_child2) {
- sibWin = pairWin->_child1;
- } else {
+ int index = pairWin->_children.indexOf(win);
+ if (index == -1) {
warning("windowClose: window tree is corrupted");
return;
}
+ sibWin = (index = ((int)pairWin->_children.size() - 1)) ?
+ pairWin->_children.front() : pairWin->_children[index + 1];
+
grandparWin = dynamic_cast<PairWindow *>(pairWin->_parent);
if (!grandparWin) {
_rootWin = sibWin;
sibWin->_parent = nullptr;
} else {
- if (grandparWin->_child1 == pairWin)
- grandparWin->_child1 = sibWin;
- else
- grandparWin->_child2 = sibWin;
+ index = grandparWin->_children.indexOf(pairWin);
+ grandparWin->_children[index] = sibWin;
sibWin->_parent = grandparWin;
}
@@ -197,10 +208,8 @@ void Windows::windowClose(Window *win, StreamResult *result) {
win->close(true);
// This probably isn't necessary, but the child *is* gone, so just in case.
- if (win == pairWin->_child1)
- pairWin->_child1 = nullptr;
- else if (win == pairWin->_child2)
- pairWin->_child2 = nullptr;
+ index = pairWin->_children.indexOf(win);
+ pairWin->_children[index] = nullptr;
// Now we can delete the parent pair.
pairWin->close(false);
@@ -462,21 +471,20 @@ Window *Windows::iterateTreeOrder(Window *win) {
PairWindow *pairWin = dynamic_cast<PairWindow *>(win);
if (pairWin) {
- if (!pairWin->_backward)
- return pairWin->_child1;
- else
- return pairWin->_child2;
+ return pairWin->_backward ? pairWin->_children.back() : pairWin->_children.front();
} else {
while (win->_parent) {
pairWin = dynamic_cast<PairWindow *>(win->_parent);
assert(pairWin);
+ int index = pairWin->_children.indexOf(win);
+ assert(index != -1);
if (!pairWin->_backward) {
- if (win == pairWin->_child1)
- return pairWin->_child2;
+ if (index < ((int)pairWin->_children.size() - 1))
+ return pairWin->_children[index + 1];
} else {
- if (win == pairWin->_child2)
- return pairWin->_child1;
+ if (index > 0)
+ return pairWin->_children[index - 1];
}
win = pairWin;
@@ -515,10 +523,11 @@ Window::~Window() {
// Remove the window from any parent
PairWindow *parent = dynamic_cast<PairWindow *>(_parent);
- if (parent && parent->_child1 == this)
- parent->_child1 = nullptr;
- if (parent && parent->_child2 == this)
- parent->_child2 = nullptr;
+ if (parent) {
+ int index = parent->_children.indexOf(this);
+ if (index != -1)
+ parent->_children[index] = nullptr;
+ }
// Delete any attached window stream
_echoStream = nullptr;
@@ -554,8 +563,8 @@ void Window::close(bool recurse) {
PairWindow *pairWin = dynamic_cast<PairWindow *>(this);
if (pairWin) {
- pairWin->_child1->close(recurse);
- pairWin->_child2->close(recurse);
+ for (uint idx = 0; idx < pairWin->_children.size(); ++idx)
+ pairWin->_children[idx]->close();
}
// Finally, delete the window