mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-26 12:48:16 +00:00
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
This commit is contained in:
parent
3ed48e3de2
commit
f1d9722f3b
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
@ -41,6 +48,24 @@ public:
|
||||
Rect(int16 x1, int16 y1, int16 x2, int16 y2) : Common::Rect(x1, y1, x2, y2) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user