/** * Display data in table, each cell contains one entry from the * data vector. Allows vertical scrolling if the data does not fit. * Data is displayed using fold_and_print_from, which allows coloring! * @param columns Number of columns, can be 1. Make sure each entry * of the data vector fits into one cell. * @param title The title text, displayed on top. * @param w The window to draw this in, the whole widow is used. */ void display_table(WINDOW *w, const std::string &title, int columns, const std::vector<std::string> &data) { const int width = getmaxx(w) - 2; // -2 for border const int rows = getmaxy(w) - 2 - 1; // -2 for border, -1 for title const int col_width = width / columns; int offset = 0; const int title_length = utf8_width(title.c_str()); while(true) { werase(w); draw_border(w); mvwprintz(w, 1, (width - title_length) / 2, c_white, "%s", title.c_str()); for(int i = 0; i < rows * columns; i++) { if(i + offset * columns >= data.size()) { break; } const int x = 2 + (i % columns) * col_width; const int y = (i / columns) + 2; fold_and_print_from(w, y, x, col_width, 0, c_white, data[i + offset * columns]); } draw_scrollbar(w, offset, rows, data.size() / 3, 2, 0); wrefresh(w); int ch = getch(); if (ch == KEY_DOWN && ((offset + 1) * columns) < data.size()) { offset++; } else if(ch == KEY_UP && offset > 0) { offset--; } else if(ch == ' ' || ch == '\n' || ch == KEY_ESCAPE) { break; } } }
void worldfactory::draw_mod_list( WINDOW *w, int &start, int &cursor, const std::vector<std::string> &mods, bool is_active_list, const std::string &text_if_empty ) { werase( w ); calcStartPos( start, cursor, getmaxy( w ), mods.size() ); if( mods.empty() ) { center_print( w, 0, c_red, "%s", text_if_empty.c_str() ); } else { const size_t wwidth = getmaxx( w ) - 1 - 3; // border (1) + ">> " (3) for( size_t i = start, c = 0; i < mods.size() && (int)c < getmaxy( w ); ++i, ++c ) { auto mod = mman->mod_map[mods[i]]; if( (int)i != cursor ) { mvwprintw( w, c, 1, " " ); } else { if( is_active_list ) { mvwprintz( w, c, 1, c_yellow, ">> " ); } else { mvwprintz( w, c, 1, c_blue, ">> " ); } } const std::string name = utf8_truncate( mod->name, wwidth ); #ifndef LUA if ( mod->need_lua ) { mvwprintz( w, c, 4, c_dkgray, "%s", name.c_str() ); } else { mvwprintz( w, c, 4, c_white, "%s", name.c_str() ); } #else mvwprintz( w, c, 4, c_white, "%s", name.c_str() ); #endif } } draw_scrollbar( w, cursor, getmaxy( w ), mods.size(), 0, 0 ); wrefresh( w ); }
/* Updates the Appointment panel */ void apoint_update_panel (int which_pan) { int title_xpos; int bordr = 1; int title_lines = 3; int app_width = win[APP].w - bordr; int app_length = win[APP].h - bordr - title_lines; long date; struct date slctd_date; /* variable inits */ slctd_date = *calendar_get_slctd_day (); title_xpos = win[APP].w - (strlen (_(monthnames[slctd_date.mm - 1])) + 16); if (slctd_date.dd < 10) title_xpos++; date = date2sec (slctd_date, 0, 0); day_write_pad (date, app_width, app_length, hilt); /* Print current date in the top right window corner. */ erase_window_part (win[APP].p, 1, title_lines, win[APP].w - 2, win[APP].h - 2); custom_apply_attr (win[APP].p, ATTR_HIGHEST); mvwprintw (win[APP].p, title_lines, title_xpos, "%s %s %d, %d", calendar_get_pom (date), _(monthnames[slctd_date.mm - 1]), slctd_date.dd, slctd_date.yyyy); custom_remove_attr (win[APP].p, ATTR_HIGHEST); /* Draw the scrollbar if necessary. */ if ((apad.length >= app_length) || (apad.first_onscreen > 0)) { float ratio = ((float) app_length) / ((float) apad.length); int sbar_length = (int) (ratio * app_length); int highend = (int) (ratio * apad.first_onscreen); unsigned hilt_bar = (which_pan == APP) ? 1 : 0; int sbar_top = highend + title_lines + 1; if ((sbar_top + sbar_length) > win[APP].h - 1) sbar_length = win[APP].h - 1 - sbar_top; draw_scrollbar (win[APP].p, sbar_top, win[APP].w - 2, sbar_length, title_lines + 1, win[APP].h - 1, hilt_bar); } wnoutrefresh (win[APP].p); pnoutrefresh (apad.ptrwin, apad.first_onscreen, 0, win[APP].y + title_lines + 1, win[APP].x + bordr, win[APP].y + win[APP].h - 2 * bordr, win[APP].x + win[APP].w - 3 * bordr); }
/* Display a scrolling window. */ void wins_scrollwin_display (struct scrollwin *sw) { const int visible_lines = sw->win.h - sw->pad.y - 1; if (sw->total_lines > visible_lines) { float ratio = ((float) visible_lines) / ((float) sw->total_lines); int sbar_length = (int) (ratio * visible_lines); int highend = (int) (ratio * sw->first_visible_line); int sbar_top = highend + sw->pad.y + 1; if ((sbar_top + sbar_length) > sw->win.h - 1) sbar_length = sw->win.h - sbar_top; draw_scrollbar (sw->win.p, sbar_top, sw->win.w + sw->win.x - 2, sbar_length, sw->pad.y + 1, sw->win.h - 1, 1); } wmove (win[STA].p, 0, 0); wnoutrefresh (sw->win.p); pnoutrefresh (sw->pad.p, sw->first_visible_line, 0, sw->pad.y, sw->pad.x, sw->win.h - sw->pad.y + 1, sw->win.w - sw->win.x); wins_doupdate (); }
static void DisplayPspList(int top, int rows) { if (max == 0) { msg_printf(TEXT(WAITING_FOR_ANOTHER_PSP_TO_JOIN)); } else { int i; char temp[20]; video_copy_rect(show_frame, draw_frame, &full_rect, &full_rect); draw_scrollbar(470, 26, 479, 270, rows, max, pos); for (i = 0; i < rows; i++) { if ((top + i) >= max) break; sceNetEtherNtostr(psplist[top + i].mac, temp); if ((top + i) == pos) { uifont_print(24, 40 + (i + 2) * 17, UI_COLOR(UI_PAL_SELECT), temp); uifont_print(190, 40 + (i + 2) * 17, UI_COLOR(UI_PAL_SELECT), psplist[top + i].name); } else { uifont_print(24, 40 + (i + 2) * 17, UI_COLOR(UI_PAL_NORMAL), temp); uifont_print(190, 40 + (i + 2) * 17, UI_COLOR(UI_PAL_NORMAL), psplist[top + i].name); } } video_flip_screen(1); } }
const recipe *select_crafting_recipe( int &batch_size ) { if( normalized_names.empty() ) { translate_all(); } const int headHeight = 3; const int subHeadHeight = 2; const int freeWidth = TERMX - FULL_SCREEN_WIDTH; bool isWide = ( TERMX > FULL_SCREEN_WIDTH && freeWidth > 15 ); const int width = isWide ? ( freeWidth > FULL_SCREEN_WIDTH ? FULL_SCREEN_WIDTH * 2 : TERMX ) : FULL_SCREEN_WIDTH; const int wStart = ( TERMX - width ) / 2; const int tailHeight = isWide ? 3 : 4; const int dataLines = TERMY - ( headHeight + subHeadHeight ) - tailHeight; const int dataHalfLines = dataLines / 2; const int dataHeight = TERMY - ( headHeight + subHeadHeight ); const int infoWidth = width - FULL_SCREEN_WIDTH - 1; const recipe *last_recipe = nullptr; WINDOW *w_head = newwin( headHeight, width, 0, wStart ); WINDOW_PTR w_head_ptr( w_head ); WINDOW *w_subhead = newwin( subHeadHeight, width, 3, wStart ); WINDOW_PTR w_subhead_ptr( w_subhead ); WINDOW *w_data = newwin( dataHeight, width, headHeight + subHeadHeight, wStart ); WINDOW_PTR w_data_ptr( w_data ); int item_info_x = infoWidth; int item_info_y = dataHeight - 3; int item_info_width = wStart + width - infoWidth; int item_info_height = headHeight + subHeadHeight; if( !isWide ) { item_info_x = 1; item_info_y = 1; item_info_width = 1; item_info_height = 1; } WINDOW *w_iteminfo = newwin( item_info_y, item_info_x, item_info_height, item_info_width ); WINDOW_PTR w_iteminfo_ptr( w_iteminfo ); list_circularizer<std::string> tab( craft_cat_list ); list_circularizer<std::string> subtab( craft_subcat_list[tab.cur()] ); std::vector<const recipe *> current; std::vector<bool> available; const int componentPrintHeight = dataHeight - tailHeight - 1; //preserves component color printout between mode rotations nc_color rotated_color = c_white; int previous_item_line = -1; std::string previous_tab = ""; std::string previous_subtab = ""; item tmp; int line = 0, ypos, scroll_pos = 0; bool redraw = true; bool keepline = false; bool done = false; bool batch = false; int batch_line = 0; int display_mode = 0; const recipe *chosen = NULL; std::vector<iteminfo> thisItem, dummy; input_context ctxt( "CRAFTING" ); ctxt.register_cardinal(); ctxt.register_action( "QUIT" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "CYCLE_MODE" ); ctxt.register_action( "SCROLL_UP" ); ctxt.register_action( "SCROLL_DOWN" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "FILTER" ); ctxt.register_action( "RESET_FILTER" ); ctxt.register_action( "HELP_RECIPE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "CYCLE_BATCH" ); const inventory &crafting_inv = g->u.crafting_inventory(); const std::vector<npc *> helpers = g->u.get_crafting_helpers(); std::string filterstring = ""; do { if( redraw ) { // When we switch tabs, redraw the header redraw = false; if( ! keepline ) { line = 0; } else { keepline = false; } if( display_mode > 2 ) { display_mode = 2; } TAB_MODE m = ( batch ) ? BATCH : ( filterstring == "" ) ? NORMAL : FILTERED; draw_recipe_tabs( w_head, tab.cur(), m ); draw_recipe_subtabs( w_subhead, tab.cur(), subtab.cur(), m ); current.clear(); available.clear(); if( batch ) { batch_recipes( crafting_inv, helpers, current, available, chosen ); } else { // Set current to all recipes in the current tab; available are possible to make pick_recipes( crafting_inv, helpers, current, available, tab.cur(), subtab.cur(), filterstring ); } } // Clear the screen of recipe data, and draw it anew werase( w_data ); if( isWide ) { werase( w_iteminfo ); } if( isWide ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); wprintz( w_data, c_white, " " ); if( filterstring != "" ) { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } else { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [m]ode, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } } else { if( filterstring != "" ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [b]atch [?] keybindings" ) ); } else { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [m]ode, [b]atch [?] keybindings" ) ); } mvwprintz( w_data, dataLines + 2, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); } // Draw borders for( int i = 1; i < width - 1; ++i ) { // _ mvwputch( w_data, dataHeight - 1, i, BORDER_COLOR, LINE_OXOX ); } for( int i = 0; i < dataHeight - 1; ++i ) { // | mvwputch( w_data, i, 0, BORDER_COLOR, LINE_XOXO ); mvwputch( w_data, i, width - 1, BORDER_COLOR, LINE_XOXO ); } mvwputch( w_data, dataHeight - 1, 0, BORDER_COLOR, LINE_XXOO ); // _| mvwputch( w_data, dataHeight - 1, width - 1, BORDER_COLOR, LINE_XOOX ); // |_ int recmin = 0, recmax = current.size(); if( recmax > dataLines ) { if( line <= recmin + dataHalfLines ) { for( int i = recmin; i < recmin + dataLines; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, i - recmin, 2, c_dkgray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, i - recmin, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i - recmin, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else if( line >= recmax - dataHalfLines ) { for( int i = recmax - dataLines; i < recmax; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataLines + i - recmax, 2, c_ltgray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else { for( int i = line - dataHalfLines; i < line - dataHalfLines + dataLines; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataHalfLines + i - line, 2, c_ltgray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } } else { for( size_t i = 0; i < current.size() && i < ( size_t )dataHeight + 1; ++i ) { std::string tmp_name = item::nname( current[i]->result ); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), ( int )i + 1, tmp_name.c_str() ); } if( ( int )i == line ) { mvwprintz( w_data, i, 2, ( available[i] ? h_white : h_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i, 2, ( available[i] ? c_white : c_dkgray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } if( !current.empty() ) { int pane = FULL_SCREEN_WIDTH - 30 - 1; int count = batch ? line + 1 : 1; // batch size nc_color col = available[ line ] ? c_white : c_ltgray; const auto &req = current[ line ]->requirements(); draw_can_craft_indicator( w_head, 0, *current[line] ); wrefresh( w_head ); ypos = 0; std::vector<std::string> component_print_buffer; auto tools = req.get_folded_tools_list( pane, col, crafting_inv, count ); auto comps = req.get_folded_components_list( pane, col, crafting_inv, count ); component_print_buffer.insert( component_print_buffer.end(), tools.begin(), tools.end() ); component_print_buffer.insert( component_print_buffer.end(), comps.begin(), comps.end() ); if( !g->u.knows_recipe( current[line] ) ) { component_print_buffer.push_back( _( "Recipe not memorized yet" ) ); } //handle positioning of component list if it needed to be scrolled int componentPrintOffset = 0; if( display_mode > 2 ) { componentPrintOffset = ( display_mode - 2 ) * componentPrintHeight; } if( component_print_buffer.size() < static_cast<size_t>( componentPrintOffset ) ) { componentPrintOffset = 0; if( previous_tab != tab.cur() || previous_subtab != subtab.cur() || previous_item_line != line ) { display_mode = 2; } else { display_mode = 0; } } //only used to preserve mode position on components when //moving to another item and the view is already scrolled previous_tab = tab.cur(); previous_subtab = subtab.cur(); previous_item_line = line; if( display_mode == 0 ) { mvwprintz( w_data, ypos++, 30, col, _( "Skills used: %s" ), ( !current[line]->skill_used ? _( "N/A" ) : current[line]->skill_used.obj().name().c_str() ) ); mvwprintz( w_data, ypos++, 30, col, _( "Required skills: %s" ), ( current[line]->required_skills_string().c_str() ) ); mvwprintz( w_data, ypos++, 30, col, _( "Difficulty: %d" ), current[line]->difficulty ); if( !current[line]->skill_used ) { mvwprintz( w_data, ypos++, 30, col, _( "Your skill level: N/A" ) ); } else { mvwprintz( w_data, ypos++, 30, col, _( "Your skill level: %d" ), // Macs don't seem to like passing this as a class, so force it to int ( int )g->u.get_skill_level( current[line]->skill_used ) ); } ypos += current[line]->print_time( w_data, ypos, 30, pane, col, count ); mvwprintz( w_data, ypos++, 30, col, _( "Dark craftable? %s" ), current[line]->has_flag( "BLIND_EASY" ) ? _( "Easy" ) : current[line]->has_flag( "BLIND_HARD" ) ? _( "Hard" ) : _( "Impossible" ) ); ypos += current[line]->print_items( w_data, ypos, 30, col, ( batch ) ? line + 1 : 1 ); } //color needs to be preserved in case part of the previous page was cut off nc_color stored_color = col; if( display_mode > 2 ) { stored_color = rotated_color; } else { rotated_color = col; } int components_printed = 0; for( size_t i = static_cast<size_t>( componentPrintOffset ); i < component_print_buffer.size(); i++ ) { if( ypos >= componentPrintHeight ) { break; } components_printed++; print_colored_text( w_data, ypos++, 30, stored_color, col, component_print_buffer[i] ); } if( ypos >= componentPrintHeight && component_print_buffer.size() > static_cast<size_t>( components_printed ) ) { mvwprintz( w_data, ypos++, 30, col, _( "v (more)" ) ); rotated_color = stored_color; } if( isWide ) { if( last_recipe != current[line] ) { last_recipe = current[line]; tmp = current[line]->create_result(); tmp.info( true, thisItem ); } draw_item_info( w_iteminfo, tmp.tname(), tmp.type_name(), thisItem, dummy, scroll_pos, true, true, true, false, true ); } } draw_scrollbar( w_data, line, dataLines, recmax, 0 ); wrefresh( w_data ); if( isWide ) { wrefresh( w_iteminfo ); } const std::string action = ctxt.handle_input(); if( action == "CYCLE_MODE" ) { display_mode = display_mode + 1; if( display_mode <= 0 ) { display_mode = 0; } } else if( action == "LEFT" ) { subtab.prev(); redraw = true; } else if( action == "SCROLL_UP" ) { scroll_pos--; } else if( action == "SCROLL_DOWN" ) { scroll_pos++; } else if( action == "PREV_TAB" ) { tab.prev(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "RIGHT" ) { subtab.next(); redraw = true; } else if( action == "NEXT_TAB" ) { tab.next(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "DOWN" ) { line++; } else if( action == "UP" ) { line--; } else if( action == "CONFIRM" ) { if( available.empty() || !available[line] ) { popup( _( "You can't do that!" ) ); } else if( !current[line]->check_eligible_containers_for_crafting( ( batch ) ? line + 1 : 1 ) ) { ; // popup is already inside check } else { chosen = current[line]; batch_size = ( batch ) ? line + 1 : 1; done = true; } } else if( action == "HELP_RECIPE" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } tmp = current[line]->create_result(); full_screen_popup( "%s\n%s", tmp.type_name( 1 ).c_str(), tmp.info( true ).c_str() ); redraw = true; keepline = true; } else if( action == "FILTER" ) { filterstring = string_input_popup( _( "Search:" ), 85, filterstring, _( "Special prefixes for requirements:\n" " [t] search tools\n" " [c] search components\n" " [q] search qualities\n" " [s] search skills\n" " [S] search skill used only\n" "Special prefixes for results:\n" " [Q] search qualities\n" "Examples:\n" " t:soldering iron\n" " c:two by four\n" " q:metal sawing\n" " s:cooking\n" " Q:fine bolt turning" ) ); redraw = true; } else if( action == "QUIT" ) { chosen = nullptr; done = true; } else if( action == "RESET_FILTER" ) { filterstring = ""; redraw = true; } else if( action == "CYCLE_BATCH" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } batch = !batch; if( batch ) { batch_line = line; chosen = current[batch_line]; } else { line = batch_line; keepline = true; } redraw = true; } if( line < 0 ) { line = current.size() - 1; } else if( line >= ( int )current.size() ) { line = 0; } } while( !done ); return chosen; }
void display_sysmenu(void) { #ifdef USING_SYSMENU // al_set_target_bitmap(sysmstate.bmp); // al_set_target_bitmap(al_get_backbuffer(display)); al_set_clipping_rectangle(editor.panel_x, editor.panel_y, editor.panel_w, editor.panel_h); al_clear_to_color(colours.base [COL_BLUE] [SHADE_MIN]); reset_i_buttons(); al_draw_textf(font[FONT_SQUARE_BOLD].fnt, colours.base [COL_GREY] [SHADE_MAX], 5, 2, ALLEGRO_ALIGN_LEFT, "System Menu"); int i; #define BUTTON_TEXT_LENGTH 30 char button_text [BUTTON_TEXT_LENGTH] = ""; int button_colour; int button_base_shade; // is increased by 1 if button highlighted, so don't set this to SHADE_MAX int button_selectable; // note that setting this to 0 just means the button doesn't look selectable int hide_button; // button completely hidden // sysmenu buttons are a bit complicated because their appearance depends on various game state things for (i = 0; i < SYSMENU_BUTTONS; i ++) { button_colour = COL_BLUE; button_base_shade = SHADE_LOW; button_selectable = 1; hide_button = 0; switch(i) { /* case SYSMENU_NEXT_TURN: switch(game.phase) { case GAME_PHASE_TURN: if (game.current_turn == 0) strcpy(button_text, "Start execution!"); else strcpy(button_text, "Next turn"); button_colour = COL_GREEN; break; case GAME_PHASE_OVER: strcpy(button_text, "Game over"); // button_colour = COL_GREEN; button_base_shade = SHADE_MIN; button_selectable = 0; break; default: strcpy(button_text, "Executing..."); if (game.pause_soft) strcpy(button_text, "Partial execution"); if (game.pause_hard) strcpy(button_text, "Halted"); button_base_shade = SHADE_MIN; button_selectable = 0; break; } break;*/ case SYSMENU_PAUSE: if (game.pause_soft == 0) strcpy(button_text, "Pause"); else { strcpy(button_text, "Unpause"); button_colour = COL_GREEN; } break; case SYSMENU_HALT: if (game.pause_hard == 0) strcpy(button_text, "Halt execution"); else { strcpy(button_text, "Restart execution"); button_colour = COL_GREEN; } break; /* case SYSMENU_FF: if (game.fast_forward == FAST_FORWARD_OFF) strcpy(button_text, "Fast forward"); else { strcpy(button_text, "Stop fast forward"); button_colour = COL_GREEN; } break;*/ case SYSMENU_SAVE: strcpy(button_text, "Save game"); break; // case SYSMENU_LOAD: // strcpy(button_text, "Load game"); // break; case SYSMENU_QUIT: if (game.phase == GAME_PHASE_OVER) { strcpy(button_text, "Return to main menu"); button_colour = COL_GREEN; } else strcpy(button_text, "Quit game"); break; case SYSMENU_QUIT_CONFIRM: if (sysmstate.quit_confirm == 1) { strcpy(button_text, "Really quit?"); button_colour = COL_RED; } else { button_selectable = 0; hide_button = 1; } break; } if (hide_button == 1) continue; if (sysmstate.button_highlight == i && button_selectable == 1) // al_draw_filled_rectangle(editor.panel_x + sysmenu_button[i].x1, editor.panel_y + sysmenu_button[i].y1, editor.panel_x + sysmenu_button[i].x2, editor.panel_y + sysmenu_button[i].y2, colours.base [button_colour] [button_base_shade + 1]); add_menu_button(editor.panel_x + sysmenu_button[i].x1, editor.panel_y + sysmenu_button[i].y1, editor.panel_x + sysmenu_button[i].x2, editor.panel_y + sysmenu_button[i].y2, colours.base [button_colour] [button_base_shade + 1], MBUTTON_TYPE_MENU); else add_menu_button(editor.panel_x + sysmenu_button[i].x1, editor.panel_y + sysmenu_button[i].y1, editor.panel_x + sysmenu_button[i].x2, editor.panel_y + sysmenu_button[i].y2, colours.base [button_colour] [button_base_shade], MBUTTON_TYPE_MENU); // al_draw_filled_rectangle(editor.panel_x + sysmenu_button[i].x1, editor.panel_y + sysmenu_button[i].y1, editor.panel_x + sysmenu_button[i].x2, editor.panel_y + sysmenu_button[i].y2, colours.base [button_colour] [button_base_shade]); add_menu_string(editor.panel_x + sysmenu_button[i].x1 + 15, editor.panel_y + sysmenu_button[i].y1 + 20, &colours.base [COL_GREY] [SHADE_HIGH], 0, FONT_SQUARE_BOLD, button_text); // al_draw_textf(font[FONT_SQUARE_BOLD].fnt, colours.base [COL_GREY] [SHADE_HIGH], editor.panel_x + sysmenu_button[i].x1 + 15, editor.panel_y + sysmenu_button[i].y1 + 20, 0, "%s", button_text); } draw_menu_buttons(); // mode buttons should be drawn in i_display.c display_log(editor.panel_x + EDIT_WINDOW_X, editor.panel_y + editor.mlog_window_y); // al_set_target_bitmap(sysmstate.bmp); al_set_clipping_rectangle(editor.panel_x, editor.panel_y, editor.panel_w, editor.panel_h); draw_scrollbar(&mlog.scrollbar_v, 0, 0); if (ex_control.panel_drag_ready == 1 || ex_control.mouse_dragging_panel == 1) draw_panel_drag_ready_line(); // al_set_target_bitmap(al_get_backbuffer(display)); // al_draw_bitmap(sysmstate.bmp, sysmstate.panel_x, sysmstate.panel_y, 0); // TO DO!!!!: need to treat the sysmenu bitmap as a subbitmap of the display backbuffer, which would let us save this drawing operation #endif }
int do_beginner_infoview() { const char* constMsg = /* TRANSLATORS: This message must not exceed 76 characters (UTF-8 code points, actually) wide or it will display incorrectly on an 80-character wide terminal. */ _( "Welcome to GNU Typist!\n" "\n" // 23456789012345678901234567890123456789012345678901234567890123456789012345 "This message is meant to get you started using gtypist. Please read the\n" "manual (at http://www.gnu.org/software/gtypist/doc/, or type \"info gtypist\")\n" "for more in-depth information!\n" "(in particular, the manual describes how to resize GTypist's window).\n" "\n" "Use the arrow keys or PGUP/PGDN to scroll this window, SPACE/ENTER to start\n" "using gtypist, or ESCAPE to use gtypist and never show this dialog again.\n" "\n" "There are two types of typing exercises: \"drills\" and \"speed tests\". In a\n" "\"drill\", gtypist displays text in every other line on the screen and waits\n" "for the user to correctly type the exact same text in the intermediate\n" "lines. In a \"speed test\", gtypist displays text on the screen and waits\n" "for the user to correctly type the exact same text over the top.\n" "\n" "In both exercise types, you have to repeat the test if your error percentage\n" "is higher than a maximum error percentage. The default is 3%, but if this is\n" "too difficult you can change it by running gtypist with the \"-e <maxpct>\"\n" "command-line option.\n" "\n" "On most X11-based terminal emulators you can use Ctrl--/Ctrl-+ to resize the\n" "terminal window. On Windows, change the properties of the terminal window by\n" "clicking on the top left corner of the window and choosing 'Properties'.\n" "\n" "Several typing courses are available from the main menu. As well as the\n" "\"QWERTY\" courses, lessons are also available for other keyboard layouts,\n" "such as Dvorak and Colemak, and numeric keypads. There are also other\n" "lessons, besides the ones available on the main menu. To see a list of the\n" "other lessons, select \"More lessons...\" from the main menu. To use one\n" "of these other lessons, run gtypist with the name of the lesson file as a\n" "command-line argument. See the comments at the top of each .typ file for\n" "more information about the source and the author of the lessons. If you want\n" "to write your own lessons, look at the gtypist manual, it's really simple!\n" "\n" "If you have any questions about GNU Typist, please write to the gtypist\n" "mailing list at <*****@*****.**>." ); char* msg; char** msgLines; char* token; int numUsableLines, numMsgLines, i, j; int width, height, xOffset, yOffset; int firstLine, lastLine, msgLen; wchar_t ch; msg = strdup(constMsg); msgLen = strlen( msg ); /* count the number of lines in msg */ numMsgLines = 0; for (i = 0; i < msgLen; i++) { if (msg[i] == '\n') { numMsgLines++; } } if (i && msg[i - 1] != '\n') { numMsgLines++; } /* split into lines: use strsep instead of strtok because strtok cannot handle empty tokens */ msgLines = malloc(numMsgLines * sizeof(char*)); msgLines[0] = msg; for (i = j = 0; i < msgLen; i++) { if (msg[i] == '\n') { msg[i] = '\0'; msgLines[++j] = &msg[ i + 1 ]; } } width = 79 - 2; /* 2x window decoration */ numUsableLines = LINES - 3; /* header, 2x window decoration */ height = MIN(numUsableLines, numMsgLines + 2); /* frame top/bottom */ xOffset = (COLS-width) / 2; yOffset = (LINES-height) / 2; /* variables for vertical scrolling */ firstLine = 0; lastLine = (numMsgLines < height - 3) ? (numMsgLines - 1) : (height - 3); clear(); banner("Beginner screen"); draw_frame(xOffset, yOffset, xOffset + width, yOffset + height - 1); ch = 0x00; while (ch != ASCII_SPACE && ch != ASCII_ESC && ch != ASCII_NL && ch != 'q' && ch != 'Q' && ch != 'd' && ch != 'D') { switch (ch) { case KEY_UP: case 'k': if (firstLine > 0) { firstLine--; lastLine--; } break; case KEY_DOWN: case 'j': if (lastLine + 1 < numMsgLines) { firstLine++; lastLine++; } break; case KEY_PPAGE: { int old_firstLine = firstLine; firstLine -= 10; if (firstLine < 0) { firstLine = 0; } lastLine += firstLine - old_firstLine; break; } case KEY_NPAGE: { int old_lastLine = lastLine; lastLine += 10; if (lastLine + 1 >= numMsgLines) { lastLine = numMsgLines - 1; } firstLine += lastLine - old_lastLine; break; } } for (i = firstLine; i <= lastLine; i++) { move(yOffset + 1 + (i-firstLine), xOffset + 1); clrtoeol(); mvwideaddstr(yOffset + 1 + (i-firstLine), xOffset + 1, msgLines[i]); } draw_scrollbar(xOffset + width, yOffset, yOffset + height - 1, firstLine, lastLine, numMsgLines); mvwideaddstr(LINES - 1, 0, _("Press SPACE, ENTER or ESCAPE to start gtypist, or 'D' to disable this dialog")); get_widech(&ch); } /* free resources */ free(msgLines); free(msg); if (ch == 'd' || ch == 'D') { remember_no_welcome_screen_option(); } return ch != 'q' && ch != 'Q'; }
int worldfactory::show_worldgen_tab_options(WINDOW *win, WORLDPTR world) { const int iTooltipHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT - 5 - iTooltipHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; WINDOW *w_options = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 4 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_optionsptr( w_options ); WINDOW *w_options_tooltip = newwin(iTooltipHeight - 2, FULL_SCREEN_WIDTH - 2, 3 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_options_tooltipptr( w_options_tooltip ); WINDOW *w_options_header = newwin(1, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 3 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_options_headerptr( w_options_header ); std::stringstream sTemp; std::map<int, bool> mapLines; mapLines[4] = true; mapLines[60] = true; for( auto &mapLine : mapLines ) { mvwputch( win, FULL_SCREEN_HEIGHT - 1, mapLine.first + 1, BORDER_COLOR, LINE_XXOX ); // _|_ } for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_options_header, 0, i, BORDER_COLOR, LINE_OXXX); } else { mvwputch(w_options_header, 0, i, BORDER_COLOR, LINE_OXOX); // Draw header line } } mvwputch(win, iTooltipHeight + 3, 0, BORDER_COLOR, LINE_XXXO); // |- mvwputch(win, iTooltipHeight + 3, 79, BORDER_COLOR, LINE_XOXX); // -| wrefresh(win); wrefresh(w_options_header); input_context ctxt("WORLDGEN_OPTION_DIALOG"); ctxt.register_cardinal(); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); int iStartPos = 0; int iCurrentLine = 0; do { for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w_options, i, j, BORDER_COLOR, LINE_XOXO); } else { mvwputch(w_options, i, j, c_black, ' '); } if (i < iTooltipHeight) { mvwputch(w_options_tooltip, i, j, c_black, ' '); } } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, mPageItems[iWorldOptPage].size()); //Draw options int iBlankOffset = 0; for (int i = iStartPos; i < iStartPos + ((iContentHeight > (int)mPageItems[iWorldOptPage].size()) ? (int)mPageItems[iWorldOptPage].size() : iContentHeight); i++) { nc_color cLineColor = c_ltgreen; if (world->world_options[mPageItems[iWorldOptPage][i]].getMenuText() == "") { iBlankOffset++; continue; } sTemp.str(""); sTemp << i + 1 - iBlankOffset; mvwprintz(w_options, i - iStartPos, 1, c_white, sTemp.str().c_str()); mvwprintz(w_options, i - iStartPos, 5, c_white, ""); if (iCurrentLine == i) { wprintz(w_options, c_yellow, ">> "); } else { wprintz(w_options, c_yellow, " "); } wprintz(w_options, c_white, "%s", (world->world_options[mPageItems[iWorldOptPage][i]].getMenuText()).c_str()); if (world->world_options[mPageItems[iWorldOptPage][i]].getValue() == "false") { cLineColor = c_ltred; } mvwprintz(w_options, i - iStartPos, 62, (iCurrentLine == i) ? hilite(cLineColor) : cLineColor, "%s", (world->world_options[mPageItems[iWorldOptPage][i]].getValueName()).c_str()); } //Draw Scrollbar draw_scrollbar(win, iCurrentLine, iContentHeight, mPageItems[iWorldOptPage].size(), iTooltipHeight + 4, 0, BORDER_COLOR); fold_and_print(w_options_tooltip, 0, 0, 78, c_white, "%s #%s", world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getTooltip().c_str(), world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getDefaultText().c_str()); wrefresh(w_options_tooltip); wrefresh(w_options); refresh(); const std::string action = ctxt.handle_input(); if (action == "DOWN") { do { iCurrentLine++; if (iCurrentLine >= (int)mPageItems[iWorldOptPage].size()) { iCurrentLine = 0; } } while(world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getMenuText() == ""); } else if (action == "UP") { do { iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = mPageItems[iWorldOptPage].size() - 1; } } while(world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].getMenuText() == ""); } else if (!mPageItems[iWorldOptPage].empty() && action == "RIGHT") { world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].setNext(); } else if (!mPageItems[iWorldOptPage].empty() && action == "LEFT") { world->world_options[mPageItems[iWorldOptPage][iCurrentLine]].setPrev(); } else if (action == "PREV_TAB") { return -1; } else if (action == "NEXT_TAB") { return 1; } else if (action == "QUIT") { return -999; } } while (true); return 0; }
const recipe *select_crafting_recipe( int &batch_size ) { if( normalized_names.empty() ) { translate_all(); } const int headHeight = 3; const int subHeadHeight = 2; const int freeWidth = TERMX - FULL_SCREEN_WIDTH; bool isWide = ( TERMX > FULL_SCREEN_WIDTH && freeWidth > 15 ); const int width = isWide ? ( freeWidth > FULL_SCREEN_WIDTH ? FULL_SCREEN_WIDTH * 2 : TERMX ) : FULL_SCREEN_WIDTH; const int wStart = ( TERMX - width ) / 2; const int tailHeight = isWide ? 3 : 4; const int dataLines = TERMY - ( headHeight + subHeadHeight ) - tailHeight; const int dataHalfLines = dataLines / 2; const int dataHeight = TERMY - ( headHeight + subHeadHeight ); const int infoWidth = width - FULL_SCREEN_WIDTH - 1; const recipe *last_recipe = nullptr; catacurses::window w_head = catacurses::newwin( headHeight, width, 0, wStart ); catacurses::window w_subhead = catacurses::newwin( subHeadHeight, width, 3, wStart ); catacurses::window w_data = catacurses::newwin( dataHeight, width, headHeight + subHeadHeight, wStart ); int item_info_x = infoWidth; int item_info_y = dataHeight - 3; int item_info_width = wStart + width - infoWidth; int item_info_height = headHeight + subHeadHeight; if( !isWide ) { item_info_x = 1; item_info_y = 1; item_info_width = 1; item_info_height = 1; } catacurses::window w_iteminfo = catacurses::newwin( item_info_y, item_info_x, item_info_height, item_info_width ); list_circularizer<std::string> tab( craft_cat_list ); list_circularizer<std::string> subtab( craft_subcat_list[tab.cur()] ); std::vector<const recipe *> current; std::vector<bool> available; const int componentPrintHeight = dataHeight - tailHeight - 1; //preserves component color printout between mode rotations nc_color rotated_color = c_white; int previous_item_line = -1; std::string previous_tab; std::string previous_subtab; item tmp; int line = 0; int ypos = 0; int scroll_pos = 0; bool redraw = true; bool keepline = false; bool done = false; bool batch = false; bool show_hidden = false; int batch_line = 0; int display_mode = 0; const recipe *chosen = nullptr; std::vector<iteminfo> thisItem; std::vector<iteminfo> dummy; input_context ctxt( "CRAFTING" ); ctxt.register_cardinal(); ctxt.register_action( "QUIT" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "CYCLE_MODE" ); ctxt.register_action( "SCROLL_UP" ); ctxt.register_action( "SCROLL_DOWN" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "FILTER" ); ctxt.register_action( "RESET_FILTER" ); ctxt.register_action( "TOGGLE_FAVORITE" ); ctxt.register_action( "HELP_RECIPE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "CYCLE_BATCH" ); ctxt.register_action( "RELATED_RECIPES" ); ctxt.register_action( "HIDE_SHOW_RECIPE" ); const inventory &crafting_inv = g->u.crafting_inventory(); const std::vector<npc *> helpers = g->u.get_crafting_helpers(); std::string filterstring; const auto &available_recipes = g->u.get_available_recipes( crafting_inv, &helpers ); std::map<const recipe *, bool> availability_cache; do { if( redraw ) { // When we switch tabs, redraw the header redraw = false; if( ! keepline ) { line = 0; } else { keepline = false; } if( display_mode > 2 ) { display_mode = 2; } TAB_MODE m = ( batch ) ? BATCH : ( filterstring.empty() ) ? NORMAL : FILTERED; draw_recipe_tabs( w_head, tab.cur(), m ); draw_recipe_subtabs( w_subhead, tab.cur(), subtab.cur(), available_recipes, m ); show_hidden = false; available.clear(); if( batch ) { current.clear(); for( int i = 1; i <= 20; i++ ) { current.push_back( chosen ); available.push_back( chosen->requirements().can_make_with_inventory( crafting_inv, i ) ); } } else { std::vector<const recipe *> picking; if( !filterstring.empty() ) { auto qry = trim( filterstring ); if( qry.size() > 2 && qry[1] == ':' ) { switch( qry[0] ) { case 't': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::tool ); break; case 'c': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::component ); break; case 's': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::skill ); break; case 'p': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::primary_skill ); break; case 'Q': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality ); break; case 'q': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality_result ); break; case 'd': picking = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::description_result ); break; case 'm': { auto &learned = g->u.get_learned_recipes(); if( query_is_yes( qry ) ) { std::set_intersection( available_recipes.begin(), available_recipes.end(), learned.begin(), learned.end(), std::back_inserter( picking ) ); } else { std::set_difference( available_recipes.begin(), available_recipes.end(), learned.begin(), learned.end(), std::back_inserter( picking ) ); } break; } case 'h': { std::copy( available_recipes.begin(), available_recipes.end(), std::back_inserter( picking ) ); if( query_is_yes( qry ) ) { show_hidden = true; } break; } default: current.clear(); } } else { picking = available_recipes.search( qry ); } } else if( subtab.cur() == "CSC_*_FAVORITE" ) { picking = available_recipes.favorite(); } else if( subtab.cur() == "CSC_*_RECENT" ) { picking = available_recipes.recent(); } else { picking = available_recipes.in_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ); } current.clear(); for( auto i : picking ) { if( ( uistate.hidden_recipes.find( i->ident() ) != uistate.hidden_recipes.end() ) == show_hidden ) { current.push_back( i ); } } if( !show_hidden ) { draw_hidden_amount( w_head, 0, picking.size() - current.size() ); } available.reserve( current.size() ); // cache recipe availability on first display for( const auto e : current ) { if( !availability_cache.count( e ) ) { availability_cache.emplace( e, e->requirements().can_make_with_inventory( crafting_inv ) ); } } if( subtab.cur() != "CSC_*_RECENT" ) { std::stable_sort( current.begin(), current.end(), []( const recipe * a, const recipe * b ) { return b->difficulty < a->difficulty; } ); std::stable_sort( current.begin(), current.end(), [&]( const recipe * a, const recipe * b ) { return availability_cache[a] && !availability_cache[b]; } ); } std::transform( current.begin(), current.end(), std::back_inserter( available ), [&]( const recipe * e ) { return availability_cache[e]; } ); } // current/available have been rebuilt, make sure our cursor is still in range if( current.empty() ) { line = 0; } else { line = std::min( line, static_cast<int>( current.size() ) - 1 ); } } // Clear the screen of recipe data, and draw it anew werase( w_data ); if( isWide ) { werase( w_iteminfo ); } if( isWide ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); wprintz( w_data, c_white, " " ); if( !filterstring.empty() ) { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } else { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } } else { if( !filterstring.empty() ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, [b]atch [?] keybindings" ) ); } else { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [m]ode, [s]how/hide, Re[L]ated, [*]Favorite, [b]atch [?] keybindings" ) ); } mvwprintz( w_data, dataLines + 2, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); } // Draw borders for( int i = 1; i < width - 1; ++i ) { // _ mvwputch( w_data, dataHeight - 1, i, BORDER_COLOR, LINE_OXOX ); } for( int i = 0; i < dataHeight - 1; ++i ) { // | mvwputch( w_data, i, 0, BORDER_COLOR, LINE_XOXO ); mvwputch( w_data, i, width - 1, BORDER_COLOR, LINE_XOXO ); } mvwputch( w_data, dataHeight - 1, 0, BORDER_COLOR, LINE_XXOO ); // _| mvwputch( w_data, dataHeight - 1, width - 1, BORDER_COLOR, LINE_XOOX ); // |_ int recmin = 0, recmax = current.size(); if( recmax > dataLines ) { if( line <= recmin + dataHalfLines ) { for( int i = recmin; i < recmin + dataLines; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, i - recmin, 2, c_dark_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, i - recmin, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i - recmin, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else if( line >= recmax - dataHalfLines ) { for( int i = recmax - dataLines; i < recmax; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataLines + i - recmax, 2, c_light_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else { for( int i = line - dataHalfLines; i < line - dataHalfLines + dataLines; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataHalfLines + i - line, 2, c_light_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } } else { for( size_t i = 0; i < current.size() && i < static_cast<size_t>( dataHeight ) + 1; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), static_cast<int>( i ) + 1, tmp_name.c_str() ); } if( static_cast<int>( i ) == line ) { mvwprintz( w_data, i, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } if( !current.empty() ) { int pane = FULL_SCREEN_WIDTH - 30 - 1; int count = batch ? line + 1 : 1; // batch size nc_color col = available[ line ] ? c_white : c_light_gray; const auto &req = current[ line ]->requirements(); draw_can_craft_indicator( w_head, 0, *current[line] ); wrefresh( w_head ); ypos = 0; auto qry = trim( filterstring ); std::string qry_comps; if( qry.compare( 0, 2, "c:" ) == 0 ) { qry_comps = qry.substr( 2 ); } std::vector<std::string> component_print_buffer; auto tools = req.get_folded_tools_list( pane, col, crafting_inv, count ); auto comps = req.get_folded_components_list( pane, col, crafting_inv, count, qry_comps ); component_print_buffer.insert( component_print_buffer.end(), tools.begin(), tools.end() ); component_print_buffer.insert( component_print_buffer.end(), comps.begin(), comps.end() ); if( !g->u.knows_recipe( current[line] ) ) { component_print_buffer.push_back( _( "Recipe not memorized yet" ) ); auto books_with_recipe = g->u.get_books_for_recipe( crafting_inv, current[line] ); std::string enumerated_books = enumerate_as_string( books_with_recipe.begin(), books_with_recipe.end(), []( itype_id type_id ) { return item::find_type( type_id )->nname( 1 ); } ); const std::string text = string_format( _( "Written in: %s" ), enumerated_books.c_str() ); std::vector<std::string> folded_lines = foldstring( text, pane ); component_print_buffer.insert( component_print_buffer.end(), folded_lines.begin(), folded_lines.end() ); } //handle positioning of component list if it needed to be scrolled int componentPrintOffset = 0; if( display_mode > 2 ) { componentPrintOffset = ( display_mode - 2 ) * componentPrintHeight; } if( component_print_buffer.size() < static_cast<size_t>( componentPrintOffset ) ) { componentPrintOffset = 0; if( previous_tab != tab.cur() || previous_subtab != subtab.cur() || previous_item_line != line ) { display_mode = 2; } else { display_mode = 0; } } //only used to preserve mode position on components when //moving to another item and the view is already scrolled previous_tab = tab.cur(); previous_subtab = subtab.cur(); previous_item_line = line; const int xpos = 30; if( display_mode == 0 ) { const int width = getmaxx( w_data ) - xpos - item_info_x; print_colored_text( w_data, ypos++, xpos, col, col, string_format( _( "Primary skill used: <color_cyan>%s</color>" ), ( !current[line]->skill_used ? _( "N/A" ) : current[line]->skill_used.obj().name() ) ) ); auto player_skill = g->u.get_skill_level( current[line]->skill_used ); std::string difficulty_color = current[ line ]->difficulty > player_skill ? "yellow" : "green"; print_colored_text( w_data, ypos++, xpos, col, col, string_format( _( "Difficulty: <color_%s>%d</color>" ), difficulty_color, current[ line ]->difficulty ) ); std::string skill_level_string = current[line]->skill_used ? string_format( _( "Your skill level: <color_%s>%d</color>" ), difficulty_color, player_skill ) : _( "Your skill level: <color_yellow>N/A</color>" ); print_colored_text( w_data, ypos++, xpos, col, col, skill_level_string ); ypos += fold_and_print( w_data, ypos, xpos, width, col, _( "Other skills used: %s" ), current[line]->required_skills_string( &g->u ) ); const int expected_turns = g->u.expected_time_to_craft( *current[line], count ) / to_moves<int>( 1_turns ); ypos += fold_and_print( w_data, ypos, xpos, pane, col, _( "Time to complete: <color_cyan>%s</color>" ), to_string( time_duration::from_turns( expected_turns ) ) ); print_colored_text( w_data, ypos++, xpos, col, col, string_format( _( "Dark craftable? <color_cyan>%s</color>" ), current[line]->has_flag( "BLIND_EASY" ) ? _( "Easy" ) : current[line]->has_flag( "BLIND_HARD" ) ? _( "Hard" ) : _( "Impossible" ) ) ); ypos += print_items( *current[line], w_data, ypos, xpos, col, batch ? line + 1 : 1 ); } //color needs to be preserved in case part of the previous page was cut off nc_color stored_color = col; if( display_mode > 2 ) { stored_color = rotated_color; } else { rotated_color = col; } int components_printed = 0; for( size_t i = static_cast<size_t>( componentPrintOffset ); i < component_print_buffer.size(); i++ ) { if( ypos >= componentPrintHeight ) { break; } components_printed++; print_colored_text( w_data, ypos++, xpos, stored_color, col, component_print_buffer[i] ); } if( ypos >= componentPrintHeight && component_print_buffer.size() > static_cast<size_t>( components_printed ) ) { mvwprintz( w_data, ypos++, xpos, col, _( "v (more)" ) ); rotated_color = stored_color; } if( isWide ) { if( last_recipe != current[line] ) { last_recipe = current[line]; tmp = current[line]->create_result(); } tmp.info( true, thisItem, count ); draw_item_info( w_iteminfo, tmp.tname(), tmp.type_name(), thisItem, dummy, scroll_pos, true, true, true, false, true ); } } draw_scrollbar( w_data, line, dataLines, recmax, 0 ); wrefresh( w_data ); if( isWide ) { wrefresh( w_iteminfo ); } const std::string action = ctxt.handle_input(); if( action == "CYCLE_MODE" ) { display_mode = display_mode + 1; if( display_mode <= 0 ) { display_mode = 0; } } else if( action == "LEFT" ) { std::string start = subtab.cur(); do { subtab.prev(); } while( subtab.cur() != start && available_recipes.empty_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ) ); redraw = true; } else if( action == "SCROLL_UP" ) { scroll_pos--; } else if( action == "SCROLL_DOWN" ) { scroll_pos++; } else if( action == "PREV_TAB" ) { tab.prev(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "RIGHT" ) { std::string start = subtab.cur(); do { subtab.next(); } while( subtab.cur() != start && available_recipes.empty_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ) ); redraw = true; } else if( action == "NEXT_TAB" ) { tab.next(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "DOWN" ) { line++; } else if( action == "UP" ) { line--; } else if( action == "CONFIRM" ) { if( available.empty() || !available[line] ) { popup( _( "You can't do that!" ) ); } else if( !g->u.check_eligible_containers_for_crafting( *current[line], ( batch ) ? line + 1 : 1 ) ) { // popup is already inside check } else { chosen = current[line]; batch_size = ( batch ) ? line + 1 : 1; done = true; } } else if( action == "HELP_RECIPE" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } tmp = current[line]->create_result(); full_screen_popup( "%s\n%s", tmp.type_name( 1 ).c_str(), tmp.info( true ).c_str() ); redraw = true; keepline = true; } else if( action == "FILTER" ) { struct SearchPrefix { char key; std::string example; std::string description; }; std::vector<SearchPrefix> prefixes = { { 'q', _( "metal sawing" ), _( "<color_cyan>quality</color> of resulting item" ) }, //~ Example result description search term { 'd', _( "reach attack" ), _( "<color_cyan>full description</color> of resulting item (slow)" ) }, { 'c', _( "two by four" ), _( "<color_cyan>component</color> required to craft" ) }, { 'p', _( "tailoring" ), _( "<color_cyan>primary skill</color> used to craft" ) }, { 's', _( "cooking" ), _( "<color_cyan>any skill</color> used to craft" ) }, { 'Q', _( "fine bolt turning" ), _( "<color_cyan>quality</color> required to craft" ) }, { 't', _( "soldering iron" ), _( "<color_cyan>tool</color> required to craft" ) }, { 'h', _( "yes" ), _( "recipes which are <color_cyan>hidden</color> or not" ) }, { 'm', _( "no" ), _( "recipes which are <color_cyan>memorized</color> or not" ) }, }; int max_example_length = 0; for( const auto &prefix : prefixes ) { max_example_length = std::max( max_example_length, utf8_width( prefix.example ) ); } std::string spaces( max_example_length, ' ' ); std::string description = _( "The default is to search result names. Some single-character prefixes " "can be used with a colon (:) to search in other ways.\n" "\n" "<color_white>Examples:</color>\n" ); { std::string example_name = _( "shirt" ); auto padding = max_example_length - utf8_width( example_name ); description += string_format( _( " <color_white>%s</color>%.*s %s\n" ), example_name, padding, spaces, _( "<color_cyan>name</color> of resulting item" ) ); } for( const auto &prefix : prefixes ) { auto padding = max_example_length - utf8_width( prefix.example ); description += string_format( _( " <color_yellow>%c</color><color_white>:%s</color>%.*s %s\n" ), prefix.key, prefix.example, padding, spaces, prefix.description ); } string_input_popup() .title( _( "Search:" ) ) .width( 85 ) .description( description ) .desc_color( c_light_gray ) .edit( filterstring ); redraw = true; } else if( action == "QUIT" ) { chosen = nullptr; done = true; } else if( action == "RESET_FILTER" ) { filterstring.clear(); redraw = true; } else if( action == "CYCLE_BATCH" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } batch = !batch; if( batch ) { batch_line = line; chosen = current[batch_line]; } else { line = batch_line; keepline = true; } redraw = true; } else if( action == "TOGGLE_FAVORITE" ) { keepline = true; redraw = true; if( current.empty() ) { popup( _( "Nothing selected!" ) ); continue; } if( uistate.favorite_recipes.find( current[line]->ident() ) != uistate.favorite_recipes.end() ) { uistate.favorite_recipes.erase( current[line]->ident() ); } else { uistate.favorite_recipes.insert( current[line]->ident() ); } } else if( action == "HIDE_SHOW_RECIPE" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } if( show_hidden ) { uistate.hidden_recipes.erase( current[line]->ident() ); } else { uistate.hidden_recipes.insert( current[line]->ident() ); } redraw = true; } else if( action == "RELATED_RECIPES" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } std::string recipe_name = peek_related_recipe( current[ line ], available_recipes ); if( recipe_name.empty() ) { keepline = true; } else { filterstring = recipe_name; } redraw = true; } if( line < 0 ) { line = current.size() - 1; } else if( line >= static_cast<int>( current.size() ) ) { line = 0; } } while( !done ); return chosen; }
const recipe *select_crafting_recipe( int &batch_size ) { if( normalized_names.empty() ) { translate_all(); } const int headHeight = 3; const int subHeadHeight = 2; const int freeWidth = TERMX - FULL_SCREEN_WIDTH; bool isWide = ( TERMX > FULL_SCREEN_WIDTH && freeWidth > 15 ); const int width = isWide ? ( freeWidth > FULL_SCREEN_WIDTH ? FULL_SCREEN_WIDTH * 2 : TERMX ) : FULL_SCREEN_WIDTH; const int wStart = ( TERMX - width ) / 2; const int tailHeight = isWide ? 3 : 4; const int dataLines = TERMY - ( headHeight + subHeadHeight ) - tailHeight; const int dataHalfLines = dataLines / 2; const int dataHeight = TERMY - ( headHeight + subHeadHeight ); const int infoWidth = width - FULL_SCREEN_WIDTH - 1; const recipe *last_recipe = nullptr; catacurses::window w_head = catacurses::newwin( headHeight, width, 0, wStart ); catacurses::window w_subhead = catacurses::newwin( subHeadHeight, width, 3, wStart ); catacurses::window w_data = catacurses::newwin( dataHeight, width, headHeight + subHeadHeight, wStart ); int item_info_x = infoWidth; int item_info_y = dataHeight - 3; int item_info_width = wStart + width - infoWidth; int item_info_height = headHeight + subHeadHeight; if( !isWide ) { item_info_x = 1; item_info_y = 1; item_info_width = 1; item_info_height = 1; } catacurses::window w_iteminfo = catacurses::newwin( item_info_y, item_info_x, item_info_height, item_info_width ); list_circularizer<std::string> tab( craft_cat_list ); list_circularizer<std::string> subtab( craft_subcat_list[tab.cur()] ); std::vector<const recipe *> current; std::vector<bool> available; const int componentPrintHeight = dataHeight - tailHeight - 1; //preserves component color printout between mode rotations nc_color rotated_color = c_white; int previous_item_line = -1; std::string previous_tab = ""; std::string previous_subtab = ""; item tmp; int line = 0, ypos, scroll_pos = 0; bool redraw = true; bool keepline = false; bool done = false; bool batch = false; int batch_line = 0; int display_mode = 0; const recipe *chosen = NULL; std::vector<iteminfo> thisItem, dummy; input_context ctxt( "CRAFTING" ); ctxt.register_cardinal(); ctxt.register_action( "QUIT" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "CYCLE_MODE" ); ctxt.register_action( "SCROLL_UP" ); ctxt.register_action( "SCROLL_DOWN" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "FILTER" ); ctxt.register_action( "RESET_FILTER" ); ctxt.register_action( "HELP_RECIPE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "CYCLE_BATCH" ); const inventory &crafting_inv = g->u.crafting_inventory(); const std::vector<npc *> helpers = g->u.get_crafting_helpers(); std::string filterstring = ""; const auto &available_recipes = g->u.get_available_recipes( crafting_inv, &helpers ); std::map<const recipe *, bool> availability_cache; do { if( redraw ) { // When we switch tabs, redraw the header redraw = false; if( ! keepline ) { line = 0; } else { keepline = false; } if( display_mode > 2 ) { display_mode = 2; } TAB_MODE m = ( batch ) ? BATCH : ( filterstring.empty() ) ? NORMAL : FILTERED; draw_recipe_tabs( w_head, tab.cur(), m ); draw_recipe_subtabs( w_subhead, tab.cur(), subtab.cur(), available_recipes, m ); available.clear(); if( batch ) { current.clear(); for( int i = 1; i <= 20; i++ ) { current.push_back( chosen ); available.push_back( chosen->requirements().can_make_with_inventory( crafting_inv, i ) ); } } else { if( filterstring.empty() ) { current = available_recipes.in_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ); } else { auto qry = trim( filterstring ); if( qry.size() > 2 && qry[1] == ':' ) { switch( qry[0] ) { case 't': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::tool ); break; case 'c': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::component ); break; case 's': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::skill ); break; case 'q': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality ); break; case 'Q': current = available_recipes.search( qry.substr( 2 ), recipe_subset::search_type::quality_result ); break; case 'm': { auto &learned = g->u.get_learned_recipes(); current.clear(); if( ( qry.substr( 2 ) == "yes" ) || ( qry.substr( 2 ) == "y" ) || ( qry.substr( 2 ) == "1" ) || ( qry.substr( 2 ) == "true" ) || ( qry.substr( 2 ) == "t" ) || ( qry.substr( 2 ) == "on" ) ) { std::set_intersection( available_recipes.begin(), available_recipes.end(), learned.begin(), learned.end(), std::back_inserter( current ) ); } else { std::set_difference( available_recipes.begin(), available_recipes.end(), learned.begin(), learned.end(), std::back_inserter( current ) ); } } break; default: current.clear(); } } else { current = available_recipes.search( qry ); } } available.reserve( current.size() ); // cache recipe availability on first display for( const auto e : current ) { if( !availability_cache.count( e ) ) { availability_cache.emplace( e, e->requirements().can_make_with_inventory( crafting_inv ) ); } } std::stable_sort( current.begin(), current.end(), []( const recipe * a, const recipe * b ) { return b->difficulty < a->difficulty; } ); std::stable_sort( current.begin(), current.end(), [&]( const recipe * a, const recipe * b ) { return availability_cache[a] && !availability_cache[b]; } ); std::transform( current.begin(), current.end(), std::back_inserter( available ), [&]( const recipe * e ) { return availability_cache[e]; } ); } // current/available have been rebuilt, make sure our cursor is still in range if( current.empty() ) { line = 0; } else { line = std::min( line, ( int )current.size() - 1 ); } } // Clear the screen of recipe data, and draw it anew werase( w_data ); if( isWide ) { werase( w_iteminfo ); } if( isWide ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); wprintz( w_data, c_white, " " ); if( !filterstring.empty() ) { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } else { wprintz( w_data, c_white, _( "[E]: Describe, [F]ind, [m]ode, %s [?] keybindings" ), ( batch ) ? _( "cancel [b]atch" ) : _( "[b]atch" ) ); } } else { if( !filterstring.empty() ) { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [R]eset, [m]ode, [b]atch [?] keybindings" ) ); } else { mvwprintz( w_data, dataLines + 1, 5, c_white, _( "[E]: Describe, [F]ind, [m]ode, [b]atch [?] keybindings" ) ); } mvwprintz( w_data, dataLines + 2, 5, c_white, _( "Press <ENTER> to attempt to craft object." ) ); } // Draw borders for( int i = 1; i < width - 1; ++i ) { // _ mvwputch( w_data, dataHeight - 1, i, BORDER_COLOR, LINE_OXOX ); } for( int i = 0; i < dataHeight - 1; ++i ) { // | mvwputch( w_data, i, 0, BORDER_COLOR, LINE_XOXO ); mvwputch( w_data, i, width - 1, BORDER_COLOR, LINE_XOXO ); } mvwputch( w_data, dataHeight - 1, 0, BORDER_COLOR, LINE_XXOO ); // _| mvwputch( w_data, dataHeight - 1, width - 1, BORDER_COLOR, LINE_XOOX ); // |_ int recmin = 0, recmax = current.size(); if( recmax > dataLines ) { if( line <= recmin + dataHalfLines ) { for( int i = recmin; i < recmin + dataLines; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, i - recmin, 2, c_dark_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, i - recmin, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i - recmin, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else if( line >= recmax - dataHalfLines ) { for( int i = recmax - dataLines; i < recmax; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataLines + i - recmax, 2, c_light_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataLines + i - recmax, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } else { for( int i = line - dataHalfLines; i < line - dataHalfLines + dataLines; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), i + 1, tmp_name.c_str() ); } mvwprintz( w_data, dataHalfLines + i - line, 2, c_light_gray, "" ); // Clear the line if( i == line ) { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, dataHalfLines + i - line, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } } else { for( size_t i = 0; i < current.size() && i < ( size_t )dataHeight + 1; ++i ) { std::string tmp_name = current[i]->result_name(); if( batch ) { tmp_name = string_format( _( "%2dx %s" ), ( int )i + 1, tmp_name.c_str() ); } if( ( int )i == line ) { mvwprintz( w_data, i, 2, ( available[i] ? h_white : h_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } else { mvwprintz( w_data, i, 2, ( available[i] ? c_white : c_dark_gray ), utf8_truncate( tmp_name, 28 ).c_str() ); } } } if( !current.empty() ) { int pane = FULL_SCREEN_WIDTH - 30 - 1; int count = batch ? line + 1 : 1; // batch size nc_color col = available[ line ] ? c_white : c_light_gray; const auto &req = current[ line ]->requirements(); draw_can_craft_indicator( w_head, 0, *current[line] ); wrefresh( w_head ); ypos = 0; auto qry = trim( filterstring ); std::string qry_comps; if( qry.compare( 0, 2, "c:" ) == 0 ) { qry_comps = qry.substr( 2 ); } std::vector<std::string> component_print_buffer; auto tools = req.get_folded_tools_list( pane, col, crafting_inv, count ); auto comps = req.get_folded_components_list( pane, col, crafting_inv, count, qry_comps ); component_print_buffer.insert( component_print_buffer.end(), tools.begin(), tools.end() ); component_print_buffer.insert( component_print_buffer.end(), comps.begin(), comps.end() ); if( !g->u.knows_recipe( current[line] ) ) { component_print_buffer.push_back( _( "Recipe not memorized yet" ) ); auto books_with_recipe = g->u.get_books_for_recipe( crafting_inv, current[line] ); std::string enumerated_books = enumerate_as_string( books_with_recipe.begin(), books_with_recipe.end(), []( itype_id type_id ) { return item::find_type( type_id )->nname( 1 ); } ); const std::string text = string_format( _( "Written in: %s" ), enumerated_books.c_str() ); std::vector<std::string> folded_lines = foldstring( text, pane ); component_print_buffer.insert( component_print_buffer.end(), folded_lines.begin(), folded_lines.end() ); } //handle positioning of component list if it needed to be scrolled int componentPrintOffset = 0; if( display_mode > 2 ) { componentPrintOffset = ( display_mode - 2 ) * componentPrintHeight; } if( component_print_buffer.size() < static_cast<size_t>( componentPrintOffset ) ) { componentPrintOffset = 0; if( previous_tab != tab.cur() || previous_subtab != subtab.cur() || previous_item_line != line ) { display_mode = 2; } else { display_mode = 0; } } //only used to preserve mode position on components when //moving to another item and the view is already scrolled previous_tab = tab.cur(); previous_subtab = subtab.cur(); previous_item_line = line; const int xpos = 30; if( display_mode == 0 ) { const int width = getmaxx( w_data ) - xpos - item_info_x; mvwprintz( w_data, ypos++, xpos, col, _( "Skills used: %s" ), ( !current[line]->skill_used ? _( "N/A" ) : current[line]->skill_used.obj().name().c_str() ) ); ypos += fold_and_print( w_data, ypos, xpos, width, col, _( "Required skills: %s" ), current[line]->required_skills_string().c_str() ); mvwprintz( w_data, ypos++, xpos, col, _( "Difficulty: %d" ), current[ line ]->difficulty ); if( !current[line]->skill_used ) { mvwprintz( w_data, ypos++, xpos, col, _( "Your skill level: N/A" ) ); } else { mvwprintz( w_data, ypos++, xpos, col, _( "Your skill level: %d" ), g->u.get_skill_level( current[line]->skill_used ) ); } const int expected_turns = g->u.expected_time_to_craft( *current[line], count ) / MOVES( 1 ); ypos += fold_and_print( w_data, ypos, xpos, pane, col, _( "Time to complete: %s" ), to_string( time_duration::from_turns( expected_turns ) ) ); mvwprintz( w_data, ypos++, xpos, col, _( "Dark craftable? %s" ), current[line]->has_flag( "BLIND_EASY" ) ? _( "Easy" ) : current[line]->has_flag( "BLIND_HARD" ) ? _( "Hard" ) : _( "Impossible" ) ); ypos += print_items( *current[line], w_data, ypos, xpos, col, batch ? line + 1 : 1 ); } //color needs to be preserved in case part of the previous page was cut off nc_color stored_color = col; if( display_mode > 2 ) { stored_color = rotated_color; } else { rotated_color = col; } int components_printed = 0; for( size_t i = static_cast<size_t>( componentPrintOffset ); i < component_print_buffer.size(); i++ ) { if( ypos >= componentPrintHeight ) { break; } components_printed++; print_colored_text( w_data, ypos++, xpos, stored_color, col, component_print_buffer[i] ); } if( ypos >= componentPrintHeight && component_print_buffer.size() > static_cast<size_t>( components_printed ) ) { mvwprintz( w_data, ypos++, xpos, col, _( "v (more)" ) ); rotated_color = stored_color; } if( isWide ) { if( last_recipe != current[line] ) { last_recipe = current[line]; tmp = current[line]->create_result(); } tmp.info( true, thisItem, count ); draw_item_info( w_iteminfo, tmp.tname(), tmp.type_name(), thisItem, dummy, scroll_pos, true, true, true, false, true ); } } draw_scrollbar( w_data, line, dataLines, recmax, 0 ); wrefresh( w_data ); if( isWide ) { wrefresh( w_iteminfo ); } const std::string action = ctxt.handle_input(); if( action == "CYCLE_MODE" ) { display_mode = display_mode + 1; if( display_mode <= 0 ) { display_mode = 0; } } else if( action == "LEFT" ) { std::string start = subtab.cur(); do { subtab.prev(); } while( subtab.cur() != start && available_recipes.empty_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ) ); redraw = true; } else if( action == "SCROLL_UP" ) { scroll_pos--; } else if( action == "SCROLL_DOWN" ) { scroll_pos++; } else if( action == "PREV_TAB" ) { tab.prev(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "RIGHT" ) { std::string start = subtab.cur(); do { subtab.next(); } while( subtab.cur() != start && available_recipes.empty_category( tab.cur(), subtab.cur() != "CSC_ALL" ? subtab.cur() : "" ) ); redraw = true; } else if( action == "NEXT_TAB" ) { tab.next(); subtab = list_circularizer<std::string>( craft_subcat_list[tab.cur()] );//default ALL redraw = true; } else if( action == "DOWN" ) { line++; } else if( action == "UP" ) { line--; } else if( action == "CONFIRM" ) { if( available.empty() || !available[line] ) { popup( _( "You can't do that!" ) ); } else if( !g->u.check_eligible_containers_for_crafting( *current[line], ( batch ) ? line + 1 : 1 ) ) { ; // popup is already inside check } else { chosen = current[line]; batch_size = ( batch ) ? line + 1 : 1; done = true; } } else if( action == "HELP_RECIPE" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } tmp = current[line]->create_result(); full_screen_popup( "%s\n%s", tmp.type_name( 1 ).c_str(), tmp.info( true ).c_str() ); redraw = true; keepline = true; } else if( action == "FILTER" ) { string_input_popup() .title( _( "Search:" ) ) .width( 85 ) .description( _( "Special prefixes for requirements:\n" " [t] search tools\n" " [c] search components\n" " [q] search qualities\n" " [s] search skills\n" "Special prefixes for results:\n" " [Q] search qualities\n" "Other:\n" " [m] search for memorized or not\n" "Examples:\n" " t:soldering iron\n" " c:two by four\n" " q:metal sawing\n" " s:cooking\n" " Q:fine bolt turning\n" " m:no" ) ) .edit( filterstring ); redraw = true; } else if( action == "QUIT" ) { chosen = nullptr; done = true; } else if( action == "RESET_FILTER" ) { filterstring.clear(); redraw = true; } else if( action == "CYCLE_BATCH" ) { if( current.empty() ) { popup( _( "Nothing selected!" ) ); redraw = true; continue; } batch = !batch; if( batch ) { batch_line = line; chosen = current[batch_line]; } else { line = batch_line; keepline = true; } redraw = true; } if( line < 0 ) { line = current.size() - 1; } else if( line >= ( int )current.size() ) { line = 0; } } while( !done ); return chosen; }
int worldfactory::show_worldgen_tab_modselection(WINDOW *win, WORLDPTR world) { // Use active_mod_order of the world, // saves us from writting 'world->active_mod_order' all the time. std::vector<std::string> &active_mod_order = world->active_mod_order; { std::vector<std::string> tmp_mod_order; // clear active_mod_order and re-add all the mods, his ensures // that changes (like changing depencies) get updated tmp_mod_order.swap(active_mod_order); for(size_t i = 0; i < tmp_mod_order.size(); i++) { mman_ui->try_add(tmp_mod_order[i], active_mod_order); } } const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; // lots of small windows so that each section can be drawn to independently of the others as necessary WINDOW *w_header1, *w_header2, *w_shift, *w_list, *w_active, *w_description; w_header1 = newwin(1, FULL_SCREEN_WIDTH / 2 - 5, 3 + iOffsetY, 1 + iOffsetX); w_header2 = newwin(1, FULL_SCREEN_WIDTH / 2 - 4, 3 + iOffsetY, FULL_SCREEN_WIDTH / 2 + 3 + iOffsetX); w_shift = newwin(13, 5, 3 + iOffsetY, FULL_SCREEN_WIDTH / 2 - 3 + iOffsetX); w_list = newwin(11, FULL_SCREEN_WIDTH / 2 - 4, 5 + iOffsetY, iOffsetX); w_active = newwin(11, FULL_SCREEN_WIDTH / 2 - 4, 5 + iOffsetY, FULL_SCREEN_WIDTH / 2 + 2 + iOffsetX); w_description = newwin(4, FULL_SCREEN_WIDTH - 2, 19 + iOffsetY, 1 + iOffsetX); draw_modselection_borders(win); std::vector<std::string> headers; headers.push_back(_("Mod List")); headers.push_back(_("Mod Load Order")); std::vector<WINDOW *> header_windows; header_windows.push_back(w_header1); header_windows.push_back(w_header2); int tab_output = 0; int last_active_header = 0; size_t active_header = 0; size_t useable_mod_count = mman_ui->usable_mods.size(); int startsel[2] = {0, 0}; int cursel[2] = {0, 0}; bool redraw_headers = true; bool redraw_shift = true; bool redraw_description = true; bool redraw_list = true; bool redraw_active = true; bool selection_changed = false; input_context ctxt("MODMANAGER_DIALOG"); ctxt.register_cardinal(); ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("CONFIRM"); ctxt.register_action("ADD_MOD"); ctxt.register_action("REMOVE_MOD"); ctxt.register_action("SAVE_DEFAULT_MODS"); while (tab_output == 0) { if (redraw_headers) { for (size_t i = 0; i < headers.size(); ++i) { werase(header_windows[i]); const int header_x = (getmaxx(header_windows[i]) - headers[i].size()) / 2; mvwprintz(header_windows[i], 0, header_x , c_cyan, "%s", headers[i].c_str()); if (active_header == i) { mvwputch(header_windows[i], 0, header_x - 3, c_red, '<'); mvwputch(header_windows[i], 0, header_x + headers[i].size() + 2, c_red, '>'); } wrefresh(header_windows[i]); } redraw_list = true; redraw_active = true; redraw_shift = true; redraw_headers = false; } if (selection_changed) { if (active_header == 0) { redraw_list = true; } if (active_header == 1) { redraw_shift = true; redraw_active = true; } selection_changed = false; redraw_description = true; } if (redraw_description) { werase(w_description); MOD_INFORMATION *selmod = NULL; if (mman_ui->usable_mods.empty()) { // Do nothing, leave selmod == NULL } else if (active_header == 0) { selmod = mman->mod_map[mman_ui->usable_mods[cursel[0]]]; } else if (!active_mod_order.empty()) { selmod = mman->mod_map[active_mod_order[cursel[1]]]; } if (selmod != NULL) { fold_and_print(w_description, 0, 1, getmaxx(w_description) - 1, c_white, mman_ui->get_information(selmod)); } redraw_description = false; wrefresh(w_description); } if (redraw_list) { werase(w_list); calcStartPos(startsel[0], cursel[0], getmaxy(w_list), useable_mod_count); if (useable_mod_count == 0) { center_print(w_list, 0, c_red, _("--NO AVAILABLE MODS--")); } else { std::stringstream list_output; for( size_t i = startsel[0], c = 0; i < useable_mod_count && c < getmaxy(w_list); ++i, ++c ) { if ((int)i != cursel[0]) { list_output << std::string(3, ' '); } else { if (active_header == 0) { list_output << "<color_yellow>"; } else { list_output << "<color_blue>"; } list_output << ">></color> "; } list_output << mman->mod_map[mman_ui->usable_mods[i]]->name << "\n"; } fold_and_print(w_list, 0, 1, getmaxx(w_list) - 1, c_white, list_output.str()); } draw_scrollbar(w_list, cursel[0], getmaxy(w_list), useable_mod_count, 0, 0); wrefresh(w_list); } if (redraw_active) { werase(w_active); const int active_count = active_mod_order.size(); calcStartPos(startsel[1], cursel[1], getmaxy(w_active), active_count); if (active_count == 0) { center_print(w_active, 0, c_red, _("--NO ACTIVE MODS--")); } else { std::stringstream list_output; for (int i = startsel[1], c = 0; i < active_count && c < getmaxy(w_active); ++i, ++c) { if (i != cursel[1]) { list_output << std::string(3, ' '); } else { if (active_header == 1) { list_output << "<color_yellow>"; } else { list_output << "<color_blue>"; } list_output << ">></color> "; } list_output << mman->mod_map[active_mod_order[i]]->name << "\n"; } fold_and_print(w_active, 0, 1, getmaxx(w_active) - 1, c_white, list_output.str()); } draw_scrollbar(w_active, cursel[1], getmaxy(w_active), active_count, 0, 0); wrefresh(w_active); } if (redraw_shift) { werase(w_shift); if (active_header == 1) { std::stringstream shift_display; // get shift information for whatever is visible in the active list for (size_t i = startsel[1], c = 0; i < active_mod_order.size() && c < getmaxy(w_active); ++i, ++c) { if (mman_ui->can_shift_up(i, active_mod_order)) { shift_display << "<color_blue>+</color> "; } else { shift_display << "<color_dkgray>+</color> "; } if (mman_ui->can_shift_down(i, active_mod_order)) { shift_display << "<color_blue>-</color>"; } else { shift_display << "<color_dkgray>-</color>"; } shift_display << "\n"; } fold_and_print(w_shift, 2, 1, getmaxx(w_shift), c_white, shift_display.str()); } redraw_shift = false; wrefresh(w_shift); } refresh(); last_active_header = active_header; const int next_header = (active_header == 1) ? 0 : 1; const int prev_header = (active_header == 0) ? 1 : 0; int selection = (active_header == 0) ? cursel[0] : cursel[1]; int last_selection = selection; unsigned int next_selection = selection + 1; int prev_selection = selection - 1; if (active_header == 0) { next_selection = (next_selection >= useable_mod_count) ? 0 : next_selection; prev_selection = (prev_selection < 0) ? useable_mod_count - 1 : prev_selection; } else { next_selection = (next_selection >= active_mod_order.size()) ? 0 : next_selection; prev_selection = (prev_selection < 0) ? active_mod_order.size() - 1 : prev_selection; } const std::string action = ctxt.handle_input(); if (action == "DOWN") { selection = next_selection; } else if (action == "UP") { selection = prev_selection; } else if (action == "RIGHT") { active_header = next_header; } else if (action == "LEFT") { active_header = prev_header; } else if (action == "CONFIRM") { if (active_header == 0 && !mman_ui->usable_mods.empty()) { // try-add mman_ui->try_add(mman_ui->usable_mods[cursel[0]], active_mod_order); redraw_active = true; redraw_shift = true; } else if (active_header == 1 && !active_mod_order.empty()) { // try-rem mman_ui->try_rem(cursel[1], active_mod_order); redraw_active = true; redraw_shift = true; if (active_mod_order.empty()) { // switch back to other list, we can't change // anything in the empty active mods list. active_header = 0; } } } else if (action == "ADD_MOD") { if (active_header == 1 && active_mod_order.size() > 1) { mman_ui->try_shift('+', cursel[1], active_mod_order); redraw_active = true; redraw_shift = true; } } else if (action == "REMOVE_MOD") { if (active_header == 1 && active_mod_order.size() > 1) { mman_ui->try_shift('-', cursel[1], active_mod_order); redraw_active = true; redraw_shift = true; } } else if (action == "NEXT_TAB") { tab_output = 1; } else if (action == "PREV_TAB") { tab_output = -1; } else if (action == "SAVE_DEFAULT_MODS") { if(mman->set_default_mods(active_mod_order)) { popup(_("Saved list of active mods as default")); draw_modselection_borders(win); redraw_headers = true; } } else if (action == "QUIT") { tab_output = -999; } // RESOLVE INPUTS if (last_active_header != (int)active_header) { redraw_headers = true; redraw_shift = true; redraw_description = true; } if (last_selection != selection) { if (active_header == 0) { redraw_list = true; cursel[0] = selection; } else { redraw_active = true; redraw_shift = true; cursel[1] = selection; } redraw_description = true; } if (active_mod_order.empty()) { redraw_active = true; cursel[1] = 0; } if (active_header == 1) { if (active_mod_order.empty()) { cursel[1] = 0; } else { if (cursel[1] < 0) { cursel[1] = 0; } else if (cursel[1] >= (int)active_mod_order.size()) { cursel[1] = active_mod_order.size() - 1; } } } // end RESOLVE INPUTS } werase(w_header1); werase(w_header2); werase(w_shift); werase(w_list); werase(w_active); werase(w_description); delwin(w_header1); delwin(w_header2); delwin(w_shift); delwin(w_list); delwin(w_active); delwin(w_description); return tab_output; }
void menu_setup_devices() { if(redraw) { clearDisplay(); clear_buttons(); redraw=0; draw_filledRect(0,0,LCD_WIDTH,35,155,100,100); draw_filledCircle(17,17,15,40,80,40); draw_text_8x6(7,10,"Back",255,100,100); uint16_t text_width = get_text_width_16pt("Setup Devices"); draw_text_16pt((LCD_WIDTH-text_width)>>1,9, "Setup Devices", 200,200,255); init_lineitems(); char buf[30]; char buf2[30]; draw_lineitem("","<new>"); for(int i = 0; i < get_device_count();i++) { snprintf(buf,30,"%i",get_device(i)->base_address); char classname[30]; if(get_device(i)->device_class_uuid == 0) { strncpy(classname,"<empty>",30); } else if(get_device_class_by_uuid(get_device(i)->device_class_uuid) == NULL) { strncpy(classname,"<missing>",30); } else { strncpy(classname,get_device_class_by_uuid(get_device(i)->device_class_uuid)->name,30); } snprintf(buf2,30,"%s - %s",classname,get_device(i)->name); draw_lineitem(buf,buf2); } draw_scrollbar(); draw_button_h(257,45,52,42,"^",155,0,0,0,255,0); if((get_device_count()<10)&&(active_row==0)) { draw_button_h(257,92,52,42,"Add",155,0,0,0,255,0); } if(active_row>0) { draw_button_h(257,92,52,42,"Edit",155,0,0,0,255,0); draw_button_h(257,139,52,42,"Delete",155,0,0,0,255,0); } draw_button_h(257,186,52,42,"v",155,0,0,0,255,0); } uint8_t field=0; uint16_t x; uint16_t y; if(check_button_press(&x,&y)==1) { if(y > 41) { field=1; if(y > 184) { field=4; }else if(y > 136) { field=3; }else if(y > 89) { field=2; } } else { if(x < 40) { redraw=1; set_current_execution(menu_setup); } } if(field == 1) { if(active_row > 0) { if(active_row==scroll_offset) { scroll_offset--; } active_row--; } redraw=1; } if(field == 4) { if(active_row < (get_device_count())) { active_row++; int drawline = active_row-scroll_offset; if(drawline==10) { scroll_offset++; } } redraw=1; } if(field == 2) { redraw=1; if(active_row==0) { if(get_device_count()<50) { set_current_execution(menu_setup_devices_add); } } else { set_current_execution(menu_setup_devices_edit); set_device_to_edit(active_row-1); } } if(field == 3) { redraw=1; if(active_row > 0) { del_device(active_row-1); if(active_row==scroll_offset) { scroll_offset--; } active_row--; } } } }
void show_auto_pickup() { save_reset_changes(false); const int iHeaderHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; std::map<int, bool> mapLines; mapLines[4] = true; mapLines[50] = true; mapLines[54] = true; const int iTotalCols = mapLines.size() - 1; WINDOW *w_auto_pickup_help = newwin((FULL_SCREEN_HEIGHT / 2) - 2, FULL_SCREEN_WIDTH * 3 / 4, 7 + iOffsetY + (FULL_SCREEN_HEIGHT / 2) / 2, iOffsetX + 19 / 2); WINDOW_PTR w_auto_pickup_helpptr( w_auto_pickup_help ); WINDOW *w_auto_pickup_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW_PTR w_auto_pickup_borderptr( w_auto_pickup_border ); WINDOW *w_auto_pickup_header = newwin(iHeaderHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_auto_pickup_headerptr( w_auto_pickup_header ); WINDOW *w_auto_pickup = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iHeaderHeight + 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_auto_pickupptr( w_auto_pickup ); draw_border(w_auto_pickup_border); mvwputch(w_auto_pickup_border, 3, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_auto_pickup_border, 3, 79, c_ltgray, LINE_XOXX); // -| for( auto &mapLine : mapLines ) { mvwputch( w_auto_pickup_border, FULL_SCREEN_HEIGHT - 1, mapLine.first + 1, c_ltgray, LINE_XXOX ); // _|_ } mvwprintz(w_auto_pickup_border, 0, 29, c_ltred, _(" AUTO PICKUP MANAGER ")); wrefresh(w_auto_pickup_border); int tmpx = 0; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<A>dd")) + 2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<R>emove")) + 2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<C>opy")) + 2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<M>ove")) + 2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<E>nable")) + 2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<D>isable")) + 2; shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<T>est")); tmpx = 0; tmpx += shortcut_print(w_auto_pickup_header, 1, tmpx, c_white, c_ltgreen, _("<+-> Move up/down")) + 2; tmpx += shortcut_print(w_auto_pickup_header, 1, tmpx, c_white, c_ltgreen, _("<Enter>-Edit")) + 2; shortcut_print(w_auto_pickup_header, 1, tmpx, c_white, c_ltgreen, _("<Tab>-Switch Page")); for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_auto_pickup_header, 2, i, c_ltgray, LINE_OXXX); mvwputch(w_auto_pickup_header, 3, i, c_ltgray, LINE_XOXO); } else { mvwputch(w_auto_pickup_header, 2, i, c_ltgray, LINE_OXOX); // Draw line under header } } mvwprintz(w_auto_pickup_header, 3, 1, c_white, "#"); mvwprintz(w_auto_pickup_header, 3, 8, c_white, _("Rules")); mvwprintz(w_auto_pickup_header, 3, 51, c_white, _("I/E")); wrefresh(w_auto_pickup_header); int iCurrentPage = 1; int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; bool bStuffChanged = false; input_context ctxt("AUTO_PICKUP"); ctxt.register_cardinal(); ctxt.register_action("CONFIRM"); ctxt.register_action("QUIT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("ADD_RULE"); ctxt.register_action("REMOVE_RULE"); ctxt.register_action("COPY_RULE"); ctxt.register_action("SWAP_RULE_GLOBAL_CHAR"); ctxt.register_action("ENABLE_RULE"); ctxt.register_action("DISABLE_RULE"); ctxt.register_action("MOVE_RULE_UP"); ctxt.register_action("MOVE_RULE_DOWN"); ctxt.register_action("TEST_RULE"); ctxt.register_action("SWITCH_AUTO_PICKUP_OPTION"); ctxt.register_action("HELP_KEYBINDINGS"); std::stringstream sTemp; while(true) { int locx = 17; locx += shortcut_print(w_auto_pickup_header, 2, locx, c_white, (iCurrentPage == 1) ? hilite(c_white) : c_white, _("[<Global>]")) + 1; shortcut_print(w_auto_pickup_header, 2, locx, c_white, (iCurrentPage == 2) ? hilite(c_white) : c_white, _("[<Character>]")); locx = 55; mvwprintz(w_auto_pickup_header, 0, locx, c_white, _("Auto pickup enabled:")); locx += shortcut_print(w_auto_pickup_header, 1, locx, ((OPTIONS["AUTO_PICKUP"]) ? c_ltgreen : c_ltred), c_white, ((OPTIONS["AUTO_PICKUP"]) ? _("True") : _("False"))); locx += shortcut_print(w_auto_pickup_header, 1, locx, c_white, c_ltgreen, " "); locx += shortcut_print(w_auto_pickup_header, 1, locx, c_white, c_ltgreen, _("<S>witch")); shortcut_print(w_auto_pickup_header, 1, locx, c_white, c_ltgreen, " "); wrefresh(w_auto_pickup_header); // Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w_auto_pickup, i, j, c_ltgray, LINE_XOXO); } else { mvwputch(w_auto_pickup, i, j, c_black, ' '); } } } const bool currentPageNonEmpty = !vAutoPickupRules[iCurrentPage].empty(); if (iCurrentPage == 2 && g->u.name == "") { vAutoPickupRules[2].clear(); mvwprintz(w_auto_pickup, 8, 15, c_white, _("Please load a character first to use this page!")); } //Draw Scrollbar draw_scrollbar(w_auto_pickup_border, iCurrentLine, iContentHeight, vAutoPickupRules[iCurrentPage].size(), 5); calcStartPos(iStartPos, iCurrentLine, iContentHeight, vAutoPickupRules[iCurrentPage].size()); // display auto pickup for (int i = iStartPos; i < (int)vAutoPickupRules[iCurrentPage].size(); i++) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > (int)vAutoPickupRules[iCurrentPage].size()) ? (int)vAutoPickupRules[iCurrentPage].size() : iContentHeight)) { nc_color cLineColor = (vAutoPickupRules[iCurrentPage][i].bActive) ? c_white : c_ltgray; sTemp.str(""); sTemp << i + 1; mvwprintz(w_auto_pickup, i - iStartPos, 1, cLineColor, "%s", sTemp.str().c_str()); mvwprintz(w_auto_pickup, i - iStartPos, 5, cLineColor, ""); if (iCurrentLine == i) { wprintz(w_auto_pickup, c_yellow, ">> "); } else { wprintz(w_auto_pickup, c_yellow, " "); } wprintz(w_auto_pickup, (iCurrentLine == i && iCurrentCol == 1) ? hilite(cLineColor) : cLineColor, "%s", ((vAutoPickupRules[iCurrentPage][i].sRule == "") ? _("<empty rule>") : vAutoPickupRules[iCurrentPage][i].sRule).c_str()); mvwprintz(w_auto_pickup, i - iStartPos, 52, (iCurrentLine == i && iCurrentCol == 2) ? hilite(cLineColor) : cLineColor, "%s", ((vAutoPickupRules[iCurrentPage][i].bExclude) ? rm_prefix(_("<Exclude>E")).c_str() : rm_prefix( _("<Include>I")).c_str())); } } wrefresh(w_auto_pickup); const std::string action = ctxt.handle_input(); if (action == "NEXT_TAB") { iCurrentPage++; if (iCurrentPage > 2) { iCurrentPage = 1; iCurrentLine = 0; } } else if (action == "PREV_TAB") { iCurrentPage--; if (iCurrentPage < 1) { iCurrentPage = 2; iCurrentLine = 0; } } else if (action == "QUIT") { break; } else if (iCurrentPage == 2 && g->u.name.empty()) { //Only allow loaded games to use the char sheet } else if (action == "DOWN") { iCurrentLine++; iCurrentCol = 1; if (iCurrentLine >= (int)vAutoPickupRules[iCurrentPage].size()) { iCurrentLine = 0; } } else if (action == "UP") { iCurrentLine--; iCurrentCol = 1; if (iCurrentLine < 0) { iCurrentLine = vAutoPickupRules[iCurrentPage].size() - 1; } } else if (action == "ADD_RULE") { bStuffChanged = true; vAutoPickupRules[iCurrentPage].push_back(cPickupRules("", true, false)); iCurrentLine = vAutoPickupRules[iCurrentPage].size() - 1; } else if (action == "REMOVE_RULE" && currentPageNonEmpty) { bStuffChanged = true; vAutoPickupRules[iCurrentPage].erase(vAutoPickupRules[iCurrentPage].begin() + iCurrentLine); if (iCurrentLine > (int)vAutoPickupRules[iCurrentPage].size() - 1) { iCurrentLine--; } if(iCurrentLine < 0){ iCurrentLine = 0; } } else if (action == "COPY_RULE" && currentPageNonEmpty) { bStuffChanged = true; vAutoPickupRules[iCurrentPage].push_back(cPickupRules( vAutoPickupRules[iCurrentPage][iCurrentLine].sRule, vAutoPickupRules[iCurrentPage][iCurrentLine].bActive, vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude)); iCurrentLine = vAutoPickupRules[iCurrentPage].size() - 1; } else if (action == "SWAP_RULE_GLOBAL_CHAR" && currentPageNonEmpty) { if ((iCurrentPage == 1 && g->u.name != "") || iCurrentPage == 2) { bStuffChanged = true; //copy over vAutoPickupRules[(iCurrentPage == 1) ? 2 : 1].push_back(cPickupRules( vAutoPickupRules[iCurrentPage][iCurrentLine].sRule, vAutoPickupRules[iCurrentPage][iCurrentLine].bActive, vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude)); //remove old vAutoPickupRules[iCurrentPage].erase(vAutoPickupRules[iCurrentPage].begin() + iCurrentLine); iCurrentLine = vAutoPickupRules[(iCurrentPage == 1) ? 2 : 1].size() - 1; iCurrentPage = (iCurrentPage == 1) ? 2 : 1; } } else if (action == "CONFIRM" && currentPageNonEmpty) { bStuffChanged = true; if (iCurrentCol == 1) { fold_and_print(w_auto_pickup_help, 1, 1, 999, c_white, _( "* is used as a Wildcard. A few Examples:\n" "\n" "wooden arrow matches the itemname exactly\n" "wooden ar* matches items beginning with wood ar\n" "*rrow matches items ending with rrow\n" "*avy fle*fi*arrow multiple * are allowed\n" "heAVY*woOD*arrOW case insensitive search\n" "") ); draw_border(w_auto_pickup_help); wrefresh(w_auto_pickup_help); vAutoPickupRules[iCurrentPage][iCurrentLine].sRule = trim_rule(string_input_popup(_("Pickup Rule:"), 30, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule)); } else if (iCurrentCol == 2) { vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude = !vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude; } } else if (action == "ENABLE_RULE" && currentPageNonEmpty) { bStuffChanged = true; vAutoPickupRules[iCurrentPage][iCurrentLine].bActive = true; } else if (action == "DISABLE_RULE" && currentPageNonEmpty) { bStuffChanged = true; vAutoPickupRules[iCurrentPage][iCurrentLine].bActive = false; } else if (action == "LEFT") { iCurrentCol--; if (iCurrentCol < 1) { iCurrentCol = iTotalCols; } } else if (action == "RIGHT") { iCurrentCol++; if (iCurrentCol > iTotalCols) { iCurrentCol = 1; } } else if (action == "MOVE_RULE_UP" && currentPageNonEmpty) { bStuffChanged = true; if (iCurrentLine < (int)vAutoPickupRules[iCurrentPage].size() - 1) { std::swap(vAutoPickupRules[iCurrentPage][iCurrentLine], vAutoPickupRules[iCurrentPage][iCurrentLine + 1]); iCurrentLine++; iCurrentCol = 1; } } else if (action == "MOVE_RULE_DOWN" && currentPageNonEmpty) { bStuffChanged = true; if (iCurrentLine > 0) { std::swap(vAutoPickupRules[iCurrentPage][iCurrentLine], vAutoPickupRules[iCurrentPage][iCurrentLine - 1]); iCurrentLine--; iCurrentCol = 1; } } else if (action == "TEST_RULE" && currentPageNonEmpty) { test_pattern(iCurrentPage, iCurrentLine); } else if (action == "SWITCH_AUTO_PICKUP_OPTION") { OPTIONS["AUTO_PICKUP"].setNext(); save_options((g->u.name != "")); } } if (bStuffChanged) { if(query_yn(_("Save changes?"))) { save_auto_pickup(false); if (g->u.name != "") { save_auto_pickup(true); } } else { save_reset_changes(true); } } }
void Messages::display_messages() { catacurses::window w = catacurses::newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0, ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0 ); input_context ctxt( "MESSAGE_LOG" ); ctxt.register_action( "UP", _( "Scroll up" ) ); ctxt.register_action( "DOWN", _( "Scroll down" ) ); ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); /* Right-Aligning Time Epochs For Readability * ========================================== * Given display_messages(); right-aligns epochs, we must declare one quick variable first: * max_padlength refers to the length of the LONGEST possible unit of time returned by to_string_clipped() any language has to offer. * This variable is, for now, set to '10', which seems most reasonable. * * The reason right-aligned epochs don't use a "shortened version" (e.g. only showing the first letter) boils down to: * 1. The first letter of every time unit being unique is a property that might not carry across to other languages. * 2. Languages where displayed characters change depending on the characters preceding/following it will become unclear. * 3. Some polymorphic languages might not be able to appropriately convey meaning with one character (FRS is not a linguist- correct her on this if needed.) * * This right padlength is then incorporated into a so-called 'epoch_format' which, in turn, will be used to format the correct epoch. * If an external language introduces time units longer than 10 characters in size, consider altering these variables. * The game (likely) shan't segfault, though the text may appear a bit messed up if these variables aren't set properly. */ const int max_padlength = 10; /* Dealing With Screen Extremities * =============================== * 'maxlength' corresponds to the most extreme length a log message may be before foldstring() wraps it around to two or more lines. * The numbers subtracted from FULL_SCREEN_WIDTH are - in order: * '-2' the characters reserved for the borders of the box, both on the left and right side. * '-1' the leftmost guide character that's drawn on screen. * '-4' the padded three-digit number each epoch starts with. * '-max_padlength' the characters of space that are allocated to time units (e.g. "years", "minutes", etc.) * * 'bottom' works much like 'maxlength', but instead it refers to the amount of lines that the message box may hold. */ const int maxlength = FULL_SCREEN_WIDTH - 2 - 1 - 4 - max_padlength; const int bottom = FULL_SCREEN_HEIGHT - 2; const int msg_count = size(); /* Dealing With Scroll Direction * ============================= * Much like how the sidebar can have variable scroll direction, so will the message box. * To properly differentiate the two methods of displaying text, we will label them NEWEST-TOP, and OLDEST-TOP. This labeling should be self explanatory. * * Note that 'offset' tracks only our current position in the list; it shan't at all affect the manner in which the messages are drawn. * Messages are always drawn top-to-bottom. If NEWEST-TOP is used, then the top line (line=1) corresponds to the newest message. The one further down the second-newest, etc. * If the OLDEST-TOP method is used, then the top line (line=1) corresponds to the oldest message, and the bottom one to the newest. * The 'for (;;)' block below is nearly completely method-agnostic, save for the `player_messages.impl_->history(i)` call. * * In case of NEWEST-TOP, the 'i' variable easily enough corresponds to the newest message. * In case of OLDEST-TOP, the 'i' variable must be flipped- meaning the highest value of 'i' returns the result for the lowest value of 'i', etc. * To achieve this, the 'flip_message' variable is set to either the value of 'msg_count', or '0'. This variable is then subtracted from 'i' in each call to player_messages.impl_->history(); * * 'offset' refers to the corresponding message that will be displayed at the very TOP of the message box window. * NEWEST-TOP: 'offset' starts simply at '0' - the very top of the window. * OLDEST-TOP: 'offset' is set to the maximum value it could possibly be. That is- 'msg_count-bottom'. This way, the screen starts with the scrollbar all the way down. * 'retrieve_history' refers to the line that should be displayed- this is either 'i' if it's NEWEST-TOP, or a flipped version of 'i' if it's OLDEST-TOP. */ int offset = log_from_top ? 0 : ( msg_count - bottom ); const int flip = log_from_top ? 0 : msg_count - 1; for( ;; ) { werase( w ); draw_border( w ); mvwprintz( w, bottom + 1, 32, c_red, _( "Press %s to return" ), ctxt.get_desc( "QUIT" ).c_str() ); draw_scrollbar( w, offset, bottom, msg_count, 1, 0, c_white, true ); int line = 1; int lasttime = -1; for( int i = offset; i < msg_count; ++i ) { const int retrieve_history = abs( i - flip ); if( line > bottom ) { break; // This statement makes it so that no non-existent messages are printed (which usually results in a segfault) } else if( retrieve_history >= msg_count ) { continue; } const game_message &m = player_messages.impl_->history( retrieve_history ); const calendar timepassed = calendar::turn - m.timestamp_in_turns; std::string long_ago = to_string_clipped( time_duration::from_turns( timepassed ) ); nc_color col = msgtype_to_color( m.type, false ); // Here we separate the unit and amount from one another so that they can be properly padded when they're drawn on the screen. // Note that the very first character of 'unit' is often a space (except for languages where the time unit directly follows the number.) const auto amount_len = long_ago.find_first_not_of( "0123456789" ); std::string amount = long_ago.substr( 0, amount_len ); std::string unit = long_ago.substr( amount_len ); if( timepassed.get_turn() != lasttime ) { right_print( w, line, 2, c_light_blue, string_format( _( "%-3s%-10s" ), amount.c_str(), unit.c_str() ) ); lasttime = timepassed.get_turn(); } nc_color col_out = col; for( const std::string &folded : foldstring( m.get_with_count(), maxlength ) ) { if( line > bottom ) { break; } print_colored_text( w, line, 2, col_out, col, folded ); // So-called special "markers"- alternating '=' and '-'s at the edges of te message window so players can properly make sense of which message belongs to which time interval. // The '+offset%4' in the calculation makes it so that the markings scroll along with the messages. // On lines divisible by 4, draw a dark gray '-' at both horizontal extremes of the window. if( ( line + offset % 4 ) % 4 == 0 ) { mvwprintz( w, line, 1, c_dark_gray, "-" ); mvwprintz( w, line, FULL_SCREEN_WIDTH - 2, c_dark_gray, "-" ); // On lines divisible by 2 (but not 4), draw a light gray '=' at the horizontal extremes of the window. } else if( ( line + offset % 4 ) % 2 == 0 ) { mvwprintz( w, line, 1, c_light_gray, "=" ); mvwprintz( w, line, FULL_SCREEN_WIDTH - 2, c_light_gray, "=" ); } // Only now are we done with this line: line++; } } if( offset < msg_count - bottom ) { mvwprintz( w, bottom + 1, 5, c_magenta, "vvv" ); } if( offset > 0 ) { mvwprintz( w, bottom + 1, FULL_SCREEN_WIDTH - 8, c_magenta, "^^^" ); } wrefresh( w ); const std::string &action = ctxt.handle_input(); if( action == "DOWN" && offset < msg_count - bottom ) { offset++; } else if( action == "UP" && offset > 0 ) { offset--; } else if( action == "QUIT" ) { break; } } player_messages.impl_->curmes = calendar::turn.get_turn(); }
void construction_menu() { static bool hide_unconstructable = false; // only display constructions the player can theoretically perform std::vector<std::string> available; std::map<std::string, std::vector<std::string>> cat_available; load_available_constructions( available, cat_available, hide_unconstructable ); if( available.empty() ) { popup( _( "You can not construct anything here." ) ); return; } int w_height = TERMY; if( ( int )available.size() + 2 < w_height ) { w_height = available.size() + 2; } if( w_height < FULL_SCREEN_HEIGHT ) { w_height = FULL_SCREEN_HEIGHT; } const int w_width = std::max( FULL_SCREEN_WIDTH, TERMX * 2 / 3); const int w_y0 = ( TERMY > w_height ) ? ( TERMY - w_height ) / 2 : 0; const int w_x0 = ( TERMX > w_width ) ? ( TERMX - w_width ) / 2 : 0; WINDOW_PTR w_con_ptr {newwin( w_height, w_width, w_y0, w_x0 )}; WINDOW *const w_con = w_con_ptr.get(); const int w_list_width = int( .375 * w_width ); const int w_list_height = w_height - 4; const int w_list_x0 = 1; WINDOW_PTR w_list_ptr {newwin( w_list_height, w_list_width, w_y0 + 3, w_x0 + w_list_x0 )}; WINDOW *const w_list = w_list_ptr.get(); draw_grid( w_con, w_list_width + w_list_x0 ); //tabcount needs to be increased to add more categories int tabcount = 10; std::string construct_cat[] = {_( "All" ), _( "Constructions" ), _( "Furniture" ), _( "Digging and Mining" ), _( "Repairing" ), _( "Reinforcing" ), _( "Decorative" ), _( "Farming and Woodcutting" ), _( "Others" ), _( "Filter" ) }; bool update_info = true; bool update_cat = true; bool isnew = true; int tabindex = 0; int select = 0; int offset = 0; bool exit = false; std::string category_name = ""; std::vector<std::string> constructs; //storage for the color text so it can be scrolled std::vector< std::vector < std::string > > construct_buffers; std::vector<std::string> full_construct_buffer; std::vector<int> construct_buffer_breakpoints; int total_project_breakpoints = 0; int current_construct_breakpoint = 0; bool previous_hide_unconstructable = false; //track the cursor to determine when to refresh the list of construction recipes int previous_tabindex = -1; int previous_select = -1; const inventory &total_inv = g->u.crafting_inventory(); input_context ctxt( "CONSTRUCTION" ); ctxt.register_action( "UP", _( "Move cursor up" ) ); ctxt.register_action( "DOWN", _( "Move cursor down" ) ); ctxt.register_action( "RIGHT", _( "Move tab right" ) ); ctxt.register_action( "LEFT", _( "Move tab left" ) ); ctxt.register_action( "PAGE_UP" ); ctxt.register_action( "PAGE_DOWN" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ); ctxt.register_action( "QUIT" ); ctxt.register_action( "HELP_KEYBINDINGS" ); ctxt.register_action( "FILTER" ); std::string filter; int previous_index = 0; do { if( update_cat ) { update_cat = false; switch( tabindex ) { case 0: category_name = "ALL"; break; case 1: category_name = "CONSTRUCT"; break; case 2: category_name = "FURN"; break; case 3: category_name = "DIG"; break; case 4: category_name = "REPAIR"; break; case 5: category_name = "REINFORCE"; break; case 6: category_name = "DECORATE"; break; case 7: category_name = "FARM_WOOD"; break; case 8: category_name = "OTHER"; break; case 9: category_name = "FILTER"; break; } if( category_name == "ALL" ) { constructs = available; previous_index = tabindex; } else if( category_name == "FILTER" ) { constructs.clear(); std::copy_if( available.begin(), available.end(), std::back_inserter( constructs ), [&](const std::string &a){ return lcmatch(a, filter); } ); } else { constructs = cat_available[category_name]; previous_index = tabindex; } if( isnew ){ if( !uistate.last_construction.empty() ){ select = std::distance(constructs.begin(), std::find( constructs.begin(), constructs.end(), uistate.last_construction )); } filter = uistate.construction_filter; } } // Erase existing tab selection & list of constructions mvwhline( w_con, 1, 1, ' ', w_list_width ); werase( w_list ); // Print new tab listing mvwprintz( w_con, 1, 1, c_yellow, "<< %s >>", construct_cat[tabindex].c_str() ); // Determine where in the master list to start printing calcStartPos( offset, select, w_list_height, constructs.size() ); // Print the constructions between offset and max (or how many will fit) for( size_t i = 0; ( int )i < w_list_height && ( i + offset ) < constructs.size(); i++ ) { int current = i + offset; std::string con_name = constructs[current]; bool highlight = ( current == select ); trim_and_print( w_list, i, 0, w_list_width, construction_color( con_name, highlight ), "%s", con_name.c_str() ); } if( update_info ) { update_info = false; // Clear out lines for tools & materials const int pos_x = w_list_width + w_list_x0 + 2; const int available_window_width = w_width - pos_x - 1; for( int i = 1; i < w_height - 1; i++ ) { mvwhline( w_con, i, pos_x, ' ', available_window_width ); } nc_color color_stage = c_white; std::vector<std::string> notes; notes.push_back( string_format( _( "Press %s or %s to tab." ), ctxt.get_desc( "LEFT" ).c_str(), ctxt.get_desc( "RIGHT" ).c_str() ) ); notes.push_back( string_format( _( "Press %s to search." ), ctxt.get_desc( "FILTER" ).c_str() ) ); notes.push_back( string_format( _( "Press %s to toggle unavailable constructions." ), ctxt.get_desc( "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ).c_str() ) ); notes.push_back( string_format( _( "Press %s to view and edit key-bindings." ), ctxt.get_desc( "HELP_KEYBINDINGS" ).c_str() ) ); //leave room for top and bottom UI text const int available_buffer_height = w_height - 3 - 3 - (int)notes.size(); // print the hotkeys regardless of if there are constructions for( size_t i = 0; i < notes.size(); ++i ) { trim_and_print( w_con, w_height - 1 - (int)notes.size() + (int)i, pos_x, available_window_width, c_white, "%s", notes[i].c_str() ); } if( !constructs.empty() ) { if( select >= (int) constructs.size() ){ select = 0; } std::string current_desc = constructs[select]; // Print construction name trim_and_print( w_con, 1, pos_x, available_window_width, c_white, "%s", current_desc.c_str() ); //only reconstruct the project list when moving away from the current item, or when changing the display mode if( previous_select != select || previous_tabindex != tabindex || previous_hide_unconstructable != hide_unconstructable ) { previous_select = select; previous_tabindex = tabindex; previous_hide_unconstructable = hide_unconstructable; //construct the project list buffer // Print stages and their requirement. std::vector<construction *> options = constructions_by_desc( current_desc ); construct_buffers.clear(); total_project_breakpoints = 0; current_construct_breakpoint = 0; construct_buffer_breakpoints.clear(); full_construct_buffer.clear(); int stage_counter = 0; for( std::vector<construction *>::iterator it = options.begin(); it != options.end(); ++it ) { stage_counter++; construction *current_con = *it; if( hide_unconstructable && !can_construct( *current_con ) ) { continue; } // Update the cached availability of components and tools in the requirement object current_con->requirements->can_make_with_inventory( total_inv ); std::vector<std::string> current_buffer; std::ostringstream current_line; // display result only if more than one step. // Assume single stage constructions should be clear // in their description what their result is. if( current_con->post_terrain != "" && options.size() > 1 ) { //also print out stage number when multiple stages are available current_line << _( "Stage #" ) << stage_counter; current_buffer.push_back( current_line.str() ); current_line.str( "" ); std::string result_string; if( current_con->post_is_furniture ) { result_string = furn_str_id( current_con->post_terrain ).obj().name; } else { result_string = ter_str_id( current_con->post_terrain ).obj().name; } current_line << "<color_" << string_from_color( color_stage ) << ">" << string_format( _( "Result: %s" ), result_string.c_str() ) << "</color>"; std::vector<std::string> folded_result_string = foldstring( current_line.str(), available_window_width ); current_buffer.insert( current_buffer.end(), folded_result_string.begin(), folded_result_string.end() ); } current_line.str( "" ); // display required skill and difficulty int pskill = g->u.get_skill_level( current_con->skill ); int diff = ( current_con->difficulty > 0 ) ? current_con->difficulty : 0; current_line << "<color_" << string_from_color( ( pskill >= diff ? c_white : c_red ) ) << ">" << string_format( _( "Skill Req: %d (%s)" ), diff, current_con->skill.obj().name().c_str() ) << "</color>"; current_buffer.push_back( current_line.str() ); // TODO: Textify pre_flags to provide a bit more information. // Example: First step of dig pit could say something about // requiring diggable ground. current_line.str( "" ); if( current_con->pre_terrain != "" ) { std::string require_string; if( current_con->pre_is_furniture ) { require_string = furn_str_id( current_con->pre_terrain ).obj().name; } else { require_string = ter_str_id( current_con->pre_terrain ).obj().name; } current_line << "<color_" << string_from_color( color_stage ) << ">" << string_format( _( "Requires: %s" ), require_string.c_str() ) << "</color>"; std::vector<std::string> folded_result_string = foldstring( current_line.str(), available_window_width ); current_buffer.insert( current_buffer.end(), folded_result_string.begin(), folded_result_string.end() ); } // get pre-folded versions of the rest of the construction project to be displayed later // get time needed std::vector<std::string> folded_time = current_con->get_folded_time_string( available_window_width ); current_buffer.insert( current_buffer.end(), folded_time.begin(), folded_time.end() ); std::vector<std::string> folded_tools = current_con->requirements->get_folded_tools_list( available_window_width, color_stage, total_inv ); current_buffer.insert( current_buffer.end(), folded_tools.begin(), folded_tools.end() ); std::vector<std::string> folded_components = current_con->requirements->get_folded_components_list( available_window_width, color_stage, total_inv ); current_buffer.insert( current_buffer.end(), folded_components.begin(), folded_components.end() ); construct_buffers.push_back( current_buffer ); } //determine where the printing starts for each project, so it can be scrolled to those points size_t current_buffer_location = 0; for( size_t i = 0; i < construct_buffers.size(); i++ ) { construct_buffer_breakpoints.push_back( static_cast<int>( current_buffer_location ) ); full_construct_buffer.insert( full_construct_buffer.end(), construct_buffers[i].begin(), construct_buffers[i].end() ); //handle text too large for one screen if( construct_buffers[i].size() > static_cast<size_t>( available_buffer_height ) ) { construct_buffer_breakpoints.push_back( static_cast<int>( current_buffer_location + static_cast<size_t>( available_buffer_height ) ) ); } current_buffer_location += construct_buffers[i].size(); if( i < construct_buffers.size() - 1 ) { full_construct_buffer.push_back( std::string( "" ) ); current_buffer_location++; } } total_project_breakpoints = static_cast<int>( construct_buffer_breakpoints.size() ); } if( current_construct_breakpoint > 0 ) { // Print previous stage indicator if breakpoint is past the beginning trim_and_print( w_con, 2, pos_x, available_window_width, c_white, _( "Press %s to show previous stage(s)." ), ctxt.get_desc( "PAGE_UP" ).c_str() ); } if( static_cast<size_t>( construct_buffer_breakpoints[current_construct_breakpoint] + available_buffer_height ) < full_construct_buffer.size() ) { // Print next stage indicator if more breakpoints are remaining after screen height trim_and_print( w_con, w_height - 2 - (int)notes.size(), pos_x, available_window_width, c_white, _( "Press %s to show next stage(s)." ), ctxt.get_desc( "PAGE_DOWN" ).c_str() ); } // Leave room for above/below indicators int ypos = 3; nc_color stored_color = color_stage; for( size_t i = static_cast<size_t>( construct_buffer_breakpoints[current_construct_breakpoint] ); i < full_construct_buffer.size(); i++ ) { //the value of 3 is from leaving room at the top of window if( ypos > available_buffer_height + 3 ) { break; } print_colored_text( w_con, ypos++, ( w_list_width + w_list_x0 + 2 ), stored_color, color_stage, full_construct_buffer[i] ); } } } // Finished updating draw_scrollbar( w_con, select, w_list_height, constructs.size(), 3 ); wrefresh( w_con ); wrefresh( w_list ); const std::string action = ctxt.handle_input(); if( action == "FILTER" ){ filter = string_input_popup( _( "Search" ), 50, filter, "", _( "Filter" ), 100, false ); if( !filter.empty() ){ update_info = true; update_cat = true; tabindex = 9; select = 0; }else if( previous_index !=9 ){ tabindex = previous_index; update_info = true; update_cat = true; select = 0; } uistate.construction_filter = filter; } else if( action == "DOWN" ) { update_info = true; if( select < ( int )constructs.size() - 1 ) { select++; } else { select = 0; } } else if( action == "UP" ) { update_info = true; if( select > 0 ) { select--; } else { select = constructs.size() - 1; } } else if( action == "LEFT" ) { update_info = true; update_cat = true; select = 0; tabindex--; if( tabindex < 0 ) { tabindex = tabcount - 1; } } else if( action == "RIGHT" ) { update_info = true; update_cat = true; select = 0; tabindex = ( tabindex + 1 ) % tabcount; } else if( action == "PAGE_UP" ) { update_info = true; if( current_construct_breakpoint > 0 ) { current_construct_breakpoint--; } if( current_construct_breakpoint < 0 ) { current_construct_breakpoint = 0; } } else if( action == "PAGE_DOWN" ) { update_info = true; if( current_construct_breakpoint < total_project_breakpoints - 1 ) { current_construct_breakpoint++; } if( current_construct_breakpoint >= total_project_breakpoints ) { current_construct_breakpoint = total_project_breakpoints - 1; } } else if( action == "QUIT" ) { exit = true; } else if( action == "HELP_KEYBINDINGS" ) { draw_grid( w_con, w_list_width + w_list_x0 ); } else if( action == "TOGGLE_UNAVAILABLE_CONSTRUCTIONS" ) { update_info = true; update_cat = true; hide_unconstructable = !hide_unconstructable; select = 0; offset = 0; load_available_constructions( available, cat_available, hide_unconstructable ); } else if( action == "CONFIRM" ) { if( constructs.empty() || select >= (int) constructs.size() ){ continue;// Nothing to be done here } if( player_can_build( g->u, total_inv, constructs[select] ) ) { place_construction( constructs[select] ); uistate.last_construction = constructs[select]; exit = true; } else { popup( _( "You can't build that!" ) ); draw_grid( w_con, w_list_width + w_list_x0 ); update_info = true; } } } while( !exit ); w_list_ptr.reset(); w_con_ptr.reset(); g->refresh_all(); }
void menu_setup_devices_add() { if(init_device) { new_device=my_malloc(sizeof(dmx_device_t)); init_device=0; new_device->name=my_malloc(1); new_device->name[0]=0; new_device->uuid=rand(); new_device->device_class_uuid=0; new_device->base_address=0; active_row = 0; scroll_offset = 0; } if(invoke != 0) { if(invoke==1) { char* name = get_keyboard_buffer(); my_free(new_device->name); new_device->name=my_malloc(strlen(name)+1); strcpy(new_device->name, name); } else if(invoke==2) { new_device->device_class_uuid = get_choose_device_class(); } else if(invoke==3) { new_device->base_address = get_keyboard_number(); } invoke=0; } if(redraw) { clearDisplay(); clear_buttons(); redraw=0; draw_filledRect(0,0,LCD_WIDTH,35,155,100,100); draw_filledCircle(17,17,15,40,80,40); draw_text_8x6(7,10,"Back",255,100,100); uint16_t text_width = get_text_width_16pt("Add Device"); draw_text_16pt((LCD_WIDTH-text_width)>>1,9, "Add Device", 200,200,255); init_lineitems(); draw_lineitem("Name",new_device->name); if(new_device->device_class_uuid == 0) { draw_lineitem("Class","<empty>"); } else if(get_device_class_by_uuid(new_device->device_class_uuid) == NULL) { draw_lineitem("Class","<missing>"); } else { draw_lineitem("Class",get_device_class_by_uuid(new_device->device_class_uuid)->name); } draw_lineitem_addr("Address",new_device->base_address); draw_scrollbar(); draw_button_h(257,45,52,42,"^",155,0,0,0,255,0); draw_button_h(257,92,52,42,"Edit",155,0,0,0,255,0); draw_button_h(257,139,52,42,"Save",155,0,0,0,255,0); draw_button_h(257,186,52,42,"v",155,0,0,0,255,0); } uint8_t field=0; uint16_t x; uint16_t y; if(check_button_press(&x,&y)==1) { if(y > 41) { field=1; if(y > 184) { field=4; }else if(y > 136) { field=3; }else if(y > 89) { field=2; } } else { if(x < 40) { redraw=1; init_device=1; my_free(new_device->name); my_free(new_device); set_current_execution(menu_setup_devices); } } if(field == 1) { if(active_row > 0) { if(active_row==scroll_offset) { scroll_offset--; } active_row--; } redraw=1; } if(field == 4) { if(active_row < 2) { active_row++; int drawline = active_row-scroll_offset; if(drawline==10) { scroll_offset++; } } redraw=1; } if(field == 2) { invoke=active_row+1; redraw=1; if(active_row==0) { invoke_keyboard("Enter Device Name",new_device->name); } else if(active_row==1) { invoke_choose_device_class(new_device->device_class_uuid); } else if(active_row==2) { invoke_numeric_keyboard("Enter Base Address",new_device->base_address); } } if(field == 3) { add_device(new_device); redraw=1; init_device=1; set_current_execution(menu_setup_devices); } } }
void game::construction_menu() { int iMaxY = TERMY; if (constructions.size()+2 < iMaxY) { iMaxY = constructions.size()+2; } if (iMaxY < FULL_SCREEN_HEIGHT) { iMaxY = FULL_SCREEN_HEIGHT; } WINDOW *w_con = newwin(iMaxY, FULL_SCREEN_WIDTH, (TERMY > iMaxY) ? (TERMY-iMaxY)/2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0); wborder(w_con, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwprintz(w_con, 0, 8, c_ltred, _(" Construction ")); mvwputch(w_con, 0, 30, c_ltgray, LINE_OXXX); mvwputch(w_con, iMaxY-1, 30, c_ltgray, LINE_XXOX); for (int i = 1; i < iMaxY-1; ++i) { mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); } mvwprintz(w_con, 1, 31, c_white, _("Difficulty:")); wrefresh(w_con); bool update_info = true; int select = 0; int chosen = 0; long ch; bool exit = false; inventory total_inv = crafting_inventory(&u); do { // Erase existing list of constructions for (int i = 1; i < iMaxY-1; i++) { for (int j = 1; j < 30; j++) mvwputch(w_con, i, j, c_black, ' '); } //Draw Scrollbar draw_scrollbar(w_con, select, iMaxY-2, constructions.size(), 1); // Determine where in the master list to start printing //int offset = select - 11; int offset = 0; if (select >= iMaxY-2) offset = select - iMaxY + 3; // Print the constructions between offset and max (or how many will fit) for (int i = 0; i < iMaxY-2 && (i + offset) < constructions.size(); i++) { int current = i + offset; nc_color col = (player_can_build(u, total_inv, constructions[current]) ? c_white : c_dkgray); // Map menu items to hotkey letters, skipping j, k, l, and q. unsigned char hotkey = 97 + current; if (hotkey > 122) hotkey = hotkey - 58; if (current == select) col = hilite(col); mvwprintz(w_con, 1 + i, 1, col, "%c %s", hotkey, constructions[current]->name.c_str()); } if (update_info) { update_info = false; constructable* current_con = constructions[select]; // Print difficulty int pskill = u.skillLevel("carpentry"); int diff = current_con->difficulty > 0 ? current_con->difficulty : 0; mvwprintz(w_con, 1, 43, (pskill >= diff ? c_white : c_red), "%d ", diff); // Clear out lines for tools & materials for (int i = 2; i < iMaxY-1; i++) { for (int j = 31; j < 79; j++) mvwputch(w_con, i, j, c_black, ' '); } // Print stages and their requirements int posx = 33, posy = 2; for (int n = 0; n < current_con->stages.size(); n++) { nc_color color_stage = (player_can_build(u, total_inv, current_con, n, false, true) ? c_white : c_dkgray); const char* mes; if (current_con->stages[n].terrain != t_null) mes = _(terlist[current_con->stages[n].terrain].name.c_str()); // FIXME i18n else if (current_con->stages[n].furniture != f_null) mes = _(furnlist[current_con->stages[n].furniture].name.c_str()); // FIXME i18n else mes = ""; posy++; mvwprintz(w_con, posy, 31, color_stage, _("Stage %1$d: %2$s"), n + 1, mes); posy++; mvwprintz(w_con, posy, 31, color_stage, _("Time: %1d minutes"), current_con->stages[n].time); // Print tools construction_stage stage = current_con->stages[n]; bool has_tool[10] = {stage.tools[0].empty(), stage.tools[1].empty(), stage.tools[2].empty(), stage.tools[3].empty(), stage.tools[4].empty(), stage.tools[5].empty(), stage.tools[6].empty(), stage.tools[7].empty(), stage.tools[8].empty(), stage.tools[9].empty()}; posy++; posx = 33; for (int i = 0; i < 9 && !has_tool[i]; i++) { mvwprintz(w_con, posy, posx-2, c_white, ">"); for (int j = 0; j < stage.tools[i].size(); j++) { itype_id tool = stage.tools[i][j].type; nc_color col = c_red; if (total_inv.has_amount(tool, 1)) { has_tool[i] = true; col = c_green; } int length = utf8_width(item_controller->find_template(tool)->name.c_str()); if (posx + length > FULL_SCREEN_WIDTH-1) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, item_controller->find_template(tool)->name.c_str()); posx += length + 1; // + 1 for an empty space if (j < stage.tools[i].size() - 1) { // "OR" if there's more if (posx > FULL_SCREEN_WIDTH-3) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += 3; } } posy ++; posx = 33; } // Print components posx = 33; bool has_component[10] = {stage.components[0].empty(), stage.components[1].empty(), stage.components[2].empty(), stage.components[3].empty(), stage.components[4].empty(), stage.components[5].empty(), stage.components[6].empty(), stage.components[7].empty(), stage.components[8].empty(), stage.components[9].empty()}; for (int i = 0; i < 10; i++) { if (has_component[i]) continue; mvwprintz(w_con, posy, posx-2, c_white, ">"); for (int j = 0; j < stage.components[i].size() && i < 10; j++) { nc_color col = c_red; component comp = stage.components[i][j]; if (( item_controller->find_template(comp.type)->is_ammo() && total_inv.has_charges(comp.type, comp.count)) || (!item_controller->find_template(comp.type)->is_ammo() && total_inv.has_amount(comp.type, comp.count))) { has_component[i] = true; col = c_green; } int length = utf8_width(item_controller->find_template(comp.type)->name.c_str()); if (posx + length > FULL_SCREEN_WIDTH-1) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, "%s x%d", item_controller->find_template(comp.type)->name.c_str(), comp.count); posx += length + 3; // + 2 for " x", + 1 for an empty space // Add more space for the length of the count if (comp.count < 10) posx++; else if (comp.count < 100) posx += 2; else posx += 3; if (j < stage.components[i].size() - 1) { // "OR" if there's more if (posx > FULL_SCREEN_WIDTH-3) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += 3; } } posy ++; posx = 33; } } wrefresh(w_con); } // Finished updating ch = getch(); switch (ch) { case KEY_DOWN: update_info = true; if (select < constructions.size() - 1) select++; else select = 0; break; case KEY_UP: update_info = true; if (select > 0) select--; else select = constructions.size() - 1; break; case ' ': case KEY_ESCAPE: case 'q': case 'Q': exit = true; break; case '\n': default: if (ch > 64 && ch < 91) //A-Z chosen = ch - 65 + 26; else if (ch > 96 && ch < 123) //a-z chosen = ch - 97; else if (ch == '\n') chosen = select; if (chosen < constructions.size()) { if (player_can_build(u, total_inv, constructions[chosen])) { place_construction(constructions[chosen]); exit = true; } else { popup(_("You can't build that!")); select = chosen; for (int i = 1; i < iMaxY-1; i++) mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); update_info = true; } } break; } } while (!exit); for (int i = iMaxY-FULL_SCREEN_HEIGHT; i <= iMaxY; ++i) { for (int j = TERRAIN_WINDOW_WIDTH; j <= FULL_SCREEN_WIDTH; ++j) { mvwputch(w_con, i, j, c_black, ' '); } } wrefresh(w_con); refresh_all(); }
void color_manager::show_gui() { const int iHeaderHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT - 2 - iHeaderHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; std::vector<int> vLines; vLines.push_back(-1); vLines.push_back(48); const int iTotalCols = vLines.size(); WINDOW *w_colors_help = newwin((FULL_SCREEN_HEIGHT / 2) - 2, FULL_SCREEN_WIDTH * 3 / 4, 7 + iOffsetY + (FULL_SCREEN_HEIGHT / 2) / 2, iOffsetX + 19 / 2); WINDOW_PTR w_colors_helpptr( w_colors_help ); WINDOW *w_colors_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW_PTR w_colors_borderptr( w_colors_border ); WINDOW *w_colors_header = newwin(iHeaderHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_colors_headerptr( w_colors_header ); WINDOW *w_colors = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iHeaderHeight + 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_colorsptr( w_colors ); draw_border( w_colors_border, BORDER_COLOR, _( " COLOR MANAGER " ) ); mvwputch(w_colors_border, 3, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_colors_border, 3, 79, c_ltgray, LINE_XOXX); // -| for (int i = 0; i < 78; i++) { mvwputch(w_colors_header, 2, i, c_ltgray, LINE_OXOX); // Draw line under header } for( auto &iCol : vLines ) { if ( iCol > -1 ) { mvwputch(w_colors_border, FULL_SCREEN_HEIGHT - 1, iCol + 1, c_ltgray, LINE_XXOX); // _|_ mvwputch(w_colors_header, 2, iCol, c_ltgray, LINE_OXXX); mvwputch(w_colors_header, 3, iCol, c_ltgray, LINE_XOXO); } } wrefresh(w_colors_border); int tmpx = 0; tmpx += shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("<R>emove custom color")) + 2; tmpx += shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("<Arrow Keys> To navigate")) + 2; tmpx += shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("<Enter>-Edit")) + 2; shortcut_print(w_colors_header, 0, tmpx, c_white, c_ltgreen, _("Load <T>emplate")); mvwprintz(w_colors_header, 1, 0, c_white, _("Some color changes may require a restart.")); mvwprintz(w_colors_header, 3, 3, c_white, _("Colorname")); mvwprintz(w_colors_header, 3, 21, c_white, _("Normal")); mvwprintz(w_colors_header, 3, 52, c_white, _("Invert")); wrefresh(w_colors_header); int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; const int iMaxColors = color_array.size(); bool bStuffChanged = false; input_context ctxt("COLORS"); ctxt.register_cardinal(); ctxt.register_action("CONFIRM"); ctxt.register_action("QUIT"); ctxt.register_action("REMOVE_CUSTOM"); ctxt.register_action("LOAD_TEMPLATE"); ctxt.register_action("HELP_KEYBINDINGS"); std::map<std::string, color_struct> name_color_map; for( const auto &pr : name_map ) { name_color_map[pr.first] = color_array[pr.second]; } while(true) { // Clear all lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { mvwputch(w_colors, i, j, c_black, ' '); for( auto &iCol : vLines ) { if ( iCol == j ) { mvwputch(w_colors, i, j, c_ltgray, LINE_XOXO); } } } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, iMaxColors); draw_scrollbar(w_colors_border, iCurrentLine, iContentHeight, iMaxColors, 5); wrefresh(w_colors_border); auto iter = name_color_map.begin(); std::advance( iter, iStartPos ); std::string sActive = ""; // display colormanager for (int i=iStartPos; iter != name_color_map.end(); ++iter, ++i) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > iMaxColors) ? iMaxColors : iContentHeight)) { auto &entry = iter->second; if (iCurrentLine == i) { sActive = iter->first; mvwprintz(w_colors, i - iStartPos, vLines[iCurrentCol-1] + 2, c_yellow, ">"); } mvwprintz(w_colors, i - iStartPos, 3, c_white, iter->first.c_str()); //colorname mvwprintz(w_colors, i - iStartPos, 21, entry.color, _("default")); //default color if ( !entry.name_custom.empty() ) { mvwprintz(w_colors, i - iStartPos, 30, name_color_map[entry.name_custom].color, entry.name_custom.c_str()); //custom color } mvwprintz(w_colors, i - iStartPos, 52, entry.invert, _("default")); //invert default color if ( !entry.name_invert_custom.empty() ) { mvwprintz(w_colors, i - iStartPos, 61, name_color_map[entry.name_invert_custom].color, entry.name_invert_custom.c_str()); //invert custom color } } } wrefresh(w_colors); const std::string action = ctxt.handle_input(); if (action == "QUIT") { break; } else if (action == "UP") { iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = iMaxColors - 1; } } else if (action == "DOWN") { iCurrentLine++; if (iCurrentLine >= (int)iMaxColors) { iCurrentLine = 0; } } else if (action == "LEFT") { iCurrentCol--; if (iCurrentCol < 1) { iCurrentCol = iTotalCols; } } else if (action == "RIGHT") { iCurrentCol++; if (iCurrentCol > iTotalCols) { iCurrentCol = 1; } } else if (action == "REMOVE_CUSTOM") { auto &entry = name_color_map[sActive]; if ( iCurrentCol == 1 && !entry.name_custom.empty() ) { bStuffChanged = true; entry.name_custom = ""; } else if ( iCurrentCol == 2 && !entry.name_invert_custom.empty() ) { bStuffChanged = true; entry.name_invert_custom = ""; } finalize(); // Need to recalculate caches } else if (action == "LOAD_TEMPLATE") { auto vFiles = get_files_from_path(".json", FILENAMES["color_templates"], false, true); if ( vFiles.size() > 0 ) { uimenu ui_templates; ui_templates.w_y = iHeaderHeight + 1 + iOffsetY; ui_templates.w_height = 18; ui_templates.return_invalid = true; ui_templates.text = _("Color templates:"); for ( const auto& filename : vFiles ) { ui_templates.addentry( filename.substr(filename.find_last_of("/") + 1) ); } ui_templates.addentry(std::string(_("Cancel"))); ui_templates.query(); if ( (size_t)ui_templates.ret < vFiles.size() ) { bStuffChanged = true; clear(); load_default(); load_custom(vFiles[ui_templates.ret]); name_color_map.clear(); for( const auto &pr : name_map ) { name_color_map[pr.first] = color_array[pr.second]; } } } finalize(); // Need to recalculate caches } else if (action == "CONFIRM") { uimenu ui_colors; ui_colors.w_y = iHeaderHeight + 1 + iOffsetY; ui_colors.w_height = 18; ui_colors.return_invalid = true; std::string sColorType = _("Normal"); std::string sSelected = name_color_map[sActive].name_custom; if ( iCurrentCol == 2 ) { sColorType = _("Invert"); sSelected = name_color_map[sActive].name_invert_custom; } ui_colors.text = string_format( _("Custom %s color:"), sColorType.c_str() ); int i = 0; for ( auto &iter : name_color_map ) { std::string sColor = iter.first; std::string sType = _("default"); std::string name_custom = ""; if ( sSelected == sColor ) { ui_colors.selected = i; } if ( !iter.second.name_custom.empty() ) { name_custom = " <color_" + iter.second.name_custom + ">" + iter.second.name_custom + "</color>"; } ui_colors.addentry(string_format( "%-17s <color_%s>%s</color>%s", iter.first.c_str(), sColor.c_str(), sType.c_str(), name_custom.c_str() ) ); i++; } ui_colors.addentry(std::string(_("Cancel"))); ui_colors.query(); if ( (size_t)ui_colors.ret < name_color_map.size() ) { bStuffChanged = true; iter = name_color_map.begin(); std::advance( iter, ui_colors.ret ); auto &entry = name_color_map[sActive]; if ( iCurrentCol == 1 ) { entry.name_custom = iter->first; } else if ( iCurrentCol == 2 ) { entry.name_invert_custom = iter->first; } } finalize(); // Need to recalculate caches } } if( bStuffChanged && query_yn(_("Save changes?") ) ) { for( const auto &pr : name_color_map ) { color_id id = name_to_id( pr.first ); color_array[id].name_custom = pr.second.name_custom; color_array[id].name_invert_custom = pr.second.name_invert_custom; } finalize(); save_custom(); clear(); load_default(); load_custom(); } }
void safemode::show( const std::string &custom_name_in, bool is_safemode_in ) { auto global_rules_old = global_rules; auto character_rules_old = character_rules; const int header_height = 4; const int content_height = FULL_SCREEN_HEIGHT - 2 - header_height; const int offset_x = ( TERMX > FULL_SCREEN_WIDTH ) ? ( TERMX - FULL_SCREEN_WIDTH ) / 2 : 0; const int offset_y = ( TERMY > FULL_SCREEN_HEIGHT ) ? ( TERMY - FULL_SCREEN_HEIGHT ) / 2 : 0; enum Columns : int { COLUMN_RULE, COLUMN_ATTITUDE, COLUMN_PROXIMITY, COLUMN_WHITE_BLACKLIST, }; std::map<int, int> column_pos; column_pos[COLUMN_RULE] = 4; column_pos[COLUMN_ATTITUDE] = 48; column_pos[COLUMN_PROXIMITY] = 59; column_pos[COLUMN_WHITE_BLACKLIST] = 66; const int num_columns = column_pos.size(); WINDOW *w_help = newwin( ( FULL_SCREEN_HEIGHT / 2 ) - 2, FULL_SCREEN_WIDTH * 3 / 4, 7 + offset_y + ( FULL_SCREEN_HEIGHT / 2 ) / 2, offset_x + 19 / 2 ); WINDOW_PTR w_helpptr( w_help ); WINDOW *w_border = newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, offset_y, offset_x ); WINDOW_PTR w_borderptr( w_border ); WINDOW *w_header = newwin( header_height, FULL_SCREEN_WIDTH - 2, 1 + offset_y, 1 + offset_x ); WINDOW_PTR w_headerptr( w_header ); WINDOW *w = newwin( content_height, FULL_SCREEN_WIDTH - 2, header_height + 1 + offset_y, 1 + offset_x ); WINDOW_PTR wptr( w ); draw_border( w_border, BORDER_COLOR, custom_name_in ); mvwputch( w_border, 3, 0, c_ltgray, LINE_XXXO ); // |- mvwputch( w_border, 3, 79, c_ltgray, LINE_XOXX ); // -| for( auto &column : column_pos ) { mvwputch( w_border, FULL_SCREEN_HEIGHT - 1, column.second + 1, c_ltgray, LINE_XXOX ); // _|_ } wrefresh( w_border ); static const std::vector<std::string> hotkeys = {{ _( "<A>dd" ), _( "<R>emove" ), _( "<C>opy" ), _( "<M>ove" ), _( "<E>nable" ), _( "<D>isable" ), _( "<T>est" ) } }; int tmpx = 0; for( auto &hotkey : hotkeys ) { tmpx += shortcut_print( w_header, 0, tmpx, c_white, c_ltgreen, hotkey ) + 2; } tmpx = 0; tmpx += shortcut_print( w_header, 1, tmpx, c_white, c_ltgreen, _( "<+-> Move up/down" ) ) + 2; tmpx += shortcut_print( w_header, 1, tmpx, c_white, c_ltgreen, _( "<Enter>-Edit" ) ) + 2; shortcut_print( w_header, 1, tmpx, c_white, c_ltgreen, _( "<Tab>-Switch Page" ) ); for( int i = 0; i < 78; i++ ) { mvwputch( w_header, 2, i, c_ltgray, LINE_OXOX ); // Draw line under header } for( auto &pos : column_pos ) { mvwputch( w_header, 2, pos.second, c_ltgray, LINE_OXXX ); mvwputch( w_header, 3, pos.second, c_ltgray, LINE_XOXO ); } mvwprintz( w_header, 3, 1, c_white, "#" ); mvwprintz( w_header, 3, column_pos[COLUMN_RULE] + 4, c_white, _( "Rules" ) ); mvwprintz( w_header, 3, column_pos[COLUMN_ATTITUDE] + 2, c_white, _( "Attitude" ) ); mvwprintz( w_header, 3, column_pos[COLUMN_PROXIMITY] + 2, c_white, _( "Dist" ) ); mvwprintz( w_header, 3, column_pos[COLUMN_WHITE_BLACKLIST] + 2, c_white, _( "B/W" ) ); wrefresh( w_header ); int tab = GLOBAL_TAB; int line = 0; int column = 0; int start_pos = 0; bool changes_made = false; input_context ctxt( "SAFEMODE" ); ctxt.register_cardinal(); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "QUIT" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "ADD_DEFAULT_RULESET" ); ctxt.register_action( "ADD_RULE" ); ctxt.register_action( "REMOVE_RULE" ); ctxt.register_action( "COPY_RULE" ); ctxt.register_action( "ENABLE_RULE" ); ctxt.register_action( "DISABLE_RULE" ); ctxt.register_action( "MOVE_RULE_UP" ); ctxt.register_action( "MOVE_RULE_DOWN" ); ctxt.register_action( "TEST_RULE" ); ctxt.register_action( "HELP_KEYBINDINGS" ); if( is_safemode_in ) { ctxt.register_action( "SWITCH_SAFEMODE_OPTION" ); ctxt.register_action( "SWAP_RULE_GLOBAL_CHAR" ); } while( true ) { int locx = 17; locx += shortcut_print( w_header, 2, locx, c_white, ( tab == GLOBAL_TAB ) ? hilite( c_white ) : c_white, _( "[<Global>]" ) ) + 1; shortcut_print( w_header, 2, locx, c_white, ( tab == CHARACTER_TAB ) ? hilite( c_white ) : c_white, _( "[<Character>]" ) ); locx = 55; mvwprintz( w_header, 0, locx, c_white, _( "Safe Mode enabled:" ) ); locx += shortcut_print( w_header, 1, locx, ( ( get_option<bool>( "SAFEMODE" ) ) ? c_ltgreen : c_ltred ), c_white, ( ( get_option<bool>( "SAFEMODE" ) ) ? _( "True" ) : _( "False" ) ) ); locx += shortcut_print( w_header, 1, locx, c_white, c_ltgreen, " " ); locx += shortcut_print( w_header, 1, locx, c_white, c_ltgreen, _( "<S>witch" ) ); shortcut_print( w_header, 1, locx, c_white, c_ltgreen, " " ); wrefresh( w_header ); // Clear the lines for( int i = 0; i < content_height; i++ ) { for( int j = 0; j < 79; j++ ) { mvwputch( w, i, j, c_black, ' ' ); } for( auto &pos : column_pos ) { mvwputch( w, i, pos.second, c_ltgray, LINE_XOXO ); } } auto ¤t_tab = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; if( tab == CHARACTER_TAB && g->u.name.empty() ) { character_rules.clear(); mvwprintz( w, 8, 15, c_white, _( "Please load a character first to use this page!" ) ); } else if( empty() ) { mvwprintz( w, 8, 15, c_white, _( "Safe Mode manager currently inactive." ) ); mvwprintz( w, 9, 15, c_white, _( "Default rules are used. Add a rule to activate." ) ); mvwprintz( w, 10, 15, c_white, _( "Press ~ to add a default ruleset to get started." ) ); } draw_scrollbar( w_border, line, content_height, current_tab.size(), 5 ); wrefresh( w_border ); calcStartPos( start_pos, line, content_height, current_tab.size() ); // display safe mode for( int i = start_pos; i < ( int )current_tab.size(); i++ ) { if( i >= start_pos && i < start_pos + std::min( content_height, static_cast<int>( current_tab.size() ) ) ) { auto rule = current_tab[i]; nc_color line_color = ( rule.active ) ? c_white : c_ltgray; mvwprintz( w, i - start_pos, 1, line_color, "%d", i + 1 ); mvwprintz( w, i - start_pos, 5, c_yellow, ( line == i ) ? ">> " : " " ); auto draw_column = [&]( Columns column_in, std::string text_in ) { mvwprintz( w, i - start_pos, column_pos[column_in] + 2, ( line == i && column == column_in ) ? hilite( line_color ) : line_color, "%s", text_in.c_str() ); }; draw_column( COLUMN_RULE, ( rule.rule.empty() ) ? _( "<empty rule>" ) : rule.rule ); draw_column( COLUMN_ATTITUDE, Creature::get_attitude_ui_data( rule.attitude ).first ); draw_column( COLUMN_PROXIMITY, ( !rule.whitelist ) ? to_string( rule.proximity ).c_str() : "---" ); draw_column( COLUMN_WHITE_BLACKLIST, ( rule.whitelist ) ? _( "Whitelist" ) : _( "Blacklist" ) ); } } wrefresh( w ); const std::string action = ctxt.handle_input(); if( action == "NEXT_TAB" ) { tab++; if( tab >= MAX_TAB ) { tab = 0; line = 0; } } else if( action == "PREV_TAB" ) { tab--; if( tab < 0 ) { tab = MAX_TAB - 1; line = 0; } } else if( action == "QUIT" ) { break; } else if( tab == CHARACTER_TAB && g->u.name.empty() ) { //Only allow loaded games to use the char sheet } else if( action == "DOWN" ) { line++; if( line >= ( int )current_tab.size() ) { line = 0; } } else if( action == "UP" ) { line--; if( line < 0 ) { line = current_tab.size() - 1; } } else if( action == "ADD_DEFAULT_RULESET" ) { changes_made = true; current_tab.push_back( rules_class( "*", true, false, Creature::A_HOSTILE, 0 ) ); line = current_tab.size() - 1; } else if( action == "ADD_RULE" ) { changes_made = true; current_tab.push_back( rules_class( "", true, false, Creature::A_HOSTILE, get_option<int>( "SAFEMODEPROXIMITY" ) ) ); line = current_tab.size() - 1; } else if( action == "REMOVE_RULE" && !current_tab.empty() ) { changes_made = true; current_tab.erase( current_tab.begin() + line ); if( line > ( int )current_tab.size() - 1 ) { line--; } if( line < 0 ) { line = 0; } } else if( action == "COPY_RULE" && !current_tab.empty() ) { changes_made = true; current_tab.push_back( current_tab[line] ); line = current_tab.size() - 1; } else if( action == "SWAP_RULE_GLOBAL_CHAR" && !current_tab.empty() ) { if( ( tab == GLOBAL_TAB && !g->u.name.empty() ) || tab == CHARACTER_TAB ) { changes_made = true; //copy over auto &temp_rules_from = ( tab == GLOBAL_TAB ) ? global_rules : character_rules; auto &temp_rules_to = ( tab == GLOBAL_TAB ) ? character_rules : global_rules; temp_rules_to.push_back( temp_rules_from[line] ); //remove old temp_rules_from.erase( temp_rules_from.begin() + line ); line = temp_rules_from.size() - 1; tab = ( tab == GLOBAL_TAB ) ? CHARACTER_TAB : GLOBAL_TAB; } } else if( action == "CONFIRM" && !current_tab.empty() ) { changes_made = true; if( column == COLUMN_RULE ) { fold_and_print( w_help, 1, 1, 999, c_white, _( "* is used as a Wildcard. A few Examples:\n" "\n" "human matches every NPC\n" "zombie matches the monster name exactly\n" "acidic zo* matches monsters beginning with 'acidic zo'\n" "*mbie matches monsters ending with 'mbie'\n" "*cid*zo*ie multiple * are allowed\n" "AcI*zO*iE case insensitive search" ) ); draw_border( w_help ); wrefresh( w_help ); current_tab[line].rule = wildcard_trim_rule( string_input_popup() .title( _( "Safe Mode Rule:" ) ) .width( 30 ) .text( current_tab[line].rule ) .query_string() ); } else if( column == COLUMN_WHITE_BLACKLIST ) { current_tab[line].whitelist = !current_tab[line].whitelist; } else if( column == COLUMN_ATTITUDE ) { auto &attitude = current_tab[line].attitude; switch( attitude ) { case Creature::A_HOSTILE: attitude = Creature::A_NEUTRAL; break; case Creature::A_NEUTRAL: attitude = Creature::A_FRIENDLY; break; case Creature::A_FRIENDLY: attitude = Creature::A_ANY; break; case Creature::A_ANY: attitude = Creature::A_HOSTILE; } } else if( column == COLUMN_PROXIMITY && !current_tab[line].whitelist ) { const auto text = string_input_popup() .title( _( "Proximity Distance (0=max viewdistance)" ) ) .width( 4 ) .text( to_string( current_tab[line].proximity ) ) .description( _( "Option: " ) + to_string( get_option<int>( "SAFEMODEPROXIMITY" ) ) + " " + get_options().get_option( "SAFEMODEPROXIMITY" ).getDefaultText() ) .max_length( 3 ) .only_digits( true ) .query_string(); if( text.empty() ) { current_tab[line].proximity = get_option<int>( "SAFEMODEPROXIMITY" ); } else { //Let the options class handle the validity of the new value auto temp_option = get_options().get_option( "SAFEMODEPROXIMITY" ); temp_option.setValue( text ); current_tab[line].proximity = atoi( temp_option.getValue().c_str() ); } } } else if( action == "ENABLE_RULE" && !current_tab.empty() ) { changes_made = true; current_tab[line].active = true; } else if( action == "DISABLE_RULE" && !current_tab.empty() ) { changes_made = true; current_tab[line].active = false; } else if( action == "LEFT" ) { column--; if( column < 0 ) { column = num_columns - 1; } } else if( action == "RIGHT" ) { column++; if( column >= num_columns ) { column = 0; } } else if( action == "MOVE_RULE_UP" && !current_tab.empty() ) { changes_made = true; if( line < ( int )current_tab.size() - 1 ) { std::swap( current_tab[line], current_tab[line + 1] ); line++; column = 0; } } else if( action == "MOVE_RULE_DOWN" && !current_tab.empty() ) { changes_made = true; if( line > 0 ) { std::swap( current_tab[line], current_tab[line - 1] ); line--; column = 0; } } else if( action == "TEST_RULE" && !current_tab.empty() ) { test_pattern( tab, line ); } else if( action == "SWITCH_SAFEMODE_OPTION" ) { get_options().get_option( "SAFEMODE" ).setNext(); get_options().save(); } } if( !changes_made ) { return; } if( query_yn( _( "Save changes?" ) ) ) { if( is_safemode_in ) { save_global(); if( !g->u.name.empty() ) { save_character(); } } else { create_rules(); } } else { global_rules = global_rules_old; character_rules = character_rules_old; } }
void construction_menu() { // only display constructions the player can theoretically perform std::vector<std::string> available; for (unsigned i = 0; i < constructions.size(); ++i) { construction *c = constructions[i]; if (can_construct(c)) { bool already_have_it = false; for (unsigned j = 0; j < available.size(); ++j) { if (available[j] == c->description) { already_have_it = true; break; } } if (!already_have_it) { available.push_back(c->description); } } } int iMaxY = TERMY; if (available.size()+2 < iMaxY) { iMaxY = available.size()+2; } if (iMaxY < FULL_SCREEN_HEIGHT) { iMaxY = FULL_SCREEN_HEIGHT; } WINDOW *w_con = newwin(iMaxY, FULL_SCREEN_WIDTH, (TERMY > iMaxY) ? (TERMY-iMaxY)/2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0); wborder(w_con, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); mvwprintz(w_con, 0, 8, c_ltred, _(" Construction ")); mvwputch(w_con, 0, 30, c_ltgray, LINE_OXXX); mvwputch(w_con, iMaxY-1, 30, c_ltgray, LINE_XXOX); for (int i = 1; i < iMaxY-1; ++i) { mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); } mvwprintz(w_con, 1, 31, c_white, _("Difficulty:")); wrefresh(w_con); bool update_info = true; int select = 0; int chosen = 0; long ch; bool exit = false; inventory total_inv = g->crafting_inventory(&(g->u)); do { // Erase existing list of constructions for (int i = 1; i < iMaxY-1; i++) { for (int j = 1; j < 30; j++) mvwputch(w_con, i, j, c_black, ' '); } //Draw Scrollbar draw_scrollbar(w_con, select, iMaxY-2, available.size(), 1); // Determine where in the master list to start printing //int offset = select - 11; int offset = 0; if (select >= iMaxY-2) offset = select - iMaxY + 3; // Print the constructions between offset and max (or how many will fit) for (int i = 0; i < iMaxY-2 && (i + offset) < available.size(); i++) { int current = i + offset; nc_color col = (player_can_build(g->u, total_inv, available[current]) ? c_white : c_dkgray); // Map menu items to hotkey letters, skipping j, k, l, and q. unsigned char hotkey = 97 + current; if (hotkey > 122) hotkey = hotkey - 58; if (current == select) col = hilite(col); mvwprintz(w_con, 1 + i, 1, col, "%c %s", hotkey, available[current].c_str()); } if (update_info) { update_info = false; std::string current_desc = available[select]; // Clear out lines for tools & materials for (int i = 2; i < iMaxY-1; i++) { for (int j = 31; j < 79; j++) mvwputch(w_con, i, j, c_black, ' '); } // Print stages and their requirement int posx = 33, posy = 0; std::vector<construction*> options = constructions_by_desc[current_desc]; for (unsigned i = 0; i < options.size(); ++i) { construction *current_con = options[i]; if (!can_construct(current_con)) { continue; } nc_color color_stage = c_white; // display difficulty int pskill = g->u.skillLevel("carpentry"); int diff = current_con->difficulty > 0 ? current_con->difficulty : 0; posy++; mvwprintz(w_con, posy, 31, (pskill >= diff ? c_white : c_red), _("Difficulty: %d"), diff); // display required terrain if (current_con->pre_terrain != "") { posy++; if (current_con->pre_is_furniture) { mvwprintz(w_con, posy, 31, color_stage, _("Replaces: %s"), furnmap[current_con->pre_terrain].name.c_str()); } else { mvwprintz(w_con, posy, 31, color_stage, _("Replaces: %s"), termap[current_con->pre_terrain].name.c_str()); } } // display result if (current_con->post_terrain != "") { posy++; if (current_con->post_is_furniture) { mvwprintz(w_con, posy, 31, color_stage, _("Result: %s"), furnmap[current_con->post_terrain].name.c_str()); } else { mvwprintz(w_con, posy, 31, color_stage, _("Result: %s"), termap[current_con->post_terrain].name.c_str()); } } // display time needed posy++; mvwprintz(w_con, posy, 31, color_stage, _("Time: %1d minutes"), current_con->time); // Print tools std::vector<bool> has_tool; posy++; posx = 33; for (int i = 0; i < current_con->tools.size(); i++) { has_tool.push_back(false); mvwprintz(w_con, posy, posx-2, c_white, ">"); for (unsigned j = 0; j < current_con->tools[i].size(); j++) { itype_id tool = current_con->tools[i][j].type; nc_color col = c_red; if (total_inv.has_amount(tool, 1)) { has_tool[i] = true; col = c_green; } int length = utf8_width(item_controller->find_template(tool)->name.c_str()); if (posx + length > FULL_SCREEN_WIDTH-1) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, item_controller->find_template(tool)->name.c_str()); posx += length + 1; // + 1 for an empty space if (j < current_con->tools[i].size() - 1) { // "OR" if there's more if (posx > FULL_SCREEN_WIDTH-3) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += 3; } } posy ++; posx = 33; } // Print components posx = 33; std::vector<bool> has_component; for (int i = 0; i < current_con->components.size(); i++) { has_component.push_back(false); mvwprintz(w_con, posy, posx-2, c_white, ">"); for (unsigned j = 0; j < current_con->components[i].size(); j++) { nc_color col = c_red; component comp = current_con->components[i][j]; if (( item_controller->find_template(comp.type)->is_ammo() && total_inv.has_charges(comp.type, comp.count)) || (!item_controller->find_template(comp.type)->is_ammo() && total_inv.has_amount(comp.type, comp.count))) { has_component[i] = true; col = c_green; } int length = utf8_width(item_controller->find_template(comp.type)->name.c_str()); if (posx + length > FULL_SCREEN_WIDTH-1) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, "%s x%d", item_controller->find_template(comp.type)->name.c_str(), comp.count); posx += length + 3; // + 2 for " x", + 1 for an empty space // Add more space for the length of the count if (comp.count < 10) posx++; else if (comp.count < 100) posx += 2; else posx += 3; if (j < current_con->components[i].size() - 1) { // "OR" if there's more if (posx > FULL_SCREEN_WIDTH-3) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += 3; } } posy ++; posx = 33; } } wrefresh(w_con); } // Finished updating ch = getch(); switch (ch) { case KEY_DOWN: update_info = true; if (select < available.size() - 1) select++; else select = 0; break; case KEY_UP: update_info = true; if (select > 0) select--; else select = available.size() - 1; break; case ' ': case KEY_ESCAPE: case 'q': case 'Q': exit = true; break; case '\n': default: if (ch > 64 && ch < 91) //A-Z chosen = ch - 65 + 26; else if (ch > 96 && ch < 123) //a-z chosen = ch - 97; else if (ch == '\n') chosen = select; if (chosen < available.size()) { if (player_can_build(g->u, total_inv, available[chosen])) { place_construction(available[chosen]); exit = true; } else { popup(_("You can't build that!")); select = chosen; for (int i = 1; i < iMaxY-1; i++) mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); update_info = true; } } break; } } while (!exit); for (int i = iMaxY-FULL_SCREEN_HEIGHT; i <= iMaxY; ++i) { for (int j = TERRAIN_WINDOW_WIDTH; j <= FULL_SCREEN_WIDTH; ++j) { mvwputch(w_con, i, j, c_black, ' '); } } wrefresh(w_con); g->refresh_all(); }
void player::power_bionics() { std::vector <bionic *> passive = filtered_bionics( *my_bionics, TAB_PASSIVE ); std::vector <bionic *> active = filtered_bionics( *my_bionics, TAB_ACTIVE ); bionic *bio_last = NULL; bionic_tab_mode tab_mode = TAB_ACTIVE; //added title_tab_height for the tabbed bionic display int TITLE_HEIGHT = 2; int TITLE_TAB_HEIGHT = 3; // Main window /** Total required height is: * top frame line: + 1 * height of title window: + TITLE_HEIGHT * height of tabs: + TITLE_TAB_HEIGHT * height of the biggest list of active/passive bionics: + bionic_count * bottom frame line: + 1 * TOTAL: TITLE_HEIGHT + TITLE_TAB_HEIGHT + bionic_count + 2 */ const int HEIGHT = std::min( TERMY, std::max( FULL_SCREEN_HEIGHT, TITLE_HEIGHT + TITLE_TAB_HEIGHT + ( int )my_bionics->size() + 2 ) ); const int WIDTH = FULL_SCREEN_WIDTH + ( TERMX - FULL_SCREEN_WIDTH ) / 2; const int START_X = ( TERMX - WIDTH ) / 2; const int START_Y = ( TERMY - HEIGHT ) / 2; //wBio is the entire bionic window catacurses::window wBio = catacurses::newwin( HEIGHT, WIDTH, START_Y, START_X ); const int LIST_HEIGHT = HEIGHT - TITLE_HEIGHT - TITLE_TAB_HEIGHT - 2; const int DESCRIPTION_WIDTH = WIDTH - 2 - 40; const int DESCRIPTION_START_Y = START_Y + TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; const int DESCRIPTION_START_X = START_X + 1 + 40; //w_description is the description panel that is controlled with ! key catacurses::window w_description = catacurses::newwin( LIST_HEIGHT, DESCRIPTION_WIDTH, DESCRIPTION_START_Y, DESCRIPTION_START_X ); // Title window const int TITLE_START_Y = START_Y + 1; const int HEADER_LINE_Y = TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; catacurses::window w_title = catacurses::newwin( TITLE_HEIGHT, WIDTH - 2, TITLE_START_Y, START_X + 1 ); const int TAB_START_Y = TITLE_START_Y + 2; //w_tabs is the tab bar for passive and active bionic groups catacurses::window w_tabs = catacurses::newwin( TITLE_TAB_HEIGHT, WIDTH - 2, TAB_START_Y, START_X + 1 ); int scroll_position = 0; int cursor = 0; //generate the tab title string and a count of the bionics owned bionic_menu_mode menu_mode = ACTIVATING; // offset for display: bionic with index i is drawn at y=list_start_y+i // drawing the bionics starts with bionic[scroll_position] const int list_start_y = HEADER_LINE_Y;// - scroll_position; int half_list_view_location = LIST_HEIGHT / 2; int max_scroll_position = std::max( 0, ( int )active.size() ); input_context ctxt( "BIONICS" ); ctxt.register_updown(); ctxt.register_action( "ANY_INPUT" ); ctxt.register_action( "TOGGLE_EXAMINE" ); ctxt.register_action( "REASSIGN" ); ctxt.register_action( "REMOVE" ); ctxt.register_action( "NEXT_TAB" ); ctxt.register_action( "PREV_TAB" ); ctxt.register_action( "CONFIRM" ); ctxt.register_action( "HELP_KEYBINDINGS" ); bool recalc = false; bool redraw = true; for( ;; ) { if( recalc ) { passive = filtered_bionics( *my_bionics, TAB_PASSIVE ); active = filtered_bionics( *my_bionics, TAB_ACTIVE ); if( active.empty() && !passive.empty() ) { tab_mode = TAB_PASSIVE; } if( --cursor < 0 ) { cursor = 0; } if( scroll_position > max_scroll_position && cursor - scroll_position < LIST_HEIGHT - half_list_view_location ) { scroll_position--; } recalc = false; // bionics were modified, so it's necessary to redraw the screen redraw = true; } //track which list we are looking at std::vector<bionic *> *current_bionic_list = ( tab_mode == TAB_ACTIVE ? &active : &passive ); max_scroll_position = std::max( 0, ( int )current_bionic_list->size() - LIST_HEIGHT ); if( redraw ) { redraw = false; werase( wBio ); draw_border( wBio, BORDER_COLOR, _( " BIONICS " ) ); // Draw symbols to connect additional lines to border mvwputch( wBio, HEADER_LINE_Y - 1, 0, BORDER_COLOR, LINE_XXXO ); // |- mvwputch( wBio, HEADER_LINE_Y - 1, WIDTH - 1, BORDER_COLOR, LINE_XOXX ); // -| int max_width = 0; std::vector<std::string>bps; for( int i = 0; i < num_bp; ++i ) { const body_part bp = bp_aBodyPart[i]; const int total = get_total_bionics_slots( bp ); const std::string s = string_format( "%s: %d/%d", body_part_name_as_heading( bp, 1 ).c_str(), total - get_free_bionics_slots( bp ), total ); bps.push_back( s ); max_width = std::max( max_width, utf8_width( s ) ); } const int pos_x = WIDTH - 2 - max_width; if( g->u.has_trait( trait_id( "DEBUG_CBM_SLOTS" ) ) ) { for( int i = 0; i < num_bp; ++i ) { mvwprintz( wBio, i + list_start_y, pos_x, c_light_gray, bps[i] ); } } if( current_bionic_list->empty() ) { std::string msg; switch( tab_mode ) { case TAB_ACTIVE: msg = _( "No activatable bionics installed." ); break; case TAB_PASSIVE: msg = _( "No passive bionics installed." ); break; } fold_and_print( wBio, list_start_y, 2, pos_x - 1, c_light_gray, msg ); } else { for( size_t i = scroll_position; i < current_bionic_list->size(); i++ ) { if( list_start_y + static_cast<int>( i ) - scroll_position == HEIGHT - 1 ) { break; } const bool is_highlighted = cursor == static_cast<int>( i ); const nc_color col = get_bionic_text_color( *( *current_bionic_list )[i], is_highlighted ); const std::string desc = string_format( "%c %s", ( *current_bionic_list )[i]->invlet, build_bionic_powerdesc_string( *( *current_bionic_list )[i] ).c_str() ); trim_and_print( wBio, list_start_y + i - scroll_position, 2, WIDTH - 3, col, desc ); if( is_highlighted && menu_mode != EXAMINING && g->u.has_trait( trait_id( "DEBUG_CBM_SLOTS" ) ) ) { const bionic_id bio_id = ( *current_bionic_list )[i]->id; draw_connectors( wBio, list_start_y + i - scroll_position, utf8_width( desc ) + 3, pos_x - 2, bio_id ); // redraw highlighted (occupied) body parts for( auto &elem : bio_id->occupied_bodyparts ) { const int i = static_cast<int>( elem.first ); mvwprintz( wBio, i + list_start_y, pos_x, c_yellow, bps[i] ); } } } } draw_scrollbar( wBio, cursor, LIST_HEIGHT, current_bionic_list->size(), list_start_y ); } wrefresh( wBio ); draw_bionics_tabs( w_tabs, active.size(), passive.size(), tab_mode ); draw_bionics_titlebar( w_title, this, menu_mode ); if( menu_mode == EXAMINING && !current_bionic_list->empty() ) { draw_description( w_description, *( *current_bionic_list )[cursor] ); } const std::string action = ctxt.handle_input(); const long ch = ctxt.get_raw_input().get_first_input(); bionic *tmp = NULL; bool confirmCheck = false; if( action == "DOWN" ) { redraw = true; if( static_cast<size_t>( cursor ) < current_bionic_list->size() - 1 ) { cursor++; } else { cursor = 0; } if( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position++; } if( scroll_position > 0 && cursor - scroll_position < half_list_view_location ) { scroll_position = std::max( cursor - half_list_view_location, 0 ); } } else if( action == "UP" ) { redraw = true; if( cursor > 0 ) { cursor--; } else { cursor = current_bionic_list->size() - 1; } if( scroll_position > 0 && cursor - scroll_position < half_list_view_location ) { scroll_position--; } if( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position = std::max( std::min<int>( current_bionic_list->size() - LIST_HEIGHT, cursor - half_list_view_location ), 0 ); } } else if( menu_mode == REASSIGNING ) { menu_mode = ACTIVATING; if( action == "CONFIRM" && !current_bionic_list->empty() ) { auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; tmp = bio_list[cursor]; } else { tmp = bionic_by_invlet( ch ); } if( tmp == nullptr ) { // Selected an non-existing bionic (or Escape, or ...) continue; } redraw = true; const long newch = popup_getkey( _( "%s; enter new letter. Space to clear. Esc to cancel." ), tmp->id->name.c_str() ); wrefresh( wBio ); if( newch == ch || newch == KEY_ESCAPE ) { continue; } if( newch == ' ' ) { tmp->invlet = ' '; continue; } if( !bionic_chars.valid( newch ) ) { popup( _( "Invalid bionic letter. Only those characters are valid:\n\n%s" ), bionic_chars.get_allowed_chars().c_str() ); continue; } bionic *otmp = bionic_by_invlet( newch ); if( otmp != nullptr ) { std::swap( tmp->invlet, otmp->invlet ); } else { tmp->invlet = newch; } // TODO: show a message like when reassigning a key to an item? } else if( action == "NEXT_TAB" ) { redraw = true; scroll_position = 0; cursor = 0; if( tab_mode == TAB_ACTIVE ) { tab_mode = TAB_PASSIVE; } else { tab_mode = TAB_ACTIVE; } } else if( action == "PREV_TAB" ) { redraw = true; scroll_position = 0; cursor = 0; if( tab_mode == TAB_PASSIVE ) { tab_mode = TAB_ACTIVE; } else { tab_mode = TAB_PASSIVE; } } else if( action == "REASSIGN" ) { menu_mode = REASSIGNING; } else if( action == "TOGGLE_EXAMINE" ) { // switches between activation and examination menu_mode = menu_mode == ACTIVATING ? EXAMINING : ACTIVATING; redraw = true; } else if( action == "REMOVE" ) { menu_mode = REMOVING; redraw = true; } else if( action == "HELP_KEYBINDINGS" ) { redraw = true; } else if( action == "CONFIRM" ) { confirmCheck = true; } else { confirmCheck = true; } //confirmation either occurred by pressing enter where the bionic cursor is, or the hotkey was selected if( confirmCheck ) { auto &bio_list = tab_mode == TAB_ACTIVE ? active : passive; if( action == "CONFIRM" && !current_bionic_list->empty() ) { tmp = bio_list[cursor]; } else { tmp = bionic_by_invlet( ch ); if( tmp && tmp != bio_last ) { // new bionic selected, update cursor and scroll position int temp_cursor = 0; for( temp_cursor = 0; temp_cursor < ( int )bio_list.size(); temp_cursor++ ) { if( bio_list[temp_cursor] == tmp ) { break; } } // if bionic is not found in current list, ignore the attempt to view/activate if( temp_cursor >= ( int )bio_list.size() ) { continue; } //relocate cursor to the bionic that was found cursor = temp_cursor; scroll_position = 0; while( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position++; } } } if( !tmp ) { // entered a key that is not mapped to any bionic, // -> leave screen break; } bio_last = tmp; const bionic_id &bio_id = tmp->id; const bionic_data &bio_data = bio_id.obj(); if( menu_mode == REMOVING ) { recalc = uninstall_bionic( bio_id ); redraw = true; continue; } if( menu_mode == ACTIVATING ) { if( bio_data.activated ) { int b = tmp - &( *my_bionics )[0]; if( tmp->powered ) { deactivate_bionic( b ); } else { activate_bionic( b ); // Clear the menu if we are firing a bionic gun if( tmp->info().gun_bionic ) { break; } } // update message log and the menu g->refresh_all(); redraw = true; if( moves < 0 ) { return; } continue; } else { popup( _( "You can not activate %s!\n" "To read a description of %s, press '!', then '%c'." ), bio_data.name.c_str(), bio_data.name.c_str(), tmp->invlet ); redraw = true; } } else if( menu_mode == EXAMINING ) { // Describing bionics, allow user to jump to description key redraw = true; if( action != "CONFIRM" ) { for( size_t i = 0; i < active.size(); i++ ) { if( active[i] == tmp ) { tab_mode = TAB_ACTIVE; cursor = static_cast<int>( i ); int max_scroll_check = std::max( 0, ( int )active.size() - LIST_HEIGHT ); if( static_cast<int>( i ) > max_scroll_check ) { scroll_position = max_scroll_check; } else { scroll_position = i; } break; } } for( size_t i = 0; i < passive.size(); i++ ) { if( passive[i] == tmp ) { tab_mode = TAB_PASSIVE; cursor = static_cast<int>( i ); int max_scroll_check = std::max( 0, ( int )passive.size() - LIST_HEIGHT ); if( static_cast<int>( i ) > max_scroll_check ) { scroll_position = max_scroll_check; } else { scroll_position = i; } break; } } } } } } }
void Messages::display_messages() { WINDOW *w = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0); size_t offset = 0; const int maxlength = FULL_SCREEN_WIDTH - 2 - 1; const int bottom = FULL_SCREEN_HEIGHT - 2; input_context ctxt("MESSAGE_LOG"); ctxt.register_action("UP", _("Scroll up")); ctxt.register_action("DOWN", _("Scroll down")); ctxt.register_action("QUIT"); ctxt.register_action("HELP_KEYBINDINGS"); while(true) { werase(w); draw_border(w); mvwprintz(w, FULL_SCREEN_HEIGHT - 1, 32, c_red, _("Press %s to return"), ctxt.get_desc("QUIT").c_str()); draw_scrollbar(w, offset, FULL_SCREEN_HEIGHT - 2, size(), 1); int line = 1; int lasttime = -1; for (size_t i = offset; i < size() && line <= bottom; i++) { const game_message &m = player_messages.messages[size() - i - 1]; const std::string mstr = m.get_with_count(); const nc_color col = m.get_color(); calendar timepassed = calendar::turn - m.turn; if (int(timepassed) > lasttime) { mvwprintz(w, line, 3, c_ltblue, _("%s ago:"), timepassed.textify_period().c_str()); line++; lasttime = int(timepassed); } std::vector<std::string> folded = foldstring(mstr, maxlength); for (size_t j = 0; j < folded.size() && line <= bottom; j++, line++) { mvwprintz(w, line, 1, col, "%s", folded[j].c_str()); } } if (offset + 1 < size()) { mvwprintz(w, FULL_SCREEN_HEIGHT - 1, 5, c_magenta, "vvv"); } if (offset > 0) { mvwprintz(w, FULL_SCREEN_HEIGHT - 1, FULL_SCREEN_WIDTH - 6, c_magenta, "^^^"); } wrefresh(w); const std::string action = ctxt.handle_input(); if (action == "DOWN" && offset + 1 < size()) { offset++; } else if (action == "UP" && offset > 0) { offset--; } else if (action == "QUIT") { break; } } player_messages.curmes = int(calendar::turn); werase(w); delwin(w); }
void show_auto_pickup() { save_reset_changes(false); const int iHeaderHeight = 4; const int iContentHeight = FULL_SCREEN_HEIGHT-2-iHeaderHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 0; std::map<int, bool> mapLines; mapLines[3] = true; mapLines[50] = true; mapLines[54] = true; const int iTotalCols = mapLines.size()-1; WINDOW* w_auto_pickup_options = newwin(FULL_SCREEN_HEIGHT/2, FULL_SCREEN_WIDTH/2, iOffsetY + (FULL_SCREEN_HEIGHT/2)/2, iOffsetX + (FULL_SCREEN_WIDTH/2)/2); WINDOW* w_auto_pickup_help = newwin((FULL_SCREEN_HEIGHT/2)-2, FULL_SCREEN_WIDTH * 3/4, 8 + iOffsetY + (FULL_SCREEN_HEIGHT/2)/2, iOffsetX + 19/2); WINDOW* w_auto_pickup_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW* w_auto_pickup_header = newwin(iHeaderHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW* w_auto_pickup = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iHeaderHeight + 1 + iOffsetY, 1 + iOffsetX); wborder(w_auto_pickup_border, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX); mvwputch(w_auto_pickup_border, 3, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_auto_pickup_border, 3, 79, c_ltgray, LINE_XOXX); // -| for (std::map<int, bool>::iterator iter = mapLines.begin(); iter != mapLines.end(); ++iter) { mvwputch(w_auto_pickup_border, FULL_SCREEN_HEIGHT-1, iter->first + 1, c_ltgray, LINE_XXOX); // _|_ } mvwprintz(w_auto_pickup_border, 0, 29, c_ltred, _(" AUTO PICKUP MANAGER ")); wrefresh(w_auto_pickup_border); int tmpx = 0; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<A>dd"))+2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<R>emove"))+2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<C>opy"))+2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<M>ove"))+2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<E>nable"))+2; tmpx += shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<D>isable"))+2; shortcut_print(w_auto_pickup_header, 0, tmpx, c_white, c_ltgreen, _("<T>est")); tmpx = 0; tmpx += shortcut_print(w_auto_pickup_header, 1, tmpx, c_white, c_ltgreen, _("<+-> Move up/down"))+2; tmpx += shortcut_print(w_auto_pickup_header, 1, tmpx, c_white, c_ltgreen, _("<Enter>-Edit"))+2; shortcut_print(w_auto_pickup_header, 1, tmpx, c_white, c_ltgreen, _("<Tab>-Switch Page")); for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_auto_pickup_header, 2, i, c_ltgray, LINE_OXXX); mvwputch(w_auto_pickup_header, 3, i, c_ltgray, LINE_XOXO); } else { mvwputch(w_auto_pickup_header, 2, i, c_ltgray, LINE_OXOX); // Draw line under header } } mvwprintz(w_auto_pickup_header, 3, 0, c_white, "#"); mvwprintz(w_auto_pickup_header, 3, 7, c_white, _("Rules")); mvwprintz(w_auto_pickup_header, 3, 51, c_white, _("I/E")); wrefresh(w_auto_pickup_header); int iCurrentPage = 1; int iCurrentLine = 0; int iCurrentCol = 1; int iStartPos = 0; bool bStuffChanged = false; char ch = ' '; std::stringstream sTemp; do { int locx = 17; locx += shortcut_print(w_auto_pickup_header, 2, locx, c_white, (iCurrentPage == 1) ? hilite(c_white) : c_white, _("[<Global>]"))+1; shortcut_print(w_auto_pickup_header, 2, locx, c_white, (iCurrentPage == 2) ? hilite(c_white) : c_white, _("[<Character>]")); wrefresh(w_auto_pickup_header); // Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w_auto_pickup, i, j, c_ltgray, LINE_XOXO); } else { mvwputch(w_auto_pickup, i, j, c_black, ' '); } } } if (iCurrentPage == 1 || iCurrentPage == 2) { if (iCurrentPage == 2 && g->u.name == "") { vAutoPickupRules[2].clear(); mvwprintz(w_auto_pickup, 8, 15, c_white, _("Please load a character first to use this page!")); } //Draw Scrollbar draw_scrollbar(w_auto_pickup_border, iCurrentLine, iContentHeight, vAutoPickupRules[iCurrentPage].size(), 5); calcStartPos(iStartPos, iCurrentLine, iContentHeight, vAutoPickupRules[iCurrentPage].size()); // display auto pickup for (int i = iStartPos; i < vAutoPickupRules[iCurrentPage].size(); i++) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > vAutoPickupRules[iCurrentPage].size()) ? vAutoPickupRules[iCurrentPage].size() : iContentHeight)) { nc_color cLineColor = (vAutoPickupRules[iCurrentPage][i].bActive) ? c_white : c_ltgray; sTemp.str(""); sTemp << i + 1; mvwprintz(w_auto_pickup, i - iStartPos, 0, cLineColor, sTemp.str().c_str()); mvwprintz(w_auto_pickup, i - iStartPos, 4, cLineColor, ""); if (iCurrentLine == i) { wprintz(w_auto_pickup, c_yellow, ">> "); } else { wprintz(w_auto_pickup, c_yellow, " "); } wprintz(w_auto_pickup, (iCurrentLine == i && iCurrentCol == 1) ? hilite(cLineColor) : cLineColor, "%s", ((vAutoPickupRules[iCurrentPage][i].sRule == "") ? _("<empty rule>") : vAutoPickupRules[iCurrentPage][i].sRule).c_str()); mvwprintz(w_auto_pickup, i - iStartPos, 52, (iCurrentLine == i && iCurrentCol == 2) ? hilite(cLineColor) : cLineColor, "%s", ((vAutoPickupRules[iCurrentPage][i].bExclude) ? rm_prefix(_("<Exclude>E")).c_str() : rm_prefix(_("<Include>I")).c_str())); } } wrefresh(w_auto_pickup); } else if (iCurrentPage == 3) { wborder(w_auto_pickup_options, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX); mvwprintz(w_auto_pickup_options, 5, 10, c_white, _("Under construction!")); wrefresh(w_auto_pickup); wrefresh(w_auto_pickup_options); } ch = (char)input(); if (iCurrentPage == 3) { switch(ch) { case '\t': //Switch to next Page iCurrentPage++; if (iCurrentPage > 3) { iCurrentPage = 1; iCurrentLine = 0; } break; } } else if (iCurrentPage == 1 || iCurrentPage == 2) { if (iCurrentPage == 2 && g->u.name == "" && ch != '\t') { //Only allow loaded games to use the char sheet } else if (vAutoPickupRules[iCurrentPage].size() > 0 || ch == 'a' || ch == '\t') { switch(ch) { case 'j': //move down iCurrentLine++; iCurrentCol = 1; if (iCurrentLine >= vAutoPickupRules[iCurrentPage].size()) { iCurrentLine = 0; } break; case 'k': //move up iCurrentLine--; iCurrentCol = 1; if (iCurrentLine < 0) { iCurrentLine = vAutoPickupRules[iCurrentPage].size()-1; } break; case 'a': //add new rule case 'A': bStuffChanged = true; vAutoPickupRules[iCurrentPage].push_back(cPickupRules("", true, false)); iCurrentLine = vAutoPickupRules[iCurrentPage].size()-1; break; case 'r': //remove rule case 'R': bStuffChanged = true; vAutoPickupRules[iCurrentPage].erase(vAutoPickupRules[iCurrentPage].begin() + iCurrentLine); if (iCurrentLine > vAutoPickupRules[iCurrentPage].size()-1) { iCurrentLine--; } break; case 'c': //copy rule case 'C': bStuffChanged = true; vAutoPickupRules[iCurrentPage].push_back(cPickupRules(vAutoPickupRules[iCurrentPage][iCurrentLine].sRule, vAutoPickupRules[iCurrentPage][iCurrentLine].bActive, vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude)); iCurrentLine = vAutoPickupRules[iCurrentPage].size()-1; break; case 'm': //move rule global <-> character case 'M': if ((iCurrentPage == 1 && g->u.name != "") || iCurrentPage == 2) { bStuffChanged = true; //copy over vAutoPickupRules[(iCurrentPage == 1) ? 2 : 1].push_back(cPickupRules(vAutoPickupRules[iCurrentPage][iCurrentLine].sRule, vAutoPickupRules[iCurrentPage][iCurrentLine].bActive, vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude)); //remove old vAutoPickupRules[iCurrentPage].erase(vAutoPickupRules[iCurrentPage].begin() + iCurrentLine); iCurrentLine = vAutoPickupRules[(iCurrentPage == 1) ? 2 : 1].size()-1; iCurrentPage = (iCurrentPage == 1) ? 2 : 1; } break; case '\t': //Switch to next Page iCurrentPage++; if (iCurrentPage > 2) { iCurrentPage = 1; iCurrentLine = 0; } break; case '\n': //Edit Col in current line bStuffChanged = true; if (iCurrentCol == 1) { fold_and_print(w_auto_pickup_help, 1, 1, 999, c_white, _( "* is used as a Wildcard. A few Examples:\n" "\n" "wood arrow matches the itemname exactly\n" "wood ar* matches items beginning with wood ar\n" "*rrow matches items ending with rrow\n" "*avy fle*fi*arrow multible * are allowed\n" "heAVY*woOD*arrOW case insesitive search\n" "") ); wborder(w_auto_pickup_help, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX); wrefresh(w_auto_pickup_help); vAutoPickupRules[iCurrentPage][iCurrentLine].sRule = trim_rule(string_input_popup(_("Pickup Rule:"), 30, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule)); } else if (iCurrentCol == 2) { vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude = !vAutoPickupRules[iCurrentPage][iCurrentLine].bExclude; } break; case 'e': //enable rule case 'E': bStuffChanged = true; vAutoPickupRules[iCurrentPage][iCurrentLine].bActive = true; break; case 'd': //disable rule case 'D': bStuffChanged = true; vAutoPickupRules[iCurrentPage][iCurrentLine].bActive = false; break; case 'h': //move left iCurrentCol--; if (iCurrentCol < 1) { iCurrentCol = iTotalCols; } break; case 'l': //move right iCurrentCol++; if (iCurrentCol > iTotalCols) { iCurrentCol = 1; } break; case '+': //move rule up bStuffChanged = true; if (iCurrentLine < vAutoPickupRules[iCurrentPage].size()-1) { std::swap(vAutoPickupRules[iCurrentPage][iCurrentLine], vAutoPickupRules[iCurrentPage][iCurrentLine+1]); iCurrentLine++; iCurrentCol = 1; } break; case '-': //move rule down bStuffChanged = true; if (iCurrentLine > 0) { std::swap(vAutoPickupRules[iCurrentPage][iCurrentLine], vAutoPickupRules[iCurrentPage][iCurrentLine-1]); iCurrentLine--; iCurrentCol = 1; } break; case 't': //test rule case 'T': test_pattern(iCurrentPage, iCurrentLine); break; } } } } while(ch != 'q' && ch != 'Q' && ch != KEY_ESCAPE); if (bStuffChanged) { if(query_yn(_("Save changes?"))) { save_auto_pickup(false); if (g->u.name != "") { save_auto_pickup(true); } } else { save_reset_changes(true); } } werase(w_auto_pickup); werase(w_auto_pickup_border); werase(w_auto_pickup_header); werase(w_auto_pickup_options); werase(w_auto_pickup_help); }
void Messages::display_messages() { WINDOW_PTR w_ptr {newwin( FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0)}; WINDOW *const w = w_ptr.get(); input_context ctxt("MESSAGE_LOG"); ctxt.register_action("UP", _("Scroll up")); ctxt.register_action("DOWN", _("Scroll down")); ctxt.register_action("QUIT"); ctxt.register_action("HELP_KEYBINDINGS"); int offset = 0; const int maxlength = FULL_SCREEN_WIDTH - 2 - 1; const int bottom = FULL_SCREEN_HEIGHT - 2; const int msg_count = size(); for (;;) { werase(w); draw_border(w); mvwprintz(w, bottom + 1, 32, c_red, _("Press %s to return"), ctxt.get_desc("QUIT").c_str()); draw_scrollbar(w, offset, bottom, msg_count, 1); int line = 1; int lasttime = -1; for( int i = offset; i < msg_count; ++i ) { if (line > bottom) { break; } const game_message &m = player_messages.impl_->history(i); const nc_color col = m.get_color(player_messages.impl_->curmes); const calendar timepassed = calendar::turn - m.time; if (timepassed.get_turn() > lasttime) { mvwprintz(w, line++, 3, c_ltblue, _("%s ago:"), timepassed.textify_period().c_str()); lasttime = timepassed.get_turn(); } for( const std::string &folded : foldstring(m.get_with_count(), maxlength) ) { if (line > bottom) { break; } mvwprintz(w, line++, 1, col, "%s", folded.c_str()); } } if (offset + 1 < msg_count) { mvwprintz(w, bottom + 1, 5, c_magenta, "vvv"); } if (offset > 0) { mvwprintz(w, bottom + 1, maxlength - 3, c_magenta, "^^^"); } wrefresh(w); const std::string &action = ctxt.handle_input(); if (action == "DOWN" && offset + 1 < msg_count) { offset++; } else if (action == "UP" && offset > 0) { offset--; } else if (action == "QUIT") { break; } } player_messages.impl_->curmes = calendar::turn.get_turn(); }
void input_context::display_help() { inp_mngr.set_timeout(-1); // Shamelessly stolen from help.cpp WINDOW *w_help = newwin(FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, 1 + (int)((TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0), 1 + (int)((TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0)); // has the user changed something? bool changed = false; // keybindings before the user changed anything. input_manager::t_action_contexts old_action_contexts(inp_mngr.action_contexts); // current status: adding/removing/showing keybindings enum { s_remove, s_add, s_add_global, s_show } status = s_show; // copy of registered_actions, but without the ANY_INPUT and COORDINATE, which should not be shown std::vector<std::string> org_registered_actions(registered_actions); std::vector<std::string>::iterator any_input = std::find(org_registered_actions.begin(), org_registered_actions.end(), ANY_INPUT); if (any_input != org_registered_actions.end()) { org_registered_actions.erase(any_input); } std::vector<std::string>::iterator coordinate = std::find(org_registered_actions.begin(), org_registered_actions.end(), COORDINATE); if (coordinate != org_registered_actions.end()) { org_registered_actions.erase(coordinate); } // colors of the keybindings static const nc_color global_key = c_ltgray; static const nc_color local_key = c_ltgreen; static const nc_color unbound_key = c_ltred; // (vertical) scroll offset size_t scroll_offset = 0; // height of the area usable for display of keybindings, excludes headers & borders const size_t display_height = FULL_SCREEN_HEIGHT - 9 - 2; // -2 for the border // width of the legend const size_t legwidth = FULL_SCREEN_WIDTH - 4 - 2; // keybindings help std::ostringstream legend; legend << "<color_" << string_from_color(unbound_key) << ">" << _("Unbound keys") << "</color>\n"; legend << "<color_" << string_from_color(local_key) << ">" << _("Keybinding active only on this screen") << "</color>\n"; legend << "<color_" << string_from_color(global_key) << ">" << _("Keybinding active globally") << "</color>\n"; legend << _("Press - to remove keybinding\nPress + to add local keybinding\nPress = to add global keybinding\n"); input_context ctxt("HELP_KEYBINDINGS"); ctxt.register_action("UP", _("Scroll up")); ctxt.register_action("DOWN", _("Scroll down")); ctxt.register_action("PAGE_DOWN"); ctxt.register_action("PAGE_UP"); ctxt.register_action("REMOVE"); ctxt.register_action("ADD_LOCAL"); ctxt.register_action("ADD_GLOBAL"); ctxt.register_action("QUIT"); ctxt.register_action("ANY_INPUT"); if (category != "HELP_KEYBINDINGS") { // avoiding inception! ctxt.register_action("HELP_KEYBINDINGS"); } std::string hotkeys = ctxt.get_available_single_char_hotkeys(display_help_hotkeys); while(true) { werase(w_help); draw_border(w_help); draw_scrollbar(w_help, scroll_offset, display_height, org_registered_actions.size() - display_height, 8); mvwprintz(w_help, 0, (FULL_SCREEN_WIDTH - utf8_width(_("Keybindings"))) / 2 - 1, c_ltred, " %s ", _("Keybindings")); fold_and_print(w_help, 1, 2, legwidth, c_white, legend.str()); for (size_t i = 0; i + scroll_offset < org_registered_actions.size() && i < display_height; i++) { const std::string &action_id = org_registered_actions[i + scroll_offset]; bool overwrite_default; const action_attributes &attributes = inp_mngr.get_action_attributes(action_id, category, &overwrite_default); char invlet; if (i < hotkeys.size()) { invlet = hotkeys[i]; } else { invlet = ' '; } if (status == s_add_global && overwrite_default) { // We're trying to add a global, but this action has a local // defined, so gray out the invlet. mvwprintz(w_help, i + 8, 2, c_dkgray, "%c ", invlet); } else if (status == s_add || status == s_add_global) { mvwprintz(w_help, i + 8, 2, c_blue, "%c ", invlet); } else if (status == s_remove) { mvwprintz(w_help, i + 8, 2, c_blue, "%c ", invlet); } else { mvwprintz(w_help, i + 8, 2, c_blue, " "); } nc_color col; if (attributes.input_events.empty()) { col = unbound_key; } else if (overwrite_default) { col = local_key; } else { col = global_key; } mvwprintz(w_help, i + 8, 4, col, "%s: ", get_action_name(action_id).c_str()); mvwprintz(w_help, i + 8, 52, col, "%s", get_desc(action_id).c_str()); } wrefresh(w_help); refresh(); // In addition to the modifiable hotkeys, we also check for hardcoded // keys, e.g. '+', '-', '=', in order to prevent the user from // entering an unrecoverable state. const std::string action = ctxt.handle_input(); const long raw_input_char = ctxt.get_raw_input().get_first_input(); if (action == "ADD_LOCAL" || raw_input_char == '+') { status = s_add; } else if (action == "ADD_GLOBAL" || raw_input_char == '=') { status = s_add_global; } else if (action == "REMOVE" || raw_input_char == '-') { status = s_remove; } else if (action == "ANY_INPUT") { const size_t hotkey_index = hotkeys.find_first_of(raw_input_char); if (status == s_show || hotkey_index == std::string::npos ) { continue; } const size_t action_index = hotkey_index + scroll_offset; if( action_index >= org_registered_actions.size() ) { continue; } const std::string &action_id = org_registered_actions[action_index]; // Check if this entry is local or global. bool is_local = false; inp_mngr.get_action_attributes(action_id, category, &is_local); const std::string name = get_action_name(action_id); if (status == s_remove && (!OPTIONS["QUERY_KEYBIND_REMOVAL"] || query_yn(_("Clear keys for %s?"), name.c_str()))) { // If it's global, reset the global actions. std::string category_to_access = category; if (!is_local) { category_to_access = default_context_id; } inp_mngr.remove_input_for_action(action_id, category_to_access); changed = true; } else if (status == s_add_global && is_local) { // Disallow adding global actions to an action that already has a local defined. popup(_("There are already local keybindings defined for this action, please remove them first.")); } else if (status == s_add || status == s_add_global) { const long newbind = popup_getkey(_("New key for %s:"), name.c_str()); const input_event new_event(newbind, CATA_INPUT_KEYBOARD); const std::string conflicts = get_conflicts(new_event); const bool has_conflicts = !conflicts.empty(); bool resolve_conflicts = false; if (has_conflicts) { resolve_conflicts = query_yn( _("This key conflicts with %s. Remove this key from the conflicting command(s), and continue?"), conflicts.c_str()); } if (!has_conflicts || resolve_conflicts) { if (resolve_conflicts) { clear_conflicting_keybindings(new_event); } // We might be adding a local or global action. std::string category_to_access = category; if (status == s_add_global) { category_to_access = default_context_id; } inp_mngr.add_input_for_action(action_id, category_to_access, new_event); changed = true; } } status = s_show; } else if (action == "DOWN") { if (scroll_offset < org_registered_actions.size() - display_height) { scroll_offset++; } } else if (action == "UP") { if (scroll_offset > 0) { scroll_offset--; } } else if (action == "PAGE_DOWN") { if( scroll_offset + display_height < org_registered_actions.size() ) { scroll_offset += std::min(display_height, org_registered_actions.size() - display_height - scroll_offset); } else if( org_registered_actions.size() > display_height ) { scroll_offset = 0; } } else if( action == "PAGE_UP" ) { if( scroll_offset >= display_height ) { scroll_offset -= display_height; } else if( scroll_offset > 0 ) { scroll_offset = 0; } else if( org_registered_actions.size() > display_height ) { scroll_offset = org_registered_actions.size() - display_height; } } else if (action == "QUIT") { if (status != s_show) { status = s_show; } else { break; } } else if (action == "HELP_KEYBINDINGS") { // update available hotkeys in case they've changed hotkeys = ctxt.get_available_single_char_hotkeys(display_help_hotkeys); } } if (changed && query_yn(_("Save changes?"))) { try { inp_mngr.save(); } catch(std::exception &err) { popup(_("saving keybindings failed: %s"), err.what()); } catch(std::string &err) { popup(_("saving keybindings failed: %s"), err.c_str()); } } else if(changed) { inp_mngr.action_contexts.swap(old_action_contexts); } werase(w_help); wrefresh(w_help); delwin(w_help); }
void game::show_options() { std::map<std::string, cOpt> OPTIONS_OLD = OPTIONS; const int iTooltipHeight = 3; const int iContentHeight = FULL_SCREEN_HEIGHT-3-iTooltipHeight; const int iOffsetX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0; const int iOffsetY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 0; std::map<int, bool> mapLines; mapLines[3] = true; mapLines[60] = true; //mapLines[68] = true; WINDOW* w_options_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); WINDOW* w_options_tooltip = newwin(iTooltipHeight, FULL_SCREEN_WIDTH - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW* w_options_header = newwin(1, FULL_SCREEN_WIDTH - 2, 1 + iTooltipHeight + iOffsetY, 1 + iOffsetX); WINDOW* w_options = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX); wborder(w_options_border, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX); mvwputch(w_options_border, 4, 0, c_ltgray, LINE_XXXO); // |- mvwputch(w_options_border, 4, 79, c_ltgray, LINE_XOXX); // -| for (std::map<int, bool>::iterator iter = mapLines.begin(); iter != mapLines.end(); ++iter) { mvwputch(w_options_border, FULL_SCREEN_HEIGHT-1, iter->first + 1, c_ltgray, LINE_XXOX); // _|_ } mvwprintz(w_options_border, 0, 36, c_ltred, _(" OPTIONS ")); wrefresh(w_options_border); for (int i = 0; i < 78; i++) { if (mapLines[i]) { mvwputch(w_options_header, 0, i, c_ltgray, LINE_OXXX); } else { mvwputch(w_options_header, 0, i, c_ltgray, LINE_OXOX); // Draw header line } } //mvwprintz(w_options_header, 3, 0, c_white, "#"); //mvwprintz(w_options_header, 3, 7, c_white, _("Option")); //mvwprintz(w_options_header, 3, 52, c_white, _("Value")); wrefresh(w_options_header); int iCurrentPage = 0; int iCurrentLine = 0; int iStartPos = 0; bool bStuffChanged = false; char ch = ' '; std::stringstream sTemp; do { //Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { if (mapLines[j]) { mvwputch(w_options, i, j, c_ltgray, LINE_XOXO); } else { mvwputch(w_options, i, j, c_black, ' '); } if (i < iTooltipHeight) { mvwputch(w_options_tooltip, i, j, c_black, ' '); } } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, mPageItems[iCurrentPage].size()); //Draw options for (int i = iStartPos; i < iStartPos + ((iContentHeight > mPageItems[iCurrentPage].size()) ? mPageItems[iCurrentPage].size() : iContentHeight); i++) { nc_color cLineColor = c_ltgreen; sTemp.str(""); sTemp << i + 1; mvwprintz(w_options, i - iStartPos, 0, c_white, sTemp.str().c_str()); mvwprintz(w_options, i - iStartPos, 4, c_white, ""); if (iCurrentLine == i) { wprintz(w_options, c_yellow, ">> "); } else { wprintz(w_options, c_yellow, " "); } wprintz(w_options, c_white, "%s", (OPTIONS[mPageItems[iCurrentPage][i]].getMenuText()).c_str()); if (OPTIONS[mPageItems[iCurrentPage][i]].getValue() == "false") { cLineColor = c_ltred; } mvwprintz(w_options, i - iStartPos, 62, (iCurrentLine == i) ? hilite(cLineColor) : cLineColor, "%s", (OPTIONS[mPageItems[iCurrentPage][i]].getName()).c_str()); } //Draw Scrollbar draw_scrollbar(w_options_border, iCurrentLine, iContentHeight, mPageItems[iCurrentPage].size(), 5); //Draw Tabs mvwprintz(w_options_header, 0, 7, c_white, ""); for (int i = 0; i < vPages.size(); i++) { if (mPageItems[i].size() > 0) { //skip empty pages wprintz(w_options_header, c_white, "["); wprintz(w_options_header, (iCurrentPage == i) ? hilite(c_ltgreen) : c_ltgreen, (vPages[i].second).c_str()); wprintz(w_options_header, c_white, "]"); wputch(w_options_header, c_white, LINE_OXOX); } } wrefresh(w_options_header); fold_and_print(w_options_tooltip, 0, 0, 78, c_white, "%s", (OPTIONS[mPageItems[iCurrentPage][iCurrentLine]].getTooltip() + " #" + OPTIONS[mPageItems[iCurrentPage][iCurrentLine]].getDefaultText()).c_str()); wrefresh(w_options_tooltip); wrefresh(w_options); ch = input(); if (mPageItems[iCurrentPage].size() > 0 || ch == '\t') { switch(ch) { case 'j': //move down iCurrentLine++; if (iCurrentLine >= mPageItems[iCurrentPage].size()) { iCurrentLine = 0; } break; case 'k': //move up iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = mPageItems[iCurrentPage].size()-1; } break; case 'l': //set to prev value OPTIONS[mPageItems[iCurrentPage][iCurrentLine]].setNext(); bStuffChanged = true; break; case 'h': //set to next value OPTIONS[mPageItems[iCurrentPage][iCurrentLine]].setPrev(); bStuffChanged = true; break; case '>': case '\t': //Switch to next Page iCurrentLine = 0; do { //skip empty pages iCurrentPage++; if (iCurrentPage >= vPages.size()) { iCurrentPage = 0; } } while(mPageItems[iCurrentPage].size() == 0); break; case '<': iCurrentLine = 0; do { //skip empty pages iCurrentPage--; if (iCurrentPage < 0) { iCurrentPage = vPages.size()-1; } } while(mPageItems[iCurrentPage].size() == 0); break; } } } while(ch != 'q' && ch != 'Q' && ch != KEY_ESCAPE); if (bStuffChanged) { if(query_yn(_("Save changes?"))) { save_options(); } else { OPTIONS = OPTIONS_OLD; } } werase(w_options); werase(w_options_border); werase(w_options_header); werase(w_options_tooltip); }
static void menu_setup_stacks_add_redraw(void) { /* if(invoke != 0) { if(invoke==1) { //printf("nameip\n"); char* name = get_keyboard_buffer(); my_free(new_device_class->name); new_device_class->name=my_malloc(strlen(name)+1); strcpy(new_device_class->name, name); } else if(invoke==2) { uint8_t ch = get_keyboard_number(); if((ch > 0) &&(ch <= PRE_ALLOCATE)) { new_device_class->channels = ch; } } else if(invoke>2) { if(invoke%2==1) { char* name = get_keyboard_buffer(); my_free(new_device_class->channel_names[(invoke-2)>>1]); new_device_class->channel_names[(invoke-2)>>1]=my_malloc(strlen(name)+1); strcpy(new_device_class->channel_names[(invoke-2)>>1], name); } else { uint8_t def = get_keyboard_number(); new_device_class->channel_defaults[(invoke-3)>>1] = def; } } invoke=0; } */ // if(redraw) // { clearDisplay(); // clear_buttons(); draw_filledRect(0,0,LCD_WIDTH,35,155,100,100); draw_filledCircle(17,17,15,40,80,40); draw_text_8x6(7,10,"Back",255,100,100); uint16_t text_width = get_text_width_16pt("Add Stack"); draw_text_16pt((LCD_WIDTH-text_width)>>1,9, "Add Stack", 200,200,255); init_lineitems(); draw_lineitem("Name",""); draw_scrollbar(); draw_button_h(257,45,52,42,"^",155,0,0,0,255,0); draw_button_h(257,92,52,42,"Edit",155,0,0,0,255,0); draw_button_h(257,139,52,42,"Save",155,0,0,0,255,0); draw_button_h(257,186,52,42,"v",155,0,0,0,255,0); }
void construction_menu() { static bool hide_unconstructable = false; // only display constructions the player can theoretically perform std::vector<std::string> available; load_available_constructions( available, hide_unconstructable ); if(available.empty()) { popup(_("You can not construct anything here.")); return; } int iMaxY = TERMY; if (available.size() + 2 < iMaxY) { iMaxY = available.size() + 2; } if (iMaxY < FULL_SCREEN_HEIGHT) { iMaxY = FULL_SCREEN_HEIGHT; } WINDOW *w_con = newwin( iMaxY, FULL_SCREEN_WIDTH, (TERMY > iMaxY) ? (TERMY - iMaxY) / 2 : 0, (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0 ); draw_border(w_con); mvwprintz(w_con, 0, 8, c_ltred, _(" Construction ")); mvwputch(w_con, 0, 30, c_ltgray, LINE_OXXX); mvwputch(w_con, iMaxY - 1, 30, c_ltgray, LINE_XXOX); for( int i = 1; i < iMaxY - 1; ++i ) { mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); } wrefresh(w_con); bool update_info = true; int select = 0; int chosen = 0; long ch; bool exit = false; inventory total_inv = g->crafting_inventory(&(g->u)); do { // Erase existing list of constructions for( int i = 1; i < iMaxY - 1; i++ ) { for( int j = 1; j < 30; j++ ) { mvwputch(w_con, i, j, c_black, ' '); } } // Determine where in the master list to start printing //int offset = select - 11; int offset = 0; if (select >= iMaxY - 2) { offset = select - iMaxY + 3; } // Print the constructions between offset and max (or how many will fit) for (int i = 0; i < iMaxY - 2 && (i + offset) < available.size(); i++) { int current = i + offset; nc_color col = ( player_can_build(g->u, total_inv, available[current]) && can_construct( available[current] ) ) ? c_white : c_dkgray; if (current == select) { col = hilite(col); } // print construction name with limited length. // limit(28) = 30(column len) - 2(letter + ' '). // If we run out of hotkeys, just stop assigning them. mvwprintz(w_con, 1 + i, 1, col, "%c %s", (current < hotkeys.size()) ? hotkeys[current] : ' ', utf8_substr(available[current].c_str(), 0, 27).c_str()); } if (update_info) { update_info = false; std::string current_desc = available[select]; // Clear out lines for tools & materials for (int i = 1; i < iMaxY - 1; i++) { for (int j = 31; j < 79; j++) { mvwputch(w_con, i, j, c_black, ' '); } } // Print instructions for toggling recipe hiding. mvwprintz(w_con, 1, 31, c_white, "%s", _("Press ';' to toggle unavailable constructions.")); // Print consruction name mvwprintz(w_con, 2, 31, c_white, "%s", current_desc.c_str()); // Print stages and their requirement int posx = 33, posy = 2; std::vector<construction *> options = constructions_by_desc(current_desc); for( unsigned i = 0; i < options.size(); ++i) { construction *current_con = options[i]; if( hide_unconstructable && !can_construct(current_con) ) { continue; } nc_color color_stage = c_white; // display required skill and difficulty int pskill = g->u.skillLevel(current_con->skill); int diff = (current_con->difficulty > 0) ? current_con->difficulty : 0; posy++; mvwprintz(w_con, posy, 31, c_white, _("Skill: %s"), Skill::skill(current_con->skill)->name().c_str()); posy++; mvwprintz(w_con, posy, 31, (pskill >= diff ? c_white : c_red), _("Difficulty: %d"), diff); // display required terrain if (current_con->pre_terrain != "") { posy++; if (current_con->pre_is_furniture) { mvwprintz(w_con, posy, 31, color_stage, _("Replaces: %s"), furnmap[current_con->pre_terrain].name.c_str()); } else { mvwprintz(w_con, posy, 31, color_stage, _("Replaces: %s"), termap[current_con->pre_terrain].name.c_str()); } } // display result if (current_con->post_terrain != "") { posy++; if (current_con->post_is_furniture) { mvwprintz(w_con, posy, 31, color_stage, _("Result: %s"), furnmap[current_con->post_terrain].name.c_str()); } else { mvwprintz(w_con, posy, 31, color_stage, _("Result: %s"), termap[current_con->post_terrain].name.c_str()); } } // display time needed posy++; mvwprintz(w_con, posy, 31, color_stage, _("Time: %1d minutes"), current_con->time); // Print tools std::vector<bool> has_tool; posy++; posx = 33; for (int i = 0; i < current_con->tools.size(); i++) { has_tool.push_back(false); mvwprintz(w_con, posy, posx - 2, c_white, ">"); for (unsigned j = 0; j < current_con->tools[i].size(); j++) { itype_id tool = current_con->tools[i][j].type; nc_color col = c_red; if (total_inv.has_tools(tool, 1)) { has_tool[i] = true; col = c_green; } int length = utf8_width(item_controller->find_template(tool)->name.c_str()); if( posx + length > FULL_SCREEN_WIDTH - 1 ) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, item_controller->find_template(tool)->name.c_str()); posx += length + 1; // + 1 for an empty space if (j < current_con->tools[i].size() - 1) { // "OR" if there's more if (posx > FULL_SCREEN_WIDTH - 3) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += utf8_width(_("OR")) + 1; } } posy ++; posx = 33; } // Print components posx = 33; std::vector<bool> has_component; for( size_t i = 0; i < current_con->components.size(); ++i ) { has_component.push_back(false); mvwprintz(w_con, posy, posx - 2, c_white, ">"); for( unsigned j = 0; j < current_con->components[i].size(); j++ ) { nc_color col = c_red; component comp = current_con->components[i][j]; if( ( item_controller->find_template(comp.type)->is_ammo() && total_inv.has_charges(comp.type, comp.count)) || (!item_controller->find_template(comp.type)->is_ammo() && total_inv.has_components(comp.type, comp.count)) ) { has_component[i] = true; col = c_green; } int length = utf8_width(item_controller->find_template(comp.type)->name.c_str()); if (posx + length > FULL_SCREEN_WIDTH - 1) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, col, "%s x%d", item_controller->find_template(comp.type)->name.c_str(), comp.count); posx += length + 3; // + 2 for " x", + 1 for an empty space // Add more space for the length of the count if (comp.count < 10) { posx++; } else if (comp.count < 100) { posx += 2; } else { posx += 3; } if (j < current_con->components[i].size() - 1) { // "OR" if there's more if (posx > FULL_SCREEN_WIDTH - 3) { posy++; posx = 33; } mvwprintz(w_con, posy, posx, c_white, _("OR")); posx += utf8_width(_("OR")) + 1; } } posy ++; posx = 33; } } } // Finished updating //Draw Scrollbar. //Doing it here lets us refresh the entire window all at once. draw_scrollbar(w_con, select, iMaxY - 2, available.size(), 1); ch = getch(); switch (ch) { case KEY_DOWN: update_info = true; if (select < available.size() - 1) { select++; } else { select = 0; } break; case KEY_UP: update_info = true; if (select > 0) { select--; } else { select = available.size() - 1; } break; case ' ': case KEY_ESCAPE: case 'q': case 'Q': exit = true; break; case ';': update_info = true; hide_unconstructable = !hide_unconstructable; load_available_constructions( available, hide_unconstructable ); break; case '\n': default: if (ch == '\n') { chosen = select; } else { // Get the index corresponding to the key pressed. chosen = hotkeys.find_first_of( ch ); if( chosen == std::string::npos ) { break; } } if (chosen < available.size()) { if (player_can_build(g->u, total_inv, available[chosen])) { place_construction(available[chosen]); exit = true; } else { popup(_("You can't build that!")); select = chosen; for (int i = 1; i < iMaxY - 1; i++) { mvwputch(w_con, i, 30, c_ltgray, LINE_XOXO); } update_info = true; } } break; } } while (!exit); for (int i = iMaxY - FULL_SCREEN_HEIGHT; i <= iMaxY; ++i) { for (int j = TERRAIN_WINDOW_WIDTH; j <= FULL_SCREEN_WIDTH; ++j) { mvwputch(w_con, i, j, c_black, ' '); } } wrefresh(w_con); g->refresh_all(); }