+ return wl->sel;
+}
+
+int tui_list_sel_next(struct tui_widget *w)
+{
+ int nelem, numvis;
+ struct tui_list *wl = (struct tui_list*)w;
+ assert(wl->type == TUI_LIST);
+
+ nelem = darr_size(wl->entries);
+
+ numvis = VISLINES(wl);
+
+ if(wl->sel + 1 >= nelem) {
+ return -1;
+ }
+
+ if(++wl->sel - wl->view_offs >= numvis) {
+ wl->view_offs = wl->sel - numvis + 1;
+ }
+ wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
+ return 0;
+}
+
+int tui_list_sel_prev(struct tui_widget *w)
+{
+ struct tui_list *wl = (struct tui_list*)w;
+ assert(wl->type == TUI_LIST);
+
+ if(wl->sel <= 0) {
+ return -1;
+ }
+ if(--wl->sel < wl->view_offs) {
+ wl->view_offs = wl->sel;
+ }
+ wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
+ return 0;
+}
+
+int tui_list_sel_start(struct tui_widget *w)
+{
+ struct tui_list *wl = (struct tui_list*)w;
+ assert(wl->type == TUI_LIST);
+
+ wl->sel = 0;
+ wl->view_offs = 0;
+ wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
+ return 0;
+}
+
+int tui_list_sel_end(struct tui_widget *w)
+{
+ int nelem, numvis;
+ struct tui_list *wl = (struct tui_list*)w;
+ assert(wl->type == TUI_LIST);
+
+ nelem = darr_size(wl->entries);
+ numvis = VISLINES(wl);
+
+ wl->sel = nelem - 1;
+ wl->view_offs = nelem - numvis;
+ if(wl->view_offs < 0) wl->view_offs = 0;
+ wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);
+ return 0;
+}
+
+void tui_sort_list(struct tui_widget *w, int (*cmpfunc)(const void*, const void*))
+{
+ int nelem;
+ struct tui_list *wl = (struct tui_list*)w;
+ assert(wl->type == TUI_LIST);
+
+ if(!cmpfunc) {
+ cmpfunc = (int (*)(const void*, const void*))strcmp;
+ }
+
+ nelem = darr_size(wl->entries);
+ qsort(wl->entries, nelem, sizeof *wl->entries, cmpfunc);
+
+ wl->dirty = 1;
+ tui_call_callback(w, TUI_ONMODIFY);