Files
armorpaint/paint/sources/ui/ui_base.c
T
2026-08-21 22:40:25 +02:00

488 lines
14 KiB
C

#include "../global.h"
extern gpu_texture_t *base_color_wheel;
extern gpu_texture_t *base_color_wheel_gradient;
void ui_base_init_on_next_frame(void *_) {
layers_init();
}
void ui_base_view_top() {
bool is_typing = g_ui->is_typing;
if (context_in_paint_area() && !is_typing) {
if (mouse_view_x() < sys_w()) {
viewport_set_view(0, 0, 1, 0, 0, 0);
}
}
}
void ui_base_on_border_hover(ui_handle_t *handle, i32 side) {
if (!base_ui_enabled) {
return;
}
if (handle != ui_base_hwnds->buffer[TAB_AREA_SIDEBAR0] && handle != ui_base_hwnds->buffer[TAB_AREA_SIDEBAR1] &&
handle != ui_base_hwnds->buffer[TAB_AREA_STATUS] && handle != ui_nodes_hwnd && handle != ui_view2d_hwnd) {
return; // Scalable handles
}
if (handle == ui_view2d_hwnd && side != BORDER_SIDE_LEFT) {
return;
}
if (handle == ui_nodes_hwnd && side == BORDER_SIDE_TOP && !ui_view2d_show) {
return;
}
if (handle == ui_base_hwnds->buffer[TAB_AREA_SIDEBAR0] && side == BORDER_SIDE_TOP) {
return;
}
if (handle == ui_nodes_hwnd && side != BORDER_SIDE_LEFT && side != BORDER_SIDE_TOP) {
return;
}
if (handle == ui_base_hwnds->buffer[TAB_AREA_STATUS] && side != BORDER_SIDE_TOP) {
return;
}
if (side == BORDER_SIDE_RIGHT) {
return; // UI is snapped to the right side
}
side == BORDER_SIDE_LEFT || side == BORDER_SIDE_RIGHT ? iron_mouse_set_cursor(IRON_CURSOR_SIZEWE) : iron_mouse_set_cursor(IRON_CURSOR_SIZENS);
if (g_ui->input_started) {
ui_base_border_started = side;
ui_base_border_handle = handle;
base_is_resizing = true;
}
}
void ui_base_on_tab_drop(ui_handle_t *to, i32 to_position, ui_handle_t *from, i32 from_position) {
i32 i = -1;
i32 j = -1;
for (i32 k = 0; k < ui_base_htabs->length; ++k) {
if (ui_base_htabs->buffer[k] == to) {
i = k;
}
if (ui_base_htabs->buffer[k] == from) {
j = k;
}
}
if (i == j && to_position == from_position) {
return;
}
if (i > -1 && j > -1) {
tab_draw_t_array_t *tabsi = ui_base_hwnd_tabs->buffer[i];
tab_draw_t_array_t *tabsj = ui_base_hwnd_tabs->buffer[j];
if (tabsj->length == 1) {
return; // Keep at least one tab in place
}
tab_draw_t *element = tabsj->buffer[from_position];
array_splice(tabsj, from_position, 1);
array_insert(tabsi, to_position, element);
ui_base_hwnds->buffer[i]->redraws = 2;
ui_base_hwnds->buffer[j]->redraws = 2;
}
}
bool ui_base_picker_button() {
return ui_icon_button("", ICON_PICKER, UI_ALIGN_CENTER);
}
void ui_base_init() {
ui_toolbar_init();
g_context->text_tool_text = string_copy(tr("Text"));
ui_header_init();
ui_statusbar_init();
ui_menubar_init();
ui_header_h = math_floor(ui_header_default_h * g_config->window_scale);
ui_menubar_w = math_floor(ui_menubar_default_w * g_config->window_scale);
if (g_context->empty_envmap == NULL) {
ui_base_make_empty_envmap(g_theme->VIEWPORT_COL);
}
if (g_context->preview_envmap == NULL) {
u8_array_t *b = u8_array_create(4);
b->buffer[0] = 0;
b->buffer[1] = 0;
b->buffer[2] = 0;
b->buffer[3] = 255;
g_context->preview_envmap = gpu_create_texture_from_bytes(b, 1, 1, GPU_TEXTURE_FORMAT_RGBA32);
array_free(b);
free(b);
}
if (g_context->saved_envmap == NULL) {
// raw.saved_envmap = scene_world._envmap;
g_context->default_irradiance = scene_world->_->irradiance;
g_context->default_radiance = scene_world->_->radiance;
g_context->default_radiance_mipmaps = scene_world->_->radiance_mipmaps;
}
scene_world->_->envmap = g_context->show_envmap ? g_context->saved_envmap : g_context->empty_envmap;
g_context->ddirty = 1;
string_array_t *resources = any_array_create_from_raw(
(void *[]){
"cursor.k",
"icons.k",
"icons05x.k",
},
3);
resource_load(resources);
f32 scale = g_config->window_scale;
ui_options_t *ops = ALLOC_INIT(
ui_options_t,
{.theme = g_theme, .font = g_font, .scale_factor = scale, .color_wheel = base_color_wheel, .black_white_gradient = base_color_wheel_gradient});
g_ui = ui_create(ops);
ui_on_border_hover = ui_base_on_border_hover;
ui_on_tab_drop = ui_base_on_tab_drop;
if (UI_SCALE() > 1) {
ui_base_set_icon_scale();
}
ui_picker_button = ui_base_picker_button;
g_context->gizmo = scene_get_child(".Gizmo");
g_context->gizmo_translate_x = object_get_child(g_context->gizmo, ".TranslateX");
g_context->gizmo_translate_y = object_get_child(g_context->gizmo, ".TranslateY");
g_context->gizmo_translate_z = object_get_child(g_context->gizmo, ".TranslateZ");
g_context->gizmo_scale_x = object_get_child(g_context->gizmo, ".ScaleX");
g_context->gizmo_scale_y = object_get_child(g_context->gizmo, ".ScaleY");
g_context->gizmo_scale_z = object_get_child(g_context->gizmo, ".ScaleZ");
g_context->gizmo_rotate_x = object_get_child(g_context->gizmo, ".RotateX");
g_context->gizmo_rotate_y = object_get_child(g_context->gizmo, ".RotateY");
g_context->gizmo_rotate_z = object_get_child(g_context->gizmo, ".RotateZ");
project_new(false);
if (string_equals(g_project->_->filepath, "")) {
sys_notify_on_next_frame(&ui_base_init_on_next_frame, NULL);
}
operator_register("view_top", ui_base_view_top);
}
void ui_base_menu_draw_viewport_mode() {
ui_handle_t *mode_handle = ui_handle(__ID__);
mode_handle->i = g_context->viewport_mode;
ui_text(tr("Viewport Mode"), UI_ALIGN_RIGHT, 0x00000000);
string_array_t *modes = base_get_viewport_modes();
string_array_t *shortcuts = base_get_viewport_mode_shortcuts();
if (gpu_raytrace_supported()) {
any_array_push(modes, tr("Path Traced"));
any_array_push(shortcuts, "p");
}
for (i32 i = 0; i < modes->length; ++i) {
ui_radio(mode_handle, i, modes->buffer[i], shortcuts->buffer[i]);
}
i32 index = string_array_index_of(shortcuts, keyboard_key_code(g_ui->key_code));
if (g_ui->is_key_pressed && index != -1) {
mode_handle->i = index;
g_ui->changed = true;
context_set_viewport_mode(mode_handle->i);
}
else if (mode_handle->changed) {
context_set_viewport_mode(mode_handle->i);
g_ui->changed = true;
}
}
void ui_base_update_next_frame(void *_) {
export_texture_run(g_context->texture_export_path, false);
}
void ui_base_update_ui_on_next_frame(void *_) {
layers_update_fill_layer(true);
make_material_parse_paint_material(false);
}
void ui_base_update(void *_) {
if (console_message_timer > 0) {
console_message_timer -= sys_delta();
if (console_message_timer <= 0) {
ui_base_hwnds->buffer[TAB_AREA_STATUS]->redraws = 2;
}
}
ui_sidebar_w_mini = math_floor(ui_sidebar_default_w_mini * UI_SCALE());
if (base_ui_enabled) {
render_gizmo_update();
util_layer_update_path();
util_touch_update();
util_stencil_transform();
util_select_update();
util_layer_check_path_grab();
util_brush_update();
util_layer_update_preview();
util_shortcut_undo_redo();
util_shortcut_global();
util_shortcut_brush();
util_shortcut_viewport();
util_resize_borders();
util_particle_update();
operator_update();
}
string_array_t *keys = map_keys(g_plugins);
for (i32 i = 0; i < keys->length; ++i) {
plugin_t *p = any_map_get(g_plugins, keys->buffer[i]);
if (p->on_update != NULL) {
minic_ctx_call_fn(p->ctx, p->on_update, NULL, 0);
}
}
array_free(keys);
free(keys);
if (!mouse_down("left")) {
ui_base_border_handle = NULL;
base_is_resizing = false;
}
util_cursor_render(_);
if (!ui_base_show && g_config->touch_ui) {
g_ui->input_enabled = true;
ui_begin(g_ui);
if (ui_window(ui_handle(__ID__), 0, 0, 150, math_floor(UI_ELEMENT_H() + UI_ELEMENT_OFFSET() + 1), false)) {
if (ui_button(tr("Close"), UI_ALIGN_CENTER, "")) {
ui_base_toggle_distract_free();
}
}
ui_end();
}
if (!ui_base_show) {
return;
}
g_ui->input_enabled = base_ui_enabled;
// Remember last tab positions
for (i32 i = 0; i < ui_base_htabs->length; ++i) {
if (ui_base_htabs->buffer[i]->changed) {
g_config->layout_tabs->buffer[i] = ui_base_htabs->buffer[i]->i;
config_save();
}
}
// Set tab positions
for (i32 i = 0; i < ui_base_htabs->length; ++i) {
ui_base_htabs->buffer[i]->i = g_config->layout_tabs->buffer[i];
}
// Nothing to display in the main area
if (!base_view3d_show && !ui_nodes_show && !ui_view2d_show) {
draw_begin(NULL, true, g_theme->SEPARATOR_COL);
gpu_texture_t *img = data_get_texture("badge_bw.k");
draw_set_color(0x22ffffff);
draw_image(img, base_view3d_w() / 2.0 - img->width / 2.0, base_h() / 2.0 - img->height / 2.0);
draw_end();
}
ui_begin(g_ui);
ui_toolbar_render_ui();
ui_menubar_render_ui();
ui_header_render_ui();
ui_statusbar_render_ui();
ui_sidebar_render_ui();
ui_end();
g_ui->input_enabled = true;
}
ui_handle_t_array_t *ui_base_init_hwnds() {
ui_handle_t_array_t *hwnds = any_array_create_from_raw(
(void *[]){
ui_handle_create(),
ui_handle_create(),
ui_handle_create(),
},
3);
return hwnds;
}
ui_handle_t_array_t *ui_base_init_htabs() {
ui_handle_t_array_t *htabs = any_array_create_from_raw(
(void *[]){
ui_handle_create(),
ui_handle_create(),
ui_handle_create(),
},
3);
return htabs;
}
tab_draw_t *_draw_callback_create(void (*f)(ui_handle_t *)) {
tab_draw_t *cb = ALLOC_INIT(tab_draw_t, {.f = f});
return cb;
}
tab_draw_array_t_array_t *ui_base_init_hwnd_tabs() {
tab_draw_array_t *a0 = any_array_create_from_raw(
(void *[]){
_draw_callback_create(tab_layers_draw),
_draw_callback_create(tab_meshes_draw),
_draw_callback_create(tab_scripts_draw),
},
3);
tab_draw_array_t *a1 = any_array_create_from_raw(
(void *[]){
_draw_callback_create(tab_materials_draw),
_draw_callback_create(tab_brushes_draw),
_draw_callback_create(tab_plugins_draw),
},
3);
tab_draw_array_t *a2 = any_array_create_from_raw(
(void *[]){
_draw_callback_create(tab_browser_draw),
_draw_callback_create(tab_textures_draw),
_draw_callback_create(tab_fonts_draw),
_draw_callback_create(tab_sounds_draw),
_draw_callback_create(tab_swatches_draw),
_draw_callback_create(tab_timeline_draw),
_draw_callback_create(tab_console_draw),
_draw_callback_create(ui_statusbar_draw_version_tab),
},
8);
#ifdef IRON_IOS
if (config_is_iphone()) {
array_splice(a2, 5, 1); // Timeline
array_splice(a2, 4, 1); // Swatches
array_splice(a2, 3, 1); // Sounds
}
#endif
#ifdef IRON_ANDROID
if (iron_window_width() <= 1080) {
array_splice(a2, 5, 1); // Timeline
array_splice(a2, 3, 1); // Sounds
}
#endif
#ifdef is_debug
any_array_push(a0, _draw_callback_create(tab_debug_draw));
#endif
tab_draw_array_t_array_t *r = any_array_create_from_raw((void *[]){}, 0);
any_array_push(r, a0);
any_array_push(r, a1);
any_array_push(r, a2);
return r;
}
void ui_base_toggle_distract_free() {
if (base_player_lock) {
return;
}
ui_base_show = !ui_base_show;
if (ui_base_show) {
g_config->workspace = WORKSPACE_PAINT_3D;
base_update_workspace();
}
base_resize();
}
void ui_base_show_material_nodes() {
// Clear input state as ui receives input events even when not drawn
ui_end_input();
ui_nodes_show = !ui_nodes_show || ui_nodes_canvas_type != CANVAS_TYPE_MATERIAL;
ui_nodes_canvas_type = CANVAS_TYPE_MATERIAL;
if (g_config->touch_ui && ui_view2d_show && base_view3d_show) {
ui_view2d_show = false;
}
if (g_config->touch_ui && ui_nodes_show && iron_window_width() < iron_window_height()) {
ui_view2d_show = false;
base_view3d_show = false;
}
if (g_config->touch_ui && !ui_nodes_show && iron_window_width() < iron_window_height()) {
base_view3d_show = true;
}
base_resize();
}
void ui_base_show_brush_nodes() {
// Clear input state as ui receives input events even when not drawn
ui_end_input();
ui_nodes_show = !ui_nodes_show || ui_nodes_canvas_type != CANVAS_TYPE_BRUSH;
ui_nodes_canvas_type = CANVAS_TYPE_BRUSH;
if (g_config->touch_ui && ui_view2d_show && base_view3d_show) {
ui_view2d_show = false;
}
if (g_config->touch_ui && ui_nodes_show && iron_window_width() < iron_window_height()) {
ui_view2d_show = false;
base_view3d_show = false;
}
if (g_config->touch_ui && !ui_nodes_show && iron_window_width() < iron_window_height()) {
base_view3d_show = true;
}
base_resize();
}
void ui_base_show_2d_view(view_2d_type_t type) {
// Clear input state as ui receives input events even when not drawn
ui_end_input();
if (ui_view2d_type != type) {
ui_view2d_show = true;
}
else {
ui_view2d_show = !ui_view2d_show;
}
ui_view2d_type = type;
ui_view2d_hwnd->redraws = 2;
if (g_config->touch_ui && ui_nodes_show && base_view3d_show) {
ui_nodes_show = false;
}
if (g_config->touch_ui && ui_view2d_show && iron_window_width() < iron_window_height()) {
ui_nodes_show = false;
base_view3d_show = false;
}
if (g_config->touch_ui && !ui_view2d_show && iron_window_width() < iron_window_height()) {
base_view3d_show = true;
}
base_resize();
}
void ui_base_show_3d_view() {
if (!base_view3d_show) {
if (g_config->touch_ui && ui_nodes_show && ui_view2d_show) {
ui_view2d_show = false;
}
if (g_config->touch_ui && (ui_nodes_show || ui_view2d_show) && iron_window_width() < iron_window_height()) {
ui_nodes_show = false;
ui_view2d_show = false;
}
}
base_view3d_show = !base_view3d_show;
base_resize();
}
void ui_base_toggle_browser() {
bool minimized = g_config->layout->buffer[LAYOUT_SIZE_STATUS_H] <= (ui_statusbar_default_h * g_config->window_scale);
g_config->layout->buffer[LAYOUT_SIZE_STATUS_H] = minimized ? 240 : ui_statusbar_default_h;
g_config->layout->buffer[LAYOUT_SIZE_STATUS_H] = math_floor(g_config->layout->buffer[LAYOUT_SIZE_STATUS_H] * g_config->window_scale);
base_resize();
}