forked from Lephenixnoir/hex-editor
171 lines
3.8 KiB
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();
|
|
}
|