Embark on an epic journey to document the dialog engine in as much detail as possible.

... and the previous commits (from 56f73cb on) were by and large a result of things noticed during this process.
This commit is contained in:
2014-12-06 03:46:37 -05:00
parent beacf9dadc
commit 88cb60fb8d
15 changed files with 3374 additions and 120 deletions

View File

@@ -289,12 +289,10 @@ void cLedGroup::recalcRect(){
frame.inset(-6,-6);
}
/** A click handler is called whenever a click is received, even on the currently selected element. */
void cLedGroup::attachClickHandler(click_callback_t f) throw() {
onClick = f;
}
/** A focus handler is called when the currently selected element changes. */
void cLedGroup::attachFocusHandler(focus_callback_t f) throw() {
onFocus = f;
}

View File

@@ -9,6 +9,9 @@
#ifndef BUTTON_H
#define BUTTON_H
/// @file
/// Button-related classes and types.
#include <SFML/Graphics.hpp>
#include <string>
@@ -17,27 +20,35 @@
#include "control.h"
#include "graphtool.h" // for eFont
/// A button type.
enum eBtnType { // w x h
BTN_SM = 0, // 23x23 (PICT id 2000 / 2001)
BTN_REG, // 63x23 (PICT id 2002 / 2003)
BTN_LG, // 102x23 (PICT id 2004 / 2005)
BTN_HELP, // 16x13 (PICT id 2006 / 2007) white bubble w/ ? mark
BTN_LEFT, // 63x23 (PICT id 2008 / 2009) with left arrow
BTN_RIGHT, // 63x23 (PICT id 2010 / 2011) with right arrow
BTN_UP, // 63x23 (PICT id 2012 / 2013) with up arrow
BTN_DOWN, // 63x23 (PICT id 2014 / 2015) with down arrow
BTN_TINY, // 14x10 (PICT id 2021)
BTN_DONE, // 63x23 (PICT id 2022 / 2023) says "Done"
BTN_TALL, // 63x40 (PICT id 2024 / 2025)
BTN_TRAIT, // 63x40 (PICT id 2026 / 2027) says "Race Good/Bad Traits"
BTN_PUSH, // 30x30 (PICT id 2028 / 2029) red round button
BTN_LED, // 14x10 (PICT id 2018 / 2019 / 2020)
BTN_SM = 0, /**< A small 23x23 button */// (PICT id 2000 / 2001)
BTN_REG, /**< A normal-sized 63x23 button */// (PICT id 2002 / 2003)
BTN_LG, /**< A large 102x23 button */// (PICT id 2004 / 2005)
BTN_HELP, /**< A small 16x13 help button - a white bubble with a ? mark */// (PICT id 2006 / 2007)
BTN_LEFT, /**< A normal-sized 63x23 button with a left-pointing arrow */// (PICT id 2008 / 2009)
BTN_RIGHT, /**< A normal-sized 63x23 button with a right-pointing arrow */// (PICT id 2010 / 2011)
BTN_UP, /**< A normal-sized 63x23 button with an up-pointing arrow */// (PICT id 2012 / 2013)
BTN_DOWN, /**< A normal-sized 63x23 button with a down-pointing arrow */// (PICT id 2014 / 2015)
BTN_TINY, /**< A tiny 14x10 button, same size as an LED */// (PICT id 2021)
BTN_DONE, /**< A normal-sized 63x23 button with "Done" on it */// (PICT id 2022 / 2023)
BTN_TALL, /**< A tall 63x40 button */// (PICT id 2024 / 2025)
BTN_TRAIT, /**< A tall 63x40 button with "Race Good/Bad Traits" on it */// (PICT id 2026 / 2027)
BTN_PUSH, /**< A round red 30x30 push button */// (PICT id 2028 / 2029)
BTN_LED, /**< A tiny 14x10 LED button */// (PICT id 2018 / 2019 / 2020)
};
/// Represents the state of an LED button.
/// Generally, led_red is used to indicate a selected button.
/// Currently, led_green is only used by the spell selection dialog,
/// where led_red indicates the spell is available amd led_green indicates it is selected.
enum eLedState {led_green = 0, led_red, led_off};
/// A clickable button control.
class cButton : public cControl {
public:
/// @copydoc cDialog::init()
static void init();
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
@@ -47,8 +58,14 @@ public:
short getFormat(eFormat prop) throw(xUnsupportedProp);
void setColour(sf::Color clr) throw(xUnsupportedProp);
sf::Color getColour() throw(xUnsupportedProp);
/// Set the type of this button.
/// @param newType The desired button type.
void setBtnType(eBtnType newType);
/// Get the type of this button.
/// @return The button type.
eBtnType getBtnType();
/// Create a new button.
/// @param parent The parent dialog.
explicit cButton(cDialog* parent);
bool isClickable();
virtual ~cButton();
@@ -56,8 +73,13 @@ public:
cButton& operator=(cButton& other) = delete;
cButton(cButton& other) = delete;
protected:
/// The type of button.
eBtnType type;
/// The click handler.
click_callback_t onClick;
/// Construct a new button.
/// @param parent The parent dialog.
/// @param t The type of control. Should be either CTRL_LED or CTRL_BTN.
cButton(cDialog* parent,eControlType t);
private:
bool wrapLabel;
@@ -65,13 +87,23 @@ private:
std::string fromList;
static RECT btnRects[13][2];
protected:
/// The index in buttons of the texture for each button type.
static size_t btnGW[14];
/// The textures that hold the graphics for the buttons.
static sf::Texture buttons[7];
};
/// A LED button that can be either on or off.
/// Additionally, it supports two possible colours, red and green.
/// By default, it behaves like a checkbox, turning on or off when clicked.
/// This default behaviour always assumes a red LED.
class cLed : public cButton {
public:
/// @copydoc cDialog::init()
static void init();
/// A handler that can be attached as a click handler to prevent the
/// default toggle-selected action of an LED.
/// @return true to indicate the event should continue.
static bool noAction(cDialog&,std::string,eKeyMod) {return true;}
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw();
@@ -79,9 +111,15 @@ public:
bool triggerFocusHandler(cDialog& me, std::string id, bool losingFocus);
void setFormat(eFormat prop, short val) throw(xUnsupportedProp);
short getFormat(eFormat prop) throw(xUnsupportedProp);
/// Create a new LED button.
/// @param parent The parent dialog.
explicit cLed(cDialog* parent);
virtual ~cLed();
/// Set the LED's current state,.
/// @param to The new state.
void setState(eLedState to);
/// Get the LED's current state.
/// @return The current state.
eLedState getState();
void draw();
cLed& operator=(cLed& other) = delete;
@@ -95,6 +133,24 @@ private:
focus_callback_t onFocus;
};
/// A group of LED buttons that behave like radio buttons.
/// As with other standard LEDs, this always assumes red LEDs.
///
/// When an LED in the group is clicked, the following sequence of events are fired:
///
/// 1. The click handler of the clicked LED.
/// 2. The click handler of the LED group.
/// 3. The focus handler of the currently selected LED (if any), with the third parameter true.
/// 4. The focus handler of the clicked LED, with the third parameter false.
/// 5. The focus handler of the LED group, with the third parameter false.
///
/// If at any stage a handler returns false, the entire sequence is aborted, and the
/// selection is not changed. A click within the group's space but not on any choice
/// triggers no events.
/// @note When the focus handlers of the individual LEDs are called, the selection has not yet been updated,
/// so calling the LED group's getSelected() method will still return the previous selection.
/// However, when the focus handler of the LED group is called, the selection _has_ been updated.,
/// so getSelected() will return the new selection. (This is the reason for the getPreviousSelection() method.)
class cLedGroup : public cControl {
std::vector<cLed> btns;
click_callback_t onClick;
@@ -106,30 +162,71 @@ class cLedGroup : public cControl {
cLedGroup& operator=(cLedGroup& other) = delete;
cLedGroup(cLedGroup& other) = delete;
public:
void attachClickHandler(click_callback_t f) throw(); // activated whenever a click is received, even on the currently active LED
void attachFocusHandler(focus_callback_t f) throw(); // activated only when the selection changes
/// @copydoc cControl::attachClickHandler()
///
/// The click handler is called whenever an LED in the group is clicked, even if it's the currently selected LED.
void attachClickHandler(click_callback_t f) throw();
/// @copydoc cControl::attachFocusHandler()
///
/// An LED group triggers focus handlers when a choice other than the currently selected one is clicked.
/// The third parameter is always false for an LED group's focus handler.
/// You can determine what changed using getPrevSelection() and getSelected(), and can do whatever post-processing
/// you want, including selecting a completely different option.
void attachFocusHandler(focus_callback_t f) throw();
bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);
bool triggerFocusHandler(cDialog& me, std::string id, bool losingFocus);
/// Add a new LED to this group.
/// @param ctrl A pointer to the LED, which should already be constructed.
/// @param key A key to be used to look up the LED later.
/// @note This function is intended for internal use, which is why it takes a control pointer instead of a unique key.
void addChoice(cLed* ctrl, std::string key);
/// Disable one of the choices in this group.
/// @param id The unique key of the choice.
void disable(std::string id);
/// Enable one of the choices in this group.
/// @param id The unique key of the choice.
void enable(std::string id);
using cControl::show;
using cControl::hide;
/// Hide one of the choices in this group.
/// @param id The unique key of the choice.
void hide(std::string id);
/// Show one of the choices in this group.
/// @param id The unique key of the choice.
void show(std::string id);
void setFormat(eFormat prop, short val) throw(xUnsupportedProp);
short getFormat(eFormat prop) throw(xUnsupportedProp);
void setColour(sf::Color clr) throw(xUnsupportedProp);
sf::Color getColour() throw(xUnsupportedProp);
/// Create a new LED group.
/// @param parent The parent dialog.
explicit cLedGroup(cDialog* parent);
bool isClickable();
bool handleClick(location where);
virtual ~cLedGroup();
/// Get one of the LED's in this group.
/// @param id The unique key of the choice.
/// @return A reference to the LED object.
/// @throw std::invalid_argument if the choice does not exist in the group.
cLed& operator[](std::string id);
/// Set the currently selected LED in this group.
/// @param id The unique key of the choice.
/// @throw std::invalid_argument if the choice does not exist in the group.
void setSelected(std::string id);
/// Get the currently selected choice.
/// @return id The unique key of the choice.
std::string getSelected();
std::string getPrevSelection(); // The id of the element that was last selected before the selection changed to the current selection.
/// Get the previously selected choice.
/// @return id The unique key of the choice.
/// @note This is intended for use by focus handlers.
///
/// This refers to the element that was last selected before the selection changed to the current selection.
std::string getPrevSelection();
/// Recalculate the LED group's bounding rect.
/// Call this after adding choices to the group to ensure that the choice is within the bounding rect.
/// If a choice is not within the bounding rect, it will not respond to clicks.
void recalcRect();
/// A convenience type for making an iterator into the choice map.
typedef std::map<std::string,cLed*>::iterator ledIter;
void draw();
};

