Implement key shortcuts to jump alphabetically in scen list.

Fix #336
This commit is contained in:
2025-05-29 12:58:15 -05:00
parent 731edb26e3
commit fd9132a0dd
4 changed files with 78 additions and 8 deletions

View File

@@ -46,7 +46,37 @@
<text outline='double' name='start3' top='205' left='59' width='342' height='84'/> <text outline='double' name='start3' top='205' left='59' width='342' height='84'/>
</page> </page>
</stack> </stack>
<button name='cancel' type='regular' top='294' left='5'>Cancel</button>
<button name='core' def-key='0' type='tiny' top='294' left='5'>Core</button>
<text name='custom' relative='pos neg' size='large' rel-anchor='prev' left='5' top='2'>Custom:</text>
<button name='a' def-key='a' type='tiny' relative='pos pos-in' rel-anchor='prev' top='2' left='3'>A</button>
<button name='b' def-key='b' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>B</button>
<button name='c' def-key='c' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>C</button>
<button name='d' def-key='d' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>D</button>
<button name='e' def-key='e' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>E</button>
<button name='f' def-key='f' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>F</button>
<button name='g' def-key='g' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>G</button>
<button name='h' def-key='h' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>H</button>
<button name='i' def-key='i' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>I</button>
<button name='j' def-key='j' type='tiny' relative='pos-in pos' anchor='a' top='2' left='0'>J</button>
<button name='k' def-key='k' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>K</button>
<button name='l' def-key='l' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>L</button>
<button name='m' def-key='m' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>M</button>
<button name='n' def-key='n' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>N</button>
<button name='o' def-key='o' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>O</button>
<button name='p' def-key='p' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>P</button>
<button name='q' def-key='q' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>Q</button>
<button name='r' def-key='r' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>R</button>
<button name='s' def-key='s' type='tiny' relative='pos-in pos' anchor='j' top='2' left='0'>S</button>
<button name='t' def-key='t' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>T</button>
<button name='u' def-key='u' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>U</button>
<button name='v' def-key='v' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>V</button>
<button name='w' def-key='w' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>W</button>
<button name='x' def-key='x' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>X</button>
<button name='y' def-key='y' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>Y</button>
<button name='z' def-key='z' type='tiny' relative='pos pos-in' rel-anchor='prev' top='0' left='4'>Z</button>
<button name='cancel' type='regular' top='330' left='5'>Cancel</button>
<button name='prev' type='left' def-key='left' relative='pos pos-in' rel-anchor='prev' top='0' left='14'/> <button name='prev' type='left' def-key='left' relative='pos pos-in' rel-anchor='prev' top='0' left='14'/>
<button name='next' type='right' def-key='right' relative='pos pos-in' rel-anchor='prev' top='0' left='0'/> <button name='next' type='right' def-key='right' relative='pos pos-in' rel-anchor='prev' top='0' left='0'/>
<button name='folder' type='large' relative='pos pos-in' rel-anchor='prev' top='0' left='14'>Show Folder</button> <button name='folder' type='large' relative='pos pos-in' rel-anchor='prev' top='0' left='14'>Show Folder</button>

View File

@@ -1774,6 +1774,21 @@ class cChooseScenario {
} }
} }
stk.setPage(0); stk.setPage(0);
// Show/hide alphabetical buttons
me["core"].hide();
if(scen_headers.size() > 0){
me["core"].show();
}
for(int i = 0; i < 26; ++i){
me[std::string(1, (char)('a' + i))].hide();
}
for(auto& hdr : scen_headers){
// I just checked, and the scenario editor will let you name your scenario "" or " "!
std::string name = name_alphabetical(hdr.name);
if(!name.empty())
me[name.substr(0, 1)].show();
}
} }
bool doCancel() { bool doCancel() {
@@ -1850,6 +1865,24 @@ public:
me["scen3"].attachClickHandler(std::bind(&cChooseScenario::doSelectScenario, this, 2)); me["scen3"].attachClickHandler(std::bind(&cChooseScenario::doSelectScenario, this, 2));
me["folder"].attachClickHandler(std::bind(&cChooseScenario::showFolder, this)); me["folder"].attachClickHandler(std::bind(&cChooseScenario::showFolder, this));
me["refresh"].attachClickHandler(std::bind(&cChooseScenario::refreshList, this)); me["refresh"].attachClickHandler(std::bind(&cChooseScenario::refreshList, this));
me["core"].attachClickHandler([](cDialog& me, std::string, eKeyMod) -> bool {
auto& stk = dynamic_cast<cStack&>(me["list"]);
stk.setPage(0);
return true;
});
for(int i = 0; i < 26; ++i){
std::string letter(1, (char)('a' + i));
me[letter].attachClickHandler([this](cDialog& me, std::string letter, eKeyMod) -> bool {
size_t first_letter_idx = std::find_if(scen_headers.begin(), scen_headers.end(), [letter](scen_header_type hdr) -> bool {
std::string name = name_alphabetical(hdr.name);
return !name.empty() && name.substr(0, 1) == letter;
}) - scen_headers.begin();
size_t page = 1 + first_letter_idx / 3;
auto& stk = dynamic_cast<cStack&>(me["list"]);
stk.setPage(page);
return true;
});
}
put_scen_info(); put_scen_info();

View File

@@ -335,6 +335,16 @@ void start_data_dump() {
const std::set<std::string> scen_extensions = {".boes", ".exs"}; const std::set<std::string> scen_extensions = {".boes", ".exs"};
extern fs::path scenDir; extern fs::path scenDir;
std::string name_alphabetical(std::string a) {
// The scenario editor will let you prepend whitespace to a scenario name :(
boost::algorithm::trim_left(a);
std::transform(a.begin(), a.end(), a.begin(), tolower);
if(a.substr(0,2) == "a ") a.erase(a.begin(), a.begin() + 2);
else if(a.substr(0,4) == "the ") a.erase(a.begin(), a.begin() + 4);
return a;
}
std::vector<scen_header_type> build_scen_headers() { std::vector<scen_header_type> build_scen_headers() {
fs::create_directories(scenDir); fs::create_directories(scenDir);
@@ -391,13 +401,7 @@ std::vector<scen_header_type> build_scen_headers() {
} }
if(!scen_headers.empty()){ if(!scen_headers.empty()){
std::sort(scen_headers.begin(), scen_headers.end(), [](scen_header_type hdr_a, scen_header_type hdr_b) -> bool { std::sort(scen_headers.begin(), scen_headers.end(), [](scen_header_type hdr_a, scen_header_type hdr_b) -> bool {
std::string a = hdr_a.name, b = hdr_b.name; std::string a = name_alphabetical(hdr_a.name), b = name_alphabetical(hdr_b.name);
std::transform(a.begin(), a.end(), a.begin(), tolower);
std::transform(b.begin(), b.end(), b.begin(), tolower);
if(a.substr(0,2) == "a ") a.erase(a.begin(), a.begin() + 2);
else if(a.substr(0,4) == "the ") a.erase(a.begin(), a.begin() + 4);
if(b.substr(0,2) == "a ") b.erase(b.begin(), b.begin() + 2);
else if(b.substr(0,4) == "the ") b.erase(b.begin(), b.begin() + 4);
return a < b; return a < b;
}); });
} }

View File

@@ -34,4 +34,7 @@ void alter_rect(rectangle *r);
bool check_autosave_trigger(std::string reason); bool check_autosave_trigger(std::string reason);
void try_auto_save(std::string reason); void try_auto_save(std::string reason);
// Turn lower-case and strip articles from the front of a scenario title, for alphabetization
std::string name_alphabetical(std::string scenario_name);
#endif #endif