item_list.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600
  1. /*************************************************************************/
  2. /* item_list.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "item_list.h"
  31. #include "core/os/os.h"
  32. #include "core/project_settings.h"
  33. void ItemList::add_item(const String &p_item, const Ref<Texture> &p_texture, bool p_selectable) {
  34. Item item;
  35. item.icon = p_texture;
  36. item.icon_transposed = false;
  37. item.icon_region = Rect2i();
  38. item.icon_modulate = Color(1, 1, 1, 1);
  39. item.text = p_item;
  40. item.selectable = p_selectable;
  41. item.selected = false;
  42. item.disabled = false;
  43. item.tooltip_enabled = true;
  44. item.custom_bg = Color(0, 0, 0, 0);
  45. items.push_back(item);
  46. update();
  47. shape_changed = true;
  48. }
  49. void ItemList::add_icon_item(const Ref<Texture> &p_item, bool p_selectable) {
  50. Item item;
  51. item.icon = p_item;
  52. item.icon_transposed = false;
  53. item.icon_region = Rect2i();
  54. item.icon_modulate = Color(1, 1, 1, 1);
  55. //item.text=p_item;
  56. item.selectable = p_selectable;
  57. item.selected = false;
  58. item.disabled = false;
  59. item.tooltip_enabled = true;
  60. item.custom_bg = Color(0, 0, 0, 0);
  61. items.push_back(item);
  62. update();
  63. shape_changed = true;
  64. }
  65. void ItemList::set_item_text(int p_idx, const String &p_text) {
  66. ERR_FAIL_INDEX(p_idx, items.size());
  67. items.write[p_idx].text = p_text;
  68. update();
  69. shape_changed = true;
  70. }
  71. String ItemList::get_item_text(int p_idx) const {
  72. ERR_FAIL_INDEX_V(p_idx, items.size(), String());
  73. return items[p_idx].text;
  74. }
  75. void ItemList::set_item_tooltip_enabled(int p_idx, const bool p_enabled) {
  76. ERR_FAIL_INDEX(p_idx, items.size());
  77. items.write[p_idx].tooltip_enabled = p_enabled;
  78. }
  79. bool ItemList::is_item_tooltip_enabled(int p_idx) const {
  80. ERR_FAIL_INDEX_V(p_idx, items.size(), false);
  81. return items[p_idx].tooltip_enabled;
  82. }
  83. void ItemList::set_item_tooltip(int p_idx, const String &p_tooltip) {
  84. ERR_FAIL_INDEX(p_idx, items.size());
  85. items.write[p_idx].tooltip = p_tooltip;
  86. update();
  87. shape_changed = true;
  88. }
  89. String ItemList::get_item_tooltip(int p_idx) const {
  90. ERR_FAIL_INDEX_V(p_idx, items.size(), String());
  91. return items[p_idx].tooltip;
  92. }
  93. void ItemList::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
  94. ERR_FAIL_INDEX(p_idx, items.size());
  95. items.write[p_idx].icon = p_icon;
  96. update();
  97. shape_changed = true;
  98. }
  99. Ref<Texture> ItemList::get_item_icon(int p_idx) const {
  100. ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Texture>());
  101. return items[p_idx].icon;
  102. }
  103. void ItemList::set_item_icon_transposed(int p_idx, const bool p_transposed) {
  104. ERR_FAIL_INDEX(p_idx, items.size());
  105. items.write[p_idx].icon_transposed = p_transposed;
  106. update();
  107. shape_changed = true;
  108. }
  109. bool ItemList::is_item_icon_transposed(int p_idx) const {
  110. ERR_FAIL_INDEX_V(p_idx, items.size(), false);
  111. return items[p_idx].icon_transposed;
  112. }
  113. void ItemList::set_item_icon_region(int p_idx, const Rect2 &p_region) {
  114. ERR_FAIL_INDEX(p_idx, items.size());
  115. items.write[p_idx].icon_region = p_region;
  116. update();
  117. shape_changed = true;
  118. }
  119. Rect2 ItemList::get_item_icon_region(int p_idx) const {
  120. ERR_FAIL_INDEX_V(p_idx, items.size(), Rect2());
  121. return items[p_idx].icon_region;
  122. }
  123. void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) {
  124. ERR_FAIL_INDEX(p_idx, items.size());
  125. items.write[p_idx].icon_modulate = p_modulate;
  126. update();
  127. }
  128. Color ItemList::get_item_icon_modulate(int p_idx) const {
  129. ERR_FAIL_INDEX_V(p_idx, items.size(), Color());
  130. return items[p_idx].icon_modulate;
  131. }
  132. void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_color) {
  133. ERR_FAIL_INDEX(p_idx, items.size());
  134. items.write[p_idx].custom_bg = p_custom_bg_color;
  135. }
  136. Color ItemList::get_item_custom_bg_color(int p_idx) const {
  137. ERR_FAIL_INDEX_V(p_idx, items.size(), Color());
  138. return items[p_idx].custom_bg;
  139. }
  140. void ItemList::set_item_custom_fg_color(int p_idx, const Color &p_custom_fg_color) {
  141. ERR_FAIL_INDEX(p_idx, items.size());
  142. items.write[p_idx].custom_fg = p_custom_fg_color;
  143. }
  144. Color ItemList::get_item_custom_fg_color(int p_idx) const {
  145. ERR_FAIL_INDEX_V(p_idx, items.size(), Color());
  146. return items[p_idx].custom_fg;
  147. }
  148. void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture> &p_tag_icon) {
  149. ERR_FAIL_INDEX(p_idx, items.size());
  150. items.write[p_idx].tag_icon = p_tag_icon;
  151. update();
  152. shape_changed = true;
  153. }
  154. Ref<Texture> ItemList::get_item_tag_icon(int p_idx) const {
  155. ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Texture>());
  156. return items[p_idx].tag_icon;
  157. }
  158. void ItemList::set_item_selectable(int p_idx, bool p_selectable) {
  159. ERR_FAIL_INDEX(p_idx, items.size());
  160. items.write[p_idx].selectable = p_selectable;
  161. }
  162. bool ItemList::is_item_selectable(int p_idx) const {
  163. ERR_FAIL_INDEX_V(p_idx, items.size(), false);
  164. return items[p_idx].selectable;
  165. }
  166. void ItemList::set_item_disabled(int p_idx, bool p_disabled) {
  167. ERR_FAIL_INDEX(p_idx, items.size());
  168. items.write[p_idx].disabled = p_disabled;
  169. update();
  170. }
  171. bool ItemList::is_item_disabled(int p_idx) const {
  172. ERR_FAIL_INDEX_V(p_idx, items.size(), false);
  173. return items[p_idx].disabled;
  174. }
  175. void ItemList::set_item_metadata(int p_idx, const Variant &p_metadata) {
  176. ERR_FAIL_INDEX(p_idx, items.size());
  177. items.write[p_idx].metadata = p_metadata;
  178. update();
  179. shape_changed = true;
  180. }
  181. Variant ItemList::get_item_metadata(int p_idx) const {
  182. ERR_FAIL_INDEX_V(p_idx, items.size(), Variant());
  183. return items[p_idx].metadata;
  184. }
  185. void ItemList::select(int p_idx, bool p_single) {
  186. ERR_FAIL_INDEX(p_idx, items.size());
  187. if (p_single || select_mode == SELECT_SINGLE) {
  188. if (!items[p_idx].selectable || items[p_idx].disabled) {
  189. return;
  190. }
  191. for (int i = 0; i < items.size(); i++) {
  192. items.write[i].selected = p_idx == i;
  193. }
  194. current = p_idx;
  195. ensure_selected_visible = false;
  196. } else {
  197. if (items[p_idx].selectable && !items[p_idx].disabled) {
  198. items.write[p_idx].selected = true;
  199. }
  200. }
  201. update();
  202. }
  203. void ItemList::unselect(int p_idx) {
  204. ERR_FAIL_INDEX(p_idx, items.size());
  205. if (select_mode != SELECT_MULTI) {
  206. items.write[p_idx].selected = false;
  207. current = -1;
  208. } else {
  209. items.write[p_idx].selected = false;
  210. }
  211. update();
  212. }
  213. void ItemList::unselect_all() {
  214. if (items.size() < 1)
  215. return;
  216. for (int i = 0; i < items.size(); i++) {
  217. items.write[i].selected = false;
  218. }
  219. current = -1;
  220. update();
  221. }
  222. bool ItemList::is_selected(int p_idx) const {
  223. ERR_FAIL_INDEX_V(p_idx, items.size(), false);
  224. return items[p_idx].selected;
  225. }
  226. void ItemList::set_current(int p_current) {
  227. ERR_FAIL_INDEX(p_current, items.size());
  228. if (select_mode == SELECT_SINGLE)
  229. select(p_current, true);
  230. else {
  231. current = p_current;
  232. update();
  233. }
  234. }
  235. int ItemList::get_current() const {
  236. return current;
  237. }
  238. void ItemList::move_item(int p_from_idx, int p_to_idx) {
  239. ERR_FAIL_INDEX(p_from_idx, items.size());
  240. ERR_FAIL_INDEX(p_to_idx, items.size());
  241. if (is_anything_selected() && get_selected_items()[0] == p_from_idx) {
  242. current = p_to_idx;
  243. }
  244. Item item = items[p_from_idx];
  245. items.remove(p_from_idx);
  246. items.insert(p_to_idx, item);
  247. update();
  248. shape_changed = true;
  249. }
  250. int ItemList::get_item_count() const {
  251. return items.size();
  252. }
  253. void ItemList::remove_item(int p_idx) {
  254. ERR_FAIL_INDEX(p_idx, items.size());
  255. items.remove(p_idx);
  256. update();
  257. shape_changed = true;
  258. defer_select_single = -1;
  259. }
  260. void ItemList::clear() {
  261. items.clear();
  262. current = -1;
  263. ensure_selected_visible = false;
  264. update();
  265. shape_changed = true;
  266. defer_select_single = -1;
  267. }
  268. void ItemList::set_fixed_column_width(int p_size) {
  269. ERR_FAIL_COND(p_size < 0);
  270. fixed_column_width = p_size;
  271. update();
  272. shape_changed = true;
  273. }
  274. int ItemList::get_fixed_column_width() const {
  275. return fixed_column_width;
  276. }
  277. void ItemList::set_same_column_width(bool p_enable) {
  278. same_column_width = p_enable;
  279. update();
  280. shape_changed = true;
  281. }
  282. bool ItemList::is_same_column_width() const {
  283. return same_column_width;
  284. }
  285. void ItemList::set_max_text_lines(int p_lines) {
  286. ERR_FAIL_COND(p_lines < 1);
  287. max_text_lines = p_lines;
  288. update();
  289. shape_changed = true;
  290. }
  291. int ItemList::get_max_text_lines() const {
  292. return max_text_lines;
  293. }
  294. void ItemList::set_max_columns(int p_amount) {
  295. ERR_FAIL_COND(p_amount < 0);
  296. max_columns = p_amount;
  297. update();
  298. }
  299. int ItemList::get_max_columns() const {
  300. return max_columns;
  301. }
  302. void ItemList::set_select_mode(SelectMode p_mode) {
  303. select_mode = p_mode;
  304. update();
  305. }
  306. ItemList::SelectMode ItemList::get_select_mode() const {
  307. return select_mode;
  308. }
  309. void ItemList::set_icon_mode(IconMode p_mode) {
  310. icon_mode = p_mode;
  311. update();
  312. shape_changed = true;
  313. }
  314. ItemList::IconMode ItemList::get_icon_mode() const {
  315. return icon_mode;
  316. }
  317. void ItemList::set_fixed_icon_size(const Size2 &p_size) {
  318. fixed_icon_size = p_size;
  319. update();
  320. }
  321. Size2 ItemList::get_fixed_icon_size() const {
  322. return fixed_icon_size;
  323. }
  324. Size2 ItemList::Item::get_icon_size() const {
  325. if (icon.is_null())
  326. return Size2();
  327. Size2 size_result = Size2(icon_region.size).abs();
  328. if (icon_region.size.x == 0 || icon_region.size.y == 0)
  329. size_result = icon->get_size();
  330. if (icon_transposed) {
  331. Size2 size_tmp = size_result;
  332. size_result.x = size_tmp.y;
  333. size_result.y = size_tmp.x;
  334. }
  335. return size_result;
  336. }
  337. void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
  338. Ref<InputEventMouseMotion> mm = p_event;
  339. if (defer_select_single >= 0 && mm.is_valid()) {
  340. defer_select_single = -1;
  341. return;
  342. }
  343. Ref<InputEventMouseButton> mb = p_event;
  344. if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
  345. select(defer_select_single, true);
  346. emit_signal("multi_selected", defer_select_single, true);
  347. defer_select_single = -1;
  348. return;
  349. }
  350. if (mb.is_valid() && (mb->get_button_index() == BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == BUTTON_RIGHT)) && mb->is_pressed()) {
  351. search_string = ""; //any mousepress cancels
  352. Vector2 pos = mb->get_position();
  353. Ref<StyleBox> bg = get_stylebox("bg");
  354. pos -= bg->get_offset();
  355. pos.y += scroll_bar->get_value();
  356. int closest = -1;
  357. for (int i = 0; i < items.size(); i++) {
  358. Rect2 rc = items[i].rect_cache;
  359. if (i % current_columns == current_columns - 1) {
  360. rc.size.width = get_size().width; //not right but works
  361. }
  362. if (rc.has_point(pos)) {
  363. closest = i;
  364. break;
  365. }
  366. }
  367. if (closest != -1) {
  368. int i = closest;
  369. if (select_mode == SELECT_MULTI && items[i].selected && mb->get_command()) {
  370. unselect(i);
  371. emit_signal("multi_selected", i, false);
  372. } else if (select_mode == SELECT_MULTI && mb->get_shift() && current >= 0 && current < items.size() && current != i) {
  373. int from = current;
  374. int to = i;
  375. if (i < current) {
  376. SWAP(from, to);
  377. }
  378. for (int j = from; j <= to; j++) {
  379. bool selected = !items[j].selected;
  380. select(j, false);
  381. if (selected)
  382. emit_signal("multi_selected", j, true);
  383. }
  384. if (mb->get_button_index() == BUTTON_RIGHT) {
  385. emit_signal("item_rmb_selected", i, get_local_mouse_position());
  386. }
  387. } else {
  388. if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == BUTTON_LEFT) {
  389. defer_select_single = i;
  390. return;
  391. }
  392. if (items[i].selected && mb->get_button_index() == BUTTON_RIGHT) {
  393. emit_signal("item_rmb_selected", i, get_local_mouse_position());
  394. } else {
  395. bool selected = items[i].selected;
  396. select(i, select_mode == SELECT_SINGLE || !mb->get_command());
  397. if (!selected || allow_reselect) {
  398. if (select_mode == SELECT_SINGLE) {
  399. emit_signal("item_selected", i);
  400. } else
  401. emit_signal("multi_selected", i, true);
  402. }
  403. if (mb->get_button_index() == BUTTON_RIGHT) {
  404. emit_signal("item_rmb_selected", i, get_local_mouse_position());
  405. } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
  406. emit_signal("item_activated", i);
  407. }
  408. }
  409. }
  410. return;
  411. }
  412. if (mb->get_button_index() == BUTTON_RIGHT) {
  413. emit_signal("rmb_clicked", mb->get_position());
  414. return;
  415. }
  416. // Since closest is null, more likely we clicked on empty space, so send signal to interested controls. Allows, for example, implement items deselecting.
  417. emit_signal("nothing_selected");
  418. }
  419. if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
  420. scroll_bar->set_value(scroll_bar->get_value() - scroll_bar->get_page() * mb->get_factor() / 8);
  421. }
  422. if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
  423. scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * mb->get_factor() / 8);
  424. }
  425. if (p_event->is_pressed() && items.size() > 0) {
  426. if (p_event->is_action("ui_up")) {
  427. if (search_string != "") {
  428. uint64_t now = OS::get_singleton()->get_ticks_msec();
  429. uint64_t diff = now - search_time_msec;
  430. if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
  431. for (int i = current - 1; i >= 0; i--) {
  432. if (items[i].text.begins_with(search_string)) {
  433. set_current(i);
  434. ensure_current_is_visible();
  435. if (select_mode == SELECT_SINGLE) {
  436. emit_signal("item_selected", current);
  437. }
  438. break;
  439. }
  440. }
  441. accept_event();
  442. return;
  443. }
  444. }
  445. if (current >= current_columns) {
  446. set_current(current - current_columns);
  447. ensure_current_is_visible();
  448. if (select_mode == SELECT_SINGLE) {
  449. emit_signal("item_selected", current);
  450. }
  451. accept_event();
  452. }
  453. } else if (p_event->is_action("ui_down")) {
  454. if (search_string != "") {
  455. uint64_t now = OS::get_singleton()->get_ticks_msec();
  456. uint64_t diff = now - search_time_msec;
  457. if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
  458. for (int i = current + 1; i < items.size(); i++) {
  459. if (items[i].text.begins_with(search_string)) {
  460. set_current(i);
  461. ensure_current_is_visible();
  462. if (select_mode == SELECT_SINGLE) {
  463. emit_signal("item_selected", current);
  464. }
  465. break;
  466. }
  467. }
  468. accept_event();
  469. return;
  470. }
  471. }
  472. if (current < items.size() - current_columns) {
  473. set_current(current + current_columns);
  474. ensure_current_is_visible();
  475. if (select_mode == SELECT_SINGLE) {
  476. emit_signal("item_selected", current);
  477. }
  478. accept_event();
  479. }
  480. } else if (p_event->is_action("ui_page_up")) {
  481. search_string = ""; //any mousepress cancels
  482. for (int i = 4; i > 0; i--) {
  483. if (current - current_columns * i >= 0) {
  484. set_current(current - current_columns * i);
  485. ensure_current_is_visible();
  486. if (select_mode == SELECT_SINGLE) {
  487. emit_signal("item_selected", current);
  488. }
  489. accept_event();
  490. break;
  491. }
  492. }
  493. } else if (p_event->is_action("ui_page_down")) {
  494. search_string = ""; //any mousepress cancels
  495. for (int i = 4; i > 0; i--) {
  496. if (current + current_columns * i < items.size()) {
  497. set_current(current + current_columns * i);
  498. ensure_current_is_visible();
  499. if (select_mode == SELECT_SINGLE) {
  500. emit_signal("item_selected", current);
  501. }
  502. accept_event();
  503. break;
  504. }
  505. }
  506. } else if (p_event->is_action("ui_left")) {
  507. search_string = ""; //any mousepress cancels
  508. if (current % current_columns != 0) {
  509. set_current(current - 1);
  510. ensure_current_is_visible();
  511. if (select_mode == SELECT_SINGLE) {
  512. emit_signal("item_selected", current);
  513. }
  514. accept_event();
  515. }
  516. } else if (p_event->is_action("ui_right")) {
  517. search_string = ""; //any mousepress cancels
  518. if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) {
  519. set_current(current + 1);
  520. ensure_current_is_visible();
  521. if (select_mode == SELECT_SINGLE) {
  522. emit_signal("item_selected", current);
  523. }
  524. accept_event();
  525. }
  526. } else if (p_event->is_action("ui_cancel")) {
  527. search_string = "";
  528. } else if (p_event->is_action("ui_select")) {
  529. if (select_mode == SELECT_MULTI && current >= 0 && current < items.size()) {
  530. if (items[current].selectable && !items[current].disabled && !items[current].selected) {
  531. select(current, false);
  532. emit_signal("multi_selected", current, true);
  533. } else if (items[current].selected) {
  534. unselect(current);
  535. emit_signal("multi_selected", current, false);
  536. }
  537. }
  538. } else if (p_event->is_action("ui_accept")) {
  539. search_string = ""; //any mousepress cance
  540. if (current >= 0 && current < items.size()) {
  541. emit_signal("item_activated", current);
  542. }
  543. } else {
  544. Ref<InputEventKey> k = p_event;
  545. if (k.is_valid() && k->get_unicode()) {
  546. uint64_t now = OS::get_singleton()->get_ticks_msec();
  547. uint64_t diff = now - search_time_msec;
  548. uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000));
  549. search_time_msec = now;
  550. if (diff > max_interval) {
  551. search_string = "";
  552. }
  553. search_string += String::chr(k->get_unicode());
  554. for (int i = 0; i < items.size(); i++) {
  555. if (items[i].text.begins_with(search_string)) {
  556. set_current(i);
  557. ensure_current_is_visible();
  558. if (select_mode == SELECT_SINGLE) {
  559. emit_signal("item_selected", current);
  560. }
  561. break;
  562. }
  563. }
  564. }
  565. }
  566. }
  567. Ref<InputEventPanGesture> pan_gesture = p_event;
  568. if (pan_gesture.is_valid()) {
  569. scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * pan_gesture->get_delta().y / 8);
  570. }
  571. }
  572. void ItemList::ensure_current_is_visible() {
  573. ensure_selected_visible = true;
  574. update();
  575. }
  576. static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) {
  577. Size2 size = p_max_size;
  578. int tex_width = p_size.width * size.height / p_size.height;
  579. int tex_height = size.height;
  580. if (tex_width > size.width) {
  581. tex_width = size.width;
  582. tex_height = p_size.height * tex_width / p_size.width;
  583. }
  584. int ofs_x = (size.width - tex_width) / 2;
  585. int ofs_y = (size.height - tex_height) / 2;
  586. return Rect2(ofs_x, ofs_y, tex_width, tex_height);
  587. }
  588. void ItemList::_notification(int p_what) {
  589. if (p_what == NOTIFICATION_RESIZED) {
  590. shape_changed = true;
  591. update();
  592. }
  593. if (p_what == NOTIFICATION_DRAW) {
  594. Ref<StyleBox> bg = get_stylebox("bg");
  595. int mw = scroll_bar->get_minimum_size().x;
  596. scroll_bar->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -mw);
  597. scroll_bar->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
  598. scroll_bar->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, bg->get_margin(MARGIN_TOP));
  599. scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -bg->get_margin(MARGIN_BOTTOM));
  600. Size2 size = get_size();
  601. int width = size.width - bg->get_minimum_size().width;
  602. if (scroll_bar->is_visible()) {
  603. width -= mw;
  604. }
  605. draw_style_box(bg, Rect2(Point2(), size));
  606. int hseparation = get_constant("hseparation");
  607. int vseparation = get_constant("vseparation");
  608. int icon_margin = get_constant("icon_margin");
  609. int line_separation = get_constant("line_separation");
  610. Ref<StyleBox> sbsel = has_focus() ? get_stylebox("selected_focus") : get_stylebox("selected");
  611. Ref<StyleBox> cursor = has_focus() ? get_stylebox("cursor") : get_stylebox("cursor_unfocused");
  612. Ref<Font> font = get_font("font");
  613. Color guide_color = get_color("guide_color");
  614. Color font_color = get_color("font_color");
  615. Color font_color_selected = get_color("font_color_selected");
  616. int font_height = font->get_height();
  617. Vector<int> line_size_cache;
  618. Vector<int> line_limit_cache;
  619. if (max_text_lines) {
  620. line_size_cache.resize(max_text_lines);
  621. line_limit_cache.resize(max_text_lines);
  622. }
  623. if (has_focus()) {
  624. VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
  625. draw_style_box(get_stylebox("bg_focus"), Rect2(Point2(), size));
  626. VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
  627. }
  628. if (shape_changed) {
  629. float max_column_width = 0;
  630. //1- compute item minimum sizes
  631. for (int i = 0; i < items.size(); i++) {
  632. Size2 minsize;
  633. if (items[i].icon.is_valid()) {
  634. if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) {
  635. minsize = fixed_icon_size * icon_scale;
  636. } else {
  637. minsize = items[i].get_icon_size() * icon_scale;
  638. }
  639. if (items[i].text != "") {
  640. if (icon_mode == ICON_MODE_TOP) {
  641. minsize.y += icon_margin;
  642. } else {
  643. minsize.x += icon_margin;
  644. }
  645. }
  646. }
  647. if (items[i].text != "") {
  648. Size2 s = font->get_string_size(items[i].text);
  649. //s.width=MIN(s.width,fixed_column_width);
  650. if (icon_mode == ICON_MODE_TOP) {
  651. minsize.x = MAX(minsize.x, s.width);
  652. if (max_text_lines > 0) {
  653. minsize.y += (font_height + line_separation) * max_text_lines;
  654. } else {
  655. minsize.y += s.height;
  656. }
  657. } else {
  658. minsize.y = MAX(minsize.y, s.height);
  659. minsize.x += s.width;
  660. }
  661. }
  662. if (fixed_column_width > 0)
  663. minsize.x = fixed_column_width;
  664. max_column_width = MAX(max_column_width, minsize.x);
  665. // elements need to adapt to the selected size
  666. minsize.y += vseparation;
  667. minsize.x += hseparation;
  668. items.write[i].rect_cache.size = minsize;
  669. items.write[i].min_rect_cache.size = minsize;
  670. }
  671. int fit_size = size.x - bg->get_minimum_size().width - mw;
  672. //2-attempt best fit
  673. current_columns = 0x7FFFFFFF;
  674. if (max_columns > 0)
  675. current_columns = max_columns;
  676. while (true) {
  677. //repeat util all fits
  678. bool all_fit = true;
  679. Vector2 ofs;
  680. int col = 0;
  681. int max_h = 0;
  682. separators.clear();
  683. for (int i = 0; i < items.size(); i++) {
  684. if (current_columns > 1 && items[i].rect_cache.size.width + ofs.x > fit_size) {
  685. //went past
  686. current_columns = MAX(col, 1);
  687. all_fit = false;
  688. break;
  689. }
  690. if (same_column_width)
  691. items.write[i].rect_cache.size.x = max_column_width;
  692. items.write[i].rect_cache.position = ofs;
  693. max_h = MAX(max_h, items[i].rect_cache.size.y);
  694. ofs.x += items[i].rect_cache.size.x + hseparation;
  695. col++;
  696. if (col == current_columns) {
  697. if (i < items.size() - 1)
  698. separators.push_back(ofs.y + max_h + vseparation / 2);
  699. for (int j = i; j >= 0 && col > 0; j--, col--) {
  700. items.write[j].rect_cache.size.y = max_h;
  701. }
  702. ofs.x = 0;
  703. ofs.y += max_h + vseparation;
  704. col = 0;
  705. max_h = 0;
  706. }
  707. }
  708. for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) {
  709. items.write[j].rect_cache.size.y = max_h;
  710. }
  711. if (all_fit) {
  712. float page = size.height - bg->get_minimum_size().height;
  713. float max = MAX(page, ofs.y + max_h);
  714. if (auto_height)
  715. auto_height_value = ofs.y + max_h + bg->get_minimum_size().height;
  716. scroll_bar->set_max(max);
  717. scroll_bar->set_page(page);
  718. if (max <= page) {
  719. scroll_bar->set_value(0);
  720. scroll_bar->hide();
  721. } else {
  722. scroll_bar->show();
  723. if (do_autoscroll_to_bottom)
  724. scroll_bar->set_value(max);
  725. }
  726. break;
  727. }
  728. }
  729. minimum_size_changed();
  730. shape_changed = false;
  731. }
  732. //ensure_selected_visible needs to be checked before we draw the list.
  733. if (ensure_selected_visible && current >= 0 && current <= items.size()) {
  734. Rect2 r = items[current].rect_cache;
  735. int from = scroll_bar->get_value();
  736. int to = from + scroll_bar->get_page();
  737. if (r.position.y < from) {
  738. scroll_bar->set_value(r.position.y);
  739. } else if (r.position.y + r.size.y > to) {
  740. scroll_bar->set_value(r.position.y + r.size.y - (to - from));
  741. }
  742. }
  743. ensure_selected_visible = false;
  744. Vector2 base_ofs = bg->get_offset();
  745. base_ofs.y -= int(scroll_bar->get_value());
  746. const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there
  747. int first_item_visible;
  748. {
  749. // do a binary search to find the first item whose rect reaches below clip.position.y
  750. int lo = 0;
  751. int hi = items.size();
  752. while (lo < hi) {
  753. const int mid = (lo + hi) / 2;
  754. const Rect2 &rcache = items[mid].rect_cache;
  755. if (rcache.position.y + rcache.size.y < clip.position.y) {
  756. lo = mid + 1;
  757. } else {
  758. hi = mid;
  759. }
  760. }
  761. // we might have ended up with column 2, or 3, ..., so let's find the first column
  762. while (lo > 0 && items[lo - 1].rect_cache.position.y == items[lo].rect_cache.position.y) {
  763. lo -= 1;
  764. }
  765. first_item_visible = lo;
  766. }
  767. for (int i = first_item_visible; i < items.size(); i++) {
  768. Rect2 rcache = items[i].rect_cache;
  769. if (rcache.position.y > clip.position.y + clip.size.y)
  770. break; // done
  771. if (!clip.intersects(rcache))
  772. continue;
  773. if (current_columns == 1) {
  774. rcache.size.width = width - rcache.position.x;
  775. }
  776. if (items[i].selected) {
  777. Rect2 r = rcache;
  778. r.position += base_ofs;
  779. r.position.y -= vseparation / 2;
  780. r.size.y += vseparation;
  781. r.position.x -= hseparation / 2;
  782. r.size.x += hseparation;
  783. draw_style_box(sbsel, r);
  784. }
  785. if (items[i].custom_bg.a > 0.001) {
  786. Rect2 r = rcache;
  787. r.position += base_ofs;
  788. // Size rect to make the align the temperature colors
  789. r.position.y -= vseparation / 2;
  790. r.size.y += vseparation;
  791. r.position.x -= hseparation / 2;
  792. r.size.x += hseparation;
  793. draw_rect(r, items[i].custom_bg);
  794. }
  795. Vector2 text_ofs;
  796. if (items[i].icon.is_valid()) {
  797. Size2 icon_size;
  798. //= _adjust_to_max_size(items[i].get_icon_size(),fixed_icon_size) * icon_scale;
  799. if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) {
  800. icon_size = fixed_icon_size * icon_scale;
  801. } else {
  802. icon_size = items[i].get_icon_size() * icon_scale;
  803. }
  804. Vector2 icon_ofs;
  805. Point2 pos = items[i].rect_cache.position + icon_ofs + base_ofs;
  806. if (icon_mode == ICON_MODE_TOP) {
  807. pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2);
  808. pos.y += MIN(
  809. Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2),
  810. items[i].rect_cache.size.height - items[i].min_rect_cache.size.height);
  811. text_ofs.y = icon_size.height + icon_margin;
  812. text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height;
  813. } else {
  814. pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2);
  815. text_ofs.x = icon_size.width + icon_margin;
  816. }
  817. Rect2 draw_rect = Rect2(pos, icon_size);
  818. if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) {
  819. Rect2 adj = _adjust_to_max_size(items[i].get_icon_size() * icon_scale, icon_size);
  820. draw_rect.position += adj.position;
  821. draw_rect.size = adj.size;
  822. }
  823. Color modulate = items[i].icon_modulate;
  824. if (items[i].disabled)
  825. modulate.a *= 0.5;
  826. // If the icon is transposed, we have to swith the size so that it is drawn correctly
  827. if (items[i].icon_transposed) {
  828. Size2 size_tmp = draw_rect.size;
  829. draw_rect.size.x = size_tmp.y;
  830. draw_rect.size.y = size_tmp.x;
  831. }
  832. Rect2 region = (items[i].icon_region.size.x == 0 || items[i].icon_region.size.y == 0) ? Rect2(Vector2(), items[i].icon->get_size()) : Rect2(items[i].icon_region);
  833. draw_texture_rect_region(items[i].icon, draw_rect, region, modulate, items[i].icon_transposed);
  834. }
  835. if (items[i].tag_icon.is_valid()) {
  836. draw_texture(items[i].tag_icon, items[i].rect_cache.position + base_ofs);
  837. }
  838. if (items[i].text != "") {
  839. int max_len = -1;
  840. Vector2 size = font->get_string_size(items[i].text);
  841. if (fixed_column_width)
  842. max_len = fixed_column_width;
  843. else if (same_column_width)
  844. max_len = items[i].rect_cache.size.x;
  845. else
  846. max_len = size.x;
  847. Color modulate = items[i].selected ? font_color_selected : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color);
  848. if (items[i].disabled)
  849. modulate.a *= 0.5;
  850. if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
  851. int ss = items[i].text.length();
  852. float ofs = 0;
  853. int line = 0;
  854. for (int j = 0; j <= ss; j++) {
  855. int cs = j < ss ? font->get_char_size(items[i].text[j], items[i].text[j + 1]).x : 0;
  856. if (ofs + cs > max_len || j == ss) {
  857. line_limit_cache.write[line] = j;
  858. line_size_cache.write[line] = ofs;
  859. line++;
  860. ofs = 0;
  861. if (line >= max_text_lines)
  862. break;
  863. } else {
  864. ofs += cs;
  865. }
  866. }
  867. line = 0;
  868. ofs = 0;
  869. text_ofs.y += font->get_ascent();
  870. text_ofs = text_ofs.floor();
  871. text_ofs += base_ofs;
  872. text_ofs += items[i].rect_cache.position;
  873. FontDrawer drawer(font, Color(1, 1, 1));
  874. for (int j = 0; j < ss; j++) {
  875. if (j == line_limit_cache[line]) {
  876. line++;
  877. ofs = 0;
  878. if (line >= max_text_lines)
  879. break;
  880. }
  881. ofs += drawer.draw_char(get_canvas_item(), text_ofs + Vector2(ofs + (max_len - line_size_cache[line]) / 2, line * (font_height + line_separation)).floor(), items[i].text[j], items[i].text[j + 1], modulate);
  882. }
  883. //special multiline mode
  884. } else {
  885. if (fixed_column_width > 0)
  886. size.x = MIN(size.x, fixed_column_width);
  887. if (icon_mode == ICON_MODE_TOP) {
  888. text_ofs.x += (items[i].rect_cache.size.width - size.x) / 2;
  889. } else {
  890. text_ofs.y += (items[i].rect_cache.size.height - size.y) / 2;
  891. }
  892. text_ofs.y += font->get_ascent();
  893. text_ofs = text_ofs.floor();
  894. text_ofs += base_ofs;
  895. text_ofs += items[i].rect_cache.position;
  896. draw_string(font, text_ofs, items[i].text, modulate, max_len + 1);
  897. }
  898. }
  899. if (select_mode == SELECT_MULTI && i == current) {
  900. Rect2 r = rcache;
  901. r.position += base_ofs;
  902. r.position.y -= vseparation / 2;
  903. r.size.y += vseparation;
  904. r.position.x -= hseparation / 2;
  905. r.size.x += hseparation;
  906. draw_style_box(cursor, r);
  907. }
  908. }
  909. int first_visible_separator = 0;
  910. {
  911. // do a binary search to find the first separator that is below clip_position.y
  912. int lo = 0;
  913. int hi = separators.size();
  914. while (lo < hi) {
  915. const int mid = (lo + hi) / 2;
  916. if (separators[mid] < clip.position.y) {
  917. lo = mid + 1;
  918. } else {
  919. hi = mid;
  920. }
  921. }
  922. first_visible_separator = lo;
  923. }
  924. for (int i = first_visible_separator; i < separators.size(); i++) {
  925. if (separators[i] > clip.position.y + clip.size.y)
  926. break; // done
  927. const int y = base_ofs.y + separators[i];
  928. draw_line(Vector2(bg->get_margin(MARGIN_LEFT), y), Vector2(width, y), guide_color);
  929. }
  930. }
  931. }
  932. void ItemList::_scroll_changed(double) {
  933. update();
  934. }
  935. int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
  936. Vector2 pos = p_pos;
  937. Ref<StyleBox> bg = get_stylebox("bg");
  938. pos -= bg->get_offset();
  939. pos.y += scroll_bar->get_value();
  940. int closest = -1;
  941. int closest_dist = 0x7FFFFFFF;
  942. for (int i = 0; i < items.size(); i++) {
  943. Rect2 rc = items[i].rect_cache;
  944. if (i % current_columns == current_columns - 1) {
  945. rc.size.width = get_size().width; //not right but works
  946. }
  947. if (rc.has_point(pos)) {
  948. closest = i;
  949. break;
  950. }
  951. float dist = rc.distance_to(pos);
  952. if (!p_exact && dist < closest_dist) {
  953. closest = i;
  954. closest_dist = dist;
  955. }
  956. }
  957. return closest;
  958. }
  959. bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
  960. if (items.empty())
  961. return true;
  962. Vector2 pos = p_pos;
  963. Ref<StyleBox> bg = get_stylebox("bg");
  964. pos -= bg->get_offset();
  965. pos.y += scroll_bar->get_value();
  966. Rect2 endrect = items[items.size() - 1].rect_cache;
  967. return (pos.y > endrect.position.y + endrect.size.y);
  968. }
  969. String ItemList::get_tooltip(const Point2 &p_pos) const {
  970. int closest = get_item_at_position(p_pos, true);
  971. if (closest != -1) {
  972. if (!items[closest].tooltip_enabled) {
  973. return "";
  974. }
  975. if (items[closest].tooltip != "") {
  976. return items[closest].tooltip;
  977. }
  978. if (items[closest].text != "") {
  979. return items[closest].text;
  980. }
  981. }
  982. return Control::get_tooltip(p_pos);
  983. }
  984. void ItemList::sort_items_by_text() {
  985. items.sort();
  986. update();
  987. shape_changed = true;
  988. if (select_mode == SELECT_SINGLE) {
  989. for (int i = 0; i < items.size(); i++) {
  990. if (items[i].selected) {
  991. select(i);
  992. return;
  993. }
  994. }
  995. }
  996. }
  997. int ItemList::find_metadata(const Variant &p_metadata) const {
  998. for (int i = 0; i < items.size(); i++) {
  999. if (items[i].metadata == p_metadata) {
  1000. return i;
  1001. }
  1002. }
  1003. return -1;
  1004. }
  1005. void ItemList::set_allow_rmb_select(bool p_allow) {
  1006. allow_rmb_select = p_allow;
  1007. }
  1008. bool ItemList::get_allow_rmb_select() const {
  1009. return allow_rmb_select;
  1010. }
  1011. void ItemList::set_allow_reselect(bool p_allow) {
  1012. allow_reselect = p_allow;
  1013. }
  1014. bool ItemList::get_allow_reselect() const {
  1015. return allow_reselect;
  1016. }
  1017. void ItemList::set_icon_scale(real_t p_scale) {
  1018. icon_scale = p_scale;
  1019. }
  1020. real_t ItemList::get_icon_scale() const {
  1021. return icon_scale;
  1022. }
  1023. Vector<int> ItemList::get_selected_items() {
  1024. Vector<int> selected;
  1025. for (int i = 0; i < items.size(); i++) {
  1026. if (items[i].selected) {
  1027. selected.push_back(i);
  1028. if (this->select_mode == SELECT_SINGLE) {
  1029. break;
  1030. }
  1031. }
  1032. }
  1033. return selected;
  1034. }
  1035. bool ItemList::is_anything_selected() {
  1036. for (int i = 0; i < items.size(); i++) {
  1037. if (items[i].selected)
  1038. return true;
  1039. }
  1040. return false;
  1041. }
  1042. void ItemList::_set_items(const Array &p_items) {
  1043. ERR_FAIL_COND(p_items.size() % 3);
  1044. clear();
  1045. for (int i = 0; i < p_items.size(); i += 3) {
  1046. String text = p_items[i + 0];
  1047. Ref<Texture> icon = p_items[i + 1];
  1048. bool disabled = p_items[i + 2];
  1049. int idx = get_item_count();
  1050. add_item(text, icon);
  1051. set_item_disabled(idx, disabled);
  1052. }
  1053. }
  1054. Array ItemList::_get_items() const {
  1055. Array items;
  1056. for (int i = 0; i < get_item_count(); i++) {
  1057. items.push_back(get_item_text(i));
  1058. items.push_back(get_item_icon(i));
  1059. items.push_back(is_item_disabled(i));
  1060. }
  1061. return items;
  1062. }
  1063. Size2 ItemList::get_minimum_size() const {
  1064. if (auto_height) {
  1065. return Size2(0, auto_height_value);
  1066. }
  1067. return Size2();
  1068. }
  1069. void ItemList::set_autoscroll_to_bottom(const bool p_enable) {
  1070. do_autoscroll_to_bottom = p_enable;
  1071. }
  1072. void ItemList::set_auto_height(bool p_enable) {
  1073. auto_height = p_enable;
  1074. shape_changed = true;
  1075. update();
  1076. }
  1077. bool ItemList::has_auto_height() const {
  1078. return auto_height;
  1079. }
  1080. void ItemList::_bind_methods() {
  1081. ClassDB::bind_method(D_METHOD("add_item", "text", "icon", "selectable"), &ItemList::add_item, DEFVAL(Variant()), DEFVAL(true));
  1082. ClassDB::bind_method(D_METHOD("add_icon_item", "icon", "selectable"), &ItemList::add_icon_item, DEFVAL(true));
  1083. ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &ItemList::set_item_text);
  1084. ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &ItemList::get_item_text);
  1085. ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &ItemList::set_item_icon);
  1086. ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &ItemList::get_item_icon);
  1087. ClassDB::bind_method(D_METHOD("set_item_icon_transposed", "idx", "rect"), &ItemList::set_item_icon_transposed);
  1088. ClassDB::bind_method(D_METHOD("is_item_icon_transposed", "idx"), &ItemList::is_item_icon_transposed);
  1089. ClassDB::bind_method(D_METHOD("set_item_icon_region", "idx", "rect"), &ItemList::set_item_icon_region);
  1090. ClassDB::bind_method(D_METHOD("get_item_icon_region", "idx"), &ItemList::get_item_icon_region);
  1091. ClassDB::bind_method(D_METHOD("set_item_icon_modulate", "idx", "modulate"), &ItemList::set_item_icon_modulate);
  1092. ClassDB::bind_method(D_METHOD("get_item_icon_modulate", "idx"), &ItemList::get_item_icon_modulate);
  1093. ClassDB::bind_method(D_METHOD("set_item_selectable", "idx", "selectable"), &ItemList::set_item_selectable);
  1094. ClassDB::bind_method(D_METHOD("is_item_selectable", "idx"), &ItemList::is_item_selectable);
  1095. ClassDB::bind_method(D_METHOD("set_item_disabled", "idx", "disabled"), &ItemList::set_item_disabled);
  1096. ClassDB::bind_method(D_METHOD("is_item_disabled", "idx"), &ItemList::is_item_disabled);
  1097. ClassDB::bind_method(D_METHOD("set_item_metadata", "idx", "metadata"), &ItemList::set_item_metadata);
  1098. ClassDB::bind_method(D_METHOD("get_item_metadata", "idx"), &ItemList::get_item_metadata);
  1099. ClassDB::bind_method(D_METHOD("set_item_custom_bg_color", "idx", "custom_bg_color"), &ItemList::set_item_custom_bg_color);
  1100. ClassDB::bind_method(D_METHOD("get_item_custom_bg_color", "idx"), &ItemList::get_item_custom_bg_color);
  1101. ClassDB::bind_method(D_METHOD("set_item_custom_fg_color", "idx", "custom_fg_color"), &ItemList::set_item_custom_fg_color);
  1102. ClassDB::bind_method(D_METHOD("get_item_custom_fg_color", "idx"), &ItemList::get_item_custom_fg_color);
  1103. ClassDB::bind_method(D_METHOD("set_item_tooltip_enabled", "idx", "enable"), &ItemList::set_item_tooltip_enabled);
  1104. ClassDB::bind_method(D_METHOD("is_item_tooltip_enabled", "idx"), &ItemList::is_item_tooltip_enabled);
  1105. ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &ItemList::set_item_tooltip);
  1106. ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &ItemList::get_item_tooltip);
  1107. ClassDB::bind_method(D_METHOD("select", "idx", "single"), &ItemList::select, DEFVAL(true));
  1108. ClassDB::bind_method(D_METHOD("unselect", "idx"), &ItemList::unselect);
  1109. ClassDB::bind_method(D_METHOD("unselect_all"), &ItemList::unselect_all);
  1110. ClassDB::bind_method(D_METHOD("is_selected", "idx"), &ItemList::is_selected);
  1111. ClassDB::bind_method(D_METHOD("get_selected_items"), &ItemList::get_selected_items);
  1112. ClassDB::bind_method(D_METHOD("move_item", "from_idx", "to_idx"), &ItemList::move_item);
  1113. ClassDB::bind_method(D_METHOD("get_item_count"), &ItemList::get_item_count);
  1114. ClassDB::bind_method(D_METHOD("remove_item", "idx"), &ItemList::remove_item);
  1115. ClassDB::bind_method(D_METHOD("clear"), &ItemList::clear);
  1116. ClassDB::bind_method(D_METHOD("sort_items_by_text"), &ItemList::sort_items_by_text);
  1117. ClassDB::bind_method(D_METHOD("set_fixed_column_width", "width"), &ItemList::set_fixed_column_width);
  1118. ClassDB::bind_method(D_METHOD("get_fixed_column_width"), &ItemList::get_fixed_column_width);
  1119. ClassDB::bind_method(D_METHOD("set_same_column_width", "enable"), &ItemList::set_same_column_width);
  1120. ClassDB::bind_method(D_METHOD("is_same_column_width"), &ItemList::is_same_column_width);
  1121. ClassDB::bind_method(D_METHOD("set_max_text_lines", "lines"), &ItemList::set_max_text_lines);
  1122. ClassDB::bind_method(D_METHOD("get_max_text_lines"), &ItemList::get_max_text_lines);
  1123. ClassDB::bind_method(D_METHOD("set_max_columns", "amount"), &ItemList::set_max_columns);
  1124. ClassDB::bind_method(D_METHOD("get_max_columns"), &ItemList::get_max_columns);
  1125. ClassDB::bind_method(D_METHOD("set_select_mode", "mode"), &ItemList::set_select_mode);
  1126. ClassDB::bind_method(D_METHOD("get_select_mode"), &ItemList::get_select_mode);
  1127. ClassDB::bind_method(D_METHOD("set_icon_mode", "mode"), &ItemList::set_icon_mode);
  1128. ClassDB::bind_method(D_METHOD("get_icon_mode"), &ItemList::get_icon_mode);
  1129. ClassDB::bind_method(D_METHOD("set_fixed_icon_size", "size"), &ItemList::set_fixed_icon_size);
  1130. ClassDB::bind_method(D_METHOD("get_fixed_icon_size"), &ItemList::get_fixed_icon_size);
  1131. ClassDB::bind_method(D_METHOD("set_icon_scale", "scale"), &ItemList::set_icon_scale);
  1132. ClassDB::bind_method(D_METHOD("get_icon_scale"), &ItemList::get_icon_scale);
  1133. ClassDB::bind_method(D_METHOD("set_allow_rmb_select", "allow"), &ItemList::set_allow_rmb_select);
  1134. ClassDB::bind_method(D_METHOD("get_allow_rmb_select"), &ItemList::get_allow_rmb_select);
  1135. ClassDB::bind_method(D_METHOD("set_allow_reselect", "allow"), &ItemList::set_allow_reselect);
  1136. ClassDB::bind_method(D_METHOD("get_allow_reselect"), &ItemList::get_allow_reselect);
  1137. ClassDB::bind_method(D_METHOD("set_auto_height", "enable"), &ItemList::set_auto_height);
  1138. ClassDB::bind_method(D_METHOD("has_auto_height"), &ItemList::has_auto_height);
  1139. ClassDB::bind_method(D_METHOD("is_anything_selected"), &ItemList::is_anything_selected);
  1140. ClassDB::bind_method(D_METHOD("get_item_at_position", "position", "exact"), &ItemList::get_item_at_position, DEFVAL(false));
  1141. ClassDB::bind_method(D_METHOD("ensure_current_is_visible"), &ItemList::ensure_current_is_visible);
  1142. ClassDB::bind_method(D_METHOD("get_v_scroll"), &ItemList::get_v_scroll);
  1143. ClassDB::bind_method(D_METHOD("_scroll_changed"), &ItemList::_scroll_changed);
  1144. ClassDB::bind_method(D_METHOD("_gui_input"), &ItemList::_gui_input);
  1145. ClassDB::bind_method(D_METHOD("_set_items"), &ItemList::_set_items);
  1146. ClassDB::bind_method(D_METHOD("_get_items"), &ItemList::_get_items);
  1147. ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
  1148. ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
  1149. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
  1150. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
  1151. ADD_PROPERTY(PropertyInfo(Variant::INT, "max_text_lines"), "set_max_text_lines", "get_max_text_lines");
  1152. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height");
  1153. ADD_GROUP("Columns", "");
  1154. ADD_PROPERTY(PropertyInfo(Variant::INT, "max_columns"), "set_max_columns", "get_max_columns");
  1155. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width");
  1156. ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_column_width"), "set_fixed_column_width", "get_fixed_column_width");
  1157. ADD_GROUP("Icon", "");
  1158. ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode");
  1159. ADD_PROPERTY(PropertyInfo(Variant::REAL, "icon_scale"), "set_icon_scale", "get_icon_scale");
  1160. ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fixed_icon_size"), "set_fixed_icon_size", "get_fixed_icon_size");
  1161. BIND_ENUM_CONSTANT(ICON_MODE_TOP);
  1162. BIND_ENUM_CONSTANT(ICON_MODE_LEFT);
  1163. BIND_ENUM_CONSTANT(SELECT_SINGLE);
  1164. BIND_ENUM_CONSTANT(SELECT_MULTI);
  1165. ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
  1166. ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::VECTOR2, "at_position")));
  1167. ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "selected")));
  1168. ADD_SIGNAL(MethodInfo("item_activated", PropertyInfo(Variant::INT, "index")));
  1169. ADD_SIGNAL(MethodInfo("rmb_clicked", PropertyInfo(Variant::VECTOR2, "at_position")));
  1170. ADD_SIGNAL(MethodInfo("nothing_selected"));
  1171. GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
  1172. ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/incremental_search_max_interval_msec", PropertyInfo(Variant::INT, "gui/timers/incremental_search_max_interval_msec", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); // No negative numbers
  1173. }
  1174. ItemList::ItemList() {
  1175. current = -1;
  1176. select_mode = SELECT_SINGLE;
  1177. icon_mode = ICON_MODE_LEFT;
  1178. fixed_column_width = 0;
  1179. same_column_width = false;
  1180. max_text_lines = 1;
  1181. max_columns = 1;
  1182. auto_height = false;
  1183. auto_height_value = 0.0f;
  1184. scroll_bar = memnew(VScrollBar);
  1185. add_child(scroll_bar);
  1186. shape_changed = true;
  1187. scroll_bar->connect("value_changed", this, "_scroll_changed");
  1188. set_focus_mode(FOCUS_ALL);
  1189. current_columns = 1;
  1190. search_time_msec = 0;
  1191. ensure_selected_visible = false;
  1192. defer_select_single = -1;
  1193. allow_rmb_select = false;
  1194. allow_reselect = false;
  1195. do_autoscroll_to_bottom = false;
  1196. icon_scale = 1.0f;
  1197. set_clip_contents(true);
  1198. }
  1199. ItemList::~ItemList() {
  1200. }