Refactor dialog parsing so each control knows how to parse itself

This commit is contained in:
2015-10-02 15:20:32 -04:00
parent a515bd0b0e
commit 22e63d898f
15 changed files with 688 additions and 683 deletions

View File

@@ -50,8 +50,8 @@ cButton::cButton(cDialog& parent) :
textClr(parent.getDefTextClr()),
fromList("none") {}
cButton::cButton(cDialog* parent,eControlType t) :
cControl(t,*parent),
cButton::cButton(cDialog& parent,eControlType t) :
cControl(t,parent),
fromList("none"),
wrapLabel(false) {/* This constructor is only called for LEDs. */}
@@ -116,6 +116,162 @@ sf::Color cButton::getColour() throw(xUnsupportedProp) {
return textClr;
}
std::string cButton::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
Iterator<Node> node;
std::string name, id;
int width = 0, height = 0;
bool foundType = false, foundTop = false, foundLeft = false; // required attributes
bool foundKey = false;
std::string keyMod, keyMain;
int keyModRow, keyModCol, keyMainRow, keyMainCol;
rectangle frame;
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
else if(name == "wrap"){
std::string val;
attr->GetValue(&val);
if(val == "true") setFormat(TXT_WRAP, true);
}else if(name == "type"){
std::string val;
foundType = true;
attr->GetValue(&val);
if(val == "small")
setBtnType(BTN_SM);
else if(val == "regular")
setBtnType(BTN_REG);
else if(val == "large")
setBtnType(BTN_LG);
else if(val == "help")
setBtnType(BTN_HELP);
else if(val == "left")
setBtnType(BTN_LEFT);
else if(val == "right")
setBtnType(BTN_RIGHT);
else if(val == "up")
setBtnType(BTN_UP);
else if(val == "down")
setBtnType(BTN_DOWN);
else if(val == "tiny")
setBtnType(BTN_TINY);
else if(val == "done")
setBtnType(BTN_DONE);
else if(val == "tall")
setBtnType(BTN_TALL);
else if(val == "trait")
setBtnType(BTN_TRAIT);
else if(val == "push")
setBtnType(BTN_PUSH);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("button",name,val,attr->Row(),attr->Column(),fname);
}
setColour(clr);
}else if(name == "def-key"){
attr->GetValue(&keyMain);
foundKey = true;
keyMainRow = attr->Row();
keyMainCol = attr->Column();
}else if(name == "key-mod"){
attr->GetValue(&keyMod);
foundKey = true;
keyModRow = attr->Row();
keyModCol = attr->Column();
// }else if(name == "fromlist"){
// attr->GetValue(&fromList);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else throw xBadAttr("button",name,attr->Row(),attr->Column(),fname);
}
if(parent->getBg() == cDialog::BG_DARK && getBtnType() == BTN_TINY)
setColour(sf::Color::White);
if(!foundType) throw xMissingAttr("button","type",who.Row(),who.Column(),fname);
if(!foundTop) throw xMissingAttr("button","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("button","left",who.Row(),who.Column(),fname);
if(foundKey) {
cKey theKey;
try{
theKey = parseKey(keyMod + " " + keyMain);
}catch(int){
try {
theKey = parseKey(keyMain);
}catch(int){
throw xBadVal("button","def-key",keyMain,keyMainRow,keyMainCol,fname);
}
throw xBadVal("button","key-mod",keyMod,keyModRow,keyModCol,fname);
}
attachKey(theKey);
}
switch(getBtnType()){
case BTN_SM:
frame.right = frame.left + 23;
frame.bottom = frame.top + 23;
break;
case BTN_LG:
frame.right = frame.left + 102;
frame.bottom = frame.top + 23;
break;
case BTN_HELP:
frame.right = frame.left + 16;
frame.bottom = frame.top + 13;
break;
case BTN_TINY:
case BTN_LED: // this should never happen
frame.right = frame.left + 14;
frame.bottom = frame.top + 10;
break;
case BTN_TALL:
case BTN_TRAIT:
frame.right = frame.left + 63;
frame.bottom = frame.top + 40;
break;
case BTN_PUSH:
frame.right = frame.left + 30;
frame.bottom = frame.top + 30;
break;
default:
frame.right = frame.left + 63;
frame.bottom = frame.top + 23;
}
if(width > 0)
frame.right = frame.left + width;
if(height > 0)
frame.bottom = frame.top + height;
setBounds(frame);
std::string content;
for(node = node.begin(&who); node != node.end(); node++){
std::string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::ELEMENT && val == "key"){
// TODO: There's surely a better way to do this
if(content.length() > 0) throw xBadVal("button",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
// labelWithKey = true;
}else if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("button",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
}
setText(content);
return id;
}
// Indices within the buttons array.
size_t cButton::btnGW[14] = {
0, // BTN_SM
@@ -190,7 +346,7 @@ void cLed::init(){
}
}
cLed::cLed(cDialog* parent) :
cLed::cLed(cDialog& parent) :
cButton(parent,CTRL_LED),
state(led_off),
textFont(FONT_BOLD),
@@ -282,8 +438,8 @@ void cLed::restore(storage_t to) {
else setState(led_off);
}
cLedGroup::cLedGroup(cDialog* parent) :
cControl(CTRL_GROUP,*parent),
cLedGroup::cLedGroup(cDialog& parent) :
cControl(CTRL_GROUP,parent),
fromList("none") {}
cButton::~cButton() {}
@@ -332,6 +488,106 @@ eLedState cLed::getState(){
return state;
}
std::string cLed::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
Iterator<Node> node;
std::string name, id;
int width = 0, height = 0;
bool foundTop = false, foundLeft = false; // requireds
rectangle frame;
if(parent->getBg() == cDialog::BG_DARK)
setColour(sf::Color::White);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
else if(name == "state"){
std::string val;
attr->GetValue(&val);
if(val == "red") setState(led_red);
else if(val == "green") setState(led_green);
else if(val == "off") setState(led_off);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
// }else if(name == "fromlist"){
// attr->GetValue(&fromList);
}else if(name == "font"){
std::string val;
attr->GetValue(&val);
if(val == "dungeon")
setFormat(TXT_FONT, FONT_DUNGEON);
else if(val == "plain")
setFormat(TXT_FONT, FONT_PLAIN);
else if(val == "bold")
setFormat(TXT_FONT, FONT_BOLD);
else if(val == "maidenword")
setFormat(TXT_FONT, FONT_MAIDWORD);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
if(val == "large")
setFormat(TXT_SIZE, 12);
else if(val == "small")
setFormat(TXT_SIZE, 10);
else if(val == "title")
setFormat(TXT_SIZE, 18);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}
setColour(clr);
} else if(name == "wrap") {
std::string val;
attr->GetValue(&val);
if(val == "true")
setFormat(TXT_WRAP, true);
else setFormat(TXT_WRAP, false);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else throw xBadAttr("led",name,attr->Row(),attr->Column(),fname);
}
if(!foundTop) throw xMissingAttr("led","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("led","left",who.Row(),who.Column(),fname);
if(width > 0) {
frame.right = frame.left + width;
}else{
frame.right = frame.left + 14;
}
if(height > 0) {
frame.bottom = frame.top + height;
}else{
frame.bottom = frame.top + 10;
}
setBounds(frame);
std::string content;
for(node = node.begin(&who); node != node.end(); node++){
std::string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("led",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
}
}
setText(content);
return id;
}
void cLedGroup::addChoice(cLed* ctrl, std::string key) {
choices[key] = ctrl;
if(ctrl->getState() != led_off)
@@ -553,3 +809,32 @@ void cLedGroup::restore(storage_t to) {
setSelected(boost::any_cast<std::string>(to["led-select"]));
else setSelected("");
}
std::string cLedGroup::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
Iterator<Element> node;
std::string name, id;
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
// else if(name == "fromlist")
// attr->GetValue(&fromList);
else throw xBadAttr("group",name,attr->Row(),attr->Column(),fname);
}
for(node = node.begin(&who); node != node.end(); node++){
std::string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::ELEMENT && val == "led"){
auto led = parent->parse<cLed>(*node);
addChoice(led.second, led.first);
}else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("group",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
}
recalcRect();
return id;
}

