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 "common/algorithm.h"
24 #include "common/textconsole.h"
25
26 #include "buried/buried.h"
27 #include "buried/graphics.h"
28 #include "buried/message.h"
29 #include "buried/window.h"
30
31 namespace Buried {
32
33 const Window *kWindowPosTop = (const Window *)nullptr;
34 const Window *kWindowPosTopMost = (const Window *)-1;
35
Window(BuriedEngine * vm,Window * parent,bool visible)36 Window::Window(BuriedEngine *vm, Window *parent, bool visible) : _vm(vm), _parent(parent), _visible(visible) {
37 _enabled = true;
38
39 // Add us to the bottom of the parent's window list
40 if (_parent)
41 _parent->_children.push_front(this);
42 }
43
~Window()44 Window::~Window() {
45 // Remove us from any of the parent's window lists
46 if (_parent) {
47 _parent->_children.remove(this);
48 _parent->_topMostChildren.remove(this);
49 }
50
51 // Remove any of our messages from the queue
52 _vm->removeAllMessages(this);
53
54 // ...and any timers
55 _vm->removeAllTimers(this);
56
57 // Make sure we're not the focused window
58 if (_vm->_focusedWindow == this)
59 _vm->_focusedWindow = nullptr;
60
61 // And also not captured
62 if (_vm->_captureWindow == this)
63 _vm->_captureWindow = nullptr;
64
65 // Invalidate this window's rect as well
66 _vm->_gfx->invalidateRect(getAbsoluteRect());
67 }
68
invalidateRect(const Common::Rect & rect,bool erase)69 void Window::invalidateRect(const Common::Rect &rect, bool erase) {
70 _vm->_gfx->invalidateRect(makeAbsoluteRect(rect), erase);
71 }
72
getClientRect() const73 Common::Rect Window::getClientRect() const {
74 return Common::Rect(_rect.width(), _rect.height());
75 }
76
getAbsoluteRect() const77 Common::Rect Window::getAbsoluteRect() const {
78 return makeAbsoluteRect(_rect);
79 }
80
sendMessage(Message * message)81 void Window::sendMessage(Message *message) {
82 switch (message->getMessageType()) {
83 case kMessageTypeKeyUp:
84 onKeyUp(((KeyUpMessage *)message)->getKeyState(), ((KeyUpMessage *)message)->getFlags());
85 break;
86 case kMessageTypeKeyDown:
87 onKeyDown(((KeyDownMessage *)message)->getKeyState(), ((KeyDownMessage *)message)->getFlags());
88 break;
89 case kMessageTypeTimer:
90 onTimer(((TimerMessage *)message)->getTimer());
91 break;
92 case kMessageTypeMouseMove:
93 onMouseMove(((MouseMoveMessage *)message)->getPoint(), ((MouseMoveMessage *)message)->getFlags());
94 break;
95 case kMessageTypeLButtonUp:
96 onLButtonUp(((LButtonUpMessage *)message)->getPoint(), ((LButtonUpMessage *)message)->getFlags());
97 break;
98 case kMessageTypeLButtonDown:
99 onLButtonDown(((LButtonDownMessage *)message)->getPoint(), ((LButtonDownMessage *)message)->getFlags());
100 break;
101 case kMessageTypeMButtonUp:
102 onMButtonUp(((MButtonUpMessage *)message)->getPoint(), ((MButtonUpMessage *)message)->getFlags());
103 break;
104 case kMessageTypeRButtonUp:
105 onRButtonUp(((RButtonUpMessage *)message)->getPoint(), ((RButtonUpMessage *)message)->getFlags());
106 break;
107 case kMessageTypeRButtonDown:
108 onRButtonDown(((RButtonDownMessage *)message)->getPoint(), ((RButtonDownMessage *)message)->getFlags());
109 break;
110 case kMessageTypeSetCursor:
111 onSetCursor(((SetCursorMessage *)message)->getMessage());
112 break;
113 case kMessageTypeEnable:
114 onEnable(((EnableMessage *)message)->getEnable());
115 break;
116 default:
117 error("Unknown message type %d", message->getMessageType());
118 }
119
120 delete message;
121 }
122
postMessage(Message * message)123 void Window::postMessage(Message *message) {
124 // Simple wrapper
125 _vm->postMessageToWindow(this, message);
126 }
127
updateWindow()128 void Window::updateWindow() {
129 // If we're not visible, ignore
130 if (!isWindowVisible())
131 return;
132
133 // If we're not in the dirty rect, ignore
134 if (!_vm->_gfx->getDirtyRect().intersects(getAbsoluteRect()))
135 return;
136
137 // If we need to erase, erase first
138 if (_vm->_gfx->needsErase())
139 onEraseBackground();
140
141 // Always draw this window first
142 onPaint();
143
144 // Draw children
145 for (WindowList::iterator it = _children.begin(); it != _children.end(); ++it)
146 (*it)->updateWindow();
147
148 // Draw top-most children
149 for (WindowList::iterator it = _topMostChildren.begin(); it != _topMostChildren.end(); ++it)
150 (*it)->updateWindow();
151 }
152
setWindowPos(const Window * insertAfter,int x,int y,int width,int height,uint flags)153 void Window::setWindowPos(const Window *insertAfter, int x, int y, int width, int height, uint flags) {
154 if (!(flags & kWindowPosNoZOrder)) {
155 assert(insertAfter != this); // I don't even want to think about this case
156
157 _parent->_children.remove(this);
158 _parent->_topMostChildren.remove(this);
159
160 if (insertAfter == kWindowPosTop) {
161 // Reposition the window to the top
162 _parent->_children.push_back(this);
163 } else if (insertAfter == kWindowPosTopMost) {
164 // Reposition the window to the top of the top-most
165 _parent->_topMostChildren.push_back(this);
166 } else {
167 // Reposition the window to after insertAfter
168 WindowList::iterator it = Common::find(_parent->_children.begin(), _parent->_children.end(), insertAfter);
169
170 if (it == _parent->_children.end()) {
171 it = Common::find(_parent->_topMostChildren.begin(), _parent->_topMostChildren.end(), insertAfter);
172
173 // It has to be in one of the lists
174 assert(it != _parent->_topMostChildren.end());
175
176 _parent->_topMostChildren.insert(it, this);
177 } else {
178 _parent->_children.insert(it, this);
179 }
180 }
181 }
182
183 if (flags & kWindowPosShowWindow) {
184 assert(!(flags & kWindowPosHideWindow));
185 showWindow(kWindowShow);
186 } else if (flags & kWindowPosHideWindow) {
187 assert(!(flags & kWindowPosShowWindow));
188 showWindow(kWindowHide);
189 }
190
191 if (!(flags & kWindowPosNoActivate)) {
192 // TODO: Activate the window
193 }
194
195 if (!(flags & kWindowPosNoMove))
196 _rect.moveTo(x, y);
197
198 if (!(flags & kWindowPosNoSize)) {
199 _rect.right = _rect.left + width;
200 _rect.bottom = _rect.top + height;
201 }
202 }
203
showWindow(WindowShowMode showMode)204 void Window::showWindow(WindowShowMode showMode) {
205 bool newVisibility = (showMode != kWindowHide);
206
207 if (_visible != newVisibility) {
208 invalidateWindow();
209 _visible = newVisibility;
210 }
211
212 if (showMode == kWindowShowNormal) {
213 // TODO: Activate
214 }
215 }
216
enableWindow(bool enable)217 void Window::enableWindow(bool enable) {
218 if (_enabled != enable) {
219 _enabled = enable;
220 postMessage(new EnableMessage(enable));
221 }
222 }
223
isWindowEnabled() const224 bool Window::isWindowEnabled() const {
225 if (_parent && !_parent->isWindowEnabled())
226 return false;
227
228 return _enabled && _visible;
229 }
230
setTimer(uint elapse)231 uint Window::setTimer(uint elapse) {
232 return _vm->createTimer(this, elapse);
233 }
234
killTimer(uint timer)235 bool Window::killTimer(uint timer) {
236 return _vm->killTimer(timer);
237 }
238
makeAbsoluteRect(const Common::Rect & rect) const239 Common::Rect Window::makeAbsoluteRect(const Common::Rect &rect) const {
240 // No parent; it's already absolute
241 if (!_parent)
242 return rect;
243
244 Common::Rect parentRect = _parent->getAbsoluteRect();
245 Common::Rect absoluteRect = rect;
246 absoluteRect.translate(parentRect.left, parentRect.top);
247 absoluteRect.right = MIN(parentRect.right, absoluteRect.right);
248 absoluteRect.bottom = MIN(parentRect.bottom, absoluteRect.bottom);
249 return absoluteRect;
250 }
251
setFocus()252 Window *Window::setFocus() {
253 // Don't allow focus to be acquired if the window is disabled
254 if (!isWindowEnabled())
255 return nullptr;
256
257 Window *oldWindow = nullptr;
258
259 // Notify the old window we just took its focus
260 if (_vm->_focusedWindow) {
261 _vm->_focusedWindow->onKillFocus(this);
262 oldWindow = _vm->_focusedWindow;
263 }
264
265 _vm->_focusedWindow = this;
266 onSetFocus(oldWindow);
267 return oldWindow;
268 }
269
childWindowAtPoint(const Common::Point & point)270 Window *Window::childWindowAtPoint(const Common::Point &point) {
271 for (WindowList::iterator it = _topMostChildren.reverse_begin(); it != _topMostChildren.end(); --it)
272 if ((*it)->getAbsoluteRect().contains(point) && (*it)->isWindowEnabled())
273 return (*it)->childWindowAtPoint(point);
274
275 for (WindowList::iterator it = _children.reverse_begin(); it != _children.end(); --it)
276 if ((*it)->getAbsoluteRect().contains(point) && (*it)->isWindowEnabled())
277 return (*it)->childWindowAtPoint(point);
278
279 return this;
280 }
281
setCapture()282 Window *Window::setCapture() {
283 Window *oldCapturedWindow = _vm->_captureWindow;
284 _vm->_captureWindow = this;
285 return oldCapturedWindow;
286 }
287
convertPointToGlobal(const Common::Point & point)288 Common::Point Window::convertPointToGlobal(const Common::Point &point) {
289 Common::Rect absoluteRect = getAbsoluteRect();
290 return Common::Point(point.x + absoluteRect.left, point.y + absoluteRect.top);
291 }
292
convertPointToLocal(const Common::Point & point)293 Common::Point Window::convertPointToLocal(const Common::Point &point) {
294 Common::Rect absoluteRect = getAbsoluteRect();
295 return Common::Point(point.x - absoluteRect.left, point.y - absoluteRect.top);
296 }
297
convertPointToWindow(const Common::Point & point,Window * dest)298 Common::Point Window::convertPointToWindow(const Common::Point &point, Window *dest) {
299 return dest->convertPointToLocal(convertPointToGlobal(point));
300 }
301
onSetCursor(uint message)302 bool Window::onSetCursor(uint message) {
303 // The default implementation is to try the parent first
304 if (_parent && _parent->onSetCursor(message))
305 return true;
306
307 // Then otherwise default to the arrow
308 _vm->_gfx->setCursor(kCursorArrow);
309 return false;
310 }
311
312 } // End of namespace Buried
313