diff --git a/src/game_inventory.cpp b/src/game_inventory.cpp index ec571ce47056a..1f969e33981de 100644 --- a/src/game_inventory.cpp +++ b/src/game_inventory.cpp @@ -206,7 +206,7 @@ void game_menus::inv::common( avatar &you ) do { you.inv->restack( you ); inv_s.clear_items(); - inv_s.add_character_items( you, false ); + inv_s.add_character_items( you ); inv_s.set_filter( filter ); if( location != item_location::nowhere ) { inv_s.select( location ); @@ -1840,7 +1840,7 @@ drop_locations game_menus::inv::multidrop( avatar &you ) inventory_drop_selector inv_s( you, preset ); - inv_s.add_character_items( you, false ); + inv_s.add_character_items( you ); inv_s.set_title( _( "Multidrop" ) ); inv_s.set_hint( _( "To drop x items, type a number before selecting." ) ); diff --git a/src/inventory_ui.cpp b/src/inventory_ui.cpp index 670751a512847..8ce0b7bab62ff 100644 --- a/src/inventory_ui.cpp +++ b/src/inventory_ui.cpp @@ -54,6 +54,18 @@ #include #include +namespace +{ + +// get topmost visible parent in an unbroken chain +item *get_topmost_parent( item *topmost, item_location loc, + inventory_selector_preset const &preset ) +{ + return preset.is_shown( loc ) ? topmost != nullptr ? topmost : loc.get_item() : nullptr; +} + +} // namespace + /** The maximum distance from the screen edge, to snap a window to it */ static const size_t max_win_snap_distance = 4; /** The minimal gap between two cells */ @@ -143,11 +155,19 @@ bool inventory_entry::is_hidden() const return false; } item_location it = locations.front(); - if( !it.has_parent() ) { - return false; + bool hidden = false; + if( topmost_parent != nullptr ) { + while( it.has_parent() ) { + item_location const prnt = it.parent_item(); + hidden |= prnt.get_item()->contained_where( *it )->settings.is_collapsed(); + if( prnt.get_item() == topmost_parent ) { + break; + } + it = prnt; + } } - item_location prnt = it.parent_item(); - return prnt.get_item()->contained_where( *it )->settings.is_collapsed(); + + return hidden; } int inventory_entry::get_total_charges() const @@ -704,24 +724,12 @@ void inventory_column::set_stack_favorite( std::vector &locations void inventory_column::set_collapsed( inventory_entry &entry, const bool collapse ) { std::vector &locations = entry.locations; - std::function do_collapse; - do_collapse = [ collapse, &do_collapse ]( item_pocket * pock, bool clps ) { - pock->settings.set_collapse( collapse ); - for( item *lctn : pock->all_items_top() ) { - if( lctn->is_container() ) { - for( item_pocket *pocket : lctn->get_all_contained_pockets().value() ) { - do_collapse( pocket, clps ); - } - } - } - }; bool collapsed = false; for( item_location &loc : locations ) { if( loc.get_item()->is_container() ) { for( item_pocket *pocket : loc->get_all_contained_pockets().value() ) { pocket->settings.set_collapse( collapse ); - do_collapse( pocket, collapse ); collapsed = true; } } @@ -888,8 +896,9 @@ void inventory_column::add_entry( const inventory_entry &entry ) has_loc = true; std::vector locations = entry_with_loc->locations; locations.insert( locations.end(), entry.locations.begin(), entry.locations.end() ); - entries.erase( entry_with_loc ); inventory_entry nentry( locations, entry.get_category_ptr() ); + nentry.topmost_parent = entry_with_loc->topmost_parent; + entries.erase( entry_with_loc ); add_entry( nentry ); } } @@ -1411,7 +1420,7 @@ const item_category *inventory_selector::naturalize_category( const item_categor void inventory_selector::add_entry( inventory_column &target_column, std::vector &&locations, const item_category *custom_category, - const size_t chosen_count ) + const size_t chosen_count, item *topmost_parent ) { if( !preset.is_shown( locations.front() ) ) { return; @@ -1423,6 +1432,7 @@ void inventory_selector::add_entry( inventory_column &target_column, /*chosen_count=*/chosen_count ); entry.collapsed = locations.front()->is_collapsed(); + entry.topmost_parent = topmost_parent; target_column.add_entry( entry ); shared_ptr_fast current_ui = ui.lock(); @@ -1434,13 +1444,14 @@ void inventory_selector::add_entry( inventory_column &target_column, void inventory_selector::add_item( inventory_column &target_column, item_location &&location, const item_category *custom_category, - const bool include_hidden ) + item *topmost_parent ) { add_entry( target_column, std::vector( 1, location ), - custom_category ); + custom_category, 0, topmost_parent ); for( item *it : location->all_items_top( item_pocket::pocket_type::CONTAINER ) ) { - add_item( target_column, item_location( location, it ), custom_category, include_hidden ); + add_item( target_column, item_location( location, it ), custom_category, + get_topmost_parent( topmost_parent, location, preset ) ); } } @@ -1472,7 +1483,7 @@ void inventory_selector::add_contained_items( item_location &container ) } void inventory_selector::add_contained_items( item_location &container, inventory_column &column, - const item_category *const custom_category ) + const item_category *const custom_category, item *topmost_parent ) { if( container->has_flag( STATIC( flag_id( "NO_UNLOAD" ) ) ) ) { return; @@ -1480,14 +1491,15 @@ void inventory_selector::add_contained_items( item_location &container, inventor for( item *it : container->all_items_top() ) { item_location child( container, it ); - add_contained_items( child, column, custom_category ); + add_contained_items( child, column, custom_category, get_topmost_parent( topmost_parent, child, + preset ) ); const item_category *nat_category = nullptr; if( custom_category == nullptr ) { nat_category = &child->get_category_of_contents(); } else if( preset.is_shown( child ) ) { nat_category = naturalize_category( *custom_category, child.position() ); } - add_entry( column, std::vector( 1, child ), nat_category ); + add_entry( column, std::vector( 1, child ), nat_category, 0, topmost_parent ); } } @@ -1503,15 +1515,15 @@ void inventory_selector::add_contained_ebooks( item_location &container ) } } -void inventory_selector::add_character_items( Character &character, bool include_hidden ) +void inventory_selector::add_character_items( Character &character ) { - character.visit_items( [ this, &character, &include_hidden ]( item * it, item * ) { + character.visit_items( [ this, &character ]( item * it, item * ) { if( it == &character.get_wielded_item() ) { add_item( own_gear_column, item_location( character, it ), - &item_category_id( "WEAPON_HELD" ).obj(), include_hidden ); + &item_category_id( "WEAPON_HELD" ).obj() ); } else if( character.is_worn( *it ) ) { add_item( own_gear_column, item_location( character, it ), - &item_category_id( "ITEMS_WORN" ).obj(), include_hidden ); + &item_category_id( "ITEMS_WORN" ).obj() ); } return VisitResponse::NEXT; } ); @@ -1524,7 +1536,7 @@ void inventory_selector::add_character_items( Character &character, bool include for( item &it_elem : *elem ) { item_location parent( character, &it_elem ); add_contained_items( parent, own_inv_column, - &item_category_id( "ITEMS_WORN" ).obj() ); + &item_category_id( "ITEMS_WORN" ).obj(), get_topmost_parent( nullptr, parent, preset ) ); } } // this is a little trick; we want the default behavior for contained items to be in own_inv_column @@ -1547,7 +1559,7 @@ void inventory_selector::add_map_items( const tripoint &target ) for( item &it_elem : items ) { item_location parent( map_cursor( target ), &it_elem ); - add_contained_items( parent, map_column, &map_cat ); + add_contained_items( parent, map_column, &map_cat, get_topmost_parent( nullptr, parent, preset ) ); } } } @@ -1573,7 +1585,8 @@ void inventory_selector::add_vehicle_items( const tripoint &target ) for( item &it_elem : items ) { item_location parent( vehicle_cursor( *veh, part ), &it_elem ); - add_contained_items( parent, map_column, &vehicle_cat ); + add_contained_items( parent, map_column, &vehicle_cat, get_topmost_parent( nullptr, parent, + preset ) ); } } @@ -2196,6 +2209,9 @@ void inventory_selector::on_input( const inventory_input &input ) } if( input.action == "HIDE_CONTENTS" || input.action == "SHOW_CONTENTS" ) { shared_ptr_fast current_ui = ui.lock(); + for( auto const &col : columns ) { + col->invalidate_paging(); + } if( current_ui ) { std::vector inv = get_selected().locations; current_ui->mark_resize(); @@ -2295,7 +2311,7 @@ void inventory_selector::toggle_categorize_contained() } add_entry( own_inv_column, std::move( entry->locations ), /*custom_category=*/custom_category, - /*chosen_count=*/entry->chosen_count ); + /*chosen_count=*/entry->chosen_count, entry->topmost_parent ); } else { replacement_column.add_entry( *entry ); } @@ -2322,7 +2338,7 @@ void inventory_selector::toggle_categorize_contained() } add_entry( own_gear_column, std::move( entry->locations ), /*custom_category=*/custom_category, - /*chosen_count=*/entry->chosen_count ); + /*chosen_count=*/entry->chosen_count, entry->topmost_parent ); } own_gear_column.order_by_parent(); own_inv_column.clear(); diff --git a/src/inventory_ui.h b/src/inventory_ui.h index 3e5db5cf6f27e..e760d6ad49a3e 100644 --- a/src/inventory_ui.h +++ b/src/inventory_ui.h @@ -146,6 +146,8 @@ class inventory_entry bool highlight_as_parent = false; bool highlight_as_child = false; bool collapsed = false; + // topmost visible parent, used for visibility checks + item *topmost_parent = nullptr; private: const item_category *custom_category = nullptr; @@ -395,6 +397,10 @@ class inventory_column indent_entries_override = entry_override; } + void invalidate_paging() { + paging_is_valid = false; + } + protected: struct entry_cell_cache_t { bool assigned = false; @@ -510,9 +516,9 @@ class inventory_selector /** These functions add items from map / vehicles. */ void add_contained_items( item_location &container ); void add_contained_items( item_location &container, inventory_column &column, - const item_category *custom_category = nullptr ); + const item_category *custom_category = nullptr, item *topmost_parent = nullptr ); void add_contained_ebooks( item_location &container ); - void add_character_items( Character &character, const bool include_hidden = true ); + void add_character_items( Character &character ); void add_map_items( const tripoint &target ); void add_vehicle_items( const tripoint &target ); void add_nearby_items( int radius = 1 ); @@ -559,12 +565,12 @@ class inventory_selector void add_entry( inventory_column &target_column, std::vector &&locations, const item_category *custom_category = nullptr, - size_t chosen_count = 0 ); + size_t chosen_count = 0, item *topmost_parent = nullptr ); void add_item( inventory_column &target_column, item_location &&location, const item_category *custom_category = nullptr, - const bool include_hidden = true ); + item *topmost_parent = nullptr ); void add_items( inventory_column &target_column, const std::function &locator,