From a8f678c74005c750c6bd95d2f1002ef50e7a99f6 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Tue, 5 Feb 2019 01:13:38 -0800 Subject: [PATCH] Full rewrite of panel layout system --- 4coder_API/4coder_types.h | 9 +- 4coder_default_framework.cpp | 2 +- 4coder_generated/app_functions.h | 14 +- 4coder_helper.cpp | 12 + 4ed.cpp | 342 ++++--------- 4ed_api_implementation.cpp | 290 +++++------ 4ed_app_models.h | 9 +- 4ed_defines.h | 1 + 4ed_edit.cpp | 28 +- 4ed_layout.cpp | 809 +++++++++++++++---------------- 4ed_layout.h | 105 ++-- 4ed_math.h | 184 ++++++- 4ed_view.cpp | 50 +- 4ed_view.h | 5 - meta/4ed_build.cpp | 4 +- 15 files changed, 888 insertions(+), 976 deletions(-) diff --git a/4coder_API/4coder_types.h b/4coder_API/4coder_types.h index c470144a..7c702c09 100644 --- a/4coder_API/4coder_types.h +++ b/4coder_API/4coder_types.h @@ -329,7 +329,12 @@ ENUM(int32_t, View_Split_Position){ /* DOC(This value indicates that the new view should be left of the existing view.) */ ViewSplit_Left, /* DOC(This value indicates that the new view should be right of the existing view.) */ - ViewSplit_Right + ViewSplit_Right, +}; + +ENUM(int32_t, View_Split_Kind){ + ViewSplitKind_Ratio, + ViewSplitKind_FixedPixels, }; /* DOC(Key_Code is the alias for key codes including raw codes and codes translated to textual input that takes modifiers into account.) */ @@ -642,8 +647,6 @@ STRUCT i32_Rect{ int32_t y1; }; -GLOBAL_VAR i32_Rect null_i32_rect = {}; - /* DOC(A four corner axis aligned rectangle, with floating point coordinates.) */ diff --git a/4coder_default_framework.cpp b/4coder_default_framework.cpp index 6cb6d363..93c2f497 100644 --- a/4coder_default_framework.cpp +++ b/4coder_default_framework.cpp @@ -72,7 +72,7 @@ static View_Summary open_footer_panel(Application_Links *app, View_Summary *view){ View_Summary special_view = open_view(app, view, ViewSplit_Bottom); new_view_settings(app, &special_view); - view_set_split_proportion(app, &special_view, .2f); + view_set_split_pixel_size(app, &special_view, (int32_t)(special_view.line_height*10.f)); view_set_passive(app, &special_view, true); return(special_view); } diff --git a/4coder_generated/app_functions.h b/4coder_generated/app_functions.h index a1ba16ce..14136b2d 100644 --- a/4coder_generated/app_functions.h +++ b/4coder_generated/app_functions.h @@ -39,7 +39,7 @@ struct Application_Links; #define VIEW_GET_SETTING_SIG(n) bool32 n(Application_Links *app, View_Summary *view, View_Setting_ID setting, int32_t *value_out) #define VIEW_SET_SETTING_SIG(n) bool32 n(Application_Links *app, View_Summary *view, View_Setting_ID setting, int32_t value) #define VIEW_GET_MANAGED_SCOPE_SIG(n) Managed_Scope n(Application_Links *app, View_ID view_id) -#define VIEW_SET_SPLIT_PROPORTION_SIG(n) bool32 n(Application_Links *app, View_Summary *view, float t) +#define VIEW_SET_SPLIT_SIG(n) bool32 n(Application_Links *app, View_Summary *view, View_Split_Kind kind, float t) #define VIEW_GET_ENCLOSURE_RECT_SIG(n) i32_Rect n(Application_Links *app, View_Summary *view) #define VIEW_COMPUTE_CURSOR_SIG(n) bool32 n(Application_Links *app, View_Summary *view, Buffer_Seek seek, Full_Cursor *cursor_out) #define VIEW_SET_CURSOR_SIG(n) bool32 n(Application_Links *app, View_Summary *view, Buffer_Seek seek, bool32 set_preferred_x) @@ -167,7 +167,7 @@ typedef SET_ACTIVE_VIEW_SIG(Set_Active_View_Function); typedef VIEW_GET_SETTING_SIG(View_Get_Setting_Function); typedef VIEW_SET_SETTING_SIG(View_Set_Setting_Function); typedef VIEW_GET_MANAGED_SCOPE_SIG(View_Get_Managed_Scope_Function); -typedef VIEW_SET_SPLIT_PROPORTION_SIG(View_Set_Split_Proportion_Function); +typedef VIEW_SET_SPLIT_SIG(View_Set_Split_Function); typedef VIEW_GET_ENCLOSURE_RECT_SIG(View_Get_Enclosure_Rect_Function); typedef VIEW_COMPUTE_CURSOR_SIG(View_Compute_Cursor_Function); typedef VIEW_SET_CURSOR_SIG(View_Set_Cursor_Function); @@ -297,7 +297,7 @@ Set_Active_View_Function *set_active_view; View_Get_Setting_Function *view_get_setting; View_Set_Setting_Function *view_set_setting; View_Get_Managed_Scope_Function *view_get_managed_scope; -View_Set_Split_Proportion_Function *view_set_split_proportion; +View_Set_Split_Function *view_set_split; View_Get_Enclosure_Rect_Function *view_get_enclosure_rect; View_Compute_Cursor_Function *view_compute_cursor; View_Set_Cursor_Function *view_set_cursor; @@ -426,7 +426,7 @@ Set_Active_View_Function *set_active_view_; View_Get_Setting_Function *view_get_setting_; View_Set_Setting_Function *view_set_setting_; View_Get_Managed_Scope_Function *view_get_managed_scope_; -View_Set_Split_Proportion_Function *view_set_split_proportion_; +View_Set_Split_Function *view_set_split_; View_Get_Enclosure_Rect_Function *view_get_enclosure_rect_; View_Compute_Cursor_Function *view_compute_cursor_; View_Set_Cursor_Function *view_set_cursor_; @@ -563,7 +563,7 @@ app_links->set_active_view_ = Set_Active_View;\ app_links->view_get_setting_ = View_Get_Setting;\ app_links->view_set_setting_ = View_Set_Setting;\ app_links->view_get_managed_scope_ = View_Get_Managed_Scope;\ -app_links->view_set_split_proportion_ = View_Set_Split_Proportion;\ +app_links->view_set_split_ = View_Set_Split;\ app_links->view_get_enclosure_rect_ = View_Get_Enclosure_Rect;\ app_links->view_compute_cursor_ = View_Compute_Cursor;\ app_links->view_set_cursor_ = View_Set_Cursor;\ @@ -692,7 +692,7 @@ static bool32 set_active_view(Application_Links *app, View_Summary *view){return static bool32 view_get_setting(Application_Links *app, View_Summary *view, View_Setting_ID setting, int32_t *value_out){return(app->view_get_setting(app, view, setting, value_out));} static bool32 view_set_setting(Application_Links *app, View_Summary *view, View_Setting_ID setting, int32_t value){return(app->view_set_setting(app, view, setting, value));} static Managed_Scope view_get_managed_scope(Application_Links *app, View_ID view_id){return(app->view_get_managed_scope(app, view_id));} -static bool32 view_set_split_proportion(Application_Links *app, View_Summary *view, float t){return(app->view_set_split_proportion(app, view, t));} +static bool32 view_set_split(Application_Links *app, View_Summary *view, View_Split_Kind kind, float t){return(app->view_set_split(app, view, kind, t));} static i32_Rect view_get_enclosure_rect(Application_Links *app, View_Summary *view){return(app->view_get_enclosure_rect(app, view));} static bool32 view_compute_cursor(Application_Links *app, View_Summary *view, Buffer_Seek seek, Full_Cursor *cursor_out){return(app->view_compute_cursor(app, view, seek, cursor_out));} static bool32 view_set_cursor(Application_Links *app, View_Summary *view, Buffer_Seek seek, bool32 set_preferred_x){return(app->view_set_cursor(app, view, seek, set_preferred_x));} @@ -821,7 +821,7 @@ static bool32 set_active_view(Application_Links *app, View_Summary *view){return static bool32 view_get_setting(Application_Links *app, View_Summary *view, View_Setting_ID setting, int32_t *value_out){return(app->view_get_setting_(app, view, setting, value_out));} static bool32 view_set_setting(Application_Links *app, View_Summary *view, View_Setting_ID setting, int32_t value){return(app->view_set_setting_(app, view, setting, value));} static Managed_Scope view_get_managed_scope(Application_Links *app, View_ID view_id){return(app->view_get_managed_scope_(app, view_id));} -static bool32 view_set_split_proportion(Application_Links *app, View_Summary *view, float t){return(app->view_set_split_proportion_(app, view, t));} +static bool32 view_set_split(Application_Links *app, View_Summary *view, View_Split_Kind kind, float t){return(app->view_set_split_(app, view, kind, t));} static i32_Rect view_get_enclosure_rect(Application_Links *app, View_Summary *view){return(app->view_get_enclosure_rect_(app, view));} static bool32 view_compute_cursor(Application_Links *app, View_Summary *view, Buffer_Seek seek, Full_Cursor *cursor_out){return(app->view_compute_cursor_(app, view, seek, cursor_out));} static bool32 view_set_cursor(Application_Links *app, View_Summary *view, Buffer_Seek seek, bool32 set_preferred_x){return(app->view_set_cursor_(app, view, seek, set_preferred_x));} diff --git a/4coder_helper.cpp b/4coder_helper.cpp index 09e30920..431e8a0a 100644 --- a/4coder_helper.cpp +++ b/4coder_helper.cpp @@ -1596,5 +1596,17 @@ begin_notepad_mode(Application_Links *app){ } } +//////////////////////////////// + +static bool32 +view_set_split_proportion(Application_Links *app, View_Summary *view, float t){ + return(view_set_split(app, view, ViewSplitKind_Ratio, t)); +} + +static bool32 +view_set_split_pixel_size(Application_Links *app, View_Summary *view, int32_t t){ + return(view_set_split(app, view, ViewSplitKind_FixedPixels, (float)t)); +} + // BOTTOM diff --git a/4ed.cpp b/4ed.cpp index f22649f2..9a6ad863 100644 --- a/4ed.cpp +++ b/4ed.cpp @@ -66,9 +66,10 @@ internal void file_cursor_to_end(System_Functions *system, Models *models, Editing_File *file){ Assert(file != 0); i32 pos = buffer_size(&file->state.buffer); - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ + Layout *layout = &models->layout; + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file != file){ continue; @@ -78,15 +79,6 @@ file_cursor_to_end(System_Functions *system, Models *models, Editing_File *file) } } -internal void -do_feedback_message(System_Functions *system, Models *models, String value){ - Editing_File *file = models->message_buffer; - if (file != 0){ - output_file_append(system, models, file, value); - file_cursor_to_end(system, models, file); - } -} - // Commands #define USE_VARS(n) App_Vars *n = command->vars @@ -110,14 +102,6 @@ do_feedback_message(System_Functions *system, Models *models, String value){ #define COMMAND_DECL(n) internal void command_##n(System_Functions *system, Models *models, Command_Binding binding) -internal View* -panel_make_empty(System_Functions *system, Models *models, Panel *panel){ - Assert(panel->view == 0); - View_And_ID new_view = live_set_alloc_view(&models->mem.heap, &models->lifetime_allocator, &models->live_set, panel); - view_set_file(system, models, new_view.view, models->scratch_buffer); - return(new_view.view); -} - COMMAND_DECL(null){} internal void @@ -133,7 +117,7 @@ view_undo_redo(System_Functions *system, Models *models, View *view, Edit_Stack } COMMAND_DECL(undo){ - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(&models->layout); View *view = active_panel->view; if (view_lock_flags(view) != 0){ return; @@ -147,7 +131,7 @@ COMMAND_DECL(undo){ } COMMAND_DECL(redo){ - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(&models->layout); View *view = active_panel->view; if (view_lock_flags(view) != 0){ return; @@ -894,39 +878,13 @@ App_Init_Sig(app_init){ models->config_api = api; models->app_links.cmd_context = models; - Partition *partition = &models->mem.part; - - i32 panel_max_count = MAX_VIEWS; - models->layout.panel_max_count = panel_max_count; - i32 divider_max_count = panel_max_count - 1; - models->layout.panel_count = 0; - - Panel *panels = push_array(partition, Panel, panel_max_count); - models->layout.panels = panels; - - dll_init_sentinel(&models->layout.free_sentinel); - dll_init_sentinel(&models->layout.used_sentinel); - - Panel *panel = panels; - for (i32 i = 0; i < panel_max_count; ++i, ++panel){ - dll_insert(&models->layout.free_sentinel, panel); - } - - Panel_Divider *dividers = push_array(partition, Panel_Divider, divider_max_count); - models->layout.dividers = dividers; - - Panel_Divider *div = dividers; - for (i32 i = 0; i < divider_max_count-1; ++i, ++div){ - div->next = (div + 1); - } - div->next = 0; - models->layout.free_divider = dividers; + Partition *part = &models->mem.part; + // NOTE(allen): live set { models->live_set.count = 0; - models->live_set.max = panel_max_count; - - models->live_set.views = push_array(partition, View, models->live_set.max); + models->live_set.max = MAX_VIEWS; + models->live_set.views = push_array(part, View, models->live_set.max); //dll_init_sentinel models->live_set.free_sentinel.transient.next = &models->live_set.free_sentinel; @@ -948,7 +906,7 @@ App_Init_Sig(app_init){ { umem memsize = KB(8); - void *mem = push_array(partition, u8, (i32)memsize); + void *mem = push_array(part, u8, (i32)memsize); parse_context_init_memory(&models->parse_context_memory, mem, memsize); parse_context_add_default(&models->parse_context_memory, &models->mem.heap); } @@ -963,12 +921,10 @@ App_Init_Sig(app_init){ } dynamic_variables_init(&models->variable_layout); - dynamic_workspace_init(&models->mem.heap, &models->lifetime_allocator, - DynamicWorkspace_Global, 0, - &models->dynamic_workspace); + dynamic_workspace_init(&models->mem.heap, &models->lifetime_allocator, DynamicWorkspace_Global, 0, &models->dynamic_workspace); // NOTE(allen): file setup - working_set_init(system, &models->working_set, partition, &vars->models.mem.heap); + working_set_init(system, &models->working_set, part, &vars->models.mem.heap); models->working_set.default_display_width = DEFAULT_DISPLAY_WIDTH; models->working_set.default_minimum_base_display_width = DEFAULT_MINIMUM_BASE_DISPLAY_WIDTH; @@ -991,7 +947,7 @@ App_Init_Sig(app_init){ // NOTE(allen): title space models->has_new_title = true; models->title_capacity = KB(4); - models->title_space = push_array(partition, char, models->title_capacity); + models->title_space = push_array(part, char, models->title_capacity); { String builder = make_string_cap(models->title_space, 0, models->title_capacity); append(&builder, WINDOW_NAME); @@ -1002,7 +958,7 @@ App_Init_Sig(app_init){ models->system = system; models->vars = vars; - // NOTE(allen): init first panel + // NOTE(allen): init baked in buffers File_Init init_files[] = { { make_lit_string("*messages*"), &models->message_buffer, true , }, { make_lit_string("*scratch*"), &models->scratch_buffer, false, }, @@ -1011,7 +967,7 @@ App_Init_Sig(app_init){ Heap *heap = &models->mem.heap; for (i32 i = 0; i < ArrayCount(init_files); ++i){ Editing_File *file = working_set_alloc_always(&models->working_set, heap, &models->lifetime_allocator); - buffer_bind_name(models, heap, partition, &models->working_set, file, init_files[i].name); + buffer_bind_name(models, heap, part, &models->working_set, file, init_files[i].name); if (init_files[i].ptr != 0){ *init_files[i].ptr = file; @@ -1029,14 +985,20 @@ App_Init_Sig(app_init){ file->settings.unwrapped_lines = true; } - Panel_And_ID p = layout_alloc_panel(&models->layout); - panel_make_empty(system, models, p.panel); - models->layout.active_panel = p.id; + // NOTE(allen): setup first panel + { + Panel *panel = layout_initialize(part, &models->layout); + View *new_view = live_set_alloc_view(&models->mem.heap, &models->lifetime_allocator, &models->live_set); + panel->view = new_view; + new_view->transient.panel = panel; + view_set_file(system, models, new_view, models->scratch_buffer); + } + // NOTE(allen): hot directory hot_directory_init(&models->hot_directory, current_directory); // NOTE(allen): child proc list setup - vars->cli_processes = make_cli_list(partition, 16); + vars->cli_processes = make_cli_list(part, MAX_VIEWS); // NOTE(allen): init GUI keys models->user_up_key = key_up; @@ -1104,18 +1066,9 @@ App_Step_Sig(app_step){ } // NOTE(allen): reorganizing panels on screen - i32 prev_width = models->layout.full_width; - i32 prev_height = models->layout.full_height; - i32 current_width = target->width; - i32 current_height = target->height; - { - models->layout.full_width = current_width; - models->layout.full_height = current_height; - - if (prev_width != current_width || prev_height != current_height){ - layout_refit(&models->layout, prev_width, prev_height); - } - } + Vec2_i32 prev_dim = layout_get_root_size(&models->layout); + Vec2_i32 current_dim = V2(target->width, target->height); + layout_set_root_size(&models->layout, current_dim); // NOTE(allen): First frame initialization if (input->first_step){ @@ -1242,8 +1195,8 @@ App_Step_Sig(app_step){ } if (input->mouse.x != models->prev_x || input->mouse.y != models->prev_y){ - b32 was_in_window = hit_check(models->prev_x, models->prev_y, i32R(0, 0, prev_width, prev_height)); - b32 is_in_window = hit_check(input->mouse.x, input->mouse.y, i32R(0, 0, current_width, current_height)); + b32 was_in_window = hit_check(models->prev_x, models->prev_y, i32R(0, 0, prev_dim.x, prev_dim.y)); + b32 is_in_window = hit_check(input->mouse.x, input->mouse.y, i32R(0, 0, current_dim.x, current_dim.y)); if (is_in_window || was_in_window){ mouse_event.keycode = key_mouse_move; input->keys.keys[input->keys.count++] = mouse_event; @@ -1255,80 +1208,42 @@ App_Step_Sig(app_step){ input->keys.keys[input->keys.count++] = mouse_event; } + // NOTE(allen): expose layout + Layout *layout = &models->layout; + // NOTE(allen): mouse hover status Panel *mouse_panel = 0; - b32 mouse_in_edit_area = false; - b32 mouse_in_margin_area = false; - b32 mouse_on_divider = false; - b32 mouse_divider_vertical = false; - i32 mouse_divider_id = 0; - i32 mouse_divider_side = 0; - - i32 mx = input->mouse.x; - i32 my = input->mouse.y; - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ - if (hit_check(mx, my, panel->inner)){ - mouse_panel = panel; - mouse_in_edit_area = true; - } - else if (hit_check(mx, my, panel->full)){ - mouse_panel = panel; - mouse_in_margin_area = true; - - if (mx >= panel->inner.x0 && mx < panel->inner.x1){ - if (my > panel->inner.y0){ - mouse_divider_side = -1; - } - else{ - mouse_divider_side = 1; - } - } - else{ - mouse_divider_vertical = true; - if (mx > panel->inner.x0){ - mouse_divider_side = -1; - } - else{ - mouse_divider_side = 1; - } - } - - if (models->layout.panel_count > 1){ - mouse_divider_id = panel->parent; - - i32 which_child = panel->which_child; - for (;;){ - Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id); - if (which_child == mouse_divider_side && div.divider->v_divider == mouse_divider_vertical){ - mouse_on_divider = true; - break; + Panel *divider_panel = 0; + b32 mouse_in_margin = false; + Vec2_i32 mouse = V2(input->mouse.x, input->mouse.y); + { + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ + if (hit_check(mouse.x, mouse.y, panel->rect_full)){ + mouse_panel = panel; + if (!hit_check(mouse.x, mouse.y, panel->rect_inner)){ + mouse_in_margin = true; + for (divider_panel = mouse_panel->parent; + divider_panel != 0; + divider_panel = divider_panel->parent){ + if (hit_check(mouse.x, mouse.y, divider_panel->rect_inner)){ + break; + } } - if (mouse_divider_id == models->layout.root){ - break; - } - mouse_divider_id = div.divider->parent; - which_child = div.divider->which_child; } - } - else{ - mouse_on_divider = false; - mouse_divider_id = 0; + if (mouse_panel != 0){ + break; } } - - if (mouse_panel != 0){ - break; - } } // NOTE(allen): consume event stream Key_Event_Data *key_ptr = input->keys.keys; Key_Event_Data *key_end = key_ptr + input->keys.count; for (;key_ptr < key_end; key_ptr += 1){ - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(layout); View *view = active_panel->view; Assert(view != 0); @@ -1344,7 +1259,7 @@ App_Step_Sig(app_step){ EventConsume_Command, }; i32 event_consume_mode = EventConsume_Command; - if (keycode == key_mouse_left && input->mouse.press_l && mouse_on_divider){ + if (keycode == key_mouse_left && input->mouse.press_l && (divider_panel != 0)){ event_consume_mode = EventConsume_BeginResize; } else if (keycode == key_mouse_left && input->mouse.press_l && mouse_panel != 0 && mouse_panel != active_panel){ @@ -1355,56 +1270,7 @@ App_Step_Sig(app_step){ case EventConsume_BeginResize: { vars->state = APP_STATE_RESIZING; - Divider_And_ID div = layout_get_divider(&models->layout, mouse_divider_id); - vars->resizing.divider = div.divider; - - f32 min = 0; - f32 max = 0; - if (mouse_divider_vertical){ - max = (f32)models->layout.full_width; - } - else{ - max = (f32)models->layout.full_height; - } - f32 mid = layout_get_position(&models->layout, mouse_divider_id); - - i32 divider_id = div.id; - do{ - Divider_And_ID other_div = layout_get_divider(&models->layout, divider_id); - b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); - f32 pos = layout_get_position(&models->layout, divider_id); - if (divider_match && pos > mid && pos < max){ - max = pos; - } - else if (divider_match && pos < mid && pos > min){ - min = pos; - } - divider_id = other_div.divider->parent; - }while(divider_id != -1); - - Temp_Memory temp = begin_temp_memory(&models->mem.part); - i32 *divider_stack = push_array(&models->mem.part, i32, models->layout.panel_count); - i32 top = 0; - divider_stack[top++] = div.id; - for (;top > 0;){ - --top; - Divider_And_ID other_div = layout_get_divider(&models->layout, divider_stack[top]); - b32 divider_match = (other_div.divider->v_divider == mouse_divider_vertical); - f32 pos = layout_get_position(&models->layout, divider_stack[top]); - if (divider_match && pos > mid && pos < max){ - max = pos; - } - else if (divider_match && pos < mid && pos > min){ - min = pos; - } - if (other_div.divider->child1 != -1){ - divider_stack[top++] = other_div.divider->child1; - } - if (other_div.divider->child2 != -1){ - divider_stack[top++] = other_div.divider->child2; - } - } - end_temp_memory(temp); + models->resizing_intermediate_panel = divider_panel; }break; case EventConsume_ClickChangeView: @@ -1422,7 +1288,7 @@ App_Step_Sig(app_step){ force_abort_coroutine(system, models, view); } - models->layout.active_panel = (i32)(mouse_panel - models->layout.panels); + layout->active_panel = mouse_panel; app_result.animating = true; active_panel = mouse_panel; view = active_panel->view; @@ -1478,21 +1344,11 @@ App_Step_Sig(app_step){ } else if (keycode == key_mouse_move){ if (input->mouse.l){ - Panel_Divider *divider = vars->resizing.divider; - i32 mouse_position = 0; - - i32 absolute_positions[MAX_VIEWS]; - i32 min = 0; - i32 max = 0; - i32 div_id = (i32)(divider - models->layout.dividers); - - layout_compute_absolute_positions(&models->layout, absolute_positions); - mouse_position = (divider->v_divider)?(mx):(my); - layout_get_min_max(&models->layout, divider, absolute_positions, &min, &max); - absolute_positions[div_id] = clamp(min, mouse_position, max); - layout_update_all_positions(&models->layout, absolute_positions); - - layout_fix_all_panels(&models->layout); + Panel *split = models->resizing_intermediate_panel; + Range limits = layout_get_limiting_range_on_split(layout, split); + i32 mouse_position = (split->vertical_split)?(mouse.x):(mouse.y); + mouse_position = clamp(limits.min, mouse_position, limits.max); + layout_set_split_absolute_position(layout, split, mouse_position); } else{ vars->state = APP_STATE_EDIT; @@ -1510,11 +1366,11 @@ App_Step_Sig(app_step){ // NOTE(allen): step panels { - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(layout); - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; GUI_Scroll_Vars *scroll_vars = 0; @@ -1533,7 +1389,7 @@ App_Step_Sig(app_step){ } b32 active = (panel == active_panel); - Input_Process_Result ip_result = do_step_file_view(system, view, models, panel->inner, active, dt, *scroll_vars, max_y); + Input_Process_Result ip_result = do_step_file_view(system, view, models, panel->rect_inner, active, dt, *scroll_vars, max_y); if (ip_result.is_animating){ app_result.animating = true; @@ -1552,9 +1408,9 @@ App_Step_Sig(app_step){ // NOTE(allen): on the first frame there should be no scrolling if (input->first_step){ - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; GUI_Scroll_Vars *scroll_vars = &view->transient.edit_pos.scroll; scroll_vars->scroll_x = (f32)scroll_vars->target_x; @@ -1578,30 +1434,31 @@ App_Step_Sig(app_step){ Partition *scratch = &models->mem.part; Temp_Memory temp = begin_temp_memory(scratch); - Buffer_ID *ids = push_array(scratch, Buffer_ID, 0); Node *first = working_set->edit_finished_list.next; Node *stop = &working_set->edit_finished_list; + + Editing_File **file_ptrs = push_array(scratch, Editing_File*, 0); for (Node *node = first; node != stop; node = node->next){ - Editing_File *file = CastFromMember(Editing_File, edit_finished_mark_node, node); - Buffer_ID *new_id = push_array(scratch, Buffer_ID, 1); - *new_id = file->id.id; - + Editing_File **file_ptr = push_array(scratch, Editing_File*, 1); + *file_ptr = CastFromMember(Editing_File, edit_finished_mark_node, node); + } + i32 id_count = (i32)(push_array(scratch, Editing_File*, 0) - file_ptrs); + + Buffer_ID *ids = push_array(scratch, Buffer_ID, id_count); + for (i32 i = 0; i < id_count; i += 1){ + ids[i] = file_ptrs[i]->id.id; } - i32 id_count = (i32)(push_array(scratch, Buffer_ID, 0) - ids); working_set->do_not_mark_edits = true; hook_file_edit_finished(&models->app_links, ids, id_count); working_set->do_not_mark_edits = false; - for (Node *node = first, *next = 0; - node != stop; - node = next){ - next = node->next; - node->next = 0; - node->prev = 0; + for (i32 i = 0; i < id_count; i += 1){ + block_zero_struct(&file_ptrs[i]->edit_finished_mark_node); } + dll_init_sentinel(&working_set->edit_finished_list); working_set->time_of_next_edit_finished_signal = 0; @@ -1630,15 +1487,15 @@ App_Step_Sig(app_step){ { begin_render_section(target, system); - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(layout); View *active_view = active_panel->view; // NOTE(allen): render the panels - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ - i32_Rect full = panel->full; - i32_Rect inner = panel->inner; + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ + i32_Rect full = panel->rect_full; + i32_Rect inner = panel->rect_inner; View *view = panel->view; Style *style = &models->styles.styles[0]; @@ -1648,7 +1505,7 @@ App_Step_Sig(app_step){ GUI_Scroll_Vars *scroll_vars = &view->transient.edit_pos.scroll; b32 active = (panel == active_panel); - do_render_file_view(system, view, models, scroll_vars, active_view, panel->inner, active, target); + do_render_file_view(system, view, models, scroll_vars, active_view, inner, active, target); u32 margin_color = 0; if (active){ @@ -1677,22 +1534,21 @@ App_Step_Sig(app_step){ } // NOTE(allen): get cursor type - if (mouse_in_edit_area){ + if (mouse_panel != 0 && !mouse_in_margin){ app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; } - else if (mouse_in_margin_area){ - if (mouse_on_divider){ - if (mouse_divider_vertical){ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT; - } - else{ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN; - } + else if (divider_panel != 0){ + if (divider_panel->vertical_split){ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_LEFTRIGHT; } else{ - app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_UPDOWN; } } + else{ + app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW; + } + models->prev_mouse_panel = mouse_panel; app_result.lctrl_lalt_is_altgr = models->settings.lctrl_lalt_is_altgr; diff --git a/4ed_api_implementation.cpp b/4ed_api_implementation.cpp index a34afabe..96e4552b 100644 --- a/4ed_api_implementation.cpp +++ b/4ed_api_implementation.cpp @@ -70,7 +70,7 @@ fill_view_summary(System_Functions *system, View_Summary *view, View *vptr, Live view->cursor = vptr->transient.edit_pos.cursor; view->preferred_x = vptr->transient.edit_pos.preferred_x; - view->view_region = vptr->transient.panel->inner; + view->view_region = vptr->transient.panel->rect_inner; view->file_region = vptr->transient.file_region; if (vptr->transient.ui_mode){ view->scroll_vars = vptr->transient.ui_scroll; @@ -212,7 +212,7 @@ DOC_SEE(Command_ID) result = true; } else{ - print_message(app,literal("WARNING: An invalid Command_ID was passed to exec_command.")); + print_message(app, literal("WARNING: An invalid Command_ID was passed to exec_command.")); } return(result); @@ -367,7 +367,7 @@ DOC_SEE(Command_Line_Interface_Flag) done:; if (!result){ - do_feedback_message(system, models, feedback_str); + print_message(app, feedback_str.str, feedback_str.size); } end_temp_memory(temp); @@ -1346,23 +1346,25 @@ DOC_SEE(Buffer_Identifier) file_free(system, &models->app_links, &models->mem.heap, &models->lifetime_allocator, file); working_set_free_file(&models->mem.heap, working_set, file); + Layout *layout = &models->layout; + Node *used = &working_set->used_sentinel; - Node *node = used->next; - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ + Node *file_node = used->next; + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ - Assert(node != used); + Assert(file_node != used); view->transient.file_data.file = 0; - Editing_File *new_file = CastFromMember(Editing_File, main_chain_node, node); + Editing_File *new_file = CastFromMember(Editing_File, main_chain_node, file_node); view_set_file(system, models, view, new_file); - if (node->next != used){ - node = node->next; + if (file_node->next != used){ + file_node = file_node->next; } else{ - node = node->next->next; - Assert(node != used); + file_node = file_node->next->next; + Assert(file_node != used); } } } @@ -1407,9 +1409,10 @@ Reopen_Buffer(Application_Links *app, Buffer_Summary *buffer, Buffer_Reopen_Flag View *vptrs[16]; i32 vptr_count = 0; - for (Panel *panel = models->layout.used_sentinel.next; - panel != &models->layout.used_sentinel; - panel = panel->next){ + Layout *layout = &models->layout; + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view_it = panel->view; if (view_it->transient.file_data.file != file){ continue; @@ -1455,33 +1458,31 @@ Reopen_Buffer(Application_Links *app, Buffer_Summary *buffer, Buffer_Reopen_Flag internal void get_view_first__internal(Models *models, View_Summary *view){ - Editing_Layout *layout = &models->layout; - Panel *panel = layout->used_sentinel.next; - Assert(panel != &layout->used_sentinel); + Panel *panel = layout_get_first_open_panel(&models->layout); fill_view_summary(models->system, view, panel->view, models); } internal void get_view_next__internal(Models *models, View_Summary *view){ System_Functions *system = models->system; - Editing_Layout *layout = &models->layout; + Layout *layout = &models->layout; Live_Views *live_set = &models->live_set; i32 index = view->view_id - 1; if (index >= 0 && index < live_set->max){ View *vptr = live_set->views + index; Panel *panel = vptr->transient.panel; if (panel != 0){ - panel = panel->next; + panel = layout_get_next_open_panel(layout, panel); } - if (panel != 0 && panel != &layout->used_sentinel){ + if (panel != 0){ fill_view_summary(system, view, panel->view, models); } else{ - memset(view, 0, sizeof(*view)); + block_zero_struct(view); } } else{ - memset(view, 0, sizeof(*view)); + block_zero_struct(view); } } @@ -1564,12 +1565,12 @@ DOC_SEE(Access_Flag) */{ Models *models = (Models*)app->cmd_context; System_Functions *system = models->system; - Panel *panel = models->layout.panels + models->layout.active_panel; + Panel *panel = layout_get_active_panel(&models->layout); Assert(panel->view != 0); View_Summary view = {}; fill_view_summary(system, &view, panel->view, &models->live_set, &models->working_set); if (!access_test(view.lock_flags, access)){ - memset(&view, 0, sizeof(view)); + block_zero_struct(&view); } return(view); } @@ -1586,52 +1587,20 @@ DOC_SEE(View_Split_Position) */{ Models *models = (Models*)app->cmd_context; System_Functions *system = models->system; + Layout *layout = &models->layout; View *vptr = imp_get_view(models, view_location); Panel *panel = vptr->transient.panel; View_Summary result = {}; - - if (models->layout.panel_count < models->layout.panel_max_count){ - b32 vsplit = ((position == ViewSplit_Left) || (position == ViewSplit_Right)); - b32 grtsplit = ((position == ViewSplit_Bottom) || (position == ViewSplit_Right)); - - Split_Result split = layout_split_panel(&models->layout, panel, vsplit); - - Panel *grtpanel = split.panel; - Panel *lsrpanel = panel; - - if (!grtsplit){ - Swap(i32, panel->which_child, split.panel->which_child); - Swap(Panel*, grtpanel, lsrpanel); - } - - split.panel->screen_region = panel->screen_region; - if (vsplit){ - i32 x_pos = round32(lerp((f32)lsrpanel->full.x0, split.divider->pos, (f32)lsrpanel->full.x1)); - - grtpanel->full.x0 = x_pos; - grtpanel->full.x1 = lsrpanel->full.x1; - lsrpanel->full.x1 = x_pos; - } - else{ - i32 y_pos = round32(lerp((f32)lsrpanel->full.y0, split.divider->pos, (f32)lsrpanel->full.y1)); - - grtpanel->full.y0 = y_pos; - grtpanel->full.y1 = lsrpanel->full.y1; - lsrpanel->full.y1 = y_pos; - } - - panel_fix_internal_area(panel); - panel_fix_internal_area(split.panel); - split.panel->prev_inner = split.panel->inner; - - models->layout.active_panel = (i32)(split.panel - models->layout.panels); - panel_make_empty(system, models, split.panel); - - fill_view_summary(system, &result, split.panel->view, models); - - models->layout.panel_state_dirty = true; + b32 vertical_split = ((position == ViewSplit_Left) || (position == ViewSplit_Right)); + b32 br_split = ((position == ViewSplit_Bottom) || (position == ViewSplit_Right)); + Panel *new_panel = layout_split_panel(layout, panel, vertical_split, br_split); + if (new_panel != 0){ + View *new_view = live_set_alloc_view(&models->mem.heap, &models->lifetime_allocator, &models->live_set); + new_panel->view = new_view; + new_view->transient.panel = new_panel; + view_set_file(system, models, new_view, models->scratch_buffer); + fill_view_summary(system, &result, new_view, models); } - return(result); } @@ -1648,82 +1617,17 @@ in the system, the call will fail.) */{ Models *models = (Models*)app->cmd_context; + Layout *layout = &models->layout; View *vptr = imp_get_view(models, view); bool32 result = false; - - if (vptr != 0 && models->layout.panel_count > 1){ - Panel *panel = vptr->transient.panel; - - live_set_free_view(&models->mem.heap, &models->lifetime_allocator, &models->live_set, vptr); - panel->view = 0; - - Divider_And_ID div = layout_get_divider(&models->layout, panel->parent); - - // This divider cannot have two child dividers. - Assert(div.divider->child1 == -1 || div.divider->child2 == -1); - - // Get the child who needs to fill in this node's spot - i32 child = div.divider->child1; - if (child == -1) child = div.divider->child2; - - i32 parent = div.divider->parent; - i32 which_child = div.divider->which_child; - - // Fill the child in the slot this node use to hold - if (parent == -1){ - Assert(models->layout.root == div.id); - models->layout.root = child; + if (vptr != 0){ + if (layout_close_panel(layout, vptr->transient.panel)){ + live_set_free_view(&models->mem.heap, &models->lifetime_allocator, &models->live_set, vptr); + result = true; } - else{ - Divider_And_ID parent_div = layout_get_divider(&models->layout, parent); - if (which_child == -1){ - parent_div.divider->child1 = child; - } - else{ - parent_div.divider->child2 = child; - } - } - - // If there was a child divider, give it information about it's new parent. - if (child != -1){ - Divider_And_ID child_div = layout_get_divider(&models->layout, child); - child_div.divider->parent = parent; - child_div.divider->which_child = div.divider->which_child; - } - - // What is the new active panel? - i32 active = -1; - if (child == -1){ - for (Panel *panel_ptr = models->layout.used_sentinel.next; - panel_ptr != &models->layout.used_sentinel; - panel_ptr = panel_ptr->next){ - if (panel_ptr != panel && panel_ptr->parent == div.id){ - panel_ptr->parent = parent; - panel_ptr->which_child = which_child; - active = (i32)(panel_ptr - models->layout.panels); - break; - } - } - } - else{ - Panel *panel_ptr = panel->next; - if (panel_ptr == &models->layout.used_sentinel) panel_ptr = panel_ptr->next; - Assert(panel_ptr != panel); - active = (i32)(panel_ptr - models->layout.panels); - } - Assert(active != -1 && panel != models->layout.panels + active); - - // If the panel we're closing was previously active, we have to switch to it's sibling. - if (models->layout.active_panel == (i32)(panel - models->layout.panels)){ - models->layout.active_panel = active; - } - - layout_free_divider(&models->layout, div.divider); - layout_free_panel(&models->layout, panel); - layout_fix_all_panels(&models->layout); } - + return(result); } @@ -1741,9 +1645,8 @@ DOC_SEE(get_active_view) View *vptr = imp_get_view(models, view); bool32 result = false; if (vptr != 0){ + models->layout.active_panel = vptr->transient.panel; result = true; - Panel *panel = vptr->transient.panel; - models->layout.active_panel = (i32)(panel - models->layout.panels); } return(result); } @@ -1862,31 +1765,59 @@ If the view_id does not specify a valid view, the returned scope is null.) } API_EXPORT bool32 -View_Set_Split_Proportion(Application_Links *app, View_Summary *view, float t) +View_Set_Split(Application_Links *app, View_Summary *view, View_Split_Kind kind, float t) /* DOC_PARAM(view, The view parameter specifies which view shall have it's size adjusted.) -DOC_PARAM(t, The t parameter specifies the proportion of the containing box that the view should occupy. t should be in [0,1].) +DOC_PARAM(kind, There are different kinds of split, see View_Split_Kind documentation for more information.) +DOC_PARAM(t, The t parameter specifies the proportion of the containing box that the view should occupy. + +For proportion values, t will be clamped to [0,1]. + +For integer values, t will be rounded to the nearest integer. +) +DOC_SEE(View_Split_Kind) DOC_RETURN(This call returns non-zero on success.) */{ - bool32 result = false; + Models *models = (Models*)app->cmd_context; + Layout *layout = &models->layout; - if (0 <= t && t <= 1.f){ - Models *models = (Models*)app->cmd_context; - Editing_Layout *layout = &models->layout; - View *vptr = imp_get_view(models, view); - - if (vptr != 0){ - result = true; - - Panel *panel = vptr->transient.panel; - Panel_Divider *div = layout->dividers + panel->parent; - - if (panel->which_child == 1){ - t = 1 - t; + View *vptr = imp_get_view(models, view); + bool32 result = false; + if (vptr != 0){ + Panel *panel = vptr->transient.panel; + Panel *intermediate = panel->parent; + if (intermediate != 0){ + Assert(intermediate->kind == PanelKind_Intermediate); + switch (kind){ + case ViewSplitKind_Ratio: + { + if (intermediate->br_panel == panel){ + intermediate->split.kind = PanelSplitKind_Ratio_BR; + } + else{ + intermediate->split.kind = PanelSplitKind_Ratio_TL; + } + intermediate->split.v_f32 = clamp(0.f, t, 1.f); + }break; + + case ViewSplitKind_FixedPixels: + { + if (intermediate->br_panel == panel){ + intermediate->split.kind = PanelSplitKind_FixedPixels_BR; + } + else{ + intermediate->split.kind = PanelSplitKind_FixedPixels_TL; + } + intermediate->split.v_i32 = round32(t); + }break; + + default: + { + print_message(app, literal("Invalid split kind passed to view_set_split, no change made to view layout")); + }break; } - - div->pos = t; - layout_fix_all_panels(layout); + layout_propogate_sizes_down_from_node(layout, intermediate); + result = true; } } @@ -1899,26 +1830,22 @@ View_Get_Enclosure_Rect(Application_Links *app, View_Summary *view) DOC_PARAM(view, The view whose parent rent will be returned.) DOC_RETURN(The rectangle of the panel containing this view.) */{ - // TODO(allen): do(update implementation of layout for better queries and traversals) - - i32_Rect result = {}; - + // TODO(allen): do(remove this from the API and put it in the custom helpers) + // we should just have full tree traversal API for the splits between views. Models *models = (Models*)app->cmd_context; - Editing_Layout *layout = &models->layout; View *vptr = imp_get_view(models, view); - + i32_Rect result = {}; if (vptr != 0){ Panel *panel = vptr->transient.panel; - - i32_Rect a = layout_get_rect(layout, panel->parent, panel->which_child); - i32_Rect b = layout_get_rect(layout, panel->parent, !panel->which_child); - - result.x0 = Min(a.x0, b.x0); - result.y0 = Min(a.y0, b.y0); - result.x1 = Max(a.x0, b.x1); - result.y1 = Max(a.y0, b.y1); + Assert(panel != 0); + Panel *parent = panel->parent; + if (parent != 0){ + result = parent->rect_full; + } + else{ + result = panel->rect_full; + } } - return(result); } @@ -3091,7 +3018,6 @@ DOC_SEE(User_Input) System_Functions *system = models->system; Coroutine_Head *coroutine = (Coroutine_Head*)app->current_coroutine; User_Input result = {}; - if (app->type_coroutine == Co_Command){ Assert(coroutine != 0); *((u32*)coroutine->out + 0) = get_type; @@ -3099,7 +3025,6 @@ DOC_SEE(User_Input) system->yield_coroutine(coroutine); result = *(User_Input*)coroutine->in; } - return(result); } @@ -3182,7 +3107,7 @@ only use for this call is in an interactive command that makes calls to get_user ) */{ Models *models = (Models*)app->cmd_context; - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(&models->layout); View *active_view = active_panel->view; Query_Slot *slot = alloc_query_slot(&active_view->transient.query_set); bool32 result = (slot != 0); @@ -3200,7 +3125,7 @@ DOC_PARAM(flags, This parameter is not currently used and should be 0 for now.) DOC(Stops showing the particular query bar specified by the bar parameter.) */{ Models *models = (Models*)app->cmd_context; - Panel *active_panel = &models->layout.panels[models->layout.active_panel]; + Panel *active_panel = layout_get_active_panel(&models->layout); View *active_view = active_panel->view; free_query_slot(&active_view->transient.query_set, bar); } @@ -3213,7 +3138,12 @@ DOC_PARAM(len, The len parameter specifies the length of the str string.) DOC(This call posts a string to the *messages* buffer.) */{ Models *models = (Models*)app->cmd_context; - do_feedback_message(models->system, models, make_string(str, len)); + System_Functions *system = models->system; + Editing_File *file = models->message_buffer; + if (file != 0){ + output_file_append(system, models, file, make_string(str, len)); + file_cursor_to_end(system, models, file); + } } API_EXPORT int32_t diff --git a/4ed_app_models.h b/4ed_app_models.h index a6b4772c..11ae43f8 100644 --- a/4ed_app_models.h +++ b/4ed_app_models.h @@ -64,7 +64,7 @@ struct Models{ Style_Library styles; u32 *palette; - Editing_Layout layout; + Layout layout; Working_Set working_set; Live_Views live_set; Parse_Context_Memory parse_context_memory; @@ -96,6 +96,8 @@ struct Models{ i32 previous_mouse_x; i32 previous_mouse_y; + Panel *resizing_intermediate_panel; + // System Context System_Functions *system; struct App_Vars *vars; @@ -132,10 +134,6 @@ enum App_State{ APP_STATE_COUNT }; -struct App_State_Resizing{ - Panel_Divider *divider; -}; - enum Input_Types{ Input_AnyKey, Input_Esc, @@ -155,7 +153,6 @@ struct App_Vars{ Models models; CLI_List cli_processes; App_State state; - App_State_Resizing resizing; }; enum Coroutine_Type{ diff --git a/4ed_defines.h b/4ed_defines.h index 8db7d678..105e9525 100644 --- a/4ed_defines.h +++ b/4ed_defines.h @@ -92,6 +92,7 @@ typedef double f64; #define TentativeAssert(c) Assert(c) #define InvalidCodePath Assert(!"Invalid Code Path!") #define NotImplemented Assert(!"Not Implemented!") +#define AssertImplies(a,b) Assert(!(a) || (b)) #define Swap(t,a,b) do { t x = a; a = b; b = x; } while(0) diff --git a/4ed_edit.cpp b/4ed_edit.cpp index dda94ae7..2dc6f33b 100644 --- a/4ed_edit.cpp +++ b/4ed_edit.cpp @@ -70,7 +70,7 @@ edit_fix_markers__read_workspace_markers(Dynamic_Workspace *workspace, Buffer_ID } internal void -edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, Editing_Layout *layout, Cursor_Fix_Descriptor desc){ +edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, Layout *layout, Cursor_Fix_Descriptor desc){ Partition *part = &models->mem.part; Temp_Memory cursor_temp = begin_temp_memory(part); @@ -79,7 +79,7 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, E Buffer_ID file_id = file->id.id; Assert(file_lifetime_object != 0); - i32 cursor_max = layout->panel_max_count * 3; + i32 cursor_max = layout_get_open_panel_count(layout)*3; i32 total_marker_count = 0; { total_marker_count += file_lifetime_object->workspace.total_marker_count; @@ -106,9 +106,9 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, E Assert(cursors != 0); Assert(r_cursors != 0); - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ write_cursor_with_index(cursors, &cursor_count, view->transient.edit_pos.cursor.pos); @@ -148,9 +148,9 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, E cursor_count = 0; r_cursor_count = 0; - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ i32 cursor_pos = cursors[cursor_count++].pos; @@ -202,7 +202,7 @@ edit_fix_markers(System_Functions *system, Models *models, Editing_File *file, E internal void edit_single__inner(System_Functions *system, Models *models, Editing_File *file, Edit_Spec spec, History_Mode history_mode){ Mem_Options *mem = &models->mem; - Editing_Layout *layout = &models->layout; + Layout *layout = &models->layout; Heap *heap = &mem->heap; Partition *part = &mem->part; @@ -319,7 +319,7 @@ edit_batch(System_Functions *system, Models *models, Editing_File *file, Edit_Sp Mem_Options *mem = &models->mem; Heap *heap = &mem->heap; Partition *part = &mem->part; - Editing_Layout *layout = &models->layout; + Layout *layout = &models->layout; // NOTE(allen): fixing stuff "beforewards"??? Assert(spec.str == 0); @@ -446,10 +446,10 @@ edit_clear(System_Functions *system, Models *models, Editing_File *file){ b32 no_views_see_file = true; - Editing_Layout *layout = &models->layout; - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ + Layout *layout = &models->layout; + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ Full_Cursor cursor = {}; diff --git a/4ed_layout.cpp b/4ed_layout.cpp index a904231c..e020bb14 100644 --- a/4ed_layout.cpp +++ b/4ed_layout.cpp @@ -9,468 +9,439 @@ // TOP -internal void -panel_init(Panel *panel){ - panel->view = 0; - panel->parent = -1; - panel->which_child = 0; - panel->screen_region.full = null_i32_rect; - panel->screen_region.inner = null_i32_rect; - panel->l_margin = 3; - panel->r_margin = 3; - panel->t_margin = 3; - panel->b_margin = 3; +internal Panel_Split +make_panel_split(Panel_Split_Kind kind, i32 v){ + Panel_Split split = {}; + split.kind = kind; + split.v_i32 = v; + return(split); } -internal Panel_Divider -panel_divider_zero(){ - Panel_Divider divider={}; - return(divider); +internal Panel_Split +make_panel_split(Panel_Split_Kind kind, f32 v){ + Panel_Split split = {}; + split.kind = kind; + split.v_f32 = v; + return(split); } -internal Divider_And_ID -layout_alloc_divider(Editing_Layout *layout){ - Assert(layout->free_divider); - - Divider_And_ID result; - result.divider = layout->free_divider; - layout->free_divider = result.divider->next; - - *result.divider = panel_divider_zero(); - result.divider->parent = -1; - result.divider->child1 = -1; - result.divider->child2 = -1; - result.id = (i32)(result.divider - layout->dividers); - if (layout->panel_count == 1){ - layout->root = result.id; +internal Panel_Split +make_panel_split_50_50(void){ + return(make_panel_split(PanelSplitKind_Ratio_TL, 0.5f)); +} + +internal Panel* +layout__alloc_panel(Layout *layout){ + Panel *panel = 0; + Node *node = layout->free_panels.next; + if (node != &layout->free_panels){ + dll_remove(node); + panel = CastFromMember(Panel, node, node); } - - return(result); -} - -internal Divider_And_ID -layout_get_divider(Editing_Layout *layout, i32 id){ - Assert(id >= 0 && id < layout->panel_max_count-1); - Divider_And_ID result; - result.id = id; - result.divider = layout->dividers + id; - return(result); + return(panel); } internal void -layout_free_divider(Editing_Layout *layout, Panel_Divider *divider){ - divider->next = layout->free_divider; - layout->free_divider = divider; -} - -internal Panel_And_ID -layout_alloc_panel(Editing_Layout *layout){ - Panel_And_ID result = {}; - - Assert(layout->panel_count < layout->panel_max_count); - ++layout->panel_count; - - result.panel = layout->free_sentinel.next; - dll_remove(result.panel); - dll_insert(&layout->used_sentinel, result.panel); - - panel_init(result.panel); - - result.id = (i32)(result.panel - layout->panels); - - return(result); +layout__free_panel(Layout *layout, Panel *panel){ + Assert(panel != layout->active_panel); + Assert(panel != layout->root); + dll_remove(&panel->node); + dll_insert(&layout->free_panels, &panel->node); } internal void -layout_free_panel(Editing_Layout *layout, Panel *panel){ - dll_remove(panel); - dll_insert(&layout->free_sentinel, panel); - --layout->panel_count; +layout__set_panel_rectangle(Layout *layout, Panel *panel, i32_Rect rect){ + panel->rect_full = rect; + panel->rect_inner = get_inner_rect(rect, layout->margin); } -internal Divider_And_ID -layout_calc_divider_id(Editing_Layout *layout, Panel_Divider *divider){ - Divider_And_ID result; - result.divider = divider; - result.id = (i32)(divider - layout->dividers); - return result; -} - -struct Split_Result{ - Panel_Divider *divider; - Panel *panel; -}; - -internal Split_Result -layout_split_panel(Editing_Layout *layout, Panel *panel, b32 vertical){ - Split_Result result = {}; - Divider_And_ID div = {}, parent_div = {}; - Panel_And_ID new_panel = {}; - - div = layout_alloc_divider(layout); - if (panel->parent != -1){ - parent_div = layout_get_divider(layout, panel->parent); - if (panel->which_child == -1){ - parent_div.divider->child1 = div.id; - } - else{ - parent_div.divider->child2 = div.id; - } - } - - div.divider->parent = panel->parent; - div.divider->which_child = panel->which_child; - if (vertical){ - div.divider->v_divider = 1; - } - else{ - div.divider->v_divider = 0; - } - div.divider->pos = 0.5f; - - new_panel = layout_alloc_panel(layout); - panel->parent = div.id; - panel->which_child = -1; - new_panel.panel->parent = div.id; - new_panel.panel->which_child = 1; - - result.divider = div.divider; - result.panel = new_panel.panel; - - return(result); -} - -internal void -panel_fix_internal_area(Panel *panel){ - panel->inner.x0 = panel->full.x0 + panel->l_margin; - panel->inner.x1 = panel->full.x1 - panel->r_margin; - panel->inner.y0 = panel->full.y0 + panel->t_margin; - panel->inner.y1 = panel->full.y1 - panel->b_margin; -} - -internal i32_Rect -layout_get_rect(Editing_Layout *layout, i32 id, i32 which_child){ - i32 divider_chain[MAX_VIEWS]; - i32 chain_count = 0; - - Panel_Divider *dividers = layout->dividers; - Panel_Divider *original_div = dividers + id; - i32 root = layout->root; - - Assert(0 <= id && id <= layout->panel_max_count - 1); - - divider_chain[chain_count++] = id; - for (;id != root;){ - Panel_Divider *div = dividers + id; - id = div->parent; - divider_chain[chain_count++] = id; - } - - i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height); - - for (i32 i = chain_count-1; i > 0; --i){ - Panel_Divider *div = dividers + divider_chain[i]; - if (div->v_divider){ - if (div->child1 == divider_chain[i-1]){ - r.x1 = round32(lerp((f32)r.x0, div->pos, (f32)r.x1)); - } - else{ - r.x0 = round32(lerp((f32)r.x0, div->pos, (f32)r.x1)); - } - } - else{ - if (div->child1 == divider_chain[i-1]){ - r.y1 = round32(lerp((f32)r.y0, div->pos, (f32)r.y1)); - } - else{ - r.y0 = round32(lerp((f32)r.y0, div->pos, (f32)r.y1)); - } - } - } - - switch (which_child){ - case 1: +internal i32 +layout__evaluate_split(Panel_Split split, i32 v0, i32 v1){ + i32 v = 0; + switch (split.kind){ + case PanelSplitKind_Ratio_TL: { - if (original_div->v_divider){ - r.x0 = round32(lerp((f32)r.x0, original_div->pos, (f32)r.x1)); - } - else{ - r.y0 = round32(lerp((f32)r.y0, original_div->pos, (f32)r.y1)); - } + v = round32(lerp((f32)v0, split.v_f32, (f32)v1)); }break; + case PanelSplitKind_Ratio_BR: + { + v = round32(lerp((f32)v1, split.v_f32, (f32)v0)); + }break; + case PanelSplitKind_FixedPixels_TL: + { + v = clamp_top(v0 + split.v_i32, v1); + }break; + case PanelSplitKind_FixedPixels_BR: + { + v = clamp_bottom(v0, v1 - split.v_i32); + }break; + } + return(v); +} + +internal void +layout_propogate_sizes_down_from_node(Layout *layout, Panel *panel){ + if (panel->kind == PanelKind_Intermediate){ + Panel *tl_panel = panel->tl_panel; + Panel *br_panel = panel->br_panel; - case -1: - { - if (original_div->v_divider){ - r.x1 = round32(lerp((f32)r.x0, original_div->pos, (f32)r.x1)); - } - else{ - r.y1 = round32(lerp((f32)r.y0, original_div->pos, (f32)r.y1)); - } - }break; + i32_Rect r1 = panel->rect_full; + i32_Rect r2 = panel->rect_full; + + if (panel->vertical_split){ + i32 x_pos = layout__evaluate_split(panel->split, r1.x0, r1.x1); + r1.x1 = x_pos; + r2.x0 = x_pos; + } + else{ + i32 y_pos = layout__evaluate_split(panel->split, r1.y0, r1.y1); + r1.y1 = y_pos; + r2.y0 = y_pos; + } + + layout__set_panel_rectangle(layout, tl_panel, r1); + layout__set_panel_rectangle(layout, br_panel, r2); + + layout_propogate_sizes_down_from_node(layout, tl_panel); + layout_propogate_sizes_down_from_node(layout, br_panel); } - - return(r); } -internal i32_Rect -layout_get_panel_rect(Editing_Layout *layout, Panel *panel){ - Assert(layout->panel_count > 1); - i32_Rect r = layout_get_rect(layout, panel->parent, panel->which_child); - return(r); +internal i32 +layout_get_open_panel_count(Layout *layout){ + return(layout->open_panel_count); +} + +internal Panel* +layout_get_first_open_panel(Layout *layout){ + Panel *panel = CastFromMember(Panel, node, layout->open_panels.next); + if (panel != 0 && &panel->node == &layout->open_panels){ + panel = 0; + } + AssertImplies(panel != 0, panel->kind == PanelKind_Final); + return(panel); +} + +internal Panel* +layout_get_next_open_panel(Layout *layout, Panel *panel){ + panel = CastFromMember(Panel, node, panel->node.next); + if (&panel->node == &layout->open_panels){ + panel = 0; + } + AssertImplies(panel != 0, panel->kind == PanelKind_Final); + return(panel); +} + +internal Panel* +layout_get_active_panel(Layout *layout){ + return(layout->active_panel); +} + +internal Panel* +layout_split_panel(Layout *layout, Panel *panel, b32 vertical_split, b32 br_split){ + Panel *new_panel = 0; + if (layout->open_panel_count < layout->open_panel_max_count){ + Panel *intermediate = layout__alloc_panel(layout); + new_panel = layout__alloc_panel(layout); + + dll_insert(&layout->open_panels, &new_panel->node); + dll_insert(&layout->intermediate_panels, &intermediate->node); + + Panel *parent = panel->parent; + + // link new intermediate and parent + intermediate->parent = parent; + if (parent != 0){ + Assert(parent->kind == PanelKind_Intermediate); + if (parent->tl_panel == panel){ + parent->tl_panel = intermediate; + } + else{ + Assert(parent->br_panel == panel); + parent->br_panel = intermediate; + } + } + else{ + Assert(layout->root == panel); + layout->root = intermediate; + } + + // link new intermediate and child panels + panel->parent = intermediate; + new_panel->parent = intermediate; + if (br_split){ + intermediate->br_panel = new_panel; + intermediate->tl_panel = panel; + } + else{ + intermediate->tl_panel = new_panel; + intermediate->br_panel = panel; + } + + // init the intermediate + intermediate->kind = PanelKind_Intermediate; + intermediate->vertical_split = vertical_split; + intermediate->split = make_panel_split_50_50(); + intermediate->screen_region = panel->screen_region; + + // init the new panel + new_panel->kind = PanelKind_Final; + new_panel->view = 0; + + // propogate rectangle sizes down from the new intermediate to + // resize the panel and the new panel. + layout_propogate_sizes_down_from_node(layout, intermediate); + + // update layout state + layout->open_panel_count += 1; + layout->active_panel = new_panel; + layout->panel_state_dirty = true; + } + return(new_panel); +} + +internal b32 +layout_close_panel(Layout *layout, Panel *panel){ + b32 result = false; + if (layout->open_panel_count > 1){ + Panel *parent = panel->parent; + Assert(parent != 0); + + // find sibling + Panel *sibling = 0; + if (parent->tl_panel == panel){ + sibling = parent->br_panel; + } + else{ + Assert(parent->br_panel == panel); + sibling = parent->tl_panel; + } + + // update layout state + if (layout->active_panel == panel){ + Panel *new_active = sibling; + for (;new_active->kind == PanelKind_Intermediate;){ + new_active = new_active->br_panel; + } + layout->active_panel = new_active; + } + layout->panel_state_dirty = true; + layout->open_panel_count -= 1; + + // link grand parent and sibling + Panel *g_parent = parent->parent; + sibling->parent = g_parent; + if (g_parent != 0){ + if (g_parent->tl_panel == parent){ + g_parent->tl_panel = sibling; + } + else{ + Assert(g_parent->br_panel == parent); + g_parent->br_panel = sibling; + } + } + else{ + Assert(parent == layout->root); + layout->root = sibling; + } + + // set sibling's size + sibling->screen_region = parent->screen_region; + + // set the sizes down stream of sibling + layout_propogate_sizes_down_from_node(layout, sibling); + + // free panel and parent + layout__free_panel(layout, panel); + layout__free_panel(layout, parent); + + result = true; + } + return(result); +} + +internal Panel* +layout_initialize(Partition *part, Layout *layout){ + i32 panel_alloc_count = MAX_VIEWS*2 - 1; + Panel *panels = push_array(part, Panel, panel_alloc_count); + + layout->margin = 3; + layout->open_panel_count = 0; + layout->open_panel_max_count = MAX_VIEWS; + + dll_init_sentinel(&layout->open_panels); + dll_init_sentinel(&layout->intermediate_panels); + + Panel *panel = panels; + layout->free_panels.next = &panel->node; + panel->node.prev = &layout->free_panels; + for (i32 i = 1; i < MAX_VIEWS; i += 1, panel += 1){ + panel[1].node.prev = &panel[0].node; + panel[0].node.next = &panel[1].node; + } + panel->node.next = &layout->free_panels; + layout->free_panels.prev = &panel->node; + + panel = layout__alloc_panel(layout); + panel->parent = 0; + panel->kind = PanelKind_Final; + panel->view = 0; + block_zero_struct(&panel->screen_region); + + dll_insert(&layout->open_panels, &panel->node); + layout->open_panel_count += 1; + layout->root = panel; + layout->active_panel = panel; + layout->panel_state_dirty = true; + + return(panel); } internal void -layout_fix_all_panels(Editing_Layout *layout){ - Panel_Divider *dividers = layout->dividers; AllowLocal(dividers); - i32 panel_count = layout->panel_count; - - if (panel_count > 1){ - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ - panel->full = layout_get_panel_rect(layout, panel); - panel_fix_internal_area(panel); - } +layout_set_margin(Layout *layout, i32 margin){ + if (layout->margin != margin){ + layout->margin = margin; + layout__set_panel_rectangle(layout, layout->root, i32R(0, 0, layout->full_dim.x, layout->full_dim.y)); + layout_propogate_sizes_down_from_node(layout, layout->root); } - else{ - Panel *panel = layout->used_sentinel.next; - panel->full.x0 = 0; - panel->full.y0 = 0; - panel->full.x1 = layout->full_width; - panel->full.y1 = layout->full_height; - panel_fix_internal_area(panel); - } - - layout->panel_state_dirty = 1; } internal void -layout_refit(Editing_Layout *layout, i32 prev_width, i32 prev_height){ - Panel_Divider *dividers = layout->dividers; - i32 max = layout->panel_max_count - 1; - - Panel_Divider *divider = dividers; - if (layout->panel_count > 1){ - Assert(prev_width != 0 && prev_height != 0); - for (i32 i = 0; i < max; ++i, ++divider){ - // TODO(casey): Allen, is this doing something? Is it just reserved for future use I guess? - if (divider->v_divider){ - divider->pos = divider->pos; - } - else{ - divider->pos = divider->pos; - } - } +layout_set_root_size(Layout *layout, Vec2_i32 dim){ + if (layout->full_dim != dim){ + layout->full_dim = dim; + layout__set_panel_rectangle(layout, layout->root, i32R(0, 0, dim.x, dim.y)); + layout_propogate_sizes_down_from_node(layout, layout->root); } - - layout_fix_all_panels(layout); } -internal f32 -layout_get_position(Editing_Layout *layout, i32 id){ - Panel_Divider *dividers = layout->dividers; - Panel_Divider *original_div = dividers + id; - - i32_Rect r = layout_get_rect(layout, id, 0); - f32 pos = 0; - if (original_div->v_divider){ - pos = lerp((f32)r.x0, original_div->pos, (f32)r.x1); +internal Vec2_i32 +layout_get_root_size(Layout *layout){ + return(layout->full_dim); +} + +internal i32 +layout_get_absolute_position_of_split(Panel *panel){ + i32 pos = 0; + if (panel->vertical_split){ + pos = layout__evaluate_split(panel->split, panel->rect_full.x0, panel->rect_full.x1); } else{ - pos = lerp((f32)r.y0, original_div->pos, (f32)r.y1); + pos = layout__evaluate_split(panel->split, panel->rect_full.y0, panel->rect_full.y1); } - return(pos); } -internal f32 -layout_compute_position(Editing_Layout *layout, Panel_Divider *divider, i32 pos){ - Panel_Divider *dividers = layout->dividers; - Panel_Divider *original_div = divider; - i32 id = (i32)(divider - dividers); - - i32_Rect r = layout_get_rect(layout, id, 0); - f32 l = 0; - if (original_div->v_divider){ - l = unlerp((f32)r.x0, (f32)pos, (f32)r.x1); - } - else{ - l = unlerp((f32)r.y0, (f32)pos, (f32)r.y1); - } - - Assert(0.f <= l && l <= 1.f); - - return(l); -} - -internal void -layout_compute_abs_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i32 *abs_pos){ - Panel_Divider *div = layout->dividers + divider_id; - - i32 p0 = 0, p1 = 0; - if (div->v_divider){ - p0 = rect.x0; p1 = rect.x1; - } - else{ - p0 = rect.y0; p1 = rect.y1; - } - - i32 pos = lerp(p0, div->pos, p1); - i32_Rect r1 = rect, r2 = rect; - - abs_pos[divider_id] = pos; - - if (div->v_divider){ - r1.x1 = pos; r2.x0 = pos; - } - else{ - r1.y1 = pos; r2.y0 = pos; - } - - if (div->child1 != -1){ - layout_compute_abs_step(layout, div->child1, r1, abs_pos); - } - - if (div->child2 != -1){ - layout_compute_abs_step(layout, div->child2, r2, abs_pos); - } -} - -internal void -layout_compute_absolute_positions(Editing_Layout *layout, i32 *abs_pos){ - i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height); - if (layout->panel_count > 1){ - layout_compute_abs_step(layout, layout->root, r, abs_pos); - } -} - -internal void -layout_get_min_max_step_up(Editing_Layout *layout, b32 v, i32 divider_id, i32 which_child, - i32 *abs_pos, i32 *min_out, i32 *max_out){ - Panel_Divider *divider = layout->dividers + divider_id; - - if (divider->v_divider == v){ - if (which_child == -1){ - if (*max_out > abs_pos[divider_id]){ - *max_out = abs_pos[divider_id]; +internal Range +layout__get_limiting_range_on_split_children(i32 mid, b32 vertical_split, Panel *panel, Range range){ + if (panel->kind == PanelKind_Intermediate){ + if (vertical_split == panel->vertical_split){ + i32 pos = layout_get_absolute_position_of_split(panel); + if (mid < pos && pos < range.max){ + range.max = pos; } + else if (range.min < pos && pos < mid){ + range.min = pos; + } + } + range = layout__get_limiting_range_on_split_children(mid, vertical_split, panel->tl_panel, range); + range = layout__get_limiting_range_on_split_children(mid, vertical_split, panel->br_panel, range); + } + return(range); +} + +internal Range +layout_get_limiting_range_on_split(Layout *layout, Panel *panel){ + // root level min max + Range range = {}; + if (panel->vertical_split){ + range.max = layout->full_dim.x; + } + else{ + range.max = layout->full_dim.y; + } + + // get mid + i32 mid = layout_get_absolute_position_of_split(panel); + + // parents min max + for (Panel *panel_it = panel; + panel_it != 0; + panel_it = panel_it->parent){ + if (panel->vertical_split == panel_it->vertical_split){ + i32 pos = layout_get_absolute_position_of_split(panel_it); + if (mid < pos && pos < range.max){ + range.max = pos; + } + else if (range.min < pos && pos < mid){ + range.min = pos; + } + } + } + + // children min max + if (panel->kind == PanelKind_Intermediate){ + range = layout__get_limiting_range_on_split_children(mid, panel->vertical_split, panel->tl_panel, range); + range = layout__get_limiting_range_on_split_children(mid, panel->vertical_split, panel->br_panel, range); + } + + return(range); +} + +internal void +layout__reverse_evaluate_panel_split(Panel *panel, i32 position){ + i32 v0 = 0; + i32 v1 = 0; + if (panel->vertical_split){ + v0 = panel->rect_full.x0; + v1 = panel->rect_full.x1; + } + else{ + v0 = panel->rect_full.y0; + v1 = panel->rect_full.y1; + } + switch (panel->split.kind){ + case PanelSplitKind_Ratio_TL: + { + panel->split.v_f32 = unlerp((f32)v0, (f32)position, (f32)v1); + }break; + case PanelSplitKind_Ratio_BR: + { + panel->split.v_f32 = unlerp((f32)v1, (f32)position, (f32)v0); + }break; + case PanelSplitKind_FixedPixels_TL: + { + panel->split.v_i32 = clamp(v0, position, v1) - v0; + }break; + case PanelSplitKind_FixedPixels_BR: + { + panel->split.v_i32 = v1 - clamp(v0, position, v1); + }break; + } +} + +internal void +layout__set_split_absolute_position_inner(Panel *panel){ + if (panel->kind == PanelKind_Intermediate){ + i32_Rect r = panel->rect_full; + i32 position = 0; + if (panel->vertical_split){ + position = layout__evaluate_split(panel->split, r.x0, r.x1); } else{ - if (*min_out < abs_pos[divider_id]){ - *min_out = abs_pos[divider_id]; - } + position = layout__evaluate_split(panel->split, r.y0, r.y1); } - } - - if (divider->parent != -1){ - layout_get_min_max_step_up(layout, v, divider->parent, divider->which_child, abs_pos, min_out, max_out); + layout__reverse_evaluate_panel_split(panel, position); } } internal void -layout_get_min_max_step_down(Editing_Layout *layout, b32 v, i32 divider_id, i32 which_child, i32 *abs_pos, i32 *min_out, i32 *max_out){ - Panel_Divider *divider = layout->dividers + divider_id; - - // NOTE(allen): The min/max is switched here, because children on the -1 side - // effect min, while if you are on the -1 side your parent effects max. - if (divider->v_divider == v){ - if (which_child == -1){ - if (*min_out < abs_pos[divider_id]){ - *min_out = abs_pos[divider_id]; - } - } - else{ - if (*max_out > abs_pos[divider_id]){ - *max_out = abs_pos[divider_id]; - } - } - } - - if (divider->child1 != -1){ - layout_get_min_max_step_down(layout, v, divider->child1, which_child, - abs_pos, min_out, max_out); - } - - if (divider->child2 != -1){ - layout_get_min_max_step_down(layout, v, divider->child2, which_child, - abs_pos, min_out, max_out); - } -} - -internal void -layout_get_min_max(Editing_Layout *layout, Panel_Divider *divider, i32 *abs_pos, i32 *min_out, i32 *max_out){ - *min_out = 0; - *max_out = max_i32; - - if (layout->panel_count > 1){ - if (divider->parent != -1){ - layout_get_min_max_step_up(layout, divider->v_divider, divider->parent, divider->which_child, - abs_pos, min_out, max_out); - } - - if (divider->child1 != -1){ - layout_get_min_max_step_down(layout, divider->v_divider, divider->child1, -1, - abs_pos, min_out, max_out); - } - - if (divider->child2 != -1){ - layout_get_min_max_step_down(layout, divider->v_divider, divider->child2, 1, - abs_pos, min_out, max_out); - } - } - else{ - if (divider->v_divider){ - *max_out = layout->full_width; - } - else{ - *max_out = layout->full_height; - } - } -} - -internal void -layout_update_pos_step(Editing_Layout *layout, i32 divider_id, i32_Rect rect, i32 *abs_pos){ - Panel_Divider *div = layout->dividers + divider_id; - - i32 p0 = 0, p1 = 0; - if (div->v_divider){ - p0 = rect.x0; p1 = rect.x1; - } - else{ - p0 = rect.y0; p1 = rect.y1; - } - - i32 pos = abs_pos[divider_id]; - i32_Rect r1 = rect, r2 = rect; - f32 lpos = unlerp((f32)p0, (f32)pos, (f32)p1); - lpos = clamp(0.f, lpos, 1.f); - - div->pos = lpos; - - if (div->v_divider){ - pos = clamp(r1.x0, pos, r2.x1); - r1.x1 = pos; r2.x0 = pos; - } - else{ - pos = clamp(r1.y0, pos, r2.y1); - r1.y1 = pos; r2.y0 = pos; - } - - if (div->child1 != -1){ - layout_update_pos_step(layout, div->child1, r1, abs_pos); - } - - if (div->child2 != -1){ - layout_update_pos_step(layout, div->child2, r2, abs_pos); - } -} - -internal void -layout_update_all_positions(Editing_Layout *layout, i32 *abs_pos){ - i32_Rect r = i32R(0, 0, layout->full_width, layout->full_height); - if (layout->panel_count > 1){ - layout_update_pos_step(layout, layout->root, r, abs_pos); +layout_set_split_absolute_position(Layout *layout, Panel *panel, i32 absolute_position){ + if (panel->kind == PanelKind_Intermediate){ + layout__reverse_evaluate_panel_split(panel, absolute_position); + layout__set_split_absolute_position_inner(panel->tl_panel); + layout__set_split_absolute_position_inner(panel->br_panel); + layout_propogate_sizes_down_from_node(layout, panel); } } diff --git a/4ed_layout.h b/4ed_layout.h index 532261a0..30741824 100644 --- a/4ed_layout.h +++ b/4ed_layout.h @@ -12,65 +12,70 @@ #if !defined(FRED_LAYOUT_H) #define FRED_LAYOUT_H -struct Panel_Divider{ - Panel_Divider *next; - i32 parent; - i32 which_child; - i32 child1, child2; - b32 v_divider; - f32 pos; +typedef i32 Panel_Split_Kind; +enum{ + PanelSplitKind_Ratio_TL = 0, + PanelSplitKind_Ratio_BR = 1, + PanelSplitKind_FixedPixels_TL = 2, + PanelSplitKind_FixedPixels_BR = 3, }; -struct Screen_Region{ - i32_Rect full; - i32_Rect inner; - i32 l_margin, r_margin; - i32 t_margin, b_margin; -}; - -struct Panel{ - Panel *next; - Panel *prev; - - struct View *view; - i32 parent; - i32 which_child; - +struct Panel_Split{ + Panel_Split_Kind kind; union{ - struct{ - i32_Rect full; - i32_Rect inner; - i32_Rect prev_inner; - i32 l_margin, r_margin; - i32 t_margin, b_margin; - }; - Screen_Region screen_region; + f32 v_f32; + i32 v_i32; }; }; -struct Editing_Layout{ - Panel *panels; - Panel free_sentinel; - Panel used_sentinel; - Panel_Divider *dividers; - Panel_Divider *free_divider; - i32 panel_count, panel_max_count; - i32 root; - i32 active_panel; - i32 full_width, full_height; +typedef i32 Panel_Kind; +enum{ + PanelKind_Intermediate = 0, + PanelKind_Final = 1, +}; + +struct Panel{ + Node node; + + Panel *parent; + Panel_Kind kind; + union{ + struct View *view; + struct{ + struct Panel *tl_panel; + struct Panel *br_panel; + b32 vertical_split; + Panel_Split split; + }; + }; + + union{ + struct{ + i32_Rect rect_full; + i32_Rect rect_inner; + } screen_region; + struct{ + i32_Rect rect_full; + i32_Rect rect_inner; + }; + }; +}; + +struct Layout{ + Node free_panels; + Node open_panels; + Node intermediate_panels; + + Panel *root; + Panel *active_panel; + + i32 margin; + i32 open_panel_count; + i32 open_panel_max_count; + Vec2_i32 full_dim; b32 panel_state_dirty; }; -struct Divider_And_ID{ - Panel_Divider* divider; - i32 id; -}; - -struct Panel_And_ID{ - Panel* panel; - i32 id; -}; - #endif // BOTTOM diff --git a/4ed_math.h b/4ed_math.h index 35a1a68e..555d1f13 100644 --- a/4ed_math.h +++ b/4ed_math.h @@ -95,7 +95,6 @@ struct Vec4{ struct{ f32 r, g, b, a; }; - struct{ f32 h, s, l, __a; }; @@ -120,31 +119,120 @@ struct Vec4{ }; }; +struct Vec2_i32{ + union{ + struct{ + i32 x, y; + }; + struct{ + i32 v[2]; + }; + }; +}; + +struct Vec3_i32{ + union{ + struct{ + i32 x, y, z; + }; + struct{ + i32 r, g, b; + }; + struct{ + Vec2 xy; + i32 _z; + }; + struct{ + i32 _x; + Vec2 yz; + }; + struct{ + i32 v[3]; + }; + }; +}; + +struct Vec4_i32{ + union{ + struct{ + i32 r, g, b, a; + }; + struct{ + i32 h, s, l, __a; + }; + struct{ + i32 x, y, z, w; + }; + struct{ + Vec3 rgb; + i32 _a; + }; + struct{ + Vec3 xyz; + i32 _w; + }; + struct{ + i32 _x; + Vec3 yzw; + }; + struct{ + i32 v[4]; + }; + }; +}; + internal Vec2 V2(f32 x, f32 y){ - Vec2 result; + Vec2 result = {}; result.x = x; result.y = y; - return result; + return(result); } internal Vec3 V3(f32 x, f32 y, f32 z){ - Vec3 result; + Vec3 result = {}; result.x = x; result.y = y; result.z = z; - return result; + return(result); } internal Vec4 V4(f32 x, f32 y, f32 z, f32 w){ - Vec4 result; + Vec4 result = {}; result.x = x; result.y = y; result.z = z; result.w = w; - return result; + return(result); +} + +internal Vec2_i32 +V2(i32 x, i32 y){ + Vec2_i32 result = {}; + result.x = x; + result.y = y; + return(result); +} + +internal Vec3_i32 +V3(i32 x, i32 y, i32 z){ + Vec3_i32 result = {}; + result.x = x; + result.y = y; + result.z = z; + return(result); +} + +internal Vec4_i32 +V4(i32 x, i32 y, i32 z, i32 w){ + Vec4_i32 result = {}; + result.x = x; + result.y = y; + result.z = z; + result.w = w; + return(result); } internal Vec2 @@ -152,7 +240,7 @@ operator+(Vec2 a, Vec2 b){ Vec2 result; result.x = a.x + b.x; result.y = a.y + b.y; - return(a + b); + return(result); } internal Vec3 @@ -161,7 +249,7 @@ operator+(Vec3 a, Vec3 b){ result.x = a.x + b.x; result.y = a.y + b.y; result.z = a.z + b.z; - return(a + b); + return(result); } internal Vec4 @@ -171,7 +259,7 @@ operator+(Vec4 a, Vec4 b){ result.y = a.y + b.y; result.z = a.z + b.z; result.w = a.w + b.w; - return(a + b); + return(result); } internal Vec2 @@ -308,6 +396,66 @@ operator*=(Vec4 &a, f32 k){ return a; } +internal b32 +operator==(Vec2 a, Vec2 b){ + return(a.x == b.x && a.y == b.y); +} + +internal b32 +operator!=(Vec2 a, Vec2 b){ + return(!(a.x == b.x && a.y == b.y)); +} + +internal b32 +operator==(Vec3 a, Vec3 b){ + return(a.x == b.x && a.y == b.y && a.z == b.z); +} + +internal b32 +operator!=(Vec3 a, Vec3 b){ + return(!(a.x == b.x && a.y == b.y && a.z == b.z)); +} + +internal b32 +operator==(Vec4 a, Vec4 b){ + return(a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); +} + +internal b32 +operator!=(Vec4 a, Vec4 b){ + return(!(a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w)); +} + +internal b32 +operator==(Vec2_i32 a, Vec2_i32 b){ + return(a.x == b.x && a.y == b.y); +} + +internal b32 +operator!=(Vec2_i32 a, Vec2_i32 b){ + return(!(a.x == b.x && a.y == b.y)); +} + +internal b32 +operator==(Vec3_i32 a, Vec3_i32 b){ + return(a.x == b.x && a.y == b.y && a.z == b.z); +} + +internal b32 +operator!=(Vec3_i32 a, Vec3_i32 b){ + return(!(a.x == b.x && a.y == b.y && a.z == b.z)); +} + +internal b32 +operator==(Vec4_i32 a, Vec4_i32 b){ + return(a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); +} + +internal b32 +operator!=(Vec4_i32 a, Vec4_i32 b){ + return(!(a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w)); +} + internal f32 dot(Vec2 a, Vec2 b){ f32 result; @@ -412,7 +560,7 @@ lerp(Vec4 a, f32 t, Vec4 b){ internal f32 unlerp(f32 a, f32 x, f32 b){ f32 r = x; - if (b > a){ + if (b != a){ r = (x - a) / (b - a); } return(r); @@ -423,7 +571,7 @@ clamp(f32 a, f32 n, f32 z){ if (n < a){ n = a; } - else if (n > z){ + else if (n > z){ n = z; } return(n); @@ -434,7 +582,7 @@ clamp(i32 a, i32 n, i32 z){ if (n < a){ n = a; } - else if (n > z){ + else if (n > z){ n = z; } return(n); @@ -445,7 +593,7 @@ clamp(i64 a, i64 n, i64 z){ if (n < a){ n = a; } - else if (n > z){ + else if (n > z){ n = z; } return(n); @@ -456,7 +604,7 @@ clamp(u32 a, u32 n, u32 z){ if (n < a){ n = a; } - else if (n > z){ + else if (n > z){ n = z; } return(n); @@ -467,7 +615,7 @@ clamp(u64 a, u64 n, u64 z){ if (n < a){ n = a; } - else if (n > z){ + else if (n > z){ n = z; } return(n); @@ -667,7 +815,7 @@ hit_check(int32_t x, int32_t y, i32_Rect rect){ internal i32_Rect get_inner_rect(i32_Rect outer, i32 margin){ - i32_Rect r; + i32_Rect r = {}; r.x0 = outer.x0 + margin; r.y0 = outer.y0 + margin; r.x1 = outer.x1 - margin; @@ -677,7 +825,7 @@ get_inner_rect(i32_Rect outer, i32 margin){ internal f32_Rect get_inner_rect(f32_Rect outer, f32 margin){ - f32_Rect r; + f32_Rect r = {}; r.x0 = outer.x0 + margin; r.y0 = outer.y0 + margin; r.x1 = outer.x1 - margin; diff --git a/4ed_view.cpp b/4ed_view.cpp index 09b09a84..d4c18ad9 100644 --- a/4ed_view.cpp +++ b/4ed_view.cpp @@ -19,27 +19,21 @@ view_get_map(View *view){ } } -internal View_And_ID -live_set_alloc_view(Heap *heap, Lifetime_Allocator *lifetime_allocator, Live_Views *live_set, Panel *panel){ +internal View* +live_set_alloc_view(Heap *heap, Lifetime_Allocator *lifetime_allocator, Live_Views *live_set){ Assert(live_set->count < live_set->max); ++live_set->count; - View_And_ID result = {}; - result.view = live_set->free_sentinel.transient.next; - result.id = (i32)(result.view - live_set->views); - Assert(result.id == result.view->persistent.id); + View *result = live_set->free_sentinel.transient.next; + Assert((i32)(result - live_set->views) == result->persistent.id); - result.view->transient.next->transient.prev = result.view->transient.prev; - result.view->transient.prev->transient.next = result.view->transient.next; - memset(&result.view->transient, 0, sizeof(result.view->transient)); + result->transient.next->transient.prev = result->transient.prev; + result->transient.prev->transient.next = result->transient.next; + block_zero_struct(&result->transient); - result.view->transient.in_use = true; - panel->view = result.view; - result.view->transient.panel = panel; - - init_query_set(&result.view->transient.query_set); - - result.view->transient.lifetime_object = lifetime_alloc_object(heap, lifetime_allocator, DynamicWorkspace_View, result.view); + result->transient.in_use = true; + init_query_set(&result->transient.query_set); + result->transient.lifetime_object = lifetime_alloc_object(heap, lifetime_allocator, DynamicWorkspace_View, result); return(result); } @@ -344,11 +338,11 @@ view_set_file(System_Functions *system, Models *models, View *view, Editing_File //////////////////////////////// internal b32 -file_is_viewed(Editing_Layout *layout, Editing_File *file){ +file_is_viewed(Layout *layout, Editing_File *file){ b32 is_viewed = false; - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ is_viewed = true; @@ -360,11 +354,11 @@ file_is_viewed(Editing_Layout *layout, Editing_File *file){ internal void adjust_views_looking_at_file_to_new_cursor(System_Functions *system, Models *models, Editing_File *file){ - Editing_Layout *layout = &models->layout; + Layout *layout = &models->layout; - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ if (!view->transient.file_data.show_temp_highlight){ @@ -388,11 +382,11 @@ file_full_remeasure(System_Functions *system, Models *models, Editing_File *file file_measure_wraps(system, &models->mem, file, font); adjust_views_looking_at_file_to_new_cursor(system, models, file); - Editing_Layout *layout = &models->layout; + Layout *layout = &models->layout; - for (Panel *panel = layout->used_sentinel.next; - panel != &layout->used_sentinel; - panel = panel->next){ + for (Panel *panel = layout_get_first_open_panel(layout); + panel != 0; + panel = layout_get_next_open_panel(layout, panel)){ View *view = panel->view; if (view->transient.file_data.file == file){ view->transient.line_height = font.metrics->height; diff --git a/4ed_view.h b/4ed_view.h index ed571351..ec2dd255 100644 --- a/4ed_view.h +++ b/4ed_view.h @@ -87,11 +87,6 @@ struct Cursor_Limits{ f32 delta; }; -struct View_And_ID{ - View *view; - i32 id; -}; - enum{ GROW_FAILED, GROW_NOT_NEEDED, diff --git a/meta/4ed_build.cpp b/meta/4ed_build.cpp index 0b714025..4b3948ff 100644 --- a/meta/4ed_build.cpp +++ b/meta/4ed_build.cpp @@ -248,6 +248,7 @@ build(Partition *part, u32 flags, u32 arch, char *code_path, char **code_files, if (flags & DEBUG_INFO){ fm_add_to_line(line, "-Zi"); + fm_add_to_line(line, "-DDO_CRAZY_EXPENSIVE_ASSERTS"); } if (flags & OPTIMIZATION){ @@ -540,8 +541,7 @@ get_freetype_include(char *out, u32 max){ #elif defined(IS_MAC) char *freetype_include = "/usr/local/include/freetype2"; size = strlen(freetype_include); - memcpy(out, freetype_include, size - ); + memcpy(out, freetype_include, size); #endif #endif return(size);