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 #ifndef ULTIMA8_GUMPS_GUMP_H
24 #define ULTIMA8_GUMPS_GUMP_H
25
26 #include "ultima/ultima8/kernel/object.h"
27 #include "ultima/ultima8/misc/rect.h"
28 #include "ultima/ultima8/graphics/frame_id.h"
29 #include "ultima/shared/std/containers.h"
30 #include "ultima/ultima8/misc/classtype.h"
31
32 namespace Ultima {
33 namespace Ultima8 {
34
35 class RenderSurface;
36 class Shape;
37 class Item;
38 class GumpNotifyProcess;
39
40 class Gump;
41 typedef bool (*FindGumpPredicate)(const Gump *g);
IsOfType(const Gump * g)42 template<class T> inline bool IsOfType(const Gump *g) { return dynamic_cast<const T*>(g) != nullptr; }
43
44 /**
45 * A Gump is a single GUI element within the game, like the backpack window, menu,
46 * conversation text, etc. Like most windowing systems, gumps nest.
47 */
48 class Gump : public Object {
49 protected:
50 uint16 _owner; // Owner item
51 Gump *_parent; // Parent gump
52 int32 _x, _y; // Gump's position in parent.
53 // Always the upper left corner!
54
55 Rect _dims; // The dimensions/coord space of the gump
56 uint32 _flags; // Gump flags
57 int32 _layer; // gump ordering layer
58
59 int32 _index; // 'Index'
60
61 const Shape *_shape; // The gumps shape (always painted at 0,0)
62 uint32 _frameNum;
63
64 //! The Gump list for this gump. This will contain all child gumps,
65 //! as well as all gump widgets.
66 Std::list<Gump *> _children; // List of all gumps
67 Gump *_focusChild; // The child that has focus
68
69 uint16 _notifier; // Process to notify when we're closing
70 uint32 _processResult; // Result for the notifier process
71
72 public:
73 ENABLE_RUNTIME_CLASSTYPE()
74 Gump();
75 Gump(int x, int y, int width, int height, uint16 owner = 0,
76 uint32 flags = 0, int32 layer = LAYER_NORMAL);
77 ~Gump() override;
78
79 public:
80
81 virtual void CreateNotifier();
82 void SetNotifyProcess(GumpNotifyProcess *proc);
83 GumpNotifyProcess *GetNotifyProcess();
GetResult()84 inline uint32 GetResult() {
85 return _processResult;
86 }
SetResult(uint32 res)87 void SetResult(uint32 res) {
88 _processResult = res;
89 }
90
91 //! Set the Gump's shape/frame
SetShape(const Shape * shape,uint32 frameNum)92 inline void SetShape(const Shape *shape, uint32 frameNum) {
93 _shape = shape;
94 _frameNum = frameNum;
95 }
96
97 void SetShape(FrameID frame, bool adjustsize = false);
98
99 //! Update the width/height to match the gump's current shape frame
100 void UpdateDimsFromShape();
101
102 //! Set the Gump's frame
Set_frameNum(uint32 frameNum)103 inline void Set_frameNum(uint32 frameNum) {
104 _frameNum = frameNum;
105 }
106
107 //! Init the gump and add it to parent; call after construction
108 //! When newparent is 0, this will call Ultima8Engine::addGump().
109 //! \param newparent The Gump's new parent or 0.
110 //! \param takefocus If true, set parent's _focusChild to this
111 virtual void InitGump(Gump *newparent, bool take_focus = true);
112
113 //! Find a gump of that matches a predicate function (this or child)
114 //! \param predicate Function to check if a gump is a match
115 //! \param recursive Recursively search through children?
116 //! \return the desired Gump, or NULL if not found
117 virtual Gump *FindGump(FindGumpPredicate predicate, bool recursive = true);
118
119 //! Find a gump of the specified type (this or child)
120 //! \param T Type of gump to look for
121 //! \param recursive Recursively search through children?
122 //! \return the desired Gump, or NULL if not found
123 template<class T> Gump *FindGump(bool recursive = true) {
124 return FindGump(&IsOfType<T>, recursive);
125 }
126
127 //! A predicate to find a ui element by its index
FindByIndex(const Gump * g)128 template<int T> static bool FindByIndex(const Gump *g) { return g->GetIndex() == T; }
129
130 //! Find gump (this, child or NULL) at parent coordinates (mx,my)
131 //! \return the Gump at these coordinates, or NULL if none
132 virtual Gump *FindGump(int mx, int my);
133
134 //! Get the mouse cursor for position mx, my relative to parents position.
135 //! If this gump doesn't want to set the cursor, the gump list will
136 //! attempt to get the cursor shape from the next lower gump.
137 //! \return true if this gump wants to set the cursor, false otherwise
138 virtual bool GetMouseCursor(int32 mx, int32 my, Shape &shape, int32 &frame);
139
140 // Notify gumps the render surface changed.
141 virtual void RenderSurfaceChanged();
142
143 //! Run the gump
144 virtual void run();
145
146 //! Close item-dependent gumps (recursively).
147 //! Called when there is a map change (so the gumps can self terminate
148 //! among other things), or when backspace is pressed by the user.
149 virtual void CloseItemDependents();
150
151 //! Paint the Gump (RenderSurface is relative to parent).
152 //! Calls PaintThis and PaintChildren
153 // \param surf The RenderSurface to paint to
154 // \param lerp_factor The lerp_factor to paint at (0-256)
155 // \param scaled Set if the gump is being drawn scaled.
156 virtual void Paint(RenderSurface *surf, int32 lerp_factor, bool scaled);
157
158 //! Paint the unscaled compontents of the Gump with compositing (RenderSurface is relative to parent).
159 //! Calls PaintComposited on self and PaintCompositing on children
160 // \param surf The RenderSurface to paint to
161 // \param lerp_factor The lerp_factor to paint at (0-256)
162 // \param scalex Fixed point scaling factor for x coord
163 // \param scaley Fixed point scaling factor for y coord
164 virtual void PaintCompositing(RenderSurface *surf, int32 lerp_factor, int32 scalex, int32 scaley);
165
166 protected:
167
168 //! Overloadable method to Paint just this Gump (RenderSurface is relative to this)
169 // \param surf The RenderSurface to paint to
170 // \param lerp_factor The lerp_factor to paint at (0-256)
171 // \param scaled Set if the gump is being drawn scaled.
172 virtual void PaintThis(RenderSurface *surf, int32 lerp_factor, bool scaled);
173
174 //! Paint the Gumps Children (RenderSurface is relative to this)
175 // \param surf The RenderSurface to paint to
176 // \param lerp_factor The lerp_factor to paint at (0-256)
177 // \param scaled Set if the gump is being drawn scaled.
178 virtual void PaintChildren(RenderSurface *surf, int32 lerp_factor, bool scaled);
179
180 //! Overloadable method to Paint just this gumps unscaled components that require compositing (RenderSurface is relative to parent).
181 // \param surf The RenderSurface to paint to
182 // \param lerp_factor The lerp_factor to paint at (0-256)
183 // \param scalex Fixed point scaling factor for x coord
184 // \param scaley Fixed point scaling factor for y coord
185 virtual void PaintComposited(RenderSurface *surf, int32 lerp_factor, int32 scalex, int32 scaley);
186
ScaleCoord(int32 c,int32 factor)187 static inline int32 ScaleCoord(int32 c, int32 factor) {
188 return ((c * factor) + (1 << 15)) >> 16;
189 }
UnscaleCoord(int32 c,int32 factor)190 static inline int32 UnscaleCoord(int32 c, int32 factor) {
191 return (c << 16) / factor;
192 }
193
194 public:
195
196 //! Close the gump
197 //! \param no_del If true, do not delete after closing
198 virtual void Close(bool no_del = false);
199
200 //! Check to see if a Gump is Closing
IsClosing()201 bool IsClosing() const {
202 return (_flags & FLAG_CLOSING) != 0;
203 }
204
205 //! Move this gump
Move(int32 x,int32 y)206 virtual void Move(int32 x, int32 y) {
207 _x = x;
208 _y = y;
209 }
210
211 //! Move this gump relative to its current position
MoveRelative(int x,int y)212 virtual void MoveRelative(int x, int y) {
213 _x += x;
214 _y += y;
215 }
216
getLocation(int32 & x,int32 & y)217 void getLocation(int32 &x, int32 &y) const {
218 x = _x;
219 y = _y;
220 }
221
222 enum Position {
223 CENTER = 1,
224 TOP_LEFT = 2,
225 TOP_RIGHT = 3,
226 BOTTOM_LEFT = 4,
227 BOTTOM_RIGHT = 5,
228 TOP_CENTER = 6,
229 BOTTOM_CENTER = 7
230 };
231
232 //! Moves this gump to a relative location on the parent gump
233 // \param pos the postition on the parent gump
234 // \param xoffset an offset from the position on the x-axis
235 // \param yoffset an offset from the position on the y-axis
236 virtual void setRelativePosition(Position pos, int xoffset = 0, int yoffset = 0);
237
238 //
239 // Points and Coords
240 //
241
242 //! Get the _dims
GetDims(Rect & d)243 virtual void GetDims(Rect &d) const {
244 d = _dims;
245 }
246
247 //! Set the _dims
SetDims(const Rect & d)248 virtual void SetDims(const Rect &d) {
249 _dims = d;
250 }
251
252 //! Detect if a point is on the gump
253 virtual bool PointOnGump(int mx, int my);
254
255 enum PointRoundDir {
256 ROUND_TOPLEFT = 0,
257 ROUND_BOTTOMRIGHT = 1
258 };
259 enum RectRoundDir {
260 ROUND_INSIDE,
261 ROUND_OUTSIDE
262 };
263
264 //! Convert a screen space point to a gump point
265 virtual void ScreenSpaceToGump(int32 &sx, int32 &sy,
266 PointRoundDir r = ROUND_TOPLEFT);
267
268 //! Convert a gump point to a screen space point
269 virtual void GumpToScreenSpace(int32 &gx, int32 &gy,
270 PointRoundDir r = ROUND_TOPLEFT);
271
272 //! Convert a parent relative point to a gump point
273 virtual void ParentToGump(int32 &px, int32 &py,
274 PointRoundDir r = ROUND_TOPLEFT);
275
276 //! Convert a gump point to parent relative point
277 virtual void GumpToParent(int32 &gx, int32 &gy,
278 PointRoundDir r = ROUND_TOPLEFT);
279
280 //! Transform a rectangle to screenspace from gumpspace
281 virtual void GumpRectToScreenSpace(Rect &gr, RectRoundDir r = ROUND_OUTSIDE);
282
283 //! Transform a rectangle to gumpspace from screenspace
284 virtual void ScreenSpaceToGumpRect(Rect &sr, RectRoundDir r = ROUND_OUTSIDE);
285
286 //! Trace a click, and return ObjId
287 virtual uint16 TraceObjId(int32 mx, int32 my);
288
289 //! Get the location of an item in the gump (coords relative to this).
290 //! \return false on failure
291 virtual bool GetLocationOfItem(uint16 itemid, int32 &gx, int32 &gy,
292 int32 lerp_factor = 256);
293
294
295 //
296 // Some event handlers. In theory they 'should' be able to be mapped to
297 // Usecode classes.
298 //
299 // mx and my are relative to parents position
300 //
301 // onMouseDown returns the Gump that handled the Input, if it was handled.
302 // The MouseUp,MouseDouble events will be sent to the same gump.
303 //
304 // onMouseMotion works like onMouseDown,
305 // but independently of the other methods.
306 //
307 // Unhandled input will be passed down to the next lower gump.
308 //
309 // A mouse click on a gump will make it focus, IF it wants it.
310 //
311
312 // Return Gump that handled event
313 virtual Gump *onMouseDown(int button, int32 mx, int32 my);
onMouseUp(int button,int32 mx,int32 my)314 virtual void onMouseUp(int button, int32 mx, int32 my) { }
onMouseClick(int button,int32 mx,int32 my)315 virtual void onMouseClick(int button, int32 mx, int32 my) { }
onMouseDouble(int button,int32 mx,int32 my)316 virtual void onMouseDouble(int button, int32 mx, int32 my) { }
317 virtual Gump *onMouseMotion(int32 mx, int32 my);
318
319 // onMouseOver is only call when the mouse first passes over the gump
320 // onMouseLeft is call as the mouse leaves the gump.
onMouseOver()321 virtual void onMouseOver() { };
onMouseLeft()322 virtual void onMouseLeft() { };
323
324 // Keyboard input gets sent to the FocusGump. Or if there isn't one, it
325 // will instead get sent to the default key handler. TextInput requires
326 // that text mode be enabled. Return true if handled, false if not.
327 // Default, returns false, unless handled by focus child
328 virtual bool OnKeyDown(int key, int mod);
329 virtual bool OnKeyUp(int key);
330 virtual bool OnTextInput(int unicode);
331
332 // This is for detecting focus changes for keyboard input. Gets called true
333 // when the this gump is being set as the focus focus gump. It is called
334 // false when focus is being taken away.
OnFocus(bool)335 virtual void OnFocus(bool /*gain*/) { }
336
337 // Makes this gump the focus
338 virtual void MakeFocus();
339
340 // Is this gump the focus?
IsFocus()341 inline bool IsFocus() {
342 return _parent ? _parent->_focusChild == this : false;
343 }
344
345 // Get the child in focus
GetFocusChild()346 inline Gump *GetFocusChild() {
347 return _focusChild;
348 }
349
350 // Find a new Child to be the focus
351 void FindNewFocusChild();
352
353
354 //
355 // Child gump related
356 //
357
358 //! Add a gump to the child list.
359 virtual void AddChild(Gump *, bool take_focus = true);
360
361 //! Remove a gump from the child list
362 virtual void RemoveChild(Gump *);
363
364 //! Move child to front (within its layer)
365 virtual void MoveChildToFront(Gump *);
366
367 //! Get the parent
GetParent()368 inline Gump *GetParent() {
369 return _parent;
370 }
371
372 //! Get the root gump (or self)
373 Gump *GetRootGump();
374
375 //! This function is used by our children to notifty us of 'something'
376 //! Think of it as a generic call back function
ChildNotify(Gump * child,uint32 message)377 virtual void ChildNotify(Gump *child, uint32 message) { }
SetIndex(int32 i)378 void SetIndex(int32 i) {
379 _index = i;
380 }
GetIndex()381 int32 GetIndex() const {
382 return _index;
383 }
384
385 // Dragging
386 //! Called when a child gump starts to be dragged.
387 //! \return false if the child isn't allowed to be dragged.
388 virtual bool StartDraggingChild(Gump *gump, int32 mx, int32 my);
389 virtual void DraggingChild(Gump *gump, int mx, int my);
390 virtual void StopDraggingChild(Gump *gump);
391
392 //! This will be called when an item in this gump starts to be dragged.
393 //! \return false if the item isn't allowed to be dragged.
StartDraggingItem(Item * item,int mx,int my)394 virtual bool StartDraggingItem(Item *item, int mx, int my) {
395 return false;
396 }
397
398 //! Called when an item is being dragged over the gump.
399 //! Note: this may be called on a different gump than StartDraggingItem.
400 //! \return false if the item can't be dragged to this location.
DraggingItem(Item * item,int mx,int my)401 virtual bool DraggingItem(Item *item, int mx, int my) {
402 return false;
403 }
404
405 //! Called when an item that was being dragged over the gump left the gump
DraggingItemLeftGump(Item * item)406 virtual void DraggingItemLeftGump(Item *item) { }
407
408 //! Called when a drag operation finished.
409 //! This is called on the same gump that received StartDraggingItem
410 //! \param moved If true, the item was actually dragged somewhere else.
411 //! If false, the drag was cancelled.
StopDraggingItem(Item * item,bool moved)412 virtual void StopDraggingItem(Item *item, bool moved) { }
413
414 //! Called when an item has been dropped on a gump.
415 //! This is called after StopDraggingItem has been called, but possibly
416 //! on a different gump.
417 //! It's guaranteed that a gump will only receive a DropItem at a location
418 //! if a DraggingItem there returned true.
DropItem(Item * item,int mx,int my)419 virtual void DropItem(Item *item, int mx, int my) { }
420
421 public:
422
423 //
424 // Gump Flags
425 //
426 enum GumpFlags {
427 FLAG_DRAGGABLE = 0x0001, // When set, the gump can be dragged
428 FLAG_HIDDEN = 0x0002, // When set, the gump will not be drawn
429 FLAG_CLOSING = 0x0004, // When set, the gump is closing
430 FLAG_CLOSE_AND_DEL = 0x0008, // When set, the gump is closing and will be deleted
431 FLAG_ITEM_DEPENDENT = 0x0010, // When set, the gump will be deleted on MapChange
432 FLAG_DONT_SAVE = 0x0020, // When set, don't save this gump. Be very careful with this one!
433 FLAG_CORE_GUMP = 0x0040, // core gump (only children are saved)
434 FLAG_KEEP_VISIBLE = 0x0080, // Keep this gump on-screen. (only for ItemRelativeGumps)
435 FLAG_PREVENT_SAVE = 0x0100 // When set, prevent game from saving
436 };
437
438 //! Does this gump have any of the given flags mask set
hasFlags(uint flags)439 inline bool hasFlags(uint flags) const {
440 return (_flags & flags) != 0;
441 }
442
IsHidden()443 inline bool IsHidden() const {
444 return (_flags & FLAG_HIDDEN) || (_parent && _parent->IsHidden());
445 }
IsDraggable()446 bool IsDraggable() const {
447 return _flags & FLAG_DRAGGABLE;
448 }
HideGump()449 virtual void HideGump() {
450 _flags |= FLAG_HIDDEN;
451 }
UnhideGump()452 virtual void UnhideGump() {
453 _flags &= ~FLAG_HIDDEN;
454 }
SetVisibility(bool visible)455 void SetVisibility(bool visible) {
456 if (visible)
457 UnhideGump();
458 else
459 HideGump();
460 }
461
462 bool mustSave(bool toplevel) const;
463
464 //
465 // Gump Layers
466 //
467 enum GumpLayers {
468 LAYER_DESKTOP = -16, // Layer for Desktop 'bottom most'
469 LAYER_GAMEMAP = -8, // Layer for the World Gump
470 LAYER_NORMAL = 0, // Layer for Normal gumps
471 LAYER_ABOVE_NORMAL = 8, // Layer for Always on top Gumps
472 LAYER_MODAL = 12, // Layer for Modal Gumps
473 LAYER_CONSOLE = 16 // Layer for the console
474 };
475
476 enum Message {
477 GUMP_CLOSING = 0x100
478 };
479
480 bool loadData(Common::ReadStream *rs, uint32 version);
481 void saveData(Common::WriteStream *ws) override;
482 };
483
484 } // End of namespace Ultima8
485 } // End of namespace Ultima
486
487 #endif
488