From c877b57f652dde48243201c5f225df484d2d8289 Mon Sep 17 00:00:00 2001 From: Allen Webster Date: Sun, 3 Apr 2016 14:48:50 -0400 Subject: [PATCH] scrolling system at minimal-suckage --- 4ed_file_view.cpp | 75 +++++++---- 4ed_gui.cpp | 323 +++++++++++++++++++++++++--------------------- 2 files changed, 229 insertions(+), 169 deletions(-) diff --git a/4ed_file_view.cpp b/4ed_file_view.cpp index 5357608f..ea2d9e50 100644 --- a/4ed_file_view.cpp +++ b/4ed_file_view.cpp @@ -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; } } } diff --git a/4ed_gui.cpp b/4ed_gui.cpp index 95bb0a78..92291066 100644 --- a/4ed_gui.cpp +++ b/4ed_gui.cpp @@ -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))