Files
armorpaint/paint/sources/ui/tab_layers.c
T
2026-06-11 20:01:25 +02:00

1262 lines
42 KiB
C

#include "../global.h"
i32 tab_layers_layer_name_edit = -1;
bool tab_layers_show_context_menu = false;
bool tab_layers_mini;
void tab_layers_button_2d_view() {
if (ui_button(tr("2D View"), UI_ALIGN_CENTER, "")) {
ui_base_show_2d_view(VIEW_2D_TYPE_LAYER);
}
else if (g_ui->is_hovered) {
ui_tooltip(string("%s (%s)", tr("Show 2D View"), (char *)any_map_get(g_keymap, "toggle_2d_view")));
}
}
void tab_layers_set_drag_layer(slot_layer_t *layer, f32 off_x, f32 off_y) {
base_drag_off_x = off_x;
base_drag_off_y = off_y;
gc_unroot(base_drag_layer);
base_drag_layer = layer;
gc_root(base_drag_layer);
g_context->drag_dest = array_index_of(g_project->_->layers, layer);
}
void tab_layers_handle_layer_icon_state(slot_layer_t *l, i32 i, ui_state_t state, f32 uix, f32 uiy) {
gpu_texture_t *texpaint_preview = l->texpaint_preview;
tab_layers_show_context_menu = false;
// Layer preview tooltip
if (g_ui->is_hovered && texpaint_preview != NULL) {
if (slot_layer_is_mask(l)) {
tab_layers_make_mask_preview_rgba32(l);
ui_tooltip_image(g_context->mask_preview_rgba32, 0);
}
else {
ui_tooltip_image(texpaint_preview, 0);
}
if (i < 9) {
i32 i1 = (i + 1);
ui_tooltip(string("%s - (%s %d)", l->name, (char *)any_map_get(g_keymap, "select_layer"), i1));
}
else {
ui_tooltip(l->name);
}
}
// Show context menu
if (g_ui->is_hovered && g_ui->input_released_r) {
context_set_layer(l);
tab_layers_show_context_menu = true;
}
if (state == UI_STATE_STARTED) {
context_set_layer(l);
tab_layers_set_drag_layer(g_context->layer, -(mouse_x - uix - g_ui->_window_x - 3), -(mouse_y - uiy - g_ui->_window_y + 1));
}
else if (state == UI_STATE_RELEASED) {
if (sys_time() - g_context->select_time < 0.2) {
ui_base_show_2d_view(VIEW_2D_TYPE_LAYER);
}
if (sys_time() - g_context->select_time > 0.2) {
g_context->select_time = sys_time();
}
if (l->fill_material != NULL) {
context_set_material(l->fill_material);
}
else if (l->path_material != NULL) {
context_set_material(l->path_material);
}
}
}
ui_state_t tab_layers_draw_layer_icon(slot_layer_t *l, i32 i, f32 uix, f32 uiy, bool mini) {
gpu_texture_t *icons = resource_get("icons.k");
i32 icon_h = (UI_ELEMENT_H() - (mini ? 2 : 3)) * 2;
if (mini && UI_SCALE() > 1) {
g_ui->_x -= 1 * UI_SCALE();
}
if (l->parent != NULL) {
g_ui->_x += (icon_h - icon_h * 0.9) / 2.0;
icon_h *= 0.9;
if (l->parent->parent != NULL) {
g_ui->_x += (icon_h - icon_h * 0.9) / 2.0;
icon_h *= 0.9;
}
}
if (!slot_layer_is_group(l)) {
gpu_texture_t *texpaint_preview = l->texpaint_preview;
gpu_texture_t *icon;
if (l->fill_material != NULL) {
icon = g_config->window_scale > 1 ? l->fill_material->image : l->fill_material->image_icon;
}
else if (l->path_material != NULL) {
icon = g_config->window_scale > 1 ? l->path_material->image : l->path_material->image_icon;
}
else {
icon = texpaint_preview;
}
if (l->fill_material == NULL && l->path_material == NULL) {
// Checker
rect_t *r = resource_tile50(icons, ICON_CHECKER);
f32 _x = g_ui->_x;
f32 _y = g_ui->_y;
f32 _w = g_ui->_w;
ui_sub_image(icons, 0xffffffff, icon_h, r->x, r->y, r->w, r->h);
g_ui->_x = _x;
g_ui->_y = _y;
g_ui->_w = _w;
}
if (l->fill_material == NULL && slot_layer_is_mask(l)) {
draw_set_pipeline(ui_view2d_pipe);
gpu_set_int(ui_view2d_channel_loc, 1);
}
ui_state_t state = ui_image(icon, 0xffffffff, icon_h);
if (l->fill_material == NULL && slot_layer_is_mask(l)) {
draw_set_pipeline(NULL);
}
// Draw layer numbers when selecting a layer via keyboard shortcut
bool is_typing = g_ui->is_typing;
if (!is_typing) {
if (i < 9 && operator_shortcut(any_map_get(g_keymap, "select_layer"), SHORTCUT_TYPE_DOWN)) {
char *number = i32_to_string(i + 1);
i32 width = draw_string_width(g_font, g_ui->font_size, number) + 10;
i32 height = draw_font_height(g_font, g_ui->font_size);
draw_set_color(g_theme->TEXT_COL);
draw_filled_rect(uix, uiy, width, height);
draw_set_color(g_theme->BUTTON_COL);
draw_string(number, uix + 5, uiy);
}
}
return state;
}
else { // Group
rect_t *folder_closed = resource_tile50(icons, ICON_FOLDER_FULL);
rect_t *folder_open = resource_tile50(icons, ICON_FOLDER_OPEN);
rect_t *folder = l->show_panel ? folder_open : folder_closed;
return ui_sub_image(icons, base_darker(g_theme->LABEL_COL, 0x00202020), icon_h, folder->x, folder->y, folder->w, folder->h);
}
}
void tab_layers_draw_layer_slot_mini(slot_layer_t *l, i32 i) {
f32 uix = g_ui->_x;
f32 uiy = g_ui->_y;
ui_state_t state = tab_layers_draw_layer_icon(l, i, uix, uiy, true);
tab_layers_handle_layer_icon_state(l, i, state, uix, uiy);
g_ui->_x = uix;
g_ui->_y = uiy + g_theme->ELEMENT_H * 2 * UI_SCALE();
}
void tab_layers_delete_layer(slot_layer_t *l) {
i32_map_t *pointers = tab_layers_init_layer_map();
if (slot_layer_is_layer(l) && slot_layer_has_masks(l, false)) {
slot_layer_t_array_t *masks = slot_layer_get_masks(l, false);
for (i32 i = 0; i < masks->length; ++i) {
slot_layer_t *m = masks->buffer[i];
g_context->layer = m;
history_delete_layer();
slot_layer_delete(m);
}
}
if (slot_layer_is_group(l)) {
slot_layer_t_array_t *children = slot_layer_get_children(l);
for (i32 i = 0; i < children->length; ++i) {
slot_layer_t *c = children->buffer[i];
if (slot_layer_has_masks(c, false)) {
slot_layer_t_array_t *masks = slot_layer_get_masks(c, false);
for (i32 i = 0; i < masks->length; ++i) {
slot_layer_t *m = masks->buffer[i];
g_context->layer = m;
history_delete_layer();
slot_layer_delete(m);
}
}
g_context->layer = c;
history_delete_layer();
slot_layer_delete(c);
}
if (slot_layer_has_masks(l, true)) {
for (i32 i = 0; i < slot_layer_get_masks(l, true)->length; ++i) {
slot_layer_t *m = slot_layer_get_masks(l, true)->buffer[i];
g_context->layer = m;
history_delete_layer();
slot_layer_delete(m);
}
}
}
g_context->layer = l;
history_delete_layer();
slot_layer_delete(l);
if (slot_layer_is_mask(l)) {
g_context->layer = l->parent;
layers_update_fill_layers();
}
// Remove empty group
if (slot_layer_is_in_group(l) && slot_layer_get_children(slot_layer_get_containing_group(l)) == NULL) {
slot_layer_t *g = slot_layer_get_containing_group(l);
// Maybe some group masks are left
if (slot_layer_has_masks(g, true)) {
for (i32 i = 0; i < slot_layer_get_masks(g, true)->length; ++i) {
slot_layer_t *m = slot_layer_get_masks(g, true)->buffer[i];
g_context->layer = m;
history_delete_layer();
slot_layer_delete(m);
}
}
g_context->layer = l->parent;
history_delete_layer();
slot_layer_delete(l->parent);
}
g_context->ddirty = 2;
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *m = g_project->_->materials->buffer[i];
tab_layers_remap_layer_pointers(m->canvas->nodes, tab_layers_fill_layer_map(pointers));
}
tab_stages_prune();
}
void tab_layers_draw_layer_slot_full_delete_layer(void *_) {
tab_layers_delete_layer(g_context->layer);
}
void tab_layers_combo_object_layer_clear(slot_layer_t *l) {
g_context->material = l->fill_material;
slot_layer_clear(l, 0x00000000, NULL, 1.0, layers_default_rough, 0.0);
layers_update_fill_layers();
}
ui_handle_t *tab_layers_combo_object(slot_layer_t *l, bool label) {
string_array_t *ar = any_array_create_from_raw(
(void *[]){
tr("Shared"),
},
1);
for (i32 i = 0; i < g_project->_->paint_objects->length; ++i) {
mesh_object_t *p = g_project->_->paint_objects->buffer[i];
any_array_push(ar, p->base->name);
}
string_array_t *atlases = project_get_used_atlases();
if (atlases != NULL) {
for (i32 i = 0; i < atlases->length; ++i) {
char *a = atlases->buffer[i];
any_array_push(ar, a);
}
}
ui_handle_t *object_handle = ui_nest(ui_handle(__ID__), l->id);
object_handle->i = l->object_mask;
l->object_mask = ui_combo(object_handle, ar, tr("Object"), label, UI_ALIGN_LEFT, true);
if (object_handle->changed) {
context_set_layer(l);
make_material_parse_mesh_material();
if (l->fill_material != NULL) {
sys_notify_on_next_frame(&tab_layers_combo_object_layer_clear, l);
}
else {
layers_set_object_mask();
}
}
return object_handle;
}
ui_handle_t *tab_layers_combo_blending(slot_layer_t *l, bool label) {
ui_handle_t *blending_handle = ui_nest(ui_handle(__ID__), l->id);
blending_handle->i = l->blending;
string_array_t *blending_combo = any_array_create_from_raw(
(void *[]){
tr("Mix"),
tr("Darken"),
tr("Multiply"),
tr("Burn"),
tr("Lighten"),
tr("Screen"),
tr("Dodge"),
tr("Add"),
tr("Overlay"),
tr("Soft Light"),
tr("Linear Light"),
tr("Difference"),
tr("Subtract"),
tr("Divide"),
tr("Hue"),
tr("Saturation"),
tr("Color"),
tr("Value"),
},
18);
ui_combo(blending_handle, blending_combo, tr("Blending"), label, UI_ALIGN_LEFT, true);
if (blending_handle->changed) {
context_set_layer(l);
history_layer_blending();
l->blending = blending_handle->i;
make_material_parse_mesh_material();
}
return blending_handle;
}
void tab_layers_layer_toggle_visible(slot_layer_t *l) {
l->visible = !l->visible;
ui_view2d_hwnd->redraws = 2;
make_material_parse_mesh_material();
}
bool tab_layers_can_delete(slot_layer_t *l) {
i32 num_layers = 0;
if (slot_layer_is_mask(l)) {
return true;
}
for (i32 i = 0; i < g_project->_->layers->length; ++i) {
slot_layer_t *slot = g_project->_->layers->buffer[i];
if (slot_layer_is_layer(slot)) {
++num_layers;
}
}
// All layers are in one group
if (slot_layer_is_group(l) && slot_layer_get_children(l)->length == num_layers) {
return false;
}
// Do not delete last layer
return num_layers > 1;
}
void tab_layers_draw_layer_context_menu_duplicate(void *_) {
slot_layer_t *l = tab_layers_l;
context_set_layer(l);
history_duplicate_layer();
layers_duplicate_layer(l);
}
bool tab_layers_has_children(slot_layer_t *l) {
return slot_layer_is_group(l) || (slot_layer_is_layer(l) && slot_layer_get_masks(l, false) != NULL) ||
(slot_layer_is_layer(l) && slot_layer_get_filters(l, false));
}
void tab_layers_draw_layer_slot_full(slot_layer_t *l, i32 i) {
i32 step = g_theme->ELEMENT_H;
f32 center = (step / 2.0) * UI_SCALE();
f32 uiw = g_ui->_w;
f32 uix = g_ui->_x;
f32 uiy = g_ui->_y;
bool has_children = tab_layers_has_children(l);
// Draw eye icon
f32_array_t *row = f32_array_create_from_raw(
(f32[]){
0.08,
},
1);
ui_row(row);
gpu_texture_t *icons = resource_get("icons.k");
rect_t *r = resource_tile18(icons, l->visible ? ICON18_EYE_ON : ICON18_EYE_OFF);
g_ui->_x = uix + 4;
g_ui->_y = uiy + 3 + center;
i32 col = g_theme->HOVER_COL + 0x00282828;
bool parent_hidden = l->parent != NULL && (!l->parent->visible || (l->parent->parent != NULL && !l->parent->parent->visible));
if (parent_hidden) {
col -= 0x99000000;
}
if (ui_sub_image(icons, col, r->h, r->x, r->y, r->w, r->h) == UI_STATE_RELEASED) {
tab_layers_layer_toggle_visible(l);
}
// Nested offset
f32 offx = 0.0;
if (l->parent != NULL) {
offx = 14 * UI_SCALE();
if (l->parent->parent != NULL) {
offx += 14 * UI_SCALE();
}
}
// Layer icon
i32 icon_h = (UI_ELEMENT_H() - 3) * 2;
g_ui->_x = uix + uiw * 0.08 + offx;
g_ui->_y = uiy + 3;
g_ui->_w = math_max(uiw * 0.16, icon_h);
ui_state_t state = tab_layers_draw_layer_icon(l, i, uix, uiy, false);
tab_layers_handle_layer_icon_state(l, i, state, uix, uiy);
// Draw layer name
bool has_blending = !slot_layer_is_group(l) && !slot_layer_is_mask(l) && !slot_layer_is_filter(l);
f32 name_x = math_max(uix + uiw * 0.25 + offx, uix + uiw * 0.08 + offx + icon_h + 4 * UI_SCALE());
f32 name_right = has_blending ? uix + uiw * 0.60 : (has_children ? uix + uiw * 0.90 : uix + uiw); // Blending combo / panel / window edge
g_ui->_x = name_x;
g_ui->_y = uiy + center;
g_ui->_w = name_right - name_x;
if (tab_layers_layer_name_edit == l->id) {
tab_layers_layer_name_handle->text = string_copy(l->name);
char *new_name = string_copy(ui_text_input(tab_layers_layer_name_handle, "", UI_ALIGN_LEFT, true, false));
tab_stages_rename_layer(l->name, new_name);
l->name = new_name;
if (g_ui->text_selected_handle != tab_layers_layer_name_handle) {
tab_layers_layer_name_edit = -1;
}
}
else {
if (g_ui->enabled && g_ui->input_enabled && g_ui->combo_selected_handle == NULL && g_ui->input_x > g_ui->_window_x + g_ui->_x &&
g_ui->input_x < g_ui->_window_x + uiw && g_ui->input_y > g_ui->_window_y + g_ui->_y - center &&
g_ui->input_y < g_ui->_window_y + g_ui->_y - center + (step * UI_SCALE()) * 2) {
if (g_ui->input_started) {
context_set_layer(l);
tab_layers_set_drag_layer(g_context->layer, -(mouse_x - uix - g_ui->_window_x - 3), -(mouse_y - uiy - g_ui->_window_y + 1));
}
else if (g_ui->input_released_r) {
context_set_layer(l);
tab_layers_show_context_menu = true;
}
}
ui_state_t state = ui_text(l->name, UI_ALIGN_LEFT, 0x00000000);
if (state == UI_STATE_RELEASED) {
if (sys_time() - g_context->select_time < 0.2) {
tab_layers_layer_name_edit = l->id;
tab_layers_layer_name_handle->text = string_copy(l->name);
ui_start_text_edit(tab_layers_layer_name_handle, UI_ALIGN_LEFT);
}
g_context->select_time = sys_time();
}
bool in_focus = g_ui->input_x > g_ui->_window_x && g_ui->input_x < g_ui->_window_x + g_ui->_window_w && g_ui->input_y > g_ui->_window_y &&
g_ui->input_y < g_ui->_window_y + g_ui->_window_h;
if (in_focus && g_ui->is_delete_down && tab_layers_can_delete(g_context->layer)) {
g_ui->is_delete_down = false;
sys_notify_on_next_frame(&tab_layers_draw_layer_slot_full_delete_layer, NULL);
}
if (in_focus && g_ui->is_ctrl_down && g_ui->is_key_pressed && g_ui->key_code == KEY_CODE_D) {
g_ui->is_key_pressed = false;
gc_unroot(tab_layers_l);
tab_layers_l = g_context->layer;
gc_root(tab_layers_l);
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_duplicate, NULL);
}
}
// Blending combo
if (!slot_layer_is_group(l) && !slot_layer_is_mask(l) && !slot_layer_is_filter(l) && l->texpaint_sculpt == NULL) {
g_ui->_x = uix + uiw * 0.60;
g_ui->_y = uiy;
g_ui->_w = uiw * 0.30;
tab_layers_combo_blending(l, false);
}
// Object combo
if (!slot_layer_is_group(l) && !slot_layer_is_mask(l) && !slot_layer_is_filter(l)) {
g_ui->_x = uix + uiw * 0.60;
g_ui->_y = l->texpaint_sculpt != NULL ? uiy + center : uiy + center * 2;
g_ui->_w = uiw * 0.30;
tab_layers_combo_object(l, false);
}
// Panel
if (has_children) {
g_ui->_x = uix + uiw * 0.90;
g_ui->_y = uiy + center;
g_ui->_w = uiw * 0.15;
ui_handle_t *layer_panel = ui_nest(ui_handle(__ID__), l->id);
layer_panel->b = l->show_panel;
l->show_panel = ui_panel(layer_panel, "", false, false, true);
}
g_ui->_x = uix;
g_ui->_y = uiy + step * 2 * UI_SCALE();
g_ui->_w = uiw;
}
void tab_layers_draw_layer_highlight(slot_layer_t *l, bool mini) {
i32 step = g_theme->ELEMENT_H;
// Separator line
ui_fill(0, 0, (g_ui->_w / (float)UI_SCALE() - 2), 1 * UI_SCALE(), g_theme->SEPARATOR_COL);
// Highlight selected
if (g_context->layer == l) {
if (mini) {
ui_rect(1, -step * 2, g_ui->_w / (float)UI_SCALE() - 1, step * 2 + (mini ? -1 : 1), g_theme->HIGHLIGHT_COL, 3);
}
else {
ui_rect(1, -step * 2 - 1, g_ui->_w / (float)UI_SCALE() - 2, step * 2 + (mini ? -2 : 1), g_theme->HIGHLIGHT_COL, 2);
}
}
}
void tab_layers_draw_layer_context_menu_export_on_file_picked(char *path) {
slot_layer_t *l = tab_layers_l;
char *f = ui_files_filename;
if (string_equals(f, "")) {
f = string_copy(tr("untitled"));
}
if (!ends_with(f, ".png")) {
f = string("%s.png", f);
}
iron_write_png(string("%s%s%s", path, PATH_SEP, f), gpu_get_texture_pixels(l->texpaint), l->texpaint->width, l->texpaint->height, 3); // RRR1
}
void tab_layers_draw_layer_context_menu_delete(void *_) {
tab_layers_delete_layer(g_context->layer);
}
void tab_layers_draw_layer_context_menu_to_paint_layer(void *_) {
slot_layer_t *l = tab_layers_l;
if (slot_layer_is_filter(l)) {
i32 pi = array_index_of(g_project->_->layers, l->parent);
array_remove(g_project->_->layers, l);
array_insert(g_project->_->layers, pi, l);
l->parent = NULL;
}
slot_layer_is_layer(l) ? history_to_paint_layer() : history_to_paint_mask();
slot_layer_to_paint_layer(l);
}
void tab_layers_draw_layer_context_menu_to_fill_layer(void *_) {
slot_layer_t *l = tab_layers_l;
slot_layer_is_layer(l) ? history_to_fill_layer() : history_to_fill_mask();
slot_layer_to_fill_layer(l);
}
bool tab_layers_can_merge_down(slot_layer_t *l) {
i32 index = array_index_of(g_project->_->layers, l);
// Lowest layer
if (index == 0) {
return false;
}
// Lowest layer that has masks
if (slot_layer_is_layer(l) && slot_layer_is_mask(g_project->_->layers->buffer[0]) && g_project->_->layers->buffer[0]->parent == l) {
return false;
}
// The lowest toplevel layer is a group
if (slot_layer_is_group(l) && slot_layer_is_in_group(g_project->_->layers->buffer[0]) &&
slot_layer_get_containing_group(g_project->_->layers->buffer[0]) == l) {
return false;
}
// Masks must be merged down to masks
if (slot_layer_is_mask(l) && !slot_layer_is_mask(g_project->_->layers->buffer[index - 1])) {
return false;
}
return true;
}
void tab_layers_draw_layer_context_menu_update_fill_layers(void *_) {
layers_update_fill_layers();
}
void tab_layers_draw_layer_context_menu_set_bits(void *_) {
layers_set_bits();
}
void tab_layers_draw_layer_context_menu_merge_down(void *_) {
slot_layer_t *l = tab_layers_l;
context_set_layer(l);
history_merge_layers();
layers_merge_down();
if (g_context->layer->fill_material != NULL)
slot_layer_to_paint_layer(g_context->layer);
}
void tab_layers_draw_layer_context_menu_merge_group(void *_) {
slot_layer_t *l = tab_layers_l;
layers_merge_group(l);
}
void tab_layers_draw_layer_context_menu_apply(void *_) {
slot_layer_t *l = tab_layers_l;
g_context->layer = l;
history_apply_mask();
slot_layer_apply_mask(l);
context_set_layer(l->parent);
make_material_parse_mesh_material();
g_context->layers_preview_dirty = true;
}
void tab_layers_draw_layer_context_menu_apply_sculpt(void *_) {
slot_layer_t *l = tab_layers_l;
g_context->layer = l;
slot_layer_apply_sculpt(l);
}
void tab_layers_draw_layer_context_menu_invert(void *_) {
slot_layer_t *l = tab_layers_l;
context_set_layer(l);
history_invert_mask();
slot_layer_invert_mask(l);
}
void tab_layers_draw_layer_context_menu_clear(void *_) {
slot_layer_t *l = tab_layers_l;
if (!slot_layer_is_group(l)) {
history_clear_layer();
slot_layer_clear(l, 0x00000000, NULL, 1.0, layers_default_rough, 0.0);
util_layer_clear_path_points(l);
}
else {
for (i32 i = 0; i < slot_layer_get_children(l)->length; ++i) {
slot_layer_t *c = slot_layer_get_children(l)->buffer[i];
g_context->layer = c;
history_clear_layer();
slot_layer_clear(c, 0x00000000, NULL, 1.0, layers_default_rough, 0.0);
}
g_context->layers_preview_dirty = true;
g_context->layer = l;
}
}
void tab_layers_draw_layer_context_menu_draw() {
slot_layer_t *l = tab_layers_l;
bool mini = tab_layers_mini;
if (mini) {
ui_handle_t *visible_handle = ui_handle(__ID__);
visible_handle->b = l->visible;
ui_check(visible_handle, tr("Visible"), "");
if (visible_handle->changed) {
tab_layers_layer_toggle_visible(l);
ui_menu_keep_open = true;
}
if (!slot_layer_is_group(l) && !slot_layer_is_mask(l) && !slot_layer_is_filter(l) && l->texpaint_sculpt == NULL) {
if (tab_layers_combo_blending(l, true)->changed) {
ui_menu_keep_open = true;
}
}
if (slot_layer_is_layer(l) && !slot_layer_is_filter(l)) {
if (tab_layers_combo_object(l, true)->changed) {
ui_menu_keep_open = true;
}
}
}
if (ui_menu_button(tr("Export"), "", ICON_EXPORT)) {
if (slot_layer_is_mask(l)) {
ui_files_show("png", true, false, &tab_layers_draw_layer_context_menu_export_on_file_picked);
}
else {
g_context->layers_export = EXPORT_MODE_SELECTED;
box_export_show_textures();
}
}
if (!slot_layer_is_group(l)) {
char *to_fill_string = slot_layer_is_layer(l) ? tr("To Fill Layer") : tr("To Fill Mask");
char *to_paint_string = slot_layer_is_layer(l) ? tr("To Paint Layer") : tr("To Paint Mask");
bool fill_layer = l->fill_material != NULL || l->path_material != NULL;
if (!fill_layer && ui_menu_button(to_fill_string, "", ICON_SPHERE)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_to_fill_layer, NULL);
}
if (fill_layer && ui_menu_button(to_paint_string, "", ICON_PAINT)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_to_paint_layer, NULL);
}
}
if (slot_layer_is_layer(l) && l->fill_material != NULL && l->texpaint_sculpt != NULL && ui_menu_button(tr("Apply"), "", ICON_CHECK)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_apply_sculpt, NULL);
}
g_ui->enabled = tab_layers_can_delete(l);
if (ui_menu_button(tr("Delete"), "delete", ICON_DELETE)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_delete, NULL);
}
g_ui->enabled = true;
if (l->fill_material == NULL && ui_menu_button(tr("Clear"), "", ICON_ERASE)) {
context_set_layer(l);
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_clear, NULL);
}
if (slot_layer_is_mask(l) && l->fill_material == NULL && ui_menu_button(tr("Invert"), "", ICON_INVERT)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_invert, NULL);
}
if (slot_layer_is_mask(l) && ui_menu_button(tr("Apply"), "", ICON_CHECK)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_apply, NULL);
}
if (slot_layer_is_group(l) && ui_menu_button(tr("Merge Group"), "", ICON_NONE)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_merge_group, NULL);
}
g_ui->enabled = tab_layers_can_merge_down(l);
if (ui_menu_button(tr("Merge Down"), "", ICON_ARROW_DOWN)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_merge_down, NULL);
}
g_ui->enabled = true;
if (ui_menu_button(tr("Duplicate"), "ctrl+d", ICON_DUPLICATE)) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_duplicate, NULL);
}
ui_menu_align();
ui_handle_t *layer_opac_handle = ui_nest(ui_handle(__ID__), l->id);
layer_opac_handle->f = l->mask_opacity;
ui_slider(layer_opac_handle, tr("Opacity"), 0.0, 1.0, true, 100.0, true, UI_ALIGN_RIGHT, true);
if (layer_opac_handle->changed) {
if (g_ui->input_started) {
history_layer_opacity();
}
l->mask_opacity = layer_opac_handle->f;
make_material_parse_mesh_material();
ui_menu_keep_open = true;
}
if (!slot_layer_is_group(l)) {
ui_menu_align();
string_array_t *ar = any_array_create_from_raw(
(void *[]){
"2048",
"4096",
"8192",
"16384",
tr("Custom"),
},
5);
ui_combo(base_res_handle, ar, tr("Resolution"), true, UI_ALIGN_LEFT, true);
if (base_res_handle->changed) {
ui_menu_keep_open = true;
config_set_texture_res(base_res_handle->i);
layers_on_resized();
}
if (base_res_handle->i == TEXTURE_RES_CUSTOM) {
static bool res_was_changed = false;
ui_menu_align();
ui_slider(base_res_x_handle, tr("Width"), 1, 16384, false, 1, true, UI_ALIGN_RIGHT, true);
ui_menu_align();
ui_slider(base_res_y_handle, tr("Height"), 1, 16384, false, 1, true, UI_ALIGN_RIGHT, true);
if (base_res_x_handle->changed || base_res_y_handle->changed) {
ui_menu_keep_open = true;
}
if (res_was_changed && !g_ui->input_down) {
res_was_changed = false;
layers_on_resized();
}
if (base_res_x_handle->changed || base_res_y_handle->changed) {
res_was_changed = true;
}
}
ui_menu_align();
ui_handle_t *huv = ui_handle(__ID__);
huv->i = l->uv_map;
string_array_t *aruv = any_array_create_from_raw(
(void *[]){
"uv0",
},
1);
if (mesh_data_get_vertex_array(g_context->paint_object->data, "tex1") != NULL) {
any_array_push(aruv, "uv1");
}
ui_combo(huv, aruv, tr("UV Map"), true, UI_ALIGN_LEFT, true);
l->uv_map = huv->i;
if (huv->changed) {
make_material_parse_paint_material(true);
make_material_parse_mesh_material();
ui_menu_keep_open = true;
}
#if defined(IRON_ANDROID) || defined(IRON_IOS)
// let bits_items: string[] = ["8"];
// ui_inline_radio(base_bits_handle, bits_items, ui_align_t.LEFT);
#else
ui_menu_separator();
ui_menu_align();
ui_menu_label(tr("Bits"), NULL);
ui_menu_align();
string_array_t *bits_items = any_array_create_from_raw(
(void *[]){
"8",
"16",
"32",
},
3);
ui_inline_radio(base_bits_handle, bits_items, UI_ALIGN_LEFT);
#endif
if (base_bits_handle->changed) {
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_set_bits, NULL);
make_material_parse_paint_material(true);
ui_menu_keep_open = true;
}
}
if (l->fill_material != NULL) {
ui_menu_align();
ui_handle_t *scale_handle = ui_nest(ui_handle(__ID__), l->id);
scale_handle->f = l->scale;
l->scale = ui_slider(scale_handle, tr("UV Scale"), 0.0, 5.0, true, 100.0, true, UI_ALIGN_RIGHT, true);
if (scale_handle->changed) {
context_set_material(l->fill_material);
context_set_layer(l);
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_update_fill_layers, NULL);
ui_menu_keep_open = true;
}
ui_menu_align();
ui_handle_t *angle_handle = ui_nest(ui_handle(__ID__), l->id);
angle_handle->f = l->angle;
l->angle = ui_slider(angle_handle, tr("Angle"), 0.0, 360, true, 1, true, UI_ALIGN_RIGHT, true);
if (angle_handle->changed) {
context_set_material(l->fill_material);
context_set_layer(l);
make_material_parse_paint_material(true);
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_update_fill_layers, NULL);
ui_menu_keep_open = true;
}
ui_menu_align();
ui_handle_t *uv_type_handle = ui_nest(ui_handle(__ID__), l->id);
uv_type_handle->i = l->uv_type;
string_array_t *uv_type_items = any_array_create_from_raw(
(void *[]){
tr("UV Map"),
tr("Triplanar"),
tr("Project"),
},
3);
l->uv_type = ui_inline_radio(uv_type_handle, uv_type_items, UI_ALIGN_LEFT);
if (uv_type_handle->changed) {
context_set_material(l->fill_material);
context_set_layer(l);
make_material_parse_paint_material(true);
sys_notify_on_next_frame(&tab_layers_draw_layer_context_menu_update_fill_layers, NULL);
ui_menu_keep_open = true;
}
}
if (!slot_layer_is_group(l)) {
ui_handle_t *base_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *opac_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *nor_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *nor_blend_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *occ_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *rough_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *met_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *height_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *height_blend_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *emis_handle = ui_nest(ui_handle(__ID__), l->id);
ui_handle_t *subs_handle = ui_nest(ui_handle(__ID__), l->id);
base_handle->b = l->paint_base;
opac_handle->b = l->paint_opac;
nor_handle->b = l->paint_nor;
nor_blend_handle->b = l->paint_nor_blend;
occ_handle->b = l->paint_occ;
rough_handle->b = l->paint_rough;
met_handle->b = l->paint_met;
height_handle->b = l->paint_height;
height_blend_handle->b = l->paint_height_blend;
emis_handle->b = l->paint_emis;
subs_handle->b = l->paint_subs;
ui_menu_separator();
ui_menu_align();
ui_menu_label(tr("Channels"), NULL);
ui_menu_align();
ui_row2();
l->paint_base = ui_check(base_handle, tr("Base Color"), "");
l->paint_opac = ui_check(opac_handle, tr("Opacity"), "");
if (g_config->workflow == WORKFLOW_PBR) {
ui_row2();
l->paint_nor = ui_check(nor_handle, tr("Normal"), "");
l->paint_nor_blend = ui_check(nor_blend_handle, tr("Normal Blend"), "");
ui_row2();
l->paint_rough = ui_check(rough_handle, tr("Roughness"), "");
l->paint_met = ui_check(met_handle, tr("Metallic"), "");
ui_row2();
l->paint_height = ui_check(height_handle, tr("Height"), "");
l->paint_height_blend = ui_check(height_blend_handle, tr("Height Blend"), "");
ui_row2();
l->paint_emis = ui_check(emis_handle, tr("Emission"), "");
l->paint_subs = ui_check(subs_handle, tr("Subsurface"), "");
l->paint_occ = ui_check(occ_handle, tr("Occlusion"), "");
}
if (base_handle->changed || opac_handle->changed || nor_handle->changed || nor_blend_handle->changed || occ_handle->changed || rough_handle->changed ||
met_handle->changed || height_handle->changed || height_blend_handle->changed || emis_handle->changed || subs_handle->changed) {
make_material_parse_mesh_material();
ui_menu_keep_open = true;
}
}
}
void tab_layers_draw_layer_context_menu(slot_layer_t *l, bool mini) {
gc_unroot(tab_layers_l);
tab_layers_l = l;
gc_root(tab_layers_l);
tab_layers_mini = mini;
ui_menu_draw(&tab_layers_draw_layer_context_menu_draw, -1, -1);
}
void tab_layers_draw_layer_slot(slot_layer_t *l, i32 i, bool mini) {
stage_t *stage = tab_stages_get_stage();
if (stage != NULL && string_array_index_of(stage->layers, l->name) < 0) {
return;
}
if (g_context->layer_filter > 0 && slot_layer_get_object_mask(l) > 0 && slot_layer_get_object_mask(l) != g_context->layer_filter) {
return;
}
bool is_sculpt_layer = l->texpaint_sculpt != NULL;
if (g_config->workflow == WORKFLOW_SCULPT && !is_sculpt_layer && !slot_layer_is_group(l) && !slot_layer_is_mask(l)) {
return;
}
if (g_config->workflow != WORKFLOW_SCULPT && is_sculpt_layer) {
return;
}
if (l->parent != NULL && !l->parent->show_panel) { // Group closed
return;
}
if (l->parent != NULL && l->parent->parent != NULL && !l->parent->parent->show_panel) {
return;
}
i32 step = g_theme->ELEMENT_H;
f32 checkw = (g_ui->_window_w / 100.0 * 8) / (float)UI_SCALE();
// Highlight drag destination
f32 absy = g_ui->_window_y + g_ui->_y;
if (base_is_dragging && base_drag_layer != NULL && context_in_layers()) {
if (mouse_y > absy + step && mouse_y < absy + step * 3) {
bool down = array_index_of(g_project->_->layers, base_drag_layer) >= i;
g_context->drag_dest = down ? i : i - 1;
slot_layer_t_array_t *ls = g_project->_->layers;
i32 dest = g_context->drag_dest;
bool to_group = down ? dest > 0 && ls->buffer[dest - 1]->parent != NULL && ls->buffer[dest - 1]->parent->show_panel
: dest < ls->length && ls->buffer[dest]->parent != NULL && ls->buffer[dest]->parent->show_panel;
bool nested_group = slot_layer_is_group(base_drag_layer) && to_group;
if (!nested_group) {
if (slot_layer_can_move(g_context->layer, g_context->drag_dest)) {
ui_fill(checkw, step * 2, (g_ui->_window_w / (float)UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), g_theme->HIGHLIGHT_COL);
}
}
}
else if (i == g_project->_->layers->length - 1 && mouse_y < absy + step) {
g_context->drag_dest = g_project->_->layers->length - 1;
if (slot_layer_can_move(g_context->layer, g_context->drag_dest)) {
ui_fill(checkw, 0, (g_ui->_window_w / (float)UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), g_theme->HIGHLIGHT_COL);
}
}
}
if (base_is_dragging && (base_drag_material != NULL || base_drag_swatch != NULL) && context_in_layers()) {
if (mouse_y > absy + step && mouse_y < absy + step * 3) {
g_context->drag_dest = i;
if (tab_layers_can_drop_new_layer(i)) {
ui_fill(checkw, 2 * step, (g_ui->_window_w / (float)UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), g_theme->HIGHLIGHT_COL);
}
}
else if (i == g_project->_->layers->length - 1 && mouse_y < absy + step) {
g_context->drag_dest = g_project->_->layers->length;
if (tab_layers_can_drop_new_layer(g_project->_->layers->length)) {
ui_fill(checkw, 0, (g_ui->_window_w / (float)UI_SCALE() - 2) - checkw, 2 * UI_SCALE(), g_theme->HIGHLIGHT_COL);
}
}
}
mini ? tab_layers_draw_layer_slot_mini(l, i) : tab_layers_draw_layer_slot_full(l, i);
tab_layers_draw_layer_highlight(l, mini);
if (tab_layers_show_context_menu) {
tab_layers_draw_layer_context_menu(l, mini);
}
}
void tab_layers_draw_slots(bool mini) {
for (i32 i = 0; i < g_project->_->layers->length; ++i) {
if (i >= g_project->_->layers->length) {
break; // Layer was deleted
}
i32 j = g_project->_->layers->length - 1 - i;
slot_layer_t *l = g_project->_->layers->buffer[j];
tab_layers_draw_layer_slot(l, j, mini);
}
}
void tab_layers_highlight_odd_lines() {
i32 step = g_theme->ELEMENT_H * 2;
i32 full_h = g_ui->_window_h - ui_base_hwnds->buffer[0]->scroll_offset;
for (i32 i = 0; i < math_floor(full_h / (float)step); ++i) {
if (i % 2 == 0) {
ui_fill(0, i * step, (g_ui->_w / (float)UI_SCALE() - 2), step, base_darker(g_theme->WINDOW_BG_COL, 0x00040404));
}
}
}
void tab_layers_button_new_to_fill_layer(slot_layer_t *m) {
slot_layer_to_fill_layer(m);
}
void tab_layers_button_new_layer_clear(slot_layer_t *m) {
slot_layer_clear(m, 0xffffffff, NULL, 1.0, layers_default_rough, 0.0);
}
void tab_layers_button_new_update_fill_layers(void *_) {
layers_update_fill_layers();
}
void tab_layers_button_new_black_mask(slot_layer_t *m) {
slot_layer_clear(m, 0x00000000, NULL, 1.0, layers_default_rough, 0.0);
}
void tab_layers_button_new_sculpt_layer(void *_) {
sculpt_layers_create_sculpt_layer();
}
void tab_layers_button_new_menu() {
slot_layer_t *l = g_context->layer;
if (g_config->workflow == WORKFLOW_SCULPT) {
if (ui_menu_button(tr("Sculpt Layer"), "", ICON_PAINT)) {
sys_notify_on_next_frame(&tab_layers_button_new_sculpt_layer, NULL);
}
}
else {
if (ui_menu_button(tr("Paint Layer"), "", ICON_PAINT)) {
layers_new_layer(true, -1, NULL);
history_new_layer();
}
}
if (ui_menu_button(tr("Fill Layer"), "", ICON_SPHERE)) {
layers_create_fill_layer(UV_TYPE_UVMAP, mat4_nan(), -1);
}
if (ui_menu_button(tr("Decal"), "", ICON_DECAL)) {
layers_create_fill_layer(UV_TYPE_PROJECT, mat4_nan(), -1);
}
if (ui_menu_button(tr("Path"), "", ICON_PATH)) {
layers_new_path_layer(false);
history_new_layer();
}
if (ui_menu_button(tr("Curve"), "", ICON_CURVE)) {
layers_new_path_layer(true);
history_new_layer();
}
if (ui_menu_button(tr("Black Mask"), "", ICON_MASK)) {
if (slot_layer_is_mask(l) || slot_layer_is_filter(l)) {
context_set_layer(l->parent);
}
l = g_context->layer;
i32_map_t *pointers = tab_layers_init_layer_map();
slot_layer_t *m = layers_new_mask(false, l, -1);
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *mat = g_project->_->materials->buffer[i];
tab_layers_remap_layer_pointers(mat->canvas->nodes, tab_layers_fill_layer_map(pointers));
}
sys_notify_on_next_frame(&tab_layers_button_new_black_mask, m);
g_context->layer_preview_dirty = true;
history_new_black_mask();
sys_notify_on_next_frame(&tab_layers_button_new_update_fill_layers, NULL);
}
if (ui_menu_button(tr("White Mask"), "", ICON_MASK_WHITE)) {
if (slot_layer_is_mask(l) || slot_layer_is_filter(l)) {
context_set_layer(l->parent);
}
l = g_context->layer;
i32_map_t *pointers = tab_layers_init_layer_map();
slot_layer_t *m = layers_new_mask(false, l, -1);
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *mat = g_project->_->materials->buffer[i];
tab_layers_remap_layer_pointers(mat->canvas->nodes, tab_layers_fill_layer_map(pointers));
}
sys_notify_on_next_frame(&tab_layers_button_new_layer_clear, m);
g_context->layer_preview_dirty = true;
history_new_white_mask();
sys_notify_on_next_frame(&tab_layers_button_new_update_fill_layers, NULL);
}
if (ui_menu_button(tr("Fill Mask"), "", ICON_MASK_FILL)) {
if (slot_layer_is_mask(l) || slot_layer_is_filter(l)) {
context_set_layer(l->parent);
}
l = g_context->layer;
i32_map_t *pointers = tab_layers_init_layer_map();
slot_layer_t *m = layers_new_mask(false, l, -1);
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *mat = g_project->_->materials->buffer[i];
tab_layers_remap_layer_pointers(mat->canvas->nodes, tab_layers_fill_layer_map(pointers));
}
sys_notify_on_next_frame(&tab_layers_button_new_to_fill_layer, m);
g_context->layer_preview_dirty = true;
history_new_fill_mask();
sys_notify_on_next_frame(&tab_layers_button_new_update_fill_layers, NULL);
}
if (ui_menu_button(tr("Filter"), "", ICON_FILTER)) {
if (slot_layer_is_mask(l) || slot_layer_is_filter(l)) {
context_set_layer(l->parent);
}
layers_create_filter();
}
g_ui->enabled = !slot_layer_is_group(g_context->layer) && !slot_layer_is_in_group(g_context->layer);
if (ui_menu_button(tr("Group"), "", ICON_FOLDER)) {
if (slot_layer_is_group(l) || slot_layer_is_in_group(l)) {
return;
}
if (slot_layer_is_layer_mask(l)) {
l = l->parent;
}
i32_map_t *pointers = tab_layers_init_layer_map();
slot_layer_t *group = layers_new_group();
context_set_layer(l);
array_remove(g_project->_->layers, group);
array_insert(g_project->_->layers, array_index_of(g_project->_->layers, l) + 1, group);
l->parent = group;
for (i32 i = 0; i < g_project->_->materials->length; ++i) {
slot_material_t *m = g_project->_->materials->buffer[i];
tab_layers_remap_layer_pointers(m->canvas->nodes, tab_layers_fill_layer_map(pointers));
}
context_set_layer(group);
history_new_group();
}
g_ui->enabled = true;
}
void tab_layers_button_new(char *text) {
if (ui_icon_button(text, ICON_PLUS, UI_ALIGN_CENTER)) {
ui_menu_draw(&tab_layers_button_new_menu, -1, -1);
}
}
void tab_layers_combo_filter() {
string_array_t *ar = any_array_create_from_raw(
(void *[]){
tr("All"),
},
1);
for (i32 i = 0; i < g_project->_->paint_objects->length; ++i) {
mesh_object_t *p = g_project->_->paint_objects->buffer[i];
any_array_push(ar, p->base->name);
}
string_array_t *atlases = project_get_used_atlases();
if (atlases != NULL) {
for (i32 i = 0; i < atlases->length; ++i) {
char *a = atlases->buffer[i];
any_array_push(ar, a);
}
}
ui_handle_t *filter_handle = ui_handle(__ID__);
filter_handle->i = g_context->layer_filter;
g_context->layer_filter = ui_combo(filter_handle, ar, tr("Filter"), false, UI_ALIGN_LEFT, true);
if (filter_handle->changed) {
tab_layers_apply_filter(g_context->layer_filter);
}
}
void tab_layers_draw_mini(ui_handle_t *htab) {
ui_set_hovered_tab_name(tr("Layers"));
i32 _ELEMENT_H = g_theme->ELEMENT_H;
g_theme->ELEMENT_H = math_floor(ui_sidebar_w_mini / 2.0 / (float)UI_SCALE());
ui_begin_sticky();
ui_separator(5, true);
tab_layers_combo_filter();
tab_layers_button_2d_view();
tab_layers_button_new("");
ui_end_sticky();
g_ui->_y += 2;
tab_layers_highlight_odd_lines();
tab_layers_draw_slots(true);
g_theme->ELEMENT_H = _ELEMENT_H;
}
void tab_layers_draw_full(ui_handle_t *htab) {
if (ui_tab(htab, tr("Layers"), false, -1, false)) {
ui_begin_sticky();
f32_array_t *row = f32_array_create_from_raw(
(f32[]){
-70,
-70,
-140,
},
3);
ui_row(row);
tab_layers_button_new(tr("New"));
tab_layers_button_2d_view();
tab_layers_combo_filter();
ui_end_sticky();
g_ui->_y += 2;
tab_layers_highlight_odd_lines();
tab_layers_draw_slots(false);
bool in_focus = g_ui->input_x > g_ui->_window_x && g_ui->input_x < g_ui->_window_x + g_ui->_window_w && g_ui->input_y > g_ui->_window_y &&
g_ui->input_y < g_ui->_window_y + g_ui->_window_h;
if (in_focus) {
// Layer selection
if (g_ui->is_key_pressed && g_ui->key_code == KEY_CODE_UP) {
i32 i = array_index_of(g_project->_->layers, g_context->layer);
while (++i < g_project->_->layers->length) {
slot_layer_t *candidate = g_project->_->layers->buffer[i];
if (candidate->parent != NULL && !candidate->parent->show_panel)
continue;
if (candidate->parent != NULL && candidate->parent->parent != NULL && !candidate->parent->parent->show_panel)
continue;
context_set_layer(candidate);
ui_base_hwnds->buffer[TAB_AREA_SIDEBAR0]->redraws = 2;
break;
}
}
if (g_ui->is_key_pressed && g_ui->key_code == KEY_CODE_DOWN) {
i32 i = array_index_of(g_project->_->layers, g_context->layer);
while (--i >= 0) {
slot_layer_t *candidate = g_project->_->layers->buffer[i];
if (candidate->parent != NULL && !candidate->parent->show_panel)
continue;
if (candidate->parent != NULL && candidate->parent->parent != NULL && !candidate->parent->parent->show_panel)
continue;
context_set_layer(candidate);
ui_base_hwnds->buffer[TAB_AREA_SIDEBAR0]->redraws = 2;
break;
}
}
// Open / close group
slot_layer_t *l = g_context->layer;
bool has_children = tab_layers_has_children(l);
if (has_children && g_ui->is_key_pressed && g_ui->key_code == KEY_CODE_RETURN) {
l->show_panel = !l->show_panel;
ui_base_hwnds->buffer[TAB_AREA_SIDEBAR0]->redraws = 2;
}
}
}
}
void tab_layers_draw(ui_handle_t *htab) {
bool mini = g_config->layout->buffer[LAYOUT_SIZE_SIDEBAR_W] <= ui_sidebar_w_mini;
mini ? tab_layers_draw_mini(htab) : tab_layers_draw_full(htab);
}
bool tab_layers_can_drop_new_layer(i32 position) {
if (position > 0 && position < g_project->_->layers->length && slot_layer_is_mask(g_project->_->layers->buffer[position - 1])) {
// 1. The layer to insert is inserted in the middle
// 2. The layer below is a mask, i.e. the layer would have to be a (group) mask, too.
return false;
}
return true;
}