Bring back --with-sys-screenrc configure flag.
[screen-lua.git] / src / list_generic.c
blobe32acf728e62bdef00785a136ab0da71e1e86036
1 /* Copyright (c) 2010
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)
8 * any later version.
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 ****************************************************************
23 #include "config.h"
24 #include "screen.h"
25 #include "list_generic.h"
26 #include "layer.h"
27 #include "extern.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 =
44 ListProcess,
45 ListAbort,
46 ListRedisplayLine,
47 ListClearLine,
48 ListRewrite,
49 ListResize,
50 ListRestore,
51 ListFree
54 /** Returns non-zero on success. */
55 struct ListData *
56 glist_display(struct GenericList *list, const char *name)
58 struct ListData *ldata;
60 if (InitOverlayPage(sizeof(struct ListData), &ListLf, 0))
61 return NULL;
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;
67 flayer->l_mode = 1;
68 flayer->l_x = 0;
69 flayer->l_y = flayer->l_height - 1;
71 return ldata;
74 static void
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--)
81 ldata->top = top;
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))
90 return row;
92 if (dir == 1)
93 row = ldata->root;
94 else
96 /* First, go to the end */
97 if (!start->next)
98 row = start;
99 else
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))
106 break;
108 return row;
111 static void
112 glist_search(char *buf, int len, char *data)
114 struct ListData *ldata = (struct ListData *)data;
115 struct ListRow *row;
117 if (ldata->search)
118 Free(ldata->search);
119 if (len > 0)
120 ldata->search = SaveStr(buf);
121 else
122 return;
124 for (row = ldata->selected; row; row = row->next)
125 if (ldata->list_fn->gl_matchrow(ldata, row, ldata->search))
126 break;
128 if (!row)
129 for (row = ldata->root; row != ldata->selected; row = row->next)
130 if (ldata->list_fn->gl_matchrow(ldata, row, ldata->search))
131 break;
133 if (row == ldata->selected)
134 return;
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;
145 int count = 0;
147 while (*plen > 0)
149 struct ListRow *old;
150 unsigned char ch;
152 if (!flayer->l_mouseevent.start && ldata->list_fn->gl_pinput &&
153 ldata->list_fn->gl_pinput(ldata, ppbuf, plen))
154 continue;
156 ch = **ppbuf;
157 ++*ppbuf;
158 --*plen;
160 if (flayer->l_mouseevent.start)
162 int r = LayProcessMouse(flayer, ch);
163 if (r == -1)
165 LayProcessMouseSwitch(flayer, 0);
166 continue;
168 else
170 if (r)
171 ch = 0222;
172 else
173 continue;
177 if (!ldata->selected)
179 *plen = 0;
180 break;
183 old = ldata->selected;
185 processchar:
186 switch (ch)
188 case ' ':
189 break;
191 case '\r':
192 case '\n':
193 break;
195 case 0220: /* up */
196 case 16: /* ^P */
197 case 'k':
198 if (!ldata->selected->prev) /* There's no where to go */
199 break;
200 ldata->selected = old->prev;
201 break;
203 case 0216: /* down */
204 case 14: /* ^N like emacs */
205 case 'j':
206 if (!ldata->selected->next) /* Nothing to do */
207 break;
208 ldata->selected = old->next;
209 break;
211 case 033: /* escape */
212 case 007: /* ^G */
213 ListAbort();
214 *plen = 0;
215 return;
217 case 0201: /* home */
218 case 0001: /* ^A */
219 ldata->selected = ldata->root;
220 break;
222 case 0205: /* end */
223 case 0005: /* ^E */
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. */
231 break;
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)
239 break;
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)
247 break;
249 case '/': /* start searching */
250 if (ldata->list_fn->gl_matchrow)
252 char *s;
253 Input("Search: ", 80, INP_COOKED, glist_search, (char *)ldata, 0);
254 if ((s = ldata->search))
256 for (; *s; s++)
258 char *ss = s;
259 int n = 1;
260 LayProcess(&ss, &n);
264 break;
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);
271 break;
273 case 'N': /* search prev */
274 if (ldata->list_fn->gl_matchrow && ldata->search)
275 ldata->selected = glist_search_dir(ldata, ldata->selected, -1);
276 break;
278 /* Now, mouse events. */
279 case 0222:
280 if (flayer->l_mouseevent.start)
282 int button = flayer->l_mouseevent.buffer[0];
283 if (button == 'a') /* Scroll down */
284 ch = 'j';
285 else if (button == '`') /* Scroll up */
286 ch = 'k';
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)
293 if (r && r->y == y)
294 ldata->selected = r;
295 ch = 0;
297 else
298 ch = 0;
299 LayProcessMouseSwitch(flayer, 0);
300 if (ch)
301 goto processchar;
303 else
304 LayProcessMouseSwitch(flayer, 1);
305 break;
308 if (old == ldata->selected) /* The selection didn't change */
309 continue;
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);
318 else
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;
324 LaySetCursor();
329 static void ListAbort(void)
331 LAY_CALL_UP(LRefreshAll(flayer, 0));
332 ExitOverlayPage();
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);
341 if (ldata->search)
342 Free(ldata->search);
345 static void ListRedisplayLine(int y, int xs, int xe, int isblank)
347 struct ListData *ldata;
348 ASSERT(flayer);
350 ldata = flayer->l_data;
351 if (y < 0)
353 glist_display_all(ldata);
354 return;
357 if (!isblank)
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);
364 else
366 struct ListRow *row;
367 for (row = ldata->top; row && row->y != -1; row = row->next)
368 if (row->y == y)
370 ldata->list_fn->gl_printrow(ldata, row);
371 break;
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)
383 return EXPENSIVE;
386 static int ListResize (int wi, int he)
388 if (wi < 10 || he < 5)
389 return -1;
391 flayer->l_width = wi;
392 flayer->l_height = he;
393 flayer->l_y = he - 1;
395 return 0;
398 static void ListRestore (void)
400 DefRestore();
403 struct ListRow *
404 glist_add_row(struct ListData *ldata, void *data, struct ListRow *after)
406 struct ListRow *r = calloc(1, sizeof(struct ListRow));
407 r->data = data;
409 if (after)
411 r->next = after->next;
412 r->prev = after;
413 after->next = r;
414 if (r->next)
415 r->next->prev = r;
417 else
419 r->next = ldata->root;
420 if (ldata->root)
421 ldata->root->prev = r;
422 ldata->root = r;
425 return r;
428 void
429 glist_remove_rows(struct ListData *ldata)
431 struct ListRow *row;
432 for (row = ldata->root; row; )
434 struct ListRow *r = row;
435 row = row->next;
436 ldata->list_fn->gl_freerow(ldata, r);
437 free(r);
439 ldata->root = ldata->selected = ldata->top = NULL;
442 void
443 glist_display_all(struct ListData *list)
445 int y;
446 struct ListRow *row;
448 LClearAll(flayer, 0);
450 y = list->list_fn->gl_printheader(list);
452 if (!list->top)
453 list->top = list->root;
454 if (!list->selected)
455 list->selected = list->root;
457 for (row = list->root; row != list->top; row = row->next)
458 row->y = -1;
460 for (row = list->top; row; row = row->next)
462 row->y = y++;
463 if (!list->list_fn->gl_printrow(list, row))
465 row->y = -1;
466 y--;
468 if (y + 1 == flayer->l_height)
469 break;
471 for (; row; row = row->next)
472 row->y = -1;
474 list->list_fn->gl_printfooter(list);
475 if (list->selected && list->selected->y != -1)
476 flayer->l_y = list->selected->y;
477 else
478 flayer->l_y = flayer->l_height - 1;
479 LaySetCursor();
482 void glist_abort(void)
484 ListAbort();