mirror of https://github.com/stella-emu/stella.git
424 lines
15 KiB
C++
424 lines
15 KiB
C++
//============================================================================
|
|
//
|
|
// SSSS tt lll lll
|
|
// SS SS tt ll ll
|
|
// SS tttttt eeee ll ll aaaa
|
|
// SSSS tt ee ee ll ll aa
|
|
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
|
|
// SS SS tt ee ll ll aa aa
|
|
// SSSS ttt eeeee llll llll aaaaa
|
|
//
|
|
// Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony
|
|
// and the Stella Team
|
|
//
|
|
// See the file "License.txt" for information on usage and redistribution of
|
|
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
|
//
|
|
// Based on code from ScummVM - Scumm Interpreter
|
|
// Copyright (C) 2002-2004 The ScummVM project
|
|
//============================================================================
|
|
|
|
#ifndef WIDGET_HXX
|
|
#define WIDGET_HXX
|
|
|
|
class Dialog;
|
|
|
|
#include <cassert>
|
|
|
|
#include "bspf.hxx"
|
|
#include "Rect.hxx"
|
|
#include "Event.hxx"
|
|
#include "EventHandlerConstants.hxx"
|
|
#include "FrameBufferConstants.hxx"
|
|
#include "StellaKeys.hxx"
|
|
#include "GuiObject.hxx"
|
|
#include "Font.hxx"
|
|
|
|
/**
|
|
This is the base class for all widgets.
|
|
|
|
@author Stephen Anthony
|
|
*/
|
|
class Widget : public GuiObject
|
|
{
|
|
friend class Dialog;
|
|
|
|
public:
|
|
Widget(GuiObject* boss, const GUI::Font& font, int x, int y, int w, int h);
|
|
~Widget() override;
|
|
|
|
virtual int getAbsX() const override { return _x + _boss->getChildX(); }
|
|
virtual int getAbsY() const override { return _y + _boss->getChildY(); }
|
|
virtual int getLeft() const { return _x; }
|
|
virtual int getTop() const { return _y; }
|
|
virtual int getRight() const { return _x + getWidth(); }
|
|
virtual int getBottom() const { return _y + getHeight(); }
|
|
virtual void setPosX(int x);
|
|
virtual void setPosY(int y);
|
|
virtual void setPos(int x, int y);
|
|
virtual void setPos(const Common::Point& pos);
|
|
void setWidth(int w) override;
|
|
void setHeight(int h) override;
|
|
virtual void setSize(int w, int h);
|
|
virtual void setSize(const Common::Point& pos);
|
|
|
|
virtual bool handleText(char text) { return false; }
|
|
virtual bool handleKeyDown(StellaKey key, StellaMod mod) { return false; }
|
|
virtual bool handleKeyUp(StellaKey key, StellaMod mod) { return false; }
|
|
virtual void handleMouseDown(int x, int y, MouseButton b, int clickCount) { }
|
|
virtual void handleMouseUp(int x, int y, MouseButton b, int clickCount) { }
|
|
virtual void handleMouseEntered();
|
|
virtual void handleMouseLeft();
|
|
virtual void handleMouseMoved(int x, int y) { }
|
|
virtual void handleMouseWheel(int x, int y, int direction) { }
|
|
virtual bool handleMouseClicks(int x, int y, MouseButton b) { return false; }
|
|
virtual void handleJoyDown(int stick, int button, bool longPress = false) { }
|
|
virtual void handleJoyUp(int stick, int button) { }
|
|
virtual void handleJoyAxis(int stick, JoyAxis axis, JoyDir adir, int button = JOY_CTRL_NONE) { }
|
|
virtual bool handleJoyHat(int stick, int hat, JoyHatDir hdir, int button = JOY_CTRL_NONE) { return false; }
|
|
virtual bool handleEvent(Event::Type event) { return false; }
|
|
|
|
void tick() override;
|
|
|
|
void setDirty() override;
|
|
void setDirtyChain() override;
|
|
void draw() override;
|
|
void drawChain() override;
|
|
void receivedFocus();
|
|
void lostFocus();
|
|
void addFocusWidget(Widget* w) override { _focusList.push_back(w); }
|
|
void addToFocusList(const WidgetArray& list) override {
|
|
Vec::append(_focusList, list);
|
|
}
|
|
|
|
/** Set/clear FLAG_ENABLED */
|
|
void setEnabled(bool e);
|
|
|
|
bool isEnabled() const { return _flags & FLAG_ENABLED; }
|
|
bool isVisible() const override { return !(_flags & FLAG_INVISIBLE); }
|
|
bool isHighlighted() const { return _flags & FLAG_HILITED; }
|
|
bool hasMouseFocus() const { return _flags & FLAG_MOUSE_FOCUS; }
|
|
virtual bool wantsFocus() const { return _flags & FLAG_RETAIN_FOCUS; }
|
|
bool wantsTab() const { return _flags & FLAG_WANTS_TAB; }
|
|
bool wantsRaw() const { return _flags & FLAG_WANTS_RAWDATA; }
|
|
|
|
void setID(uInt32 id) { _id = id; }
|
|
uInt32 getID() const { return _id; }
|
|
|
|
virtual const GUI::Font& font() const { return _font; }
|
|
|
|
void setTextColor(ColorId color) { _textcolor = color; setDirty(); }
|
|
void setTextColorHi(ColorId color) { _textcolorhi = color; setDirty(); }
|
|
void setBGColor(ColorId color) { _bgcolor = color; setDirty(); }
|
|
void setBGColorHi(ColorId color) { _bgcolorhi = color; setDirty(); }
|
|
void setShadowColor(ColorId color) { _shadowcolor = color; setDirty(); }
|
|
|
|
void setToolTip(const string& text);
|
|
virtual string getToolTip(const Common::Point& pos) const { return _toolTipText; }
|
|
virtual bool changedToolTip(const Common::Point& oldPos,
|
|
const Common::Point& newPos) const { return false; }
|
|
|
|
void setHelpAnchor(const string& helpAnchor, bool debugger = false);
|
|
void setHelpURL(const string& helpURL);
|
|
|
|
virtual void loadConfig() { }
|
|
|
|
protected:
|
|
virtual void drawWidget(bool hilite) { }
|
|
|
|
virtual void receivedFocusWidget() { }
|
|
virtual void lostFocusWidget() { }
|
|
|
|
virtual Widget* findWidget(int x, int y) { return this; }
|
|
|
|
void releaseFocus() override { assert(_boss); _boss->releaseFocus(); }
|
|
|
|
virtual bool wantsToolTip() const { return hasMouseFocus() && hasToolTip(); }
|
|
virtual bool hasToolTip() const { return !_toolTipText.empty(); }
|
|
|
|
// By default, delegate unhandled commands to the boss
|
|
void handleCommand(CommandSender* sender, int cmd, int data, int id) override
|
|
{ assert(_boss); _boss->handleCommand(sender, cmd, data, id); }
|
|
|
|
const string getHelpURL() const override;
|
|
bool hasHelp() const override { return !getHelpURL().empty(); }
|
|
|
|
protected:
|
|
GuiObject* _boss{nullptr};
|
|
const GUI::Font& _font;
|
|
Widget* _next{nullptr};
|
|
uInt32 _id{0};
|
|
bool _hasFocus{false};
|
|
int _fontWidth{0};
|
|
int _lineHeight{0};
|
|
ColorId _bgcolor{kWidColor};
|
|
ColorId _bgcolorhi{kWidColor};
|
|
ColorId _bgcolorlo{kBGColorLo};
|
|
ColorId _textcolor{kTextColor};
|
|
ColorId _textcolorhi{kTextColorHi};
|
|
ColorId _textcolorlo{kBGColorLo};
|
|
ColorId _shadowcolor{kShadowColor};
|
|
string _toolTipText;
|
|
string _helpAnchor;
|
|
string _helpURL;
|
|
bool _debuggerHelp{false};
|
|
|
|
public:
|
|
static Widget* findWidgetInChain(Widget* start, int x, int y);
|
|
|
|
/** Determine if 'find' is in the chain pointed to by 'start' */
|
|
static bool isWidgetInChain(Widget* start, Widget* find);
|
|
|
|
/** Determine if 'find' is in the widget array */
|
|
static bool isWidgetInChain(const WidgetArray& list, Widget* find);
|
|
|
|
/** Select either previous, current, or next widget in chain to have
|
|
focus, and deselects all others */
|
|
static Widget* setFocusForChain(GuiObject* boss, WidgetArray& arr,
|
|
Widget* w, int direction,
|
|
bool emitFocusEvents = true);
|
|
|
|
/** Sets all widgets in this chain to be dirty (must be redrawn) */
|
|
static void setDirtyInChain(Widget* start);
|
|
|
|
private:
|
|
// Following constructors and assignment operators not supported
|
|
Widget() = delete;
|
|
Widget(const Widget&) = delete;
|
|
Widget(Widget&&) = delete;
|
|
Widget& operator=(const Widget&) = delete;
|
|
Widget& operator=(Widget&&) = delete;
|
|
};
|
|
|
|
/* StaticTextWidget */
|
|
class StaticTextWidget : public Widget, public CommandSender
|
|
{
|
|
public:
|
|
enum {
|
|
kClickedCmd = 'STcl',
|
|
kOpenUrlCmd = 'STou'
|
|
};
|
|
|
|
public:
|
|
StaticTextWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y, int w, int h,
|
|
const string& text = "", TextAlign align = TextAlign::Left,
|
|
ColorId shadowColor = kNone);
|
|
StaticTextWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y,
|
|
const string& text = "", TextAlign align = TextAlign::Left,
|
|
ColorId shadowColor = kNone);
|
|
~StaticTextWidget() override = default;
|
|
|
|
void setCmd(int cmd) { _cmd = cmd; }
|
|
|
|
void setValue(int value);
|
|
void setLabel(const string& label);
|
|
void setAlign(TextAlign align) { _align = align; setDirty(); }
|
|
const string& getLabel() const { return _label; }
|
|
bool isEditable() const { return _editable; }
|
|
|
|
void setLink(size_t start = string::npos, int len = 0, bool underline = false);
|
|
bool setUrl(const string& url = EmptyString, const string& label = EmptyString,
|
|
const string& placeHolder = EmptyString);
|
|
const string& getUrl() const { return _url; }
|
|
|
|
protected:
|
|
void handleMouseEntered() override;
|
|
void handleMouseLeft() override;
|
|
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
|
|
|
void drawWidget(bool hilite) override;
|
|
|
|
protected:
|
|
string _label;
|
|
bool _editable{false};
|
|
TextAlign _align{TextAlign::Left};
|
|
int _cmd{0};
|
|
size_t _linkStart{string::npos};
|
|
int _linkLen{0};
|
|
bool _linkUnderline{false};
|
|
string _url;
|
|
|
|
private:
|
|
// Following constructors and assignment operators not supported
|
|
StaticTextWidget() = delete;
|
|
StaticTextWidget(const StaticTextWidget&) = delete;
|
|
StaticTextWidget(StaticTextWidget&&) = delete;
|
|
StaticTextWidget& operator=(const StaticTextWidget&) = delete;
|
|
StaticTextWidget& operator=(StaticTextWidget&&) = delete;
|
|
};
|
|
|
|
/* ButtonWidget */
|
|
class ButtonWidget : public StaticTextWidget
|
|
{
|
|
public:
|
|
ButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y, int w, int h,
|
|
const string& label, int cmd = 0, bool repeat = false);
|
|
ButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y, int dw,
|
|
const string& label, int cmd = 0, bool repeat = false);
|
|
ButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y,
|
|
const string& label, int cmd = 0, bool repeat = false);
|
|
ButtonWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y, int dw, int dh,
|
|
const uInt32* bitmap, int bmw, int bmh,
|
|
int cmd = 0, bool repeat = false);
|
|
~ButtonWidget() override = default;
|
|
|
|
bool handleEvent(Event::Type event) override;
|
|
|
|
void setCmd(int cmd) { _cmd = cmd; }
|
|
int getCmd() const { return _cmd; }
|
|
/* Sets/changes the button's bitmap **/
|
|
void setBitmap(const uInt32* bitmap, int bmw, int bmh);
|
|
|
|
protected:
|
|
bool handleMouseClicks(int x, int y, MouseButton b) override;
|
|
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
|
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
|
void handleMouseEntered() override;
|
|
void handleMouseLeft() override;
|
|
|
|
void drawWidget(bool hilite) override;
|
|
|
|
protected:
|
|
bool _repeat{false}; // button repeats
|
|
bool _useBitmap{false};
|
|
const uInt32* _bitmap{nullptr};
|
|
int _bmw{0}, _bmh{0};
|
|
|
|
private:
|
|
// Following constructors and assignment operators not supported
|
|
ButtonWidget() = delete;
|
|
ButtonWidget(const ButtonWidget&) = delete;
|
|
ButtonWidget(ButtonWidget&&) = delete;
|
|
ButtonWidget& operator=(const ButtonWidget&) = delete;
|
|
ButtonWidget& operator=(ButtonWidget&&) = delete;
|
|
};
|
|
|
|
/* CheckboxWidget */
|
|
class CheckboxWidget : public ButtonWidget
|
|
{
|
|
public:
|
|
enum { kCheckActionCmd = 'CBAC' };
|
|
enum class FillType { Normal, Inactive, Circle };
|
|
|
|
public:
|
|
CheckboxWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
|
|
const string& label, int cmd = 0);
|
|
~CheckboxWidget() override = default;
|
|
|
|
void setEditable(bool editable);
|
|
void setFill(FillType type);
|
|
|
|
void setState(bool state, bool changed = false);
|
|
void toggleState() { setState(!_state); }
|
|
bool getState() const { return _state; }
|
|
|
|
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
|
|
|
static int boxSize(const GUI::Font& font)
|
|
{
|
|
return font.getFontHeight() < 24 ? 14 : 22; // box is square
|
|
}
|
|
static int prefixSize(const GUI::Font& font)
|
|
{
|
|
return boxSize(font) + font.getMaxCharWidth() * 0.75;
|
|
}
|
|
|
|
protected:
|
|
void drawWidget(bool hilite) override;
|
|
|
|
protected:
|
|
bool _state{false};
|
|
bool _holdFocus{true};
|
|
bool _drawBox{true};
|
|
bool _changed{false};
|
|
|
|
const uInt32* _outerCircle{nullptr};
|
|
const uInt32* _innerCircle{nullptr};
|
|
const uInt32* _img{nullptr};
|
|
ColorId _fillColor{kColor};
|
|
int _boxY{0};
|
|
int _textY{0};
|
|
int _boxSize{14};
|
|
|
|
private:
|
|
// Following constructors and assignment operators not supported
|
|
CheckboxWidget() = delete;
|
|
CheckboxWidget(const CheckboxWidget&) = delete;
|
|
CheckboxWidget(CheckboxWidget&&) = delete;
|
|
CheckboxWidget& operator=(const CheckboxWidget&) = delete;
|
|
CheckboxWidget& operator=(CheckboxWidget&&) = delete;
|
|
};
|
|
|
|
/* SliderWidget */
|
|
class SliderWidget : public ButtonWidget
|
|
{
|
|
public:
|
|
SliderWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y, int w, int h,
|
|
const string& label = "", int labelWidth = 0, int cmd = 0,
|
|
int valueLabelWidth = 0, const string& valueUnit = "",
|
|
int valueLabelGap = 0, bool forceLabelSign = false);
|
|
SliderWidget(GuiObject* boss, const GUI::Font& font,
|
|
int x, int y,
|
|
const string& label = "", int labelWidth = 0, int cmd = 0,
|
|
int valueLabelWidth = 0, const string& valueUnit = "",
|
|
int valueLabelGap = 0, bool forceLabelSign = false);
|
|
~SliderWidget() override = default;
|
|
|
|
void setValue(int value);
|
|
int getValue() const { return BSPF::clamp(_value, _valueMin, _valueMax); }
|
|
|
|
void setMinValue(int value);
|
|
int getMinValue() const { return _valueMin; }
|
|
void setMaxValue(int value);
|
|
int getMaxValue() const { return _valueMax; }
|
|
void setStepValue(int value);
|
|
int getStepValue() const { return _stepValue; }
|
|
void setValueLabel(const string& valueLabel);
|
|
void setValueLabel(int value);
|
|
const string& getValueLabel() const { return _valueLabel; }
|
|
void setValueUnit(const string& valueUnit);
|
|
|
|
void setTickmarkIntervals(int numIntervals);
|
|
|
|
protected:
|
|
void handleMouseMoved(int x, int y) override;
|
|
void handleMouseDown(int x, int y, MouseButton b, int clickCount) override;
|
|
void handleMouseUp(int x, int y, MouseButton b, int clickCount) override;
|
|
void handleMouseWheel(int x, int y, int direction) override;
|
|
bool handleEvent(Event::Type event) override;
|
|
|
|
void drawWidget(bool hilite) override;
|
|
|
|
int valueToPos(int value) const;
|
|
int posToValue(int pos) const;
|
|
|
|
protected:
|
|
int _value{-INT_MAX}, _stepValue{1};
|
|
int _valueMin{0}, _valueMax{100};
|
|
bool _isDragging{false};
|
|
int _labelWidth{0};
|
|
string _valueLabel;
|
|
string _valueUnit;
|
|
int _valueLabelGap{0};
|
|
int _valueLabelWidth{0};
|
|
bool _forceLabelSign{false};
|
|
int _numIntervals{0};
|
|
|
|
private:
|
|
// Following constructors and assignment operators not supported
|
|
SliderWidget() = delete;
|
|
SliderWidget(const SliderWidget&) = delete;
|
|
SliderWidget(SliderWidget&&) = delete;
|
|
SliderWidget& operator=(const SliderWidget&) = delete;
|
|
SliderWidget& operator=(SliderWidget&&) = delete;
|
|
};
|
|
|
|
#endif
|