From 9cc837132dbc3717b050ef3471e4af052cb31f0e Mon Sep 17 00:00:00 2001 From: Maykeye Date: Tue, 18 Aug 2015 13:34:15 +0600 Subject: [PATCH] Added simple filter to filter part installation Filter filters parts by name Updated curses port to behave more like curses * Added redrawwin * Added handling of null pointer to wrefresh Moved lcmatch to game.cpp and game.h Function lcmatch was declared too many times in too many files. Since all of them included game.h already and including ui.h made little sense just for lcmatch, moved it to game.* Workaround for popup in tiles In several places in tiles build popup didn't appear for the following reason: Curses port writes to back renderer but the actual screen is not updated anywhere in cursesport.cpp. It's updated from renderer in try_update which is called from message handling routine. If screen was rewritten before message processed started again, then no matter how many calls to wrefresh were done, they were not actually printed to the screen. Only backscreen renderer changed. Update wrefresh to update actual renderer. Note that it's not placed inside of `if (win->draw)`. In e.g. when popup() calls refresh mainwin->draw is false. Refactored input_context to keep track of windows Now after input_context corrupts screen after HELP_KEYBINDING, it redraws windows that were assigned to it. As result, it fixes #8514, fixes #9835 in * Character menu (in-game) * Construction menu * Character creation menu * World creation menu * Vehicle interaction menu --- src/catacurse.h | 1 + src/construction.cpp | 2 +- src/crafting.cpp | 3 --- src/cursesport.cpp | 20 ++++++++++++++++++++ src/game.cpp | 13 ++++++++++++- src/game.h | 3 +++ src/input.cpp | 14 ++++++++++++++ src/input.h | 15 ++++++++++++++- src/newcharacter.cpp | 11 +++++++++-- src/overmap.cpp | 1 - src/overmapbuffer.cpp | 1 - src/player.cpp | 5 +++++ src/ui.cpp | 12 ------------ src/veh_interact.cpp | 40 ++++++++++++++++++++++++++++++++++++---- src/worldfactory.cpp | 7 +++++++ 15 files changed, 122 insertions(+), 26 deletions(-) diff --git a/src/catacurse.h b/src/catacurse.h index b376843715197..b3423d07a52f9 100644 --- a/src/catacurse.h +++ b/src/catacurse.h @@ -130,6 +130,7 @@ int mvwhline(WINDOW *win, int y, int x, chtype ch, int n); int mvwvline(WINDOW *win, int y, int x, chtype ch, int n); int wrefresh(WINDOW *win); +int redrawwin(WINDOW *win); int refresh(void); int getch(void); int wgetch(WINDOW *win); diff --git a/src/construction.cpp b/src/construction.cpp index 06285fd1795dd..d5a91c3577e9a 100644 --- a/src/construction.cpp +++ b/src/construction.cpp @@ -198,7 +198,7 @@ void construction_menu() ctxt.register_action("QUIT"); ctxt.register_action("ANY_INPUT"); ctxt.register_action("HELP_KEYBINDINGS"); - + ctxt.assign_windows({(&w_con)}); std::string hotkeys = ctxt.get_available_single_char_hotkeys(); do { diff --git a/src/crafting.cpp b/src/crafting.cpp index 2d9ad7376476e..561670f3b2f55 100644 --- a/src/crafting.cpp +++ b/src/crafting.cpp @@ -1200,9 +1200,6 @@ int recipe::print_time(WINDOW *w, int ypos, int xpos, int width, return fold_and_print( w, ypos, xpos, width, col, text ); } -// ui.cpp -extern bool lcmatch(const std::string &str, const std::string &findstr); - template bool lcmatch_any(const std::vector< std::vector > &list_of_list, const std::string &filter) { diff --git a/src/cursesport.cpp b/src/cursesport.cpp index ba1b62b36bdb6..6a3ac2b07d4c8 100644 --- a/src/cursesport.cpp +++ b/src/cursesport.cpp @@ -265,6 +265,13 @@ int wrefresh(WINDOW *win) if( win != nullptr && win->draw ) { curses_drawwindow(win); } + +#ifdef TILES + void try_update(); + if (win == mainwin) { + try_update(); + } +#endif return 1; } @@ -617,6 +624,19 @@ int clearok(WINDOW *win) return 1; } +int redrawwin(WINDOW* win) +{ + if (! win) { + return 0; + } + win->draw = true; + for (int i = 0; i < win->height; i++) { + win->line[i].touched = true; + } + return 1; +} + + //gets the max x of a window (the width) int getmaxx(WINDOW *win) { diff --git a/src/game.cpp b/src/game.cpp index 50a355d59638d..77f1439c26488 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -128,6 +128,18 @@ bool is_valid_in_w_terrain(int x, int y) return x >= 0 && x < TERRAIN_WINDOW_WIDTH && y >= 0 && y < TERRAIN_WINDOW_HEIGHT; } +/* + * case insensitive string::find( string::findstr ). findstr must be lowercased + */ +bool lcmatch(const std::string &str, const std::string &findstr) +{ + std::string ret = ""; + ret.reserve( str.size() ); + transform( str.begin(), str.end(), std::back_inserter(ret), tolower ); + return ( (int)ret.find( findstr ) != -1 ); +} + + // This is the main game set-up process. game::game() : map_ptr( new map() ), @@ -8982,7 +8994,6 @@ tripoint game::look_around( WINDOW *w_info, const tripoint &start_point, return tripoint( INT_MIN, INT_MIN, INT_MIN ); } -bool lcmatch(const std::string &str, const std::string &findstr); // ui.cpp bool game::list_items_match(const item *item, std::string sPattern) { diff --git a/src/game.h b/src/game.h index b5ecdbd5b92d8..c7f0da9cd6a25 100644 --- a/src/game.h +++ b/src/game.h @@ -109,6 +109,9 @@ typedef std::vector< const std::list* > const_invslice; typedef std::vector< std::pair*, int> > indexed_invslice; typedef std::function item_filter; +// Helper functions +bool lcmatch(const std::string &str, const std::string &findstr); + class game { friend class editmap; diff --git a/src/input.cpp b/src/input.cpp index a6ba8aac9034d..0cf17c6d6f956 100644 --- a/src/input.cpp +++ b/src/input.cpp @@ -716,6 +716,7 @@ const std::string &input_context::handle_input() // Special help action if(action == "HELP_KEYBINDINGS") { display_help(); + redraw_windows(); return HELP_KEYBINDINGS; } @@ -1258,3 +1259,16 @@ std::string input_context::press_x(const std::string &action_id, const std::stri keyed << key_bound_suf; return keyed.str(); } + +void input_context::assign_windows(const std::vector& windows) +{ + context_windows = windows; +} + +void input_context::redraw_windows() +{ + for (auto win : context_windows) { + redrawwin(*win); + wrefresh(*win); + } +} diff --git a/src/input.h b/src/input.h index 19509d115fb04..da627ec931038 100644 --- a/src/input.h +++ b/src/input.h @@ -439,8 +439,8 @@ class input_context */ std::vector keys_bound_to(const std::string &action_id) const; private: - std::vector registered_actions; + public: const std::string &input_to_action(input_event &inp); private: @@ -475,6 +475,19 @@ class input_context * keybindings. */ void clear_conflicting_keybindings(const input_event &event); + + public: + /** + * Assigns windows that are displayed when context is used + */ + void assign_windows(const std::vector& windows); + /** + * Redraws all assigned windows + */ + void redraw_windows(); + private: + std::vector context_windows; + }; /** diff --git a/src/newcharacter.cpp b/src/newcharacter.cpp index 8896c26665dcf..2ba7ec8fab35e 100644 --- a/src/newcharacter.cpp +++ b/src/newcharacter.cpp @@ -65,8 +65,6 @@ int set_description(WINDOW *w, player *u, character_type type, int &points); void save_template(player *u); -bool lcmatch(const std::string &str, const std::string &findstr); // ui.cpp - void Character::pick_name(bool bUseDefault) { if (bUseDefault && OPTIONS["DEF_CHAR_NAME"]) { @@ -588,6 +586,9 @@ int set_stats(WINDOW *w, player *u, int &points) int read_spd; WINDOW *w_description = newwin(8, FULL_SCREEN_WIDTH - iSecondColumn - 1, 6 + getbegy(w), iSecondColumn + getbegx(w)); + + ctxt.assign_windows({&w, &w_description}); + // There is no map loaded currently, so any access to the map will // fail (player::suffer, called from player::reset_stats), might access // the map: @@ -839,6 +840,7 @@ int set_traits(WINDOW *w, player *u, int &points, int max_trait_points) ctxt.register_action("PREV_TAB"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("HELP_KEYBINDINGS"); + ctxt.assign_windows({&w, &w_description}); do { mvwprintz(w, 3, 2, c_ltgray, _("Points left:%4d "), points); @@ -1071,6 +1073,7 @@ int set_profession(WINDOW *w, player *u, int &points) ctxt.register_action("SORT"); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("FILTER"); + ctxt.assign_windows({&w, &w_description, &w_items, &w_genderswap}); bool recalc_profs = true; int profs_length = 0; @@ -1360,6 +1363,7 @@ int set_skills(WINDOW *w, player *u, int &points) ctxt.register_action("PREV_TAB"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("HELP_KEYBINDINGS"); + ctxt.assign_windows({&w, &w_description}); do { mvwprintz(w, 3, 2, c_ltgray, _("Points left:%4d "), points); @@ -1522,6 +1526,7 @@ int set_scenario(WINDOW *w, player *u, int &points) ctxt.register_action("SORT"); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("FILTER"); + ctxt.assign_windows({&w, &w_description, &w_profession, &w_location, &w_flags}); bool recalc_scens = true; int scens_length = 0; @@ -1811,6 +1816,8 @@ int set_description(WINDOW *w, player *u, character_type type, int &points) ctxt.register_action("REROLL_CHARACTER"); ctxt.register_action("REROLL_CHARACTER_WITH_SCENARIO"); ctxt.register_action("ANY_INPUT"); + ctxt.assign_windows({&w, &w_name, + &w_gender, &w_location, &w_stats, &w_traits, &w_scenario, &w_profession, &w_skills, &w_guide}); uimenu select_location; select_location.text = _("Select a starting location."); diff --git a/src/overmap.cpp b/src/overmap.cpp index ff4b9ac979a91..0bd4a8615e478 100644 --- a/src/overmap.cpp +++ b/src/overmap.cpp @@ -999,7 +999,6 @@ void overmap::delete_note(int const x, int const y, int const z) add_note(x, y, z, std::string {}); } -extern bool lcmatch(const std::string& text, const std::string& pattern); std::vector overmap::find_notes(int const z, std::string const &text) { std::vector note_locations; diff --git a/src/overmapbuffer.cpp b/src/overmapbuffer.cpp index 3872840045dcc..17dd6c78aa2d1 100644 --- a/src/overmapbuffer.cpp +++ b/src/overmapbuffer.cpp @@ -754,7 +754,6 @@ void overmapbuffer::despawn_monster(const monster &critter) om.monster_map.insert( std::make_pair( sm, critter ) ); } -extern bool lcmatch(const std::string& text, const std::string& pattern); overmapbuffer::t_notes_vector overmapbuffer::get_notes(int z, const std::string* pattern) { t_notes_vector result; diff --git a/src/player.cpp b/src/player.cpp index 9f4d231166eb8..ce6ea56fa80d2 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -2585,6 +2585,11 @@ Strength - 4; Dexterity - 4; Intelligence - 4; Perception - 4")); ctxt.register_action("QUIT"); ctxt.register_action("CONFIRM", _("Toggle skill training")); ctxt.register_action("HELP_KEYBINDINGS"); + ctxt.assign_windows({&w_grid_top, &w_grid_skill, &w_grid_effect, &w_grid_trait, + &w_tip, &w_stats, &w_traits, &w_encumb, &w_effects, &w_speed, &w_skills, &w_info, + }); + + std::string action; std::string help_msg = string_format(_("Press %s for help."), ctxt.get_desc("HELP_KEYBINDINGS").c_str()); diff --git a/src/ui.cpp b/src/ui.cpp index dd46ab3f3dc52..d6cba2a931b40 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -194,17 +194,6 @@ void uimenu::init() hotkeys = DEFAULT_HOTKEYS; } -/* - * case insensitive string::find( string::findstr ). findstr must be lowercased - */ -bool lcmatch(const std::string &str, const std::string &findstr) -{ - std::string ret = ""; - ret.reserve( str.size() ); - transform( str.begin(), str.end(), std::back_inserter(ret), tolower ); - return ( (int)ret.find( findstr ) != -1 ); -} - /* * repopulate filtered entries list (fentries) and set fselected accordingly */ @@ -907,4 +896,3 @@ void pointmenu_cb::refresh( uimenu *menu ) { menu->redraw( false ); menu->show(); } - diff --git a/src/veh_interact.cpp b/src/veh_interact.cpp index 12aada249e677..baa748b4f1c91 100644 --- a/src/veh_interact.cpp +++ b/src/veh_interact.cpp @@ -36,7 +36,16 @@ const skill_id skill_mechanics( "mechanics" ); * Creates a blank veh_interact window. */ veh_interact::veh_interact () - : main_context("VEH_INTERACT") + : w_grid(nullptr) + , w_mode(nullptr) + , w_msg(nullptr) + , w_disp(nullptr) + , w_parts(nullptr) + , w_stats(nullptr) + , w_list(nullptr) + , w_details(nullptr) + , w_name(nullptr) + , main_context("VEH_INTERACT") { cpart = -1; ddx = 0; @@ -76,6 +85,10 @@ veh_interact::veh_interact () main_context.register_action("NEXT_TAB"); main_context.register_action("CONFIRM"); main_context.register_action("HELP_KEYBINDINGS"); + main_context.register_action("FILTER"); + + main_context.assign_windows({&w_grid, &w_mode, &w_msg, &w_disp, + &w_parts, &w_stats, &w_list, &w_details, &w_name}); } /** @@ -291,6 +304,7 @@ void veh_interact::do_main_loop() } else if (action == "PREV_TAB") { move_fuel_cursor(-1); } + if (sel_cmd != ' ') { finish = true; } @@ -762,6 +776,17 @@ void veh_interact::do_install() int pos = 0; size_t tab = 0; + + std::string sFilter; + std::function user_filter = [&](const vpart_info *p) { + return lcmatch(p->name, sFilter); + }; + + std::function part_filter = [&](const vpart_info *p) { + return user_filter(p) && tab_filters[tab](p); + }; + + while (true) { display_list(pos, tab_vparts, 2); @@ -824,9 +849,15 @@ void veh_interact::do_install() tab = ( tab < tab_list.size() - 1 ) ? tab + 1 : 0; } - copy_if(can_mount.begin(), can_mount.end(), back_inserter(tab_vparts), tab_filters[tab]); - } - else { + copy_if(can_mount.begin(), can_mount.end(), back_inserter(tab_vparts), part_filter); + } else if (action == "FILTER") { + sFilter = string_input_popup(_("Name filter:"), 55, sFilter, + _("UP: history, CTRL-U clear line, ESC: abort, ENTER: save"), "veh_part_filter", 256); + main_context.redraw_windows(); + pos = 0; + tab_vparts.clear(); + copy_if(can_mount.begin(), can_mount.end(), back_inserter(tab_vparts), part_filter); + } else { move_in_list(pos, action, tab_vparts.size(), 2); } } @@ -841,6 +872,7 @@ void veh_interact::do_install() display_name(); } + bool veh_interact::move_in_list(int &pos, const std::string &action, const int size, const int header) const { int lines_per_page = page_size - header; diff --git a/src/worldfactory.cpp b/src/worldfactory.cpp index 053b30ebecbdd..f40e02b00d054 100644 --- a/src/worldfactory.cpp +++ b/src/worldfactory.cpp @@ -460,6 +460,7 @@ WORLDPTR worldfactory::pick_world( bool show_prompt ) ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("CONFIRM"); + ctxt.assign_windows({&w_worlds_border, &w_worlds_tooltip, &w_worlds_header, &w_worlds}); std::stringstream sTemp; @@ -648,6 +649,9 @@ int worldfactory::show_worldgen_tab_options(WINDOW *win, WORLDPTR world) ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); + + ctxt.assign_windows({&win, &w_options, &w_options_tooltip, &w_options_header}); + int iStartPos = 0; int iCurrentLine = 0; @@ -907,6 +911,8 @@ int worldfactory::show_worldgen_tab_modselection(WINDOW *win, WORLDPTR world) FULL_SCREEN_WIDTH / 2 + 2 + iOffsetX); w_description = newwin(4, FULL_SCREEN_WIDTH - 2, 19 + iOffsetY, 1 + iOffsetX); + ctxt.assign_windows({&win, &w_header1, &w_header2, &w_shift, &w_list, &w_active, &w_description}); + draw_modselection_borders(win, &ctxt); std::vector headers; headers.push_back(_("Mod List")); @@ -1203,6 +1209,7 @@ int worldfactory::show_worldgen_tab_confirm(WINDOW *win, WORLDPTR world) ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("PICK_RANDOM_WORLDNAME"); + ctxt.assign_windows({&win, &w_confirmation}); std::string worldname = world->world_name; do {