202 lines
5.0 KiB
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");
|
|
}
|