diff --git a/plugins/search.cpp b/plugins/search.cpp index 6a5a713c9..e911a73be 100644 --- a/plugins/search.cpp +++ b/plugins/search.cpp @@ -20,283 +20,338 @@ using namespace df::enums; using df::global::gps; - void OutputString(int8_t color, int &x, int y, const std::string &text) { Screen::paintString(Screen::Pen(' ', color, 0), x, y, text); x += text.length(); } -struct search_struct + +// +// START: Base Search functionality +// +template +struct search_parent { - static string search_string; - static bool entry_mode; - - void print_search_option(int &x) - { - OutputString(12, x, gps->dimy - 2, "s"); - OutputString(15, x, gps->dimy - 2, ": Search"); - if (search_string.length() > 0 || entry_mode) - OutputString(15, x, gps->dimy - 2, ": " + search_string); - if (entry_mode) - OutputString(12, x, gps->dimy - 2, "_"); - } - - bool process_input(df::interface_key select_key, set *input, bool &string_changed) - { - bool key_processed = true; - string_changed = false; - - if (entry_mode) - { - df::interface_key last_token = *input->rbegin(); - if (last_token >= interface_key::STRING_A032 && last_token <= interface_key::STRING_A126) - { - search_string += 32 + last_token - interface_key::STRING_A032; - string_changed = true; - } - else if (last_token == interface_key::STRING_A000) - { - if (search_string.length() > 0) - { - search_string.erase(search_string.length()-1); - string_changed = true; - } - } - else if (input->count(interface_key::SELECT) || input->count(interface_key::LEAVESCREEN)) - { - entry_mode = false; - } - else if (input->count(interface_key::CURSOR_UP) || input->count(interface_key::CURSOR_DOWN)) - { - entry_mode = false; - key_processed = false; - } - } - else if (input->count(select_key)) - { - entry_mode = true; - } - else - { - key_processed = false; - } - - return key_processed; - } + vector *sort_list1; + vector *sort_list2; + int *cursor_pos; + char select_key; + const S *viewscreen; + + bool valid; + bool entry_mode; + bool redo_search; + string search_string; + vector saved_list1; + vector saved_list2; + + df::interface_key select_token; + const int ascii_to_enum_offset; + + search_parent() : ascii_to_enum_offset(interface_key::STRING_A048 - '0') + { + reset_all(); + } + + virtual void init(int *cursor_pos, vector *sort_list1, vector *sort_list2 = NULL, char select_key = 's') + { + this->cursor_pos = cursor_pos; + this->sort_list1 = sort_list1; + this->sort_list2 = sort_list2; + this->select_key = select_key; + select_token = (df::interface_key) (ascii_to_enum_offset + select_key); + valid = true; + } + + void reset_search() + { + entry_mode = false; + search_string = ""; + saved_list1.clear(); + saved_list2.clear(); + } + + void reset_all() + { + reset_search(); + valid = false; + sort_list1 = NULL; + sort_list2 = NULL; + viewscreen = NULL; + select_key = 's'; + } + + void clear_search() + { + if (saved_list1.size() > 0) + { + *sort_list1 = saved_list1; + if (sort_list2 != NULL) + *sort_list2 = saved_list2; + } + } + + void do_search() + { + if (search_string.length() == 0) + { + clear_search(); + return; + } + + if (saved_list1.size() == 0) + { + saved_list1 = *sort_list1; + if (sort_list2 != NULL) + saved_list2 = *sort_list2; + } + sort_list1->clear(); + if (sort_list2 != NULL) + sort_list2->clear(); + + string search_string_l = toLower(search_string); + for (int i = 0; i < saved_list1.size(); i++ ) + { + T *element = saved_list1[i]; + string desc = toLower(get_element_description(element)); + if (desc.find(search_string_l) != string::npos) + { + sort_list1->push_back(element); + if (sort_list2 != NULL) + sort_list2->push_back(saved_list2[i]); + } + } + + *cursor_pos = 0; + } + + virtual bool process_input(const set *input) + { + bool key_processed = true; + + if (entry_mode) + { + df::interface_key last_token = *input->rbegin(); + if (last_token >= interface_key::STRING_A032 && last_token <= interface_key::STRING_A126) + { + search_string += last_token - ascii_to_enum_offset; + do_search(); + } + else if (last_token == interface_key::STRING_A000) + { + 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)) + { + entry_mode = false; + } + else if (input->count(interface_key::CURSOR_UP) || input->count(interface_key::CURSOR_DOWN) + || input->count(interface_key::CURSOR_LEFT) || input->count(interface_key::CURSOR_RIGHT)) + { + entry_mode = false; + key_processed = false; + } + } + else if (input->count(select_token)) + { + entry_mode = true; + } + else + { + key_processed = false; + } + + return key_processed; + } + + + virtual string get_element_description(T *element) const = 0; + virtual void render () const = 0; + + virtual void do_post_update_check() + { + if (redo_search) + { + do_search(); + redo_search = false; + } + } + + void print_search_option(int x) const + { + OutputString((entry_mode) ? 4 : 12, x, gps->dimy - 2, string(1, select_key)); + OutputString((entry_mode) ? 10 : 15, x, gps->dimy - 2, ": Search"); + if (search_string.length() > 0 || entry_mode) + OutputString(15, x, gps->dimy - 2, ": " + search_string); + if (entry_mode) + OutputString(10, x, gps->dimy - 2, "_"); + } }; -string search_struct::search_string = ""; -bool search_struct::entry_mode = false; - -struct stocks_search : df::viewscreen_storesst, search_struct +template +struct search_hook : T { - typedef df::viewscreen_storesst interpose_base; - - static vector saved_items; - - static void reset_search() - { - entry_mode = false; - search_string = ""; - saved_items.clear(); - } - - void clear_search() - { - if (saved_items.size() > 0) - { - items = saved_items; - } - } - - - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - - int x = 1; - print_search_option(x); - } - - DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) - { - if (in_group_mode) - { - INTERPOSE_NEXT(feed)(input); - return; - } - - - bool string_changed = false; - - if ((input->count(interface_key::CURSOR_UP) || input->count(interface_key::CURSOR_DOWN)) && !in_right_list) - { - saved_items.clear(); - entry_mode = false; - if (search_string.length() > 0) - string_changed = true; - INTERPOSE_NEXT(feed)(input); - } - else - { - if (!process_input(interface_key::CUSTOM_S, input, string_changed) && !entry_mode) - { - INTERPOSE_NEXT(feed)(input); - if (in_group_mode) - { - clear_search(); - reset_search(); - } - } - } - - if (string_changed) - { - if (search_string.length() == 0) - { - clear_search(); - return; - } - - if (saved_items.size() == 0 && items.size() > 0) - { - saved_items = items; - } - items.clear(); - - for (int i = 0; i < saved_items.size(); i++ ) - { - string search_string_l = toLower(search_string); - string desc = Items::getDescription(saved_items[i], 0, true); - if (desc.find(search_string_l) != string::npos) - { - items.push_back(saved_items[i]); - } - } - - item_cursor = 0; - } - } - + typedef T interpose_base; + + static V module; + + DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) + { + module.init(this); + if (!module.process_input(input)) + { + INTERPOSE_NEXT(feed)(input); + module.do_post_update_check(); + } + + } + + DEFINE_VMETHOD_INTERPOSE(void, render, ()) + { + module.init(this); + INTERPOSE_NEXT(render)(); + module.render(); + } }; -vector stocks_search::saved_items; - +template V search_hook ::module; -IMPLEMENT_VMETHOD_INTERPOSE(stocks_search, feed); -IMPLEMENT_VMETHOD_INTERPOSE(stocks_search, render); +// +// END: Base Search functionality +// -struct unitlist_search : df::viewscreen_unitlistst, search_struct +// +// START: Stocks screen search +// +struct stocks_search : search_parent { - typedef df::viewscreen_unitlistst interpose_base; - - static vector saved_units; - static vector saved_jobs; - - - static void reset_search() - { - entry_mode = false; - search_string = ""; - saved_units.clear(); - saved_jobs.clear(); - } - - void clear_search() - { - if (saved_units.size() > 0) - { - units[page] = saved_units; - jobs[page] = saved_jobs; - } - } - - void do_search() - { - if (search_string.length() == 0) - { - clear_search(); - return; - } - - while(1) - { - if (saved_units.size() == 0) - { - saved_units = units[page]; - saved_jobs = jobs[page]; - } - units[page].clear(); - jobs[page].clear(); - - for (int i = 0; i < saved_units.size(); i++ ) - { - df::unit *unit = saved_units[i]; - string search_string_l = toLower(search_string); - string name = toLower(Translation::TranslateName(Units::getVisibleName(unit), false)); - if (name.find(search_string_l) != string::npos) - { - units[page].push_back(unit); - jobs[page].push_back(saved_jobs[i]); - } - } - - if (units[page].size() > 0) - { - cursor_pos[page] = 0; - break; - } - - search_string.erase(search_string.length()-1); - } - } - - DEFINE_VMETHOD_INTERPOSE(void, feed, (set *input)) - { - bool string_changed = false; - if (!process_input(interface_key::CUSTOM_S, input, string_changed)) - { - if (!entry_mode) - { - if (input->count(interface_key::CURSOR_LEFT) || input->count(interface_key::CURSOR_RIGHT)) - { - clear_search(); - reset_search(); - } - INTERPOSE_NEXT(feed)(input); - } - } - else if (string_changed) - do_search(); - } - - DEFINE_VMETHOD_INTERPOSE(void, render, ()) - { - INTERPOSE_NEXT(render)(); - - if (units[page].size()) - { - int x = 28; - print_search_option(x); - } - } + virtual void render() const + { + if (!viewscreen->in_group_mode) + print_search_option(1); + else + { + int x = 1; + OutputString(15, x, gps->dimy - 2, "Tab to enable Search"); + } + } + + virtual string get_element_description(df::item *element) const + { + return Items::getDescription(element, 0, true); + } + + virtual bool process_input(const set *input) + { + if (viewscreen->in_group_mode) + return false; + + if ((input->count(interface_key::CURSOR_UP) || input->count(interface_key::CURSOR_DOWN)) && !viewscreen->in_right_list) + { + saved_list1.clear(); + entry_mode = false; + if (search_string.length() > 0) + redo_search = true; + + return false; + } + else + return search_parent::process_input(input) || entry_mode; + + return true; + } + + virtual void do_post_update_check() + { + if (viewscreen->in_group_mode) + { + clear_search(); + reset_search(); + } + else + search_parent::do_post_update_check(); + } + + virtual void init(df::viewscreen_storesst *screen) + { + if (!valid) + { + viewscreen = screen; + search_parent::init(&screen->item_cursor, &screen->items); + } + } }; -vector unitlist_search::saved_units; -vector unitlist_search::saved_jobs; +typedef search_hook stocks_search_hook; +IMPLEMENT_VMETHOD_INTERPOSE(stocks_search_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(stocks_search_hook, render); + +// +// END: Stocks screen search +// -IMPLEMENT_VMETHOD_INTERPOSE(unitlist_search, feed); -IMPLEMENT_VMETHOD_INTERPOSE(unitlist_search, render); +// +// START: Unit screen search +// +struct unitlist_search : search_parent +{ + virtual void render() const + { + print_search_option(28); + } + + virtual string get_element_description(df::unit *element) const + { + return Translation::TranslateName(Units::getVisibleName(element), false); + } + + virtual bool process_input(const set *input) + { + if (input->count(interface_key::CURSOR_LEFT) || input->count(interface_key::CURSOR_RIGHT)) + { + if (!entry_mode) + { + clear_search(); + reset_search(); + return false; + } + } + else + return search_parent::process_input(input) || entry_mode; + + return true; + } + + virtual void init(df::viewscreen_unitlistst *screen) + { + if (!valid) + { + viewscreen = screen; + search_parent::init(&screen->cursor_pos[viewscreen->page], &screen->units[viewscreen->page], &screen->jobs[viewscreen->page]); + } + } +}; + +typedef search_hook unitlist_search_hook; +IMPLEMENT_VMETHOD_INTERPOSE(unitlist_search_hook, feed); +IMPLEMENT_VMETHOD_INTERPOSE(unitlist_search_hook, render); + +// +// END: Unit screen search +// DFHACK_PLUGIN("search"); @@ -304,8 +359,8 @@ DFHACK_PLUGIN("search"); DFhackCExport command_result plugin_init ( color_ostream &out, vector &commands) { - if (!gps || !INTERPOSE_HOOK(unitlist_search, feed).apply() || !INTERPOSE_HOOK(unitlist_search, render).apply() - || !INTERPOSE_HOOK(stocks_search, feed).apply() || !INTERPOSE_HOOK(stocks_search, render).apply()) + if (!gps || !INTERPOSE_HOOK(unitlist_search_hook, feed).apply() || !INTERPOSE_HOOK(unitlist_search_hook, render).apply() + || !INTERPOSE_HOOK(stocks_search_hook, feed).apply() || !INTERPOSE_HOOK(stocks_search_hook, render).apply()) out.printerr("Could not insert Search hooks!\n"); return CR_OK; @@ -313,15 +368,16 @@ DFhackCExport command_result plugin_init ( color_ostream &out, vector