FxLibcTest/src/widgets/flog.c

202 lines
5.0 KiB
C

#include <ft/widgets/flog.h>
#include <ft/util.h>
#include <justui/jwidget-api.h>
#include <stdlib.h>
#include <string.h>
/* Type identifier for flog */
static int flog_type_id = -1;
flog *flog_create(void *parent)
{
if(flog_type_id < 0) return NULL;
flog *l = malloc(sizeof *l);
if(!l) return NULL;
jwidget_init(&l->widget, flog_type_id, parent);
l->log = NULL;
l->log_size = -1;
l->lines = 0;
l->visible = 0;
l->top = 0;
l->font = dfont_default();
l->line_spacing = 1;
return l;
}
void flog_set_log(flog *l, char const *log, int log_size)
{
if(log_size == -1 && log != NULL)
log_size = strlen(log);
l->log = log;
l->log_size = log_size;
l->top = 0;
l->widget.dirty = 1;
}
font_t const *flog_font(flog *l)
{
return l->font;
}
void flog_set_font(flog *l, font_t const *font)
{
if(l->font == font) return;
l->font = font;
l->widget.dirty = 1;
}
int flog_line_spacing(flog *l)
{
return l->line_spacing;
}
void flog_set_line_spacing(flog *l, int line_spacing)
{
if(l->line_spacing == line_spacing) return;
l->line_spacing = line_spacing;
l->widget.dirty = 1;
}
//---
// Polymorphic widget operations
//---
static void flog_poly_layout(void *l0)
{
flog *l = l0;
int total_height = jwidget_content_height(l) + l->line_spacing;
l->visible = total_height / (l->font->line_height + l->line_spacing);
/* Compute number of lines. Keep 3 pixels of room for the scrollbar */
int const w = max(0, jwidget_content_width(l) - _(3,33));
char const *log = l->log;
l->lines = 0;
if(l->log) while(log < l->log + l->log_size) {
if(log[0] == '\n') {
log++;
l->lines++;
}
else {
char const *endscreen = drsize(log, l->font, w, NULL);
char const *endline = strchrnul(log, '\n');
int len = max(1, min(endscreen-log, endline-log));
log += len + (log[len] == '\n');
l->lines++;
}
}
}
static void flog_poly_render(void *l0, int x, int y)
{
flog *l = l0;
if(!l->log || l->log_size <= 0) return;
int const w = jwidget_content_width(l);
int const h = jwidget_content_height(l);
char const *log = l->log;
font_t const *old_font = dfont(l->font);
/* current_y is ignored until current_line >= top, at which point it
starts at y and increases each line */
int current_line = 0;
int current_y = y;
while(log < l->log + l->log_size)
{
#ifdef FXCG50
if(current_line >= l->top && current_line < l->top + l->visible)
dprint_opt(x+22, current_y, C_BLACK, C_NONE,
DTEXT_RIGHT, DTEXT_TOP, "%d", current_line+1);
#endif
if(log[0] == '\n') {
log++;
}
else {
char const *endscreen = drsize(log, NULL, w - _(3,33), NULL);
char const *endline = strchrnul(log, '\n');
int len = max(1, min(endscreen-log, endline-log));
if(current_line >= l->top && current_line < l->top + l->visible)
dtext_opt(x+_(0,30), current_y, C_BLACK, C_NONE, DTEXT_LEFT,
DTEXT_TOP, log, len);
log += len + (log[len] == '\n');
}
if(current_line >= l->top && current_line < l->top + l->visible) {
#ifdef FXCG50
int previous_y = current_y;
dline(x+26, previous_y, x+26, current_y-1, C_BLACK);
#endif
current_y += l->font->line_height + l->line_spacing;
}
current_line++;
}
if(current_line > l->visible) {
/* Area where the scroll bar lives */
int area_w = _(1,2);
int area_x = x + w - area_w;
int area_y = y;
int area_h = h;
/* Position and size of scroll bar within the area */
int bar_y = (l->top * area_h) / current_line;
int bar_h = (l->visible * area_h) / current_line;
#ifdef FXCG50
drect(area_x, area_y, area_x+area_w-1, area_y+area_h-1,
C_RGB(24,24,24));
#endif
drect(area_x, area_y + bar_y, area_x + area_w - 1,
area_y + bar_y + bar_h, C_BLACK);
}
dfont(old_font);
}
static bool flog_poly_event(void *l0, jevent e)
{
flog *l = l0;
int key = (e.type==JWIDGET_KEY && e.key.type!=KEYEV_UP) ? e.key.key : 0;
int scroll_speed = 1;
if(e.key.shift) scroll_speed = 4;
if(e.key.alpha) scroll_speed = 16;
if(key == KEY_UP && l->top > 0) {
l->top = max(0, l->top - scroll_speed);
l->widget.update = 1;
return true;
}
if(key == KEY_DOWN) {
l->top = max(0, min(l->lines - l->visible, l->top + scroll_speed));
l->widget.update = 1;
return true;
}
return false;
}
/* flog typed definition */
static jwidget_poly type_flog = {
.name = "flog",
.layout = flog_poly_layout,
.render = flog_poly_render,
.event = flog_poly_event,
};
/* Type registration */
__attribute__((constructor(2000)))
static void j_register_flog(void)
{
flog_type_id = j_register_widget(&type_flog, "jwidget");
}