GUI timeline widget
This commit is contained in:
@@ -2,7 +2,8 @@ CC=gcc
|
||||
CFLAGS=-Wall -g -pthread
|
||||
|
||||
OBJS=init.o loop.o toplevel_window.o x.o container.o widget.o \
|
||||
gui.o label.o event.o xy_plot.o textlist.o notify.o positioner.o
|
||||
gui.o label.o event.o xy_plot.o textlist.o notify.o positioner.o \
|
||||
timeline.o
|
||||
|
||||
gui.a: $(OBJS)
|
||||
ar cr gui.a $(OBJS)
|
||||
|
||||
@@ -26,6 +26,8 @@ widget *new_label(gui *gui, const char *text);
|
||||
widget *new_xy_plot(gui *gui, int width, int height, char *label,
|
||||
int vruler_width);
|
||||
widget *new_textlist(gui *gui, int width, int nlines, int background_color);
|
||||
widget *new_timeline(gui *gui, int width, int number_of_sublines,
|
||||
int subline_height);
|
||||
|
||||
void label_set_clickable(gui *gui, widget *label, int clickable);
|
||||
|
||||
@@ -52,6 +54,12 @@ void textlist_get_line(gui *gui, widget *this, int line,
|
||||
char **text, int *color);
|
||||
void textlist_set_color(gui *gui, widget *this, int line, int color);
|
||||
|
||||
void timeline_clear(gui *gui, widget *this);
|
||||
void timeline_add_points(gui *gui, widget *this, int subline, int color,
|
||||
int *x, int len);
|
||||
void timeline_set_subline_background_color(gui *gui, widget *this,
|
||||
int subline, int color);
|
||||
|
||||
void gui_loop(gui *gui);
|
||||
|
||||
void glock(gui *gui);
|
||||
@@ -67,6 +75,8 @@ int new_color(gui *gui, char *color);
|
||||
* - click { int [2]: line, button }
|
||||
* - label:
|
||||
* - click { int: button } (if enabled)
|
||||
* - timeline
|
||||
* - resize { int: width }
|
||||
*/
|
||||
|
||||
/* same type as in gui_defs.h */
|
||||
|
||||
@@ -30,7 +30,8 @@ extern int volatile gui_logd;
|
||||
/*************************************************************************/
|
||||
|
||||
enum widget_type {
|
||||
TOPLEVEL_WINDOW, CONTAINER, POSITIONER, TEXT_LIST, XY_PLOT, BUTTON, LABEL
|
||||
TOPLEVEL_WINDOW, CONTAINER, POSITIONER, TEXT_LIST, XY_PLOT, BUTTON, LABEL,
|
||||
TIMELINE
|
||||
};
|
||||
|
||||
struct widget_list;
|
||||
@@ -117,6 +118,22 @@ struct xy_plot_widget {
|
||||
int nplots;
|
||||
};
|
||||
|
||||
struct timeline_subline {
|
||||
int *color; /* length = width of timeline widget
|
||||
* value = -1 if no color
|
||||
*/
|
||||
int width;
|
||||
int background; /* background color of the subline */
|
||||
};
|
||||
|
||||
struct timeline_widget {
|
||||
struct widget common;
|
||||
int n; /* number of sublines */
|
||||
struct timeline_subline *s;
|
||||
int subline_height;
|
||||
int wanted_width;
|
||||
};
|
||||
|
||||
struct button_widget {
|
||||
struct widget common;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
#include "gui.h"
|
||||
#include "gui_defs.h"
|
||||
#include "x.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void paint(gui *_gui, widget *_this)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
struct timeline_widget *this = _this;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
for (i = 0; i < this->n; i++) {
|
||||
x_fill_rectangle(g->x, g->xwin, this->s[i].background,
|
||||
this->common.x, this->common.y + i * this->subline_height,
|
||||
this->common.width, this->subline_height);
|
||||
for (j = 0; j < this->s[i].width; j++)
|
||||
if (this->s[i].color[j] != -1)
|
||||
x_draw_line(g->x, g->xwin, this->s[i].color[j],
|
||||
this->common.x + j, this->common.y + i * this->subline_height,
|
||||
this->common.x + j, this->common.y + this->subline_height -1
|
||||
+ i * this->subline_height);
|
||||
}
|
||||
|
||||
LOGD("PAINT timeline xywh %d %d %d %d\n", this->common.x, this->common.y, this->common.width, this->common.height);
|
||||
}
|
||||
|
||||
static void hints(gui *_gui, widget *_w, int *width, int *height)
|
||||
{
|
||||
struct timeline_widget *w = _w;
|
||||
*width = w->wanted_width;
|
||||
*height = w->n * w->subline_height;
|
||||
LOGD("HINTS timeline wh %d %d\n", *width, *height);
|
||||
}
|
||||
|
||||
static void allocate(gui *_gui, widget *_this,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
struct timeline_widget *this = _this;
|
||||
int i;
|
||||
int j;
|
||||
this->common.x = x;
|
||||
this->common.y = y;
|
||||
this->common.width = width;
|
||||
this->common.height = height;
|
||||
LOGD("ALLOCATE timeline %p xywh %d %d %d %d\n", this, x, y, width, height);
|
||||
for (i = 0; i < this->n; i++) {
|
||||
this->s[i].width = width;
|
||||
this->s[i].color = realloc(this->s[i].color, width * sizeof(int));
|
||||
if (this->s[i].color == NULL) abort();
|
||||
for (j = 0; j < width; j++) this->s[i].color[j] = -1;
|
||||
}
|
||||
gui_notify(_gui, "resize", _this, &width);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* creation function */
|
||||
/*************************************************************************/
|
||||
|
||||
widget *new_timeline(gui *_gui, int width, int number_of_sublines,
|
||||
int subline_height)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
struct timeline_widget *w;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
glock(g);
|
||||
|
||||
w = new_widget(g, TIMELINE, sizeof(struct timeline_widget));
|
||||
|
||||
w->wanted_width = width;
|
||||
w->n = number_of_sublines;
|
||||
w->s = calloc(w->n, sizeof(struct timeline_subline)); if (w->s == NULL) OOM;
|
||||
w->subline_height = subline_height;
|
||||
|
||||
/* initialize colors */
|
||||
for (i = 0; i < w->n; i++) {
|
||||
w->s[i].width = width;
|
||||
w->s[i].color = calloc(width, sizeof(int));
|
||||
if (w->s[i].color == NULL) abort();
|
||||
for (j = 0; j < width; j++) w->s[i].color[j] = -1;
|
||||
w->s[i].background = BACKGROUND_COLOR;
|
||||
}
|
||||
|
||||
w->common.paint = paint;
|
||||
w->common.hints = hints;
|
||||
w->common.allocate = allocate;
|
||||
|
||||
gunlock(g);
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* public functions */
|
||||
/*************************************************************************/
|
||||
|
||||
void timeline_clear(gui *_gui, widget *_this)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
struct timeline_widget *this = _this;
|
||||
int i;
|
||||
int j;
|
||||
|
||||
glock(g);
|
||||
|
||||
for (i = 0; i < this->n; i++)
|
||||
for (j = 0; j < this->s[i].width; j++)
|
||||
this->s[i].color[j] = -1;
|
||||
|
||||
send_event(g, DIRTY, this->common.id);
|
||||
|
||||
gunlock(g);
|
||||
}
|
||||
|
||||
void timeline_add_points(gui *_gui, widget *_this, int subline, int color,
|
||||
int *x, int len)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
struct timeline_widget *this = _this;
|
||||
int i;
|
||||
|
||||
glock(g);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (x[i] >= this->s[subline].width) { WARN("out of bounds\n"); continue; }
|
||||
this->s[subline].color[x[i]] = color;
|
||||
}
|
||||
|
||||
send_event(g, DIRTY, this->common.id);
|
||||
|
||||
gunlock(g);
|
||||
}
|
||||
|
||||
void timeline_set_subline_background_color(gui *_gui, widget *_this,
|
||||
int subline, int color)
|
||||
{
|
||||
struct gui *g = _gui;
|
||||
struct timeline_widget *this = _this;
|
||||
|
||||
glock(g);
|
||||
|
||||
this->s[subline].background = color;
|
||||
|
||||
send_event(g, DIRTY, this->common.id);
|
||||
|
||||
gunlock(g);
|
||||
}
|
||||
@@ -265,7 +265,7 @@ void widget_dirty(gui *_gui, widget *_this)
|
||||
|
||||
static const char *names[] = {
|
||||
"TOPLEVEL_WINDOW", "CONTAINER", "POSITIONER", "TEXT_LIST",
|
||||
"XY_PLOT", "BUTTON", "LABEL"
|
||||
"XY_PLOT", "BUTTON", "LABEL", "TIMELINE"
|
||||
};
|
||||
const char *widget_name(enum widget_type type)
|
||||
{
|
||||
@@ -278,6 +278,7 @@ const char *widget_name(enum widget_type type)
|
||||
case XY_PLOT:
|
||||
case BUTTON:
|
||||
case LABEL:
|
||||
case TIMELINE:
|
||||
return names[type];
|
||||
}
|
||||
return "UNKNOWN (error)";
|
||||
|
||||
Reference in New Issue
Block a user