First version of the new dialog engine added to the repository. It compiles, and links with one error. Because of this, it is untested as yet.
git-svn-id: http://openexile.googlecode.com/svn/trunk@73 4ebdad44-0ea0-11de-aab3-ff745001d230
This commit is contained in:
920
osx/dialogxml/dialog.cpp
Normal file
920
osx/dialogxml/dialog.cpp
Normal file
@@ -0,0 +1,920 @@
|
||||
/*
|
||||
* dialog.cpp
|
||||
* BoE
|
||||
*
|
||||
* Created by Celtic Minstrel on 11/05/09.
|
||||
*
|
||||
*/
|
||||
#define SLEEP_TICKS 2L
|
||||
#define MOUSE_REGION 0L
|
||||
#define IN_FRONT (WindowPtr)-1L
|
||||
|
||||
#include "dialog.h"
|
||||
#include "graphtool.h"
|
||||
#include "soundtool.h"
|
||||
using namespace std;
|
||||
using namespace ticpp;
|
||||
|
||||
extern bool play_sounds;
|
||||
const short cDialog::BG_DARK = 5, cDialog::BG_LIGHT = 16;
|
||||
|
||||
template<> pair<string,cPict*> cDialog::parse(Element& who /*pict*/){
|
||||
pair<string,cPict*> p;
|
||||
Iterator<Attribute> attr;
|
||||
string name, val;
|
||||
int width = 0, height = 0;
|
||||
bool wide = false, tall = false, custom = false;
|
||||
p.second = new cPict(this);
|
||||
for(attr = attr.begin(&who); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "name")
|
||||
p.first = val;
|
||||
else if(name == "type"){
|
||||
if(val == "blank"){
|
||||
p.second->picType = PIC_TER;
|
||||
p.second->picNum = -1;
|
||||
}else if(val == "ter")
|
||||
p.second->picType = PIC_TER;
|
||||
else if(val == "teranim")
|
||||
p.second->picType = PIC_TER_ANIM;
|
||||
else if(val == "monst")
|
||||
p.second->picType = PIC_MONST;
|
||||
else if(val == "dlog")
|
||||
p.second->picType = PIC_DLOG;
|
||||
else if(val == "talk")
|
||||
p.second->picType = PIC_TALK;
|
||||
else if(val == "scen")
|
||||
p.second->picType = PIC_SCEN;
|
||||
else if(val == "item")
|
||||
p.second->picType = PIC_ITEM;
|
||||
else if(val == "pc")
|
||||
p.second->picType = PIC_PC;
|
||||
else if(val == "field")
|
||||
p.second->picType = PIC_FIELD;
|
||||
else if(val == "boom")
|
||||
p.second->picType = PIC_BOOM;
|
||||
else if(val == "missile")
|
||||
p.second->picType = PIC_MISSILE;
|
||||
else if(val == "full")
|
||||
p.second->picType = PIC_FULL;
|
||||
else throw xBadVal("pict",name,val);
|
||||
}else if(name == "custom") if(val == "true")
|
||||
custom = true;
|
||||
else if(name == "clickable") if(val == "true")
|
||||
p.second->clickable = true;
|
||||
else if(name == "size"){
|
||||
if(val == "wide") wide = true;
|
||||
else if(val == "tall") tall = true;
|
||||
else if(val == "large") wide = tall = true;
|
||||
else throw xBadVal("pict",name,val);
|
||||
}else if(name == "num"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->picNum;
|
||||
}else if(name == "top"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.top;
|
||||
}else if(name == "left"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.left;
|
||||
}else if(name == "width"){
|
||||
istringstream sin(val);
|
||||
sin >> width;
|
||||
}else if(name == "height"){
|
||||
istringstream sin(val);
|
||||
sin >> height;
|
||||
}else throw xBadAttr("pict",name);
|
||||
}
|
||||
if(wide && !tall && p.second->picType == PIC_MONST) p.second->picType = PIC_MONST_WIDE;
|
||||
else if(!wide && tall && p.second->picType == PIC_MONST) p.second->picType = PIC_MONST_TALL;
|
||||
else if(wide && tall){
|
||||
if(p.second->picType == PIC_MONST) p.second->picType = PIC_MONST_LG;
|
||||
else if(p.second->picType == PIC_SCEN) p.second->picType = PIC_SCEN_LG;
|
||||
else if(p.second->picType == PIC_DLOG) p.second->picType = PIC_DLOG_LG;
|
||||
}
|
||||
if(width > 0 || height > 0 || p.second->picType == PIC_FULL){
|
||||
p.second->frame.right = p.second->frame.left + width;
|
||||
p.second->frame.bottom = p.second->frame.top + height;
|
||||
}else switch(p.second->picType){
|
||||
case PIC_DLOG:
|
||||
p.second->frame.right = p.second->frame.left + 36;
|
||||
p.second->frame.bottom = p.second->frame.top + 36;
|
||||
break;
|
||||
case PIC_DLOG_LG:
|
||||
p.second->frame.right = p.second->frame.left + 72;
|
||||
p.second->frame.bottom = p.second->frame.top + 72;
|
||||
break;
|
||||
case PIC_SCEN:
|
||||
case PIC_TALK:
|
||||
p.second->frame.right = p.second->frame.left + 32;
|
||||
p.second->frame.bottom = p.second->frame.top + 32;
|
||||
break;
|
||||
case PIC_SCEN_LG:
|
||||
p.second->frame.right = p.second->frame.left + 64;
|
||||
p.second->frame.bottom = p.second->frame.top + 64;
|
||||
break;
|
||||
case PIC_MISSILE:
|
||||
p.second->frame.right = p.second->frame.left + 18;
|
||||
p.second->frame.bottom = p.second->frame.top + 18;
|
||||
break;
|
||||
default:
|
||||
p.second->frame.right = p.second->frame.left + 28;
|
||||
p.second->frame.bottom = p.second->frame.top + 36;
|
||||
break;
|
||||
}
|
||||
if(custom) p.second->picType += PIC_CUSTOM;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<> pair<string,cTextMsg*> cDialog::parse(Element& who /*text*/){
|
||||
pair<string,cTextMsg*> p;
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Node> node;
|
||||
string name, val;
|
||||
int width = 0, height = 0;
|
||||
p.second = new cTextMsg(this);
|
||||
for(attr = attr.begin(&who); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "name")
|
||||
p.first = val;
|
||||
else if(name == "framed") if(val == "true")
|
||||
p.second->drawFramed = true;
|
||||
else if(name == "clickable") if(val == "true")
|
||||
p.second->clickable = true;
|
||||
else if(name == "font"){
|
||||
if(val == "dungeon")
|
||||
p.second->textFont = DUNGEON;
|
||||
else if(val == "geneva")
|
||||
p.second->textFont = GENEVA;
|
||||
else if(val == "silom")
|
||||
p.second->textFont = SILOM;
|
||||
else if(val == "maidenword")
|
||||
p.second->textFont = MAIDENWORD;
|
||||
else throw xBadVal("text",name,val);
|
||||
}else if(name == "size"){
|
||||
if(val == "large")
|
||||
p.second->textSize = 12;
|
||||
else if(val == "small")
|
||||
p.second->textSize = 10;
|
||||
else throw xBadVal("text",name,val);
|
||||
}else if(name == "color" || name == "colour"){
|
||||
RGBColor clr;
|
||||
try{
|
||||
clr = parseColor(val);
|
||||
}catch(int){
|
||||
throw xBadVal("text",name,val);
|
||||
}
|
||||
p.second->color = clr;
|
||||
}else if(name == "top"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.top;
|
||||
}else if(name == "left"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.left;
|
||||
}else if(name == "width"){
|
||||
istringstream sin(val);
|
||||
sin >> width;
|
||||
}else if(name == "height"){
|
||||
istringstream sin(val);
|
||||
sin >> height;
|
||||
}else if(name == "fromlist"){
|
||||
p.second->fromList = val;
|
||||
}else throw xBadAttr("pict",name);
|
||||
}
|
||||
p.second->frame.right = p.second->frame.left + width;
|
||||
p.second->frame.bottom = p.second->frame.top + height;
|
||||
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 == "br") content += '|'; // because vertical bar is replaced by a newline when drawing strings
|
||||
else if(type == TiXmlNode::TEXT) content += val;
|
||||
else{
|
||||
val = '<' + val + '>';
|
||||
throw xBadVal("text","<content>",content + val);
|
||||
}
|
||||
}
|
||||
p.second->lbl = content;
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an HTML-style colour string, recognizing three-digit hex, six-digit hex, and HTML colour names.
|
||||
*/
|
||||
RGBColor cDialog::parseColor(string what){
|
||||
RGBColor clr;
|
||||
if(what[0] == '#'){
|
||||
unsigned int r,g,b;
|
||||
if(sscanf(what.c_str(),"#%2x%2x%2x",&r,&g,&b) < 3)
|
||||
if(sscanf(what.c_str(),"#%1x%1x%1x",&r,&g,&b) < 3)
|
||||
throw -1;
|
||||
clr.red = r, clr.green = g, clr.blue = b;
|
||||
}else if(what == "black")
|
||||
clr.red = 0x00, clr.green = 0x00, clr.blue = 0x00;
|
||||
else if(what == "red")
|
||||
clr.red = 0xFF, clr.green = 0x00, clr.blue = 0x00;
|
||||
else if(what == "lime")
|
||||
clr.red = 0x00, clr.green = 0xFF, clr.blue = 0x00;
|
||||
else if(what == "blue")
|
||||
clr.red = 0x00, clr.green = 0x00, clr.blue = 0xFF;
|
||||
else if(what == "yellow")
|
||||
clr.red = 0xFF, clr.green = 0xFF, clr.blue = 0x00;
|
||||
else if(what == "aqua")
|
||||
clr.red = 0x00, clr.green = 0xFF, clr.blue = 0xFF;
|
||||
else if(what == "fuchsia")
|
||||
clr.red = 0xFF, clr.green = 0x00, clr.blue = 0xFF;
|
||||
else if(what == "white")
|
||||
clr.red = 0xFF, clr.green = 0xFF, clr.blue = 0xFF;
|
||||
else if(what == "gray" || what == "grey")
|
||||
clr.red = 0x80, clr.green = 0x80, clr.blue = 0x80;
|
||||
else if(what == "maroon")
|
||||
clr.red = 0x80, clr.green = 0x00, clr.blue = 0x00;
|
||||
else if(what == "green")
|
||||
clr.red = 0x00, clr.green = 0x80, clr.blue = 0x00;
|
||||
else if(what == "navy")
|
||||
clr.red = 0x00, clr.green = 0x00, clr.blue = 0x80;
|
||||
else if(what == "olive")
|
||||
clr.red = 0x80, clr.green = 0x80, clr.blue = 0x00;
|
||||
else if(what == "teal")
|
||||
clr.red = 0x00, clr.green = 0x80, clr.blue = 0x80;
|
||||
else if(what == "purple")
|
||||
clr.red = 0x80, clr.green = 0x00, clr.blue = 0x80;
|
||||
else if(what == "silver")
|
||||
clr.red = 0xC0, clr.green = 0xC0, clr.blue = 0xC0;
|
||||
else throw -1;
|
||||
clr.red *= clr.red;
|
||||
clr.green *= clr.green;
|
||||
clr.blue *= clr.blue;
|
||||
return clr;
|
||||
}
|
||||
|
||||
template<> pair<string,cButton*> cDialog::parse(Element& who /*button*/){
|
||||
pair<string,cButton*> p;
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Node> node;
|
||||
string name, val;
|
||||
int width = 0, height = 0;
|
||||
p.second = new cButton(this);
|
||||
for(attr = attr.begin(&who); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "name")
|
||||
p.first = val;
|
||||
else if(name == "wrap") if(val == "true")
|
||||
p.second->wrapLabel = true;
|
||||
else if(name == "type"){
|
||||
if(val == "small")
|
||||
p.second->type = BTN_SM;
|
||||
else if(val == "regular")
|
||||
p.second->type = BTN_REG;
|
||||
else if(val == "large")
|
||||
p.second->type = BTN_LG;
|
||||
else if(val == "help")
|
||||
p.second->type = BTN_HELP;
|
||||
else if(val == "left")
|
||||
p.second->type = BTN_LEFT;
|
||||
else if(val == "right")
|
||||
p.second->type = BTN_RIGHT;
|
||||
else if(val == "up")
|
||||
p.second->type = BTN_UP;
|
||||
else if(val == "down")
|
||||
p.second->type = BTN_DOWN;
|
||||
else if(val == "tiny")
|
||||
p.second->type = BTN_TINY;
|
||||
else if(val == "done")
|
||||
p.second->type = BTN_DONE;
|
||||
else if(val == "tall")
|
||||
p.second->type = BTN_TALL;
|
||||
else if(val == "trait")
|
||||
p.second->type = BTN_TRAIT;
|
||||
else if(val == "push")
|
||||
p.second->type = BTN_PUSH;
|
||||
}else if(name == "def-key"){
|
||||
try{
|
||||
p.second->key = parseKey(val);
|
||||
}catch(int){
|
||||
throw xBadVal("button",name,val);
|
||||
}
|
||||
}else if(name == "fromlist")
|
||||
p.second->fromList = val;
|
||||
else if(name == "top"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.top;
|
||||
}else if(name == "left"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.left;
|
||||
}else if(name == "width"){
|
||||
istringstream sin;
|
||||
sin >> width;
|
||||
}else if(name == "height"){
|
||||
istringstream sin;
|
||||
sin >> height;
|
||||
}else throw xBadAttr("button",name);
|
||||
}
|
||||
if(width > 0 || height > 0) {
|
||||
p.second->frame.right = p.second->frame.left + width;
|
||||
p.second->frame.bottom = p.second->frame.top + height;
|
||||
}else switch(p.second->type){
|
||||
case BTN_SM:
|
||||
p.second->frame.right = p.second->frame.left + 23;
|
||||
p.second->frame.bottom = p.second->frame.top + 23;
|
||||
break;
|
||||
case BTN_LG:
|
||||
p.second->frame.right = p.second->frame.left + 102;
|
||||
p.second->frame.bottom = p.second->frame.top + 23;
|
||||
break;
|
||||
case BTN_HELP:
|
||||
p.second->frame.right = p.second->frame.left + 16;
|
||||
p.second->frame.bottom = p.second->frame.top + 13;
|
||||
break;
|
||||
case BTN_TINY:
|
||||
case BTN_LED: // this should never happen
|
||||
p.second->frame.right = p.second->frame.left + 14;
|
||||
p.second->frame.bottom = p.second->frame.top + 10;
|
||||
break;
|
||||
case BTN_TALL:
|
||||
case BTN_TRAIT:
|
||||
p.second->frame.right = p.second->frame.left + 63;
|
||||
p.second->frame.bottom = p.second->frame.top + 40;
|
||||
break;
|
||||
case BTN_PUSH:
|
||||
p.second->frame.right = p.second->frame.left + 30;
|
||||
p.second->frame.bottom = p.second->frame.top + 30;
|
||||
break;
|
||||
default:
|
||||
p.second->frame.right = p.second->frame.left + 63;
|
||||
p.second->frame.bottom = p.second->frame.top + 23;
|
||||
}
|
||||
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"){
|
||||
if(content.length() > 0) throw xBadVal("button","<content>",content + val);
|
||||
p.second->labelWithKey = true;
|
||||
}else if(type == TiXmlNode::TEXT) content += val;
|
||||
else{
|
||||
val = '<' + val + '>';
|
||||
throw xBadVal("text","<content>",val);
|
||||
}
|
||||
}
|
||||
p.second->lbl = content;
|
||||
return p;
|
||||
}
|
||||
|
||||
cKey cDialog::parseKey(string what){
|
||||
cKey key;
|
||||
key.spec = false;
|
||||
key.c = 0;
|
||||
key.mod = mod_none;
|
||||
istringstream sin(what);
|
||||
string parts[4];
|
||||
sin >> parts[0] >> parts[1] >> parts[2] >> parts[3];
|
||||
for(int i = 0; i < 4; i++){
|
||||
if(parts[i] == "ctrl") key.mod += mod_ctrl;
|
||||
else if(parts[i] == "alt") key.mod += mod_alt;
|
||||
else if(parts[i] == "shift") key.mod += mod_shift;
|
||||
else if(parts[i] == "left") {
|
||||
key.spec = true;
|
||||
key.k = key_left;
|
||||
break;
|
||||
}else if(parts[i] == "right") {
|
||||
key.spec = true;
|
||||
key.k = key_right;
|
||||
break;
|
||||
}else if(parts[i] == "up") {
|
||||
key.spec = true;
|
||||
key.k = key_up;
|
||||
break;
|
||||
}else if(parts[i] == "down") {
|
||||
key.spec = true;
|
||||
key.k = key_down;
|
||||
break;
|
||||
}else if(parts[i] == "esc") {
|
||||
key.spec = true;
|
||||
key.k = key_esc;
|
||||
break;
|
||||
}else if(parts[i] == "enter" || parts[i] == "return") {
|
||||
key.spec = true;
|
||||
key.k = key_enter;
|
||||
break;
|
||||
}else if(parts[i] == "tab") {
|
||||
key.spec = true;
|
||||
key.k = key_tab;
|
||||
break;
|
||||
}else if(parts[i] == "help") {
|
||||
key.spec = true;
|
||||
key.k = key_help;
|
||||
break;
|
||||
}else if(parts[i] == "space") {
|
||||
key.c = ' ';
|
||||
break;
|
||||
}else if(parts[i].length() == 1) {
|
||||
key.c = parts[i][0];
|
||||
break;
|
||||
}else throw -1;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
template<> pair<string,cLed*> cDialog::parse(Element& who /*LED*/){
|
||||
pair<string,cLed*> p;
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Node> node;
|
||||
string name, val;
|
||||
int width = 0, height = 0;
|
||||
p.second = new cLed(this);
|
||||
for(attr = attr.begin(&who); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "name")
|
||||
p.first = val;
|
||||
else if(name == "state"){
|
||||
if(val == "red") p.second->state = led_red;
|
||||
else if(val == "green") p.second->state = led_green;
|
||||
else if(val == "off") p.second->state = led_off;
|
||||
else throw xBadVal("led",name,val);
|
||||
}else if(name == "fromlist")
|
||||
p.second->fromList = val;
|
||||
else if(name == "font"){
|
||||
if(val == "dungeon")
|
||||
p.second->textFont = DUNGEON;
|
||||
else if(val == "geneva")
|
||||
p.second->textFont = GENEVA;
|
||||
else if(val == "silom")
|
||||
p.second->textFont = SILOM;
|
||||
else if(val == "maidenword")
|
||||
p.second->textFont = MAIDENWORD;
|
||||
else throw xBadVal("text",name,val);
|
||||
}else if(name == "size"){
|
||||
if(val == "large")
|
||||
p.second->textSize = 12;
|
||||
else if(val == "small")
|
||||
p.second->textSize = 10;
|
||||
else throw xBadVal("text",name,val);
|
||||
}else if(name == "color" || name == "colour"){
|
||||
RGBColor clr;
|
||||
try{
|
||||
clr = parseColor(val);
|
||||
}catch(int){
|
||||
throw xBadVal("text",name,val);
|
||||
}
|
||||
p.second->color = clr;
|
||||
}else if(name == "top"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.top;
|
||||
}else if(name == "left"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.left;
|
||||
}else if(name == "width"){
|
||||
istringstream sin;
|
||||
sin >> width;
|
||||
}else if(name == "height"){
|
||||
istringstream sin;
|
||||
sin >> height;
|
||||
}else throw xBadAttr("button",name);
|
||||
}
|
||||
if(width > 0 || height > 0) {
|
||||
p.second->frame.right = p.second->frame.left + width;
|
||||
p.second->frame.bottom = p.second->frame.top + height;
|
||||
}else{
|
||||
p.second->frame.right = p.second->frame.left + 14;
|
||||
p.second->frame.bottom = p.second->frame.top + 10;
|
||||
}
|
||||
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 += val;
|
||||
else{
|
||||
val = '<' + val + '>';
|
||||
throw xBadVal("text","<content>",content + val);
|
||||
}
|
||||
}
|
||||
p.second->lbl = content;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<> pair<string,cLedGroup*> cDialog::parse(Element& who /*group*/){
|
||||
pair<string,cLedGroup*> p;
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Element> node;
|
||||
string name, val;
|
||||
p.second = new cLedGroup(this);
|
||||
for(attr = attr.begin(&who); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "name")
|
||||
p.first = val;
|
||||
else if(name == "fromlist")
|
||||
p.second->fromList = val;
|
||||
else throw xBadAttr("button",name);
|
||||
}
|
||||
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 == "led"){
|
||||
p.second->choices.insert(parse<cLed>(*node));
|
||||
}else{
|
||||
val = '<' + val + '>';
|
||||
throw xBadVal("text","<content>", content + val);
|
||||
}
|
||||
}
|
||||
p.second->lbl = content;
|
||||
return p;
|
||||
}
|
||||
|
||||
template<> pair<string,cTextField*> cDialog::parse(Element& who /*field*/){
|
||||
pair<string,cTextField*> p;
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Node> node;
|
||||
string name, val;
|
||||
int width = 0, height = 0;
|
||||
p.second = new cTextField(this);
|
||||
for(attr = attr.begin(&who); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "name")
|
||||
p.first = val;
|
||||
else if(name == "type"){
|
||||
if(val == "num")
|
||||
p.second->isNumericField = true;
|
||||
else if(val == "text")
|
||||
p.second->isNumericField = false;
|
||||
else throw xBadVal("field",name,val);
|
||||
}else if(name == "top"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.top;
|
||||
}else if(name == "left"){
|
||||
istringstream sin(val);
|
||||
sin >> p.second->frame.left;
|
||||
}else if(name == "width"){
|
||||
istringstream sin;
|
||||
sin >> width;
|
||||
}else if(name == "height"){
|
||||
istringstream sin;
|
||||
sin >> height;
|
||||
}else throw xBadAttr("button",name);
|
||||
}
|
||||
p.second->frame.right = p.second->frame.left + width;
|
||||
p.second->frame.bottom = p.second->frame.top + height;
|
||||
return p;
|
||||
}
|
||||
|
||||
cDialog::cDialog(string path){
|
||||
try{
|
||||
Document xml(path);
|
||||
xml.LoadFile();
|
||||
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Element> node;
|
||||
string type, name, val;
|
||||
|
||||
xml.GetValue(&type);
|
||||
if(type != "dialog") throw xBadNode(type);
|
||||
for(attr = attr.begin(&xml); attr != attr.end(); attr++){
|
||||
attr->GetName(&name);
|
||||
attr->GetValue(&val);
|
||||
if(name == "skin"){
|
||||
if(val == "light") bg = BG_LIGHT;
|
||||
else if(val == "dark") bg = BG_DARK;
|
||||
else{
|
||||
istringstream sin(val);
|
||||
sin >> bg;
|
||||
if(sin.fail()) throw xBadVal(type,name,val);
|
||||
}
|
||||
}else if(name != "debug")
|
||||
throw xBadAttr(type,name);
|
||||
}
|
||||
|
||||
for(node = node.begin(xml.FirstChildElement()); node != node.end(); node++){
|
||||
node->GetValue(&type);
|
||||
// Yes, I'm using insert instead of [] to add elements to the map.
|
||||
// In this situation, it's actually easier that way; the reason being, the
|
||||
// map key is obtained from the name attribute of each element.
|
||||
if(type == "field")
|
||||
controls.insert(parse<cTextField>(*node));
|
||||
else if(type == "text")
|
||||
controls.insert(parse<cTextMsg>(*node));
|
||||
else if(type == "pict")
|
||||
controls.insert(parse<cPict>(*node));
|
||||
else if(type == "button")
|
||||
controls.insert(parse<cButton>(*node));
|
||||
else if(type == "led")
|
||||
controls.insert(parse<cLed>(*node));
|
||||
else if(type == "group")
|
||||
controls.insert(parse<cLedGroup>(*node));
|
||||
else throw xBadNode(type);
|
||||
}
|
||||
} catch(Exception& x){ // XML processing exception
|
||||
printf(x.what());
|
||||
} catch(xBadVal& x){ // Invalid value for an attribute
|
||||
printf(x.what());
|
||||
} catch(xBadAttr& x){ // Invalid attribute for an element
|
||||
printf(x.what());
|
||||
} catch(xBadNode& x){ // Invalid element
|
||||
printf(x.what());
|
||||
}
|
||||
dialogNotToast = true;
|
||||
bg = BG_DARK; // default is dark background
|
||||
// now calculate window rect
|
||||
SetRect(&winRect,0,0,0,0);
|
||||
ctrlIter iter = controls.begin();
|
||||
currentFocus = NULL;
|
||||
while(iter != controls.end()){
|
||||
if(iter->second->frame.right > winRect.right)
|
||||
winRect.right = iter->second->frame.right;
|
||||
if(iter->second->frame.bottom > winRect.bottom)
|
||||
winRect.bottom = iter->second->frame.bottom;
|
||||
if(typeid(iter->second) == typeid(cTextField*)){
|
||||
cTextField* fld = (cTextField*) iter->second;
|
||||
if(currentFocus == NULL) currentFocus = fld;
|
||||
// TODO: Should probably create controls and put them in the window?
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
winRect.right += 4;
|
||||
winRect.bottom += 4;
|
||||
win = NewCWindow(NULL, &winRect, (unsigned char*) "", false, dBoxProc, IN_FRONT, false, 0);
|
||||
}
|
||||
|
||||
void cDialog::init(){
|
||||
cControl::init();
|
||||
cButton::init();
|
||||
cLed::init();
|
||||
cPict::init();
|
||||
}
|
||||
|
||||
cDialog::~cDialog(){
|
||||
ctrlIter iter = controls.begin();
|
||||
while(iter != controls.end()){
|
||||
delete iter->second;
|
||||
iter++;
|
||||
}
|
||||
DisposeWindow(win);
|
||||
}
|
||||
|
||||
bool cDialog::add(cControl* what, std::string key){
|
||||
// First make sure the key is not already present.
|
||||
// If it is, we can't add the control, so return false.
|
||||
if(controls.find(key) != controls.end()) return false;
|
||||
controls.insert(std::make_pair(key,what));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cDialog::remove(std::string key){
|
||||
ctrlIter ctrl = controls.find(key);
|
||||
if(ctrl == controls.end()) return false;
|
||||
delete ctrl->second;
|
||||
controls.erase(ctrl);
|
||||
return true;
|
||||
}
|
||||
|
||||
void cDialog::run(){
|
||||
char c, k;
|
||||
cKey key;
|
||||
EventRecord currentEvent;
|
||||
std::string itemHit = "";
|
||||
dialogNotToast = true;
|
||||
ShowWindow(win);
|
||||
BeginAppModalStateForWindow(win);
|
||||
while(dialogNotToast){
|
||||
WaitNextEvent(everyEvent, ¤tEvent, SLEEP_TICKS, MOUSE_REGION);
|
||||
switch(currentEvent.what){
|
||||
case updateEvt:
|
||||
BeginUpdate(win);
|
||||
draw();
|
||||
EndUpdate(win);
|
||||
break;
|
||||
case keyDown:
|
||||
case autoKey:
|
||||
c = currentEvent.message & charCodeMask;
|
||||
k = (currentEvent.message & keyCodeMask) >> 8;
|
||||
switch(k){
|
||||
case 126:
|
||||
key.spec = true;
|
||||
key.k = key_up;
|
||||
break;
|
||||
case 124:
|
||||
key.spec = true;
|
||||
key.k = key_right;
|
||||
break;
|
||||
case 123:
|
||||
key.spec = true;
|
||||
key.k = key_left;
|
||||
break;
|
||||
case 125:
|
||||
key.spec = true;
|
||||
key.k = key_down;
|
||||
break;
|
||||
case 53:
|
||||
key.spec = true;
|
||||
key.k = key_esc;
|
||||
break;
|
||||
case 36: case 76:
|
||||
key.spec = true;
|
||||
key.k = key_enter;
|
||||
break;
|
||||
// TODO: Add cases for key_tab and key_help
|
||||
default:
|
||||
key.spec = false;
|
||||
key.c = c;
|
||||
break;
|
||||
}
|
||||
key.mod = mod_none;
|
||||
if(currentEvent.modifiers & cmdKey){
|
||||
if(key.spec){
|
||||
if(key.k == key_left) key.k = key_home;
|
||||
else if(key.k == key_right) key.k = key_end;
|
||||
else if(key.k == key_up) key.k = key_pgup;
|
||||
else if(key.k == key_down) key.k = key_pgdn;
|
||||
else key.mod += mod_ctrl;
|
||||
}else key.mod += mod_ctrl;
|
||||
}if(currentEvent.modifiers & shiftKey) key.mod += mod_shift;
|
||||
if(currentEvent.modifiers & alphaLock) key.mod += mod_shift;
|
||||
if(currentEvent.modifiers & optionKey) key.mod += mod_alt;
|
||||
if(currentEvent.modifiers & controlKey) key.mod += mod_ctrl;
|
||||
if(currentEvent.modifiers & rightShiftKey) key.mod += mod_shift;
|
||||
if(currentEvent.modifiers & rightOptionKey) key.mod += mod_alt;
|
||||
if(currentEvent.modifiers & rightControlKey) key.mod += mod_ctrl;
|
||||
itemHit = process_keystroke(key); // TODO: This should be a separate check from the fields thing?
|
||||
if(typeid(controls[itemHit]) == typeid(cTextField*)){
|
||||
if(!key.spec || key.k == key_bsp || key.k == key_del || key.k == key_home ||
|
||||
key.k == key_end || key.k == key_pgup || key.k == key_pgdn ||
|
||||
key.k == key_left || key.k == key_right || key.k == key_up || key.k == key_down){
|
||||
// TODO: If the dialog contains a field, handle it here.
|
||||
// Basically, we should end up here if the user is typing into the field.
|
||||
itemHit = "";
|
||||
}else if(key.spec && key.k == key_tab){
|
||||
// TODO: Tabbing through fields, and trigger focus events.
|
||||
ctrlIter cur = controls.find(itemHit), iter;
|
||||
if(!cur->second->triggerFocusHandler(*this,itemHit,true)) break;
|
||||
iter = cur;
|
||||
while(iter != cur){
|
||||
if(typeid(iter->second) == typeid(cTextField*)){
|
||||
if(iter->second->triggerFocusHandler(*this,iter->first,false)){
|
||||
currentFocus = (cTextField*) iter->second;
|
||||
itemHit = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
iter++;
|
||||
if(iter == controls.end()) iter = controls.begin();
|
||||
}
|
||||
if(iter == cur) // no focus change occured!
|
||||
; // TODO: Surely something should happen here?
|
||||
}
|
||||
}
|
||||
break;
|
||||
case mouseDown:
|
||||
if(!PtInRect(currentEvent.where,&winRect)) break; // may be superfluous?
|
||||
key.mod = mod_none;
|
||||
if(currentEvent.modifiers & cmdKey) key.mod += mod_ctrl;
|
||||
if(currentEvent.modifiers & shiftKey) key.mod += mod_shift;
|
||||
if(currentEvent.modifiers & alphaLock) key.mod += mod_shift;
|
||||
if(currentEvent.modifiers & optionKey) key.mod += mod_alt;
|
||||
if(currentEvent.modifiers & controlKey) key.mod += mod_ctrl;
|
||||
if(currentEvent.modifiers & rightShiftKey) key.mod += mod_shift;
|
||||
if(currentEvent.modifiers & rightOptionKey) key.mod += mod_alt;
|
||||
if(currentEvent.modifiers & rightControlKey) key.mod += mod_ctrl;
|
||||
itemHit = process_click(currentEvent.where,key.mod);
|
||||
break;
|
||||
}
|
||||
ctrlIter ctrl = controls.find(itemHit);
|
||||
if(ctrl != controls.end()) ctrl->second->triggerClickHandler(*this,itemHit,key.mod);
|
||||
}
|
||||
EndAppModalStateForWindow(win);
|
||||
HideWindow(win);
|
||||
}
|
||||
|
||||
void cDialog::setBg(short n){
|
||||
bg = n;
|
||||
}
|
||||
|
||||
void cDialog::setDefTextClr(RGBColor clr){
|
||||
defTextClr = clr;
|
||||
}
|
||||
|
||||
void cDialog::toast(){
|
||||
dialogNotToast = false;
|
||||
}
|
||||
|
||||
std::string cDialog::process_keystroke(cKey keyHit){
|
||||
unsigned long dummy;
|
||||
ctrlIter iter = controls.begin();
|
||||
while(iter != controls.end()){
|
||||
if(iter->second->visible && iter->second->isClickable() && iter->second->key == keyHit){
|
||||
iter->second->depressed = true;
|
||||
iter->second->draw();
|
||||
if (play_sounds) {
|
||||
if(typeid(iter->second) == typeid(cLed*))
|
||||
play_sound(34);
|
||||
else play_sound(37);
|
||||
Delay(6,&dummy);
|
||||
}
|
||||
else Delay(14,&dummy);
|
||||
iter->second->depressed = false;
|
||||
iter->second->draw();
|
||||
Delay(8,&dummy);
|
||||
return iter->first;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
// If you get an escape and it isn't processed, make it an enter.
|
||||
if(keyHit.spec && keyHit.k == key_esc){
|
||||
keyHit.k = key_enter;
|
||||
return process_keystroke(keyHit);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string cDialog::process_click(Point where, eKeyMod mods){
|
||||
ctrlIter iter = controls.begin();
|
||||
while(iter != controls.end()){
|
||||
if(iter->second->visible && iter->second->isClickable() && PtInRect(where,&iter->second->frame)){
|
||||
if(iter->second->handleClick())
|
||||
return iter->first;
|
||||
else return "";
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
xBadNode::xBadNode(std::string t) throw() : type(t), msg(NULL) {}
|
||||
|
||||
const char* xBadNode::what() throw() {
|
||||
if(msg == NULL){
|
||||
char* s = new (nothrow) char[100];
|
||||
if(s == NULL){
|
||||
printf("Allocation of memory for error message failed, bailing out...");
|
||||
abort();
|
||||
}
|
||||
sprintf(s,"XML Parse Error: Unknown element %s encountered.",type.c_str());
|
||||
msg = s;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
xBadNode::~xBadNode() throw(){
|
||||
if(msg != NULL) delete msg;
|
||||
}
|
||||
|
||||
xBadAttr::xBadAttr(std::string t, std::string n) throw() : type(t), name(n), msg(NULL) {}
|
||||
|
||||
const char* xBadAttr::what() throw() {
|
||||
if(msg == NULL){
|
||||
char* s = new (nothrow) char[100];
|
||||
if(s == NULL){
|
||||
printf("Allocation of memory for error message failed, bailing out...");
|
||||
abort();
|
||||
}
|
||||
sprintf(s,"XML Parse Error: Unknown attribute %s encountered on element %s.",name.c_str(),type.c_str());
|
||||
msg = s;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
xBadAttr::~xBadAttr() throw(){
|
||||
if(msg != NULL) delete msg;
|
||||
}
|
||||
|
||||
xBadVal::xBadVal(std::string t, std::string n, std::string v) throw() : type(t), name(n), val(v), msg(NULL) {}
|
||||
|
||||
const char* xBadVal::what() throw() {
|
||||
if(msg == NULL){
|
||||
char* s = new (nothrow) char[100];
|
||||
if(s == NULL){
|
||||
printf("Allocation of memory for error message failed, bailing out...");
|
||||
abort();
|
||||
}
|
||||
sprintf(s,"XML Parse Error: Invalid value %s for attribute %s encountered on element %s.",val.c_str(),name.c_str(),type.c_str());
|
||||
msg = s;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
xBadVal::~xBadVal() throw(){
|
||||
if(msg != NULL) delete msg;
|
||||
}
|
||||
|
||||
void cDialog::draw(){
|
||||
GrafPtr old_port;
|
||||
GetPort(&old_port);
|
||||
SetPortWindowPort(win);
|
||||
FillCRect(&winRect,::bg[bg]);
|
||||
|
||||
ctrlIter iter = controls.begin();
|
||||
while(iter != controls.end()){
|
||||
iter->second->draw();
|
||||
iter++;
|
||||
}
|
||||
|
||||
SetPort(old_port);
|
||||
}
|
Reference in New Issue
Block a user