Пример #1
0
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;

    const char* line_of_32_underscores = "________________________________";

    WINDOW *w_confirmation = newwin(iContentHeight, FULL_SCREEN_WIDTH - 2,
                                    iTooltipHeight + 2 + iOffsetY, 1 + iOffsetX);
    WINDOW_PTR w_confirmationptr( w_confirmation );

    unsigned namebar_y = 1;
    unsigned namebar_x = 3 + utf8_width(_("World Name:"));

    int line = 1;
    bool noname = false;
    input_context ctxt("WORLDGEN_CONFIRM_DIALOG");
    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, line_of_32_underscores);
        fold_and_print(w_confirmation, 3, 2, 76, c_ltgray,
                       _("Press <color_yellow>%s</color> to pick a random name for your world."), ctxt.get_desc("PICK_RANDOM_WORLDNAME").c_str());
        fold_and_print(w_confirmation, FULL_SCREEN_HEIGHT / 2 - 2, 2, 76, c_ltgray, _("\
Press <color_yellow>%s</color> when you are satisfied with the world as it is and are ready \
to continue, or <color_yellow>%s</color> to go back and review your world."), ctxt.get_desc("NEXT_TAB").c_str(), ctxt.get_desc("PREV_TAB").c_str());
        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, line_of_32_underscores);
            noname = false;
        }

        wrefresh(win);
        wrefresh(w_confirmation);
        refresh();

        const std::string action = ctxt.handle_input();
        if (action == "NEXT_TAB") {
#ifndef LUA
            MOD_INFORMATION *temp = NULL;
            for (std::string &mod : world->active_mod_order) {
                temp = mman->mod_map[mod];
                if ( temp->need_lua ) {
                    popup(_("Mod '%s' requires Lua support."), temp->name.c_str());
                    return -2; // Move back to modselect tab.
                }
            }
#endif
            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;
                return 1;
            } else {
                continue;
            }
        } else if (action == "PREV_TAB") {
            world->world_name = worldname;
            return -1;
        } else if (action == "PICK_RANDOM_WORLDNAME") {
            mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, line_of_32_underscores);
            world->world_name = worldname = pick_random_name();
        } else if (action == "QUIT") {
            // Cache the current name just in case they say No to the exit query.
            world->world_name = worldname;
            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 );
                    if(tmplen > 0 && tmplen + utf8_width(worldname) < 30) {
                        worldname.append(tmp);
                    }
                } else if( !newtext.empty() && is_char_allowed( newtext.at( 0 ) ) ) {
                    // No empty string, no slash, no backslash, no control sequence
                    wrap.append( newtext );
                    worldname = wrap.str();
                }
                mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, line_of_32_underscores);
                mvwprintz(w_confirmation, namebar_y, namebar_x, c_ltgray, "%s", worldname.c_str());
                wprintz(w_confirmation, h_ltgray, "_");
            }
            break;
            }
        }
    } while (true);

    return 0;
}
Пример #2
0
std::string string_input_win(WINDOW *w, std::string input, int max_length, int startx, int starty,
                             int endx, bool loop, long &ch, int &pos, std::string identifier,
                             int w_x, int w_y, bool dorefresh, bool only_digits )
{
    std::string ret = input;
    nc_color string_color = c_magenta;
    nc_color cursor_color = h_ltgray;
    nc_color underscore_color = c_ltgray;
    if ( pos == -1 ) {
        pos = utf8_width(input.c_str());
    }
    int lastpos = pos;
    int scrmax = endx - startx;
    int shift = 0;
    int lastshift = shift;
    bool redraw = true;

    do {

        if ( pos < 0 ) {
            pos = 0;
        }

        if ( pos < shift ) {
            shift = pos;
        } else if ( pos > shift + scrmax ) {
            shift = pos - scrmax;
        }

        if (shift < 0 ) {
            shift = 0;
        }

        if( redraw || lastshift != shift ) {
            redraw = false;
            for ( int reti = shift, scri = 0; scri <= scrmax; reti++, scri++ ) {
                if( reti < ret.size() ) {
                    mvwputch(w, starty, startx + scri, (reti == pos ? cursor_color : string_color ), ret[reti] );
                } else {
                    mvwputch(w, starty, startx + scri, (reti == pos ? cursor_color : underscore_color ), '_');
                }
            }
        } else if ( lastpos != pos ) {
            if ( lastpos >= shift && lastpos <= shift + scrmax ) {
                if ( lastpos - shift >= 0 && lastpos - shift < ret.size() ) {
                    mvwputch(w, starty, startx + lastpos, string_color, ret[lastpos - shift]);
                } else {
                    mvwputch(w, starty, startx + lastpos, underscore_color, '_' );
                }
            }
            if (pos < ret.size() ) {
                mvwputch(w, starty, startx + pos, cursor_color, ret[pos - shift]);
            } else {
                mvwputch(w, starty, startx + pos, cursor_color, '_' );
            }
        }

        lastpos = pos;
        lastshift = shift;
        if (dorefresh) {
            wrefresh(w);
        }
        ch = getch();
        bool return_key = false;
        if (ch == 27) { // Escape
            return "";
        } else if (ch == '\n') {
            return_key = true;
        } else if (ch == KEY_UP ) {
            if(identifier.size() > 0) {
                std::vector<std::string> *hist = uistate.gethistory(identifier);
                if(hist != NULL) {
                    uimenu hmenu;
                    hmenu.title = _("d: delete history");
                    hmenu.return_invalid = true;
                    for(int h = 0; h < hist->size(); h++) {
                        hmenu.addentry(h, true, -2, (*hist)[h].c_str());
                    }
                    if ( ret.size() > 0 && ( hmenu.entries.size() == 0 ||
                                             hmenu.entries[hist->size() - 1].txt != ret ) ) {
                        hmenu.addentry(hist->size(), true, -2, ret);
                        hmenu.selected = hist->size();
                    } else {
                        hmenu.selected = hist->size() - 1;
                    }
                    // number of lines that make up the menu window: title,2*border+entries
                    hmenu.w_height = 3 + hmenu.entries.size();
                    hmenu.w_y = w_y - hmenu.w_height;
                    if (hmenu.w_y < 0 ) {
                        hmenu.w_y = 0;
                        hmenu.w_height = std::max(w_y, 4);
                    }
                    hmenu.w_x = w_x;

                    hmenu.query();
                    if ( hmenu.ret >= 0 && hmenu.entries[hmenu.ret].txt != ret ) {
                        ret = hmenu.entries[hmenu.ret].txt;
                        if( hmenu.ret < hist->size() ) {
                            hist->erase(hist->begin() + hmenu.ret);
                            hist->push_back(ret);
                        }
                        pos = ret.size();
                        redraw = true;
                    } else if ( hmenu.keypress == 'd' ) {
                        hist->clear();
                    }
                }
            }
        } else if (ch == KEY_DOWN || ch == KEY_NPAGE || ch == KEY_PPAGE ) {
            /* absolutely nothing */
        } else if (ch == KEY_RIGHT ) {
            if( pos + 1 <= ret.size() ) {
                pos++;
            }
            redraw = true;
        } else if (ch == KEY_LEFT ) {
            if ( pos > 0 ) {
                pos--;
            }
            redraw = true;
        } else if (ch == 0x15 ) {                      // ctrl-u: delete all the things
            pos = 0;
            ret.erase(0);
            redraw = true;
        } else if (ch == KEY_BACKSPACE || ch == 127) { // Move the cursor back and re-draw it
            if( pos > 0 &&
                pos <= ret.size() ) {         // but silently drop input if we're at 0, instead of adding '^'
                pos--;                                     //TODO: it is safe now since you only input ascii chars
                ret.erase(pos, 1);
                redraw = true;
            }
        } 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);
            }
        } else if( ch != 0 && ch != ERR && (ret.size() < max_length || max_length == 0) ) {
            if ( only_digits && !isdigit(ch) ) {
                return_key = true;
            } else {
                if ( pos == ret.size() ) {
                    ret += ch;
                } else {
                    ret.insert(pos, 1, ch);
                }
                redraw = true;
                pos++;
            }
        }
        if (return_key) {//"/n" return code
            {
                if(identifier.size() > 0 && ret.size() > 0 ) {
                    std::vector<std::string> *hist = uistate.gethistory(identifier);
                    if( hist != NULL ) {
                        if ( hist->size() == 0 || (*hist)[hist->size() - 1] != ret ) {
                            hist->push_back(ret);
                        }
                    }
                }
                return ret;
            }
        }
    } while ( loop == true );
    return ret;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
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);
}
Пример #6
0
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;
}