popup_menu.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /*************************************************************************/
  2. /* popup_menu.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "popup_menu.h"
  30. #include "print_string.h"
  31. #include "os/keyboard.h"
  32. #include "translation.h"
  33. String PopupMenu::_get_accel_text(uint32_t p_accel) const {
  34. return keycode_get_string(p_accel);
  35. /*
  36. String atxt;
  37. if (p_accel&KEY_MASK_SHIFT)
  38. atxt+="Shift+";
  39. if (p_accel&KEY_MASK_ALT)
  40. atxt+="Alt+";
  41. if (p_accel&KEY_MASK_CTRL)
  42. atxt+="Ctrl+";
  43. if (p_accel&KEY_MASK_META)
  44. atxt+="Meta+";
  45. p_accel&=KEY_CODE_MASK;
  46. atxt+=String::chr(p_accel).to_upper();
  47. return atxt;
  48. */
  49. }
  50. Size2 PopupMenu::get_minimum_size() const {
  51. int vseparation = get_constant("vseparation");
  52. int hseparation = get_constant("hseparation");
  53. Size2 minsize = get_stylebox("panel")->get_minimum_size();
  54. Ref<Font> font = get_font("font");
  55. float max_w=0;
  56. int font_h = font->get_height();
  57. int check_w = get_icon("checked")->get_width();
  58. int accel_max_w=0;
  59. for (int i=0;i<items.size();i++) {
  60. Size2 size;
  61. if (!items[i].icon.is_null()) {
  62. Size2 icon_size = items[i].icon->get_size();
  63. size.height = MAX( icon_size.height, font_h );
  64. size.width+=icon_size.width;
  65. size.width+=hseparation;
  66. } else {
  67. size.height=font_h;
  68. }
  69. if (items[i].checkable) {
  70. size.width+=check_w+hseparation;
  71. }
  72. size.width+=font->get_string_size(items[i].text).width;
  73. if (i>0)
  74. size.height+=vseparation;
  75. if (items[i].accel) {
  76. int accel_w = hseparation*2;
  77. accel_w+=font->get_string_size(_get_accel_text(items[i].accel)).width;
  78. accel_max_w = MAX( accel_w, accel_max_w );
  79. }
  80. minsize.height+=size.height;
  81. max_w = MAX( max_w, size.width );
  82. }
  83. minsize.width+=max_w+accel_max_w;
  84. return minsize;
  85. }
  86. int PopupMenu::_get_mouse_over(const Point2& p_over) const {
  87. if (p_over.x<0 || p_over.x>=get_size().width)
  88. return -1;
  89. Ref<StyleBox> style = get_stylebox("panel");
  90. Point2 ofs=style->get_offset();
  91. if (ofs.y>p_over.y)
  92. return -1;
  93. Ref<Font> font = get_font("font");
  94. int vseparation = get_constant("vseparation");
  95. // int hseparation = get_constant("hseparation");
  96. float font_h=font->get_height();
  97. for (int i=0;i<items.size();i++) {
  98. if (i>0)
  99. ofs.y+=vseparation;
  100. float h;
  101. if (!items[i].icon.is_null()) {
  102. Size2 icon_size = items[i].icon->get_size();
  103. h = MAX( icon_size.height, font_h );
  104. } else {
  105. h=font_h;
  106. }
  107. ofs.y+=h;
  108. if (p_over.y < ofs.y) {
  109. return i;
  110. }
  111. }
  112. return -1;
  113. }
  114. void PopupMenu::_activate_submenu(int over) {
  115. Node* n = get_node(items[over].submenu);
  116. ERR_EXPLAIN("item subnode does not exist: "+items[over].submenu);
  117. ERR_FAIL_COND(!n);
  118. Popup *pm = n->cast_to<Popup>();
  119. ERR_EXPLAIN("item subnode is not a Popup: "+items[over].submenu);
  120. ERR_FAIL_COND(!pm);
  121. if (pm->is_visible())
  122. return; //already visible!
  123. Point2 p = get_global_pos();
  124. Rect2 pr(p,get_size());
  125. Ref<StyleBox> style = get_stylebox("panel");
  126. pm->set_pos(p+Point2(get_size().width,items[over]._ofs_cache-style->get_offset().y));
  127. pm->popup();
  128. PopupMenu *pum = pm->cast_to<PopupMenu>();
  129. if (pum) {
  130. pr.pos-=pum->get_global_pos();
  131. pum->clear_autohide_areas();
  132. pum->add_autohide_area(Rect2(pr.pos.x,pr.pos.y,pr.size.x,items[over]._ofs_cache));
  133. if (over<items.size()-1) {
  134. int from = items[over+1]._ofs_cache;
  135. pum->add_autohide_area(Rect2(pr.pos.x,pr.pos.y+from,pr.size.x,pr.size.y-from));
  136. }
  137. }
  138. }
  139. void PopupMenu::_submenu_timeout() {
  140. if (mouse_over==submenu_over) {
  141. _activate_submenu(mouse_over);
  142. submenu_over=-1;
  143. }
  144. }
  145. void PopupMenu::_input_event(const InputEvent &p_event) {
  146. switch( p_event.type) {
  147. case InputEvent::KEY: {
  148. if (!p_event.key.pressed)
  149. break;
  150. switch(p_event.key.scancode) {
  151. case KEY_DOWN: {
  152. for(int i=mouse_over+1;i<items.size();i++) {
  153. if (i<0 || i>=items.size())
  154. continue;
  155. if (!items[i].separator && !items[i].disabled) {
  156. mouse_over=i;
  157. update();
  158. break;
  159. }
  160. }
  161. } break;
  162. case KEY_UP: {
  163. for(int i=mouse_over-1;i>=0;i--) {
  164. if (i<0 || i>=items.size())
  165. continue;
  166. if (!items[i].separator && !items[i].disabled) {
  167. mouse_over=i;
  168. update();
  169. break;
  170. }
  171. }
  172. } break;
  173. case KEY_RETURN:
  174. case KEY_ENTER: {
  175. if (mouse_over>=0 && mouse_over<items.size() && !items[mouse_over].separator) {
  176. activate_item(mouse_over);
  177. }
  178. } break;
  179. }
  180. } break;
  181. case InputEvent::MOUSE_BUTTON: {
  182. const InputEventMouseButton &b=p_event.mouse_button;
  183. if (b.pressed)
  184. break;
  185. switch(b.button_index) {
  186. case BUTTON_WHEEL_DOWN: {
  187. if (get_global_pos().y + get_size().y > get_viewport_rect().size.y) {
  188. int vseparation = get_constant("vseparation");
  189. Ref<Font> font = get_font("font");
  190. Point2 pos = get_pos();
  191. int s = (vseparation+font->get_height())*3;
  192. pos.y-=s;
  193. set_pos(pos);
  194. //update hover
  195. InputEvent ie;
  196. ie.type=InputEvent::MOUSE_MOTION;
  197. ie.mouse_motion.x=b.x;
  198. ie.mouse_motion.y=b.y+s;
  199. _input_event(ie);
  200. }
  201. } break;
  202. case BUTTON_WHEEL_UP: {
  203. if (get_global_pos().y < 0) {
  204. int vseparation = get_constant("vseparation");
  205. Ref<Font> font = get_font("font");
  206. Point2 pos = get_pos();
  207. int s = (vseparation+font->get_height())*3;
  208. pos.y+=s;
  209. set_pos(pos);
  210. //update hover
  211. InputEvent ie;
  212. ie.type=InputEvent::MOUSE_MOTION;
  213. ie.mouse_motion.x=b.x;
  214. ie.mouse_motion.y=b.y-s;
  215. _input_event(ie);
  216. }
  217. } break;
  218. case BUTTON_LEFT: {
  219. int over=_get_mouse_over(Point2(b.x,b.y));
  220. if (over<0 || items[over].separator || items[over].disabled)
  221. break; //non-activable
  222. if (items[over].submenu!="") {
  223. _activate_submenu(over);
  224. return;
  225. }
  226. activate_item(over);
  227. } break;
  228. }
  229. //update();
  230. } break;
  231. case InputEvent::MOUSE_MOTION: {
  232. const InputEventMouseMotion &m=p_event.mouse_motion;
  233. for(List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) {
  234. if (!Rect2(Point2(),get_size()).has_point(Point2(m.x,m.y)) && E->get().has_point(Point2(m.x,m.y))) {
  235. call_deferred("hide");
  236. return;
  237. }
  238. }
  239. int over=_get_mouse_over(Point2(m.x,m.y));
  240. int id = (over<0 || items[over].separator || items[over].disabled)?-1:items[over].ID;
  241. if (id<0)
  242. break;
  243. if (items[over].submenu!="" && submenu_over!=over) {
  244. submenu_over=over;
  245. submenu_timer->start();
  246. }
  247. if (over!=mouse_over) {
  248. mouse_over=over;
  249. update();
  250. }
  251. } break;
  252. }
  253. }
  254. bool PopupMenu::has_point(const Point2& p_point) const {
  255. if (parent_rect.has_point(p_point))
  256. return true;
  257. for(const List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) {
  258. if (E->get().has_point(p_point))
  259. return true;
  260. }
  261. return Control::has_point(p_point);
  262. }
  263. void PopupMenu::_notification(int p_what) {
  264. switch(p_what) {
  265. case NOTIFICATION_DRAW: {
  266. RID ci = get_canvas_item();
  267. Size2 size=get_size();
  268. Ref<StyleBox> style = get_stylebox("panel");
  269. Ref<StyleBox> hover = get_stylebox("hover");
  270. Ref<Font> font = get_font("font");
  271. Ref<Texture> check = get_icon("checked");
  272. Ref<Texture> uncheck = get_icon("unchecked");
  273. Ref<Texture> submenu= get_icon("submenu");
  274. Ref<StyleBox> separator = get_stylebox("separator");
  275. style->draw( ci, Rect2( Point2(), get_size() ) );
  276. Point2 ofs=style->get_offset();
  277. int vseparation = get_constant("vseparation");
  278. int hseparation = get_constant("hseparation");
  279. Color font_color = get_color("font_color");
  280. Color font_color_disabled = get_color("font_color_disabled");
  281. Color font_color_accel = get_color("font_color_accel");
  282. Color font_color_hover = get_color("font_color_hover");
  283. float font_h=font->get_height();
  284. for (int i=0;i<items.size();i++) {
  285. if (i>0)
  286. ofs.y+=vseparation;
  287. Point2 item_ofs=ofs;
  288. float h;
  289. Size2 icon_size;
  290. if (!items[i].icon.is_null()) {
  291. icon_size = items[i].icon->get_size();
  292. h = MAX( icon_size.height, font_h );
  293. } else {
  294. h=font_h;
  295. }
  296. if (i==mouse_over) {
  297. hover->draw(ci, Rect2( ofs+Point2(-hseparation,-vseparation), Size2( get_size().width - style->get_minimum_size().width + hseparation*2, h+vseparation*2 ) ));
  298. }
  299. if (items[i].separator) {
  300. int sep_h=separator->get_center_size().height+separator->get_minimum_size().height;
  301. separator->draw(ci, Rect2( ofs+Point2(0,Math::floor((h-sep_h)/2.0)), Size2( get_size().width - style->get_minimum_size().width , sep_h ) ));
  302. }
  303. if (items[i].checkable) {
  304. if (items[i].checked)
  305. check->draw(ci, item_ofs+Point2(0,Math::floor((h-check->get_height())/2.0)));
  306. else
  307. uncheck->draw(ci, item_ofs+Point2(0,Math::floor((h-check->get_height())/2.0)));
  308. item_ofs.x+=check->get_width()+hseparation;
  309. }
  310. if (!items[i].icon.is_null()) {
  311. items[i].icon->draw( ci, item_ofs+Point2(0,Math::floor((h-icon_size.height)/2.0)));
  312. item_ofs.x+=items[i].icon->get_width();
  313. item_ofs.x+=hseparation;
  314. }
  315. if (items[i].submenu!="") {
  316. submenu->draw( ci, Point2(size.width - style->get_margin(MARGIN_RIGHT) - submenu->get_width(),item_ofs.y+Math::floor(h-submenu->get_height())/2));
  317. }
  318. item_ofs.y+=font->get_ascent();
  319. if (!items[i].separator)
  320. font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),items[i].text,items[i].disabled?font_color_disabled:(i==mouse_over?font_color_hover:font_color));
  321. if (items[i].accel) {
  322. //accelerator
  323. String text = _get_accel_text(items[i].accel);
  324. item_ofs.x=size.width-style->get_margin(MARGIN_RIGHT)-font->get_string_size(text).width;
  325. font->draw(ci,item_ofs+Point2(0,Math::floor((h-font_h)/2.0)),text,i==mouse_over?font_color_hover:font_color_accel);
  326. }
  327. items[i]._ofs_cache=ofs.y;
  328. ofs.y+=h;
  329. }
  330. } break;
  331. case NOTIFICATION_MOUSE_ENTER: {
  332. grab_focus();
  333. } break;
  334. case NOTIFICATION_MOUSE_EXIT: {
  335. if (mouse_over>=0) {
  336. mouse_over=-1;
  337. update();
  338. }
  339. } break;
  340. }
  341. }
  342. void PopupMenu::add_icon_item(const Ref<Texture>& p_icon,const String& p_label,int p_ID,uint32_t p_accel) {
  343. Item item;
  344. item.icon=p_icon;
  345. item.text=p_label;
  346. item.accel=p_accel;
  347. item.ID=(p_ID<0)?idcount++:p_ID;
  348. items.push_back(item);
  349. update();
  350. }
  351. void PopupMenu::add_item(const String& p_label,int p_ID,uint32_t p_accel) {
  352. Item item;
  353. item.text=XL_MESSAGE(p_label);
  354. item.accel=p_accel;
  355. item.ID=(p_ID<0)?idcount++:p_ID;
  356. items.push_back(item);
  357. update();
  358. }
  359. void PopupMenu::add_submenu_item(const String& p_label, const String& p_submenu,int p_ID){
  360. Item item;
  361. item.text=XL_MESSAGE(p_label);
  362. item.ID=(p_ID<0)?idcount++:p_ID;
  363. item.submenu=p_submenu;
  364. items.push_back(item);
  365. update();
  366. }
  367. void PopupMenu::add_icon_check_item(const Ref<Texture>& p_icon,const String& p_label,int p_ID,uint32_t p_accel) {
  368. Item item;
  369. item.icon=p_icon;
  370. item.text=XL_MESSAGE(p_label);
  371. item.accel=p_accel;
  372. item.ID=(p_ID<0)?idcount++:p_ID;
  373. item.checkable=true;
  374. items.push_back(item);
  375. update();
  376. }
  377. void PopupMenu::add_check_item(const String& p_label,int p_ID,uint32_t p_accel) {
  378. Item item;
  379. item.text=XL_MESSAGE(p_label);
  380. item.accel=p_accel;
  381. item.ID=(p_ID<0)?idcount++:p_ID;
  382. item.checkable=true;
  383. items.push_back(item);
  384. update();
  385. }
  386. void PopupMenu::set_item_text(int p_idx,const String& p_text) {
  387. ERR_FAIL_INDEX(p_idx,items.size());
  388. items[p_idx].text=XL_MESSAGE(p_text);
  389. update();
  390. }
  391. void PopupMenu::set_item_icon(int p_idx,const Ref<Texture>& p_icon) {
  392. ERR_FAIL_INDEX(p_idx,items.size());
  393. items[p_idx].icon=p_icon;
  394. update();
  395. }
  396. void PopupMenu::set_item_checked(int p_idx,bool p_checked) {
  397. ERR_FAIL_INDEX(p_idx,items.size());
  398. items[p_idx].checked=p_checked;
  399. update();
  400. }
  401. void PopupMenu::set_item_ID(int p_idx,int p_ID) {
  402. ERR_FAIL_INDEX(p_idx,items.size());
  403. items[p_idx].ID=p_ID;
  404. update();
  405. }
  406. void PopupMenu::set_item_accelerator(int p_idx,uint32_t p_accel) {
  407. ERR_FAIL_INDEX(p_idx,items.size());
  408. items[p_idx].accel=p_accel;
  409. update();
  410. }
  411. void PopupMenu::set_item_metadata(int p_idx,const Variant& p_meta) {
  412. ERR_FAIL_INDEX(p_idx,items.size());
  413. items[p_idx].metadata=p_meta;
  414. update();
  415. }
  416. void PopupMenu::set_item_disabled(int p_idx,bool p_disabled) {
  417. ERR_FAIL_INDEX(p_idx,items.size());
  418. items[p_idx].disabled=p_disabled;
  419. update();
  420. }
  421. void PopupMenu::set_item_submenu(int p_idx, const String& p_submenu) {
  422. ERR_FAIL_INDEX(p_idx,items.size());
  423. items[p_idx].submenu=p_submenu;
  424. update();
  425. }
  426. String PopupMenu::get_item_text(int p_idx) const {
  427. ERR_FAIL_INDEX_V(p_idx,items.size(),"");
  428. return items[p_idx].text;
  429. }
  430. Ref<Texture> PopupMenu::get_item_icon(int p_idx) const {
  431. ERR_FAIL_INDEX_V(p_idx,items.size(),Ref<Texture>());
  432. return items[p_idx].icon;
  433. }
  434. uint32_t PopupMenu::get_item_accelerator(int p_idx) const {
  435. ERR_FAIL_INDEX_V(p_idx,items.size(),0);
  436. return items[p_idx].accel;
  437. }
  438. Variant PopupMenu::get_item_metadata(int p_idx) const {
  439. ERR_FAIL_INDEX_V(p_idx,items.size(),Variant());
  440. return items[p_idx].metadata;
  441. }
  442. bool PopupMenu::is_item_disabled(int p_idx) const {
  443. ERR_FAIL_INDEX_V(p_idx,items.size(),false);
  444. return items[p_idx].disabled;
  445. }
  446. bool PopupMenu::is_item_checked(int p_idx) const {
  447. ERR_FAIL_INDEX_V(p_idx,items.size(),false);
  448. return items[p_idx].checked;
  449. }
  450. int PopupMenu::get_item_ID(int p_idx) const {
  451. ERR_FAIL_INDEX_V(p_idx,items.size(),0);
  452. return items[p_idx].ID;
  453. }
  454. int PopupMenu::get_item_index(int p_ID) const {
  455. for(int i=0;i<items.size();i++) {
  456. if (items[i].ID==p_ID)
  457. return i;
  458. }
  459. return -1;
  460. }
  461. String PopupMenu::get_item_submenu(int p_idx) const {
  462. ERR_FAIL_INDEX_V(p_idx,items.size(),"");
  463. return items[p_idx].submenu;
  464. }
  465. String PopupMenu::get_item_tooltip(int p_idx) const {
  466. ERR_FAIL_INDEX_V(p_idx,items.size(),"");
  467. return items[p_idx].tooltip;
  468. }
  469. void PopupMenu::set_item_as_separator(int p_idx, bool p_separator) {
  470. ERR_FAIL_INDEX(p_idx,items.size());
  471. items[p_idx].separator=p_separator;
  472. update();
  473. }
  474. bool PopupMenu::is_item_separator(int p_idx) const {
  475. ERR_FAIL_INDEX_V(p_idx,items.size(),false);
  476. return items[p_idx].separator;
  477. }
  478. void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
  479. ERR_FAIL_INDEX(p_idx,items.size());
  480. items[p_idx].checkable=p_checkable;
  481. update();
  482. }
  483. void PopupMenu::set_item_tooltip(int p_idx,const String& p_tooltip) {
  484. ERR_FAIL_INDEX(p_idx,items.size());
  485. items[p_idx].tooltip=p_tooltip;
  486. update();
  487. }
  488. bool PopupMenu::is_item_checkable(int p_idx) const {
  489. ERR_FAIL_INDEX_V(p_idx,items.size(),false);
  490. return items[p_idx].checkable;
  491. }
  492. int PopupMenu::get_item_count() const {
  493. return items.size();
  494. }
  495. int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const {
  496. int il=items.size();
  497. for(int i=0;i<il;i++) {
  498. if (items[i].accel==p_accel)
  499. return i;
  500. }
  501. return -1;
  502. }
  503. void PopupMenu::activate_item(int p_item) {
  504. ERR_FAIL_INDEX(p_item,items.size());
  505. ERR_FAIL_COND(items[p_item].separator);
  506. emit_signal("item_pressed",items[p_item].ID);
  507. hide();
  508. }
  509. void PopupMenu::remove_item(int p_idx) {
  510. items.remove(p_idx);
  511. update();
  512. }
  513. void PopupMenu::add_separator() {
  514. Item sep;
  515. sep.separator=true;
  516. sep.ID=-1;
  517. items.push_back(sep);
  518. update();
  519. }
  520. void PopupMenu::clear() {
  521. items.clear();
  522. update();
  523. idcount=0;
  524. }
  525. Array PopupMenu::_get_items() const {
  526. Array items;
  527. for(int i=0;i<get_item_count();i++) {
  528. items.push_back(get_item_text(i));
  529. items.push_back(get_item_icon(i));
  530. items.push_back(is_item_checkable(i));
  531. items.push_back(is_item_checked(i));
  532. items.push_back(is_item_disabled(i));
  533. items.push_back(get_item_ID(i));
  534. items.push_back(get_item_accelerator(i));
  535. items.push_back(get_item_metadata(i));
  536. items.push_back(get_item_submenu(i));
  537. items.push_back(is_item_separator(i));
  538. }
  539. return items;
  540. }
  541. void PopupMenu::_set_items(const Array& p_items){
  542. ERR_FAIL_COND(p_items.size() % 10);
  543. clear();
  544. for(int i=0;i<p_items.size();i+=10) {
  545. String text=p_items[i+0];
  546. Ref<Texture> icon=p_items[i+1];
  547. bool checkable=p_items[i+2];
  548. bool checked=p_items[i+3];
  549. bool disabled=p_items[i+4];
  550. int id=p_items[i+5];
  551. int accel=p_items[i+6];
  552. Variant meta=p_items[i+7];
  553. String subm=p_items[i+8];
  554. bool sep=p_items[i+9];
  555. int idx=get_item_count();
  556. add_item(text,id);
  557. set_item_icon(idx,icon);
  558. set_item_as_checkable(idx,checkable);
  559. set_item_checked(idx,checked);
  560. set_item_disabled(idx,disabled);
  561. set_item_ID(idx,id);
  562. set_item_metadata(idx,meta);
  563. set_item_as_separator(idx,sep);
  564. set_item_accelerator(idx,accel);
  565. set_item_submenu(idx,subm);
  566. }
  567. }
  568. String PopupMenu::get_tooltip(const Point2& p_pos) const {
  569. int over=_get_mouse_over(p_pos);
  570. if (over<0 || over>=items.size())
  571. return "";
  572. return items[over].tooltip;
  573. }
  574. void PopupMenu::set_parent_rect(const Rect2& p_rect) {
  575. parent_rect=p_rect;
  576. }
  577. void PopupMenu::get_translatable_strings(List<String> *p_strings) const {
  578. for(int i=0;i<items.size();i++) {
  579. if (items[i].text!="")
  580. p_strings->push_back(items[i].text);
  581. }
  582. }
  583. void PopupMenu::add_autohide_area(const Rect2& p_area) {
  584. autohide_areas.push_back(p_area);
  585. }
  586. void PopupMenu::clear_autohide_areas(){
  587. autohide_areas.clear();
  588. }
  589. void PopupMenu::_bind_methods() {
  590. ObjectTypeDB::bind_method(_MD("_input_event"),&PopupMenu::_input_event);
  591. ObjectTypeDB::bind_method(_MD("add_icon_item","texture","label","id","accel"),&PopupMenu::add_icon_item,DEFVAL(-1),DEFVAL(0));
  592. ObjectTypeDB::bind_method(_MD("add_item","label","id","accel"),&PopupMenu::add_item,DEFVAL(-1),DEFVAL(0));
  593. ObjectTypeDB::bind_method(_MD("add_icon_check_item","texture","label","id","accel"),&PopupMenu::add_icon_check_item,DEFVAL(-1),DEFVAL(0));
  594. ObjectTypeDB::bind_method(_MD("add_check_item","label","id","accel"),&PopupMenu::add_check_item,DEFVAL(-1),DEFVAL(0));
  595. ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_check_item,DEFVAL(-1));
  596. ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&PopupMenu::set_item_text);
  597. ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon"),&PopupMenu::set_item_icon);
  598. ObjectTypeDB::bind_method(_MD("set_item_accelerator","idx","accel"),&PopupMenu::set_item_accelerator);
  599. ObjectTypeDB::bind_method(_MD("set_item_metadata","idx","metadata"),&PopupMenu::set_item_metadata);
  600. ObjectTypeDB::bind_method(_MD("set_item_checked","idx"),&PopupMenu::set_item_checked);
  601. ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&PopupMenu::set_item_disabled);
  602. ObjectTypeDB::bind_method(_MD("set_item_submenu","idx","submenu"),&PopupMenu::set_item_submenu);
  603. ObjectTypeDB::bind_method(_MD("set_item_as_separator","idx","enable"),&PopupMenu::set_item_as_separator);
  604. ObjectTypeDB::bind_method(_MD("set_item_as_checkable","idx","enable"),&PopupMenu::set_item_as_checkable);
  605. ObjectTypeDB::bind_method(_MD("set_item_ID","idx","id"),&PopupMenu::set_item_ID);
  606. ObjectTypeDB::bind_method(_MD("get_item_text","idx"),&PopupMenu::get_item_text);
  607. ObjectTypeDB::bind_method(_MD("get_item_icon","idx"),&PopupMenu::get_item_icon);
  608. ObjectTypeDB::bind_method(_MD("get_item_metadata","idx"),&PopupMenu::get_item_metadata);
  609. ObjectTypeDB::bind_method(_MD("get_item_accelerator","idx"),&PopupMenu::get_item_accelerator);
  610. ObjectTypeDB::bind_method(_MD("get_item_submenu","idx"),&PopupMenu::get_item_submenu);
  611. ObjectTypeDB::bind_method(_MD("is_item_separator","idx"),&PopupMenu::is_item_separator);
  612. ObjectTypeDB::bind_method(_MD("is_item_checkable","idx"),&PopupMenu::is_item_checkable);
  613. ObjectTypeDB::bind_method(_MD("is_item_checked","idx"),&PopupMenu::is_item_checked);
  614. ObjectTypeDB::bind_method(_MD("is_item_disabled","idx"),&PopupMenu::is_item_disabled);
  615. ObjectTypeDB::bind_method(_MD("get_item_ID","idx"),&PopupMenu::get_item_ID);
  616. ObjectTypeDB::bind_method(_MD("get_item_index","id"),&PopupMenu::get_item_index);
  617. ObjectTypeDB::bind_method(_MD("get_item_count"),&PopupMenu::get_item_count);
  618. ObjectTypeDB::bind_method(_MD("add_separator"),&PopupMenu::add_separator);
  619. ObjectTypeDB::bind_method(_MD("remove_item","idx"),&PopupMenu::remove_item);
  620. ObjectTypeDB::bind_method(_MD("clear"),&PopupMenu::clear);
  621. ObjectTypeDB::bind_method(_MD("_set_items"),&PopupMenu::_set_items);
  622. ObjectTypeDB::bind_method(_MD("_get_items"),&PopupMenu::_get_items);
  623. ObjectTypeDB::bind_method(_MD("_submenu_timeout"),&PopupMenu::_submenu_timeout);
  624. ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"items",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_items"),_SCS("_get_items") );
  625. ADD_SIGNAL( MethodInfo("item_pressed", PropertyInfo( Variant::INT,"ID") ) );
  626. }
  627. PopupMenu::PopupMenu() {
  628. idcount=0;
  629. mouse_over=-1;
  630. set_focus_mode(FOCUS_ALL);
  631. set_as_toplevel(true);
  632. submenu_timer = memnew( Timer );
  633. submenu_timer->set_wait_time(0.3);
  634. submenu_timer->set_one_shot(true);
  635. submenu_timer->connect("timeout",this,"_submenu_timeout");
  636. add_child(submenu_timer);
  637. }
  638. PopupMenu::~PopupMenu() {
  639. }