ui_view2d.ts 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. let ui_view2d_pipe: gpu_pipeline_t;
  2. let ui_view2d_channel_loc: i32;
  3. let ui_view2d_text_input_hover: bool = false;
  4. let ui_view2d_uvmap_show: bool = false;
  5. let ui_view2d_tex_type: paint_tex_t = paint_tex_t.BASE;
  6. let ui_view2d_layer_mode: view_2d_layer_mode_t = view_2d_layer_mode_t.SELECTED;
  7. ///if is_paint
  8. let ui_view2d_type: view_2d_type_t = view_2d_type_t.LAYER;
  9. ///else
  10. let ui_view2d_type: view_2d_type_t = view_2d_type_t.ASSET;
  11. ///end
  12. let ui_view2d_show: bool = false;
  13. let ui_view2d_wx: i32;
  14. let ui_view2d_wy: i32;
  15. let ui_view2d_ww: i32;
  16. let ui_view2d_wh: i32;
  17. let ui_view2d_ui: ui_t;
  18. let ui_view2d_hwnd: ui_handle_t = ui_handle_create();
  19. let ui_view2d_pan_x: f32 = 0.0;
  20. let ui_view2d_pan_y: f32 = 0.0;
  21. let ui_view2d_pan_scale: f32 = 1.0;
  22. let ui_view2d_tiled_show: bool = false;
  23. let ui_view2d_controls_down: bool = false;
  24. let _ui_view2d_render_tex: gpu_texture_t;
  25. let _ui_view2d_render_x: f32;
  26. let _ui_view2d_render_y: f32;
  27. let _ui_view2d_render_tw: f32;
  28. let _ui_view2d_render_th: f32;
  29. let ui_view2d_grid: gpu_texture_t = null;
  30. let ui_view2d_grid_redraw: bool = true;
  31. function ui_view2d_init() {
  32. ///if is_paint
  33. ui_view2d_pipe = gpu_create_pipeline();
  34. ui_view2d_pipe.vertex_shader = sys_get_shader("layer_view.vert");
  35. ui_view2d_pipe.fragment_shader = sys_get_shader("layer_view.frag");
  36. let vs: gpu_vertex_structure_t = {};
  37. gpu_vertex_struct_add(vs, "pos", vertex_data_t.F32_2X);
  38. ui_view2d_pipe.input_layout = vs;
  39. ui_view2d_pipe.blend_source = blend_factor_t.BLEND_ONE;
  40. ui_view2d_pipe.blend_destination = blend_factor_t.BLEND_ZERO;
  41. ARRAY_ACCESS(ui_view2d_pipe.color_write_mask_alpha, 0) = false;
  42. gpu_pipeline_compile(ui_view2d_pipe);
  43. pipes_offset = 0;
  44. pipes_get_constant_location("mat4");
  45. pipes_get_constant_location("float4");
  46. pipes_get_constant_location("float4");
  47. pipes_get_constant_location("float4");
  48. ui_view2d_channel_loc = pipes_get_constant_location("int");
  49. ///end
  50. let scale: f32 = config_raw.window_scale;
  51. let ops: ui_options_t = {
  52. theme: base_theme,
  53. font: base_font,
  54. color_wheel: base_color_wheel,
  55. black_white_gradient: base_color_wheel_gradient,
  56. scale_factor: scale
  57. };
  58. ui_view2d_ui = ui_create(ops);
  59. ui_view2d_ui.scroll_enabled = false;
  60. }
  61. function ui_view2d_render() {
  62. ui_view2d_ww = config_raw.layout[layout_size_t.NODES_W];
  63. ///if is_paint
  64. ui_view2d_wx = math_floor(sys_w()) + ui_toolbar_w(true);
  65. ///else
  66. ui_view2d_wx = math_floor(sys_w());
  67. ///end
  68. ui_view2d_wy = 0;
  69. ///if is_paint
  70. if (!ui_base_show) {
  71. ui_view2d_ww += config_raw.layout[layout_size_t.SIDEBAR_W] + ui_toolbar_w(true);
  72. ui_view2d_wx -= ui_toolbar_w(true);
  73. }
  74. ///end
  75. if (!ui_view2d_show) {
  76. return;
  77. }
  78. if (iron_window_width() == 0 || iron_window_height() == 0) {
  79. return;
  80. }
  81. if (context_raw.pdirty >= 0) {
  82. ui_view2d_hwnd.redraws = 2; // Paint was active
  83. }
  84. // Cache grid
  85. if (ui_view2d_grid_redraw) {
  86. if (ui_view2d_grid != null) {
  87. iron_delete_texture(ui_view2d_grid);
  88. }
  89. ui_view2d_grid = ui_nodes_draw_grid(ui_view2d_pan_scale);
  90. ui_view2d_grid_redraw = false;
  91. }
  92. // Ensure UV map is drawn
  93. ///if is_paint
  94. if (ui_view2d_uvmap_show) {
  95. util_uv_cache_uv_map();
  96. }
  97. ///end
  98. // Ensure font image is drawn
  99. ///if is_paint
  100. if (context_raw.font.image == null) {
  101. util_render_make_font_preview();
  102. }
  103. ///end
  104. ui_begin(ui_view2d_ui);
  105. let headerh: i32 = config_raw.layout[layout_size_t.HEADER] == 1 ? ui_header_h * 2 : ui_header_h;
  106. let apph: i32 = iron_window_height() - config_raw.layout[layout_size_t.STATUS_H] + headerh;
  107. ui_view2d_wh = iron_window_height() - config_raw.layout[layout_size_t.STATUS_H];
  108. if (ui_nodes_show) {
  109. ui_view2d_wh -= config_raw.layout[layout_size_t.NODES_H];
  110. if (config_raw.touch_ui) {
  111. ui_view2d_wh += ui_header_h;
  112. }
  113. }
  114. if (ui_window(ui_view2d_hwnd, ui_view2d_wx, ui_view2d_wy, ui_view2d_ww, ui_view2d_wh)) {
  115. ui_tab(ui_handle(__ID__), tr("2D View"));
  116. // Grid
  117. draw_set_color(0xffffffff);
  118. let step: f32 = ui_nodes_grid_cell_w * ui_view2d_pan_scale;
  119. let x: f32 = math_fmod(ui_view2d_pan_x, step) - step;
  120. let y: f32 = math_fmod(ui_view2d_pan_y, step) - step;
  121. draw_image(ui_view2d_grid, x, y);
  122. // Texture
  123. let tex: gpu_texture_t = null;
  124. let l: slot_layer_t = context_raw.layer;
  125. let channel: i32 = 0;
  126. let tw: f32 = ui_view2d_ww * 0.95 * ui_view2d_pan_scale;
  127. let tx: f32 = ui_view2d_ww / 2 - tw / 2 + ui_view2d_pan_x;
  128. let ty: f32 = apph / 2 - tw / 2 + ui_view2d_pan_y;
  129. if (ui_view2d_type == view_2d_type_t.ASSET) {
  130. tex = project_get_image(context_raw.texture);
  131. }
  132. else if (ui_view2d_type == view_2d_type_t.NODE) {
  133. ///if is_paint
  134. tex = context_raw.node_preview;
  135. ///else
  136. let nodes: ui_nodes_t = ui_nodes_get_nodes();
  137. if (nodes.nodes_selected_id.length > 0) {
  138. let sel: ui_node_t = ui_get_node(ui_nodes_get_canvas(true).nodes, nodes.nodes_selected_id[0]);
  139. let brush_node: logic_node_ext_t = parser_logic_get_logic_node(sel);
  140. if (brush_node != null) {
  141. tex = logic_node_get_cached_image(brush_node.base);
  142. }
  143. }
  144. ///end
  145. }
  146. else if (ui_view2d_type == view_2d_type_t.LAYER) {
  147. let layer: slot_layer_t = l;
  148. if (config_raw.brush_live && render_path_paint_live_layer_drawn > 0) {
  149. layer = render_path_paint_live_layer;
  150. }
  151. if (ui_view2d_layer_mode == view_2d_layer_mode_t.VISIBLE) {
  152. let current: gpu_texture_t = _draw_current;
  153. let in_use: bool = gpu_in_use;
  154. if (in_use) draw_end();
  155. layer = layers_flatten();
  156. if (in_use) draw_begin(current);
  157. }
  158. else if (slot_layer_is_group(layer)) {
  159. let current: gpu_texture_t = _draw_current;
  160. let in_use: bool = gpu_in_use;
  161. if (in_use) draw_end();
  162. layer = layers_flatten(false, slot_layer_get_children(layer));
  163. if (in_use) draw_begin(current);
  164. }
  165. tex =
  166. slot_layer_is_mask(context_raw.layer) ? layer.texpaint :
  167. ui_view2d_tex_type == paint_tex_t.BASE ? layer.texpaint :
  168. ui_view2d_tex_type == paint_tex_t.OPACITY ? layer.texpaint :
  169. ui_view2d_tex_type == paint_tex_t.NORMAL ? layer.texpaint_nor :
  170. layer.texpaint_pack;
  171. channel =
  172. slot_layer_is_mask(context_raw.layer) ? 1 :
  173. ui_view2d_tex_type == paint_tex_t.OCCLUSION ? 1 :
  174. ui_view2d_tex_type == paint_tex_t.ROUGHNESS ? 2 :
  175. ui_view2d_tex_type == paint_tex_t.METALLIC ? 3 :
  176. ui_view2d_tex_type == paint_tex_t.OPACITY ? 4 :
  177. ui_view2d_tex_type == paint_tex_t.HEIGHT ? 4 :
  178. ui_view2d_tex_type == paint_tex_t.NORMAL ? 5 :
  179. 0;
  180. }
  181. else if (ui_view2d_type == view_2d_type_t.FONT) {
  182. tex = context_raw.font.image;
  183. }
  184. let th: f32 = tw;
  185. if (tex != null) {
  186. th = tw * (tex.height / tex.width);
  187. ty = apph / 2 - th / 2 + ui_view2d_pan_y;
  188. ///if is_paint
  189. if (ui_view2d_type == view_2d_type_t.LAYER) {
  190. draw_set_pipeline(ui_view2d_pipe);
  191. if (!context_raw.texture_filter) {
  192. draw_set_bilinear_filter(false);
  193. }
  194. gpu_set_int(ui_view2d_channel_loc, channel);
  195. }
  196. ///end
  197. draw_scaled_image(tex, tx, ty, tw, th);
  198. if (ui_view2d_tiled_show) {
  199. draw_scaled_image(tex, tx - tw, ty, tw, th);
  200. draw_scaled_image(tex, tx - tw, ty - th, tw, th);
  201. draw_scaled_image(tex, tx - tw, ty + th, tw, th);
  202. draw_scaled_image(tex, tx + tw, ty, tw, th);
  203. draw_scaled_image(tex, tx + tw, ty - th, tw, th);
  204. draw_scaled_image(tex, tx + tw, ty + th, tw, th);
  205. draw_scaled_image(tex, tx, ty - th, tw, th);
  206. draw_scaled_image(tex, tx, ty + th, tw, th);
  207. }
  208. ///if is_paint
  209. if (ui_view2d_type == view_2d_type_t.LAYER) {
  210. draw_set_pipeline(null);
  211. if (!context_raw.texture_filter) {
  212. draw_set_bilinear_filter(true);
  213. }
  214. }
  215. // Texture and node preview color picking
  216. if ((context_in_2d_view(view_2d_type_t.ASSET) || context_in_2d_view(view_2d_type_t.NODE)) && context_raw.tool == workspace_tool_t.PICKER && ui_view2d_ui.input_down) {
  217. _ui_view2d_render_tex = tex;
  218. _ui_view2d_render_x = ui_view2d_ui.input_x - tx - ui_view2d_wx;;
  219. _ui_view2d_render_y = ui_view2d_ui.input_y - ty - ui_view2d_wy;
  220. _ui_view2d_render_tw = tw;
  221. _ui_view2d_render_th = th;
  222. sys_notify_on_next_frame(function () {
  223. let rt: render_target_t = map_get(render_path_render_targets, "texpaint_picker");
  224. let texpaint_picker: gpu_texture_t = rt._image;
  225. draw_begin(texpaint_picker);
  226. draw_scaled_image(_ui_view2d_render_tex, -_ui_view2d_render_x, -_ui_view2d_render_y, _ui_view2d_render_tw, _ui_view2d_render_th);
  227. draw_end();
  228. let a: buffer_t = gpu_get_texture_pixels(texpaint_picker);
  229. ///if (arm_metal || arm_vulkan)
  230. let i0: i32 = 2;
  231. let i1: i32 = 1;
  232. let i2: i32 = 0;
  233. ///else
  234. let i0: i32 = 0;
  235. let i1: i32 = 1;
  236. let i2: i32 = 2;
  237. ///end
  238. context_raw.picked_color.base = color_set_rb(context_raw.picked_color.base, buffer_get_u8(a, i0));
  239. context_raw.picked_color.base = color_set_gb(context_raw.picked_color.base, buffer_get_u8(a, i1));
  240. context_raw.picked_color.base = color_set_bb(context_raw.picked_color.base, buffer_get_u8(a, i2));
  241. ui_header_handle.redraws = 2;
  242. });
  243. }
  244. ///end
  245. }
  246. ///if is_paint
  247. // UV map
  248. if (ui_view2d_type == view_2d_type_t.LAYER && ui_view2d_uvmap_show) {
  249. draw_scaled_image(util_uv_uvmap, tx, ty, tw, th);
  250. }
  251. ///end
  252. // Menu
  253. let ew: i32 = math_floor(ui_ELEMENT_W(ui_view2d_ui));
  254. draw_set_color(ui_view2d_ui.ops.theme.SEPARATOR_COL);
  255. draw_filled_rect(0, ui_ELEMENT_H(ui_view2d_ui), ui_view2d_ww, ui_ELEMENT_H(ui_view2d_ui) + ui_ELEMENT_OFFSET(ui_view2d_ui) * 2);
  256. draw_set_color(0xffffffff);
  257. let start_y: f32 = ui_ELEMENT_H(ui_view2d_ui) + ui_ELEMENT_OFFSET(ui_view2d_ui);
  258. ui_view2d_ui._x = 2;
  259. ui_view2d_ui._y = 2 + start_y;
  260. ui_view2d_ui._w = ew;
  261. // Editable layer name
  262. let h: ui_handle_t = ui_handle(__ID__);
  263. ///if is_paint
  264. let text: string = ui_view2d_type == view_2d_type_t.NODE ? context_raw.node_preview_name : h.text;
  265. ///else
  266. let text: string = h.text;
  267. ///end
  268. ui_view2d_ui._w = math_floor(math_min(draw_string_width(ui_view2d_ui.ops.font, ui_view2d_ui.font_size, text) + 15 * ui_SCALE(ui_view2d_ui), 100 * ui_SCALE(ui_view2d_ui)));
  269. if (ui_view2d_type == view_2d_type_t.ASSET) {
  270. let asset: asset_t = context_raw.texture;
  271. if (asset != null) {
  272. let asset_names: string[] = project_asset_names;
  273. let i: i32 = array_index_of(asset_names, asset.name);
  274. h.text = asset.name;
  275. asset.name = ui_text_input(h, "");
  276. asset_names[i] = asset.name;
  277. }
  278. }
  279. else if (ui_view2d_type == view_2d_type_t.NODE) {
  280. ///if is_paint
  281. ui_text(context_raw.node_preview_name);
  282. ///else
  283. let nodes: ui_nodes_t = ui_nodes_get_nodes();
  284. if (nodes.nodes_selected_id.length > 0) {
  285. ui_text(ui_get_node(ui_nodes_get_canvas(true).nodes, nodes.nodes_selected_id[0]).name);
  286. }
  287. ///end
  288. }
  289. ///if is_paint
  290. else if (ui_view2d_type == view_2d_type_t.LAYER) {
  291. h.text = l.name;
  292. l.name = ui_text_input(h, "");
  293. ui_view2d_text_input_hover = ui_view2d_ui.is_hovered;
  294. }
  295. else if (ui_view2d_type == view_2d_type_t.FONT) {
  296. h.text = context_raw.font.name;
  297. context_raw.font.name = ui_text_input(h, "");
  298. }
  299. ///end
  300. if (h.changed) {
  301. ui_base_hwnds[0].redraws = 2;
  302. }
  303. ui_view2d_ui._x += ui_view2d_ui._w + 3;
  304. ui_view2d_ui._y = 2 + start_y;
  305. ui_view2d_ui._w = ew;
  306. ///if is_paint
  307. if (ui_view2d_type == view_2d_type_t.LAYER) {
  308. let h_layer_mode: ui_handle_t = ui_handle(__ID__);
  309. if (h_layer_mode.init) {
  310. h_layer_mode.position = ui_view2d_layer_mode;
  311. }
  312. let layer_mode_combo: string[] = [tr("Visible"), tr("Selected")];
  313. ui_view2d_layer_mode = ui_combo(h_layer_mode, layer_mode_combo, tr("Layers"));
  314. ui_view2d_ui._x += ew + 3;
  315. ui_view2d_ui._y = 2 + start_y;
  316. if (!slot_layer_is_mask(context_raw.layer)) {
  317. let h_tex_type: ui_handle_t = ui_handle(__ID__);
  318. if (h_tex_type.init) {
  319. h_tex_type.position = ui_view2d_tex_type;
  320. }
  321. let tex_type_combo: string[] = [
  322. tr("Base Color"),
  323. tr("Normal Map"),
  324. tr("Occlusion"),
  325. tr("Roughness"),
  326. tr("Metallic"),
  327. tr("Opacity"),
  328. tr("Height"),
  329. ];
  330. ui_view2d_tex_type = ui_combo(h_tex_type, tex_type_combo, tr("Texture"));
  331. ui_view2d_ui._x += ew + 3;
  332. ui_view2d_ui._y = 2 + start_y;
  333. }
  334. ui_view2d_ui._w = math_floor(ew * 0.7 + 3);
  335. let h_uvmap_show: ui_handle_t = ui_handle(__ID__);
  336. if (h_uvmap_show.init) {
  337. h_uvmap_show.selected = ui_view2d_uvmap_show;
  338. }
  339. ui_view2d_uvmap_show = ui_check(h_uvmap_show, tr("UV Map"));
  340. ui_view2d_ui._x += ew * 0.7 + 3;
  341. ui_view2d_ui._y = 2 + start_y;
  342. }
  343. ///end
  344. let h_tiled_show: ui_handle_t = ui_handle(__ID__);
  345. if (h_tiled_show.init) {
  346. h_tiled_show.selected = ui_view2d_tiled_show;
  347. }
  348. ui_view2d_tiled_show = ui_check(h_tiled_show, tr("Tiled"));
  349. ui_view2d_ui._x += ew * 0.7 + 3;
  350. ui_view2d_ui._y = 2 + start_y;
  351. if (ui_view2d_type == view_2d_type_t.ASSET && tex != null) { // Texture resolution
  352. ui_text(tex.width + "x" + tex.height);
  353. }
  354. // Picked position
  355. ///if is_paint
  356. if (context_raw.tool == workspace_tool_t.PICKER && (ui_view2d_type == view_2d_type_t.LAYER || ui_view2d_type == view_2d_type_t.ASSET)) {
  357. let cursor_img: gpu_texture_t = resource_get("cursor.k");
  358. let hsize: f32 = 16 * ui_SCALE(ui_view2d_ui);
  359. let size: f32 = hsize * 2;
  360. draw_scaled_image(cursor_img, tx + tw * context_raw.uvx_picked - hsize, ty + th * context_raw.uvy_picked - hsize, size, size);
  361. }
  362. ///end
  363. }
  364. ui_end();
  365. }
  366. function ui_view2d_update() {
  367. let headerh: f32 = ui_ELEMENT_H(ui_view2d_ui) * 1.4;
  368. ///if is_paint
  369. context_raw.paint2d = false;
  370. ///end
  371. if (!base_ui_enabled ||
  372. !ui_view2d_show ||
  373. mouse_x < ui_view2d_wx ||
  374. mouse_x > ui_view2d_wx + ui_view2d_ww ||
  375. mouse_y < ui_view2d_wy + headerh ||
  376. mouse_y > ui_view2d_wy + ui_view2d_wh) {
  377. if (ui_view2d_controls_down) {
  378. let control: ui_canvas_control_t = ui_nodes_get_canvas_control(ui_view2d_ui, ui_view2d_controls_down);
  379. ui_view2d_controls_down = control.controls_down;
  380. }
  381. return;
  382. }
  383. let control: ui_canvas_control_t = ui_nodes_get_canvas_control(ui_view2d_ui, ui_view2d_controls_down);
  384. ui_view2d_pan_x += control.pan_x;
  385. ui_view2d_pan_y += control.pan_y;
  386. ui_view2d_controls_down = control.controls_down;
  387. if (control.zoom != 0.0) {
  388. let _pan_x: f32 = ui_view2d_pan_x / ui_view2d_pan_scale;
  389. let _pan_y: f32 = ui_view2d_pan_y / ui_view2d_pan_scale;
  390. ui_view2d_pan_scale += control.zoom;
  391. if (ui_view2d_pan_scale < 0.1) {
  392. ui_view2d_pan_scale = 0.1;
  393. }
  394. if (ui_view2d_pan_scale > 6.0) {
  395. ui_view2d_pan_scale = 6.0;
  396. }
  397. ui_view2d_pan_x = _pan_x * ui_view2d_pan_scale;
  398. ui_view2d_pan_y = _pan_y * ui_view2d_pan_scale;
  399. if (ui_touch_scroll) {
  400. // Zoom to finger location
  401. ui_view2d_pan_x -= (ui_view2d_ui.input_x - ui_view2d_ui._window_x - ui_view2d_ui._window_w / 2) * control.zoom;
  402. ui_view2d_pan_y -= (ui_view2d_ui.input_y - ui_view2d_ui._window_y - ui_view2d_ui._window_h / 2) * control.zoom;
  403. }
  404. ui_view2d_grid_redraw = true;
  405. }
  406. ///if is_paint
  407. let decal_mask: bool = context_is_decal_mask_paint();
  408. let set_clone_source: bool = context_raw.tool == workspace_tool_t.CLONE &&
  409. operator_shortcut(map_get(config_keymap, "set_clone_source") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN);
  410. let bake: bool = context_raw.tool == workspace_tool_t.BAKE;
  411. if (ui_view2d_type == view_2d_type_t.LAYER &&
  412. !ui_view2d_text_input_hover &&
  413. !bake &&
  414. (operator_shortcut(map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN) ||
  415. operator_shortcut(map_get(config_keymap, "brush_ruler") + "+" + map_get(config_keymap, "action_paint"), shortcut_type_t.DOWN) ||
  416. decal_mask ||
  417. set_clone_source ||
  418. config_raw.brush_live)) {
  419. context_raw.paint2d = true;
  420. }
  421. ///end
  422. if (ui_view2d_ui.is_typing) {
  423. return;
  424. }
  425. if (keyboard_started("left")) {
  426. ui_view2d_pan_x -= 5;
  427. }
  428. else if (keyboard_started("right")) {
  429. ui_view2d_pan_x += 5;
  430. }
  431. if (keyboard_started("up")) {
  432. ui_view2d_pan_y -= 5;
  433. }
  434. else if (keyboard_started("down")) {
  435. ui_view2d_pan_y += 5;
  436. }
  437. // Limit panning to keep texture in viewport
  438. let border: i32 = 32;
  439. let tw: f32 = ui_view2d_ww * 0.95 * ui_view2d_pan_scale;
  440. let tx: f32 = ui_view2d_ww / 2 - tw / 2 + ui_view2d_pan_x;
  441. let hh: f32 = sys_h();
  442. let ty: f32 = hh / 2 - tw / 2 + ui_view2d_pan_y;
  443. if (tx + border > ui_view2d_ww) {
  444. ui_view2d_pan_x = ui_view2d_ww / 2 + tw / 2 - border;
  445. }
  446. else if (tx - border < -tw) {
  447. ui_view2d_pan_x = -tw / 2 - ui_view2d_ww / 2 + border;
  448. }
  449. if (ty + border > hh) {
  450. ui_view2d_pan_y = hh / 2 + tw / 2 - border;
  451. }
  452. else if (ty - border < -tw) {
  453. ui_view2d_pan_y = -tw / 2 - hh / 2 + border;
  454. }
  455. if (operator_shortcut(map_get(config_keymap, "view_reset"))) {
  456. ui_view2d_pan_x = 0.0;
  457. ui_view2d_pan_y = 0.0;
  458. ui_view2d_pan_scale = 1.0;
  459. }
  460. }