tab_layers.ts 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102
  1. let tab_layers_layer_name_edit: i32 = -1;
  2. let tab_layers_layer_name_handle: ui_handle_t = ui_handle_create();
  3. let tab_layers_show_context_menu: bool = false;
  4. let tab_layers_l: slot_layer_t;
  5. let tab_layers_mini: bool;
  6. function tab_layers_draw(htab: ui_handle_t) {
  7. let mini: bool = config_raw.layout[layout_size_t.SIDEBAR_W] <= ui_sidebar_w_mini;
  8. mini ? tab_layers_draw_mini(htab) : tab_layers_draw_full(htab);
  9. }
  10. function tab_layers_draw_mini(htab: ui_handle_t) {
  11. ui_set_hovered_tab_name(tr("Layers"));
  12. let _ELEMENT_H: i32 = ui.ops.theme.ELEMENT_H;
  13. ui.ops.theme.ELEMENT_H = math_floor(ui_sidebar_w_mini / 2 / UI_SCALE());
  14. ui_begin_sticky();
  15. ui_separator(5);
  16. tab_layers_combo_filter();
  17. tab_layers_button_2d_view();
  18. tab_layers_button_new("+");
  19. ui_end_sticky();
  20. ui._y += 2;
  21. tab_layers_highlight_odd_lines();
  22. tab_layers_draw_slots(true);
  23. ui.ops.theme.ELEMENT_H = _ELEMENT_H;
  24. }
  25. function tab_layers_draw_full(htab: ui_handle_t) {
  26. if (ui_tab(htab, tr("Layers"))) {
  27. ui_begin_sticky();
  28. let row: f32[] = [ -70, -70, -140 ];
  29. ui_row(row);
  30. tab_layers_button_new(tr("New"));
  31. tab_layers_button_2d_view();
  32. tab_layers_combo_filter();
  33. ui_end_sticky();
  34. ui._y += 2;
  35. tab_layers_highlight_odd_lines();
  36. tab_layers_draw_slots(false);
  37. }
  38. }
  39. function tab_layers_button_2d_view() {
  40. if (ui_button(tr("2D View"))) {
  41. ui_base_show_2d_view(view_2d_type_t.LAYER);
  42. }
  43. else if (ui.is_hovered) {
  44. ui_tooltip(tr("Show 2D View") + " (" + map_get(config_keymap, "toggle_2d_view") + ")");
  45. }
  46. }
  47. function tab_layers_draw_slots(mini: bool) {
  48. for (let i: i32 = 0; i < project_layers.length; ++i) {
  49. if (i >= project_layers.length) {
  50. break; // Layer was deleted
  51. }
  52. let j: i32 = project_layers.length - 1 - i;
  53. let l: slot_layer_t = project_layers[j];
  54. tab_layers_draw_layer_slot(l, j, mini);
  55. }
  56. }
  57. function tab_layers_highlight_odd_lines() {
  58. let step: i32 = ui.ops.theme.ELEMENT_H * 2;
  59. let full_h: i32 = ui._window_h - ui_base_hwnds[0].scroll_offset;
  60. for (let i: i32 = 0; i < math_floor(full_h / step); ++i) {
  61. if (i % 2 == 0) {
  62. ui_fill(0, i * step, (ui._w / UI_SCALE() - 2), step, ui.ops.theme.WINDOW_BG_COL - 0x00040404);
  63. }
  64. }
  65. }
  66. function tab_layers_button_new(text: string) {
  67. if (ui_button(text)) {
  68. ui_menu_draw(function() {
  69. let l: slot_layer_t = context_raw.layer;
  70. if (ui_menu_button(tr("Paint Layer"), "", icon_t.PAINT)) {
  71. layers_new_layer();
  72. history_new_layer();
  73. }
  74. if (ui_menu_button(tr("Fill Layer"), "", icon_t.SPHERE)) {
  75. layers_create_fill_layer(uv_type_t.UVMAP);
  76. }
  77. if (ui_menu_button(tr("Decal Layer"), "", icon_t.DECAL)) {
  78. layers_create_fill_layer(uv_type_t.PROJECT);
  79. }
  80. if (config_raw.experimental) {
  81. if (ui_menu_button(tr("Sculpt Layer"))) {
  82. sys_notify_on_next_frame(function() {
  83. sculpt_layers_create_sculpt_layer();
  84. });
  85. }
  86. }
  87. if (ui_menu_button(tr("Black Mask"), "", icon_t.MASK)) {
  88. if (slot_layer_is_mask(l)) {
  89. context_set_layer(l.parent);
  90. }
  91. l = context_raw.layer;
  92. let m: slot_layer_t = layers_new_mask(false, l);
  93. sys_notify_on_next_frame(function(m: slot_layer_t) {
  94. slot_layer_clear(m, 0x00000000);
  95. }, m);
  96. context_raw.layer_preview_dirty = true;
  97. history_new_black_mask();
  98. sys_notify_on_next_frame(function() {
  99. layers_update_fill_layers();
  100. });
  101. }
  102. if (ui_menu_button(tr("White Mask"), "", icon_t.MASK_WHITE)) {
  103. if (slot_layer_is_mask(l)) {
  104. context_set_layer(l.parent);
  105. }
  106. l = context_raw.layer;
  107. let m: slot_layer_t = layers_new_mask(false, l);
  108. sys_notify_on_next_frame(function(m: slot_layer_t) {
  109. slot_layer_clear(m, 0xffffffff);
  110. }, m);
  111. context_raw.layer_preview_dirty = true;
  112. history_new_white_mask();
  113. sys_notify_on_next_frame(function() {
  114. layers_update_fill_layers();
  115. });
  116. }
  117. if (ui_menu_button(tr("Fill Mask"), "", icon_t.MASK_FILL)) {
  118. if (slot_layer_is_mask(l)) {
  119. context_set_layer(l.parent);
  120. }
  121. l = context_raw.layer;
  122. let m: slot_layer_t = layers_new_mask(false, l);
  123. sys_notify_on_next_frame(function(m: slot_layer_t) {
  124. slot_layer_to_fill_layer(m);
  125. }, m);
  126. context_raw.layer_preview_dirty = true;
  127. history_new_fill_mask();
  128. sys_notify_on_next_frame(function() {
  129. layers_update_fill_layers();
  130. });
  131. }
  132. ui.enabled = !slot_layer_is_group(context_raw.layer) && !slot_layer_is_in_group(context_raw.layer);
  133. if (ui_menu_button(tr("Group"), "", icon_t.FOLDER)) {
  134. if (slot_layer_is_group(l) || slot_layer_is_in_group(l)) {
  135. return;
  136. }
  137. if (slot_layer_is_layer_mask(l)) {
  138. l = l.parent;
  139. }
  140. let pointers: map_t<slot_layer_t, i32> = tab_layers_init_layer_map();
  141. let group: slot_layer_t = layers_new_group();
  142. context_set_layer(l);
  143. array_remove(project_layers, group);
  144. array_insert(project_layers, array_index_of(project_layers, l) + 1, group);
  145. l.parent = group;
  146. for (let i: i32 = 0; i < project_materials.length; ++i) {
  147. let m: slot_material_t = project_materials[i];
  148. tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
  149. }
  150. context_set_layer(group);
  151. history_new_group();
  152. }
  153. ui.enabled = true;
  154. });
  155. }
  156. }
  157. function tab_layers_combo_filter() {
  158. let ar: string[] = [ tr("All") ];
  159. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  160. let p: mesh_object_t = project_paint_objects[i];
  161. array_push(ar, p.base.name);
  162. }
  163. let atlases: string[] = project_get_used_atlases();
  164. if (atlases != null) {
  165. for (let i: i32 = 0; i < atlases.length; ++i) {
  166. let a: string = atlases[i];
  167. array_push(ar, a);
  168. }
  169. }
  170. let filter_handle: ui_handle_t = ui_handle(__ID__);
  171. filter_handle.i = context_raw.layer_filter;
  172. context_raw.layer_filter = ui_combo(filter_handle, ar, tr("Filter"), false, ui_align_t.LEFT);
  173. if (filter_handle.changed) {
  174. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  175. let p: mesh_object_t = project_paint_objects[i];
  176. let filter_name: string = ar[context_raw.layer_filter];
  177. p.base.visible = context_raw.layer_filter == 0 || p.base.name == filter_name || project_is_atlas_object(p);
  178. }
  179. if (context_raw.layer_filter == 0 && context_raw.merged_object_is_atlas) { // All
  180. util_mesh_merge();
  181. }
  182. else if (context_raw.layer_filter > project_paint_objects.length) { // Atlas
  183. let visibles: mesh_object_t[] = [];
  184. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  185. let p: mesh_object_t = project_paint_objects[i];
  186. if (p.base.visible) {
  187. array_push(visibles, p);
  188. }
  189. }
  190. util_mesh_merge(visibles);
  191. }
  192. layers_set_object_mask();
  193. util_uv_uvmap_cached = false;
  194. context_raw.ddirty = 2;
  195. render_path_raytrace_ready = false;
  196. }
  197. }
  198. function tab_layers_remap_layer_pointers(nodes: ui_node_t[], pointer_map: map_t<i32, i32>) {
  199. for (let i: i32 = 0; i < nodes.length; ++i) {
  200. let n: ui_node_t = nodes[i];
  201. if (n.type == "LAYER" || n.type == "LAYER_MASK") {
  202. let i: i32 = n.buttons[0].default_value[0];
  203. if (map_get(pointer_map, i) != -1) {
  204. n.buttons[0].default_value[0] = map_get(pointer_map, i);
  205. }
  206. }
  207. }
  208. }
  209. function tab_layers_init_layer_map(): map_t<slot_layer_t, i32> {
  210. let res: map_t<slot_layer_t, i32> = map_create();
  211. for (let i: i32 = 0; i < project_layers.length; ++i) {
  212. map_set(res, project_layers[i], i);
  213. }
  214. return res;
  215. }
  216. function tab_layers_fill_layer_map(map: map_t<slot_layer_t, i32>): map_t<i32, i32> {
  217. let res: map_t<i32, i32> = map_create();
  218. let keys: string[] = map_keys(map);
  219. for (let i: i32 = 0; i < keys.length; ++i) {
  220. let l: string = keys[i];
  221. map_set(res, map_get(map, l), array_index_of(project_layers, l) > -1 ? array_index_of(project_layers, l) : 9999);
  222. }
  223. return res;
  224. }
  225. function tab_layers_set_drag_layer(layer: slot_layer_t, off_x: f32, off_y: f32) {
  226. base_drag_off_x = off_x;
  227. base_drag_off_y = off_y;
  228. base_drag_layer = layer;
  229. context_raw.drag_dest = array_index_of(project_layers, layer);
  230. }
  231. function tab_layers_draw_layer_slot(l: slot_layer_t, i: i32, mini: bool) {
  232. if (context_raw.layer_filter > 0 && slot_layer_get_object_mask(l) > 0 && slot_layer_get_object_mask(l) != context_raw.layer_filter) {
  233. return;
  234. }
  235. if (l.parent != null && !l.parent.show_panel) { // Group closed
  236. return;
  237. }
  238. if (l.parent != null && l.parent.parent != null && !l.parent.parent.show_panel) {
  239. return;
  240. }
  241. let step: i32 = ui.ops.theme.ELEMENT_H;
  242. let checkw: f32 = (ui._window_w / 100 * 8) / UI_SCALE();
  243. // Highlight drag destination
  244. let absy: f32 = ui._window_y + ui._y;
  245. if (base_is_dragging && base_drag_layer != null && context_in_layers()) {
  246. if (mouse_y > absy + step && mouse_y < absy + step * 3) {
  247. let down: bool = array_index_of(project_layers, base_drag_layer) >= i;
  248. context_raw.drag_dest = down ? i : i - 1;
  249. let ls: slot_layer_t[] = project_layers;
  250. let dest: i32 = context_raw.drag_dest;
  251. let to_group: bool = down ? dest > 0 && ls[dest - 1].parent != null && ls[dest - 1].parent.show_panel
  252. : dest < ls.length && ls[dest].parent != null && ls[dest].parent.show_panel;
  253. let nested_group: bool = slot_layer_is_group(base_drag_layer) && to_group;
  254. if (!nested_group) {
  255. if (slot_layer_can_move(context_raw.layer, context_raw.drag_dest)) {
  256. ui_fill(checkw, step * 2, (ui._window_w / UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), ui.ops.theme.HIGHLIGHT_COL);
  257. }
  258. }
  259. }
  260. else if (i == project_layers.length - 1 && mouse_y < absy + step) {
  261. context_raw.drag_dest = project_layers.length - 1;
  262. if (slot_layer_can_move(context_raw.layer, context_raw.drag_dest)) {
  263. ui_fill(checkw, 0, (ui._window_w / UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), ui.ops.theme.HIGHLIGHT_COL);
  264. }
  265. }
  266. }
  267. if (base_is_dragging && (base_drag_material != null || base_drag_swatch != null) && context_in_layers()) {
  268. if (mouse_y > absy + step && mouse_y < absy + step * 3) {
  269. context_raw.drag_dest = i;
  270. if (tab_layers_can_drop_new_layer(i)) {
  271. ui_fill(checkw, 2 * step, (ui._window_w / UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), ui.ops.theme.HIGHLIGHT_COL);
  272. }
  273. }
  274. else if (i == project_layers.length - 1 && mouse_y < absy + step) {
  275. context_raw.drag_dest = project_layers.length;
  276. if (tab_layers_can_drop_new_layer(project_layers.length)) {
  277. ui_fill(checkw, 0, (ui._window_w / UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), ui.ops.theme.HIGHLIGHT_COL);
  278. }
  279. }
  280. }
  281. mini ? tab_layers_draw_layer_slot_mini(l, i) : tab_layers_draw_layer_slot_full(l, i);
  282. tab_layers_draw_layer_highlight(l, mini);
  283. if (tab_layers_show_context_menu) {
  284. tab_layers_draw_layer_context_menu(l, mini);
  285. }
  286. }
  287. function tab_layers_draw_layer_slot_mini(l: slot_layer_t, i: i32) {
  288. let uix: f32 = ui._x;
  289. let uiy: f32 = ui._y;
  290. let state: ui_state_t = tab_layers_draw_layer_icon(l, i, uix, uiy, true);
  291. tab_layers_handle_layer_icon_state(l, i, state, uix, uiy);
  292. ui._x = uix;
  293. ui._y = uiy + ui.ops.theme.ELEMENT_H * 2 * UI_SCALE();
  294. }
  295. function tab_layers_draw_layer_slot_full(l: slot_layer_t, i: i32) {
  296. let step: i32 = ui.ops.theme.ELEMENT_H;
  297. let center: f32 = (step / 2) * UI_SCALE();
  298. let uiw: f32 = ui._w;
  299. let uix: f32 = ui._x;
  300. let uiy: f32 = ui._y;
  301. let has_children: bool = slot_layer_is_group(l) || (slot_layer_is_layer(l) && slot_layer_get_masks(l, false) != null);
  302. // Draw eye icon
  303. let row: f32[] = [ 0.08 ];
  304. ui_row(row);
  305. let icons: gpu_texture_t = resource_get("icons.k");
  306. let r: rect_t = resource_tile18(icons, l.visible ? icon18_t.EYE_ON : icon18_t.EYE_OFF);
  307. ui._x = uix + 4;
  308. ui._y = uiy + 3 + center;
  309. let col: i32 = ui.ops.theme.ACCENT_COL;
  310. let parent_hidden: bool = l.parent != null && (!l.parent.visible || (l.parent.parent != null && !l.parent.parent.visible));
  311. if (parent_hidden) {
  312. col -= 0x99000000;
  313. }
  314. if (ui_sub_image(icons, col, -1.0, r.x, r.y, r.w, r.h) == ui_state_t.RELEASED) {
  315. tab_layers_layer_toggle_visible(l);
  316. }
  317. // Nested offset
  318. let offx: f32 = 0.0;
  319. if (l.parent != null) {
  320. offx = 14 * UI_SCALE();
  321. if (l.parent.parent != null) {
  322. offx += 14 * UI_SCALE();
  323. }
  324. }
  325. // Layer icon
  326. ui._x = uix + uiw * 0.08 + offx;
  327. ui._y = uiy + 3;
  328. ui._w = uiw * 0.16;
  329. let state: ui_state_t = tab_layers_draw_layer_icon(l, i, uix, uiy, false);
  330. tab_layers_handle_layer_icon_state(l, i, state, uix, uiy);
  331. // Draw layer name
  332. ui._x = uix + uiw * 0.24 + 2 + offx;
  333. ui._y = uiy + center;
  334. ui._w = uiw * 0.36;
  335. if (config_raw.touch_ui) {
  336. ui._x += 12 * UI_SCALE();
  337. }
  338. if (tab_layers_layer_name_edit == l.id) {
  339. tab_layers_layer_name_handle.text = l.name;
  340. l.name = ui_text_input(tab_layers_layer_name_handle);
  341. if (ui.text_selected_handle != tab_layers_layer_name_handle) {
  342. tab_layers_layer_name_edit = -1;
  343. }
  344. }
  345. else {
  346. if (ui.enabled && ui.input_enabled && ui.combo_selected_handle == null && ui.input_x > ui._window_x + ui._x && ui.input_x < ui._window_x + uiw &&
  347. ui.input_y > ui._window_y + ui._y - center && ui.input_y < ui._window_y + ui._y - center + (step * UI_SCALE()) * 2) {
  348. if (ui.input_started) {
  349. context_set_layer(l);
  350. tab_layers_set_drag_layer(context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
  351. }
  352. else if (ui.input_released_r) {
  353. context_set_layer(l);
  354. tab_layers_show_context_menu = true;
  355. }
  356. }
  357. let state: ui_state_t = ui_text(l.name);
  358. if (state == ui_state_t.RELEASED) {
  359. if (sys_time() - context_raw.select_time < 0.2) {
  360. tab_layers_layer_name_edit = l.id;
  361. tab_layers_layer_name_handle.text = l.name;
  362. ui_start_text_edit(tab_layers_layer_name_handle);
  363. }
  364. context_raw.select_time = sys_time();
  365. }
  366. let in_focus: bool =
  367. ui.input_x > ui._window_x && ui.input_x < ui._window_x + ui._window_w && ui.input_y > ui._window_y && ui.input_y < ui._window_y + ui._window_h;
  368. if (in_focus && ui.is_delete_down && tab_layers_can_delete(context_raw.layer)) {
  369. ui.is_delete_down = false;
  370. sys_notify_on_next_frame(function() {
  371. tab_layers_delete_layer(context_raw.layer);
  372. });
  373. }
  374. }
  375. // Blending combo
  376. if (!slot_layer_is_group(l)) {
  377. ui._x = uix + uiw * 0.60;
  378. ui._y = uiy;
  379. ui._w = uiw * 0.30;
  380. if (slot_layer_is_mask(l)) {
  381. ui._y += center;
  382. }
  383. tab_layers_combo_blending(l);
  384. }
  385. // Object combo
  386. if (!slot_layer_is_group(l) && !slot_layer_is_mask(l)) {
  387. ui._x = uix + uiw * 0.60;
  388. ui._y = uiy + center * 2;
  389. ui._w = uiw * 0.30;
  390. tab_layers_combo_object(l);
  391. }
  392. // Panel
  393. if (has_children) {
  394. ui._x = uix + uiw * 0.90;
  395. ui._y = uiy + center;
  396. ui._w = uiw * 0.15;
  397. let layer_panel: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  398. layer_panel.b = l.show_panel;
  399. l.show_panel = ui_panel(layer_panel, "", false, false, true);
  400. }
  401. ui._x = uix;
  402. ui._y = uiy + step * 2 * UI_SCALE();
  403. ui._w = uiw;
  404. }
  405. function tab_layers_combo_object(l: slot_layer_t, label: bool = false): ui_handle_t {
  406. let ar: string[] = [ tr("Shared") ];
  407. for (let i: i32 = 0; i < project_paint_objects.length; ++i) {
  408. let p: mesh_object_t = project_paint_objects[i];
  409. array_push(ar, p.base.name);
  410. }
  411. let atlases: string[] = project_get_used_atlases();
  412. if (atlases != null) {
  413. for (let i: i32 = 0; i < atlases.length; ++i) {
  414. let a: string = atlases[i];
  415. array_push(ar, a);
  416. }
  417. }
  418. let object_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  419. object_handle.i = l.object_mask;
  420. l.object_mask = ui_combo(object_handle, ar, tr("Object"), label, ui_align_t.LEFT);
  421. if (object_handle.changed) {
  422. context_set_layer(l);
  423. make_material_parse_mesh_material();
  424. if (l.fill_layer != null) { // Fill layer
  425. sys_notify_on_next_frame(function(l: slot_layer_t) {
  426. context_raw.material = l.fill_layer;
  427. slot_layer_clear(l);
  428. layers_update_fill_layers();
  429. }, l);
  430. }
  431. else {
  432. layers_set_object_mask();
  433. }
  434. }
  435. return object_handle;
  436. }
  437. function tab_layers_combo_blending(l: slot_layer_t, label: bool = false): ui_handle_t {
  438. let blending_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  439. blending_handle.i = l.blending;
  440. let blending_combo: string[] = [
  441. tr("Mix"),
  442. tr("Darken"),
  443. tr("Multiply"),
  444. tr("Burn"),
  445. tr("Lighten"),
  446. tr("Screen"),
  447. tr("Dodge"),
  448. tr("Add"),
  449. tr("Overlay"),
  450. tr("Soft Light"),
  451. tr("Linear Light"),
  452. tr("Difference"),
  453. tr("Subtract"),
  454. tr("Divide"),
  455. tr("Hue"),
  456. tr("Saturation"),
  457. tr("Color"),
  458. tr("Value"),
  459. ];
  460. ui_combo(blending_handle, blending_combo, tr("Blending"), label);
  461. if (blending_handle.changed) {
  462. context_set_layer(l);
  463. history_layer_blending();
  464. l.blending = blending_handle.i;
  465. make_material_parse_mesh_material();
  466. }
  467. return blending_handle;
  468. }
  469. function tab_layers_layer_toggle_visible(l: slot_layer_t) {
  470. l.visible = !l.visible;
  471. ui_view2d_hwnd.redraws = 2;
  472. make_material_parse_mesh_material();
  473. }
  474. function tab_layers_draw_layer_highlight(l: slot_layer_t, mini: bool) {
  475. let step: i32 = ui.ops.theme.ELEMENT_H;
  476. // Separator line
  477. ui_fill(0, 0, (ui._w / UI_SCALE() - 2), 1 * UI_SCALE(), ui.ops.theme.SEPARATOR_COL);
  478. // Highlight selected
  479. if (context_raw.layer == l) {
  480. if (mini) {
  481. ui_rect(1, -step * 2, ui._w / UI_SCALE() - 1, step * 2 + (mini ? -1 : 1), ui.ops.theme.HIGHLIGHT_COL, 3);
  482. }
  483. else {
  484. ui_rect(1, -step * 2 - 1, ui._w / UI_SCALE() - 2, step * 2 + (mini ? -2 : 1), ui.ops.theme.HIGHLIGHT_COL, 2);
  485. }
  486. }
  487. }
  488. function tab_layers_handle_layer_icon_state(l: slot_layer_t, i: i32, state: ui_state_t, uix: f32, uiy: f32) {
  489. let texpaint_preview: gpu_texture_t = l.texpaint_preview;
  490. tab_layers_show_context_menu = false;
  491. // Layer preview tooltip
  492. if (ui.is_hovered && texpaint_preview != null) {
  493. if (slot_layer_is_mask(l)) {
  494. tab_layers_make_mask_preview_rgba32(l);
  495. ui_tooltip_image(context_raw.mask_preview_rgba32);
  496. }
  497. else {
  498. ui_tooltip_image(texpaint_preview);
  499. }
  500. if (i < 9) {
  501. let i1: i32 = (i + 1);
  502. ui_tooltip(l.name + " - (" + map_get(config_keymap, "select_layer") + " " + i1 + ")");
  503. }
  504. else {
  505. ui_tooltip(l.name);
  506. }
  507. }
  508. // Show context menu
  509. if (ui.is_hovered && ui.input_released_r) {
  510. context_set_layer(l);
  511. tab_layers_show_context_menu = true;
  512. }
  513. if (state == ui_state_t.STARTED) {
  514. context_set_layer(l);
  515. tab_layers_set_drag_layer(context_raw.layer, -(mouse_x - uix - ui._window_x - 3), -(mouse_y - uiy - ui._window_y + 1));
  516. }
  517. else if (state == ui_state_t.RELEASED) {
  518. if (sys_time() - context_raw.select_time < 0.2) {
  519. ui_base_show_2d_view(view_2d_type_t.LAYER);
  520. }
  521. if (sys_time() - context_raw.select_time > 0.2) {
  522. context_raw.select_time = sys_time();
  523. }
  524. if (l.fill_layer != null) {
  525. context_set_material(l.fill_layer);
  526. }
  527. }
  528. }
  529. function tab_layers_draw_layer_icon(l: slot_layer_t, i: i32, uix: f32, uiy: f32, mini: bool): ui_state_t {
  530. let icons: gpu_texture_t = resource_get("icons.k");
  531. let icon_h: i32 = (UI_ELEMENT_H() - (mini ? 2 : 3)) * 2;
  532. if (mini && UI_SCALE() > 1) {
  533. ui._x -= 1 * UI_SCALE();
  534. }
  535. if (l.parent != null) {
  536. ui._x += (icon_h - icon_h * 0.9) / 2;
  537. icon_h *= 0.9;
  538. if (l.parent.parent != null) {
  539. ui._x += (icon_h - icon_h * 0.9) / 2;
  540. icon_h *= 0.9;
  541. }
  542. }
  543. if (!slot_layer_is_group(l)) {
  544. let texpaint_preview: gpu_texture_t = l.texpaint_preview;
  545. let icon: gpu_texture_t = l.fill_layer == null ? texpaint_preview : l.fill_layer.image_icon;
  546. if (l.fill_layer == null) {
  547. // Checker
  548. let r: rect_t = resource_tile50(icons, icon_t.CHECKER);
  549. let _x: f32 = ui._x;
  550. let _y: f32 = ui._y;
  551. let _w: f32 = ui._w;
  552. ui_sub_image(icons, 0xffffffff, icon_h, r.x, r.y, r.w, r.h);
  553. ui._x = _x;
  554. ui._y = _y;
  555. ui._w = _w;
  556. }
  557. if (l.fill_layer == null && slot_layer_is_mask(l)) {
  558. draw_set_pipeline(ui_view2d_pipe);
  559. gpu_set_int(ui_view2d_channel_loc, 1);
  560. }
  561. let state: ui_state_t = ui_image(icon, 0xffffffff, icon_h);
  562. if (l.fill_layer == null && slot_layer_is_mask(l)) {
  563. draw_set_pipeline(null);
  564. }
  565. // Draw layer numbers when selecting a layer via keyboard shortcut
  566. let is_typing: bool = ui.is_typing;
  567. if (!is_typing) {
  568. if (i < 9 && operator_shortcut(map_get(config_keymap, "select_layer"), shortcut_type_t.DOWN)) {
  569. let number: string = i32_to_string(i + 1);
  570. let width: i32 = draw_string_width(ui.ops.font, ui.font_size, number) + 10;
  571. let height: i32 = draw_font_height(ui.ops.font, ui.font_size);
  572. draw_set_color(ui.ops.theme.TEXT_COL);
  573. draw_filled_rect(uix, uiy, width, height);
  574. draw_set_color(ui.ops.theme.BUTTON_COL);
  575. draw_string(number, uix + 5, uiy);
  576. }
  577. }
  578. return state;
  579. }
  580. else { // Group
  581. let folder_closed: rect_t = resource_tile50(icons, icon_t.FOLDER_FULL);
  582. let folder_open: rect_t = resource_tile50(icons, icon_t.FOLDER_OPEN);
  583. let folder: rect_t = l.show_panel ? folder_open : folder_closed;
  584. return ui_sub_image(icons, ui.ops.theme.LABEL_COL - 0x00202020, icon_h, folder.x, folder.y, folder.w, folder.h);
  585. }
  586. }
  587. function tab_layers_can_merge_down(l: slot_layer_t): bool {
  588. let index: i32 = array_index_of(project_layers, l);
  589. // Lowest layer
  590. if (index == 0) {
  591. return false;
  592. }
  593. // Lowest layer that has masks
  594. if (slot_layer_is_layer(l) && slot_layer_is_mask(project_layers[0]) && project_layers[0].parent == l) {
  595. return false;
  596. }
  597. // The lowest toplevel layer is a group
  598. if (slot_layer_is_group(l) && slot_layer_is_in_group(project_layers[0]) && slot_layer_get_containing_group(project_layers[0]) == l) {
  599. return false;
  600. }
  601. // Masks must be merged down to masks
  602. if (slot_layer_is_mask(l) && !slot_layer_is_mask(project_layers[index - 1])) {
  603. return false;
  604. }
  605. return true;
  606. }
  607. function tab_layers_draw_layer_context_menu(l: slot_layer_t, mini: bool) {
  608. tab_layers_l = l;
  609. tab_layers_mini = mini;
  610. ui_menu_draw(function() {
  611. let l: slot_layer_t = tab_layers_l;
  612. let mini: bool = tab_layers_mini;
  613. if (mini) {
  614. let visible_handle: ui_handle_t = ui_handle(__ID__);
  615. visible_handle.b = l.visible;
  616. ui_check(visible_handle, tr("Visible"));
  617. if (visible_handle.changed) {
  618. tab_layers_layer_toggle_visible(l);
  619. ui_menu_keep_open = true;
  620. }
  621. if (!slot_layer_is_group(l)) {
  622. if (tab_layers_combo_blending(l, true).changed) {
  623. ui_menu_keep_open = true;
  624. }
  625. }
  626. if (slot_layer_is_layer(l)) {
  627. if (tab_layers_combo_object(l, true).changed) {
  628. ui_menu_keep_open = true;
  629. }
  630. }
  631. }
  632. if (ui_menu_button(tr("Export"), "", icon_t.EXPORT)) {
  633. if (slot_layer_is_mask(l)) {
  634. ui_files_show("png", true, false, function(path: string) {
  635. let l: slot_layer_t = tab_layers_l;
  636. let f: string = ui_files_filename;
  637. if (f == "") {
  638. f = tr("untitled");
  639. }
  640. if (!ends_with(f, ".png")) {
  641. f += ".png";
  642. }
  643. iron_write_png(path + path_sep + f, gpu_get_texture_pixels(l.texpaint), l.texpaint.width, l.texpaint.height, 3); // RRR1
  644. });
  645. }
  646. else {
  647. context_raw.layers_export = export_mode_t.SELECTED;
  648. box_export_show_textures();
  649. }
  650. }
  651. if (!slot_layer_is_group(l)) {
  652. let to_fill_string: string = slot_layer_is_layer(l) ? tr("To Fill Layer") : tr("To Fill Mask");
  653. let to_paint_string: string = slot_layer_is_layer(l) ? tr("To Paint Layer") : tr("To Paint Mask");
  654. if (l.fill_layer == null && ui_menu_button(to_fill_string, "", icon_t.SPHERE)) {
  655. sys_notify_on_next_frame(function() {
  656. let l: slot_layer_t = tab_layers_l;
  657. slot_layer_is_layer(l) ? history_to_fill_layer() : history_to_fill_mask();
  658. slot_layer_to_fill_layer(l);
  659. });
  660. }
  661. if (l.fill_layer != null && ui_menu_button(to_paint_string, "", icon_t.PAINT)) {
  662. sys_notify_on_next_frame(function() {
  663. let l: slot_layer_t = tab_layers_l;
  664. slot_layer_is_layer(l) ? history_to_paint_layer() : history_to_paint_mask();
  665. slot_layer_to_paint_layer(l);
  666. });
  667. }
  668. }
  669. ui.enabled = tab_layers_can_delete(l);
  670. if (ui_menu_button(tr("Delete"), "delete", icon_t.DELETE)) {
  671. sys_notify_on_next_frame(function() {
  672. tab_layers_delete_layer(context_raw.layer);
  673. });
  674. }
  675. ui.enabled = true;
  676. if (l.fill_layer == null && ui_menu_button(tr("Clear"), "", icon_t.ERASE)) {
  677. context_set_layer(l);
  678. sys_notify_on_next_frame(function() {
  679. let l: slot_layer_t = tab_layers_l;
  680. if (!slot_layer_is_group(l)) {
  681. history_clear_layer();
  682. slot_layer_clear(l);
  683. }
  684. else {
  685. for (let i: i32 = 0; i < slot_layer_get_children(l).length; ++i) {
  686. let c: slot_layer_t = slot_layer_get_children(l)[i];
  687. context_raw.layer = c;
  688. history_clear_layer();
  689. slot_layer_clear(c);
  690. }
  691. context_raw.layers_preview_dirty = true;
  692. context_raw.layer = l;
  693. }
  694. });
  695. }
  696. if (slot_layer_is_mask(l) && l.fill_layer == null && ui_menu_button(tr("Invert"), "", icon_t.INVERT)) {
  697. sys_notify_on_next_frame(function() {
  698. let l: slot_layer_t = tab_layers_l;
  699. context_set_layer(l);
  700. history_invert_mask();
  701. slot_layer_invert_mask(l);
  702. });
  703. }
  704. if (slot_layer_is_mask(l) && ui_menu_button(tr("Apply"), "", icon_t.CHECK)) {
  705. sys_notify_on_next_frame(function() {
  706. let l: slot_layer_t = tab_layers_l;
  707. context_raw.layer = l;
  708. history_apply_mask();
  709. slot_layer_apply_mask(l);
  710. context_set_layer(l.parent);
  711. make_material_parse_mesh_material();
  712. context_raw.layers_preview_dirty = true;
  713. });
  714. }
  715. if (slot_layer_is_group(l) && ui_menu_button(tr("Merge Group"))) {
  716. sys_notify_on_next_frame(function() {
  717. let l: slot_layer_t = tab_layers_l;
  718. layers_merge_group(l);
  719. });
  720. }
  721. ui.enabled = tab_layers_can_merge_down(l);
  722. if (ui_menu_button(tr("Merge Down"), "", icon_t.ARROW_DOWN)) {
  723. sys_notify_on_next_frame(function() {
  724. let l: slot_layer_t = tab_layers_l;
  725. context_set_layer(l);
  726. history_merge_layers();
  727. layers_merge_down();
  728. if (context_raw.layer.fill_layer != null)
  729. slot_layer_to_paint_layer(context_raw.layer);
  730. });
  731. }
  732. ui.enabled = true;
  733. if (ui_menu_button(tr("Duplicate"), "", icon_t.DUPLICATE)) {
  734. sys_notify_on_next_frame(function() {
  735. let l: slot_layer_t = tab_layers_l;
  736. context_set_layer(l);
  737. history_duplicate_layer();
  738. layers_duplicate_layer(l);
  739. });
  740. }
  741. ui_menu_align();
  742. let layer_opac_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  743. layer_opac_handle.f = l.mask_opacity;
  744. ui_slider(layer_opac_handle, tr("Opacity"), 0.0, 1.0, true);
  745. if (layer_opac_handle.changed) {
  746. if (ui.input_started) {
  747. history_layer_opacity();
  748. }
  749. l.mask_opacity = layer_opac_handle.f;
  750. make_material_parse_mesh_material();
  751. ui_menu_keep_open = true;
  752. }
  753. if (!slot_layer_is_group(l)) {
  754. ui_menu_align();
  755. /// if (arm_android || arm_ios)
  756. let ar: string[] = [ "128", "256", "512", "1024", "2048", "4096" ];
  757. /// else
  758. let ar: string[] = [ "128", "256", "512", "1024", "2048", "4096", "8192", "16384" ];
  759. /// end
  760. let h: ui_handle_t = ui_handle(__ID__);
  761. let changed_last: bool = h.changed;
  762. h.i = base_res_handle.i;
  763. base_res_handle.i = ui_combo(h, ar, tr("Resolution"), true);
  764. if (h.changed) {
  765. ui_menu_keep_open = true;
  766. }
  767. if (changed_last && !h.changed) {
  768. layers_on_resized();
  769. }
  770. ui_menu_align();
  771. let huv: ui_handle_t = ui_handle(__ID__);
  772. huv.i = l.uv_map;
  773. let aruv: string[] = [ "uv0" ];
  774. if (mesh_data_get_vertex_array(context_raw.paint_object.data, "tex1") != null) {
  775. array_push(aruv, "uv1");
  776. }
  777. ui_combo(huv, aruv, tr("UV Map"), true);
  778. l.uv_map = huv.i;
  779. if (huv.changed) {
  780. make_material_parse_paint_material();
  781. make_material_parse_mesh_material();
  782. ui_menu_keep_open = true;
  783. }
  784. /// if (arm_android || arm_ios)
  785. // let bits_items: string[] = ["8"];
  786. // ui_inline_radio(base_bits_handle, bits_items, ui_align_t.LEFT);
  787. /// else
  788. ui_menu_separator();
  789. ui_menu_align();
  790. ui_menu_label(tr("Bits"));
  791. ui_menu_align();
  792. let bits_items: string[] = [ "8", "16", "32" ];
  793. ui_inline_radio(base_bits_handle, bits_items, ui_align_t.LEFT);
  794. /// end
  795. if (base_bits_handle.changed) {
  796. sys_notify_on_next_frame(layers_set_bits);
  797. make_material_parse_paint_material();
  798. ui_menu_keep_open = true;
  799. }
  800. }
  801. if (l.fill_layer != null) {
  802. ui_menu_align();
  803. let scale_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  804. scale_handle.f = l.scale;
  805. l.scale = ui_slider(scale_handle, tr("UV Scale"), 0.0, 5.0, true);
  806. if (scale_handle.changed) {
  807. context_set_material(l.fill_layer);
  808. context_set_layer(l);
  809. sys_notify_on_next_frame(function() {
  810. layers_update_fill_layers();
  811. });
  812. ui_menu_keep_open = true;
  813. }
  814. ui_menu_align();
  815. let angle_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  816. angle_handle.f = l.angle;
  817. l.angle = ui_slider(angle_handle, tr("Angle"), 0.0, 360, true, 1);
  818. if (angle_handle.changed) {
  819. context_set_material(l.fill_layer);
  820. context_set_layer(l);
  821. make_material_parse_paint_material();
  822. sys_notify_on_next_frame(function() {
  823. layers_update_fill_layers();
  824. });
  825. ui_menu_keep_open = true;
  826. }
  827. ui_menu_align();
  828. let uv_type_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  829. uv_type_handle.i = l.uv_type;
  830. let uv_type_items: string[] = [ tr("UV Map"), tr("Triplanar"), tr("Project") ];
  831. l.uv_type = ui_inline_radio(uv_type_handle, uv_type_items, ui_align_t.LEFT);
  832. if (uv_type_handle.changed) {
  833. context_set_material(l.fill_layer);
  834. context_set_layer(l);
  835. make_material_parse_paint_material();
  836. sys_notify_on_next_frame(function() {
  837. layers_update_fill_layers();
  838. });
  839. ui_menu_keep_open = true;
  840. }
  841. }
  842. if (!slot_layer_is_group(l)) {
  843. let base_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  844. let opac_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  845. let nor_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  846. let nor_blend_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  847. let occ_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  848. let rough_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  849. let met_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  850. let height_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  851. let height_blend_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  852. let emis_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  853. let subs_handle: ui_handle_t = ui_nest(ui_handle(__ID__), l.id);
  854. base_handle.b = l.paint_base;
  855. opac_handle.b = l.paint_opac;
  856. nor_handle.b = l.paint_nor;
  857. nor_blend_handle.b = l.paint_nor_blend;
  858. occ_handle.b = l.paint_occ;
  859. rough_handle.b = l.paint_rough;
  860. met_handle.b = l.paint_met;
  861. height_handle.b = l.paint_height;
  862. height_blend_handle.b = l.paint_height_blend;
  863. emis_handle.b = l.paint_emis;
  864. subs_handle.b = l.paint_subs;
  865. ui_menu_separator();
  866. ui_menu_align();
  867. ui_menu_label(tr("Channels"));
  868. ui_menu_align();
  869. ui_row2();
  870. l.paint_base = ui_check(base_handle, tr("Base Color"));
  871. l.paint_opac = ui_check(opac_handle, tr("Opacity"));
  872. ui_row2();
  873. l.paint_nor = ui_check(nor_handle, tr("Normal"));
  874. l.paint_nor_blend = ui_check(nor_blend_handle, tr("Normal Blend"));
  875. ui_row2();
  876. l.paint_rough = ui_check(rough_handle, tr("Roughness"));
  877. l.paint_met = ui_check(met_handle, tr("Metallic"));
  878. ui_row2();
  879. l.paint_height = ui_check(height_handle, tr("Height"));
  880. l.paint_height_blend = ui_check(height_blend_handle, tr("Height Blend"));
  881. ui_row2();
  882. l.paint_emis = ui_check(emis_handle, tr("Emission"));
  883. l.paint_subs = ui_check(subs_handle, tr("Subsurface"));
  884. l.paint_occ = ui_check(occ_handle, tr("Occlusion"));
  885. if (base_handle.changed || opac_handle.changed || nor_handle.changed || nor_blend_handle.changed || occ_handle.changed || rough_handle.changed ||
  886. met_handle.changed || height_handle.changed || height_blend_handle.changed || emis_handle.changed || subs_handle.changed) {
  887. make_material_parse_mesh_material();
  888. ui_menu_keep_open = true;
  889. }
  890. }
  891. });
  892. }
  893. function tab_layers_make_mask_preview_rgba32(l: slot_layer_t) {
  894. if (context_raw.mask_preview_rgba32 == null) {
  895. context_raw.mask_preview_rgba32 = gpu_create_render_target(util_render_layer_preview_size, util_render_layer_preview_size);
  896. }
  897. // Convert from R8 to RGBA32 for tooltip display
  898. if (context_raw.mask_preview_last != l) {
  899. context_raw.mask_preview_last = l;
  900. tab_layers_l = l;
  901. sys_notify_on_next_frame(function() {
  902. let l: slot_layer_t = tab_layers_l;
  903. draw_begin(context_raw.mask_preview_rgba32);
  904. draw_set_pipeline(ui_view2d_pipe);
  905. gpu_set_int(ui_view2d_channel_loc, 1);
  906. draw_image(l.texpaint_preview, 0, 0);
  907. draw_end();
  908. draw_set_pipeline(null);
  909. });
  910. }
  911. }
  912. function tab_layers_delete_layer(l: slot_layer_t) {
  913. let pointers: map_t<slot_layer_t, i32> = tab_layers_init_layer_map();
  914. if (slot_layer_is_layer(l) && slot_layer_has_masks(l, false)) {
  915. let masks: slot_layer_t[] = slot_layer_get_masks(l, false);
  916. for (let i: i32 = 0; i < masks.length; ++i) {
  917. let m: slot_layer_t = masks[i];
  918. context_raw.layer = m;
  919. history_delete_layer();
  920. slot_layer_delete(m);
  921. }
  922. }
  923. if (slot_layer_is_group(l)) {
  924. let children: slot_layer_t[] = slot_layer_get_children(l);
  925. for (let i: i32 = 0; i < children.length; ++i) {
  926. let c: slot_layer_t = children[i];
  927. if (slot_layer_has_masks(c, false)) {
  928. let masks: slot_layer_t[] = slot_layer_get_masks(c, false);
  929. for (let i: i32 = 0; i < masks.length; ++i) {
  930. let m: slot_layer_t = masks[i];
  931. context_raw.layer = m;
  932. history_delete_layer();
  933. slot_layer_delete(m);
  934. }
  935. }
  936. context_raw.layer = c;
  937. history_delete_layer();
  938. slot_layer_delete(c);
  939. }
  940. if (slot_layer_has_masks(l)) {
  941. for (let i: i32 = 0; i < slot_layer_get_masks(l).length; ++i) {
  942. let m: slot_layer_t = slot_layer_get_masks(l)[i];
  943. context_raw.layer = m;
  944. history_delete_layer();
  945. slot_layer_delete(m);
  946. }
  947. }
  948. }
  949. context_raw.layer = l;
  950. history_delete_layer();
  951. slot_layer_delete(l);
  952. if (slot_layer_is_mask(l)) {
  953. context_raw.layer = l.parent;
  954. layers_update_fill_layers();
  955. }
  956. // Remove empty group
  957. if (slot_layer_is_in_group(l) && slot_layer_get_children(slot_layer_get_containing_group(l)) == null) {
  958. let g: slot_layer_t = slot_layer_get_containing_group(l);
  959. // Maybe some group masks are left
  960. if (slot_layer_has_masks(g)) {
  961. for (let i: i32 = 0; i < slot_layer_get_masks(g).length; ++i) {
  962. let m: slot_layer_t = slot_layer_get_masks(g)[i];
  963. context_raw.layer = m;
  964. history_delete_layer();
  965. slot_layer_delete(m);
  966. }
  967. }
  968. context_raw.layer = l.parent;
  969. history_delete_layer();
  970. slot_layer_delete(l.parent);
  971. }
  972. context_raw.ddirty = 2;
  973. for (let i: i32 = 0; i < project_materials.length; ++i) {
  974. let m: slot_material_t = project_materials[i];
  975. tab_layers_remap_layer_pointers(m.canvas.nodes, tab_layers_fill_layer_map(pointers));
  976. }
  977. }
  978. function tab_layers_can_delete(l: slot_layer_t): bool {
  979. let num_layers: i32 = 0;
  980. if (slot_layer_is_mask(l)) {
  981. return true;
  982. }
  983. for (let i: i32 = 0; i < project_layers.length; ++i) {
  984. let slot: slot_layer_t = project_layers[i];
  985. if (slot_layer_is_layer(slot)) {
  986. ++num_layers;
  987. }
  988. }
  989. // All layers are in one group
  990. if (slot_layer_is_group(l) && slot_layer_get_children(l).length == num_layers) {
  991. return false;
  992. }
  993. // Do not delete last layer
  994. return num_layers > 1;
  995. }
  996. function tab_layers_can_drop_new_layer(position: i32): bool {
  997. if (position > 0 && position < project_layers.length && slot_layer_is_mask(project_layers[position - 1])) {
  998. // 1. The layer to insert is inserted in the middle
  999. // 2. The layer below is a mask, i.e. the layer would have to be a (group) mask, too.
  1000. return false;
  1001. }
  1002. return true;
  1003. }