Upload files to 'btk'
This commit is contained in:
parent
5e4aed7040
commit
6878bd881b
441
btk/btk-cell-render.c
Normal file
441
btk/btk-cell-render.c
Normal file
@ -0,0 +1,441 @@
|
|||||||
|
void fill_cell (btk_cell_t *, cairo_t *, btk_rgb_t);
|
||||||
|
void guard_scroll (int *, int, int, unsigned int, int);
|
||||||
|
void render_button (btk_cell_t *, cairo_t *);
|
||||||
|
void render_editor (btk_cell_t *);
|
||||||
|
void render_gauge (btk_cell_t *, cairo_t *);
|
||||||
|
void render_input (btk_cell_t *, cairo_t *);
|
||||||
|
void render_list (btk_cell_t *);
|
||||||
|
void render_mark (btk_cell_t *, cairo_t *);
|
||||||
|
void render_prompt (btk_cell_t *, cairo_t *);
|
||||||
|
void render_table (btk_cell_t *);
|
||||||
|
void render_table_row (btk_cell_t *, char *, int, btk_rgb_t, btk_rgb_t);
|
||||||
|
void render_text (btk_cell_t *);
|
||||||
|
void render_switch (btk_cell_t *, cairo_t *);
|
||||||
|
void render_wheel (btk_cell_t *, cairo_t *);
|
||||||
|
void reset_field (btk_cell_t *);
|
||||||
|
void write_label (cairo_t *, int, int, unsigned int, int, char *, btk_rgb_t);
|
||||||
|
|
||||||
|
static cairo_font_options_t *font_opt;
|
||||||
|
static btk_pos_t label_offset;
|
||||||
|
static btk_size_t glyph;
|
||||||
|
|
||||||
|
/* ch is a modifier to force the heigth of a rendered cell to 1 cell unit */
|
||||||
|
void
|
||||||
|
fill_cell(btk_cell_t *c, cairo_t *c_ctx, btk_rgb_t cl)
|
||||||
|
{
|
||||||
|
cairo_set_source_rgb(c_ctx, cl.r, cl.g, cl.b);
|
||||||
|
cairo_rectangle(c_ctx, c->pa.x, c->pa.y, c->pa.w, c->pa.h);
|
||||||
|
cairo_fill(c_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pi = pixel indent, of each scrollable element in the considered axis */
|
||||||
|
/* cl = cell length, in the considered axis */
|
||||||
|
void
|
||||||
|
guard_scroll(int *scroll_var, int pi, int cl, unsigned int items_n, int extra)
|
||||||
|
{
|
||||||
|
if (*scroll_var < 0 || !items_n) { /* no negative scroll position */
|
||||||
|
*scroll_var = 0;
|
||||||
|
} else if (cl >= pi * items_n + extra) { /* reset scroll pos if everything fits in */
|
||||||
|
*scroll_var = 0;
|
||||||
|
} else if (*scroll_var + cl > pi * items_n + extra) {
|
||||||
|
*scroll_var = pi * items_n - cl + extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_button(btk_cell_t *c, cairo_t *c_ctx)
|
||||||
|
{
|
||||||
|
btk_rgb_t clt, cl;
|
||||||
|
if ((c->state & BTK_CELL_STATE_DISABLED)) {
|
||||||
|
cl = btk_cl_dyn_disabled;
|
||||||
|
clt = btk_cl_text_disabled;
|
||||||
|
} else if ((c->state & BTK_CELL_STATE_PRESSED)) {
|
||||||
|
cl = btk_cl_dyn_pressed;
|
||||||
|
clt = btk_cl_text_hilight;
|
||||||
|
} else {
|
||||||
|
cl = btk_cl_dyn_idle;
|
||||||
|
clt = btk_cl_text_normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_cell(c, c_ctx, cl);
|
||||||
|
write_label(c_ctx, c->pa.x, c->pa.y, c->pa.w, BTK_JUSTIFY_LEFT, c->label, clt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_editor(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
btk_pp_editor_t *pp = PP_EDITOR(c);
|
||||||
|
|
||||||
|
cairo_set_source_rgb(c->fd->c_ctx, btk_cl_field.r, btk_cl_field.g, btk_cl_field.b);
|
||||||
|
cairo_paint(c->fd->c_ctx);
|
||||||
|
|
||||||
|
int text_n = 0;
|
||||||
|
if (*pp->text)
|
||||||
|
text_n = strlen(pp->text);
|
||||||
|
|
||||||
|
guard_scroll(&pp->scroll, glyph.h + btk_text_spacing, c->pa.h, pp->par->rows_n, label_offset.y);
|
||||||
|
|
||||||
|
/* render caret */
|
||||||
|
if (!(c->state & BTK_CELL_STATE_DISABLED)) {
|
||||||
|
cairo_set_source_rgb(c->fd->c_ctx,
|
||||||
|
btk_cl_bell.r,
|
||||||
|
btk_cl_bell.g,
|
||||||
|
btk_cl_bell.b);
|
||||||
|
cairo_move_to(c->fd->c_ctx,
|
||||||
|
label_offset.x + pp->caret_2d.x * glyph.w,
|
||||||
|
pp->caret_2d.y * (glyph.h + btk_text_spacing) +
|
||||||
|
btk_caret_offset + label_offset.y - pp->scroll);
|
||||||
|
cairo_show_text(c->fd->c_ctx, "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* just render label if there are no rows to draw */
|
||||||
|
if (!text_n || !pp->par) {
|
||||||
|
write_label(c->fd->c_ctx,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
c->pa.w,
|
||||||
|
BTK_JUSTIFY_LEFT,
|
||||||
|
c->label,
|
||||||
|
btk_cl_text_lolight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
btk_rgb_t cl;
|
||||||
|
/* else render row by row */
|
||||||
|
for (int i = 0; i < pp->par->rows_n; i++) {
|
||||||
|
cl = btk_cl[pp->par->rows_spot[i]];
|
||||||
|
cairo_set_source_rgb(c->fd->c_ctx, cl.r, cl.g, cl.b);
|
||||||
|
cairo_move_to(c->fd->c_ctx,
|
||||||
|
label_offset.x,
|
||||||
|
label_offset.y - pp->scroll + i * (glyph.h + btk_text_spacing));
|
||||||
|
cairo_show_text(c->fd->c_ctx, pp->par->rows + i * pp->par->rows_max_w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_input(btk_cell_t *c, cairo_t *c_ctx)
|
||||||
|
{
|
||||||
|
btk_pp_input_t *pp = PP_INPUT(c);
|
||||||
|
int text_n = strlen(pp->text);
|
||||||
|
btk_rgb_t clt, clt2;
|
||||||
|
|
||||||
|
/* passive components */
|
||||||
|
clt = (c->state & BTK_CELL_STATE_DISABLED) ? btk_cl_dyn_disabled : btk_cl_pass_on;
|
||||||
|
fill_cell(c, c_ctx, btk_cl_field);
|
||||||
|
cairo_set_source_rgb(c_ctx, clt.r, clt.g, clt.b);
|
||||||
|
cairo_move_to(c_ctx, c->pa.x + label_offset.x, c->pa.y + label_offset.y);
|
||||||
|
cairo_show_text(c_ctx, "►");
|
||||||
|
|
||||||
|
/* limits */
|
||||||
|
int max_n = (c->pa.w - 3 * label_offset.x ) / glyph.w - 1;
|
||||||
|
if (pp->caret > pp->scroll + max_n - 1)
|
||||||
|
pp->scroll = pp->caret - max_n + 1;
|
||||||
|
if (pp->caret < pp->scroll)
|
||||||
|
pp->scroll = pp->caret;
|
||||||
|
if (text_n > max_n && pp->scroll + max_n > text_n)
|
||||||
|
pp->scroll -= pp->scroll + max_n - text_n;
|
||||||
|
|
||||||
|
/* render caret */
|
||||||
|
if (!(c->state & BTK_CELL_STATE_DISABLED)) {
|
||||||
|
cairo_set_source_rgb(c_ctx, btk_cl_bell.r, btk_cl_bell.g, btk_cl_bell.b);
|
||||||
|
cairo_move_to(c_ctx,
|
||||||
|
c->pa.x + 2 * label_offset.x + (1 + pp->caret - pp->scroll) * glyph.w,
|
||||||
|
c->pa.y + label_offset.y + btk_caret_offset);
|
||||||
|
cairo_show_text(c_ctx, "_");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare text to render */
|
||||||
|
char cut_text[max_n + 1];
|
||||||
|
if (text_n) {
|
||||||
|
strncpy(cut_text, pp->text + pp->scroll, max_n);
|
||||||
|
cut_text[max_n] = '\0';
|
||||||
|
clt2 = btk_cl_text_disabled;
|
||||||
|
} else {
|
||||||
|
strcpy(cut_text, c->label);
|
||||||
|
clt2 = btk_cl_text_lolight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* render text */
|
||||||
|
cairo_set_source_rgb(c_ctx, clt2.r, clt2.g, clt2.b);
|
||||||
|
cairo_move_to(c_ctx,
|
||||||
|
c->pa.x + 2 * label_offset.x + glyph.w,
|
||||||
|
c->pa.y + label_offset.y);
|
||||||
|
cairo_show_text(c_ctx, cut_text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_list(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
reset_field(c);
|
||||||
|
guard_scroll(&(PP_LIST(c)->scroll),
|
||||||
|
btk_cp.h + btk_frame,
|
||||||
|
c->pa.h,
|
||||||
|
*(PP_LIST(c)->items_n),
|
||||||
|
0);
|
||||||
|
|
||||||
|
/* compute item range to render */
|
||||||
|
int item_min = PP_LIST(c)->scroll / (btk_cp.h + btk_frame);
|
||||||
|
int item_max = (PP_LIST(c)->scroll + c->pa.h) / (btk_cp.h + btk_frame) + 1;
|
||||||
|
item_max = BTK_MIN(item_max, *(PP_LIST(c)->items_n));
|
||||||
|
|
||||||
|
/* just render label if there are no rows to draw */
|
||||||
|
if (!*(PP_LIST(c)->items_n)) {
|
||||||
|
write_label(c->fd->c_ctx,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
c->pa.w,
|
||||||
|
BTK_JUSTIFY_LEFT,
|
||||||
|
c->label,
|
||||||
|
btk_cl_text_lolight);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* render sub cells */
|
||||||
|
btk_rgb_t cl, clt;
|
||||||
|
int row_pos;
|
||||||
|
for (int i = item_min; i < item_max; i++) {
|
||||||
|
if (i == PP_LIST(c)->item_sel) {
|
||||||
|
if ((c->state & BTK_CELL_STATE_PRESSED)) {
|
||||||
|
cl = btk_cl_dyn_pressed;
|
||||||
|
clt = btk_cl_text_hilight;
|
||||||
|
} else {
|
||||||
|
clt = btk_cl_text_select;
|
||||||
|
cl = btk_cl_select;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cl = btk_cl_field;
|
||||||
|
clt = btk_cl_text_disabled;
|
||||||
|
if (PP_LIST(c)->spot)
|
||||||
|
clt = btk_cl[*(*(PP_LIST(c)->spot) + i)];
|
||||||
|
}
|
||||||
|
row_pos = (btk_cp.h + btk_frame) * i - PP_LIST(c)->scroll;
|
||||||
|
cairo_set_source_rgb(c->fd->c_ctx, cl.r, cl.g, cl.b);
|
||||||
|
cairo_rectangle(c->fd->c_ctx, 0, row_pos, c->pa.w, btk_cp.h);
|
||||||
|
cairo_fill(c->fd->c_ctx);
|
||||||
|
write_label(c->fd->c_ctx,
|
||||||
|
0,
|
||||||
|
row_pos,
|
||||||
|
c->pa.w,
|
||||||
|
BTK_JUSTIFY_LEFT,
|
||||||
|
*(PP_LIST(c)->items) + i * PP_LIST(c)->items_w,
|
||||||
|
clt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_mark(btk_cell_t *c, cairo_t *c_ctx)
|
||||||
|
{
|
||||||
|
fill_cell(c, c_ctx, btk_cl_pass_off);
|
||||||
|
|
||||||
|
btk_rgb_t clt, cl = {0.0f, 0.0f, 0.0f};
|
||||||
|
if ((c->state & BTK_CELL_STATE_BELL)) {
|
||||||
|
cl = btk_cl_bell;
|
||||||
|
clt = btk_cl_text_bell;
|
||||||
|
} else if ((c->state & BTK_CELL_STATE_ON)) {
|
||||||
|
cl = btk_cl_pass_on;
|
||||||
|
clt = btk_cl_text_hilight;
|
||||||
|
} else {
|
||||||
|
clt = c->state & BTK_CELL_STATE_DISABLED ?
|
||||||
|
btk_cl_text_disabled : btk_cl_text_normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((c->state & (BTK_CELL_STATE_BELL | BTK_CELL_STATE_ON))) {
|
||||||
|
cairo_set_source_rgb(c_ctx, cl.r, cl.g, cl.b);
|
||||||
|
cairo_rectangle(c_ctx,
|
||||||
|
c->pa.x + btk_frame,
|
||||||
|
c->pa.y + btk_frame,
|
||||||
|
c->pa.w - 2 * btk_frame,
|
||||||
|
c->pa.h - 2 * btk_frame);
|
||||||
|
cairo_fill(c_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_label(c_ctx, c->pa.x, c->pa.y, c->pa.w, PP_MARK(c)->justify, c->label, clt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_switch(btk_cell_t *c, cairo_t *c_ctx)
|
||||||
|
{
|
||||||
|
btk_rgb_t clt, cl;
|
||||||
|
if ((c->state & BTK_CELL_STATE_DISABLED)) {
|
||||||
|
cl = btk_cl_dyn_disabled;
|
||||||
|
clt = btk_cl_text_disabled;
|
||||||
|
} else if ((c->state & BTK_CELL_STATE_PRESSED)) {
|
||||||
|
cl = btk_cl_dyn_pressed;
|
||||||
|
clt = btk_cl_text_hilight;
|
||||||
|
} else {
|
||||||
|
cl = btk_cl_dyn_idle;
|
||||||
|
clt = btk_cl_text_normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
fill_cell(c, c_ctx, cl);
|
||||||
|
write_label(c_ctx,
|
||||||
|
c->pa.x,
|
||||||
|
c->pa.y,
|
||||||
|
c->pa.w - btk_cp.h,
|
||||||
|
BTK_JUSTIFY_LEFT,
|
||||||
|
c->label,
|
||||||
|
clt);
|
||||||
|
|
||||||
|
/* state indicator */
|
||||||
|
cl = (c->state & BTK_CELL_STATE_ON) ? btk_cl_pass_on : btk_cl_pass_off;
|
||||||
|
cairo_set_source_rgb(c_ctx, btk_cl_frame.r, btk_cl_frame.g, btk_cl_frame.b);
|
||||||
|
cairo_rectangle(c_ctx,
|
||||||
|
c->pa.x + c->pa.w - btk_cp.h + btk_padding,
|
||||||
|
c->pa.y + btk_padding,
|
||||||
|
btk_cp.h - 2 * btk_padding,
|
||||||
|
btk_cp.h - 2 * btk_padding);
|
||||||
|
cairo_fill(c_ctx);
|
||||||
|
cairo_set_source_rgb(c_ctx, cl.r, cl.g, cl.b);
|
||||||
|
cairo_rectangle(c_ctx,
|
||||||
|
c->pa.x + c->pa.w - btk_cp.h + btk_padding + btk_frame,
|
||||||
|
c->pa.y + btk_padding + btk_frame,
|
||||||
|
btk_cp.h - 2 * (btk_padding + btk_frame),
|
||||||
|
btk_cp.h - 2 * (btk_padding + btk_frame));
|
||||||
|
cairo_fill(c_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_table(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
reset_field(c);
|
||||||
|
btk_pp_table_t *pp = PP_TABLE(c);
|
||||||
|
|
||||||
|
/* horizontal then vertical scroll */
|
||||||
|
guard_scroll(&pp->scroll.x, pp->tw, c->pa.w, 1, 0);
|
||||||
|
guard_scroll(&pp->scroll.y, btk_cp.h + btk_frame, c->pa.h, *pp->rows_n + 1, 0);
|
||||||
|
|
||||||
|
int header_indent = pp->header ? 1 : 0;
|
||||||
|
|
||||||
|
/* compute item range to render */
|
||||||
|
int item_min = pp->scroll.y / (btk_cp.h + btk_frame);
|
||||||
|
int item_max = (pp->scroll.y + c->pa.h) / (btk_cp.h + btk_frame);
|
||||||
|
item_max = BTK_MIN(item_max, *pp->rows_n);
|
||||||
|
|
||||||
|
/* just render label if there are no rows to draw */
|
||||||
|
if (!*pp->rows_n) {
|
||||||
|
write_label(c->fd->c_ctx,
|
||||||
|
0,
|
||||||
|
header_indent * (btk_cp.h + btk_frame),
|
||||||
|
c->pa.w,
|
||||||
|
BTK_JUSTIFY_LEFT,
|
||||||
|
c->label,
|
||||||
|
btk_cl_text_lolight);
|
||||||
|
goto header;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* render rows */
|
||||||
|
btk_rgb_t cl, clt;
|
||||||
|
int row_pos;
|
||||||
|
for (int i = item_min; i < item_max; i++) {
|
||||||
|
if (i == pp->row_sel) {
|
||||||
|
if ((c->state & BTK_CELL_STATE_PRESSED)) {
|
||||||
|
cl = btk_cl_dyn_pressed;
|
||||||
|
clt = btk_cl_text_hilight;
|
||||||
|
} else {
|
||||||
|
clt = btk_cl_text_select;
|
||||||
|
cl = btk_cl_select;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cl = btk_cl_field;
|
||||||
|
clt = btk_cl_text_disabled;
|
||||||
|
if (pp->spot)
|
||||||
|
clt = btk_cl[*(*(PP_TABLE(c)->spot) + i)];
|
||||||
|
}
|
||||||
|
row_pos = (btk_cp.h + btk_frame) * (i + header_indent) - pp->scroll.y;
|
||||||
|
render_table_row(c, btk_cell_table_get_item(c, 0, i), row_pos, cl, clt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* render header */
|
||||||
|
header:
|
||||||
|
if (pp->header)
|
||||||
|
render_table_row(c, pp->header, 0, btk_cl_pass_off, btk_cl_text_normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
render_table_row(btk_cell_t *c,
|
||||||
|
char *row_data_start,
|
||||||
|
int row_pos,
|
||||||
|
btk_rgb_t cl,
|
||||||
|
btk_rgb_t clt)
|
||||||
|
{
|
||||||
|
btk_pp_table_t *pp = PP_TABLE(c);
|
||||||
|
char label[pp->items_w];
|
||||||
|
btk_rgb_t clt2;
|
||||||
|
|
||||||
|
for (int i = 0; i < pp->cols_n; i++) {
|
||||||
|
cairo_set_source_rgb(c->fd->c_ctx, cl.r, cl.g, cl.b);
|
||||||
|
cairo_rectangle(c->fd->c_ctx,
|
||||||
|
pp->cols_px[i] - pp->scroll.x,
|
||||||
|
row_pos, pp->cols_pw[i],
|
||||||
|
btk_cp.h);
|
||||||
|
cairo_fill(c->fd->c_ctx);
|
||||||
|
|
||||||
|
clt2 = clt;
|
||||||
|
strcpy(label, row_data_start + i * pp->items_w);
|
||||||
|
if (label[0] == '\n' || label[0] == '\0') {
|
||||||
|
clt2 = btk_cl_text_lolight;
|
||||||
|
strncpy(label, "-/-", pp->items_w);
|
||||||
|
}
|
||||||
|
write_label(c->fd->c_ctx,
|
||||||
|
pp->cols_px[i] - pp->scroll.x,
|
||||||
|
row_pos,
|
||||||
|
pp->cols_pw[i],
|
||||||
|
BTK_JUSTIFY_LEFT,
|
||||||
|
label,
|
||||||
|
clt2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
reset_field(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
if (!c->fd) {
|
||||||
|
btk_log_warning(BTK_WARNING_DRAW_NO_FIELD);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cairo_set_source_rgb(c->fd->c_ctx, btk_cl_empty.r, btk_cl_empty.g, btk_cl_empty.b);
|
||||||
|
cairo_paint(c->fd->c_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write_label(cairo_t *c_ctx,
|
||||||
|
int px,
|
||||||
|
int py,
|
||||||
|
unsigned int pw,
|
||||||
|
int justify,
|
||||||
|
char *label,
|
||||||
|
btk_rgb_t clt)
|
||||||
|
{
|
||||||
|
int n = strlen(label);
|
||||||
|
int max_n = (pw - 2 * label_offset.x) / glyph.w;
|
||||||
|
char cut_label[max_n];
|
||||||
|
|
||||||
|
/* make label fit in cell if needed */
|
||||||
|
if (n > max_n) {
|
||||||
|
int caret;
|
||||||
|
if (justify == BTK_JUSTIFY_LEFT) {
|
||||||
|
caret = max_n - 3;
|
||||||
|
strncpy(cut_label, label, max_n);
|
||||||
|
} else {
|
||||||
|
caret = 0;
|
||||||
|
strncpy(cut_label, label + n - max_n, max_n);
|
||||||
|
}
|
||||||
|
cut_label[caret] = '.';
|
||||||
|
cut_label[++caret] = '.';
|
||||||
|
cut_label[++caret] = '.';
|
||||||
|
cut_label[max_n] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* draw label */
|
||||||
|
cairo_set_source_rgb(c_ctx, clt.r, clt.g, clt.b);
|
||||||
|
if (justify == BTK_JUSTIFY_LEFT) {
|
||||||
|
cairo_move_to(c_ctx, px + label_offset.x, py + label_offset.y);
|
||||||
|
} else {
|
||||||
|
int a = n > max_n ? max_n : n;
|
||||||
|
cairo_move_to(c_ctx, px + pw - label_offset.x - glyph.w * a, py + label_offset.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *l = n > max_n ? cut_label : label;
|
||||||
|
cairo_show_text(c_ctx, l);
|
||||||
|
}
|
712
btk/btk-cell.c
Normal file
712
btk/btk-cell.c
Normal file
@ -0,0 +1,712 @@
|
|||||||
|
#include <cairo/cairo.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "btk-cell.h"
|
||||||
|
#include "btk-log.h"
|
||||||
|
#include "btk-cell-render.c"
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_button(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
char *label,
|
||||||
|
void (*func)(void))
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, 1);
|
||||||
|
c->group = BTK_CELL_GROUP_DYNAMIC;
|
||||||
|
c->type = BTK_CELL_TYPE_BUTTON;
|
||||||
|
c->lh = 1;
|
||||||
|
c->label = label;
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_button_t, c->pp);
|
||||||
|
PP_BUTTON(c)->func = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_editor(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
unsigned int ch,
|
||||||
|
char *text,
|
||||||
|
unsigned int text_w)
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, ch);
|
||||||
|
c->group = BTK_CELL_GROUP_FIELD;
|
||||||
|
c->type = BTK_CELL_TYPE_EDITOR;
|
||||||
|
c->lh = 0;
|
||||||
|
c->label = "no data";
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_editor_t, c->pp);
|
||||||
|
PP_EDITOR(c)->text = text;
|
||||||
|
PP_EDITOR(c)->text_w = text_w;
|
||||||
|
PP_EDITOR(c)->caret = 0;
|
||||||
|
PP_EDITOR(c)->caret_2d.x = 0;
|
||||||
|
PP_EDITOR(c)->caret_2d.y = 0;
|
||||||
|
PP_EDITOR(c)->scroll = 0;
|
||||||
|
PP_EDITOR(c)->par = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_empty(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
unsigned int ch)
|
||||||
|
{
|
||||||
|
c->group = BTK_CELL_GROUP_PASSIVE;
|
||||||
|
c->type = BTK_CELL_TYPE_EMPTY;
|
||||||
|
c->state = BTK_CELL_STATE_INITIAL;
|
||||||
|
c->ca.x = cx;
|
||||||
|
c->ca.y = cy;
|
||||||
|
c->ca.w = cw;
|
||||||
|
c->ca.h = ch;
|
||||||
|
c->lh = 0;
|
||||||
|
c->pp = NULL;
|
||||||
|
c->fd = NULL;
|
||||||
|
c->label = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_mark(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
int justify,
|
||||||
|
char *label)
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, 1);
|
||||||
|
c->type = BTK_CELL_TYPE_MARK;
|
||||||
|
c->lh = 1;
|
||||||
|
c->label = label;
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_mark_t, c->pp);
|
||||||
|
PP_MARK(c)->justify = justify;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_input(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
char *text,
|
||||||
|
unsigned int text_w)
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, 1);
|
||||||
|
c->group = BTK_CELL_GROUP_DYNAMIC;
|
||||||
|
c->type = BTK_CELL_TYPE_INPUT;
|
||||||
|
c->lh = 1;
|
||||||
|
c->label = "-/-";
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_input_t, c->pp);
|
||||||
|
PP_INPUT(c)->text = text;
|
||||||
|
PP_INPUT(c)->text_w = text_w;
|
||||||
|
PP_INPUT(c)->caret = 0;
|
||||||
|
PP_INPUT(c)->scroll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_list(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
unsigned int ch,
|
||||||
|
char **items,
|
||||||
|
unsigned int *items_n,
|
||||||
|
unsigned int items_w,
|
||||||
|
int **filter,
|
||||||
|
int **order,
|
||||||
|
int **spot,
|
||||||
|
void (*func_trigger)(int),
|
||||||
|
void (*func_sel)(int))
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, ch);
|
||||||
|
c->group = BTK_CELL_GROUP_FIELD;
|
||||||
|
c->type = BTK_CELL_TYPE_LIST;
|
||||||
|
c->label = "no data";
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_list_t, c->pp);
|
||||||
|
PP_LIST(c)->items = items;
|
||||||
|
PP_LIST(c)->items_n = items_n;
|
||||||
|
PP_LIST(c)->items_w = items_w;
|
||||||
|
PP_LIST(c)->item_sel = -1;
|
||||||
|
PP_LIST(c)->filter = filter;
|
||||||
|
PP_LIST(c)->order = order;
|
||||||
|
PP_LIST(c)->spot = spot;
|
||||||
|
PP_LIST(c)->scroll = 0;
|
||||||
|
PP_LIST(c)->func_trigger = func_trigger;
|
||||||
|
PP_LIST(c)->func_sel = func_sel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_switch(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
char *label,
|
||||||
|
void (*func)(int, btk_arg_t),
|
||||||
|
btk_arg_t func_args)
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, 1);
|
||||||
|
c->group = BTK_CELL_GROUP_DYNAMIC;
|
||||||
|
c->type = BTK_CELL_TYPE_SWITCH;
|
||||||
|
c->lh = 1;
|
||||||
|
c->label = label;
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_switch_t, c->pp);
|
||||||
|
PP_SWITCH(c)->func = func;
|
||||||
|
PP_SWITCH(c)->func_args = func_args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_set_table(btk_cell_t *c,
|
||||||
|
unsigned int cx,
|
||||||
|
unsigned int cy,
|
||||||
|
unsigned int cw,
|
||||||
|
unsigned int ch,
|
||||||
|
char *header, /* must be same item_w as items */
|
||||||
|
char **items,
|
||||||
|
unsigned int items_w,
|
||||||
|
unsigned int cols_n,
|
||||||
|
unsigned int *rows_n,
|
||||||
|
int *cols_ena,
|
||||||
|
unsigned int *cols_cw,
|
||||||
|
unsigned int sc,
|
||||||
|
int **filter,
|
||||||
|
int **order,
|
||||||
|
int **spot,
|
||||||
|
void (*func_trigger)(int),
|
||||||
|
void (*func_sel)(int))
|
||||||
|
{
|
||||||
|
btk_cell_set_empty(c, cx, cy, cw, ch);
|
||||||
|
c->group = BTK_CELL_GROUP_FIELD;
|
||||||
|
c->type = BTK_CELL_TYPE_TABLE;
|
||||||
|
c->label = "no data";
|
||||||
|
|
||||||
|
NEW_PP(btk_pp_table_t, c->pp);
|
||||||
|
PP_TABLE(c)->header = header;
|
||||||
|
PP_TABLE(c)->items = items;
|
||||||
|
PP_TABLE(c)->items_w = items_w;
|
||||||
|
PP_TABLE(c)->rows_n = rows_n;
|
||||||
|
PP_TABLE(c)->cols_n = cols_n;
|
||||||
|
PP_TABLE(c)->row_sel = -1;
|
||||||
|
PP_TABLE(c)->cols_ena = cols_ena;
|
||||||
|
PP_TABLE(c)->cols_cw = cols_cw;
|
||||||
|
PP_TABLE(c)->sc = sc;
|
||||||
|
PP_TABLE(c)->tw = 0;
|
||||||
|
PP_TABLE(c)->filter = filter;
|
||||||
|
PP_TABLE(c)->order = order;
|
||||||
|
PP_TABLE(c)->spot = spot;
|
||||||
|
PP_TABLE(c)->scroll.x = 0;
|
||||||
|
PP_TABLE(c)->scroll.y = 0;
|
||||||
|
PP_TABLE(c)->func_trigger = func_trigger;
|
||||||
|
PP_TABLE(c)->func_sel = func_sel;
|
||||||
|
|
||||||
|
PP_TABLE(c)->cols_pw = (unsigned int*)malloc(cols_n * sizeof(int));
|
||||||
|
PP_TABLE(c)->cols_px = (unsigned int*)malloc(cols_n * sizeof(int));
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************************************************************************/
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_button_trigger(btk_cell_t *c, int button)
|
||||||
|
{
|
||||||
|
if (button == 1 && PP_BUTTON(c)->func)
|
||||||
|
PP_BUTTON(c)->func();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_destroy(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
if (c->pp) {
|
||||||
|
switch (c->type) {
|
||||||
|
case BTK_CELL_TYPE_TABLE:
|
||||||
|
free(PP_TABLE(c)->cols_pw);
|
||||||
|
free(PP_TABLE(c)->cols_px);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_EDITOR:
|
||||||
|
btk_text_destroy_par(PP_EDITOR(c)->par);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(c->pp);
|
||||||
|
}
|
||||||
|
free(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_draw(btk_cell_t *c, cairo_t *c_ctx)
|
||||||
|
{
|
||||||
|
if (!c)
|
||||||
|
return;
|
||||||
|
if ((c->state & BTK_CELL_STATE_HIDDEN))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch(c->type) {
|
||||||
|
case BTK_CELL_TYPE_MARK:
|
||||||
|
render_mark(c, c_ctx);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_BUTTON:
|
||||||
|
render_button(c, c_ctx);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_SWITCH:
|
||||||
|
render_switch(c, c_ctx);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_LIST:
|
||||||
|
render_list(c);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_TABLE:
|
||||||
|
render_table(c);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_INPUT:
|
||||||
|
render_input(c, c_ctx);
|
||||||
|
break;
|
||||||
|
case BTK_CELL_TYPE_EDITOR:
|
||||||
|
render_editor(c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fill_cell(c, c_ctx, btk_cl_empty);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_editor_input_button(btk_cell_t *c, int button, int combo, btk_pos_t pt)
|
||||||
|
{
|
||||||
|
/* scrolling if appropriate button is clicked */
|
||||||
|
switch (button) {
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
PP_EDITOR(c)->scroll -= btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
case 5:
|
||||||
|
PP_EDITOR(c)->scroll += btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* caret positioning */
|
||||||
|
if (pt.x < label_offset.x || pt.x >= c->pa.w - label_offset.x ||
|
||||||
|
pt.y < label_offset.y - glyph.h)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PP_EDITOR(c)->caret_2d.x = (pt.x - label_offset.x) / glyph.w;
|
||||||
|
PP_EDITOR(c)->caret_2d.y = (pt.y - label_offset.y + PP_EDITOR(c)->scroll + glyph.h) / (glyph.h + btk_text_spacing);
|
||||||
|
PP_EDITOR(c)->caret_2d = btk_text_guard_2d_caret(PP_EDITOR(c)->par, PP_EDITOR(c)->caret_2d);
|
||||||
|
PP_EDITOR(c)->caret = btk_text_caret_2dto1d(PP_EDITOR(c)->par, PP_EDITOR(c)->caret_2d);
|
||||||
|
//btk_text_caret_1dto2d(PP_EDITOR(c)->par, PP_EDITOR(c)->caret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_editor_input_key(btk_cell_t *c, uint32_t key)
|
||||||
|
{
|
||||||
|
btk_pp_editor_t *pp = PP_EDITOR(c);
|
||||||
|
int caret_type, modif = 0;
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 0xff08:
|
||||||
|
pp->caret -= btk_text_del_char(pp->text, pp->caret, 0);
|
||||||
|
caret_type = 0;
|
||||||
|
modif = 1;
|
||||||
|
break;
|
||||||
|
case 0xff50:
|
||||||
|
pp->caret_2d.x = 0;
|
||||||
|
caret_type = 1;
|
||||||
|
break;
|
||||||
|
case 0xff51:
|
||||||
|
pp->caret--;
|
||||||
|
caret_type = 0;
|
||||||
|
break;
|
||||||
|
case 0xff52:
|
||||||
|
pp->caret_2d.y--;
|
||||||
|
caret_type = 1;
|
||||||
|
break;
|
||||||
|
case 0xff53:
|
||||||
|
pp->caret++;
|
||||||
|
caret_type = 0;
|
||||||
|
break;
|
||||||
|
case 0xff54:
|
||||||
|
pp->caret_2d.y++;
|
||||||
|
caret_type = 1;
|
||||||
|
break;
|
||||||
|
case 0xff57:
|
||||||
|
pp->caret_2d.x = pp->text_w;
|
||||||
|
caret_type = 1;
|
||||||
|
break;
|
||||||
|
case 0xffff:
|
||||||
|
btk_text_del_char(pp->text, pp->caret, 1);
|
||||||
|
caret_type = 0;
|
||||||
|
modif = 1;
|
||||||
|
break;
|
||||||
|
case 0xff0d:
|
||||||
|
pp->caret += btk_text_insert_char(pp->text, '\n', pp->caret, pp->text_w);
|
||||||
|
caret_type = 0;
|
||||||
|
modif = 1;
|
||||||
|
break;
|
||||||
|
case 0xff09:
|
||||||
|
pp->caret += btk_text_insert_char(pp->text, '\t', pp->caret, pp->text_w);
|
||||||
|
caret_type = 0;
|
||||||
|
modif = 1;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
/* only allow ascii printable chars */
|
||||||
|
if (key < 32 || key >= 127)
|
||||||
|
return;
|
||||||
|
pp->caret += btk_text_insert_char(pp->text, key, pp->caret, pp->text_w);
|
||||||
|
caret_type = 0;
|
||||||
|
modif = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (modif) {
|
||||||
|
btk_cell_editor_update_text(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (caret_type) {
|
||||||
|
pp->caret_2d = btk_text_guard_2d_caret(pp->par, pp->caret_2d);
|
||||||
|
pp->caret = btk_text_caret_2dto1d(pp->par, pp->caret_2d);
|
||||||
|
} else {
|
||||||
|
pp->caret = btk_text_guard_1d_caret(pp->text, pp->caret);
|
||||||
|
pp->caret_2d = btk_text_caret_1dto2d(pp->par, pp->caret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* modify scroll to show caret if needed */
|
||||||
|
if (pp->caret_2d.y * (glyph.h + btk_text_spacing) < pp->scroll)
|
||||||
|
pp->scroll = pp->caret_2d.y * (glyph.h + btk_text_spacing);
|
||||||
|
if (pp->caret_2d.y * (glyph.h + btk_text_spacing) >= pp->scroll + c->pa.h - 2 * label_offset.y) {
|
||||||
|
pp->scroll = (pp->caret_2d.y + 1) * (glyph.h + btk_text_spacing) - c->pa.h + label_offset.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_editor_reset_caret(btk_cell_t*c)
|
||||||
|
{
|
||||||
|
PP_EDITOR(c)->caret = 0;
|
||||||
|
PP_EDITOR(c)->caret_2d.x = 0;
|
||||||
|
PP_EDITOR(c)->caret_2d.y = 0;
|
||||||
|
PP_EDITOR(c)->scroll = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_editor_update_text(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
btk_pp_editor_t *pp = PP_EDITOR(c);
|
||||||
|
int max_n = (c->pa.w - 2 * label_offset.x) / glyph.w + 1;
|
||||||
|
|
||||||
|
if (!pp->text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pp->par)
|
||||||
|
btk_text_destroy_par(pp->par);
|
||||||
|
|
||||||
|
pp->par = btk_text_get_par(pp->text, max_n);
|
||||||
|
pp->caret_2d = btk_text_caret_1dto2d(pp->par, pp->caret);
|
||||||
|
|
||||||
|
/* modify scroll to show caret if needed */
|
||||||
|
if (pp->caret_2d.y * (glyph.h + btk_text_spacing) < pp->scroll)
|
||||||
|
pp->scroll = pp->caret_2d.y * (glyph.h + btk_text_spacing);
|
||||||
|
if (pp->caret_2d.y * (glyph.h + btk_text_spacing) >= pp->scroll + c->pa.h - label_offset.y) {
|
||||||
|
pp->scroll = (pp->caret_2d.y + 1) * (glyph.h + btk_text_spacing) - c->pa.h + label_offset.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btk_field_t*
|
||||||
|
btk_cell_field_create(cairo_surface_t *c_srf, btk_area_t a)
|
||||||
|
{
|
||||||
|
btk_field_t *f = (btk_field_t *)malloc(sizeof(btk_field_t));
|
||||||
|
f->c_srf = cairo_surface_create_for_rectangle(c_srf, a.x, a.y, a.w, a.h);
|
||||||
|
f->c_ctx = cairo_create(f->c_srf);
|
||||||
|
|
||||||
|
cairo_set_font_options(f->c_ctx, font_opt);
|
||||||
|
cairo_set_font_size(f->c_ctx, btk_font_size);
|
||||||
|
cairo_select_font_face(f->c_ctx,
|
||||||
|
btk_font_name,
|
||||||
|
CAIRO_FONT_SLANT_NORMAL,
|
||||||
|
CAIRO_FONT_WEIGHT_NORMAL);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_field_destroy(btk_field_t *f)
|
||||||
|
{
|
||||||
|
if (!f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cairo_destroy(f->c_ctx);
|
||||||
|
cairo_surface_destroy(f->c_srf);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_input_button(btk_cell_t *c, int button, int combo, btk_pos_t pt)
|
||||||
|
{
|
||||||
|
if (button != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pt.x >= 2 * label_offset.x + glyph.w && pt.x < c->pa.w - label_offset.x)
|
||||||
|
PP_INPUT(c)->caret = (pt.x - 2 * label_offset.x - glyph.w) /
|
||||||
|
glyph.w + PP_INPUT(c)->scroll;
|
||||||
|
|
||||||
|
int text_n = strlen(PP_INPUT(c)->text);
|
||||||
|
if (PP_INPUT(c)->caret < 0)
|
||||||
|
PP_INPUT(c)->caret = 0;
|
||||||
|
if (PP_INPUT(c)->caret > text_n)
|
||||||
|
PP_INPUT(c)->caret = text_n;
|
||||||
|
|
||||||
|
/* TODO combo clicks selections */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_input_input_key(btk_cell_t *c, uint32_t key)
|
||||||
|
{
|
||||||
|
btk_pp_input_t *pp = PP_INPUT(c);
|
||||||
|
|
||||||
|
switch (key) {
|
||||||
|
case 0xff08:
|
||||||
|
pp->caret -= btk_text_del_char(pp->text, pp->caret, 0);
|
||||||
|
break;
|
||||||
|
case 0xff50:
|
||||||
|
pp->caret = 0;
|
||||||
|
break;
|
||||||
|
case 0xff51:
|
||||||
|
pp->caret--;
|
||||||
|
break;
|
||||||
|
case 0xff53:
|
||||||
|
pp->caret++;
|
||||||
|
break;
|
||||||
|
case 0xff57:
|
||||||
|
pp->caret = pp->text_w;
|
||||||
|
break;
|
||||||
|
case 0xffff:
|
||||||
|
btk_text_del_char(pp->text, pp->caret, 1);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
/* only allow ascii printable chars */
|
||||||
|
if (key < 32 || key >= 127)
|
||||||
|
return;
|
||||||
|
pp->caret += btk_text_insert_char(pp->text, key, pp->caret, pp->text_w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int text_n = strlen(pp->text);
|
||||||
|
if (pp->caret < 0)
|
||||||
|
pp->caret = 0;
|
||||||
|
if (pp->caret > text_n)
|
||||||
|
pp->caret = text_n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_input_reset_caret(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
PP_INPUT(c)->caret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_list_deselect(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
PP_LIST(c)->item_sel = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_list_input_button(btk_cell_t *c, int button, int combo, btk_pos_t pt)
|
||||||
|
{
|
||||||
|
btk_pp_list_t *pp = PP_LIST(c);
|
||||||
|
int prev_sel = pp->item_sel;
|
||||||
|
|
||||||
|
/* scrolling if appropriate button is clicked */
|
||||||
|
switch (button) {
|
||||||
|
case 4:
|
||||||
|
pp->scroll -= btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
case 5:
|
||||||
|
pp->scroll += btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* filter out remaining unwanted inputs */
|
||||||
|
if (button != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* find item under pointer */
|
||||||
|
pp->item_sel = (pt.y + pp->scroll) / (btk_cp.h + btk_frame);
|
||||||
|
|
||||||
|
/* deselect if out of bounds */
|
||||||
|
if (pp->item_sel < 0 || pp->item_sel >= *(pp->items_n))
|
||||||
|
pp->item_sel = -1;
|
||||||
|
|
||||||
|
/* adjust scrolling so that select item is displayed in full */
|
||||||
|
// TODO
|
||||||
|
|
||||||
|
/* on selection change, exec sel func */
|
||||||
|
if (prev_sel != pp->item_sel && pp->func_sel)
|
||||||
|
pp->func_sel(pp->item_sel);
|
||||||
|
|
||||||
|
/* if double click, exec trigger func */
|
||||||
|
if (combo == 2 && pp->func_trigger)
|
||||||
|
pp->func_trigger(pp->item_sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
btk_cell_list_get_sel(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
return PP_LIST(c)->item_sel;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_setup_font(cairo_t *c_ctx)
|
||||||
|
{
|
||||||
|
font_opt = cairo_font_options_create();
|
||||||
|
cairo_font_options_set_subpixel_order(font_opt, CAIRO_SUBPIXEL_ORDER_DEFAULT);
|
||||||
|
cairo_font_options_set_antialias(font_opt, CAIRO_ANTIALIAS_NONE);
|
||||||
|
cairo_font_options_set_hint_style(font_opt, CAIRO_HINT_STYLE_SLIGHT);
|
||||||
|
cairo_font_options_set_hint_metrics(font_opt, CAIRO_HINT_METRICS_ON);
|
||||||
|
|
||||||
|
cairo_set_font_options(c_ctx, font_opt);
|
||||||
|
cairo_set_font_size(c_ctx, btk_font_size);
|
||||||
|
cairo_select_font_face(c_ctx,
|
||||||
|
btk_font_name,
|
||||||
|
CAIRO_FONT_SLANT_NORMAL,
|
||||||
|
CAIRO_FONT_WEIGHT_NORMAL);
|
||||||
|
|
||||||
|
cairo_font_extents_t fe;
|
||||||
|
cairo_font_extents(c_ctx, &fe);
|
||||||
|
glyph.h = fe.height;
|
||||||
|
glyph.w = fe.max_x_advance;
|
||||||
|
label_offset.x = (btk_cp.h - fe.ascent) / 2 + btk_text_offset_tweak.x;
|
||||||
|
label_offset.y = (btk_cp.h - fe.ascent) / 2 + btk_text_offset_tweak.y + fe.ascent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_switch_toggle(btk_cell_t *c, int button)
|
||||||
|
{
|
||||||
|
if (button != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
c->state ^= BTK_CELL_STATE_ON;
|
||||||
|
if (PP_SWITCH(c)->func)
|
||||||
|
PP_SWITCH(c)->func(((c->state & BTK_CELL_STATE_ON) >> 4), PP_SWITCH(c)->func_args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_table_deselect(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
PP_TABLE(c)->row_sel = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
btk_cell_table_get_item(btk_cell_t *c, int col, int row)
|
||||||
|
{
|
||||||
|
if (col < 0 || row < 0 || col >= PP_TABLE(c)->cols_n || row >= *(PP_TABLE(c)->rows_n))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return *(PP_TABLE(c)->items) +
|
||||||
|
PP_TABLE(c)->items_w * (col + row * PP_TABLE(c)->cols_n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_table_input_button(btk_cell_t *c, int button, int combo, btk_pos_t pt)
|
||||||
|
{
|
||||||
|
btk_pp_table_t *pp = PP_TABLE(c);
|
||||||
|
int prev_sel = pp->row_sel;
|
||||||
|
|
||||||
|
/* scrolling if appropriate button is clicked */
|
||||||
|
switch (button) {
|
||||||
|
case 4:
|
||||||
|
pp->scroll.y -= btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
case 5:
|
||||||
|
pp->scroll.y += btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
case 6:
|
||||||
|
pp->scroll.x -= btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
case 7:
|
||||||
|
pp->scroll.x += btk_scroll_speed;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO ugly af block, to redo */
|
||||||
|
/* if click on header */
|
||||||
|
if (pt.y < btk_cp.h) {
|
||||||
|
int ena;
|
||||||
|
/* find clicked column */
|
||||||
|
for (int i = 0; i < pp->cols_n; i++) {
|
||||||
|
ena = pp->cols_ena ? pp->cols_ena[i] : 1;
|
||||||
|
if (ena && pt.x > pp->cols_px[i] && pt.x <= pp->cols_px[i] + pp->cols_pw[i]) {
|
||||||
|
switch (button) {
|
||||||
|
case 1:
|
||||||
|
pp->cols_cw[i]++;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
/* TODO sorting ? */
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
pp->cols_cw[i] -= pp->cols_cw[i] > 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
btk_cell_table_update_geometry(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remaining item list actions */
|
||||||
|
/* filter out unwanted inputs */
|
||||||
|
if (button != 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* find item under pointer */
|
||||||
|
pp->row_sel = (pt.y + pp->scroll.y) / (btk_cp.h + btk_frame) -1;
|
||||||
|
|
||||||
|
/* deselect if out of bounds */
|
||||||
|
if (pp->row_sel < 0 || pp->row_sel >= *(pp->rows_n))
|
||||||
|
pp->row_sel = -1;
|
||||||
|
|
||||||
|
/* on selection change, exec sel func */
|
||||||
|
if (prev_sel != pp->row_sel && pp->func_sel)
|
||||||
|
pp->func_sel(pp->row_sel);
|
||||||
|
|
||||||
|
/* if double click, exec trigger func */
|
||||||
|
if (combo == 2 && pp->func_trigger)
|
||||||
|
pp->func_trigger(pp->row_sel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_cell_table_update_geometry(btk_cell_t *c)
|
||||||
|
{
|
||||||
|
btk_pp_table_t *pp = PP_TABLE(c);
|
||||||
|
unsigned int cw = 0; /* width in cell units */
|
||||||
|
unsigned int pw = 0; /* total minimum pixel width */
|
||||||
|
unsigned int ew = 0; /* extra width if tw > minimum width */
|
||||||
|
int ena;
|
||||||
|
|
||||||
|
/* calculate extra width in pixels */
|
||||||
|
for (int i = 0; i < pp->cols_n; i++) {
|
||||||
|
ena = pp->cols_ena ? pp->cols_ena[i] : 1;
|
||||||
|
cw += ena ? pp->cols_cw[i] : 0;
|
||||||
|
}
|
||||||
|
pw = cw * (btk_cp.w + btk_frame) - btk_frame;
|
||||||
|
ew = pw < c->pa.w ? c->pa.w - pw : 0;
|
||||||
|
pp->tw = pw + ew;
|
||||||
|
|
||||||
|
/* calculate each columns widths in pixels */
|
||||||
|
for (int i = 0; i < pp->cols_n; i++) {
|
||||||
|
pp->cols_pw[i] = pp->cols_cw[i] * (btk_cp.w + btk_frame) - btk_frame;
|
||||||
|
pp->cols_pw[i] += pp->sc == i ? ew : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate columns positions */
|
||||||
|
int pos = 0;
|
||||||
|
for (int i = 0; i < pp->cols_n; i++) {
|
||||||
|
pp->cols_px[i] = pos;
|
||||||
|
ena = pp->cols_ena ? pp->cols_ena[i] : 1;
|
||||||
|
pos += ena ? pp->cols_pw[i] + btk_frame : 0;
|
||||||
|
}
|
||||||
|
}
|
223
btk/btk-cell.h
Normal file
223
btk/btk-cell.h
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
#include <cairo/cairo.h>
|
||||||
|
|
||||||
|
#include "btk-text.h"
|
||||||
|
|
||||||
|
#define NEW_PP(type, pp) (pp = (type*)malloc(sizeof(type)))
|
||||||
|
|
||||||
|
#define PP_BUTTON(c) ((btk_pp_button_t*)c->pp)
|
||||||
|
#define PP_EDITOR(c) ((btk_pp_editor_t*)c->pp)
|
||||||
|
#define PP_INPUT(c) ((btk_pp_input_t*)c->pp)
|
||||||
|
#define PP_LIST(c) ((btk_pp_list_t*)c->pp)
|
||||||
|
#define PP_MARK(c) ((btk_pp_mark_t*)c->pp)
|
||||||
|
#define PP_SWITCH(c) ((btk_pp_switch_t*)c->pp)
|
||||||
|
#define PP_TABLE(c) ((btk_pp_table_t*)c->pp)
|
||||||
|
|
||||||
|
enum btk_cell_states {
|
||||||
|
BTK_CELL_STATE_INITIAL = 0,
|
||||||
|
BTK_CELL_STATE_HIDDEN = 1U << 0,
|
||||||
|
BTK_CELL_STATE_DISABLED = 1U << 1,
|
||||||
|
BTK_CELL_STATE_FOCUSED = 1U << 2,
|
||||||
|
BTK_CELL_STATE_PRESSED = 1U << 3,
|
||||||
|
BTK_CELL_STATE_ON = 1U << 4,
|
||||||
|
BTK_CELL_STATE_BELL = 1U << 5,
|
||||||
|
BTK_CELL_STATE_IN = 1U << 6
|
||||||
|
};
|
||||||
|
|
||||||
|
enum btk_cell_group {
|
||||||
|
BTK_CELL_GROUP_PASSIVE,
|
||||||
|
BTK_CELL_GROUP_DYNAMIC,
|
||||||
|
BTK_CELL_GROUP_FIELD
|
||||||
|
};
|
||||||
|
|
||||||
|
enum btk_cell_type {
|
||||||
|
BTK_CELL_TYPE_EMPTY,
|
||||||
|
BTK_CELL_TYPE_MARK,
|
||||||
|
BTK_CELL_TYPE_GAUGE,
|
||||||
|
BTK_CELL_TYPE_BUTTON,
|
||||||
|
BTK_CELL_TYPE_SWITCH,
|
||||||
|
BTK_CELL_TYPE_WHEEL,
|
||||||
|
BTK_CELL_TYPE_LIST,
|
||||||
|
BTK_CELL_TYPE_TABLE,
|
||||||
|
BTK_CELL_TYPE_INPUT,
|
||||||
|
BTK_CELL_TYPE_PROMPT,
|
||||||
|
BTK_CELL_TYPE_EDITOR
|
||||||
|
};
|
||||||
|
|
||||||
|
enum btk_cell_table_col_state {
|
||||||
|
BTK_CELL_TABLE_COL_HIDDEN,
|
||||||
|
BTK_CELL_TABLE_COL_VISIBLE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* global properties */
|
||||||
|
unsigned int group;
|
||||||
|
unsigned int type;
|
||||||
|
unsigned int state;
|
||||||
|
btk_area_t ca; /* geometry in cell coordinates */
|
||||||
|
btk_area_t pa; /* geometry in pixel coordinates */
|
||||||
|
void *pp; /* type specific properties to cast */
|
||||||
|
btk_field_t *fd; /* for field group types only */
|
||||||
|
int lh; /* lock pixel height from stretching */
|
||||||
|
char *label;
|
||||||
|
} btk_cell_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*func)(void);
|
||||||
|
} btk_pp_button_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *text;
|
||||||
|
unsigned int text_w;
|
||||||
|
btk_pos_t caret_2d;
|
||||||
|
int caret;
|
||||||
|
int scroll;
|
||||||
|
btk_par_t *par;
|
||||||
|
} btk_pp_editor_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *text;
|
||||||
|
unsigned int text_w; /* max text size */
|
||||||
|
int caret;
|
||||||
|
int scroll;
|
||||||
|
} btk_pp_input_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char **items;
|
||||||
|
unsigned int *items_n;
|
||||||
|
unsigned int items_w;
|
||||||
|
int item_sel;
|
||||||
|
int **filter; // TODO
|
||||||
|
int **order; // TODO
|
||||||
|
int **spot;
|
||||||
|
int scroll;
|
||||||
|
void (*func_trigger)(int);
|
||||||
|
void (*func_sel)(int);
|
||||||
|
} btk_pp_list_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int justify;
|
||||||
|
} btk_pp_mark_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
void (*func)(int, btk_arg_t);
|
||||||
|
btk_arg_t func_args;
|
||||||
|
} btk_pp_switch_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *header;
|
||||||
|
char **items;
|
||||||
|
unsigned int items_w;
|
||||||
|
unsigned int cols_n;
|
||||||
|
unsigned int *rows_n;
|
||||||
|
int row_sel;
|
||||||
|
int *cols_ena; /* hidden cols */
|
||||||
|
unsigned int *cols_cw; /* width in cell units of each col */
|
||||||
|
unsigned int *cols_pw; /* width in picels of each col */
|
||||||
|
unsigned int *cols_px; /* position of each col in pixels */
|
||||||
|
unsigned int sc; /* stretch col */
|
||||||
|
unsigned int tw; /* columns total pixel width */
|
||||||
|
int **filter; // TODO
|
||||||
|
int **order; // TODO
|
||||||
|
int **spot;
|
||||||
|
btk_pos_t scroll;
|
||||||
|
void (*func_trigger)(int);
|
||||||
|
void (*func_sel)(int);
|
||||||
|
} btk_pp_table_t;
|
||||||
|
|
||||||
|
void btk_cell_set_button (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
char *,
|
||||||
|
void (*)(void));
|
||||||
|
|
||||||
|
void btk_cell_set_editor (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
char *,
|
||||||
|
unsigned int);
|
||||||
|
|
||||||
|
void btk_cell_set_empty (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int);
|
||||||
|
|
||||||
|
void btk_cell_set_input (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
char *,
|
||||||
|
unsigned int);
|
||||||
|
|
||||||
|
void btk_cell_set_list (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
char **,
|
||||||
|
unsigned int *,
|
||||||
|
unsigned int,
|
||||||
|
int **,
|
||||||
|
int **,
|
||||||
|
int **,
|
||||||
|
void (*)(int),
|
||||||
|
void (*)(int));
|
||||||
|
|
||||||
|
void btk_cell_set_mark (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
int,
|
||||||
|
char *);
|
||||||
|
|
||||||
|
void btk_cell_set_switch (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
char *,
|
||||||
|
void (*)(int, btk_arg_t),
|
||||||
|
btk_arg_t);
|
||||||
|
|
||||||
|
void btk_cell_set_table (btk_cell_t *,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
char *,
|
||||||
|
char **,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int,
|
||||||
|
unsigned int *,
|
||||||
|
int *,
|
||||||
|
unsigned int *,
|
||||||
|
unsigned int,
|
||||||
|
int **,
|
||||||
|
int **,
|
||||||
|
int **,
|
||||||
|
void (*)(int),
|
||||||
|
void (*)(int));
|
||||||
|
|
||||||
|
void btk_cell_button_trigger (btk_cell_t *, int);
|
||||||
|
void btk_cell_destroy (btk_cell_t *);
|
||||||
|
void btk_cell_draw (btk_cell_t *, cairo_t *);
|
||||||
|
void btk_cell_editor_input_button (btk_cell_t *, int, int, btk_pos_t);
|
||||||
|
void btk_cell_editor_input_key (btk_cell_t *, uint32_t);
|
||||||
|
void btk_cell_editor_reset_caret (btk_cell_t*);
|
||||||
|
void btk_cell_editor_update_text (btk_cell_t *);
|
||||||
|
btk_field_t* btk_cell_field_create (cairo_surface_t *, btk_area_t);
|
||||||
|
void btk_cell_input_button (btk_cell_t *, int, int, btk_pos_t);
|
||||||
|
void btk_cell_input_input_key (btk_cell_t *, uint32_t);
|
||||||
|
void btk_cell_input_reset_caret (btk_cell_t *);
|
||||||
|
void btk_cell_field_destroy (btk_field_t *);
|
||||||
|
void btk_cell_list_deselect (btk_cell_t*);
|
||||||
|
void btk_cell_list_input_button (btk_cell_t *, int, int, btk_pos_t);
|
||||||
|
int btk_cell_list_get_sel (btk_cell_t *);
|
||||||
|
void btk_cell_setup_font (cairo_t *c_ctx);
|
||||||
|
void btk_cell_switch_toggle (btk_cell_t *, int);
|
||||||
|
void btk_cell_table_deselect (btk_cell_t*);
|
||||||
|
char* btk_cell_table_get_item (btk_cell_t *, int, int);
|
||||||
|
void btk_cell_table_input_button (btk_cell_t *, int, int, btk_pos_t);
|
||||||
|
void btk_cell_table_update_geometry (btk_cell_t *);
|
359
btk/btk.c
Normal file
359
btk/btk.c
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "btk.h"
|
||||||
|
#include "btk-log.h"
|
||||||
|
|
||||||
|
void event_button_press (btk_session_t *, xcb_button_press_event_t *);
|
||||||
|
void event_button_release (btk_session_t *, xcb_button_release_event_t *);
|
||||||
|
void event_client_message (btk_session_t *, xcb_client_message_event_t *);
|
||||||
|
void event_enter_window (btk_session_t *, xcb_enter_notify_event_t *);
|
||||||
|
void event_expose (btk_session_t *, xcb_expose_event_t *);
|
||||||
|
void event_key_press (btk_session_t *, xcb_key_press_event_t *);
|
||||||
|
void event_leave_window (btk_session_t *, xcb_leave_notify_event_t *);
|
||||||
|
void event_pointer_motion (btk_session_t *, xcb_motion_notify_event_t *);
|
||||||
|
int get_btk_window_id (btk_session_t *, xcb_window_t);
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_close(btk_session_t *s)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < s->windows_n; i++)
|
||||||
|
if (!s->windows[i])
|
||||||
|
btk_window_destroy(s->windows[i]);
|
||||||
|
|
||||||
|
xcb_disconnect(s->x_con);
|
||||||
|
btk_log(BTK_LOG_SESSION_CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_loop(btk_session_t *s, btk_window_t **w, int windows_n)
|
||||||
|
{
|
||||||
|
if (!w || !windows_n) {
|
||||||
|
btk_log_warning(BTK_WARNING_EMPTY_LOOP);
|
||||||
|
btk_log(BTK_LOG_EVENT_LOOP_OUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->windows = w;
|
||||||
|
s->windows_n = windows_n;
|
||||||
|
s->window_focus = 0;
|
||||||
|
s->window_press = -1;
|
||||||
|
|
||||||
|
/* set initial cell geometry and fonts */
|
||||||
|
for (int i = 0; i < windows_n; i++) {
|
||||||
|
btk_cell_setup_font(w[i]->c_ctx);
|
||||||
|
btk_window_init_cells(w[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* actual event loop */
|
||||||
|
btk_log(BTK_LOG_EVENT_LOOP_IN);
|
||||||
|
xcb_generic_event_t *x_ev;
|
||||||
|
while ((x_ev = xcb_wait_for_event(s->x_con))) {
|
||||||
|
switch (x_ev->response_type & ~0x80) {
|
||||||
|
case XCB_EXPOSE:
|
||||||
|
event_expose(s, (xcb_expose_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_MOTION_NOTIFY:
|
||||||
|
event_pointer_motion(s, (xcb_motion_notify_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_BUTTON_PRESS:
|
||||||
|
event_button_press(s, (xcb_button_press_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_BUTTON_RELEASE:
|
||||||
|
event_button_release(s, (xcb_button_release_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_KEY_PRESS:
|
||||||
|
event_key_press(s, (xcb_key_press_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_ENTER_NOTIFY:
|
||||||
|
event_enter_window(s, (xcb_enter_notify_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_LEAVE_NOTIFY:
|
||||||
|
event_leave_window(s, (xcb_leave_notify_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
case XCB_CLIENT_MESSAGE:
|
||||||
|
event_client_message(s, (xcb_client_message_event_t*)x_ev);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
btk_log(BTK_LOG_GENERIC_EVENT_NOTIFY);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
free(x_ev);
|
||||||
|
xcb_flush(s->x_con);
|
||||||
|
}
|
||||||
|
btk_log(BTK_LOG_EVENT_LOOP_OUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_map(btk_session_t *s, btk_window_t *w)
|
||||||
|
{
|
||||||
|
w->state |= BTK_WINDOW_STATE_MAPPED;
|
||||||
|
xcb_map_window(s->x_con, w->x_win);
|
||||||
|
xcb_flush(s->x_con);
|
||||||
|
btk_log(BTK_LOG_WINDOW_MAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
btk_session_t*
|
||||||
|
btk_open()
|
||||||
|
{
|
||||||
|
btk_session_t *s = (btk_session_t*)malloc(sizeof(btk_session_t));
|
||||||
|
|
||||||
|
/* base X stuff */
|
||||||
|
s->x_con = xcb_connect(NULL, NULL);
|
||||||
|
if (!s->x_con)
|
||||||
|
btk_log_error(BTK_ERROR_X_CONNECTION);
|
||||||
|
|
||||||
|
s->x_scr = xcb_setup_roots_iterator(xcb_get_setup(s->x_con)).data;
|
||||||
|
if (!s->x_scr)
|
||||||
|
btk_log_error(BTK_ERROR_X_SCREEN);
|
||||||
|
|
||||||
|
/* setup x visual type for cairo surfaces */
|
||||||
|
/* magic function from documentation */
|
||||||
|
xcb_depth_iterator_t x_di = xcb_screen_allowed_depths_iterator(s->x_scr);
|
||||||
|
for (; x_di.rem; xcb_depth_next(&x_di)) {
|
||||||
|
xcb_visualtype_iterator_t x_vi;
|
||||||
|
x_vi = xcb_depth_visuals_iterator(x_di.data);
|
||||||
|
for (; x_vi.rem; xcb_visualtype_next(&x_vi)) {
|
||||||
|
if (s->x_scr->root_visual == x_vi.data->visual_id) {
|
||||||
|
s->x_vis = x_vi.data;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!s->x_vis)
|
||||||
|
btk_log_error(BTK_ERROR_X_VISUAL);
|
||||||
|
|
||||||
|
/* setup keysym table for keyboard input */
|
||||||
|
const xcb_setup_t *x_stp = xcb_get_setup(s->x_con);
|
||||||
|
xcb_get_keyboard_mapping_reply_t* x_km =
|
||||||
|
xcb_get_keyboard_mapping_reply(
|
||||||
|
s->x_con,
|
||||||
|
xcb_get_keyboard_mapping(
|
||||||
|
s->x_con,
|
||||||
|
x_stp->min_keycode,
|
||||||
|
x_stp->max_keycode - x_stp->min_keycode + 1),
|
||||||
|
NULL);
|
||||||
|
if (!x_km)
|
||||||
|
btk_log_error(BTK_ERROR_X_KEYSYMS);
|
||||||
|
xcb_keysym_t *x_ks = (xcb_keysym_t*)(x_km + 1);
|
||||||
|
s->x_nks = x_km->keysyms_per_keycode;
|
||||||
|
s->x_nkc = x_km->length / s->x_nks;
|
||||||
|
/* copy x_ks into s->x_ksm because x_ks breaks due to cairo for some reason */
|
||||||
|
s->x_ksm = (xcb_keysym_t*)malloc(sizeof(xcb_keysym_t) * s->x_nkc * s->x_nks);
|
||||||
|
for (int i = 0; i < s->x_nkc * s->x_nks; i++) {
|
||||||
|
s->x_ksm[i] = x_ks[i];
|
||||||
|
}
|
||||||
|
free(x_km);
|
||||||
|
|
||||||
|
xcb_flush(s->x_con);
|
||||||
|
btk_log(BTK_LOG_SESSION_OPEN);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
btk_unmap(btk_session_t *s, btk_window_t *w)
|
||||||
|
{
|
||||||
|
w->state &= ~BTK_WINDOW_STATE_MAPPED;
|
||||||
|
xcb_unmap_window(s->x_con, w->x_win);
|
||||||
|
xcb_flush(s->x_con);
|
||||||
|
btk_log(BTK_LOG_WINDOW_UNMAP);
|
||||||
|
|
||||||
|
/* undo all and focus press states if any */
|
||||||
|
if (w->cell_press >= 0) {
|
||||||
|
w->cells[w->cell_press].state &= ~BTK_CELL_STATE_PRESSED;
|
||||||
|
w->cell_press = -1;
|
||||||
|
}
|
||||||
|
if (w->cell_focus >= 0) {
|
||||||
|
w->cells[w->cell_focus].state &= ~BTK_CELL_STATE_FOCUSED;
|
||||||
|
w->cell_focus = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_button_press(btk_session_t *s, xcb_button_press_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_BUTTON_PRESS);
|
||||||
|
|
||||||
|
if (x_ev->time - s->combo_t < btk_click_speed && x_ev->detail == s->combo_b) {
|
||||||
|
s->combo_n++;
|
||||||
|
btk_log(BTK_LOG_EVENT_BUTTON_COMBO);
|
||||||
|
} else {
|
||||||
|
s->combo_n = 1;
|
||||||
|
s->combo_b = x_ev->detail;
|
||||||
|
btk_log(BTK_LOG_EVENT_BUTTON_COMBO_BREAK);
|
||||||
|
}
|
||||||
|
s->combo_t = x_ev->time;
|
||||||
|
|
||||||
|
/* only applies for left click */
|
||||||
|
if (s->combo_b == 1)
|
||||||
|
s->window_press = s->window_focus;
|
||||||
|
|
||||||
|
btk_window_input_button(s->windows[s->window_focus], s->combo_b, s->combo_n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_button_release(btk_session_t *s, xcb_button_release_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_BUTTON_RELEASE);
|
||||||
|
|
||||||
|
/* only applies for left-middle-right click */
|
||||||
|
if (x_ev->detail > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* undo all press states */
|
||||||
|
btk_window_t *w = s->windows[s->window_press];
|
||||||
|
s->window_press = -1;
|
||||||
|
|
||||||
|
if (w->cell_press < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
btk_cell_t *c = &(w->cells[w->cell_press]);
|
||||||
|
c->state &= ~BTK_CELL_STATE_PRESSED;
|
||||||
|
btk_window_redraw_cell(w, w->cell_press);
|
||||||
|
w->cell_press = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_client_message(btk_session_t *s, xcb_client_message_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_CLIENT_MESSAGE);
|
||||||
|
btk_window_t *w = s->windows[get_btk_window_id(s, x_ev->window)];
|
||||||
|
|
||||||
|
/* when receiving a WM_DELETE_WINDOW atom, execute func_kill of the
|
||||||
|
* corresponding window, it func_kill = NULL, destroy window */
|
||||||
|
if (x_ev->type && 384) { /* 384 = id of atom for WM_WINDOW_DELETE */
|
||||||
|
if (w->func_kill) {
|
||||||
|
w->func_kill();
|
||||||
|
} else {
|
||||||
|
btk_window_destroy(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if anyone ever reads this, I know that it is a wrong method,
|
||||||
|
* that I first need to check to an WM_PROTOCOL atom then for
|
||||||
|
* WM_DELETE_WINDOW one */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_enter_window(btk_session_t *s, xcb_enter_notify_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_WINDOW_ENTER);
|
||||||
|
|
||||||
|
int w_id = get_btk_window_id(s, x_ev->event);
|
||||||
|
s->window_focus = w_id;
|
||||||
|
s->windows[w_id]->state |= BTK_WINDOW_STATE_FOCUSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_expose(btk_session_t *s, xcb_expose_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_EXPOSE);
|
||||||
|
btk_window_t *w = s->windows[get_btk_window_id(s, x_ev->window)];
|
||||||
|
|
||||||
|
/* c->fd need to be created when window is mapped to be able to display stuff */
|
||||||
|
/* TODO better way to do the first field creations */
|
||||||
|
if (!s->start) {
|
||||||
|
btk_window_init_cells(w);
|
||||||
|
s->start = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
btk_window_resize(w);
|
||||||
|
btk_window_redraw(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_key_press(btk_session_t *s, xcb_key_press_event_t *x_ev)
|
||||||
|
{
|
||||||
|
/* XCB_MOD_MASK_SHIFT (1) : shift
|
||||||
|
* XCB_MOD_MASK_LOCK (2) : caps
|
||||||
|
* XCB_MOD_MASK_CONTROL (4) : ctrl
|
||||||
|
* XCB_MOD_MASK_1 (8) : alt
|
||||||
|
* XCB_MOD_MASK_2 (16) : numlock
|
||||||
|
* XCB_MOD_MASK_3 (32) : ???
|
||||||
|
* XCB_MOD_MASK_4 (64) : super
|
||||||
|
* XCB_MOD_MASK_5 (128) : alt-gr */
|
||||||
|
|
||||||
|
btk_log(BTK_LOG_EVENT_KEY_PRESS);
|
||||||
|
|
||||||
|
unsigned int keysym_mod = 0;
|
||||||
|
if (((x_ev->state & XCB_MOD_MASK_LOCK) >> 1) ^ (x_ev->state & XCB_MOD_MASK_SHIFT))
|
||||||
|
keysym_mod = 1;
|
||||||
|
if ((x_ev->state & XCB_MOD_MASK_5))
|
||||||
|
keysym_mod = 4;
|
||||||
|
unsigned int keysym = s->x_ksm[(x_ev->detail - 8) * s->x_nks + keysym_mod];
|
||||||
|
|
||||||
|
/* convert utf-8 numpad chars to equivalent ascii */
|
||||||
|
if ((x_ev->state & XCB_MOD_MASK_2)) {
|
||||||
|
switch (keysym) {
|
||||||
|
case 0xffaf: keysym = '/'; break;
|
||||||
|
case 0xffaa: keysym = '*'; break;
|
||||||
|
case 0xffad: keysym = '-'; break;
|
||||||
|
case 0xff95: keysym = '7'; break;
|
||||||
|
case 0xff97: keysym = '8'; break;
|
||||||
|
case 0xff9a: keysym = '9'; break;
|
||||||
|
case 0xff96: keysym = '4'; break;
|
||||||
|
case 0xff9d: keysym = '5'; break;
|
||||||
|
case 0xff98: keysym = '6'; break;
|
||||||
|
case 0xff9c: keysym = '1'; break;
|
||||||
|
case 0xff99: keysym = '2'; break;
|
||||||
|
case 0xff9b: keysym = '3'; break;
|
||||||
|
case 0xff9e: keysym = '0'; break;
|
||||||
|
case 0xff9f: keysym = '.'; break;
|
||||||
|
case 0xffab: keysym = '+'; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* custom keysym conversions for reasons */
|
||||||
|
switch (keysym) {
|
||||||
|
case 0x00a7: keysym = 0x0000; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* special cases that are keycode dependent only */
|
||||||
|
switch (x_ev->detail) {
|
||||||
|
case 65: keysym = ' '; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
btk_window_input_key(s->windows[s->window_focus], keysym);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_leave_window(btk_session_t *s, xcb_leave_notify_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_WINDOW_LEAVE);
|
||||||
|
|
||||||
|
/* remove all focuses */
|
||||||
|
/* TODO
|
||||||
|
btk_window_t *w = s->windows[get_btk_window_id(s, x_ev->event)];
|
||||||
|
if (w->cell_focus >= 0) {
|
||||||
|
btk_cell_t *c = &(w->cells[w->cell_focus]);
|
||||||
|
c->state &= ~(BTK_CELL_STATE_FOCUSED);
|
||||||
|
btk_window_redraw_cell_focus(w, c);
|
||||||
|
}
|
||||||
|
w->state &= ~(BTK_WINDOW_STATE_FOCUSED);
|
||||||
|
w->cell_focus = -1;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
event_pointer_motion(btk_session_t *s, xcb_motion_notify_event_t *x_ev)
|
||||||
|
{
|
||||||
|
btk_log(BTK_LOG_EVENT_POINTER_MOTION);
|
||||||
|
btk_pos_t pt;
|
||||||
|
pt.x = x_ev->event_x;
|
||||||
|
pt.y = x_ev->event_y;
|
||||||
|
btk_window_input_pointer(s->windows[s->window_focus], pt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_btk_window_id(btk_session_t *s, xcb_window_t x_win)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < s->windows_n; i++) {
|
||||||
|
if (s->windows[i]->x_win == x_win)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
btk_log_warning(BTK_WARNING_WINDOW_GET);
|
||||||
|
return -1;
|
||||||
|
}
|
30
btk/btk.h
Normal file
30
btk/btk.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#include <xcb/xcb.h>
|
||||||
|
|
||||||
|
#include "btk-window.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
xcb_connection_t *x_con;
|
||||||
|
int pad0;
|
||||||
|
xcb_screen_t *x_scr;
|
||||||
|
int pad1;
|
||||||
|
xcb_visualtype_t *x_vis;
|
||||||
|
int pad2;
|
||||||
|
xcb_keysym_t *x_ksm; /* keysym table */
|
||||||
|
int pad3;
|
||||||
|
int x_nks; /* keysyms per keycode */
|
||||||
|
int x_nkc; /* number of keycodes */
|
||||||
|
btk_window_t **windows;
|
||||||
|
unsigned int windows_n;
|
||||||
|
int window_focus;
|
||||||
|
int window_press;
|
||||||
|
xcb_timestamp_t combo_t; /* timestamp of last click */
|
||||||
|
int combo_n; /* number of successive clicks */
|
||||||
|
int combo_b; /* button used for combo */
|
||||||
|
int start; /* TODO, see expose event handler */
|
||||||
|
} btk_session_t;
|
||||||
|
|
||||||
|
void btk_close (btk_session_t *);
|
||||||
|
void btk_loop (btk_session_t *, btk_window_t **, int);
|
||||||
|
void btk_map (btk_session_t *, btk_window_t *);
|
||||||
|
btk_session_t* btk_open ();
|
||||||
|
void btk_unmap (btk_session_t *, btk_window_t *);
|
Loading…
Reference in New Issue
Block a user