More intuitive multi-page browsing
Here is the new multi-page listing functionality I promised in
5db9c2aea1
.
It may look very easy, but getting this to work right wasn't,
unfortunately.
Этот коммит содержится в:
родитель
c68a229e09
Коммит
b7ccf78b90
@ -4,6 +4,7 @@ git - ?
|
||||
- Fixed crash on browsing dirs with a small window size (#2991787)
|
||||
- Fixed buffer overflow when some directories can't be scanned (#2981704)
|
||||
- Improved browsing performance
|
||||
- More intuitive multi-page browsing
|
||||
- Various minor fixes
|
||||
|
||||
1.6 - 2009-10-23
|
||||
|
@ -205,12 +205,10 @@ void browse_draw() {
|
||||
return;
|
||||
|
||||
/* get start position */
|
||||
t = dirlist_get(-1*((winrows)/2));
|
||||
if(t == dirlist_next(NULL))
|
||||
t = NULL;
|
||||
t = dirlist_top(0);
|
||||
|
||||
/* print the list to the screen */
|
||||
for(i=0; (t=dirlist_next(t)) && i<winrows-3; i++) {
|
||||
for(i=0; t && i<winrows-3; t=dirlist_next(t),i++) {
|
||||
browse_draw_item(t, 2+i);
|
||||
/* save the selected row number for later */
|
||||
if(t->flags & FF_BSEL)
|
||||
@ -284,28 +282,34 @@ int browse_key(int ch) {
|
||||
case KEY_UP:
|
||||
case 'k':
|
||||
dirlist_select(dirlist_get(-1));
|
||||
dirlist_top(-1);
|
||||
info_start = 0;
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
case 'j':
|
||||
dirlist_select(dirlist_get(1));
|
||||
dirlist_top(1);
|
||||
info_start = 0;
|
||||
break;
|
||||
case KEY_HOME:
|
||||
dirlist_select(dirlist_next(NULL));
|
||||
dirlist_top(2);
|
||||
info_start = 0;
|
||||
break;
|
||||
case KEY_LL:
|
||||
case KEY_END:
|
||||
dirlist_select(dirlist_get(1<<30));
|
||||
dirlist_top(1);
|
||||
info_start = 0;
|
||||
break;
|
||||
case KEY_PPAGE:
|
||||
dirlist_select(dirlist_get(-1*(winrows-3)));
|
||||
dirlist_top(-1);
|
||||
info_start = 0;
|
||||
break;
|
||||
case KEY_NPAGE:
|
||||
dirlist_select(dirlist_get(winrows-3));
|
||||
dirlist_top(1);
|
||||
info_start = 0;
|
||||
break;
|
||||
|
||||
@ -338,15 +342,19 @@ int browse_key(int ch) {
|
||||
case 10:
|
||||
case KEY_RIGHT:
|
||||
case 'l':
|
||||
if(sel != NULL && sel->sub != NULL)
|
||||
if(sel != NULL && sel->sub != NULL) {
|
||||
dirlist_open(sel->sub);
|
||||
dirlist_top(-3);
|
||||
}
|
||||
info_show = 0;
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
case 'h':
|
||||
case '<':
|
||||
if(sel != NULL && sel->parent->parent != NULL)
|
||||
if(sel != NULL && sel->parent->parent != NULL) {
|
||||
dirlist_open(sel->parent);
|
||||
dirlist_top(-3);
|
||||
}
|
||||
info_show = 0;
|
||||
break;
|
||||
|
||||
|
@ -509,6 +509,7 @@ int calc_process() {
|
||||
freedir(orig);
|
||||
}
|
||||
browse_init(root->sub);
|
||||
dirlist_top(-3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -236,6 +236,7 @@ void delete_process() {
|
||||
else {
|
||||
nextsel->flags |= FF_BSEL;
|
||||
browse_init(nextsel);
|
||||
dirlist_top(-4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +40,7 @@ int dirlist_sort_desc = 1,
|
||||
|
||||
/* private state vars */
|
||||
struct dir dirlist_parent_alloc;
|
||||
struct dir *head, *head_real, *selected;
|
||||
struct dir *head, *head_real, *selected, *top = NULL;
|
||||
|
||||
|
||||
|
||||
@ -282,6 +282,67 @@ void dirlist_select(struct dir *d) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* We need a hint in order to figure out which item should be on top:
|
||||
* 0 = only get the current top, don't set anything
|
||||
* 1 = selected has moved down
|
||||
* -1 = selected has moved up
|
||||
* -2 = selected = first item in the list (faster version of '1')
|
||||
* -3 = top should be considered as invalid (after sorting or opening an other dir)
|
||||
* -4 = an item has been deleted
|
||||
* -5 = hidden flag has been changed
|
||||
*
|
||||
* Actions:
|
||||
* hint = -1 or -4 -> top = selected_is_visible ? top : selected
|
||||
* hint = -2 or -3 -> top = selected-(winrows-3)/2
|
||||
* hint = 1 -> top = selected_is_visible ? top : selected-(winrows-4)
|
||||
* hint = 0 or -5 -> top = selected_is_visible ? top : selected-(winrows-3)/2
|
||||
*
|
||||
* Regardless of the hint, the returned top will always be chosen such that the
|
||||
* selected item is visible.
|
||||
*/
|
||||
struct dir *dirlist_top(int hint) {
|
||||
struct dir *t;
|
||||
int i = winrows-3, visible = 0;
|
||||
|
||||
if(hint == -2 || hint == -3)
|
||||
top = NULL;
|
||||
|
||||
/* check whether the current selected item is within the visible window */
|
||||
if(top) {
|
||||
i = winrows-3;
|
||||
t = dirlist_get(0);
|
||||
while(t && i--) {
|
||||
if(t == top) {
|
||||
visible++;
|
||||
break;
|
||||
}
|
||||
t = dirlist_prev(t);
|
||||
}
|
||||
}
|
||||
|
||||
/* otherwise, get a new top */
|
||||
if(!visible)
|
||||
top = hint == -1 || hint == -4 ? dirlist_get(0) :
|
||||
hint == 1 ? dirlist_get(-1*(winrows-4)) :
|
||||
dirlist_get(-1*(winrows-3)/2);
|
||||
|
||||
/* also make sure that if the list is longer than the window and the last
|
||||
* item is visible, that this last item is also the last on the window */
|
||||
t = top;
|
||||
i = winrows-3;
|
||||
while(t && i--)
|
||||
t = dirlist_next(t);
|
||||
t = top;
|
||||
do {
|
||||
top = t;
|
||||
t = dirlist_prev(t);
|
||||
} while(t && i-- > 0);
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
|
||||
void dirlist_set_sort(int col, int desc, int df) {
|
||||
/* update config */
|
||||
if(col != DL_NOCHANGE)
|
||||
@ -297,11 +358,13 @@ void dirlist_set_sort(int col, int desc, int df) {
|
||||
dirlist_parent->next = head_real;
|
||||
else
|
||||
head = head_real;
|
||||
dirlist_top(-3);
|
||||
}
|
||||
|
||||
|
||||
void dirlist_set_hidden(int hidden) {
|
||||
dirlist_hidden = hidden;
|
||||
dirlist_fixup();
|
||||
dirlist_top(-5);
|
||||
}
|
||||
|
||||
|
@ -49,6 +49,9 @@ struct dir *dirlist_next(struct dir *);
|
||||
* hidden items aren't considered */
|
||||
struct dir *dirlist_get(int i);
|
||||
|
||||
/* Get/set the first visible item in the list on the screen */
|
||||
struct dir *dirlist_top(int hint);
|
||||
|
||||
/* Set selected dir (must be in the currently opened directory, obviously) */
|
||||
void dirlist_select(struct dir *);
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user