Upload files to 'btk'

This commit is contained in:
bricks 2022-07-06 22:11:17 -04:00
parent 8df4ea2e57
commit 5b03bf5004
3 changed files with 617 additions and 0 deletions

75
btk/btk-utils.h Normal file
View File

@ -0,0 +1,75 @@
#include <cairo/cairo.h>
#include <stdint.h>
#define BTK_MIN(a, b) (a < b ? a : b)
#define BTK_MAX(a, b) (a > b ? a : b)
enum btk_label_justify {
BTK_JUSTIFY_LEFT,
BTK_JUSTIFY_RIGHT
};
typedef struct {
float r, g, b;
} btk_rgb_t;
typedef struct {
float r, g, b, a;
} btk_rgba_t;
typedef struct {
int x, y;
} btk_pos_t;
typedef struct {
unsigned int w, h;
} btk_size_t;
typedef struct {
int x, y;
unsigned int w, h;
} btk_area_t;
/* cairo related */
typedef struct {
cairo_surface_t *c_srf;
cairo_t *c_ctx;
} btk_field_t;
typedef struct {
int i;
float f;
char *c;
void *p;
} btk_arg_t;
/* xcb related */
typedef struct
{
uint32_t flags;
int32_t x, y;
int32_t w, h;
int32_t min_w, min_h;
int32_t max_w, max_h;
int32_t w_inc, h_inc;
int32_t min_aspect_num, min_aspect_den;
int32_t max_aspect_num, max_aspect_den;
int32_t base_w, base_h;
uint32_t gravity;
} btk_wm_size_hint_t;
enum btk_wm_size_hint_flags
{
BTK_WM_SIZE_HINT_US_POSITION = 1U << 0,
BTK_WM_SIZE_HINT_US_SIZE = 1U << 1,
BTK_WM_SIZE_HINT_P_POSITION = 1U << 2,
BTK_WM_SIZE_HINT_P_SIZE = 1U << 3,
BTK_WM_SIZE_HINT_P_MIN_SIZE = 1U << 4,
BTK_WM_SIZE_HINT_P_MAX_SIZE = 1U << 5,
BTK_WM_SIZE_HINT_P_RESIZE_INC = 1U << 6,
BTK_WM_SIZE_HINT_P_ASPECT = 1U << 7,
BTK_WM_SIZE_HINT_BASE_SIZE = 1U << 8,
BTK_WM_SIZE_HINT_P_WIN_GRAVITY = 1U << 9
};

476
btk/btk-window.c Normal file
View File

