popup.cpp 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720
  1. #include <precomp.h>
  2. #include <api/wnd/api_window.h>
  3. #include <api/locales/xlatstr.h>
  4. #ifndef WASABI_WANT_FF_POPUP
  5. #include "popup.h"
  6. #ifdef _WIN32
  7. #include "../../../Plugins/General/gen_ff/wa2frontend.h"
  8. extern HINSTANCE hInstance;
  9. #endif
  10. PopupMenu::PopupMenu()
  11. {
  12. hmenu = NULL;
  13. parent = NULL;
  14. }
  15. PopupMenu::PopupMenu(ifc_window *_parent)
  16. {
  17. hmenu = NULL;
  18. parent = _parent;
  19. }
  20. PopupMenu::PopupMenu(PopupMenu *_parent)
  21. {
  22. hmenu = NULL;
  23. parent = _parent->getParent();
  24. }
  25. PopupMenu::~PopupMenu()
  26. {
  27. invalidateMenu();
  28. entries.deleteAll();
  29. sortedentries.removeAll();
  30. }
  31. void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled)
  32. {
  33. invalidateMenu();
  34. PopupMenuEntry *e = new PopupMenuEntry(text, -1, menu, 0, disabled);
  35. entries.addItem(e);
  36. sortedentries.addItem(e);
  37. }
  38. void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param)
  39. {
  40. invalidateMenu();
  41. PopupMenuEntry *e = new PopupMenuEntry(text, -1, NULL, 0, 0, cb, param);
  42. entries.addItem(e);
  43. sortedentries.addItem(e);
  44. }
  45. void PopupMenu::addCommand(const wchar_t *text, int command, int checked, int disabled, int addpos)
  46. {
  47. invalidateMenu();
  48. PopupMenuEntry *e = new PopupMenuEntry(text, command, NULL, checked, disabled);
  49. entries.addItem(e);
  50. sortedentries.addItem(e, addpos);
  51. }
  52. void PopupMenu::addSeparator(int addpos)
  53. {
  54. invalidateMenu();
  55. PopupMenuEntry *e = new PopupMenuEntry(NULL, -1, NULL, 0, 0);
  56. entries.addItem(e);
  57. sortedentries.addItem(e, addpos);
  58. };
  59. void PopupMenu::checkCommand(int cmd, int check)
  60. {
  61. invalidateMenu();
  62. PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) & cmd);
  63. if (e) e->setChecked(check);
  64. }
  65. void PopupMenu::disableCommand(int cmd, int disable)
  66. {
  67. invalidateMenu();
  68. PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) & cmd);
  69. if (e) e->setDisabled(disable);
  70. }
  71. int PopupMenu::popAtXY(int x, int y, int native)
  72. {
  73. rebuildMenu();
  74. #ifdef _WIN32
  75. if (!native)
  76. return DoTrackPopup(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1;
  77. else
  78. return TrackPopupMenuEx(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd()), NULL) - 1;
  79. #elif defined(__APPLE__)
  80. return PopUpMenuSelect(getOSMenuHandle(), x, y, 0);
  81. #endif
  82. }
  83. int PopupMenu::popAnchored(int type)
  84. { // dropped off the sourceWnd given above
  85. #ifdef _WIN32
  86. int flag = 0;
  87. switch (type)
  88. {
  89. case POPUP_ANCHOR_UL: flag |= TPM_LEFTALIGN | TPM_TOPALIGN; break;
  90. case POPUP_ANCHOR_LL: flag |= TPM_LEFTALIGN | TPM_BOTTOMALIGN; break;
  91. case POPUP_ANCHOR_UR: flag |= TPM_RIGHTALIGN | TPM_TOPALIGN; break;
  92. case POPUP_ANCHOR_LR: flag |= TPM_RIGHTALIGN | TPM_BOTTOMALIGN; break;
  93. }
  94. #endif
  95. rebuildMenu();
  96. int x, y;
  97. Wasabi::Std::getMousePos(&x, &y);
  98. #ifdef _WIN32
  99. return DoTrackPopup(getOSMenuHandle(), flag | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1;
  100. #elif defined(__APPLE__)
  101. return PopUpMenuSelect(getOSMenuHandle(), x, y, 0);
  102. #endif
  103. }
  104. int PopupMenu::popAtMouse()
  105. {
  106. rebuildMenu();
  107. int x, y;
  108. Wasabi::Std::getMousePos(&x, &y);
  109. #ifdef _WIN32
  110. return DoTrackPopup(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1;
  111. #elif defined(__APPLE__)
  112. return PopUpMenuSelect(getOSMenuHandle(), x, y, 0);
  113. #endif
  114. }
  115. int PopupMenu::getNumCommands()
  116. {
  117. return entries.getNumItems();
  118. }
  119. const wchar_t *PopupMenu::getCommandText(int command)
  120. {
  121. PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) &command);
  122. if (e) return e->getText();
  123. return NULL;
  124. }
  125. OSMENUHANDLE PopupMenu::getOSMenuHandle()
  126. {
  127. rebuildMenu();
  128. return hmenu;
  129. }
  130. void PopupMenu::rebuildMenu()
  131. {
  132. #ifdef WIN32
  133. if (hmenu != NULL) return ;
  134. hmenu = CreatePopupMenu();
  135. int i = 0;
  136. foreach(entries)
  137. PopupMenuEntry *e = entries.getfor();
  138. OSMENUHANDLE submenu = NULL;
  139. if (e->getCallback())
  140. {
  141. PopupMenu *m = e->getCallback()->popupMenuCallback(this, e->getCallbackParam());
  142. if (m) submenu = m->getOSMenuHandle();
  143. }
  144. else if (e->isSubmenu())
  145. {
  146. submenu = e->getSubmenu()->getOSMenuHandle();
  147. }
  148. InsertMenuW(hmenu, i++, MF_BYPOSITION | (e->getChecked() ? MF_CHECKED : MF_UNCHECKED) | (e->getDisabled() ? MF_GRAYED : 0) | (e->isSeparator() ? MF_SEPARATOR : (e->isSubmenu() ? MF_POPUP : 0) | (e->getText() ? MF_STRING : 0)), e->isSubmenu() ? (UINT_PTR)submenu : e->getCommand() + 1, e->getText());
  149. endfor;
  150. #else
  151. if (hmenu != NULL) return ;
  152. CreateNewMenu(0, 0, &hmenu);
  153. foreach(entries)
  154. PopupMenuEntry *e = entries.getfor();
  155. OSMENUHANDLE submenu = NULL;
  156. if (e->getCallback())
  157. {
  158. PopupMenu *m = e->getCallback()->popupMenuCallback(this, e->getCallbackParam());
  159. if (m) submenu = m->getOSMenuHandle();
  160. }
  161. else if (e->isSubmenu())
  162. {
  163. submenu = e->getSubmenu()->getOSMenuHandle();
  164. }
  165. const wchar_t *name = e->getText();
  166. CFStringRef menuStr = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)name, wcslen(name)*sizeof(wchar_t), kCFStringEncodingUTF32, false);
  167. MenuItemIndex newMenuItem;
  168. MenuItemAttributes menuAttr = kMenuItemAttrIgnoreMeta;
  169. if (e->getDisabled())
  170. menuAttr|=kMenuItemAttrDisabled;
  171. if (e->isSeparator())
  172. menuAttr|=kMenuItemAttrSeparator;
  173. AppendMenuItemTextWithCFString(hmenu, menuStr, menuAttr, e->getCommand(), &newMenuItem);
  174. if (submenu)
  175. SetMenuItemHierarchicalMenu(hmenu, newMenuItem, submenu);
  176. if (e->getChecked())
  177. CheckMenuItem(hmenu, newMenuItem, true);
  178. CFRelease(menuStr);
  179. endfor;
  180. #endif
  181. }
  182. void PopupMenu::invalidateMenu()
  183. {
  184. #ifdef WIN32
  185. if (hmenu) DestroyMenu(hmenu);
  186. #elif defined(__APPLE__)
  187. if (hmenu) DisposeMenu(hmenu);
  188. #endif
  189. hmenu = NULL;
  190. }
  191. void PopupMenu::abort()
  192. {
  193. #ifdef WIN32
  194. HWND w = (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd());
  195. PostMessage(w, WM_LBUTTONDOWN, 0, 0xdeadc0de);
  196. PostMessage(w, WM_LBUTTONUP, 0, 0xdeadc0de);
  197. #elif defined(__APPLE__)
  198. CancelMenuTracking(hmenu, true, 0);
  199. #endif
  200. }
  201. #else // WASABI_WANT_FF_POPUP
  202. #include <bfc/api/api_wnd.h>
  203. #include <bfc/api/api_syscb.h>
  204. #include "popup.h"
  205. #include <bfc/notifmsg.h>
  206. #include <studio/assert.h>
  207. #include <studio/api.h>
  208. #include <bfc/wasabi_std.h>
  209. #include <common/xlatstr.h>
  210. #include <bfc/wnds/buttwnd.h>
  211. #include <bfc/util/pathparse.h>
  212. #include <bfc/attribs/cfgitem.h>
  213. #include <common/script/c_script/c_guiobject.h>
  214. #include <common/script/c_script/c_menubutton.h>
  215. #include <common/script/scriptguid.h>
  216. #include <common/menusurface.h>
  217. #ifndef WANT_NEW_POPUPMENU
  218. #define SELMARGIN 1
  219. // todo:
  220. // check marks
  221. // more?
  222. PopupMenu::PopupMenu(ifc_window *sourceWnd)
  223. {
  224. ASSERT(sourceWnd != NULL);
  225. setStartHidden(1);
  226. setRenderRatio(1.0);
  227. parentRootWnd = sourceWnd;
  228. parentWnd = sourceWnd->getOsWindowHandle();
  229. reverse_side = 0;
  230. kbdhooked = 0;
  231. keyctrl = 0;
  232. toplevelmenu = 0;
  233. chainmenu = NULL;
  234. lastxy.x = lastxy.y = -1;
  235. WASABI_API_WND->appdeactivation_push_disallow(this);
  236. init(sourceWnd->getOsModuleHandle(), parentWnd, TRUE);
  237. WASABI_API_WND->appdeactivation_pop_disallow(this);
  238. }
  239. PopupMenu::PopupMenu()
  240. {
  241. setStartHidden(1);
  242. setRenderRatio(1.0);
  243. parentRootWnd = NULL;
  244. parentWnd = INVALIDOSWINDOWHANDLE;
  245. chainmenu = NULL;
  246. reverse_side = 0;
  247. kbdhooked = 0;
  248. toplevelmenu = 0;
  249. keyctrl = 0;
  250. lastxy.x = lastxy.y = -1;
  251. WASABI_API_WND->appdeactivation_push_disallow(this);
  252. init(hInstance, WASABI_API_WND->main_getRootWnd()->gethWnd(), TRUE);
  253. WASABI_API_WND->appdeactivation_pop_disallow(this);
  254. }
  255. PopupMenu::PopupMenu(HWND sourceWnd)
  256. {
  257. parentRootWnd = NULL;
  258. parentWnd = sourceWnd;
  259. setStartHidden(1);
  260. setRenderRatio(1.0);
  261. reverse_side = 0;
  262. kbdhooked = 0;
  263. toplevelmenu = 0;
  264. keyctrl = 0;
  265. chainmenu = NULL;
  266. lastxy.x = lastxy.y = -1;
  267. WASABI_API_WND->appdeactivation_push_disallow(this);
  268. init(hInstance, sourceWnd, TRUE);
  269. WASABI_API_WND->appdeactivation_pop_disallow(this);
  270. }
  271. PopupMenu::PopupMenu(PopupMenu *sourceWnd)
  272. {
  273. parentRootWnd = sourceWnd;
  274. parentWnd = sourceWnd->gethWnd();
  275. setStartHidden(1);
  276. setRenderRatio(1.0);
  277. reverse_side = 0;
  278. kbdhooked = 0;
  279. toplevelmenu = 0;
  280. chainmenu = NULL;
  281. keyctrl = 0;
  282. lastxy.x = lastxy.y = -1;
  283. WASABI_API_WND->appdeactivation_push_disallow(this);
  284. init(sourceWnd, TRUE);
  285. WASABI_API_WND->appdeactivation_pop_disallow(this);
  286. }
  287. int PopupMenu::onInit()
  288. {
  289. POPUPMENU_PARENT::onInit();
  290. bdown = 0;
  291. lastitem = -1;
  292. rcp = 0;
  293. openmenuid = -1;
  294. timerset = 0;
  295. timeritem = -1;
  296. rcode = -1;
  297. toplevelmenu = 0;
  298. disable_autopop = 0;
  299. popupdelay = 250; //TODO: Config
  300. #ifdef WASABI_COMPILE_CONFIG
  301. // {9149C445-3C30-4e04-8433-5A518ED0FDDE}
  302. const GUID uioptions_guid =
  303. { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
  304. setTransparency(_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), "Popup menu alpha", 255));
  305. #else
  306. setTransparency(255);
  307. #endif
  308. tex = "wasabi.popup.menu.background";
  309. ful = "wasabi.popup.menu.border.topLeft";
  310. fur = "wasabi.popup.menu.border.topRight";
  311. fll = "wasabi.popup.menu.border.bottomLeft";
  312. flr = "wasabi.popup.menu.border.bottomRight";
  313. fl = "wasabi.popup.menu.border.left";
  314. fr = "wasabi.popup.menu.border.right";
  315. ft = "wasabi.popup.menu.border.top";
  316. fb = "wasabi.popup.menu.border.bottom";
  317. sl = "wasabi.popup.menu.selection.left";
  318. sr = "wasabi.popup.menu.selection.right";
  319. sc = "wasabi.popup.menu.selection.center";
  320. return 1;
  321. }
  322. PopupMenu::~PopupMenu()
  323. {
  324. if (kbdhooked)
  325. {
  326. WASABI_API_WND->unhookKeyboard(this);
  327. kbdhooked = 0;
  328. }
  329. int x, n;
  330. n = items.getNumItems();
  331. for (x = 0; x < n; x ++)
  332. {
  333. if (items[x])
  334. {
  335. if (items[x]->butt) delete items[x]->butt;
  336. if (items[x]->menu) delete items[x]->menu;
  337. delete items[x];
  338. }
  339. }
  340. }
  341. void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled)
  342. {
  343. ASSERT(text != NULL);
  344. ButtonWnd *b = new ButtonWnd();
  345. b->init(this);
  346. b->setParent(this);
  347. b->setNotifyId( -1);
  348. b->setButtonText(translateButtonText(text), 14);
  349. // b->setTextJustification(BUTTONJUSTIFY_LEFT);
  350. b->setTextAlign(TEXTALIGN_LEFT);
  351. b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
  352. if (disabled) b->enableButton(FALSE);
  353. ItemT *t = new ItemT;
  354. t->issep = 0;
  355. t->butt = b;
  356. t->menu = menu;
  357. t->cmd = -1;
  358. t->cb = NULL;
  359. items.addItem(t);
  360. }
  361. void PopupMenu::addSubMenuImage(PopupMenu *menu, const char *bitmap, const char *pushedbitmap, const char *highlightbitmap)
  362. {
  363. ButtonWnd *b = new ButtonWnd();
  364. b->init(this);
  365. b->setParent(this);
  366. b->setBitmaps(bitmap, pushedbitmap, highlightbitmap);
  367. b->setBitmapCenter(1);
  368. b->setNotifyId( -1);
  369. b->setAutoDim(1);
  370. b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
  371. ItemT *t = new ItemT;
  372. t->issep = 0;
  373. t->butt = b;
  374. t->menu = menu;
  375. t->cb = NULL;
  376. t->cmd = -1;
  377. items.addItem(t);
  378. }
  379. void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param)
  380. {
  381. ASSERT(text != NULL);
  382. ASSERT(cb != NULL);
  383. ButtonWnd *b = new ButtonWnd();
  384. b->init(this);
  385. b->setParent(this);
  386. b->setNotifyId( -1);
  387. b->setButtonText(translateButtonText(text), 14);
  388. // b->setTextJustification(BUTTONJUSTIFY_LEFT);
  389. b->setTextAlign(TEXTALIGN_LEFT);
  390. b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
  391. ItemT *t = new ItemT;
  392. t->issep = 0;
  393. t->butt = b;
  394. t->menu = 0;
  395. t->cb = cb;
  396. t->cbparam = param;
  397. t->cmd = -1;
  398. items.addItem(t);
  399. }
  400. void PopupMenu::addSeparator(int addpos)
  401. {
  402. ButtonWnd *b = new ButtonWnd();
  403. b->init(this);
  404. b->setParent(this);
  405. b->setNotifyId( -1);
  406. b->setBitmaps("wasabi.popup.menu.seperator");
  407. b->setBitmapCenter(0);
  408. b->enableButton(0);
  409. b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
  410. ItemT *t = new ItemT;
  411. t->issep = 1;
  412. t->butt = b;
  413. t->menu = 0;
  414. t->cb = NULL;
  415. t->cmd = -1;
  416. items.addItem(t, addpos);
  417. }
  418. void PopupMenu::addCommandImage(const char *bitmap, const char *pushedbitmap, const char *highlightbitmap, int command, int checked, int disabled, int addpos)
  419. {
  420. ButtonWnd *b = new ButtonWnd();
  421. b->init(this);
  422. b->setParent(this);
  423. b->setBitmaps(bitmap, pushedbitmap, highlightbitmap);
  424. b->setBitmapCenter(1);
  425. b->setNotifyId(command);
  426. b->enableButton(disabled ? 0 : 1);
  427. b->setChecked(checked ? 1 : 0);
  428. b->setAutoDim(1);
  429. b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
  430. ItemT *t = new ItemT;
  431. t->issep = 0;
  432. t->butt = b;
  433. t->menu = 0;
  434. t->cb = NULL;
  435. t->cmd = -1;
  436. items.addItem(t);
  437. }
  438. void PopupMenu::addCommand(const wchar_t *_txt, int command, int checked, int disabled, int addpos)
  439. {
  440. if (!_txt)
  441. {
  442. addSeparator();
  443. return ;
  444. }
  445. String txt = translateButtonText(_txt);
  446. ButtonWnd *b = new ButtonWnd();
  447. b->init(this);
  448. b->setParent(this);
  449. b->setNotifyId(disabled ? -1 : command);
  450. #ifdef WASABI_COMPILE_LOCALES
  451. const wchar_t *bind = (command != 0) ? WASABI_API_LOCALE->locales_getBindFromAction(command) : NULL;
  452. if (bind) txt += StringPrintfW(L"\t%s", bind);
  453. #endif
  454. b->setButtonText(txt);
  455. // b->setTextJustification(BUTTONJUSTIFY_LEFT);
  456. b->setTextAlign(TEXTALIGN_LEFT);
  457. b->enableButton(disabled ? 0 : 1);
  458. b->setChecked(checked);
  459. if (checked == 2) b->setAlpha(128);
  460. b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText");
  461. ItemT *t = new ItemT;
  462. t->issep = 0;
  463. t->butt = b;
  464. t->menu = 0;
  465. t->cmd = command;
  466. t->cb = NULL;
  467. ASSERT(PTRLIST_POS_LAST == -1); //BU
  468. items.addItem(t, addpos);
  469. }
  470. void PopupMenu::disableCommand(int cmd, int disable)
  471. {
  472. for (int i = 0;i < items.getNumItems();i++)
  473. if (items.enumItem(i)->cmd == cmd)
  474. {
  475. if (items.enumItem(i)->butt)
  476. items.enumItem(i)->butt->enableButton(!!!disable);
  477. break;
  478. }
  479. }
  480. void PopupMenu::checkCommand(int cmd, int check)
  481. {
  482. for (int i = 0;i < items.getNumItems();i++)
  483. if (items.enumItem(i)->cmd == cmd)
  484. {
  485. if (items.enumItem(i)->butt)
  486. items.enumItem(i)->butt->setChecked(check);
  487. break;
  488. }
  489. }
  490. const wchar_t *PopupMenu::getCommandText(int command)
  491. {
  492. for (int i = 0;i < items.getNumItems();i++)
  493. if (items.enumItem(i)->cmd == command && items.enumItem(i)->butt)
  494. return items.enumItem(i)->butt->getName();
  495. return NULL;
  496. }
  497. int PopupMenu::popAtXY(int x, int y)
  498. {
  499. toplevelmenu = 1;
  500. rcode = -1;
  501. if (items.getNumItems())
  502. {
  503. POINT pt = {x, y};
  504. #ifdef WIN32
  505. HWND oldcw = GetCapture(); // nonportable
  506. ifc_window *oldcrw = (ifc_window*)GetWindowLong(oldcw, GWL_USERDATA);
  507. if (oldcrw != NULL) oldcrw->cancelCapture();
  508. #endif
  509. WASABI_API_SYSCB->syscb_registerCallback(static_cast<SkinCallbackI*>(this));
  510. showAtXY(x, y, &rcode);
  511. beginCapture();
  512. MSG msg;
  513. #ifdef WIN32
  514. SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE
  515. #endif
  516. while (rcode == -1 && GetMessage( &msg, INVALIDOSWINDOWHANDLE, 0, 0 ))
  517. {
  518. TranslateMessage(&msg);
  519. DispatchMessage(&msg);
  520. }
  521. endCapture();
  522. hide();
  523. // if (hadcapture && under) under->beginCapture();
  524. #ifdef WIN32
  525. if (rcode == -2 || rcode == -3)
  526. {
  527. DWORD p = GetMessagePos();
  528. POINT pt;
  529. pt.x = (signed short)LOWORD(p);
  530. pt.y = (signed short)HIWORD(p);
  531. HWND w = WindowFromPoint(pt);
  532. ScreenToClient(w, &pt);
  533. p = (pt.x & 0xFFFF) | (pt.y << 16);
  534. //if (under) under->getRootParent()->wndProc(under->getRootParent()->gethWnd(), WM_MOUSEMOVE, 0, p);
  535. //PostMessage(w, (rcode == -2) ? WM_MOUSEMOVE : WM_RBUTTONDOWN, 0, p);
  536. //PostMessage(w, (rcode == -2) ? WM_LBUTTONDOWN : WM_RBUTTONDOWN, 0, p);
  537. }
  538. #else
  539. DebugString("portme: popup.cpp pass on click");
  540. #endif
  541. }
  542. WASABI_API_SYSCB->syscb_deregisterCallback(static_cast<SkinCallbackI*>(this));
  543. //DebugString("appdeactivation_pop_disallow\n");
  544. WASABI_API_WND->appdeactivation_pop_disallow(this);
  545. onPostPop(rcode);
  546. #ifdef WASABI_COMPILE_SKIN
  547. if (!switchskinto.isempty())
  548. {
  549. WASABI_API_SKIN->skin_switchSkin(switchskinto.getNonConstVal());
  550. switchskinto = "";
  551. }
  552. #endif
  553. return rcode;
  554. }
  555. void PopupMenu::showAtXY(int x, int y, int *rc, int revside, int parentW)
  556. {
  557. int i, n;
  558. int w = 0, h = 0;
  559. lastitem = -1;
  560. rcp = rc;
  561. n = items.getNumItems();
  562. for (i = 0; i < n; i ++)
  563. {
  564. if (items[i]->menu || items[i]->cb)
  565. items[i]->butt->setRightBitmap("wasabi.popup.menu.submenu");
  566. if (!items[i]->butt->getChecked()) items[i]->butt->setChecked( -1);
  567. h += items[i]->butt->getHeight();
  568. items[i]->butt->setUseBaseTexture(0);
  569. items[i]->butt->setBorders(0);
  570. int tw = items[i]->butt->getWidth();
  571. if (w < tw)w = tw;
  572. }
  573. int neww = w + 6 + fl.getWidth() + fr.getWidth();
  574. int newh = h + 6 + ft.getHeight() + fb.getHeight();
  575. POINT p = {x, y};
  576. RECT vp;
  577. Std::getViewport(&vp, &p);
  578. // maintain parent's reversal state
  579. reverse_side = revside;
  580. int savx = x;
  581. if (reverse_side) x -= (neww + parentW);
  582. if (x + neww > vp.right || x < 0)
  583. {
  584. reverse_side = !reverse_side;
  585. x = savx;
  586. if (reverse_side) x -= (neww + parentW);
  587. }
  588. if (y + newh > vp.bottom) y -= newh;
  589. if (x < vp.left) x = vp.left;
  590. if (y < vp.top) y = vp.top;
  591. resize(x, y, neww, newh);
  592. h = 0;
  593. for (i = 0; i < n; i ++)
  594. {
  595. int lh = h;
  596. h += items[i]->butt->getHeight();
  597. items[i]->butt->resize(3 + fl.getWidth(), 3 + lh + ft.getHeight(), w, h - lh);
  598. items[i]->butt->setHilite(0);
  599. items[i]->butt->setPushed(0);
  600. }
  601. WASABI_API_WND->appdeactivation_push_disallow(this);
  602. #ifdef WIN32
  603. SetWindowPos(gethWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  604. #elif defined(LINUX)
  605. Atom NET_STATE = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE", True );
  606. Atom state[2];
  607. state[0] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", True );
  608. state[1] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_ABOVE", True );
  609. if ( NET_STATE && state[0] && state[1] )
  610. {
  611. XChangeProperty( Linux::getDisplay(), gethWnd(), NET_STATE, XA_ATOM, 32,
  612. PropModeReplace, (unsigned char *)state, 2 );
  613. }
  614. #endif
  615. WASABI_API_WND->appdeactivation_pop_disallow(this);
  616. setVisible(1);
  617. }
  618. void PopupMenu::onSetVisible(int v)
  619. {
  620. POPUPMENU_PARENT::onSetVisible(v);
  621. if (v && !kbdhooked)
  622. {
  623. WASABI_API_WND->hookKeyboard(this);
  624. kbdhooked = 1;
  625. }
  626. else if (!v && kbdhooked)
  627. {
  628. WASABI_API_WND->unhookKeyboard(this);
  629. kbdhooked = 0;
  630. }
  631. }
  632. void PopupMenu::hide()
  633. {
  634. if (lastitem >= 0 && items[lastitem]->menu)
  635. {
  636. items[lastitem]->menu->hide();
  637. lastitem = -1;
  638. }
  639. setVisible(0);
  640. }
  641. int PopupMenu::popAnchored(int type)
  642. {
  643. RECT wr;
  644. if (parentRootWnd != NULL)
  645. {
  646. parentRootWnd->getWindowRect(&wr);
  647. }
  648. else if (parentWnd != INVALIDOSWINDOWHANDLE)
  649. {
  650. #ifdef WIN32
  651. GetWindowRect(parentWnd, &wr);
  652. #else
  653. DebugString("portme PopupMenu::popAnchored\n");
  654. #endif
  655. }
  656. else
  657. {
  658. ASSERTALWAYS("can't call popAnchored without instantiating with a parent window");
  659. }
  660. switch (type)
  661. {
  662. case POPUP_ANCHOR_UL: return popAtXY(wr.left, wr.top);
  663. case POPUP_ANCHOR_LL: return popAtXY(wr.left, wr.bottom);
  664. case POPUP_ANCHOR_UR: return popAtXY(wr.right, wr.top);
  665. case POPUP_ANCHOR_LR: return popAtXY(wr.right, wr.bottom);
  666. }
  667. return 0;
  668. }
  669. int PopupMenu::popAtMouse()
  670. {
  671. int x, y;
  672. Std::getMousePos(&x, &y);
  673. return popAtXY(x, y);
  674. }
  675. int PopupMenu::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2)
  676. {
  677. if (msg == ChildNotify::BUTTON_LEFTPUSH || msg == ChildNotify::BUTTON_RIGHTPUSH)
  678. {
  679. for (int i = 0;i < items.getNumItems();i++)
  680. {
  681. if (child == items[i]->butt && (items[i]->menu || items[i]->cb))
  682. {
  683. if (!items[i]->butt->getEnabled()) continue;
  684. if (items[i]->cb) initMenuCallback(i);
  685. if (!items[i]->menu) continue;
  686. if (openmenuid == i) continue;
  687. RECT r;
  688. if (openmenuid >= 0)
  689. {
  690. items[openmenuid]->menu->hide();
  691. openmenuid = -1;
  692. }
  693. items[i]->butt->getWindowRect(&r);
  694. PopupMenu *p = items[i]->menu;
  695. p->showAtXY(r.right, r.top, rcp, reverse_side, r.right - r.left);
  696. if (p1)
  697. {
  698. p->selectFirst();
  699. }
  700. openmenuid = i;
  701. }
  702. }
  703. // mig: changed this to call getNotifyId();
  704. // *rcp=p1;
  705. *rcp = child->getNotifyId();
  706. return 0;
  707. }
  708. if (msg == ChildNotify::POPUP_SUBMENUCLOSE)
  709. {
  710. for (int i = 0;i < items.getNumItems();i++)
  711. {
  712. if (child == items[i]->menu)
  713. {
  714. if (openmenuid != i) continue;
  715. items[openmenuid]->menu->hide();
  716. openmenuid = -1;
  717. return 0;
  718. }
  719. }
  720. }
  721. return POPUPMENU_PARENT::childNotify(child, msg, p1, p2);
  722. }
  723. void PopupMenu::selectFirst()
  724. {
  725. ButtonWnd *b = NULL;
  726. int i;
  727. for (i = 0; i < items.getNumItems(); i++)
  728. {
  729. b = items.enumItem(i)->butt;
  730. if (b != NULL) break;
  731. }
  732. if (b == NULL) return ;
  733. lastitem = i;
  734. b->setHilite(1);
  735. invalidate();
  736. }
  737. int PopupMenu::getWhichItem(POINT &p)
  738. {
  739. int x, n;
  740. RECT r2;
  741. getWindowRect(&r2);
  742. n = items.getNumItems();
  743. for (x = 0; x < n; x ++)
  744. {
  745. RECT r;
  746. items[x]->butt->getWindowRect(&r);
  747. r.right = r2.right;
  748. r.left = r2.left;
  749. if (Std::pointInRect(r, p))
  750. {
  751. return x;
  752. }
  753. }
  754. return -1;
  755. }
  756. int PopupMenu::isMine(int x, int y)
  757. {
  758. RECT r;
  759. getWindowRect(&r);
  760. POINT p = {x, y};
  761. if (Std::pointInRect(r, p)) return 1;
  762. if (lastitem >= 0 && items[lastitem]->menu && items[lastitem]->menu->isMine(x, y)) return 1;
  763. return 0;
  764. }
  765. void PopupMenu::setFriendlyId(const char *id)
  766. {
  767. friendid = id;
  768. }
  769. int PopupMenu::onLeftButtonDown(int x, int y)
  770. {
  771. clientToScreen(&x, &y);
  772. onButtonDown(1, x, y);
  773. return 0;
  774. }
  775. int PopupMenu::onRightButtonDown(int x, int y)
  776. {
  777. clientToScreen(&x, &y);
  778. onButtonDown(2, x, y);
  779. return 0;
  780. }
  781. int PopupMenu::onMouseMove(int x, int y)
  782. {
  783. POPUPMENU_PARENT::onMouseMove(x, y);
  784. POINT pnt = {x, y};
  785. clientToScreen(&pnt);
  786. if (keyctrl && lastxy.x == pnt.x && lastxy.y == pnt.y) return 1;
  787. keyctrl = 0;
  788. lastxy = pnt;
  789. if (lastitem >= 0)
  790. {
  791. if (openmenuid >= 0 && items[openmenuid]->menu && items[openmenuid]->menu->isMine(pnt.x, pnt.y))
  792. {
  793. if (lastitem != openmenuid)
  794. {
  795. items[lastitem]->butt->setHilite(0);
  796. items[lastitem]->butt->setPushed(0);
  797. items[openmenuid]->butt->setHilite(1);
  798. items[openmenuid]->butt->setPushed(1);
  799. invalidateItem(lastitem);
  800. lastitem = openmenuid;
  801. invalidateItem(lastitem);
  802. }
  803. resetTimer( -1);
  804. items[openmenuid]->menu->screenToClient(&pnt);
  805. items[openmenuid]->menu->onMouseMove(pnt.x, pnt.y);
  806. return 0;
  807. }
  808. }
  809. int p = getWhichItem(pnt);
  810. if (p >= 0)
  811. {
  812. ItemT *it = items[p];
  813. if (!it->issep)
  814. {
  815. if (p != lastitem)
  816. {
  817. if (lastitem >= 0)
  818. {
  819. /* if (items[lastitem]->menu)
  820. {
  821. items[lastitem]->menu->hide();
  822. }*/
  823. items[lastitem]->butt->setHilite(0);
  824. items[lastitem]->butt->setPushed(0);
  825. invalidateItem(lastitem);
  826. }
  827. invalidateItem(lastitem);
  828. lastitem = p;
  829. invalidateItem(lastitem);
  830. items[p]->butt->setHilite(1);
  831. if (bdown) items[p]->butt->setPushed(1);
  832. /* if (items[p]->menu) {
  833. RECT r;
  834. items[p]->butt->getWindowRect(&r);
  835. items[p]->menu->showAtXY(r.right,r.top,rcp);
  836. }*/
  837. resetTimer(p);
  838. invalidateItem(lastitem);
  839. }
  840. }
  841. else
  842. {
  843. RECT _r;
  844. getClientRect(&_r);
  845. int inside = (x >= 0 && y >= 0 && x <= _r.right - _r.left && y <= _r.bottom - _r.top);
  846. if (lastitem >= 0 && !inside)
  847. {
  848. items[lastitem]->butt->setHilite(0);
  849. items[lastitem]->butt->setPushed(0);
  850. invalidateItem(lastitem);
  851. lastitem = -1;
  852. }
  853. }
  854. }
  855. else
  856. {
  857. if (!friendid.isempty())
  858. {
  859. ifc_window *w = WASABI_API_WND->rootWndFromPoint(&pnt);
  860. if (w != NULL)
  861. {
  862. MenuButtonSurface *s = static_cast<MenuButtonSurface *>(w->getInterface(menuButtonSurfaceGuid));
  863. if (s != NULL)
  864. {
  865. if (s->getParentWnd() != parentRootWnd)
  866. {
  867. const char *str = s->getParentMenuId();
  868. if (STRCASEEQLSAFE(str, friendid))
  869. {
  870. abort();
  871. rcode = -4;
  872. chainmenu = s;
  873. }
  874. }
  875. }
  876. }
  877. }
  878. }
  879. return 0;
  880. }
  881. void PopupMenu::resetTimer(int p)
  882. {
  883. if (timerset)
  884. {
  885. killTimer(POPUP_TIMERID);
  886. timeritem = -1;
  887. }
  888. if (p >= 0 && !disable_autopop)
  889. {
  890. setTimer(POPUP_TIMERID, popupdelay);
  891. timeritem = p;
  892. timerset = 1;
  893. }
  894. }
  895. void PopupMenu::timerCallback(int id)
  896. {
  897. switch (id)
  898. {
  899. case POPUP_TIMERID:
  900. killTimer(POPUP_TIMERID);
  901. timerset = 0;
  902. if (timeritem == openmenuid)
  903. {
  904. timeritem = -1;
  905. break;
  906. }
  907. if (openmenuid >= 0 && items[openmenuid]->menu)
  908. {
  909. items[openmenuid]->menu->hide();
  910. openmenuid = -1;
  911. }
  912. if (timeritem >= 0)
  913. {
  914. if (items[timeritem]->cb) initMenuCallback(timeritem);
  915. if (items[timeritem]->butt->getEnabled() && items[timeritem]->menu)
  916. {
  917. RECT r;
  918. items[timeritem]->butt->getWindowRect(&r);
  919. items[timeritem]->menu->showAtXY(r.right, r.top, rcp, reverse_side, r.right - r.left);
  920. openmenuid = timeritem;
  921. }
  922. timeritem = -1;
  923. }
  924. break;
  925. default:
  926. POPUPMENU_PARENT::timerCallback(id);
  927. break;
  928. }
  929. }
  930. void PopupMenu::initMenuCallback(int item)
  931. {
  932. int a = rcode;
  933. rcode = 0;
  934. PopupMenu *p = items[item]->cb->popupMenuCallback(this, items[item]->cbparam);
  935. rcode = a;
  936. if (p)
  937. {
  938. items[item]->cb = NULL;
  939. items[item]->menu = p;
  940. }
  941. }
  942. int PopupMenu::onLeftButtonUp(int x, int y)
  943. {
  944. clientToScreen(&x, &y);
  945. onButtonUp(1, x, y);
  946. return 0;
  947. }
  948. int PopupMenu::onRightButtonUp(int x, int y)
  949. {
  950. clientToScreen(&x, &y);
  951. onButtonUp(2, x, y);
  952. return 0;
  953. }
  954. void PopupMenu::onButtonDown(int wb, int x, int y)
  955. {
  956. POINT pos = {x, y};
  957. RECT r;
  958. bdown |= wb;
  959. if (lastitem >= 0)
  960. {
  961. if (items[lastitem]->menu && items[lastitem]->menu->isMine(pos.x, pos.y))
  962. {
  963. items[lastitem]->menu->onButtonDown(wb, x, y);
  964. return ;
  965. }
  966. }
  967. getWindowRect(&r);
  968. if (!Std::pointInRect(r, pos))
  969. {
  970. rcode = (wb == 1) ? -2 : -3;
  971. }
  972. else
  973. {
  974. int item = getWhichItem(pos);
  975. if (item >= 0) items[item]->butt->setPushed(1);
  976. }
  977. }
  978. void PopupMenu::onButtonUp(int wb, int x, int y)
  979. {
  980. if (lastitem >= 0)
  981. {
  982. POINT pos = {x, y};
  983. if (items[lastitem]->menu && items[lastitem]->menu->isMine(pos.x, pos.y))
  984. {
  985. items[lastitem]->menu->onButtonUp(wb, x, y);
  986. return ;
  987. }
  988. }
  989. if (bdown & wb)
  990. {
  991. bdown &= ~wb;
  992. POINT pnt = {x, y};
  993. int p = getWhichItem(pnt);
  994. if (p >= 0)
  995. {
  996. items[p]->butt->onLeftPush(x, y);
  997. if (!bdown)
  998. {
  999. items[p]->butt->setPushed(0);
  1000. }
  1001. }
  1002. }
  1003. }
  1004. int PopupMenu::onKillFocus()
  1005. {
  1006. #ifndef LINUX
  1007. if (rcode == -1) rcode = -2;
  1008. #endif
  1009. return POPUPMENU_PARENT::onKillFocus();
  1010. }
  1011. // only translates the text, not the optional accelerator
  1012. String PopupMenu::translateButtonText(const wchar_t *text)
  1013. {
  1014. PathParser pp(text, "\t");
  1015. String ret;
  1016. for (int i = 0; i < pp.getNumStrings(); i++)
  1017. {
  1018. if (i == 0) ret += _(pp.enumString(i)); // translate first
  1019. else ret += pp.enumString(i);
  1020. if (i != pp.getNumStrings() - 1) ret += "\t";
  1021. }
  1022. return ret;
  1023. }
  1024. int PopupMenu::onPaint(Canvas *canvas)
  1025. {
  1026. PaintBltCanvas paintcanvas;
  1027. if (canvas == NULL)
  1028. {
  1029. if (!paintcanvas.beginPaint(this)) return 0;
  1030. canvas = &paintcanvas;
  1031. }
  1032. POPUPMENU_PARENT::onPaint(canvas);
  1033. RECT r, r2;
  1034. getClientRect(&r);
  1035. tex.getBitmap()->blitTile(canvas, &r);
  1036. // left side
  1037. ful.getBitmap()->blitAlpha(canvas, 0, 0);
  1038. r2.left = 0;
  1039. r2.right = fl.getWidth();
  1040. r2.top = ful.getHeight();
  1041. r2.bottom = r.bottom - fll.getHeight();
  1042. fl.getBitmap()->stretchToRectAlpha(canvas, &r2);
  1043. fll.getBitmap()->blitAlpha(canvas, 0, r.bottom - fll.getHeight());
  1044. // right side
  1045. fur.getBitmap()->blitAlpha(canvas, r.right - fur.getWidth(), 0);
  1046. r2.left = r.right - fr.getWidth();
  1047. r2.right = r.right;
  1048. r2.top = fur.getHeight();
  1049. r2.bottom = r.bottom - flr.getHeight();
  1050. fr.getBitmap()->stretchToRectAlpha(canvas, &r2);
  1051. flr.getBitmap()->blitAlpha(canvas, r.right - flr.getWidth(), r.bottom - flr.getHeight());
  1052. // top
  1053. r2.left = ful.getWidth();
  1054. r2.right = r.right - fur.getWidth();
  1055. r2.top = 0;
  1056. r2.bottom = ft.getHeight();
  1057. ft.getBitmap()->stretchToRectAlpha(canvas, &r2);
  1058. // bottom
  1059. r2.left = fll.getWidth();
  1060. r2.right = r.right - flr.getWidth();
  1061. r2.top = r.bottom - fb.getHeight();
  1062. r2.bottom = r.bottom;
  1063. fb.getBitmap()->stretchToRectAlpha(canvas, &r2);
  1064. // selection bar
  1065. if (lastitem != -1)
  1066. {
  1067. ItemT *it = items[lastitem];
  1068. RECT r3, c;
  1069. it->butt->getClientRect(&r3);
  1070. // left
  1071. r2.left = r.left + fl.getWidth() + SELMARGIN;
  1072. r2.top = r.top + r3.top;
  1073. r2.right = r2.left + sl.getWidth();
  1074. r2.bottom = r2.top + (r3.bottom - r3.top);
  1075. sl.getBitmap()->stretchToRectAlpha(canvas, &r2);
  1076. c = r2;
  1077. c.left = c.right - 1;
  1078. // right
  1079. r2.right = r.right - fr.getWidth() - SELMARGIN;
  1080. r2.left = r2.right - sr.getWidth();
  1081. sr.getBitmap()->stretchToRectAlpha(canvas, &r2);
  1082. c.right = r2.left;
  1083. // center
  1084. sc.getBitmap()->stretchToRectAlpha(canvas, &c);
  1085. }
  1086. return 1;
  1087. }
  1088. void PopupMenu::invalidateItem(int i)
  1089. {
  1090. if (i < 0 || i >= items.getNumItems()) return ;
  1091. RECT r, r2, r3;
  1092. getClientRect(&r);
  1093. ItemT *it = items[i];
  1094. it->butt->getClientRect(&r3);
  1095. r2.left = r.left + fl.getWidth();
  1096. r2.top = r.top + r3.top;
  1097. r2.right = r.right - fl.getWidth();
  1098. r2.bottom = r2.top + (r3.bottom - r3.top);
  1099. invalidateRect(&r2);
  1100. }
  1101. int PopupMenu::getNumCommands()
  1102. {
  1103. return items.getNumItems();
  1104. }
  1105. #ifdef WASABI_COMPILE_SKIN
  1106. int PopupMenu::skincb_onCheckPreventSwitch(const char *skinname)
  1107. {
  1108. switchskinto = skinname;
  1109. rcode = -2;
  1110. return 1;
  1111. }
  1112. #endif
  1113. int PopupMenu::onSysKeyDown(int code, int d)
  1114. {
  1115. int a = POPUPMENU_PARENT::onSysKeyDown(code, d);
  1116. /* if (d & (1<<29)) {
  1117. //ALT key pressed, abort menu (mimics win32 popup behavior)
  1118. abort();
  1119. if(getParent()) SendMessageW(getParent()->gethWnd(),WM_SYSKEYDOWN,code,d);
  1120. return 0;
  1121. }*/
  1122. if (a == 0)
  1123. return onKeyDown(code);
  1124. return 0;
  1125. }
  1126. int PopupMenu::onKeyDown(int code)
  1127. {
  1128. if (POPUPMENU_PARENT::onKeyDown(code)) return 1;
  1129. switch (code)
  1130. {
  1131. case STDKEY_DOWN:
  1132. navigate(1);
  1133. return 1;
  1134. case STDKEY_UP:
  1135. navigate( -1);
  1136. return 1;
  1137. case STDKEY_RETURN:
  1138. navigate(0, 1);
  1139. return 1;
  1140. case STDKEY_RIGHT:
  1141. navigate(0, 0);
  1142. return 1;
  1143. case VK_LEFT:
  1144. if (!toplevelmenu)
  1145. notifyParent(ChildNotify::POPUP_SUBMENUCLOSE);
  1146. return 1;
  1147. case VK_ESCAPE:
  1148. abort();
  1149. return 1;
  1150. }
  1151. return 0;
  1152. }
  1153. void PopupMenu::abort()
  1154. {
  1155. if (toplevelmenu)
  1156. rcode = -2;
  1157. else
  1158. notifyParent(ChildNotify::POPUP_SUBMENUCLOSE);
  1159. }
  1160. void PopupMenu::navigate(int p, int f)
  1161. {
  1162. keyctrl = 1;
  1163. int i = lastitem;
  1164. ItemT *t = NULL;
  1165. if (p == 0)
  1166. {
  1167. if (lastitem >= 0)
  1168. {
  1169. ItemT *t = items.enumItem(lastitem);
  1170. if (f || t->menu || t->cb)
  1171. {
  1172. t->butt->setHilite(1);
  1173. t->butt->setPushed(1);
  1174. childNotify(t->butt, ChildNotify::BUTTON_LEFTPUSH, 1, 0);
  1175. }
  1176. }
  1177. return ;
  1178. }
  1179. while (!t || t->issep)
  1180. {
  1181. i += p;
  1182. i %= items.getNumItems();
  1183. if (i == -1) i = items.getNumItems() - 1;
  1184. if (i >= items.getNumItems()) return ;
  1185. t = items.enumItem(i);
  1186. }
  1187. if (t->butt)
  1188. {
  1189. int i;
  1190. i = items.searchItem(t);
  1191. t->butt->setHilite(1);
  1192. if (lastitem != -1)
  1193. {
  1194. ItemT *s = items.enumItem(lastitem);
  1195. if (s->butt)
  1196. {
  1197. s->butt->setPushed(0);
  1198. s->butt->setHilite(0);
  1199. }
  1200. }
  1201. lastitem = i;
  1202. invalidate();
  1203. }
  1204. }
  1205. #else
  1206. //------------------------------------------------------------------------------------------------------------------------------------------
  1207. //------------------------------------------------------------------------------------------------------------------------------------------
  1208. //------------------------------------------------------------------------------------------------------------------------------------------
  1209. // 3rd level popup menu, yay
  1210. #include "script/c_script/c_text.h"
  1211. #include "script/c_script/c_rootobj.h"
  1212. #include "script/c_script/c_button.h"
  1213. #include "script/c_script/c_group.h"
  1214. PopupMenu::PopupMenu(ifc_window *sourceWnd)
  1215. {
  1216. ASSERT(sourceWnd != NULL);
  1217. myInit();
  1218. setParent(sourceWnd);
  1219. sourceWnd->setAllowDeactivation(0);
  1220. init(HINSTANCEfromHWND(getParent()->gethWnd()), sourceWnd->gethWnd(), TRUE);
  1221. sourceWnd->setAllowDeactivation(1);
  1222. }
  1223. PopupMenu::PopupMenu()
  1224. {
  1225. myInit();
  1226. setParent(WASABI_API_WND->main_getRootWnd());
  1227. WASABI_API_WND->main_getRootWnd()->setAllowDeactivation(0);
  1228. init(hInstance, WASABI_API_WND->main_getRootWnd()->gethWnd(), TRUE);
  1229. WASABI_API_WND->main_getRootWnd()->setAllowDeactivation(1);
  1230. }
  1231. PopupMenu::PopupMenu(PopupMenu *sourceWnd)
  1232. {
  1233. myInit();
  1234. setParent(sourceWnd);
  1235. sourceWnd->setAllowDeactivation(0);
  1236. init(GetModuleHandle(NULL), sourceWnd->gethWnd(), TRUE);
  1237. sourceWnd->setAllowDeactivation(1);
  1238. }
  1239. void PopupMenu::myInit()
  1240. {
  1241. setVirtual(0);
  1242. setStartHidden(1);
  1243. setRenderRatio(1.0);
  1244. reverse_side = 0;
  1245. rcode = 0;
  1246. submenus = 0;
  1247. c_grouplist = NULL;
  1248. WASABI_API_WND->popupexit_register(this, this);
  1249. }
  1250. PopupMenu::~PopupMenu()
  1251. {
  1252. WASABI_API_WND->popupexit_deregister(this);
  1253. delete c_grouplist;
  1254. }
  1255. int PopupMenu::onInit()
  1256. {
  1257. POPUPMENU_PARENT::onInit();
  1258. #ifdef WASABI_COMPILE_CONFIG
  1259. // {9149C445-3C30-4e04-8433-5A518ED0FDDE}
  1260. const GUID uioptions_guid =
  1261. { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } };
  1262. setTransparency(_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), "Popup menu alpha", 255));
  1263. #else
  1264. setTransparency(255);
  1265. #endif
  1266. setContent("wasabi.popup.main.group");
  1267. return 1;
  1268. }
  1269. int PopupMenu::popAtXY(int x, int y)
  1270. {
  1271. rcode = -1;
  1272. if (1 /*items.getNumItems()*/)
  1273. {
  1274. POINT pt = {x, y};
  1275. //DebugString("appdeactivation_push_disallow\n");
  1276. WASABI_API_WND->appdeactivation_push_disallow(this);
  1277. showAtXY(x, y, &rcode);
  1278. //MSG msg;
  1279. /*while (rcode == -1 && GetMessage( &msg, NULL, 0, 0 )) {
  1280. TranslateMessage(&msg);
  1281. DispatchMessage(&msg);
  1282. }*/
  1283. SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE
  1284. int quit = 0;
  1285. while (!quit)
  1286. {
  1287. rcode = getGuiObject()->guiobject_runModal();
  1288. if (rcode & 0x40000000 && rcode != -2 && rcode != -1)
  1289. {
  1290. int submenuentry = rcode & ~0x40000000;
  1291. ItemT *t = items.enumItem(submenuentry);
  1292. if (t->cb != NULL)
  1293. initMenuCallback(submenuentry);
  1294. if (t->menu != NULL)
  1295. {
  1296. setAllowDeactivation(0);
  1297. t->menu->showAtXY(0, 0, NULL, 0, 0);
  1298. setAllowDeactivation(1);
  1299. }
  1300. }
  1301. else
  1302. quit = 1;
  1303. }
  1304. setVisible(0);
  1305. }
  1306. //DebugString("appdeactivation_pop_disallow\n");
  1307. WASABI_API_WND->appdeactivation_pop_disallow(this);
  1308. onPostPop(rcode);
  1309. return rcode;
  1310. }
  1311. void PopupMenu::showAtXY(int x, int y, int *rc, int revside /* =0 */, int parentW /* =0 */)
  1312. {
  1313. fillContent();
  1314. int neww = getPreferences(SUGGESTED_W);
  1315. int newh = getPreferences(SUGGESTED_H);;
  1316. POINT p = {x, y};
  1317. RECT vp;
  1318. Std::getViewport(&vp, &p);
  1319. // maintain parent's reversal state
  1320. reverse_side = revside;
  1321. int savx = x;
  1322. if (reverse_side) x -= (neww + parentW);
  1323. if (x + neww > vp.right || x < 0)
  1324. {
  1325. reverse_side = !reverse_side;
  1326. x = savx;
  1327. if (reverse_side) x -= (neww + parentW);
  1328. }
  1329. if (y + newh > vp.bottom) y -= newh;
  1330. if (x < vp.left) x = vp.left;
  1331. if (y < vp.top) y = vp.top;
  1332. resize(x, y, neww, newh);
  1333. WASABI_API_WND->appdeactivation_push_disallow(this);
  1334. #ifdef WIN32
  1335. SetWindowPos(gethWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1336. #else
  1337. Atom NET_STATE = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE", True );
  1338. Atom state[2];
  1339. state[0] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", True );
  1340. state[1] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_ABOVE", True );
  1341. if ( NET_STATE && state[0] && state[1] )
  1342. {
  1343. XChangeProperty( Linux::getDisplay(), gethWnd(), NET_STATE, XA_ATOM, 32,
  1344. PropModeReplace, (unsigned char *)state, 2 );
  1345. }
  1346. #endif
  1347. WASABI_API_WND->appdeactivation_pop_disallow(this);
  1348. setVisible(1);
  1349. }
  1350. int PopupMenu::popAnchored(int type)
  1351. {
  1352. RECT wr;
  1353. getParent()->getWindowRect(&wr);
  1354. switch (type)
  1355. {
  1356. case POPUP_ANCHOR_UL: return popAtXY(wr.left, wr.top);
  1357. case POPUP_ANCHOR_LL: return popAtXY(wr.left, wr.bottom);
  1358. case POPUP_ANCHOR_UR: return popAtXY(wr.right, wr.top);
  1359. case POPUP_ANCHOR_LR: return popAtXY(wr.right, wr.bottom);
  1360. }
  1361. return 0;
  1362. }
  1363. int PopupMenu::popAtMouse()
  1364. {
  1365. int x, y;
  1366. Std::getMousePos(&x, &y);
  1367. return popAtXY(x, y);
  1368. }
  1369. void PopupMenu::onNewContent()
  1370. {
  1371. POPUPMENU_PARENT::onNewContent();
  1372. if (isVisible())
  1373. fillContent();
  1374. }
  1375. void PopupMenu::fillContent()
  1376. {
  1377. GuiObject *grouplist = findObject("popup.content");
  1378. if (grouplist != NULL)
  1379. {
  1380. delete c_grouplist;
  1381. c_grouplist = new C_GroupList(*grouplist);
  1382. c_grouplist->removeAll();
  1383. c_grouplist->setRedraw(0);
  1384. for (int i = 0;i < items.getNumItems();i++)
  1385. {
  1386. addItem(items.enumItem(i));
  1387. }
  1388. c_grouplist->setRedraw(1);
  1389. }
  1390. }
  1391. void PopupMenu::addItem(ItemT *i)
  1392. {
  1393. if (c_grouplist == NULL) return ;
  1394. switch (i->type)
  1395. {
  1396. case POPUPITEM_TYPE_TEXT:
  1397. {
  1398. c_grouplist->instantiate("wasabi.popup.text.item", 1);
  1399. ScriptObject *o = c_grouplist->enumItem(c_grouplist->getNumItems() - 1);
  1400. if (o != NULL)
  1401. {
  1402. C_Group grp(o);
  1403. C_RootObject g(o);
  1404. g.notify("arrow", StringPrintfW(L"%d", (submenus) ? 1 : 0), 0, 0);
  1405. g.notify("checkmark", StringPrintfW(L"%d", menuchecks ? 1 : 0), 0, 0);
  1406. g.notify("id", StringPrintfW(L"%d", i->cmd), 0, 0);
  1407. ScriptObject *check = grp.getObject("popup.item.checkmark");
  1408. if (check != NULL)
  1409. {
  1410. C_Button toggle(check);
  1411. toggle.setActivated(i->checked);
  1412. }
  1413. ScriptObject *arrow = grp.getObject("popup.item.submenuarrow");
  1414. if (check != NULL)
  1415. {
  1416. C_Button sub(arrow);
  1417. sub.setActivated((i->menu != NULL || i->cb != NULL));
  1418. }
  1419. ScriptObject *txt = grp.getObject("popup.item.text");
  1420. if (txt != NULL)
  1421. {
  1422. C_Text itemtxt(txt);
  1423. itemtxt.setText(i->txt);
  1424. }
  1425. }
  1426. break;
  1427. }
  1428. case POPUPITEM_TYPE_IMAGE:
  1429. c_grouplist->instantiate("wasabi.popup.image.item", 1);
  1430. break;
  1431. case POPUPITEM_TYPE_SEPARATOR:
  1432. c_grouplist->instantiate("wasabi.popup.separator.item", 1);
  1433. break;
  1434. }
  1435. }
  1436. String PopupMenu::translateButtonText(const wchar_t *text)
  1437. {
  1438. PathParser pp(text, "\t");
  1439. String ret;
  1440. for (int i = 0; i < pp.getNumStrings(); i++)
  1441. {
  1442. if (i == 0) ret += _(pp.enumString(i)); // translate first
  1443. else ret += pp.enumString(i);
  1444. if (i != pp.getNumStrings() - 1) ret += "\t";
  1445. }
  1446. return ret;
  1447. }
  1448. void PopupMenu::addCommand(const wchar_t *_txt, int command, int checked, int disabled, int addpos)
  1449. {
  1450. if (!_txt)
  1451. {
  1452. addSeparator();
  1453. return ;
  1454. }
  1455. String txt = translateButtonText(_txt);
  1456. #ifdef WASABI_COMPILE_LOCALES
  1457. const char *bind = WASABI_API_LOCALE->locales_getBindFromAction(command);
  1458. if (bind) txt += StringPrintfW(L"\t%s", bind);
  1459. #endif
  1460. ItemT *t = new ItemT;
  1461. t->type = POPUPITEM_TYPE_TEXT;
  1462. t->cmd = command;
  1463. t->txt = txt;
  1464. t->checked = checked;
  1465. t->menu = NULL;
  1466. t->cb = NULL;
  1467. t->cmd = -1;
  1468. ASSERT(PTRLIST_POS_LAST == -1); //BU
  1469. items.addItem(t, addpos);
  1470. }
  1471. int PopupMenu::popupexitcb_onExitPopup()
  1472. {
  1473. getGuiObject()->guiobject_endModal( -2);
  1474. return 1;
  1475. }
  1476. void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text)
  1477. {
  1478. ASSERT(text != NULL);
  1479. submenus = 1;
  1480. ItemT *t = new ItemT;
  1481. t->type = POPUPITEM_TYPE_TEXT;
  1482. t->cmd = items.getNumItems() | 0x40000000;
  1483. t->txt = translateButtonText(text);
  1484. t->checked = 0;
  1485. t->menu = menu;
  1486. t->cb = NULL;
  1487. t->cmd = -1;
  1488. t->cmd = -1;
  1489. items.addItem(t);
  1490. }
  1491. void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param)
  1492. {
  1493. ASSERT(text != NULL);
  1494. ASSERT(cb != NULL);
  1495. ItemT *t = new ItemT;
  1496. submenus = 1;
  1497. t->type = POPUPITEM_TYPE_TEXT;
  1498. t->checked = 0;
  1499. t->cmd = items.getNumItems() | 0x40000000;
  1500. t->menu = NULL;
  1501. t->cb = cb;
  1502. t->cbparam = param;
  1503. t->txt = translateButtonText(text);
  1504. t->cmd = -1;
  1505. items.addItem(t);
  1506. }
  1507. void PopupMenu::initMenuCallback(int item)
  1508. {
  1509. int a = rcode;
  1510. rcode = 0;
  1511. PopupMenu *p = items[item]->cb->popupMenuCallback(this, items[item]->cbparam);
  1512. rcode = a;
  1513. if (p)
  1514. {
  1515. items[item]->cb = NULL;
  1516. items[item]->menu = p;
  1517. }
  1518. }
  1519. #endif
  1520. #endif //WASABI_WANT_FF_POPUP