491 lines
16 KiB
C++
491 lines
16 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#ifndef ULTIMA8_GUMPS_GUMP_H
|
|
#define ULTIMA8_GUMPS_GUMP_H
|
|
|
|
#include "common/rect.h"
|
|
#include "ultima/ultima8/kernel/object.h"
|
|
#include "ultima/ultima8/gfx/frame_id.h"
|
|
#include "ultima/shared/std/containers.h"
|
|
#include "ultima/ultima8/misc/classtype.h"
|
|
|
|
namespace Ultima {
|
|
namespace Ultima8 {
|
|
|
|
class RenderSurface;
|
|
class Shape;
|
|
class Item;
|
|
class GumpNotifyProcess;
|
|
|
|
class Gump;
|
|
typedef bool (*FindGumpPredicate)(const Gump *g);
|
|
template<class T> inline bool IsOfType(const Gump *g) { return dynamic_cast<const T*>(g) != nullptr; }
|
|
|
|
/**
|
|
* A Gump is a single GUI element within the game, like the backpack window, menu,
|
|
* conversation text, etc. Like most windowing systems, gumps nest.
|
|
*/
|
|
class Gump : public Object {
|
|
protected:
|
|
uint16 _owner; // Owner item
|
|
Gump *_parent; // Parent gump
|
|
int32 _x, _y; // Gump's position in parent.
|
|
// Always the upper left corner!
|
|
|
|
Common::Rect32 _dims; // The dimensions/coord space of the gump
|
|
uint32 _flags; // Gump flags
|
|
int32 _layer; // gump ordering layer
|
|
|
|
int32 _index; // 'Index'
|
|
|
|
const Shape *_shape; // The gumps shape (always painted at 0,0)
|
|
uint32 _frameNum;
|
|
|
|
//! The Gump list for this gump. This will contain all child gumps,
|
|
//! as well as all gump widgets.
|
|
Std::list<Gump *> _children; // List of all gumps
|
|
Gump *_focusChild; // The child that has focus
|
|
|
|
uint16 _notifier; // Process to notify when we're closing
|
|
uint32 _processResult; // Result for the notifier process
|
|
|
|
public:
|
|
ENABLE_RUNTIME_CLASSTYPE()
|
|
Gump();
|
|
Gump(int x, int y, int width, int height, uint16 owner = 0,
|
|
uint32 flags = 0, int32 layer = LAYER_NORMAL);
|
|
~Gump() override;
|
|
|
|
public:
|
|
|
|
virtual void CreateNotifier();
|
|
void SetNotifyProcess(GumpNotifyProcess *proc);
|
|
GumpNotifyProcess *GetNotifyProcess();
|
|
inline uint32 GetResult() {
|
|
return _processResult;
|
|
}
|
|
void SetResult(uint32 res) {
|
|
_processResult = res;
|
|
}
|
|
|
|
//! Set the Gump's shape/frame
|
|
inline void SetShape(const Shape *shape, uint32 frameNum) {
|
|
_shape = shape;
|
|
_frameNum = frameNum;
|
|
}
|
|
|
|
void SetShape(FrameID frame, bool adjustsize = false);
|
|
|
|
//! Update the width/height to match the gump's current shape frame
|
|
void UpdateDimsFromShape();
|
|
|
|
//! Set the Gump's frame
|
|
inline void Set_frameNum(uint32 frameNum) {
|
|
_frameNum = frameNum;
|
|
}
|
|
|
|
//! Init the gump and add it to parent; call after construction
|
|
//! When newparent is 0, this will call Ultima8Engine::addGump().
|
|
//! \param newparent The Gump's new parent or 0.
|
|
//! \param takefocus If true, set parent's _focusChild to this
|
|
virtual void InitGump(Gump *newparent, bool take_focus = true);
|
|
|
|
//! Find a gump of that matches a predicate function (this or child)
|
|
//! \param predicate Function to check if a gump is a match
|
|
//! \param recursive Recursively search through children?
|
|
//! \return the desired Gump, or NULL if not found
|
|
virtual Gump *FindGump(FindGumpPredicate predicate, bool recursive = true);
|
|
|
|
//! Find a gump of the specified type (this or child)
|
|
//! \param T Type of gump to look for
|
|
//! \param recursive Recursively search through children?
|
|
//! \return the desired Gump, or NULL if not found
|
|
template<class T> Gump *FindGump(bool recursive = true) {
|
|
return FindGump(&IsOfType<T>, recursive);
|
|
}
|
|
|
|
//! A predicate to find a ui element by its index
|
|
template<int T> static bool FindByIndex(const Gump *g) { return g->GetIndex() == T; }
|
|
|
|
//! Find gump (this, child or NULL) at parent coordinates (mx,my)
|
|
//! \return the Gump at these coordinates, or NULL if none
|
|
virtual Gump *FindGump(int mx, int my);
|
|
|
|
//! Get the mouse cursor for position mx, my relative to parents position.
|
|
//! If this gump doesn't want to set the cursor, the gump list will
|
|
//! attempt to get the cursor shape from the next lower gump.
|
|
//! \return true if this gump wants to set the cursor, false otherwise
|
|
virtual bool GetMouseCursor(int32 mx, int32 my, Shape &shape, int32 &frame);
|
|
|
|
// Notify gumps the render surface changed.
|
|
virtual void RenderSurfaceChanged();
|
|
|
|
//! Run the gump
|
|
virtual void run();
|
|
|
|
//! Close item-dependent gumps (recursively).
|
|
//! Called when there is a map change (so the gumps can self terminate
|
|
//! among other things), or when backspace is pressed by the user.
|
|
virtual void CloseItemDependents();
|
|
|
|
//! Paint the Gump (RenderSurface is relative to parent).
|
|
//! Calls PaintThis and PaintChildren
|
|
// \param surf The RenderSurface to paint to
|
|
// \param lerp_factor The lerp_factor to paint at (0-256)
|
|
// \param scaled Set if the gump is being drawn scaled.
|
|
virtual void Paint(RenderSurface *surf, int32 lerp_factor, bool scaled);
|
|
|
|
//! Paint the unscaled compontents of the Gump with compositing (RenderSurface is relative to parent).
|
|
//! Calls PaintComposited on self and PaintCompositing on children
|
|
// \param surf The RenderSurface to paint to
|
|
// \param lerp_factor The lerp_factor to paint at (0-256)
|
|
// \param scalex Fixed point scaling factor for x coord
|
|
// \param scaley Fixed point scaling factor for y coord
|
|
virtual void PaintCompositing(RenderSurface *surf, int32 lerp_factor, int32 scalex, int32 scaley);
|
|
|
|
protected:
|
|
|
|
//! Overloadable method to Paint just this Gump (RenderSurface is relative to this)
|
|
// \param surf The RenderSurface to paint to
|
|
// \param lerp_factor The lerp_factor to paint at (0-256)
|
|
// \param scaled Set if the gump is being drawn scaled.
|
|
virtual void PaintThis(RenderSurface *surf, int32 lerp_factor, bool scaled);
|
|
|
|
//! Paint the Gumps Children (RenderSurface is relative to this)
|
|
// \param surf The RenderSurface to paint to
|
|
// \param lerp_factor The lerp_factor to paint at (0-256)
|
|
// \param scaled Set if the gump is being drawn scaled.
|
|
virtual void PaintChildren(RenderSurface *surf, int32 lerp_factor, bool scaled);
|
|
|
|
//! Overloadable method to Paint just this gumps unscaled components that require compositing (RenderSurface is relative to parent).
|
|
// \param surf The RenderSurface to paint to
|
|
// \param lerp_factor The lerp_factor to paint at (0-256)
|
|
// \param scalex Fixed point scaling factor for x coord
|
|
// \param scaley Fixed point scaling factor for y coord
|
|
virtual void PaintComposited(RenderSurface *surf, int32 lerp_factor, int32 scalex, int32 scaley);
|
|
|
|
static inline int32 ScaleCoord(int32 c, int32 factor) {
|
|
return ((c * factor) + (1 << 15)) >> 16;
|
|
}
|
|
static inline int32 UnscaleCoord(int32 c, int32 factor) {
|
|
return (c << 16) / factor;
|
|
}
|
|
|
|
public:
|
|
|
|
//! Close the gump
|
|
//! \param no_del If true, do not delete after closing
|
|
virtual void Close(bool no_del = false);
|
|
|
|
//! Check to see if a Gump is Closing
|
|
bool IsClosing() const {
|
|
return (_flags & FLAG_CLOSING) != 0;
|
|
}
|
|
|
|
//! Move this gump
|
|
virtual void Move(int32 x, int32 y) {
|
|
_x = x;
|
|
_y = y;
|
|
}
|
|
|
|
//! Move this gump relative to its current position
|
|
virtual void MoveRelative(int x, int y) {
|
|
_x += x;
|
|
_y += y;
|
|
}
|
|
|
|
void getLocation(int32 &x, int32 &y) const {
|
|
x = _x;
|
|
y = _y;
|
|
}
|
|
|
|
enum Position {
|
|
CENTER = 1,
|
|
TOP_LEFT = 2,
|
|
TOP_RIGHT = 3,
|
|
BOTTOM_LEFT = 4,
|
|
BOTTOM_RIGHT = 5,
|
|
TOP_CENTER = 6,
|
|
BOTTOM_CENTER = 7,
|
|
LEFT_CENTER = 8,
|
|
RIGHT_CENTER = 9
|
|
};
|
|
|
|
//! Moves this gump to a relative location on the parent gump
|
|
// \param pos the postition on the parent gump
|
|
// \param xoffset an offset from the position on the x-axis
|
|
// \param yoffset an offset from the position on the y-axis
|
|
virtual void setRelativePosition(Position pos, int xoffset = 0, int yoffset = 0);
|
|
|
|
//
|
|
// Points and Coords
|
|
//
|
|
|
|
//! Get the _dims
|
|
const Common::Rect32 &getDims() const {
|
|
return _dims;
|
|
}
|
|
|
|
//! Set the _dims
|
|
void setDims(const Common::Rect32 &d) {
|
|
_dims = d;
|
|
}
|
|
|
|
//! Detect if a point is on the gump
|
|
virtual bool PointOnGump(int mx, int my);
|
|
|
|
enum PointRoundDir {
|
|
ROUND_TOPLEFT = 0,
|
|
ROUND_BOTTOMRIGHT = 1
|
|
};
|
|
enum RectRoundDir {
|
|
ROUND_INSIDE,
|
|
ROUND_OUTSIDE
|
|
};
|
|
|
|
//! Convert a screen space point to a gump point
|
|
virtual void ScreenSpaceToGump(int32 &sx, int32 &sy,
|
|
PointRoundDir r = ROUND_TOPLEFT);
|
|
|
|
//! Convert a gump point to a screen space point
|
|
virtual void GumpToScreenSpace(int32 &gx, int32 &gy,
|
|
PointRoundDir r = ROUND_TOPLEFT);
|
|
|
|
//! Convert a parent relative point to a gump point
|
|
virtual void ParentToGump(int32 &px, int32 &py,
|
|
PointRoundDir r = ROUND_TOPLEFT);
|
|
|
|
//! Convert a gump point to parent relative point
|
|
virtual void GumpToParent(int32 &gx, int32 &gy,
|
|
PointRoundDir r = ROUND_TOPLEFT);
|
|
|
|
//! Transform a rectangle to screenspace from gumpspace
|
|
virtual void GumpRectToScreenSpace(Common::Rect32 &gr, RectRoundDir r = ROUND_OUTSIDE);
|
|
|
|
//! Transform a rectangle to gumpspace from screenspace
|
|
virtual void ScreenSpaceToGumpRect(Common::Rect32 &sr, RectRoundDir r = ROUND_OUTSIDE);
|
|
|
|
//! Trace a click, and return ObjId
|
|
virtual uint16 TraceObjId(int32 mx, int32 my);
|
|
|
|
//! Get the location of an item in the gump (coords relative to this).
|
|
//! \return false on failure
|
|
virtual bool GetLocationOfItem(uint16 itemid, int32 &gx, int32 &gy,
|
|
int32 lerp_factor = 256);
|
|
|
|
|
|
//
|
|
// Some event handlers. In theory they 'should' be able to be mapped to
|
|
// Usecode classes.
|
|
//
|
|
// mx and my are relative to parents position
|
|
//
|
|
// onMouseDown returns the Gump that handled the Input, if it was handled.
|
|
// The MouseUp,MouseDouble events will be sent to the same gump.
|
|
//
|
|
// onMouseMotion works like onMouseDown,
|
|
// but independently of the other methods.
|
|
//
|
|
// Unhandled input will be passed down to the next lower gump.
|
|
//
|
|
// A mouse click on a gump will make it focus, IF it wants it.
|
|
//
|
|
// It is often preferrable to handle both click and double events
|
|
// rather than only the up event to avoid unintended clicks after
|
|
// performing intended action.
|
|
|
|
// Return Gump that handled event
|
|
virtual Gump *onMouseDown(int button, int32 mx, int32 my);
|
|
virtual void onMouseUp(int button, int32 mx, int32 my) { }
|
|
virtual void onMouseClick(int button, int32 mx, int32 my) { }
|
|
virtual void onMouseDouble(int button, int32 mx, int32 my) { }
|
|
virtual Gump *onMouseMotion(int32 mx, int32 my);
|
|
|
|
// onMouseOver is only call when the mouse first passes over the gump
|
|
// onMouseLeft is call as the mouse leaves the gump.
|
|
virtual void onMouseOver() { };
|
|
virtual void onMouseLeft() { };
|
|
|
|
// Keyboard input gets sent to the FocusGump. Or if there isn't one, it
|
|
// will instead get sent to the default key handler. TextInput requires
|
|
// that text mode be enabled. Return true if handled, false if not.
|
|
// Default, returns false, unless handled by focus child
|
|
virtual bool OnKeyDown(int key, int mod);
|
|
virtual bool OnKeyUp(int key);
|
|
virtual bool OnTextInput(int unicode);
|
|
|
|
// This is for detecting focus changes for keyboard input. Gets called true
|
|
// when the this gump is being set as the focus focus gump. It is called
|
|
// false when focus is being taken away.
|
|
virtual void OnFocus(bool /*gain*/) { }
|
|
|
|
// Makes this gump the focus
|
|
virtual void MakeFocus();
|
|
|
|
// Is this gump the focus?
|
|
inline bool IsFocus() {
|
|
return _parent ? _parent->_focusChild == this : false;
|
|
}
|
|
|
|
// Get the child in focus
|
|
inline Gump *GetFocusChild() {
|
|
return _focusChild;
|
|
}
|
|
|
|
// Find a new Child to be the focus
|
|
void FindNewFocusChild();
|
|
|
|
|
|
//
|
|
// Child gump related
|
|
//
|
|
|
|
//! Add a gump to the child list.
|
|
virtual void AddChild(Gump *, bool take_focus = true);
|
|
|
|
//! Remove a gump from the child list
|
|
virtual void RemoveChild(Gump *);
|
|
|
|
//! Move child to front (within its layer)
|
|
virtual void MoveChildToFront(Gump *);
|
|
|
|
//! Get the parent
|
|
inline Gump *GetParent() {
|
|
return _parent;
|
|
}
|
|
|
|
//! Get the root gump (or self)
|
|
Gump *GetRootGump();
|
|
|
|
//! This function is used by our children to notifty us of 'something'
|
|
//! Think of it as a generic call back function
|
|
virtual void ChildNotify(Gump *child, uint32 message) { }
|
|
void SetIndex(int32 i) {
|
|
_index = i;
|
|
}
|
|
int32 GetIndex() const {
|
|
return _index;
|
|
}
|
|
|
|
//! Called when a gump starts to be dragged.
|
|
//! \return false if the gump isn't allowed to be dragged.
|
|
virtual bool onDragStart(int32 mx, int32 my);
|
|
virtual void onDragStop(int32 mx, int32 my);
|
|
virtual void onDrag(int32 mx, int32 my);
|
|
|
|
//! This will be called when an item in this gump starts to be dragged.
|
|
//! \return false if the item isn't allowed to be dragged.
|
|
virtual bool StartDraggingItem(Item *item, int mx, int my) {
|
|
return false;
|
|
}
|
|
|
|
//! Called when an item is being dragged over the gump.
|
|
//! Note: this may be called on a different gump than StartDraggingItem.
|
|
//! \return false if the item can't be dragged to this location.
|
|
virtual bool DraggingItem(Item *item, int mx, int my) {
|
|
return false;
|
|
}
|
|
|
|
//! Called when an item that was being dragged over the gump left the gump
|
|
virtual void DraggingItemLeftGump(Item *item) { }
|
|
|
|
//! Called when a drag operation finished.
|
|
//! This is called on the same gump that received StartDraggingItem
|
|
//! \param moved If true, the item was actually dragged somewhere else.
|
|
//! If false, the drag was cancelled.
|
|
virtual void StopDraggingItem(Item *item, bool moved) { }
|
|
|
|
//! Called when an item has been dropped on a gump.
|
|
//! This is called after StopDraggingItem has been called, but possibly
|
|
//! on a different gump.
|
|
//! It's guaranteed that a gump will only receive a DropItem at a location
|
|
//! if a DraggingItem there returned true.
|
|
virtual void DropItem(Item *item, int mx, int my) { }
|
|
|
|
public:
|
|
|
|
//
|
|
// Gump Flags
|
|
//
|
|
enum GumpFlags {
|
|
FLAG_DRAGGABLE = 0x0001, // When set, the gump can be dragged
|
|
FLAG_HIDDEN = 0x0002, // When set, the gump will not be drawn
|
|
FLAG_CLOSING = 0x0004, // When set, the gump is closing
|
|
FLAG_CLOSE_AND_DEL = 0x0008, // When set, the gump is closing and will be deleted
|
|
FLAG_ITEM_DEPENDENT = 0x0010, // When set, the gump will be deleted on MapChange
|
|
FLAG_DONT_SAVE = 0x0020, // When set, don't save this gump. Be very careful with this one!
|
|
FLAG_CORE_GUMP = 0x0040, // core gump (only children are saved)
|
|
FLAG_KEEP_VISIBLE = 0x0080, // Keep this gump on-screen. (only for ItemRelativeGumps)
|
|
FLAG_PREVENT_SAVE = 0x0100 // When set, prevent game from saving
|
|
};
|
|
|
|
//! Does this gump have any of the given flags mask set
|
|
inline bool hasFlags(uint flags) const {
|
|
return (_flags & flags) != 0;
|
|
}
|
|
|
|
inline bool IsHidden() const {
|
|
return (_flags & FLAG_HIDDEN) || (_parent && _parent->IsHidden());
|
|
}
|
|
bool IsDraggable() const {
|
|
return _flags & FLAG_DRAGGABLE;
|
|
}
|
|
virtual void HideGump() {
|
|
_flags |= FLAG_HIDDEN;
|
|
}
|
|
virtual void UnhideGump() {
|
|
_flags &= ~FLAG_HIDDEN;
|
|
}
|
|
void SetVisibility(bool visible) {
|
|
if (visible)
|
|
UnhideGump();
|
|
else
|
|
HideGump();
|
|
}
|
|
|
|
bool mustSave(bool toplevel) const;
|
|
|
|
//
|
|
// Gump Layers
|
|
//
|
|
enum GumpLayers {
|
|
LAYER_DESKTOP = -16, // Layer for Desktop 'bottom most'
|
|
LAYER_GAMEMAP = -8, // Layer for the World Gump
|
|
LAYER_NORMAL = 0, // Layer for Normal gumps
|
|
LAYER_ABOVE_NORMAL = 8, // Layer for Always on top Gumps
|
|
LAYER_MODAL = 12, // Layer for Modal Gumps
|
|
LAYER_CONSOLE = 16 // Layer for the console
|
|
};
|
|
|
|
enum Message {
|
|
GUMP_CLOSING = 0x100
|
|
};
|
|
|
|
bool loadData(Common::ReadStream *rs, uint32 version);
|
|
void saveData(Common::WriteStream *ws) override;
|
|
};
|
|
|
|
} // End of namespace Ultima8
|
|
} // End of namespace Ultima
|
|
|
|
#endif
|