dialogs can have a button respond to Escape
I'm planning to make it so the Enter key will never cancel a yes/no dialog. To do this, I'm adding an Escape button to dialogs. So cancel/accept keyboard shortcuts will be predictable and intuitive. Dialogs that require extra confirmation will have a 'really confirm' LED.
This commit is contained in:
@@ -158,7 +158,7 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
|
||||
Iterator<Attribute> attr;
|
||||
Iterator<Element> node;
|
||||
string type, name, val, defbtn;
|
||||
string type, name, val, defbtn, escbtn;
|
||||
|
||||
xml.FirstChildElement()->GetValue(&type);
|
||||
if(type != "dialog") throw xBadNode(type,xml.FirstChildElement()->Row(),xml.FirstChildElement()->Column(),fname);
|
||||
@@ -181,8 +181,10 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
throw xBadVal("text",name,val,attr->Row(),attr->Column(),fname);
|
||||
}
|
||||
defTextClr = clr;
|
||||
} else if(name == "defbtn") {
|
||||
}else if(name == "defbtn"){
|
||||
defbtn = val;
|
||||
}else if(name == "escbtn"){
|
||||
escbtn = val;
|
||||
}else if(name != "debug")
|
||||
throw xBadAttr(type,name,attr->Row(),attr->Column(),fname);
|
||||
}
|
||||
@@ -337,6 +339,8 @@ void cDialog::loadFromFile(const DialogDefn& file){
|
||||
|
||||
// Set the default button.
|
||||
setDefaultButton(defbtn);
|
||||
// Set the escape button.
|
||||
setEscapeButton(escbtn);
|
||||
|
||||
// Sort by tab order
|
||||
// First, fill any gaps that might have been left, using ones that had no specific tab order
|
||||
@@ -912,11 +916,12 @@ bool cDialog::addLabelFor(std::string key, std::string label, eLabelPos where, s
|
||||
void cDialog::process_keystroke(cKey keyHit){
|
||||
ctrlIter iter = controls.begin();
|
||||
bool enterKeyHit = keyHit.spec && keyHit.k == key_enter;
|
||||
bool escapeKeyHit = keyHit.spec && keyHit.k == key_esc;
|
||||
while(iter != controls.end()){
|
||||
cControl* ctrl = iter->second;
|
||||
if(ctrl->isVisible()){
|
||||
if(ctrl->isClickable() &&
|
||||
(ctrl->getAttachedKey() == keyHit || (ctrl->isDefault() && enterKeyHit))){
|
||||
(ctrl->getAttachedKey() == keyHit || (ctrl->isDefault() && enterKeyHit) || (ctrl->isEscape() && escapeKeyHit))){
|
||||
|
||||
ctrl->handleKeyTriggered(*this);
|
||||
return;
|
||||
@@ -940,11 +945,6 @@ void cDialog::process_keystroke(cKey keyHit){
|
||||
}
|
||||
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;
|
||||
process_keystroke(keyHit);
|
||||
}
|
||||
}
|
||||
|
||||
void cDialog::process_click(location where, eKeyMod mods, cFramerateLimiter& fps_limiter){
|
||||
@@ -1157,21 +1157,38 @@ bool cDialog::hasControl(std::string id) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void cDialog::setDefaultButton(std::string defbtn) {
|
||||
if(!defbtn.empty() && !hasControl(defbtn)){
|
||||
void cDialog::setSpecialButton(std::string& name_ref, std::string name, bool escape) {
|
||||
if(!name.empty() && !hasControl(name)){
|
||||
// this is likely because the dialogxml is malformed. maybe the linter already checks this,
|
||||
// but the engine might as well also.
|
||||
throw std::string { "Requested default button does not exist: " } + defbtn;
|
||||
throw std::string { "Requested button does not exist: " } + name;
|
||||
}
|
||||
if(!defaultButton.empty()){
|
||||
getControl(defaultButton).setDefault(false);
|
||||
if(!name_ref.empty()){
|
||||
if(escape){
|
||||
getControl(name_ref).setEscape(false);
|
||||
}else{
|
||||
getControl(name_ref).setDefault(false);
|
||||
}
|
||||
name_ref = "";
|
||||
}
|
||||
if(!defbtn.empty()){
|
||||
defaultButton = defbtn;
|
||||
getControl(defaultButton).setDefault(true);
|
||||
if(!name.empty()){
|
||||
name_ref = name;
|
||||
if(escape){
|
||||
getControl(name).setEscape(true);
|
||||
}else{
|
||||
getControl(name).setDefault(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cDialog::setDefaultButton(std::string defbtn) {
|
||||
setSpecialButton(defaultButton, defbtn, false);
|
||||
}
|
||||
|
||||
void cDialog::setEscapeButton(std::string escbtn) {
|
||||
setSpecialButton(escapeButton, escbtn, true);
|
||||
}
|
||||
|
||||
const char*const xBadVal::CONTENT = "$content$";
|
||||
|
||||
cDialogIterator::cDialogIterator() : parent(nullptr) {}
|
||||
|
@@ -266,7 +266,9 @@ public:
|
||||
inline void setAnimPictFPS(int fps) { if(fps == -1) fps = 2; anim_pict_fps = fps; }
|
||||
inline void setDoAnimations(bool value) { doAnimations = value; }
|
||||
void setDefaultButton(std::string defbtn);
|
||||
void setEscapeButton(std::string escbtn);
|
||||
private:
|
||||
void setSpecialButton(std::string& name_ref, std::string name, bool escape);
|
||||
void draw();
|
||||
void handle_events();
|
||||
void handle_one_event(const sf::Event&, cFramerateLimiter& fps_limiter);
|
||||
@@ -277,6 +279,7 @@ private:
|
||||
boost::any result;
|
||||
std::string fname;
|
||||
std::string defaultButton;
|
||||
std::string escapeButton;
|
||||
sf::Clock animTimer, paintTimer;
|
||||
friend class cControl;
|
||||
friend class cContainer;
|
||||
|
@@ -172,6 +172,8 @@ public:
|
||||
std::string getAttachedKeyDescription() const;
|
||||
inline void setDefault(bool value) { isDefaultControl = value; }
|
||||
inline bool isDefault() { return isDefaultControl; }
|
||||
inline void setEscape(bool value) { isEscapeControl = value; }
|
||||
inline bool isEscape() { return isEscapeControl; }
|
||||
/// Attach an event handler to this control.
|
||||
/// @tparam t The type of event to attach.
|
||||
/// @param handler The event handler function or functor. Its signature depends on the event type.
|
||||
@@ -477,6 +479,8 @@ protected:
|
||||
cKey key;
|
||||
/// Whether the control is the default control of its dialog.
|
||||
bool isDefaultControl = false;
|
||||
/// Whether the control is the cancel control of its dialog.
|
||||
bool isEscapeControl = false;
|
||||
|
||||
/// Draw a frame around the control.
|
||||
/// @param amt How much to offset the frame from the control's bounding rect.
|
||||
|
Reference in New Issue
Block a user