2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3, or (at your option)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program (see the file COPYING); if not, see
17 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
20 ****************************************************************
25 #include "list_generic.h"
29 /* Deals with a generic list display */
31 extern struct layer
*flayer
;
33 static void ListProcess
__P((char **, int *));
34 static void ListAbort
__P((void));
35 static void ListRedisplayLine
__P((int, int, int, int));
36 static void ListClearLine
__P((int, int, int, int));
37 static int ListRewrite
__P((int, int, int, struct mchar
*, int));
38 static int ListResize
__P((int, int));
39 static void ListRestore
__P((void));
40 static void ListFree
__P((void *));
42 struct LayFuncs ListLf
=
54 /** Returns non-zero on success. */
56 glist_display(struct GenericList
*list
, const char *name
)
58 struct ListData
*ldata
;
60 if (InitOverlayPage(sizeof(struct ListData
), &ListLf
, 0))
62 ldata
= flayer
->l_data
;
64 ldata
->name
= name
; /* We do not SaveStr, since the strings should be all static literals */
65 ldata
->list_fn
= list
;
69 flayer
->l_y
= flayer
->l_height
- 1;
75 glist_decide_top(struct ListData
*ldata
)
77 int count
= flayer
->l_height
- 5; /* 2 for header, 1 for footer */
78 struct ListRow
*top
= ldata
->selected
;
79 for (; count
&& top
!= ldata
->root
; top
= top
->prev
, count
--)
84 static struct ListRow
*
85 glist_search_dir(struct ListData
*ldata
, struct ListRow
*start
, int dir
)
87 struct ListRow
*row
= (dir
== 1) ? start
->next
: start
->prev
;
88 for (; row
; row
= (dir
== 1) ? row
->next
: row
->prev
)
89 if (ldata
->list_fn
->gl_matchrow(ldata
, row
, ldata
->search
))
96 /* First, go to the end */
100 for (row
= start
->next
; row
->next
; row
= row
->next
)
104 for (; row
!= start
; row
= (dir
== 1) ? row
->next
: row
->prev
)
105 if (ldata
->list_fn
->gl_matchrow(ldata
, row
, ldata
->search
))
112 glist_search(char *buf
, int len
, char *data
)
114 struct ListData
*ldata
= (struct ListData
*)data
;
120 ldata
->search
= SaveStr(buf
);
124 for (row
= ldata
->selected
; row
; row
= row
->next
)
125 if (ldata
->list_fn
->gl_matchrow(ldata
, row
, ldata
->search
))
129 for (row
= ldata
->root
; row
!= ldata
->selected
; row
= row
->next
)
130 if (ldata
->list_fn
->gl_matchrow(ldata
, row
, ldata
->search
))
133 if (row
== ldata
->selected
)
136 ldata
->selected
= row
;
137 if (ldata
->selected
->y
== -1)
138 glist_decide_top(ldata
);
139 glist_display_all(ldata
);
142 static void ListProcess(char **ppbuf
, int *plen
)
144 struct ListData
*ldata
= flayer
->l_data
;
152 if (!flayer
->l_mouseevent
.start
&& ldata
->list_fn
->gl_pinput
&&
153 ldata
->list_fn
->gl_pinput(ldata
, ppbuf
, plen
))
160 if (flayer
->l_mouseevent
.start
)
162 int r
= LayProcessMouse(flayer
, ch
);
165 LayProcessMouseSwitch(flayer
, 0);
177 if (!ldata
->selected
)
183 old
= ldata
->selected
;
198 if (!ldata
->selected
->prev
) /* There's no where to go */
200 ldata
->selected
= old
->prev
;
203 case 0216: /* down */
204 case 14: /* ^N like emacs */
206 if (!ldata
->selected
->next
) /* Nothing to do */
208 ldata
->selected
= old
->next
;
211 case 033: /* escape */
217 case 0201: /* home */
219 ldata
->selected
= ldata
->root
;
224 while (ldata
->selected
->next
)
225 ldata
->selected
= ldata
->selected
->next
;
226 if (ldata
->selected
->y
!= -1)
228 /* Both old and current selections are on the screen. So we can just
229 * redraw these two affected rows. */
233 case 0004: /* ^D (half-page down) */
234 case 0006: /* page-down, ^F */
235 count
= (flayer
->l_height
- 4) >> (ch
== 0004);
236 for (; ldata
->selected
->next
&& --count
;
237 ldata
->selected
= ldata
->selected
->next
)
241 case 0025: /* ^U (half-page up) */
242 case 0002: /* page-up, ^B */
243 count
= (flayer
->l_height
- 4) >> (ch
== 0025);
244 for (; ldata
->selected
->prev
&& --count
;
245 ldata
->selected
= ldata
->selected
->prev
)
249 case '/': /* start searching */
250 if (ldata
->list_fn
->gl_matchrow
)
253 Input("Search: ", 80, INP_COOKED
, glist_search
, (char *)ldata
, 0);
254 if ((s
= ldata
->search
))
266 /* The following deal with searching. */
268 case 'n': /* search next */
269 if (ldata
->list_fn
->gl_matchrow
&& ldata
->search
)
270 ldata
->selected
= glist_search_dir(ldata
, ldata
->selected
, 1);
273 case 'N': /* search prev */
274 if (ldata
->list_fn
->gl_matchrow
&& ldata
->search
)
275 ldata
->selected
= glist_search_dir(ldata
, ldata
->selected
, -1);
278 /* Now, mouse events. */
280 if (flayer
->l_mouseevent
.start
)
282 int button
= flayer
->l_mouseevent
.buffer
[0];
283 if (button
== 'a') /* Scroll down */
285 else if (button
== '`') /* Scroll up */
287 else if (button
== ' ') /* Left click */
289 int y
= flayer
->l_mouseevent
.buffer
[2];
290 struct ListRow
*r
= ldata
->top
;
291 for (r
= ldata
->top
; r
&& r
->y
!= -1 && r
->y
!= y
; r
= r
->next
)
299 LayProcessMouseSwitch(flayer
, 0);
304 LayProcessMouseSwitch(flayer
, 1);
308 if (old
== ldata
->selected
) /* The selection didn't change */
311 if (ldata
->selected
->y
== -1)
313 /* We need to list all the rows, since we are scrolling down. But first,
314 * find the top of the visible list. */
315 glist_decide_top(ldata
);
316 glist_display_all(ldata
);
320 /* just redisplay the two lines. */
321 ldata
->list_fn
->gl_printrow(ldata
, old
);
322 ldata
->list_fn
->gl_printrow(ldata
, ldata
->selected
);
323 flayer
->l_y
= ldata
->selected
->y
;
329 static void ListAbort(void)
331 LAY_CALL_UP(LRefreshAll(flayer
, 0));
335 static void ListFree(void *d
)
337 struct ListData
*ldata
= d
;
338 glist_remove_rows(ldata
);
339 if (ldata
->list_fn
->gl_free
)
340 ldata
->list_fn
->gl_free(ldata
);
345 static void ListRedisplayLine(int y
, int xs
, int xe
, int isblank
)
347 struct ListData
*ldata
;
350 ldata
= flayer
->l_data
;
353 glist_display_all(ldata
);
358 LClearArea(flayer
, xs
, y
, xe
, y
, 0, 0);
360 if (ldata
->top
&& y
< ldata
->top
->y
)
361 ldata
->list_fn
->gl_printheader(ldata
);
362 else if (y
+ 1 == flayer
->l_height
)
363 ldata
->list_fn
->gl_printfooter(ldata
);
367 for (row
= ldata
->top
; row
&& row
->y
!= -1; row
= row
->next
)
370 ldata
->list_fn
->gl_printrow(ldata
, row
);
376 static void ListClearLine(int y
, int xs
, int xe
, int bce
)
378 DefClearLine(y
, xs
, xe
, bce
);
381 static int ListRewrite(int y
, int xs
, int xe
, struct mchar
*rend
, int doit
)
386 static int ListResize (int wi
, int he
)
388 if (wi
< 10 || he
< 5)
391 flayer
->l_width
= wi
;
392 flayer
->l_height
= he
;
393 flayer
->l_y
= he
- 1;
398 static void ListRestore (void)
404 glist_add_row(struct ListData
*ldata
, void *data
, struct ListRow
*after
)
406 struct ListRow
*r
= calloc(1, sizeof(struct ListRow
));
411 r
->next
= after
->next
;
419 r
->next
= ldata
->root
;
421 ldata
->root
->prev
= r
;
429 glist_remove_rows(struct ListData
*ldata
)
432 for (row
= ldata
->root
; row
; )
434 struct ListRow
*r
= row
;
436 ldata
->list_fn
->gl_freerow(ldata
, r
);
439 ldata
->root
= ldata
->selected
= ldata
->top
= NULL
;
443 glist_display_all(struct ListData
*list
)
448 LClearAll(flayer
, 0);
450 y
= list
->list_fn
->gl_printheader(list
);
453 list
->top
= list
->root
;
455 list
->selected
= list
->root
;
457 for (row
= list
->root
; row
!= list
->top
; row
= row
->next
)
460 for (row
= list
->top
; row
; row
= row
->next
)
463 if (!list
->list_fn
->gl_printrow(list
, row
))
468 if (y
+ 1 == flayer
->l_height
)
471 for (; row
; row
= row
->next
)
474 list
->list_fn
->gl_printfooter(list
);
475 if (list
->selected
&& list
->selected
->y
!= -1)
476 flayer
->l_y
= list
->selected
->y
;
478 flayer
->l_y
= flayer
->l_height
- 1;
482 void glist_abort(void)