Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable category toggle in pickup selectors #58917

Merged
merged 3 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 99 additions & 50 deletions src/inventory_ui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ bool always_yes( const inventory_entry & )
return true;
}

bool return_item( const inventory_entry &entry )
{
return entry.is_item();
}

bool is_container( const item_location &loc )
{
return loc.where() == item_location::type::container;
}

} // namespace

bool is_worn_ablative( item_location const &container, item_location const &child )
Expand Down Expand Up @@ -171,7 +181,7 @@ struct container_data {

static int contained_offset( const item_location &loc )
{
if( loc.where() != item_location::type::container ) {
if( !is_container( loc ) ) {
return 0;
}
return 2 + contained_offset( loc.parent_item() );
Expand Down Expand Up @@ -554,8 +564,7 @@ bool inventory_holster_preset::is_shown( const item_location &contained ) const
if( contained.eventually_contains( holster ) || holster.eventually_contains( contained ) ) {
return false;
}
if( contained.where() != item_location::type::container
&& contained->made_of( phase_id::LIQUID ) ) {
if( !is_container( contained ) && contained->made_of( phase_id::LIQUID ) ) {
// spilt liquid cannot be picked up
return false;
}
Expand Down Expand Up @@ -2446,73 +2455,100 @@ bool inventory_selector::is_overflown( size_t client_width ) const
return get_columns_occupancy_ratio( client_width ) > 1.0;
}

void inventory_selector::_categorize( inventory_column &col )
{
// Remove custom category and allow entries to categorize by their item's category
for( inventory_entry *entry : col.get_entries( return_item, true ) ) {
const item_location loc = entry->any_item();
const item_category *custom_category = nullptr;

// ensure top-level equipped entries don't lose their special categories
if( &*loc == &u.get_wielded_item() ) {
custom_category = &item_category_WEAPON_HELD.obj();
} else if( u.is_worn( *loc ) ) {
custom_category = &item_category_ITEMS_WORN.obj();
}

entry->set_custom_category( custom_category );
}
col.set_indent_entries_override( false );
col.invalidate_paging();
}

void inventory_selector::_uncategorize( inventory_column &col )
{
for( inventory_entry *entry : col.get_entries( return_item, true ) ) {
// find the topmost parent of the entry's item and categorize it by that
// to form the hierarchy
item_location ancestor = entry->any_item();
while( ancestor.has_parent() ) {
ancestor = ancestor.parent_item();
}

const item_category *custom_category = nullptr;
if( ancestor.where() != item_location::type::character ) {
const std::string name = to_upper_case( remove_color_tags( ancestor.describe() ) );
const item_category map_cat( name, no_translation( name ), 100 );
custom_category = naturalize_category( map_cat, ancestor.position() );
} else if( &*ancestor == &u.get_wielded_item() ) {
custom_category = &item_category_WEAPON_HELD.obj();
} else if( u.is_worn( *ancestor ) ) {
custom_category = &item_category_ITEMS_WORN.obj();
}

entry->set_custom_category( custom_category );
}
col.clear_indent_entries_override();
col.invalidate_paging();
}

void inventory_selector::toggle_categorize_contained()
{
const auto return_item = []( const inventory_entry & entry ) {
return entry.is_item();
};
std::vector<item_location> highlighted;
if( get_highlighted().is_item() ) {
highlighted = get_highlighted().locations;
}

if( _uimode == uimode::hierarchy ) {
inventory_column replacement_column;
for( inventory_entry *entry : own_gear_column.get_entries( return_item, true ) ) {
item_location const loc = entry->locations.front();
if( entry->any_item().where() == item_location::type::container &&
!is_worn_ablative( loc.parent_item(), loc ) ) {
item_location ancestor = entry->any_item();
while( ancestor.has_parent() ) {
ancestor = ancestor.parent_item();
}
const item_category *custom_category = nullptr;
if( ancestor.where() != item_location::type::character ) {
// might have been merged from the map column
custom_category = entry->get_category_ptr();
}
inventory_entry *ret =
add_entry( own_inv_column, std::move( entry->locations ), custom_category,
entry->chosen_count, entry->topmost_parent, entry->chevron );
ret->generation = entry->generation;

} else {
replacement_column.add_entry( *entry );
}
// split entries into either worn/held gear or contained items
for( inventory_entry *entry : own_gear_column.get_entries( return_item, true ) ) {
const item_location loc = entry->any_item();
inventory_column *col = is_container( loc ) && !is_worn_ablative( loc.parent_item(), loc ) ?
&own_inv_column : &replacement_column;
col->add_entry( *entry );
}
own_gear_column.clear();
replacement_column.move_entries_to( own_gear_column );
own_inv_column.set_indent_entries_override( false );

for( inventory_column *col : columns ) {
_categorize( *col );
}
_uimode = uimode::categories;
} else {
for( inventory_entry *entry : own_inv_column.get_entries( return_item, true ) ) {
item_location ancestor = entry->any_item();
while( ancestor.has_parent() ) {
ancestor = ancestor.parent_item();
}
const item_category *custom_category = nullptr;
if( ancestor.where() != item_location::type::character ) {
// might have been merged from the map column
custom_category = entry->get_category_ptr();
} else if( &*ancestor == &u.get_wielded_item() ) {
custom_category = &item_category_WEAPON_HELD.obj();
} else if( u.is_worn( *ancestor ) ) {
custom_category = &item_category_ITEMS_WORN.obj();
}
inventory_entry *ret =
add_entry( own_gear_column, std::move( entry->locations ), custom_category,
entry->chosen_count, entry->topmost_parent, entry->chevron );
ret->generation = entry->generation;
// move all entries into one big gear column and turn into hierarchy
own_inv_column.move_entries_to( own_gear_column );
for( inventory_column *col : columns ) {
_uncategorize( *col );
}
own_inv_column.clear();
_uimode = uimode::hierarchy;
}

if( !highlighted.empty() ) {
highlight_one_of( highlighted );
}

// needs to be called now so that new invlets can be assigned
// and subclasses w/ selection columns can then re-populate entries
// using the new invlets
prepare_layout();

// invalidate, but dont mark resize, to avoid re-calling prepare_layout()
// and as a consequence reassign_custom_invlets()
shared_ptr_fast<ui_adaptor> current_ui = ui.lock();
if( current_ui ) {
current_ui->mark_resize();
current_ui->invalidate_ui();
}
}

Expand Down Expand Up @@ -2621,9 +2657,6 @@ void inventory_selector::action_examine( const item_location sitem )

void inventory_selector::highlight()
{
const auto return_item = []( const inventory_entry & entry ) {
return entry.is_item();
};
const inventory_entry &selected = get_active_column().get_highlighted();
if( !selected.is_item() ) {
return;
Expand Down Expand Up @@ -2986,6 +3019,20 @@ void inventory_multiselector::deselect_contained_items()
}
}

void inventory_multiselector::toggle_categorize_contained()
{
selection_col->clear();
inventory_selector::toggle_categorize_contained();

for( inventory_column *col : get_all_columns() ) {
for( inventory_entry *entry : col->get_entries( return_item, true ) ) {
if( entry->chosen_count > 0 ) {
toggle_entry( *entry, entry->chosen_count );
}
}
}
}

void inventory_multiselector::on_input( const inventory_input &input )
{
bool const noMarkCountBound = ctxt.keys_bound_to( "MARK_WITH_COUNT" ).empty();
Expand Down Expand Up @@ -3015,6 +3062,8 @@ void inventory_multiselector::on_input( const inventory_input &input )
? count < max ? count + 1 : max
: count > 1 ? count - 1 : 0;
toggle_entry( entry, newcount );
} else if( input.action == "VIEW_CATEGORY_MODE" ) {
toggle_categorize_contained();
} else {
inventory_selector::on_input( input );
}
Expand Down
12 changes: 12 additions & 0 deletions src/inventory_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ class inventory_entry
size_t generation = 0;
bool chevron = false;

void set_custom_category( const item_category *category ) {
custom_category = category;
}

private:
const item_category *custom_category = nullptr;
bool enabled = true;
Expand Down Expand Up @@ -424,6 +428,10 @@ class inventory_column
indent_entries_override = entry_override;
}

void clear_indent_entries_override() {
indent_entries_override = cata::nullopt;
}

void invalidate_paging() {
paging_is_valid = false;
}
Expand Down Expand Up @@ -844,6 +852,9 @@ class inventory_selector

uimode _uimode = uimode::categories;

void _categorize( inventory_column &col );
void _uncategorize( inventory_column &col );

public:
std::string action_bound_to_key( char key ) const;
};
Expand Down Expand Up @@ -890,6 +901,7 @@ class inventory_multiselector : public inventory_selector
void on_input( const inventory_input &input );
int count = 0;
stats get_raw_stats() const override;
void toggle_categorize_contained();
private:
std::unique_ptr<inventory_column> selection_col;
GetStats get_stats;
Expand Down