View File

@@ -50,6 +50,7 @@ class cButton : public cControl {
public:
/// @copydoc cDialog::init()
static void init();
std::string parse(ticpp::Element& who, std::string fname);
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);
@@ -83,7 +84,7 @@ protected:
/// 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);
cButton(cDialog& parent,eControlType t);
private:
bool labelWithKey;
std::string fromList;
@@ -111,6 +112,7 @@ public:
/// default toggle-selected action of an LED.
/// @return true to indicate the event should continue.
static bool noAction(cDialog&,std::string,eKeyMod) {return true;}
std::string parse(ticpp::Element& who, std::string fname);
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw();
bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);
@@ -121,7 +123,7 @@ public:
void restore(storage_t to);
/// Create a new LED button.
/// @param parent The parent dialog.
explicit cLed(cDialog* parent);
explicit cLed(cDialog& parent);
virtual ~cLed();
/// Set the LED's current state,.
/// @param to The new state.
@@ -169,6 +171,7 @@ class cLedGroup : public cControl {
cLedGroup& operator=(cLedGroup& other) = delete;
cLedGroup(cLedGroup& other) = delete;
public:
std::string parse(ticpp::Element& who, std::string fname);
/// @copydoc cControl::attachClickHandler()
///
/// The click handler is called whenever an LED in the group is clicked, even if it's the currently selected LED.
@@ -209,7 +212,7 @@ public:
sf::Color getColour() throw(xUnsupportedProp);
/// Create a new LED group.
/// @param parent The parent dialog.
explicit cLedGroup(cDialog* parent);
explicit cLedGroup(cDialog& parent);
bool isClickable();
bool handleClick(location where);
virtual ~cLedGroup();

View File

@@ -86,9 +86,14 @@ public:
/// 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.
///
/// All control subclasses must have a constructor that takes a single cDialog& parameter,
/// in order for the parsing template to work.
class cControl {
public:
using storage_t = std::map<std::string, boost::any>;
/// Parses the control from an XML element
virtual std::string parse(ticpp::Element& who, std::string fname) = 0;
/// 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);
@@ -226,6 +231,16 @@ public:
cControl& operator=(cControl& other) = delete;
cControl(cControl& other) = delete;
protected:
/// Parses an HTML colour code.
/// Recognizes three-digit hex, six-digit hex, and HTML colour names.
/// @param code The colour code to parse.
static sf::Color parseColor(std::string code);
/// Parses a key code.
/// @param what The code to parse.
static cKey parseKey(std::string what);
/// Filters newlines and tabs from a string, leaving spaces intact.
/// @param toFilter The string to filter.
static std::string dlogStringFilter(std::string toFilter);
/// The parent dialog of the control.
/// May be null, if the control was created via cControl(eControlType,sf::RenderWindow&).
cDialog* parent;
@@ -253,6 +268,7 @@ protected:
/// Intended to be called from handleClick(), where there is usually a minor event loop happening.
void redraw();
private:
friend class cDialog; // TODO: This is only so it can access parseColour... hack!
eControlType type;
};

View File

@@ -33,7 +33,7 @@ const short cDialog::BG_DARK = 5, cDialog::BG_LIGHT = 16;
short cDialog::defaultBackground = cDialog::BG_DARK;
cDialog* cDialog::topWindow = nullptr;
static std::string generateRandomString(){
std::string cDialog::generateRandomString(){
// Not bothering to seed, because it doesn't actually matter if it's truly random.
// Though, this will be called after srand() is called in main() anyway.
int n_chars = rand() % 100;
@@ -45,144 +45,7 @@ static std::string generateRandomString(){
return s;
}
template<> pair<string,cPict*> cDialog::parse(Element& who /*pict*/){
std::pair<std::string,cPict*> p;
Iterator<Attribute> attr;
std::string name;
ePicType type;
bool wide = false, tall = false, custom = false, tiny = false;
bool foundTop = false, foundLeft = false, foundType = false, foundNum = false; // required attributes
rectangle frame;
int width = 0, height = 0;
p.second = new cPict(*this);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
else if(name == "type"){
std::string val;
foundType = true;
attr->GetValue(&val);
if(val == "blank"){
p.second->setPict(cPict::BLANK, PIC_TER);
foundNum = true;
continue;
}else if(val == "ter")
type = PIC_TER;
else if(val == "teranim")
type = PIC_TER_ANIM;
else if(val == "monst")
type = PIC_MONST;
else if(val == "dlog")
type = PIC_DLOG;
else if(val == "talk")
type = PIC_TALK;
else if(val == "scen")
type = PIC_SCEN;
else if(val == "item")
type = PIC_ITEM;
else if(val == "pc")
type = PIC_PC;
else if(val == "field")
type = PIC_FIELD;
else if(val == "boom")
type = PIC_BOOM;
else if(val == "missile")
type = PIC_MISSILE;
else if(val == "full")
type = PIC_FULL;
else if(val == "map")
type = PIC_TER_MAP;
else if(val == "status")
type = PIC_STATUS;
else throw xBadVal("pict",name,val,attr->Row(),attr->Column(),fname);
if(foundNum) {
pic_num_t wasPic = p.second->getPicNum();
p.second->setPict(wasPic, type);
}
}else if(name == "custom"){
std::string val;
attr->GetValue(&val);
if(val == "true") custom = true;
}else if(name == "scaled"){
std::string val;
attr->GetValue(&val);
if(val == "true") p.second->setFormat(TXT_WRAP, false);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
if(val == "wide") wide = true;
else if(val == "tall") tall = true;
else if(val == "large") wide = tall = true;
else if(val == "small") tiny = true;
else throw xBadVal("pict",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "def-key"){
std::string val;
attr->GetValue(&val);
// TODO: The modifiers are now in key-mod, so this needs to be updated
try{
p.second->attachKey(parseKey(val));
}catch(int){
throw xBadVal("pict",name,val,attr->Row(),attr->Column(),fname);
}
}else if(name == "num"){
pic_num_t newPic;
attr->GetValue(&newPic), foundNum = true;
if(foundType) p.second->setPict(newPic, type);
else p.second->setPict(newPic);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else if(name == "framed"){
std::string val;
attr->GetValue(&val);
if(val == "true") p.second->setFormat(TXT_FRAME, true);
else p.second->setFormat(TXT_FRAME, false);
}else throw xBadAttr("pict",name,attr->Row(),attr->Column(),fname);
}
if(!foundType) throw xMissingAttr("pict","type",who.Row(),who.Column(),fname);
if(!foundNum) throw xMissingAttr("pict","num",who.Row(),who.Column(),fname);
if(!foundTop) throw xMissingAttr("pict","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("pict","left",who.Row(),who.Column(),fname);
if(wide || tall) {
pic_num_t wasPic = p.second->getPicNum();
if(wide && !tall && p.second->getPicType() == PIC_MONST) p.second->setPict(wasPic, PIC_MONST_WIDE);
else if(!wide && tall && p.second->getPicType() == PIC_MONST) p.second->setPict(wasPic, PIC_MONST_TALL);
else if(wide && tall){
if(p.second->getPicType() == PIC_MONST) p.second->setPict(wasPic, PIC_MONST_LG);
else if(p.second->getPicType() == PIC_SCEN) p.second->setPict(wasPic, PIC_SCEN_LG);
else if(p.second->getPicType() == PIC_DLOG) p.second->setPict(wasPic, PIC_DLOG_LG);
}
} else if(tiny && type == PIC_ITEM) {
pic_num_t wasPic = p.second->getPicNum();
p.second->setPict(wasPic, PIC_TINY_ITEM);
}
frame.right = frame.left;
frame.bottom = frame.top;
if(width > 0 || height > 0 || p.second->getPicType() == PIC_FULL){
frame.right = frame.left + width;
frame.bottom = frame.top + height;
}
p.second->setBounds(frame);
pic_num_t wasPic = p.second->getPicNum();
if(custom) {
p.second->setPict(wasPic, p.second->getPicType() + PIC_CUSTOM);
} else p.second->setPict(wasPic, p.second->getPicType());
// The above line also sets the graphic's bounding rect, if necessary
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
static string dlogStringFilter(string toFilter) {
string cControl::dlogStringFilter(string toFilter) {
string filtered;
bool found_nl = false;
for(char c : toFilter) {
@@ -196,108 +59,7 @@ static string dlogStringFilter(string toFilter) {
return filtered;
}
template<> pair<string,cTextMsg*> cDialog::parse(Element& who /*text*/){
pair<string,cTextMsg*> p;
Iterator<Attribute> attr;
Iterator<Node> node;
string name;
int width = 0, height = 0;
bool foundTop = false, foundLeft = false; // top and left are required attributes
rectangle frame;
p.second = new cTextMsg(*this);
if(bg == BG_DARK) p.second->setColour(sf::Color::White);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
else if(name == "framed"){
std::string val;
attr->GetValue(&val);
if(val == "true") p.second->setFormat(TXT_FRAME, true);
}else if(name == "font"){
std::string val;
attr->GetValue(&val);
if(val == "dungeon")
p.second->setFormat(TXT_FONT, FONT_DUNGEON);
else if(val == "plain")
p.second->setFormat(TXT_FONT, FONT_PLAIN);
else if(val == "bold")
p.second->setFormat(TXT_FONT, FONT_BOLD);
else if(val == "maidenword")
p.second->setFormat(TXT_FONT, FONT_MAIDWORD);
else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
if(val == "large")
p.second->setFormat(TXT_SIZE, 12);
else if(val == "small")
p.second->setFormat(TXT_SIZE, 10);
else if(val == "title")
p.second->setFormat(TXT_SIZE, 18);
else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}
p.second->setColour(clr);
}else if(name == "def-key"){
std::string val;
attr->GetValue(&val);
try{
p.second->attachKey(parseKey(val));
}catch(int){
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
// }else if(name == "fromlist"){
// attr->GetValue(&p.second->fromList);
}else throw xBadAttr("text",name,attr->Row(),attr->Column(),fname);
}
if(!foundTop) throw xMissingAttr("text","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("text","left",who.Row(),who.Column(),fname);
frame.right = frame.left + width;
frame.bottom = frame.top + height;
p.second->setBounds(frame);
string content;
for(node = node.begin(&who); node != node.end(); node++){
string val;
int type = node->Type();
node->GetValue(&val);
// TODO: De-magic the | character
if(type == TiXmlNode::ELEMENT && val == "br") content += '|'; // because vertical bar is replaced by a newline when drawing strings
else if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("text",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
}
}
p.second->setText(content);
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
/**
* Parses an HTML-style colour string, recognizing three-digit hex, six-digit hex, and HTML colour names.
*/
sf::Color cDialog::parseColor(string what){
sf::Color cControl::parseColor(string what){
sf::Color clr;
if(what[0] == '#'){
unsigned int r,g,b;
@@ -347,168 +109,7 @@ sf::Color cDialog::parseColor(string what){
return clr;
}
template<> pair<string,cButton*> cDialog::parse(Element& who /*button*/){
pair<string,cButton*> p;
Iterator<Attribute> attr;
Iterator<Node> node;
string name;
int width = 0, height = 0;
bool foundType = false, foundTop = false, foundLeft = false; // required attributes
bool foundKey = false;
std::string keyMod, keyMain;
int keyModRow, keyModCol, keyMainRow, keyMainCol;
rectangle frame;
p.second = new cButton(*this);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
else if(name == "wrap"){
std::string val;
attr->GetValue(&val);
if(val == "true") p.second->setFormat(TXT_WRAP, true);
}else if(name == "type"){
std::string val;
foundType = true;
attr->GetValue(&val);
if(val == "small")
p.second->setBtnType(BTN_SM);
else if(val == "regular")
p.second->setBtnType(BTN_REG);
else if(val == "large")
p.second->setBtnType(BTN_LG);
else if(val == "help")
p.second->setBtnType(BTN_HELP);
else if(val == "left")
p.second->setBtnType(BTN_LEFT);
else if(val == "right")
p.second->setBtnType(BTN_RIGHT);
else if(val == "up")
p.second->setBtnType(BTN_UP);
else if(val == "down")
p.second->setBtnType(BTN_DOWN);
else if(val == "tiny")
p.second->setBtnType(BTN_TINY);
else if(val == "done")
p.second->setBtnType(BTN_DONE);
else if(val == "tall")
p.second->setBtnType(BTN_TALL);
else if(val == "trait")
p.second->setBtnType(BTN_TRAIT);
else if(val == "push")
p.second->setBtnType(BTN_PUSH);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("button",name,val,attr->Row(),attr->Column(),fname);
}
p.second->setColour(clr);
}else if(name == "def-key"){
attr->GetValue(&keyMain);
foundKey = true;
keyMainRow = attr->Row();
keyMainCol = attr->Column();
}else if(name == "key-mod"){
attr->GetValue(&keyMod);
foundKey = true;
keyModRow = attr->Row();
keyModCol = attr->Column();
// }else if(name == "fromlist"){
// attr->GetValue(&p.second->fromList);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else throw xBadAttr("button",name,attr->Row(),attr->Column(),fname);
}
if(bg == BG_DARK && p.second->getBtnType() == BTN_TINY) p.second->setColour(sf::Color::White);
if(!foundType) throw xMissingAttr("button","type",who.Row(),who.Column(),fname);
if(!foundTop) throw xMissingAttr("button","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("button","left",who.Row(),who.Column(),fname);
if(foundKey) {
cKey theKey;
try{
theKey = parseKey(keyMod + " " + keyMain);
}catch(int){
try {
theKey = parseKey(keyMain);
}catch(int){
throw xBadVal("button","def-key",keyMain,keyMainRow,keyMainCol,fname);
}
throw xBadVal("button","key-mod",keyMod,keyModRow,keyModCol,fname);
}
p.second->attachKey(theKey);
}
switch(p.second->getBtnType()){
case BTN_SM:
frame.right = frame.left + 23;
frame.bottom = frame.top + 23;
break;
case BTN_LG:
frame.right = frame.left + 102;
frame.bottom = frame.top + 23;
break;
case BTN_HELP:
frame.right = frame.left + 16;
frame.bottom = frame.top + 13;
break;
case BTN_TINY:
case BTN_LED: // this should never happen
frame.right = frame.left + 14;
frame.bottom = frame.top + 10;
break;
case BTN_TALL:
case BTN_TRAIT:
frame.right = frame.left + 63;
frame.bottom = frame.top + 40;
break;
case BTN_PUSH:
frame.right = frame.left + 30;
frame.bottom = frame.top + 30;
break;
default:
frame.right = frame.left + 63;
frame.bottom = frame.top + 23;
}
if(width > 0)
frame.right = frame.left + width;
if(height > 0)
frame.bottom = frame.top + height;
p.second->setBounds(frame);
string content;
for(node = node.begin(&who); node != node.end(); node++){
string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::ELEMENT && val == "key"){
// TODO: There's surely a better way to do this
if(content.length() > 0) throw xBadVal("button",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
// p.second->labelWithKey = true;
}else if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("button",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
}
p.second->setText(content);
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
cKey cDialog::parseKey(string what){
cKey cControl::parseKey(string what){
cKey key;
key.spec = false;
key.c = 0;
@@ -564,271 +165,6 @@ cKey cDialog::parseKey(string what){
return key;
}
template<> pair<string,cLed*> cDialog::parse(Element& who /*LED*/){
pair<string,cLed*> p;
Iterator<Attribute> attr;
Iterator<Node> node;
string name;
int width = 0, height = 0;
bool foundTop = false, foundLeft = false; // requireds
rectangle frame;
p.second = new cLed(this);
if(bg == BG_DARK) p.second->setColour(sf::Color::White);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
else if(name == "state"){
std::string val;
attr->GetValue(&val);
if(val == "red") p.second->setState(led_red);
else if(val == "green") p.second->setState(led_green);
else if(val == "off") p.second->setState(led_off);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
// }else if(name == "fromlist"){
// attr->GetValue(&p.second->fromList);
}else if(name == "font"){
std::string val;
attr->GetValue(&val);
if(val == "dungeon")
p.second->setFormat(TXT_FONT, FONT_DUNGEON);
else if(val == "plain")
p.second->setFormat(TXT_FONT, FONT_PLAIN);
else if(val == "bold")
p.second->setFormat(TXT_FONT, FONT_BOLD);
else if(val == "maidenword")
p.second->setFormat(TXT_FONT, FONT_MAIDWORD);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
if(val == "large")
p.second->setFormat(TXT_SIZE, 12);
else if(val == "small")
p.second->setFormat(TXT_SIZE, 10);
else if(val == "title")
p.second->setFormat(TXT_SIZE, 18);
else throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("led",name,val,attr->Row(),attr->Column(),fname);
}
p.second->setColour(clr);
} else if(name == "wrap") {
std::string val;
attr->GetValue(&val);
if(val == "true")
p.second->setFormat(TXT_WRAP, true);
else p.second->setFormat(TXT_WRAP, false);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else throw xBadAttr("led",name,attr->Row(),attr->Column(),fname);
}
if(!foundTop) throw xMissingAttr("led","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("led","left",who.Row(),who.Column(),fname);
if(width > 0) {
frame.right = frame.left + width;
}else{
frame.right = frame.left + 14;
}
if(height > 0) {
frame.bottom = frame.top + height;
}else{
frame.bottom = frame.top + 10;
}
p.second->setBounds(frame);
string content;
for(node = node.begin(&who); node != node.end(); node++){
string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("led",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
}
}
p.second->setText(content);
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
template<> pair<string,cLedGroup*> cDialog::parse(Element& who /*group*/){
pair<string,cLedGroup*> p;
Iterator<Attribute> attr;
Iterator<Element> node;
string name;
p.second = new cLedGroup(this);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
// else if(name == "fromlist")
// attr->GetValue(&p.second->fromList);
else throw xBadAttr("group",name,attr->Row(),attr->Column(),fname);
}
for(node = node.begin(&who); node != node.end(); node++){
string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::ELEMENT && val == "led"){
auto led = parse<cLed>(*node);
p.second->addChoice(led.second, led.first);
}else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("group",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
}
p.second->recalcRect();
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
template<> pair<string,cTextField*> cDialog::parse(Element& who /*field*/){
pair<string,cTextField*> p;
Iterator<Attribute> attr;
Iterator<Node> node;
string name;
int width = 0, height = 0;
bool foundTop = false, foundLeft = false; // requireds
rectangle frame;
p.second = new cTextField(this);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
else if(name == "type"){
std::string val;
attr->GetValue(&val);
if(val == "int")
p.second->setInputType(FLD_INT);
else if(val == "uint")
p.second->setInputType(FLD_UINT);
else if(val == "real")
p.second->setInputType(FLD_REAL);
else if(val == "text")
p.second->setInputType(FLD_TEXT);
else throw xBadVal("field",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else if(name == "tab-order"){
attr->GetValue(&p.second->tabOrder);
}else throw xBadAttr("field",name,attr->Row(),attr->Column(),fname);
}
if(!foundTop) throw xMissingAttr("field","top",attr->Row(),attr->Column(),fname);
if(!foundLeft) throw xMissingAttr("field","left",attr->Row(),attr->Column(),fname);
frame.right = frame.left + width;
frame.bottom = frame.top + height;
p.second->setBounds(frame);
string content;
for(node = node.begin(&who); node != node.end(); node++){
string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("field",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
}
p.second->setText(content);
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
// Note: This specialization must come last because it requires the other specializations
template<> pair<string,cStack*> cDialog::parse(Element& who /*stack*/) {
pair<string, cStack*> p;
Iterator<Attribute> attr;
Iterator<Element> node;
string name;
p.second = new cStack(*this);
for(attr = attr.begin(&who); attr != attr.end(); attr++) {
attr->GetName(&name);
if(name == "name")
attr->GetValue(&p.first);
else if(name == "pages") {
size_t val;
attr->GetValue(&val);
p.second->setPageCount(val);
} else throw xBadAttr("stack",name,attr->Row(),attr->Column(),fname);
}
vector<string> stack;
for(node = node.begin(&who); node != node.end(); node++) {
string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::ELEMENT) {
if(val == "field") {
auto field = parse<cTextField>(*node);
controls.insert(field);
stack.push_back(field.first);
tabOrder.push_back(field);
} else if(val == "text") {
auto text = parse<cTextMsg>(*node);
controls.insert(text);
stack.push_back(text.first);
} else if(val == "pict") {
auto pict = parse<cPict>(*node);
controls.insert(pict);
stack.push_back(pict.first);
} else if(val == "button") {
auto button = parse<cButton>(*node);
controls.insert(button);
stack.push_back(button.first);
} else if(val == "led") {
auto led = parse<cLed>(*node);
controls.insert(led);
stack.push_back(led.first);
} else if(val == "group") {
auto group = parse<cLedGroup>(*node);
controls.insert(group);
stack.push_back(group.first);
} else throw xBadNode(val,node->Row(),node->Column(),fname);
} else if(type != TiXmlNode::COMMENT)
throw xBadVal("stack",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
p.second->controls = stack;
p.second->recalcRect();
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
cDialog::cDialog(cDialog* p) : parent(p) {}
cDialog::cDialog(std::string path, cDialog* p) : parent(p) {
@@ -865,7 +201,7 @@ void cDialog::loadFromFile(std::string path){
}else if(name == "fore"){
sf::Color clr;
try{
clr = parseColor(val);
clr = cControl::parseColor(val);
}catch(int){
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}

View File

@@ -39,12 +39,10 @@ class cDialog {
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;
std::string generateRandomString();
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;
@@ -188,6 +186,22 @@ public:
static bool sendInput(cKey key);
/// Sets whether to animate graphics in dialogs.
static bool doAnimations;
/// Adds a new control described by the passed XML element.
/// @tparam Ctrl The type of control to add.
/// @param who The XML element describing the control.
/// @note It is up to the caller to ensure that that the element
/// passed describes the type of control being requested.
template<class Ctrl> std::pair<std::string,Ctrl*> parse(ticpp::Element& who) {
std::pair<std::string,Ctrl*> p;
p.second = new Ctrl(*this);
p.first = p.second->parse(who, fname);
if(p.first == ""){
do{
p.first = generateRandomString();
}while(controls.find(p.first) != controls.end());
}
return p;
}
cDialog& operator=(cDialog& other) = delete;
cDialog(cDialog& other) = delete;
private:

View File

@@ -197,8 +197,8 @@ bool cTextField::hasFocus() {
return haveFocus;
}
cTextField::cTextField(cDialog* parent) :
cControl(CTRL_FIELD,*parent),
cTextField::cTextField(cDialog& parent) :
cControl(CTRL_FIELD,parent),
color(sf::Color::Black),
insertionPoint(-1),
selectionPoint(0),
@@ -630,6 +630,63 @@ void cTextField::handleInput(cKey key) {
selectionPoint = sp;
}
std::string cTextField::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
Iterator<Node> node;
std::string name, id;
int width = 0, height = 0;
bool foundTop = false, foundLeft = false; // requireds
rectangle frame;
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
else if(name == "type"){
std::string val;
attr->GetValue(&val);
if(val == "int")
setInputType(FLD_INT);
else if(val == "uint")
setInputType(FLD_UINT);
else if(val == "real")
setInputType(FLD_REAL);
else if(val == "text")
setInputType(FLD_TEXT);
else throw xBadVal("field",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else if(name == "tab-order"){
attr->GetValue(&tabOrder);
}else throw xBadAttr("field",name,attr->Row(),attr->Column(),fname);
}
if(!foundTop) throw xMissingAttr("field","top",attr->Row(),attr->Column(),fname);
if(!foundLeft) throw xMissingAttr("field","left",attr->Row(),attr->Column(),fname);
frame.right = frame.left + width;
frame.bottom = frame.top + height;
setBounds(frame);
std::string content;
for(node = node.begin(&who); node != node.end(); node++){
std::string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("field",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
}
setText(content);
return id;
}
aTextInsert::aTextInsert(cTextField& in, int at, std::string text) : cAction("insert text"), in(in), at(at), text(text) {}
void aTextInsert::undo() {

View File

@@ -33,6 +33,7 @@ enum eFldType {
/// There is no Unicode support.
class cTextField : public cControl {
public:
std::string parse(ticpp::Element& who, std::string fname);
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.
@@ -54,7 +55,7 @@ public:
sf::Color getColour() throw(xUnsupportedProp);
/// Create a new editable text field.
/// @param parent The parent dialog.
explicit cTextField(cDialog* parent);
explicit cTextField(cDialog& parent);
bool isClickable();
virtual ~cTextField();
void draw();

View File

@@ -73,6 +73,99 @@ short cTextMsg::getFormat(eFormat prop) throw(xUnsupportedProp){
return 0;
}
std::string cTextMsg::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
Iterator<Node> node;
std::string name, id;
int width = 0, height = 0;
bool foundTop = false, foundLeft = false; // top and left are required attributes
rectangle frame;
if(parent->getBg() == cDialog::BG_DARK)
setColour(sf::Color::White);
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
else if(name == "framed"){
std::string val;
attr->GetValue(&val);
if(val == "true") setFormat(TXT_FRAME, true);
}else if(name == "font"){
std::string val;
attr->GetValue(&val);
if(val == "dungeon")
setFormat(TXT_FONT, FONT_DUNGEON);
else if(val == "plain")
setFormat(TXT_FONT, FONT_PLAIN);
else if(val == "bold")
setFormat(TXT_FONT, FONT_BOLD);
else if(val == "maidenword")
setFormat(TXT_FONT, FONT_MAIDWORD);
else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
if(val == "large")
setFormat(TXT_SIZE, 12);
else if(val == "small")
setFormat(TXT_SIZE, 10);
else if(val == "title")
setFormat(TXT_SIZE, 18);
else throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "color" || name == "colour"){
std::string val;
attr->GetValue(&val);
sf::Color clr;
try{
clr = parseColor(val);
}catch(int){
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}
setColour(clr);
}else if(name == "def-key"){
std::string val;
attr->GetValue(&val);
try{
attachKey(parseKey(val));
}catch(int){
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
}
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
// }else if(name == "fromlist"){
// attr->GetValue(&p.second->fromList);
}else throw xBadAttr("text",name,attr->Row(),attr->Column(),fname);
}
if(!foundTop) throw xMissingAttr("text","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("text","left",who.Row(),who.Column(),fname);
frame.right = frame.left + width;
frame.bottom = frame.top + height;
setBounds(frame);
std::string content;
for(node = node.begin(&who); node != node.end(); node++){
std::string val;
int type = node->Type();
node->GetValue(&val);
// TODO: De-magic the | character
if(type == TiXmlNode::ELEMENT && val == "br") content += '|'; // because vertical bar is replaced by a newline when drawing strings
else if(type == TiXmlNode::TEXT)
content += dlogStringFilter(val);
else if(type != TiXmlNode::COMMENT) {
val = '<' + val + '>';
throw xBadVal("text",xBadVal::CONTENT,content + val,node->Row(),node->Column(),fname);
}
}
setText(content);
return id;
}
cTextMsg::cTextMsg(cDialog& parent) :
cControl(CTRL_TEXT,parent),
drawFramed(false),

View File

@@ -22,6 +22,7 @@
/// This class can also create a frame for grouping controls or a clickable area.
class cTextMsg : public cControl {
public:
std::string parse(ticpp::Element& who, std::string fname);
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);

View File

@@ -443,6 +443,137 @@ void cPict::advanceAnim() {
if(animFrame >= 256) animFrame = 0;
}
std::string cPict::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
std::string name, id;
ePicType type;
bool wide = false, tall = false, custom = false, tiny = false;
bool foundTop = false, foundLeft = false, foundType = false, foundNum = false; // required attributes
rectangle frame;
int width = 0, height = 0;
for(attr = attr.begin(&who); attr != attr.end(); attr++){
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
else if(name == "type"){
std::string val;
foundType = true;
attr->GetValue(&val);
if(val == "blank"){
setPict(cPict::BLANK, PIC_TER);
foundNum = true;
continue;
}else if(val == "ter")
type = PIC_TER;
else if(val == "teranim")
type = PIC_TER_ANIM;
else if(val == "monst")
type = PIC_MONST;
else if(val == "dlog")
type = PIC_DLOG;
else if(val == "talk")
type = PIC_TALK;
else if(val == "scen")
type = PIC_SCEN;
else if(val == "item")
type = PIC_ITEM;
else if(val == "pc")
type = PIC_PC;
else if(val == "field")
type = PIC_FIELD;
else if(val == "boom")
type = PIC_BOOM;
else if(val == "missile")
type = PIC_MISSILE;
else if(val == "full")
type = PIC_FULL;
else if(val == "map")
type = PIC_TER_MAP;
else if(val == "status")
type = PIC_STATUS;
else throw xBadVal("pict",name,val,attr->Row(),attr->Column(),fname);
if(foundNum) {
pic_num_t wasPic = getPicNum();
setPict(wasPic, type);
}
}else if(name == "custom"){
std::string val;
attr->GetValue(&val);
if(val == "true") custom = true;
}else if(name == "scaled"){
std::string val;
attr->GetValue(&val);
if(val == "true") setFormat(TXT_WRAP, false);
}else if(name == "size"){
std::string val;
attr->GetValue(&val);
if(val == "wide") wide = true;
else if(val == "tall") tall = true;
else if(val == "large") wide = tall = true;
else if(val == "small") tiny = true;
else throw xBadVal("pict",name,val,attr->Row(),attr->Column(),fname);
}else if(name == "def-key"){
std::string val;
attr->GetValue(&val);
// TODO: The modifiers are now in key-mod, so this needs to be updated
try{
attachKey(parseKey(val));
}catch(int){
throw xBadVal("pict",name,val,attr->Row(),attr->Column(),fname);
}
}else if(name == "num"){
pic_num_t newPic;
attr->GetValue(&newPic), foundNum = true;
if(foundType) setPict(newPic, type);
else setPict(newPic);
}else if(name == "top"){
attr->GetValue(&frame.top), foundTop = true;
}else if(name == "left"){
attr->GetValue(&frame.left), foundLeft = true;
}else if(name == "width"){
attr->GetValue(&width);
}else if(name == "height"){
attr->GetValue(&height);
}else if(name == "framed"){
std::string val;
attr->GetValue(&val);
if(val == "true") setFormat(TXT_FRAME, true);
else setFormat(TXT_FRAME, false);
}else throw xBadAttr("pict",name,attr->Row(),attr->Column(),fname);
}
if(!foundType) throw xMissingAttr("pict","type",who.Row(),who.Column(),fname);
if(!foundNum) throw xMissingAttr("pict","num",who.Row(),who.Column(),fname);
if(!foundTop) throw xMissingAttr("pict","top",who.Row(),who.Column(),fname);
if(!foundLeft) throw xMissingAttr("pict","left",who.Row(),who.Column(),fname);
if(wide || tall) {
pic_num_t wasPic = getPicNum();
if(wide && !tall && getPicType() == PIC_MONST) setPict(wasPic, PIC_MONST_WIDE);
else if(!wide && tall && getPicType() == PIC_MONST) setPict(wasPic, PIC_MONST_TALL);
else if(wide && tall){
if(getPicType() == PIC_MONST) setPict(wasPic, PIC_MONST_LG);
else if(getPicType() == PIC_SCEN) setPict(wasPic, PIC_SCEN_LG);
else if(getPicType() == PIC_DLOG) setPict(wasPic, PIC_DLOG_LG);
}
} else if(tiny && type == PIC_ITEM) {
pic_num_t wasPic = getPicNum();
setPict(wasPic, PIC_TINY_ITEM);
}
frame.right = frame.left;
frame.bottom = frame.top;
if(width > 0 || height > 0 || getPicType() == PIC_FULL){
frame.right = frame.left + width;
frame.bottom = frame.top + height;
}
setBounds(frame);
pic_num_t wasPic = getPicNum();
if(custom) {
setPict(wasPic, getPicType() + PIC_CUSTOM);
} else setPict(wasPic, getPicType());
// The above line also sets the graphic's bounding rect, if necessary
return id;
}
void cPict::recalcRect() {
rectangle bounds = getBounds();
switch(picType) {

View File

@@ -25,6 +25,7 @@ class cPict : public cControl {
public:
/// @copydoc cDialog::init()
static void init();
std::string parse(ticpp::Element& who, std::string fname);
void attachClickHandler(click_callback_t f) throw();
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);

View File

@@ -201,6 +201,12 @@ void cScrollbar::draw() {
rect_draw_some_item(scroll_gw, from_rect, *inWindow, draw_rect);
}
std::string cScrollbar::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
// TODO: Parse scrollbars
return "";
}
cControl::storage_t cScrollbar::store() {
storage_t storage = cControl::store();
storage["scroll-pos"] = pos;

View File

@@ -32,6 +32,7 @@ class cScrollbar : public cControl {
public:
/// @copydoc cDialog::init()
static void init();
std::string parse(ticpp::Element& who, std::string fname);
/// Create a new scrollbar without a parent dialog.
/// @param parent The parent window.
explicit cScrollbar(sf::RenderWindow& parent);

View File

@@ -8,6 +8,9 @@
#include "stack.hpp"
#include "field.hpp"
#include "button.hpp"
#include "message.hpp"
#include "pict.hpp"
void cStack::attachClickHandler(click_callback_t f) throw(xHandlerNotSupported) {
onClick = f;
@@ -151,3 +154,59 @@ void cStack::fillTabOrder(std::vector<int>& specificTabs, std::vector<int>& reve
cStack::cStack(cDialog& parent) : cControl(CTRL_STACK, parent), curPage(0), nPages(0) {}
std::string cStack::parse(ticpp::Element& who, std::string fname) {
using namespace ticpp;
Iterator<Attribute> attr;
Iterator<Element> node;
std::string name, id;
for(attr = attr.begin(&who); attr != attr.end(); attr++) {
attr->GetName(&name);
if(name == "name")
attr->GetValue(&id);
else if(name == "pages") {
size_t val;
attr->GetValue(&val);
setPageCount(val);
} else throw xBadAttr("stack",name,attr->Row(),attr->Column(),fname);
}
std::vector<std::string> stack;
for(node = node.begin(&who); node != node.end(); node++) {
std::string val;
int type = node->Type();
node->GetValue(&val);
if(type == TiXmlNode::ELEMENT) {
if(val == "field") {
auto field = parent->parse<cTextField>(*node);
parent->add(field.second, field.second->getBounds(), field.first);
stack.push_back(field.first);
// TODO: Add field to tab order
//tabOrder.push_back(field);
} else if(val == "text") {
auto text = parent->parse<cTextMsg>(*node);
parent->add(text.second, text.second->getBounds(), text.first);
stack.push_back(text.first);
} else if(val == "pict") {
auto pict = parent->parse<cPict>(*node);
parent->add(pict.second, pict.second->getBounds(), pict.first);
stack.push_back(pict.first);
} else if(val == "button") {
auto button = parent->parse<cButton>(*node);
parent->add(button.second, button.second->getBounds(), button.first);
stack.push_back(button.first);
} else if(val == "led") {
auto led = parent->parse<cLed>(*node);
parent->add(led.second, led.second->getBounds(), led.first);
stack.push_back(led.first);
} else if(val == "group") {
auto group = parent->parse<cLedGroup>(*node);
parent->add(group.second, group.second->getBounds(), group.first);
stack.push_back(group.first);
} else throw xBadNode(val,node->Row(),node->Column(),fname);
} else if(type != TiXmlNode::COMMENT)
throw xBadVal("stack",xBadVal::CONTENT,val,node->Row(),node->Column(),fname);
}
controls = stack;
recalcRect();
return id;
}

View File

@@ -42,6 +42,7 @@ class cStack : public cControl {
std::vector<std::string> controls;
click_callback_t onClick;
public:
std::string parse(ticpp::Element& who, std::string fname);
void attachClickHandler(click_callback_t f) throw(xHandlerNotSupported);
void attachFocusHandler(focus_callback_t f) throw(xHandlerNotSupported);
bool triggerClickHandler(cDialog& me, std::string id, eKeyMod mods);