Add a generic list box implementation

This adds a very generic list box implementation. List boxes with items
of different heights are supported. Two callback functions to determine
the height of every single item and to draw a specific item are used.

Signed-off-by: Lukas Fleischer <calcurse@cryptocrack.de>
This commit is contained in:
Lukas Fleischer 2014-05-13 20:30:02 +02:00
parent 7184da0fa3
commit 27b39a56ef
3 changed files with 165 additions and 0 deletions

View File

@ -23,6 +23,7 @@ calcurse_SOURCES = \
ical.c \
io.c \
keys.c \
listbox.c \
llist.c \
note.c \
notify.c \

View File

@ -515,6 +515,20 @@ struct scrollwin {
const char *label;
};
/* Generic list box structure. */
typedef int (*listbox_fn_item_height_t) (int, void *);
typedef void (*listbox_fn_draw_item_t) (int, WINDOW *, int, int, void *);
struct listbox {
struct scrollwin sw;
unsigned item_count;
unsigned item_sel;
listbox_fn_item_height_t fn_height;
unsigned *ch;
listbox_fn_draw_item_t fn_draw;
void *cb_data;
};
/* Pad structure to handle scrolling. */
struct pad {
int width;
@ -802,6 +816,18 @@ void keys_save_bindings(FILE *);
int keys_check_missing_bindings(void);
void keys_fill_missing(void);
/* listbox.c */
void listbox_init(struct listbox *, int, int, int, int, const char *, listbox_fn_item_height_t, listbox_fn_draw_item_t);
void listbox_delete(struct listbox *);
void listbox_resize(struct listbox *, int, int, int, int);
void listbox_set_cb_data(struct listbox *, void *);
void listbox_load_items(struct listbox *, int);
void listbox_draw_deco(struct listbox *);
void listbox_display(struct listbox *);
int listbox_get_sel(struct listbox *);
void listbox_set_sel(struct listbox *, unsigned);
void listbox_sel_move(struct listbox *, int);
/* mem.c */
void *xmalloc(size_t);
void *xcalloc(size_t, size_t);

138
src/listbox.c Normal file
View File

@ -0,0 +1,138 @@
/*
* Calcurse - text-based organizer
*
* Copyright (c) 2004-2014 calcurse Development Team <misc@calcurse.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the
* following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Send your feedback or comments to : misc@calcurse.org
* Calcurse home page : http://calcurse.org
*
*/
#include "calcurse.h"
void listbox_init(struct listbox *lb, int y, int x, int h, int w,
const char *label, listbox_fn_item_height_t fn_height,
listbox_fn_draw_item_t fn_draw)
{
EXIT_IF(lb == NULL, "null pointer");
wins_scrollwin_init(&(lb->sw), y, x, h, w, label);
lb->item_count = lb->item_sel = 0;
lb->fn_height = fn_height;
lb->ch = NULL;
lb->fn_draw = fn_draw;
lb->cb_data = NULL;
}
void listbox_delete(struct listbox *lb)
{
EXIT_IF(lb == NULL, "null pointer");
wins_scrollwin_delete(&(lb->sw));
free(lb->ch);
}
void listbox_resize(struct listbox *lb, int y, int x, int h, int w)
{
EXIT_IF(lb == NULL, "null pointer");
wins_scrollwin_resize(&(lb->sw), y, x, h, w);
wins_scrollwin_ensure_visible(&(lb->sw), lb->ch[lb->item_sel]);
wins_scrollwin_ensure_visible(&(lb->sw), lb->ch[lb->item_sel + 1] - 1);
}
void listbox_set_cb_data(struct listbox *lb, void *cb_data)
{
lb->cb_data = cb_data;
}
void listbox_load_items(struct listbox *lb, int item_count)
{
int i, ch;
lb->item_count = item_count;
if (lb->item_sel >= item_count)
lb->item_sel = item_count - 1;
free(lb->ch);
lb->ch = xmalloc((item_count + 1) * sizeof(unsigned));
for (i = 0, ch = 0; i < item_count; i++) {
lb->ch[i] = ch;
ch += lb->fn_height(i, lb->cb_data);
}
lb->ch[item_count] = ch;
wins_scrollwin_set_linecount(&(lb->sw), ch);
}
void listbox_draw_deco(struct listbox *lb)
{
wins_scrollwin_draw_deco(&(lb->sw));
}
void listbox_display(struct listbox *lb)
{
int i;
werase(lb->sw.inner);
for (i = 0; i < lb->item_count; i++) {
int is_sel = (i == lb->item_sel);
lb->fn_draw(i, lb->sw.inner, lb->ch[i], is_sel, lb->cb_data);
}
wins_scrollwin_display(&(lb->sw));
}
int listbox_get_sel(struct listbox *lb)
{
return lb->item_sel;
}
void listbox_set_sel(struct listbox *lb, unsigned pos)
{
lb->item_sel = pos;
wins_scrollwin_ensure_visible(&(lb->sw), lb->ch[lb->item_sel]);
wins_scrollwin_ensure_visible(&(lb->sw), lb->ch[lb->item_sel + 1] - 1);
}
void listbox_sel_move(struct listbox *lb, int delta)
{
if (lb->item_count == 0)
return;
if (delta < 0 && lb->item_sel < -delta)
lb->item_sel = 0;
else if (delta > 0 && lb->item_sel + delta >= lb->item_count)
lb->item_sel = lb->item_count - 1;
else
lb->item_sel += delta;
wins_scrollwin_ensure_visible(&(lb->sw), lb->ch[lb->item_sel]);
wins_scrollwin_ensure_visible(&(lb->sw), lb->ch[lb->item_sel + 1] - 1);
}