#include #include #include #include #include /* 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"); }