scrolling system at minimal-suckage

master
Allen Webster 2016-04-03 14:48:50 -04:00
parent 3b17899d8e
commit c877b57f65
2 changed files with 229 additions and 169 deletions

View File

@ -68,14 +68,14 @@ struct View{
View *next, *prev;
b32 in_use;
i32 id;
Models *models;
Panel *panel;
Command_Map *map;
Editing_File *file;
View_UI showing_ui;
GUI_Target gui_target;
void *gui_mem;
@ -3328,20 +3328,20 @@ interactive_shit(System_Functions *system, View *view, UI_State *state, UI_Layou
append(&s, view->dest);
append(&s, " has unsaved changes, kill it?");
do_label(state, layout, s, 1.f);
i32 id = 0;
if (do_list_option(++id, state, layout, make_lit_string("(Y)es"))){
action = 0;
}
if (do_list_option(++id, state, layout, make_lit_string("(N)o"))){
action = 1;
}
if (do_list_option(++id, state, layout, make_lit_string("(S)ave and kill"))){
action = 2;
}
if (action == -1 && input_stage){
i32 key_count = keys->count;
for (i32 i = 0; i < key_count; ++i){
@ -3355,20 +3355,20 @@ interactive_shit(System_Functions *system, View *view, UI_State *state, UI_Layou
if (action != -1) break;
}
}
if (action != -1){
complete = 1;
view->user_action = action;
}
}break;
}
if (complete){
view->finished = 1;
interactive_view_complete(view);
result= 1;
}
return(result);
}
@ -3504,7 +3504,6 @@ file_step(View *view, i32_Rect region, Input_Summary *user_input, b32 is_active)
if (target_x != scroll_vars.target_x || target_y != scroll_vars.target_y){
view->gui_target.scroll_updated.target_x = target_x;
view->gui_target.scroll_updated.target_y = target_y;
gui_activate_scrolling(&view->gui_target);
}
if (file->state.paste_effect.tick_down > 0){
@ -3594,12 +3593,14 @@ step_file_view(System_Functions *system, View *view, b32 is_active){
}
}
gui_start_scrollable(target, view->showing_ui, view->file_scroll, delta);
gui_begin_scrollable(target, view->showing_ui, view->file_scroll, delta);
if (view->file_scroll.scroll_y < min_target_y) view->file_scroll.scroll_y = min_target_y;
if (view->file_scroll.scroll_y > max_target_y) view->file_scroll.scroll_y = max_target_y;
gui_do_file(target);
gui_end_scrollable(target);
}
gui_end_serial_section(target);
@ -3649,17 +3650,17 @@ step_file_view(System_Functions *system, View *view, b32 is_active){
gui_do_text_field(target, message, text);
gui_get_scroll_vars(target, view->showing_ui, &view->gui_scroll);
gui_start_scrollable(target, view->showing_ui, view->gui_scroll, 9.f * view->font_height);
gui_begin_scrollable(target, view->showing_ui, view->gui_scroll, 9.f * view->font_height);
for (i = 0; i < files->count; ++i, ++info){
append(&full_path, info->filename);
terminate_with_null(&full_path);
file = working_set_contains(system, &models->working_set, full_path);
b8 is_folder = (info->folder != 0);
b8 name_match = (filename_match(front_name, &absolutes, info->filename, 0) != 0);
b8 is_loaded = (file != 0 && file_is_ready(file));
String message = message_nothing;
if (is_loaded){
switch (buffer_get_sync(file)){
@ -3668,7 +3669,7 @@ step_file_view(System_Functions *system, View *view, b32 is_active){
case SYNC_UNSAVED: message = message_unsaved; break;
}
}
if (name_match){
file_option_id.id[0] = (u64)(info);
if (gui_do_file_option(target, file_option_id, info->filename, is_folder, message)){
@ -3677,6 +3678,8 @@ step_file_view(System_Functions *system, View *view, b32 is_active){
}
full_path.size = r;
}
gui_end_scrollable(target);
}break;
}break;
}
@ -3703,6 +3706,7 @@ do_input_file_view(System_Functions *system, Exchange *exchange,
View *view, i32_Rect rect, b32 is_active, Input_Summary *user_input){
i32 result = 0;
b32 is_file_scroll = 0;
GUI_Session gui_session;
GUI_Header *h;
@ -3725,14 +3729,12 @@ do_input_file_view(System_Functions *system, Exchange *exchange,
f32 new_min_y = -(f32)(gui_session.clip_rect.y0 - gui_session.rect.y0);
if (old_min_y != new_min_y){
view->gui_target.scroll_updated.min_y = new_min_y;
gui_activate_scrolling(&view->gui_target);
}
f32 old_max_y = view->gui_target.scroll_updated.max_y;
f32 new_max_y = view_compute_max_target_y(view);
if (old_max_y != new_max_y){
view->gui_target.scroll_updated.max_y = new_max_y;
gui_activate_scrolling(&view->gui_target);
}
if (view->reinit_scrolling){
@ -3741,6 +3743,7 @@ do_input_file_view(System_Functions *system, Exchange *exchange,
if (file_step(view, gui_session.rect, user_input, is_active)){
result = 1;
}
is_file_scroll = 1;
}break;
case guicom_text_field: break;
@ -3765,7 +3768,7 @@ do_input_file_view(System_Functions *system, Exchange *exchange,
target->hover = {0};
}
}break;
case guicom_scrollable_top:
{
GUI_id id = gui_id_scrollbar_top();
@ -3853,6 +3856,23 @@ do_input_file_view(System_Functions *system, Exchange *exchange,
target->hover = {0};
}
}break;
case guicom_scrollable_section_end:
{
if (!is_file_scroll){
f32 old_min_y = view->gui_target.scroll_updated.min_y;
f32 new_min_y = gui_session.suggested_min_y;
if (old_min_y != new_min_y){
view->gui_target.scroll_updated.min_y = new_min_y;
}
f32 old_max_y = view->gui_target.scroll_updated.max_y;
f32 new_max_y = gui_session.suggested_max_y;
if (old_max_y != new_max_y){
view->gui_target.scroll_updated.max_y = new_max_y;
}
}
}break;
}
}
}
@ -3872,7 +3892,6 @@ do_input_file_view(System_Functions *system, Exchange *exchange,
&scroll_vars.scroll_x, &scroll_vars.scroll_y,
(view->id) + 1, is_new_target)){
result = 1;
gui_activate_scrolling(&view->gui_target);
}
scroll_vars.prev_target_x = scroll_vars.target_x;
@ -4318,14 +4337,12 @@ do_render_file_view(System_Functions *system, Exchange *exchange,
case guicom_file:
{
target->push_clip(target, gui_session.clip_rect);
if (view->reinit_scrolling){
view_reinit_scrolling(view);
}
if (file && file_is_ready(file)){
result = draw_file_loaded(view, gui_session.rect, is_active, target);
}
target->pop_clip(target);
}break;
case guicom_text_field:
@ -4412,6 +4429,16 @@ do_render_file_view(System_Functions *system, Exchange *exchange,
draw_rectangle(target, box, back);
draw_rectangle_outline(target, box, outline);
}break;
case guicom_scrollable_section_begin:
{
target->push_clip(target, gui_session.absolute_rect);
}break;
case guicom_scrollable_section_end:
{
target->pop_clip(target);
}break;
}
}
}

