2
0

item_list.cpp 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618
  1. /*************************************************************************/
  2. /* item_list.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2020 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. shape_changed = true;
  299. }
  300. int ItemList::get_max_columns() const {
  301. return max_columns;
  302. }
  303. void ItemList::set_select_mode(SelectMode p_mode) {
  304. select_mode = p_mode;
  305. update();
  306. }
  307. ItemList::SelectMode ItemList::get_select_mode() const {
  308. return select_mode;
  309. }
  310. void ItemList::set_icon_mode(IconMode p_mode) {
  311. ERR_FAIL_INDEX((int)p_mode, 2);
  312. icon_mode = p_mode;
  313. update();
  314. shape_changed = true;
  315. }
  316. ItemList::IconMode ItemList::get_icon_mode() const {
  317. return icon_mode;
  318. }
  319. void ItemList::set_fixed_icon_size(const Size2 &p_size) {
  320. fixed_icon_size = p_size;
  321. update();
  322. }
  323. Size2 ItemList::get_fixed_icon_size() const {
  324. return fixed_icon_size;
  325. }
  326. Size2 ItemList::Item::get_icon_size() const {
  327. if (icon.is_null())
  328. return Size2();
  329. Size2 size_result = Size2(icon_region.size).abs();
  330. if (icon_region.size.x == 0 || icon_region.size.y == 0)
  331. size_result = icon->get_size();
  332. if (icon_transposed) {
  333. Size2 size_tmp = size_result;
  334. size_result.x = size_tmp.y;
  335. size_result.y = size_tmp.x;
  336. }
  337. return size_result;
  338. }
  339. void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
  340. double prev_scroll = scroll_bar->get_value();
  341. Ref<InputEventMouseMotion> mm = p_event;
  342. if (defer_select_single >= 0 && mm.is_valid()) {
  343. defer_select_single = -1;
  344. return;
  345. }
  346. Ref<InputEventMouseButton> mb = p_event;
  347. if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
  348. select(defer_select_single, true);
  349. emit_signal("multi_selected", defer_select_single, true);
  350. defer_select_single = -1;
  351. return;
  352. }
  353. if (mb.is_valid() && (mb->get_button_index() == BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == BUTTON_RIGHT)) && mb->is_pressed()) {
  354. search_string = ""; //any mousepress cancels
  355. Vector2 pos = mb->get_position();
  356. Ref<StyleBox> bg = get_stylebox("bg");
  357. pos -= bg->get_offset();
  358. pos.y += scroll_bar->get_value();
  359. int closest = -1;
  360. for (int i = 0; i < items.size(); i++) {
  361. Rect2 rc = items[i].rect_cache;
  362. if (i % current_columns == current_columns - 1) {
  363. rc.size.width = get_size().width; //not right but works
  364. }
  365. if (rc.has_point(pos)) {
  366. closest = i;
  367. break;
  368. }
  369. }
  370. if (closest != -1) {
  371. int i = closest;
  372. if (select_mode == SELECT_MULTI && items[i].selected && mb->get_command()) {
  373. unselect(i);
  374. emit_signal("multi_selected", i, false);
  375. } else if (select_mode == SELECT_MULTI && mb->get_shift() && current >= 0 && current < items.size() && current != i) {
  376. int from = current;
  377. int to = i;
  378. if (i < current) {
  379. SWAP(from, to);
  380. }
  381. for (int j = from; j <= to; j++) {
  382. bool selected = !items[j].selected;
  383. select(j, false);
  384. if (selected)
  385. emit_signal("multi_selected", j, true);
  386. }
  387. if (mb->get_button_index() == BUTTON_RIGHT) {
  388. emit_signal("item_rmb_selected", i, get_local_mouse_position());
  389. }
  390. } else {
  391. 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) {
  392. defer_select_single = i;
  393. return;
  394. }
  395. if (items[i].selected && mb->get_button_index() == BUTTON_RIGHT) {
  396. emit_signal("item_rmb_selected", i, get_local_mouse_position());
  397. } else {
  398. bool selected = items[i].selected;
  399. select(i, select_mode == SELECT_SINGLE || !mb->get_command());
  400. if (!selected || allow_reselect) {
  401. if (select_mode == SELECT_SINGLE) {
  402. emit_signal("item_selected", i);
  403. } else
  404. emit_signal("multi_selected", i, true);
  405. }
  406. if (mb->get_button_index() == BUTTON_RIGHT) {
  407. emit_signal("item_rmb_selected", i, get_local_mouse_position());
  408. } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) {
  409. emit_signal("item_activated", i);
  410. }
  411. }
  412. }
  413. return;
  414. }
  415. if (mb->get_button_index() == BUTTON_RIGHT) {
  416. emit_signal("rmb_clicked", mb->get_position());
  417. return;
  418. }
  419. // Since closest is null, more likely we clicked on empty space, so send signal to interested controls. Allows, for example, implement items deselecting.
  420. emit_signal("nothing_selected");
  421. }
  422. if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) {
  423. scroll_bar->set_value(scroll_bar->get_value() - scroll_bar->get_page() * mb->get_factor() / 8);
  424. }
  425. if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) {
  426. scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * mb->get_factor() / 8);
  427. }
  428. if (p_event->is_pressed() && items.size() > 0) {
  429. if (p_event->is_action("ui_up")) {
  430. if (search_string != "") {
  431. uint64_t now = OS::get_singleton()->get_ticks_msec();
  432. uint64_t diff = now - search_time_msec;
  433. if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
  434. for (int i = current - 1; i >= 0; i--) {
  435. if (items[i].text.begins_with(search_string)) {
  436. set_current(i);
  437. ensure_current_is_visible();
  438. if (select_mode == SELECT_SINGLE) {
  439. emit_signal("item_selected", current);
  440. }
  441. break;
  442. }
  443. }
  444. accept_event();
  445. return;
  446. }
  447. }
  448. if (current >= current_columns) {
  449. set_current(current - current_columns);
  450. ensure_current_is_visible();
  451. if (select_mode == SELECT_SINGLE) {
  452. emit_signal("item_selected", current);
  453. }
  454. accept_event();
  455. }
  456. } else if (p_event->is_action("ui_down")) {
  457. if (search_string != "") {
  458. uint64_t now = OS::get_singleton()->get_ticks_msec();
  459. uint64_t diff = now - search_time_msec;
  460. if (diff < uint64_t(ProjectSettings::get_singleton()->get("gui/timers/incremental_search_max_interval_msec")) * 2) {
  461. for (int i = current + 1; i < items.size(); i++) {
  462. if (items[i].text.begins_with(search_string)) {
  463. set_current(i);
  464. ensure_current_is_visible();
  465. if (select_mode == SELECT_SINGLE) {
  466. emit_signal("item_selected", current);
  467. }
  468. break;
  469. }
  470. }
  471. accept_event();
  472. return;
  473. }
  474. }
  475. if (current < items.size() - current_columns) {
  476. set_current(current + current_columns);
  477. ensure_current_is_visible();
  478. if (select_mode == SELECT_SINGLE) {
  479. emit_signal("item_selected", current);
  480. }
  481. accept_event();
  482. }
  483. } else if (p_event->is_action("ui_page_up")) {
  484. search_string = ""; //any mousepress cancels
  485. for (int i = 4; i > 0; i--) {
  486. if (current - current_columns * i >= 0) {
  487. set_current(current - current_columns * i);
  488. ensure_current_is_visible();
  489. if (select_mode == SELECT_SINGLE) {
  490. emit_signal("item_selected", current);
  491. }
  492. accept_event();
  493. break;
  494. }
  495. }
  496. } else if (p_event->is_action("ui_page_down")) {
  497. search_string = ""; //any mousepress cancels
  498. for (int i = 4; i > 0; i--) {
  499. if (current + current_columns * i < items.size()) {
  500. set_current(current + current_columns * i);
  501. ensure_current_is_visible();
  502. if (select_mode == SELECT_SINGLE) {
  503. emit_signal("item_selected", current);
  504. }
  505. accept_event();
  506. break;
  507. }
  508. }
  509. } else if (p_event->is_action("ui_left")) {
  510. search_string = ""; //any mousepress cancels
  511. if (current % current_columns != 0) {
  512. set_current(current - 1);
  513. ensure_current_is_visible();
  514. if (select_mode == SELECT_SINGLE) {
  515. emit_signal("item_selected", current);
  516. }
  517. accept_event();
  518. }
  519. } else if (p_event->is_action("ui_right")) {
  520. search_string = ""; //any mousepress cancels
  521. if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) {
  522. set_current(current + 1);
  523. ensure_current_is_visible();
  524. if (select_mode == SELECT_SINGLE) {
  525. emit_signal("item_selected", current);
  526. }
  527. accept_event();
  528. }
  529. } else if (p_event->is_action("ui_cancel")) {
  530. search_string = "";
  531. } else if (p_event->is_action("ui_select") && select_mode == SELECT_MULTI) {
  532. if (current >= 0 && current < items.size()) {
  533. if (items[current].selectable && !items[current].disabled && !items[current].selected) {
  534. select(current, false);
  535. emit_signal("multi_selected", current, true);
  536. } else if (items[current].selected) {
  537. unselect(current);
  538. emit_signal("multi_selected", current, false);
  539. }
  540. }
  541. } else if (p_event->is_action("ui_accept")) {
  542. search_string = ""; //any mousepress cance
  543. if (current >= 0 && current < items.size()) {
  544. emit_signal("item_activated", current);
  545. }
  546. } else {
  547. Ref<InputEventKey> k = p_event;
  548. if (k.is_valid() && k->get_unicode()) {
  549. uint64_t now = OS::get_singleton()->get_ticks_msec();
  550. uint64_t diff = now - search_time_msec;
  551. uint64_t max_interval = uint64_t(GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000));
  552. search_time_msec = now;
  553. if (diff > max_interval) {
  554. search_string = "";
  555. }
  556. if (String::chr(k->get_unicode()) != search_string)
  557. search_string += String::chr(k->get_unicode());
  558. for (int i = current + 1; i <= items.size(); i++) {
  559. if (i == items.size()) {
  560. if (current == 0 || current == -1)
  561. break;
  562. else
  563. i = 0;
  564. }
  565. if (i == current)
  566. break;
  567. if (items[i].text.findn(search_string) == 0) {
  568. set_current(i);
  569. ensure_current_is_visible();
  570. if (select_mode == SELECT_SINGLE) {
  571. emit_signal("item_selected", current);
  572. }
  573. break;
  574. }
  575. }
  576. }
  577. }
  578. }
  579. Ref<InputEventPanGesture> pan_gesture = p_event;
  580. if (pan_gesture.is_valid()) {
  581. scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * pan_gesture->get_delta().y / 8);
  582. }
  583. if (scroll_bar->get_value() != prev_scroll)
  584. accept_event(); //accept event if scroll changed
  585. }
  586. void ItemList::ensure_current_is_visible() {
  587. ensure_selected_visible = true;
  588. update();
  589. }
  590. static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) {
  591. Size2 size = p_max_size;
  592. int tex_width = p_size.width * size.height / p_size.height;
  593. int tex_height = size.height;
  594. if (tex_width > size.width) {
  595. tex_width = size.width;
  596. tex_height = p_size.height * tex_width / p_size.width;
  597. }
  598. int ofs_x = (size.width - tex_width) / 2;
  599. int ofs_y = (size.height - tex_height) / 2;
  600. return Rect2(ofs_x, ofs_y, tex_width, tex_height);
  601. }
  602. void ItemList::_notification(int p_what) {
  603. if (p_what == NOTIFICATION_RESIZED) {
  604. shape_changed = true;
  605. update();
  606. }
  607. if (p_what == NOTIFICATION_DRAW) {
  608. Ref<StyleBox> bg = get_stylebox("bg");
  609. int mw = scroll_bar->get_minimum_size().x;
  610. scroll_bar->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -mw);
  611. scroll_bar->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0);
  612. scroll_bar->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, bg->get_margin(MARGIN_TOP));
  613. scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -bg->get_margin(MARGIN_BOTTOM));
  614. Size2 size = get_size();
  615. int width = size.width - bg->get_minimum_size().width;
  616. if (scroll_bar->is_visible()) {
  617. width -= mw;
  618. }
  619. draw_style_box(bg, Rect2(Point2(), size));
  620. int hseparation = get_constant("hseparation");
  621. int vseparation = get_constant("vseparation");
  622. int icon_margin = get_constant("icon_margin");
  623. int line_separation = get_constant("line_separation");
  624. Ref<StyleBox> sbsel = has_focus() ? get_stylebox("selected_focus") : get_stylebox("selected");
  625. Ref<StyleBox> cursor = has_focus() ? get_stylebox("cursor") : get_stylebox("cursor_unfocused");
  626. Ref<Font> font = get_font("font");
  627. Color guide_color = get_color("guide_color");
  628. Color font_color = get_color("font_color");
  629. Color font_color_selected = get_color("font_color_selected");
  630. int font_height = font->get_height();
  631. Vector<int> line_size_cache;
  632. Vector<int> line_limit_cache;
  633. if (max_text_lines) {
  634. line_size_cache.resize(max_text_lines);
  635. line_limit_cache.resize(max_text_lines);
  636. }
  637. if (has_focus()) {
  638. VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true);
  639. draw_style_box(get_stylebox("bg_focus"), Rect2(Point2(), size));
  640. VisualServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), false);
  641. }
  642. if (shape_changed) {
  643. float max_column_width = 0;
  644. //1- compute item minimum sizes
  645. for (int i = 0; i < items.size(); i++) {
  646. Size2 minsize;
  647. if (items[i].icon.is_valid()) {
  648. if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) {
  649. minsize = fixed_icon_size * icon_scale;
  650. } else {
  651. minsize = items[i].get_icon_size() * icon_scale;
  652. }
  653. if (items[i].text != "") {
  654. if (icon_mode == ICON_MODE_TOP) {
  655. minsize.y += icon_margin;
  656. } else {
  657. minsize.x += icon_margin;
  658. }
  659. }
  660. }
  661. if (items[i].text != "") {
  662. Size2 s = font->get_string_size(items[i].text);
  663. //s.width=MIN(s.width,fixed_column_width);
  664. if (icon_mode == ICON_MODE_TOP) {
  665. minsize.x = MAX(minsize.x, s.width);
  666. if (max_text_lines > 0) {
  667. minsize.y += (font_height + line_separation) * max_text_lines;
  668. } else {
  669. minsize.y += s.height;
  670. }
  671. } else {
  672. minsize.y = MAX(minsize.y, s.height);
  673. minsize.x += s.width;
  674. }
  675. }
  676. if (fixed_column_width > 0)
  677. minsize.x = fixed_column_width;
  678. max_column_width = MAX(max_column_width, minsize.x);
  679. // elements need to adapt to the selected size
  680. minsize.y += vseparation;
  681. minsize.x += hseparation;
  682. items.write[i].rect_cache.size = minsize;
  683. items.write[i].min_rect_cache.size = minsize;
  684. }
  685. int fit_size = size.x - bg->get_minimum_size().width - mw;
  686. //2-attempt best fit
  687. current_columns = 0x7FFFFFFF;
  688. if (max_columns > 0)
  689. current_columns = max_columns;
  690. while (true) {
  691. //repeat until all fits
  692. bool all_fit = true;
  693. Vector2 ofs;
  694. int col = 0;
  695. int max_h = 0;
  696. separators.clear();
  697. for (int i = 0; i < items.size(); i++) {
  698. if (current_columns > 1 && items[i].rect_cache.size.width + ofs.x > fit_size) {
  699. //went past
  700. current_columns = MAX(col, 1);
  701. all_fit = false;
  702. break;
  703. }
  704. if (same_column_width)
  705. items.write[i].rect_cache.size.x = max_column_width;
  706. items.write[i].rect_cache.position = ofs;
  707. max_h = MAX(max_h, items[i].rect_cache.size.y);
  708. ofs.x += items[i].rect_cache.size.x + hseparation;
  709. col++;
  710. if (col == current_columns) {
  711. if (i < items.size() - 1)
  712. separators.push_back(ofs.y + max_h + vseparation / 2);
  713. for (int j = i; j >= 0 && col > 0; j--, col--) {
  714. items.write[j].rect_cache.size.y = max_h;
  715. }
  716. ofs.x = 0;
  717. ofs.y += max_h + vseparation;
  718. col = 0;
  719. max_h = 0;
  720. }
  721. }
  722. for (int j = items.size() - 1; j >= 0 && col > 0; j--, col--) {
  723. items.write[j].rect_cache.size.y = max_h;
  724. }
  725. if (all_fit) {
  726. float page = MAX(0, size.height - bg->get_minimum_size().height);
  727. float max = MAX(page, ofs.y + max_h);
  728. if (auto_height)
  729. auto_height_value = ofs.y + max_h + bg->get_minimum_size().height;
  730. scroll_bar->set_max(max);
  731. scroll_bar->set_page(page);
  732. if (max <= page) {
  733. scroll_bar->set_value(0);
  734. scroll_bar->hide();
  735. } else {
  736. scroll_bar->show();
  737. if (do_autoscroll_to_bottom)
  738. scroll_bar->set_value(max);
  739. }
  740. break;
  741. }
  742. }
  743. minimum_size_changed();
  744. shape_changed = false;
  745. }
  746. //ensure_selected_visible needs to be checked before we draw the list.
  747. if (ensure_selected_visible && current >= 0 && current < items.size()) {
  748. Rect2 r = items[current].rect_cache;
  749. int from = scroll_bar->get_value();
  750. int to = from + scroll_bar->get_page();
  751. if (r.position.y < from) {
  752. scroll_bar->set_value(r.position.y);
  753. } else if (r.position.y + r.size.y > to) {
  754. scroll_bar->set_value(r.position.y + r.size.y - (to - from));
  755. }
  756. }
  757. ensure_selected_visible = false;
  758. Vector2 base_ofs = bg->get_offset();
  759. base_ofs.y -= int(scroll_bar->get_value());
  760. const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there
  761. int first_item_visible;
  762. {
  763. // do a binary search to find the first item whose rect reaches below clip.position.y
  764. int lo = 0;
  765. int hi = items.size();
  766. while (lo < hi) {
  767. const int mid = (lo + hi) / 2;
  768. const Rect2 &rcache = items[mid].rect_cache;
  769. if (rcache.position.y + rcache.size.y < clip.position.y) {
  770. lo = mid + 1;
  771. } else {
  772. hi = mid;
  773. }
  774. }
  775. // we might have ended up with column 2, or 3, ..., so let's find the first column
  776. while (lo > 0 && items[lo - 1].rect_cache.position.y == items[lo].rect_cache.position.y) {
  777. lo -= 1;
  778. }
  779. first_item_visible = lo;
  780. }
  781. for (int i = first_item_visible; i < items.size(); i++) {
  782. Rect2 rcache = items[i].rect_cache;
  783. if (rcache.position.y > clip.position.y + clip.size.y)
  784. break; // done
  785. if (!clip.intersects(rcache))
  786. continue;
  787. if (current_columns == 1) {
  788. rcache.size.width = width - rcache.position.x;
  789. }
  790. if (items[i].selected) {
  791. Rect2 r = rcache;
  792. r.position += base_ofs;
  793. r.position.y -= vseparation / 2;
  794. r.size.y += vseparation;
  795. r.position.x -= hseparation / 2;
  796. r.size.x += hseparation;
  797. draw_style_box(sbsel, r);
  798. }
  799. if (items[i].custom_bg.a > 0.001) {
  800. Rect2 r = rcache;
  801. r.position += base_ofs;
  802. // Size rect to make the align the temperature colors
  803. r.position.y -= vseparation / 2;
  804. r.size.y += vseparation;
  805. r.position.x -= hseparation / 2;
  806. r.size.x += hseparation;
  807. draw_rect(r, items[i].custom_bg);
  808. }
  809. Vector2 text_ofs;
  810. if (items[i].icon.is_valid()) {
  811. Size2 icon_size;
  812. //= _adjust_to_max_size(items[i].get_icon_size(),fixed_icon_size) * icon_scale;
  813. if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) {
  814. icon_size = fixed_icon_size * icon_scale;
  815. } else {
  816. icon_size = items[i].get_icon_size() * icon_scale;
  817. }
  818. Vector2 icon_ofs;
  819. Point2 pos = items[i].rect_cache.position + icon_ofs + base_ofs;
  820. if (icon_mode == ICON_MODE_TOP) {
  821. pos.x += Math::floor((items[i].rect_cache.size.width - icon_size.width) / 2);
  822. pos.y += MIN(
  823. Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2),
  824. items[i].rect_cache.size.height - items[i].min_rect_cache.size.height);
  825. text_ofs.y = icon_size.height + icon_margin;
  826. text_ofs.y += items[i].rect_cache.size.height - items[i].min_rect_cache.size.height;
  827. } else {
  828. pos.y += Math::floor((items[i].rect_cache.size.height - icon_size.height) / 2);
  829. text_ofs.x = icon_size.width + icon_margin;
  830. }
  831. Rect2 draw_rect = Rect2(pos, icon_size);
  832. if (fixed_icon_size.x > 0 && fixed_icon_size.y > 0) {
  833. Rect2 adj = _adjust_to_max_size(items[i].get_icon_size() * icon_scale, icon_size);
  834. draw_rect.position += adj.position;
  835. draw_rect.size = adj.size;
  836. }
  837. Color modulate = items[i].icon_modulate;
  838. if (items[i].disabled)
  839. modulate.a *= 0.5;
  840. // If the icon is transposed, we have to switch the size so that it is drawn correctly
  841. if (items[i].icon_transposed) {
  842. Size2 size_tmp = draw_rect.size;
  843. draw_rect.size.x = size_tmp.y;
  844. draw_rect.size.y = size_tmp.x;
  845. }
  846. 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);
  847. draw_texture_rect_region(items[i].icon, draw_rect, region, modulate, items[i].icon_transposed);
  848. }
  849. if (items[i].tag_icon.is_valid()) {
  850. draw_texture(items[i].tag_icon, items[i].rect_cache.position + base_ofs);
  851. }
  852. if (items[i].text != "") {
  853. int max_len = -1;
  854. Vector2 size2 = font->get_string_size(items[i].text);
  855. if (fixed_column_width)
  856. max_len = fixed_column_width;
  857. else if (same_column_width)
  858. max_len = items[i].rect_cache.size.x;
  859. else
  860. max_len = size2.x;
  861. Color modulate = items[i].selected ? font_color_selected : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color);
  862. if (items[i].disabled)
  863. modulate.a *= 0.5;
  864. if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) {
  865. int ss = items[i].text.length();
  866. float ofs = 0;
  867. int line = 0;
  868. for (int j = 0; j <= ss; j++) {
  869. int cs = j < ss ? font->get_char_size(items[i].text[j], items[i].text[j + 1]).x : 0;
  870. if (ofs + cs > max_len || j == ss) {
  871. line_limit_cache.write[line] = j;
  872. line_size_cache.write[line] = ofs;
  873. line++;
  874. ofs = 0;
  875. if (line >= max_text_lines)
  876. break;
  877. } else {
  878. ofs += cs;
  879. }
  880. }
  881. line = 0;
  882. ofs = 0;
  883. text_ofs.y += font->get_ascent();
  884. text_ofs = text_ofs.floor();
  885. text_ofs += base_ofs;
  886. text_ofs += items[i].rect_cache.position;
  887. FontDrawer drawer(font, Color(1, 1, 1));
  888. for (int j = 0; j < ss; j++) {
  889. if (j == line_limit_cache[line]) {
  890. line++;
  891. ofs = 0;
  892. if (line >= max_text_lines)
  893. break;
  894. }
  895. 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);
  896. }
  897. //special multiline mode
  898. } else {
  899. if (fixed_column_width > 0)
  900. size2.x = MIN(size2.x, fixed_column_width);
  901. if (icon_mode == ICON_MODE_TOP) {
  902. text_ofs.x += (items[i].rect_cache.size.width - size2.x) / 2;
  903. } else {
  904. text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2;
  905. }
  906. text_ofs.y += font->get_ascent();
  907. text_ofs = text_ofs.floor();
  908. text_ofs += base_ofs;
  909. text_ofs += items[i].rect_cache.position;
  910. draw_string(font, text_ofs, items[i].text, modulate, max_len + 1);
  911. }
  912. }
  913. if (select_mode == SELECT_MULTI && i == current) {
  914. Rect2 r = rcache;
  915. r.position += base_ofs;
  916. r.position.y -= vseparation / 2;
  917. r.size.y += vseparation;
  918. r.position.x -= hseparation / 2;
  919. r.size.x += hseparation;
  920. draw_style_box(cursor, r);
  921. }
  922. }
  923. int first_visible_separator = 0;
  924. {
  925. // do a binary search to find the first separator that is below clip_position.y
  926. int lo = 0;
  927. int hi = separators.size();
  928. while (lo < hi) {
  929. const int mid = (lo + hi) / 2;
  930. if (separators[mid] < clip.position.y) {
  931. lo = mid + 1;
  932. } else {
  933. hi = mid;
  934. }
  935. }
  936. first_visible_separator = lo;
  937. }
  938. for (int i = first_visible_separator; i < separators.size(); i++) {
  939. if (separators[i] > clip.position.y + clip.size.y)
  940. break; // done
  941. const int y = base_ofs.y + separators[i];
  942. draw_line(Vector2(bg->get_margin(MARGIN_LEFT), y), Vector2(width, y), guide_color);
  943. }
  944. }
  945. }
  946. void ItemList::_scroll_changed(double) {
  947. update();
  948. }
  949. int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const {
  950. Vector2 pos = p_pos;
  951. Ref<StyleBox> bg = get_stylebox("bg");
  952. pos -= bg->get_offset();
  953. pos.y += scroll_bar->get_value();
  954. int closest = -1;
  955. int closest_dist = 0x7FFFFFFF;
  956. for (int i = 0; i < items.size(); i++) {
  957. Rect2 rc = items[i].rect_cache;
  958. if (i % current_columns == current_columns - 1) {
  959. rc.size.width = get_size().width - rc.position.x; //make sure you can still select the last item when clicking past the column
  960. }
  961. if (rc.has_point(pos)) {
  962. closest = i;
  963. break;
  964. }
  965. float dist = rc.distance_to(pos);
  966. if (!p_exact && dist < closest_dist) {
  967. closest = i;
  968. closest_dist = dist;
  969. }
  970. }
  971. return closest;
  972. }
  973. bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
  974. if (items.empty())
  975. return true;
  976. Vector2 pos = p_pos;
  977. Ref<StyleBox> bg = get_stylebox("bg");
  978. pos -= bg->get_offset();
  979. pos.y += scroll_bar->get_value();
  980. Rect2 endrect = items[items.size() - 1].rect_cache;
  981. return (pos.y > endrect.position.y + endrect.size.y);
  982. }
  983. String ItemList::get_tooltip(const Point2 &p_pos) const {
  984. int closest = get_item_at_position(p_pos, true);
  985. if (closest != -1) {
  986. if (!items[closest].tooltip_enabled) {
  987. return "";
  988. }
  989. if (items[closest].tooltip != "") {
  990. return items[closest].tooltip;
  991. }
  992. if (items[closest].text != "") {
  993. return items[closest].text;
  994. }
  995. }
  996. return Control::get_tooltip(p_pos);
  997. }
  998. void ItemList::sort_items_by_text() {
  999. items.sort();
  1000. update();
  1001. shape_changed = true;
  1002. if (select_mode == SELECT_SINGLE) {
  1003. for (int i = 0; i < items.size(); i++) {
  1004. if (items[i].selected) {
  1005. select(i);
  1006. return;
  1007. }
  1008. }
  1009. }
  1010. }
  1011. int ItemList::find_metadata(const Variant &p_metadata) const {
  1012. for (int i = 0; i < items.size(); i++) {
  1013. if (items[i].metadata == p_metadata) {
  1014. return i;
  1015. }
  1016. }
  1017. return -1;
  1018. }
  1019. void ItemList::set_allow_rmb_select(bool p_allow) {
  1020. allow_rmb_select = p_allow;
  1021. }
  1022. bool ItemList::get_allow_rmb_select() const {
  1023. return allow_rmb_select;
  1024. }
  1025. void ItemList::set_allow_reselect(bool p_allow) {
  1026. allow_reselect = p_allow;
  1027. }
  1028. bool ItemList::get_allow_reselect() const {
  1029. return allow_reselect;
  1030. }
  1031. void ItemList::set_icon_scale(real_t p_scale) {
  1032. icon_scale = p_scale;
  1033. }
  1034. real_t ItemList::get_icon_scale() const {
  1035. return icon_scale;
  1036. }
  1037. Vector<int> ItemList::get_selected_items() {
  1038. Vector<int> selected;
  1039. for (int i = 0; i < items.size(); i++) {
  1040. if (items[i].selected) {
  1041. selected.push_back(i);
  1042. if (this->select_mode == SELECT_SINGLE) {
  1043. break;
  1044. }
  1045. }
  1046. }
  1047. return selected;
  1048. }
  1049. bool ItemList::is_anything_selected() {
  1050. for (int i = 0; i < items.size(); i++) {
  1051. if (items[i].selected)
  1052. return true;
  1053. }
  1054. return false;
  1055. }
  1056. void ItemList::_set_items(const Array &p_items) {
  1057. ERR_FAIL_COND(p_items.size() % 3);
  1058. clear();
  1059. for (int i = 0; i < p_items.size(); i += 3) {
  1060. String text = p_items[i + 0];
  1061. Ref<Texture> icon = p_items[i + 1];
  1062. bool disabled = p_items[i + 2];
  1063. int idx = get_item_count();
  1064. add_item(text, icon);
  1065. set_item_disabled(idx, disabled);
  1066. }
  1067. }
  1068. Array ItemList::_get_items() const {
  1069. Array items;
  1070. for (int i = 0; i < get_item_count(); i++) {
  1071. items.push_back(get_item_text(i));
  1072. items.push_back(get_item_icon(i));
  1073. items.push_back(is_item_disabled(i));
  1074. }
  1075. return items;
  1076. }
  1077. Size2 ItemList::get_minimum_size() const {
  1078. if (auto_height) {
  1079. return Size2(0, auto_height_value);
  1080. }
  1081. return Size2();
  1082. }
  1083. void ItemList::set_autoscroll_to_bottom(const bool p_enable) {
  1084. do_autoscroll_to_bottom = p_enable;
  1085. }
  1086. void ItemList::set_auto_height(bool p_enable) {
  1087. auto_height = p_enable;
  1088. shape_changed = true;
  1089. update();
  1090. }
  1091. bool ItemList::has_auto_height() const {
  1092. return auto_height;
  1093. }
  1094. void ItemList::_bind_methods() {
  1095. ClassDB::bind_method(D_METHOD("add_item", "text", "icon", "selectable"), &ItemList::add_item, DEFVAL(Variant()), DEFVAL(true));
  1096. ClassDB::bind_method(D_METHOD("add_icon_item", "icon", "selectable"), &ItemList::add_icon_item, DEFVAL(true));
  1097. ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &ItemList::set_item_text);
  1098. ClassDB::bind_method(D_METHOD("get_item_text", "idx"), &ItemList::get_item_text);
  1099. ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &ItemList::set_item_icon);
  1100. ClassDB::bind_method(D_METHOD("get_item_icon", "idx"), &ItemList::get_item_icon);
  1101. ClassDB::bind_method(D_METHOD("set_item_icon_transposed", "idx", "transposed"), &ItemList::set_item_icon_transposed);
  1102. ClassDB::bind_method(D_METHOD("is_item_icon_transposed", "idx"), &ItemList::is_item_icon_transposed);
  1103. ClassDB::bind_method(D_METHOD("set_item_icon_region", "idx", "rect"), &ItemList::set_item_icon_region);
  1104. ClassDB::bind_method(D_METHOD("get_item_icon_region", "idx"), &ItemList::get_item_icon_region);
  1105. ClassDB::bind_method(D_METHOD("set_item_icon_modulate", "idx", "modulate"), &ItemList::set_item_icon_modulate);
  1106. ClassDB::bind_method(D_METHOD("get_item_icon_modulate", "idx"), &ItemList::get_item_icon_modulate);
  1107. ClassDB::bind_method(D_METHOD("set_item_selectable", "idx", "selectable"), &ItemList::set_item_selectable);
  1108. ClassDB::bind_method(D_METHOD("is_item_selectable", "idx"), &ItemList::is_item_selectable);
  1109. ClassDB::bind_method(D_METHOD("set_item_disabled", "idx", "disabled"), &ItemList::set_item_disabled);
  1110. ClassDB::bind_method(D_METHOD("is_item_disabled", "idx"), &ItemList::is_item_disabled);
  1111. ClassDB::bind_method(D_METHOD("set_item_metadata", "idx", "metadata"), &ItemList::set_item_metadata);
  1112. ClassDB::bind_method(D_METHOD("get_item_metadata", "idx"), &ItemList::get_item_metadata);
  1113. ClassDB::bind_method(D_METHOD("set_item_custom_bg_color", "idx", "custom_bg_color"), &ItemList::set_item_custom_bg_color);
  1114. ClassDB::bind_method(D_METHOD("get_item_custom_bg_color", "idx"), &ItemList::get_item_custom_bg_color);
  1115. ClassDB::bind_method(D_METHOD("set_item_custom_fg_color", "idx", "custom_fg_color"), &ItemList::set_item_custom_fg_color);
  1116. ClassDB::bind_method(D_METHOD("get_item_custom_fg_color", "idx"), &ItemList::get_item_custom_fg_color);
  1117. ClassDB::bind_method(D_METHOD("set_item_tooltip_enabled", "idx", "enable"), &ItemList::set_item_tooltip_enabled);
  1118. ClassDB::bind_method(D_METHOD("is_item_tooltip_enabled", "idx"), &ItemList::is_item_tooltip_enabled);
  1119. ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &ItemList::set_item_tooltip);
  1120. ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &ItemList::get_item_tooltip);
  1121. ClassDB::bind_method(D_METHOD("select", "idx", "single"), &ItemList::select, DEFVAL(true));
  1122. ClassDB::bind_method(D_METHOD("unselect", "idx"), &ItemList::unselect);
  1123. ClassDB::bind_method(D_METHOD("unselect_all"), &ItemList::unselect_all);
  1124. ClassDB::bind_method(D_METHOD("is_selected", "idx"), &ItemList::is_selected);
  1125. ClassDB::bind_method(D_METHOD("get_selected_items"), &ItemList::get_selected_items);
  1126. ClassDB::bind_method(D_METHOD("move_item", "from_idx", "to_idx"), &ItemList::move_item);
  1127. ClassDB::bind_method(D_METHOD("get_item_count"), &ItemList::get_item_count);
  1128. ClassDB::bind_method(D_METHOD("remove_item", "idx"), &ItemList::remove_item);
  1129. ClassDB::bind_method(D_METHOD("clear"), &ItemList::clear);
  1130. ClassDB::bind_method(D_METHOD("sort_items_by_text"), &ItemList::sort_items_by_text);
  1131. ClassDB::bind_method(D_METHOD("set_fixed_column_width", "width"), &ItemList::set_fixed_column_width);
  1132. ClassDB::bind_method(D_METHOD("get_fixed_column_width"), &ItemList::get_fixed_column_width);
  1133. ClassDB::bind_method(D_METHOD("set_same_column_width", "enable"), &ItemList::set_same_column_width);
  1134. ClassDB::bind_method(D_METHOD("is_same_column_width"), &ItemList::is_same_column_width);
  1135. ClassDB::bind_method(D_METHOD("set_max_text_lines", "lines"), &ItemList::set_max_text_lines);
  1136. ClassDB::bind_method(D_METHOD("get_max_text_lines"), &ItemList::get_max_text_lines);
  1137. ClassDB::bind_method(D_METHOD("set_max_columns", "amount"), &ItemList::set_max_columns);
  1138. ClassDB::bind_method(D_METHOD("get_max_columns"), &ItemList::get_max_columns);
  1139. ClassDB::bind_method(D_METHOD("set_select_mode", "mode"), &ItemList::set_select_mode);
  1140. ClassDB::bind_method(D_METHOD("get_select_mode"), &ItemList::get_select_mode);
  1141. ClassDB::bind_method(D_METHOD("set_icon_mode", "mode"), &ItemList::set_icon_mode);
  1142. ClassDB::bind_method(D_METHOD("get_icon_mode"), &ItemList::get_icon_mode);
  1143. ClassDB::bind_method(D_METHOD("set_fixed_icon_size", "size"), &ItemList::set_fixed_icon_size);
  1144. ClassDB::bind_method(D_METHOD("get_fixed_icon_size"), &ItemList::get_fixed_icon_size);
  1145. ClassDB::bind_method(D_METHOD("set_icon_scale", "scale"), &ItemList::set_icon_scale);
  1146. ClassDB::bind_method(D_METHOD("get_icon_scale"), &ItemList::get_icon_scale);
  1147. ClassDB::bind_method(D_METHOD("set_allow_rmb_select", "allow"), &ItemList::set_allow_rmb_select);
  1148. ClassDB::bind_method(D_METHOD("get_allow_rmb_select"), &ItemList::get_allow_rmb_select);
  1149. ClassDB::bind_method(D_METHOD("set_allow_reselect", "allow"), &ItemList::set_allow_reselect);
  1150. ClassDB::bind_method(D_METHOD("get_allow_reselect"), &ItemList::get_allow_reselect);
  1151. ClassDB::bind_method(D_METHOD("set_auto_height", "enable"), &ItemList::set_auto_height);
  1152. ClassDB::bind_method(D_METHOD("has_auto_height"), &ItemList::has_auto_height);
  1153. ClassDB::bind_method(D_METHOD("is_anything_selected"), &ItemList::is_anything_selected);
  1154. ClassDB::bind_method(D_METHOD("get_item_at_position", "position", "exact"), &ItemList::get_item_at_position, DEFVAL(false));
  1155. ClassDB::bind_method(D_METHOD("ensure_current_is_visible"), &ItemList::ensure_current_is_visible);
  1156. ClassDB::bind_method(D_METHOD("get_v_scroll"), &ItemList::get_v_scroll);
  1157. ClassDB::bind_method(D_METHOD("_scroll_changed"), &ItemList::_scroll_changed);
  1158. ClassDB::bind_method(D_METHOD("_gui_input"), &ItemList::_gui_input);
  1159. ClassDB::bind_method(D_METHOD("_set_items"), &ItemList::_set_items);
  1160. ClassDB::bind_method(D_METHOD("_get_items"), &ItemList::_get_items);
  1161. ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
  1162. ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
  1163. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
  1164. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
  1165. ADD_PROPERTY(PropertyInfo(Variant::INT, "max_text_lines", PROPERTY_HINT_RANGE, "1,10,1,or_greater"), "set_max_text_lines", "get_max_text_lines");
  1166. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height");
  1167. ADD_GROUP("Columns", "");
  1168. ADD_PROPERTY(PropertyInfo(Variant::INT, "max_columns", PROPERTY_HINT_RANGE, "0,10,1,or_greater"), "set_max_columns", "get_max_columns");
  1169. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "same_column_width"), "set_same_column_width", "is_same_column_width");
  1170. ADD_PROPERTY(PropertyInfo(Variant::INT, "fixed_column_width", PROPERTY_HINT_RANGE, "0,100,1,or_greater"), "set_fixed_column_width", "get_fixed_column_width");
  1171. ADD_GROUP("Icon", "");
  1172. ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode");
  1173. ADD_PROPERTY(PropertyInfo(Variant::REAL, "icon_scale"), "set_icon_scale", "get_icon_scale");
  1174. ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "fixed_icon_size"), "set_fixed_icon_size", "get_fixed_icon_size");
  1175. BIND_ENUM_CONSTANT(ICON_MODE_TOP);
  1176. BIND_ENUM_CONSTANT(ICON_MODE_LEFT);
  1177. BIND_ENUM_CONSTANT(SELECT_SINGLE);
  1178. BIND_ENUM_CONSTANT(SELECT_MULTI);
  1179. ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
  1180. ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::VECTOR2, "at_position")));
  1181. ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "selected")));
  1182. ADD_SIGNAL(MethodInfo("item_activated", PropertyInfo(Variant::INT, "index")));
  1183. ADD_SIGNAL(MethodInfo("rmb_clicked", PropertyInfo(Variant::VECTOR2, "at_position")));
  1184. ADD_SIGNAL(MethodInfo("nothing_selected"));
  1185. GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000);
  1186. 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
  1187. }
  1188. ItemList::ItemList() {
  1189. current = -1;
  1190. select_mode = SELECT_SINGLE;
  1191. icon_mode = ICON_MODE_LEFT;
  1192. fixed_column_width = 0;
  1193. same_column_width = false;
  1194. max_text_lines = 1;
  1195. max_columns = 1;
  1196. auto_height = false;
  1197. auto_height_value = 0.0f;
  1198. scroll_bar = memnew(VScrollBar);
  1199. add_child(scroll_bar);
  1200. shape_changed = true;
  1201. scroll_bar->connect("value_changed", this, "_scroll_changed");
  1202. set_focus_mode(FOCUS_ALL);
  1203. current_columns = 1;
  1204. search_time_msec = 0;
  1205. ensure_selected_visible = false;
  1206. defer_select_single = -1;
  1207. allow_rmb_select = false;
  1208. allow_reselect = false;
  1209. do_autoscroll_to_bottom = false;
  1210. icon_scale = 1.0f;
  1211. set_clip_contents(true);
  1212. }
  1213. ItemList::~ItemList() {
  1214. }