implement some Gui module hotkey guards

and clean up focus string matching logic
develop
Myk Taylor 2023-02-06 00:58:57 -08:00
parent 032b62dcbe
commit 9e318842a4
No known key found for this signature in database
4 changed files with 56 additions and 164 deletions

@ -958,17 +958,18 @@ Screens
[1] = "dwarfmode/Info/CREATURES/CITIZEN"
[2] = "dwardmode/Squads"
* ``dfhack.gui.matchFocusString(focus_string)``
* ``dfhack.gui.matchFocusString(focus_string[, viewscreen])``
Returns ``true`` if the given ``focus_string`` is found in the current
focus strings, or as a prefix to any of the focus strings, or ``false``
if no match is found. Matching is case insensitive.
if no match is found. Matching is case insensitive. If ``viewscreen`` is
specified, gets the focus strings to match from the given viewscreen.
* ``dfhack.gui.getCurFocus([skip_dismissed])``
Returns the focus string of the current viewscreen.
* ``dfhack.gui.getViewscreenByType(type [, depth])``
* ``dfhack.gui.getViewscreenByType(type[, depth])``
Returns the topmost viewscreen out of the top ``depth`` viewscreens with
the specified type (e.g. ``df.viewscreen_titlest``), or ``nil`` if none match.

@ -67,7 +67,7 @@ namespace DFHack
namespace Gui
{
DFHACK_EXPORT std::vector<std::string> getFocusStrings(df::viewscreen *top);
DFHACK_EXPORT bool matchFocusString(std::string focusString, bool prefixMatch = true);
DFHACK_EXPORT bool matchFocusString(std::string focus_string, df::viewscreen *top = NULL);
// Full-screen item details view

@ -57,6 +57,7 @@ using namespace DFHack;
#include "df/building_trapst.h"
#include "df/building_type.h"
#include "df/building_workshopst.h"
#include "df/cri_unitst.h"
#include "df/d_init.h"
#include "df/game_mode.h"
#include "df/general_ref.h"
@ -459,7 +460,7 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dwarfmode)
}
if (!newFocusString.size()) {
focusStrings.push_back(baseFocus);
focusStrings.push_back(baseFocus + "/Default");
}
}
@ -475,12 +476,14 @@ DEFINE_GET_FOCUS_STRING_HANDLER(dungeonmode)
}
*/
bool Gui::matchFocusString(std::string focusString, bool prefixMatch) {
focusString = toLower(focusString);
std::vector<std::string> currentFocusStrings = getFocusStrings(getCurViewscreen(true));
bool Gui::matchFocusString(std::string focus_string, df::viewscreen *top) {
focus_string = toLower(focus_string);
if (!top)
top = getCurViewscreen(true);
std::vector<std::string> currentFocusStrings = getFocusStrings(top);
return std::find_if(currentFocusStrings.begin(), currentFocusStrings.end(), [&focusString, &prefixMatch](std::string item) {
return prefixMatch ? prefix_matches(focusString, toLower(item)) : focusString == toLower(item);
return std::find_if(currentFocusStrings.begin(), currentFocusStrings.end(), [&focus_string](std::string item) {
return prefix_matches(focus_string, toLower(item));
}) != currentFocusStrings.end();
}
@ -535,17 +538,7 @@ std::vector<std::string> Gui::getFocusStrings(df::viewscreen* top)
bool Gui::default_hotkey(df::viewscreen *top)
{
// Default hotkey guard function
for (;top ;top = top->parent)
{
if (strict_virtual_cast<df::viewscreen_dwarfmodest>(top))
return true;
/* TODO: understand how this changes for v50
if (strict_virtual_cast<df::viewscreen_dungeonmodest>(top))
return true;
*/
}
return false;
return World::isFortressMode() || World::isAdventureMode();
}
bool Gui::anywhere_hotkey(df::viewscreen *) {
@ -553,24 +546,7 @@ bool Gui::anywhere_hotkey(df::viewscreen *) {
}
bool Gui::dwarfmode_hotkey(df::viewscreen *top) {
return World::isFortressMode();
}
bool Gui::unitjobs_hotkey(df::viewscreen *top)
{
/* TODO: understand how this changes for v50
// Require the unit or jobs list
return !!strict_virtual_cast<df::viewscreen_joblistst>(top) ||
!!strict_virtual_cast<df::viewscreen_unitlistst>(top);
*/ return false;
}
bool Gui::item_details_hotkey(df::viewscreen *top)
{
/* TODO: understand how this changes for v50
// Require the main dwarf mode screen
return !!strict_virtual_cast<df::viewscreen_itemst>(top);
*/ return false;
return matchFocusString("dwarfmode", top);
}
static bool has_cursor()
@ -595,164 +571,82 @@ bool Gui::workshop_job_hotkey(df::viewscreen *top)
if (!dwarfmode_hotkey(top))
return false;
/* TODO: understand how this changes for v50
using namespace ui_sidebar_mode;
using df::global::ui_workshop_in_add;
using df::global::ui_workshop_job_cursor;
switch (plotinfo->main.mode) {
case QueryBuilding:
{
if (!ui_workshop_job_cursor) // allow missing
return false;
df::building *selected = world->selected_building;
df::building *selected = getAnyBuilding(top);
if (!virtual_cast<df::building_workshopst>(selected) &&
!virtual_cast<df::building_furnacest>(selected))
return false;
// No jobs?
if (selected->jobs.empty() ||
selected->jobs[0]->job_type == job_type::DestroyBuilding)
return false;
// Add job gui activated?
if (ui_workshop_in_add && *ui_workshop_in_add)
return false;
return true;
};
default:
return false;
}
*/ return false;
}
bool Gui::build_selector_hotkey(df::viewscreen *top)
{
if (!dwarfmode_hotkey(top))
return false;
using df::global::buildreq;
/* TODO: understand how this changes for v50
using namespace ui_sidebar_mode;
using df::global::ui_build_selector;
switch (plotinfo->main.mode) {
case Build:
{
if (!ui_build_selector) // allow missing
if (!dwarfmode_hotkey(top))
return false;
// Not selecting, or no choices?
if (ui_build_selector->building_type < 0 ||
ui_build_selector->stage != 2 ||
ui_build_selector->choices.empty())
if (buildreq->building_type < 0 ||
buildreq->stage != 2 ||
buildreq->choices.empty())
return false;
return true;
};
default:
return false;
}
*/ return false;
}
bool Gui::view_unit_hotkey(df::viewscreen *top)
{
if (!dwarfmode_hotkey(top))
return false;
/* TODO: understand how this changes for v50
using df::global::ui_selected_unit;
if (plotinfo->main.mode != ui_sidebar_mode::ViewUnits)
return false;
if (!ui_selected_unit) // allow missing
return false;
return vector_get(world->units.active, *ui_selected_unit) != NULL;
*/ return false;
return !!getAnyUnit(top);
}
bool Gui::unit_inventory_hotkey(df::viewscreen *top)
bool Gui::any_job_hotkey(df::viewscreen *top)
{
using df::global::ui_unit_view_mode;
if (!view_unit_hotkey(top))
return false;
if (!ui_unit_view_mode)
return false;
return ui_unit_view_mode->value == df::ui_unit_view_mode::Inventory;
return matchFocusString("dwarfmode/Info/JOBS", top)
|| matchFocusString("dwarfmode/Info/CREATURES/CITIZEN", top)
|| workshop_job_hotkey(top);
}
df::job *Gui::getSelectedWorkshopJob(color_ostream &out, bool quiet)
{
using df::global::ui_workshop_job_cursor;
if (!workshop_job_hotkey(Core::getTopViewscreen())) {
if (!quiet)
out.printerr("Not in a workshop, or no job is highlighted.\n");
auto bld = getSelectedBuilding(out, true);
if (!bld)
return NULL;
}
df::building *selected = world->selected_building;
int idx = *ui_workshop_job_cursor;
if (size_t(idx) >= selected->jobs.size())
{
out.printerr("Invalid job cursor index: %d\n", idx);
return NULL;
}
return selected->jobs[idx];
}
bool Gui::any_job_hotkey(df::viewscreen *top)
{
/* TODO: understand how this changes for v50
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_joblistst, top))
return vector_get(screen->jobs, screen->cursor_pos) != NULL;
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_unitlistst, top))
return vector_get(screen->jobs[screen->page], screen->cursor_pos[screen->page]) != NULL;
return workshop_job_hotkey(top);
*/ return false;
// no way to select a specific job; just get the first one
return bld->jobs.size() ? bld->jobs[0] : NULL;
}
df::job *Gui::getSelectedJob(color_ostream &out, bool quiet)
{
/* TODO: understand how this changes for v50
df::viewscreen *top = Core::getTopViewscreen();
if (VIRTUAL_CAST_VAR(screen, df::viewscreen_jobst, top))
{
return screen->job;
}
if (VIRTUAL_CAST_VAR(joblist, df::viewscreen_joblistst, top))
{
df::job *job = vector_get(joblist->jobs, joblist->cursor_pos);
using df::global::game;
if (!job && !quiet)
out.printerr("Selected unit has no job\n");
auto top = Core::getTopViewscreen();
if (auto dfscreen = dfhack_viewscreen::try_cast(top))
return dfscreen->getSelectedJob();
return job;
if (matchFocusString("dwarfmode/Info/JOBS")) {
auto &cri_job = game->main_interface.info.jobs.cri_job;
// no way to select specific jobs; just get the first one
return cri_job.size() ? cri_job[0]->jb : NULL;
}
else if (VIRTUAL_CAST_VAR(unitlist, df::viewscreen_unitlistst, top))
{
int page = unitlist->page;
df::job *job = vector_get(unitlist->jobs[page], unitlist->cursor_pos[page]);
if (auto unit = getAnyUnit(top)) {
df::job *job = unit->job.current_job;
if (!job && !quiet)
out.printerr("Selected unit has no job\n");
return job;
}
else if (auto dfscreen = dfhack_viewscreen::try_cast(top))
return dfscreen->getSelectedJob();
else
return getSelectedWorkshopJob(out, quiet);
*/ return getSelectedWorkshopJob(out, quiet);
}
df::unit *Gui::getAnyUnit(df::viewscreen *top)

@ -69,7 +69,6 @@ public:
enum cstate { INACTIVE, ACTIVE, SELECTED };
virtual string get_id() = 0;
virtual string get_focus_string() = 0;
virtual bool match_prefix() = 0;
virtual bool set_state(cstate) = 0;
static bool set_state(string id, cstate state)
@ -305,7 +304,7 @@ public:
conf_wrapper *wrapper = confirmations[this->get_id()];
if(wrapper->is_paused()) {
std::string concernedFocus = this->get_focus_string();
if(!Gui::matchFocusString(this->get_focus_string(), this->match_prefix()))
if(!Gui::matchFocusString(this->get_focus_string()))
wrapper->set_paused(false);
return false;
} else if (state == INACTIVE)
@ -469,7 +468,6 @@ public:
}
string get_id() override = 0;
string get_focus_string() override = 0;
bool match_prefix() override = 0;
#define CONF_LUA_START using namespace conf_lua; Lua::StackUnwinder unwind(l_state); push(screen); push(get_id());
bool intercept_key (df::interface_key key)
{
@ -560,7 +558,6 @@ static int conf_register_##cls = conf_register(&cls##_instance, {\
class confirmation_##cls : public confirmation<df::screen> { \
virtual string get_id() { static string id = char_replace(#cls, '_', '-'); return id; } \
virtual string get_focus_string() { return focusString; } \
virtual bool match_prefix() { return focusString[strlen(focusString) - 1] == '*'; } \
}; \
IMPLEMENT_CONFIRMATION_HOOKS(confirmation_##cls, 0);
@ -585,7 +582,7 @@ DEFINE_CONFIRMATION(haul_delete_stop, viewscreen_dwarfmodest, "dwarfmode/Hau
DEFINE_CONFIRMATION(depot_remove, viewscreen_dwarfmodest, "dwarfmode/ViewSheets/BUILDING");
DEFINE_CONFIRMATION(squad_disband, viewscreen_dwarfmodest, "dwarfmode/Squads");
DEFINE_CONFIRMATION(order_remove, viewscreen_dwarfmodest, "dwarfmode/Info/WORK_ORDERS");
DEFINE_CONFIRMATION(zone_remove, viewscreen_dwarfmodest, "dwarfmode/Zone*");
DEFINE_CONFIRMATION(zone_remove, viewscreen_dwarfmodest, "dwarfmode/Zone");
DEFINE_CONFIRMATION(burrow_remove, viewscreen_dwarfmodest, "dwarfmode/Burrow");
DEFINE_CONFIRMATION(stockpile_remove, viewscreen_dwarfmodest, "dwarfmode/Some/Stockpile");