(UNDER CONSTRUCTION) cursetree is now a non-binary tree yippiegit add .
also abstracted ncurses WINDOW into the ct_surface structure. and added ct_bounds to complement ct_dims.
This commit is contained in:
parent
b04f0b4aa3
commit
759920a9cc
9 changed files with 476 additions and 193 deletions
109
cursetree/dims.c
109
cursetree/dims.c
|
|
@ -1,4 +1,5 @@
|
|||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -25,35 +26,97 @@ struct ct_dims *dup_dims(const struct ct_dims *const dims) {
|
|||
return dup;
|
||||
}
|
||||
|
||||
static struct ct_bounds *__bounds(const enum ct_boundtype type, const int wmin,
|
||||
const int wmax, const int hmin,
|
||||
const int hmax) {
|
||||
struct ct_bounds *bounds;
|
||||
|
||||
bounds = (struct ct_bounds *)malloc(sizeof(struct ct_bounds));
|
||||
*bounds = (struct ct_bounds){
|
||||
.type = type,
|
||||
.wmin = wmin,
|
||||
.wmax = wmax,
|
||||
.hmin = hmin,
|
||||
.hmax = hmax,
|
||||
};
|
||||
return bounds;
|
||||
}
|
||||
|
||||
static inline void clamp(int *const val, const int min, const int max,
|
||||
const int do_ceiling) {
|
||||
if (*val == __BOUND_UNLIMITED)
|
||||
*val = do_ceiling ? max : min;
|
||||
else if (*val > max)
|
||||
*val = max;
|
||||
else if (*val < min)
|
||||
*val = min;
|
||||
}
|
||||
#define CLAMP_ABS(val, is_max) \
|
||||
(clamp(&val, __BOUND_ABS_MIN, __BOUND_ABS_MAX, is_max))
|
||||
#define CLAMP_REL(val, is_max) \
|
||||
(clamp(&val, __BOUND_REL_MIN, __BOUND_REL_MAX, is_max))
|
||||
|
||||
struct ct_bounds *bounds_none(void) {
|
||||
return __bounds(BOUND_NONE, __BOUND_ABS_MIN, __BOUND_ABS_MAX, __BOUND_ABS_MIN,
|
||||
__BOUND_ABS_MAX);
|
||||
}
|
||||
|
||||
struct ct_bounds *bounds_absolute(int wmin, int wmax,
|
||||
int hmin, int hmax) {
|
||||
CLAMP_ABS(wmin, false);
|
||||
CLAMP_ABS(wmax, true);
|
||||
CLAMP_ABS(hmin, false);
|
||||
CLAMP_ABS(hmax, true);
|
||||
return __bounds(BOUND_ABSOLUTE, wmin, wmax, hmin, hmax);
|
||||
}
|
||||
|
||||
struct ct_bounds *bounds_relative(int wmin, int wmax,
|
||||
int hmin, int hmax) {
|
||||
CLAMP_REL(wmin, false);
|
||||
CLAMP_REL(wmax, true);
|
||||
CLAMP_REL(hmin, false);
|
||||
CLAMP_REL(hmax, true);
|
||||
return __bounds(BOUND_RELATIVE, wmin, wmax, hmin, hmax);
|
||||
}
|
||||
|
||||
struct ct_bounds *dup_bounds(const struct ct_bounds *const bounds) {
|
||||
struct ct_bounds *dup;
|
||||
dup = (struct ct_bounds *)malloc(sizeof(struct ct_bounds));
|
||||
memcpy(dup, bounds, sizeof(struct ct_bounds));
|
||||
|
||||
return dup;
|
||||
}
|
||||
|
||||
/* Calculate the dimensions for nodes resulting from a bifurcation.
|
||||
* Returns 0 on success, and 1 on failure if any width/height are 0 characters.
|
||||
* WARNING: This function does not guarantee the x,y positions returned
|
||||
* WARNING: are valid screen coordinates.
|
||||
*/
|
||||
int bifurcate_dims(const struct ct_dims *const parent_dims,
|
||||
const enum ct_axis axis, const float ratio,
|
||||
struct ct_dims **const dims0, struct ct_dims **const dims1) {
|
||||
assert(0 < ratio && ratio < 1);
|
||||
struct ct_dims *_dims0, *_dims1;
|
||||
// int bifurcate_dims(const struct ct_dims *const parent_dims,
|
||||
// const enum ct_axis axis, const float ratio,
|
||||
// struct ct_dims **const dims0, struct ct_dims **const
|
||||
// dims1) {
|
||||
// assert(0 < ratio && ratio < 1);
|
||||
// struct ct_dims *_dims0, *_dims1;
|
||||
|
||||
_dims0 = dup_dims(parent_dims);
|
||||
_dims1 = dup_dims(parent_dims);
|
||||
// _dims0 = dup_dims(parent_dims);
|
||||
// _dims1 = dup_dims(parent_dims);
|
||||
|
||||
if (axis == AXIS_X) {
|
||||
_dims0->width *= ratio;
|
||||
_dims1->width -= _dims0->width;
|
||||
_dims1->x += _dims0->width;
|
||||
} else {
|
||||
_dims0->height *= ratio;
|
||||
_dims1->height -= _dims0->height;
|
||||
_dims1->y += _dims0->height;
|
||||
}
|
||||
// if (axis == AXIS_X) {
|
||||
// _dims0->width *= ratio;
|
||||
// _dims1->width -= _dims0->width;
|
||||
// _dims1->x += _dims0->width;
|
||||
// } else {
|
||||
// _dims0->height *= ratio;
|
||||
// _dims1->height -= _dims0->height;
|
||||
// _dims1->y += _dims0->height;
|
||||
// }
|
||||
|
||||
if (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height)
|
||||
return 1;
|
||||
// if (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height)
|
||||
// return 1;
|
||||
|
||||
// propagate bifurcated dimensions
|
||||
*dims0 = _dims0;
|
||||
*dims1 = _dims1;
|
||||
return 0;
|
||||
}
|
||||
// // propagate bifurcated dimensions
|
||||
// *dims0 = _dims0;
|
||||
// *dims1 = _dims1;
|
||||
// return 0;
|
||||
// }
|
||||
|
|
|
|||
|
|
@ -1,11 +1,23 @@
|
|||
#ifndef CURSETREE_DIMS_H
|
||||
#define CURSETREE_DIMS_H
|
||||
|
||||
#define __BOUND_UNLIMITED (-1)
|
||||
#define __BOUND_ABS_MIN (1)
|
||||
#define __BOUND_ABS_MAX (INT_MAX)
|
||||
#define __BOUND_REL_MIN ((float)0)
|
||||
#define __BOUND_REL_MAX ((float)1)
|
||||
|
||||
enum ct_axis {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
};
|
||||
|
||||
enum ct_boundtype {
|
||||
BOUND_NONE,
|
||||
BOUND_ABSOLUTE,
|
||||
BOUND_RELATIVE,
|
||||
};
|
||||
|
||||
/* Stores a node's starting x,y coordinates, width, & height.
|
||||
* NOTE: Intended for interfunction communication.
|
||||
*/
|
||||
|
|
@ -13,11 +25,22 @@ struct ct_dims {
|
|||
int x, y, width, height;
|
||||
};
|
||||
|
||||
struct ct_bounds {
|
||||
enum ct_boundtype type;
|
||||
int wmin, wmax, hmin, hmax;
|
||||
};
|
||||
|
||||
struct ct_dims *new_dims(int x, int y, int width, int height);
|
||||
struct ct_dims *dup_dims(const struct ct_dims *const dims);
|
||||
|
||||
int bifurcate_dims(const struct ct_dims *const parent_dims,
|
||||
const enum ct_axis axis, const float ratio,
|
||||
struct ct_dims **const dims0, struct ct_dims **const dims1);
|
||||
struct ct_bounds *bounds_none(void);
|
||||
struct ct_bounds *bounds_absolute(int wmin, int wmax, int hmin, int hmax);
|
||||
struct ct_bounds *bounds_relative(int wmin, int wmax, int hmin, int hmax);
|
||||
struct ct_bounds *dup_bounds(const struct ct_bounds *const bounds);
|
||||
|
||||
// int bifurcate_dims(const struct ct_dims *const parent_dims,
|
||||
// const enum ct_axis axis, const float ratio,
|
||||
// struct ct_dims **const dims0, struct ct_dims **const
|
||||
// dims1);
|
||||
|
||||
#endif /* CURSETREE_DIMS_H */
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ void init_ncurses(void) {
|
|||
curs_set(0); // hide cursor
|
||||
}
|
||||
|
||||
void end_ncurses(void) {
|
||||
endwin();
|
||||
}
|
||||
|
||||
/* Initialise (with default IO configuration) a new ncurses WINDOW.
|
||||
*/
|
||||
WINDOW *new_window(const int x, const int y, const int width,
|
||||
|
|
@ -105,7 +109,7 @@ struct ct_dims *windims(WINDOW *win) {
|
|||
* NOTE: Failure occurs if width or height <= 0,
|
||||
* NOTE: or if the x,y coordinate is outside the screen bounds.
|
||||
*/
|
||||
int resizemv_window(const int x, const int y, const int width, const int height,
|
||||
WINDOW *const win) {
|
||||
int resizemv_window(WINDOW *const win, const int x, const int y,
|
||||
const int width, const int height) {
|
||||
return wresize(win, height, width) || mvwin(win, y, x);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
#include "dims.h"
|
||||
|
||||
# ifndef __NCURSES_H
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
# endif /* __NCURSES_H */
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
enum crs_termmode {
|
||||
/* tty cbreak mode */
|
||||
|
|
@ -20,22 +20,25 @@ enum crs_termmode {
|
|||
|
||||
int termmode(const enum crs_termmode mode);
|
||||
void termsize(int *const width, int *const height);
|
||||
struct ct_dims *termdims(void);
|
||||
|
||||
void init_ncurses(void);
|
||||
void end_ncurses(void);
|
||||
|
||||
WINDOW *new_window(const int x, const int y, const int width, const int height);
|
||||
WINDOW *new_window_fs(void);
|
||||
void destroy_window(WINDOW *);
|
||||
|
||||
#define winpos(win, x, y) (x = winposx(win), y = winposy(win))
|
||||
#define winsize(win, width, height) (width = winwidth(win), height=winheight(win))
|
||||
#define winsize(win, width, height) \
|
||||
(width = winwidth(win), height = winheight(win))
|
||||
int winposx(WINDOW *const);
|
||||
int winposy(WINDOW *const);
|
||||
int winwidth(WINDOW *const);
|
||||
int winheight(WINDOW *const);
|
||||
struct ct_dims *windims(WINDOW *win);
|
||||
|
||||
int resizemv_window(const int x, const int y, const int width, const int height,
|
||||
WINDOW *const win);
|
||||
int resizemv_window(WINDOW *const win, const int x, const int y,
|
||||
const int width, const int height);
|
||||
|
||||
#endif /* CURSETREE_NCRSWRAP_H */
|
||||
|
|
|
|||
342
cursetree/node.c
342
cursetree/node.c
|
|
@ -1,153 +1,259 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ncrswrap.h"
|
||||
#include "dims.h"
|
||||
#include "node.h"
|
||||
#include "surface.h"
|
||||
|
||||
/* Internal allocator method for ct_node structures.
|
||||
*/
|
||||
static inline struct ct_node *__alloc_node(const enum ct_nodetype type) {
|
||||
static inline struct ct_node *__alloc_node(void) {
|
||||
struct ct_node *node = (struct ct_node *)malloc(sizeof(struct ct_node));
|
||||
node->type = type;
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Construct a new window node (ct_node of type NODE_WIN).
|
||||
/* Returns NULL if memory allocation failed.
|
||||
*/
|
||||
struct ct_node *init_window_node(WINDOW *const win) {
|
||||
struct ct_node *node = __alloc_node(NODE_WINDOW);
|
||||
node->win = win;
|
||||
struct ct_node *new_node(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds,
|
||||
struct ct_node *const parent) {
|
||||
struct ct_node *node = __alloc_node();
|
||||
if (node == NULL) {
|
||||
*node = (struct ct_node){
|
||||
.surface = new_surface(dims, bounds),
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
static struct ct_node *
|
||||
auto_window_node(const struct ct_dims *const dims) {
|
||||
WINDOW *win = new_window(dims->x, dims->y, dims->width, dims->height);
|
||||
return init_window_node(win);
|
||||
}
|
||||
|
||||
static struct ct_node *init_abstract_node(struct ct_node *const node0,
|
||||
struct ct_node *const node1,
|
||||
const enum ct_axis axis,
|
||||
const float ratio,
|
||||
struct ct_dims *const dims) {
|
||||
struct ct_node *node = __alloc_node(NODE_ABSTRACT);
|
||||
node->axis = axis;
|
||||
node->ratio = ratio;
|
||||
node->dims = dims;
|
||||
|
||||
node->child[0] = node0;
|
||||
node->child[1] = node1;
|
||||
return node;
|
||||
}
|
||||
|
||||
void destroy_node(struct ct_node *const node) {
|
||||
if (node->type == NODE_WINDOW) {
|
||||
/* Window Node */
|
||||
destroy_window(node->win);
|
||||
goto end;
|
||||
.parent = parent,
|
||||
.child = (struct ct_node **)malloc(NODE_INIT_CHILDREN *
|
||||
sizeof(struct ct_node *)),
|
||||
.csize = NODE_INIT_CHILDREN,
|
||||
.cindex = 0,
|
||||
.axis = AXIS_X,
|
||||
.ratio = 0,
|
||||
};
|
||||
}
|
||||
/* Abstract Node */
|
||||
assert(node->type == NODE_ABSTRACT);
|
||||
destroy_node(node->child[0]);
|
||||
destroy_node(node->child[1]);
|
||||
free(node->dims);
|
||||
|
||||
end:
|
||||
return node;
|
||||
}
|
||||
|
||||
/* WARNING: Do NOT use __destroy_node() to destroy a node's children!
|
||||
* WARNING: Use the destroy_child_node() function instead.
|
||||
*/
|
||||
void __destroy_node(struct ct_node *const node) {
|
||||
if (node == NULL)
|
||||
return;
|
||||
|
||||
// destroy children first
|
||||
for (int j = 0; j < node->cindex; j++) {
|
||||
__destroy_node(node->child[j]);
|
||||
}
|
||||
|
||||
destroy_surface(node->surface);
|
||||
free(node);
|
||||
}
|
||||
|
||||
static inline struct ct_dims *nodedims(const struct ct_node *const node) {
|
||||
struct ct_dims *dims;
|
||||
if (node->type == NODE_WINDOW) {
|
||||
/* Window Node */
|
||||
dims = windims(node->win);
|
||||
} else {
|
||||
/* Abstract Node */
|
||||
assert(node->type == NODE_ABSTRACT);
|
||||
dims = dup_dims(node->dims);
|
||||
void satisfy_node(struct ct_node *const node, struct ct_dims *const dims) {
|
||||
double axismax;
|
||||
if (IS_PARENT_NODE(node)) {
|
||||
for (int i = 0; i < node->cindex; i++) {
|
||||
if (node->axis == AXIS_X) {
|
||||
axismax += dims->width * node->child[i]->surface->bounds->wmax;
|
||||
} else {
|
||||
assert(node->axis == AXIS_Y);
|
||||
axismax += dims->width * node->child[i]->surface->bounds->hmax;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return dims;
|
||||
}
|
||||
|
||||
/* NOTE: resize_node calls wnoutrefresh(3x), which expects
|
||||
* NOTE: a call doupdate(3x) call afterwards to flush ncurses
|
||||
* NOTE: virtual screen to the physical screen.
|
||||
/*
|
||||
*/
|
||||
void resize_node(struct ct_node *const node,
|
||||
struct ct_dims *const new_dims) {
|
||||
if (node->type == NODE_WINDOW) {
|
||||
/* Window Node */
|
||||
resizemv_window(new_dims->x, new_dims->y, new_dims->width, new_dims->height,
|
||||
node->win);
|
||||
free(new_dims);
|
||||
void resize_node(struct ct_node *const node, struct ct_dims *const dims) {
|
||||
int cwidth, cheight; // child dimensions
|
||||
|
||||
wnoutrefresh(node->win);
|
||||
if (IS_PARENT_NODE(node)) {
|
||||
dims->width / node->cindex;
|
||||
}
|
||||
|
||||
resize_surface(node->surface, dims);
|
||||
|
||||
for (int j = 0; j < node->cindex; j++) {
|
||||
/* TODO */
|
||||
resize_node(node->child[j], TODO);
|
||||
}
|
||||
// bifurcate_dims(dims, node->axis, node->ratio, &dims0, &dims1);
|
||||
|
||||
// resize_node(node->child[0], dims0);
|
||||
// resize_node(node->child[1], dims1);
|
||||
}
|
||||
|
||||
static int __set_cbounds(struct ct_node *const parent,
|
||||
const struct ct_node *const child,
|
||||
const bool additive) {
|
||||
/* child and parent w/h min aliases */
|
||||
int c_wmin, c_hmin;
|
||||
int p_wmin_rel, p_hmin_rel;
|
||||
|
||||
c_wmin = child->surface->bounds->wmin;
|
||||
c_hmin = child->surface->bounds->hmin;
|
||||
|
||||
if (!additive) {
|
||||
c_wmin *= -1;
|
||||
c_hmin *= -1;
|
||||
}
|
||||
|
||||
if (child->surface->bounds->type == BOUND_RELATIVE) {
|
||||
parent->cbounds.wmin_abs++;
|
||||
parent->cbounds.hmin_abs++;
|
||||
|
||||
p_wmin_rel = parent->cbounds.wmin_rel + c_wmin;
|
||||
p_hmin_rel = parent->cbounds.hmin_rel + c_wmin;
|
||||
if (p_wmin_rel > __BOUND_REL_MAX || p_hmin_rel >= __BOUND_REL_MAX)
|
||||
return 1;
|
||||
|
||||
parent->cbounds.wmin_rel = p_wmin_rel;
|
||||
parent->cbounds.hmin_rel = p_hmin_rel;
|
||||
assert(parent->cbounds.wmin_rel > __BOUND_REL_MIN);
|
||||
assert(parent->cbounds.hmin_rel > __BOUND_REL_MIN);
|
||||
} else {
|
||||
/* Abstract Node */
|
||||
assert(node->type == NODE_ABSTRACT);
|
||||
struct ct_dims *dims0, *dims1;
|
||||
|
||||
free(node->dims);
|
||||
node->dims = new_dims;
|
||||
bifurcate_dims(new_dims, node->axis, node->ratio, &dims0, &dims1);
|
||||
|
||||
resize_node(node->child[0], dims0);
|
||||
resize_node(node->child[1], dims1);
|
||||
parent->cbounds.wmin_abs += c_wmin;
|
||||
parent->cbounds.hmin_abs += c_hmin;
|
||||
assert(parent->cbounds.wmin_abs > __BOUND_ABS_MIN);
|
||||
assert(parent->cbounds.hmin_abs > __BOUND_ABS_MIN);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Subdivide a window node's allocated region into two window nodes
|
||||
* replacing the original node with an abstract node.
|
||||
* Parameters:
|
||||
* axis - controls which direction the subdivision occurs
|
||||
* invert_axis - invert index of the original node in the new abstract node
|
||||
/* Returns:
|
||||
* 0 -> success
|
||||
* 1 -> failed (max child limit reached)
|
||||
* 2 -> failed (cumulative relative bounds surpasses 100%)
|
||||
*/
|
||||
static void __bifurcate_window_node(struct ct_node **const node,
|
||||
const enum ct_axis axis, const int invert_axis,
|
||||
const float ratio) {
|
||||
assert((*node)->type == NODE_WINDOW);
|
||||
struct ct_dims *dims0, *dims1;
|
||||
struct ct_node *node0, *node1;
|
||||
int insert_child_node(struct ct_node *const parent, struct ct_node *const child,
|
||||
const cindex i) {
|
||||
if (parent->cindex == CINDEX_MAX)
|
||||
return 1;
|
||||
else if (__set_cbounds(parent, child, true))
|
||||
return 2;
|
||||
else if (parent->cindex == parent->csize) {
|
||||
// grow child array size and clamp maximum
|
||||
parent->csize *= NODE_CHILDREN_GROWTH;
|
||||
if (parent->csize > CINDEX_MAX)
|
||||
parent->csize = CINDEX_MAX;
|
||||
|
||||
struct ct_dims *original_dims = nodedims(*node);
|
||||
if (bifurcate_dims(original_dims, axis, ratio, &dims0, &dims1)) {
|
||||
/* TODO: handle this error properly */
|
||||
free(original_dims);
|
||||
exit(1);
|
||||
return;
|
||||
parent->child =
|
||||
reallocarray(parent->child, parent->csize, sizeof(struct ct_node *));
|
||||
}
|
||||
|
||||
if (invert_axis) {
|
||||
/* Inverted Bifurcation */
|
||||
node0 = auto_window_node(dims0);
|
||||
node1 = *node;
|
||||
resize_node(node1, dims1);
|
||||
// shift all children up for insertion
|
||||
for (int j = parent->cindex; j > i; j--) {
|
||||
parent->child[j] = parent->child[j - 1];
|
||||
}
|
||||
// do insertion
|
||||
parent->child[i] = child;
|
||||
parent->cindex++;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* Returns:
|
||||
* 0 -> success
|
||||
* 1 -> failed (max child limit reached)
|
||||
* 2 -> failed (cumulative relative bounds surpasses 100%)
|
||||
*/
|
||||
int append_child_node(struct ct_node *const parent,
|
||||
struct ct_node *const child) {
|
||||
return insert_child_node(parent, child, parent->cindex);
|
||||
}
|
||||
|
||||
/* Remove a child node from a parent node by index.
|
||||
* Returns NULL if an invalid index was provided, otherwise returns
|
||||
* a pointer to the child node removed.
|
||||
* NOTE: This does NOT destroy the child node and should be
|
||||
* NOTE: used when moving the child somewhere else.
|
||||
* NOTE: Otherwise use destroy_child_node() instead.
|
||||
*/
|
||||
struct ct_node *remove_child_node(struct ct_node *const parent,
|
||||
const cindex i) {
|
||||
struct ct_node *child;
|
||||
|
||||
if (i >= parent->cindex)
|
||||
return NULL;
|
||||
else if (parent->cindex <= parent->csize / NODE_CHILDREN_GROWTH) {
|
||||
// shrink child array to avoid memory bloat
|
||||
parent->csize /= NODE_CHILDREN_GROWTH;
|
||||
parent->child =
|
||||
reallocarray(parent->child, parent->csize, sizeof(struct ct_node *));
|
||||
}
|
||||
|
||||
child = &parent[i];
|
||||
// shift all children down to fill removal
|
||||
for (int j = i; j < parent->cindex; j++) {
|
||||
parent->child[j] = parent->child[j + 1];
|
||||
}
|
||||
parent->cindex--;
|
||||
__set_cbounds(parent, child, false);
|
||||
return child;
|
||||
}
|
||||
|
||||
/* Remove and destroy a child node by index.
|
||||
* Returns 1 on failure (invalid index provided), and 0 on success.
|
||||
* NOTE: Use remove_child_node() instead if the child should live.
|
||||
*/
|
||||
int destroy_child_node(struct ct_node *const parent, const cindex i) {
|
||||
struct ct_node *child = remove_child_node(parent, i);
|
||||
__destroy_node(child);
|
||||
return (child == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns:
|
||||
* 0 -> success
|
||||
* 1 -> failed (node has no parent)
|
||||
* 2 -> failed (parent has no reference to node, CRITICAL)
|
||||
*/
|
||||
static int __index_as_child(const struct ct_node *const node,
|
||||
int *const index) {
|
||||
if (node->parent == NULL)
|
||||
return 1;
|
||||
|
||||
for (int i = 0; i < node->parent->cindex; i++) {
|
||||
if (node->parent->child[i] == node) {
|
||||
*index = i;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* If preserve_bounds is set then upon collapse the new node maintains the
|
||||
* original node's bounds struct. Otherwise the bounds of the child collapsed
|
||||
* onto are used.
|
||||
*/
|
||||
void collapse_node(struct ct_node **const node, const int i,
|
||||
const bool preserve_bounds) {
|
||||
assert(0 <= i && i < (*node)->cindex);
|
||||
int parent_index;
|
||||
struct ct_node *const parent = (*node)->parent;
|
||||
struct ct_node *collapse_target = remove_child_node(*node, i);
|
||||
struct ct_dims *dims = dup_dims((*node)->surface->dims);
|
||||
struct ct_bounds *bounds;
|
||||
|
||||
if (preserve_bounds) {
|
||||
bounds = dup_bounds((*node)->surface->bounds);
|
||||
rebind_surface(collapse_target->surface, bounds);
|
||||
}
|
||||
|
||||
/* Destroy original node and point to the collapse_target */
|
||||
if (__index_as_child(*node, &parent_index)) {
|
||||
/* __index_as_child fails (typically) because
|
||||
* the *node is cursetree's root node. */
|
||||
__destroy_node(*node);
|
||||
*node = collapse_target;
|
||||
} else {
|
||||
/* Non-Inverted Bifurcation */
|
||||
node0 = *node;
|
||||
node1 = auto_window_node(dims1);
|
||||
resize_node(node0, dims0);
|
||||
destroy_child_node(parent, parent_index);
|
||||
insert_child_node(parent, collapse_target, parent_index);
|
||||
}
|
||||
|
||||
*node = init_abstract_node(node0, node1, axis, ratio, original_dims);
|
||||
}
|
||||
|
||||
/* Collapse an abstract node, killing one child node and resizing
|
||||
* the other to take its place.
|
||||
*/
|
||||
static void collapse_abstract_node(struct ct_node **const node,
|
||||
const int collapse_i) {
|
||||
assert((*node)->type == NODE_ABSTRACT);
|
||||
assert(0 <= collapse_i && collapse_i < NODE_CHILD_N);
|
||||
|
||||
// WARNING: only works for NODE_CHILD_N=2 (binary trees)
|
||||
destroy_node((*node)->child[!collapse_i]);
|
||||
|
||||
struct ct_node *collapse_target = (*node)->child[collapse_i];
|
||||
free(*node);
|
||||
*node = collapse_target;
|
||||
resize_node(collapse_target, dims);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,48 +2,52 @@
|
|||
#define CURSETREE_NODE_H
|
||||
|
||||
#include "dims.h"
|
||||
#include "limits.h"
|
||||
#include "surface.h"
|
||||
|
||||
# ifndef __NCURSES_H
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
# endif /* __NCURSES_H */
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
#define NODE_CHILD_N 2
|
||||
#define NODE_INIT_CHILDREN 4
|
||||
#define NODE_CHILDREN_GROWTH 1.5
|
||||
#define CINDEX_MAX UCHAR_MAX
|
||||
|
||||
/* MACRO:
|
||||
* Get widnow node start x,y coordinates, width, & height.
|
||||
* void NODEDIMS(struct ct_node *node, struct ct_dims dims);
|
||||
*/
|
||||
#define GET_WNODEDIMS(dims, node) \
|
||||
(getbegyx((node)->win, dims.y, dims.x)); \
|
||||
getmaxyx((node)->win, dims.y, dims.x)
|
||||
|
||||
enum ct_nodetype {
|
||||
NODE_WINDOW,
|
||||
NODE_ABSTRACT,
|
||||
};
|
||||
/* Child Index */
|
||||
typedef unsigned char cindex;
|
||||
|
||||
struct ct_node {
|
||||
enum ct_nodetype type;
|
||||
// union value depends on ct_node.type
|
||||
union {
|
||||
WINDOW *win;
|
||||
struct {
|
||||
enum ct_axis axis;
|
||||
float ratio;
|
||||
struct ct_dims *dims;
|
||||
struct ct_node *child[NODE_CHILD_N];
|
||||
};
|
||||
};
|
||||
struct ct_surface *surface;
|
||||
|
||||
struct ct_node *parent;
|
||||
enum ct_axis axis;
|
||||
struct ct_node **child;
|
||||
cindex csize, cindex;
|
||||
/* child imposed minimum bounds */
|
||||
struct {
|
||||
int wmin_abs;
|
||||
int hmin_abs;
|
||||
int wmin_rel;
|
||||
int hmin_rel;
|
||||
} cbounds;
|
||||
|
||||
float ratio;
|
||||
};
|
||||
|
||||
/* === External Interface === */
|
||||
struct ct_node *init_window_node(WINDOW *const win);
|
||||
void destroy_node(struct ct_node *const node);
|
||||
void resize_node(struct ct_node *const node,
|
||||
struct ct_dims *const new_dims);
|
||||
#define IS_PARENT_NODE(node) (node->cindex != 0)
|
||||
|
||||
void bifurcate_window_node(struct ct_node **const node,
|
||||
const enum ct_axis axis, const int invert_axis,
|
||||
const float ratio);
|
||||
struct ct_node *new_node(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds,
|
||||
struct ct_node *const parent);
|
||||
void destroy_node(struct ct_node *const node);
|
||||
void resize_node(struct ct_node *const node, struct ct_dims *const new_dims);
|
||||
|
||||
void collapse_node(struct ct_node **const node, const int i,
|
||||
const bool preserve_bounds);
|
||||
|
||||
// void bifurcate_window_node(struct ct_node **const node, const enum ct_axis
|
||||
// axis,
|
||||
// const int invert_axis, const float ratio);
|
||||
|
||||
#endif /* CURSETREE_NODE_H */
|
||||
|
|
|
|||
46
cursetree/surface.c
Normal file
46
cursetree/surface.c
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "ncrswrap.h"
|
||||
#include "surface.h"
|
||||
|
||||
static inline struct ct_surface *__surface(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds,
|
||||
WINDOW *const win) {
|
||||
struct ct_surface *surface;
|
||||
|
||||
surface = (struct ct_surface *)malloc(sizeof(struct ct_surface));
|
||||
*surface = (struct ct_surface){
|
||||
.dims = dims,
|
||||
.bounds = bounds,
|
||||
.win = win,
|
||||
.updatereq = true,
|
||||
};
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
struct ct_surface *new_surface(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds) {
|
||||
WINDOW *const win = new_window(dims->x, dims->y, dims->width, dims->height);
|
||||
return __surface(dims, bounds, win);
|
||||
}
|
||||
|
||||
void destroy_surface(struct ct_surface *const surface) {
|
||||
destroy_window(surface->win);
|
||||
free(surface->dims);
|
||||
}
|
||||
|
||||
void resize_surface(struct ct_surface *const surface,
|
||||
struct ct_dims *const dims) {
|
||||
free(surface->dims);
|
||||
surface->dims = dims;
|
||||
surface->updatereq = true;
|
||||
|
||||
resizemv_window(surface->win, dims->x, dims->y, dims->width, dims->height);
|
||||
}
|
||||
|
||||
void rebind_surface(struct ct_surface *const surface,
|
||||
struct ct_bounds *const bounds) {
|
||||
free(surface->bounds);
|
||||
surface->bounds = bounds;
|
||||
}
|
||||
26
cursetree/surface.h
Normal file
26
cursetree/surface.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
#ifndef CURSETREE_SURFACE_H
|
||||
#define CURSETREE_SURFACE_H
|
||||
|
||||
#include "dims.h"
|
||||
|
||||
#ifndef __NCURSES_H
|
||||
typedef struct _win_st WINDOW;
|
||||
#endif /* __NCURSES_H */
|
||||
|
||||
struct ct_surface {
|
||||
struct ct_dims *dims;
|
||||
struct ct_bounds *bounds;
|
||||
WINDOW *win;
|
||||
unsigned char updatereq;
|
||||
};
|
||||
|
||||
struct ct_surface *new_surface(struct ct_dims *const dims,
|
||||
struct ct_bounds *const bounds);
|
||||
void destroy_surface(struct ct_surface *const surface);
|
||||
|
||||
void resize_surface(struct ct_surface *const surface,
|
||||
struct ct_dims *const dims);
|
||||
void rebind_surface(struct ct_surface *const surface,
|
||||
struct ct_bounds *const bounds);
|
||||
|
||||
#endif /* CURSETREE_SURFACE_H */
|
||||
|
|
@ -5,22 +5,19 @@
|
|||
|
||||
/*
|
||||
*/
|
||||
static struct ct_node *init_root_node(void) {
|
||||
WINDOW *rootwin;
|
||||
|
||||
rootwin = new_window_fs();
|
||||
return init_window_node(rootwin);
|
||||
static inline struct ct_node *__root_node(void) {
|
||||
return new_node(termdims(), NULL);
|
||||
}
|
||||
|
||||
int init_tree(struct ct_tree **const tree) {
|
||||
*tree = (struct ct_tree *)malloc(sizeof(struct ct_tree));
|
||||
(*tree)->root = init_root_node();
|
||||
return EXIT_SUCCESS;
|
||||
*tree = (struct ct_tree *)malloc(sizeof(struct ct_tree));
|
||||
(*tree)->root = __root_node();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
void destroy_tree(struct ct_tree *const tree) {
|
||||
destroy_node(tree->root);
|
||||
endwin();
|
||||
end_ncurses();
|
||||
free(tree);
|
||||
}
|
||||
|
||||
|
|
@ -28,3 +25,14 @@ void resize_tree(struct ct_tree *const tree, struct ct_dims *const dims) {
|
|||
resize_node(tree->root, dims);
|
||||
}
|
||||
|
||||
void switch_nodes(struct ct_node **const node0, struct ct_node **const node1) {
|
||||
struct ct_node *const node0ptr = *node0;
|
||||
struct ct_dims *const node0dims = dup_dims((*node0)->dims);
|
||||
struct ct_dims *const node1dims = dup_dims((*node1)->dims);
|
||||
|
||||
*node0 = *node1;
|
||||
resize_node(*node0, node1dims);
|
||||
|
||||
*node1 = node0ptr;
|
||||
resize_node(*node1, node0dims);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue