line_edit.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371
  1. /*************************************************************************/
  2. /* line_edit.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "line_edit.h"
  30. #include "os/keyboard.h"
  31. #include "os/os.h"
  32. #include "print_string.h"
  33. #include "label.h"
  34. #include "translation.h"
  35. #ifdef TOOLS_ENABLED
  36. #include "tools/editor/editor_settings.h"
  37. #endif
  38. static bool _is_text_char(CharType c) {
  39. return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
  40. }
  41. void LineEdit::_input_event(InputEvent p_event) {
  42. switch(p_event.type) {
  43. case InputEvent::MOUSE_BUTTON: {
  44. const InputEventMouseButton &b = p_event.mouse_button;
  45. if (b.pressed && b.button_index==BUTTON_RIGHT) {
  46. menu->set_pos(get_global_transform().xform(get_local_mouse_pos()));
  47. menu->set_size(Vector2(1,1));
  48. menu->popup();
  49. grab_focus();
  50. return;
  51. }
  52. if (b.button_index!=BUTTON_LEFT)
  53. break;
  54. _reset_caret_blink_timer();
  55. if (b.pressed) {
  56. shift_selection_check_pre(b.mod.shift);
  57. set_cursor_at_pixel_pos(b.x);
  58. if (b.mod.shift) {
  59. selection_fill_at_cursor();
  60. selection.creating=true;
  61. } else {
  62. if (b.doubleclick) {
  63. selection.enabled=true;
  64. selection.begin=0;
  65. selection.end=text.length();
  66. selection.doubleclick=true;
  67. }
  68. selection.drag_attempt=false;
  69. if ((cursor_pos<selection.begin) || (cursor_pos>selection.end) || !selection.enabled) {
  70. selection_clear();
  71. selection.cursor_start=cursor_pos;
  72. selection.creating=true;
  73. } else if (selection.enabled) {
  74. selection.drag_attempt=true;
  75. }
  76. }
  77. // if (!editable)
  78. // non_editable_clicked_signal.call();
  79. update();
  80. } else {
  81. if ( (!selection.creating) && (!selection.doubleclick)) {
  82. selection_clear();
  83. }
  84. selection.creating=false;
  85. selection.doubleclick=false;
  86. if (OS::get_singleton()->has_virtual_keyboard())
  87. OS::get_singleton()->show_virtual_keyboard(text,get_global_rect());
  88. }
  89. update();
  90. } break;
  91. case InputEvent::MOUSE_MOTION: {
  92. const InputEventMouseMotion& m=p_event.mouse_motion;
  93. if (m.button_mask&BUTTON_LEFT) {
  94. if (selection.creating) {
  95. set_cursor_at_pixel_pos(m.x);
  96. selection_fill_at_cursor();
  97. }
  98. }
  99. } break;
  100. case InputEvent::KEY: {
  101. const InputEventKey &k =p_event.key;
  102. if (!k.pressed)
  103. return;
  104. unsigned int code = k.scancode;
  105. if (k.mod.command) {
  106. bool handled=true;
  107. switch (code) {
  108. case (KEY_X): { // CUT
  109. if(editable) {
  110. cut_text();
  111. }
  112. } break;
  113. case (KEY_C): { // COPY
  114. copy_text();
  115. } break;
  116. case (KEY_V): { // PASTE
  117. if(editable) {
  118. paste_text();
  119. }
  120. } break;
  121. case (KEY_Z): { // Simple One level undo
  122. if(editable) {
  123. undo();
  124. }
  125. } break;
  126. case (KEY_U): { // Delete from start to cursor
  127. if(editable) {
  128. selection_clear();
  129. undo_text = text;
  130. text = text.substr(cursor_pos,text.length()-cursor_pos);
  131. Ref<Font> font = get_font("font");
  132. cached_width = 0;
  133. if (font != NULL) {
  134. for (int i = 0; i < text.length(); i++)
  135. cached_width += font->get_char_size(text[i]).width;
  136. }
  137. set_cursor_pos(0);
  138. _text_changed();
  139. }
  140. } break;
  141. case (KEY_Y): { // PASTE (Yank for unix users)
  142. if(editable) {
  143. paste_text();
  144. }
  145. } break;
  146. case (KEY_K): { // Delete from cursor_pos to end
  147. if(editable) {
  148. selection_clear();
  149. undo_text = text;
  150. text = text.substr(0,cursor_pos);
  151. _text_changed();
  152. }
  153. } break;
  154. case (KEY_A): { //Select All
  155. select();
  156. } break;
  157. default: { handled=false;}
  158. }
  159. if (handled) {
  160. accept_event();
  161. return;
  162. }
  163. }
  164. _reset_caret_blink_timer();
  165. if (!k.mod.meta) {
  166. bool handled=true;
  167. switch (code) {
  168. case KEY_ENTER:
  169. case KEY_RETURN: {
  170. emit_signal( "text_entered",text );
  171. if (OS::get_singleton()->has_virtual_keyboard())
  172. OS::get_singleton()->hide_virtual_keyboard();
  173. return;
  174. } break;
  175. case KEY_BACKSPACE: {
  176. if (!editable)
  177. break;
  178. if (selection.enabled) {
  179. undo_text=text;
  180. selection_delete();
  181. break;
  182. }
  183. #ifdef APPLE_STYLE_KEYS
  184. if (k.mod.alt) {
  185. #else
  186. if (k.mod.alt) {
  187. handled=false;
  188. break;
  189. } else if (k.mod.command) {
  190. #endif
  191. int cc=cursor_pos;
  192. bool prev_char=false;
  193. while (cc>0) {
  194. bool ischar=_is_text_char(text[cc-1]);
  195. if (prev_char && !ischar)
  196. break;
  197. prev_char=ischar;
  198. cc--;
  199. }
  200. delete_text(cc, cursor_pos);
  201. set_cursor_pos(cc);
  202. } else {
  203. undo_text=text;
  204. delete_char();
  205. }
  206. } break;
  207. case KEY_KP_4: {
  208. if (k.unicode != 0) {
  209. handled = false;
  210. break;
  211. }
  212. // numlock disabled. fallthrough to key_left
  213. }
  214. case KEY_LEFT: {
  215. #ifndef APPLE_STYLE_KEYS
  216. if (!k.mod.alt)
  217. #endif
  218. shift_selection_check_pre(k.mod.shift);
  219. #ifdef APPLE_STYLE_KEYS
  220. if (k.mod.command) {
  221. set_cursor_pos(0);
  222. } else if (k.mod.alt) {
  223. #else
  224. if (k.mod.alt) {
  225. handled=false;
  226. break;
  227. } else if (k.mod.command) {
  228. #endif
  229. bool prev_char=false;
  230. int cc=cursor_pos;
  231. while (cc>0) {
  232. bool ischar=_is_text_char(text[cc-1]);
  233. if (prev_char && !ischar)
  234. break;
  235. prev_char=ischar;
  236. cc--;
  237. }
  238. set_cursor_pos(cc);
  239. } else {
  240. set_cursor_pos(get_cursor_pos()-1);
  241. }
  242. shift_selection_check_post(k.mod.shift);
  243. } break;
  244. case KEY_KP_6: {
  245. if (k.unicode != 0) {
  246. handled = false;
  247. break;
  248. }
  249. // numlock disabled. fallthrough to key_right
  250. }
  251. case KEY_RIGHT: {
  252. shift_selection_check_pre(k.mod.shift);
  253. #ifdef APPLE_STYLE_KEYS
  254. if (k.mod.command) {
  255. set_cursor_pos(text.length());
  256. } else if (k.mod.alt) {
  257. #else
  258. if (k.mod.alt) {
  259. handled=false;
  260. break;
  261. } else if (k.mod.command) {
  262. #endif
  263. bool prev_char=false;
  264. int cc=cursor_pos;
  265. while (cc<text.length()) {
  266. bool ischar=_is_text_char(text[cc]);
  267. if (prev_char && !ischar)
  268. break;
  269. prev_char=ischar;
  270. cc++;
  271. }
  272. set_cursor_pos(cc);
  273. } else {
  274. set_cursor_pos(get_cursor_pos()+1);
  275. }
  276. shift_selection_check_post(k.mod.shift);
  277. } break;
  278. case KEY_DELETE: {
  279. if (!editable)
  280. break;
  281. if (k.mod.shift && !k.mod.command && !k.mod.alt) {
  282. cut_text();
  283. break;
  284. }
  285. if (selection.enabled) {
  286. undo_text=text;
  287. selection_delete();
  288. break;
  289. }
  290. int text_len = text.length();
  291. if (cursor_pos==text_len)
  292. break; // nothing to do
  293. #ifdef APPLE_STYLE_KEYS
  294. if (k.mod.alt) {
  295. #else
  296. if (k.mod.alt) {
  297. handled=false;
  298. break;
  299. } else if (k.mod.command) {
  300. #endif
  301. int cc=cursor_pos;
  302. bool prev_char=false;
  303. while (cc<text.length()) {
  304. bool ischar=_is_text_char(text[cc]);
  305. if (prev_char && !ischar)
  306. break;
  307. prev_char=ischar;
  308. cc++;
  309. }
  310. delete_text(cursor_pos,cc);
  311. } else {
  312. undo_text=text;
  313. set_cursor_pos(cursor_pos+1);
  314. delete_char();
  315. }
  316. } break;
  317. case KEY_KP_7: {
  318. if (k.unicode != 0) {
  319. handled = false;
  320. break;
  321. }
  322. // numlock disabled. fallthrough to key_home
  323. }
  324. case KEY_HOME: {
  325. shift_selection_check_pre(k.mod.shift);
  326. set_cursor_pos(0);
  327. shift_selection_check_post(k.mod.shift);
  328. } break;
  329. case KEY_KP_1: {
  330. if (k.unicode != 0) {
  331. handled = false;
  332. break;
  333. }
  334. // numlock disabled. fallthrough to key_end
  335. }
  336. case KEY_END: {
  337. shift_selection_check_pre(k.mod.shift);
  338. set_cursor_pos(text.length());
  339. shift_selection_check_post(k.mod.shift);
  340. } break;
  341. default: {
  342. handled=false;
  343. } break;
  344. }
  345. if (handled) {
  346. accept_event();
  347. } else if (!k.mod.alt && !k.mod.command) {
  348. if (k.unicode>=32 && k.scancode!=KEY_DELETE) {
  349. if (editable) {
  350. selection_delete();
  351. CharType ucodestr[2]={(CharType)k.unicode,0};
  352. append_at_cursor(ucodestr);
  353. _text_changed();
  354. accept_event();
  355. }
  356. } else {
  357. return;
  358. }
  359. }
  360. update();
  361. }
  362. return;
  363. } break;
  364. }
  365. }
  366. void LineEdit::set_align(Align p_align) {
  367. ERR_FAIL_INDEX(p_align, 4);
  368. align = p_align;
  369. update();
  370. }
  371. LineEdit::Align LineEdit::get_align() const{
  372. return align;
  373. }
  374. Variant LineEdit::get_drag_data(const Point2& p_point) {
  375. if (selection.drag_attempt && selection.enabled) {
  376. String t = text.substr(selection.begin, selection.end - selection.begin);
  377. Label *l = memnew( Label );
  378. l->set_text(t);
  379. set_drag_preview(l);
  380. return t;
  381. }
  382. return Variant();
  383. }
  384. bool LineEdit::can_drop_data(const Point2& p_point,const Variant& p_data) const{
  385. return p_data.get_type()==Variant::STRING;
  386. }
  387. void LineEdit::drop_data(const Point2& p_point,const Variant& p_data){
  388. if (p_data.get_type()==Variant::STRING) {
  389. set_cursor_at_pixel_pos(p_point.x);
  390. int selected = selection.end - selection.begin;
  391. Ref<Font> font = get_font("font");
  392. if (font != NULL) {
  393. for (int i = selection.begin; i < selection.end; i++)
  394. cached_width -= font->get_char_size(text[i]).width;
  395. }
  396. text.erase(selection.begin, selected);
  397. append_at_cursor(p_data);
  398. selection.begin = cursor_pos-selected;
  399. selection.end = cursor_pos;
  400. }
  401. }
  402. void LineEdit::_notification(int p_what) {
  403. switch(p_what) {
  404. #ifdef TOOLS_ENABLED
  405. case NOTIFICATION_ENTER_TREE: {
  406. if (get_tree()->is_editor_hint()) {
  407. cursor_set_blink_enabled(EDITOR_DEF("text_editor/caret_blink", false));
  408. cursor_set_blink_speed(EDITOR_DEF("text_editor/caret_blink_speed", 0.65));
  409. if (!EditorSettings::get_singleton()->is_connected("settings_changed",this,"_editor_settings_changed")) {
  410. EditorSettings::get_singleton()->connect("settings_changed",this,"_editor_settings_changed");
  411. }
  412. }
  413. } break;
  414. #endif
  415. case NOTIFICATION_RESIZED: {
  416. set_cursor_pos( get_cursor_pos() );
  417. } break;
  418. case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
  419. window_has_focus = true;
  420. draw_caret = true;
  421. update();
  422. } break;
  423. case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
  424. window_has_focus = false;
  425. draw_caret = false;
  426. update();
  427. } break;
  428. case NOTIFICATION_DRAW: {
  429. if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
  430. draw_caret = false;
  431. }
  432. int width,height;
  433. Size2 size=get_size();
  434. width=size.width;
  435. height=size.height;
  436. RID ci = get_canvas_item();
  437. Ref<StyleBox> style = get_stylebox("normal");
  438. if (!is_editable())
  439. style=get_stylebox("read_only");
  440. Ref<Font> font=get_font("font");
  441. style->draw( ci, Rect2( Point2(), size ) );
  442. if (has_focus()) {
  443. get_stylebox("focus")->draw( ci, Rect2( Point2(), size ) );
  444. }
  445. int x_ofs=0;
  446. switch (align) {
  447. case ALIGN_FILL:
  448. case ALIGN_LEFT: {
  449. x_ofs=style->get_offset().x;
  450. } break;
  451. case ALIGN_CENTER: {
  452. x_ofs=int(size.width-(cached_width))/2;
  453. } break;
  454. case ALIGN_RIGHT: {
  455. x_ofs=int(size.width-style->get_offset().x-(cached_width));
  456. } break;
  457. }
  458. int ofs_max=width-style->get_minimum_size().width;
  459. int char_ofs=window_pos;
  460. int y_area=height-style->get_minimum_size().height;
  461. int y_ofs=style->get_offset().y;
  462. int font_ascent=font->get_ascent();
  463. Color selection_color=get_color("selection_color");
  464. Color font_color=get_color("font_color");
  465. Color font_color_selected=get_color("font_color_selected");
  466. Color cursor_color=get_color("cursor_color");
  467. const String& t = text.empty() ? placeholder : text;
  468. // draw placeholder color
  469. if(text.empty())
  470. font_color.a *= placeholder_alpha;
  471. int caret_height = font->get_height() > y_area ? y_area : font->get_height();
  472. while(true) {
  473. //end of string, break!
  474. if (char_ofs>=t.length())
  475. break;
  476. CharType cchar=pass?'*':t[char_ofs];
  477. CharType next=pass?'*':t[char_ofs+1];
  478. int char_width=font->get_char_size( cchar,next ).width;
  479. // end of widget, break!
  480. if ((x_ofs + char_width) > ofs_max)
  481. break;
  482. bool selected=selection.enabled && char_ofs>=selection.begin && char_ofs<selection.end;
  483. if (selected)
  484. VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, caret_height)), selection_color);
  485. font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
  486. if (char_ofs==cursor_pos && draw_caret) {
  487. VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
  488. Point2( x_ofs , y_ofs ), Size2( 1, caret_height ) ), cursor_color );
  489. }
  490. x_ofs+=char_width;
  491. char_ofs++;
  492. }
  493. if (char_ofs==cursor_pos && draw_caret) {//may be at the end
  494. VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
  495. Point2( x_ofs , y_ofs ), Size2( 1, caret_height ) ), cursor_color );
  496. }
  497. } break;
  498. case NOTIFICATION_FOCUS_ENTER: {
  499. if (!caret_blink_enabled) {
  500. draw_caret = true;
  501. }
  502. if (OS::get_singleton()->has_virtual_keyboard())
  503. OS::get_singleton()->show_virtual_keyboard(text,get_global_rect());
  504. } break;
  505. case NOTIFICATION_FOCUS_EXIT: {
  506. if (OS::get_singleton()->has_virtual_keyboard())
  507. OS::get_singleton()->hide_virtual_keyboard();
  508. } break;
  509. }
  510. }
  511. void LineEdit::copy_text() {
  512. if(selection.enabled) {
  513. OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
  514. }
  515. }
  516. void LineEdit::cut_text() {
  517. if(selection.enabled) {
  518. undo_text = text;
  519. OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
  520. selection_delete();
  521. }
  522. }
  523. void LineEdit::paste_text() {
  524. String paste_buffer = OS::get_singleton()->get_clipboard();
  525. if(paste_buffer != "") {
  526. if(selection.enabled) selection_delete();
  527. append_at_cursor(paste_buffer);
  528. _text_changed();
  529. }
  530. }
  531. void LineEdit::undo() {
  532. int old_cursor_pos = cursor_pos;
  533. text = undo_text;
  534. Ref<Font> font = get_font("font");
  535. cached_width = 0;
  536. for (int i = 0; i<text.length(); i++)
  537. cached_width += font->get_char_size(text[i]).width;
  538. if(old_cursor_pos > text.length()) {
  539. set_cursor_pos(text.length());
  540. } else {
  541. set_cursor_pos(old_cursor_pos);
  542. }
  543. _text_changed();
  544. }
  545. void LineEdit::shift_selection_check_pre(bool p_shift) {
  546. if (!selection.enabled && p_shift) {
  547. selection.cursor_start=cursor_pos;
  548. }
  549. if (!p_shift)
  550. selection_clear();
  551. }
  552. void LineEdit::shift_selection_check_post(bool p_shift) {
  553. if (p_shift)
  554. selection_fill_at_cursor();
  555. }
  556. void LineEdit::set_cursor_at_pixel_pos(int p_x) {
  557. Ref<Font> font = get_font("font");
  558. int ofs = window_pos;
  559. Ref<StyleBox> style = get_stylebox("normal");
  560. int pixel_ofs = 0;
  561. Size2 size = get_size();
  562. switch (align) {
  563. case ALIGN_FILL:
  564. case ALIGN_LEFT: {
  565. pixel_ofs = int(style->get_offset().x);
  566. } break;
  567. case ALIGN_CENTER: {
  568. pixel_ofs=int(size.width-(cached_width))/2;
  569. } break;
  570. case ALIGN_RIGHT: {
  571. pixel_ofs=int(size.width-style->get_offset().x-(cached_width));
  572. } break;
  573. }
  574. while (ofs<text.length()) {
  575. int char_w = 0;
  576. if (font != NULL) {
  577. char_w = font->get_char_size(text[ofs]).width;
  578. }
  579. pixel_ofs+=char_w;
  580. if (pixel_ofs > p_x) { //found what we look for
  581. break;
  582. }
  583. ofs++;
  584. }
  585. set_cursor_pos( ofs );
  586. /*
  587. int new_cursor_pos=p_x;
  588. int charwidth=draw_area->get_font_char_width(' ',0);
  589. new_cursor_pos=( ( (new_cursor_pos-2)+ (charwidth/2) ) /charwidth );
  590. if (new_cursor_pos>(int)text.length()) new_cursor_pos=text.length();
  591. set_cursor_pos(window_pos+new_cursor_pos); */
  592. }
  593. bool LineEdit::cursor_get_blink_enabled() const {
  594. return caret_blink_enabled;
  595. }
  596. void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
  597. caret_blink_enabled = p_enabled;
  598. if (p_enabled) {
  599. caret_blink_timer->start();
  600. } else {
  601. caret_blink_timer->stop();
  602. }
  603. draw_caret = true;
  604. }
  605. float LineEdit::cursor_get_blink_speed() const {
  606. return caret_blink_timer->get_wait_time();
  607. }
  608. void LineEdit::cursor_set_blink_speed(const float p_speed) {
  609. ERR_FAIL_COND(p_speed <= 0);
  610. caret_blink_timer->set_wait_time(p_speed);
  611. }
  612. void LineEdit::_reset_caret_blink_timer() {
  613. if (caret_blink_enabled) {
  614. caret_blink_timer->stop();
  615. caret_blink_timer->start();
  616. draw_caret = true;
  617. update();
  618. }
  619. }
  620. void LineEdit::_toggle_draw_caret() {
  621. draw_caret = !draw_caret;
  622. if (is_visible() && has_focus() && window_has_focus) {
  623. update();
  624. }
  625. }
  626. void LineEdit::delete_char() {
  627. if ((text.length()<=0) || (cursor_pos==0)) return;
  628. Ref<Font> font = get_font("font");
  629. if (font != NULL) {
  630. cached_width -= font->get_char_size(text[cursor_pos - 1]).width;
  631. }
  632. text.erase( cursor_pos-1, 1 );
  633. set_cursor_pos(get_cursor_pos()-1);
  634. if (cursor_pos==window_pos) {
  635. // set_window_pos(cursor_pos-get_window_length());
  636. }
  637. _text_changed();
  638. }
  639. void LineEdit::delete_text(int p_from_column, int p_to_column) {
  640. undo_text = text;
  641. if (text.size() > 0)
  642. {
  643. Ref<Font> font = get_font("font");
  644. if (font != NULL) {
  645. for (int i = p_from_column; i < p_to_column; i++)
  646. cached_width -= font->get_char_size(text[i]).width;
  647. }
  648. }
  649. else
  650. {
  651. cached_width = 0;
  652. }
  653. text.erase(p_from_column,p_to_column-p_from_column);
  654. cursor_pos-=CLAMP( cursor_pos-p_from_column, 0, p_to_column-p_from_column);
  655. if (cursor_pos>=text.length()) {
  656. cursor_pos=text.length();
  657. }
  658. if (window_pos>cursor_pos) {
  659. window_pos=cursor_pos;
  660. }
  661. _text_changed();
  662. }
  663. void LineEdit::set_text(String p_text) {
  664. clear_internal();
  665. append_at_cursor(p_text);
  666. update();
  667. cursor_pos=0;
  668. window_pos=0;
  669. }
  670. void LineEdit::clear() {
  671. clear_internal();
  672. _text_changed();
  673. }
  674. String LineEdit::get_text() const {
  675. return text;
  676. }
  677. void LineEdit::set_placeholder(String p_text) {
  678. placeholder = XL_MESSAGE(p_text);
  679. update();
  680. }
  681. String LineEdit::get_placeholder() const {
  682. return placeholder;
  683. }
  684. void LineEdit::set_placeholder_alpha(float p_alpha) {
  685. placeholder_alpha = p_alpha;
  686. update();
  687. }
  688. float LineEdit::get_placeholder_alpha() const {
  689. return placeholder_alpha;
  690. }
  691. void LineEdit::set_cursor_pos(int p_pos) {
  692. if (p_pos>(int)text.length())
  693. p_pos=text.length();
  694. if(p_pos<0)
  695. p_pos=0;
  696. cursor_pos=p_pos;
  697. if (!is_inside_tree()) {
  698. window_pos=cursor_pos;
  699. return;
  700. }
  701. Ref<StyleBox> style = get_stylebox("normal");
  702. Ref<Font> font=get_font("font");
  703. if (cursor_pos<window_pos) {
  704. /* Adjust window if cursor goes too much to the left */
  705. set_window_pos(cursor_pos);
  706. } else if (cursor_pos>window_pos) {
  707. /* Adjust window if cursor goes too much to the right */
  708. int window_width=get_size().width-style->get_minimum_size().width;
  709. if (window_width<0)
  710. return;
  711. int wp=window_pos;
  712. if (font.is_valid()) {
  713. int accum_width=0;
  714. for(int i=cursor_pos;i>=window_pos;i--) {
  715. if (i>=text.length()) {
  716. accum_width=font->get_char_size(' ').width; //anything should do
  717. } else {
  718. accum_width+=font->get_char_size(text[i],i+1<text.length()?text[i+1]:0).width; //anything should do
  719. }
  720. if (accum_width>=window_width)
  721. break;
  722. wp=i;
  723. }
  724. }
  725. if (wp!=window_pos)
  726. set_window_pos( wp );
  727. }
  728. update();
  729. }
  730. int LineEdit::get_cursor_pos() const {
  731. return cursor_pos;
  732. }
  733. void LineEdit::set_window_pos(int p_pos) {
  734. window_pos=p_pos;
  735. if (window_pos<0) window_pos=0;
  736. }
  737. void LineEdit::append_at_cursor(String p_text) {
  738. if ( ( max_length <= 0 ) || (text.length()+p_text.length() <= max_length)) {
  739. undo_text = text;
  740. Ref<Font> font = get_font("font");
  741. if (font != NULL) {
  742. for (int i = 0; i < p_text.length(); i++)
  743. cached_width += font->get_char_size(p_text[i]).width;
  744. }
  745. else {
  746. cached_width = 0;
  747. }
  748. String pre = text.substr( 0, cursor_pos );
  749. String post = text.substr( cursor_pos, text.length()-cursor_pos );
  750. text=pre+p_text+post;
  751. set_cursor_pos(cursor_pos+p_text.length());
  752. }
  753. }
  754. void LineEdit::clear_internal() {
  755. cached_width = 0;
  756. cursor_pos=0;
  757. window_pos=0;
  758. undo_text="";
  759. text="";
  760. update();
  761. }
  762. Size2 LineEdit::get_minimum_size() const {
  763. Ref<StyleBox> style = get_stylebox("normal");
  764. Ref<Font> font=get_font("font");
  765. Size2 min=style->get_minimum_size();
  766. min.height+=font->get_height();
  767. //minimum size of text
  768. int space_size = font->get_char_size(' ').x;
  769. int mstext = get_constant("minimum_spaces")*space_size;
  770. if (expand_to_text_length) {
  771. mstext=MAX(mstext,font->get_string_size(text).x+space_size); //add a spce because some fonts are too exact
  772. }
  773. min.width+=mstext;
  774. return min;
  775. }
  776. /* selection */
  777. void LineEdit::selection_clear() {
  778. selection.begin=0;
  779. selection.end=0;
  780. selection.cursor_start=0;
  781. selection.enabled=false;
  782. selection.creating=false;
  783. selection.doubleclick=false;
  784. update();
  785. }
  786. void LineEdit::selection_delete() {
  787. if (selection.enabled)
  788. delete_text(selection.begin,selection.end);
  789. selection_clear();
  790. }
  791. void LineEdit::set_max_length(int p_max_length) {
  792. ERR_FAIL_COND(p_max_length<0);
  793. max_length = p_max_length;
  794. set_text(text);
  795. }
  796. int LineEdit::get_max_length() const {
  797. return max_length;
  798. }
  799. void LineEdit::selection_fill_at_cursor() {
  800. int aux;
  801. selection.begin=cursor_pos;
  802. selection.end=selection.cursor_start;
  803. if (selection.end<selection.begin) {
  804. aux=selection.end;
  805. selection.end=selection.begin;
  806. selection.begin=aux;
  807. }
  808. selection.enabled=(selection.begin!=selection.end);
  809. }
  810. void LineEdit::select_all() {
  811. if (!text.length())
  812. return;
  813. selection.begin=0;
  814. selection.end=text.length();
  815. selection.enabled=true;
  816. update();
  817. }
  818. void LineEdit::set_editable(bool p_editable) {
  819. editable=p_editable;
  820. update();
  821. }
  822. bool LineEdit::is_editable() const {
  823. return editable;
  824. }
  825. void LineEdit::set_secret(bool p_secret) {
  826. pass=p_secret;
  827. update();
  828. }
  829. bool LineEdit::is_secret() const {
  830. return pass;
  831. }
  832. void LineEdit::select(int p_from, int p_to) {
  833. if (p_from==0 && p_to==0) {
  834. selection_clear();
  835. return;
  836. }
  837. int len = text.length();
  838. if (p_from<0)
  839. p_from=0;
  840. if (p_from>len)
  841. p_from=len;
  842. if (p_to<0 || p_to>len)
  843. p_to=len;
  844. if (p_from>=p_to)
  845. return;
  846. selection.enabled=true;
  847. selection.begin=p_from;
  848. selection.end=p_to;
  849. selection.creating=false;
  850. selection.doubleclick=false;
  851. update();
  852. }
  853. bool LineEdit::is_text_field() const {
  854. return true;
  855. }
  856. void LineEdit::menu_option(int p_option) {
  857. switch(p_option) {
  858. case MENU_CUT: {
  859. if (editable) {
  860. cut_text();
  861. }
  862. } break;
  863. case MENU_COPY: {
  864. copy_text();
  865. } break;
  866. case MENU_PASTE: {
  867. if (editable) {
  868. paste_text();
  869. }
  870. } break;
  871. case MENU_CLEAR: {
  872. if (editable) {
  873. clear();
  874. }
  875. } break;
  876. case MENU_SELECT_ALL: {
  877. select_all();
  878. } break;
  879. case MENU_UNDO: {
  880. undo();
  881. } break;
  882. }
  883. }
  884. PopupMenu *LineEdit::get_menu() const {
  885. return menu;
  886. }
  887. #ifdef TOOLS_ENABLED
  888. void LineEdit::_editor_settings_changed() {
  889. cursor_set_blink_enabled(EDITOR_DEF("text_editor/caret_blink", false));
  890. cursor_set_blink_speed(EDITOR_DEF("text_editor/caret_blink_speed", 0.65));
  891. }
  892. #endif
  893. void LineEdit::set_expand_to_text_length(bool p_enabled) {
  894. expand_to_text_length = p_enabled;
  895. minimum_size_changed();
  896. }
  897. bool LineEdit::get_expand_to_text_length() const{
  898. return expand_to_text_length;
  899. }
  900. void LineEdit::_text_changed() {
  901. if (expand_to_text_length)
  902. minimum_size_changed();
  903. emit_signal("text_changed",text);
  904. _change_notify("text");
  905. }
  906. void LineEdit::_bind_methods() {
  907. ObjectTypeDB::bind_method(_MD("_toggle_draw_caret"),&LineEdit::_toggle_draw_caret);
  908. #ifdef TOOLS_ENABLED
  909. ObjectTypeDB::bind_method("_editor_settings_changed",&LineEdit::_editor_settings_changed);
  910. #endif
  911. ObjectTypeDB::bind_method(_MD("set_align", "align"), &LineEdit::set_align);
  912. ObjectTypeDB::bind_method(_MD("get_align"), &LineEdit::get_align);
  913. ObjectTypeDB::bind_method(_MD("_input_event"),&LineEdit::_input_event);
  914. ObjectTypeDB::bind_method(_MD("clear"),&LineEdit::clear);
  915. ObjectTypeDB::bind_method(_MD("select_all"),&LineEdit::select_all);
  916. ObjectTypeDB::bind_method(_MD("set_text","text"),&LineEdit::set_text);
  917. ObjectTypeDB::bind_method(_MD("get_text"),&LineEdit::get_text);
  918. ObjectTypeDB::bind_method(_MD("set_placeholder","text"),&LineEdit::set_placeholder);
  919. ObjectTypeDB::bind_method(_MD("get_placeholder"),&LineEdit::get_placeholder);
  920. ObjectTypeDB::bind_method(_MD("set_placeholder_alpha","alpha"),&LineEdit::set_placeholder_alpha);
  921. ObjectTypeDB::bind_method(_MD("get_placeholder_alpha"),&LineEdit::get_placeholder_alpha);
  922. ObjectTypeDB::bind_method(_MD("set_cursor_pos","pos"),&LineEdit::set_cursor_pos);
  923. ObjectTypeDB::bind_method(_MD("get_cursor_pos"),&LineEdit::get_cursor_pos);
  924. ObjectTypeDB::bind_method(_MD("set_expand_to_text_length","enabled"),&LineEdit::set_expand_to_text_length);
  925. ObjectTypeDB::bind_method(_MD("get_expand_to_text_length"),&LineEdit::get_expand_to_text_length);
  926. ObjectTypeDB::bind_method(_MD("cursor_set_blink_enabled", "enabled"),&LineEdit::cursor_set_blink_enabled);
  927. ObjectTypeDB::bind_method(_MD("cursor_get_blink_enabled"),&LineEdit::cursor_get_blink_enabled);
  928. ObjectTypeDB::bind_method(_MD("cursor_set_blink_speed", "blink_speed"),&LineEdit::cursor_set_blink_speed);
  929. ObjectTypeDB::bind_method(_MD("cursor_get_blink_speed"),&LineEdit::cursor_get_blink_speed);
  930. ObjectTypeDB::bind_method(_MD("set_max_length","chars"),&LineEdit::set_max_length);
  931. ObjectTypeDB::bind_method(_MD("get_max_length"),&LineEdit::get_max_length);
  932. ObjectTypeDB::bind_method(_MD("append_at_cursor","text"),&LineEdit::append_at_cursor);
  933. ObjectTypeDB::bind_method(_MD("set_editable","enabled"),&LineEdit::set_editable);
  934. ObjectTypeDB::bind_method(_MD("is_editable"),&LineEdit::is_editable);
  935. ObjectTypeDB::bind_method(_MD("set_secret","enabled"),&LineEdit::set_secret);
  936. ObjectTypeDB::bind_method(_MD("is_secret"),&LineEdit::is_secret);
  937. ObjectTypeDB::bind_method(_MD("select","from","to"),&LineEdit::select,DEFVAL(0),DEFVAL(-1));
  938. ObjectTypeDB::bind_method(_MD("menu_option","option"),&LineEdit::menu_option);
  939. ObjectTypeDB::bind_method(_MD("get_menu:PopupMenu"),&LineEdit::get_menu);
  940. ADD_SIGNAL( MethodInfo("text_changed", PropertyInfo( Variant::STRING, "text" )) );
  941. ADD_SIGNAL( MethodInfo("text_entered", PropertyInfo( Variant::STRING, "text" )) );
  942. BIND_CONSTANT(ALIGN_LEFT);
  943. BIND_CONSTANT(ALIGN_CENTER);
  944. BIND_CONSTANT(ALIGN_RIGHT);
  945. BIND_CONSTANT(ALIGN_FILL);
  946. BIND_CONSTANT( MENU_CUT );
  947. BIND_CONSTANT( MENU_COPY );
  948. BIND_CONSTANT( MENU_PASTE );
  949. BIND_CONSTANT( MENU_CLEAR );
  950. BIND_CONSTANT( MENU_SELECT_ALL );
  951. BIND_CONSTANT( MENU_UNDO );
  952. BIND_CONSTANT( MENU_MAX );
  953. ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") );
  954. ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "placeholder/text" ), _SCS("set_placeholder"),_SCS("get_placeholder") );
  955. ADD_PROPERTYNZ( PropertyInfo( Variant::REAL, "placeholder/alpha",PROPERTY_HINT_RANGE,"0,1,0.001" ), _SCS("set_placeholder_alpha"),_SCS("get_placeholder_alpha") );
  956. ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), _SCS("set_align"), _SCS("get_align"));
  957. ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") );
  958. ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") );
  959. ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") );
  960. ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "expand_to_len" ), _SCS("set_expand_to_text_length"),_SCS("get_expand_to_text_length") );
  961. ADD_PROPERTY( PropertyInfo( Variant::INT,"focus_mode", PROPERTY_HINT_ENUM, "None,Click,All" ), _SCS("set_focus_mode"), _SCS("get_focus_mode") );
  962. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret/caret_blink"), _SCS("cursor_set_blink_enabled"), _SCS("cursor_get_blink_enabled"));;
  963. ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret/caret_blink_speed",PROPERTY_HINT_RANGE,"0.1,10,0.1"), _SCS("cursor_set_blink_speed"),_SCS("cursor_get_blink_speed") );
  964. }
  965. LineEdit::LineEdit() {
  966. align = ALIGN_LEFT;
  967. cached_width = 0;
  968. cursor_pos=0;
  969. window_pos=0;
  970. window_has_focus=true;
  971. max_length = 0;
  972. pass=false;
  973. placeholder_alpha=0.6;
  974. selection_clear();
  975. set_focus_mode( FOCUS_ALL );
  976. editable=true;
  977. set_default_cursor_shape(CURSOR_IBEAM);
  978. set_stop_mouse(true);
  979. draw_caret=true;
  980. caret_blink_enabled=false;
  981. caret_blink_timer = memnew(Timer);
  982. add_child(caret_blink_timer);
  983. caret_blink_timer->set_wait_time(0.65);
  984. caret_blink_timer->connect("timeout", this,"_toggle_draw_caret");
  985. cursor_set_blink_enabled(false);
  986. menu = memnew( PopupMenu );
  987. add_child(menu);
  988. menu->add_item(TTR("Cut"),MENU_CUT,KEY_MASK_CMD|KEY_X);
  989. menu->add_item(TTR("Copy"),MENU_COPY,KEY_MASK_CMD|KEY_C);
  990. menu->add_item(TTR("Paste"),MENU_PASTE,KEY_MASK_CMD|KEY_V);
  991. menu->add_separator();
  992. menu->add_item(TTR("Select All"),MENU_SELECT_ALL,KEY_MASK_CMD|KEY_A);
  993. menu->add_item(TTR("Clear"),MENU_CLEAR);
  994. menu->add_separator();
  995. menu->add_item(TTR("Undo"),MENU_UNDO,KEY_MASK_CMD|KEY_Z);
  996. menu->connect("item_pressed",this,"menu_option");
  997. expand_to_text_length=false;
  998. }
  999. LineEdit::~LineEdit() {
  1000. }