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 WINDOW *wBio = newwin( HEIGHT, WIDTH, START_Y, START_X ); WINDOW_PTR wBioptr( wBio ); 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 WINDOW *w_description = newwin( LIST_HEIGHT, DESCRIPTION_WIDTH, DESCRIPTION_START_Y, DESCRIPTION_START_X ); WINDOW_PTR w_descriptionptr( w_description ); // Title window const int TITLE_START_Y = START_Y + 1; const int HEADER_LINE_Y = TITLE_HEIGHT + TITLE_TAB_HEIGHT + 1; WINDOW *w_title = newwin( TITLE_HEIGHT, WIDTH - 2, TITLE_START_Y, START_X + 1 ); WINDOW_PTR w_titleptr( w_title ); const int TAB_START_Y = TITLE_START_Y + 2; //w_tabs is the tab bar for passive and active bionic groups WINDOW *w_tabs = newwin( TITLE_TAB_HEIGHT, WIDTH - 2, TAB_START_Y, START_X + 1 ); WINDOW_PTR w_tabsptr( w_tabs ); 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, ( tab_mode == TAB_ACTIVE ? ( int )active.size() : ( int )passive.size() ) - LIST_HEIGHT ); 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 ); // -| 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, WIDTH - 3, c_ltgray, 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, "%s", desc.c_str() ); // draw bodyparts if( is_highlighted && menu_mode != EXAMINING ) { 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; const std::string 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 ); for( int i = 0; i < num_bp; ++i ) { mvwprintz( wBio, i + list_start_y, pos_x, bionic_info( bio_id ).occupied_bodyparts.count( bp_aBodyPart[i] ) > 0 ? c_yellow : c_ltgray, "%s", bps[i].c_str() ); } } } } 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( menu_mode == REASSIGNING ) { menu_mode = ACTIVATING; 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." ), bionic_info( tmp->id ).name.c_str() ); wrefresh( wBio ); if( newch == ch || newch == ' ' || newch == KEY_ESCAPE ) { 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 == "DOWN" ) { redraw = true; if( static_cast<size_t>( cursor ) < current_bionic_list->size() - 1 ) { cursor++; } if( scroll_position < max_scroll_position && cursor - scroll_position > LIST_HEIGHT - half_list_view_location ) { scroll_position++; } } else if( action == "UP" ) { redraw = true; if( cursor > 0 ) { cursor--; } if( scroll_position > 0 && cursor - scroll_position < half_list_view_location ) { scroll_position--; } } 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 std::string &bio_id = tmp->id; const bionic_data &bio_data = bionic_info( bio_id ); 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 ); } // update message log and the menu g->refresh_all(); redraw = true; 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 test_pattern(int iCurrentPage, int iCurrentLine) { std::vector<std::string> vMatchingItems; std::string sItemName = ""; if (vAutoPickupRules[iCurrentPage][iCurrentLine].sRule == "") { return; } //Loop through all itemfactory items //TODO: somehow generate damaged, fitting or container items for (int i = 0; i < standard_itype_ids.size(); i++) { sItemName = item_controller->find_template(standard_itype_ids[i])->name; if (vAutoPickupRules[iCurrentPage][iCurrentLine].bActive && auto_pickup_match(sItemName, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule)) { vMatchingItems.push_back(sItemName); } } const int iOffsetX = 15 + ((TERMX > FULL_SCREEN_WIDTH) ? (TERMX-FULL_SCREEN_WIDTH)/2 : 0); const int iOffsetY = 5 + ((TERMY > FULL_SCREEN_HEIGHT) ? (TERMY-FULL_SCREEN_HEIGHT)/2 : 0); int iStartPos = 0; const int iContentHeight = FULL_SCREEN_HEIGHT - 8; const int iContentWidth = FULL_SCREEN_WIDTH - 30; char ch; std::stringstream sTemp; WINDOW* w_test_rule_border = newwin(iContentHeight + 2, iContentWidth, iOffsetY, iOffsetX); WINDOW* w_test_rule_content = newwin(iContentHeight, iContentWidth - 2, 1 + iOffsetY, 1 + iOffsetX); wborder(w_test_rule_border, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX); int nmatch = vMatchingItems.size(); std::string buf = string_format(ngettext("%1$d item matches: %2$s", "%1$d items match: %2$s", nmatch), nmatch, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule.c_str()); mvwprintz(w_test_rule_border, 0, iContentWidth/2 - utf8_width(buf.c_str())/2, hilite(c_white), buf.c_str()); mvwprintz(w_test_rule_border, iContentHeight + 1, 1, red_background(c_white), _("Won't display damaged, fits and can/bottle items")); wrefresh(w_test_rule_border); iCurrentLine = 0; do { // Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { mvwputch(w_test_rule_content, i, j, c_black, ' '); } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, vMatchingItems.size()); // display auto pickup for (int i = iStartPos; i < vMatchingItems.size(); i++) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > vMatchingItems.size()) ? vMatchingItems.size() : iContentHeight)) { nc_color cLineColor = c_white; sTemp.str(""); sTemp << i + 1; mvwprintz(w_test_rule_content, i - iStartPos, 0, cLineColor, sTemp.str().c_str()); mvwprintz(w_test_rule_content, i - iStartPos, 4, cLineColor, ""); if (iCurrentLine == i) { wprintz(w_test_rule_content, c_yellow, ">> "); } else { wprintz(w_test_rule_content, c_yellow, " "); } wprintz(w_test_rule_content, (iCurrentLine == i) ? hilite(cLineColor) : cLineColor, vMatchingItems[i].c_str()); } } wrefresh(w_test_rule_content); ch = (char)input(); switch(ch) { case 'j': //move down iCurrentLine++; if (iCurrentLine >= vMatchingItems.size()) { iCurrentLine = 0; } break; case 'k': //move up iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = vMatchingItems.size()-1; } break; } } while(ch == 'j' || ch == 'k'); werase(w_test_rule_border); werase(w_test_rule_content); }
std::string string_input_popup(std::string title, int max_length, std::string input) { std::string ret = input; int titlesize = utf8_width(title.c_str()); int startx = titlesize + 2; int iPopupWidth = (max_length == 0) ? FULL_SCREEN_WIDTH : max_length + titlesize + 4; if (iPopupWidth > FULL_SCREEN_WIDTH) { iPopupWidth = FULL_SCREEN_WIDTH; max_length = FULL_SCREEN_WIDTH - titlesize - 4; } WINDOW *w = newwin(3, iPopupWidth, (TERMY-3)/2, ((TERMX > iPopupWidth) ? (TERMX-iPopupWidth)/2 : 0)); wborder(w, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); std::string underline = ""; for (int i = startx ; i < iPopupWidth-1; i++) underline.push_back('_'); mvwprintz(w, 1, 1, c_ltred, "%s", title.c_str()); mvwprintz(w, 1, startx, c_ltgray, "%s", underline.c_str()); if (input != "") mvwprintz(w, 1, startx, c_magenta, "%s", input.c_str()); int posx = startx + utf8_width(input.c_str()); mvwputch(w, 1, posx, h_ltgray, '_'); do { wrefresh(w); long ch = getch(); if (ch == 27) { // Escape werase(w); wrefresh(w); delwin(w); refresh(); return ""; } else if (ch == '\n') { werase(w); wrefresh(w); delwin(w); refresh(); return ret; } else if (ch == KEY_BACKSPACE || ch == 127) { // Move the cursor back and re-draw it if (ret.size() > 0) { //erease utf8 character TODO: make a function while(ret.size()>0 && ((unsigned char)ret[ret.size()-1])>=128 && ((unsigned char)ret[(int)ret.size()-1])<=191) { ret.erase(ret.size()-1); } ret.erase(ret.size()-1); } } else if(ch==KEY_F(2)) { std::string tmp = get_input_string_from_file(); int tmplen = utf8_width(tmp.c_str()); if(tmplen>0 && (tmplen+utf8_width(ret.c_str())<=max_length||max_length==0)) { ret.append(tmp); } } //experimental unicode input else { std::string tmp = utf32_to_utf8(ch); int tmplen = utf8_width(tmp.c_str()); if(tmplen>0 && (tmplen+utf8_width(ret.c_str())<=max_length||max_length==0)) { ret.append(tmp); } } mvwprintz(w, 1, startx, c_ltgray, "%s", underline.c_str()); mvwprintz(w, 1, startx, c_ltgray, "%s", ret.c_str()); wprintz(w, h_ltgray, "_"); } while (true); }
/* * This is intended to be a generic tool to select strings from a list * of strings. * * Args lsel -- the items as well as the answer are contained in this list * flags -- There is some inconsistent flags usage. Notice that the * flag SFL_ALLOW_LISTMODE is a flag passed in the flags * argument whereas the flag SFL_NOSELECT is a per item * (that is, per LIST_SEL_S) flag. * title -- passed to conf_scroll_screen * pdesc -- passed to conf_scroll_screen * help -- passed to conf_scroll_screen * helptitle -- passed to conf_scroll_screen * * You have screen width - 4 columns to work with. If you want to overflow to * a second (or third or fourth) line for an item just send another item * in the list but with the SFL_NOSELECT flag set. Only the selectable lines * will be highlighted, which is kind of a crock, but it looked like a lot * of work to fix that. * * Returns 0 on successful choice * -1 if cancelled */ int select_from_list_screen(LIST_SEL_S *lsel, long unsigned int flags, char *title, char *pdesc, HelpType help, char *htitle, LIST_SEL_S *starting_val) { CONF_S *ctmp = NULL, *first_line = NULL; OPT_SCREEN_S screen; int j, lv, ret = -1; LIST_SEL_S *p; char *display; size_t l; ScreenMode listmode = SingleMode; int (*tool)(struct pine *, int, CONF_S **, unsigned); if(!lsel) return(ret); /* find longest value's length */ for(lv = 0, p = lsel; p; p = p->next){ if(!(p->flags & SFL_NOSELECT)){ display = p->display_item ? p->display_item : p->item ? p->item : ""; if(lv < (j = utf8_width(display))) lv = j; } } lv = MIN(lv, ps_global->ttyo->screen_cols - 4); tool = (flags & SFL_CTRLC) ? select_from_list_tool_allow_noselections : select_from_list_tool; /* * Convert the passed in list to conf_scroll lines. */ if(flags & SFL_ALLOW_LISTMODE){ if(flags & SFL_ONLY_LISTMODE) {assert(flags & SFL_STARTIN_LISTMODE);} for(p = lsel; p; p = p->next){ display = p->display_item ? p->display_item : p->item ? p->item : ""; new_confline(&ctmp); if(!first_line && !(p->flags & SFL_NOSELECT)) first_line = ctmp; if(!first_line && !(p->flags & SFL_NOSELECT)) if(!starting_val || (starting_val == p)) first_line = ctmp; /* generous allocation */ l = lv + 4 + strlen(display); ctmp->value = (char *) fs_get((l + 1) * sizeof(char)); utf8_snprintf(ctmp->value, l+1, " %-*.*w", lv, lv, display); ctmp->value[l] = '\0'; ctmp->d.l.lsel = p; ctmp->d.l.listmode = &listmode; if(flags & SFL_ONLY_LISTMODE){ if(flags & SFL_CTRLC) ctmp->keymenu = &sel_from_list_olm_ctrlc; else ctmp->keymenu = &sel_from_list_olm; } else{ if(flags & SFL_CTRLC) ctmp->keymenu = &sel_from_list_sm_ctrlc; else ctmp->keymenu = &sel_from_list_sm; } ctmp->help = help; ctmp->help_title = htitle; ctmp->tool = tool; ctmp->flags = CF_STARTITEM | ((p->flags & SFL_NOSELECT) ? CF_NOSELECT : 0); } } else{ assert(!(flags & SFL_ONLY_LISTMODE)); assert(!(flags & SFL_STARTIN_LISTMODE)); for(p = lsel; p; p = p->next){ display = p->display_item ? p->display_item : p->item ? p->item : ""; new_confline(&ctmp); if(!first_line && !(p->flags & SFL_NOSELECT)) if(!starting_val || (starting_val == p)) first_line = ctmp; l = lv + strlen(display); ctmp->value = (char *) fs_get((l + 1) * sizeof(char)); utf8_snprintf(ctmp->value, l+1, "%-*.*w", lv, lv, display); ctmp->value[l] = '\0'; ctmp->d.l.lsel = p; ctmp->d.l.listmode = &listmode; if(flags & SFL_CTRLC) ctmp->keymenu = &sel_from_list_ctrlc; else ctmp->keymenu = &sel_from_list; ctmp->help = help; ctmp->help_title = htitle; ctmp->tool = tool; ctmp->flags = CF_STARTITEM | ((p->flags & SFL_NOSELECT) ? CF_NOSELECT : 0); ctmp->valoffset = 4; } } /* just convert to start in listmode after the fact, easier that way */ if(flags & SFL_STARTIN_LISTMODE){ listmode = ListMode; for(ctmp = first_line; ctmp; ctmp = next_confline(ctmp)) if(!(ctmp->flags & CF_NOSELECT) && ctmp->value){ ctmp->value[0] = '['; ctmp->value[1] = ctmp->d.l.lsel->selected ? 'X' : SPACE; ctmp->value[2] = ']'; if(flags & SFL_ONLY_LISTMODE){ if(flags & SFL_CTRLC) ctmp->keymenu = &sel_from_list_olm_ctrlc; else ctmp->keymenu = &sel_from_list_olm; } else{ if(flags & SFL_CTRLC) ctmp->keymenu = &sel_from_list_lm_ctrlc; else ctmp->keymenu = &sel_from_list_lm; } } } memset(&screen, 0, sizeof(screen)); switch(conf_scroll_screen(ps_global, &screen, first_line, title, pdesc, 0)){ case 1: ret = 0; break; default: break; } ps_global->mangled_screen = 1; return(ret); }
size_t inventory_column::get_entry_width( const inventory_entry &entry ) const { return get_entry_indent( entry ) + utf8_width( get_entry_text( entry ), true ); }
/** * Calculate sizes, populate arrays, initialize window */ void uimenu::setup() { bool w_auto = (w_width == -1 || w_width == -2 ); bool w_autofold = ( w_width == -2); // Space for a line between text and entries. Only needed if there is actually text. const int text_separator_line = text.empty() ? 0 : 1; if ( w_auto ) { w_width = 4; if ( !title.empty() ) { w_width = title.size() + 5; } } bool h_auto = (w_height == -1); if ( h_auto ) { w_height = 4; } if ( desc_enabled && !(w_auto && h_auto) ) { desc_enabled = false; // give up debugmsg( "desc_enabled without w_auto and h_auto (h: %d, w: %d)", static_cast<int>( h_auto ), static_cast<int>( w_auto ) ); } max_entry_len = 0; max_column_len = 0; std::vector<int> autoassign; int pad = pad_left + pad_right + 2; int descwidth_final = 0; // for description width guard for ( size_t i = 0; i < entries.size(); i++ ) { int txtwidth = utf8_width( remove_color_tags(entries[i].txt) ); int ctxtwidth = utf8_width( remove_color_tags(entries[i].ctxt) ); if ( txtwidth > max_entry_len ) { max_entry_len = txtwidth; } if ( ctxtwidth > max_column_len ) { max_column_len = ctxtwidth; } int clen = (ctxtwidth > 0) ? ctxtwidth + 2: 0; if(entries[ i ].enabled) { if( entries[ i ].hotkey > 0 ) { keymap[ entries[ i ].hotkey ] = i; } else if ( entries[ i ].hotkey == -1 && i < 100 ) { autoassign.push_back(i); } if ( entries[ i ].retval == -1 ) { entries[ i ].retval = i; } if ( w_auto && w_width < txtwidth + pad + 4 + clen ) { w_width = txtwidth + pad + 4 + clen; } } else { if ( w_auto && w_width < txtwidth + pad + 4 + clen ) { w_width = txtwidth + pad + 4 + clen; // @todo: or +5 if header } } if ( desc_enabled ) { const int min_width = std::min( TERMX, std::max( w_width, descwidth_final ) ) - 4; const int max_width = TERMX - 4; int descwidth = find_minimum_fold_width( entries[i].desc, desc_lines, min_width, max_width ); descwidth += 4; // 2x border + 2x ' ' pad if ( descwidth_final < descwidth ) { descwidth_final = descwidth; } } if ( entries[ i ].text_color == c_red_red ) { entries[ i ].text_color = text_color; } fentries.push_back( i ); } size_t next_free_hotkey = 0; for( auto it = autoassign.begin(); it != autoassign.end() && next_free_hotkey < hotkeys.size(); ++it ) { while( next_free_hotkey < hotkeys.size() ) { const int setkey = hotkeys[next_free_hotkey]; next_free_hotkey++; if( keymap.count( setkey ) == 0 ) { entries[*it].hotkey = setkey; keymap[setkey] = *it; break; } } } if (desc_enabled) { if (descwidth_final > TERMX) { desc_enabled = false; // give up debugmsg("description would exceed terminal width (%d vs %d available)", descwidth_final, TERMX); } else if (descwidth_final > w_width) { w_width = descwidth_final; } } if(!text.empty() ) { int twidth = utf8_width( remove_color_tags(text) ); bool formattxt = true; int realtextwidth = 0; if ( textwidth == -1 ) { if ( w_autofold || !w_auto ) { realtextwidth = w_width - 4; } else { realtextwidth = twidth; if ( twidth + 4 > w_width ) { if ( realtextwidth + 4 > TERMX ) { realtextwidth = TERMX - 4; } textformatted = foldstring(text, realtextwidth); formattxt = false; realtextwidth = 10; for (auto &l : textformatted) { const int w = utf8_width( remove_color_tags( l ) ); if ( w > realtextwidth ) { realtextwidth = w; } } if ( realtextwidth + 4 > w_width ) { w_width = realtextwidth + 4; } } } } else if ( textwidth != -1 ) { realtextwidth = textwidth; if( realtextwidth + 4 > w_width ) { w_width = realtextwidth + 4; } } if ( formattxt ) { textformatted = foldstring(text, realtextwidth); } } // shrink-to-fit if( desc_enabled ) { desc_lines = 0; for( const uimenu_entry &ent : entries ) { // -2 for borders, -2 for padding desc_lines = std::max<int>( desc_lines, foldstring( ent.desc, w_width - 4 ).size() ); } if( desc_lines <= 0 ) { desc_enabled = false; } } if( w_auto && w_width > TERMX ) { w_width = TERMX; } vmax = entries.size(); int additional_lines = 2 + text_separator_line + // add two for top & bottom borders static_cast<int>( textformatted.size() ); if( desc_enabled ) { additional_lines += desc_lines + 1; // add one for description separator line } if (h_auto) { w_height = vmax + additional_lines; } if ( w_height > TERMY ) { w_height = TERMY; } if( vmax + additional_lines > w_height ) { vmax = w_height - additional_lines; if( vmax < 1 ) { if( textformatted.empty() ) { popup( "Can't display menu options, 0 %d available screen rows are occupied\nThis is probably a bug.\n", TERMY ); } else { popup( "Can't display menu options, %lu %d available screen rows are occupied by\n'%s\n(snip)\n%s'\nThis is probably a bug.\n", static_cast<unsigned long>( textformatted.size() ), TERMY, textformatted[ 0 ].c_str(), textformatted[ textformatted.size() - 1 ].c_str() ); } } } if (w_x == -1) { w_x = int((TERMX - w_width) / 2); } if (w_y == -1) { w_y = int((TERMY - w_height) / 2); } if ( scrollbar_side == -1 ) { scrollbar_side = ( pad_left > 0 ? 1 : 0 ); } if ( (int)entries.size() <= vmax ) { scrollbar_auto = false; } window = catacurses::newwin( w_height, w_width, w_y, w_x ); fselected = selected; if(fselected < 0) { fselected = selected = 0; } else if(fselected >= static_cast<int>(entries.size())) { fselected = selected = static_cast<int>(entries.size()) - 1; } if(!entries.empty() && !entries[fselected].enabled) { for(size_t i = 0; i < entries.size(); ++i) { if(entries[i].enabled) { fselected = selected = i; break; } } } started = true; }
int minesweeper_game::start_game() { const int iCenterX = (TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0; const int iCenterY = (TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0; WINDOW *w_minesweeper_border = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iCenterY, iCenterX); WINDOW_PTR w_minesweeper_borderptr( w_minesweeper_border ); WINDOW *w_minesweeper = newwin(FULL_SCREEN_HEIGHT - 2, FULL_SCREEN_WIDTH - 2, iCenterY + 1, iCenterX + 1); WINDOW_PTR w_minesweeperptr( w_minesweeper ); draw_border(w_minesweeper_border); std::vector<std::string> shortcuts; shortcuts.push_back(_("<n>ew level")); shortcuts.push_back(_("<f>lag")); shortcuts.push_back(_("<q>uit")); int iWidth = 0; for( auto &shortcut : shortcuts ) { if ( iWidth > 0 ) { iWidth += 1; } iWidth += utf8_width(shortcut); } int iPos = FULL_SCREEN_WIDTH - iWidth - 1; for( auto &shortcut : shortcuts ) { shortcut_print(w_minesweeper_border, 0, iPos, c_white, c_ltgreen, shortcut); iPos += utf8_width(shortcut) + 1; } mvwputch(w_minesweeper_border, 0, 2, hilite(c_white), _("Minesweeper")); wrefresh(w_minesweeper_border); input_context ctxt("MINESWEEPER"); ctxt.register_cardinal(); ctxt.register_action("NEW"); ctxt.register_action("FLAG"); ctxt.register_action("CONFIRM"); ctxt.register_action("QUIT"); ctxt.register_action("HELP_KEYBINDINGS"); static const std::array<int, 9> aColors = {{ c_white, c_ltgray, c_cyan, c_blue, c_ltblue, c_green, c_magenta, c_red, c_yellow }}; int iScore = 5; int iPlayerY = 0; int iPlayerX = 0; std::function<void (int, int)> rec_reveal = [&](const int y, const int x) { if ( mLevelReveal[y][x] == unknown || mLevelReveal[y][x] == flag ) { mLevelReveal[y][x] = seen; if ( mLevel[y][x] == 0 ) { const auto circle = closest_tripoints_first( 1, {x, y, 0} ); for( const auto &p : circle ) { if ( p.x >= 0 && p.x < iLevelX && p.y >= 0 && p.y < iLevelY ) { if ( mLevelReveal[p.y][p.x] != seen ) { rec_reveal(p.y, p.x); } } } mvwputch(w_minesweeper, iOffsetY + y, iOffsetX + x, c_black, " "); } else { mvwputch(w_minesweeper, iOffsetY + y, iOffsetX + x, (x == iPlayerX && y == iPlayerY) ? hilite(aColors[mLevel[y][x]]) : aColors[mLevel[y][x]], to_string(mLevel[y][x])); } } }; int iDirY, iDirX; std::string action = "NEW"; do { if (action == "NEW") { new_level(w_minesweeper); iPlayerY = 0; iPlayerX = 0; } wrefresh(w_minesweeper); if (check_win()) { popup_top(_("Congratulations, you won!")); iScore = 30; action = "QUIT"; } else { action = ctxt.handle_input(); } if (ctxt.get_direction(iDirX, iDirY, action)) { if ( iPlayerX + iDirX >= 0 && iPlayerX + iDirX < iLevelX && iPlayerY + iDirY >= 0 && iPlayerY + iDirY < iLevelY ) { std::string sGlyph; nc_color cColor; for ( int i=0; i < 2; i++ ) { cColor = c_white; if ( mLevelReveal[iPlayerY][iPlayerX] == flag ) { sGlyph = "!"; cColor = c_yellow; } else if ( mLevelReveal[iPlayerY][iPlayerX] == seen ) { if ( mLevel[iPlayerY][iPlayerX] == 0 ) { sGlyph = " "; cColor = c_black; } else { sGlyph = to_string(mLevel[iPlayerY][iPlayerX]); cColor = aColors[mLevel[iPlayerY][iPlayerX]]; } } else { sGlyph = '#'; } mvwputch(w_minesweeper, iOffsetY + iPlayerY, iOffsetX + iPlayerX, (i == 0) ? cColor : hilite(cColor), sGlyph.c_str()); if ( i == 0 ) { iPlayerX += iDirX; iPlayerY += iDirY; } } } } else if (action == "FLAG") { if ( mLevelReveal[iPlayerY][iPlayerX] == unknown ) { mLevelReveal[iPlayerY][iPlayerX] = flag; mvwputch(w_minesweeper, iOffsetY + iPlayerY, iOffsetX + iPlayerX, hilite(c_yellow), "!"); } else if ( mLevelReveal[iPlayerY][iPlayerX] == flag ) { mLevelReveal[iPlayerY][iPlayerX] = unknown; mvwputch(w_minesweeper, iOffsetY + iPlayerY, iOffsetX + iPlayerX, hilite(c_white), "#"); } } else if (action == "CONFIRM") { if ( mLevelReveal[iPlayerY][iPlayerX] != seen ) { if ( mLevel[iPlayerY][iPlayerX] == (int)bomb ) { for ( int y = 0; y < iLevelY; y++ ) { for ( int x = 0; x < iLevelX; x++ ) { if (mLevel[y][x] == (int)bomb) { mvwputch(w_minesweeper, iOffsetY + y, iOffsetX + x, hilite(c_red), (mLevelReveal[y][x] == flag) ? "!" : "*" ); } } } wrefresh(w_minesweeper); popup_top(_("Boom, you're dead! Better luck next time.")); action = "QUIT"; } else if ( mLevelReveal[iPlayerY][iPlayerX] == unknown ) { rec_reveal(iPlayerY, iPlayerX); } } } } while (action != "QUIT"); return iScore; }
int worldfactory::show_worldgen_tab_confirm(WINDOW *win, WORLDPTR world) { const int iTooltipHeight = 1; 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; WINDOW *w_confirmation = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX); unsigned namebar_y = 1; unsigned namebar_x = 3 + utf8_width(_("World Name:")); int line = 1; bool noname = false; input_context ctxt("WORLDGEN_CONFIRM_DIALOG"); // Disabled because it conflicts with the "pick random world name" option, // feel free to enable it and change its keybinding in keybindings.json // ctxt.register_action("HELP_KEYBINDINGS"); ctxt.register_action("QUIT"); ctxt.register_action("ANY_INPUT"); ctxt.register_action("NEXT_TAB"); ctxt.register_action("PREV_TAB"); ctxt.register_action("PICK_RANDOM_WORLDNAME"); std::string worldname = world->world_name; do { mvwprintz(w_confirmation, namebar_y, 2, c_white, _("World Name:")); mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________"); fold_and_print(w_confirmation, 3, 2, 76, c_ltgray, _("Press <color_yellow>?</color> to pick a random name for your world.")); fold_and_print(w_confirmation, FULL_SCREEN_HEIGHT / 2 - 2, 2, 76, c_ltgray, _("\ Press <color_yellow>></color> when you are satisfied with the world as it is and are ready \ to continue, or <color_yellow><</color> to go back and review your world.")); if (!noname) { mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "%s", worldname.c_str()); if (line == 1) { wprintz(w_confirmation, h_ltgray, "_"); } } if (noname) { mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________"); noname = false; } wrefresh(win); wrefresh(w_confirmation); refresh(); const std::string action = ctxt.handle_input(); if (action == "NEXT_TAB") { if (worldname.empty()) { mvwprintz(w_confirmation, namebar_y, namebar_x, h_ltgray, _("______NO NAME ENTERED!!!!_____")); noname = true; wrefresh(w_confirmation); if (!query_yn(_("Are you SURE you're finished? World name will be randomly generated."))) { continue; } else { world->world_name = pick_random_name(); if (!valid_worldname(world->world_name)) { continue; } return 1; } } else if (query_yn(_("Are you SURE you're finished?")) && valid_worldname(worldname)) { world->world_name = worldname; werase(w_confirmation); delwin(w_confirmation); return 1; } else { continue; } } else if (action == "PREV_TAB") { world->world_name = worldname; werase(w_confirmation); delwin(w_confirmation); return -1; } else if (action == "PICK_RANDOM_WORLDNAME") { mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________"); world->world_name = worldname = pick_random_name(); } else if (action == "QUIT") { world->world_name = worldname; // cache the current worldname just in case they say No to the exit query return -999; } else if (action == "ANY_INPUT") { const input_event ev = ctxt.get_raw_input(); const long ch = ev.get_first_input(); switch (line) { case 1: { utf8_wrapper wrap(worldname); utf8_wrapper newtext( ev.text ); if( ch == KEY_BACKSPACE ) { if (!wrap.empty()) { wrap.erase(wrap.length() - 1, 1); worldname = wrap.str(); } } else if(ch == KEY_F(2)) { std::string tmp = get_input_string_from_file(); int tmplen = utf8_width(tmp.c_str()); if(tmplen > 0 && tmplen + utf8_width(worldname.c_str()) < 30) { worldname.append(tmp); } } else if( !newtext.empty() && is_char_allowed( newtext.at( 0 ) ) ) { // no emty string, no slash, no backslash, no control sequence wrap.append( newtext ); worldname = wrap.str(); } mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "______________________________ "); mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "%s", worldname.c_str()); wprintz(w_confirmation, h_ltgray, "_"); } break; } } } while (true); return 0; }
/*---------------------------------------------------------------------- Ask a yes/no question in the status line Args: question -- string to prompt user with dflt -- The default answer to the question (should probably be y or n) on_ctrl_C -- Answer returned on ^C help -- Two line help text flags -- Flags to modify behavior WT_FLUSH_IN - Discard pending input. WT_SEQ_SENSITIVE - Caller is sensitive to sequence number changes caused by unsolicited expunges while we're viewing a message. Result: Messes up the status line, returns y, n, dflt, on_ctrl_C, or SEQ_EXCEPTION ---*/ int want_to(char *question, int dflt, int on_ctrl_C, HelpType help, int flags) { char *free_this = NULL, *free_this2 = NULL, *prompt; int rv, width; size_t len; if(!ps_global->ttyo) return(pre_screen_config_want_to(question, dflt, on_ctrl_C)); #ifdef _WINDOWS if (mswin_usedialog ()) { mswin_flush (); switch (mswin_yesno_utf8 (question)) { default: case 0: return (on_ctrl_C); case 1: return ('y'); case 2: return ('n'); } } #endif /*---- One problem with adding the (y/n) here is that shrinking the screen while in radio_buttons() will cause it to get chopped off. It would be better to truncate the question passed in here and leave the full "(y/n) [x] : " on. ----*/ len = strlen(question) + 4; free_this = (char *) fs_get(len); width = utf8_width(question); if(width + 2 < ps_global->ttyo->screen_cols){ snprintf(free_this, len, "%s? ", question); free_this[len-1] = '\0'; prompt = free_this; } else if(width + 1 < ps_global->ttyo->screen_cols){ snprintf(free_this, len, "%s?", question); free_this[len-1] = '\0'; prompt = free_this; } else if(width < ps_global->ttyo->screen_cols){ snprintf(free_this, len, "%s", question); free_this[len-1] = '\0'; prompt = free_this; } else{ free_this2 = (char *) fs_get(len); snprintf(free_this2, len, "%s? ", question); prompt = short_str(free_this2, free_this, len, ps_global->ttyo->screen_cols-1, MidDots); } if(on_ctrl_C == 'n') /* don't ever let cancel == 'n' */ on_ctrl_C = 0; rv = radio_buttons(prompt, (ps_global->ttyo->screen_rows > 4) ? - FOOTER_ROWS(ps_global) : -1, yorn, dflt, on_ctrl_C, help, flags); if(free_this) fs_give((void **) &free_this); if(free_this2) fs_give((void **) &free_this2); return(rv); }
void string_input_popup::create_window() { nc_color title_color = c_light_red; nc_color desc_color = c_green; int titlesize = utf8_width( _title ); // Occupied horizontal space if( _max_length <= 0 ) { _max_length = _width; } // 2 for border (top and bottom) and 1 for the input text line. int w_height = 2 + 1; // |"w_width = width + titlesize (this text) + 5": _____ | int w_width = FULL_SCREEN_WIDTH; if( _width <= 0 ) { _width = std::max( 5, FULL_SCREEN_WIDTH - titlesize - 5 ); // Default if unspecified } else { _width = std::min( FULL_SCREEN_WIDTH - 20, _width ); w_width = _width + titlesize + 5; } std::vector<std::string> title_split = { _title }; if( w_width > FULL_SCREEN_WIDTH ) { // Out of horizontal space- wrap the title titlesize = FULL_SCREEN_WIDTH - _width - 5; w_width = FULL_SCREEN_WIDTH; for( int wraplen = w_width - 2; wraplen >= titlesize; wraplen-- ) { title_split = foldstring( _title, wraplen ); if( int( title_split.back().size() ) <= titlesize ) { break; } } w_height += int( title_split.size() ) - 1; } std::vector<std::string> descformatted; if( !_description.empty() ) { const int twidth = std::min( utf8_width( remove_color_tags( _description ) ), w_width - 4 ); descformatted = foldstring( _description, twidth ); w_height += descformatted.size(); } // length of title + border (left) + space _startx = titlesize + 2; // Below the description and below the top border _starty = 1 + descformatted.size(); if( _max_length <= 0 ) { _max_length = 1024; } _endx = w_width - 3; _position = -1; const int w_y = ( TERMY - w_height ) / 2; const int w_x = std::max( ( TERMX - w_width ) / 2, 0 ); w = catacurses::newwin( w_height, w_width, w_y, w_x ); draw_border( w ); for( size_t i = 0; i < descformatted.size(); ++i ) { trim_and_print( w, 1 + i, 1, w_width - 2, desc_color, descformatted[i] ); } for( int i = 0; i < int( title_split.size() ) - 1; i++ ) { mvwprintz( w, _starty++, i + 1, title_color, title_split[i] ); } right_print( w, _starty, w_width - titlesize - 1, title_color, title_split.back() ); _starty = w_height - 2; // The ____ looks better at the bottom right when the title folds }
const std::string &string_input_popup::query_string( const bool loop, const bool draw_only ) { if( !w ) { create_window(); } if( !ctxt ) { create_context(); } utf8_wrapper ret( _text ); utf8_wrapper edit( ctxt->get_edittext() ); if( _position == -1 ) { _position = ret.length(); } const int scrmax = _endx - _startx; // in output (console) cells, not characters of the string! int shift = 0; bool redraw = true; int ch = 0; do { if( _position < 0 ) { _position = 0; } const size_t left_shift = ret.substr( 0, _position ).display_width(); if( ( int )left_shift < shift ) { shift = 0; } else if( _position < ( int )ret.length() && ( int )left_shift + 1 >= shift + scrmax ) { // if the cursor is inside the input string, keep one cell right of // the cursor visible, because the cursor might be on a multi-cell // character. shift = left_shift - scrmax + 2; } else if( _position == ( int )ret.length() && ( int )left_shift >= shift + scrmax ) { // cursor is behind the end of the input string, keep the // trailing '_' visible (always a single cell character) shift = left_shift - scrmax + 1; } else if( shift < 0 ) { shift = 0; } const size_t xleft_shift = ret.substr_display( 0, shift ).display_width(); if( ( int )xleft_shift != shift ) { // This prevents a multi-cell character from been split, which is not possible // instead scroll a cell further to make that character disappear completely shift++; } if( redraw ) { redraw = false; draw( ret, edit, shift ); wrefresh( w ); } wrefresh( w ); if( draw_only ) { return _text; } const std::string action = ctxt->handle_input(); const input_event ev = ctxt->get_raw_input(); ch = ev.type == CATA_INPUT_KEYBOARD ? ev.get_first_input() : 0; if( callbacks[ch] ) { if( callbacks[ch]() ) { continue; } } // This class only registers the ANY_INPUT action by default. If the // client provides their own input_context with registered actions // besides ANY_INPUT, ignore those so that the client may handle them. if( action != "ANY_INPUT" ) { continue; } if( ch == KEY_ESCAPE ) { _text.clear(); _canceled = true; return _text; } else if( ch == '\n' ) { add_to_history( ret.str() ); _text = ret.str(); return _text; } else if( ch == KEY_UP ) { show_history( ret ); redraw = true; } else if( ch == KEY_DOWN || ch == KEY_NPAGE || ch == KEY_PPAGE || ch == KEY_BTAB || ch == 9 ) { /* absolutely nothing */ } else if( ch == KEY_RIGHT ) { if( _position + 1 <= ( int )ret.size() ) { _position++; } redraw = true; } else if( ch == KEY_LEFT ) { if( _position > 0 ) { _position--; } redraw = true; } else if( ch == 0x15 ) { // ctrl-u: delete all the things _position = 0; ret.erase( 0 ); redraw = true; // Move the cursor back and re-draw it } else if( ch == KEY_BACKSPACE ) { // but silently drop input if we're at 0, instead of adding '^' if( _position > 0 && _position <= ( int )ret.size() ) { //TODO: it is safe now since you only input ASCII chars _position--; ret.erase( _position, 1 ); redraw = true; } } else if( ch == KEY_HOME ) { _position = 0; redraw = true; } else if( ch == KEY_END ) { _position = ret.size(); redraw = true; } else if( ch == KEY_DC ) { if( _position < ( int )ret.size() ) { ret.erase( _position, 1 ); redraw = true; } } else if( ch == KEY_F( 2 ) ) { std::string tmp = get_input_string_from_file(); int tmplen = utf8_width( tmp ); if( tmplen > 0 && ( tmplen + utf8_width( ret.c_str() ) <= _max_length || _max_length == 0 ) ) { ret.append( tmp ); } } else if( !ev.text.empty() && _only_digits && !( isdigit( ev.text[0] ) || ev.text[0] == '-' ) ) { // ignore non-digit (and '-' is a digit as well) } else if( _max_length > 0 && ( int )ret.length() >= _max_length ) { // no further input possible, ignore key } else if( !ev.text.empty() ) { const utf8_wrapper t( ev.text ); ret.insert( _position, t ); _position += t.length(); edit.erase( 0 ); ctxt->set_edittext( edit.c_str() ); redraw = true; } else if( ev.edit_refresh ) { const utf8_wrapper t( ev.edit ); edit.erase( 0 ); edit.insert( 0, t ); ctxt->set_edittext( edit.c_str() ); redraw = true; } else if( ev.edit.empty() ) { edit.erase( 0 ); ctxt->set_edittext( edit.c_str() ); redraw = true; } } while( loop == true ); _text = ret.str(); return _text; }
/** * Displays the vehicle's stats at the bottom of the window. */ void veh_interact::display_stats () { bool conf = veh->valid_wheel_config(); const int second_column = 29; const int third_column = 56; std::string speed_units = OPTIONS["USE_METRIC_SPEEDS"].getValue(); float speed_factor = 0.01f; if (OPTIONS["USE_METRIC_SPEEDS"] == "km/h") { speed_factor *= 1.61; } std::string weight_units = OPTIONS["USE_METRIC_WEIGHTS"].getValue(); float weight_factor; if (OPTIONS["USE_METRIC_WEIGHTS"] == "kg") { weight_factor = 1; } else { weight_factor = 2.2f; } mvwprintz(w_stats, 0, 1, c_ltgray, _("Name: ")); mvwprintz(w_stats, 0, 1 + utf8_width(_("Name: ")), c_ltgreen, veh->name.c_str()); fold_and_print(w_stats, 1, 1, second_column, c_ltgray, _("Safe speed: <color_ltgreen>%3d</color> %s"), int(veh->safe_velocity(false) * speed_factor), speed_units.c_str()); fold_and_print(w_stats, 2, 1, second_column, c_ltgray, _("Top speed: <color_ltred>%3d</color> %s"), int(veh->max_velocity(false) * speed_factor), speed_units.c_str()); fold_and_print(w_stats, 3, 1, second_column, c_ltgray, _("Acceleration: <color_ltblue>%3d</color> %s/t"), int(veh->acceleration(false) * speed_factor), speed_units.c_str()); fold_and_print(w_stats, 4, 1, second_column, c_ltgray, _("Mass: <color_ltblue>%5d</color> %s"), int(veh->total_mass() * weight_factor), weight_units.c_str()); if (conf) { fold_and_print(w_stats, 5, second_column, third_column, c_ltgray, _("Wheels: <color_ltgreen>enough</color>")); } else { fold_and_print(w_stats, 5, second_column, third_column, c_ltgray, _("Wheels: <color_ltred>lack</color>")); } fold_and_print(w_stats, 2, second_column, third_column, c_ltgray, _("K dynamics: <color_ltblue>%3d</color>%%"), int(veh->k_dynamics() * 100)); fold_and_print(w_stats, 3, second_column, third_column, c_ltgray, _("K mass: <color_ltblue>%3d</color>%%"), int(veh->k_mass() * 100)); mvwprintz(w_stats, 1, second_column, c_ltgray, _("Fuel usage (safe): ")); int fuel_usage_x = 1 + second_column + utf8_width(_("Fuel usage (safe): ")); ammotype fuel_types[3] = { "gasoline", "battery", "plasma" }; nc_color fuel_colors[3] = { c_ltred, c_yellow, c_ltblue }; bool first = true; for (int i = 0; i < 3; ++i) { int fuel_usage = veh->basic_consumption (fuel_types[i]); if (fuel_usage > 0) { fuel_usage = fuel_usage / 100; if (fuel_usage < 1) { fuel_usage = 1; } if (!first) { mvwprintz(w_stats, 1, fuel_usage_x++, c_ltgray, "/"); } mvwprintz(w_stats, 1, fuel_usage_x++, fuel_colors[i], "%d", fuel_usage); if (fuel_usage > 9) { fuel_usage_x++; } if (fuel_usage > 99) { fuel_usage_x++; } first = false; } } veh->print_fuel_indicator (w_stats, 1, third_column, true, true); // Write the overall damage int column = 1; mvwprintz(w_stats, 5, 1, c_ltgray, _("Status: ")); column += utf8_width(_("Status: ")) + 1; fold_and_print(w_stats, 5, column, third_column, totalDurabilityColor, totalDurabilityText.c_str()); // Write the most damaged part if (mostDamagedPart != -1) { std::string partName; mvwprintz(w_stats, 4, second_column, c_ltgray, _("Most damaged: ")); column = second_column + utf8_width(_("Most damaged: ")) + 1; std::string partID = veh->parts[mostDamagedPart].id; vehicle_part part = veh->parts[mostDamagedPart]; int damagepercent = part.hp / vehicle_part_types[part.id].durability; nc_color damagecolor = getDurabilityColor(damagepercent * 100); partName = vehicle_part_types[partID].name; fold_and_print(w_stats, 4, column, third_column, damagecolor, "%s", partName.c_str()); } wrefresh (w_stats); }
/* * Wrap the text, if necessary. The variable indent is the indent for the * first line, indent2 is the indent for all other lines. * If indent is negative, assume that already -indent columns have been * consumed (and no extra indent is necessary for the first line). */ int strbuf_add_wrapped_text(struct strbuf *buf, const char *text, int indent, int indent2, int width) { int w = indent, assume_utf8 = is_utf8(text); const char *bol = text, *space = NULL; if (width <= 0) { strbuf_add_indented_text(buf, text, indent, indent2); return 1; } if (indent < 0) { w = -indent; space = text; } for (;;) { char c; size_t skip; while ((skip = display_mode_esc_sequence_len(text))) text += skip; c = *text; if (!c || isspace(c)) { if (w < width || !space) { const char *start = bol; if (!c && text == start) return w; if (space) start = space; else print_spaces(buf, indent); strbuf_write(buf, start, text - start); if (!c) return w; space = text; if (c == '\t') w |= 0x07; else if (c == '\n') { space++; if (*space == '\n') { strbuf_write(buf, "\n", 1); goto new_line; } else if (!isalnum(*space)) goto new_line; else strbuf_write(buf, " ", 1); } w++; text++; } else { new_line: strbuf_write(buf, "\n", 1); text = bol = space + isspace(*space); space = NULL; w = indent = indent2; } continue; } if (assume_utf8) w += utf8_width(&text, NULL); else { w++; text++; } } }
int worldfactory::show_worldgen_tab_confirm(WINDOW *win, WORLDPTR world) { const int iTooltipHeight = 1; 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; WINDOW *w_confirmation = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2, iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX); unsigned namebar_pos = 3 + utf8_width(_("World Name:")); int line = 1; bool noname = false; long ch; std::string worldname = world->world_name; do { mvwprintz(w_confirmation, 2, 2, c_ltgray, _("World Name:")); mvwprintz(w_confirmation, 2, namebar_pos, c_ltgray, "______________________________"); fold_and_print(w_confirmation, 10, 2, 76, c_ltgray, _("When you are satisfied with the world as it is and are ready to continue, press >")); fold_and_print(w_confirmation, 12, 2, 76, c_ltgray, _("To go back and review your world, press <")); fold_and_print(w_confirmation, 14, 2, 76, c_green, _("To pick a random name for your world, press ?.")); if (!noname) { mvwprintz(w_confirmation, 2, namebar_pos, c_ltgray, "%s", worldname.c_str()); if (line == 1) { wprintz(w_confirmation, h_ltgray, "_"); } } wrefresh(win); wrefresh(w_confirmation); refresh(); ch = input(); if (noname) { mvwprintz(w_confirmation, 2, namebar_pos, c_ltgray, "______________________________"); noname = false; } if (ch == '>') { if (worldname.size() == 0) { mvwprintz(w_confirmation, 2, namebar_pos, h_ltgray, _("______NO NAME ENTERED!!!!_____")); noname = true; wrefresh(w_confirmation); if (!query_yn(_("Are you SURE you're finished? World name will be randomly generated."))) { continue; continue; } else { world->world_name = pick_random_name(); if (!valid_worldname(world->world_name)) { continue; } return 1; } } else if (query_yn(_("Are you SURE you're finished?")) && valid_worldname(worldname)) { world->world_name = worldname; werase(w_confirmation); delwin(w_confirmation); return 1; } else { continue; } } else if (ch == '<') { world->world_name = worldname; werase(w_confirmation); delwin(w_confirmation); return -1; } else if (ch == '?') { mvwprintz(w_confirmation, 2, namebar_pos, c_ltgray, "______________________________"); world->world_name = worldname = pick_random_name(); } else if (ch == KEY_ESCAPE){ world->world_name = worldname; // cache the current worldname just in case they say No to the exit query return -999; } else { switch (line) { case 1: if (ch == KEY_BACKSPACE || ch == 127) { if (worldname.size() > 0) { //erase utf8 character TODO: make a function while(worldname.size() > 0 && ((unsigned char)worldname[worldname.size() - 1]) >= 128 && ((unsigned char)worldname[(int)worldname.size() - 1]) <= 191) { worldname.erase(worldname.size() - 1); } worldname.erase(worldname.size() - 1); mvwprintz(w_confirmation, 2, namebar_pos, c_ltgray, "______________________________ "); mvwprintz(w_confirmation, 2, namebar_pos, c_ltgray, "%s", worldname.c_str()); wprintz(w_confirmation, h_ltgray, "_"); } } else if (is_char_allowed(ch) && utf8_width(worldname.c_str()) < 30) { worldname.push_back(ch); } else if(ch == KEY_F(2)) { std::string tmp = get_input_string_from_file(); int tmplen = utf8_width(tmp.c_str()); if(tmplen > 0 && tmplen + utf8_width(worldname.c_str()) < 30) { worldname.append(tmp); } } //experimental unicode input else if(ch > 127) { std::string tmp = utf32_to_utf8(ch); int tmplen = utf8_width(tmp.c_str()); if(tmplen > 0 && tmplen + utf8_width(worldname.c_str()) < 30) { worldname.append(tmp); } } break; } } } while (true); return 0; }
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(); }
/*---------------------------------------------------------------------- Prompt user for a choice among alternatives Args -- utf8prompt: The prompt for the question/selection line: The line to prompt on, if negative then relative to bottom esc_list: ESC_KEY_S list of keys dflt: The selection when the <CR> is pressed (should probably be one of the chars in esc_list) on_ctrl_C: The selection when ^C is pressed help_text: Text to be displayed on bottom two lines flags: Logically OR'd flags modifying our behavior to: RB_FLUSH_IN - Discard any pending input chars. RB_ONE_TRY - Only give one chance to answer. Returns on_ctrl_C value if not answered acceptably on first try. RB_NO_NEWMAIL - Quell the usual newmail check. RB_SEQ_SENSITIVE - The caller is sensitive to sequence number changes so return on_ctrl_C if an unsolicited expunge happens while we're viewing a message. RB_RET_HELP - Instead of the regular internal handling way of handling help_text, this just causes radio_buttons to return 3 when help is asked for, so that the caller handles it instead. Note: If there are enough keys in the esc_list to need a second screen, and there is no help, then the 13th key will be put in the help position. Result -- Returns the letter pressed. Will be one of the characters in the esc_list argument, or dflt, or on_ctrl_C, or SEQ_EXCEPTION. This will pause for any new status message to be seen and then prompt the user. The prompt will be truncated to fit on the screen. Redraw and resize are handled along with ^Z suspension. Typing ^G will toggle the help text on and off. Character types that are not buttons will result in a beep (unless one_try is set). ----*/ int radio_buttons(char *utf8prompt, int line, ESCKEY_S *esc_list, int dflt, int on_ctrl_C, HelpType help_text, int flags) { UCS ucs; register int ch, real_line; char *q, *ds = NULL; unsigned maxcol; int max_label, i, start, fkey_table[12]; int km_popped = 0; struct key rb_keys[12]; struct key_menu rb_keymenu; bitmap_t bitmap; struct variable *vars = ps_global->vars; COLOR_PAIR *lastc = NULL, *promptc = NULL; #ifdef _WINDOWS int cursor_shown; if (mswin_usedialog()){ MDlgButton button_list[25]; LPTSTR free_names[25]; LPTSTR free_labels[25]; int b, i, ret; char **help; memset(&free_names, 0, sizeof(LPTSTR) * 25); memset(&free_labels, 0, sizeof(LPTSTR) * 25); memset(&button_list, 0, sizeof (MDlgButton) * 25); b = 0; if(flags & RB_RET_HELP){ if(help_text != NO_HELP) panic("RET_HELP and help in radio_buttons!"); button_list[b].ch = '?'; button_list[b].rval = 3; button_list[b].name = TEXT("?"); free_labels[b] = utf8_to_lptstr(N_("Help")); button_list[b].label = free_labels[b]; ++b; } for(i = 0; esc_list && esc_list[i].ch != -1 && i < 23; ++i){ if(esc_list[i].ch != -2){ button_list[b].ch = esc_list[i].ch; button_list[b].rval = esc_list[i].rval; free_names[b] = utf8_to_lptstr(esc_list[i].name); button_list[b].name = free_names[b]; free_labels[b] = utf8_to_lptstr(esc_list[i].label); button_list[b].label = free_labels[b]; ++b; } } button_list[b].ch = -1; /* assumption here is that HelpType is char ** */ help = help_text; ret = mswin_select(utf8prompt, button_list, dflt, on_ctrl_C, help, flags); for(i = 0; i < 25; i++){ if(free_names[i]) fs_give((void **) &free_names[i]); if(free_labels[i]) fs_give((void **) &free_labels[i]); } return (ret); } #endif /* _WINDOWS */ suspend_busy_cue(); flush_ordered_messages(); /* show user previous status msgs */ mark_status_dirty(); /* clear message next display call */ real_line = line > 0 ? line : ps_global->ttyo->screen_rows + line; MoveCursor(real_line, RAD_BUT_COL); CleartoEOLN(); /*---- Find widest label ----*/ max_label = 0; for(i = 0; esc_list && esc_list[i].ch != -1 && i < 11; i++){ if(esc_list[i].ch == -2) /* -2 means to skip this key and leave blank */ continue; if(esc_list[i].name) max_label = MAX(max_label, utf8_width(esc_list[i].name)); } if(ps_global->ttyo->screen_cols - max_label - 1 > 0) maxcol = ps_global->ttyo->screen_cols - max_label - 1; else maxcol = 0; /* * We need to be able to truncate q, so copy it in case it is * a readonly string. */ q = cpystr(utf8prompt); /*---- Init structs for keymenu ----*/ for(i = 0; i < 12; i++) memset((void *)&rb_keys[i], 0, sizeof(struct key)); memset((void *)&rb_keymenu, 0, sizeof(struct key_menu)); rb_keymenu.how_many = 1; rb_keymenu.keys = rb_keys; /*---- Setup key menu ----*/ start = 0; clrbitmap(bitmap); memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(int)); if(flags & RB_RET_HELP && help_text != NO_HELP) panic("RET_HELP and help in radio_buttons!"); /* if shown, always at position 0 */ if(help_text != NO_HELP || flags & RB_RET_HELP){ rb_keymenu.keys[0].name = "?"; rb_keymenu.keys[0].label = N_("Help"); setbitn(0, bitmap); fkey_table[0] = ctrl('G'); start++; } if(on_ctrl_C){ rb_keymenu.keys[1].name = "^C"; rb_keymenu.keys[1].label = N_("Cancel"); setbitn(1, bitmap); fkey_table[1] = ctrl('C'); start++; } start = start ? 2 : 0; /*---- Show the usual possible keys ----*/ for(i=start; esc_list && esc_list[i-start].ch != -1; i++){ /* * If we have an esc_list item we'd like to put in the non-existent * 13th slot, and there is no help, we put it in the help slot * instead. We're hacking now...! * * We may also have invisible esc_list items that don't show up * on the screen. We use this when we have two different keys * which are synonyms, like ^P and KEY_UP. If all the slots are * already full we can still fit invisible keys off the screen to * the right. A key is invisible if it's label is "". */ if(i >= 12){ if(esc_list[i-start].label && esc_list[i-start].label[0] != '\0'){ /* visible */ if(i == 12){ /* special case where we put it in help slot */ if(help_text != NO_HELP) panic("Programming botch in radio_buttons(): too many keys"); if(esc_list[i-start].ch != -2) setbitn(0, bitmap); /* the help slot */ fkey_table[0] = esc_list[i-start].ch; rb_keymenu.keys[0].name = esc_list[i-start].name; if(esc_list[i-start].ch != -2 && esc_list[i-start].rval == dflt && esc_list[i-start].label){ size_t l; l = strlen(esc_list[i-start].label) + 2; ds = (char *)fs_get((l+1) * sizeof(char)); snprintf(ds, l+1, "[%s]", esc_list[i-start].label); ds[l] = '\0'; rb_keymenu.keys[0].label = ds; } else rb_keymenu.keys[0].label = esc_list[i-start].label; } else panic("Botch in radio_buttons(): too many keys"); } } else{ if(esc_list[i-start].ch != -2) setbitn(i, bitmap); fkey_table[i] = esc_list[i-start].ch; rb_keymenu.keys[i].name = esc_list[i-start].name; if(esc_list[i-start].ch != -2 && esc_list[i-start].rval == dflt && esc_list[i-start].label){ size_t l; l = strlen(esc_list[i-start].label) + 2; ds = (char *)fs_get((l+1) * sizeof(char)); snprintf(ds, l+1, "[%s]", esc_list[i-start].label); ds[l] = '\0'; rb_keymenu.keys[i].label = ds; } else rb_keymenu.keys[i].label = esc_list[i-start].label; } } for(; i < 12; i++) rb_keymenu.keys[i].name = NULL; ps_global->mangled_footer = 1; #ifdef _WINDOWS cursor_shown = mswin_showcaret(1); #endif if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR && VAR_PROMPT_BACK_COLOR && pico_is_good_color(VAR_PROMPT_FORE_COLOR) && pico_is_good_color(VAR_PROMPT_BACK_COLOR)){ lastc = pico_get_cur_color(); if(lastc){ promptc = new_color_pair(VAR_PROMPT_FORE_COLOR, VAR_PROMPT_BACK_COLOR); (void)pico_set_colorp(promptc, PSC_NONE); } } else StartInverse(); draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q); while(1){ fflush(stdout); /*---- Paint the keymenu ----*/ if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); draw_keymenu(&rb_keymenu, bitmap, ps_global->ttyo->screen_cols, 1 - FOOTER_ROWS(ps_global), 0, FirstMenu); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); MoveCursor(real_line, MIN(RAD_BUT_COL+utf8_width(q), maxcol+1)); if(flags & RB_FLUSH_IN) flush_input(); newcmd: /* Timeout 5 min to keep imap mail stream alive */ ucs = read_char(600); dprint((2, "Want_to read: %s (0x%x)\n", pretty_command(ucs), ucs)); if((ucs < 0x80) && isupper((unsigned char) ucs)) ucs = tolower((unsigned char) ucs); if(F_ON(F_USE_FK,ps_global) && (((ucs < 0x80) && isalpha((unsigned char) ucs) && !strchr("YyNn",(int) ucs)) || ((ucs >= PF1 && ucs <= PF12) && (ucs = fkey_table[ucs - PF1]) == NO_OP_COMMAND))){ /* * The funky test above does two things. It maps * esc_list character commands to function keys, *and* prevents * character commands from input while in function key mode. * NOTE: this breaks if we ever need more than the first * twelve function keys... */ if(flags & RB_ONE_TRY){ ch = ucs = on_ctrl_C; goto out_of_loop; } Writechar(BELL, 0); continue; } switch(ucs){ default: for(i = 0; esc_list && esc_list[i].ch != -1; i++) if(ucs == esc_list[i].ch){ int len, n; MoveCursor(real_line,len=MIN(RAD_BUT_COL+utf8_width(q),maxcol+1)); for(n = 0, len = ps_global->ttyo->screen_cols - len; esc_list[i].label && esc_list[i].label[n] && len > 0; n++, len--) Writechar(esc_list[i].label[n], 0); ch = esc_list[i].rval; goto out_of_loop; } if(flags & RB_ONE_TRY){ ch = on_ctrl_C; goto out_of_loop; } Writechar(BELL, 0); break; case ctrl('M'): case ctrl('J'): ch = dflt; for(i = 0; esc_list && esc_list[i].ch != -1; i++) if(ch == esc_list[i].rval){ int len, n; MoveCursor(real_line,len=MIN(RAD_BUT_COL+utf8_width(q),maxcol+1)); for(n = 0, len = ps_global->ttyo->screen_cols - len; esc_list[i].label && esc_list[i].label[n] && len > 0; n++, len--) Writechar(esc_list[i].label[n], 0); break; } goto out_of_loop; case ctrl('C'): if(on_ctrl_C || (flags & RB_ONE_TRY)){ ch = on_ctrl_C; goto out_of_loop; } Writechar(BELL, 0); break; case '?': case ctrl('G'): if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){ km_popped++; FOOTER_ROWS(ps_global) = 3; line = -3; real_line = ps_global->ttyo->screen_rows + line; if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); clearfooter(ps_global); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q); break; } if(flags & RB_RET_HELP){ ch = 3; goto out_of_loop; } else if(help_text != NO_HELP && FOOTER_ROWS(ps_global) > 1){ mark_keymenu_dirty(); if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); MoveCursor(real_line + 1, RAD_BUT_COL); CleartoEOLN(); MoveCursor(real_line + 2, RAD_BUT_COL); CleartoEOLN(); radio_help(real_line, RAD_BUT_COL, help_text); sleep(5); MoveCursor(real_line, MIN(RAD_BUT_COL+utf8_width(q), maxcol+1)); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); } else Writechar(BELL, 0); break; case NO_OP_COMMAND: goto newcmd; /* misunderstood escape? */ case NO_OP_IDLE: /* UNODIR, keep the stream alive */ if(flags & RB_NO_NEWMAIL) goto newcmd; i = new_mail(0, VeryBadTime, NM_DEFER_SORT); if(sp_expunge_count(ps_global->mail_stream) && flags & RB_SEQ_SENSITIVE){ if(on_ctrl_C) ch = on_ctrl_C; else ch = SEQ_EXCEPTION; goto out_of_loop; } if(i < 0) break; /* no changes, get on with life */ /* Else fall into redraw to adjust displayed numbers and such */ case KEY_RESIZE: case ctrl('L'): real_line = line > 0 ? line : ps_global->ttyo->screen_rows + line; if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); ClearScreen(); redraw_titlebar(); if(ps_global->redrawer != NULL) (*ps_global->redrawer)(); if(FOOTER_ROWS(ps_global) == 3 || km_popped) redraw_keymenu(); if(ps_global->ttyo->screen_cols - max_label - 1 > 0) maxcol = ps_global->ttyo->screen_cols - max_label - 1; else maxcol = 0; if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); draw_radio_prompt(real_line, RAD_BUT_COL, maxcol, q); break; } /* switch */ } out_of_loop: #ifdef _WINDOWS if(!cursor_shown) mswin_showcaret(0); #endif fs_give((void **) &q); if(ds) fs_give((void **) &ds); if(lastc){ (void) pico_set_colorp(lastc, PSC_NONE); free_color_pair(&lastc); if(promptc) free_color_pair(&promptc); } else EndInverse(); fflush(stdout); resume_busy_cue(0); if(km_popped){ FOOTER_ROWS(ps_global) = 1; clearfooter(ps_global); ps_global->mangled_body = 1; } return(ch); }
/** * Displays the vehicle's stats at the bottom of the window. */ void veh_interact::display_stats () { bool conf = veh->valid_wheel_config(); const int second_column = 29; const int third_column = 56; std::string speed_units = OPTIONS["USE_METRIC_SPEEDS"].getValue(); float speed_factor = 0.01f; if (OPTIONS["USE_METRIC_SPEEDS"] == "km/h") { speed_factor *= 1.61; } std::string weight_units = OPTIONS["USE_METRIC_WEIGHTS"].getValue(); float weight_factor; if (OPTIONS["USE_METRIC_WEIGHTS"] == "kg") { weight_factor = 1; } else { weight_factor = 2.2f; } mvwprintz(w_stats, 0, 1, c_ltgray, _("Name: ")); mvwprintz(w_stats, 0, 1+utf8_width(_("Name: ")), c_ltgreen, veh->name.c_str()); fold_and_print(w_stats, 1, 1, second_column, c_ltgray, _("Safe speed: <color_ltgreen>%3d</color> %s"), int(veh->safe_velocity(false) * speed_factor), speed_units.c_str()); fold_and_print(w_stats, 2, 1, second_column, c_ltgray, _("Top speed: <color_ltred>%3d</color> %s"), int(veh->max_velocity(false) * speed_factor), speed_units.c_str()); fold_and_print(w_stats, 3, 1, second_column, c_ltgray, _("Acceleration: <color_ltblue>%3d</color> %s/t"), int(veh->acceleration(false) * speed_factor), speed_units.c_str()); fold_and_print(w_stats, 4, 1, second_column, c_ltgray, _("Mass: <color_ltblue>%5d</color> %s"), int(veh->total_mass() * weight_factor), weight_units.c_str()); if (conf) { fold_and_print(w_stats, 5, 1, second_column, c_ltgray, _("Wheels: <color_ltgreen>enough</color>")); } else { fold_and_print(w_stats, 5, 1, second_column, c_ltgray, _("Wheels: <color_ltred> lack</color>")); } fold_and_print(w_stats, 2, second_column, third_column, c_ltgray, _("K dynamics: <color_ltblue>%3d</color>%%"), int(veh->k_dynamics() * 100)); fold_and_print(w_stats, 3, second_column, third_column, c_ltgray, _("K mass: <color_ltblue>%3d</color>%%"), int(veh->k_mass() * 100)); mvwprintz(w_stats, 1, second_column, c_ltgray, _("Fuel usage (safe): ")); int fuel_usage_x = 1 + second_column + utf8_width(_("Fuel usage (safe): ")); ammotype fuel_types[3] = { "gasoline", "battery", "plasma" }; nc_color fuel_colors[3] = { c_ltred, c_yellow, c_ltblue }; bool first = true; for (int i = 0; i < 3; ++i) { int fuel_usage = veh->basic_consumption (fuel_types[i]); if (fuel_usage > 0) { fuel_usage = fuel_usage / 100; if (fuel_usage < 1) { fuel_usage = 1; } if (!first) { mvwprintz(w_stats, 1, fuel_usage_x++, c_ltgray, "/"); } mvwprintz(w_stats, 1, fuel_usage_x++, fuel_colors[i], "%d", fuel_usage); if (fuel_usage > 9) { fuel_usage_x++; } if (fuel_usage > 99) { fuel_usage_x++; } first = false; } } veh->print_fuel_indicator (w_stats, 1, third_column, true, true); wrefresh (w_stats); }
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 - 2 - 2; // -2 for the border // width of the legend const size_t legwidth = FULL_SCREEN_WIDTH - 51 - 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("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(), 1); mvwprintz(w_help, 0, (FULL_SCREEN_WIDTH - utf8_width(_("Keybindings"))) / 2 - 1, c_ltred, " %s ", _("Keybindings")); fold_and_print(w_help, 1, 51, 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 + 1, 2, c_dkgray, "%c ", invlet); } else if (status == s_add || status == s_add_global) { mvwprintz(w_help, i + 1, 2, c_blue, "%c ", invlet); } else if (status == s_remove) { mvwprintz(w_help, i + 1, 2, c_blue, "%c ", invlet); } else { mvwprintz(w_help, i + 1, 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 + 1, 4, col, "%s: ", get_action_name(action_id).c_str()); mvwprintz(w_help, i + 1, 30, 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 || hotkey_index >= org_registered_actions.size()) { continue; } const int action_index = hotkey_index + scroll_offset; 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 + 1 < org_registered_actions.size()) { scroll_offset++; } } else if (action == "UP") { if (scroll_offset > 0) { scroll_offset--; } } 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); }
int sokoban_game::start_game() { int iScore = 0; int iMoves = 0; iTotalMoves = 0; int iDirY, iDirX; 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; parse_level(); WINDOW *w_sokoban = newwin(FULL_SCREEN_HEIGHT, FULL_SCREEN_WIDTH, iOffsetY, iOffsetX); draw_border(w_sokoban); center_print(w_sokoban, 0, hilite(c_white), _("Sokoban")); std::vector<std::string> shortcuts; shortcuts.push_back(_("<+> next")); // '+': next shortcuts.push_back(_("<-> prev")); // '-': prev shortcuts.push_back(_("<r>eset")); // 'r': reset shortcuts.push_back(_("<q>uit")); // 'q': quit shortcuts.push_back(_("<u>ndo move")); // 'u': undo move int indent = 10; for (size_t i = 0; i < shortcuts.size(); i++) { indent = std::max(indent, utf8_width(shortcuts[i].c_str()) + 1); } indent = std::min(indent, 30); for (size_t i = 0; i < shortcuts.size(); i++) { shortcut_print(w_sokoban, i + 1, FULL_SCREEN_WIDTH - indent, c_white, c_ltgreen, shortcuts[i]); } int input = '.'; int iPlayerY = 0; int iPlayerX = 0; bool bNewLevel = true; bool bMoved = false; do { if (bNewLevel) { bNewLevel = false; iMoves = 0; vUndo.clear(); iPlayerY = mLevelInfo[iCurrentLevel]["PlayerY"]; iPlayerX = mLevelInfo[iCurrentLevel]["PlayerX"]; mLevel = vLevel[iCurrentLevel]; } print_score(w_sokoban, iScore, iMoves); if (check_win()) { //we won yay if (!mAlreadyWon[iCurrentLevel]) { iScore += 500; mAlreadyWon[iCurrentLevel] = true; } input = '+'; } else { draw_level(w_sokoban); wrefresh(w_sokoban); //Check input input = getch(); } bMoved = false; switch (input) { case KEY_UP: /* up */ iDirY = -1; iDirX = 0; bMoved = true; break; case KEY_DOWN: /* down */ iDirY = 1; iDirX = 0; bMoved = true; break; case KEY_LEFT: /* left */ iDirY = 0; iDirX = -1; bMoved = true; break; case KEY_RIGHT: /* right */ iDirY = 0; iDirX = 1; bMoved = true; break; case 'q': return iScore; break; case 'u': { int iPlayerYNew = 0; int iPlayerXNew = 0; bool bUndoSkip = false; //undo move if (!vUndo.empty()) { //reset last player pos mLevel[iPlayerY][iPlayerX] = (mLevel[iPlayerY][iPlayerX] == "+") ? "." : " "; iPlayerYNew = vUndo[vUndo.size() - 1].iOldY; iPlayerXNew = vUndo[vUndo.size() - 1].iOldX; mLevel[iPlayerYNew][iPlayerXNew] = vUndo[vUndo.size() - 1].sTileOld; vUndo.pop_back(); bUndoSkip = true; } if (bUndoSkip && !vUndo.empty()) { iDirY = vUndo[vUndo.size() - 1].iOldY; iDirX = vUndo[vUndo.size() - 1].iOldX; if (vUndo[vUndo.size() - 1].sTileOld == "$" || vUndo[vUndo.size() - 1].sTileOld == "*") { mLevel[iPlayerY][iPlayerX] = (mLevel[iPlayerY][iPlayerX] == ".") ? "*" : "$"; mLevel[iPlayerY + iDirY][iPlayerX + iDirX] = (mLevel[iPlayerY + iDirY][iPlayerX + iDirX] == "*") ? "." : " "; vUndo.pop_back(); } } if (bUndoSkip) { iPlayerY = iPlayerYNew; iPlayerX = iPlayerXNew; } } break; case 'r': //reset level bNewLevel = true; break; case '+': //next level clear_level(w_sokoban); iCurrentLevel++; if (iCurrentLevel >= iNumLevel) { iCurrentLevel = 0; } bNewLevel = true; break; case '-': //prev level clear_level(w_sokoban); iCurrentLevel--; if (iCurrentLevel < 0) { iCurrentLevel = iNumLevel - 1; } bNewLevel = true; break; default: break; } if (bMoved) { //check if we can move the player std::string sMoveTo = mLevel[iPlayerY + iDirY][iPlayerX + iDirX]; bool bMovePlayer = false; if (sMoveTo != "#") { if (sMoveTo == "$" || sMoveTo == "*") { //Check if we can move the package std::string sMovePackTo = mLevel[iPlayerY + (iDirY * 2)][iPlayerX + (iDirX * 2)]; if (sMovePackTo == "." || sMovePackTo == " ") { //move both bMovePlayer = true; mLevel[iPlayerY + (iDirY * 2)][iPlayerX + (iDirX * 2)] = (sMovePackTo == ".") ? "*" : "$"; vUndo.push_back(cUndo(iDirY, iDirX, sMoveTo)); iMoves--; } } else { bMovePlayer = true; } if (bMovePlayer) { //move player vUndo.push_back(cUndo(iPlayerY, iPlayerX, mLevel[iPlayerY][iPlayerX])); mLevel[iPlayerY][iPlayerX] = (mLevel[iPlayerY][iPlayerX] == "+") ? "." : " "; mLevel[iPlayerY + iDirY][iPlayerX + iDirX] = (sMoveTo == "." || sMoveTo == "*") ? "+" : "@"; iPlayerY += iDirY; iPlayerX += iDirX; iMoves++; iTotalMoves++; } } } } while (true); return iScore; }
static LINE_CACHE_REC * view_update_line_cache(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line) { INDENT_FUNC indent_func; LINE_CACHE_REC *rec; LINE_CACHE_SUB_REC *sub; GSList *lines; unsigned char cmd; const unsigned char *ptr, *next_ptr, *last_space_ptr; int xpos, pos, indent_pos, last_space, last_color, color, linecount; int char_len; unichar chr; g_return_val_if_fail(line->text != NULL, NULL); color = ATTR_RESETFG | ATTR_RESETBG; xpos = 0; indent_pos = view->default_indent; last_space = last_color = 0; last_space_ptr = NULL; sub = NULL; indent_func = view->default_indent_func; linecount = 1; lines = NULL; for (ptr = line->text;;) { if (*ptr == '\0') { /* command */ ptr++; cmd = *ptr; ptr++; if (cmd == LINE_CMD_EOL || cmd == LINE_CMD_FORMAT) break; if (cmd == LINE_CMD_CONTINUE) { unsigned char *tmp; memcpy(&tmp, ptr, sizeof(char *)); ptr = tmp; continue; } if (cmd == LINE_CMD_INDENT) { /* set indentation position here - don't do it if we're too close to right border */ if (xpos < view->width-5) indent_pos = xpos; } else if (cmd == LINE_CMD_INDENT_FUNC) { memcpy(&indent_func, ptr, sizeof(INDENT_FUNC)); ptr += sizeof(INDENT_FUNC); if (indent_func == NULL) indent_func = view->default_indent_func; } else update_cmd_color(cmd, &color); continue; } if (!view->utf8) { next_ptr = ptr+1; char_len = 1; } else { char_len = 1; while (ptr[char_len] != '\0' && char_len < 6) char_len++; next_ptr = ptr; chr = get_utf8_char(&next_ptr, char_len); if (chr < 0) char_len = 1; else char_len = utf8_width(chr); next_ptr++; } if (xpos + char_len > view->width && sub != NULL && (last_space <= indent_pos || last_space <= 10) && view->longword_noindent) { /* long word, remove the indentation from this line */ xpos -= sub->indent; sub->indent = 0; } if (xpos + char_len > view->width) { xpos = indent_func == NULL ? indent_pos : indent_func(view, line, -1); sub = g_new0(LINE_CACHE_SUB_REC, 1); if (last_space > indent_pos && last_space > 10) { /* go back to last space */ color = last_color; ptr = last_space_ptr; while (*ptr == ' ') ptr++; } else if (view->longword_noindent) { /* long word, no indentation in next line */ xpos = 0; sub->continues = TRUE; } sub->start = ptr; sub->indent = xpos; sub->indent_func = indent_func; sub->color = color; lines = g_slist_append(lines, sub); linecount++; last_space = 0; continue; } if (*ptr == ' ') { last_space = xpos; last_space_ptr = ptr; last_color = color; } xpos += char_len; ptr = next_ptr; } rec = g_malloc(sizeof(LINE_CACHE_REC)-sizeof(LINE_CACHE_SUB_REC) + sizeof(LINE_CACHE_SUB_REC) * (linecount-1)); rec->last_access = time(NULL); rec->count = linecount; if (rec->count > 1) { for (pos = 0; lines != NULL; pos++) { memcpy(&rec->lines[pos], lines->data, sizeof(LINE_CACHE_SUB_REC)); g_free(lines->data); lines = g_slist_remove(lines, lines->data); } } g_hash_table_insert(view->cache->line_cache, line, rec); return rec; }
void faction::randomize() { // Set up values // TODO: Not always in overmap 0,0 mapx = rng(OMAPX / 10, OMAPX - OMAPX / 10); mapy = rng(OMAPY / 10, OMAPY - OMAPY / 10); // Pick an overall goal. goal = faction_goal(rng(1, NUM_FACGOALS - 1)); if (one_in(4)) { goal = FACGOAL_NONE; // Slightly more likely to not have a real goal } good = facgoal_data[goal].good; strength = facgoal_data[goal].strength; sneak = facgoal_data[goal].sneak; crime = facgoal_data[goal].crime; cult = facgoal_data[goal].cult; job1 = faction_job(rng(1, NUM_FACJOBS - 1)); do { job2 = faction_job(rng(0, NUM_FACJOBS - 1)); } while (job2 == job1); good += facjob_data[job1].good + facjob_data[job2].good; strength += facjob_data[job1].strength + facjob_data[job2].strength; sneak += facjob_data[job1].sneak + facjob_data[job2].sneak; crime += facjob_data[job1].crime + facjob_data[job2].crime; cult += facjob_data[job1].cult + facjob_data[job2].cult; int num_values = 0; int tries = 0; values = 0; do { int v = rng(1, NUM_FACVALS - 1); if (!has_value(faction_value(v)) && matches_us(faction_value(v))) { values |= mfb(v); tries = 0; num_values++; good += facval_data[v].good; strength += facval_data[v].strength; sneak += facval_data[v].sneak; crime += facval_data[v].crime; cult += facval_data[v].cult; } else { tries++; } } while((one_in(num_values) || one_in(num_values)) && tries < 15); std::string noun; int sel = 1, best = strength; if (sneak > best) { sel = 2; best = sneak; } if (crime > best) { sel = 3; best = crime; } if (cult > best) { sel = 4; } if (strength <= 0 && sneak <= 0 && crime <= 0 && cult <= 0) { sel = 0; } switch (sel) { case 1: noun = faction_noun_strong[rng(0, 14)]; power = dice(5, 20); size = dice(5, 6); break; case 2: noun = faction_noun_sneak [rng(0, 14)]; power = dice(5, 8); size = dice(5, 8); break; case 3: noun = faction_noun_crime [rng(0, 14)]; power = dice(5, 16); size = dice(5, 8); break; case 4: noun = faction_noun_cult [rng(0, 14)]; power = dice(8, 8); size = dice(4, 6); break; default: noun = faction_noun_none [rng(0, 14)]; power = dice(6, 8); size = dice(6, 6); } if (one_in(4)) { do { name = string_format(_("The %1$s of %2$s"), noun.c_str(), invent_name().c_str()); } while (utf8_width(name.c_str()) > MAX_FAC_NAME_SIZE); } else if (one_in(2)) { do { name = string_format(_("The %1$s %2$s"), invent_adj().c_str(), noun.c_str()); } while (utf8_width(name.c_str()) > MAX_FAC_NAME_SIZE); } else { do { std::string adj; if (good >= 3) { adj = faction_adj_pos[rng(0, 14)]; } else if (good <= -3) { adj = faction_adj_bad[rng(0, 14)]; } else { adj = faction_adj_neu[rng(0, 14)]; } name = string_format(_("The %1$s %2$s"), adj.c_str(), noun.c_str()); if (one_in(4)) { name = string_format(_("%1$s of %2$s"), name.c_str(), invent_name().c_str()); } } while (utf8_width(name.c_str()) > MAX_FAC_NAME_SIZE); } }
static int view_line_draw(TEXT_BUFFER_VIEW_REC *view, LINE_REC *line, int subline, int ypos, int max) { INDENT_FUNC indent_func; LINE_CACHE_REC *cache; const unsigned char *text, *end, *text_newline; unsigned char *tmp; int xpos, color, drawcount, first, need_move, need_clrtoeol, char_width; if (view->dirty) /* don't bother drawing anything - redraw is coming */ return 0; cache = textbuffer_view_get_line_cache(view, line); if (subline >= cache->count) return 0; color = ATTR_RESET; need_move = TRUE; need_clrtoeol = FALSE; xpos = drawcount = 0; first = TRUE; text_newline = text = subline == 0 ? line->text : cache->lines[subline-1].start; for (;;) { if (text == text_newline) { if (need_clrtoeol && xpos < term_width) { term_set_color(view->window, ATTR_RESET); term_clrtoeol(view->window); } if (first) first = FALSE; else { ypos++; if (--max == 0) break; } if (subline > 0) { /* continuing previous line - indent it */ indent_func = cache->lines[subline-1].indent_func; if (indent_func == NULL) xpos = cache->lines[subline-1].indent; color = cache->lines[subline-1].color; } else { indent_func = NULL; } if (xpos == 0 && indent_func == NULL) need_clrtoeol = TRUE; else { /* line was indented - need to clear the indented area first */ term_set_color(view->window, ATTR_RESET); term_move(view->window, 0, ypos); term_clrtoeol(view->window); if (indent_func != NULL) xpos = indent_func(view, line, ypos); } if (need_move || xpos > 0) term_move(view->window, xpos, ypos); term_set_color(view->window, color); if (subline == cache->count-1) { text_newline = NULL; need_move = FALSE; } else { /* get the beginning of the next subline */ text_newline = cache->lines[subline].start; need_move = !cache->lines[subline].continues; } drawcount++; subline++; } if (*text == '\0') { /* command */ text++; if (*text == LINE_CMD_EOL || *text == LINE_CMD_FORMAT) break; if (*text == LINE_CMD_CONTINUE) { /* jump to next block */ memcpy(&tmp, text+1, sizeof(unsigned char *)); text = tmp; continue; } else if (*text == LINE_CMD_INDENT_FUNC) { text += sizeof(INDENT_FUNC); } else { update_cmd_color(*text, &color); term_set_color(view->window, color); } text++; continue; } end = text; if (view->utf8) { unichar chr = get_utf8_char(&end, 6); char_width = utf8_width(chr); } else { char_width = 1; } xpos += char_width; if (xpos <= term_width) { if (*text >= 32 && (end != text || (*text & 127) >= 32)) { for (; text < end; text++) term_addch(view->window, *text); term_addch(view->window, *text); } else { /* low-ascii */ term_set_color(view->window, ATTR_RESET|ATTR_REVERSE); term_addch(view->window, (*text & 127)+'A'-1); term_set_color(view->window, color); } } text++; } if (need_clrtoeol && xpos < term_width) { term_set_color(view->window, ATTR_RESET); term_clrtoeol(view->window); } return drawcount; }
/* * Wrap the text, if necessary. The variable indent is the indent for the * first line, indent2 is the indent for all other lines. * If indent is negative, assume that already -indent columns have been * consumed (and no extra indent is necessary for the first line). */ void strbuf_add_wrapped_text(struct strbuf *buf, const char *text, int indent1, int indent2, int width) { int indent, w, assume_utf8 = 1; const char *bol, *space, *start = text; size_t orig_len = buf->len; if (width <= 0) { strbuf_add_indented_text(buf, text, indent1, indent2); return; } retry: bol = text; w = indent = indent1; space = NULL; if (indent < 0) { w = -indent; space = text; } for (;;) { char c; size_t skip; while ((skip = display_mode_esc_sequence_len(text))) text += skip; c = *text; if (!c || isspace(c)) { if (w <= width || !space) { const char *start = bol; if (!c && text == start) return; if (space) start = space; else strbuf_addchars(buf, ' ', indent); strbuf_add(buf, start, text - start); if (!c) return; space = text; if (c == '\t') w |= 0x07; else if (c == '\n') { space++; if (*space == '\n') { strbuf_addch(buf, '\n'); goto new_line; } else if (!isalnum(*space)) goto new_line; else strbuf_addch(buf, ' '); } w++; text++; } else { new_line: strbuf_addch(buf, '\n'); text = bol = space + isspace(*space); space = NULL; w = indent = indent2; } continue; } if (assume_utf8) { w += utf8_width(&text, NULL); if (!text) { assume_utf8 = 0; text = start; strbuf_setlen(buf, orig_len); goto retry; } } else { w++; text++; } } }
int optionally_enter(char *utf8string, int y_base, int x_base, int utf8string_size, char *utf8prompt, ESCKEY_S *escape_list, HelpType help, int *flags) { UCS *string = NULL, ucs; size_t string_size; UCS *s2; UCS *saved_original = NULL; char *candidate; UCS *kill_buffer = NULL; UCS *k, *kb; int field_pos; /* offset into array dline.vl */ int i, j, return_v, cols, prompt_width, too_thin, real_y_base, km_popped, passwd; char **help_text; long fkey_table[12]; struct key_menu *km; bitmap_t bitmap; COLOR_PAIR *lastc = NULL, *promptc = NULL; struct variable *vars = ps_global->vars; struct display_line dline; #ifdef _WINDOWS int cursor_shown; #endif dprint((5, "=== optionally_enter called ===\n")); dprint((9, "utf8string:\"%s\" y:%d x:%d length: %d append: %d\n", utf8string ? utf8string : "", x_base, y_base, utf8string_size, (flags && *flags & OE_APPEND_CURRENT))); dprint((9, "passwd:%d utf8prompt:\"%s\" label:\"%s\"\n", (flags && *flags & OE_PASSWD_NOAST) ? 10 : (flags && *flags & OE_PASSWD) ? 1 : 0, utf8prompt ? utf8prompt : "", (escape_list && escape_list[0].ch != -1 && escape_list[0].label) ? escape_list[0].label: "")); if(!ps_global->ttyo) return(pre_screen_config_opt_enter(utf8string, utf8string_size, utf8prompt, escape_list, help, flags)); #ifdef _WINDOWS if (mswin_usedialog ()) return(win_dialog_opt_enter(utf8string, utf8string_size, utf8prompt, escape_list, help, flags)); #endif /* * Utf8string comes in as UTF-8. We'll convert it to a UCS-4 array and operate on * that array, then convert it back before returning. Utf8string_size is the size * of the utf8string array but that doesn't help us much for the array we need to * operate on here. We'll just allocate a big array and then cut it off when * sending it back. * * This should come before the specialized calls above but those aren't * converted to use UCS-4 yet. */ string = utf8_to_ucs4_cpystr(utf8string); dline.vused = ucs4_strlen(string); string_size = (2 * MAX(utf8string_size,dline.vused) + 100); fs_resize((void **) &string, string_size * sizeof(UCS)); suspend_busy_cue(); cols = ps_global->ttyo->screen_cols; prompt_width = utf8_width(utf8prompt); too_thin = 0; km_popped = 0; if(y_base > 0) real_y_base = y_base; else{ real_y_base = y_base + ps_global->ttyo->screen_rows; real_y_base = MAX(real_y_base, 0); } flush_ordered_messages(); mark_status_dirty(); if(flags && *flags & OE_APPEND_CURRENT) /* save a copy in case of cancel */ saved_original = ucs4_cpystr(string); /* * build the function key mapping table, skipping predefined keys... */ memset(fkey_table, NO_OP_COMMAND, 12 * sizeof(long)); for(i = 0, j = 0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){ if(i+j == OE_HELP_KEY) j++; if(i+j == OE_CANCEL_KEY) j++; if(i+j == OE_ENTER_KEY) j++; fkey_table[i+j] = escape_list[i].ch; } /* assumption that HelpType is char ** */ help_text = help; if(help_text){ /*---- Show help text -----*/ int width = ps_global->ttyo->screen_cols - x_base; if(FOOTER_ROWS(ps_global) == 1){ km_popped++; FOOTER_ROWS(ps_global) = 3; clearfooter(ps_global); y_base = -3; real_y_base = y_base + ps_global->ttyo->screen_rows; } for(j = 0; j < 2 && help_text[j]; j++){ MoveCursor(real_y_base + 1 + j, x_base); CleartoEOLN(); if(width < utf8_width(help_text[j])){ char *tmp = cpystr(help_text[j]); (void) utf8_truncate(tmp, width); PutLine0(real_y_base + 1 + j, x_base, tmp); fs_give((void **) &tmp); } else PutLine0(real_y_base + 1 + j, x_base, help_text[j]); } } else{ clrbitmap(bitmap); clrbitmap((km = &oe_keymenu)->bitmap); /* force formatting */ if(!(flags && (*flags) & OE_DISALLOW_HELP)) setbitn(OE_HELP_KEY, bitmap); setbitn(OE_ENTER_KEY, bitmap); if(!(flags && (*flags) & OE_DISALLOW_CANCEL)) setbitn(OE_CANCEL_KEY, bitmap); setbitn(OE_CTRL_T_KEY, bitmap); /*---- Show the usual possible keys ----*/ for(i=0,j=0; escape_list && escape_list[i].ch != -1 && i+j < 12; i++){ if(i+j == OE_HELP_KEY) j++; if(i+j == OE_CANCEL_KEY) j++; if(i+j == OE_ENTER_KEY) j++; oe_keymenu.keys[i+j].label = escape_list[i].label; oe_keymenu.keys[i+j].name = escape_list[i].name; setbitn(i+j, bitmap); } for(i = i+j; i < 12; i++) if(!(i == OE_HELP_KEY || i == OE_ENTER_KEY || i == OE_CANCEL_KEY)) oe_keymenu.keys[i].name = NULL; draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu); } if(pico_usingcolor() && VAR_PROMPT_FORE_COLOR && VAR_PROMPT_BACK_COLOR && pico_is_good_color(VAR_PROMPT_FORE_COLOR) && pico_is_good_color(VAR_PROMPT_BACK_COLOR)){ lastc = pico_get_cur_color(); if(lastc){ promptc = new_color_pair(VAR_PROMPT_FORE_COLOR, VAR_PROMPT_BACK_COLOR); (void)pico_set_colorp(promptc, PSC_NONE); } } else StartInverse(); /* * if display length isn't wide enough to support input, * shorten up the prompt... */ if((dline.dwid = cols - (x_base + prompt_width)) < MIN_OPT_ENT_WIDTH){ char *p; unsigned got_width; /* * Scoot prompt pointer forward at least (MIN_OPT_ENT_WIDTH - dline.dwid) screencells. */ p = utf8_count_forw_width(utf8prompt, MIN_OPT_ENT_WIDTH-dline.dwid, &got_width); if(got_width < MIN_OPT_ENT_WIDTH-dline.dwid) p = utf8_count_forw_width(utf8prompt, MIN_OPT_ENT_WIDTH+1-dline.dwid, &got_width); if(p){ prompt_width = utf8_width(p); dline.dwid = cols - (x_base + prompt_width); utf8prompt = p; } } /* * How many UCS-4 characters will we need to make up the width dwid? It could be * unlimited because of zero-width characters, I suppose, but realistically it * isn't going to be much more than dwid. */ dline.dlen = 2 * dline.dwid + 100; dline.dl = (UCS *) fs_get(dline.dlen * sizeof(UCS)); dline.olddl = (UCS *) fs_get(dline.dlen * sizeof(UCS)); memset(dline.dl, 0, dline.dlen * sizeof(UCS)); memset(dline.olddl, 0, dline.dlen * sizeof(UCS)); dline.movecursor = MoveCursor; dline.writechar = Writewchar; dline.row = real_y_base; dline.col = x_base + prompt_width; dline.vl = string; dline.vlen = --string_size; /* -1 for terminating zero */ dline.vbase = field_pos = 0; #ifdef _WINDOWS cursor_shown = mswin_showcaret(1); #endif PutLine0(real_y_base, x_base, utf8prompt); /* * If appending, position field_pos at end of input. */ if(flags && *flags & OE_APPEND_CURRENT) while(string[field_pos]) field_pos++; passwd = (flags && *flags & OE_PASSWD_NOAST) ? 10 : (flags && *flags & OE_PASSWD) ? 1 : 0; line_paint(field_pos, &dline, &passwd); /*---------------------------------------------------------------------- The main loop loops until someone sets the return_v. ----------------------------------------------------------------------*/ return_v = -10; while(return_v == -10) { #ifdef MOUSE mouse_in_content(KEY_MOUSE, -1, -1, 0x5, 0); register_mfunc(mouse_in_content, real_y_base, x_base + prompt_width, real_y_base, ps_global->ttyo->screen_cols); #endif #ifdef _WINDOWS mswin_allowpaste(MSWIN_PASTE_LINE); g_mc_row = real_y_base; g_mc_col = x_base + prompt_width; mswin_mousetrackcallback(pcpine_oe_cursor); #endif /* Timeout 10 min to keep imap mail stream alive */ ps_global->conceal_sensitive_debugging = passwd ? 1 : 0; ucs = read_char(600); ps_global->conceal_sensitive_debugging = 0; #ifdef MOUSE clear_mfunc(mouse_in_content); #endif #ifdef _WINDOWS mswin_allowpaste(MSWIN_PASTE_DISABLE); mswin_mousetrackcallback(NULL); #endif /* * Don't want to intercept all characters if typing in passwd. * We select an ad hoc set that we will catch and let the rest * through. We would have caught the set below in the big switch * but we skip the switch instead. Still catch things like ^K, * DELETE, ^C, RETURN. */ if(passwd) switch(ucs){ case ctrl('F'): case KEY_RIGHT: case ctrl('B'): case KEY_LEFT: case ctrl('U'): case ctrl('A'): case KEY_HOME: case ctrl('E'): case KEY_END: case TAB: goto ok_for_passwd; } if(too_thin && ucs != KEY_RESIZE && ucs != ctrl('Z') && ucs != ctrl('C')) goto bleep; switch(ucs){ /*--------------- KEY RIGHT ---------------*/ case ctrl('F'): case KEY_RIGHT: if(field_pos >= string_size || string[field_pos] == '\0') goto bleep; line_paint(++field_pos, &dline, &passwd); break; /*--------------- KEY LEFT ---------------*/ case ctrl('B'): case KEY_LEFT: if(field_pos <= 0) goto bleep; line_paint(--field_pos, &dline, &passwd); break; /*-------------------- WORD SKIP --------------------*/ case ctrl('@'): /* * Note: read_char *can* return NO_OP_COMMAND which is * the def'd with the same value as ^@ (NULL), BUT since * read_char has a big timeout (>25 secs) it won't. */ /* skip thru current word */ while(string[field_pos] && isalnum((unsigned char) string[field_pos])) field_pos++; /* skip thru current white space to next word */ while(string[field_pos] && !isalnum((unsigned char) string[field_pos])) field_pos++; line_paint(field_pos, &dline, &passwd); break; /*-------------------- RETURN --------------------*/ case PF4: if(F_OFF(F_USE_FK,ps_global)) goto bleep; case ctrl('J'): case ctrl('M'): return_v = 0; break; /*-------------------- Destructive backspace --------------------*/ case '\177': /* DEL */ case ctrl('H'): /* Try and do this with by telling the terminal to delete a a character. If that fails, then repaint the rest of the line, acheiving the same much less efficiently */ if(field_pos <= 0) goto bleep; field_pos--; /* drop thru to pull line back ... */ /*-------------------- Delete char --------------------*/ case ctrl('D'): case KEY_DEL: if(field_pos >= string_size || !string[field_pos]) goto bleep; dline.vused--; for(s2 = &string[field_pos]; *s2 != 0; s2++) *s2 = s2[1]; *s2 = 0; /* Copy last NULL */ line_paint(field_pos, &dline, &passwd); if(flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; break; /*--------------- Kill line -----------------*/ case ctrl('K'): if(kill_buffer != NULL) fs_give((void **) &kill_buffer); if(field_pos != 0 || string[0]){ if(!passwd && F_ON(F_DEL_FROM_DOT, ps_global)) dline.vused -= ucs4_strlen(&string[i = field_pos]); else dline.vused = i = 0; kill_buffer = ucs4_cpystr(&string[field_pos = i]); string[field_pos] = '\0'; line_paint(field_pos, &dline, &passwd); if(flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; } break; /*------------------- Undelete line --------------------*/ case ctrl('U'): if(kill_buffer == NULL) goto bleep; /* Make string so it will fit */ kb = ucs4_cpystr(kill_buffer); if(ucs4_strlen(kb) + ucs4_strlen(string) > string_size) kb[string_size - ucs4_strlen(string)] = '\0'; if(string[field_pos] == '\0') { /*--- adding to the end of the string ----*/ for(k = kb; *k; k++) string[field_pos++] = *k; string[field_pos] = '\0'; } else{ int shift; shift = ucs4_strlen(kb); /* shift field_pos ... end to right */ for(k = &string[field_pos] + ucs4_strlen(&string[field_pos]); k >= &string[field_pos]; k--) *(k+shift) = *k; for(k = kb; *k; k++) string[field_pos++] = *k; } if(*kb && flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; dline.vused = ucs4_strlen(string); fs_give((void **) &kb); line_paint(field_pos, &dline, &passwd); break; /*-------------------- Interrupt --------------------*/ case ctrl('C'): /* ^C */ if(F_ON(F_USE_FK,ps_global) || (flags && ((*flags) & OE_DISALLOW_CANCEL))) goto bleep; goto cancel; case PF2: if(F_OFF(F_USE_FK,ps_global) || (flags && ((*flags) & OE_DISALLOW_CANCEL))) goto bleep; cancel: return_v = 1; if(saved_original){ for(i = 0; saved_original[i]; i++) string[i] = saved_original[i]; string[i] = 0; } break; case ctrl('A'): case KEY_HOME: /*-------------------- Start of line -------------*/ line_paint(field_pos = 0, &dline, &passwd); break; case ctrl('E'): case KEY_END: /*-------------------- End of line ---------------*/ line_paint(field_pos = dline.vused, &dline, &passwd); break; /*-------------------- Help --------------------*/ case ctrl('G') : case PF1: if(flags && ((*flags) & OE_DISALLOW_HELP)) goto bleep; else if(FOOTER_ROWS(ps_global) == 1 && km_popped == 0){ km_popped++; FOOTER_ROWS(ps_global) = 3; clearfooter(ps_global); if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); draw_keymenu(km, bitmap, cols, 1-FOOTER_ROWS(ps_global), 0, FirstMenu); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); mark_keymenu_dirty(); y_base = -3; dline.row = real_y_base = y_base + ps_global->ttyo->screen_rows; PutLine0(real_y_base, x_base, utf8prompt); memset(dline.dl, 0, dline.dlen * sizeof(UCS)); memset(dline.olddl, 0, dline.dlen * sizeof(UCS)); line_paint(field_pos, &dline, &passwd); break; } if(FOOTER_ROWS(ps_global) > 1){ mark_keymenu_dirty(); return_v = 3; } else goto bleep; break; #ifdef MOUSE /* Mouse support untested in pine 5.00 */ case KEY_MOUSE : { MOUSEPRESS mp; int w; mouse_get_last (NULL, &mp); switch(mp.button){ case M_BUTTON_LEFT : /* position cursor */ mp.col -= dline.col; /* * We have to figure out which character is under the cursor. * This is complicated by the fact that characters may * be other than one cell wide. */ /* the -1 is for the '<' when text is offscreen left */ w = (dline.vbase > 0) ? mp.col-1 : mp.col; if(mp.col <= 0) field_pos = dline.vbase - 1; else{ if(dline.vused <= dline.vbase || ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vused-1) <= w) field_pos = dline.vused; else{ /* * Find index of 1st character that causes the * width to be > w. */ for(i = 0; ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vbase+i) <= w; i++) ; field_pos = dline.vbase + i; } } field_pos = MIN(MAX(field_pos, 0), dline.vused); /* just allow line_paint to choose vbase */ line_paint(field_pos, &dline, &passwd); break; case M_BUTTON_RIGHT : #ifdef _WINDOWS /* * Same as M_BUTTON_LEFT except we paste in text after * moving the cursor. */ mp.col -= dline.col; /* the -1 is for the '<' when text is offscreen left */ w = (dline.vbase > 0) ? mp.col-1 : mp.col; if(mp.col <= 0) field_pos = dline.vbase - 1; else{ if(dline.vused <= dline.vbase || ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vused-1) <= w) field_pos = dline.vused; else{ /* * Find index of 1st character that causes the * width to be > w. */ for(i = 0; ucs4_str_width_a_to_b(dline.vl,dline.vbase,dline.vbase+i) <= w; i++) ; field_pos = dline.vbase + i; } } field_pos = MIN(MAX(field_pos, 0), dline.vused); line_paint(field_pos, &dline, &passwd); mswin_allowpaste(MSWIN_PASTE_LINE); mswin_paste_popup(); mswin_allowpaste(MSWIN_PASTE_DISABLE); break; #endif case M_BUTTON_MIDDLE : /* NO-OP for now */ default: /* just ignore */ break; } } break; #endif case NO_OP_IDLE: /* * Keep mail stream alive by checking for new mail. * If we're asking for a password in a login prompt * we don't want to check for new_mail because the * new mail check might be what got us here in the first * place (because of a filter trying to save a message). * If we need to wait for the user to come back then * the caller will just have to deal with the failure * to login. */ i = -1; if(!ps_global->no_newmail_check_from_optionally_enter) i = new_mail(0, 2, NM_DEFER_SORT); if(sp_expunge_count(ps_global->mail_stream) && flags && ((*flags) & OE_SEQ_SENSITIVE)) goto cancel; if(i < 0){ line_paint(field_pos, &dline, &passwd); break; /* no changes, get on with life */ } /* Else fall into redraw */ /*-------------------- Redraw --------------------*/ case ctrl('L'): /*---------------- re size ----------------*/ case KEY_RESIZE: dline.row = real_y_base = y_base > 0 ? y_base : y_base + ps_global->ttyo->screen_rows; if(lastc) (void)pico_set_colorp(lastc, PSC_NONE); else EndInverse(); ClearScreen(); redraw_titlebar(); if(ps_global->redrawer != (void (*)(void))NULL) (*ps_global->redrawer)(); redraw_keymenu(); if(promptc) (void)pico_set_colorp(promptc, PSC_NONE); else StartInverse(); PutLine0(real_y_base, x_base, utf8prompt); cols = ps_global->ttyo->screen_cols; too_thin = 0; if(cols < x_base + prompt_width + 4){ Writechar(BELL, 0); PutLine0(real_y_base, 0, "Screen's too thin. Ouch!"); too_thin = 1; } else{ dline.col = x_base + prompt_width; dline.dwid = cols - (x_base + prompt_width); dline.dlen = 2 * dline.dwid + 100; fs_resize((void **) &dline.dl, (size_t) dline.dlen * sizeof(UCS)); fs_resize((void **) &dline.olddl, (size_t) dline.dlen * sizeof(UCS)); memset(dline.dl, 0, dline.dlen * sizeof(UCS)); memset(dline.olddl, 0, dline.dlen * sizeof(UCS)); line_paint(field_pos, &dline, &passwd); } fflush(stdout); dprint((9, "optionally_enter RESIZE new_cols:%d too_thin: %d\n", cols, too_thin)); break; case PF3 : /* input to potentially remap */ case PF5 : case PF6 : case PF7 : case PF8 : case PF9 : case PF10 : case PF11 : case PF12 : if(F_ON(F_USE_FK,ps_global) && fkey_table[ucs - PF1] != NO_OP_COMMAND) ucs = fkey_table[ucs - PF1]; /* remap function key input */ default: if(escape_list){ /* in the escape key list? */ for(j=0; escape_list[j].ch != -1; j++){ if(escape_list[j].ch == ucs){ return_v = escape_list[j].rval; break; } } if(return_v != -10) break; } if(ucs < 0x80 && FILTER_THIS((unsigned char) ucs)){ bleep: putc(BELL, stdout); continue; } ok_for_passwd: /*--- Insert a character -----*/ if(dline.vused >= string_size) goto bleep; /*---- extending the length of the string ---*/ for(s2 = &string[++dline.vused]; s2 - string > field_pos; s2--) *s2 = *(s2-1); string[field_pos++] = ucs; line_paint(field_pos, &dline, &passwd); if(flags) /* record change if requested */ *flags |= OE_USER_MODIFIED; } /*---- End of switch on char ----*/ } #ifdef _WINDOWS if(!cursor_shown) mswin_showcaret(0); #endif if(dline.dl) fs_give((void **) &dline.dl); if(dline.olddl) fs_give((void **) &dline.olddl); if(saved_original) fs_give((void **) &saved_original); if(kill_buffer) fs_give((void **) &kill_buffer); /* * Change string back into UTF-8. */ candidate = ucs4_to_utf8_cpystr(string); if(string) fs_give((void **) &string); if(candidate){ strncpy(utf8string, candidate, utf8string_size); utf8string[utf8string_size-1] = '\0'; fs_give((void **) &candidate); } if (!(flags && (*flags) & OE_KEEP_TRAILING_SPACE)) removing_trailing_white_space(utf8string); if(lastc){ (void)pico_set_colorp(lastc, PSC_NONE); free_color_pair(&lastc); if(promptc) free_color_pair(&promptc); } else EndInverse(); MoveCursor(real_y_base, x_base); /* Move the cursor to show we're done */ fflush(stdout); resume_busy_cue(0); if(km_popped){ FOOTER_ROWS(ps_global) = 1; clearfooter(ps_global); ps_global->mangled_body = 1; } return(return_v); }
/* * Calculate sizes, populate arrays, initialize window */ void uimenu::setup() { bool w_auto = (w_width == -1 || w_width == -2 ); bool w_autofold = ( w_width == -2); if ( w_auto ) { w_width = 4; if ( !title.empty() ) { w_width = title.size() + 5; } } bool h_auto = (w_height == -1); if ( h_auto ) { w_height = 4; } max_entry_len = 0; std::vector<int> autoassign; int pad = pad_left + pad_right + 2; for ( size_t i = 0; i < entries.size(); i++ ) { int txtwidth = utf8_width(entries[ i ].txt.c_str()); if ( txtwidth > max_entry_len ) { max_entry_len = txtwidth; } if(entries[ i ].enabled) { if( entries[ i ].hotkey > 0 ) { keymap[ entries[ i ].hotkey ] = i; } else if ( entries[ i ].hotkey == -1 && i < 100 ) { autoassign.push_back(i); } if ( entries[ i ].retval == -1 ) { entries[ i ].retval = i; } if ( w_auto && w_width < txtwidth + pad + 4 ) { w_width = txtwidth + pad + 4; } } else { if ( w_auto && w_width < txtwidth + pad + 4 ) { w_width = txtwidth + pad + 4; // todo: or +5 if header } } if ( entries[ i ].text_color == C_UNSET_MASK ) { entries[ i ].text_color = text_color; } fentries.push_back( i ); } static const std::string hotkeys("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); size_t next_free_hotkey = 0; for( auto it = autoassign.begin(); it != autoassign.end() && next_free_hotkey < hotkeys.size(); ++it ) { while( next_free_hotkey < hotkeys.size() ) { const int setkey = hotkeys[next_free_hotkey]; next_free_hotkey++; if( keymap.count( setkey ) == 0 ) { entries[*it].hotkey = setkey; keymap[setkey] = *it; break; } } } if (w_auto && w_width > TERMX) { w_width = TERMX; } if(!text.empty() ) { int twidth = utf8_width(text.c_str()); bool formattxt = true; int realtextwidth = 0; if ( textwidth == -1 ) { if ( w_autofold || !w_auto ) { realtextwidth = w_width - 4; } else { realtextwidth = twidth; if ( twidth + 4 > w_width ) { if ( realtextwidth + 4 > TERMX ) { realtextwidth = TERMX - 4; } textformatted = foldstring(text, realtextwidth); formattxt = false; realtextwidth = 10; for (auto &l : textformatted) { if ( utf8_width(l.c_str()) > realtextwidth ) { realtextwidth = utf8_width(l.c_str()); } } if ( realtextwidth + 4 > w_width ) { w_width = realtextwidth + 4; } } } } else if ( textwidth != -1 ) { realtextwidth = textwidth; } if ( formattxt == true ) { textformatted = foldstring(text, realtextwidth); } } if (h_auto) { w_height = 3 + textformatted.size() + entries.size(); } if ( w_height > TERMY ) { w_height = TERMY; } vmax = entries.size(); if ( vmax + 3 + (int)textformatted.size() > w_height ) { vmax = w_height - 3 - textformatted.size(); if ( vmax < 1 ) { if (textformatted.empty()) { popup("Can't display menu options, 0 %d available screen rows are occupied\nThis is probably a bug.\n", TERMY); } else { popup("Can't display menu options, %d %d available screen rows are occupied by\n'%s\n(snip)\n%s'\nThis is probably a bug.\n", textformatted.size(), TERMY, textformatted[0].c_str(), textformatted[ textformatted.size() - 1 ].c_str() ); } } } if (w_x == -1) { w_x = int((TERMX - w_width) / 2); } if (w_y == -1) { w_y = int((TERMY - w_height) / 2); } if ( scrollbar_side == -1 ) { scrollbar_side = ( pad_left > 0 ? 1 : 0 ); } if ( (int)entries.size() <= vmax ) { scrollbar_auto = false; } window = newwin(w_height, w_width, w_y, w_x); werase(window); draw_border(window, border_color); if( !title.empty() ) { mvwprintz(window, 0, 1, border_color, "< "); wprintz(window, title_color, "%s", title.c_str() ); wprintz(window, border_color, " >"); } fselected = selected; if(fselected < 0) { fselected = selected = 0; } else if(fselected >= static_cast<int>(entries.size())) { fselected = selected = static_cast<int>(entries.size()) - 1; } if(!entries.empty() && !entries[fselected].enabled) { for(size_t i = 0; i < entries.size(); ++i) { if(entries[i].enabled) { fselected = selected = i; break; } } } started = true; }
void test_pattern(int iCurrentPage, int iCurrentLine) { std::vector<std::string> vMatchingItems; std::string sItemName = ""; if (vAutoPickupRules[iCurrentPage][iCurrentLine].sRule == "") { return; } //Loop through all itemfactory items //APU now ignores prefixes, bottled items and suffix combinations still not generated for( auto &p : item_controller->get_all_itypes() ) { sItemName = p.second->nname(1); if (vAutoPickupRules[iCurrentPage][iCurrentLine].bActive && auto_pickup_match(sItemName, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule)) { vMatchingItems.push_back(sItemName); } } const int iOffsetX = 15 + ((TERMX > FULL_SCREEN_WIDTH) ? (TERMX - FULL_SCREEN_WIDTH) / 2 : 0); const int iOffsetY = 5 + ((TERMY > FULL_SCREEN_HEIGHT) ? (TERMY - FULL_SCREEN_HEIGHT) / 2 : 0); int iStartPos = 0; const int iContentHeight = FULL_SCREEN_HEIGHT - 8; const int iContentWidth = FULL_SCREEN_WIDTH - 30; std::stringstream sTemp; WINDOW *w_test_rule_border = newwin(iContentHeight + 2, iContentWidth, iOffsetY, iOffsetX); WINDOW_PTR w_test_rule_borderptr( w_test_rule_border ); WINDOW *w_test_rule_content = newwin(iContentHeight, iContentWidth - 2, 1 + iOffsetY, 1 + iOffsetX); WINDOW_PTR w_test_rule_contentptr( w_test_rule_content ); draw_border(w_test_rule_border); int nmatch = vMatchingItems.size(); std::string buf = string_format(ngettext("%1$d item matches: %2$s", "%1$d items match: %2$s", nmatch), nmatch, vAutoPickupRules[iCurrentPage][iCurrentLine].sRule.c_str()); mvwprintz(w_test_rule_border, 0, iContentWidth / 2 - utf8_width(buf.c_str()) / 2, hilite(c_white), "%s", buf.c_str()); mvwprintz(w_test_rule_border, iContentHeight + 1, 1, red_background(c_white), _("Won't display bottled and suffixes=(fits)")); wrefresh(w_test_rule_border); iCurrentLine = 0; input_context ctxt("AUTO_PICKUP_TEST"); ctxt.register_updown(); ctxt.register_action("QUIT"); while(true) { // Clear the lines for (int i = 0; i < iContentHeight; i++) { for (int j = 0; j < 79; j++) { mvwputch(w_test_rule_content, i, j, c_black, ' '); } } calcStartPos(iStartPos, iCurrentLine, iContentHeight, vMatchingItems.size()); // display auto pickup for (int i = iStartPos; i < (int)vMatchingItems.size(); i++) { if (i >= iStartPos && i < iStartPos + ((iContentHeight > (int)vMatchingItems.size()) ? (int)vMatchingItems.size() : iContentHeight)) { nc_color cLineColor = c_white; sTemp.str(""); sTemp << i + 1; mvwprintz(w_test_rule_content, i - iStartPos, 0, cLineColor, "%s", sTemp.str().c_str()); mvwprintz(w_test_rule_content, i - iStartPos, 4, cLineColor, ""); if (iCurrentLine == i) { wprintz(w_test_rule_content, c_yellow, ">> "); } else { wprintz(w_test_rule_content, c_yellow, " "); } wprintz(w_test_rule_content, (iCurrentLine == i) ? hilite(cLineColor) : cLineColor, vMatchingItems[i].c_str()); } } wrefresh(w_test_rule_content); const std::string action = ctxt.handle_input(); if (action == "DOWN") { iCurrentLine++; if (iCurrentLine >= (int)vMatchingItems.size()) { iCurrentLine = 0; } } else if (action == "UP") { iCurrentLine--; if (iCurrentLine < 0) { iCurrentLine = vMatchingItems.size() - 1; } } else { break; } } }
void game::item_action_menu() { const auto &gen = item_action_generator::generator(); const action_map &item_actions = gen.get_item_action_map(); // A bit of a hack for now. If more pseudos get implemented, this should be un-hacked std::vector<item *> pseudos; item toolset( "toolset", calendar::turn ); if( u.has_active_bionic( "bio_tools" ) ) { pseudos.push_back( &toolset ); } item_action_map iactions = gen.map_actions_to_items( u, pseudos ); if( iactions.empty() ) { popup( _( "You don't have any items with registered uses" ) ); } uimenu kmenu; kmenu.text = _( "Execute which action?" ); kmenu.return_invalid = true; input_context ctxt( "ITEM_ACTIONS" ); actmenu_cb callback( item_actions ); kmenu.callback = &callback; int num = 0; const auto assigned_action = [&iactions]( const item_action_id & action ) { return iactions.find( action ) != iactions.end(); }; std::vector<std::tuple<item_action_id, std::string, std::string>> menu_items; // Sorts menu items by action. typedef decltype( menu_items )::iterator Iter; const auto sort_menu = [&menu_items]( Iter from, Iter to ) { std::sort( from, to, []( const std::tuple<item_action_id, std::string, std::string> &lhs, const std::tuple<item_action_id, std::string, std::string> &rhs ) { return std::get<1>( lhs ).compare( std::get<1>( rhs ) ) < 0; } ); }; // Add mapped actions to the menu vector. std::transform( iactions.begin(), iactions.end(), std::back_inserter( menu_items ), []( const std::pair<item_action_id, item *> &elem ) { std::stringstream ss; ss << elem.second->display_name(); if( elem.second->ammo_required() ) { ss << " (" << elem.second->ammo_required() << '/' << elem.second->ammo_remaining() << ')'; } const auto method = elem.second->get_use( elem.first ); return std::make_tuple( method->get_type(), method->get_name(), ss.str() ); } ); // Sort mapped actions. sort_menu( menu_items.begin(), menu_items.end() ); // Add unmapped but binded actions to the menu vector. for( const auto &elem : item_actions ) { if( key_bound_to( ctxt, elem.first ) != '\0' && !assigned_action( elem.first ) ) { menu_items.emplace_back( elem.first, gen.get_action_name( elem.first ), "-" ); } } // Sort unmapped actions. auto iter = menu_items.begin(); std::advance( iter, iactions.size() ); sort_menu( iter, menu_items.end() ); // Determine max lengths, to print the menu nicely. std::pair<int, int> max_len; for( const auto &elem : menu_items ) { max_len.first = std::max( max_len.first, utf8_width( std::get<1>( elem ), true ) ); max_len.second = std::max( max_len.second, utf8_width( std::get<2>( elem ), true ) ); } // Fill the menu. for( const auto &elem : menu_items ) { std::stringstream ss; ss << std::get<1>( elem ) << std::string( max_len.first - utf8_width( std::get<1>( elem ), true ), ' ' ) << std::string( 4, ' ' ); ss << std::get<2>( elem ) << std::string( max_len.second - utf8_width( std::get<2>( elem ), true ), ' ' ); const char bind = key_bound_to( ctxt, std::get<0>( elem ) ); const bool enabled = assigned_action( std::get<0>( elem ) ); kmenu.addentry( num, enabled, bind, ss.str() ); num++; } kmenu.query(); if( kmenu.ret < 0 || kmenu.ret >= ( int )iactions.size() ) { return; } draw_ter(); const item_action_id action = std::get<0>( menu_items[kmenu.ret] ); item *it = iactions[action]; if( u.invoke_item( it, action ) ) { u.i_rem( it ); // Need to remove item } u.inv.restack( &u ); u.inv.unsort(); }
void uimenu::show() { if (!started) { bool w_auto = (w_width == -1 || w_width == -2 ); bool w_autofold = ( w_width == -2); int realtextwidth = 0; if ( w_auto ) { w_width = 4; } bool h_auto = (w_height == -1); if ( h_auto ) { w_height = 4; } std::vector<int> autoassign; autoassign.clear(); int pad = pad_left + pad_right + 2; for ( int i = 0; i < entries.size(); i++ ) { int txtwidth = utf8_width(entries[ i ].txt.c_str()); if(entries[ i ].enabled) { if( entries[ i ].hotkey > 0 ) { keymap[ entries[ i ].hotkey ] = i; } else if ( entries[ i ].hotkey == -1 && i < 100 ) { autoassign.push_back(i); } if ( entries[ i ].retval == -1 ) { entries[ i ].retval = i; } if ( w_auto && w_width < txtwidth + pad + 4 ) { w_width = txtwidth + pad + 4; } } else { if ( w_auto && w_width < txtwidth + pad + 4 ) { w_width = txtwidth + pad + 4; // todo: or +5 if header } } if ( entries[ i ].text_color == C_UNSET_MASK ) { entries[ i ].text_color = text_color; } } if ( autoassign.size() > 0 ) { for ( int a = 0; a < autoassign.size(); a++ ) { int palloc = autoassign[ a ]; int setkey=-1; if ( palloc < 9 ) { setkey = palloc + 49; // 1-9; } else if ( palloc == 9 ) { setkey = palloc + 39; // 0; } else if ( palloc < 36 ) { setkey = palloc + 87; // a-z } else if ( palloc < 61 ) { setkey = palloc + 29; // A-Z } if ( setkey != -1 && keymap.find(setkey) == keymap.end() ) { entries[ palloc ].hotkey = setkey; keymap[ setkey ] = palloc; } } } if (w_auto && w_width > TERMX) { w_width = TERMX; } if(text.size() > 0 ) { int twidth = utf8_width(text.c_str()); bool formattxt=true; if ( textwidth == -1 ) { if ( w_autofold || !w_auto ) { realtextwidth = w_width - 4; } else { realtextwidth = twidth; if ( twidth + 4 > w_width ) { if ( realtextwidth + 4 > TERMX ) { realtextwidth = TERMX - 4; } textformatted = foldstring(text, realtextwidth); formattxt=false; realtextwidth = 10; for ( int l=0; l < textformatted.size(); l++ ) { if ( utf8_width(textformatted[l].c_str()) > realtextwidth ) { realtextwidth = utf8_width(textformatted[l].c_str()); } } if ( realtextwidth + 4 > w_width ) { w_width = realtextwidth + 4; } } } } else if ( textwidth != -1 ) { realtextwidth = textwidth; } if ( formattxt == true ) { textformatted = foldstring(text, realtextwidth); } } if (h_auto) { w_height = 2 + textformatted.size() + entries.size(); } vmax = entries.size(); if ( w_height > TERMY ) { w_height = TERMY; } if ( vmax + 2 + textformatted.size() > w_height ) { vmax = w_height - 2 - textformatted.size(); if ( vmax < 1 ) { popup("Can't display menu options, %d %d available screen rows are occupied by\n'%s\n(snip)\n%s'\nThis is probably a bug.\n", textformatted.size(),TERMY,textformatted[0].c_str(),textformatted[textformatted.size()-1].c_str() ); } } if (w_x == -1) { w_x = int((TERMX - w_width) / 2); } if (w_y == -1) { w_y = int((TERMY - w_height) / 2); } window = newwin(w_height, w_width, w_y, w_x); werase(window); wattron(window, border_color); wborder(window, LINE_XOXO, LINE_XOXO, LINE_OXOX, LINE_OXOX, LINE_OXXO, LINE_OOXX, LINE_XXOO, LINE_XOOX ); wattroff(window, border_color); if( title.size() > 0 ) { mvwprintz(window, 0, 1, border_color, "< "); wprintz(window, title_color, "%s", title.c_str() ); wprintz(window, border_color, " >"); } started = true; } std::string padspaces = std::string(w_width - 2 - pad_left - pad_right, ' '); for ( int i = 0; i < textformatted.size(); i++ ) { mvwprintz(window, 1+i, 2, text_color, "%s", textformatted[i].c_str()); } int estart = textformatted.size() + 1; // todo fold text + get offset if ( selected < vshift ) { vshift=selected; } else if ( selected >= vshift + vmax ) { vshift=1+selected-vmax; } for ( int ei = vshift, si=0; si < vmax; ei++,si++ ) { if ( ei < entries.size() ) { nc_color co = ( ei == selected ? hilight_color : ( entries[ ei ].enabled ? entries[ ei ].text_color : disabled_color ) ); if ( hilight_full ) { mvwprintz(window, estart + si, pad_left + 1, co , "%s", padspaces.c_str()); } if(entries[ ei ].enabled && entries[ ei ].hotkey > 33 && entries[ ei ].hotkey < 126 ) { mvwprintz(window, estart + si, pad_left + 2, ( ei == selected ? hilight_color : hotkey_color ) , "%c", entries[ ei ].hotkey); } mvwprintz(window, estart + si, pad_left + 4, co, "%s", entries[ ei ].txt.c_str() ); } else { mvwprintz(window, estart + si, pad_left + 1, c_ltgray , "%s", padspaces.c_str()); } } wrefresh(window); }
void game::print_menu(WINDOW *w_open, int iSel, const int iMenuOffsetX, int iMenuOffsetY, bool bShowDDA) { // Clear Lines werase(w_open); // Define window size int window_width = getmaxx(w_open); int window_height = getmaxy(w_open); // Draw horizontal line for (int i = 1; i < window_width - 1; ++i) { mvwputch(w_open, window_height - 2, i, c_white, LINE_OXOX); } center_print(w_open, window_height - 1, c_red, _("Please report bugs to [email protected] or post on the forums.")); int iLine = 0; const int iOffsetX = (window_width - FULL_SCREEN_WIDTH) / 2; const nc_color cColor1 = c_ltcyan; const nc_color cColor2 = c_ltblue; const nc_color cColor3 = c_ltblue; if (mmenu_title.size() > 1) { for (size_t i = 0; i < mmenu_title.size(); ++i) { if (i == 6) { if (!bShowDDA) { break; } if (FULL_SCREEN_HEIGHT > 24) { ++iLine; } } mvwprintz(w_open, iLine++, iOffsetX, i < 6 ? cColor1 : cColor2, mmenu_title[i].c_str()); } } else { center_print(w_open, iLine++, cColor1, mmenu_title[0].c_str()); } if (bShowDDA) { iLine++; center_print(w_open, iLine++, cColor3, _("Version: %s"), getVersionString()); } int menu_length = 0; for( size_t i = 0; i < vMenuItems.size(); ++i ) { menu_length += utf8_width(vMenuItems[i], true) + 2; if (!vMenuHotkeys[i].empty()) { menu_length += utf8_width(vMenuHotkeys[i][0]); } } const int free_space = std::max(0, window_width - menu_length - iMenuOffsetX); const int spacing = free_space / ((int)vMenuItems.size() + 1); const int width_of_spacing = spacing * (vMenuItems.size() + 1); const int adj_offset = std::max(0, (free_space - width_of_spacing) / 2); const int final_offset = iMenuOffsetX + adj_offset + spacing; print_menu_items(w_open, vMenuItems, iSel, iMenuOffsetY, final_offset, spacing); refresh(); wrefresh(w_open); refresh(); }
void draw_connectors( WINDOW *win, const int start_y, const int start_x, const int last_x, const std::string &bio_id ) { const int LIST_START_Y = 6; // first: pos_y, second: occupied slots std::vector<std::pair<int, size_t>> pos_and_num; for( const auto &elem : bionic_info( bio_id ).occupied_bodyparts ) { pos_and_num.emplace_back( static_cast<int>( elem.first ) + LIST_START_Y, elem.second ); } if( pos_and_num.empty() ) { return; } // draw horizontal line from selected bionic const int turn_x = start_x + ( last_x - start_x ) * 2 / 3; mvwputch( win, start_y, start_x, BORDER_COLOR, '>' ); mvwhline( win, start_y, start_x + 1, LINE_OXOX, turn_x - start_x - 1 ); int min_y = start_y; int max_y = start_y; for( const auto &elem : pos_and_num ) { min_y = std::min( min_y, elem.first ); max_y = std::max( max_y, elem.first ); } if( max_y - min_y > 1 ) { mvwvline( win, min_y + 1, turn_x, LINE_XOXO, max_y - min_y - 1 ); } bool move_up = false; bool move_same = false; bool move_down = false; for( const auto &elem : pos_and_num ) { const int y = elem.first; if( !move_up && y < start_y ) { move_up = true; } if( !move_same && y == start_y ) { move_same = true; } if( !move_down && y > start_y ) { move_down = true; } // symbol is defined incorrectly for case ( y == start_y ) but // that's okay because it's overlapped by bionic_chr anyway long bp_chr = ( y > start_y ) ? LINE_XXOO : LINE_OXXO; if( ( max_y > y && y > start_y ) || ( min_y < y && y < start_y ) ) { bp_chr = LINE_XXXO; } mvwputch( win, y, turn_x, BORDER_COLOR, bp_chr ); // draw horizontal line to bodypart title mvwhline( win, y, turn_x + 1, LINE_OXOX, last_x - turn_x - 1 ); mvwputch( win, y, last_x, BORDER_COLOR, '<' ); // draw amount of consumed slots by this cbm const std::string fmt_num = string_format( "(%d)", elem.second ); mvwprintz( win, y, turn_x + std::max( 1, ( last_x - turn_x - utf8_width( fmt_num ) ) / 2 ), c_yellow, "%s", fmt_num.c_str() ); } // define and draw a proper intersection character long bionic_chr = LINE_OXOX; // '-' // 001 if( move_up && !move_down && !move_same ) { // 100 bionic_chr = LINE_XOOX; // '_|' } else if( move_up && move_down && !move_same ) { // 110 bionic_chr = LINE_XOXX; // '-|' } else if( move_up && move_down && move_same ) { // 111 bionic_chr = LINE_XXXX; // '-|-' } else if( move_up && !move_down && move_same ) { // 101 bionic_chr = LINE_XXOX; // '_|_' } else if( !move_up && move_down && !move_same ) { // 010 bionic_chr = LINE_OOXX; // '^|' } else if( !move_up && move_down && move_same ) { // 011 bionic_chr = LINE_OXXX; // '^|^' } mvwputch( win, start_y, turn_x, BORDER_COLOR, bionic_chr ); }