Index: src/settings.cpp =================================================================== --- src/settings.cpp (revision 12357) +++ src/settings.cpp (working copy) @@ -49,6 +49,7 @@ #endif #include "spritecache.h" #include "transparency.h" +#include "textbuf_gui.h" #include "string_func.h" #include "gui.h" #include "town.h" @@ -1284,6 +1285,8 @@ SDTG_VAR("player_face", SLE_UINT32, S, 0, _player_face, 0,0,0xFFFFFFFF,0, STR_NULL, NULL), SDTG_VAR("transparency_options", SLE_UINT, S, 0, _transparency_opt, 0,0,0x1FF,0, STR_NULL, NULL), SDTG_VAR("transparency_locks", SLE_UINT, S, 0, _transparency_lock, 0,0,0x1FF,0, STR_NULL, NULL), + SDTG_STR("keyboard", SLE_STRB, S, 0, _keyboard_opt[0],NULL, STR_NULL, NULL), + SDTG_STR("keyboard_caps", SLE_STRB, S, 0, _keyboard_opt[1],NULL, STR_NULL, NULL), SDTG_END() }; Index: src/gfx_func.h =================================================================== --- src/gfx_func.h (revision 12357) +++ src/gfx_func.h (working copy) @@ -99,6 +99,8 @@ void DrawStringRightAlignedTruncated(int x, int y, StringID str, uint16 color, uint maxw); void DrawStringRightAlignedUnderline(int x, int y, StringID str, uint16 color); +void DrawCharCentered(uint32 c, int x, int y, uint16 color); + void GfxFillRect(int left, int top, int right, int bottom, int color); void GfxDrawLine(int left, int top, int right, int bottom, int color); void DrawBox(int x, int y, int dx1, int dy1, int dx2, int dy2, int dx3, int dy3); Index: src/lang/german.txt =================================================================== --- src/lang/german.txt (revision 12357) +++ src/lang/german.txt (working copy) @@ -3468,3 +3468,8 @@ STR_DRAG_SIGNALS_DENSITY_DECREASE_TIP :{BLACK}Signalabstand verringern STR_DRAG_SIGNALS_DENSITY_INCREASE_TIP :{BLACK}Signalabstand erhöhen ######## + +############ on screen keyboard +STR_OSK_KEYBOARD_LAYOUT :^1234567890ß' qwertzuiopü+asdfghjklöä#YXCVBNM;:_ . +######## Index: src/lang/english.txt =================================================================== --- src/lang/english.txt (revision 12357) +++ src/lang/english.txt (working copy) @@ -1352,6 +1352,7 @@ STR_NETWORK_PLAYER_NAME :{BLACK}Player name: STR_NETWORK_ENTER_NAME_TIP :{BLACK}This is the name other players will identify you by +STR_NETWORK_PLAYER_NAME_OSKTITLE :{BLACK}Enter your name STR_NETWORK_CONNECTION :{BLACK}Connection: STR_NETWORK_CONNECTION_TIP :{BLACK}Choose between an internet game or a Local Area Network (LAN) game @@ -1395,6 +1396,7 @@ STR_NETWORK_NEW_GAME_NAME :{BLACK}Game name: STR_NETWORK_NEW_GAME_NAME_TIP :{BLACK}The game name will be displayed to other players in the multiplayer game selection menu +STR_NETWORK_NEW_GAME_NAME_OSKTITLE :{BLACK}Enter a name for the network game STR_NETWORK_SET_PASSWORD :{BLACK}Set password STR_NETWORK_PASSWORD_TIP :{BLACK}Protect your game with a password if you don't want it to be publicly accessible STR_NETWORK_SELECT_MAP :{BLACK}Select a map: @@ -1549,6 +1551,7 @@ STR_NETWORK_CHAT_TO_CLIENT :[Private] To {STRING}: {GRAY}{STRING} STR_NETWORK_CHAT_ALL_CAPTION :[All] : STR_NETWORK_CHAT_ALL :[All] {STRING}: {GRAY}{STRING} +STR_NETWORK_CHAT_OSKTITLE :{BLACK}Enter text for network chat STR_NETWORK_NAME_CHANGE :has changed his/her name to STR_NETWORK_SERVER_SHUTDOWN :{WHITE} The server closed the session STR_NETWORK_SERVER_REBOOT :{WHITE} The server is restarting...{}Please wait... @@ -1951,6 +1954,7 @@ STR_400F_SELECT_SCENARIO_GREEN_PRE :{BLACK}Select scenario (green), pre-set game (blue), or random new game STR_4010_GENERATE_RANDOM_NEW_GAME :Generate random new game STR_LOAD_HEIGHTMAP :{WHITE}Load Heightmap +STR_SAVE_OSKTITLE :{BLACK}Enter a name for the savegame ##id 0x4800 STR_4800_IN_THE_WAY :{WHITE}{STRING} in the way @@ -3265,6 +3269,7 @@ STR_WORLD_GENERATION_CAPTION :{WHITE}World generation STR_RANDOM_SEED :{BLACK}Random Seed: STR_RANDOM_SEED_HELP :{BLACK}Click to enter a random seed +STR_RANDOM_SEED_OSKTITLE :{BLACK}Enter a random seed STR_LAND_GENERATOR :{BLACK}Land generator: STR_TREE_PLACER :{BLACK}Tree algorithm: STR_HEIGHTMAP_ROTATION :{BLACK}Heightmap rotation: @@ -3412,6 +3417,7 @@ #### Improved sign GUI STR_NEXT_SIGN_TOOLTIP :{BLACK}Go to next sign STR_PREVIOUS_SIGN_TOOLTIP :{BLACK}Go to previous sign +STR_SIGN_OSKTITLE :{BLACK}Enter a name for the sign ######## @@ -3484,3 +3490,8 @@ STR_DRAG_SIGNALS_DENSITY_DECREASE_TIP :{BLACK}Decrease dragging signal density STR_DRAG_SIGNALS_DENSITY_INCREASE_TIP :{BLACK}Increase dragging signal density ######## + +############ on screen keyboard +STR_OSK_KEYBOARD_LAYOUT :`1234567890-=\qwertyuiop[]asdfghjkl;' zxcvbnm,./ . +STR_OSK_KEYBOARD_LAYOUT_CAPS :~!@#$%^&*()_+|QWERTYUIOP ASDFGHJKL:" ZXCVBNM<>? . +######## Index: src/genworld_gui.cpp =================================================================== --- src/genworld_gui.cpp (revision 12357) +++ src/genworld_gui.cpp (working copy) @@ -127,7 +127,7 @@ { WWT_DROPDOWN, RESIZE_NONE, 12, 114, 175, 130, 141, 0x0, STR_NULL}, // Number of industries { WWT_TEXT, RESIZE_NONE, 0, 12, 110, 153, 163, STR_RANDOM_SEED, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, 15, 114, 207, 152, 163, 0x0, STR_RANDOM_SEED_HELP}, // Edit box for seed +{ WWT_EDITBOX, RESIZE_NONE, 15, 114, 207, 152, 163, STR_RANDOM_SEED_OSKTITLE, STR_RANDOM_SEED_HELP}, // Edit box for seed { WWT_TEXTBTN, RESIZE_NONE, 12, 216, 326, 152, 163, STR_RANDOM, STR_RANDOM_HELP}, { WWT_TEXTBTN, RESIZE_NONE, 6, 243, 326, 228, 257, STR_GENERATE, STR_NULL}, // Generate button @@ -181,7 +181,7 @@ { WWT_DROPDOWN, RESIZE_NONE, 12, 114, 175, 152, 163, 0x0, STR_NULL}, // Number of industries { WWT_TEXT, RESIZE_NONE, 0, 12, 110, 175, 185, STR_RANDOM_SEED, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, 15, 114, 207, 174, 185, 0x0, STR_RANDOM_SEED_HELP}, // Edit box for seed +{ WWT_EDITBOX, RESIZE_NONE, 15, 114, 207, 174, 185, STR_RANDOM_SEED_OSKTITLE, STR_RANDOM_SEED_HELP}, // Edit box for seed { WWT_TEXTBTN, RESIZE_NONE, 12, 216, 326, 174, 185, STR_RANDOM, STR_RANDOM_HELP}, { WWT_TEXTBTN, RESIZE_NONE, 6, 243, 326, 196, 225, STR_GENERATE, STR_NULL}, // Generate button @@ -373,7 +373,9 @@ UpdateTextBufferSize(&_genseed_query.text); SetWindowDirty(w); break; - + case GLAND_RANDOM_EDITBOX: // edit box for random seed + ShowOnScreenKeyboard(w, & _genseed_query, GLAND_RANDOM_EDITBOX, 0, 0); + break; case GLAND_GENERATE_BUTTON: // Generate UpdatePatches(); Index: src/textbuf_gui.h =================================================================== --- src/textbuf_gui.h (revision 12357) +++ src/textbuf_gui.h (working copy) @@ -26,6 +26,8 @@ }; assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(querystr_d)); +extern char _edit_str_buf[64]; +extern char _orig_str_buf[lengthof(_edit_str_buf)]; void DrawEditBox(Window *w, querystr_d *string, int wid); void HandleEditBox(Window *w, querystr_d *string, int wid); @@ -43,4 +45,7 @@ void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, Window *parent, CharSetFilter afilter); void ShowQuery(StringID caption, StringID message, Window *w, void (*callback)(Window*, bool)); +extern char _keyboard_opt[2][100]; +void ShowOnScreenKeyboard(Window *parent, querystr_d *q, int button, int cancel, int ok); + #endif /* TEXTBUF_GUI_H */ Index: src/misc_gui.cpp =================================================================== --- src/misc_gui.cpp (revision 12357) +++ src/misc_gui.cpp (working copy) @@ -1084,6 +1084,8 @@ const Widget *wi = &w->widget[wid]; const Textbuf *tb = &string->text; + assert((wi->type & WWT_MASK) == WWT_EDITBOX); + GfxFillRect(wi->left + 1, wi->top + 1, wi->right - 1, wi->bottom - 1, 215); /* Limit the drawing of the string inside the widget boundaries */ @@ -1135,6 +1137,9 @@ case WE_CLICK: switch (e->we.click.widget) { + case QUERY_STR_WIDGET_TEXT: + ShowOnScreenKeyboard(w, &WP(w, querystr_d), QUERY_STR_WIDGET_TEXT, QUERY_STR_WIDGET_CANCEL, QUERY_STR_WIDGET_OK); + break; case QUERY_STR_WIDGET_OK: press_ok:; if (qs->orig == NULL || strcmp(qs->text.buf, qs->orig) != 0) { @@ -1188,7 +1193,7 @@ { WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, { WWT_CAPTION, RESIZE_NONE, 14, 11, 259, 0, 13, STR_012D, STR_NULL}, { WWT_PANEL, RESIZE_NONE, 14, 0, 259, 14, 29, 0x0, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, 14, 2, 257, 16, 27, 0x0, STR_NULL}, +{ WWT_EDITBOX, RESIZE_NONE, 14, 2, 257, 16, 27, 0x0, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 14, 0, 129, 30, 41, STR_012E_CANCEL, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 14, 130, 259, 30, 41, STR_012F_OK, STR_NULL}, { WIDGETS_END}, @@ -1202,7 +1207,8 @@ QueryStringWndProc }; -static char _edit_str_buf[64]; +char _edit_str_buf[64]; +char _orig_str_buf[lengthof(_edit_str_buf)]; /** Show a query popup window with a textbox in it. * @param str StringID for the text shown in the textbox @@ -1215,7 +1221,6 @@ * @param afilter filters out unwanted character input */ void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, Window *parent, CharSetFilter afilter) { - static char orig_str_buf[lengthof(_edit_str_buf)]; Window *w; uint realmaxlen = maxlen & ~0x1000; @@ -1233,8 +1238,8 @@ if (maxlen & 0x1000) { WP(w, querystr_d).orig = NULL; } else { - strecpy(orig_str_buf, _edit_str_buf, lastof(orig_str_buf)); - WP(w, querystr_d).orig = orig_str_buf; + strecpy(_orig_str_buf, _edit_str_buf, lastof(_orig_str_buf)); + WP(w, querystr_d).orig = _orig_str_buf; } w->LowerWidget(QUERY_STR_WIDGET_TEXT); @@ -1379,7 +1384,7 @@ { WWT_INSET, RESIZE_RB, 14, 2, 243, 50, 150, 0x0, STR_400A_LIST_OF_DRIVES_DIRECTORIES}, { WWT_SCROLLBAR, RESIZE_LRB, 14, 245, 256, 60, 151, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, { WWT_PANEL, RESIZE_RTB, 14, 0, 256, 152, 167, 0x0, STR_NULL}, -{ WWT_PANEL, RESIZE_RTB, 14, 2, 254, 154, 165, 0x0, STR_400B_CURRENTLY_SELECTED_NAME}, +{ WWT_EDITBOX, RESIZE_RTB, 14, 2, 254, 154, 165, STR_SAVE_OSKTITLE,STR_400B_CURRENTLY_SELECTED_NAME}, { WWT_PUSHTXTBTN, RESIZE_TB, 14, 0, 127, 168, 179, STR_4003_DELETE, STR_400C_DELETE_THE_CURRENTLY_SELECTED}, { WWT_PUSHTXTBTN, RESIZE_TB, 14, 128, 244, 168, 179, STR_4002_SAVE, STR_400D_SAVE_THE_CURRENT_GAME_USING}, { WWT_RESIZEBOX, RESIZE_LRTB, 14, 245, 256, 168, 179, 0x0, STR_RESIZE_BUTTON}, @@ -1586,7 +1591,10 @@ } break; } - + case 10: // edit box + ShowOnScreenKeyboard(w, &WP(w, querystr_d), e->we.click.widget, 0, 0); + break; + case 11: case 12: // Delete, Save game break; } Index: src/table/sprites.h =================================================================== --- src/table/sprites.h (revision 12357) +++ src/table/sprites.h (working copy) @@ -49,7 +49,7 @@ /* Extra graphic spritenumbers */ SPR_OPENTTD_BASE = 4896, - OPENTTD_SPRITE_COUNT = 138, + OPENTTD_SPRITE_COUNT = 144, /* Halftile-selection sprites */ SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE, @@ -73,6 +73,14 @@ SPR_PIN_UP = SPR_OPENTTD_BASE + 51, // pin icon SPR_PIN_DOWN = SPR_OPENTTD_BASE + 52, + /* on screen keyboard icons */ + SPR_OSK_LEFT = SPR_OPENTTD_BASE + 138, + SPR_OSK_RIGHT = SPR_OPENTTD_BASE + 139, + SPR_OSK_CAPS = SPR_OPENTTD_BASE + 140, + SPR_OSK_SHIFT = SPR_OPENTTD_BASE + 141, + SPR_OSK_BACKSPACE = SPR_OPENTTD_BASE + 142, + SPR_OSK_SPECIAL = SPR_OPENTTD_BASE + 143, + /* Clone vehicles stuff */ SPR_CLONE_TRAIN = SPR_OPENTTD_BASE + 106, SPR_CLONE_ROADVEH = SPR_OPENTTD_BASE + 107, Index: src/window_type.h =================================================================== --- src/window_type.h (revision 12357) +++ src/window_type.h (working copy) @@ -90,6 +90,7 @@ WC_VEHICLE_TIMETABLE, WC_BUILD_SIGNAL, WC_COMPANY_PASSWORD_WINDOW, + WC_OSK, }; struct Window; Index: src/window_gui.h =================================================================== --- src/window_gui.h (revision 12357) +++ src/window_gui.h (working copy) @@ -499,6 +499,7 @@ WWT_CLOSEBOX, WWT_DROPDOWN, ///< Raised drop down list (regular) WWT_DROPDOWNIN, ///< Inset drop down list (used on game options only) + WWT_EDITBOX, ///< a textbox for typing (don't forget to call ShowOnScreenKeyboard() when clicked) WWT_LAST, ///< Last Item. use WIDGETS_END to fill up padding!! WWT_MASK = 0x1F, Index: src/widget.cpp =================================================================== --- src/widget.cpp (revision 12357) +++ src/widget.cpp (working copy) @@ -222,6 +222,11 @@ break; } + case WWT_EDITBOX: { + DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_LOWERED | FR_DARKENED); + break; + } + case WWT_TEXTBTN: case WWT_TEXTBTN_2: { DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE); Index: src/network/network_gui.cpp =================================================================== --- src/network/network_gui.cpp (revision 12357) +++ src/network/network_gui.cpp (working copy) @@ -35,6 +35,7 @@ #define BTC 15 struct chatquerystr_d : public querystr_d { + DestType dtype; int dest; }; assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(chatquerystr_d)); @@ -59,7 +60,7 @@ /* Global to remember sorting after window has been closed */ static Listing _ng_sorting; -static char _edit_str_buf[150]; +static char _edit_str_net_buf[150]; static bool _chat_tab_completion_active; static void ShowNetworkStartServerWindow(); @@ -425,6 +426,10 @@ case WE_CLICK: nd->field = e->we.click.widget; switch (e->we.click.widget) { + + case NGWW_PLAYER: + ShowOnScreenKeyboard(w, &WP(w, network_ql_d).q, NGWW_PLAYER, 0, 0); + break; case NGWW_CANCEL: // Cancel button DeleteWindowById(WC_NETWORK_WINDOW, 0); break; @@ -526,8 +531,8 @@ if (HandleEditBoxKey(w, &WP(w, network_ql_d).q, NGWW_PLAYER, e) == 1) break; // enter pressed /* The name is only allowed when it starts with a letter! */ - if (_edit_str_buf[0] != '\0' && _edit_str_buf[0] != ' ') { - ttd_strlcpy(_network_player_name, _edit_str_buf, lengthof(_network_player_name)); + if (_edit_str_net_buf[0] != '\0' && _edit_str_net_buf[0] != ' ') { + ttd_strlcpy(_network_player_name, _edit_str_net_buf, lengthof(_network_player_name)); } else { ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name)); } @@ -573,7 +578,7 @@ { WWT_TEXT, RESIZE_NONE, BGC, 9, 85, 23, 35, STR_NETWORK_CONNECTION, STR_NULL}, { WWT_DROPDOWNIN, RESIZE_NONE, BGC, 90, 181, 22, 33, STR_NETWORK_LAN_INTERNET_COMBO, STR_NETWORK_CONNECTION_TIP}, // NGWW_CONN_BTN -{ WWT_PANEL, RESIZE_LR, BGC, 290, 440, 22, 33, 0x0, STR_NETWORK_ENTER_NAME_TIP}, // NGWW_PLAYER +{ WWT_EDITBOX, RESIZE_LR, BGC, 290, 440, 22, 33, STR_NETWORK_PLAYER_NAME_OSKTITLE, STR_NETWORK_ENTER_NAME_TIP}, // NGWW_PLAYER /* LEFT SIDE */ { WWT_PUSHTXTBTN, RESIZE_RIGHT, BTC, 10, 70, 42, 53, STR_NETWORK_GAME_NAME, STR_NETWORK_GAME_NAME_TIP}, // NGWW_NAME @@ -634,9 +639,9 @@ if (w != NULL) { querystr_d *querystr = &WP(w, network_ql_d).q; - ttd_strlcpy(_edit_str_buf, _network_player_name, lengthof(_edit_str_buf)); + ttd_strlcpy(_edit_str_net_buf, _network_player_name, lengthof(_edit_str_net_buf)); querystr->afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&querystr->text, _edit_str_buf, lengthof(_edit_str_buf), 120); + InitializeTextBuffer(&querystr->text, _edit_str_net_buf, lengthof(_edit_str_net_buf), 120); UpdateNetworkGameWindow(true); } @@ -734,7 +739,9 @@ case NSSW_CANCEL: // Cancel button ShowNetworkGameWindow(); break; - + case NSSW_GAMENAME: + ShowOnScreenKeyboard(w, &WP(w, network_ql_d).q, NSSW_GAMENAME, 0, 0); + break; case NSSW_SETPWD: // Set password button nd->widget_id = NSSW_SETPWD; ShowQueryString(BindCString(_network_server_password), STR_NETWORK_SET_PASSWORD, 20, 250, w, CS_ALPHANUMERAL); @@ -885,7 +892,7 @@ /* Set game name and password widgets */ { WWT_TEXT, RESIZE_NONE, BGC, 10, 90, 22, 34, STR_NETWORK_NEW_GAME_NAME, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, BGC, 100, 272, 22, 33, 0x0, STR_NETWORK_NEW_GAME_NAME_TIP}, // NSSW_GAMENAME +{ WWT_EDITBOX, RESIZE_NONE, BGC, 100, 272, 22, 33, STR_NETWORK_NEW_GAME_NAME_OSKTITLE, STR_NETWORK_NEW_GAME_NAME_TIP}, // NSSW_GAMENAME { WWT_PUSHTXTBTN, RESIZE_NONE, BTC, 285, 405, 22, 33, STR_NETWORK_SET_PASSWORD, STR_NETWORK_PASSWORD_TIP}, // NSSW_SETPWD /* List of playable scenarios */ @@ -937,7 +944,7 @@ DeleteWindowById(WC_NETWORK_WINDOW, 0); w = AllocateWindowDesc(&_network_start_server_window_desc); - ttd_strlcpy(_edit_str_buf, _network_server_name, lengthof(_edit_str_buf)); + ttd_strlcpy(_edit_str_net_buf, _network_server_name, lengthof(_edit_str_net_buf)); _saveload_mode = SLD_NEW_GAME; BuildFileList(); @@ -945,7 +952,7 @@ w->vscroll.count = _fios_num + 1; WP(w, network_ql_d).q.afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_buf, lengthof(_edit_str_buf), 160); + InitializeTextBuffer(&WP(w, network_ql_d).q.text, _edit_str_net_buf, lengthof(_edit_str_net_buf), 160); } static PlayerID NetworkLobbyFindCompanyIndex(byte pos) @@ -1173,7 +1180,7 @@ w = AllocateWindowDesc(&_network_lobby_window_desc); if (w != NULL) { WP(w, network_ql_d).n.server = ngl; - strcpy(_edit_str_buf, ""); + strcpy(_edit_str_net_buf, ""); w->vscroll.cap = 10; } } @@ -1708,7 +1715,7 @@ */ static void ChatTabCompletion(Window *w) { - static char _chat_tab_completion_buf[lengthof(_edit_str_buf)]; + static char _chat_tab_completion_buf[lengthof(_edit_str_net_buf)]; Textbuf *tb = &WP(w, chatquerystr_d).text; uint len, tb_len; uint item; @@ -1761,9 +1768,9 @@ /* Change to the found name. Add ': ' if we are at the start of the line (pretty) */ if (pre_buf == tb_buf) { - snprintf(tb->buf, lengthof(_edit_str_buf), "%s: ", cur_name); + snprintf(tb->buf, lengthof(_edit_str_net_buf), "%s: ", cur_name); } else { - snprintf(tb->buf, lengthof(_edit_str_buf), "%s %s", pre_buf, cur_name); + snprintf(tb->buf, lengthof(_edit_str_net_buf), "%s %s", pre_buf, cur_name); } /* Update the textbuffer */ @@ -1790,7 +1797,7 @@ /* * uses chatquerystr_d WP macro - * uses chatquerystr_d->caption to store type of chat message (Private/Team/All) + * uses chatquerystr_d->dtype to store type of chat message (Private/Team/All) */ static void ChatWindowWndProc(Window *w, WindowEvent *e) { @@ -1810,16 +1817,20 @@ DrawWindowWidgets(w); - assert(WP(w, chatquerystr_d).caption < lengthof(chat_captions)); - msg = chat_captions[WP(w, chatquerystr_d).caption]; + assert((uint) WP(w, chatquerystr_d).dtype < lengthof(chat_captions)); + msg = chat_captions[WP(w, chatquerystr_d).dtype]; DrawStringRightAligned(w->widget[2].left - 2, w->widget[2].top + 1, msg, TC_BLACK); DrawEditBox(w, &WP(w, chatquerystr_d), 2); } break; case WE_CLICK: switch (e->we.click.widget) { + case 2: + ShowOnScreenKeyboard(w, &WP(w, chatquerystr_d), 2, 0, 3); + break; + case 3: { /* Send */ - DestType type = (DestType)WP(w, chatquerystr_d).caption; + DestType type = WP(w, chatquerystr_d).dtype; int dest = WP(w, chatquerystr_d).dest; SendChat(WP(w, chatquerystr_d).text.buf, type, dest); } /* FALLTHROUGH */ @@ -1838,7 +1849,7 @@ _chat_tab_completion_active = false; switch (HandleEditBoxKey(w, &WP(w, chatquerystr_d), 2, e)) { case 1: { /* Return */ - DestType type = (DestType)WP(w, chatquerystr_d).caption; + DestType type = WP(w, chatquerystr_d).dtype; int dest = WP(w, chatquerystr_d).dest; SendChat(WP(w, chatquerystr_d).text.buf, type, dest); } /* FALLTHROUGH */ @@ -1855,10 +1866,10 @@ } static const Widget _chat_window_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_PANEL, RESIZE_RIGHT, 14, 11, 319, 0, 13, 0x0, STR_NULL}, // background -{ WWT_PANEL, RESIZE_RIGHT, 14, 75, 257, 1, 12, 0x0, STR_NULL}, // text box -{ WWT_PUSHTXTBTN, RESIZE_LR, 14, 258, 319, 1, 12, STR_NETWORK_SEND, STR_NULL}, // send button +{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_PANEL, RESIZE_RIGHT, 14, 11, 319, 0, 13, 0x0, STR_NULL}, // background +{ WWT_EDITBOX, RESIZE_RIGHT, 14, 75, 257, 1, 12, STR_NETWORK_CHAT_OSKTITLE, STR_NULL}, // text box +{ WWT_PUSHTXTBTN, RESIZE_LR, 14, 258, 319, 1, 12, STR_NETWORK_SEND, STR_NULL}, // send button { WIDGETS_END}, }; @@ -1876,16 +1887,16 @@ DeleteWindowById(WC_SEND_NETWORK_MSG, 0); - _edit_str_buf[0] = '\0'; + _edit_str_net_buf[0] = '\0'; _chat_tab_completion_active = false; w = AllocateWindowDesc(&_chat_window_desc); w->LowerWidget(2); - WP(w, chatquerystr_d).caption = type; // Misuse of caption + WP(w, chatquerystr_d).dtype = type; WP(w, chatquerystr_d).dest = dest; WP(w, chatquerystr_d).afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&WP(w, chatquerystr_d).text, _edit_str_buf, lengthof(_edit_str_buf), 0); + InitializeTextBuffer(&WP(w, chatquerystr_d).text, _edit_str_net_buf, lengthof(_edit_str_net_buf), 0); } /** Enum for NetworkGameWindow, referring to _network_game_window_widgets */ @@ -1912,12 +1923,12 @@ switch (e->we.click.widget) { case NCPWW_OK: { if (w->IsWidgetLowered(NCPWW_SAVE_AS_DEFAULT_PASSWORD)) { - snprintf(_network_default_company_pass, lengthof(_network_default_company_pass), "%s", _edit_str_buf); + snprintf(_network_default_company_pass, lengthof(_network_default_company_pass), "%s", _edit_str_net_buf); } /* empty password is a '*' because of console argument */ - if (StrEmpty(_edit_str_buf)) snprintf(_edit_str_buf, lengthof(_edit_str_buf), "*"); - char *password = _edit_str_buf; + if (StrEmpty(_edit_str_net_buf)) snprintf(_edit_str_net_buf, lengthof(_edit_str_net_buf), "*"); + char *password = _edit_str_net_buf; NetworkChangeCompanyPassword(1, &password); } @@ -1930,6 +1941,9 @@ w->ToggleWidgetLoweredState(NCPWW_SAVE_AS_DEFAULT_PASSWORD); SetWindowDirty(w); break; + case NCPWW_PASSWORD: + ShowOnScreenKeyboard(w, &WP(w, chatquerystr_d), NCPWW_PASSWORD, 2, 1); + break; } break; @@ -1944,7 +1958,6 @@ e->we.click.widget = NCPWW_OK; NetworkCompanyPasswordWindowWndProc(w, e); break; - case 2: // Escape DeleteWindow(w); break; @@ -1958,7 +1971,7 @@ { WWT_CAPTION, RESIZE_NONE, 14, 11, 299, 0, 13, STR_COMPANY_PASSWORD_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, { WWT_PANEL, RESIZE_NONE, 14, 0, 299, 14, 50, 0x0, STR_NULL}, { WWT_TEXT, RESIZE_NONE, 14, 5, 100, 19, 30, STR_COMPANY_PASSWORD, STR_NULL}, -{ WWT_PANEL, RESIZE_NONE, 14, 101, 294, 19, 30, 0x0, STR_NULL}, +{ WWT_EDITBOX, RESIZE_NONE, 14, 101, 294, 19, 30, STR_SET_COMPANY_PASSWORD, STR_NULL}, { WWT_TEXTBTN, RESIZE_NONE, 14, 101, 294, 35, 46, STR_MAKE_DEFAULT_COMPANY_PASSWORD, STR_MAKE_DEFAULT_COMPANY_PASSWORD_TIP}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 0, 149, 51, 62, STR_012E_CANCEL, STR_COMPANY_PASSWORD_CANCEL}, { WWT_PUSHTXTBTN, RESIZE_NONE, 14, 150, 299, 51, 62, STR_012F_OK, STR_COMPANY_PASSWORD_OK}, @@ -1977,10 +1990,10 @@ { DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0); - _edit_str_buf[0] = '\0'; + _edit_str_net_buf[0] = '\0'; Window *w = AllocateWindowDesc(&_ncp_window_desc); WP(w, chatquerystr_d).afilter = CS_ALPHANUMERAL; - InitializeTextBuffer(&WP(w, chatquerystr_d).text, _edit_str_buf, min(lengthof(_network_default_company_pass), lengthof(_edit_str_buf)), 0); + InitializeTextBuffer(&WP(w, chatquerystr_d).text, _edit_str_net_buf, min(lengthof(_network_default_company_pass), lengthof(_edit_str_net_buf)), 0); } #endif /* ENABLE_NETWORK */ Index: src/osk_gui.cpp =================================================================== --- src/osk_gui.cpp (revision 0) +++ src/osk_gui.cpp (revision 0) @@ -0,0 +1,357 @@ +/* $Id : XXXXXX $ */ + +/** @file osk_gui.cpp */ + +#include "stdafx.h" +#include "openttd.h" +#include "heightmap.h" +#include "debug.h" +#include "landscape.h" +#include "newgrf.h" +#include "newgrf_text.h" +#include "saveload.h" +#include "tile_map.h" +#include "gui.h" +#include "window_gui.h" +#include "station_gui.h" +#include "textbuf_gui.h" +#include "viewport_func.h" +#include "gfx_func.h" +#include "station.h" +#include "command_func.h" +#include "player_func.h" +#include "player_base.h" +#include "town.h" +#include "network/network.h" +#include "variables.h" +#include "train.h" +#include "tgp.h" +#include "cargotype.h" +#include "player_face.h" +#include "strings_func.h" +#include "fileio.h" +#include "fios.h" +#include "tile_cmd.h" +#include "zoom_func.h" +#include "functions.h" +#include "window_func.h" +#include "date_func.h" +#include "sound_func.h" +#include "string_func.h" +#include "player_gui.h" +#include "settings_type.h" + +#include "table/sprites.h" +#include "table/strings.h" +#include "table/tree_land.h" + +struct osk_d { + querystr_d *qs; // text-input + int text_btn; // widget number of parent's text field + int ok_btn; // widget number of parent's ok button (=0 when ok shouldn't be passed on) + int cancel_btn; // widget number of parent's cancel button (=0 when cancel shouldn't be passed on; text will be reverted to original) + Textbuf *text; // pointer to parent's textbuffer (to update caret position) + char *orig; // the original text, in case we cancel +}; +assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(osk_d)); + +enum OskWidgets { + OSK_WIDGET_TEXT = 3, + OSK_WIDGET_CANCEL = 5, + OSK_WIDGET_OK, + OSK_WIDGET_BACKSPACE, + OSK_WIDGET_SPECIAL, + OSK_WIDGET_CAPS, + OSK_WIDGET_SHIFT, + OSK_WIDGET_SPACE, + OSK_WIDGET_LEFT, + OSK_WIDGET_RIGHT, + OSK_WIDGET_LETTERS +}; + +char _keyboard_opt[2][100]; +WChar _keyboard[2][50]; + +#define KEYS_NONE 0x0 +#define KEYS_SHIFT 1 +#define KEYS_CAPS 2 +byte _keystate = KEYS_NONE; + +/* on screen keyboard */ +static void OskWndProc(Window *w, WindowEvent *e) +{ + querystr_d *qs = WP(w,osk_d).qs; + + switch (e->event) { + case WE_CREATE: + SetBit(_no_scroll, SCROLL_EDIT); + break; + + case WE_PAINT: { + bool shift = HasBit(_keystate, KEYS_CAPS) || HasBit(_keystate, KEYS_SHIFT); + + w->LowerWidget(OSK_WIDGET_TEXT); + w->SetWidgetLoweredState(OSK_WIDGET_SHIFT, HasBit(_keystate, KEYS_SHIFT)); + w->SetWidgetLoweredState(OSK_WIDGET_CAPS, HasBit(_keystate, KEYS_CAPS)); + + SetDParam(0, qs->caption); + DrawWindowWidgets(w); + + for(int i=0; i<50; i++) { + DrawCharCentered(_keyboard[shift][i], + w->widget[OSK_WIDGET_LETTERS + i].left + 8, + w->widget[OSK_WIDGET_LETTERS + i].top + 3, + TC_BLACK); + } + + DrawEditBox(w, qs, OSK_WIDGET_TEXT); + break; + } + + case WE_CLICK: + /* clicked a letter */ + if (e->we.click.widget >= OSK_WIDGET_LETTERS) { + bool shift = HasBit(_keystate, KEYS_CAPS) || HasBit(_keystate, KEYS_SHIFT); + + WChar c = _keyboard[shift][ e->we.click.widget - OSK_WIDGET_LETTERS ]; + if(!IsValidChar(c, qs->afilter)) + break; + + if (InsertTextBufferChar(&qs->text, c)) + w->InvalidateWidget(OSK_WIDGET_TEXT); + + if(HasBit(_keystate, KEYS_SHIFT)) { + ToggleBit(_keystate, KEYS_SHIFT); + w->widget[OSK_WIDGET_SHIFT].color = HasBit(_keystate, KEYS_SHIFT)?15:14; + SetWindowDirty(w); + } + break; + } + + switch (e->we.click.widget) { + case OSK_WIDGET_BACKSPACE: + if (DeleteTextBufferChar(&qs->text, WKC_BACKSPACE)) + w->InvalidateWidget(OSK_WIDGET_TEXT); + break; + case OSK_WIDGET_SPECIAL: + /* anything device specific can go here. for the NDS i plan to insert the username, which can be read from the firmware */ + break; + case OSK_WIDGET_CAPS: + ToggleBit(_keystate, KEYS_CAPS); + SetWindowDirty(w); + break; + case OSK_WIDGET_SHIFT: + ToggleBit(_keystate, KEYS_SHIFT); + SetWindowDirty(w); + break; + case OSK_WIDGET_SPACE: + if (InsertTextBufferChar(&qs->text, ' ')) + w->InvalidateWidget(OSK_WIDGET_TEXT); + break; + case OSK_WIDGET_LEFT: + if (MoveTextBufferPos(&qs->text, WKC_LEFT)) + w->InvalidateWidget(OSK_WIDGET_TEXT); + break; + case OSK_WIDGET_RIGHT: + if (MoveTextBufferPos(&qs->text, WKC_RIGHT)) + w->InvalidateWidget(OSK_WIDGET_TEXT); + break; + case OSK_WIDGET_OK: + if (qs->orig == NULL || strcmp(qs->text.buf, qs->orig) != 0) { + /* pass information by simulating a button press on parent window */ + if(WP(w,osk_d).ok_btn != 0) { + Window *parent = w->parent; + WindowEvent e; + e.event = WE_CLICK; + e.we.click.widget = WP(w,osk_d).ok_btn; + parent->wndproc(parent, &e); + } + } + DeleteWindow(w); + break; + case OSK_WIDGET_CANCEL: + if(WP(w,osk_d).cancel_btn != 0) { // pass a cancel event to the parent window + Window *parent = w->parent; + WindowEvent e; + e.event = WE_CLICK; + e.we.click.widget = WP(w,osk_d).cancel_btn; + parent->wndproc(parent, &e); + } else { // or reset to original string + strcpy(qs->text.buf, WP(w,osk_d).orig); + UpdateTextBufferSize(&qs->text); + MoveTextBufferPos(&qs->text, WKC_END); + } + DeleteWindow(w); + break; + } + // make sure that the parent window's textbox also gets updated + if(w->parent != NULL) + w->parent->InvalidateWidget(WP(w,osk_d).text_btn); + break; + + case WE_MOUSELOOP: + HandleEditBox(w, qs, OSK_WIDGET_TEXT); + // make the caret of the parent window also blink + w->parent->InvalidateWidget(WP(w,osk_d).text_btn); + break; + + case WE_DESTROY: + break; + + } + +} + +static const Widget _osk_widgets[] = { +{ WWT_EMPTY, RESIZE_NONE, 0, 0, 0, 0, 0, 0x0, STR_NULL}, +{ WWT_CAPTION, RESIZE_NONE, 14, 0, 255, 0, 13, STR_012D, STR_NULL}, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 255, 14, 29, 0x0, STR_NULL}, +{ WWT_EDITBOX, RESIZE_NONE, 14, 2, 253, 16, 27, 0x0, STR_NULL}, + +{ WWT_PANEL, RESIZE_NONE, 14, 0, 255, 30, 139, 0x0, STR_NULL}, + +{ WWT_TEXTBTN, RESIZE_NONE, 14, 3, 108, 35, 46, STR_012E_CANCEL, STR_NULL}, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 111, 216, 35, 46, STR_012F_OK, STR_NULL}, +{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 219, 252, 35, 46, SPR_OSK_BACKSPACE,STR_NULL}, + +{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 3, 27, 67, 82, SPR_OSK_SPECIAL, STR_NULL}, +{ WWT_IMGBTN, RESIZE_NONE, 14, 3, 36, 85, 100, SPR_OSK_CAPS, STR_NULL}, +{ WWT_IMGBTN, RESIZE_NONE, 14, 3, 27, 103, 118, SPR_OSK_SHIFT, STR_NULL}, + +{ WWT_PUSHTXTBTN, RESIZE_NONE, 14, 75, 189, 121, 136, STR_EMPTY, STR_NULL}, + +{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 219, 234, 121, 136, SPR_OSK_LEFT, STR_NULL}, +{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 237, 252, 121, 136, SPR_OSK_RIGHT, STR_NULL}, + +{ WWT_PUSHBTN, RESIZE_NONE, 14, 3, 18, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 21, 36, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 39, 54, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 57, 72, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 75, 90, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 93, 108, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 111, 126, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 129, 144, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 147, 162, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 165, 180, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 183, 198, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 201, 216, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 219, 234, 49, 64, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 237, 252, 49, 64, 0x0, STR_NULL}, + +{ WWT_PUSHBTN, RESIZE_NONE, 14, 30, 45, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 48, 63, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 66, 81, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 84, 99, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 102, 117, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 120, 135, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 138, 153, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 156, 171, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 174, 189, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 192, 207, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 210, 225, 67, 82, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 228, 243, 67, 82, 0x0, STR_NULL}, + +{ WWT_PUSHBTN, RESIZE_NONE, 14, 39, 54, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 57, 72, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 75, 90, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 93, 108, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 111, 126, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 129, 144, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 147, 162, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 165, 180, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 183, 198, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 201, 216, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 219, 234, 85, 100, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 237, 252, 85, 100, 0x0, STR_NULL}, + +{ WWT_PUSHBTN, RESIZE_NONE, 14, 30, 45, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 48, 63, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 66, 81, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 84, 99, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 102, 117, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 120, 135, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 138, 153, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 156, 171, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 174, 189, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 192, 207, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 210, 225, 103, 118, 0x0, STR_NULL}, +{ WWT_PUSHBTN, RESIZE_NONE, 14, 228, 243, 103, 118, 0x0, STR_NULL}, + +{ WIDGETS_END}, +}; + +WindowDesc _osk_desc = { + WDP_CENTER, WDP_CENTER, 256, 140, 256, 140, + WC_OSK, WC_NONE, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS, + _osk_widgets, + OskWndProc +}; + +/* Retrieve keyboard layout from language string or (if set) config file. + * Also check for invalid characters. */ +void GetKeyboardLayout() +{ + char keyboard[2][100]; + + if(_keyboard_opt[0][0] == '\0') + GetString(keyboard[0], STR_OSK_KEYBOARD_LAYOUT, lastof(keyboard[0])); + else + strncpy (keyboard[0], _keyboard_opt[0], 100); + + if(_keyboard_opt[1][0] == '\0') + GetString(keyboard[1], STR_OSK_KEYBOARD_LAYOUT_CAPS, lastof(keyboard[1])); + else + strncpy (keyboard[1], _keyboard_opt[1], 100); + + const char *kbd[2] = { keyboard[0], keyboard[1] }; + + DEBUG(misc, 1, "Keyboard: >>>%s<<<", keyboard[0]); + DEBUG(misc, 1, " Caps: >>>%s<<<", keyboard[1]); + + for(int j=0; j<2; j++) + for(int i=0; i<50; i++) { + _keyboard[j][i] = Utf8Consume(&kbd[j]); + + if(!IsPrintable(_keyboard[j][i])) { + ShowInfoF("The keyboard layout you selected contains an invalid char at position %i in %s layout! (Between %c and %c)", i, j?"caps lock":"normal", _keyboard[j][i-1], _keyboard[j][i+1]); + _keyboard[j][i] = ' '; + } + } +} + +/** Show the osk associated with a given textbox + * @param parent pointer to the Window where this keyboard originated from + * @param q querystr_d pointer to the query string of the parent, which is + * shared for both windows + * @param int button widget number of parent's textbox + * @param int cancel widget number of parent's cancel button (0 if cancel events + * should not be passed) + * @param int ok widget number of parent's ok button (0 if ok events should not + * be passed) */ +void ShowOnScreenKeyboard(Window *parent, querystr_d *q, int button, int cancel, int ok) +{ + Window *w; + + DeleteWindowById(WC_OSK, 0); + + w = AllocateWindowDesc(&_osk_desc); + + w->parent = parent; + assert(parent != NULL); + + if(parent->widget[button].data != 0) + q->caption = parent->widget[button].data; + + WP(w, osk_d).qs = q; + WP(w, osk_d).text_btn = button; + WP(w, osk_d).cancel_btn = cancel; + WP(w, osk_d).ok_btn = ok; + WP(w, osk_d).text = &q->text; + + GetKeyboardLayout(); + + // make a copy in case we need to reset later + strcpy(_orig_str_buf, WP(w, osk_d).qs->text.buf); + WP(w, osk_d).orig = _orig_str_buf; +} Index: src/signs_gui.cpp =================================================================== --- src/signs_gui.cpp (revision 12357) +++ src/signs_gui.cpp (working copy) @@ -164,8 +164,6 @@ SignID cur_sign; }; -static char _edit_str_buf[64]; - enum QueryEditSignWidgets { QUERY_EDIT_SIGN_WIDGET_TEXT = 3, QUERY_EDIT_SIGN_WIDGET_OK, @@ -249,6 +247,10 @@ UpdateSignEditWindow(w, si); break; + case QUERY_EDIT_SIGN_WIDGET_TEXT: + ShowOnScreenKeyboard(w, qs, e->we.click.widget, QUERY_EDIT_SIGN_WIDGET_CANCEL, QUERY_EDIT_SIGN_WIDGET_OK); + break; + case QUERY_EDIT_SIGN_WIDGET_DELETE: /* Only need to set the buffer to null, the rest is handled as the OK button */ DeleteTextBufferAll(&qs->text); @@ -287,16 +289,16 @@ } static const Widget _query_sign_edit_widgets[] = { -{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, -{ WWT_CAPTION, RESIZE_NONE, 14, 11, 259, 0, 13, STR_012D, STR_NULL }, -{ WWT_PANEL, RESIZE_NONE, 14, 0, 259, 14, 29, STR_NULL, STR_NULL }, -{ WWT_PANEL, RESIZE_NONE, 14, 2, 257, 16, 27, STR_NULL, STR_NULL }, // Text field -{ WWT_TEXTBTN, RESIZE_NONE, 14, 0, 60, 30, 41, STR_012F_OK, STR_NULL }, -{ WWT_TEXTBTN, RESIZE_NONE, 14, 61, 120, 30, 41, STR_012E_CANCEL, STR_NULL }, -{ WWT_TEXTBTN, RESIZE_NONE, 14, 121, 180, 30, 41, STR_0290_DELETE, STR_NULL }, -{ WWT_PANEL, RESIZE_NONE, 14, 181, 237, 30, 41, STR_NULL, STR_NULL }, -{ WWT_TEXTBTN, RESIZE_NONE, 14, 238, 248, 30, 41, STR_6819, STR_PREVIOUS_SIGN_TOOLTIP }, -{ WWT_TEXTBTN, RESIZE_NONE, 14, 249, 259, 30, 41, STR_681A, STR_NEXT_SIGN_TOOLTIP }, +{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, RESIZE_NONE, 14, 11, 259, 0, 13, STR_012D, STR_NULL }, +{ WWT_PANEL, RESIZE_NONE, 14, 0, 259, 14, 29, STR_NULL, STR_NULL }, +{ WWT_EDITBOX, RESIZE_NONE, 14, 2, 257, 16, 27, STR_SIGN_OSKTITLE, STR_NULL }, // Text field +{ WWT_TEXTBTN, RESIZE_NONE, 14, 0, 60, 30, 41, STR_012F_OK, STR_NULL }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 61, 120, 30, 41, STR_012E_CANCEL, STR_NULL }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 121, 180, 30, 41, STR_0290_DELETE, STR_NULL }, +{ WWT_PANEL, RESIZE_NONE, 14, 181, 237, 30, 41, STR_NULL, STR_NULL }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 238, 248, 30, 41, STR_6819, STR_PREVIOUS_SIGN_TOOLTIP }, +{ WWT_TEXTBTN, RESIZE_NONE, 14, 249, 259, 30, 41, STR_681A, STR_NEXT_SIGN_TOOLTIP }, { WIDGETS_END }, }; Index: src/gfx.cpp =================================================================== --- src/gfx.cpp (revision 12357) +++ src/gfx.cpp (working copy) @@ -561,6 +561,20 @@ return br; } +void DrawCharCentered(WChar c, int x, int y, uint16 real_color) +{ + FontSize size = FS_NORMAL; + byte color = real_color & 0xFF; + uint palette = _use_dos_palette ? 1 : 0; + int w = GetCharacterWidth(size, c); + + _string_colorremap[1] = _string_colormap[palette][color].text; + _string_colorremap[2] = _string_colormap[palette][color].shadow; + _color_remap_ptr = _string_colorremap; + + GfxMainBlitter(GetGlyph(size, c), x - w/2, y, BM_COLOUR_REMAP); +} + /** Draw a string at the given coordinates with the given colour * @param string the string to draw * @param x offset from left side of the screen, if negative offset from the right side Index: bin/data/openttdw.grf =================================================================== Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream Index: source.list =================================================================== --- source.list (revision 12357) +++ source.list (working copy) @@ -289,6 +289,7 @@ newgrf_gui.cpp news_gui.cpp order_gui.cpp +osk_gui.cpp player_gui.cpp rail_gui.cpp road_gui.cpp