View File

@@ -9,6 +9,9 @@
#ifndef CONTROL_H
#define CONTROL_H
/// @file
/// Control-related classes and types.
#include <SFML/Graphics.hpp>
#include <string>
@@ -23,94 +26,217 @@
// short type;
//};
/// Formatting properties
enum eFormat {
TXT_FRAME,
TXT_FONT,
TXT_SIZE,
TXT_WRAP,
TXT_FRAMESTYLE,
TXT_FRAME, ///< Whether to draw a frame around the control. Should be a boolean (true or false).
TXT_FONT, ///< The control's text font. Should be one of the constants FONT_PLAIN, FONT_BOLD, FONT_DUNGEON, FONT_MAIDEN.
TXT_SIZE, ///< The control's text size. Should be an integer indicating point size.
TXT_WRAP, ///< Whether the control should wrap. Should be a boolean (true or false).
TXT_FRAMESTYLE, ///< The control's frame style. Should be a boolean (true or false). @see cControl::drawFrame()
};
/// Specifies the type of a control.
enum eControlType {
CTRL_UNKNOWN,
CTRL_BTN, // An ordinary push button
CTRL_LED, // An LED (checkbox/radiobutton)
CTRL_PICT, // A picture
CTRL_FIELD, // An edit text field
CTRL_TEXT, // A static text object
CTRL_GROUP, // A LED radiobutton-like group
CTRL_STACK, // A group of controls that display pages (not implemented yet)
CTRL_SCROLL,// A scrollbar (not implemented yet)
CTRL_BTN, ///< An ordinary push button
CTRL_LED, ///< An LED (checkbox/radiobutton)
CTRL_PICT, ///< A picture
CTRL_FIELD, ///< An edit text field
CTRL_TEXT, ///< A static text object
CTRL_GROUP, ///< A LED radiobutton-like group
CTRL_STACK, ///< A group of controls that display pages (not implemented yet)
CTRL_SCROLL,///< A scrollbar
};
//typedef bool (*click_callback_t)(cDialog&/*me*/,std::string/*id*/, eKeyMod/*mods*/);
//typedef bool (*focus_callback_t)(cDialog&/*me*/,std::string/*id*/,bool/*losing*/); // losing is true if losing focus, false if gaining focus.
/// The signature of a click handler.
typedef std::function<bool(cDialog&,std::string,eKeyMod)> click_callback_t;
/// The signature of a focus handler.
typedef std::function<bool(cDialog&,std::string,bool)> focus_callback_t;
/// Thrown when you try to set a handler that the control does not support.
class xHandlerNotSupported : std::exception {
static const char* focusMsg;
static const char* clickMsg;
bool isFocus;
public:
/// Construct a new exception.
/// @param isFocus true to indicate a focus event, false for a click event.
xHandlerNotSupported(bool isFocus);
/// @return The error message.
const char* what();
};
/// Thrown when you try to set or retrieve a formatting property that the control does not support.
class xUnsupportedProp : std::exception {
eFormat whichProp;
char* msg;
public:
/// Construct a new exception.
/// @param prop The unsupported format property.
xUnsupportedProp(eFormat prop) throw();
~xUnsupportedProp() throw();
/// @return The error message.
const char* what() throw();
};
/// The superclass of all dialog controls.
/// Some controls can be created in an arbitrary window, rather than a dialog controlled by cDialog.
/// In this case, the event loop of the parent window is responsible for calling draw() when the control needs
/// to be drawn, handleClick() when a mousedown event is received within the control's bounding rect, and
/// triggerClickHandler() if a click occurs, either because handleClick() returns true or because
/// a keyboard event is received that should trigger the control.
class cControl {
public:
/// Attach a keyboard shortcut to a control. Pressing the keyboard shortcut is equivalent to clicking the control.
/// @param key The desired keyboard shortcut.
void attachKey(cKey key);
/// Detach any currently assigned keyboard shortcut from the control.
void detachKey();
/// Set the control's text to a representation of its assigned keyboard shortcut.
void setTextToKey();
/// Check if the control has an assigned keyboard shortcut.
/// @return true if a keyboard shortcut is assigned.
bool hasKey();
/// Retrieve the control's current keyboard shortcut.
/// @return the currently-assigned keyboard shortcut.
/// @note You should first check that a shortcut is assigned using hasKey().
cKey getAttachedKey();
/// Attach a click handler to this control.
/// @param f The click handler to attach.
/// @throw xHandlerNotSupported if this control does not support click handlers. Most controls do support click handlers.
/// @note Only one click handler can be set at a time. To remove the click handler, set it to null.
///
/// A click handler must be able to accept three parameters: a reference to the containing dialog, the unique key of the
/// clicked item, and a representation of any modifier keys that are currently held.
virtual void attachClickHandler(click_callback_t f) throw(xHandlerNotSupported) = 0;
/// Attach a focus handler to this control.
/// @param f The focus handler to attach.
/// @throw xHandlerNotSupported if this control does not support focus handlers. Most controls do not support focus handlers.
/// @note Only one focus handler can be set at a time. To remove the focus handler, set it to null.
///
/// A focus handler must be able to accept three parameters: a reference to the containing dialog, the unique key of the
/// clicked item, and a boolean indicating whether focus is being lost or gained; a value of true indicates that
/// focus is being lost, while false indicates it's being gained. Most handlers will only need to act when the
/// third parameter is true. If the handler returns false, the focus change is cancelled.
virtual void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported) = 0;
/// Trigger the click handler for this control.
/// @param me A reference to the current dialog.
/// @param id The unique key of this control.
/// @param mods The currently-held keyboard modifiers.
/// @return true if the event should continue, false if it should be cancelled.
virtual bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);
/// Trigger the focus handler for this control.
/// @param me A reference to the current dialog.
/// @param id The unique key of this control.
/// @param losingFocus true if this control is losing focus, false if it is gaining focus.
/// @return true if the event should continue, false if it should be cancelled.
virtual bool triggerFocusHandler(cDialog& me, std::string id, bool losingFocus);
//virtual void setPict(short pict, short type) = 0;
/// Make this control visible.
virtual void show(); // cd_activate_item true
/// Make this control invisible.
virtual void hide(); // cd_activate_item false
/// Check if this control is visible.
/// @return true if it's visible
bool isVisible(); // cd_get_active
/// Set if this control is active. A control is normally active when the mouse button is held down within its bounding rect.
/// @param active true if it should be active, false if not
void setActive(bool active); // "active" here means "selected", so if it's a button, draw it pressed
/// Get the type of this control
/// @return The type of control
eControlType getType();
/// Set the control's text.
/// @param l The new text.
virtual void setText(std::string l);
/// Fetch the control's text.
/// @return The control's current text.
virtual std::string getText();
/// Get the bounding rect of this control.
/// @return The control's bounding rect.
RECT getBounds();
/// Set the bounding rect of this control.
/// @param newBounds The new bounding rect.
void setBounds(RECT newBounds);
/// Set the position of this control.
/// @param to The new position.
void relocate(location to);
/// Get the control's text as an integer.
/// @return The control's text, coerced to an integer.
long long getTextAsNum();
/// Set the control's text to an integer value.
/// @param what The desired value.
void setTextToNum(long long what);
/// Set one of the control's formatting parameters.
/// @param prop The parameter to set.
/// @param val The desired value of the parameter.
/// @throw xUnsupportedProp if this control doesn't support the given parameter.
virtual void setFormat(eFormat prop, short val) throw(xUnsupportedProp) = 0;
/// Get one of the control's formatting parameters.
/// @param prop The parameter to retrieve.
/// @return The value of the parameter.
/// @throw xUnsupportedProp if this control doesn't support the given parameter.
virtual short getFormat(eFormat prop) throw(xUnsupportedProp) = 0;
/// Set the control's colour (usually text colour).
/// @param clr The desired colour.
/// @throw xUnsupportedProp if this control does not support colour.
virtual void setColour(sf::Color clr) throw(xUnsupportedProp) = 0;
/// Get the control's colour.
/// @return The current colour.
/// @throw xUnsupportedProp if this control does not support colour.
virtual sf::Color getColour() throw(xUnsupportedProp) = 0;
/// Check if the control is clickable.
/// @return true if it's clickable.
/// @note This does not indicate whether the control supports click handlers.
/// In fact, some controls return true only if a click handler is assigned.
/// Others, like editable text fields, are clickable but do not support click handlers.
virtual bool isClickable() = 0;
/// Handles the action of clicking this control.
/// @param where The exact location at which the mouse was pressed, relative to the dialog.
/// @return true if the click was successful; false if it was cancelled.
///
/// This function should implement an event loop and terminate when the mouse button is released.
/// It can be overridden to customize the reaction of the control to mouse events.
/// The default implementation works for a simple clickable object such as a button that
/// should be hilited in some way while pressed and is cancelled by releasing the mouse
/// button outside the control's bounds.
virtual bool handleClick(location where);
/// Create a new control attached to an arbitrary window, rather than a dialog.
/// @param t The type of the control.
/// @param p The parent window.
cControl(eControlType t, sf::RenderWindow& p);
/// Create a new control attached to a dialog.
/// @param t The type of the control.
/// @param p The parent dialog.
cControl(eControlType t, cDialog& p);
virtual ~cControl();
/// Draw the control into its parent window.
virtual void draw() = 0;
cControl& operator=(cControl& other) = delete;
cControl(cControl& other) = delete;
protected:
/// The parent dialog of the control.
/// May be null, if the control was created via cControl(eControlType,sf::RenderWindow&).
cDialog* parent;
/// The parent window of the control.
/// This is for use in implementing draw().
sf::RenderWindow* inWindow;
/// The control's current text.
std::string lbl;
bool visible, depressed = false; // depressed is only applicable for clickable controls
/// Whether the control is visible
bool visible, depressed = false; ///< Whether the control is depressed; only applicable for clickable controls
/// The control's bounding rect.
RECT frame;
/// The control's frame style.
int frameStyle;
/// The control's attached key.
cKey key;
/// Draw a frame around the control.
/// @param amt How much to offset the frame from the control's bounding rect.
/// @param med_or_lt true to use a darker colour for the frame.
/// @note The TXT_FRAMESTYLE formatting property is normally used for the second parameter.
void drawFrame(short amt, bool med_or_lt);
/// Redraws the parent dialog, if any.
/// Intended to be called from handleClick(), where there is usually a minor event loop happening.
void redraw();
private:
eControlType type;

