mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
cfg: clean up stale buttons and lights alt bindings on save (#534)
## Link to GitHub Issue, if one exists n/a ## Description of change For buttons and lights, it's possible to have multiple alternatives. When you create alternatives and then clear then, the config files continue to have stale entries. This is because alternatives are stored in a vector and elements are never deleted when unbound; they get written out to the XML on modification. These stale XML entries live forever, and get loaded on next startup of spice. This PR fixes that by deleting stale entries - basically, XML nodes will be kept only until the last valid node (properly bound button or light), trimming the trailing invalid entries. ## Testing Manual testing, validating XML.
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "util/logging.h"
|
#include "util/logging.h"
|
||||||
|
#include "cfg/button.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This code absolutely sucks.
|
* This code absolutely sucks.
|
||||||
@@ -510,8 +511,10 @@ bool Config::updateBinding(const Game &game, const Button &button, int alternati
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tinyxml2::XMLElement *gameButtonNode = nullptr;
|
||||||
|
|
||||||
// iterate button nodes
|
// iterate button nodes
|
||||||
tinyxml2::XMLElement *gameButtonNode = gameButtonsNode->FirstChildElement("button");
|
gameButtonNode = gameButtonsNode->FirstChildElement("button");
|
||||||
int button_count = 0;
|
int button_count = 0;
|
||||||
while (gameButtonNode != nullptr) {
|
while (gameButtonNode != nullptr) {
|
||||||
const char *buttonNodeName = gameButtonNode->Attribute("name");
|
const char *buttonNodeName = gameButtonNode->Attribute("name");
|
||||||
@@ -574,6 +577,39 @@ bool Config::updateBinding(const Game &game, const Button &button, int alternati
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim the trailing invalid (unbound) alternatives
|
||||||
|
tinyxml2::XMLElement *to_delete = nullptr;
|
||||||
|
gameButtonNode = gameButtonsNode->LastChildElement("button");
|
||||||
|
while (gameButtonNode != nullptr) {
|
||||||
|
const char *name = gameButtonNode->Attribute("name");
|
||||||
|
const char *devid = gameButtonNode->Attribute("devid");
|
||||||
|
int vkey = INVALID_VKEY;
|
||||||
|
gameButtonNode->QueryIntAttribute("vkey", &vkey);
|
||||||
|
|
||||||
|
// wrong button, ignore and keep iterating backwards
|
||||||
|
if (name == nullptr || std::string(name) != button.getName()) {
|
||||||
|
gameButtonNode = gameButtonNode->PreviousSiblingElement("button");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found a node for this button, which means to_delete is not the first one
|
||||||
|
// delete the node for to_delete
|
||||||
|
if (to_delete != nullptr) {
|
||||||
|
log_misc("cfg", "deleting excessive button binding for {}", name);
|
||||||
|
gameButtonsNode->DeleteChild(to_delete);
|
||||||
|
to_delete = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((devid == nullptr || strlen(devid) == 0) && vkey == INVALID_VKEY) {
|
||||||
|
// unbound button with no device ID, make a note of it so it can be deleted later
|
||||||
|
to_delete = gameButtonNode;
|
||||||
|
gameButtonNode = gameButtonNode->PreviousSiblingElement("button");
|
||||||
|
} else {
|
||||||
|
// valid binding found; stop iterating
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check if button was not found
|
// check if button was not found
|
||||||
if (button_count == 0) {
|
if (button_count == 0) {
|
||||||
return false;
|
return false;
|
||||||
@@ -760,6 +796,37 @@ bool Config::updateBinding(const Game &game, const Light &light, int alternative
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trim the trailing invalid (unbound) alternatives
|
||||||
|
tinyxml2::XMLElement *to_delete = nullptr;
|
||||||
|
gameLightNode = gameLightsNode->LastChildElement("light");
|
||||||
|
while (gameLightNode != nullptr) {
|
||||||
|
const char *name = gameLightNode->Attribute("name");
|
||||||
|
const char *devid = gameLightNode->Attribute("devid");
|
||||||
|
|
||||||
|
// wrong light, ignore and keep iterating backwards
|
||||||
|
if (name == nullptr || std::string(name) != light.getName()) {
|
||||||
|
gameLightNode = gameLightNode->PreviousSiblingElement("light");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// found a node for this button, which means to_delete is not the first one
|
||||||
|
// delete the node for to_delete
|
||||||
|
if (to_delete != nullptr) {
|
||||||
|
log_misc("cfg", "deleting excessive light binding for {}", name);
|
||||||
|
gameLightsNode->DeleteChild(to_delete);
|
||||||
|
to_delete = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devid == nullptr || strlen(devid) == 0) {
|
||||||
|
// unbound light, make a note of it so it can be deleted later
|
||||||
|
to_delete = gameLightNode;
|
||||||
|
gameLightNode = gameLightNode->PreviousSiblingElement("light");
|
||||||
|
} else {
|
||||||
|
// valid binding found; stop iterating
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// check if light was not found
|
// check if light was not found
|
||||||
if (light_count == 0) {
|
if (light_count == 0) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user