@ -0,0 +1,476 @@
#include <cairo/cairo.h>
#include <cairo/cairo-xcb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xcb/xcb.h>
#include "btk-window.h"
#include "btk-log.h"
void draw_overlay (btk_window_t *, btk_area_t);
void update_cell_area (btk_window_t *, btk_cell_t *);
void update_stretch_area (btk_window_t *);
btk_window_t*
btk_window_create(xcb_connection_t *x_con,
xcb_screen_t *x_scr,
xcb_visualtype_t *x_vis,
unsigned int cw,
unsigned int ch,
int sc,
int sr,
unsigned int ew,
unsigned int eh,
unsigned int cells_n,
void (*func_kill)(void))
{
btk_window_t *w = (btk_window_t*)malloc(sizeof(btk_window_t));
w->cells = (btk_cell_t*)(malloc(sizeof(btk_cell_t) * cells_n));
w->cells_n = cells_n;
w->func_kill = func_kill;
/* states setup */
w->state = BTK_WINDOW_STATE_INITIAL;
w->cell_focus = -1;
w->cell_press = -1;
w->focus_in = -1;
/* geometry setup */
w->cs.w = cw;
w->cs.h = ch;
w->es.w = sc < 0 ? 0 : ew;
w->es.h = sr < 0 ? 0 : eh;
w->ms.w = cw * (btk_cp.w + btk_frame) + btk_frame;
w->ms.h = ch * (btk_cp.h + btk_frame) + btk_frame;
w->ps.w = w->ms.w + w->es.w;
w->ps.h = w->ms.h + w->es.h;
w->sc.x = sc;
w->sc.y = sr;
update_stretch_area(w);
/* xcb setup */
uint32_t mask_vals[2] = {
x_scr->black_pixel,
XCB_EVENT_MASK_EXPOSURE |
XCB_EVENT_MASK_POINTER_MOTION |
XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_ENTER_WINDOW |
XCB_EVENT_MASK_LEAVE_WINDOW |
XCB_EVENT_MASK_KEY_PRESS
};
w->x_con = x_con;
w->x_win = xcb_generate_id(x_con);
xcb_create_window(x_con,
XCB_COPY_FROM_PARENT,
w->x_win,
x_scr->root,
0, 0,
w->ps.w, w->ps.h,
0,
XCB_WINDOW_CLASS_INPUT_OUTPUT,
x_scr->root_visual,
XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK,
mask_vals);
/* wm hints setup */
btk_wm_size_hint_t x_hints = {
.flags = BTK_WM_SIZE_HINT_P_MIN_SIZE | BTK_WM_SIZE_HINT_P_MAX_SIZE,
.min_w = w->ms.w,
.min_h = w->ms.h
};
if (sc < 0) x_hints.max_w = w->ms.w;
if (sr < 0) x_hints.max_h = w->ms.h;
xcb_change_property(w->x_con,
XCB_PROP_MODE_REPLACE,
w->x_win,
XCB_ATOM_WM_NORMAL_HINTS,
XCB_ATOM_WM_SIZE_HINTS,
32,
sizeof(btk_wm_size_hint_t),
&x_hints);
/* suscribe to WM_DELETE_WINDOW protocol from the wm */
xcb_intern_atom_cookie_t x_cookie_protocol =
xcb_intern_atom(x_con, 0, strlen("WM_PROTOCOLS"), "WM_PROTOCOLS");
xcb_intern_atom_reply_t *x_reply_protocol =
xcb_intern_atom_reply(x_con, x_cookie_protocol, NULL);
xcb_intern_atom_cookie_t x_cookie_del =
xcb_intern_atom(x_con, 0, strlen("WM_DELETE_WINDOW"), "WM_DELETE_WINDOW");
xcb_intern_atom_reply_t *x_reply_del =
xcb_intern_atom_reply(x_con, x_cookie_del, NULL);
xcb_change_property(x_con,
XCB_PROP_MODE_REPLACE,
w->x_win,
x_reply_protocol->atom,
XCB_ATOM_ATOM,
32,
1,
&(x_reply_del->atom));
/* cairo setup */
w->c_srf = cairo_xcb_surface_create(x_con, w->x_win, x_vis, w->ps.w, w->ps.h);
w->c_ctx = cairo_create(w->c_srf);
/* setup font */
xcb_flush(x_con);
cairo_surface_flush(w->c_srf);
btk_log(BTK_LOG_WINDOW_CREATE);
return w;
}
void
btk_window_destroy(btk_window_t *w)
{
if (!w) {
btk_log_warning(BTK_WARNING_WINDOW_DESTROY);
return;
}
cairo_destroy(w->c_ctx);
cairo_surface_destroy(w->c_srf);
free(w->cells);
free(w);
btk_log(BTK_LOG_WINDOW_DESTROY);
}
void
btk_window_disable(btk_window_t *w)
{
w->state |= BTK_WINDOW_STATE_DISABLED;
btk_window_redraw(w);
}
void
btk_window_enable(btk_window_t *w)
{
w->state &= ~BTK_WINDOW_STATE_DISABLED;
btk_window_redraw(w);
}
void
btk_window_init_cells(btk_window_t *w)
{
for (int i = 0; i < w->cells_n; i++) {
btk_window_update_cell_area(w, &(w->cells[i]));
}
}
void
btk_window_input_button(btk_window_t *w, int button, int combo)
{
if ((w->state & BTK_WINDOW_STATE_DISABLED))
return;
if (w->cell_focus < 0)
return;
btk_cell_t *c = &(w->cells[w->cell_focus]);
if ((c->state & BTK_CELL_STATE_DISABLED) && button < 4)
return;
if (button == 1) {
c->state |= BTK_CELL_STATE_PRESSED;
w->cell_press = w->cell_focus;
}
/* relative pointer position the the pressed cell */
btk_pos_t rel_pt;
rel_pt.x = w->pt.x - c->pa.x;
rel_pt.y = w->pt.y - c->pa.y;
/* forward press event to individual handlers for special actions */
switch (c->type) {
case BTK_CELL_TYPE_BUTTON:
btk_cell_button_trigger(c, button);
break;
case BTK_CELL_TYPE_INPUT:
btk_cell_input_button(c, button, combo, rel_pt);
break;
case BTK_CELL_TYPE_LIST:
btk_cell_list_input_button(c, button, combo, rel_pt);
break;
case BTK_CELL_TYPE_SWITCH:
btk_cell_switch_toggle(c, button);
break;
case BTK_CELL_TYPE_TABLE:
btk_cell_table_input_button(c, button, combo, rel_pt);
break;
case BTK_CELL_TYPE_EDITOR:
btk_cell_editor_input_button(c, button, combo, rel_pt);
break;
default:
break;
}
btk_cell_draw(c, w->c_ctx);
draw_overlay(w, c->pa);
}
void
btk_window_input_key(btk_window_t *w, xcb_keysym_t key)
{
if ((w->state & BTK_WINDOW_STATE_DISABLED))
return;
if (w->cell_focus < 0)
return;
btk_cell_t *c = &(w->cells[w->cell_focus]);
switch (c->type) {
case BTK_CELL_TYPE_INPUT:
btk_cell_input_input_key(c, (uint32_t)key);
break;
case BTK_CELL_TYPE_EDITOR:
btk_cell_editor_input_key(c, (uint32_t)key);
break;
default:
return;
}
btk_cell_draw(c, w->c_ctx);
draw_overlay(w, c->pa);
}
/* updates the pointer position on the windows and the focused cell */
void
btk_window_input_pointer(btk_window_t *w, btk_pos_t pos)
{
if ((w->state & BTK_WINDOW_STATE_DISABLED))
return;
int prev_focus = w->cell_focus;
w->pt.x = pos.x;
w->pt.y = pos.y;
/* iteration instead of calculation to avoid frame interference in the
* case of thick frames */
for (int i = 0; i < w->cells_n; i++) {
if (w->pt.x >= w->cells[i].pa.x &&
w->pt.y >= w->cells[i].pa.y &&
w->pt.x <= w->cells[i].pa.x + w->cells[i].pa.w &&
w->pt.y <= w->cells[i].pa.y + w->cells[i].pa.h) {
w->cell_focus = i;
break;
}
}
/* if focus didn't change, leave */
if (w->cell_focus == prev_focus)
return;
/* unfocus previous cell if any */
if (prev_focus >= 0) {
w->cells[prev_focus].state &= ~BTK_CELL_STATE_FOCUSED;
btk_window_redraw_cell_focus(w, &(w->cells[prev_focus]));
}
/* focus new cell */
w->cells[w->cell_focus].state |= BTK_CELL_STATE_FOCUSED;
btk_window_redraw_cell_focus(w, &(w->cells[w->cell_focus]));
}
void
btk_window_redraw(btk_window_t *w)
{
/* clear surface to redraw */
cairo_set_source_rgb(w->c_ctx, btk_cl_frame.r, btk_cl_frame.g, btk_cl_frame.b);
cairo_paint(w->c_ctx);
/* hilight frame around focused cell if any */
if (w->cell_focus >= 0) {
btk_rgb_t cl = w->focus_in >= 0 ? btk_cl_frame_in : btk_cl_frame_focus;
cairo_set_source_rgb(w->c_ctx, cl.r, cl.g, cl.b);
cairo_rectangle(w->c_ctx,
w->cells[w->cell_focus].pa.x - btk_frame,
w->cells[w->cell_focus].pa.y - btk_frame,
w->cells[w->cell_focus].pa.w + 2 * btk_frame,
w->cells[w->cell_focus].pa.h + 2 * btk_frame);
cairo_fill(w->c_ctx);
}
/* render cells */
for (int i = 0; i < w->cells_n; i++)
btk_cell_draw(&(w->cells[i]), w->c_ctx);
/* disable overlay */
btk_area_t ov;
ov.x = 0;
ov.y = 0;
ov.w = w->ps.w;
ov.h = w->ps.h;
draw_overlay(w, ov);
cairo_surface_flush(w->c_srf);
}
/* to be used to regenretate cells externally */
void
btk_window_redraw_cell(btk_window_t *w, unsigned int c_id)
{
if ((c_id) >= w->cells_n) {
btk_log_warning(BTK_WARNING_OUT_OF_BOUND_CELL);
return;
}
btk_cell_draw(&(w->cells[c_id]), w->c_ctx);
draw_overlay(w, w->cells[c_id].pa);
}
/* only redraw a specific cell and not the whole window
* unlike calling btk_winsow_redraw_cell, this function
* also redraws the frame around the cell */
void
btk_window_redraw_cell_focus(btk_window_t *w, btk_cell_t *c)
{
/* redraw frame */
btk_rgb_t cl;
if ((c->state & BTK_CELL_STATE_IN)) {
cl = btk_cl_frame_in;
} else if ((c->state & BTK_CELL_STATE_FOCUSED)) {
cl = btk_cl_frame_focus;
} else {
cl = btk_cl_frame;
}
cairo_set_source_rgb(w->c_ctx, cl.r, cl.g, cl.b);
cairo_rectangle(w->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(w->c_ctx);
/* redraw cell */
btk_cell_draw(c, w->c_ctx);
/* disable overlay */
btk_area_t ov;
ov.x = c->pa.x - btk_frame;
ov.y = c->pa.y - btk_frame;
ov.w = c->pa.w + 2 * btk_frame;
ov.h = c->pa.h + 2 * btk_frame;
draw_overlay(w, ov);
cairo_surface_flush(w->c_srf);
}
/* only called by an expose event */
int
btk_window_resize(btk_window_t *w)
{
/* check if window geometry changed, update window size if it did */
xcb_get_geometry_reply_t *x_geom;
xcb_get_geometry_cookie_t x_cookie = xcb_get_geometry(w->x_con, w->x_win);
x_geom = xcb_get_geometry_reply(w->x_con, x_cookie, NULL);
if (!x_geom)
return 0;
if (w->ps.w == x_geom->width && w->ps.h == x_geom->height)
return 0;
/* update window's geometry */
w->ps.w = x_geom->width;
w->ps.h = x_geom->height;
w->es.w = w->ps.w - w->ms.w;
w->es.h = w->ps.h - w->ms.h;
update_stretch_area(w);
cairo_xcb_surface_set_size(w->c_srf, w->ps.w, w->ps.h);
/* update cell's geometry */
/* only for those after the stretch col and row */
btk_cell_t *c;
for (int i = 0; i < w->cells_n; i++) {
c = &(w->cells[i]);
if (c->ca.x + c->ca.w >= w->sc.x || c->ca.y + c->ca.h >= w->sc.y)
btk_window_update_cell_area(w, c);
}
cairo_surface_flush(w->c_srf);
btk_log(BTK_LOG_WINDOW_RESIZE);
return 1;
}
void
btk_window_set_name(btk_window_t *w, char *name)
{
xcb_change_property(w->x_con,
XCB_PROP_MODE_REPLACE,
w->x_win,
XCB_ATOM_WM_NAME,
XCB_ATOM_STRING,
8,
strlen(name),
name);
btk_log(BTK_LOG_WINDOW_RENAME);
}
void
btk_window_update_cell_area(btk_window_t *w, btk_cell_t *c)
{
unsigned int ex, ey, ew, eh = 0; /* extra to account for stretched columns & rows */
ex = c->ca.x > w->sc.x ? w->es.w : 0;
ey = c->ca.y > w->sc.y ? w->es.h : 0;
ew = c->ca.x <= w->sc.x && c->ca.x + c->ca.w > w->sc.x ? w->es.w : 0;
if (!(c->lh))
eh = c->ca.y <= w->sc.y && c->ca.y + c->ca.h > w->sc.y ? w->es.h : 0;
c->pa.x = c->ca.x * (btk_cp.w + btk_frame) + btk_frame + ex;
c->pa.y = c->ca.y * (btk_cp.h + btk_frame) + btk_frame + ey;
c->pa.w = c->ca.w * (btk_cp.w + btk_frame) - btk_frame + ew;
c->pa.h = c->ca.h * (btk_cp.h + btk_frame) - btk_frame + eh;
/* field re-creation with correct size */
if (c->group == BTK_CELL_GROUP_FIELD) {
if (c->fd)
btk_cell_field_destroy(c->fd);
c->fd = btk_cell_field_create(w->c_srf, c->pa);
}
/* special geometry depending on cell type */
switch (c->type) {
case BTK_CELL_TYPE_TABLE:
btk_cell_table_update_geometry(c);
break;
case BTK_CELL_TYPE_EDITOR:
btk_cell_editor_update_text(c);
break;
default:
break;
}
}
/* add semi-transparent block overlay on areas to redraw if the window is disabled */
void
draw_overlay(btk_window_t *w, btk_area_t a)
{
if (!(w->state & BTK_WINDOW_STATE_DISABLED))
return;
if ((w->state & BTK_WINDOW_STATE_DISABLED)) {
cairo_set_source_rgba(w->c_ctx,
btk_cl_window_overlay.r,
btk_cl_window_overlay.g,
btk_cl_window_overlay.b,
btk_cl_window_overlay.a);
cairo_rectangle(w->c_ctx, a.x, a.y, a.w, a.h);
cairo_fill(w->c_ctx);
}
}
void
update_stretch_area(btk_window_t *w)
{
w->sa.x = w->sc.x * (btk_cp.w + btk_frame);
w->sa.y = w->sc.y * (btk_cp.h + btk_frame);
w->sa.w = w->sa.x + w->es.w + btk_cp.w;
w->sa.h = w->sa.x + w->es.h + btk_cp.h;
}

66
btk/btk-window.h Normal file
View File

@ -0,0 +1,66 @@
#include <cairo/cairo.h>
#include <xcb/xcb.h>
#include "btk-cell.h"
/* window states mask */
enum btk_window_states {
BTK_WINDOW_STATE_INITIAL = 0,
BTK_WINDOW_STATE_MAPPED = 1U << 0,
BTK_WINDOW_STATE_DISABLED = 1U << 1,
BTK_WINDOW_STATE_FOCUSED = 1U << 2,
BTK_WINDOW_STATE_LOCKED = 1U << 3
};
typedef struct {
/* xcb + cairo */
xcb_connection_t *x_con;
int pad0;
xcb_window_t x_win;
cairo_surface_t *c_srf;
int pad1;
cairo_t *c_ctx;
int pad2;
/* self info */
int state;
btk_size_t ps; /* actual pixel dimensions */
btk_size_t ms; /* minimum pixel dimensions */
btk_size_t es; /* extra pixel dimensions */
btk_size_t cs; /* dimensions in cells */
btk_pos_t sc; /* stretch row and column positions in cells */
btk_area_t sa; /* area of the stretched core */
btk_pos_t pt; /* pointer position in pixels */
/* contents */
btk_cell_t *cells; /* array of cell */
unsigned int cells_n; /* number of cells */
int cell_focus; /* id of currently focused cell */
int cell_press; /* id of cell under the pointer when press */
int focus_in; /* = 1 if the focus is 'inside' the cell */
void (*func_kill)(void);
} btk_window_t;
btk_window_t* btk_window_create (xcb_connection_t *,
xcb_screen_t *,
xcb_visualtype_t *,
unsigned int,
unsigned int,
int,
int,
unsigned int,
unsigned int,
unsigned int,
void (*)(void));
void btk_window_destroy (btk_window_t *);
void btk_window_disable (btk_window_t *);
void btk_window_enable (btk_window_t *);
void btk_window_init_cells (btk_window_t *);
void btk_window_input_button (btk_window_t *, int, int);
void btk_window_input_key (btk_window_t *, xcb_keysym_t);
void btk_window_input_pointer (btk_window_t *, btk_pos_t);
void btk_window_redraw (btk_window_t *);
void btk_window_redraw_cell (btk_window_t *, unsigned int);
void btk_window_redraw_cell_focus (btk_window_t *, btk_cell_t*);
int btk_window_resize (btk_window_t *); /* returns 1 if size actually changed */
void btk_window_set_name (btk_window_t *, char *);
void btk_window_update_cell_area (btk_window_t *, btk_cell_t*);