Initial commit
This commit is contained in:
490
engines/ultima/ultima8/gumps/gump.h
Normal file
490
engines/ultima/ultima8/gumps/gump.h
Normal file
@@ -0,0 +1,490 @@
|
||||
/* 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
|
||||
Reference in New Issue
Block a user