249 lines
6.6 KiB
C
249 lines
6.6 KiB
C
#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, &key_modifiers);
|
|
}
|
|
/* scroll down */
|
|
if (button == 5 && up == 0) {
|
|
gui_notify(g, "scrolldown", _this, &key_modifiers);
|
|
}
|
|
/* 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);
|
|
}
|