native_menu_windows.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170
  1. /**************************************************************************/
  2. /* native_menu_windows.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "native_menu_windows.h"
  31. #include "display_server_windows.h"
  32. #include "scene/resources/image_texture.h"
  33. HBITMAP NativeMenuWindows::_make_bitmap(const Ref<Image> &p_img) const {
  34. Vector2i texture_size = p_img->get_size();
  35. UINT image_size = texture_size.width * texture_size.height;
  36. COLORREF *buffer = nullptr;
  37. BITMAPV5HEADER bi;
  38. ZeroMemory(&bi, sizeof(bi));
  39. bi.bV5Size = sizeof(bi);
  40. bi.bV5Width = texture_size.width;
  41. bi.bV5Height = -texture_size.height;
  42. bi.bV5Planes = 1;
  43. bi.bV5BitCount = 32;
  44. bi.bV5Compression = BI_BITFIELDS;
  45. bi.bV5RedMask = 0x00ff0000;
  46. bi.bV5GreenMask = 0x0000ff00;
  47. bi.bV5BlueMask = 0x000000ff;
  48. bi.bV5AlphaMask = 0xff000000;
  49. HDC dc = GetDC(nullptr);
  50. HBITMAP bitmap = CreateDIBSection(dc, reinterpret_cast<BITMAPINFO *>(&bi), DIB_RGB_COLORS, reinterpret_cast<void **>(&buffer), nullptr, 0);
  51. for (UINT index = 0; index < image_size; index++) {
  52. int row_index = floor(index / texture_size.width);
  53. int column_index = (index % int(texture_size.width));
  54. const Color &c = p_img->get_pixel(column_index, row_index);
  55. *(buffer + index) = c.to_argb32();
  56. }
  57. ReleaseDC(nullptr, dc);
  58. return bitmap;
  59. }
  60. void NativeMenuWindows::_menu_activate(HMENU p_menu, int p_index) const {
  61. if (menu_lookup.has(p_menu)) {
  62. MenuData *md = menus.get_or_null(menu_lookup[p_menu]);
  63. if (md) {
  64. int count = GetMenuItemCount(md->menu);
  65. if (p_index >= 0 && p_index < count) {
  66. MENUITEMINFOW item;
  67. ZeroMemory(&item, sizeof(item));
  68. item.cbSize = sizeof(item);
  69. item.fMask = MIIM_STATE | MIIM_DATA;
  70. if (GetMenuItemInfoW(md->menu, p_index, true, &item)) {
  71. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  72. if (item_data) {
  73. if (item_data->max_states > 0) {
  74. item_data->state++;
  75. if (item_data->state >= item_data->max_states) {
  76. item_data->state = 0;
  77. }
  78. }
  79. if (item_data->checkable_type == CHECKABLE_TYPE_CHECK_BOX) {
  80. if ((item.fState & MFS_CHECKED) == MFS_CHECKED) {
  81. item.fState &= ~MFS_CHECKED;
  82. } else {
  83. item.fState |= MFS_CHECKED;
  84. }
  85. SetMenuItemInfoW(md->menu, p_index, true, &item);
  86. }
  87. if (item_data->callback.is_valid()) {
  88. Variant ret;
  89. Callable::CallError ce;
  90. const Variant *args[1] = { &item_data->meta };
  91. item_data->callback.callp(args, 1, ret, ce);
  92. if (ce.error != Callable::CallError::CALL_OK) {
  93. ERR_PRINT(vformat("Failed to execute menu callback: %s.", Variant::get_callable_error_text(item_data->callback, args, 1, ce)));
  94. }
  95. }
  96. }
  97. }
  98. }
  99. }
  100. }
  101. }
  102. bool NativeMenuWindows::has_feature(Feature p_feature) const {
  103. switch (p_feature) {
  104. // case FEATURE_GLOBAL_MENU:
  105. // case FEATURE_OPEN_CLOSE_CALLBACK:
  106. // case FEATURE_HOVER_CALLBACK:
  107. // case FEATURE_KEY_CALLBACK:
  108. case FEATURE_POPUP_MENU:
  109. return true;
  110. default:
  111. return false;
  112. }
  113. }
  114. bool NativeMenuWindows::has_system_menu(SystemMenus p_menu_id) const {
  115. return false;
  116. }
  117. RID NativeMenuWindows::get_system_menu(SystemMenus p_menu_id) const {
  118. return RID();
  119. }
  120. RID NativeMenuWindows::create_menu() {
  121. MenuData *md = memnew(MenuData);
  122. md->menu = CreatePopupMenu();
  123. MENUINFO menu_info;
  124. ZeroMemory(&menu_info, sizeof(menu_info));
  125. menu_info.cbSize = sizeof(menu_info);
  126. menu_info.fMask = MIM_STYLE;
  127. menu_info.dwStyle = MNS_NOTIFYBYPOS;
  128. SetMenuInfo(md->menu, &menu_info);
  129. RID rid = menus.make_rid(md);
  130. menu_lookup[md->menu] = rid;
  131. return rid;
  132. }
  133. bool NativeMenuWindows::has_menu(const RID &p_rid) const {
  134. return menus.owns(p_rid);
  135. }
  136. void NativeMenuWindows::free_menu(const RID &p_rid) {
  137. MenuData *md = menus.get_or_null(p_rid);
  138. if (md) {
  139. clear(p_rid);
  140. DestroyMenu(md->menu);
  141. menus.free(p_rid);
  142. menu_lookup.erase(md->menu);
  143. memdelete(md);
  144. }
  145. }
  146. Size2 NativeMenuWindows::get_size(const RID &p_rid) const {
  147. const MenuData *md = menus.get_or_null(p_rid);
  148. ERR_FAIL_NULL_V(md, Size2());
  149. Size2 size;
  150. int count = GetMenuItemCount(md->menu);
  151. for (int i = 0; i < count; i++) {
  152. RECT rect;
  153. if (GetMenuItemRect(NULL, md->menu, i, &rect)) {
  154. size.x = MAX(size.x, rect.right - rect.left);
  155. size.y += rect.bottom - rect.top;
  156. }
  157. }
  158. return size;
  159. }
  160. void NativeMenuWindows::popup(const RID &p_rid, const Vector2i &p_position) {
  161. const MenuData *md = menus.get_or_null(p_rid);
  162. ERR_FAIL_NULL(md);
  163. HWND hwnd = (HWND)DisplayServer::get_singleton()->window_get_native_handle(DisplayServer::WINDOW_HANDLE, DisplayServer::MAIN_WINDOW_ID);
  164. UINT flags = TPM_HORIZONTAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_LEFTBUTTON | TPM_VERPOSANIMATION;
  165. if (md->is_rtl) {
  166. flags |= TPM_LAYOUTRTL;
  167. }
  168. SetForegroundWindow(hwnd);
  169. TrackPopupMenuEx(md->menu, flags, p_position.x, p_position.y, hwnd, nullptr);
  170. PostMessage(hwnd, WM_NULL, 0, 0);
  171. }
  172. void NativeMenuWindows::set_interface_direction(const RID &p_rid, bool p_is_rtl) {
  173. MenuData *md = menus.get_or_null(p_rid);
  174. ERR_FAIL_NULL(md);
  175. if (md->is_rtl == p_is_rtl) {
  176. return;
  177. }
  178. md->is_rtl = p_is_rtl;
  179. }
  180. void NativeMenuWindows::set_popup_open_callback(const RID &p_rid, const Callable &p_callback) {
  181. // Not supported.
  182. }
  183. Callable NativeMenuWindows::get_popup_open_callback(const RID &p_rid) const {
  184. // Not supported.
  185. return Callable();
  186. }
  187. void NativeMenuWindows::set_popup_close_callback(const RID &p_rid, const Callable &p_callback) {
  188. // Not supported.
  189. }
  190. Callable NativeMenuWindows::get_popup_close_callback(const RID &p_rid) const {
  191. // Not supported.
  192. return Callable();
  193. }
  194. void NativeMenuWindows::set_minimum_width(const RID &p_rid, float p_width) {
  195. // Not supported.
  196. }
  197. float NativeMenuWindows::get_minimum_width(const RID &p_rid) const {
  198. // Not supported.
  199. return 0.f;
  200. }
  201. bool NativeMenuWindows::is_opened(const RID &p_rid) const {
  202. // Not supported.
  203. return false;
  204. }
  205. int NativeMenuWindows::add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag, int p_index) {
  206. MenuData *md = menus.get_or_null(p_rid);
  207. MenuData *md_sub = menus.get_or_null(p_submenu_rid);
  208. ERR_FAIL_NULL_V(md, -1);
  209. ERR_FAIL_NULL_V(md_sub, -1);
  210. ERR_FAIL_COND_V_MSG(md->menu == md_sub->menu, -1, "Can't set submenu to self!");
  211. if (p_index == -1) {
  212. p_index = GetMenuItemCount(md->menu);
  213. } else {
  214. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  215. }
  216. MenuItemData *item_data = memnew(MenuItemData);
  217. item_data->meta = p_tag;
  218. item_data->checkable_type = CHECKABLE_TYPE_NONE;
  219. item_data->max_states = 0;
  220. item_data->state = 0;
  221. Char16String label = p_label.utf16();
  222. MENUITEMINFOW item;
  223. ZeroMemory(&item, sizeof(item));
  224. item.cbSize = sizeof(item);
  225. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_SUBMENU;
  226. item.fType = MFT_STRING;
  227. item.hSubMenu = md_sub->menu;
  228. item.dwItemData = (ULONG_PTR)item_data;
  229. item.dwTypeData = (LPWSTR)label.get_data();
  230. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  231. memdelete(item_data);
  232. return -1;
  233. }
  234. return p_index;
  235. }
  236. int NativeMenuWindows::add_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  237. const MenuData *md = menus.get_or_null(p_rid);
  238. ERR_FAIL_NULL_V(md, -1);
  239. if (p_index == -1) {
  240. p_index = GetMenuItemCount(md->menu);
  241. } else {
  242. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  243. }
  244. MenuItemData *item_data = memnew(MenuItemData);
  245. item_data->callback = p_callback;
  246. item_data->meta = p_tag;
  247. item_data->checkable_type = CHECKABLE_TYPE_NONE;
  248. item_data->max_states = 0;
  249. item_data->state = 0;
  250. Char16String label = p_label.utf16();
  251. MENUITEMINFOW item;
  252. ZeroMemory(&item, sizeof(item));
  253. item.cbSize = sizeof(item);
  254. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
  255. item.fType = MFT_STRING;
  256. item.dwItemData = (ULONG_PTR)item_data;
  257. item.dwTypeData = (LPWSTR)label.get_data();
  258. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  259. memdelete(item_data);
  260. return -1;
  261. }
  262. return p_index;
  263. }
  264. int NativeMenuWindows::add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  265. const MenuData *md = menus.get_or_null(p_rid);
  266. ERR_FAIL_NULL_V(md, -1);
  267. if (p_index == -1) {
  268. p_index = GetMenuItemCount(md->menu);
  269. } else {
  270. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  271. }
  272. MenuItemData *item_data = memnew(MenuItemData);
  273. item_data->callback = p_callback;
  274. item_data->meta = p_tag;
  275. item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
  276. item_data->max_states = 0;
  277. item_data->state = 0;
  278. Char16String label = p_label.utf16();
  279. MENUITEMINFOW item;
  280. ZeroMemory(&item, sizeof(item));
  281. item.cbSize = sizeof(item);
  282. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
  283. item.fType = MFT_STRING;
  284. item.dwItemData = (ULONG_PTR)item_data;
  285. item.dwTypeData = (LPWSTR)label.get_data();
  286. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  287. memdelete(item_data);
  288. return -1;
  289. }
  290. return p_index;
  291. }
  292. int NativeMenuWindows::add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  293. const MenuData *md = menus.get_or_null(p_rid);
  294. ERR_FAIL_NULL_V(md, -1);
  295. if (p_index == -1) {
  296. p_index = GetMenuItemCount(md->menu);
  297. } else {
  298. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  299. }
  300. MenuItemData *item_data = memnew(MenuItemData);
  301. item_data->callback = p_callback;
  302. item_data->meta = p_tag;
  303. item_data->checkable_type = CHECKABLE_TYPE_NONE;
  304. item_data->max_states = 0;
  305. item_data->state = 0;
  306. item_data->img = p_icon->get_image();
  307. item_data->img = item_data->img->duplicate();
  308. if (item_data->img->is_compressed()) {
  309. item_data->img->decompress();
  310. }
  311. item_data->bmp = _make_bitmap(item_data->img);
  312. Char16String label = p_label.utf16();
  313. MENUITEMINFOW item;
  314. ZeroMemory(&item, sizeof(item));
  315. item.cbSize = sizeof(item);
  316. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
  317. item.fType = MFT_STRING;
  318. item.dwItemData = (ULONG_PTR)item_data;
  319. item.dwTypeData = (LPWSTR)label.get_data();
  320. item.hbmpItem = item_data->bmp;
  321. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  322. memdelete(item_data);
  323. return -1;
  324. }
  325. return p_index;
  326. }
  327. int NativeMenuWindows::add_icon_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  328. const MenuData *md = menus.get_or_null(p_rid);
  329. ERR_FAIL_NULL_V(md, -1);
  330. if (p_index == -1) {
  331. p_index = GetMenuItemCount(md->menu);
  332. } else {
  333. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  334. }
  335. MenuItemData *item_data = memnew(MenuItemData);
  336. item_data->callback = p_callback;
  337. item_data->meta = p_tag;
  338. item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
  339. item_data->max_states = 0;
  340. item_data->state = 0;
  341. item_data->img = p_icon->get_image();
  342. item_data->img = item_data->img->duplicate();
  343. if (item_data->img->is_compressed()) {
  344. item_data->img->decompress();
  345. }
  346. item_data->bmp = _make_bitmap(item_data->img);
  347. Char16String label = p_label.utf16();
  348. MENUITEMINFOW item;
  349. ZeroMemory(&item, sizeof(item));
  350. item.cbSize = sizeof(item);
  351. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
  352. item.fType = MFT_STRING;
  353. item.dwItemData = (ULONG_PTR)item_data;
  354. item.dwTypeData = (LPWSTR)label.get_data();
  355. item.hbmpItem = item_data->bmp;
  356. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  357. memdelete(item_data);
  358. return -1;
  359. }
  360. return p_index;
  361. }
  362. int NativeMenuWindows::add_radio_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  363. const MenuData *md = menus.get_or_null(p_rid);
  364. ERR_FAIL_NULL_V(md, -1);
  365. if (p_index == -1) {
  366. p_index = GetMenuItemCount(md->menu);
  367. } else {
  368. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  369. }
  370. MenuItemData *item_data = memnew(MenuItemData);
  371. item_data->callback = p_callback;
  372. item_data->meta = p_tag;
  373. item_data->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
  374. item_data->max_states = 0;
  375. item_data->state = 0;
  376. Char16String label = p_label.utf16();
  377. MENUITEMINFOW item;
  378. ZeroMemory(&item, sizeof(item));
  379. item.cbSize = sizeof(item);
  380. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
  381. item.fType = MFT_STRING | MFT_RADIOCHECK;
  382. item.dwItemData = (ULONG_PTR)item_data;
  383. item.dwTypeData = (LPWSTR)label.get_data();
  384. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  385. memdelete(item_data);
  386. return -1;
  387. }
  388. return p_index;
  389. }
  390. int NativeMenuWindows::add_icon_radio_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  391. const MenuData *md = menus.get_or_null(p_rid);
  392. ERR_FAIL_NULL_V(md, -1);
  393. if (p_index == -1) {
  394. p_index = GetMenuItemCount(md->menu);
  395. } else {
  396. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  397. }
  398. MenuItemData *item_data = memnew(MenuItemData);
  399. item_data->callback = p_callback;
  400. item_data->meta = p_tag;
  401. item_data->checkable_type = CHECKABLE_TYPE_RADIO_BUTTON;
  402. item_data->max_states = 0;
  403. item_data->state = 0;
  404. item_data->img = p_icon->get_image();
  405. item_data->img = item_data->img->duplicate();
  406. if (item_data->img->is_compressed()) {
  407. item_data->img->decompress();
  408. }
  409. item_data->bmp = _make_bitmap(item_data->img);
  410. Char16String label = p_label.utf16();
  411. MENUITEMINFOW item;
  412. ZeroMemory(&item, sizeof(item));
  413. item.cbSize = sizeof(item);
  414. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA | MIIM_BITMAP;
  415. item.fType = MFT_STRING | MFT_RADIOCHECK;
  416. item.dwItemData = (ULONG_PTR)item_data;
  417. item.dwTypeData = (LPWSTR)label.get_data();
  418. item.hbmpItem = item_data->bmp;
  419. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  420. memdelete(item_data);
  421. return -1;
  422. }
  423. return p_index;
  424. }
  425. int NativeMenuWindows::add_multistate_item(const RID &p_rid, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) {
  426. const MenuData *md = menus.get_or_null(p_rid);
  427. ERR_FAIL_NULL_V(md, -1);
  428. if (p_index == -1) {
  429. p_index = GetMenuItemCount(md->menu);
  430. } else {
  431. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  432. }
  433. MenuItemData *item_data = memnew(MenuItemData);
  434. item_data->callback = p_callback;
  435. item_data->meta = p_tag;
  436. item_data->checkable_type = CHECKABLE_TYPE_NONE;
  437. item_data->max_states = p_max_states;
  438. item_data->state = p_default_state;
  439. Char16String label = p_label.utf16();
  440. MENUITEMINFOW item;
  441. ZeroMemory(&item, sizeof(item));
  442. item.cbSize = sizeof(item);
  443. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
  444. item.fType = MFT_STRING;
  445. item.dwItemData = (ULONG_PTR)item_data;
  446. item.dwTypeData = (LPWSTR)label.get_data();
  447. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  448. memdelete(item_data);
  449. return -1;
  450. }
  451. return p_index;
  452. }
  453. int NativeMenuWindows::add_separator(const RID &p_rid, int p_index) {
  454. const MenuData *md = menus.get_or_null(p_rid);
  455. ERR_FAIL_NULL_V(md, -1);
  456. if (p_index == -1) {
  457. p_index = GetMenuItemCount(md->menu);
  458. } else {
  459. p_index = CLAMP(p_index, 0, GetMenuItemCount(md->menu));
  460. }
  461. MenuItemData *item_data = memnew(MenuItemData);
  462. item_data->checkable_type = CHECKABLE_TYPE_NONE;
  463. item_data->max_states = 0;
  464. item_data->state = 0;
  465. MENUITEMINFOW item;
  466. ZeroMemory(&item, sizeof(item));
  467. item.cbSize = sizeof(item);
  468. item.fMask = MIIM_FTYPE | MIIM_DATA;
  469. item.fType = MFT_SEPARATOR;
  470. item.dwItemData = (ULONG_PTR)item_data;
  471. if (!InsertMenuItemW(md->menu, p_index, true, &item)) {
  472. memdelete(item_data);
  473. return -1;
  474. }
  475. return p_index;
  476. }
  477. int NativeMenuWindows::find_item_index_with_text(const RID &p_rid, const String &p_text) const {
  478. const MenuData *md = menus.get_or_null(p_rid);
  479. ERR_FAIL_NULL_V(md, -1);
  480. MENUITEMINFOW item;
  481. int count = GetMenuItemCount(md->menu);
  482. for (int i = 0; i < count; i++) {
  483. ZeroMemory(&item, sizeof(item));
  484. item.cbSize = sizeof(item);
  485. item.fMask = MIIM_STRING;
  486. item.dwTypeData = nullptr;
  487. if (GetMenuItemInfoW(md->menu, i, true, &item)) {
  488. item.cch++;
  489. Char16String str;
  490. str.resize(item.cch);
  491. item.dwTypeData = (LPWSTR)str.ptrw();
  492. if (GetMenuItemInfoW(md->menu, i, true, &item)) {
  493. if (String::utf16((const char16_t *)str.get_data()) == p_text) {
  494. return i;
  495. }
  496. }
  497. }
  498. }
  499. return -1;
  500. }
  501. int NativeMenuWindows::find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const {
  502. const MenuData *md = menus.get_or_null(p_rid);
  503. ERR_FAIL_NULL_V(md, -1);
  504. MENUITEMINFOW item;
  505. int count = GetMenuItemCount(md->menu);
  506. for (int i = 0; i < count; i++) {
  507. ZeroMemory(&item, sizeof(item));
  508. item.cbSize = sizeof(item);
  509. item.fMask = MIIM_DATA;
  510. if (GetMenuItemInfoW(md->menu, i, true, &item)) {
  511. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  512. if (item_data) {
  513. if (item_data->meta == p_tag) {
  514. return i;
  515. }
  516. }
  517. }
  518. }
  519. return -1;
  520. }
  521. bool NativeMenuWindows::is_item_checked(const RID &p_rid, int p_idx) const {
  522. ERR_FAIL_COND_V(p_idx < 0, false);
  523. const MenuData *md = menus.get_or_null(p_rid);
  524. ERR_FAIL_NULL_V(md, false);
  525. int count = GetMenuItemCount(md->menu);
  526. ERR_FAIL_COND_V(p_idx >= count, false);
  527. MENUITEMINFOW item;
  528. ZeroMemory(&item, sizeof(item));
  529. item.cbSize = sizeof(item);
  530. item.fMask = MIIM_STATE;
  531. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  532. return (item.fState & MFS_CHECKED) == MFS_CHECKED;
  533. }
  534. return false;
  535. }
  536. bool NativeMenuWindows::is_item_checkable(const RID &p_rid, int p_idx) const {
  537. ERR_FAIL_COND_V(p_idx < 0, false);
  538. const MenuData *md = menus.get_or_null(p_rid);
  539. ERR_FAIL_NULL_V(md, false);
  540. int count = GetMenuItemCount(md->menu);
  541. ERR_FAIL_COND_V(p_idx >= count, false);
  542. MENUITEMINFOW item;
  543. ZeroMemory(&item, sizeof(item));
  544. item.cbSize = sizeof(item);
  545. item.fMask = MIIM_DATA;
  546. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  547. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  548. if (item_data) {
  549. return item_data->checkable_type == CHECKABLE_TYPE_CHECK_BOX;
  550. }
  551. }
  552. return false;
  553. }
  554. bool NativeMenuWindows::is_item_radio_checkable(const RID &p_rid, int p_idx) const {
  555. ERR_FAIL_COND_V(p_idx < 0, false);
  556. const MenuData *md = menus.get_or_null(p_rid);
  557. ERR_FAIL_NULL_V(md, false);
  558. int count = GetMenuItemCount(md->menu);
  559. ERR_FAIL_COND_V(p_idx >= count, false);
  560. MENUITEMINFOW item;
  561. ZeroMemory(&item, sizeof(item));
  562. item.cbSize = sizeof(item);
  563. item.fMask = MIIM_DATA;
  564. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  565. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  566. if (item_data) {
  567. return item_data->checkable_type == CHECKABLE_TYPE_RADIO_BUTTON;
  568. }
  569. }
  570. return false;
  571. }
  572. Callable NativeMenuWindows::get_item_callback(const RID &p_rid, int p_idx) const {
  573. ERR_FAIL_COND_V(p_idx < 0, Callable());
  574. const MenuData *md = menus.get_or_null(p_rid);
  575. ERR_FAIL_NULL_V(md, Callable());
  576. int count = GetMenuItemCount(md->menu);
  577. ERR_FAIL_COND_V(p_idx >= count, Callable());
  578. MENUITEMINFOW item;
  579. ZeroMemory(&item, sizeof(item));
  580. item.cbSize = sizeof(item);
  581. item.fMask = MIIM_DATA;
  582. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  583. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  584. if (item_data) {
  585. return item_data->callback;
  586. }
  587. }
  588. return Callable();
  589. }
  590. Callable NativeMenuWindows::get_item_key_callback(const RID &p_rid, int p_idx) const {
  591. // Not supported.
  592. return Callable();
  593. }
  594. Variant NativeMenuWindows::get_item_tag(const RID &p_rid, int p_idx) const {
  595. ERR_FAIL_COND_V(p_idx < 0, Variant());
  596. const MenuData *md = menus.get_or_null(p_rid);
  597. ERR_FAIL_NULL_V(md, Variant());
  598. int count = GetMenuItemCount(md->menu);
  599. ERR_FAIL_COND_V(p_idx >= count, Variant());
  600. MENUITEMINFOW item;
  601. ZeroMemory(&item, sizeof(item));
  602. item.cbSize = sizeof(item);
  603. item.fMask = MIIM_DATA;
  604. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  605. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  606. if (item_data) {
  607. return item_data->meta;
  608. }
  609. }
  610. return Variant();
  611. }
  612. String NativeMenuWindows::get_item_text(const RID &p_rid, int p_idx) const {
  613. ERR_FAIL_COND_V(p_idx < 0, String());
  614. const MenuData *md = menus.get_or_null(p_rid);
  615. ERR_FAIL_NULL_V(md, String());
  616. int count = GetMenuItemCount(md->menu);
  617. ERR_FAIL_COND_V(p_idx >= count, String());
  618. MENUITEMINFOW item;
  619. ZeroMemory(&item, sizeof(item));
  620. item.cbSize = sizeof(item);
  621. item.fMask = MIIM_STRING;
  622. item.dwTypeData = nullptr;
  623. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  624. item.cch++;
  625. Char16String str;
  626. str.resize(item.cch);
  627. item.dwTypeData = (LPWSTR)str.ptrw();
  628. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  629. return String::utf16((const char16_t *)str.get_data());
  630. }
  631. }
  632. return String();
  633. }
  634. RID NativeMenuWindows::get_item_submenu(const RID &p_rid, int p_idx) const {
  635. ERR_FAIL_COND_V(p_idx < 0, RID());
  636. const MenuData *md = menus.get_or_null(p_rid);
  637. ERR_FAIL_NULL_V(md, RID());
  638. int count = GetMenuItemCount(md->menu);
  639. ERR_FAIL_COND_V(p_idx >= count, RID());
  640. MENUITEMINFOW item;
  641. ZeroMemory(&item, sizeof(item));
  642. item.cbSize = sizeof(item);
  643. item.fMask = MIIM_SUBMENU;
  644. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  645. if (menu_lookup.has(item.hSubMenu)) {
  646. return menu_lookup[item.hSubMenu];
  647. }
  648. }
  649. return RID();
  650. }
  651. Key NativeMenuWindows::get_item_accelerator(const RID &p_rid, int p_idx) const {
  652. // Not supported.
  653. return Key::NONE;
  654. }
  655. bool NativeMenuWindows::is_item_disabled(const RID &p_rid, int p_idx) const {
  656. ERR_FAIL_COND_V(p_idx < 0, false);
  657. const MenuData *md = menus.get_or_null(p_rid);
  658. ERR_FAIL_NULL_V(md, false);
  659. int count = GetMenuItemCount(md->menu);
  660. ERR_FAIL_COND_V(p_idx >= count, false);
  661. MENUITEMINFOW item;
  662. ZeroMemory(&item, sizeof(item));
  663. item.cbSize = sizeof(item);
  664. item.fMask = MIIM_STATE;
  665. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  666. return (item.fState & MFS_DISABLED) == MFS_DISABLED;
  667. }
  668. return false;
  669. }
  670. bool NativeMenuWindows::is_item_hidden(const RID &p_rid, int p_idx) const {
  671. // Not supported.
  672. return false;
  673. }
  674. String NativeMenuWindows::get_item_tooltip(const RID &p_rid, int p_idx) const {
  675. // Not supported.
  676. return String();
  677. }
  678. int NativeMenuWindows::get_item_state(const RID &p_rid, int p_idx) const {
  679. ERR_FAIL_COND_V(p_idx < 0, -1);
  680. const MenuData *md = menus.get_or_null(p_rid);
  681. ERR_FAIL_NULL_V(md, -1);
  682. int count = GetMenuItemCount(md->menu);
  683. ERR_FAIL_COND_V(p_idx >= count, -1);
  684. MENUITEMINFOW item;
  685. ZeroMemory(&item, sizeof(item));
  686. item.cbSize = sizeof(item);
  687. item.fMask = MIIM_DATA;
  688. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  689. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  690. if (item_data) {
  691. return item_data->state;
  692. }
  693. }
  694. return -1;
  695. }
  696. int NativeMenuWindows::get_item_max_states(const RID &p_rid, int p_idx) const {
  697. ERR_FAIL_COND_V(p_idx < 0, -1);
  698. const MenuData *md = menus.get_or_null(p_rid);
  699. ERR_FAIL_NULL_V(md, -1);
  700. int count = GetMenuItemCount(md->menu);
  701. ERR_FAIL_COND_V(p_idx >= count, -1);
  702. MENUITEMINFOW item;
  703. ZeroMemory(&item, sizeof(item));
  704. item.cbSize = sizeof(item);
  705. item.fMask = MIIM_DATA;
  706. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  707. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  708. if (item_data) {
  709. return item_data->max_states;
  710. }
  711. }
  712. return -1;
  713. }
  714. Ref<Texture2D> NativeMenuWindows::get_item_icon(const RID &p_rid, int p_idx) const {
  715. ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
  716. const MenuData *md = menus.get_or_null(p_rid);
  717. ERR_FAIL_NULL_V(md, Ref<Texture2D>());
  718. int count = GetMenuItemCount(md->menu);
  719. ERR_FAIL_COND_V(p_idx >= count, Ref<Texture2D>());
  720. MENUITEMINFOW item;
  721. ZeroMemory(&item, sizeof(item));
  722. item.cbSize = sizeof(item);
  723. item.fMask = MIIM_DATA;
  724. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  725. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  726. if (item_data) {
  727. return ImageTexture::create_from_image(item_data->img);
  728. }
  729. }
  730. return Ref<Texture2D>();
  731. }
  732. int NativeMenuWindows::get_item_indentation_level(const RID &p_rid, int p_idx) const {
  733. // Not supported.
  734. return 0;
  735. }
  736. void NativeMenuWindows::set_item_checked(const RID &p_rid, int p_idx, bool p_checked) {
  737. ERR_FAIL_COND(p_idx < 0);
  738. const MenuData *md = menus.get_or_null(p_rid);
  739. ERR_FAIL_NULL(md);
  740. int count = GetMenuItemCount(md->menu);
  741. ERR_FAIL_COND(p_idx >= count);
  742. MENUITEMINFOW item;
  743. ZeroMemory(&item, sizeof(item));
  744. item.cbSize = sizeof(item);
  745. item.fMask = MIIM_STATE;
  746. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  747. if (p_checked) {
  748. item.fState |= MFS_CHECKED;
  749. } else {
  750. item.fState &= ~MFS_CHECKED;
  751. }
  752. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  753. }
  754. }
  755. void NativeMenuWindows::set_item_checkable(const RID &p_rid, int p_idx, bool p_checkable) {
  756. ERR_FAIL_COND(p_idx < 0);
  757. const MenuData *md = menus.get_or_null(p_rid);
  758. ERR_FAIL_NULL(md);
  759. int count = GetMenuItemCount(md->menu);
  760. ERR_FAIL_COND(p_idx >= count);
  761. MENUITEMINFOW item;
  762. ZeroMemory(&item, sizeof(item));
  763. item.cbSize = sizeof(item);
  764. item.fMask = MIIM_FTYPE | MIIM_DATA;
  765. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  766. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  767. if (item_data) {
  768. item.fType &= ~MFT_RADIOCHECK;
  769. item_data->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE;
  770. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  771. }
  772. }
  773. }
  774. void NativeMenuWindows::set_item_radio_checkable(const RID &p_rid, int p_idx, bool p_checkable) {
  775. ERR_FAIL_COND(p_idx < 0);
  776. const MenuData *md = menus.get_or_null(p_rid);
  777. ERR_FAIL_NULL(md);
  778. int count = GetMenuItemCount(md->menu);
  779. ERR_FAIL_COND(p_idx >= count);
  780. MENUITEMINFOW item;
  781. ZeroMemory(&item, sizeof(item));
  782. item.cbSize = sizeof(item);
  783. item.fMask = MIIM_FTYPE | MIIM_DATA;
  784. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  785. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  786. if (item_data) {
  787. if (p_checkable) {
  788. item.fType |= MFT_RADIOCHECK;
  789. item_data->checkable_type = CHECKABLE_TYPE_CHECK_BOX;
  790. } else {
  791. item.fType &= ~MFT_RADIOCHECK;
  792. item_data->checkable_type = CHECKABLE_TYPE_NONE;
  793. }
  794. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  795. }
  796. }
  797. }
  798. void NativeMenuWindows::set_item_callback(const RID &p_rid, int p_idx, const Callable &p_callback) {
  799. ERR_FAIL_COND(p_idx < 0);
  800. const MenuData *md = menus.get_or_null(p_rid);
  801. ERR_FAIL_NULL(md);
  802. int count = GetMenuItemCount(md->menu);
  803. ERR_FAIL_COND(p_idx >= count);
  804. MENUITEMINFOW item;
  805. ZeroMemory(&item, sizeof(item));
  806. item.cbSize = sizeof(item);
  807. item.fMask = MIIM_DATA;
  808. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  809. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  810. if (item_data) {
  811. item_data->callback = p_callback;
  812. }
  813. }
  814. }
  815. void NativeMenuWindows::set_item_key_callback(const RID &p_rid, int p_idx, const Callable &p_key_callback) {
  816. // Not supported.
  817. }
  818. void NativeMenuWindows::set_item_hover_callbacks(const RID &p_rid, int p_idx, const Callable &p_callback) {
  819. // Not supported.
  820. }
  821. void NativeMenuWindows::set_item_tag(const RID &p_rid, int p_idx, const Variant &p_tag) {
  822. ERR_FAIL_COND(p_idx < 0);
  823. const MenuData *md = menus.get_or_null(p_rid);
  824. ERR_FAIL_NULL(md);
  825. int count = GetMenuItemCount(md->menu);
  826. ERR_FAIL_COND(p_idx >= count);
  827. MENUITEMINFOW item;
  828. ZeroMemory(&item, sizeof(item));
  829. item.cbSize = sizeof(item);
  830. item.fMask = MIIM_DATA;
  831. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  832. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  833. if (item_data) {
  834. item_data->meta = p_tag;
  835. }
  836. }
  837. }
  838. void NativeMenuWindows::set_item_text(const RID &p_rid, int p_idx, const String &p_text) {
  839. ERR_FAIL_COND(p_idx < 0);
  840. const MenuData *md = menus.get_or_null(p_rid);
  841. ERR_FAIL_NULL(md);
  842. int count = GetMenuItemCount(md->menu);
  843. ERR_FAIL_COND(p_idx >= count);
  844. Char16String label = p_text.utf16();
  845. MENUITEMINFOW item;
  846. ZeroMemory(&item, sizeof(item));
  847. item.cbSize = sizeof(item);
  848. item.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_DATA;
  849. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  850. item.dwTypeData = (LPWSTR)label.get_data();
  851. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  852. }
  853. }
  854. void NativeMenuWindows::set_item_submenu(const RID &p_rid, int p_idx, const RID &p_submenu_rid) {
  855. ERR_FAIL_COND(p_idx < 0);
  856. const MenuData *md = menus.get_or_null(p_rid);
  857. ERR_FAIL_NULL(md);
  858. int count = GetMenuItemCount(md->menu);
  859. ERR_FAIL_COND(p_idx >= count);
  860. MenuData *md_sub = menus.get_or_null(p_submenu_rid);
  861. ERR_FAIL_COND_MSG(md->menu == md_sub->menu, "Can't set submenu to self!");
  862. MENUITEMINFOW item;
  863. ZeroMemory(&item, sizeof(item));
  864. item.cbSize = sizeof(item);
  865. item.fMask = MIIM_SUBMENU;
  866. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  867. if (p_submenu_rid.is_valid()) {
  868. item.hSubMenu = md_sub->menu;
  869. } else {
  870. item.hSubMenu = 0;
  871. }
  872. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  873. }
  874. }
  875. void NativeMenuWindows::set_item_accelerator(const RID &p_rid, int p_idx, Key p_keycode) {
  876. // Not supported.
  877. }
  878. void NativeMenuWindows::set_item_disabled(const RID &p_rid, int p_idx, bool p_disabled) {
  879. ERR_FAIL_COND(p_idx < 0);
  880. const MenuData *md = menus.get_or_null(p_rid);
  881. ERR_FAIL_NULL(md);
  882. int count = GetMenuItemCount(md->menu);
  883. ERR_FAIL_COND(p_idx >= count);
  884. MENUITEMINFOW item;
  885. ZeroMemory(&item, sizeof(item));
  886. item.cbSize = sizeof(item);
  887. item.fMask = MIIM_STATE;
  888. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  889. if (p_disabled) {
  890. item.fState |= MFS_DISABLED;
  891. } else {
  892. item.fState &= ~MFS_DISABLED;
  893. }
  894. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  895. }
  896. }
  897. void NativeMenuWindows::set_item_hidden(const RID &p_rid, int p_idx, bool p_hidden) {
  898. // Not supported.
  899. }
  900. void NativeMenuWindows::set_item_tooltip(const RID &p_rid, int p_idx, const String &p_tooltip) {
  901. // Not supported.
  902. }
  903. void NativeMenuWindows::set_item_state(const RID &p_rid, int p_idx, int p_state) {
  904. ERR_FAIL_COND(p_idx < 0);
  905. const MenuData *md = menus.get_or_null(p_rid);
  906. ERR_FAIL_NULL(md);
  907. int count = GetMenuItemCount(md->menu);
  908. ERR_FAIL_COND(p_idx >= count);
  909. MENUITEMINFOW item;
  910. ZeroMemory(&item, sizeof(item));
  911. item.cbSize = sizeof(item);
  912. item.fMask = MIIM_DATA;
  913. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  914. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  915. if (item_data) {
  916. item_data->state = p_state;
  917. }
  918. }
  919. }
  920. void NativeMenuWindows::set_item_max_states(const RID &p_rid, int p_idx, int p_max_states) {
  921. ERR_FAIL_COND(p_idx < 0);
  922. const MenuData *md = menus.get_or_null(p_rid);
  923. ERR_FAIL_NULL(md);
  924. int count = GetMenuItemCount(md->menu);
  925. ERR_FAIL_COND(p_idx >= count);
  926. MENUITEMINFOW item;
  927. ZeroMemory(&item, sizeof(item));
  928. item.cbSize = sizeof(item);
  929. item.fMask = MIIM_DATA;
  930. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  931. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  932. if (item_data) {
  933. item_data->max_states = p_max_states;
  934. }
  935. }
  936. }
  937. void NativeMenuWindows::set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon) {
  938. ERR_FAIL_COND(p_idx < 0);
  939. const MenuData *md = menus.get_or_null(p_rid);
  940. ERR_FAIL_NULL(md);
  941. int count = GetMenuItemCount(md->menu);
  942. ERR_FAIL_COND(p_idx >= count);
  943. MENUITEMINFOW item;
  944. ZeroMemory(&item, sizeof(item));
  945. item.cbSize = sizeof(item);
  946. item.fMask = MIIM_DATA | MIIM_BITMAP;
  947. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  948. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  949. if (item_data) {
  950. if (item_data->bmp) {
  951. DeleteObject(item_data->bmp);
  952. }
  953. if (p_icon.is_valid()) {
  954. item_data->img = p_icon->get_image();
  955. item_data->img = item_data->img->duplicate();
  956. if (item_data->img->is_compressed()) {
  957. item_data->img->decompress();
  958. }
  959. item_data->bmp = _make_bitmap(item_data->img);
  960. } else {
  961. item_data->img = Ref<Image>();
  962. item_data->bmp = 0;
  963. }
  964. item.hbmpItem = item_data->bmp;
  965. SetMenuItemInfoW(md->menu, p_idx, true, &item);
  966. }
  967. }
  968. }
  969. void NativeMenuWindows::set_item_indentation_level(const RID &p_rid, int p_idx, int p_level) {
  970. // Not supported.
  971. }
  972. int NativeMenuWindows::get_item_count(const RID &p_rid) const {
  973. const MenuData *md = menus.get_or_null(p_rid);
  974. ERR_FAIL_NULL_V(md, 0);
  975. return GetMenuItemCount(md->menu);
  976. }
  977. bool NativeMenuWindows::is_system_menu(const RID &p_rid) const {
  978. return false;
  979. }
  980. void NativeMenuWindows::remove_item(const RID &p_rid, int p_idx) {
  981. ERR_FAIL_COND(p_idx < 0);
  982. const MenuData *md = menus.get_or_null(p_rid);
  983. ERR_FAIL_NULL(md);
  984. int count = GetMenuItemCount(md->menu);
  985. ERR_FAIL_COND(p_idx >= count);
  986. MENUITEMINFOW item;
  987. ZeroMemory(&item, sizeof(item));
  988. item.cbSize = sizeof(item);
  989. item.fMask = MIIM_DATA;
  990. if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
  991. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  992. if (item_data) {
  993. if (item_data->bmp) {
  994. DeleteObject(item_data->bmp);
  995. }
  996. memdelete(item_data);
  997. }
  998. }
  999. RemoveMenu(md->menu, p_idx, MF_BYPOSITION);
  1000. }
  1001. void NativeMenuWindows::clear(const RID &p_rid) {
  1002. const MenuData *md = menus.get_or_null(p_rid);
  1003. ERR_FAIL_NULL(md);
  1004. MENUITEMINFOW item;
  1005. int count = GetMenuItemCount(md->menu);
  1006. for (int i = 0; i < count; i++) {
  1007. ZeroMemory(&item, sizeof(item));
  1008. item.cbSize = sizeof(item);
  1009. item.fMask = MIIM_DATA;
  1010. if (GetMenuItemInfoW(md->menu, 0, true, &item)) {
  1011. MenuItemData *item_data = (MenuItemData *)item.dwItemData;
  1012. if (item_data) {
  1013. if (item_data->bmp) {
  1014. DeleteObject(item_data->bmp);
  1015. }
  1016. memdelete(item_data);
  1017. }
  1018. }
  1019. RemoveMenu(md->menu, 0, MF_BYPOSITION);
  1020. }
  1021. }
  1022. NativeMenuWindows::NativeMenuWindows() {}
  1023. NativeMenuWindows::~NativeMenuWindows() {}