#include "gui.h" #include "gui_defs.h" #include "x.h" #include <stdio.h> #include <stdlib.h> #include <string.h> static void paint(gui *_gui, widget *_this) { struct gui *g = _gui; struct textlist_widget *this = _this; int i, j; LOGD("PAINT textlist %p xywh %d %d %d %d starting line %d allocated nlines %d text_count %d\n", _this, this->common.x, this->common.y, this->common.width, this->common.height, this->starting_line, this->allocated_nlines, this->text_count); x_fill_rectangle(g->x, g->xwin, this->background_color, this->common.x, this->common.y, this->common.width, this->common.height); for (i = 0, j = this->starting_line; i < this->allocated_nlines && j < this->text_count; i++, j++) x_draw_clipped_string(g->x, g->xwin, DEFAULT_FONT, this->color[j], this->common.x, this->common.y + i * this->line_height + this->baseline, this->text[j], this->common.x, this->common.y, this->common.width, this->common.height); } static void hints(gui *_gui, widget *_w, int *width, int *height) { struct textlist_widget *w = _w; *width = w->wanted_width; *height = w->wanted_nlines * w->line_height; LOGD("HINTS textlist wh %d %d\n", *width, *height); } static void allocate( gui *gui, widget *_this, int x, int y, int width, int height) { struct textlist_widget *this = _this; this->common.x = x; this->common.y = y; this->common.width = width; this->common.height = height; this->allocated_nlines = height / this->line_height; LOGD("ALLOCATE textlist %p xywh %d %d %d %d nlines %d\n", this, x, y, width, height, this->allocated_nlines); } static void button(gui *_g, widget *_this, int x, int y, int key_modifiers, int button, int up) { struct gui *g = _g; struct textlist_widget *this = _this; LOGD("BUTTON textlist %p xy %d %d button %d up %d\n", _this, x, y, button, up); y -= this->common.y; x -= this->common.x; /* scroll up */ if (button == 4 && up == 0) { gui_notify(g, "scrollup", _this, NULL); } /* scroll down */ if (button == 5 && up == 0) { gui_notify(g, "scrolldown", _this, NULL); } /* button 1/2/3 click */ if (button >= 1 && button <= 3 && up == 0) { int line = this->starting_line + y / this->line_height; if (line >= 0 && line < this->text_count) gui_notify(g, "click", _this, (int[2]){ line, button }); } } widget *new_textlist(gui *_gui, int width, int nlines, int bgcol) { struct gui *g = _gui; struct textlist_widget *w; int dummy; glock(g); w = new_widget(g, TEXT_LIST, sizeof(struct textlist_widget)); w->wanted_nlines = nlines; x_text_get_dimensions(g->x, DEFAULT_FONT, ".", &dummy, &w->line_height, &w->baseline); w->background_color = bgcol; w->wanted_width = width; w->common.paint = paint; w->common.hints = hints; w->common.allocate = allocate; w->common.button = button; gunlock(g); return w; } /*************************************************************************/ /* public functions */ /*************************************************************************/ static void _textlist_add(gui *_gui, widget *_this, const char *text, int position, int color, int silent) { struct gui *g = _gui; struct textlist_widget *this = _this; glock(g); if (position < 0) position = this->text_count; if (position > this->text_count) position = this->text_count; this->text_count++; this->text = realloc(this->text, this->text_count * sizeof(char *)); if (this->text == NULL) OOM; this->color = realloc(this->color, this->text_count * sizeof(int)); if (this->color == NULL) OOM; memmove(this->text + position + 1, this->text + position, (this->text_count-1 - position) * sizeof(char *)); memmove(this->color + position + 1, this->color + position, (this->text_count-1 - position) * sizeof(int)); this->text[position] = strdup(text); if (this->text[position] == NULL) OOM; this->color[position] = color; if (!silent) send_event(g, DIRTY, this->common.id); gunlock(g); } static void _textlist_del(gui *_gui, widget *_this, int position, int silent) { struct gui *g = _gui; struct textlist_widget *this = _this; glock(g); /* TODO: useful check? */ if (this->text_count == 0) goto done; if (position < 0) position = this->text_count; if (position > this->text_count-1) position = this->text_count-1; free(this->text[position]); memmove(this->text + position, this->text + position + 1, (this->text_count-1 - position) * sizeof(char *)); memmove(this->color + position, this->color + position + 1, (this->text_count-1 - position) * sizeof(int)); this->text_count--; this->text = realloc(this->text, this->text_count * sizeof(char *)); if (this->text == NULL) OOM; this->color = realloc(this->color, this->text_count * sizeof(int)); if (this->color == NULL) OOM; if (!silent) send_event(g, DIRTY, this->common.id); done: gunlock(g); } void textlist_add(gui *gui, widget *this, const char *text, int position, int color) { _textlist_add(gui, this, text, position, color, 0); } void textlist_del(gui *gui, widget *this, int position) { _textlist_del(gui, this, position, 0); } void textlist_add_silent(gui *gui, widget *this, const char *text, int position, int color) { _textlist_add(gui, this, text, position, color, 1); } void textlist_del_silent(gui *gui, widget *this, int position) { _textlist_del(gui, this, position, 1); } void textlist_state(gui *_gui, widget *_this, int *visible_lines, int *start_line, int *number_of_lines) { struct gui *g = _gui; struct textlist_widget *this = _this; glock(g); *visible_lines = this->allocated_nlines; *start_line = this->starting_line; *number_of_lines = this->text_count; gunlock(g); } void textlist_set_start_line(gui *_gui, widget *_this, int line) { struct gui *g = _gui; struct textlist_widget *this = _this; glock(g); this->starting_line = line; send_event(g, DIRTY, this->common.id); gunlock(g); } void textlist_get_line(gui *_gui, widget *_this, int line, char **text, int *color) { struct gui *g = _gui; struct textlist_widget *this = _this; glock(g); if (line < 0 || line >= this->text_count) { *text = NULL; *color = -1; } else { *text = this->text[line]; *color = this->color[line]; } gunlock(g); } void textlist_set_color(gui *_gui, widget *_this, int line, int color) { struct gui *g = _gui; struct textlist_widget *this = _this; glock(g); if (line >= 0 && line < this->text_count) { this->color[line] = color; send_event(g, DIRTY, this->common.id); } gunlock(g); }