double-LL allocation for panels

master
Allen Webster 2016-03-02 11:18:10 -05:00
parent 6575a1cccd
commit be67657aed
5 changed files with 502 additions and 577 deletions

567
4ed.cpp
View File

@ -244,27 +244,22 @@ panel_make_empty(System_Functions *system, Exchange *exchange,
App_Vars *vars, Style *style, Panel *panel){
Mem_Options *mem = &vars->mem;
Live_Views *live_set = &vars->live_set;
Editing_Layout *layout = &vars->layout;
Working_Set *working_set = &vars->working_set;
// TODO(allen): vars->delay pointer for directing all delayed actions to appropriate place
Delay *delay = &vars->delay1;
View *new_view;
File_View *file_view;
new_view = live_set_alloc_view(live_set, mem);
if (panel->view){
view_replace_major(system, exchange, new_view, panel, live_set);
}
else{
view_set_first(new_view, panel);
}
file_view = file_view_init(new_view, layout, working_set, delay,
View_And_ID new_view;
Assert(panel->view == 0);
new_view = live_set_alloc_view(&vars->live_set, mem);
panel->view = new_view.view;
panel->view->panel = panel;
file_view = file_view_init(panel->view, layout, working_set, delay,
&vars->settings, &vars->hot_directory, mem, &vars->styles);
view_set_file(file_view, 0, vars->font_set, style, 0, 0, 0);
new_view->map = app_get_map(vars, mapid_global);
panel->view->map = app_get_map(vars, mapid_global);
return(file_view);
}
@ -699,12 +694,10 @@ COMMAND_DECL(paste){
USE_LAYOUT(layout);
USE_MEM(mem);
Panel *current_panel;
Panel *panel, *used_panels;
String *src;
File_View *current_view;
i32 pos_left, next_cursor_pos;
i32 panel_count;
i32 i;
if (working_set->clipboard_size > 0){
view->next_mode.rewrite = 1;
@ -718,12 +711,11 @@ COMMAND_DECL(paste){
view_cursor_move(view, next_cursor_pos);
view->mark = pos_left;
current_panel = layout->panels;
panel_count = layout->panel_count;
for (i = 0; i < panel_count; ++i, ++current_panel){
current_view = view_to_file_view(current_panel->view);
if (current_view && current_view->file == file){
used_panels = &layout->used_sentinel;
for (dll_items(panel, used_panels)){
current_view = view_to_file_view(panel->view);
if (current_view->file == file){
view_post_paste_effect(current_view, 20, pos_left, src->size,
current_view->style->main.paste_color);
}
@ -738,6 +730,8 @@ COMMAND_DECL(paste_next){
USE_WORKING_SET(working_set);
USE_LAYOUT(layout);
USE_MEM(mem);
Panel *panel, *used_panels;
if (working_set->clipboard_size > 0 && view->mode.rewrite == 1){
view->next_mode.rewrite = 1;
@ -751,15 +745,12 @@ COMMAND_DECL(paste_next){
view_cursor_move(view, next_cursor_pos);
view->mark = range.start;
used_panels = &layout->used_sentinel;
for (dll_items(panel, used_panels)){
File_View *current_view = view_to_file_view(panel->view);
Editing_Layout *layout = command->layout;
Panel *panels = layout->panels;
i32 panel_count = layout->panel_count;
for (i32 i = 0; i < panel_count; ++i){
Panel *current_panel = panels + i;
File_View *current_view = view_to_file_view(current_panel->view);
if (current_view && current_view->file == file){
if (current_view->file == file){
view_post_paste_effect(current_view, 20, range.start, src->size,
current_view->style->main.paste_color);
}
@ -852,14 +843,7 @@ COMMAND_DECL(interactive_new){
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_interactive(system, fview, &vars->map_ui,
IAct_New, IInt_Sys_File_List, make_lit_string("New: "));
}
@ -916,9 +900,7 @@ COMMAND_DECL(interactive_open){
ProfileMomentFunction();
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_DELAY(delay);
USE_EXCHANGE(exchange);
char *filename = 0;
int filename_len = 0;
@ -954,10 +936,6 @@ COMMAND_DECL(interactive_open){
File_View *fview = view_to_file_view(view);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_interactive(system, fview, &vars->map_ui,
IAct_Open, IInt_Sys_File_List, make_lit_string("Open: "));
}
@ -965,9 +943,7 @@ COMMAND_DECL(interactive_open){
internal void
view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){
Live_Views *live_set = cmd->live_set;
Mem_Options *mem = cmd->mem;
Exchange *exchange = cmd->exchange;
System_Functions *system = cmd->system;
Editing_Layout *layout = cmd->layout;
App_Vars *vars = cmd->vars;
@ -977,17 +953,14 @@ view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){
Partition old_part;
Temp_Memory temp;
View *new_view, *old_view;
View *old_view;
File_View *file_view;
new_view = live_set_alloc_view(live_set, mem);
view_replace_major(system, exchange, new_view, panel, live_set);
file_view = file_view_init(new_view, layout, working_set, delay,
file_view = file_view_init(panel->view, layout, working_set, delay,
&vars->settings, &vars->hot_directory, mem, &vars->styles);
old_view = cmd->view;
cmd->view = new_view;
cmd->view = panel->view;
old_part = cmd->part;
temp = begin_temp_memory(&mem->part);
@ -1000,7 +973,7 @@ view_file_in_panel(Command_Data *cmd, Panel *panel, Editing_File *file){
end_temp_memory(temp);
cmd->view = old_view;
new_view->map = app_get_map(vars, file->settings.base_map_id);
panel->view->map = app_get_map(vars, file->settings.base_map_id);
}
// TODO(allen): Improvements to reopen
@ -1086,14 +1059,7 @@ COMMAND_DECL(interactive_save_as){
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_interactive(system, fview, &vars->map_ui,
IAct_Save_As, IInt_Sys_File_List, make_lit_string("Save As: "));
}
@ -1101,25 +1067,19 @@ COMMAND_DECL(interactive_save_as){
COMMAND_DECL(change_active_panel){
ProfileMomentFunction();
USE_LAYOUT(layout);
if (layout->panel_count > 1){
++layout->active_panel;
if (layout->active_panel >= layout->panel_count){
layout->active_panel = 0;
}
USE_PANEL(panel);
panel = panel->next;
if (panel == &layout->used_sentinel){
panel = panel->next;
}
layout->active_panel = (i32)(panel - layout->panels);
}
COMMAND_DECL(interactive_switch_buffer){
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_interactive(system, fview, &vars->map_ui,
IAct_Switch, IInt_Live_File_List, make_lit_string("Switch Buffer: "));
@ -1129,13 +1089,6 @@ COMMAND_DECL(interactive_kill_buffer){
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_interactive(system, fview, &vars->map_ui,
IAct_Kill, IInt_Live_File_List, make_lit_string("Kill Buffer: "));
@ -1360,20 +1313,20 @@ COMMAND_DECL(open_panel_vsplit){
if (layout->panel_count < layout->panel_max_count){
Split_Result split = layout_split_panel(layout, panel, 1);
Panel *panel1 = panel;
Panel *panel2 = split.panel;
panel2->screen_region = panel1->screen_region;
panel2->full.x0 = split.divider->pos;
panel2->full.x1 = panel1->full.x1;
panel1->full.x1 = split.divider->pos;
panel_fix_internal_area(panel1);
panel_fix_internal_area(panel2);
panel2->prev_inner = panel2->inner;
layout->active_panel = (i32)(panel2 - layout->panels);
panel_make_empty(system, exchange, vars, style, panel2);
}
@ -1386,23 +1339,23 @@ COMMAND_DECL(open_panel_hsplit){
USE_EXCHANGE(exchange);
USE_VARS(vars);
USE_STYLE(style);
if (layout->panel_count < layout->panel_max_count){
Split_Result split = layout_split_panel(layout, panel, 0);
Panel *panel1 = panel;
Panel *panel2 = split.panel;
panel2->screen_region = panel1->screen_region;
panel2->full.y0 = split.divider->pos;
panel2->full.y1 = panel1->full.y1;
panel1->full.y1 = split.divider->pos;
panel_fix_internal_area(panel1);
panel_fix_internal_area(panel2);
panel2->prev_inner = panel2->inner;
layout->active_panel = (i32)(panel2 - layout->panels);
panel_make_empty(system, exchange, vars, style, panel2);
}
@ -1414,67 +1367,77 @@ COMMAND_DECL(close_panel){
USE_PANEL(panel);
USE_VIEW(view);
USE_EXCHANGE(exchange);
Panel *panel_ptr, *used_panels;
Divider_And_ID div, parent_div, child_div;
i32 child;
i32 parent;
i32 which_child;
i32 active;
if (layout->panel_count > 1){
if (view){
live_set_free_view(system, exchange, command->live_set, view);
panel->view = 0;
}
Divider_And_ID div = layout_get_divider(layout, panel->parent);
live_set_free_view(system, exchange, command->live_set, view);
panel->view = 0;
div = layout_get_divider(layout, panel->parent);
// This divider cannot have two child dividers.
Assert(div.divider->child1 == -1 || div.divider->child2 == -1);
i32 child;
if (div.divider->child1 == -1){
child = div.divider->child2;
}
else{
child = div.divider->child1;
}
i32 parent = div.divider->parent;
i32 which_child = div.divider->which_child;
if (parent != -1){
Divider_And_ID par = layout_get_divider(layout, parent);
if (which_child == -1){
par.divider->child1 = child;
}
else{
par.divider->child2 = child;
}
}
else{
// Get the child who needs to fill in this node's spot
child = div.divider->child1;
if (child == -1) child = div.divider->child2;
parent = div.divider->parent;
which_child = div.divider->which_child;
// Fill the child in the slot this node use to hold
if (parent == -1){
Assert(layout->root == div.id);
layout->root = child;
}
if (child != -1){
Divider_And_ID chi = layout_get_divider(layout, child);
chi.divider->parent = parent;
chi.divider->which_child = div.divider->which_child;
else{
parent_div = layout_get_divider(layout, parent);
if (which_child == -1){
parent_div.divider->child1 = child;
}
else{
parent_div.divider->child2 = child;
}
}
layout_free_divider(layout, div.divider);
layout_free_panel(layout, panel);
// If there was a child divider, give it information about it's new parent.
if (child != -1){
child_div = layout_get_divider(layout, child);
child_div.divider->parent = parent;
child_div.divider->which_child = div.divider->which_child;
}
// What is the new active panel?
active = -1;
if (child == -1){
panel = layout->panels;
layout->active_panel = -1;
for (i32 i = 0; i < layout->panel_count; ++i){
if (panel->parent == div.id){
panel->parent = parent;
panel->which_child = which_child;
layout->active_panel = i;
used_panels = &layout->used_sentinel;
for (dll_items(panel_ptr, used_panels)){
if (panel_ptr != panel && panel_ptr->parent == div.id){
panel_ptr->parent = parent;
panel_ptr->which_child = which_child;
active = (i32)(panel_ptr - layout->panels);
break;
}
++panel;
}
Assert(layout->active_panel != -1);
}
else{
layout->active_panel = layout->active_panel % layout->panel_count;
panel_ptr = panel->next;
if (panel_ptr == &layout->used_sentinel) panel_ptr = panel_ptr->next;
Assert(panel_ptr != panel);
active = (i32)(panel_ptr - layout->panels);
}
Assert(active != -1 && panel != layout->panels + active);
layout->active_panel = active;
layout_free_divider(layout, div.divider);
layout_free_panel(layout, panel);
layout_fix_all_panels(layout);
}
}
@ -1619,40 +1582,9 @@ COMMAND_DECL(page_up){
}
COMMAND_DECL(open_color_tweaker){
#if 0
ProfileMomentFunction();
USE_VARS(vars);
USE_LIVE_SET(live_set);
USE_MEM(mem);
USE_PANEL(panel);
USE_EXCHANGE(exchange);
{
View *new_view = live_set_alloc_view(live_set, mem);
view_replace_minor(system, exchange, new_view, panel, live_set);
new_view->map = &vars->map_ui;
Color_View *color_view = color_view_init(new_view, &vars->working_set);
color_view->hot_directory = &vars->hot_directory;
color_view->main_style = &vars->style;
color_view->styles = &vars->styles;
color_view->palette = vars->palette;
color_view->palette_size = vars->palette_size;
color_view->font_set = vars->font_set;
}
#endif
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_theme(fview, &vars->map_ui);
}
@ -1661,13 +1593,6 @@ COMMAND_DECL(open_config){
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_config(fview, &vars->map_ui);
}
@ -1676,13 +1601,6 @@ COMMAND_DECL(open_menu){
ProfileMomentFunction();
USE_FILE_VIEW(fview);
USE_VARS(vars);
USE_PANEL(panel);
USE_STYLE(style);
USE_EXCHANGE(exchange);
if (!fview){
fview = panel_make_empty(system, exchange, vars, style, panel);
}
view_show_menu(fview, &vars->map_ui);
}
@ -3036,61 +2954,63 @@ App_Init_Sig(app_init){
Partition *partition = &vars->mem.part;
target->partition = partition;
Panel *panels;
Panel *panels, *panel;
Panel_Divider *dividers, *div;
i32 panel_max_count;
i32 divider_max_count;
panel_max_count = vars->layout.panel_max_count = 16;
divider_max_count = panel_max_count - 1;
vars->layout.panel_count = 1;
panels = push_array(partition, Panel, panel_max_count);
vars->layout.panels = panels;
dividers = push_array(partition, Panel_Divider, divider_max_count);
vars->layout.dividers = dividers;
div = dividers;
for (i32 i = 0; i < divider_max_count-1; ++i, ++div){
div->next = (div + 1);
{
i32 i;
panel_max_count = vars->layout.panel_max_count = 16;
divider_max_count = panel_max_count - 1;
vars->layout.panel_count = 0;
panels = push_array(partition, Panel, panel_max_count);
vars->layout.panels = panels;
dll_init_sentinel(&vars->layout.free_sentinel);
dll_init_sentinel(&vars->layout.used_sentinel);
panel = panels;
for (i = 0; i < panel_max_count; ++i, ++panel){
dll_insert(&vars->layout.free_sentinel, panel);
}
dividers = push_array(partition, Panel_Divider, divider_max_count);
vars->layout.dividers = dividers;
div = dividers;
for (i = 0; i < divider_max_count-1; ++i, ++div){
div->next = (div + 1);
}
div->next = 0;
vars->layout.free_divider = dividers;
}
div->next = 0;
vars->layout.free_divider = dividers;
i32 view_chunk_size = 0;
i32 view_sizes[] = {
sizeof(File_View)
};
{
char *vptr = 0;
View *v = 0, *n = 0;
i32 i = 0, max = 0;
View *v = 0;
i32 i = 0;
i32 max = 0;
i32 view_size = sizeof(File_View);
vars->live_set.count = 0;
vars->live_set.max = panel_max_count;
for (i = 0; i < ArrayCount(view_sizes); ++i){
view_chunk_size = Max(view_chunk_size, view_sizes[i]);
}
vars->live_set.stride = view_chunk_size;
vars->live_set.views = push_block(partition, view_chunk_size*vars->live_set.max);
vars->live_set.stride = view_size;
vars->live_set.views = push_block(partition, view_size*vars->live_set.max);
dll_init_sentinel(&vars->live_set.free_sentinel);
max = vars->live_set.max;
vptr = (char*)vars->live_set.views;
vars->live_set.free_view = (View*)vptr;
for (i = 0; i < max; ++i){
for (i = 0; i < max; ++i, vptr += view_size){
v = (View*)(vptr);
n = (View*)(vptr + view_chunk_size);
v->next_free = n;
vptr = (char*)n;
dll_insert(&vars->live_set.free_sentinel, v);
}
v->next_free = 0;
}
setup_command_table();
Command_Map *global = &vars->map_top;
@ -3302,16 +3222,17 @@ App_Init_Sig(app_init){
vars->palette_size = 40;
vars->palette = push_array(partition, u32, vars->palette_size);
// NOTE(allen): init first panel
panel_init(&panels[0]);
panel_make_empty(system, exchange, vars, &vars->style, &panels[0]);
Panel_And_ID p = layout_alloc_panel(&vars->layout);
panel_make_empty(system, exchange, vars, &vars->style, p.panel);
vars->layout.active_panel = p.id;
String hdbase = make_fixed_width_string(vars->hot_dir_base_);
hot_directory_init(&vars->hot_directory, hdbase, current_directory, system->slash);
vars->mini_str = make_string((char*)vars->mini_buffer, 0, 512);
// NOTE(allen): child proc list setup
i32 max_children = 16;
partition_align(partition, 8);
@ -3325,6 +3246,21 @@ App_Init_Sig(app_init){
vars->sys_app_bindings = (Sys_App_Binding*)push_array(partition, Sys_App_Binding, vars->sys_app_max);
}
// NOTE(allen): while I transition away from this view system to something that has
// more unified behavior, I will use this to add checks to the program's state so that I
// can make sure it behaving well.
internal void
correctness_check(App_Vars *vars){
Panel *panel, *used_panels;
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
Assert(panel->view);
Assert(panel->parent != -1 || vars->layout.panel_count == 1);
}
panel = vars->layout.panels + vars->layout.active_panel;
Assert(panel->ALLOCED);
}
App_Step_Sig(app_step){
ProfileStart(OS_syncing);
Application_Step_Result app_result = *result;
@ -3361,7 +3297,6 @@ App_Step_Sig(app_step){
}
// NOTE(allen): update child processes
Panel *panels = vars->layout.panels;
if (time_step){
Temp_Memory temp = begin_temp_memory(&vars->mem.part);
u32 max = Kbytes(32);
@ -3416,11 +3351,14 @@ App_Step_Sig(app_step){
new_cursor = spec.step.post_pos;
}
Panel *panel = panels;
i32 panel_count = vars->layout.panel_count;
for (i32 i = 0; i < panel_count; ++i, ++panel){
View *view = panel->view;
File_View *fview = view_to_file_view(view);
Panel *panel, *used_panels;
View *view;
File_View *fview;
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
view = panel->view;
fview = view_to_file_view(view);
Assert(fview);
if (fview->file == out_file){
view_cursor_move(fview, new_cursor);
@ -3428,7 +3366,7 @@ App_Step_Sig(app_step){
}
}
}
vars->cli_processes.count = count;
end_temp_memory(temp);
}
@ -3439,20 +3377,18 @@ App_Step_Sig(app_step){
i32 prev_height = vars->layout.full_height;
i32 current_width = target->width;
i32 current_height = target->height;
Panel *panel;
Panel *panel, *used_panels;
File_View *fview;
i32 i, count;
vars->layout.full_width = current_width;
vars->layout.full_height = current_height;
if (prev_width != current_width || prev_height != current_height){
layout_refit(&vars->layout, prev_width, prev_height);
count = vars->layout.panel_count;
panel = panels;
for (i = 0; i < count; ++i, ++panel){
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
fview = view_to_file_view(panel->view);
Assert(fview);
// TODO(allen): All responses to a panel changing size should
@ -3477,18 +3413,7 @@ App_Step_Sig(app_step){
ProfileEnd(OS_syncing);
// NOTE(allen): while I transition away from this view system to something that has
// more unified behavior, I will use this to add checks to the program's state so that I
// can make sure it behaving well.
ProfileStart(correctness_checks);
{
Panel *panel = panels;
i32 panel_count = vars->layout.panel_count;
for (i32 i = 0; i < panel_count; ++i, ++panel){
Assert(panel->view);
}
}
ProfileEnd(correctness_checks);
correctness_check(vars);
ProfileStart(hover_status);
// NOTE(allen): detect mouse hover status
@ -3496,12 +3421,10 @@ App_Step_Sig(app_step){
i32 my = mouse->y;
b32 mouse_in_edit_area = 0;
b32 mouse_in_margin_area = 0;
Panel *mouse_panel = 0;
i32 mouse_panel_i = 0;
i32 panel_count = vars->layout.panel_count;
mouse_panel = panels;
for (mouse_panel_i = 0; mouse_panel_i < panel_count; ++mouse_panel_i, ++mouse_panel){
Panel *mouse_panel, *used_panels;
used_panels = &vars->layout.used_sentinel;
for (dll_items(mouse_panel, used_panels)){
if (hit_check(mx, my, mouse_panel->inner)){
mouse_in_edit_area = 1;
break;
@ -3514,7 +3437,6 @@ App_Step_Sig(app_step){
if (!(mouse_in_edit_area || mouse_in_margin_area)){
mouse_panel = 0;
mouse_panel_i = 0;
}
b32 mouse_on_divider = 0;
@ -3572,13 +3494,15 @@ App_Step_Sig(app_step){
}
ProfileEnd(hover_status);
correctness_check(vars);
// NOTE(allen): prepare to start executing commands
ProfileStart(command_coroutine);
ProfileStart(prepare_commands);
Command_Data *cmd = &vars->command_data;
cmd->mem = &vars->mem;
cmd->panel = panels + vars->layout.active_panel;
cmd->panel = vars->layout.panels + vars->layout.active_panel;
cmd->view = cmd->panel->view;
cmd->working_set = &vars->working_set;
cmd->layout = &vars->layout;
@ -3590,16 +3514,16 @@ App_Step_Sig(app_step){
cmd->screen_width = target->width;
cmd->screen_height = target->height;
cmd->system = system;
Temp_Memory param_stack_temp = begin_temp_memory(&vars->mem.part);
cmd->part = partition_sub_part(&vars->mem.part, 16 << 10);
if (first_step){
if (vars->hooks[hook_start]){
vars->hooks[hook_start](&app_links);
cmd->part.pos = 0;
}
i32 i;
String file_name;
Panel *panel = vars->layout.panels;
@ -3617,7 +3541,7 @@ App_Step_Sig(app_step){
}
}
}
ProfileEnd(hover_status);
ProfileEnd(prepare_commands);
// NOTE(allen): process the command_coroutine if it is unfinished
ProfileStart(command_coroutine);
@ -3753,6 +3677,8 @@ App_Step_Sig(app_step){
ProfileEnd(command_coroutine);
correctness_check(vars);
// NOTE(allen): pass raw input to the panels
ProfileStart(step);
@ -3794,22 +3720,21 @@ App_Step_Sig(app_step){
if (consumed_input[5]){
mouse_state.wheel = 0;
}
{
Panel *panel = panels;
for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){
Panel *panel, *used_panels;
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
View *view_ = panel->view;
if (view_){
Assert(view_->do_view);
b32 active = (panel == cmd->panel);
Input_Summary input = (active)?(active_input):(dead_input);
if (panel == mouse_panel && !mouse->out_of_window){
input.mouse = mouse_state;
}
if (view_->do_view(system, exchange, view_, panel->inner, cmd->view,
VMSG_STEP, 0, &input, &active_input)){
app_result.redraw = 1;
}
Assert(view_->do_view);
b32 active = (panel == cmd->panel);
Input_Summary input = (active)?(active_input):(dead_input);
if (panel == mouse_panel && !mouse->out_of_window){
input.mouse = mouse_state;
}
if (view_->do_view(system, exchange, view_, panel->inner, cmd->view,
VMSG_STEP, 0, &input, &active_input)){
app_result.redraw = 1;
}
}
}
@ -3817,6 +3742,8 @@ App_Step_Sig(app_step){
update_command_data(vars, cmd);
ProfileEnd(step);
correctness_check(vars);
// NOTE(allen): command execution
ProfileStart(command);
if (!consumed_input[0] || !consumed_input[1]){
@ -3877,7 +3804,9 @@ App_Step_Sig(app_step){
update_command_data(vars, cmd);
ProfileEnd(command);
correctness_check(vars);
ProfileStart(resizing);
// NOTE(allen): panel resizing
switch (vars->state){
@ -3976,13 +3905,15 @@ App_Step_Sig(app_step){
}
if (mouse_in_edit_area && mouse_panel != 0 && mouse->press_l){
vars->layout.active_panel = mouse_panel_i;
vars->layout.active_panel = (i32)(mouse_panel - vars->layout.panels);
app_result.redraw = 1;
}
update_command_data(vars, cmd);
ProfileEnd(resizing);
correctness_check(vars);
// NOTE(allen): processing sys app bindings
ProfileStart(sys_app_bind_processing);
{
@ -4227,17 +4158,13 @@ App_Step_Sig(app_step){
file_create_empty(system, mem, working_set, file.file, string.str,
vars->font_set, style->font_id);
table_add(&working_set->table, file.file->name.source_path, file.index);
View *new_view = live_set_alloc_view(live_set, mem);
view_replace_major(system, exchange, new_view, panel, live_set);
File_View *file_view = file_view_init(
new_view, &vars->layout, working_set, &vars->delay2,
&vars->settings, &vars->hot_directory, mem, &vars->styles);
cmd->view = (View*)file_view;
view_set_file(file_view, file.file, vars->font_set, style,
View *view = panel->view;
File_View *fview = view_to_file_view(view);
view_set_file(fview, file.file, vars->font_set, style,
system, vars->hooks[hook_open_file], &app_links);
new_view->map = app_get_map(vars, file.file->settings.base_map_id);
view->map = app_get_map(vars, file.file->settings.base_map_id);
#if BUFFER_EXPERIMENT_SCALPEL <= 0
if (file.file->settings.tokens_exist)
file_first_lex_parallel(system, general, file.file);
@ -4248,18 +4175,12 @@ App_Step_Sig(app_step){
{
Editing_File *file = working_set_lookup_file(working_set, string);
if (file){
View *new_view = live_set_alloc_view(live_set, mem);
view_replace_major(system, exchange, new_view, panel, live_set);
File_View *file_view = file_view_init(
new_view, &vars->layout, working_set, &vars->delay2,
&vars->settings, &vars->hot_directory, mem, &vars->styles);
cmd->view = (View*)file_view;
view_set_file(file_view, file, vars->font_set, style,
View *view = panel->view;
File_View *fview = view_to_file_view(view);
view_set_file(fview, file, vars->font_set, style,
system, vars->hooks[hook_open_file], &app_links);
new_view->map = app_get_map(vars, file->settings.base_map_id);
view->map = app_get_map(vars, file->settings.base_map_id);
}
}break;
@ -4308,15 +4229,18 @@ App_Step_Sig(app_step){
}
Swap(vars->delay1, vars->delay2);
}
end_temp_memory(param_stack_temp);
ProfileEnd(delayed_actions);
end_temp_memory(param_stack_temp);
correctness_check(vars);
ProfileStart(resize);
// NOTE(allen): send resize messages to panels that have changed size
{
Panel *panel = panels;
for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){
Panel *panel, *used_panels;
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
i32_Rect prev = panel->prev_inner;
i32_Rect inner = panel->inner;
if (prev.x0 != inner.x0 || prev.y0 != inner.y0 ||
@ -4349,10 +4273,10 @@ App_Step_Sig(app_step){
&file->state.buffer, advance_data);
}
}
Panel *panel = panels;
i32 count = vars->layout.panel_count;
for (i32 i = 0; i < count; ++i, ++panel){
Panel *panel, *used_panels;
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
View *view = panel->view;
if (view){
view->do_view(system, exchange,
@ -4362,6 +4286,8 @@ App_Step_Sig(app_step){
}
}
ProfileEnd(style_change);
correctness_check(vars);
ProfileStart(redraw);
if (mouse_panel != vars->prev_mouse_panel) app_result.redraw = 1;
@ -4372,11 +4298,12 @@ App_Step_Sig(app_step){
draw_push_clip(target, rect_from_target(target));
// NOTE(allen): render the panels
Panel *panel = panels;
for (i32 panel_i = vars->layout.panel_count; panel_i > 0; --panel_i, ++panel){
Panel *panel, *used_panels;
used_panels = &vars->layout.used_sentinel;
for (dll_items(panel, used_panels)){
i32_Rect full = panel->full;
i32_Rect inner = panel->inner;
View *view = panel->view;
Style *style = &vars->style;
@ -4416,13 +4343,7 @@ App_Step_Sig(app_step){
ProfileStart(get_cursor);
// NOTE(allen): get cursor type
if (mouse_in_edit_area){
View *view = mouse_panel->view;
if (view){
app_result.mouse_cursor_type = view->mouse_cursor_type;
}
else{
app_result.mouse_cursor_type = APP_MOUSE_CURSOR_ARROW;
}
}
else if (mouse_in_margin_area){
if (mouse_on_divider){
@ -4443,6 +4364,8 @@ App_Step_Sig(app_step){
*result = app_result;
result->lctrl_lalt_is_altgr = vars->settings.lctrl_lalt_is_altgr;
correctness_check(vars);
// end-of-app_step
}

View File

@ -35,6 +35,7 @@
#define FCPP_LEXER_IMPLEMENTATION
#include "4cpp_lexer.h"
#include "4ed_template.cpp"
#include "4ed_exchange.cpp"
#include "4ed_font_set.cpp"
#include "4ed_rendering_helper.cpp"

View File

@ -414,27 +414,6 @@ get_opaque_font_advance(Render_Font *font){
return result;
}
#if 0
internal void
file_grow_widths_as_needed(General_Memory *general, Buffer_Type *buffer){
i32 line_count = buffer->line_count;
if (line_count > buffer->widths_max || buffer->widths_max == 0){
i32 new_max = LargeRoundUp(line_count, Kbytes(1));
if (new_max < Kbytes(1)) new_max = Kbytes(1);
if (buffer->line_widths){
buffer->line_widths = (f32*)
general_memory_reallocate(general, buffer->line_widths,
sizeof(f32)*buffer->widths_count, sizeof(f32)*new_max, BUBBLE_WIDTHS);
}
else{
buffer->line_widths = (f32*)
general_memory_allocate(general, sizeof(f32)*new_max, BUBBLE_WIDTHS);
}
buffer->widths_max = new_max;
}
}
#endif
internal void
file_remeasure_widths_(System_Functions *system,
General_Memory *general, Buffer_Type *buffer, Render_Font *font,
@ -1498,25 +1477,6 @@ view_set_widget(File_View *view, File_View_Widget_Type type){
}
#if 0
inline i32
view_widget_height(File_View *view, i32 font_height){
i32 result = 0;
switch (view->widget.type){
case FWIDG_NONE:
{
Query_Slot *slot;
for (slot = view->query_set.used_slot; slot != 0; slot = slot->next){
result += view->font_height + 2;
}
}
break;
case FWIDG_TIMELINES: result = view->widget.height; break;
}
return result;
}
#endif
inline i32_Rect
view_widget_rect(File_View *view, i32 font_height){
Panel *panel = view->view_base.panel;
@ -1526,13 +1486,6 @@ view_widget_rect(File_View *view, i32 font_height){
result.y0 = result.y0 + font_height + 2;
}
#if 0
if (view->file){
result.y0 = result.y0 + font_height + 2;
}
result.y1 = result.y0 + view_widget_height(view, font_height);
#endif
return(result);
}
@ -2869,7 +2822,6 @@ interactive_view_complete(File_View *view){
case IAct_Save_As:
delayed_save_as(view->delay, view->hot_directory->string, panel);
view_show_file(view, 0);
break;
case IAct_New:
@ -2899,9 +2851,9 @@ interactive_view_complete(File_View *view){
delayed_kill(view->delay, view->dest, panel);
break;
}
view_show_file(view, 0);
break;
}
view_show_file(view, 0);
}
internal void
@ -3513,7 +3465,6 @@ config_shit(File_View *view, UI_State *state, UI_Layout *layout){
internal i32
step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Rect rect,
b32 is_active, Input_Summary *user_input){
view_->mouse_cursor_type = APP_MOUSE_CURSOR_IBEAM;
i32 result = 0;
File_View *view = (File_View*)view_;
@ -3565,13 +3516,6 @@ step_file_view(System_Functions *system, Exchange *exchange, View *view_, i32_Re
f32 extra_top = (f32)widget_height;
f32 taken_top_space = line_height + extra_top;
if (user_input->mouse.y < rect.y0 + taken_top_space){
view_->mouse_cursor_type = APP_MOUSE_CURSOR_ARROW;
}
else{
view_->mouse_cursor_type = APP_MOUSE_CURSOR_IBEAM;
}
if (user_input->mouse.wheel != 0){
f32 wheel_multiplier = 3.f;
f32 delta_target_y = delta_y*user_input->mouse.wheel*wheel_multiplier;

View File

@ -9,55 +9,6 @@
// TOP
struct Interactive_Style{
u32 bar_color;
u32 bar_active_color;
u32 base_color;
u32 pop1_color;
u32 pop2_color;
};
struct Interactive_Bar{
Interactive_Style style;
f32 pos_x, pos_y;
f32 text_shift_x, text_shift_y;
i32_Rect rect;
i16 font_id;
};
enum View_Message{
VMSG_STEP,
VMSG_DRAW,
VMSG_RESIZE,
VMSG_STYLE_CHANGE,
VMSG_FREE
};
struct View;
#define Do_View_Sig(name) \
i32 (name)(System_Functions *system, Exchange *exchange, \
View *view, i32_Rect rect, View *active, \
View_Message message, Render_Target *target, \
Input_Summary *user_input, Input_Summary *active_input)
typedef Do_View_Sig(Do_View_Function);
struct Panel;
struct View{
View *next_free;
Panel *panel;
Command_Map *map;
Do_View_Function *do_view;
Application_Mouse_Cursor mouse_cursor_type;
};
struct Live_Views{
void *views;
View *free_view;
i32 count, max;
i32 stride;
};
struct Panel_Divider{
Panel_Divider *next;
i32 parent;
@ -76,9 +27,15 @@ struct Screen_Region{
};
struct Panel{
View *view;
Panel *next;
Panel *prev;
struct View *view;
i32 parent;
i32 which_child;
int ALLOCED;
union{
struct{
i32_Rect full;
@ -93,6 +50,8 @@ struct Panel{
struct Editing_Layout{
Panel *panels;
Panel free_sentinel;
Panel used_sentinel;
Panel_Divider *dividers;
Panel_Divider *free_divider;
i32 panel_count, panel_max_count;
@ -101,86 +60,30 @@ struct Editing_Layout{
i32 full_width, full_height;
};
internal void
intbar_draw_string(Render_Target *target,
Interactive_Bar *bar, u8 *str, u32 char_color){
i16 font_id = bar->font_id;
struct Divider_And_ID{
Panel_Divider* divider;
i32 id;
};
draw_string(target, font_id, (char*)str,
(i32)(bar->pos_x + bar->text_shift_x),
(i32)(bar->pos_y + bar->text_shift_y),
char_color);
bar->pos_x += font_string_width(target, font_id, (char*)str);
}
internal void
intbar_draw_string(Render_Target *target, Interactive_Bar *bar,
String str, u32 char_color){
i16 font_id = bar->font_id;
draw_string(target, font_id, str,
(i32)(bar->pos_x + bar->text_shift_x),
(i32)(bar->pos_y + bar->text_shift_y),
char_color);
bar->pos_x += font_string_width(target, font_id, str);
}
struct Panel_And_ID{
Panel* panel;
i32 id;
};
internal void
panel_init(Panel *panel){
*panel = {};
panel->view = 0;
panel->parent = -1;
panel->which_child = 0;
panel->screen_region.full = {};
panel->screen_region.inner = {};
panel->screen_region.prev_inner = {};
panel->l_margin = 3;
panel->r_margin = 3;
panel->t_margin = 3;
panel->b_margin = 3;
}
internal View*
live_set_get_view(Live_Views *live_set, i32 i){
void *result = ((char*)live_set->views + i*live_set->stride);
return (View*)result;
}
internal View*
live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){
Assert(live_set->count < live_set->max);
View *result = 0;
result = live_set->free_view;
live_set->free_view = result->next_free;
memset(result, 0, live_set->stride);
++live_set->count;
return result;
}
inline void
live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *live_set, View *view){
Assert(live_set->count > 0);
view->do_view(system, exchange, view, {}, 0, VMSG_FREE, 0, {}, 0);
view->next_free = live_set->free_view;
live_set->free_view = view;
--live_set->count;
}
inline void
view_set_first(View *new_view, Panel *panel){
new_view->panel = panel;
panel->view = new_view;
}
inline void
view_replace_major(System_Functions *system, Exchange *exchange,
View *new_view, Panel *panel, Live_Views *live_set){
View *view = panel->view;
live_set_free_view(system, exchange, live_set, view);
new_view->panel = panel;
panel->view = new_view;
}
struct Divider_And_ID{
Panel_Divider* divider;
i32 id;
};
internal Divider_And_ID
layout_alloc_divider(Editing_Layout *layout){
Divider_And_ID result;
@ -203,20 +106,13 @@ layout_alloc_divider(Editing_Layout *layout){
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;
Assert(id >= 0 && id < layout->panel_max_count-1);
result.id = id;
result.divider = layout->dividers + id;
return result;
}
internal Panel*
layout_alloc_panel(Editing_Layout *layout){
Assert(layout->panel_count < layout->panel_max_count);
Panel *result = layout->panels + layout->panel_count;
*result = {};
++layout->panel_count;
return result;
return(result);
}
internal void
@ -225,19 +121,33 @@ layout_free_divider(Editing_Layout *layout, Panel_Divider *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);
result.panel->ALLOCED = 1;
return(result);
}
internal void
layout_free_panel(Editing_Layout *layout, Panel *panel){
Panel *p, *panels;
i32 panel_count, i;
dll_remove(panel);
dll_insert(&layout->free_sentinel, panel);
--layout->panel_count;
panels = layout->panels;
panel_count = --layout->panel_count;
p = panel;
for (i = (i32)(panel - layout->panels); i < panel_count; ++i, ++p){
*p = panels[i+1];
p->view->panel = p;
}
panel->ALLOCED = 0;
}
internal Divider_And_ID
@ -257,7 +167,7 @@ internal Split_Result
layout_split_panel(Editing_Layout *layout, Panel *panel, b32 vertical){
Split_Result result = {};
Divider_And_ID div = {}, parent_div = {};
Panel *new_panel = 0;
Panel_And_ID new_panel = {};
div = layout_alloc_divider(layout);
if (panel->parent != -1){
@ -284,71 +194,67 @@ layout_split_panel(Editing_Layout *layout, Panel *panel, b32 vertical){
new_panel = layout_alloc_panel(layout);
panel->parent = div.id;
panel->which_child = -1;
new_panel->parent = div.id;
new_panel->which_child = 1;
new_panel.panel->parent = div.id;
new_panel.panel->which_child = 1;
result.divider = div.divider;
result.panel = new_panel;
result.panel = new_panel.panel;
return result;
}
internal void
panel_fix_internal_area(Panel *panel){
i32 left, right, top, bottom;
left = panel->l_margin;
right = panel->r_margin;
top = panel->t_margin;
bottom = panel->b_margin;
panel->inner.x0 = panel->full.x0 + left;
panel->inner.x1 = panel->full.x1 - right;
panel->inner.y0 = panel->full.y0 + top;
panel->inner.y1 = panel->full.y1 - bottom;
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 void
layout_fix_all_panels(Editing_Layout *layout){
Panel *panels = layout->panels;
if (layout->panel_count > 1){
Panel_Divider *dividers = layout->dividers;
int panel_count = layout->panel_count;
Panel *panel = panels;
for (i32 i = 0; i < panel_count; ++i){
i32 x0, x1, y0, y1;
x0 = 0;
x1 = x0 + layout->full_width;
y0 = 0;
y1 = y0 + layout->full_height;
i32 pos;
i32 which_child = panel->which_child;
Divider_And_ID div;
Panel *panel;
Panel_Divider *dividers = layout->dividers;
i32 panel_count = layout->panel_count;
i32_Rect r;
i32 pos, which_child, action;
Divider_And_ID div;
if (panel_count > 1){
for (panel = layout->used_sentinel.next;
panel != &layout->used_sentinel;
panel = panel->next){
r.x0 = 0;
r.x1 = r.x0 + layout->full_width;
r.y0 = 0;
r.y1 = r.y0 + layout->full_height;
which_child = panel->which_child;
div.id = panel->parent;
for (;;){
Assert(div.id != -1);
div.divider = dividers + div.id;
pos = div.divider->pos;
div.divider = dividers + div.id;
// NOTE(allen): sorry if this is hard to read through, there are
// two binary conditionals that combine into four possible cases.
// Why am I appologizing to you? IF YOU CANT HANDLE MY CODE GET OUT!
i32 action = (div.divider->v_divider << 1) | (which_child > 0);
action = (div.divider->v_divider << 1) | (which_child > 0);
switch (action){
case 0: // v_divider : 0, which_child : -1
if (pos < y1) y1 = pos;
if (pos < r.y1) r.y1 = pos;
break;
case 1: // v_divider : 0, which_child : 1
if (pos > y0) y0 = pos;
if (pos > r.y0) r.y0 = pos;
break;
case 2: // v_divider : 1, which_child : -1
if (pos < x1) x1 = pos;
if (pos < r.x1) r.x1 = pos;
break;
case 3: // v_divider : 1, which_child : 1
if (pos > x0) x0 = pos;
if (pos > r.x0) r.x0 = pos;
break;
}
if (div.id != layout->root){
div.id = div.divider->parent;
which_child = div.divider->which_child;
@ -357,22 +263,19 @@ layout_fix_all_panels(Editing_Layout *layout){
break;
}
}
panel->full.x0 = x0;
panel->full.y0 = y0;
panel->full.x1 = x1;
panel->full.y1 = y1;
panel->full = r;
panel_fix_internal_area(panel);
++panel;
}
}
else{
panels[0].full.x0 = 0;
panels[0].full.y0 = 0;
panels[0].full.x1 = layout->full_width;
panels[0].full.y1 = layout->full_height;
panel_fix_internal_area(panels);
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);
}
}
@ -406,20 +309,133 @@ layout_refit(Editing_Layout *layout, i32 prev_width, i32 prev_height){
layout_fix_all_panels(layout);
}
inline real32
view_base_compute_width(View *view){
Panel *panel = view->panel;
return (real32)(panel->inner.x1 - panel->inner.x0);
enum View_Message{
VMSG_STEP,
VMSG_DRAW,
VMSG_RESIZE,
VMSG_STYLE_CHANGE,
VMSG_FREE
};
struct View;
#define Do_View_Sig(name) \
i32 (name)(System_Functions *system, Exchange *exchange, \
View *view, i32_Rect rect, View *active, \
View_Message message, Render_Target *target, \
Input_Summary *user_input, Input_Summary *active_input)
typedef Do_View_Sig(Do_View_Function);
struct View{
View *next, *prev;
Panel *panel;
Command_Map *map;
Do_View_Function *do_view;
};
struct Live_Views{
void *views;
View free_sentinel;
i32 count, max;
i32 stride;
};
struct View_And_ID{
View *view;
i32 id;
};
internal View*
live_set_get_view(Live_Views *live_set, i32 id){
void *result = ((char*)live_set->views + id);
return (View*)result;
}
inline real32
internal View_And_ID
live_set_alloc_view(Live_Views *live_set, Mem_Options *mem){
View_And_ID result = {};
Assert(live_set->count < live_set->max);
++live_set->count;
result.view = live_set->free_sentinel.next;
result.id = (i32)((char*)result.view - (char*)live_set->views);
dll_remove(result.view);
memset(result.view, 0, live_set->stride);
return(result);
}
inline void
live_set_free_view(System_Functions *system, Exchange *exchange, Live_Views *live_set, View *view){
Assert(live_set->count > 0);
--live_set->count;
view->do_view(system, exchange, view, {}, 0, VMSG_FREE, 0, {}, 0);
dll_insert(&live_set->free_sentinel, view);
}
inline void
view_set_first(View *new_view, Panel *panel){
new_view->panel = panel;
panel->view = new_view;
}
inline f32
view_base_compute_width(View *view){
Panel *panel = view->panel;
return (f32)(panel->inner.x1 - panel->inner.x0);
}
inline f32
view_base_compute_height(View *view){
Panel *panel = view->panel;
return (real32)(panel->inner.y1 - panel->inner.y0);
return (f32)(panel->inner.y1 - panel->inner.y0);
}
#define view_compute_width(view) (view_base_compute_width(&(view)->view_base))
#define view_compute_height(view) (view_base_compute_height(&(view)->view_base))
struct Interactive_Style{
u32 bar_color;
u32 bar_active_color;
u32 base_color;
u32 pop1_color;
u32 pop2_color;
};
struct Interactive_Bar{
Interactive_Style style;
f32 pos_x, pos_y;
f32 text_shift_x, text_shift_y;
i32_Rect rect;
i16 font_id;
};
internal void
intbar_draw_string(Render_Target *target,
Interactive_Bar *bar, u8 *str, u32 char_color){
i16 font_id = bar->font_id;
draw_string(target, font_id, (char*)str,
(i32)(bar->pos_x + bar->text_shift_x),
(i32)(bar->pos_y + bar->text_shift_y),
char_color);
bar->pos_x += font_string_width(target, font_id, (char*)str);
}
internal void
intbar_draw_string(Render_Target *target, Interactive_Bar *bar,
String str, u32 char_color){
i16 font_id = bar->font_id;
draw_string(target, font_id, str,
(i32)(bar->pos_x + bar->text_shift_x),
(i32)(bar->pos_y + bar->text_shift_y),
char_color);
bar->pos_x += font_string_width(target, font_id, str);
}
// BOTTOM

41
4ed_template.cpp Normal file
View File

@ -0,0 +1,41 @@
/*
* Mr. 4th Dimention - Allen Webster
*
* 01.03.2016
*
* Templated code.
*
*/
// TOP
// NOTE(allen): This is an experiment, BUT remember a lot of people shit on templates.
// So if you start getting a wiff of stupidity from this back out immediately!
template<typename T>
inline void
dll_init_sentinel(T *sentinel){
sentinel->next = sentinel;
sentinel->prev = sentinel;
}
template<typename T>
inline void
dll_insert(T *pos, T *v){
v->next = pos->next;
v->prev = pos;
pos->next = v;
v->next->prev = v;
}
template<typename T>
inline void
dll_remove(T *v){
v->next->prev = v->prev;
v->prev->next = v->next;
}
#define dll_items(it, st) ((it) = (st)->next); ((it) != (st)); ((it) = (it)->next)
// BOTTOM