ui_menu.ts 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660
  1. let ui_menu_show: bool = false;
  2. let ui_menu_category: i32 = 0;
  3. let ui_menu_x: i32 = 0;
  4. let ui_menu_y: i32 = 0;
  5. let ui_menu_h: i32 = 0;
  6. let ui_menu_elements: i32 = 0; ////
  7. let ui_menu_keep_open: bool = false;
  8. let ui_menu_commands: (ui: ui_t)=>void = null;
  9. let ui_menu_show_first: bool = true;
  10. let ui_menu_hide_flag: bool = false;
  11. let _ui_menu_render_msg: string;
  12. type update_info_t = {
  13. version: i32;
  14. version_name: string;
  15. };
  16. function ui_menu_render() {
  17. let ui: ui_t = base_ui_menu;
  18. let menu_w: i32 = ui_menu_commands != null ?
  19. math_floor(base_default_element_w * ui_SCALE(base_ui_menu) * 2.3) :
  20. math_floor(ui_ELEMENT_W(ui) * 2.3);
  21. let _FILL_BUTTON_BG: i32 = ui.ops.theme.FILL_BUTTON_BG;
  22. ui.ops.theme.FILL_BUTTON_BG = false;
  23. let _ELEMENT_OFFSET: i32 = ui.ops.theme.ELEMENT_OFFSET;
  24. ui.ops.theme.ELEMENT_OFFSET = 0;
  25. let _ELEMENT_H: i32 = ui.ops.theme.ELEMENT_H;
  26. ui.ops.theme.ELEMENT_H = config_raw.touch_ui ? (28 + 2) : 28;
  27. // First draw out of screen, then align the menu based on menu height
  28. if (ui_menu_show_first) {
  29. ui_menu_x -= iron_window_width() * 2;
  30. ui_menu_y -= iron_window_height() * 2;
  31. }
  32. draw_begin();
  33. ui_begin_region(ui, ui_menu_x, ui_menu_y, menu_w);
  34. ui_menu_start(ui);
  35. if (ui_menu_commands != null) {
  36. ui_menu_commands(ui);
  37. }
  38. else {
  39. if (ui_menu_category == menu_category_t.FILE) {
  40. if (ui_menu_button(tr("New Project..."), map_get(config_keymap, "file_new"))) {
  41. project_new_box();
  42. }
  43. if (ui_menu_button(tr("Open..."), map_get(config_keymap, "file_open"))) {
  44. project_open();
  45. }
  46. if (ui_menu_button(tr("Open Recent..."), map_get(config_keymap, "file_open_recent"))) {
  47. box_projects_show();
  48. }
  49. if (ui_menu_button(tr("Save"), map_get(config_keymap, "file_save"))) {
  50. project_save();
  51. }
  52. if (ui_menu_button(tr("Save As..."), map_get(config_keymap, "file_save_as"))) {
  53. project_save_as();
  54. }
  55. ui_menu_separator(ui);
  56. if (ui_menu_button(tr("Import Texture..."), map_get(config_keymap, "file_import_assets"))) {
  57. project_import_asset(string_array_join(path_texture_formats, ","), false);
  58. }
  59. if (ui_menu_button(tr("Import Envmap..."))) {
  60. ui_files_show("hdr", false, false, function (path: string) {
  61. if (!ends_with(path, ".hdr")) {
  62. console_error(tr("Error: .hdr file expected"));
  63. return;
  64. }
  65. import_asset_run(path);
  66. });
  67. }
  68. ///if is_paint
  69. if (ui_menu_button(tr("Import Font..."))) {
  70. project_import_asset("ttf,ttc,otf");
  71. }
  72. if (ui_menu_button(tr("Import Material..."))) {
  73. project_import_material();
  74. }
  75. if (ui_menu_button(tr("Import Brush..."))) {
  76. project_import_brush();
  77. }
  78. ///end
  79. ///if (is_paint || is_lab)
  80. if (ui_menu_button(tr("Import Swatches..."))) {
  81. project_import_swatches();
  82. }
  83. ///end
  84. if (ui_menu_button(tr("Import Mesh..."))) {
  85. project_import_mesh();
  86. }
  87. if (ui_menu_button(tr("Reimport Mesh"), map_get(config_keymap, "file_reimport_mesh"))) {
  88. project_reimport_mesh();
  89. }
  90. if (ui_menu_button(tr("Reimport Textures"), map_get(config_keymap, "file_reimport_textures"))) {
  91. project_reimport_textures();
  92. }
  93. ui_menu_separator(ui);
  94. ///if (is_paint || is_lab)
  95. if (ui_menu_button(tr("Export Textures..."), map_get(config_keymap, "file_export_textures_as"))) {
  96. context_raw.layers_export = export_mode_t.VISIBLE;
  97. box_export_show_textures();
  98. }
  99. if (ui_menu_button(tr("Export Swatches..."))) {
  100. project_export_swatches();
  101. }
  102. ///end
  103. if (ui_menu_button(tr("Export Mesh..."))) {
  104. context_raw.export_mesh_index = 0; // All
  105. box_export_show_mesh();
  106. }
  107. ///if is_paint
  108. if (ui_menu_button(tr("Bake Material..."))) {
  109. box_export_show_bake_material();
  110. }
  111. ///end
  112. ui_menu_separator(ui);
  113. if (ui_menu_button(tr("Exit"))) {
  114. iron_stop();
  115. }
  116. }
  117. else if (ui_menu_category == menu_category_t.EDIT) {
  118. let step_undo: string = "";
  119. let step_redo: string = "";
  120. if (history_undos > 0) {
  121. step_undo = history_steps[history_steps.length - 1 - history_redos].name;
  122. }
  123. if (history_redos > 0) {
  124. step_redo = history_steps[history_steps.length - history_redos].name;
  125. }
  126. ui.enabled = history_undos > 0;
  127. let vars_undo: map_t<string, string> = map_create();
  128. map_set(vars_undo, "step", step_undo);
  129. if (ui_menu_button(tr("Undo {step}", vars_undo), map_get(config_keymap, "edit_undo"))) {
  130. history_undo();
  131. }
  132. ui.enabled = history_redos > 0;
  133. let vars_redo: map_t<string, string> = map_create();
  134. map_set(vars_redo, "step", step_redo);
  135. if (ui_menu_button(tr("Redo {step}", vars_redo), map_get(config_keymap, "edit_redo"))) {
  136. history_redo();
  137. }
  138. ui.enabled = true;
  139. ui_menu_separator(ui);
  140. if (ui_menu_button(tr("Preferences..."), map_get(config_keymap, "edit_prefs"))) {
  141. box_preferences_show();
  142. }
  143. }
  144. else if (ui_menu_category == menu_category_t.VIEWPORT) {
  145. if (ui_menu_button(tr("Distract Free"), map_get(config_keymap, "view_distract_free"))) {
  146. ui_base_toggle_distract_free();
  147. ui_base_ui.is_hovered = false;
  148. }
  149. ///if !(arm_android || arm_ios)
  150. if (ui_menu_button(tr("Toggle Fullscreen"), "alt+enter")) {
  151. base_toggle_fullscreen();
  152. }
  153. ///end
  154. ui.changed = false;
  155. let p: world_data_t = scene_world;
  156. let env_handle: ui_handle_t = ui_handle(__ID__);
  157. env_handle.value = p.strength;
  158. ui_menu_align(ui);
  159. p.strength = ui_slider(env_handle, tr("Environment"), 0.0, 8.0, true);
  160. if (env_handle.changed) {
  161. context_raw.ddirty = 2;
  162. }
  163. let enva_handle: ui_handle_t = ui_handle(__ID__);
  164. enva_handle.value = context_raw.envmap_angle / math_pi() * 180.0;
  165. if (enva_handle.value < 0) {
  166. enva_handle.value += (math_floor(-enva_handle.value / 360) + 1) * 360;
  167. }
  168. else if (enva_handle.value > 360) {
  169. enva_handle.value -= math_floor(enva_handle.value / 360) * 360;
  170. }
  171. ui_menu_align(ui);
  172. context_raw.envmap_angle = ui_slider(enva_handle, tr("Environment Angle"), 0.0, 360.0, true, 1) / 180.0 * math_pi();
  173. if (ui.is_hovered) {
  174. let vars: map_t<string, string> = map_create();
  175. map_set(vars, "shortcut", map_get(config_keymap, "rotate_envmap"));
  176. ui_tooltip(tr("{shortcut} and move mouse", vars));
  177. }
  178. if (enva_handle.changed) {
  179. context_raw.ddirty = 2;
  180. }
  181. ///if is_paint
  182. let split_view_handle: ui_handle_t = ui_handle(__ID__);
  183. if (split_view_handle.init) {
  184. split_view_handle.selected = context_raw.split_view;
  185. }
  186. context_raw.split_view = ui_check(split_view_handle, " " + tr("Split View"));
  187. if (split_view_handle.changed) {
  188. base_resize();
  189. }
  190. ///end
  191. ///if is_lab
  192. let brush_scale_handle: ui_handle_t = ui_handle(__ID__);
  193. if (brush_scale_handle.init) {
  194. brush_scale_handle.value = context_raw.brush_scale;
  195. }
  196. ui_menu_align(ui);
  197. context_raw.brush_scale = ui_slider(brush_scale_handle, tr("UV Scale"), 0.01, 5.0, true);
  198. if (brush_scale_handle.changed) {
  199. make_material_parse_mesh_material();
  200. render_path_raytrace_uv_scale = context_raw.brush_scale;
  201. render_path_raytrace_ready = false;
  202. }
  203. ///end
  204. let cull_handle: ui_handle_t = ui_handle(__ID__);
  205. if (cull_handle.init) {
  206. cull_handle.selected = context_raw.cull_backfaces;
  207. }
  208. context_raw.cull_backfaces = ui_check(cull_handle, " " + tr("Cull Backfaces"));
  209. if (cull_handle.changed) {
  210. make_material_parse_mesh_material();
  211. }
  212. let filter_handle: ui_handle_t = ui_handle(__ID__);
  213. if (filter_handle.init) {
  214. filter_handle.selected = context_raw.texture_filter;
  215. }
  216. context_raw.texture_filter = ui_check(filter_handle, " " + tr("Filter Textures"));
  217. if (filter_handle.changed) {
  218. make_material_parse_paint_material();
  219. make_material_parse_mesh_material();
  220. }
  221. ///if is_paint
  222. context_raw.draw_wireframe = ui_check(context_raw.wireframe_handle, " " + tr("Wireframe"));
  223. if (context_raw.wireframe_handle.changed) {
  224. let current: gpu_texture_t = _draw_current;
  225. draw_end();
  226. util_uv_cache_uv_map();
  227. draw_begin(current);
  228. make_material_parse_mesh_material();
  229. }
  230. ///end
  231. ///if is_paint
  232. context_raw.draw_texels = ui_check(context_raw.texels_handle, " " + tr("Texels"));
  233. if (context_raw.texels_handle.changed) {
  234. make_material_parse_mesh_material();
  235. }
  236. ///end
  237. let compass_handle: ui_handle_t = ui_handle(__ID__);
  238. if (compass_handle.init) {
  239. compass_handle.selected = context_raw.show_compass;
  240. }
  241. context_raw.show_compass = ui_check(compass_handle, " " + tr("Compass"));
  242. if (compass_handle.changed) {
  243. context_raw.ddirty = 2;
  244. }
  245. context_raw.show_envmap = ui_check(context_raw.show_envmap_handle, " " + tr("Envmap"));
  246. if (context_raw.show_envmap_handle.changed) {
  247. context_load_envmap();
  248. context_raw.ddirty = 2;
  249. }
  250. context_raw.show_envmap_blur = ui_check(context_raw.show_envmap_blur_handle, " " + tr("Blur Envmap"));
  251. if (context_raw.show_envmap_blur_handle.changed) {
  252. context_raw.ddirty = 2;
  253. }
  254. context_update_envmap();
  255. if (ui.changed) {
  256. ui_menu_keep_open = true;
  257. }
  258. }
  259. else if (ui_menu_category == menu_category_t.MODE) {
  260. let mode_handle: ui_handle_t = ui_handle(__ID__);
  261. mode_handle.position = context_raw.viewport_mode;
  262. let modes: string[] = [
  263. tr("Lit"),
  264. tr("Base Color"),
  265. ///if (is_paint || is_lab)
  266. tr("Normal"),
  267. tr("Occlusion"),
  268. tr("Roughness"),
  269. tr("Metallic"),
  270. tr("Opacity"),
  271. tr("Height"),
  272. ///end
  273. ///if (is_paint)
  274. tr("Emission"),
  275. tr("Subsurface"),
  276. ///end
  277. ///if is_paint
  278. tr("TexCoord"),
  279. tr("Object Normal"),
  280. tr("Material ID"),
  281. tr("Object ID"),
  282. tr("Mask")
  283. ///end
  284. ];
  285. let shortcuts: string[] = ["l", "b", "n", "o", "r", "m", "a", "h", "e", "s", "t", "1", "2", "3", "4"];
  286. if (gpu_raytrace_supported()) {
  287. array_push(modes, tr("Path Traced"));
  288. array_push(shortcuts, "p");
  289. }
  290. for (let i: i32 = 0; i < modes.length; ++i) {
  291. let shortcut: string = config_raw.touch_ui ? "" : map_get(config_keymap, "viewport_mode") + ", " + shortcuts[i];
  292. ui_radio(mode_handle, i, modes[i], shortcut);
  293. }
  294. if (mode_handle.changed) {
  295. context_set_viewport_mode(mode_handle.position);
  296. // TODO: rotate mode is not supported for path tracing yet
  297. if (mode_handle.position == viewport_mode_t.PATH_TRACE && context_raw.camera_controls == camera_controls_t.ROTATE) {
  298. context_raw.camera_controls = camera_controls_t.ORBIT;
  299. viewport_reset();
  300. }
  301. }
  302. }
  303. else if (ui_menu_category == menu_category_t.CAMERA) {
  304. if (ui_menu_button(tr("Reset"), map_get(config_keymap, "view_reset"))) {
  305. viewport_reset();
  306. viewport_scale_to_bounds();
  307. }
  308. ui_menu_separator(ui);
  309. if (ui_menu_button(tr("Front"), map_get(config_keymap, "view_front"))) {
  310. viewport_set_view(0, -1, 0, math_pi() / 2, 0, 0);
  311. }
  312. if (ui_menu_button(tr("Back"), map_get(config_keymap, "view_back"))) {
  313. viewport_set_view(0, 1, 0, math_pi() / 2, 0, math_pi());
  314. }
  315. if (ui_menu_button(tr("Right"), map_get(config_keymap, "view_right"))) {
  316. viewport_set_view(1, 0, 0, math_pi() / 2, 0, math_pi() / 2);
  317. }
  318. if (ui_menu_button(tr("Left"), map_get(config_keymap, "view_left"))) {
  319. viewport_set_view(-1, 0, 0, math_pi() / 2, 0, -math_pi() / 2);
  320. }
  321. if (ui_menu_button(tr("Top"), map_get(config_keymap, "view_top"))) {
  322. viewport_set_view(0, 0, 1, 0, 0, 0);
  323. }
  324. if (ui_menu_button(tr("Bottom"), map_get(config_keymap, "view_bottom"))) {
  325. viewport_set_view(0, 0, -1, math_pi(), 0, math_pi());
  326. }
  327. ui_menu_separator(ui);
  328. ui.changed = false;
  329. if (ui_menu_button(tr("Orbit Left"), map_get(config_keymap, "view_orbit_left"))) {
  330. viewport_orbit(-math_pi() / 12, 0);
  331. }
  332. if (ui_menu_button(tr("Orbit Right"), map_get(config_keymap, "view_orbit_right"))) {
  333. viewport_orbit(math_pi() / 12, 0);
  334. }
  335. if (ui_menu_button(tr("Orbit Up"), map_get(config_keymap, "view_orbit_up"))) {
  336. viewport_orbit(0, -math_pi() / 12);
  337. }
  338. if (ui_menu_button(tr("Orbit Down"), map_get(config_keymap, "view_orbit_down"))) {
  339. viewport_orbit(0, math_pi() / 12);
  340. }
  341. if (ui_menu_button(tr("Orbit Opposite"), map_get(config_keymap, "view_orbit_opposite"))) {
  342. viewport_orbit_opposite();
  343. }
  344. if (ui_menu_button(tr("Zoom In"), map_get(config_keymap, "view_zoom_in"))) {
  345. viewport_zoom(0.2);
  346. }
  347. if (ui_menu_button(tr("Zoom Out"), map_get(config_keymap, "view_zoom_out"))) {
  348. viewport_zoom(-0.2);
  349. }
  350. let cam: camera_object_t = scene_camera;
  351. context_raw.fov_handle = ui_handle(__ID__);
  352. if (context_raw.fov_handle.init) {
  353. context_raw.fov_handle.value = math_floor(cam.data.fov * 100) / 100;
  354. }
  355. ui_menu_align(ui);
  356. cam.data.fov = ui_slider(context_raw.fov_handle, tr("FoV"), 0.3, 1.4, true);
  357. if (context_raw.fov_handle.changed) {
  358. viewport_update_camera_type(context_raw.camera_type);
  359. }
  360. ui_menu_align(ui);
  361. let camera_controls_handle: ui_handle_t = ui_handle(__ID__);
  362. camera_controls_handle.position = context_raw.camera_controls;
  363. let camera_controls_items: string[] = [tr("Orbit"), tr("Rotate"), tr("Fly")];
  364. context_raw.camera_controls = ui_inline_radio(camera_controls_handle, camera_controls_items, ui_align_t.LEFT);
  365. let vars: map_t<string, string> = map_create();
  366. map_set(vars, "rotate_shortcut", map_get(config_keymap, "action_rotate"));
  367. map_set(vars, "zoom_shortcut", map_get(config_keymap, "action_zoom"));
  368. map_set(vars, "pan_shortcut", map_get(config_keymap, "action_pan"));
  369. let orbit_and_rotate_tooltip: string = tr("Orbit and Rotate mode:\n{rotate_shortcut} or move right mouse button to rotate.\n{zoom_shortcut} or scroll to zoom.\n{pan_shortcut} or move middle mouse to pan.", vars);
  370. let fly_tooltip: string = tr("Fly mode:\nHold the right mouse button and one of the following commands:\nmove mouse to rotate.\nw, up or scroll up to move forward.\ns, down or scroll down to move backward.\na or left to move left.\nd or right to move right.\ne to move up.\nq to move down.\nHold shift to move faster or alt to move slower.");
  371. if (ui.is_hovered) {
  372. ui_tooltip(orbit_and_rotate_tooltip + "\n\n" + fly_tooltip);
  373. }
  374. ui_menu_align(ui);
  375. let camera_type_items: string[] = [tr("Perspective"), tr("Orthographic")];
  376. context_raw.camera_type = ui_inline_radio(context_raw.cam_handle, camera_type_items, ui_align_t.LEFT);
  377. if (ui.is_hovered) {
  378. ui_tooltip(tr("Camera Type") + " (" + map_get(config_keymap, "view_camera_type") + ")");
  379. }
  380. if (context_raw.cam_handle.changed) {
  381. viewport_update_camera_type(context_raw.camera_type);
  382. }
  383. if (ui.changed) {
  384. ui_menu_keep_open = true;
  385. }
  386. }
  387. else if (ui_menu_category == menu_category_t.HELP) {
  388. if (ui_menu_button(tr("Manual"))) {
  389. file_load_url(manifest_url + "/manual");
  390. }
  391. if (ui_menu_button(tr("How To"))) {
  392. file_load_url(manifest_url + "/howto");
  393. }
  394. if (ui_menu_button(tr("What's New"))) {
  395. file_load_url(manifest_url + "/notes");
  396. }
  397. if (ui_menu_button(tr("Issue Tracker"))) {
  398. file_load_url("https://github.com/armory3d/armortools/issues");
  399. }
  400. if (ui_menu_button(tr("Report Bug"))) {
  401. ///if (arm_macos || arm_ios) // Limited url length
  402. file_load_url("https://github.com/armory3d/armortools/issues/new?labels=bug&template=bug_report.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id());
  403. ///else
  404. file_load_url("https://github.com/armory3d/armortools/issues/new?labels=bug&template=bug_report.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id() + "*%0A%0A**Issue description:**%0A%0A**Steps to reproduce:**%0A%0A");
  405. ///end
  406. }
  407. if (ui_menu_button(tr("Request Feature"))) {
  408. ///if (arm_macos || arm_ios) // Limited url length
  409. file_load_url("https://github.com/armory3d/armortools/issues/new?labels=feature%20request&template=feature_request.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id());
  410. ///else
  411. file_load_url("https://github.com/armory3d/armortools/issues/new?labels=feature%20request&template=feature_request.md&body=*" + manifest_title + "%20" + manifest_version + "-" + config_get_sha() + ",%20" + iron_system_id() + "*%0A%0A**Feature description:**%0A%0A");
  412. ///end
  413. }
  414. ui_menu_separator(ui);
  415. if (ui_menu_button(tr("Check for Updates..."))) {
  416. ///if arm_android
  417. file_load_url(manifest_url_android);
  418. ///elseif arm_ios
  419. file_load_url(manifest_url_ios);
  420. ///else
  421. // Retrieve latest version number
  422. file_download_bytes("https://server.armorpaint.org/" + to_lower_case(manifest_title) + ".html", function (url: string, buffer: buffer_t) {
  423. if (buffer != null) {
  424. // Compare versions
  425. let update: update_info_t = json_parse(sys_buffer_to_string(buffer));
  426. let update_version: i32 = math_floor(update.version);
  427. if (update_version > 0) {
  428. let date: string = config_get_date(); // 2019 -> 19
  429. date = substring(date, 2, date.length);
  430. let date_int: i32 = parse_int(string_replace_all(date, "-", ""));
  431. if (update_version > date_int) {
  432. let vars: map_t<string, string> = map_create();
  433. map_set(vars, "url", manifest_url);
  434. ui_box_show_message(tr("Update"), tr("Update is available!\nPlease visit {url}.", vars));
  435. }
  436. else {
  437. ui_box_show_message(tr("Update"), tr("You are up to date!"));
  438. }
  439. }
  440. }
  441. else {
  442. let vars: map_t<string, string> = map_create();
  443. map_set(vars, "url", manifest_url);
  444. ui_box_show_message(tr("Update"), tr("Unable to check for updates.\nPlease visit {url}.", vars));
  445. }
  446. });
  447. ///end
  448. }
  449. if (ui_menu_button(tr("About..."))) {
  450. let msg: string = manifest_title + ".org - v" + manifest_version + " (" + config_get_date() + ") - " + config_get_sha() + "\n";
  451. msg += iron_system_id() + " - " + strings_graphics_api();
  452. ///if arm_windows
  453. let save: string;
  454. if (path_is_protected()) {
  455. save = iron_internal_save_path();
  456. }
  457. else {
  458. save = path_data();
  459. }
  460. save += path_sep + "tmp.txt";
  461. iron_sys_command("wmic path win32_VideoController get name > \"" + save + "\"");
  462. let blob: buffer_t = iron_load_blob(save);
  463. let u8: u8_array_t = blob;
  464. let gpu_raw: string = "";
  465. for (let i: i32 = 0; i < math_floor(u8.length / 2); ++i) {
  466. let c: string = string_from_char_code(u8[i * 2]);
  467. gpu_raw += c;
  468. }
  469. let gpus: string[] = string_split(gpu_raw, "\n");
  470. array_splice(gpus, 1, gpus.length - 2);
  471. let gpu: string = "";
  472. for (let i: i32 = 0; i < gpus.length; ++i) {
  473. let g: string = gpus[i];
  474. gpu += trim_end(g) + ", ";
  475. }
  476. gpu = substring(gpu, 0, gpu.length - 2);
  477. msg += "\n" + gpu;
  478. ///else
  479. // { lshw -C display }
  480. ///end
  481. _ui_menu_render_msg = msg;
  482. ui_box_show_custom(function (ui: ui_t) {
  483. let tab_vertical: bool = config_raw.touch_ui;
  484. if (ui_tab(ui_handle(__ID__), tr("About"), tab_vertical)) {
  485. let img: gpu_texture_t = data_get_image("badge.k");
  486. ui_image(img);
  487. _ui_end_element();
  488. let h: ui_handle_t = ui_handle(__ID__);
  489. if (h.init) {
  490. h.text = _ui_menu_render_msg;
  491. }
  492. ui_text_area(h, ui_align_t.LEFT, false);
  493. ui_row3();
  494. ///if (arm_windows || arm_linux || arm_macos)
  495. if (ui_button(tr("Copy"))) {
  496. iron_copy_to_clipboard(_ui_menu_render_msg);
  497. }
  498. ///else
  499. _ui_end_element();
  500. ///end
  501. if (ui_button(tr("Contributors"))) {
  502. file_load_url("https://github.com/armory3d/armortools/graphs/contributors");
  503. }
  504. if (ui_button(tr("OK"))) {
  505. ui_box_hide();
  506. }
  507. }
  508. }, 400, 320);
  509. }
  510. }
  511. }
  512. ui_menu_hide_flag = ui.combo_selected_handle == null && !ui_menu_keep_open && !ui_menu_show_first && (ui.changed || ui.input_released || ui.input_released_r || ui.is_escape_down);
  513. ui_menu_keep_open = false;
  514. ui.ops.theme.FILL_BUTTON_BG = _FILL_BUTTON_BG;
  515. ui.ops.theme.ELEMENT_OFFSET = _ELEMENT_OFFSET;
  516. ui.ops.theme.ELEMENT_H = _ELEMENT_H;
  517. ui_menu_end(ui);
  518. ui_end_region();
  519. draw_end();
  520. if (ui_menu_show_first) {
  521. ui_menu_show_first = false;
  522. ui_menu_h = ui._y - ui_menu_y;
  523. ui_menu_x += iron_window_width() * 2;
  524. ui_menu_y += iron_window_height() * 2;
  525. ui_menu_fit_to_screen();
  526. ui_menu_render(); // Render at correct position now
  527. }
  528. if (ui_menu_hide_flag) {
  529. ui_menu_hide();
  530. ui_menu_show_first = true;
  531. ui_menu_commands = null;
  532. }
  533. }
  534. function ui_menu_hide() {
  535. ui_menu_show = false;
  536. base_redraw_ui();
  537. }
  538. function ui_menu_draw(commands: (ui: ui_t)=>void = null, x: i32 = -1, y: i32 = -1) {
  539. ui_end_input();
  540. ui_menu_show = true;
  541. ui_menu_commands = commands;
  542. ui_menu_x = x > -1 ? x : math_floor(mouse_x + 1);
  543. ui_menu_y = y > -1 ? y : math_floor(mouse_y + 1);
  544. ui_menu_h = 0;
  545. }
  546. function ui_menu_fit_to_screen() {
  547. // Prevent the menu going out of screen
  548. let menu_w: f32 = base_default_element_w * ui_SCALE(base_ui_menu) * 2.3;
  549. if (ui_menu_x + menu_w > iron_window_width()) {
  550. if (ui_menu_x - menu_w > 0) {
  551. ui_menu_x = math_floor(ui_menu_x - menu_w);
  552. }
  553. else {
  554. ui_menu_x = math_floor(iron_window_width() - menu_w);
  555. }
  556. }
  557. if (ui_menu_y + ui_menu_h > iron_window_height()) {
  558. if (ui_menu_y - ui_menu_h > 0) {
  559. ui_menu_y = math_floor(ui_menu_y - ui_menu_h);
  560. }
  561. else {
  562. ui_menu_y = iron_window_height() - ui_menu_h;
  563. }
  564. ui_menu_x += 1; // Move out of mouse focus
  565. }
  566. }
  567. function ui_menu_separator(ui: ui_t) {
  568. ui._y++;
  569. if (config_raw.touch_ui) {
  570. ui_fill(0, 0, ui._w / ui_SCALE(ui), 1, ui.ops.theme.BUTTON_COL);
  571. }
  572. else {
  573. ui_fill(26, 0, ui._w / ui_SCALE(ui) - 26, 1, ui.ops.theme.BUTTON_COL);
  574. }
  575. }
  576. function ui_menu_button(text: string, label: string = ""): bool {
  577. if (config_raw.touch_ui) {
  578. label = "";
  579. }
  580. return ui_button(config_button_spacing + text, config_button_align, label);
  581. }
  582. function ui_menu_align(ui: ui_t) {
  583. if (!config_raw.touch_ui) {
  584. let row: f32[] = [12 / 100, 88 / 100];
  585. ui_row(row);
  586. _ui_end_element();
  587. }
  588. }
  589. function ui_menu_start(ui: ui_t) {
  590. ui_draw_shadow(ui._x, ui._y, ui._w, ui_menu_h);
  591. draw_set_color(ui.ops.theme.SEPARATOR_COL);
  592. ui_draw_rect(true, ui._x, ui._y, ui._w, ui_menu_h);
  593. draw_set_color(0xffffffff);
  594. }
  595. function ui_menu_end(ui: ui_t) {
  596. }