Full rewrite of panel layout system

master
Allen Webster 2019-02-05 01:13:38 -08:00
parent 4e60d34016
commit a8f678c740
15 changed files with 888 additions and 976 deletions

View File

@ -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.)
*/

View File

@ -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);
}

View File

@ -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));}

View File

@ -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

342
4ed.cpp
View File

@ -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;

View File

@ -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

View File

@ -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{

View File

@ -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)

View File

@ -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 = {};

View File

@ -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);
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -87,11 +87,6 @@ struct Cursor_Limits{
f32 delta;
};
struct View_And_ID{
View *view;
i32 id;
};
enum{
GROW_FAILED,
GROW_NOT_NEEDED,

View File

@ -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);