scummvm/engines/saga2/panel.h

572 lines
17 KiB
C
Raw Normal View History

2021-05-17 18:47:39 +00:00
/* 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.
2021-05-17 18:47:39 +00:00
*
* 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/>.
2021-05-17 18:47:39 +00:00
*
*
* Based on the original sources
* Faery Tale II -- The Halls of the Dead
* (c) 1993-1996 The Wyrmkeep Entertainment Co.
*/
#ifndef SAGA2_PANEL_H
#define SAGA2_PANEL_H
#include "saga2/input.h"
#include "saga2/vdraw.h"
2021-05-17 18:47:39 +00:00
namespace Common {
struct Event;
}
2021-05-17 18:47:39 +00:00
namespace Saga2 {
// Fix problem with DOS's encroachment on name space that should
// rightfully belong to the application programmer.
#ifdef enable
#undef enable
#undef disable
#endif
/* ===================================================================== *
Cursor Cycling Stuff
* ===================================================================== */
void cycleCursor();
/* ===================================================================== *
Forward declarations
* ===================================================================== */
class gPanel;
class gPanelList;
class gPanelMessage;
class gWindow;
/* ===================================================================== *
Input dispatching functions
* ===================================================================== */
void HandleTimerTick(long newTick);
2021-06-13 14:56:52 +00:00
void EventLoop(bool &running, bool modal = false);
2021-05-17 18:47:39 +00:00
/* ===================================================================== *
Constants
* ===================================================================== */
enum gEventType {
2022-10-29 11:41:51 +00:00
kEventNone = 0, // no event occurred
kEventMouseDown, // left button pressed
kEventMouseUp, // left button released
kEventRMouseDown, // right button pressed
kEventRMouseUp, // right button released
kEventMouseMove, // mouse moved
kEventMouseDrag, // mouse dragged
kEventMouseOutside, // mouse click outside of window
kEventKeyDown, // keystroke
kEventNewValue, // object had new value
kEventDoubleClick, // double-clicked on object
kEventAltValue, // for multi-function objects
kEventLast
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
gEvent: returns input events to the user
* ===================================================================== */
struct gEvent {
gPanel *panel; // where event came from
2022-10-28 21:40:11 +00:00
gEventType eventType; // type of event that occurred
2021-05-17 18:47:39 +00:00
Point16 mouse; // mouse position
int32 value; // new value of control
gWindow *window; // active window
};
typedef void AppFunc(gEvent &);
#ifndef __WATCOMC__
#define APPFUNCDECL __cdecl
#else
#define APPFUNCDECL
#endif
#define APPFUNC(a) void a ( gEvent &ev )
#define APPFUNCV(a) void a ( gEvent & )
// Note: panels in this system are not, in general, resizeable
/* ===================================================================== *
gPanel class: The basic user interface element
* ===================================================================== */
2021-07-03 01:54:53 +00:00
class gPanel {
2021-05-17 18:47:39 +00:00
friend class gToolBase;
friend class gWindow;
AppFunc *_command; // application function
2021-05-17 18:47:39 +00:00
protected:
gWindow &_window; // window this belongs to
Rect16 _extent; // rectangular bounds of the control
const char *_title; // title of the panel
byte _enabled, // allows disabling the panel
_selected, // some panels have a selected state
_imageLabel, // button label is image, not text
_ghosted, // button is dimmed
_wantMousePoll; // send mousemoves even if mouse not moving!
2021-05-17 18:47:39 +00:00
// window constructor
gPanel(gWindow &, const Rect16 &, AppFunc *cmd);
public:
uint32 _id; // panel id number
void *_userData; // data for this panel
2021-05-17 18:47:39 +00:00
// constructor
2021-05-27 13:44:09 +00:00
gPanel(gPanelList &, const Rect16 &, const char *, uint16, AppFunc *cmd = NULL);
2021-05-17 18:47:39 +00:00
gPanel(gPanelList &, const Rect16 &, gPixelMap &, uint16, AppFunc *cmd = NULL);
gPanel(gPanelList &, const StaticRect &, const char *, uint16, AppFunc *cmd = NULL);
2021-05-17 18:47:39 +00:00
virtual ~gPanel(); // destructor
virtual gPanel *hitTest(const Point16 &p);
virtual gPanel *keyTest(int16 key);
protected:
virtual void pointerMove(gPanelMessage &msg);
virtual bool pointerHit(gPanelMessage &msg);
virtual bool pointerRHit(gPanelMessage &msg);
virtual void pointerDrag(gPanelMessage &msg);
virtual void pointerRelease(gPanelMessage &msg);
virtual bool keyStroke(gPanelMessage &msg);
virtual void timerTick(gPanelMessage &msg);
2021-09-11 09:13:35 +00:00
virtual void onMouseHintDelay();
2021-05-17 18:47:39 +00:00
2022-10-28 21:40:11 +00:00
void notify(gEventType, int32 value);
2021-05-17 18:47:39 +00:00
void notify(gEvent &ev) {
if (_command) _command(ev);
2021-05-17 18:47:39 +00:00
}
2022-10-28 21:40:11 +00:00
void drawTitle(TextPositions placement);
2021-05-17 18:47:39 +00:00
public:
2021-09-11 09:13:35 +00:00
bool isActive(); // true if we are active panel
2021-05-17 18:47:39 +00:00
virtual bool activate(gEventType why); // activate the control
2021-09-11 09:13:35 +00:00
virtual void deactivate(); // deactivate the control
virtual void draw(); // redraw the panel.
2021-05-17 18:47:39 +00:00
virtual void enable(bool abled);
2021-06-21 12:27:31 +00:00
virtual void select(uint16 selected);
2021-05-17 18:47:39 +00:00
virtual void ghost(bool ghosted);
2021-06-18 17:53:14 +00:00
virtual void invalidate(Rect16 *area = nullptr);
2021-05-17 18:47:39 +00:00
virtual void setMousePoll(bool abled) {
_wantMousePoll = abled ? 1 : 0;
2021-05-17 18:47:39 +00:00
}
// Redraw the panel, but only a small clipped section,
// and perhaps drawn onto an off-screen map.
virtual void drawClipped(
gPort &port,
const Point16 &offset,
const Rect16 &r);
// void setCommand( AppFunc *func ) { command = func; }
2021-09-11 09:13:35 +00:00
gWindow *getWindow() {
return &_window;
2021-05-17 18:47:39 +00:00
}
2021-09-11 09:13:35 +00:00
void makeActive();
Rect16 getExtent() {
return _extent;
2021-05-17 18:47:39 +00:00
}
2021-09-11 09:13:35 +00:00
bool isSelected() {
return _selected != 0;
2021-05-17 18:47:39 +00:00
}
2021-09-11 09:13:35 +00:00
bool isGhosted() {
return _ghosted != 0;
2021-05-17 18:47:39 +00:00
}
2021-09-11 09:13:35 +00:00
bool getEnabled() const {
return (bool)_enabled;
2021-05-17 18:47:39 +00:00
}
2021-06-13 14:56:52 +00:00
void show(bool shown = true, bool inval = true) {
2021-05-17 18:47:39 +00:00
enable(shown);
2021-06-18 17:53:14 +00:00
if (inval)
invalidate();
2021-05-17 18:47:39 +00:00
}
void moveToFront(gPanelList &l);
void moveToBack(gPanelList &l);
};
/* ===================================================================== *
gPanelMessage class: How user input is distributes to panels
* ===================================================================== */
class gPanelMessage {
public:
Point16 _pickPos, // mouse position relative to panel
_pickAbsPos; // mouse position relative to display
byte _leftButton, // left button state
_rightButton, // right button state
_inPanel, // whether mouse is currently in panel
_pointerEnter, // set when pointer enters panel
_pointerLeave, // set when pointer leaves panel
_doubleClick; // set when double click detected
2021-05-17 18:47:39 +00:00
// For keyboard input
uint16 _key, // keystroke from keyboard
_qualifier; // qualifier from keyboard
2021-05-17 18:47:39 +00:00
uint32 _timeStamp; // time of message
2021-07-16 22:21:12 +00:00
gPanelMessage() {
_leftButton = 0;
_rightButton = 0;
_inPanel = 0;
_pointerEnter = 0;
_pointerLeave = 0;
_doubleClick = 0;
_key = 0;
_qualifier = 0;
_timeStamp = 0;
2021-07-16 22:21:12 +00:00
}
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
gPanelList class: A list of panels
* ===================================================================== */
2021-07-03 01:54:53 +00:00
class gControl;
2021-05-17 18:47:39 +00:00
class gPanelList : public gPanel {
friend class gControl;
friend class gToolBase;
friend void gPanel::moveToFront(gPanelList &l);
friend void gPanel::moveToBack(gPanelList &l);
protected:
Common::List<gPanel *> _contents; // list of panels
2021-05-17 18:47:39 +00:00
gPanelList(gWindow &, const Rect16 &, char *, uint16, AppFunc *cmd = NULL);
public:
gPanelList(gPanelList &);
~gPanelList();
gPanel *hitTest(const Point16 &p);
gPanel *keyTest(int16 key);
2021-09-11 09:13:35 +00:00
void removeControls();
2021-05-17 18:47:39 +00:00
public:
2021-06-18 17:53:14 +00:00
void invalidate(Rect16 *area = nullptr);
2021-09-11 09:13:35 +00:00
void draw(); // redraw the controls
2021-05-17 18:47:39 +00:00
void drawClipped(
gPort &port,
const Point16 &offset,
const Rect16 &r);
void enable(bool abled); // enable list and all children
// void setPointer( gPixelMap &map, int x, int y );
};
inline void gPanel::moveToFront(gPanelList &l) {
l._contents.remove(this);
l._contents.push_front(this);
2021-05-17 18:47:39 +00:00
}
inline void gPanel::moveToBack(gPanelList &l) {
l._contents.remove(this);
l._contents.push_back(this);
2021-05-17 18:47:39 +00:00
}
/* ===================================================================== *
gWindow class: A context for holding panels.
* ===================================================================== */
/*
enum windowFeatures {
windowTitleBar = (1<<0), // window has a title bar
windowCanDrag = (1<<1), // window is draggable
// windowVisible = (1<<2), // window is visible
// windowBackSaved = (1<<3), // backsave data under window
// windowCloseBox = (1<<4), // create a close box
// windowNoBorder = (1<<5), // window with no border
};
*/
class gWindow : public gPanelList {
friend class gControl;
friend class gPanel;
friend class gToolBase;
public:
gDisplayPort _windowPort;
2021-05-17 18:47:39 +00:00
gWindow(const Rect16 &, uint16, const char saveName[], AppFunc *cmd = NULL);
~gWindow();
operator gPort() {
return _windowPort;
2021-05-17 18:47:39 +00:00
}
void postEvent(gEvent &ev) {
gPanel::notify(ev);
}
protected:
bool _openFlag; // true if window open.
2021-05-17 18:47:39 +00:00
//gWindowWinInfoInINIFile saver;
private:
bool activate(gEventType why); // activate the control
2021-09-11 09:13:35 +00:00
void deactivate();
2021-05-17 18:47:39 +00:00
void pointerMove(gPanelMessage &msg);
bool pointerHit(gPanelMessage &msg);
void pointerDrag(gPanelMessage &msg);
void pointerRelease(gPanelMessage &msg);
// Dragging modes for window -- private and static!
enum drag_modes {
2022-10-29 11:41:51 +00:00
kDragNone = 0,
kDragPosition
2021-05-17 18:47:39 +00:00
};
static int _dragMode; // current dragging mode
static StaticRect _dragExtent; // dragging extent
static StaticPoint16 _dragOffset; // offset to window origin
2021-05-17 18:47:39 +00:00
2021-09-11 09:13:35 +00:00
void shadow();
2021-05-17 18:47:39 +00:00
public:
void setExtent(const Rect16 &); // set window position and size
2021-09-11 09:13:35 +00:00
Rect16 getExtent() {
return _extent; // set window position and size
2021-05-17 18:47:39 +00:00
}
protected:
void setPos(Point16 pos); // set window position
2021-09-11 09:13:35 +00:00
void insert(); // insert window into window list
virtual void toFront(); // re-order the windows
2021-05-17 18:47:39 +00:00
public:
2021-09-11 09:13:35 +00:00
bool isOpen() {
return _openFlag; // true if window is visible
2021-05-17 18:47:39 +00:00
}
2021-09-11 09:13:35 +00:00
void draw(); // redraw the panel.
2021-05-17 18:47:39 +00:00
void drawClipped(
gPort &port,
const Point16 &offset,
const Rect16 &r);
// Redraw the window, but only a small clipped section,
// and perhaps drawn onto an off-screen map.
// void drawClipped(
// gPort &port,
// const Point16 &offset,
// const Rect16 &r );
void enable(bool abled);
2021-06-21 12:27:31 +00:00
void select(uint16 sel); // activate the window
2021-05-17 18:47:39 +00:00
2021-09-11 09:13:35 +00:00
virtual bool open();
virtual void close();
virtual bool isModal();
2021-05-17 18:47:39 +00:00
// Update a region of a window, and all floaters which
// might be above that window.
virtual void update(const Rect16 &updateRect) = 0;
// void setPointer( gPixelMap &map, int x, int y );
};
/* ===================================================================== *
gControl class: The basis for buttons and other controls.
* ===================================================================== */
class gControl : public gPanel {
public:
uint8 _accelKey;
gPanelList *_list;
2021-05-17 18:47:39 +00:00
2021-05-27 13:44:09 +00:00
gControl(gPanelList &, const Rect16 &, const char *, uint16, AppFunc *cmd = NULL);
2021-05-17 18:47:39 +00:00
gControl(gPanelList &, const Rect16 &, gPixelMap &, uint16, AppFunc *cmd = NULL);
gControl(gPanelList &, const StaticRect &, const char *, uint16, AppFunc *cmd = NULL);
2021-05-17 18:47:39 +00:00
~gControl(); // destructor
gPanel *keyTest(int16 key);
void enable(bool abled); // enable the control
2021-06-21 12:27:31 +00:00
void select(uint16 sel); // selecte the control
2021-05-17 18:47:39 +00:00
void ghost(bool ghosted);
// virtual void newValue( void );
2021-09-11 09:13:35 +00:00
void draw(); // redraw the control.
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
gGenericControl class: A generic button that notifies everything
* ===================================================================== */
class gGenericControl : public gControl {
bool _dblClickFlag;
2021-05-17 18:47:39 +00:00
public:
gGenericControl(gPanelList &, const Rect16 &, uint16, AppFunc *cmd = NULL);
// Disable double click for next mouse click
2021-09-11 09:13:35 +00:00
void disableDblClick() {
_dblClickFlag = true;
2021-05-17 18:47:39 +00:00
}
enum controlValue {
2022-10-29 11:41:51 +00:00
kCVEnter = (1 << 0),
kCVLeave = (1 << 1)
2021-05-17 18:47:39 +00:00
};
protected:
bool activate(gEventType why); // activate the control
2021-09-11 09:13:35 +00:00
void deactivate();
2021-05-17 18:47:39 +00:00
void pointerMove(gPanelMessage &msg);
bool pointerHit(gPanelMessage &msg);
void pointerDrag(gPanelMessage &msg);
void pointerRelease(gPanelMessage &msg);
2021-09-11 09:13:35 +00:00
void draw(); // redraw the control.
2021-05-17 18:47:39 +00:00
};
/* ===================================================================== *
gToolBase class: The primary dispatcher for user interface events
* ===================================================================== */
void setMouseTextF(char *format, ...);
void LockUI(bool state);
class gToolBase {
friend class gWindow;
friend class gPanel;
friend void EventLoop(bool &running);
2021-09-11 09:13:35 +00:00
friend int16 leftButtonState();
friend int16 rightButtonState();
friend void StageModeCleanup();
friend void TileModeCleanup();
2021-05-17 18:47:39 +00:00
friend void dumpGBASE(char *msg);
// windows
Common::List<gWindow *> _windowList; // list of windows
gWindow *_mouseWindow, // window mouse is in
*_activeWindow; // current active window
gPanel *_mousePanel, // panel that mouse is in
*_activePanel; // panel that has input focus
Rect16 _dragRect; // dragging rectangle for windows
Point16 _pickPos; // mouse pos relative to panel
uint8 _leftDrag, // left-button dragging
_rightDrag; // right button dragging
gPanelMessage _msg; // message that we send out
2021-05-17 18:47:39 +00:00
int32 _lastMouseMoveTime; // time of last mouse move
gMouseState _curMouseState;
2021-05-17 18:47:39 +00:00
public:
bool _mouseHintSet; // true if mouse hint is up.
2021-05-17 18:47:39 +00:00
2021-07-16 22:21:12 +00:00
gToolBase() {
_mouseWindow = nullptr;
_activeWindow = nullptr;
_mousePanel = nullptr;
_activePanel = nullptr;
_leftDrag = 0;
_rightDrag = 0;
_lastMouseMoveTime = 0;
2021-07-16 22:21:12 +00:00
}
2021-05-17 18:47:39 +00:00
private:
2021-05-27 14:02:19 +00:00
void setMsgQ(gPanelMessage &msg_, gPanel *panel) {
if (panel == &panel->_window)
msg_._pickPos = _pickPos;
2021-05-17 18:47:39 +00:00
else {
_msg._pickPos.x = (int16)(_pickPos.x - panel->_extent.x);
_msg._pickPos.y = (int16)(_pickPos.y - panel->_extent.y);
2021-05-17 18:47:39 +00:00
}
}
2021-05-27 14:02:19 +00:00
void setMsg(gPanelMessage &msg_, gPanel *panel) {
setMsgQ(msg_, panel);
_msg._inPanel = (msg_._pickPos.x >= 0
&& msg_._pickPos.y >= 0
&& msg_._pickPos.x < panel->_extent.width
&& msg_._pickPos.y < panel->_extent.height);
2021-05-17 18:47:39 +00:00
// panel->extent.ptInside( pickPos );
}
public:
void setActive(gPanel *newActive);
2021-09-11 09:13:35 +00:00
void leavePanel(); // we're changing windows
2021-05-17 18:47:39 +00:00
public:
void handleMouse(Common::Event &event, uint32 time);
void handleKeyStroke(Common::Event &event);
2021-05-17 18:47:39 +00:00
void handleTimerTick(int32 tick);
2021-09-11 09:13:35 +00:00
Common::List<gWindow *>::iterator topWindowIterator() {
return _windowList.end();
2021-07-03 01:54:53 +00:00
}
2021-09-11 09:13:35 +00:00
Common::List<gWindow *>::iterator bottomWindowIterator() {
return _windowList.reverse_begin();
2021-07-03 01:54:53 +00:00
}
2021-09-11 09:13:35 +00:00
gWindow *topWindow() {
return _windowList.front();
2021-05-17 18:47:39 +00:00
}
2021-09-11 09:13:35 +00:00
gWindow *bottomWindow() {
return _windowList.back();
2021-05-17 18:47:39 +00:00
}
bool isMousePanel(gPanel *p) {
return (_mousePanel != NULL) ? (p == _mousePanel) : (p == topWindow());
2021-05-17 18:47:39 +00:00
}
};
/* ===================================================================== *
Application functions to call for event handling
* ===================================================================== */
void EventLoop(bool &running);
void initPanels(gDisplayPort &port);
2021-09-11 09:13:35 +00:00
void cleanupPanels();
2021-05-17 18:47:39 +00:00
//void writeHelpLine( char *msg, ... );
2021-09-11 09:13:35 +00:00
int16 leftButtonState();
int16 rightButtonState();
2021-05-17 18:47:39 +00:00
// Kludge structure to contain both a mouse event and a time stamp
struct MouseExtState {
gMouseState st;
int32 time;
};
} // end of namespace Saga2
#endif