tab_layers.ts 35 KB

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