Beispiel #1
0
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;
                        }
                    }
                }
            }
        }
    }
}
Beispiel #2
0
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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
/*
 * 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 );
}
Beispiel #6
0
/**
 * 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;
}
Beispiel #9
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);
}
Beispiel #13
0
Datei: utf8.c Projekt: samv/git
/*
 * 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;
}
Beispiel #15
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();
}
Beispiel #16
0
/*----------------------------------------------------------------------
    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);
}
Beispiel #17
0
/**
 * 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);
}
Beispiel #18
0
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;
}
Beispiel #20
0
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;
}
Beispiel #21
0
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);
    }
}
Beispiel #22
0
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;
}
Beispiel #23
0
/*
 * 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++;
		}
	}
}
Beispiel #24
0
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);
}
Beispiel #25
0
/*
 * 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();
}
Beispiel #28
0
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);
}
Beispiel #29
0
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();
}
Beispiel #30
0
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 );
}