Make stack control a real container instead of a controller
- Also add framed/outlined attributes to it and to LED groups
This commit is contained in:
@@ -651,11 +651,15 @@ void cLedGroup::hide(std::string id){
|
||||
choices[id]->hide();
|
||||
}
|
||||
|
||||
void cLedGroup::setFormat(eFormat prop, short) throw(xUnsupportedProp) {
|
||||
throw xUnsupportedProp(prop);
|
||||
void cLedGroup::setFormat(eFormat prop, short val) throw(xUnsupportedProp) {
|
||||
if(prop == TXT_FRAME) drawFramed = val;
|
||||
else if(prop == TXT_FRAMESTYLE) frameStyle = eFrameStyle(val);
|
||||
else throw xUnsupportedProp(prop);
|
||||
}
|
||||
|
||||
short cLedGroup::getFormat(eFormat prop) throw(xUnsupportedProp) {
|
||||
if(prop == TXT_FRAME) return drawFramed;
|
||||
else if(prop == TXT_FRAMESTYLE) return frameStyle;
|
||||
throw xUnsupportedProp(prop);
|
||||
}
|
||||
|
||||
@@ -737,6 +741,7 @@ void cLedGroup::draw(){
|
||||
iter->second->draw();
|
||||
iter++;
|
||||
}
|
||||
if(drawFramed) drawFrame(2, frameStyle);
|
||||
}
|
||||
|
||||
void cButton::setBtnType(eBtnType newType){
|
||||
@@ -806,7 +811,18 @@ std::string cLedGroup::parse(ticpp::Element& who, std::string fname) {
|
||||
attr->GetValue(&id);
|
||||
// else if(name == "fromlist")
|
||||
// attr->GetValue(&fromList);
|
||||
else throw xBadAttr("group",name,attr->Row(),attr->Column(),fname);
|
||||
else if(name == "framed"){
|
||||
std::string val;
|
||||
attr->GetValue(&val);
|
||||
if(val == "true") setFormat(TXT_FRAME, true);
|
||||
}else if(name == "outline") {
|
||||
std::string val;
|
||||
attr->GetValue(&val);
|
||||
if(val == "solid") setFormat(TXT_FRAMESTYLE, FRM_SOLID);
|
||||
else if(val == "inset") setFormat(TXT_FRAMESTYLE, FRM_INSET);
|
||||
else if(val == "outset") setFormat(TXT_FRAMESTYLE, FRM_OUTSET);
|
||||
else if(val == "double") setFormat(TXT_FRAMESTYLE, FRM_DOUBLE);
|
||||
}else throw xBadAttr("group",name,attr->Row(),attr->Column(),fname);
|
||||
}
|
||||
for(node = node.begin(&who); node != node.end(); node++){
|
||||
std::string val;
|
||||
|
@@ -163,6 +163,7 @@ private:
|
||||
class cLedGroup : public cContainer {
|
||||
click_callback_t onClick;
|
||||
focus_callback_t onFocus;
|
||||
bool drawFramed;
|
||||
std::map<std::string,cLed*> choices;
|
||||
std::string fromList;
|
||||
std::string curSelect, prevSelect;
|
||||
|
@@ -43,7 +43,7 @@ const char* xHandlerNotSupported::clickMsg = "This control cannot handle click e
|
||||
xHandlerNotSupported::xHandlerNotSupported(bool isFocus){
|
||||
this->isFocus = isFocus;
|
||||
}
|
||||
const char* xHandlerNotSupported::what(){
|
||||
const char* xHandlerNotSupported::what() const throw() {
|
||||
if(isFocus) return focusMsg;
|
||||
else return clickMsg;
|
||||
}
|
||||
@@ -55,7 +55,7 @@ xUnsupportedProp::xUnsupportedProp(eFormat prop) throw(){
|
||||
xUnsupportedProp::~xUnsupportedProp() throw(){
|
||||
if(msg != nullptr) delete msg;
|
||||
}
|
||||
const char* xUnsupportedProp::what() throw(){
|
||||
const char* xUnsupportedProp::what() const throw(){
|
||||
if(msg == nullptr){
|
||||
msg = new char[62];
|
||||
std::string s;
|
||||
|
@@ -64,7 +64,7 @@ typedef std::function<bool(cDialog&,std::string,eKeyMod)> click_callback_t;
|
||||
typedef std::function<bool(cDialog&,std::string,bool)> focus_callback_t;
|
||||
|
||||
/// Thrown when you try to set a handler that the control does not support.
|
||||
class xHandlerNotSupported : std::exception {
|
||||
class xHandlerNotSupported : public std::exception {
|
||||
static const char* focusMsg;
|
||||
static const char* clickMsg;
|
||||
bool isFocus;
|
||||
@@ -73,20 +73,20 @@ public:
|
||||
/// @param isFocus true to indicate a focus event, false for a click event.
|
||||
xHandlerNotSupported(bool isFocus);
|
||||
/// @return The error message.
|
||||
const char* what();
|
||||
const char* what() const throw();
|
||||
};
|
||||
|
||||
/// Thrown when you try to set or retrieve a formatting property that the control does not support.
|
||||
class xUnsupportedProp : std::exception {
|
||||
class xUnsupportedProp : public std::exception {
|
||||
eFormat whichProp;
|
||||
char* msg;
|
||||
mutable char* msg;
|
||||
public:
|
||||
/// Construct a new exception.
|
||||
/// @param prop The unsupported format property.
|
||||
xUnsupportedProp(eFormat prop) throw();
|
||||
~xUnsupportedProp() throw();
|
||||
/// @return The error message.
|
||||
const char* what() throw();
|
||||
const char* what() const throw();
|
||||
};
|
||||
|
||||
/// The superclass of all dialog controls.
|
||||
|
@@ -13,6 +13,15 @@
|
||||
#include "pict.hpp"
|
||||
#include "scrollbar.hpp"
|
||||
|
||||
bool cStack::hasChild(std::string id) {
|
||||
return controls.find(id) != controls.end();
|
||||
}
|
||||
|
||||
cControl& cStack::getChild(std::string id) {
|
||||
if(!hasChild(id)) throw std::invalid_argument(id + " was not found in the stack");
|
||||
return *controls[id];
|
||||
}
|
||||
|
||||
void cStack::attachClickHandler(click_callback_t f) throw(xHandlerNotSupported) {
|
||||
onClick = f;
|
||||
}
|
||||
@@ -21,23 +30,21 @@ void cStack::attachFocusHandler(focus_callback_t) throw(xHandlerNotSupported) {
|
||||
throw xHandlerNotSupported(true);
|
||||
}
|
||||
|
||||
// TODO: The only reason the handleClick and delegation here is needed is because the engine currently has no concept of layering.
|
||||
// This means a stack hides any of its controls that happen to end up underneath it.
|
||||
bool cStack::triggerClickHandler(cDialog& me, std::string id, eKeyMod mods) {
|
||||
std::string which_clicked = clicking;
|
||||
clicking = "";
|
||||
|
||||
if(onClick) onClick(me, id, mods);
|
||||
return parent->getControl(which_clicked).triggerClickHandler(me, id, mods);
|
||||
return controls[which_clicked]->triggerClickHandler(me, which_clicked, mods);
|
||||
}
|
||||
|
||||
bool cStack::handleClick(location where) {
|
||||
std::string which_clicked;
|
||||
auto iter = controls.begin();
|
||||
while(iter != controls.end()){
|
||||
if(parent->getControl(*iter).isVisible() && where.in(parent->getControl(*iter).getBounds())){
|
||||
if(parent->getControl(*iter).handleClick(where)) {
|
||||
which_clicked = *iter;
|
||||
if(iter->second->isVisible() && where.in(iter->second->getBounds())){
|
||||
if(iter->second->handleClick(where)) {
|
||||
which_clicked = iter->first;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -50,11 +57,15 @@ bool cStack::handleClick(location where) {
|
||||
return true;
|
||||
}
|
||||
|
||||
void cStack::setFormat(eFormat prop, short) throw(xUnsupportedProp) {
|
||||
throw xUnsupportedProp(prop);
|
||||
void cStack::setFormat(eFormat prop, short val) throw(xUnsupportedProp) {
|
||||
if(prop == TXT_FRAME) drawFramed = val;
|
||||
else if(prop == TXT_FRAMESTYLE) frameStyle = eFrameStyle(val);
|
||||
else throw xUnsupportedProp(prop);
|
||||
}
|
||||
|
||||
short cStack::getFormat(eFormat prop) throw(xUnsupportedProp) {
|
||||
if(prop == TXT_FRAME) return drawFramed;
|
||||
else if(prop == TXT_FRAMESTYLE) return frameStyle;
|
||||
throw xUnsupportedProp(prop);
|
||||
}
|
||||
|
||||
@@ -71,15 +82,22 @@ bool cStack::isClickable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
void cStack::draw() {}
|
||||
void cStack::draw() {
|
||||
if(!isVisible()) return;
|
||||
for(auto& p : controls) {
|
||||
p.second->draw();
|
||||
}
|
||||
if(drawFramed) drawFrame(2, frameStyle);
|
||||
}
|
||||
|
||||
bool cStack::setPage(size_t n) {
|
||||
if(n >= nPages) return false;
|
||||
if(n == curPage) return true;
|
||||
cTextField* focus = parent->getFocus();
|
||||
bool failed = false;
|
||||
for(auto id : controls) {
|
||||
cControl& ctrl = parent->getControl(id);
|
||||
for(auto p : controls) {
|
||||
const std::string& id = p.first;
|
||||
cControl& ctrl = *p.second;
|
||||
storage[curPage][id] = ctrl.store();
|
||||
if(!ctrl.triggerFocusHandler(*parent, id, true))
|
||||
failed = true;
|
||||
@@ -119,7 +137,7 @@ void cStack::recalcRect() {
|
||||
auto iter = controls.begin();
|
||||
frame = {INT_MAX, INT_MAX, 0, 0};
|
||||
while(iter != controls.end()){
|
||||
cControl& ctrl = parent->getControl(*iter);
|
||||
cControl& ctrl = *iter->second;
|
||||
rectangle otherFrame = ctrl.getBounds();
|
||||
if(otherFrame.right > frame.right)
|
||||
frame.right = otherFrame.right;
|
||||
@@ -134,15 +152,9 @@ void cStack::recalcRect() {
|
||||
frame.inset(-6,-6);
|
||||
}
|
||||
|
||||
cControl& cStack::operator[](std::string id) {
|
||||
auto iter = std::find(controls.begin(), controls.end(), id);
|
||||
if(iter == controls.end()) throw std::invalid_argument(id + " does not exist in the stack.");
|
||||
return parent->getControl(id);
|
||||
}
|
||||
|
||||
void cStack::fillTabOrder(std::vector<int>& specificTabs, std::vector<int>& reverseTabs) {
|
||||
for(auto id : controls) {
|
||||
cControl& ctrl = parent->getControl(id);
|
||||
for(auto p : controls) {
|
||||
cControl& ctrl = *p.second;
|
||||
if(ctrl.getType() == CTRL_FIELD) {
|
||||
cTextField& field = dynamic_cast<cTextField&>(ctrl);
|
||||
if(field.tabOrder > 0)
|
||||
@@ -153,7 +165,7 @@ void cStack::fillTabOrder(std::vector<int>& specificTabs, std::vector<int>& reve
|
||||
}
|
||||
}
|
||||
|
||||
cStack::cStack(cDialog& parent) : cControl(CTRL_STACK, parent), curPage(0), nPages(0) {}
|
||||
cStack::cStack(cDialog& parent) : cContainer(CTRL_STACK, parent), curPage(0), nPages(0) {}
|
||||
|
||||
std::string cStack::parse(ticpp::Element& who, std::string fname) {
|
||||
using namespace ticpp;
|
||||
@@ -168,9 +180,19 @@ std::string cStack::parse(ticpp::Element& who, std::string fname) {
|
||||
size_t val;
|
||||
attr->GetValue(&val);
|
||||
setPageCount(val);
|
||||
}else if(name == "framed"){
|
||||
std::string val;
|
||||
attr->GetValue(&val);
|
||||
if(val == "true") setFormat(TXT_FRAME, true);
|
||||
}else if(name == "outline") {
|
||||
std::string val;
|
||||
attr->GetValue(&val);
|
||||
if(val == "solid") setFormat(TXT_FRAMESTYLE, FRM_SOLID);
|
||||
else if(val == "inset") setFormat(TXT_FRAMESTYLE, FRM_INSET);
|
||||
else if(val == "outset") setFormat(TXT_FRAMESTYLE, FRM_OUTSET);
|
||||
else if(val == "double") setFormat(TXT_FRAMESTYLE, FRM_DOUBLE);
|
||||
} 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();
|
||||
@@ -178,39 +200,31 @@ std::string cStack::parse(ticpp::Element& who, std::string fname) {
|
||||
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);
|
||||
controls.insert(field);
|
||||
// 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);
|
||||
controls.insert(text);
|
||||
} else if(val == "pict") {
|
||||
auto pict = parent->parse<cPict>(*node);
|
||||
parent->add(pict.second, pict.second->getBounds(), pict.first);
|
||||
stack.push_back(pict.first);
|
||||
controls.insert(pict);
|
||||
} else if(val == "slider") {
|
||||
auto slide = parent->parse<cScrollbar>(*node);
|
||||
parent->add(slide.second, slide.second->getBounds(), slide.first);
|
||||
stack.push_back(slide.first);
|
||||
controls.insert(slide);
|
||||
} else if(val == "button") {
|
||||
auto button = parent->parse<cButton>(*node);
|
||||
parent->add(button.second, button.second->getBounds(), button.first);
|
||||
stack.push_back(button.first);
|
||||
controls.insert(button);
|
||||
} else if(val == "led") {
|
||||
auto led = parent->parse<cLed>(*node);
|
||||
parent->add(led.second, led.second->getBounds(), led.first);
|
||||
stack.push_back(led.first);
|
||||
controls.insert(led);
|
||||
} else if(val == "group") {
|
||||
auto group = parent->parse<cLedGroup>(*node);
|
||||
parent->add(group.second, group.second->getBounds(), group.first);
|
||||
stack.push_back(group.first);
|
||||
controls.insert(group);
|
||||
} 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;
|
||||
}
|
||||
|
@@ -20,13 +20,9 @@
|
||||
/// and stores the hidden portion of the array within itself.
|
||||
/// @note The stack itself provides no mechanism for switching pages. You will need
|
||||
/// other controls, not within the stack, to trigger the switch.
|
||||
/// @note Unlike an LED group, a stack does not have ownership of its contained controls.
|
||||
/// It merely keeps track of a reference to the controls, which are in the parent dialog's
|
||||
/// dictionary. Thus, a stack requires a parent dialog.
|
||||
///
|
||||
/// A stack supports a click handler, which is triggered prior to passing it on to the
|
||||
/// clicked control, though at present this should not be relied on due to the lack of
|
||||
/// any layering concept in the engine.
|
||||
/// clicked control.
|
||||
///
|
||||
/// When the stack's page is changed, the focus handlers for any edit text fields in
|
||||
/// the stack are triggered with the third parameter set to true to indicate they are
|
||||
@@ -34,13 +30,14 @@
|
||||
/// In addition, if one of the fields in the stack previously held the focus, its
|
||||
/// focus handler is called with the third parameter set to false, to indicate that
|
||||
/// it is gaining focus.
|
||||
class cStack : public cControl {
|
||||
class cStack : public cContainer {
|
||||
friend class cDialog; // So it can insert controls
|
||||
size_t nPages, curPage = 0;
|
||||
std::string clicking;
|
||||
std::vector<std::map<std::string,storage_t>> storage;
|
||||
std::vector<std::string> controls;
|
||||
std::map<std::string,cControl*> controls;
|
||||
click_callback_t onClick;
|
||||
bool drawFramed;
|
||||
public:
|
||||
std::string parse(ticpp::Element& who, std::string fname);
|
||||
void attachClickHandler(click_callback_t f) throw(xHandlerNotSupported);
|
||||
@@ -53,6 +50,8 @@ public:
|
||||
sf::Color getColour() throw(xUnsupportedProp);
|
||||
bool isClickable();
|
||||
void draw();
|
||||
bool hasChild(std::string id);
|
||||
cControl& getChild(std::string id);
|
||||
/// Switch the stack to a particular page.
|
||||
/// You need to do this before retrieving data from that page.
|
||||
/// @param The new page number
|
||||
@@ -74,9 +73,6 @@ public:
|
||||
size_t getPageCount();
|
||||
/// Recalculate the stack's bounding rect based on its contained controls.
|
||||
void recalcRect();
|
||||
/// Retrieve a control reference from the stack.
|
||||
/// @param id The control's unique ID
|
||||
cControl& operator[](std::string id);
|
||||
/// Adds any fields in this stack to the tab order building arrays.
|
||||
/// Meant for internal use.
|
||||
void fillTabOrder(std::vector<int>& specificTabs, std::vector<int>& reverseTabs);
|
||||
|
Reference in New Issue
Block a user