#ifndef WH_LIST_H_d192002c_ #define WH_LIST_H_d192002c_ /* * List abstraction. * * A list consists of a list of items, each of which takes up one or * more screen lines. They can be filtered for display (potentially * suppressing some subset of the items) and are displayed in the * order induced by a user-supplied comparison function. * * When displayed, usually, one item of a list is highlighted; this is * the "current" item. The highlight can be moved by the user. * Changing the sort order does not change which item is highlighted, * though of course it can change where the highlighted item falls in * the display order. * * Lists can also be run in a no-highlight mode, in which case no item * is highlighted and all the list provides is scrolling. * * By default, a list is in highlight mode; until a call to one of the * movement calls (list_set_hl_*, list_move_highlight, or * list_scroll) is made, the first line will be highlighted even if * the item that corresponds to changes (as items are added). (But * movement calls when the list is empty do not take the list out of * "always highlight first line" mode.) * * Lists can optionally have a scrollbarish display indicating where * the displayed portion falls in what's available. This is * controlled with list_set_scrollbar (qv). (If the scrollbar line * count isn't smaller than the screen line count, the scrollbar is * suppressed even if it would otherwise be displayed.) * * Each item has an `index', a small integer which is set at the time * that item is added to the list and never changed unless the item is * removed (at this writing the only ways to remove any items are to * clear or destroy the list). * * An item's display takes the form of one or more screen lines, * rendered by a callback. * * An item is represented in the API by a void *. * * All callbacks take, as their first argument, a void * which is * opaque to the list package. When a callback's argument list is * described herein, it is the arguments after the opaque cookie that * are being described. * * The LIST type is opaque to callers of this package. */ typedef struct list LIST; /* * Create and return a new LIST. * * new_list(v,f,c,l,r,p,e) * * Note that, as mentioned above, all callbacks take a void * cookie as * their first argument. Only second-and-later arguments are * discussed below. * * v is the callback cookie. * * f is the filter function; it is passed a list item and returns true * if that item should be displayed or false if not. * * c is the sort-order comparison function. c(x,y) returns <0 if x * should come before y, >0 if x should come after y, or 0 if it * doesn't matter which comes first (for the sake of stable display, * it preferably should not return zero if x!=y). * * l is the display-line-count function. It returns the number of * display lines taken up by this item. It is an error for this * function to return a number less than 1. * * r renders a line. It is called with the line object, the relative * line number, the screen line number, and flags. The render * function is expected to implement whatever rendering is appropriate * for the line; typically it will be mvprintw + clrtoeol or the like. * * The relative line number is 0 to render the object's first (or only) * line, 1 for the second, etc; this number can be as high as one less * than the number returned by the line-count function. The screen * line number has already had the offset implied by list_render's * second argument applied to it (eg, list_render(l,3) will pass 3 as * the lowest screen line number). The flags bitmask can include: * LIST_HIGHLIGHTED * Set iff this line is to be highlighted. (Never set if * the list is in no-highlight mode.) * clrtoeol() or similar, when appropriate, must be done by the render * function. * * p prints debugging information. It is called with the line object * and a (stdio) FILE *; it is expected to print a short rendition of * the object, appropriate for debugging output, to the FILE *. This * is never called unless debugging is on (see list_set_debug()). * * e is passed as the item pointer to the render function when * rendering a line that is not part of the list (eg, a list of four * items, each occupying one line, when told to render in a ten-line * area, will do this for six screen lines). e is also opaque to the * list package. * * Any of these pointers may be nil here, but other calls, except for * the set-functions calls, produce undefined behaviour if the * functions haven't been set by then. (And, of course, the opaque * pointers, the cookie and empty-item pointers, are opaque to the * list package and thus may be nil whenever the caller deems that * appropriate.) */ extern LIST *list_new( void *, // callback cookie int (*)(void *, void *), // filter int (*)(void *, void *, void *), // sort comparison int (*)(void *, void *), // display line count void (*)(void *, void *, unsigned int, // render a line unsigned int, unsigned int), #define LIST_HIGHLIGHTED 0x00000001 void (*)(void *, void *, FILE *), // debug-print a line void * // empty-line item ); /* * Set the callback functions or opaque pointers for a list. These * just replace the corresponding things specified when the list was * created. * * Setting the function to what it currently is with one of the *_set_* * functions does nothing at all. Actually *changing* the function * causes the relevant portion(s) of the list's internal data * structures to be recomputed. The *_change_* functions are the same * except that they always provoke recomputation, even if the new * function is the same as the old. (This is suitable if, for * example, your compare function depends on some state in the cookie * to determine its sort order, and you've changed that state.) * * You can pass a nil function pointer to the *_change_* functions to * force a recomputation without actually changing the function. */ extern void list_set_cookie(LIST *, void *); extern void list_set_filter(LIST *, int (*)(void *, void *)); extern void list_change_filter(LIST *, int (*)(void *, void *)); extern void list_set_compare(LIST *, int (*)(void *, void *, void *)); extern void list_change_compare(LIST *, int (*)(void *, void *, void *)); extern void list_set_linecount(LIST *, int (*)(void *, void *)); extern void list_change_linecount(LIST *, int (*)(void *, void *)); extern void list_set_render(LIST *, void (*)(void *, void *, unsigned int, unsigned int, unsigned int)); extern void list_set_empty_item(LIST *, void *); /* * Clear a list. The non-_cb version does nothing with any entry * pointers that may be present; the _cb version calls the callback * for each of them. (As usual, the callback gets the cookie as its * first argument.) Nothing is promised about what order the items * have their callback calls made. */ extern void list_clear(LIST *); extern void list_clear_cb(LIST *, void (*)(void *, void *)); /* * Destroy a list. The list effectively has list_clear() called on it * first. (If you want a callback, a la list_clear_cb(), then call * that before calling list_destroy().) * * The LIST * goes invalid at some point during this function's * execution; it must not be used after that. */ extern void list_destroy(LIST *); /* * Add an item to a list. The return value is the item's index. */ extern int list_add1(LIST *, void *); /* * Add items to a list. The items are passed as an array-and-length. * The vector of ints has the same size and is used to return the * items' indices, with, of course, item vector [i]'s index being * returned in index vector [i]. */ extern void list_addn(LIST *, void * const *, int, int *); /* * Set how many display lines a list has available to it. * * It is an error for the line count to be <2. * * This must be called before list_render can work. */ extern void list_set_lines(LIST *, int); /* * Return the number of display lines the list would want in order to * display all its items; to put it another way, return the number of * lines the list would occupy if it had an infinite number of screen * lines available to it. * * The return value is not necessarily correct unless list_update or * list_render has been called since the last relevant change to the * list. */ extern int list_lines_wanted(LIST *); /* * Return which line is currently at top-of-screen, as a number from 0 * through list_lines_wanted()-1. * * If the list is empty, the returned value is 0. */ extern int list_cur_top(LIST *); /* * Return which line is highlighted, as a number from 0 upwards, or -1 * if the list is in no-highlight mode. 0 is the topmost line, 1 is * the line below that, etc. * * If the list is empty, the returned value is 0. */ extern int list_cur_hl_line(LIST *); /* * Return the item corresponding to the highlighted line, as an item * pointer. If the list is empty, the returned value is nil. It is * an error to call this on a list which is in no-highlight mode. If * an item renders as multiple lines, that item is returned whenever * any of those lines is highlighted. */ extern void *list_item_hl_ptr(LIST *); /* * Return the item corresponding to the highlighted line, as an item * index. If the list is empty, the returned value is -1. This is * otherwise identical to list_item_hl_ptr. */ extern int list_item_hl_inx(LIST *); /* * Set which item is highlighted. The argument is a line number. * Passing a number >= the number of screen lines (list_lines_wanted's * return value) will highlight the last line; passing a number < 0 * will highlight the first line. * * If the list is in no-highlight mode, this puts the list in highlight * mode. If the list is empty, it does nothing else. */ extern void list_set_hl_line(LIST *, int); /* * Set which item is highlighted. The second argument is an item * index; the third argument is a line within that item, ranging from * 0 up to one less than what the list's linecount function returns * for that item. It is an error for the item index to be >= the * number of items the list has or < 0, or for the line-within-item to * be out of range for the item. (Thus, there can be no valid call to * this if the list is empty.) */ extern void list_set_hl_inx(LIST *, int, int); /* * Put the list in no-highlight mode. (To get it out of no-highlight * mode, call list_set_highlight().) */ extern void list_set_no_highlight(LIST *); /* * Move the highlight. * * If the list is in highlight mode, the argument is, effectively, * added to the highlighted line number, except that it is limited to * the range from 0 through one less than what list_lines_wanted would * return. Moving the highlight can cause the list to scroll. * * If the list is in no-highlight mode, the argument is, effectively, * added to the top-of-screen line number, scrolling the list, except * that it is limited to the screen lines available. * * Thus, for example, if j moves "down", it is appropriate to respond * to it by calling list_move_highlight(list,1), regardless of whether * the list is a no-highlight list or not. * * If the list is empty, this does nothing. */ extern void list_move_highlight(LIST *, int); /* * Move the highlight. This is conceptually equivalent to * list_move_highlight with negative infinity as argument. */ extern void list_move_highlight_first(LIST *); /* * Move the highlight. This is conceptually equivalent to * list_move_highlight with positive infinity as argument. */ extern void list_move_highlight_last(LIST *); /* * Control the list's scrollbar setting. * * If the function pointer is nil, the integer is ignored, and the list * is put in no-scrollbar mode. (This is the default mode.) * * If the function pointer is non-nil, it is called during list_render * to render the scrollbar. The integer is the number of lines that * should be subtracted from the line count to account for the * scrollbar, if it's displayed. The first argument to the callback * is the list's callback cookie, as for other callbacks. If the * whole list is visible, ie, if the scrollbar should not be * displayed, the other arguments are -1, -1, -1. Otherwise, the * other arguments are n1, n2, n3, where n1 is the number of lines not * visible off the top of the display, n2 is the number of lines * displayed, and n3 is the number of lines not visible off the bottom * of the display. */ extern void list_set_scrollbar(LIST *, void (*)(void *, int, int, int), int); /* * Scroll the list. * * The list is scrolled by as many lines as the argument specifies, * where positive means scrolling down (hiding lines at the top, * introducing new lines at the bottom) and negative means scrolling * the other way. If the list is in no-highlight mode, this is * operationally equivalent to list_move_highlight. But, in highlight * mode, scrolling the list can cause the highlighted line to change. * * If the list is empty, this does nothing. */ extern void list_scroll(LIST *, int); /* * Update the list. This does everything list_render() does except * actually calling the render function to draw the lines. * * After this, inquiries such as list_lines_wanted() will return values * corresponding to the current state of the list. * * Calling list_update is cheap if nothing relevant has been done to * the list since the last update or render. */ extern void list_update(LIST *); /* * Redraw the list. * * This calls the list's render function for all lines on the screen. * The second argument is the screen line number to be used for the * first of the list's lines. For example, if in a 20-line window we * want to use all but the top two and bottom three lines, the * appropriate calls would be * list_set_lines(list,15); * list_render(list,2); * The list package would then, among others, move(2,0) and call the * render function for whichever line should be at the top of the 15 * lines in use. Nothing is promised about what order the screen * lines are redrawn in. * * It is possible for a list in highlight mode to not highlight any * lines. This happens when the list has no entries. */ extern void list_render(LIST *, int); /* * Return the debug setting: false if off, true if on. */ extern int list_get_debug(void); /* * Set the debug setting: false for no debugging, true for debugging. * The default, of course, is no debugging. */ extern void list_set_debug(int); /* * Turn on debugging (like list_set_debug(1)) but also set the FILE * * debugging output is to be sent to. */ extern void list_debug_to(FILE *); #endif