View File

@ -123,6 +123,8 @@ enum GUI_Command_Type{
guicom_scrollable_top,
guicom_scrollable_slider,
guicom_scrollable_bottom,
guicom_scrollable_section_begin,
guicom_scrollable_section_end,
};
internal b32
@ -247,16 +249,6 @@ gui_push_string(GUI_Target *target, GUI_Header *h, String s){
gui_push_string(target, h, s, 0);
}
internal void
gui_begin_top_level(GUI_Target *target){
target->push.pos = 0;
}
internal void
gui_end_top_level(GUI_Target *target){
gui_push_simple_command(target, guicom_null);
}
internal void
gui_begin_overlap(GUI_Target *target){
gui_push_simple_command(target, guicom_begin_overlap);
@ -277,6 +269,16 @@ gui_end_serial_section(GUI_Target *target){
gui_push_simple_command(target, guicom_end_serial);
}
internal void
gui_begin_top_level(GUI_Target *target){
target->push.pos = 0;
}
internal void
gui_end_top_level(GUI_Target *target){
gui_push_simple_command(target, guicom_null);
}
internal void
gui_do_top_bar(GUI_Target *target){
gui_push_simple_command(target, guicom_top_bar);
@ -342,15 +344,17 @@ gui_id_scrollbar_bottom(){
internal b32
gui_get_scroll_vars(GUI_Target *target, u32 scroll_id, GUI_Scroll_Vars *vars_out){
b32 result = 0;
if (gui_id_eq(target->active, gui_id_scrollbar()) && target->scroll_id == scroll_id){
if (target->scroll_id == scroll_id){
*vars_out = target->scroll_updated;
result = 1;
if (gui_id_eq(target->active, gui_id_scrollbar())){
result = 1;
}
}
return(result);
}
internal void
gui_start_scrollable(GUI_Target *target, u32 scroll_id, GUI_Scroll_Vars scroll_vars, f32 delta){
gui_begin_scrollable(GUI_Target *target, u32 scroll_id, GUI_Scroll_Vars scroll_vars, f32 delta){
GUI_Header *h;
target->delta = delta;
@ -363,6 +367,12 @@ gui_start_scrollable(GUI_Target *target, u32 scroll_id, GUI_Scroll_Vars scroll_v
gui_push_simple_command(target, guicom_scrollable_top);
gui_push_simple_command(target, guicom_scrollable_slider);
gui_push_simple_command(target, guicom_scrollable_bottom);
gui_push_simple_command(target, guicom_scrollable_section_begin);
}
internal void
gui_end_scrollable(GUI_Target *target){
gui_push_simple_command(target, guicom_scrollable_section_end);
}
internal void
@ -379,6 +389,10 @@ struct GUI_Session{
i32_Rect full_rect;
i32_Rect clip_rect;
i32_Rect rect;
i32_Rect absolute_rect;
f32 suggested_min_y;
f32 suggested_max_y;
i32 line_height;
i32 scroll_bar_w;
@ -483,6 +497,7 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h){
GUI_Section *prev_section = 0;
GUI_Section *end_section = 0;
b32 give_to_user = 0;
b32 always_give_to_user = 0;
i32_Rect rect = {0};
i32 y = 0;
i32 end_v = -1;
@ -494,137 +509,151 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h){
y = section->v;
if (!session->is_scrollable) scroll_v = 0;
if (y - scroll_v < session->full_rect.y1){
switch (h->type){
case guicom_null: Assert(0); break;
case guicom_begin_overlap:
++session->t;
Assert(session->t < ArrayCount(session->sections));
new_section = &session->sections[session->t];
new_section->overlapped = 1;
new_section->v = y;
new_section->max_v = y;
break;
case guicom_end_overlap:
Assert(session->t > 0);
Assert(section->overlapped);
prev_section = &session->sections[--session->t];
end_v = section->max_v;
end_section = prev_section;
break;
case guicom_begin_serial:
++session->t;
Assert(session->t < ArrayCount(session->sections));
new_section = &session->sections[session->t];
new_section->overlapped = 0;
new_section->v = y;
new_section->max_v = y;
break;
case guicom_end_serial:
Assert(session->t > 0);
Assert(!section->overlapped);
prev_section = &session->sections[--session->t];
end_v = section->max_v;
end_section = prev_section;
break;
case guicom_top_bar:
give_to_user = 1;
rect = gui_layout_fixed_h(session, y, session->line_height + 2);
end_v = rect.y1;
end_section = section;
break;
case guicom_file:
give_to_user = 1;
rect = gui_layout_top_bottom(session, y, session->full_rect.y1);
end_v = rect.y1;
end_section = section;
scroll_v = 0;
break;
case guicom_text_field:
give_to_user = 1;
rect = gui_layout_fixed_h(session, y, session->line_height + 2);
end_v = rect.y1;
end_section = section;
break;
case guicom_file_option:
give_to_user = 1;
rect = gui_layout_fixed_h(session, y, session->line_height * 2);
end_v = rect.y1;
end_section = section;
break;
case guicom_scrollable:
Assert(session->is_scrollable == 0);
Assert(!section->overlapped);
give_to_user = 1;
rect.x1 = session->full_rect.x1;
rect.x0 = rect.x1 - session->scroll_bar_w;
rect.y0 = y;
rect.y1 = session->full_rect.y1;
session->scroll_rect = rect;
session->is_scrollable = 1;
{
i32_Rect scrollable_rect;
scrollable_rect.x0 = session->full_rect.x0;
scrollable_rect.x1 = rect.x0;
scrollable_rect.y0 = rect.y0;
scrollable_rect.y1 = rect.y1;
target->scroll_updated.region = scrollable_rect;
}
break;
case guicom_scrollable_top:
Assert(session->is_scrollable);
Assert(!section->overlapped);
give_to_user = 1;
gui_scrollbar_top(session->scroll_rect, &rect);
scroll_v = 0;
break;
case guicom_scrollable_slider:
Assert(session->is_scrollable);
Assert(!section->overlapped);
give_to_user = 1;
lerp_space_scroll_v = unlerp(
(f32)target->scroll_original.min_y, (f32)target->scroll_original.target_y, (f32)target->scroll_original.max_y);
gui_scrollbar_slider(session->scroll_rect, &rect, lerp_space_scroll_v, &session->scroll_top, &session->scroll_bottom);
scroll_v = 0;
break;
case guicom_scrollable_bottom:
Assert(session->is_scrollable);
Assert(!section->overlapped);
give_to_user = 1;
gui_scrollbar_bottom(session->scroll_rect, &rect);
scroll_v = 0;
break;
switch (h->type){
case guicom_null: Assert(0); break;
case guicom_begin_overlap:
++session->t;
Assert(session->t < ArrayCount(session->sections));
new_section = &session->sections[session->t];
new_section->overlapped = 1;
new_section->v = y;
new_section->max_v = y;
break;
case guicom_end_overlap:
Assert(session->t > 0);
Assert(section->overlapped);
prev_section = &session->sections[--session->t];
end_v = section->max_v;
end_section = prev_section;
break;
case guicom_begin_serial:
++session->t;
Assert(session->t < ArrayCount(session->sections));
new_section = &session->sections[session->t];
new_section->overlapped = 0;
new_section->v = y;
new_section->max_v = y;
break;
case guicom_end_serial:
Assert(session->t > 0);
Assert(!section->overlapped);
prev_section = &session->sections[--session->t];
end_v = section->max_v;
end_section = prev_section;
break;
case guicom_top_bar:
give_to_user = 1;
rect = gui_layout_fixed_h(session, y, session->line_height + 2);
end_v = rect.y1;
end_section = section;
break;
case guicom_file:
give_to_user = 1;
rect = gui_layout_top_bottom(session, y, session->full_rect.y1);
end_v = rect.y1;
end_section = section;
scroll_v = 0;
break;
case guicom_text_field:
give_to_user = 1;
rect = gui_layout_fixed_h(session, y, session->line_height + 2);
end_v = rect.y1;
end_section = section;
break;
case guicom_file_option:
give_to_user = 1;
rect = gui_layout_fixed_h(session, y, session->line_height * 2);
end_v = rect.y1;
end_section = section;
break;
case guicom_scrollable:
Assert(session->is_scrollable == 0);
Assert(!section->overlapped);
give_to_user = 1;
rect.x1 = session->full_rect.x1;
rect.x0 = rect.x1 - session->scroll_bar_w;
rect.y0 = y;
rect.y1 = session->full_rect.y1;
session->scroll_rect = rect;
session->is_scrollable = 1;
{
i32_Rect scrollable_rect;
scrollable_rect.x0 = session->full_rect.x0;
scrollable_rect.x1 = rect.x0;
scrollable_rect.y0 = rect.y0;
scrollable_rect.y1 = rect.y1;
target->scroll_updated.region = scrollable_rect;
}
if (give_to_user){
GUI_Section *section = session->sections;
i32 max_v = 0;
i32 i = 0;
for (i = 0; i <= session->t; ++i, ++section){
if (section->overlapped){
max_v = Max(max_v, section->max_v);
}
break;
case guicom_scrollable_top:
Assert(session->is_scrollable);
Assert(!section->overlapped);
give_to_user = 1;
gui_scrollbar_top(session->scroll_rect, &rect);
scroll_v = 0;
break;
case guicom_scrollable_slider:
Assert(session->is_scrollable);
Assert(!section->overlapped);
give_to_user = 1;
lerp_space_scroll_v = unlerp(
(f32)target->scroll_original.min_y, (f32)target->scroll_original.target_y, (f32)target->scroll_original.max_y);
gui_scrollbar_slider(session->scroll_rect, &rect, lerp_space_scroll_v, &session->scroll_top, &session->scroll_bottom);
scroll_v = 0;
break;
case guicom_scrollable_bottom:
Assert(session->is_scrollable);
Assert(!section->overlapped);
give_to_user = 1;
gui_scrollbar_bottom(session->scroll_rect, &rect);
scroll_v = 0;
break;
case guicom_scrollable_section_begin:
always_give_to_user = 1;
session->suggested_min_y = -(f32)(session->clip_rect.y0 - session->rect.y0);
session->suggested_max_y = (f32)(session->absolute_rect.y1 - session->full_rect.y1 * .5f);
rect = gui_layout_top_bottom(session, y, session->full_rect.y1);
end_v = rect.y1;
break;
case guicom_scrollable_section_end:
always_give_to_user = 1;
break;
}
{
GUI_Section *section = session->sections;
i32 max_v = 0;
i32 i = 0;
for (i = 0; i <= session->t; ++i, ++section){
if (section->overlapped){
max_v = Max(max_v, section->max_v);
}
}
session->absolute_rect = rect;
if (give_to_user){
rect.y0 -= scroll_v;
rect.y1 -= scroll_v;
if (rect.y1 > session->full_rect.y0){
session->rect = rect;
@ -637,15 +666,19 @@ gui_interpret(GUI_Target *target, GUI_Session *session, GUI_Header *h){
}
else{
give_to_user = 0;
}
}
if (end_section){
gui_section_end_item(end_section, end_v);
}
}
}
return(give_to_user);
if (end_section){
gui_section_end_item(end_section, end_v);
}
if (y - scroll_v >= session->full_rect.y1){
give_to_user = 0;
}
return(give_to_user || always_give_to_user);
}
#define NextHeader(h) ((GUI_Header*)((char*)(h) + (h)->size))