HelenOS sources
This source file includes following definitions.
- ui_list_create
- ui_list_destroy
- ui_list_set_cb
- ui_list_get_cb_arg
- ui_list_entry_height
- ui_list_entry_paint
- ui_list_paint
- ui_list_kbd_event
- ui_list_pos_event
- ui_list_ctl
- ui_list_set_rect
- ui_list_page_size
- ui_list_inside_rect
- ui_list_scrollbar_rect
- ui_list_scrollbar_pos
- ui_list_scrollbar_update
- ui_list_is_active
- ui_list_activate
- ui_list_deactivate
- ui_list_entry_attr_init
- ui_list_ctl_destroy
- ui_list_ctl_paint
- ui_list_ctl_kbd_event
- ui_list_ctl_pos_event
- ui_list_entry_append
- ui_list_entry_move_up
- ui_list_entry_move_down
- ui_list_entry_destroy
- ui_list_entry_delete
- ui_list_entry_get_arg
- ui_list_entry_get_list
- ui_list_entry_set_caption
- ui_list_clear_entries
- ui_list_entries_cnt
- ui_list_first
- ui_list_last
- ui_list_next
- ui_list_prev
- ui_list_page_nth_entry
- ui_list_get_cursor
- ui_list_set_cursor
- ui_list_cursor_move
- ui_list_cursor_up
- ui_list_cursor_down
- ui_list_cursor_top
- ui_list_cursor_bottom
- ui_list_page_up
- ui_list_page_down
- ui_list_scroll_up
- ui_list_scroll_down
- ui_list_scroll_page_up
- ui_list_scroll_page_down
- ui_list_scroll_pos
- ui_list_activate_req
- ui_list_sort
- ui_list_entry_get_idx
- ui_list_cursor_center
- ui_list_selected
- ui_list_scrollbar_up
- ui_list_scrollbar_down
- ui_list_scrollbar_page_up
- ui_list_scrollbar_page_down
- ui_list_scrollbar_moved
- ui_list_entry_ptr_cmp
#include <errno.h>
#include <gfx/render.h>
#include <gfx/text.h>
#include <stdlib.h>
#include <str.h>
#include <ui/control.h>
#include <ui/list.h>
#include <ui/paint.h>
#include <ui/resource.h>
#include <ui/scrollbar.h>
#include "../private/list.h"
#include "../private/resource.h"
static void ui_list_ctl_destroy(void *);
static errno_t ui_list_ctl_paint(void *);
static ui_evclaim_t ui_list_ctl_kbd_event(void *, kbd_event_t *);
static ui_evclaim_t ui_list_ctl_pos_event(void *, pos_event_t *);
ui_control_ops_t ui_list_ctl_ops = {
.destroy = ui_list_ctl_destroy,
.paint = ui_list_ctl_paint,
.kbd_event = ui_list_ctl_kbd_event,
.pos_event = ui_list_ctl_pos_event
};
enum {
list_entry_hpad = 2,
list_entry_vpad = 2,
list_entry_hpad_text = 1,
list_entry_vpad_text = 0,
};
static void ui_list_scrollbar_up(ui_scrollbar_t *, void *);
static void ui_list_scrollbar_down(ui_scrollbar_t *, void *);
static void ui_list_scrollbar_page_up(ui_scrollbar_t *, void *);
static void ui_list_scrollbar_page_down(ui_scrollbar_t *, void *);
static void ui_list_scrollbar_moved(ui_scrollbar_t *, void *, gfx_coord_t);
static ui_scrollbar_cb_t ui_list_scrollbar_cb = {
.up = ui_list_scrollbar_up,
.down = ui_list_scrollbar_down,
.page_up = ui_list_scrollbar_page_up,
.page_down = ui_list_scrollbar_page_down,
.moved = ui_list_scrollbar_moved
};
errno_t ui_list_create(ui_window_t *window, bool active,
ui_list_t **rlist)
{
ui_list_t *list;
errno_t rc;
list = calloc(1, sizeof(ui_list_t));
if (list == NULL)
return ENOMEM;
rc = ui_control_new(&ui_list_ctl_ops, (void *)list,
&list->control);
if (rc != EOK) {
free(list);
return rc;
}
rc = ui_scrollbar_create(ui_window_get_ui(window), window,
ui_sbd_vert, &list->scrollbar);
if (rc != EOK)
goto error;
ui_scrollbar_set_cb(list->scrollbar, &ui_list_scrollbar_cb,
(void *) list);
list->window = window;
list_initialize(&list->entries);
list->entries_cnt = 0;
list->active = active;
*rlist = list;
return EOK;
error:
ui_control_delete(list->control);
free(list);
return rc;
}
void ui_list_destroy(ui_list_t *list)
{
ui_list_clear_entries(list);
ui_control_delete(list->control);
free(list);
}
void ui_list_set_cb(ui_list_t *list, ui_list_cb_t *cb, void *arg)
{
list->cb = cb;
list->cb_arg = arg;
}
void *ui_list_get_cb_arg(ui_list_t *list)
{
return list->cb_arg;
}
gfx_coord_t ui_list_entry_height(ui_list_t *list)
{
ui_resource_t *res;
gfx_font_metrics_t metrics;
gfx_coord_t height;
gfx_coord_t vpad;
res = ui_window_get_res(list->window);
if (res->textmode) {
vpad = list_entry_vpad_text;
} else {
vpad = list_entry_vpad;
}
gfx_font_get_metrics(res->font, &metrics);
height = metrics.ascent + metrics.descent + 1;
return height + 2 * vpad;
}
errno_t ui_list_entry_paint(ui_list_entry_t *entry, size_t entry_idx)
{
ui_list_t *list = entry->list;
gfx_context_t *gc = ui_window_get_gc(list->window);
ui_resource_t *res = ui_window_get_res(list->window);
gfx_font_t *font = ui_resource_get_font(res);
gfx_text_fmt_t fmt;
gfx_coord2_t pos;
gfx_rect_t rect;
gfx_rect_t lrect;
gfx_rect_t crect;
gfx_color_t *bgcolor;
gfx_coord_t hpad, vpad;
gfx_coord_t line_height;
size_t rows;
errno_t rc;
line_height = ui_list_entry_height(list);
ui_list_inside_rect(entry->list, &lrect);
gfx_text_fmt_init(&fmt);
fmt.font = font;
rows = ui_list_page_size(list) + 1;
if (entry_idx < list->page_idx ||
entry_idx >= list->page_idx + rows)
return EOK;
if (res->textmode) {
hpad = list_entry_hpad_text;
vpad = list_entry_vpad_text;
} else {
hpad = list_entry_hpad;
vpad = list_entry_vpad;
}
pos.x = lrect.p0.x;
pos.y = lrect.p0.y + line_height * (entry_idx - list->page_idx);
if (entry == list->cursor && list->active) {
fmt.color = res->entry_sel_text_fg_color;
bgcolor = res->entry_sel_text_bg_color;
} else {
if (entry->color != NULL)
fmt.color = entry->color;
else
fmt.color = res->entry_fg_color;
if (entry->bgcolor != NULL)
bgcolor = entry->bgcolor;
else
bgcolor = res->entry_bg_color;
}
rect.p0 = pos;
rect.p1.x = lrect.p1.x;
rect.p1.y = rect.p0.y + line_height;
gfx_rect_clip(&rect, &lrect, &crect);
rc = gfx_set_color(gc, bgcolor);
if (rc != EOK)
return rc;
rc = gfx_fill_rect(gc, &crect);
if (rc != EOK)
return rc;
rc = gfx_set_clip_rect(gc, &crect);
if (rc != EOK)
return rc;
pos.x += hpad;
pos.y += vpad;
rc = gfx_puttext(&pos, &fmt, entry->caption);
if (rc != EOK) {
(void) gfx_set_clip_rect(gc, NULL);
return rc;
}
return gfx_set_clip_rect(gc, NULL);
}
errno_t ui_list_paint(ui_list_t *list)
{
gfx_context_t *gc = ui_window_get_gc(list->window);
ui_resource_t *res = ui_window_get_res(list->window);
ui_list_entry_t *entry;
int i, lines;
errno_t rc;
rc = gfx_set_color(gc, res->entry_bg_color);
if (rc != EOK)
return rc;
rc = gfx_fill_rect(gc, &list->rect);
if (rc != EOK)
return rc;
if (!res->textmode) {
rc = ui_paint_inset_frame(res, &list->rect, NULL);
if (rc != EOK)
return rc;
}
lines = ui_list_page_size(list) + 1;
i = 0;
entry = list->page;
while (entry != NULL && i < lines) {
rc = ui_list_entry_paint(entry, list->page_idx + i);
if (rc != EOK)
return rc;
++i;
entry = ui_list_next(entry);
}
rc = ui_scrollbar_paint(list->scrollbar);
if (rc != EOK)
return rc;
rc = gfx_update(gc);
if (rc != EOK)
return rc;
return EOK;
}
ui_evclaim_t ui_list_kbd_event(ui_list_t *list, kbd_event_t *event)
{
if (!list->active)
return ui_unclaimed;
if (event->type == KEY_PRESS) {
if ((event->mods & (KM_CTRL | KM_ALT | KM_SHIFT)) == 0) {
switch (event->key) {
case KC_UP:
ui_list_cursor_up(list);
break;
case KC_DOWN:
ui_list_cursor_down(list);
break;
case KC_HOME:
ui_list_cursor_top(list);
break;
case KC_END:
ui_list_cursor_bottom(list);
break;
case KC_PAGE_UP:
ui_list_page_up(list);
break;
case KC_PAGE_DOWN:
ui_list_page_down(list);
break;
case KC_ENTER:
ui_list_selected(list->cursor);
break;
default:
break;
}
}
}
return ui_claimed;
}
ui_evclaim_t ui_list_pos_event(ui_list_t *list, pos_event_t *event)
{
gfx_coord2_t pos;
gfx_rect_t irect;
ui_list_entry_t *entry;
gfx_coord_t line_height;
size_t entry_idx;
ui_evclaim_t claim;
int n;
claim = ui_scrollbar_pos_event(list->scrollbar, event);
if (claim == ui_claimed)
return ui_claimed;
line_height = ui_list_entry_height(list);
pos.x = event->hpos;
pos.y = event->vpos;
if (!gfx_pix_inside_rect(&pos, &list->rect))
return ui_unclaimed;
if (event->type == POS_PRESS || event->type == POS_DCLICK) {
ui_list_inside_rect(list, &irect);
if (gfx_pix_inside_rect(&pos, &irect)) {
n = (pos.y - irect.p0.y) / line_height;
entry = ui_list_page_nth_entry(list, n, &entry_idx);
if (entry == NULL)
return ui_claimed;
if (event->type == POS_PRESS) {
ui_list_cursor_move(list, entry, entry_idx);
} else {
ui_list_selected(entry);
}
} else {
if (event->type == POS_PRESS) {
if (pos.y >= (irect.p0.y + irect.p1.y) / 2)
ui_list_page_down(list);
else
ui_list_page_up(list);
}
}
}
if (!list->active && event->type == POS_PRESS)
ui_list_activate_req(list);
return ui_claimed;
}
ui_control_t *ui_list_ctl(ui_list_t *list)
{
return list->control;
}
void ui_list_set_rect(ui_list_t *list, gfx_rect_t *rect)
{
gfx_rect_t srect;
list->rect = *rect;
ui_list_scrollbar_rect(list, &srect);
ui_scrollbar_set_rect(list->scrollbar, &srect);
}
unsigned ui_list_page_size(ui_list_t *list)
{
gfx_coord_t line_height;
gfx_rect_t irect;
line_height = ui_list_entry_height(list);
ui_list_inside_rect(list, &irect);
return (irect.p1.y - irect.p0.y) / line_height;
}
void ui_list_inside_rect(ui_list_t *list, gfx_rect_t *irect)
{
ui_resource_t *res = ui_window_get_res(list->window);
gfx_rect_t rect;
gfx_coord_t width;
if (res->textmode) {
rect = list->rect;
} else {
ui_paint_get_inset_frame_inside(res, &list->rect, &rect);
}
if (res->textmode) {
width = 1;
} else {
width = 23;
}
irect->p0 = rect.p0;
irect->p1.x = rect.p1.x - width;
irect->p1.y = rect.p1.y;
}
void ui_list_scrollbar_rect(ui_list_t *list, gfx_rect_t *srect)
{
ui_resource_t *res = ui_window_get_res(list->window);
gfx_rect_t rect;
gfx_coord_t width;
if (res->textmode) {
rect = list->rect;
} else {
ui_paint_get_inset_frame_inside(res, &list->rect, &rect);
}
if (res->textmode) {
width = 1;
} else {
width = 23;
}
srect->p0.x = rect.p1.x - width;
srect->p0.y = rect.p0.y;
srect->p1 = rect.p1;
}
gfx_coord_t ui_list_scrollbar_pos(ui_list_t *list)
{
size_t entries;
size_t pglen;
size_t sbar_len;
entries = list_count(&list->entries);
pglen = ui_list_page_size(list);
sbar_len = ui_scrollbar_move_length(list->scrollbar);
if (entries > pglen)
return sbar_len * list->page_idx / (entries - pglen);
else
return 0;
}
void ui_list_scrollbar_update(ui_list_t *list)
{
ui_scrollbar_set_pos(list->scrollbar,
ui_list_scrollbar_pos(list));
}
bool ui_list_is_active(ui_list_t *list)
{
return list->active;
}
errno_t ui_list_activate(ui_list_t *list)
{
list->active = true;
(void) ui_list_paint(list);
return EOK;
}
void ui_list_deactivate(ui_list_t *list)
{
list->active = false;
(void) ui_list_paint(list);
}
void ui_list_entry_attr_init(ui_list_entry_attr_t *attr)
{
memset(attr, 0, sizeof(*attr));
}
void ui_list_ctl_destroy(void *arg)
{
ui_list_t *list = (ui_list_t *) arg;
ui_list_destroy(list);
}
errno_t ui_list_ctl_paint(void *arg)
{
ui_list_t *list = (ui_list_t *) arg;
return ui_list_paint(list);
}
ui_evclaim_t ui_list_ctl_kbd_event(void *arg, kbd_event_t *event)
{
ui_list_t *list = (ui_list_t *) arg;
return ui_list_kbd_event(list, event);
}
ui_evclaim_t ui_list_ctl_pos_event(void *arg, pos_event_t *event)
{
ui_list_t *list = (ui_list_t *) arg;
return ui_list_pos_event(list, event);
}
errno_t ui_list_entry_append(ui_list_t *list, ui_list_entry_attr_t *attr,
ui_list_entry_t **rentry)
{
ui_list_entry_t *entry;
entry = calloc(1, sizeof(ui_list_entry_t));
if (entry == NULL)
return ENOMEM;
entry->list = list;
entry->caption = str_dup(attr->caption);
if (entry->caption == NULL) {
free(entry);
return ENOMEM;
}
entry->arg = attr->arg;
entry->color = attr->color;
entry->bgcolor = attr->bgcolor;
link_initialize(&entry->lentries);
list_append(&entry->lentries, &list->entries);
if (list->entries_cnt == 0) {
list->cursor = entry;
list->cursor_idx = 0;
list->page = entry;
list->page_idx = 0;
}
++list->entries_cnt;
if (rentry != NULL)
*rentry = entry;
return EOK;
}
void ui_list_entry_move_up(ui_list_entry_t *entry)
{
ui_list_t *list = entry->list;
ui_list_entry_t *prev;
prev = ui_list_prev(entry);
if (prev == NULL) {
return;
}
list_remove(&entry->lentries);
list_insert_before(&entry->lentries, &prev->lentries);
if (list->page == entry) {
list->page = prev;
} else if (list->page == prev) {
list->page = entry;
}
if (list->cursor == entry) {
list->cursor = prev;
ui_list_cursor_move(list, entry, list->cursor_idx - 1);
} else if (list->cursor == prev) {
list->cursor = entry;
ui_list_cursor_move(list, prev, list->cursor_idx + 1);
}
}
void ui_list_entry_move_down(ui_list_entry_t *entry)
{
ui_list_t *list = entry->list;
ui_list_entry_t *next;
next = ui_list_next(entry);
if (next == NULL) {
return;
}
list_remove(&entry->lentries);
list_insert_after(&entry->lentries, &next->lentries);
if (list->page == entry) {
list->page = next;
} else if (list->page == next) {
list->page = entry;
}
if (list->cursor == entry) {
list->cursor = next;
ui_list_cursor_move(list, entry, list->cursor_idx + 1);
} else if (list->cursor == next) {
list->cursor = entry;
ui_list_cursor_move(list, next, list->cursor_idx - 1);
}
}
void ui_list_entry_destroy(ui_list_entry_t *entry)
{
if (entry->list->cursor == entry)
entry->list->cursor = NULL;
if (entry->list->page == entry)
entry->list->page = NULL;
list_remove(&entry->lentries);
--entry->list->entries_cnt;
free((char *) entry->caption);
free(entry);
}
void ui_list_entry_delete(ui_list_entry_t *entry)
{
ui_list_t *list = entry->list;
if (entry->list->cursor == entry)
ui_list_cursor_up(entry->list);
if (entry->list->cursor == entry)
ui_list_cursor_down(entry->list);
if (entry->list->page == entry)
ui_list_scroll_up(entry->list);
if (entry->list->page == entry)
ui_list_scroll_down(entry->list);
ui_list_entry_destroy(entry);
if (list->page == NULL) {
list->page = ui_list_first(list);
list->page_idx = 0;
} else {
list->page_idx = ui_list_entry_get_idx(list->page);
}
if (list->cursor == NULL) {
list->cursor = ui_list_first(list);
list->cursor_idx = 0;
} else {
list->cursor_idx = ui_list_entry_get_idx(list->cursor);
}
}
void *ui_list_entry_get_arg(ui_list_entry_t *entry)
{
return entry->arg;
}
ui_list_t *ui_list_entry_get_list(ui_list_entry_t *entry)
{
return entry->list;
}
errno_t ui_list_entry_set_caption(ui_list_entry_t *entry, const char *caption)
{
char *dcaption;
dcaption = str_dup(caption);
if (dcaption == NULL)
return ENOMEM;
free(entry->caption);
entry->caption = dcaption;
(void)ui_list_entry_paint(entry, ui_list_entry_get_idx(entry));
return EOK;
}
void ui_list_clear_entries(ui_list_t *list)
{
ui_list_entry_t *entry;
entry = ui_list_first(list);
while (entry != NULL) {
ui_list_entry_destroy(entry);
entry = ui_list_first(list);
}
}
size_t ui_list_entries_cnt(ui_list_t *list)
{
return list->entries_cnt;
}
ui_list_entry_t *ui_list_first(ui_list_t *list)
{
link_t *link;
link = list_first(&list->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_list_entry_t, lentries);
}
ui_list_entry_t *ui_list_last(ui_list_t *list)
{
link_t *link;
link = list_last(&list->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_list_entry_t, lentries);
}
ui_list_entry_t *ui_list_next(ui_list_entry_t *cur)
{
link_t *link;
link = list_next(&cur->lentries, &cur->list->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_list_entry_t, lentries);
}
ui_list_entry_t *ui_list_prev(ui_list_entry_t *cur)
{
link_t *link;
link = list_prev(&cur->lentries, &cur->list->entries);
if (link == NULL)
return NULL;
return list_get_instance(link, ui_list_entry_t, lentries);
}
ui_list_entry_t *ui_list_page_nth_entry(ui_list_t *list,
size_t n, size_t *ridx)
{
ui_list_entry_t *entry;
size_t i;
size_t idx;
assert(n <= ui_list_page_size(list));
entry = list->page;
if (entry == NULL)
return NULL;
idx = list->page_idx;
for (i = 0; i < n; i++) {
entry = ui_list_next(entry);
if (entry == NULL)
return NULL;
++idx;
}
*ridx = idx;
return entry;
}
ui_list_entry_t *ui_list_get_cursor(ui_list_t *list)
{
return list->cursor;
}
void ui_list_set_cursor(ui_list_t *list, ui_list_entry_t *entry)
{
size_t idx;
idx = ui_list_entry_get_idx(entry);
ui_list_cursor_move(list, entry, idx);
}
void ui_list_cursor_move(ui_list_t *list,
ui_list_entry_t *entry, size_t entry_idx)
{
gfx_context_t *gc = ui_window_get_gc(list->window);
ui_list_entry_t *old_cursor;
size_t old_idx;
size_t rows;
ui_list_entry_t *e;
size_t i;
rows = ui_list_page_size(list);
old_cursor = list->cursor;
old_idx = list->cursor_idx;
list->cursor = entry;
list->cursor_idx = entry_idx;
if (entry_idx >= list->page_idx &&
entry_idx < list->page_idx + rows) {
ui_list_entry_paint(old_cursor, old_idx);
ui_list_entry_paint(list->cursor, list->cursor_idx);
(void) gfx_update(gc);
} else {
if (entry_idx < list->page_idx) {
list->page = entry;
list->page_idx = entry_idx;
}
if (entry_idx >= list->page_idx + rows) {
if (entry_idx >= rows) {
list->page_idx = entry_idx - rows + 1;
e = entry;
for (i = 0; i + 1 < rows; i++) {
e = ui_list_prev(e);
}
assert(e != NULL);
list->page = e;
} else {
list->page = ui_list_first(list);
list->page_idx = 0;
}
}
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
}
}
void ui_list_cursor_up(ui_list_t *list)
{
ui_list_entry_t *prev;
size_t prev_idx;
prev = ui_list_prev(list->cursor);
prev_idx = list->cursor_idx - 1;
if (prev != NULL)
ui_list_cursor_move(list, prev, prev_idx);
}
void ui_list_cursor_down(ui_list_t *list)
{
ui_list_entry_t *next;
size_t next_idx;
next = ui_list_next(list->cursor);
next_idx = list->cursor_idx + 1;
if (next != NULL)
ui_list_cursor_move(list, next, next_idx);
}
void ui_list_cursor_top(ui_list_t *list)
{
ui_list_cursor_move(list, ui_list_first(list), 0);
}
void ui_list_cursor_bottom(ui_list_t *list)
{
ui_list_cursor_move(list, ui_list_last(list),
list->entries_cnt - 1);
}
void ui_list_page_up(ui_list_t *list)
{
gfx_context_t *gc = ui_window_get_gc(list->window);
ui_list_entry_t *old_page;
ui_list_entry_t *old_cursor;
size_t old_idx;
size_t rows;
ui_list_entry_t *entry;
size_t i;
rows = ui_list_page_size(list);
old_page = list->page;
old_cursor = list->cursor;
old_idx = list->cursor_idx;
for (i = 0; i < rows; i++) {
entry = ui_list_prev(list->page);
if (entry != NULL) {
list->page = entry;
--list->page_idx;
}
}
for (i = 0; i < rows; i++) {
entry = ui_list_prev(list->cursor);
if (entry != NULL) {
list->cursor = entry;
--list->cursor_idx;
}
}
if (list->page != old_page) {
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
} else if (list->cursor != old_cursor) {
ui_list_entry_paint(old_cursor, old_idx);
ui_list_entry_paint(list->cursor, list->cursor_idx);
(void) gfx_update(gc);
}
}
void ui_list_page_down(ui_list_t *list)
{
gfx_context_t *gc = ui_window_get_gc(list->window);
ui_list_entry_t *old_page;
ui_list_entry_t *old_cursor;
size_t old_idx;
size_t max_idx;
size_t rows;
ui_list_entry_t *entry;
size_t i;
rows = ui_list_page_size(list);
old_page = list->page;
old_cursor = list->cursor;
old_idx = list->cursor_idx;
if (list->entries_cnt > rows)
max_idx = list->entries_cnt - rows;
else
max_idx = 0;
for (i = 0; i < rows; i++) {
entry = ui_list_next(list->page);
if (entry != NULL && list->page_idx < max_idx) {
list->page = entry;
++list->page_idx;
}
}
for (i = 0; i < rows; i++) {
entry = ui_list_next(list->cursor);
if (entry != NULL) {
list->cursor = entry;
++list->cursor_idx;
}
}
if (list->page != old_page) {
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
} else if (list->cursor != old_cursor) {
ui_list_entry_paint(old_cursor, old_idx);
ui_list_entry_paint(list->cursor, list->cursor_idx);
(void) gfx_update(gc);
}
}
void ui_list_scroll_up(ui_list_t *list)
{
ui_list_entry_t *prev;
if (list->page == NULL)
return;
prev = ui_list_prev(list->page);
if (prev == NULL)
return;
list->page = prev;
assert(list->page_idx > 0);
--list->page_idx;
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
}
void ui_list_scroll_down(ui_list_t *list)
{
ui_list_entry_t *next;
ui_list_entry_t *pgend;
size_t i;
size_t rows;
if (list->page == NULL)
return;
next = ui_list_next(list->page);
if (next == NULL)
return;
rows = ui_list_page_size(list);
pgend = list->page;
for (i = 0; i < rows && pgend != NULL; i++) {
pgend = ui_list_next(pgend);
}
if (pgend != NULL) {
list->page = next;
++list->page_idx;
}
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
}
void ui_list_scroll_page_up(ui_list_t *list)
{
ui_list_entry_t *prev;
size_t i;
size_t rows;
prev = ui_list_prev(list->page);
if (prev == NULL)
return;
rows = ui_list_page_size(list);
for (i = 0; i < rows && prev != NULL; i++) {
list->page = prev;
assert(list->page_idx > 0);
--list->page_idx;
prev = ui_list_prev(prev);
}
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
}
void ui_list_scroll_page_down(ui_list_t *list)
{
ui_list_entry_t *next;
ui_list_entry_t *pgend;
size_t i;
size_t rows;
next = ui_list_next(list->page);
if (next == NULL)
return;
rows = ui_list_page_size(list);
pgend = list->page;
for (i = 0; i < rows && pgend != NULL; i++) {
pgend = ui_list_next(pgend);
}
for (i = 0; i < rows && pgend != NULL; i++) {
list->page = next;
++list->page_idx;
next = ui_list_next(next);
pgend = ui_list_next(pgend);
}
ui_list_scrollbar_update(list);
(void) ui_list_paint(list);
}
void ui_list_scroll_pos(ui_list_t *list, size_t page_idx)
{
ui_list_entry_t *entry;
size_t i;
entry = ui_list_first(list);
for (i = 0; i < page_idx; i++) {
entry = ui_list_next(entry);
assert(entry != NULL);
}
list->page = entry;
list->page_idx = page_idx;
(void) ui_list_paint(list);
}
void ui_list_activate_req(ui_list_t *list)
{
if (list->cb != NULL && list->cb->activate_req != NULL) {
list->cb->activate_req(list, list->cb_arg);
} else {
ui_list_activate(list);
}
}
errno_t ui_list_sort(ui_list_t *list)
{
ui_list_entry_t **emap;
ui_list_entry_t *entry;
size_t i;
emap = calloc(list->entries_cnt, sizeof(ui_list_entry_t *));
if (emap == NULL)
return ENOMEM;
entry = ui_list_first(list);
i = 0;
while (entry != NULL) {
assert(i < list->entries_cnt);
emap[i++] = entry;
entry = ui_list_next(entry);
}
qsort(emap, list->entries_cnt, sizeof(ui_list_entry_t *),
ui_list_entry_ptr_cmp);
entry = ui_list_first(list);
while (entry != NULL) {
list_remove(&entry->lentries);
entry = ui_list_first(list);
}
for (i = 0; i < list->entries_cnt; i++)
list_append(&emap[i]->lentries, &list->entries);
free(emap);
list->page = ui_list_first(list);
list->page_idx = 0;
list->cursor = ui_list_first(list);
list->cursor_idx = 0;
return EOK;
}
size_t ui_list_entry_get_idx(ui_list_entry_t *entry)
{
ui_list_entry_t *ep;
size_t idx;
idx = 0;
ep = ui_list_prev(entry);
while (ep != NULL) {
++idx;
ep = ui_list_prev(ep);
}
return idx;
}
void ui_list_cursor_center(ui_list_t *list, ui_list_entry_t *entry)
{
ui_list_entry_t *prev;
size_t idx;
size_t max_idx;
size_t pg_size;
size_t i;
idx = ui_list_entry_get_idx(entry);
list->cursor = entry;
list->cursor_idx = idx;
list->page = list->cursor;
list->page_idx = list->cursor_idx;
pg_size = ui_list_page_size(list);
for (i = 0; i < pg_size / 2; i++) {
prev = ui_list_prev(list->page);
if (prev == NULL)
break;
list->page = prev;
--list->page_idx;
}
if (list->entries_cnt > pg_size)
max_idx = list->entries_cnt - pg_size;
else
max_idx = 0;
while (list->page_idx > 0 && list->page_idx > max_idx) {
prev = ui_list_prev(list->page);
if (prev == NULL)
break;
list->page = prev;
--list->page_idx;
}
}
void ui_list_selected(ui_list_entry_t *entry)
{
if (entry->list->cb != NULL && entry->list->cb->selected != NULL)
entry->list->cb->selected(entry, entry->arg);
}
static void ui_list_scrollbar_up(ui_scrollbar_t *scrollbar, void *arg)
{
ui_list_t *list = (ui_list_t *)arg;
ui_list_scroll_up(list);
}
static void ui_list_scrollbar_down(ui_scrollbar_t *scrollbar, void *arg)
{
ui_list_t *list = (ui_list_t *)arg;
ui_list_scroll_down(list);
}
static void ui_list_scrollbar_page_up(ui_scrollbar_t *scrollbar, void *arg)
{
ui_list_t *list = (ui_list_t *)arg;
ui_list_scroll_page_up(list);
}
static void ui_list_scrollbar_page_down(ui_scrollbar_t *scrollbar,
void *arg)
{
ui_list_t *list = (ui_list_t *)arg;
ui_list_scroll_page_down(list);
}
static void ui_list_scrollbar_moved(ui_scrollbar_t *scrollbar, void *arg,
gfx_coord_t pos)
{
ui_list_t *list = (ui_list_t *)arg;
size_t entries;
size_t pglen;
size_t sbar_len;
size_t pgstart;
entries = list_count(&list->entries);
pglen = ui_list_page_size(list);
sbar_len = ui_scrollbar_move_length(list->scrollbar);
if (entries > pglen)
pgstart = (entries - pglen) * pos / (sbar_len - 1);
else
pgstart = 0;
ui_list_scroll_pos(list, pgstart);
}
int ui_list_entry_ptr_cmp(const void *pa, const void *pb)
{
ui_list_entry_t *a = *(ui_list_entry_t **)pa;
ui_list_entry_t *b = *(ui_list_entry_t **)pb;
return a->list->cb->compare(a, b);
}
HelenOS homepage, sources at GitHub