diff --git a/include/justui/jframe.h b/include/justui/jframe.h index 323e1fb..f61f335 100644 --- a/include/justui/jframe.h +++ b/include/justui/jframe.h @@ -81,7 +81,11 @@ void jframe_set_visibility_margin(jframe *f, int margin_x, int margin_y); If either dimension of the provided region is larger than the content size of the frame minus the visibility margin, the center of the region will be shown at the center of the view along that direciton. Otherwise, the view - will scroll the minimum amount possible to bring the region into view. */ -void jframe_scroll_to_region(jframe *f, jrect region); + will scroll the minimum amount possible to bring the region into view. + + If clamp is set to false, the frame will allow scrolling beyond current + boundaries, which is helpful as a hack when calling this function while a + layout is occuring. */ +void jframe_scroll_to_region(jframe *f, jrect region, bool clamp); #endif /* _J_JFRAME */ diff --git a/src/jframe.c b/src/jframe.c index 8c1d335..3a65951 100644 --- a/src/jframe.c +++ b/src/jframe.c @@ -140,7 +140,7 @@ void jframe_set_visibility_margin(jframe *f, int margin_x, int margin_y) // Scrolling //--- -void jframe_scroll_to_region(jframe *f, jrect region) +void jframe_scroll_to_region(jframe *f, jrect region, bool do_clamp) { jwidget *child = frame_child(f); if(!child) @@ -180,8 +180,10 @@ void jframe_scroll_to_region(jframe *f, jrect region) f->scroll_y = clamp(f->scroll_y, y2 - vp_y2, y1 - vp_y1); /* Safety clamp */ - f->scroll_x = clamp(f->scroll_x, 0, f->max_scroll_x); - f->scroll_y = clamp(f->scroll_y, 0, f->max_scroll_y); + if(do_clamp) { + f->scroll_x = clamp(f->scroll_x, 0, f->max_scroll_x); + f->scroll_y = clamp(f->scroll_y, 0, f->max_scroll_y); + } f->widget.update = 1; } diff --git a/src/jscrolledlist.c b/src/jscrolledlist.c index e50031c..f835e42 100644 --- a/src/jscrolledlist.c +++ b/src/jscrolledlist.c @@ -21,7 +21,6 @@ jscrolledlist *jscrolledlist_create(void *parent, jwidget_init(&l->widget, jscrolledlist_type_id, parent); jwidget_set_stretch(l, 1, 1, false); - jlayout_set_vbox(l); l->frame = jframe_create(l); jwidget_set_stretch(l->frame, 1, 1, false); @@ -33,31 +32,49 @@ jscrolledlist *jscrolledlist_create(void *parent, return l; } +static void shake_scroll(jscrolledlist *l, bool clamp) +{ + int cursor = jlist_selected_item(l->list); + if(cursor >= 0) { + jrect r = jlist_selected_region(l->list); + jframe_scroll_to_region(l->frame, r, clamp); + } +} + //--- // Polymorphic widget operations //--- +static void jscrolledlist_poly_layout(void *l0) +{ + jscrolledlist *l = l0; + + l->frame->widget.x = 0; + l->frame->widget.y = 0; + l->frame->widget.w = jwidget_content_width(l); + l->frame->widget.h = jwidget_content_height(l); + + shake_scroll(l, false); +} + static bool jscrolledlist_poly_event(void *l0, jevent e) { jscrolledlist *l = l0; - if((e.type == JLIST_SELECTION_MOVED || e.type == JLIST_MODEL_UPDATED) - && e.source == l->list) { - int cursor = jlist_selected_item(l->list); - if(cursor >= 0) { - jrect r = jlist_selected_region(l->list); - jframe_scroll_to_region(l->frame, r); - /* Allow the event to propagate up */ - return false; - } - } + if(e.type == JLIST_SELECTION_MOVED && e.source == l->list) + shake_scroll(l, true); + if(e.type == JLIST_MODEL_UPDATED && e.source == l->list) + shake_scroll(l, true); + + /* Allow the evnts to bubble up */ return false; } /* jscrolledlist type definition */ static jwidget_poly type_jscrolledlist = { .name = "jscrolledlist", + .layout = jscrolledlist_poly_layout, .event = jscrolledlist_poly_event, };