hex-editor/src/hlist.c

171 lines
3.8 KiB
C

#include "hlist.h"
#include <justui/jwidget.h>
#include <justui/jwidget-api.h>
#include <gint/display.h>
#include <stdlib.h>
/* Type identifier for hlist */
static int hlist_type_id = -1;
/* Events */
uint16_t HLIST_VALIDATED;
uint16_t HLIST_CANCELED;
hlist *hlist_create(void *parent)
{
if(hlist_type_id < 0) return NULL;
hlist *l = malloc(sizeof *l);
if(!l) return NULL;
jwidget_init(&l->widget, hlist_type_id, parent);
l->entries = NULL;
l->entry_size = 0;
l->entry_count = 0;
l->render_height = 0;
l->render_func = NULL;
l->selected_index = -1;
l->cursor = 0;
l->scroll = 0;
l->visible_lines = 0;
return l;
}
static void count_visible_lines(hlist *l)
{
int ch = jwidget_content_height(l);
l->visible_lines = ch / l->render_height;
}
void hlist_set_entries(hlist *l, void *entries, size_t entry_size, int count)
{
l->entries = entries;
l->entry_size = entry_size;
l->entry_count = count;
l->cursor = 0;
l->scroll = 0;
l->widget.update = true;
}
void hlist_set_renderer(hlist *l, int render_height, void *render)
{
if(l->render_height != render_height)
l->widget.dirty = true;
l->render_height = render_height;
l->render_func = render;
l->widget.update = true;
}
int hlist_selected_index(hlist *l)
{
return l->selected_index;
}
// Polymorphic widget operations //
static void hlist_poly_csize(void *l0)
{
hlist *l = l0;
int lines = l->entry_count;
int lheight = l->render_height;
l->widget.w = 128;
l->widget.h = (lines && lheight) ? lines * lheight : 64;
}
static void hlist_poly_layout(void *l0)
{
hlist *l = l0;
count_visible_lines(l);
}
static void hlist_poly_render(void *l0, int x, int y)
{
hlist *l = l0;
if(!l->entries)
return;
int cw = jwidget_content_width(l);
for(int i = 0; i < l->visible_lines && l->scroll+i < l->entry_count; i++) {
bool selected = (l->cursor == l->scroll + i);
void *entry = l->entries + l->entry_size * i;
int line_y = y + l->render_height * i;
if(l->render_func)
l->render_func(x, line_y, cw, l->render_height, entry, selected);
}
}
static bool hlist_poly_event(void *l0, jevent e)
{
hlist *l = l0;
if(!l->entries || e.type != JWIDGET_KEY)
return false;
key_event_t ev = e.key;
if(ev.type != KEYEV_DOWN && ev.type != KEYEV_HOLD)
return false;
int key = ev.key;
bool moved = false;
if(key == KEY_UP && l->cursor > 0) {
l->cursor = ev.shift ? 0 : l->cursor - 1;
moved = true;
}
if(key == KEY_DOWN && l->cursor < l->entry_count - 1) {
l->cursor = ev.shift ? l->entry_count - 1 : l->cursor + 1;
moved = true;
}
if(l->scroll > 0 && l->cursor <= l->scroll)
l->scroll = max(l->cursor - 1, 0);
if(l->scroll + l->visible_lines < l->entry_count
&& l->cursor >= l->scroll + l->visible_lines - 2) {
l->scroll = min(l->cursor - l->visible_lines + 2,
l->entry_count - l->visible_lines);
}
if(moved) {
l->widget.update = true;
return true;
}
if(key == KEY_EXIT) {
jwidget_emit(l, (jevent){ .type = HLIST_CANCELED });
return true;
}
else if(key == KEY_EXE) {
l->selected_index = l->cursor;
jwidget_emit(l, (jevent){ .type = HLIST_VALIDATED });
return true;
}
return false;
}
/* hlist type definition */
static jwidget_poly type_hlist = {
.name = "hlist",
.csize = hlist_poly_csize,
.layout = hlist_poly_layout,
.render = hlist_poly_render,
.event = hlist_poly_event,
};
__attribute__((constructor(1004)))
static void j_register_hlist(void)
{
hlist_type_id = j_register_widget(&type_hlist, "jwidget");
HLIST_VALIDATED = j_register_event();
HLIST_CANCELED = j_register_event();
}