diff --git a/conf.py b/conf.py index 60c3be579..ffcc24b75 100644 --- a/conf.py +++ b/conf.py @@ -78,8 +78,7 @@ def write_tool_docs(): os.makedirs(os.path.join('docs/tools', os.path.dirname(k[0])), mode=0o755, exist_ok=True) with write_file_if_changed('docs/tools/{}.rst'.format(k[0])) as outfile: - if k[0] != 'search': - outfile.write(label) + outfile.write(label) outfile.write(include) diff --git a/docs/about/Removed.rst b/docs/about/Removed.rst index 86d7e0f75..67c4530bb 100644 --- a/docs/about/Removed.rst +++ b/docs/about/Removed.rst @@ -220,6 +220,12 @@ ruby Support for the Ruby language in DFHack scripts was removed due to the issues the Ruby library causes when used as an embedded language. +.. _search-plugin: + +search +====== +Functionality was merged into `sort`. + .. _show-unit-syndromes: show-unit-syndromes diff --git a/docs/images/search-stockpile.png b/docs/images/search-stockpile.png deleted file mode 100644 index a0e837875..000000000 Binary files a/docs/images/search-stockpile.png and /dev/null differ diff --git a/docs/images/search.png b/docs/images/search.png deleted file mode 100644 index 384c3c533..000000000 Binary files a/docs/images/search.png and /dev/null differ diff --git a/docs/plugins/search.rst b/docs/plugins/search.rst deleted file mode 100644 index e07c81cbf..000000000 --- a/docs/plugins/search.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _search-plugin: - -search -====== - -.. dfhack-tool:: - :summary: Adds search capabilities to the UI. - :tags: unavailable - :no-command: - -Search options are added to the Stocks, Animals, Trading, Stockpile, Noble -assignment candidates), Military (position candidates), Burrows (unit list), -Rooms, Announcements, Job List, and Unit List screens all get hotkeys that allow -you to dynamically filter the displayed lists. - -Usage ------ - -:: - - enable search - -.. image:: ../images/search.png - -Searching works the same way as the search option in :guilabel:`Move to Depot`. -You will see the Search option displayed on screen with a hotkey -(usually :kbd:`s`). Pressing it lets you start typing a query and the relevant -list will start filtering automatically. - -Pressing :kbd:`Enter`, :kbd:`Esc` or the arrow keys will return you to browsing -the now filtered list, which still functions as normal. You can clear the filter -by either going back into search mode and backspacing to delete it, or pressing -the "shifted" version of the search hotkey while browsing the list (e.g. if the -hotkey is :kbd:`s`, then hitting :kbd:`Shift`:kbd:`s` will clear any filter). - -Leaving any screen automatically clears the filter. - -In the Trade screen, the actual trade will always only act on items that are -actually visible in the list; the same effect applies to the Trade Value numbers -displayed by the screen. Because of this, the :kbd:`t` key is blocked while -search is active, so you have to reset the filters first. Pressing -:kbd:`Alt`:kbd:`C` will clear both search strings. - -In the stockpile screen the option only appears if the cursor is in the -rightmost list: - -.. image:: ../images/search-stockpile.png - -Note that the 'Permit XXX'/'Forbid XXX' keys conveniently operate only on items -actually shown in the rightmost list, so it is possible to select only fat or -tallow by forbidding fats, then searching for fat/tallow, and using Permit Fats -again while the list is filtered. diff --git a/docs/plugins/sort.rst b/docs/plugins/sort.rst index c0111fa0c..4833cbf83 100644 --- a/docs/plugins/sort.rst +++ b/docs/plugins/sort.rst @@ -6,10 +6,12 @@ sort :tags: fort productivity interface :no-command: -The ``sort`` tool provides overlays that sorting and searching options for -lists displayed in the DF interface. +The ``sort`` tool provides search and sort functionality for lists displayed in +the DF interface. -Searching and sorting functionality is provided by `overlay` widgets, and widgets for individual lists can be moved via `gui/overlay` or turned on or off via `gui/control-panel`. +Searching and sorting functionality is provided by `overlay` widgets, and +widgets for individual lists can be moved via `gui/overlay` or turned on or off +via `gui/control-panel`. Squad assignment overlay ------------------------ diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index efeae25f9..eee446db6 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -153,7 +153,6 @@ if(BUILD_SUPPORTED) #dfhack_plugin(rename rename.cpp LINK_LIBRARIES lua PROTOBUFS rename) #add_subdirectory(rendermax) dfhack_plugin(reveal reveal.cpp LINK_LIBRARIES lua) - #dfhack_plugin(search search.cpp) dfhack_plugin(seedwatch seedwatch.cpp LINK_LIBRARIES lua) dfhack_plugin(showmood showmood.cpp) #dfhack_plugin(siege-engine siege-engine.cpp LINK_LIBRARIES lua) diff --git a/plugins/search.cpp b/plugins/search.cpp deleted file mode 100644 index b69480778..000000000 --- a/plugins/search.cpp +++ /dev/null @@ -1,2568 +0,0 @@ -#include "MiscUtils.h" -#include "VTableInterpose.h" -#include "uicommon.h" - -#include "modules/Buildings.h" -#include "modules/Gui.h" -#include "modules/Job.h" -#include "modules/Screen.h" -#include "modules/Translation.h" -#include "modules/Units.h" - -#include "df/creature_raw.h" -#include "df/global_objects.h" -#include "df/historical_figure.h" -#include "df/interface_key.h" -#include "df/interfacest.h" -#include "df/job.h" -#include "df/layer_object_listst.h" -#include "df/misc_trait_type.h" -#include "df/report.h" -#include "df/ui_look_list.h" -#include "df/unit.h" -#include "df/unit_misc_trait.h" -#include "df/viewscreen_announcelistst.h" -#include "df/viewscreen_buildinglistst.h" -#include "df/viewscreen_dwarfmodest.h" -#include "df/viewscreen_joblistst.h" -#include "df/viewscreen_justicest.h" -#include "df/viewscreen_kitchenprefst.h" -#include "df/viewscreen_layer_militaryst.h" -#include "df/viewscreen_layer_noblelistst.h" -#include "df/viewscreen_layer_stockpilest.h" -#include "df/viewscreen_layer_stone_restrictionst.h" -#include "df/viewscreen_locationsst.h" -#include "df/viewscreen_petst.h" -#include "df/viewscreen_storesst.h" -#include "df/viewscreen_topicmeeting_fill_land_holder_positionsst.h" -#include "df/viewscreen_tradegoodsst.h" -#include "df/viewscreen_unitlistst.h" -#include "df/viewscreen_workshop_profilest.h" - -using namespace std; -using std::set; -using std::vector; -using std::string; - -using namespace DFHack; -using namespace df::enums; - -DFHACK_PLUGIN("search"); -DFHACK_PLUGIN_IS_ENABLED(is_enabled); - -REQUIRE_GLOBAL(gps); -REQUIRE_GLOBAL(gview); -REQUIRE_GLOBAL(plotinfo); -REQUIRE_GLOBAL(ui_building_assign_units); -REQUIRE_GLOBAL(ui_building_in_assign); -REQUIRE_GLOBAL(ui_building_item_cursor); -REQUIRE_GLOBAL(ui_look_cursor); -REQUIRE_GLOBAL(ui_look_list); -REQUIRE_GLOBAL(world); - -/* -Search Plugin - -A plugin that adds a "Search" hotkey to some screens (Units, Trade and Stocks) -that allows filtering of the list items by a typed query. - -Works by manipulating the vector(s) that the list based viewscreens use to store -their items. When a search is started the plugin saves the original vectors and -with each keystroke creates a new filtered vector off the saves for the screen -to use. -*/ - - -void make_text_dim(int x1, int x2, int y) -{ - for (int x = x1; x <= x2; x++) - { - Screen::Pen pen = Screen::readTile(x,y); - - if (pen.valid()) - { - if (pen.fg != 0) - { - if (pen.fg == 7) - pen.adjust(0,true); - else - pen.bold = 0; - } - - Screen::paintTile(pen,x,y); - } - } -} - -static bool is_live_screen(const df::viewscreen *screen) -{ - for (df::viewscreen *cur = &gview->view; cur; cur = cur->child) - if (cur == screen && cur->breakdown_level == interface_breakdown_types::NONE) - return true; - return false; -} - -static string get_unit_description(df::unit *unit) -{ - if (!unit) - return ""; - string desc; - auto name = Units::getVisibleName(unit); - if (name->has_name) - desc = Translation::TranslateName(name, false); - desc += ", " + Units::getProfessionName(unit); // Check animal type too - - return desc; -} - -static bool cursor_key_pressed (std::set *input, bool in_entry_mode) -{ - if (in_entry_mode) - { - // give text input (e.g. "2") priority over cursor keys - for (auto it = input->begin(); it != input->end(); ++it) - { - if (Screen::keyToChar(*it) != -1) - return false; - } - } - return - input->count(df::interface_key::CURSOR_UP) || - input->count(df::interface_key::CURSOR_DOWN) || - input->count(df::interface_key::CURSOR_LEFT) || - input->count(df::interface_key::CURSOR_RIGHT) || - input->count(df::interface_key::CURSOR_UPLEFT) || - input->count(df::interface_key::CURSOR_UPRIGHT) || - input->count(df::interface_key::CURSOR_DOWNLEFT) || - input->count(df::interface_key::CURSOR_DOWNRIGHT) || - input->count(df::interface_key::CURSOR_UP_FAST) || - input->count(df::interface_key::CURSOR_DOWN_FAST) || - input->count(df::interface_key::CURSOR_LEFT_FAST) || - input->count(df::interface_key::CURSOR_RIGHT_FAST) || - input->count(df::interface_key::CURSOR_UPLEFT_FAST) || - input->count(df::interface_key::CURSOR_UPRIGHT_FAST) || - input->count(df::interface_key::CURSOR_DOWNLEFT_FAST) || - input->count(df::interface_key::CURSOR_DOWNRIGHT_FAST) || - input->count(df::interface_key::CURSOR_UP_Z) || - input->count(df::interface_key::CURSOR_DOWN_Z) || - input->count(df::interface_key::CURSOR_UP_Z_AUX) || - input->count(df::interface_key::CURSOR_DOWN_Z_AUX); -} - -// -// START: Generic Search functionality -// - -template -class search_generic -{ -public: - bool init(S *screen) - { - if (screen != viewscreen && !reset_on_change()) - return false; - - if (!can_init(screen)) - { - if (is_valid()) - { - clear_search(); - reset_all(); - } - - return false; - } - - if (!is_valid()) - { - this->viewscreen = screen; - this->cursor_pos = get_viewscreen_cursor(); - this->primary_list = get_primary_list(); - this->select_key = get_search_select_key(); - select_token = Screen::charToKey(select_key); - shift_select_token = Screen::charToKey(select_key + 'A' - 'a'); - valid = true; - do_post_init(); - } - - return true; - } - - // Called each time you enter or leave a searchable screen. Resets everything. - virtual void reset_all() - { - reset_search(); - valid = false; - primary_list = NULL; - viewscreen = NULL; - select_key = 's'; - } - - bool reset_on_change() - { - if (valid && is_live_screen(viewscreen)) - return false; - - reset_all(); - return true; - } - - bool is_valid() - { - return valid; - } - - // A new keystroke is received in a searchable screen - virtual bool process_input(set *input) - { - // If the page has two search options (Trade screen), only allow one to operate - // at a time - if (lock != NULL && lock != this) - return false; - - // Allows custom preprocessing for each screen - if (!should_check_input(input)) - return false; - - bool key_processed = true; - - if (entry_mode) - { - // Query typing mode - - df::interface_key last_token = get_string_key(input); - int charcode = Screen::keyToChar(last_token); - if (charcode >= 32 && charcode <= 126) - { - // Standard character - search_string += char(charcode); - do_search(); - } - else if (last_token == interface_key::STRING_A000) - { - // Backspace - if (search_string.length() > 0) - { - search_string.erase(search_string.length()-1); - do_search(); - } - } - else if (input->count(interface_key::SELECT) || input->count(interface_key::LEAVESCREEN)) - { - // ENTER or ESC: leave typing mode - end_entry_mode(); - } - else if (cursor_key_pressed(input, entry_mode)) - { - // Arrow key pressed. Leave entry mode and allow screen to process key - end_entry_mode(); - key_processed = false; - } - } - // Not in query typing mode - else if (input->count(select_token)) - { - // Hotkey pressed, enter typing mode - start_entry_mode(); - } - else if (input->count(shift_select_token)) - { - // Shift + Hotkey pressed, clear query - clear_search(); - } - else - { - // Not a key for us, pass it on to the screen - key_processed = false; - } - - return key_processed || entry_mode; // Only pass unrecognized keys down if not in typing mode - } - - // Called after a keystroke has been processed - virtual void do_post_input_feed() - { - } - - static search_generic *lock; - - bool in_entry_mode() - { - return entry_mode; - } - -protected: - virtual string get_element_description(T element) const = 0; - virtual void render() const = 0; - virtual int32_t *get_viewscreen_cursor() = 0; - virtual vector *get_primary_list() = 0; - - search_generic() - { - reset_all(); - } - - virtual bool can_init(S *screen) - { - return true; - } - - virtual void do_post_init() - { - - } - - void start_entry_mode() - { - entry_mode = true; - lock = this; - } - - void end_entry_mode() - { - entry_mode = false; - lock = NULL; - } - - virtual char get_search_select_key() - { - return 's'; - } - - virtual void reset_search() - { - end_entry_mode(); - search_string = ""; - saved_list1.clear(); - } - - // Shortcut to clear the search immediately - virtual void clear_search() - { - if (saved_list1.size() > 0) - { - *primary_list = saved_list1; - saved_list1.clear(); - } - search_string = ""; - } - - virtual void save_original_values() - { - saved_list1 = *primary_list; - } - - virtual void do_pre_incremental_search() - { - - } - - virtual void clear_viewscreen_vectors() - { - primary_list->clear(); - } - - virtual void add_to_filtered_list(size_t i) - { - primary_list->push_back(saved_list1[i]); - } - - virtual void do_post_search() - { - - } - - virtual bool is_valid_for_search(size_t index) - { - return true; - } - - virtual bool force_in_search(size_t index) - { - return false; - } - - // The actual sort - virtual void do_search() - { - if (search_string.length() == 0) - { - clear_search(); - return; - } - - if (saved_list1.size() == 0) - // On first run, save the original list - save_original_values(); - else - do_pre_incremental_search(); - - clear_viewscreen_vectors(); - - string search_string_l = to_search_normalized(search_string); - for (size_t i = 0; i < saved_list1.size(); i++ ) - { - if (force_in_search(i)) - { - add_to_filtered_list(i); - continue; - } - - if (!is_valid_for_search(i)) - continue; - - T element = saved_list1[i]; - string desc = to_search_normalized(get_element_description(element)); - if (desc.find(search_string_l) != string::npos) - { - add_to_filtered_list(i); - } - } - - do_post_search(); - - if (cursor_pos) - *cursor_pos = 0; - } - - virtual bool should_check_input(set *input) - { - return true; - } - - // Display hotkey message - void print_search_option(int x, int y = -1) const - { - auto dim = Screen::getWindowSize(); - if (y == -1) - y = dim.y - 2; - - OutputString((entry_mode) ? 4 : 12, x, y, string(1, select_key)); - OutputString((entry_mode) ? 10 : 15, x, y, ": Search"); - if (search_string.length() > 0 || entry_mode) - OutputString(15, x, y, ": " + search_string); - if (entry_mode) - OutputString(10, x, y, "_"); - } - - S *viewscreen; - vector saved_list1, reference_list, *primary_list; - - //bool redo_search; - string search_string; - -protected: - int *cursor_pos; - char select_key; - bool valid; - bool entry_mode; - - df::interface_key select_token; - df::interface_key shift_select_token; -}; - -template search_generic *search_generic ::lock = NULL; - - -// Search class helper for layered screens -template -class layered_search : public search_generic -{ -protected: - virtual bool can_init(S *screen) - { - auto list = getLayerList(screen); - if (!is_list_valid(screen) || !list || !list->active) - return false; - - return true; - } - - virtual bool is_list_valid(S*) - { - return true; - } - - virtual void do_search() - { - search_generic::do_search(); - auto list = getLayerList(this->viewscreen); - list->num_entries = this->get_primary_list()->size(); - } - - int32_t *get_viewscreen_cursor() - { - auto list = getLayerList(this->viewscreen); - return &list->cursor; - } - - virtual void clear_search() - { - search_generic::clear_search(); - - if (is_list_valid(this->viewscreen)) - { - auto list = getLayerList(this->viewscreen); - list->num_entries = this->get_primary_list()->size(); - } - } - -private: - static df::layer_object_listst *getLayerList(const df::viewscreen_layer *layer) - { - return virtual_cast(vector_get(layer->layer_objects, LIST_ID)); - } -}; - - - -// Parent class for screens that have more than one primary list to synchronise -template < class S, class T, class PARENT = search_generic > -class search_multicolumn_modifiable_generic : public PARENT -{ -protected: - vector reference_list; - vector saved_indexes; - bool read_only; - - virtual void update_saved_secondary_list_item(size_t i, size_t j) = 0; - virtual void save_secondary_values() = 0; - virtual void clear_secondary_viewscreen_vectors() = 0; - virtual void add_to_filtered_secondary_lists(size_t i) = 0; - virtual void clear_secondary_saved_lists() = 0; - virtual void reset_secondary_viewscreen_vectors() = 0; - virtual void restore_secondary_values() = 0; - - virtual void do_post_init() - { - // If true, secondary list isn't modifiable so don't bother synchronising values - read_only = false; - } - - void reset_all() - { - PARENT::reset_all(); - reference_list.clear(); - saved_indexes.clear(); - reset_secondary_viewscreen_vectors(); - } - - void reset_search() - { - PARENT::reset_search(); - reference_list.clear(); - saved_indexes.clear(); - clear_secondary_saved_lists(); - } - - virtual void clear_search() - { - if (this->saved_list1.size() > 0) - { - do_pre_incremental_search(); - restore_secondary_values(); - } - clear_secondary_saved_lists(); - PARENT::clear_search(); - do_post_search(); - } - - virtual bool is_match(T &a, T &b) = 0; - - virtual bool is_match(vector &a, vector &b) = 0; - - void do_pre_incremental_search() - { - PARENT::do_pre_incremental_search(); - if (read_only) - return; - - bool list_has_been_sorted = (this->primary_list->size() == reference_list.size() - && !is_match(*this->primary_list, reference_list)); - - for (size_t i = 0; i < saved_indexes.size(); i++) - { - int adjusted_item_index = i; - if (list_has_been_sorted) - { - for (size_t j = 0; j < this->primary_list->size(); j++) - { - if (is_match((*this->primary_list)[j], reference_list[i])) - { - adjusted_item_index = j; - break; - } - } - } - - update_saved_secondary_list_item(saved_indexes[i], adjusted_item_index); - } - saved_indexes.clear(); - } - - void clear_viewscreen_vectors() - { - search_generic::clear_viewscreen_vectors(); - saved_indexes.clear(); - clear_secondary_viewscreen_vectors(); - } - - void add_to_filtered_list(size_t i) - { - search_generic::add_to_filtered_list(i); - add_to_filtered_secondary_lists(i); - if (!read_only) - saved_indexes.push_back(i); // Used to map filtered indexes back to original, if needed - } - - virtual void do_post_search() - { - if (!read_only) - reference_list = *this->primary_list; - } - - void save_original_values() - { - search_generic::save_original_values(); - save_secondary_values(); - } -}; - -// This basic match function is separated out from the generic multi column class, because the -// pets screen, which uses a union in its primary list, will cause a compile failure if this -// match function exists in the generic class -template < class S, class T, class PARENT = search_generic > -class search_multicolumn_modifiable : public search_multicolumn_modifiable_generic -{ - bool is_match(T &a, T &b) - { - return a == b; - } - - bool is_match(vector &a, vector &b) - { - return a == b; - } -}; - -// General class for screens that have only one secondary list to keep in sync -template < class S, class T, class V, class PARENT = search_generic > -class search_twocolumn_modifiable : public search_multicolumn_modifiable -{ -public: -protected: - virtual vector * get_secondary_list() = 0; - - virtual void do_post_init() - { - search_multicolumn_modifiable::do_post_init(); - secondary_list = get_secondary_list(); - } - - void save_secondary_values() - { - saved_secondary_list = *secondary_list; - } - - void reset_secondary_viewscreen_vectors() - { - secondary_list = NULL; - } - - virtual void update_saved_secondary_list_item(size_t i, size_t j) - { - saved_secondary_list[i] = (*secondary_list)[j]; - } - - void clear_secondary_viewscreen_vectors() - { - secondary_list->clear(); - } - - void add_to_filtered_secondary_lists(size_t i) - { - secondary_list->push_back(saved_secondary_list[i]); - } - - void clear_secondary_saved_lists() - { - saved_secondary_list.clear(); - } - - void restore_secondary_values() - { - *secondary_list = saved_secondary_list; - } - - vector *secondary_list, saved_secondary_list; -}; - - -// Parent struct for the hooks, use optional param D to generate multiple search classes in the same -// viewscreen but different static modules -template -struct generic_search_hook : T -{ - typedef T interpose_base; - - static V module; - - DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) - { - if (!module.init(this)) - { - INTERPOSE_NEXT(feed)(input); - return; - } - - if (!module.process_input(input)) - { - INTERPOSE_NEXT(feed)(input); - module.do_post_input_feed(); - } - - } - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - bool ok = module.init(this); - INTERPOSE_NEXT(render)(); - if (ok) - module.render(); - } - - DEFINE_VMETHOD_INTERPOSE(bool, key_conflict, (df::interface_key key)) - { - if (module.in_entry_mode() && (key == interface_key::MOVIES || key == interface_key::HELP)) - return true; - return INTERPOSE_NEXT(key_conflict)(key); - } -}; - -template V generic_search_hook ::module; - - -// Hook definition helpers -#define IMPLEMENT_HOOKS_WITH_ID(screen, module, id, prio) \ - typedef generic_search_hook module##_hook; \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, feed, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, render, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, key_conflict, prio) - -#define IMPLEMENT_HOOKS(screen, module) \ - typedef generic_search_hook module##_hook; \ - template<> IMPLEMENT_VMETHOD_INTERPOSE(module##_hook, feed); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE(module##_hook, render); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE(module##_hook, key_conflict) - -#define IMPLEMENT_HOOKS_PRIO(screen, module, prio) \ - typedef generic_search_hook module##_hook; \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, feed, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, render, prio); \ - template<> IMPLEMENT_VMETHOD_INTERPOSE_PRIO(module##_hook, key_conflict, prio); - -// -// END: Generic Search functionality -// - - -// -// START: Animal screen search -// - -typedef search_multicolumn_modifiable_generic pets_search_base; -class pets_search : public pets_search_base -{ - typedef df::viewscreen_petst::T_animal T_animal; - typedef df::viewscreen_petst::T_mode T_mode; -public: - void render() const - { - print_search_option(25, 4); - } - -private: - bool can_init(df::viewscreen_petst *screen) - { - return pets_search_base::can_init(screen) && screen->mode == T_mode::List; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor; - } - - vector *get_primary_list() - { - return &viewscreen->animal; - } - - virtual void do_post_init() - { - is_vermin = &viewscreen->is_vermin; - is_tame = &viewscreen->is_tame; - is_adopting = &viewscreen->is_adopting; - } - - string get_element_description(df::viewscreen_petst::T_animal element) const - { - return get_unit_description(element.unit); - } - - bool should_check_input() - { - return viewscreen->mode == T_mode::List; - } - - bool is_valid_for_search(size_t i) - { - return is_vermin_s[i] == 0; - } - - void save_secondary_values() - { - is_vermin_s = *is_vermin; - is_tame_s = *is_tame; - is_adopting_s = *is_adopting; - } - - void reset_secondary_viewscreen_vectors() - { - is_vermin = NULL; - is_tame = NULL; - is_adopting = NULL; - } - - void update_saved_secondary_list_item(size_t i, size_t j) - { - is_vermin_s[i] = (*is_vermin)[j]; - is_tame_s[i] = (*is_tame)[j]; - is_adopting_s[i] = (*is_adopting)[j]; - } - - void clear_secondary_viewscreen_vectors() - { - is_vermin->clear(); - is_tame->clear(); - is_adopting->clear(); - } - - void add_to_filtered_secondary_lists(size_t i) - { - is_vermin->push_back(is_vermin_s[i]); - is_tame->push_back(is_tame_s[i]); - is_adopting->push_back(is_adopting_s[i]); - } - - void clear_secondary_saved_lists() - { - is_vermin_s.clear(); - is_tame_s.clear(); - is_adopting_s.clear(); - } - - void restore_secondary_values() - { - *is_vermin = is_vermin_s; - *is_tame = is_tame_s; - *is_adopting = is_adopting_s; - } - - bool is_match(T_animal &a, T_animal &b) - { - return a.unit == b.unit; - } - - bool is_match(vector &a, vector &b) - { - for (size_t i = 0; i < a.size(); i++) - { - if (!is_match(a[i], b[i])) - return false; - } - - return true; - } - - std::vector *is_vermin, is_vermin_s; - std::vector *is_tame, is_tame_s; - std::vector *is_adopting, is_adopting_s; -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, pets_search, 1, 0); - -// -// END: Animal screen search -// - - -// -// START: Animal knowledge screen search -// - -typedef search_generic animal_knowledge_search_base; -class animal_knowledge_search : public animal_knowledge_search_base -{ - typedef df::viewscreen_petst::T_mode T_mode; - bool can_init(df::viewscreen_petst *screen) - { - return animal_knowledge_search_base::can_init(screen) && screen->mode == T_mode::TrainingKnowledge; - } - -public: - void render() const - { - print_search_option(2, 4); - } - -private: - int32_t *get_viewscreen_cursor() - { - return NULL; - } - - vector *get_primary_list() - { - return &viewscreen->known; - } - - string get_element_description(int32_t id) const - { - auto craw = df::creature_raw::find(id); - string out; - if (craw) - { - for (size_t i = 0; i < 3; ++i) - out += craw->name[i] + " "; - } - return out; - } -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, animal_knowledge_search, 2, 0); - -// -// END: Animal knowledge screen search -// - - -// -// START: Animal trainer search -// - -typedef search_twocolumn_modifiable animal_trainer_search_base; -class animal_trainer_search : public animal_trainer_search_base -{ - typedef df::viewscreen_petst::T_mode T_mode; - typedef df::viewscreen_petst::T_trainer_mode T_trainer_mode; - - bool can_init(df::viewscreen_petst *screen) - { - return animal_trainer_search_base::can_init(screen) && screen->mode == T_mode::SelectTrainer; - } - -public: - void render() const - { - Screen::paintTile(Screen::Pen('\xBA', 8, 0), 14, 2); - Screen::paintTile(Screen::Pen('\xBA', 8, 0), gps->dimx - 14, 2); - Screen::paintTile(Screen::Pen('\xC9', 8, 0), 14, 1); - Screen::paintTile(Screen::Pen('\xBB', 8, 0), gps->dimx - 14, 1); - for (int x = 15; x <= gps->dimx - 15; ++x) - { - Screen::paintTile(Screen::Pen('\xCD', 8, 0), x, 1); - Screen::paintTile(Screen::Pen('\x00', 0, 0), x, 2); - } - print_search_option(16, 2); - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->trainer_cursor; - } - - vector *get_primary_list() - { - return &viewscreen->trainer_unit; - } - - string get_element_description(df::unit *u) const - { - return get_unit_description(u); - } - - std::vector *get_secondary_list() - { - return &viewscreen->trainer_mode; - } - -public: - bool process_input(set *input) - { - if (input->count(interface_key::SELECT) && viewscreen->trainer_unit.empty() && !in_entry_mode()) - return true; - return animal_trainer_search_base::process_input(input); - } - -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_petst, animal_trainer_search, 3, 0); - -// -// END: Animal trainer search -// - - -// -// START: Stocks screen search -// -typedef search_generic stocks_search_base; -class stocks_search : public stocks_search_base -{ -public: - - void render() const - { - if (!viewscreen->in_group_mode) - print_search_option(2); - else - { - auto dim = Screen::getWindowSize(); - int x = 2, y = dim.y - 2; - OutputString(15, x, y, "Tab to enable Search"); - } - } - - bool process_input(set *input) - { - if (viewscreen->in_group_mode) - return false; - - redo_search = false; - - if ((input->count(interface_key::CURSOR_UP) || input->count(interface_key::CURSOR_DOWN)) && !viewscreen->in_right_list) - { - // Redo search if category changes - saved_list1.clear(); - end_entry_mode(); - if (search_string.length() > 0) - redo_search = true; - - return false; - } - - return stocks_search_base::process_input(input); - } - - virtual void do_post_input_feed() - { - if (viewscreen->in_group_mode) - { - // Disable search if item lists are grouped - clear_search(); - reset_search(); - } - else if (redo_search) - { - do_search(); - redo_search = false; - } - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->item_cursor; - } - - virtual vector *get_primary_list() - { - return &viewscreen->items; - } - - -private: - string get_element_description(df::item *element) const - { - if (!element) - return ""; - return Items::getDescription(element, 0, true); - } - - bool redo_search; -}; - - -IMPLEMENT_HOOKS_PRIO(df::viewscreen_storesst, stocks_search, 100); - -// -// END: Stocks screen search -// - - -// -// START: Unit screen search -// -typedef search_twocolumn_modifiable unitlist_search_base; -class unitlist_search : public unitlist_search_base -{ -public: - void render() const - { - print_search_option(28); - } - -private: - void do_post_init() - { - unitlist_search_base::do_post_init(); - read_only = true; - } - - static string get_non_work_description(df::unit *unit) - { - if (!unit) - return ""; - for (auto p = unit->status.misc_traits.begin(); p < unit->status.misc_traits.end(); p++) - { - if ((*p)->id == misc_trait_type::Migrant) - { - return ".new arrival.migrant"; - } - } - - if (Units::isBaby(unit) || - Units::isChild(unit) || - unit->profession == profession::DRUNK) - { - return ""; - } - - if (ENUM_ATTR(profession, military, unit->profession)) - return ".military"; - - return ".idle.no job"; - } - - string get_element_description(df::unit *unit) const - { - if (!unit) - return "Inactive"; - string desc = get_unit_description(unit); - if (!unit->job.current_job) - { - desc += get_non_work_description(unit); - } - - return desc; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::STANDARDSCROLL_LEFT) || - input->count(interface_key::STANDARDSCROLL_RIGHT) || - (!in_entry_mode() && input->count(interface_key::UNITVIEW_PRF_PROF))) - { - if (!in_entry_mode()) - { - // Changing screens, reset search - int32_t *cursor_pos = get_viewscreen_cursor(); - if (cursor_pos && *cursor_pos < 0) - *cursor_pos = 0; - clear_search(); - reset_all(); - return false; - } - else - { - // Ignore cursor keys when typing - input->erase(interface_key::STANDARDSCROLL_LEFT); - input->erase(interface_key::STANDARDSCROLL_RIGHT); - } - } - - return true; - } - - char get_search_select_key() - { - return 'q'; - } - - vector *get_secondary_list() - { - return &viewscreen->jobs[viewscreen->page]; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_pos[viewscreen->page]; - } - - vector *get_primary_list() - { - return &viewscreen->units[viewscreen->page]; - } -}; - -typedef generic_search_hook unitlist_search_hook; -IMPLEMENT_HOOKS_PRIO(df::viewscreen_unitlistst, unitlist_search, 100); - -// -// END: Unit screen search -// - - -// -// START: Trade screen search -// -class trade_search_base : public search_multicolumn_modifiable -{ -protected: - virtual vector *get_selected_list() = 0; - virtual vector *get_count_list() = 0; - -private: - string get_element_description(df::item *element) const - { - if (!element) - return ""; - return Items::getDescription(element, 0, true); - } - - bool should_check_input(set *input) - { - if (in_entry_mode()) - return true; - - if (input->count(interface_key::TRADE_TRADE) || - input->count(interface_key::TRADE_OFFER) || - input->count(interface_key::TRADE_SEIZE)) - { - // Block the keys if were searching - if (!search_string.empty()) - { - input->clear(); - } - - return false; - } - else if (input->count(interface_key::CUSTOM_ALT_C)) - { - clear_search_for_trade(); - return true; - } - - return true; - } - - void clear_search_for_trade() - { - // Trying to trade, reset search - clear_search(); - reset_all(); - } - - void do_post_init() - { - search_multicolumn_modifiable::do_post_init(); - - selected = get_selected_list(); - count = get_count_list(); - } - - void save_secondary_values() - { - selected_s = *selected; - count_s = *count; - } - - void reset_secondary_viewscreen_vectors() - { - selected = NULL; - count = NULL; - } - - void update_saved_secondary_list_item(size_t i, size_t j) - { - selected_s[i] = (*selected)[j]; - count_s[i] = (*count)[j]; - } - - void clear_secondary_viewscreen_vectors() - { - selected->clear(); - count->clear(); - } - - void add_to_filtered_secondary_lists(size_t i) - { - selected->push_back(selected_s[i]); - count->push_back(count_s[i]); - } - - void clear_secondary_saved_lists() - { - selected_s.clear(); - count_s.clear(); - } - - void restore_secondary_values() - { - *selected = selected_s; - *count = count_s; - } - - std::vector *selected, selected_s; - std::vector *count, count_s; -}; - - -class trade_search_merc : public trade_search_base -{ -public: - virtual void render() const - { - if (viewscreen->counteroffer.size() > 0) - { - // The merchant is proposing a counteroffer. - // Not only is there nothing to search, - // but the native hotkeys are where we normally write. - return; - } - - print_search_option(2, -1); - - if (!search_string.empty()) - { - int32_t x = 2; - int32_t y = gps->dimy - 3; - make_text_dim(2, gps->dimx-2, y); - OutputString(COLOR_LIGHTRED, x, y, string(1, select_key + 'A' - 'a')); - OutputString(COLOR_WHITE, x, y, ": Clear search to trade "); - } - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->trader_cursor; - } - - vector *get_primary_list() - { - return &viewscreen->trader_items; - } - - vector *get_selected_list() - { - return &viewscreen->trader_selected; - } - - vector *get_count_list() - { - return &viewscreen->trader_count; - } - - char get_search_select_key() - { - return 'q'; - } -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_tradegoodsst, trade_search_merc, 1, 100); - - -class trade_search_fort : public trade_search_base -{ -public: - virtual void render() const - { - if (viewscreen->counteroffer.size() > 0) - { - // The merchant is proposing a counteroffer. - // Not only is there nothing to search, - // but the native hotkeys are where we normally write. - return; - } - - int32_t x = gps->dimx / 2 + 2; - print_search_option(x, -1); - - if (!search_string.empty()) - { - int32_t y = gps->dimy - 3; - make_text_dim(2, gps->dimx-2, y); - OutputString(COLOR_LIGHTRED, x, y, string(1, select_key + 'A' - 'a')); - OutputString(COLOR_WHITE, x, y, ": Clear search to trade "); - } - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->broker_cursor; - } - - vector *get_primary_list() - { - return &viewscreen->broker_items; - } - - vector *get_selected_list() - { - return &viewscreen->broker_selected; - } - - vector *get_count_list() - { - return &viewscreen->broker_count; - } - - char get_search_select_key() - { - return 'w'; - } -}; - -IMPLEMENT_HOOKS_WITH_ID(df::viewscreen_tradegoodsst, trade_search_fort, 2, 100); - -// -// END: Trade screen search -// - - -// -// START: Stockpile screen search -// -typedef layered_search stocks_layer; -class stockpile_search : public search_twocolumn_modifiable -{ -public: - void update_saved_secondary_list_item(size_t i, size_t j) - { - *saved_secondary_list[i] = *(*secondary_list)[j]; - } - - string get_element_description(string *element) const - { - return *element; - } - - void render() const - { - print_search_option(51, 23); - } - - vector *get_primary_list() - { - return &viewscreen->item_names; - } - - vector *get_secondary_list() - { - return &viewscreen->item_status; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::STOCKPILE_SETTINGS_DISABLE) && !in_entry_mode() && !search_string.empty()) - { - // Restore original list - clear_search(); - reset_all(); - } - - return true; - } - -}; - -IMPLEMENT_HOOKS(df::viewscreen_layer_stockpilest, stockpile_search); - -// -// END: Stockpile screen search -// - - -// -// START: Military screen search -// -typedef layered_search military_search_base; -class military_search : public military_search_base -{ -public: - - string get_element_description(df::unit *element) const - { - return get_unit_description(element); - } - - void render() const - { - print_search_option(52, 22); - } - - char get_search_select_key() - { - return 'q'; - } - - // When not on the positions page, this list is used for something - // else entirely, so screwing with it seriously breaks stuff. - bool is_list_valid(df::viewscreen_layer_militaryst *screen) - { - if (screen->page != df::viewscreen_layer_militaryst::Positions) - return false; - - return true; - } - - vector *get_primary_list() - { - return &viewscreen->positions.candidates; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::SELECT) && !in_entry_mode() && !search_string.empty()) - { - // About to make an assignment, so restore original list (it will be changed by the game) - int32_t *cursor = get_viewscreen_cursor(); - auto list = get_primary_list(); - if (size_t(*cursor) >= list->size()) - return false; - df::unit *selected_unit = list->at(*cursor); - clear_search(); - - for (*cursor = 0; size_t(*cursor) < list->size(); (*cursor)++) - { - if (list->at(*cursor) == selected_unit) - break; - } - - reset_all(); - } - - return true; - } -}; - -IMPLEMENT_HOOKS_PRIO(df::viewscreen_layer_militaryst, military_search, 100); - -// -// END: Military screen search -// - - -// -// START: Room list search -// -typedef search_twocolumn_modifiable roomlist_search_base; -class roomlist_search : public roomlist_search_base -{ -public: - void render() const - { - print_search_option(2, 23); - } - -private: - void do_post_init() - { - roomlist_search_base::do_post_init(); - read_only = true; - } - - string get_element_description(df::building *bld) const - { - if (!bld) - return ""; - - string desc; - desc.reserve(100); - if (bld->owner) - desc += get_unit_description(bld->owner); - - desc += "."; - - string room_desc = Buildings::getRoomDescription(bld, nullptr); - desc += room_desc; - if (room_desc.empty()) - { - if (!bld->owner) - desc += "no owner"; - - string name; - bld->getName(&name); - if (!name.empty()) - { - desc += name; - } - } - - return desc; - } - - vector *get_secondary_list() - { - return &viewscreen->room_value; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor; - } - - vector *get_primary_list() - { - return &viewscreen->buildings; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_buildinglistst, roomlist_search); - -// -// END: Room list search -// - - - -// -// START: Announcement list search -// -class announcement_search : public search_generic -{ -public: - void render() const - { - print_search_option(2, gps->dimy - 3); - } - -private: - int32_t *get_viewscreen_cursor() - { - return &viewscreen->sel_idx; - } - - virtual vector *get_primary_list() - { - return &viewscreen->reports; - } - - -private: - string get_element_description(df::report *element) const - { - if (!element) - return ""; - return element->text; - } -}; - - -IMPLEMENT_HOOKS(df::viewscreen_announcelistst, announcement_search); - -// -// END: Announcement list search -// - - -// -// START: Nobles search list -// -typedef df::viewscreen_layer_noblelistst::T_candidates T_candidates; -typedef layered_search nobles_search_base; -class nobles_search : public nobles_search_base -{ -public: - - string get_element_description(T_candidates *element) const - { - if (!element->unit) - return ""; - - return get_unit_description(element->unit); - } - - void render() const - { - print_search_option(2, 23); - } - - bool force_in_search(size_t index) - { - return index == 0; // Leave Vacant - } - - bool can_init(df::viewscreen_layer_noblelistst *screen) - { - if (screen->mode != df::viewscreen_layer_noblelistst::Appoint) - return false; - - return nobles_search_base::can_init(screen); - } - - vector *get_primary_list() - { - return &viewscreen->candidates; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_layer_noblelistst, nobles_search); - -// -// END: Nobles search list -// - -// -// START: Workshop profiles search list -// -typedef search_generic profiles_search_base; -class profiles_search : public profiles_search_base -{ -public: - - bool can_init (df::viewscreen_workshop_profilest *screen) - { - return screen->tab == df::viewscreen_workshop_profilest::T_tab::Workers; - } - - string get_element_description(df::unit *element) const - { - return get_unit_description(element); - } - - void render() const - { - print_search_option(2, gps->dimy - 5); - } - - vector *get_primary_list() - { - return &viewscreen->workers; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->worker_idx; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_workshop_profilest, profiles_search); - -// -// END: Workshop profiles search list -// - - -// -// START: Job list search -// -void get_job_details(string &desc, df::job *job) -{ - string job_name = ENUM_KEY_STR(job_type,job->job_type); - for (size_t i = 0; i < job_name.length(); i++) - { - char c = job_name[i]; - if (c >= 'A' && c <= 'Z') - desc += " "; - desc += c; - } - desc += "."; - - df::item_type itype = ENUM_ATTR(job_type, item, job->job_type); - - MaterialInfo mat(job); - if (itype == item_type::FOOD) - mat.decode(-1); - - if (mat.isValid() || job->material_category.whole) - { - desc += mat.toString(); - desc += "."; - if (job->material_category.whole) - { - desc += bitfield_to_string(job->material_category); - desc += "."; - } - } - - if (!job->reaction_name.empty()) - { - for (size_t i = 0; i < job->reaction_name.length(); i++) - { - if (job->reaction_name[i] == '_') - desc += " "; - else - desc += job->reaction_name[i]; - } - - desc += "."; - } - - if (job->flags.bits.suspend) - desc += "suspended."; -} - -typedef search_twocolumn_modifiable joblist_search_base; -class joblist_search : public joblist_search_base -{ -public: - void render() const - { - print_search_option(2); - } - -private: - void do_post_init() - { - joblist_search_base::do_post_init(); - read_only = true; - } - - string get_element_description(df::job *element) const - { - if (!element) - return "no job.idle"; - - string desc; - desc.reserve(100); - get_job_details(desc, element); - df::unit *worker = DFHack::Job::getWorker(element); - if (worker) - desc += get_unit_description(worker); - else - desc += "Inactive"; - - return desc; - } - - char get_search_select_key() - { - return 'q'; - } - - vector *get_secondary_list() - { - return &viewscreen->units; - } - - int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_pos; - } - - vector *get_primary_list() - { - return &viewscreen->jobs; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_joblistst, joblist_search); - -// -// END: Job list search -// - - -// -// START: Look menu search -// - -typedef search_generic look_menu_search_base; -class look_menu_search : public look_menu_search_base -{ - typedef df::ui_look_list::T_items::T_type elt_type; -public: - bool can_init(df::viewscreen_dwarfmodest *screen) - { - if (plotinfo->main.mode == df::ui_sidebar_mode::LookAround) - { - return look_menu_search_base::can_init(screen); - } - - return false; - } - - string get_element_description(df::ui_look_list::T_items *element) const - { - std::string desc = ""; - switch (element->type) - { - case elt_type::Item: - if (element->data.Item) - desc = Items::getDescription(element->data.Item, 0, true); - break; - case elt_type::Unit: - if (element->data.Unit) - desc = get_unit_description(element->data.Unit); - break; - case elt_type::Building: - if (element->data.Building) - element->data.Building->getName(&desc); - break; - default: - break; - } - return desc; - } - - bool force_in_search (size_t i) - { - df::ui_look_list::T_items *element = saved_list1[i]; - switch (element->type) - { - case elt_type::Item: - case elt_type::Unit: - case elt_type::Building: - return false; - break; - default: - return true; - break; - } - } - - void render() const - { - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = 1; - - print_search_option(x, y); - } - - vector *get_primary_list() - { - return &ui_look_list->items; - } - - virtual int32_t * get_viewscreen_cursor() - { - return ui_look_cursor; - } - - - bool should_check_input(set *input) - { - if (input->count(interface_key::SECONDSCROLL_UP) - || input->count(interface_key::SECONDSCROLL_DOWN) - || input->count(interface_key::SECONDSCROLL_PAGEUP) - || input->count(interface_key::SECONDSCROLL_PAGEDOWN)) - { - end_entry_mode(); - return false; - } - bool hotkey_pressed = - input->lower_bound(interface_key::D_HOTKEY1) != input->upper_bound(interface_key::D_HOTKEY16); - if (cursor_key_pressed(input, in_entry_mode()) || hotkey_pressed) - { - end_entry_mode(); - clear_search(); - return false; - } - - return true; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, look_menu_search); - -// -// END: Look menu search -// - - -// -// START: Burrow assignment search -// - -typedef search_twocolumn_modifiable burrow_search_base; -class burrow_search : public burrow_search_base -{ -public: - bool can_init(df::viewscreen_dwarfmodest *screen) - { - if (plotinfo->main.mode == df::ui_sidebar_mode::Burrows && plotinfo->burrows.in_add_units_mode) - { - return burrow_search_base::can_init(screen); - } - - return false; - } - - string get_element_description(df::unit *element) const - { - return get_unit_description(element); - } - - void render() const - { - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = 23; - - print_search_option(x, y); - } - - vector *get_primary_list() - { - return &plotinfo->burrows.list_units; - } - - vector *get_secondary_list() - { - return &plotinfo->burrows.sel_units; - } - - virtual int32_t * get_viewscreen_cursor() - { - return &plotinfo->burrows.unit_cursor_pos; - } - - - bool should_check_input(set *input) - { - if (input->count(interface_key::SECONDSCROLL_UP) || input->count(interface_key::SECONDSCROLL_DOWN) - || input->count(interface_key::SECONDSCROLL_PAGEUP) || input->count(interface_key::SECONDSCROLL_PAGEDOWN)) - { - end_entry_mode(); - return false; - } - - return true; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, burrow_search); - -// -// END: Burrow assignment search -// - - -// -// START: Room assignment search -// - -typedef search_generic room_assign_search_base; -class room_assign_search : public room_assign_search_base -{ -public: - bool can_init(df::viewscreen_dwarfmodest *screen) - { - if (plotinfo->main.mode == df::ui_sidebar_mode::QueryBuilding && *ui_building_in_assign) - { - return room_assign_search_base::can_init(screen); - } - - return false; - } - - string get_element_description(df::unit *element) const - { - return element ? get_unit_description(element) : "Nobody"; - } - - void render() const - { - auto dims = Gui::getDwarfmodeViewDims(); - int left_margin = dims.menu_x1 + 1; - int x = left_margin; - int y = 19; - - print_search_option(x, y); - } - - vector *get_primary_list() - { - return ui_building_assign_units; - } - - virtual int32_t * get_viewscreen_cursor() - { - return ui_building_item_cursor; - } - - bool should_check_input(set *input) - { - if (input->count(interface_key::SECONDSCROLL_UP) || input->count(interface_key::SECONDSCROLL_DOWN) - || input->count(interface_key::SECONDSCROLL_PAGEUP) || input->count(interface_key::SECONDSCROLL_PAGEDOWN)) - { - end_entry_mode(); - return false; - } - - return true; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_dwarfmodest, room_assign_search); - -// -// END: Room assignment search -// - -// -// START: Noble suggestion search -// - -typedef search_generic noble_suggest_search_base; -class noble_suggest_search : public noble_suggest_search_base -{ -public: - string get_element_description (int32_t hf_id) const - { - df::historical_figure *histfig = df::historical_figure::find(hf_id); - if (!histfig) - return ""; - df::unit *unit = df::unit::find(histfig->unit_id); - if (!unit) - return ""; - return get_unit_description(unit); - } - - void render() const - { - print_search_option(2, gps->dimy - 4); - } - - vector *get_primary_list() - { - return &viewscreen->candidate_histfig_ids; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor; - } - -}; - -IMPLEMENT_HOOKS(df::viewscreen_topicmeeting_fill_land_holder_positionsst, noble_suggest_search); - -// -// END: Noble suggestion search -// - -// -// START: Location occupation assignment search -// - -typedef search_generic location_assign_occupation_search_base; -class location_assign_occupation_search : public location_assign_occupation_search_base -{ -public: - bool can_init (df::viewscreen_locationsst *screen) - { - return screen->menu == df::viewscreen_locationsst::AssignOccupation; - } - - string get_element_description (df::unit *unit) const - { - return unit ? get_unit_description(unit) : "Nobody"; - } - - void render() const - { - print_search_option(37, gps->dimy - 3); - } - - vector *get_primary_list() - { - return &viewscreen->units; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->unit_idx; - } - -}; - -IMPLEMENT_HOOKS(df::viewscreen_locationsst, location_assign_occupation_search); - -// -// END: Location occupation assignment search -// - -// -// START: Kitchen preferences search -// - -typedef search_multicolumn_modifiable kitchen_pref_search_base; -class kitchen_pref_search : public kitchen_pref_search_base -{ -public: - - string get_element_description(string *s) const override - { - return s ? *s : ""; - } - - void render() const override - { - print_search_option(40, gps->dimy - 2); - } - - int32_t *get_viewscreen_cursor() override - { - return &viewscreen->cursor; - } - - vector *get_primary_list() override - { - return &viewscreen->item_str[viewscreen->page]; - } - - bool should_check_input(set *input) override - { - if (input->count(interface_key::CHANGETAB) || input->count(interface_key::SEC_CHANGETAB)) - { - // Restore original list - clear_search(); - reset_all(); - } - - return true; - } - - -#define KITCHEN_VECTORS \ - KVEC(df::item_type, item_type); \ - KVEC(int16_t, item_subtype); \ - KVEC(int16_t, mat_type); \ - KVEC(int32_t, mat_index); \ - KVEC(int32_t, count); \ - KVEC(df::kitchen_pref_flag, forbidden); \ - KVEC(df::kitchen_pref_flag, possible) - - - virtual void do_post_init() - { - kitchen_pref_search_base::do_post_init(); - #define KVEC(type, name) name = &viewscreen->name[viewscreen->page] - KITCHEN_VECTORS; - #undef KVEC - } - - void save_secondary_values() - { - #define KVEC(type, name) name##_s = *name - KITCHEN_VECTORS; - #undef KVEC - } - - void reset_secondary_viewscreen_vectors() - { - #define KVEC(type, name) name = nullptr - KITCHEN_VECTORS; - #undef KVEC - } - - virtual void update_saved_secondary_list_item(size_t i, size_t j) - { - #define KVEC(type, name) name##_s[i] = (*name)[j]; - KITCHEN_VECTORS; - #undef KVEC - } - - void clear_secondary_viewscreen_vectors() - { - #define KVEC(type, name) name->clear() - KITCHEN_VECTORS; - #undef KVEC - } - - void add_to_filtered_secondary_lists(size_t i) - { - #define KVEC(type, name) name->push_back(name##_s[i]) - KITCHEN_VECTORS; - #undef KVEC - } - - void clear_secondary_saved_lists() - { - #define KVEC(type, name) name##_s.clear() - KITCHEN_VECTORS; - #undef KVEC - } - - void restore_secondary_values() - { - #define KVEC(type, name) *name = name##_s - KITCHEN_VECTORS; - #undef KVEC - } - - #define KVEC(type, name) vector *name, name##_s - KITCHEN_VECTORS; - #undef KVEC -#undef KITCHEN_VECTORS -}; - -IMPLEMENT_HOOKS(df::viewscreen_kitchenprefst, kitchen_pref_search); - -// -// END: Kitchen preferences search -// - - -// -// START: Stone status screen search -// -typedef layered_search stone_search_layer; -class stone_search : public search_twocolumn_modifiable -{ - // bool in_update = false; -public: - void render() const override - { - print_search_option(21, 23); - } - - vector *get_primary_list() override - { - return &viewscreen->stone_type[viewscreen->type_tab]; - } - - vector *get_secondary_list() override - { - return &viewscreen->stone_economic[viewscreen->type_tab]; - } - - string get_element_description(int32_t stone_type) const override - { - auto iraw = vector_get(world->raws.inorganics, stone_type); - if (!iraw) - return ""; - return iraw->material.stone_name + " " + iraw->material.state_name[0]; - } - - bool should_check_input(set *input) override - { - // if (in_update) - // return false; - - if (input->count(interface_key::CHANGETAB)) - { - // Restore original list - clear_search(); - reset_all(); - } - - return true; - } - - // virtual void do_post_input_feed() override - // { - // auto *list1 = get_primary_list(); - // auto *list2 = get_secondary_list(); - // bool appended = false; - // if (list1->empty()) - // { - // // Clear uses - // auto *use_list = virtual_cast(viewscreen->layer_objects[4]); - // if (use_list) - // use_list->num_entries = 0; - // return; - // } - // else if (list1->size() == 1) - // { - // list1->push_back(list1->back()); - // list2->push_back(list2->back()); - // appended = true; - // } - - // in_update = true; - // Core::printerr("updating\n"); - // viewscreen->feed_key(interface_key::STANDARDSCROLL_DOWN); - // viewscreen->feed_key(interface_key::STANDARDSCROLL_UP); - // Core::printerr("updating done\n"); - // in_update = false; - - // if (appended) - // { - // list1->pop_back(); - // list2->pop_back(); - // } - // } -}; - -IMPLEMENT_HOOKS(df::viewscreen_layer_stone_restrictionst, stone_search); - -// -// END: Stone status screen search -// - -// -// START: Justice screen conviction search -// - -typedef search_generic justice_conviction_search_base; -class justice_conviction_search : public justice_conviction_search_base -{ -public: - bool can_init (df::viewscreen_justicest *screen) - { - return screen->cur_column == df::viewscreen_justicest::ConvictChoices; - } - - string get_element_description (df::unit *unit) const - { - return get_unit_description(unit); - } - - void render() const - { - print_search_option(37); - } - - vector *get_primary_list() - { - return &viewscreen->convict_choices; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_right; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_justicest, justice_conviction_search); - -// -// END: Justice screen conviction search -// - -// -// START: Justice screen interrogation search -// - -typedef search_generic justice_interrogation_search_base; -class justice_interrogation_search : public justice_interrogation_search_base -{ -public: - bool can_init (df::viewscreen_justicest *screen) - { - return screen->cur_column == df::viewscreen_justicest::InterrogateChoices; - } - - string get_element_description (df::unit *unit) const - { - return get_unit_description(unit); - } - - void render() const - { - print_search_option(37); - } - - vector *get_primary_list() - { - return &viewscreen->interrogate_choices; - } - - virtual int32_t *get_viewscreen_cursor() - { - return &viewscreen->cursor_right; - } -}; - -IMPLEMENT_HOOKS(df::viewscreen_justicest, justice_interrogation_search); - -// -// END: Justice screen conviction search -// - -#define SEARCH_HOOKS \ - HOOK_ACTION(unitlist_search_hook) \ - HOOK_ACTION(roomlist_search_hook) \ - HOOK_ACTION(trade_search_merc_hook) \ - HOOK_ACTION(trade_search_fort_hook) \ - HOOK_ACTION(stocks_search_hook) \ - HOOK_ACTION(pets_search_hook) \ - HOOK_ACTION(animal_knowledge_search_hook) \ - HOOK_ACTION(animal_trainer_search_hook) \ - HOOK_ACTION(military_search_hook) \ - HOOK_ACTION(nobles_search_hook) \ - HOOK_ACTION(profiles_search_hook) \ - HOOK_ACTION(announcement_search_hook) \ - HOOK_ACTION(joblist_search_hook) \ - HOOK_ACTION(look_menu_search_hook) \ - HOOK_ACTION(burrow_search_hook) \ - HOOK_ACTION(stockpile_search_hook) \ - HOOK_ACTION(room_assign_search_hook) \ - HOOK_ACTION(noble_suggest_search_hook) \ - HOOK_ACTION(location_assign_occupation_search_hook) \ - HOOK_ACTION(kitchen_pref_search_hook) \ - HOOK_ACTION(stone_search_hook) \ - HOOK_ACTION(justice_conviction_search_hook) \ - HOOK_ACTION(justice_interrogation_search_hook) \ - - -DFhackCExport command_result plugin_enable ( color_ostream &out, bool enable) -{ - if (!gps || !gview) - return CR_FAILURE; - - if (is_enabled != enable) - { -#define HOOK_ACTION(hook) \ - !INTERPOSE_HOOK(hook, feed).apply(enable) || \ - !INTERPOSE_HOOK(hook, render).apply(enable) || \ - !INTERPOSE_HOOK(hook, key_conflict).apply(enable) || - - if (SEARCH_HOOKS 0) - return CR_FAILURE; - - is_enabled = enable; - } -#undef HOOK_ACTION - - return CR_OK; -} - -DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) -{ - return CR_OK; -} - -DFhackCExport command_result plugin_shutdown ( color_ostream &out ) -{ -#define HOOK_ACTION(hook) \ - INTERPOSE_HOOK(hook, feed).remove(); \ - INTERPOSE_HOOK(hook, render).remove(); \ - INTERPOSE_HOOK(hook, key_conflict).remove(); - - SEARCH_HOOKS - -#undef HOOK_ACTION - - return CR_OK; -} - -DFhackCExport command_result plugin_onstatechange ( color_ostream &out, state_change_event event ) -{ -#define HOOK_ACTION(hook) hook::module.reset_on_change(); - - switch (event) { - case SC_VIEWSCREEN_CHANGED: - SEARCH_HOOKS - break; - - default: - break; - } - - return CR_OK; - -#undef HOOK_ACTION -} - -#undef IMPLEMENT_HOOKS -#undef SEARCH_HOOKS