PopupMenu.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. using System;
  2. using UnityEngine;
  3. namespace FairyGUI
  4. {
  5. /// <summary>
  6. ///
  7. /// </summary>
  8. public class PopupMenu : EventDispatcher
  9. {
  10. protected GComponent _contentPane;
  11. protected GList _list;
  12. protected GObject _expandingItem;
  13. PopupMenu _parentMenu;
  14. TimerCallback _showSubMenu;
  15. TimerCallback _closeSubMenu;
  16. EventListener _onPopup;
  17. EventListener _onClose;
  18. public int visibleItemCount;
  19. public bool hideOnClickItem;
  20. public bool autoSize;
  21. const string EVENT_TYPE = "PopupMenuItemClick";
  22. public PopupMenu()
  23. {
  24. Create(null);
  25. }
  26. /// <summary>
  27. ///
  28. /// </summary>
  29. /// <param name="resourceURL"></param>
  30. public PopupMenu(string resourceURL)
  31. {
  32. Create(resourceURL);
  33. }
  34. public EventListener onPopup
  35. {
  36. get { return _onPopup ?? (_onPopup = new EventListener(this, "onPopup")); }
  37. }
  38. public EventListener onClose
  39. {
  40. get { return _onClose ?? (_onClose = new EventListener(this, "onClose")); }
  41. }
  42. void Create(string resourceURL)
  43. {
  44. if (resourceURL == null)
  45. {
  46. resourceURL = UIConfig.popupMenu;
  47. if (resourceURL == null)
  48. {
  49. Debug.LogError("FairyGUI: UIConfig.popupMenu not defined");
  50. return;
  51. }
  52. }
  53. _contentPane = UIPackage.CreateObjectFromURL(resourceURL).asCom;
  54. _contentPane.onAddedToStage.Add(__addedToStage);
  55. _contentPane.onRemovedFromStage.Add(__removeFromStage);
  56. _contentPane.focusable = false;
  57. _list = _contentPane.GetChild("list").asList;
  58. _list.RemoveChildrenToPool();
  59. _list.AddRelation(_contentPane, RelationType.Width);
  60. _list.RemoveRelation(_contentPane, RelationType.Height);
  61. _contentPane.AddRelation(_list, RelationType.Height);
  62. _list.onClickItem.Add(__clickItem);
  63. hideOnClickItem = true;
  64. _showSubMenu = __showSubMenu;
  65. _closeSubMenu = CloseSubMenu;
  66. }
  67. /// <summary>
  68. ///
  69. /// </summary>
  70. /// <param name="caption"></param>
  71. /// <param name="callback"></param>
  72. /// <returns></returns>
  73. public GButton AddItem(string caption, EventCallback0 callback)
  74. {
  75. GButton item = CreateItem(caption, callback);
  76. _list.AddChild(item);
  77. return item;
  78. }
  79. /// <summary>
  80. ///
  81. /// </summary>
  82. /// <param name="caption"></param>
  83. /// <param name="callback"></param>
  84. /// <returns></returns>
  85. public GButton AddItem(string caption, EventCallback1 callback)
  86. {
  87. GButton item = CreateItem(caption, callback);
  88. _list.AddChild(item);
  89. return item;
  90. }
  91. /// <summary>
  92. ///
  93. /// </summary>
  94. /// <param name="caption"></param>
  95. /// <param name="index"></param>
  96. /// <param name="callback"></param>
  97. /// <returns></returns>
  98. public GButton AddItemAt(string caption, int index, EventCallback1 callback)
  99. {
  100. GButton item = CreateItem(caption, callback);
  101. _list.AddChildAt(item, index);
  102. return item;
  103. }
  104. /// <summary>
  105. ///
  106. /// </summary>
  107. /// <param name="caption"></param>
  108. /// <param name="index"></param>
  109. /// <param name="callback"></param>
  110. /// <returns></returns>
  111. public GButton AddItemAt(string caption, int index, EventCallback0 callback)
  112. {
  113. GButton item = CreateItem(caption, callback);
  114. _list.AddChildAt(item, index);
  115. return item;
  116. }
  117. GButton CreateItem(string caption, Delegate callback)
  118. {
  119. GButton item = _list.GetFromPool(_list.defaultItem).asButton;
  120. item.title = caption;
  121. item.grayed = false;
  122. Controller c = item.GetController("checked");
  123. if (c != null)
  124. c.selectedIndex = 0;
  125. item.RemoveEventListeners(EVENT_TYPE);
  126. if (callback is EventCallback0)
  127. item.AddEventListener(EVENT_TYPE, (EventCallback0)callback);
  128. else
  129. item.AddEventListener(EVENT_TYPE, (EventCallback1)callback);
  130. item.onRollOver.Add(__rollOver);
  131. item.onRollOut.Add(__rollOut);
  132. return item;
  133. }
  134. /// <summary>
  135. ///
  136. /// </summary>
  137. public void AddSeperator()
  138. {
  139. AddSeperator(-1);
  140. }
  141. /// <summary>
  142. ///
  143. /// </summary>
  144. public void AddSeperator(int index)
  145. {
  146. if (UIConfig.popupMenu_seperator == null)
  147. {
  148. Debug.LogError("FairyGUI: UIConfig.popupMenu_seperator not defined");
  149. return;
  150. }
  151. if (index == -1)
  152. _list.AddItemFromPool(UIConfig.popupMenu_seperator);
  153. else
  154. {
  155. GObject item = _list.GetFromPool(UIConfig.popupMenu_seperator);
  156. _list.AddChildAt(item, index);
  157. }
  158. }
  159. /// <summary>
  160. ///
  161. /// </summary>
  162. /// <param name="index"></param>
  163. /// <returns></returns>
  164. public string GetItemName(int index)
  165. {
  166. GButton item = _list.GetChildAt(index).asButton;
  167. return item.name;
  168. }
  169. /// <summary>
  170. ///
  171. /// </summary>
  172. /// <param name="name"></param>
  173. /// <param name="caption"></param>
  174. public void SetItemText(string name, string caption)
  175. {
  176. GButton item = _list.GetChild(name).asButton;
  177. item.title = caption;
  178. }
  179. /// <summary>
  180. ///
  181. /// </summary>
  182. /// <param name="name"></param>
  183. /// <param name="visible"></param>
  184. public void SetItemVisible(string name, bool visible)
  185. {
  186. GButton item = _list.GetChild(name).asButton;
  187. if (item.visible != visible)
  188. {
  189. item.visible = visible;
  190. _list.SetBoundsChangedFlag();
  191. }
  192. }
  193. /// <summary>
  194. ///
  195. /// </summary>
  196. /// <param name="name"></param>
  197. /// <param name="grayed"></param>
  198. public void SetItemGrayed(string name, bool grayed)
  199. {
  200. GButton item = _list.GetChild(name).asButton;
  201. item.grayed = grayed;
  202. }
  203. /// <summary>
  204. ///
  205. /// </summary>
  206. /// <param name="name"></param>
  207. /// <param name="checkable"></param>
  208. public void SetItemCheckable(string name, bool checkable)
  209. {
  210. GButton item = _list.GetChild(name).asButton;
  211. Controller c = item.GetController("checked");
  212. if (c != null)
  213. {
  214. if (checkable)
  215. {
  216. if (c.selectedIndex == 0)
  217. c.selectedIndex = 1;
  218. }
  219. else
  220. c.selectedIndex = 0;
  221. }
  222. }
  223. /// <summary>
  224. ///
  225. /// </summary>
  226. /// <param name="name"></param>
  227. /// <param name="check"></param>
  228. public void SetItemChecked(string name, bool check)
  229. {
  230. GButton item = _list.GetChild(name).asButton;
  231. Controller c = item.GetController("checked");
  232. if (c != null)
  233. c.selectedIndex = check ? 2 : 1;
  234. }
  235. [Obsolete("Use IsItemChecked instead")]
  236. public bool isItemChecked(string name)
  237. {
  238. return IsItemChecked(name);
  239. }
  240. /// <summary>
  241. ///
  242. /// </summary>
  243. /// <param name="name"></param>
  244. /// <returns></returns>
  245. public bool IsItemChecked(string name)
  246. {
  247. GButton item = _list.GetChild(name).asButton;
  248. Controller c = item.GetController("checked");
  249. if (c != null)
  250. return c.selectedIndex == 2;
  251. else
  252. return false;
  253. }
  254. /// <summary>
  255. ///
  256. /// </summary>
  257. /// <param name="name"></param>
  258. public void RemoveItem(string name)
  259. {
  260. GComponent item = _list.GetChild(name).asCom;
  261. if (item != null)
  262. {
  263. item.RemoveEventListeners(EVENT_TYPE);
  264. if (item.data is PopupMenu)
  265. {
  266. ((PopupMenu)item.data).Dispose();
  267. item.data = null;
  268. }
  269. int index = _list.GetChildIndex(item);
  270. _list.RemoveChildToPoolAt(index);
  271. }
  272. }
  273. /// <summary>
  274. ///
  275. /// </summary>
  276. public void ClearItems()
  277. {
  278. _list.RemoveChildrenToPool();
  279. }
  280. /// <summary>
  281. ///
  282. /// </summary>
  283. public int itemCount
  284. {
  285. get { return _list.numChildren; }
  286. }
  287. /// <summary>
  288. ///
  289. /// </summary>
  290. public GComponent contentPane
  291. {
  292. get { return _contentPane; }
  293. }
  294. /// <summary>
  295. ///
  296. /// </summary>
  297. public GList list
  298. {
  299. get { return _list; }
  300. }
  301. public void Dispose()
  302. {
  303. int cnt = _list.numChildren;
  304. for (int i = 0; i < cnt; i++)
  305. {
  306. GObject obj = _list.GetChildAt(i);
  307. if (obj.data is PopupMenu)
  308. ((PopupMenu)obj.data).Dispose();
  309. }
  310. _contentPane.Dispose();
  311. }
  312. /// <summary>
  313. ///
  314. /// </summary>
  315. public void Show()
  316. {
  317. Show(null, PopupDirection.Auto);
  318. }
  319. /// <summary>
  320. ///
  321. /// </summary>
  322. /// <param name="target"></param>
  323. public void Show(GObject target)
  324. {
  325. Show(target, PopupDirection.Auto, null);
  326. }
  327. [Obsolete]
  328. public void Show(GObject target, object downward)
  329. {
  330. Show(target, downward == null ? PopupDirection.Auto : ((bool)downward == true ? PopupDirection.Down : PopupDirection.Up), null);
  331. }
  332. /// <summary>
  333. ///
  334. /// </summary>
  335. /// <param name="target"></param>
  336. /// <param name="dir"></param>
  337. public void Show(GObject target, PopupDirection dir)
  338. {
  339. Show(target, PopupDirection.Auto, null);
  340. }
  341. /// <summary>
  342. ///
  343. /// </summary>
  344. /// <param name="target"></param>
  345. /// <param name="dir"></param>
  346. /// <param name="parentMenu"></param>
  347. public void Show(GObject target, PopupDirection dir, PopupMenu parentMenu)
  348. {
  349. GRoot r = target != null ? target.root : GRoot.inst;
  350. r.ShowPopup(this.contentPane, (target is GRoot) ? null : target, dir);
  351. _parentMenu = parentMenu;
  352. }
  353. public void Hide()
  354. {
  355. if (contentPane.parent != null)
  356. ((GRoot)contentPane.parent).HidePopup(contentPane);
  357. }
  358. void ShowSubMenu(GObject item)
  359. {
  360. _expandingItem = item;
  361. PopupMenu popup = item.data as PopupMenu;
  362. if (item is GButton)
  363. ((GButton)item).selected = true;
  364. popup.Show(item, PopupDirection.Auto, this);
  365. Vector2 pt = contentPane.LocalToRoot(new Vector2(item.x + item.width - 5, item.y - 5), item.root);
  366. popup.contentPane.position = pt;
  367. }
  368. void CloseSubMenu(object param)
  369. {
  370. if (contentPane.isDisposed)
  371. return;
  372. if (_expandingItem == null)
  373. return;
  374. if (_expandingItem is GButton)
  375. ((GButton)_expandingItem).selected = false;
  376. PopupMenu popup = (PopupMenu)_expandingItem.data;
  377. if (popup == null)
  378. return;
  379. _expandingItem = null;
  380. popup.Hide();
  381. }
  382. private void __clickItem(EventContext context)
  383. {
  384. GButton item = ((GObject)context.data).asButton;
  385. if (item == null)
  386. return;
  387. if (item.grayed)
  388. {
  389. _list.selectedIndex = -1;
  390. return;
  391. }
  392. Controller c = item.GetController("checked");
  393. if (c != null && c.selectedIndex != 0)
  394. {
  395. if (c.selectedIndex == 1)
  396. c.selectedIndex = 2;
  397. else
  398. c.selectedIndex = 1;
  399. }
  400. if (hideOnClickItem)
  401. {
  402. if (_parentMenu != null)
  403. _parentMenu.Hide();
  404. Hide();
  405. }
  406. item.DispatchEvent(EVENT_TYPE, item); //event data is for backward compatibility
  407. }
  408. void __addedToStage()
  409. {
  410. DispatchEvent("onPopup", null);
  411. if (autoSize)
  412. {
  413. _list.EnsureBoundsCorrect();
  414. int cnt = _list.numChildren;
  415. float maxDelta = -1000;
  416. for (int i = 0; i < cnt; i++)
  417. {
  418. GButton obj = _list.GetChildAt(i).asButton;
  419. if (obj == null)
  420. continue;
  421. GTextField tf = obj.GetTextField();
  422. if (tf != null)
  423. {
  424. float v = tf.textWidth - tf.width;
  425. if (v > maxDelta)
  426. maxDelta = v;
  427. }
  428. }
  429. if (contentPane.width + maxDelta > contentPane.initWidth)
  430. contentPane.width += maxDelta;
  431. else
  432. contentPane.width = contentPane.initWidth;
  433. }
  434. _list.selectedIndex = -1;
  435. _list.ResizeToFit(visibleItemCount > 0 ? visibleItemCount : int.MaxValue, 10);
  436. }
  437. void __removeFromStage()
  438. {
  439. _parentMenu = null;
  440. if (_expandingItem != null)
  441. Timers.inst.Add(0, 1, _closeSubMenu);
  442. DispatchEvent("onClose", null);
  443. }
  444. void __rollOver(EventContext context)
  445. {
  446. GObject item = (GObject)context.sender;
  447. if ((item.data is PopupMenu) || _expandingItem != null)
  448. {
  449. Timers.inst.Add(0.1f, 1, _showSubMenu, item);
  450. }
  451. }
  452. void __showSubMenu(object param)
  453. {
  454. if (contentPane.isDisposed)
  455. return;
  456. GObject item = (GObject)param;
  457. GRoot r = contentPane.root;
  458. if (r == null)
  459. return;
  460. if (_expandingItem != null)
  461. {
  462. if (_expandingItem == item)
  463. return;
  464. CloseSubMenu(null);
  465. }
  466. PopupMenu popup = item.data as PopupMenu;
  467. if (popup == null)
  468. return;
  469. ShowSubMenu(item);
  470. }
  471. void __rollOut(EventContext context)
  472. {
  473. if (_expandingItem == null)
  474. return;
  475. Timers.inst.Remove(_showSubMenu);
  476. GRoot r = contentPane.root;
  477. if (r != null)
  478. {
  479. PopupMenu popup = (PopupMenu)_expandingItem.data;
  480. Vector2 pt = popup.contentPane.GlobalToLocal(context.inputEvent.position);
  481. if (pt.x >= 0 && pt.y >= 0 && pt.x < popup.contentPane.width && pt.y < popup.contentPane.height)
  482. return;
  483. }
  484. CloseSubMenu(null);
  485. }
  486. }
  487. }