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