View File

@@ -9,6 +9,9 @@
#ifndef DIALOG_H
#define DIALOG_H
/// @file
/// Dialog-related classes and types.
#include <SFML/Graphics.hpp>
#include <string>
@@ -24,10 +27,12 @@
class cControl;
class cTextField;
/// Specifies the relative position of a control's labelling text.
enum eLabelPos {
LABEL_LEFT, LABEL_ABOVE, LABEL_RIGHT, LABEL_BELOW,
};
/// Defines a fancy dialog box with various controls.
class cDialog {
typedef std::map<std::string,cControl*>::iterator ctrlIter;
std::map<std::string,cControl*> controls;
@@ -43,35 +48,113 @@ class cDialog {
template<typename Iter> void handleTabOrder(std::string& itemHit, Iter begin, Iter end);
std::vector<std::pair<std::string,cTextField*>> tabOrder;
public:
/// Performs essential startup initialization. Generally should not be called directly.
static void init();
static const short BG_LIGHT, BG_DARK;
/// The light background pattern used by the scenario editor dialogs.
static const short BG_LIGHT, BG_DARK; ///< The dark background pattern used by the game dialogs.
/// The default background pattern for newly created dialogs.
static short defaultBackground;
explicit cDialog(cDialog* p = NULL); // dialog with no items
/// Create a new dialog with no items.
/// @param p Optionally, a parent dialog.
explicit cDialog(cDialog* p = NULL);
/// Creates a new dialog, loading its definition from a file.
/// @param path The name of the file to load. It must be in the game's dialogs directory.
/// @param p Optionally, a parent dialog.
explicit cDialog(std::string path, cDialog* p = NULL); // cd_create_dialog
~cDialog(); // cd_kill_dialog
bool add(cControl* what, RECT ctrl_frame, std::string key); // returns false if the key is used, true if the control was added
bool remove(std::string key); // returns true if the key existed and was removed, false if the key did not exist
bool addLabelFor(std::string key, std::string label, eLabelPos where, short offset, bool bold); // returns true if the label was added
/// Add a new control to the dialog.
/// @param what A pointer to the control, which should already be constructed.
/// @param ctrl_frame The control's bounding rect, which includes its position in the dialog.
/// @param key A key to be used to look up the control later.
/// @return false if the key is used, true if the control was added.
/// @note This function is intended for internal use, which is why it takes a control pointer instead of a unique key.
bool add(cControl* what, RECT ctrl_frame, std::string key);
/// Remove a control from the dialog.
/// @param key The control's unique key.
/// @return true if the key existed and the control was removed, false if the key did not exist
bool remove(std::string key);
/// Add a new static text control, positioned to function as a label for an existing control.
/// @param key The unique key of the control to be labelled.
/// @param label The text of the label.
/// @param where Specifies the position of the label relative to the control.
/// @param offset An offset in pixels between the control and the label.
/// @param bold If true, the label will be bolded.
/// @return true if the label was added, false if not (usually because it already had a label)
bool addLabelFor(std::string key, std::string label, eLabelPos where, short offset, bool bold);
/// Show the dialog and start its event loop. All dialogs are modal.
void run(); // cd_run_dialog
/// Get the result of the dialog.
/// @tparam type The result type.
/// @throw boost::bad_any_cast if the provided result type is different from the type set by getResult().
/// @return The dialog's result.
template<typename type> type getResult(){
return boost::any_cast<type>(result);
}
/// Set the result of the dialog.
/// @tparam type The result type.
/// @param val The result value.
template<typename type> void setResult(const type& val){
result = val;
}
/// Set the background pattern of the dialog.
/// @param n The numeric index of the background pattern, which should be in the range [0,20].
/// You can use the constants BG_LIGHT or BG_DARK to reference the most commonly used backgrounds.
void setBg(short n);
/// Get the background pattern of the dialog.
/// @return The numeric index of the background pattern.
short getBg();
/// Set the default text colour applied to new dialogs when loading from a file.
/// @param clr The text colour.
void setDefTextClr(sf::Color clr);
/// Set the default button, which will be drawn outlined and respond to the enter key.
/// @param defBtn The unique key of the default button.
///
/// This function does not check that the default button exists and is a button.
void setDefBtn(std::string defBtn);
/// Get the default text colour applied to new dialogs when loading from a file.
/// @return The text colour.
sf::Color getDefTextClr();
bool setFocus(cTextField* newFocus, bool force = false); // Setting force = true skips focus handlers
/// Set the focused text field.
/// @param newFocus A pointer to the text field to receive focus.
/// @param force If true, the change will be forced.
/// The focus handlers for both the previously focused text field and the newly focused text field will not be triggered.
/// @return true if the focus changed; if it returns false, it could mean either that the control did not exist in the dialog
/// or that one of the focus handlers prevented the focus change.
/// @note This function is intended for internal use, which is why it takes a control pointer instead of a unique key.
bool setFocus(cTextField* newFocus, bool force = false);
/// Close the dialog.
/// @param triggerFocus true to allow the focus handler of the currently focused text field to prevent the dialog from closing
/// @return true unless the currently focused field prevented the dialog from closing
///
/// Generally, you would pass true in a handler for an OK button and false in a handler for a Cancel button.
bool toast(bool triggerFocus);
/// Get a reference to a control.
/// @param id The unique key of the control.
/// @throw std::invalid_argument if the control does not exist.
/// @return a reference to the requested control.
cControl& getControl(std::string id);
/// @copydoc getControl()
cControl& operator[](std::string id);
/// Recalculate the dialog's bounding rect.
/// Call this after adding controls to the dialog to ensure that the control is within the bounding rect.
void recalcRect();
// TODO: It seems like a bad thing for these two to not use the typedefs...
/// Attach the same click handler to several controls.
/// @param handler The handler to attach.
/// @param controls A list of the unique keys of the controls to which you want the handler attached.
/// @throw xHandlerNotSupported if any of the controls do not support click handlers.
/// @throw std::invalid_argument if any of the controls do not exist.
/// @see cControl::attachClickHandler()
void attachClickHandlers(std::function<bool(cDialog&,std::string,eKeyMod)> handler, std::vector<std::string> controls);
/// Attach the same focus handler to several controls.
/// @param handler The handler to attach.
/// @param controls A list of the unique keys of the controls to which you want the handler attached.
/// @throw xHandlerNotSupported if any of the controls do not support focus handlers.
/// @throw std::invalid_argument if any of the controls do not exist.
/// @see cControl::attachFocusHandler()
void attachFocusHandlers(std::function<bool(cDialog&,std::string,bool)> handler, std::vector<std::string> controls);
/// Get the bounding rect of the dialog.
/// @return The dialog's bounding rect.
RECT getBounds() {return winRect;}
cDialog& operator=(cDialog& other) = delete;
cDialog(cDialog& other) = delete;
@@ -87,44 +170,78 @@ private:
friend class cControl;
};
/// Thrown when an invalid element is found while parsing an XML dialog definition.
class xBadNode : std::exception {
std::string type, dlg;
int row, col;
const char* msg;
public:
/// Construct a new exception.
/// @param t The tag name of the invalid element.
/// @param r The line number of the element in the source.
/// @param c The column number of the element in the source.
/// @param dlg The name of the file in which the element occurred.
xBadNode(std::string t, int r, int c, std::string dlg) throw();
~xBadNode() throw();
/// @return The error message.
const char* what() throw();
};
/// Thrown when an invalid attribute is found while parsing an XML dialog definition.
class xBadAttr : std::exception {
std::string type, name, dlg;
int row, col;
const char* msg;
public:
/// Construct a new exception.
/// @param t The tag name of the element with the invalid attribute.
/// @param n The name of the invalid attribute.
/// @param r The line number of the element in the source.
/// @param c The column number of the element in the source.
/// @param dlg The name of the file in which the element occurred.
xBadAttr(std::string t,std::string n, int r, int c, std::string dlg) throw();
~xBadAttr() throw();
/// @return The error message.
const char* what() throw();
};
/// Thrown when an element is missing a required attribute while parsing an XML dialog definition.
class xMissingAttr : std::exception {
std::string type, name, dlg;
int row, col;
const char* msg;
public:
/// Construct a new exception.
/// @param t The tag name of the element with the missing attribute.
/// @param n The name of the missing attribute.
/// @param r The line number of the element in the source.
/// @param c The column number of the element in the source.
/// @param dlg The name of the file in which the element occurred.
xMissingAttr(std::string t,std::string n, int r, int c, std::string dlg) throw();
~xMissingAttr() throw();
/// @return The error message.
const char* what() throw();
};
/// Thrown when an invalid value is found anywhere within an element's or attribute's content.
class xBadVal : std::exception {
std::string type, name, val, dlg;
int row, col;
const char* msg;
public:
/// A magic value to indicate errors in an element's content, rather than an attribute's content.
static constexpr const char*const CONTENT = "<content>";
/// Construct a new exception.
/// @param t The tag name of the element with the invalid value.
/// @param n The name of the attribute with the invalid value.
/// You should pass xBadVal::CONTENT if the bad value is within an element's content.
/// @param v The invalid value.
/// @param r The line number of the element in the source.
/// @param c The column number of the element in the source.
/// @param dlg The name of the file in which the element occurred.
xBadVal(std::string t,std::string n,std::string v, int r, int c, std::string dlg) throw();
~xBadVal() throw();
/// @return The error message.
const char* what() throw();
};

View File

@@ -9,15 +9,32 @@
#ifndef BoE_dialog_keys_h
#define BoE_dialog_keys_h
/// @file
/// Key-related classes and types.
/// Keyboard modifiers, as a bit-field-like enumeration.
/// Note that mod_ctrl refers to both the control key and the Mac's command key.
/// It also covers the "meta" key supported in certain other systems, and may
/// also be triggered by the Windows key.
///
/// Use mod_contains() to check if a specific modifier is set in the bit field.
enum eKeyMod {
mod_none = 0,
mod_none = 0, ///< No modifier
/// @{ A single modifier
mod_alt = 1, mod_shift = 2, mod_ctrl = 4,
/// @}
/// @{ Two modifiers
mod_altshift = mod_alt + mod_shift,
mod_altctrl = mod_alt + mod_ctrl,
mod_shiftctrl = mod_shift + mod_ctrl,
/// @}
/// All modifiers
mod_all = mod_alt + mod_shift + mod_ctrl,
};
/// Representations of special keys.
/// Not all of these represent a literal single keypress.
/// Some refer to common two-keypress keyboard shortcuts.
enum eSpecKey {
key_left, key_right, key_up, key_down,
key_esc, key_enter, key_tab, key_help, // key_help should bind to the help key on Mac and the F1 key on Windows
@@ -28,21 +45,47 @@ enum eSpecKey {
// This is in addition to the home, end, pgup, pgdn keys triggering these.
};
/// Represents a keypress.
struct cKey {
/// If true, it's a special key. Otherwise, a character has been typed.
bool spec;
union {
/// The character that has been typed.
unsigned char c;
/// The special key that was pressed.
eSpecKey k;
};
/// A bit field of held key modifiers.
eKeyMod mod;
};
/// Combine two key modifiers.
/// @param lhs @param rhs
/// @return lhs + rhs
eKeyMod operator + (eKeyMod lhs, eKeyMod rhs);
/// Cancel out a key modifier.
/// @param lhs @param rhs
/// @return lhs - rhs
eKeyMod operator - (eKeyMod lhs, eKeyMod rhs);
/// Combine two key modifiers.
/// @param lhs The key modifier set to modify.
/// @param rhs The key modifier to remove.
/// @return lhs, now modified.
eKeyMod&operator += (eKeyMod&lhs, eKeyMod rhs);
/// Cancel out a key modifier.
/// @param lhs The key modifier set to modify.
/// @param rhs The key modifier to remove.
/// @return lhs, now modified.
eKeyMod&operator -= (eKeyMod&lhs, eKeyMod rhs);
/// Compare two keys.
/// @param a @param b
/// @return Whether they are equal.
bool operator== (cKey a, cKey b);
/// Check if haystack contains the modifier specified by needle.
/// @param haystack The set of modifiers to check.
/// @param needle The modifier to check for; generally one of mod_alt, mod_shift, or mod_ctrl.
/// @return true if the needle is in the haystack
bool mod_contains(eKeyMod haystack, eKeyMod needle);
#endif

View File

@@ -6,7 +6,11 @@
*
*/
size_t available_btns[53] = { // This array is a list of indices into the following array.
/// @file
/// Preset button specifications for cThreeChoice
/// The buttons available to special nodes; consists of indices into the basic_buttons array.
size_t available_btns[53] = {
0, 63, 64, 65, 1, 4, 5, 8, 128,9,
10, 11, 12, 13, 14, 15, 16, 17, 29, 51,
60, 61, 62, 66, 69, 70, 71, 72, 73, 74,
@@ -15,6 +19,7 @@ size_t available_btns[53] = { // This array is a list of indices into the follow
135,136,137
};
/// A list of preset button types. Many of these are unused.
bbtt basic_buttons[] = {
{BTN_DONE, " ", {false,0,mod_none}}, // Formerly DLG_BTN_REG with "Done " as the string
{BTN_REG, "Ask", {false,0,mod_none}},

View File

@@ -536,7 +536,7 @@ void giveError(std::string str1, std::string str2, cDialog* parent){
error.show();
}
void oopsError(short error, short code, short mode){ // mode is 0 for scened, 1 for game, 2 for pced
void oopsError(short error, short code, short mode){
std::ostringstream error_str1, error_str2;
static const char* progname[3] = {"the scenario editor", "Blades of Exile", "the PC editor"};
static const char* filetname[3] = {"scenario", "game", "game"};

View File

@@ -9,6 +9,9 @@
#ifndef DIALOG_UTIL_H
#define DIALOG_UTIL_H
/// @file
/// A set of utility classes for simple and common dialogs.
#include <string>
#include <vector>
#include <functional>
@@ -19,9 +22,10 @@
#include "button.h"
#include <boost/optional.hpp>
//typedef void (*record_callback_t)(std::string,std::string);
/// The signature of a record handler for cStrDlog.
typedef std::function<void(cDialog&)> record_callback_t;
/// A simple dialog with one or two long strings, an optional title, and an optional record button.
class cStrDlog {
static std::string getFileName(short n_strs, ePicType type, bool hasTitle);
cDialog dlg;
@@ -32,31 +36,75 @@ class cStrDlog {
bool onRecord(std::string id);
bool onDismiss();
public:
/// Construct a string dialog.
/// @param str1 The first string.
/// @param str2 The second string. If left as an empty string, there will be only one string in the dialog.
/// @param title The title. If left as an empty string, there will be no title.
/// @param pic The icon to show at the top left.
/// @param t The type of icon to show.
/// @param parent Optionally, a parent dialog.
cStrDlog(std::string str1,std::string str2,std::string title,pic_num_t pic,ePicType t,cDialog* parent = NULL);
/// Set a sound to be played when the dialog is shown.
/// @param num The sound number.
/// @return This object, for method-call chaining.
cStrDlog& setSound(snd_num_t num);
/// Set a record handler.
/// @param rec The handler.
/// @return This object, for method-call chaining.
/// @note Only one record handler can be set at a time. To remove it, set it to null.
/// @note The presence of the Record button is determined entirely by the presence of a record handler.
///
/// A record handler should take one parameter, which is a reference to the dialog.
/// (That's the cDialog, not the cStrDlog.) It should return void.
cStrDlog& setRecordHandler(record_callback_t rec);
/// Reference the cDialog powering this choice dialog, perhaps to customize details of it.
/// @return A pointer to the dialog.
cDialog* operator->();
/// Show the dialog.
void show();
};
/// A simple dialog that lets you select one of several buttons.
/// This class loads a definition from a file, so there can be any amount of other stuff in the dialog,
/// and the buttons could be arranged in any fashion you want.
class cChoiceDlog {
cDialog dlg;
protected:
/// The click handler for the dialog's buttons.
/// @param me A reference to the current dialog.
/// @param id The unique key of the clicked control.
/// @return true, indicating the event should continue.
bool onClick(cDialog& me, std::string id);
/// Create a choice dialog, but don't initialize it.
/// @param p Optionally, a parent dialog.
explicit cChoiceDlog(cDialog* p = NULL);
public:
/// Create a choice dialog with just one button.
/// @param file The file to load the dialog definition from.
/// @param p Optionally, a parent dialog.
/// @note The dialog definition file must include a button whose name attribute is "okay".
explicit cChoiceDlog(std::string file, cDialog* p = NULL);
/// Create a choice dialog with several buttons.
/// @param file The file to load the dialog definition from.
/// @param buttons A list of the buttons to handle. All of them must be defined in the file.
/// @param p Optionally, a parent dialog.
cChoiceDlog(std::string file, std::vector<std::string> buttons, cDialog* p = NULL);
/// Reference the cDialog powering this choice dialog, perhaps to customize details of it.
/// @return A pointer to the dialog.
cDialog* operator->();
/// Show the dialog.
/// @return The unique key of the clicked button.
std::string show();
};
struct bbtt { // stands for "basic button type template"
eBtnType type;
std::string label;
cKey defaultKey;
/// Basic button type template
struct bbtt {
eBtnType type; ///< The type of the preset button.
std::string label; ///< The preset button's label, if any.
cKey defaultKey; ///< The preset button's default key shortcut, if any.
};
/// Represents a preset button for use with cThreeChoice.
typedef boost::optional<bbtt> cBasicButtonType;
namespace {cBasicButtonType null_btn = boost::none;}
@@ -65,6 +113,10 @@ extern bbtt basic_buttons[];
extern size_t available_btns[53];
#endif
/// A choice dialog with several strings and up to three buttons.
/// This is the class used for dialogs generated by special nodes.
/// It generates the dialog dynamically from the given input.
/// Note that the dialog is not limited to six strings.
class cThreeChoice : public cChoiceDlog {
//static std::string getFileName(size_t n_strs);
cBasicButtonType btns[3];
@@ -74,12 +126,34 @@ class cThreeChoice : public cChoiceDlog {
void init_pict(pic_num_t pic);
const ePicType type;
public:
/// Create a dialog with just one button.
/// @param strings A list of the strings to place in the dialog.
/// @param button The specification of the button.
/// @param pic The icon to show at the top left.
/// @param t The type of the icon.
/// @param parent Optionally, a parent dialog.
cThreeChoice(std::vector<std::string>& strings, cBasicButtonType button, pic_num_t pic, ePicType t, cDialog* parent = NULL);
/// Create a dialog with up to three buttons.
/// @param strings A list of the strings to place in the dialog.
/// @param buttons A list of the button specifications.
/// @param pic The icon to show at the top left.
/// @param t The type of the icon.
/// @param parent Optionally, a parent dialog.
cThreeChoice(std::vector<std::string>& strings, std::array<cBasicButtonType, 3>& buttons, pic_num_t pic, ePicType t, cDialog* parent = NULL);
/// Create a dialog with up to three buttons.
/// @param strings A list of the strings to place in the dialog.
/// @param buttons A list of the index of the button; this is an index into available_btns which is in turn used to index basic_buttons.
/// @param pic The icon to show at the top left.
/// @param t The type of the icon.
/// @param parent Optionally, a parent dialog.
cThreeChoice(std::vector<std::string>& strings, std::array<short, 3>& buttons, pic_num_t pic, ePicType t, cDialog* parent = NULL);
/// @copydoc cChoiceDlog::show()
/// @note The unique key in this case is the label specified in the button specification.
std::string show();
};
/// A dialog that presents a list of strings with LEDs and allows you to choose one.
/// The list may span several pages.
class cStringChoice {
static const size_t per_page;
cDialog dlg;
@@ -94,12 +168,29 @@ class cStringChoice {
size_t page, cur;
cLedGroup* leds;
public:
/// Initializes a dialog from a list of strings.
/// @param strs A list of all strings in the dialog.
/// @param title The title to show in the dialog.
/// @param parent Optionally, a parent dialog.
explicit cStringChoice(std::vector<std::string>& strs, std::string title, cDialog* parent = NULL);
/// Initializes a dialog from an iterator pair.
/// @param begin An iterator to the first string in the dialog.
/// @param end An iterator to one past the last string in the dialog.
/// @param title The title to show in the dialog.
/// @param parent Optionally, a parent dialog.
/// @note Currently, only vector iterators are supported.
cStringChoice(std::vector<std::string>::iterator begin, std::vector<std::string>::iterator end, std::string title, cDialog* parent = NULL);
/// Reference the cDialog powering this choice dialog, perhaps to customize details of it.
/// @return A pointer to the dialog.
cDialog* operator->();
/// Show the dialog.
/// @param selectedIndex The index of the string that should be initially selected when the dialog is shown.
/// @return The index of the newly selected string; if the user cancelled, this will be equal to selectedIndex.
/// If initialized from an iterator range, this will be relative to begin.
size_t show(size_t selectedIndex);
};
/// Like cStringChoice, but presents a list of icons rather than strings.
class cPictChoice {
static const size_t per_page;
bool didAccept;
@@ -115,17 +206,51 @@ class cPictChoice {
size_t page, cur;
cLedGroup* leds;
public:
/// Initializes a dialog from a list of icons.
/// @param pics A list of all icons in the dialog.
/// @param t The type of icons to show; all icons are assumed to be of the same type.
/// @param parent Optionally, a parent dialog.
cPictChoice(std::vector<pic_num_t>& pics, ePicType t, cDialog* parent = NULL);
/// Initializes a dialog from a list of icons.
/// @param pics A list of all icons in the dialog as {num,type} pairs.
/// @param parent Optionally, a parent dialog.
cPictChoice(std::vector<std::pair<pic_num_t,ePicType>>& pics, cDialog* parent = NULL);
/// Initializes a dialog from an iterator pair.
/// @param begin An iterator to the first icon in the dialog.
/// @param end An iterator to one past the last icon in the dialog.
/// @param t The type of icons to show; all icons are assumed to be of the same type.
/// @param parent Optionally, a parent dialog.
cPictChoice(std::vector<pic_num_t>::iterator begin, std::vector<pic_num_t>::iterator end, ePicType t, cDialog* parent = NULL);
/// Initializes a dialog from an index pair.
/// @param first The number of the first icon in the dialog.
/// @param last The number of the last icon in the dialog.
/// @param t The type of icons to show; all icons are assumed to be of the same type.
/// @param parent Optionally, a parent dialog.
cPictChoice(pic_num_t first, pic_num_t last, ePicType t, cDialog* parent = NULL);
/// Reference the cDialog powering this choice dialog, perhaps to customize details of it.
/// @return A pointer to the dialog.
cDialog* operator->();
/// Show the dialog.
/// @param cur_sel The index of the icon that should be initially selected when the dialog is shown.
/// @return false if the user clicked Cancel, true otherwise.
/// @note If for some reason an icon appears twice in the list, there's no way to determine which of the two was selected.
bool show(size_t cur_sel);
/// Get the chosen icon.
/// @return The number of the chosen icon.
pic_num_t getPicChosen();
/// Get the chosen icon.
/// @return The type of the chosen icon.
ePicType getPicChosenType();
// returns the _number_ of the chosen picture, _not_ the index; there's no way to distinguish between duplicates
};
#endif
/// Shows a simple error dialog.
/// @param str1 The first string in the error dialog.
/// @param str2 The second string in the error dialog.
/// @param parent Optionally, a parent dialog.
void giveError(std::string str1, std::string str2 = "", cDialog* parent = NULL);
/// Shows a generic error dialog and exits.
/// @param error An arbitrary code intended to be used for locating the error in the source.
/// @param code A code indicating the result of a failed action that triggered the error.
/// @param mode 0 for scenario editor, 1 for game, 2 for pc editor
void oopsError(short error,short code = 0, short mode = 0);

View File

@@ -9,36 +9,59 @@
#ifndef FIELD_H
#define FIELD_H
/// @file
/// Field-related classes and types.
#include <string>
#include "control.h"
/// The field's expected input type.
enum eFldType {
FLD_INT,
FLD_UINT,
FLD_REAL,
FLD_TEXT,
FLD_INT, ///< A field that accepts only integers.
FLD_UINT, ///< A field that accepts only positive integers.
FLD_REAL, ///< A field that accepts any real (floating-point) number.
FLD_TEXT, ///< A field that accepts any text. This is the default.
};
/// An editable text field.
/// The text field supports multiline input and text selection.
/// It automatically scrolls to keep the insertion point in view.
/// (If there's a current selection, the mobile end of the selection is kept in view.)
/// Mouse support is currently nonexistent, except for focusing when clicked.
/// There is no Unicode support.
class cTextField : public cControl {
public:
void attachClickHandler(click_callback_t f) throw(xHandlerNotSupported);
/// @copydoc cControl::attachFocusHandler()
/// For text fields, this is triggered when it loses or gains the input focus.
void attachFocusHandler(focus_callback_t f) throw();
bool triggerFocusHandler(cDialog& me, std::string id, bool losingFocus);
bool handleClick(location where);
void setFormat(eFormat prop, short val) throw(xUnsupportedProp);
short getFormat(eFormat prop) throw(xUnsupportedProp);
void setColour(sf::Color clr) throw(xUnsupportedProp);
/// Get the current input type of the field.
/// @return The input type.
eFldType getInputType();
/// Set the input type of the field.
/// @param newType The new input type.
void setInputType(eFldType newType);
sf::Color getColour() throw(xUnsupportedProp);
/// Create a new editable text field.
/// @param parent The parent dialog.
explicit cTextField(cDialog* parent);
bool isClickable();
virtual ~cTextField();
void draw();
/// Check if this text field currently has input focus.
/// @return true if it it is currently focused.
bool hasFocus();
/// Handle keyboard input.
/// @param key The keypress to handle.
void handleInput(cKey key);
cTextField& operator=(cTextField& other) = delete;
cTextField(cTextField& other) = delete;
/// This field is only used by cDialog during the loading process. Changing it will have no effect.
long tabOrder = 0;
private:
eFldType field_type;

View File

@@ -9,12 +9,17 @@
#ifndef MESSAGE_H
#define MESSAGE_H
/// @file
/// Message-related classes and types.
#include <SFML/Graphics.hpp>
#include <string>
#include "control.h"
#include "graphtool.h" // for eFont
/// A simple static text message.
/// This class can also create a frame for grouping controls or a clickable area.
class cTextMsg : public cControl {
public:
void attachClickHandler(click_callback_t f) throw();
@@ -24,7 +29,11 @@ public:
short getFormat(eFormat prop) throw(xUnsupportedProp);
void setColour(sf::Color clr) throw(xUnsupportedProp);
sf::Color getColour() throw(xUnsupportedProp);
/// Create a new text message.
/// @param parent The parent dialog.
explicit cTextMsg(cDialog& parent);
/// Create a new text message without a parent dialog.
/// @param parent The parent window.
explicit cTextMsg(sf::RenderWindow& parent);
bool isClickable();
virtual ~cTextMsg();

View File

@@ -9,6 +9,9 @@
#ifndef PICT_H
#define PICT_H
/// @file
/// Icon-related classes and types.
#include <SFML/Graphics.hpp>
#include <vector>
@@ -16,86 +19,94 @@
#include "graphtool.h" // for pic_num_t
#include "control.h"
/// Specifies an icon type.
enum ePicType {
PIC_TER = 1, // 28x36 terrain graphic from the preset sheets
PIC_TER_ANIM = 2, // 28x36 terrain graphic from the preset animated terrain sheet
PIC_MONST = 3, // 28x36 monster graphic from the preset sheets
PIC_DLOG = 4, // 36x36 dialog graphic from the preset sheet
PIC_TALK = 5, // 32x32 talking portrait from the preset sheet
PIC_SCEN = 6, // 32x32 scenario graphic from the scenario sheet
PIC_ITEM = 7, // 28x36 item graphic from the large item sheet, or 18x18 item graphic from the small sheet centred in a 28x36 space
PIC_PC = 8, // 28x36 pc graphic from the player sheet
PIC_FIELD = 9, // 28x36 field graphic from the fields sheet
PIC_BOOM = 10, // 28x36 boom graphic from the booms sheet
PIC_FULL = 11, // entire sheet graphic; number is the resource ID
PIC_MISSILE = 12, // 18x18 missile graphic from the missiles sheet
PIC_DLOG_LG = 13, // 72x72 dialog graphic from the dialog sheet
PIC_SCEN_LG = 14, // 64x64 scenario graphic (currently each is on its own sheet)
PIC_TER_MAP = 15, // 12x12 map graphic... or should it be 6x6?
PIC_STATUS = 16, // 12x12 status icon
PIC_MONST_WIDE = 23, // 56x36 monster graphic from the preset sheets, resized to fit and centred in a 28x36 space
PIC_MONST_TALL = 43, // 28x72 monster graphic from the preset sheets, resized to fit and centred in a 28x36 space
PIC_MONST_LG = 63, // 56x72 monster graphic from the preset sheets, resized to fit in a 28x36 space
PIC_CUSTOM_TER = 101, // 28x36 custom graphic from the custom sheets
PIC_CUSTOM_TER_ANIM = 102,
PIC_CUSTOM_MONST = 103,
PIC_CUSTOM_DLOG = 104, // 36x36 dialog graphic drawn from two 18x26 halves in the custom sheets
PIC_CUSTOM_TALK = 105, // 32x32 talking portrait drawn from two 16x32 halves in the custom sheets
PIC_CUSTOM_SCEN = 106, // 32x32 scenario portrait loading from scenname.exr/scenario.png
PIC_CUSTOM_ITEM = 107,
PIC_CUSTOM_FULL = 111, // entire sheet graphic, drawn from scenname.exr/sheetxxx.png where xxx is the number
PIC_CUSTOM_MISSILE = 112, // 18x18 missile graphic drawn from the the custom sheets
PIC_CUSTOM_DLOG_LG = 113, // 72x72 dialog graphic from the custom sheet, taken from 8 successive slots
PIC_CUSTOM_TER_MAP = 115, // 12x12 map graphic (should it be 6x6?) taken from the custom sheet
PIC_CUSTOM_MONST_WIDE = 123, // 56x36 monster graphic from the custom sheets, resized to fit and centred in a 28x36 space
PIC_CUSTOM_MONST_TALL = 143, // 28x72 monster graphic from the custom sheets, resized to fit and centred in a 28x36 space
PIC_CUSTOM_MONST_LG = 163, // 56x72 monster graphic from the custom sheets, resized to fit in a 28x36 space
PIC_PARTY_MONST = 203, // 28x36 graphic drawn from the savegame sheet
PIC_PARTY_SCEN = 206, // 32x32 graphic drawn from the scenario headers sheet
PIC_PARTY_ITEM = 207,
PIC_PARTY_PC = 208,
PIC_PARTY_MONST_WIDE = 223, // 56x36 monster graphic from the savegame sheet, resized to fit and centred in a 28x36 space
PIC_PARTY_MONST_TALL = 243, // 28x72 monster graphic from the savegame sheet, resized to fit and centred in a 28x36 space
PIC_PARTY_MONST_LG = 263, // 56x72 monster graphic from the savegame sheet, resized to fit in a 28x36 space
PIC_TER = 1, ///< 28x36 terrain graphic from the preset sheets
PIC_TER_ANIM = 2, ///< 28x36 terrain graphic from the preset animated terrain sheet
PIC_MONST = 3, ///< 28x36 monster graphic from the preset sheets
PIC_DLOG = 4, ///< 36x36 dialog graphic from the preset sheet
PIC_TALK = 5, ///< 32x32 talking portrait from the preset sheet
PIC_SCEN = 6, ///< 32x32 scenario graphic from the scenario sheet
PIC_ITEM = 7, ///< 28x36 item graphic from the large item sheet,
///< or 18x18 item graphic from the small sheet centred in a 28x36 space
PIC_PC = 8, ///< 28x36 pc graphic from the player sheet
PIC_FIELD = 9, ///< 28x36 field graphic from the fields sheet
PIC_BOOM = 10, ///< 28x36 boom graphic from the booms sheet
PIC_FULL = 11, ///< entire sheet graphic; number is the resource ID
PIC_MISSILE = 12, ///< 18x18 missile graphic from the missiles sheet
PIC_DLOG_LG = 13, ///< 72x72 dialog graphic from the dialog sheet
PIC_SCEN_LG = 14, ///< 64x64 scenario graphic (currently each is on its own sheet)
PIC_TER_MAP = 15, ///< 12x12 map graphic... or should it be 6x6?
PIC_STATUS = 16, ///< 12x12 status icon
PIC_MONST_WIDE = 23, ///< 56x36 monster graphic from the preset sheets, resized to fit and centred in a 28x36 space
PIC_MONST_TALL = 43, ///< 28x72 monster graphic from the preset sheets, resized to fit and centred in a 28x36 space
PIC_MONST_LG = 63, ///< 56x72 monster graphic from the preset sheets, resized to fit in a 28x36 space
PIC_CUSTOM_TER = 101, ///< 28x36 custom terrain graphic from the custom sheets
PIC_CUSTOM_TER_ANIM = 102, ///< 28x36 custom animated terrain graphic from the custom sheets
PIC_CUSTOM_MONST = 103, ///< 28x36 custom monster graphic from the custom sheets
PIC_CUSTOM_DLOG = 104, ///< 36x36 dialog graphic drawn from two 18x26 halves in the custom sheets
PIC_CUSTOM_TALK = 105, ///< 32x32 talking portrait drawn from two 16x32 halves in the custom sheets
PIC_CUSTOM_SCEN = 106, ///< 32x32 scenario portrait loading from scenname.exr/scenario.png
PIC_CUSTOM_ITEM = 107, ///< 28x36 custom item graphic from the custom sheets
PIC_CUSTOM_FULL = 111, ///< entire sheet graphic, drawn from scenname.exr/sheetxxx.png where xxx is the number
PIC_CUSTOM_MISSILE = 112, ///< 18x18 missile graphic drawn from the the custom sheets
PIC_CUSTOM_DLOG_LG = 113, ///< 72x72 dialog graphic from the custom sheet, taken from 8 successive slots
PIC_CUSTOM_TER_MAP = 115, ///< 12x12 map graphic (should it be 6x6?) taken from the custom sheet
PIC_CUSTOM_MONST_WIDE = 123,///< 56x36 monster graphic from the custom sheets, resized to fit and centred in a 28x36 space
PIC_CUSTOM_MONST_TALL = 143,///< 28x72 monster graphic from the custom sheets, resized to fit and centred in a 28x36 space
PIC_CUSTOM_MONST_LG = 163, ///< 56x72 monster graphic from the custom sheets, resized to fit in a 28x36 space
PIC_PARTY_MONST = 203, ///< 28x36 monster graphic drawn from the savegame sheet
PIC_PARTY_SCEN = 206, ///< 32x32 graphic drawn from the scenario headers sheet
PIC_PARTY_ITEM = 207, ///< 28x36 item graphic drawn from the savegame sheet
PIC_PARTY_PC = 208, ///< 28x36 PC graphic drawn from the savegame sheet
PIC_PARTY_MONST_WIDE = 223, ///< 56x36 monster graphic from the savegame sheet, resized to fit and centred in a 28x36 space
PIC_PARTY_MONST_TALL = 243, ///< 28x72 monster graphic from the savegame sheet, resized to fit and centred in a 28x36 space
PIC_PARTY_MONST_LG = 263, ///< 56x72 monster graphic from the savegame sheet, resized to fit in a 28x36 space
NUM_PIC_TYPES
};
/// Flags that modify icon types.
/// Can be added to or subtracted from ePicType enums, returning an ePicType.
enum ePicTypeMod {
// Can be added to or subtracted from ePicType enums, returning an ePicType.
PIC_PRESET = 0, // just for good measure
PIC_WIDE = 20, // if applied to any derivative of PIC_MONST, makes the x-dimension 2 instead of 1
PIC_TALL = 40, // if applied to any derivative of PIC_MONST, makes the y-dimension 2 instead of 1
PIC_LARGE = PIC_WIDE + PIC_TALL,
PIC_CUSTOM = 100, // if applied to any customizable graphic, makes it custom instead of preset
PIC_PARTY = 200, // similar to above
PIC_PRESET = 0, ///< No mod, included just for good measure; can be added to cancel out all mods.
PIC_WIDE = 20, ///< If applied to any derivative of PIC_MONST, makes the x-dimension 2 instead of 1.
PIC_TALL = 40, ///< If applied to any derivative of PIC_MONST, makes the y-dimension 2 instead of 1.
PIC_LARGE = PIC_WIDE + PIC_TALL, ///< A combination of PIC_WIDE and PIC_TALL.
PIC_CUSTOM = 100, ///< If applied to any customizable graphic, makes it custom instead of preset.
PIC_PARTY = 200, ///< If applies to any exportable graphic, makes it exported instead of preset.
};
/// Specifies a graphics sheet that icons are drawn from.
enum eSheetType {
SHEET_TER,
SHEET_TER_ANIM,
SHEET_MONST,
SHEET_DLOG,
SHEET_TALK,
SHEET_SCEN,
SHEET_SCEN_LG,
SHEET_ITEM,
SHEET_TINY_ITEM,
SHEET_PC,
SHEET_FIELD,
SHEET_BOOM,
SHEET_MISSILE,
SHEET_PARTY,
SHEET_HEADER,
SHEET_TER_MAP,
SHEET_FULL,
SHEET_STATUS,
SHEET_CUSTOM,
SHEET_TER, ///< The preset terrain sheets, terX.png
SHEET_TER_ANIM, ///< The animated terrains sheet, teranim.png
SHEET_MONST, ///< The preset monster sheets, monstX.png
SHEET_DLOG, ///< The preset dialog icons sheet, dlogpics.png
SHEET_TALK, ///< The preset talk icons sheet, talkportraits.png
SHEET_SCEN, ///< The preset scenario icons sheet, scenpics.png
SHEET_SCEN_LG, ///< The large scenario icons sheet, bigscenpics.png
SHEET_ITEM, ///< The preset large items sheet, objects.png
SHEET_TINY_ITEM,///< The small itesm sheet, tinyobj.png
SHEET_PC, ///< The PC graphics sheet, pcs.png
SHEET_FIELD, ///< The fields and objects sheet, fields.png
SHEET_BOOM, ///< The special effects sheet, booms.png
SHEET_MISSILE, ///< The missile animations sheet, missles.png
SHEET_PARTY, ///< The exported graphics sheet stored in the saved game
SHEET_HEADER, ///< The scenario header sheet
SHEET_TER_MAP, ///< The terrain map icons sheet, termap.png
SHEET_FULL, ///< Any full sheet
SHEET_STATUS, ///< The status icons sheet, staticons.png
SHEET_CUSTOM, ///< Any custom graphics sheet
// TODO: Vehicle sheet is missing.
// TODO: Documentation of full, custom, header, and exported sheets is still lacking.
NUM_SHEET_TYPES
};
/// A simple icon.
/// This control can also be made clickable.
class cPict : public cControl {
public:
/// @copydoc cDialog::init()
static void init();
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
@@ -104,16 +115,40 @@ public:
short getFormat(eFormat prop) throw(xUnsupportedProp);
void setColour(sf::Color clr) throw(xUnsupportedProp);
sf::Color getColour() throw(xUnsupportedProp);
/// @copydoc setPict(pic_num_t)
/// @param type The type of the new icon
/// @note If you change to a type with a different bounding rect,
/// you will need to separately update the bounding rect.
/// (The bounding rect is mostly ignored when drawing, so if the icon is opaque, the control is not clickable,
/// and there is no frame, you can usually safely skip this step.)
void setPict(pic_num_t num, ePicType type);
/// Set the pict's icon.
/// @param num The new icon index.
void setPict(pic_num_t num);
/// Get the current icon.
/// @return The number of the current icon.
pic_num_t getPicNum();
/// Get the current icon's type.
/// @return The type of the current icon.
ePicType getPicType();
/// Create a new icon.
/// @param parent The parent dialog.
explicit cPict(cDialog& parent);
/// Create a new icon without a parent dialog.
/// @param parent The parent window.
explicit cPict(sf::RenderWindow& parent);
bool isClickable();
/// Advance the current animation frame.
/// Should be called at predictable intervals if the dialog might contain an animated graphic.
static void advanceAnim();
virtual ~cPict();
void draw();
/// A utility function to draw an icon into an arbitrary window.
/// @param win The window to draw in.
/// @param dest The bounding rect to draw in (ignored for drawing the actual, but used for background fill and framing)
/// @param which_g The icon to draw.
/// @param type_g The type of icon to draw.
/// @param framed Whether to draw a frame around the icon.
static void drawAt(sf::RenderWindow& win, RECT dest, pic_num_t which_g, ePicType type_g, bool framed);
cPict& operator=(cPict& other) = delete;
cPict(cPict& other) = delete;
@@ -165,12 +200,43 @@ private:
click_callback_t onClick;
};
/// Apply a modifier to an icon type.
/// @param lhs The base icon type to modify.
/// @param rhs The modifier to apply.
/// @return The modified icon type.
/// @note As a special case, adding PIC_PRESET removes all modifiers.
ePicType operator + (ePicType lhs, ePicTypeMod rhs);
/// Remove a modifier from an icon type.
/// @param lhs The base icon type to modify.
/// @param rhs The modifier to remove.
/// @return The modified icon type.
ePicType operator - (ePicType lhs, ePicTypeMod rhs);
/// Apply a modifier to an icon type.
/// @param lhs The modifier to apply.
/// @param rhs The base icon type to modify.
/// @return The modified icon type.
/// @note As a special case, adding PIC_PRESET removes all modifiers.
ePicType operator + (ePicTypeMod lhs, ePicType rhs);
/// Remove a modifier from an icon type.
/// @param lhs The modifier to remove.
/// @param rhs The base icon type to modify.
/// @return The modified icon type.
ePicType operator - (ePicTypeMod lhs, ePicType rhs);
/// Apply a modifier to an icon type.
/// @param lhs The base icon type to modify.
/// @param rhs The modifier to apply.
/// @return lhs, now modified.
/// @note As a special case, adding PIC_PRESET removes all modifiers.
ePicType&operator +=(ePicType&lhs, ePicTypeMod rhs);
/// Remove a modifier from an icon type.
/// @param lhs The base icon type to modify.
/// @param rhs The modifier to remove.
/// @return lhs, now modified.
ePicType&operator -=(ePicType&lhs, ePicTypeMod rhs);
/// Check if an icon type has a modifier applied.
/// @param lhs The icon type to check.
/// @param rhs The modifier type to test for.
/// @return true if the modifier is present.
bool operator& (ePicType lhs, ePicTypeMod rhs);
#endif

View File

@@ -9,8 +9,14 @@
#ifndef BoE_scrollbar_h
#define BoE_scrollbar_h
/// @file
/// Scrollbar-related classes and types.
#include "control.h"
/// A simple vertical scrollbar.
/// This has no coupling with scrollable data; that must be handled externally by
/// using the methods to get the scrollbar's position.
class cScrollbar : public cControl {
int pos, max, pgsz;
enum {
@@ -23,8 +29,13 @@ class cScrollbar : public cControl {
click_callback_t onClick;
static sf::Texture scroll_gw;
public:
/// @copydoc cDialog::init()
static void init();
/// Create a new scrollbar without a parent dialog.
/// @param parent The parent window.
explicit cScrollbar(sf::RenderWindow& parent);
/// Create a new scrollbar.
/// @param parent The parent dialog.
explicit cScrollbar(cDialog& parent);
void attachClickHandler(click_callback_t f) throw(xHandlerNotSupported);
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
@@ -35,11 +46,29 @@ public:
void setColour(sf::Color clr) throw(xUnsupportedProp);
sf::Color getColour() throw(xUnsupportedProp);
bool isClickable();
/// Get the scrollbar thumb's current position.
/// @return The current position.
long getPosition();
/// Get the scrollbar thumb's maximum value.
/// @return The maximum value.
long getMaximum();
/// Get the scrollbar thumb's page size.
/// @return The page size.
///
/// The page size is the number of steps scrolled when a click is received
/// in the area between the arrow buttons and the scrollbar thumb.
long getPageSize();
/// Set the scrollbar thumb's current position.
/// @param to The current position.
void setPosition(long to);
/// Set the scrollbar thumb's maximum value.
/// @param to The maximum value.
void setMaximum(long to);
/// Set the scrollbar thumb's page size.
/// @param to The page size.
///
/// The page size is the number of steps scrolled when a click is received
/// in the area between the arrow buttons and the scrollbar thumb.
void setPageSize(long to);
void draw();
cScrollbar& operator=(cScrollbar& other) = delete;

1
osx/doxy/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
html/

2325
osx/doxy/Doxyfile Normal file

File diff suppressed because it is too large Load Diff

290
osx/doxy/mainpage.md Normal file
View File

@@ -0,0 +1,290 @@
Blades of Exile Documentation {#mainpage}
=============================
This is the documentation for parts of the Blades of Exile source code.
Currently it covers only the dialog engine.
Defining a Dialog
=================
Creating a new dialog consists of two basic steps: first, you have to
create the XML dialog definition, and then you need to write the code to
set it up and implement all the required callbacks.
The format of the XML dialog files is defined by the schema in
_rsrc/schemas/dialog.xsd_, but this document will cover what you need to
know in a more readable manner. A dialog definition consists of a
`<dialog>` tag containing any number of tags representing various dialog
controls. Each tag will be documented in some detail below.
Common Attributes
-----------------
The following attributes are allowed on all or most elements:
* `top`, `left`, `width`, `height` - Specifies the location and bounding
rect of the control within the dialog. All non-container controls
support these attributes, and in fact the `top` and `left` attributes
are required. Some controls may ignore the `width` and `height`
attributes.
* `def-key`, `key-mod` - Specifies the default keyboard shortcut for the
control. See **Keyboard Shortcuts** below for more information on the
format of these attributes.
* `font`, `size`, `color`, `colour` - Specifies text attributes of the
control. See **Text Formatting** below for details on accepted values.
* `name` - Give the control a unique identifier which you can use to
refer to it from the code. If omitted, the code will generate a random
identifier. All controls support this attribute.
* `fromlist` - Currently unused, but the intended use is to look up the
control's text value in a string list (in _rsrc/strings_)
The `<dialog>` tag
------------------
The `<dialog>` tag accepts the following attributes:
* `skin` - Specify the dialog's background pattern. Currently only
accepts `dark` or `light`. If omitted, a default is used which depends
on whether the dialog is used in the game or the scenario editor. As
such, this attribute should be omitted for most dialogs.
* `debug` - This attribute is completely ignored by the game, but if set
to `true`, the XSL stylesheet will draw the bounding rects of LEDs and
other debug information.
* `fore` - The default text colour. Generally this shouldn't be needed.
* `defbtn` - The ID (`name` attribute) of the default button. This is an
IDREF, so it must exist in the dialog.
The `<text>` tag
----------------
The `<text>` tag can be used either for a non-editable text message or
for a frame to group elements. Within a `<text>` tag, you can use a
`<br>` tag to insert a line break. See **Whitespace** for an explanation
of the intended whitespace collapsing behaviour.
The `<text>` tag accepts the following attributes:
* `framed` - Specifies whether a frame is drawn around the text. Can be
either `true` or `false`; defaults to `false`.
* `clickable` - Specifies that the text is clickable. This attribute is
useless, as clickability is determined solely by having a click handler
set in the code.
* `fromlist`, `font`, `size`, `color`, `colour`, `def-key`, `key-mod` -
See **Common Attributes** above.
The `<button>` tag
------------------
The `<button>` tag decribes a non-LED button. It can contain label text
as well as an optional empty `<key>` element. It does not support the
`<br>` tag. The `<key>` element was intended as a way of inserting a
readable form of the button's keyboard shortcut, but at present this is
unimplemented.
The `<button>` tag accepts the following attributes:
* `name` - This attribute is required on the `<button>` tag. See
**Common Attributes** above.
* `type` - Specifies the type of button. This attribute is required.
* `wrap` - Specifies whether to wrap the text on the button. Can be
either `true` or `false`; defaults to `false`.
* `fromlist`, `def-key`, `key-mod` - See **Common Attributes** above.
The possible values for the `type` attribute are:
* `small` - A small 23x23 button.
* `regular` - A normal-sized 63x23 button.
* `large` - A large 102x23 button.
* `help` - A small 16x13 help button - a white bubble with a ? mark.
* `left` - A normal-sized 63x23 button with a left-pointing arrow.
* `right` - A normal-sized 63x23 button with a right-pointing arrow.
* `up` - A normal-sized 63x23 button with an up-pointing arrow.
* `down` - A normal-sized 63x23 button with a down-pointing arrow.
* `tiny` - A tiny 14x10 button, same size as an LED.
* `done` - A normal-sized 63x23 button with "Done" on it.
* `tall` - A tall 63x40 button.
* `trait` - A tall 63x40 button with "Race Good/Bad Traits" on it.
* `push` - A round red 30x30 push button.
(Naturally, they correspond perfectly with the values of the eBtnType
enumeration.)
The `<led>` tag
---------------
The `<led>` tag descripts an LED button. It can contain label text,
which is drawn to the right of the button graphic. This differs from
normal practice in the original Blades of Exile dialog engine, where LED
labels were typically left-aligned to the _left_ of their associated
LED. I've chosen to make this change because I feel it is easier to see
which LED a label is associated to, and because the behaviour is more
similar to the checkboxes and radio buttons found in normal GUIs.
The `<led>` tag accepts the following attributes:
* `name` - This attribute is required on the `<led>` tag. See **Common
Attributes** above.
* `state` - Specifies the starting state of the LED. Can be one of
`red`, `green`, or `off`; defaults to `off`.
* `font`, `size`, `color`, `colour` - See **Common Attributes** above.
The `<group>` tag
-----------------
The `<group>` tag defines an LED group, a collection of LEDs that behave
like radio buttons rather than checkboxes. The tag can contain any
number of `<led>` elements.
The `<group>` tag accepts the following attributes:
* `fromlist` - See **Common Attributes** above. I don't remember exactly
how this would have applied to an LED group though; perhaps it would use
the string list to assign labels to its component LEDs in order of
declaration?
The `<pict>` tag
----------------
The `<pict>` tag defines a dialog picture. This covers a wide range of
things, from large pictures to small icons.
The `<pict>` tag accepts the following attributes:
* `type` - Specifies the type of graphic. This attribute is required.
* `num` - Specifies the graphic number. This attribute is required.
* `clickable` - Specifies that the picture is clickable. This attribute
is useless, as clickability is determined solely by having a click
handler set in the code.
* `custom` - Specifies whether the picture is custom or preset. Can be
either `true` or `false`; defaults to `false`.
* `framed` - Specifies whether a frame is drawn around the picture. Can
be either `true` or `false`; defaults to `true`.
* `size` - For certain types of graphics, this provides an additional
hint. Can be one of `small`, `wide`, `tall`, or `large`.
* `def-key`, `key-mod` - See **Common Attributes** above.
The possible values for the `type` attribute are:
* `blank` - Draw no graphic, just fill the bounding rect with black.
* `ter` - A terrain graphic.
* `teranim` - An animated terrain graphic.
* `monst` - A monster graphic. The `size` attribute can be set to any of
its four accepted values to indicate the size of the monster.
* `dlog` - A dialog graphic. The `size` attribute can be `small` (the
default) or `large`.
* `talk` - A conversation graphic.
* `scen` - A scenario icon. The `size` attribute can be `small` (the
default) or `large`.
* `item` - An item graphic.
* `pc` - A PC graphic.
* `field` - A field graphic.
* `boom` - A boom graphic.
* `missile` - A missile graphic.
* `map` - A map graphic.
* `status` - A status icon.
* `full` - A full sheet. With this value and with `custom` left at
`false`, the `num` parameter must be one of the following:
* 1100 - The inventory help frame.
* 1200 - The stats area help frame.
* 1300 - The action points help fram.
* 1400 - The outdoor toolbar help frame.
* 1401 - The combat toolbar help frame.
* 1402 - The town toolbar help frame.
* 1500 - The stat icons help frame.
The `<field>` tag
-----------------
The `<field>` tag defines an editable text field. It can contain default
text as its contents, but does not support the `<br>` tag.
The `<field>` tag accepts the following attributes:
* `type` - Specifies the input type of the field. Can be one of `text`,
`int`, `uint`, or `real`; defaults to `text`.
* `tab-order` - Specifies the tab order of the field. This must be an
integer that is unique in the dialog.
The `<stack>` tag
-----------------
The `<stack>` tag is currently unimplemented. Trying to load a dialog
that contains it will crash the game.
Keyboard Shortcuts
------------------
Keyboard shortcuts are specified with a pair of attributes.
The `def-key` attribute specifies the main key that triggers the
control. It can take any of the following values:
* A single digit
* A lowercase letter
* One of the following special characters:
` - = [ ] \ ; ' , . /
* `left` - The left arrow key
* `right` - The right arrow key
* `up` - The up arrow key
* `down` - The down arrow key
* `esc` - The escape key
* `enter` - The enter key.
* `return` - The enter key. (Note: Theoretically, `enter` should be
numpad enter while this is normal enter; I don't think this distinction
is implemented though.)
* `tab` - The tab key.
* `help` - The help key (on keyboards that have one) or the F1 key.
* `space` - The space key.
* `none` - No key shortcut (the default).
The `key-mod` attribute contains a space-separated list of any of the
following values:
* `ctrl` - The primary accelerator key (either control or command).
* `shift` - The shift key
* `alt` - The alt or option key
Text Formatting
---------------
Text formatting options in dialogs are actually quite limited. There are
only three possible attributes, with a very limited number of possible
values.
* `font` - This attribute can take one of the following values: `plain`,
`bold`, `dungeon`, `maidenword`. It defaults to `bold`. The latter two
options are fantasy-style scripts such as that used for the conversation
screen.
* `size` - Although the dialog engine supports any font size, the XML
specification simplifies it to three keywords: `small`, `large`, and
`title`, representing 10pt, 12pt, and 18pt font, respectively.
* `color` or `colour` - This is the only truly unrestricted attribute,
accepting any HTML colour code. It understands three-digit hex codes (eg
`#333`, which is equivalent to `#333333`), six-digit hex codes, and the
sixteen standard HTML colour names. Both the British and American
spelling are supported for the attribute name.
Whitespace
----------
Whitespace collapse rules within Dialog XML elements are a little weird.
All tabs are stripped out, and then runs of newlines are replaced with a
single space, but runs of spaces are left as-is.
Note: Currently, the runs of newlines are simply removed rather than
replaced with a space. This needs to be fixed.
Implementing a Dialog
=====================
Once the dialog is defined, it needs to be implemented! This consists of
a few steps - construct the dialog, attach handlers, possibly populate
the dialog's fields and other dynamic elements according to whatever the
dialog is supposed to display, and then run the dialog.
Use of `std::bind` for attaching the handlers is encouraged, and can be
used in conjunction with `std::ref` to provide state for the dialog.
Lambda expressions may also be useful for some of the simpler handlers.
Use of `dynamic_cast` will be required when dealing with LEDs or icons.