267 lines
12 KiB
C++
267 lines
12 KiB
C++
/*
|
|
* dialog.h
|
|
* BoE
|
|
*
|
|
* Created by Celtic Minstrel on 11/05/09.
|
|
*
|
|
*/
|
|
|
|
#ifndef DIALOG_H
|
|
#define DIALOG_H
|
|
|
|
/// @file
|
|
/// Dialog-related classes and types.
|
|
|
|
#include <SFML/Graphics.hpp>
|
|
|
|
#include <string>
|
|
#include <map>
|
|
#include <vector>
|
|
#include <exception>
|
|
|
|
#include "ticpp.h"
|
|
#include "dialog.keys.h"
|
|
#include "location.h"
|
|
#include <boost/any.hpp>
|
|
|
|
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;
|
|
short bg;
|
|
sf::Color defTextClr;
|
|
template<class T> std::pair<std::string,T*> parse(ticpp::Element& who);
|
|
sf::Color parseColor(std::string what);
|
|
cKey parseKey(std::string what);
|
|
sf::RenderWindow win;
|
|
std::string currentFocus;
|
|
cDialog* parent;
|
|
void loadFromFile(std::string path);
|
|
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();
|
|
/// 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;
|
|
/// 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
|
|
/// 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, rectangle 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)
|
|
/// @note Even if it returns false, the label has been attached (ie, the existing label was updated).
|
|
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;
|
|
}
|
|
/// Iterate through all the controls in the dialog.
|
|
/// @param callback A function taking a string as its first argument
|
|
/// and a control reference as its second argument.
|
|
template<typename Fcn> void forEach(Fcn callback) {
|
|
for(auto ctrl : controls) {
|
|
callback(ctrl.first, *ctrl.second);
|
|
}
|
|
}
|
|
/// 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();
|
|
/// 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
|
|
/// @note The dialog is not actually closed immediately;
|
|
/// instead, a flag is set that triggers the event loop to end and the dialog to close.
|
|
///
|
|
/// 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);
|
|
/// Reopen the dialog after closing it.
|
|
/// This is meant to be called from within an event handler to reverse a previous call to toast();
|
|
/// if you're already out of the dialog's event loop, you should instead call run() to reopen it.
|
|
void untoast();
|
|
/// 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.
|
|
rectangle getBounds() {return winRect;}
|
|
/// Sets whether to animate graphics in dialogs.
|
|
static bool doAnimations;
|
|
cDialog& operator=(cDialog& other) = delete;
|
|
cDialog(cDialog& other) = delete;
|
|
private:
|
|
void draw();
|
|
std::string process_keystroke(cKey keyHit);
|
|
std::string process_click(location where);
|
|
bool dialogNotToast;
|
|
rectangle winRect;
|
|
std::string defaultButton;
|
|
boost::any result;
|
|
std::string fname;
|
|
sf::Clock animTimer, paintTimer;
|
|
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();
|
|
};
|
|
|
|
#endif
|