void inventory_selector::set_active_column( size_t index ) { if( index < columns.size() && index != active_column_index && get_column( index ).activatable() ) { get_active_column().on_deactivate(); active_column_index = index; get_active_column().on_activate(); } }
void inventory_selector::draw( WINDOW *w ) const { mvwprintw( w, 0, 0, title.c_str() ); // Position of inventory columns is adaptive. They're aligned to the left if they occupy less than 2/3 of the screen. // Otherwise they're aligned symmetrically to the center of the screen. static const float min_ratio_to_center = 1.f / 3; const int free_space = getmaxx( w ) - get_columns_width(); const bool center_align = std::abs( float( free_space ) / getmaxx( w ) ) <= min_ratio_to_center; const int max_gap = ( columns.size() > 1 ) ? free_space / ( int( columns.size() ) - 1 ) : 0; const int gap = center_align ? max_gap : std::min<int>( max_gap, 4 ); const int gap_rounding_error = ( center_align && columns.size() > 1 ) ? free_space % ( columns.size() - 1 ) : 0; size_t x = 1; size_t y = 2; size_t active_x = 0; for( const auto &column : columns ) { if( &column == &columns.back() ) { x += gap_rounding_error; } if( !is_active_column( *column ) ) { column->draw( w, x, y ); } else { active_x = x; } if( column->pages_count() > 1 ) { mvwprintw( w, getmaxy( w ) - 2, x, _( "Page %d/%d" ), column->page_index() + 1, column->pages_count() ); } x += column->get_width() + gap; } get_active_column().draw( w, active_x, y ); if( empty() ) { center_print( w, getmaxy( w ) / 2, c_dkgray, _( "Your inventory is empty." ) ); } const std::string msg_str = ( navigation == navigation_mode::CATEGORY ) ? _( "Category selection; [TAB] switches mode, arrows select." ) : _( "Item selection; [TAB] switches mode, arrows select." ); const nc_color msg_color = ( navigation == navigation_mode::CATEGORY ) ? h_white : c_ltgray; if( center_align ) { center_print( w, getmaxy( w ) - 1, msg_color, msg_str.c_str() ); } else { trim_and_print( w, getmaxy( w ) - 1, 1, getmaxx( w ), msg_color, msg_str.c_str() ); } }
std::list<std::pair<int, int>> inventory_selector::execute_multidrop( const std::string &title ) { insert_selection_column( "ITEMS TO DROP", _( "ITEMS TO DROP" ) ); prepare_columns( true ); int count = 0; while( true ) { display( title, SM_MULTIDROP ); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); auto entry = find_entry_by_invlet( ch ); if( ch >= '0' && ch <= '9' ) { count = std::min( count, INT_MAX / 10 - 10 ); count *= 10; count += ch - '0'; } else if( entry != nullptr ) { set_drop_count( *entry, count ); count = 0; } else if( action == "RIGHT" ) { for( const auto &entry : get_active_column().get_all_selected() ) { set_drop_count( *entry, count ); } count = 0; } else if( action == "CONFIRM" ) { break; } else if( action == "QUIT" ) { return std::list<std::pair<int, int> >(); } else { on_action( action ); count = 0; } } std::list<std::pair<int, int>> dropped_pos_and_qty; for( auto drop_pair : dropping ) { dropped_pos_and_qty.push_back( std::make_pair( drop_pair.first, drop_pair.second ) ); } return dropped_pos_and_qty; }
item_location &inventory_pick_selector::execute() { prepare_columns( false ); while( true ) { refresh_window(); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); const auto entry = find_entry_by_invlet( ch ); if( entry != nullptr ) { return entry->get_location(); } else if( action == "QUIT" ) { return *null_location; } else if( action == "RIGHT" || action == "CONFIRM" ) { return get_active_column().get_selected().get_location(); } else { on_action( action ); } } }
int inventory_selector::execute_pick( const std::string &title ) { prepare_columns( false ); while( true ) { display( title, SM_PICK ); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); const auto entry = find_entry_by_invlet( ch ); if( entry != nullptr ) { return entry->item_pos; } else if ( action == "CONFIRM" || action == "RIGHT" ) { return get_active_column().get_selected().item_pos; } else if ( action == "QUIT" ) { return INT_MIN; } else { on_action( action ); } } }
item_location inventory_selector::execute_pick_map( const std::string &title, std::unordered_map<item *, item_location> &opts ) { prepare_columns( false ); while( true ) { display( title, SM_PICK ); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); const auto entry = find_entry_by_invlet( ch ); if( entry != nullptr ) { item *it = const_cast<item *>( entry->it ); const auto iter = opts.find( it ); return ( iter != opts.end() ) ? std::move( iter->second ) : item_location( u, it ); } else if( action == "QUIT" ) { return item_location(); } else if( action == "RIGHT" || action == "CONFIRM" ) { const auto selected = get_active_column().get_selected(); const auto it = const_cast<item *>( selected.it ); // Item in inventory if( selected.item_pos != INT_MIN ) { return item_location( u, it ); } // Item on ground or in vehicle auto iter = opts.find( it ); if( iter != opts.end() ) { return std::move( iter->second ); } return item_location(); } else { on_action( action ); } } }
std::pair<const item *, const item *> inventory_compare_selector::execute() { prepare_columns( true ); while(true) { refresh_window(); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); const auto entry = find_entry_by_invlet( ch ); if( entry != nullptr ) { toggle_entry( entry ); } else if(action == "RIGHT") { const auto selection( get_active_column().get_all_selected() ); for( auto &entry : selection ) { if( entry->chosen_count == 0 || selection.size() == 1 ) { toggle_entry( entry ); if( compared.size() == 2 ) { break; } } } } else if( action == "QUIT" ) { return std::make_pair( nullptr, nullptr ); } else { on_action( action ); } if( compared.size() == 2 ) { const auto res = std::make_pair( &compared.back()->get_item(), &compared.front()->get_item() ); toggle_entry( compared.back() ); return res; } } }
void inventory_selector::display( const std::string &title, selector_mode mode ) const { werase(w_inv); mvwprintw(w_inv, 0, 0, title.c_str()); // Position of inventory columns is adaptive. They're aligned to the left if they occupy less than 2/3 of the screen. // Otherwise they're aligned symmetrically to the center of the screen. static const float min_ratio_to_center = 1.f / 3; const int free_space = getmaxx( w_inv ) - get_columns_width(); const bool center_align = std::abs( float( free_space ) / getmaxx( w_inv ) ) <= min_ratio_to_center; const int max_gap = ( columns.size() > 1 ) ? free_space / ( columns.size() - 1 ) : 0; const int gap = center_align ? max_gap : std::min<int>( max_gap, 4 ); const int gap_rounding_error = ( center_align && columns.size() > 1 ) ? free_space % ( columns.size() - 1 ) : 0; size_t x = 1; size_t y = 2; size_t active_x = 0; for( const auto &column : columns ) { if( &column == &columns.back() ) { x += gap_rounding_error; } if( !is_active_column( *column ) ) { column->draw( w_inv, x, y ); } else { active_x = x; } if( column->pages_count() > 1 ) { mvwprintw( w_inv, getmaxy( w_inv ) - 2, x, _( "Page %d/%d" ), column->page_index() + 1, column->pages_count() ); } x += column->get_width() + gap; } get_active_column().draw( w_inv, active_x, y ); if( mode == SM_PICK ) { mvwprintw(w_inv, 1, 61, _("Hotkeys: %d/%d "), u.allocated_invlets().size(), inv_chars.size()); } if (mode == SM_MULTIDROP) { // Make copy, remove to be dropped items from that // copy and let the copy recalculate the volume capacity // (can be affected by various traits). player tmp = u; // first round: remove weapon & worn items, start with larges worn index for( const auto &elem : dropping ) { if( elem.first == -1 && elem.second == -1 ) { tmp.remove_weapon(); } else if( elem.first == -1 && elem.second != -1 ) { tmp.weapon.charges -= elem.second; } else if( elem.first < 0 ) { tmp.i_rem( elem.first ); } } remove_dropping_items(tmp); print_inv_weight_vol(tmp.weight_carried(), tmp.volume_carried(), tmp.volume_capacity()); mvwprintw(w_inv, 1, 0, _("To drop x items, type a number and then the item hotkey.")); } else { print_inv_weight_vol(u.weight_carried(), u.volume_carried(), u.volume_capacity()); } if( empty() ) { center_print( w_inv, getmaxy( w_inv ) / 2, c_dkgray, _( "Your inventory is empty." ) ); } const std::string msg_str = ( navigation == navigation_mode::CATEGORY ) ? _( "Category selection; [TAB] switches mode, arrows select." ) : _( "Item selection; [TAB] switches mode, arrows select." ); const nc_color msg_color = ( navigation == navigation_mode::CATEGORY ) ? h_white : c_ltgray; if( center_align ) { center_print( w_inv, getmaxy( w_inv ) - 1, msg_color, msg_str.c_str() ); } else { trim_and_print( w_inv, getmaxy( w_inv ) - 1, 1, getmaxx( w_inv ), msg_color, msg_str.c_str() ); } wrefresh(w_inv); }
void refresh_active_column() { if( !get_active_column().activatable() ) { toggle_active_column(); } }
bool is_active_column( const inventory_column &column ) const { return &column == &get_active_column(); }
void inventory_selector::execute_compare( const std::string &title ) { insert_selection_column( "ITEMS TO COMPARE", _( "ITEMS TO COMPARE" ) ); prepare_columns( true ); std::vector<inventory_entry *> compared; const auto toggle_entry = [ this, &compared ]( inventory_entry *entry ) { const auto iter = std::find( compared.begin(), compared.end(), entry ); entry->chosen_count = ( iter == compared.end() ) ? 1 : 0; if( entry->chosen_count != 0 ) { compared.push_back( entry ); } else { compared.erase( iter ); } on_change( *entry ); }; while(true) { display( title, SM_COMPARE ); const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); const auto entry = find_entry_by_invlet( ch ); if( entry != nullptr ) { toggle_entry( entry ); } else if(action == "RIGHT") { const auto selection( get_active_column().get_all_selected() ); for( auto &entry : selection ) { if( entry->chosen_count == 0 || selection.size() == 1 ) { toggle_entry( entry ); if( compared.size() == 2 ) { break; } } } } else if( action == "QUIT" ) { break; } else { on_action( action ); } if( compared.size() == 2 ) { const item *first_item = compared.back()->it; const item *second_item = compared.front()->it; std::vector<iteminfo> vItemLastCh, vItemCh; std::string sItemLastCh, sItemCh, sItemTn; first_item->info( true, vItemCh ); sItemCh = first_item->tname(); sItemTn = first_item->type_name(); second_item->info(true, vItemLastCh); sItemLastCh = second_item->tname(); int iScrollPos = 0; int iScrollPosLast = 0; int ch = ( int ) ' '; do { draw_item_info( 0, ( TERMX - VIEW_OFFSET_X * 2 ) / 2, 0, TERMY - VIEW_OFFSET_Y * 2, sItemLastCh, sItemTn, vItemLastCh, vItemCh, iScrollPosLast, true ); //without getch() ch = draw_item_info( ( TERMX - VIEW_OFFSET_X * 2) / 2, (TERMX - VIEW_OFFSET_X * 2 ) / 2, 0, TERMY - VIEW_OFFSET_Y * 2, sItemCh, sItemTn, vItemCh, vItemLastCh, iScrollPos ); if( ch == KEY_PPAGE ) { iScrollPos--; iScrollPosLast--; } else if( ch == KEY_NPAGE ) { iScrollPos++; iScrollPosLast++; } } while ( ch == KEY_PPAGE || ch == KEY_NPAGE ); toggle_entry( compared.back() ); } } }