Merge pull request #2823 from myk002/myk_hotkey_guards

implement some Gui module hotkey guards
develop
Myk 2023-02-06 09:17:18 -08:00 committed by GitHub
commit 448598e391
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 164 deletions

@ -958,17 +958,18 @@ Screens
[1] = "dwarfmode/Info/CREATURES/CITIZEN" [1] = "dwarfmode/Info/CREATURES/CITIZEN"
[2] = "dwardmode/Squads" [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 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`` 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])`` * ``dfhack.gui.getCurFocus([skip_dismissed])``
Returns the focus string of the current viewscreen. 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 Returns the topmost viewscreen out of the top ``depth`` viewscreens with
the specified type (e.g. ``df.viewscreen_titlest``), or ``nil`` if none match. the specified type (e.g. ``df.viewscreen_titlest``), or ``nil`` if none match.

@ -67,7 +67,7 @@ namespace DFHack
namespace Gui namespace Gui
{ {
DFHACK_EXPORT std::vector<std::string> getFocusStrings(df::viewscreen *top); 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 // Full-screen item details view

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

@ -69,7 +69,6 @@ public:
enum cstate { INACTIVE, ACTIVE, SELECTED }; enum cstate { INACTIVE, ACTIVE, SELECTED };
virtual string get_id() = 0; virtual string get_id() = 0;
virtual string get_focus_string() = 0; virtual string get_focus_string() = 0;
virtual bool match_prefix() = 0;
virtual bool set_state(cstate) = 0; virtual bool set_state(cstate) = 0;
static bool set_state(string id, cstate state) static bool set_state(string id, cstate state)
@ -305,7 +304,7 @@ public:
conf_wrapper *wrapper = confirmations[this->get_id()]; conf_wrapper *wrapper = confirmations[this->get_id()];
if(wrapper->is_paused()) { if(wrapper->is_paused()) {
std::string concernedFocus = this->get_focus_string(); 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); wrapper->set_paused(false);
return false; return false;
} else if (state == INACTIVE) } else if (state == INACTIVE)
@ -469,7 +468,6 @@ public:
} }
string get_id() override = 0; string get_id() override = 0;
string get_focus_string() 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()); #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) 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> { \ class confirmation_##cls : public confirmation<df::screen> { \
virtual string get_id() { static string id = char_replace(#cls, '_', '-'); return id; } \ virtual string get_id() { static string id = char_replace(#cls, '_', '-'); return id; } \
virtual string get_focus_string() { return focusString; } \ virtual string get_focus_string() { return focusString; } \
virtual bool match_prefix() { return focusString[strlen(focusString) - 1] == '*'; } \
}; \ }; \
IMPLEMENT_CONFIRMATION_HOOKS(confirmation_##cls, 0); 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(depot_remove, viewscreen_dwarfmodest, "dwarfmode/ViewSheets/BUILDING");
DEFINE_CONFIRMATION(squad_disband, viewscreen_dwarfmodest, "dwarfmode/Squads"); DEFINE_CONFIRMATION(squad_disband, viewscreen_dwarfmodest, "dwarfmode/Squads");
DEFINE_CONFIRMATION(order_remove, viewscreen_dwarfmodest, "dwarfmode/Info/WORK_ORDERS"); 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(burrow_remove, viewscreen_dwarfmodest, "dwarfmode/Burrow");
DEFINE_CONFIRMATION(stockpile_remove, viewscreen_dwarfmodest, "dwarfmode/Some/Stockpile"); DEFINE_CONFIRMATION(stockpile_remove, viewscreen_dwarfmodest, "dwarfmode/Some/Stockpile");