diff --git a/cursetree/cursetree.c b/cursetree/cursetree.c index 8d80831..a5f178f 100644 --- a/cursetree/cursetree.c +++ b/cursetree/cursetree.c @@ -1,264 +1,16 @@ -#include #include -#include #include "ncrswrap.h" -#include "cursetree.h" - -/* Internal allocator method for crs_node structures. - */ -static inline struct crs_node *__alloc_node(const enum crs_nodetype type) { - struct crs_node *node = (struct crs_node *)malloc(sizeof(struct crs_node)); - node->type = type; - return node; -} - -/* Construct a new window node (crs_node of type NODE_WIN). - */ -static struct crs_node *init_window_node(WINDOW *const win) { - struct crs_node *node = __alloc_node(NODE_WINDOW); - node->win = win; - - return node; -} - -static struct crs_node * -auto_window_node(const struct crs_nodedims *const dims) { - WINDOW *win = newwin(dims->height, dims->width, dims->y, dims->x); - return init_window_node(win); -} - -static struct crs_node *init_abstract_node(struct crs_node *const node0, - struct crs_node *const node1, - const enum crs_axis axis, - const float ratio, - struct crs_nodedims *const dims) { - struct crs_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; -} - -static void destroy_node(struct crs_node *const node) { - if (node->type == NODE_WINDOW) { - /* Window Node */ - delwin(node->win); - goto end; - } - /* Abstract Node */ - assert(node->type == NODE_ABSTRACT); - destroy_node(node->child[0]); - destroy_node(node->child[1]); - free(node->dims); - -end: - free(node); -} - -static inline struct crs_nodedims *__alloc_dims(int x, int y, int width, - int height) { - struct crs_nodedims *dims; - - dims = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); - *dims = (struct crs_nodedims){ - .x = x, - .y = y, - .width = width, - .height = height, - }; - return dims; -} - -static inline struct crs_nodedims * -__dup_dims(const struct crs_nodedims *const dims) { - struct crs_nodedims *dup; - dup = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); - memcpy(dup, dims, sizeof(struct crs_nodedims)); - - return dup; -} - -static inline struct crs_nodedims *termdims(void) { - struct crs_nodedims *dims = __alloc_dims(0, 0, 0, 0); - termsize(dims->width, dims->height); - - return dims; -} - -static inline void nodesize(const struct crs_node *const node, int *const width, - int *const height) { - if (node->type == NODE_WINDOW) { - /* Window Node */ - getmaxyx(node->win, *height, *width); - } else { - /* Abstract Node */ - assert(node->type == NODE_ABSTRACT); - *width = node->dims->width; - *height = node->dims->height; - } -} - -static inline struct crs_nodedims *nodedims(const struct crs_node *const node) { - struct crs_nodedims *dims; - if (node->type == NODE_WINDOW) { - /* Window Node */ - dims = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); - getbegyx(node->win, dims->y, dims->x); - getmaxyx(node->win, dims->height, dims->width); - } else { - /* Abstract Node */ - assert(node->type == NODE_ABSTRACT); - dims = __dup_dims(node->dims); - } - - return dims; -} - -/* 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. - */ -static int bifurcate_dims(const struct crs_nodedims *const parent_dims, - const enum crs_axis axis, const float ratio, - struct crs_nodedims **const dims0, - struct crs_nodedims **const dims1) { - assert(0 < ratio && ratio < 1); - struct crs_nodedims *_dims0, *_dims1; - - _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 (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height) - return 1; - - // propagate bifurcated dimensions - *dims0 = _dims0; - *dims1 = _dims1; - return 0; -} - -/* 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. - */ -static void resize_node(struct crs_node *const node, - struct crs_nodedims *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); - - wnoutrefresh(node->win); - } else { - /* Abstract Node */ - assert(node->type == NODE_ABSTRACT); - struct crs_nodedims *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); - } -} - -/* 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 - */ -void bifurcate_window_node(struct crs_node **const node, - const enum crs_axis axis, const int invert_axis, - const float ratio) { - assert((*node)->type == NODE_WINDOW); - struct crs_nodedims *dims0, *dims1; - struct crs_node *node0, *node1; - - struct crs_nodedims *original_dims = nodedims(*node); - if (bifurcate_dims(original_dims, axis, ratio, &dims0, &dims1)) { - /* TODO: handle this error properly */ - free(original_dims); - exit(1); - return; - } - - if (invert_axis) { - /* Inverted Bifurcation */ - node0 = auto_window_node(dims0); - node1 = *node; - resize_node(node1, dims1); - } else { - /* Non-Inverted Bifurcation */ - node0 = *node; - node1 = auto_window_node(dims1); - resize_node(node0, dims0); - } - - *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 crs_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 crs_node *collapse_target = (*node)->child[collapse_i]; - free(*node); - *node = collapse_target; -} - -/* - */ -static struct crs_node *init_root_node(void) { - WINDOW *rootwin; - - rootwin = root_window(); - return init_window_node(rootwin); -} +#include "tree.h" int ct_init(struct crs_tree **const tree) { - *tree = (struct crs_tree *)malloc(sizeof(struct crs_tree)); - /* Initialise NCurses Library & Root Node */ init_ncurses(); - (*tree)->root = init_root_node(); + init_tree(tree); return EXIT_SUCCESS; } -void destroy_tree(struct crs_tree *const tree) { - destroy_node(tree->root); - endwin(); - free(tree); -} - -void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims) { - resize_node(tree->root, dims); -} void ct_update(struct crs_tree *const tree) { struct crs_nodedims * term_dims; diff --git a/cursetree/cursetree.h b/cursetree/cursetree.h index 74d804f..abbf9e9 100644 --- a/cursetree/cursetree.h +++ b/cursetree/cursetree.h @@ -1,63 +1,10 @@ #ifndef CURSETREE_CURSETREE_H #define CURSETREE_CURSETREE_H -#ifndef __NCURSES_H -typedef struct _win_st WINDOW; -#endif /* __NCURSES_H */ - -#define NODE_CHILD_N 2 - -/* MACRO: - * Get widnow node start x,y coordinates, width, & height. - * void NODEDIMS(struct crs_node *node, struct crs_nodedims dims); - */ -#define GET_WNODEDIMS(dims, node) \ - (getbegyx((node)->win, dims.y, dims.x)); \ - getmaxyx((node)->win, dims.y, dims.x) - -enum crs_nodetype { - NODE_WINDOW, - NODE_ABSTRACT, -}; - -/* Stores a node's starting x,y coordinates, width, & height. - * NOTE: Intended for interfunction communication. - */ -struct crs_nodedims { - int x, y, width, height; -}; - -enum crs_axis { - AXIS_X, - AXIS_Y, -}; - -struct crs_node { - enum crs_nodetype type; - // union value depends on crs_node.type - union { - WINDOW *win; - struct { - enum crs_axis axis; - float ratio; - struct crs_nodedims *dims; - struct crs_node *child[NODE_CHILD_N]; - }; - }; -}; - -struct crs_tree { - struct crs_node *root; -}; +#include "tree.h" /* === External Interface === */ int ct_init(struct crs_tree **const tree); -void destroy_tree(struct crs_tree *const tree); -void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims); void ct_update(struct crs_tree *const tree); -void bifurcate_window_node(struct crs_node **const node, - const enum crs_axis axis, const int invert_axis, - const float ratio); - #endif /* CURSETREE_CURSETREE_H */ diff --git a/cursetree/node.c b/cursetree/node.c new file mode 100644 index 0000000..38f7129 --- /dev/null +++ b/cursetree/node.c @@ -0,0 +1,232 @@ +#include +#include +#include + +#include "ncrswrap.h" +#include "node.h" + +/* Internal allocator method for crs_node structures. + */ +static inline struct crs_node *__alloc_node(const enum crs_nodetype type) { + struct crs_node *node = (struct crs_node *)malloc(sizeof(struct crs_node)); + node->type = type; + return node; +} + +/* Construct a new window node (crs_node of type NODE_WIN). + */ +struct crs_node *init_window_node(WINDOW *const win) { + struct crs_node *node = __alloc_node(NODE_WINDOW); + node->win = win; + + return node; +} + +static struct crs_node * +auto_window_node(const struct crs_nodedims *const dims) { + WINDOW *win = newwin(dims->height, dims->width, dims->y, dims->x); + return init_window_node(win); +} + +static struct crs_node *init_abstract_node(struct crs_node *const node0, + struct crs_node *const node1, + const enum crs_axis axis, + const float ratio, + struct crs_nodedims *const dims) { + struct crs_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 crs_node *const node) { + if (node->type == NODE_WINDOW) { + /* Window Node */ + delwin(node->win); + goto end; + } + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + destroy_node(node->child[0]); + destroy_node(node->child[1]); + free(node->dims); + +end: + free(node); +} + +static inline struct crs_nodedims *__alloc_dims(int x, int y, int width, + int height) { + struct crs_nodedims *dims; + + dims = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); + *dims = (struct crs_nodedims){ + .x = x, + .y = y, + .width = width, + .height = height, + }; + return dims; +} + +static inline struct crs_nodedims * +__dup_dims(const struct crs_nodedims *const dims) { + struct crs_nodedims *dup; + dup = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); + memcpy(dup, dims, sizeof(struct crs_nodedims)); + + return dup; +} + +static inline struct crs_nodedims *termdims(void) { + struct crs_nodedims *dims = __alloc_dims(0, 0, 0, 0); + termsize(dims->width, dims->height); + + return dims; +} + +static inline void nodesize(const struct crs_node *const node, int *const width, + int *const height) { + if (node->type == NODE_WINDOW) { + /* Window Node */ + getmaxyx(node->win, *height, *width); + } else { + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + *width = node->dims->width; + *height = node->dims->height; + } +} + +static inline struct crs_nodedims *nodedims(const struct crs_node *const node) { + struct crs_nodedims *dims; + if (node->type == NODE_WINDOW) { + /* Window Node */ + dims = (struct crs_nodedims *)malloc(sizeof(struct crs_nodedims)); + getbegyx(node->win, dims->y, dims->x); + getmaxyx(node->win, dims->height, dims->width); + } else { + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + dims = __dup_dims(node->dims); + } + + return dims; +} + +/* 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. + */ +static int bifurcate_dims(const struct crs_nodedims *const parent_dims, + const enum crs_axis axis, const float ratio, + struct crs_nodedims **const dims0, + struct crs_nodedims **const dims1) { + assert(0 < ratio && ratio < 1); + struct crs_nodedims *_dims0, *_dims1; + + _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 (!_dims0->width || !_dims0->height || !_dims1->width || !_dims1->height) + return 1; + + // propagate bifurcated dimensions + *dims0 = _dims0; + *dims1 = _dims1; + return 0; +} + +/* 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 crs_node *const node, + struct crs_nodedims *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); + + wnoutrefresh(node->win); + } else { + /* Abstract Node */ + assert(node->type == NODE_ABSTRACT); + struct crs_nodedims *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); + } +} + +/* 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 + */ +void bifurcate_window_node(struct crs_node **const node, + const enum crs_axis axis, const int invert_axis, + const float ratio) { + assert((*node)->type == NODE_WINDOW); + struct crs_nodedims *dims0, *dims1; + struct crs_node *node0, *node1; + + struct crs_nodedims *original_dims = nodedims(*node); + if (bifurcate_dims(original_dims, axis, ratio, &dims0, &dims1)) { + /* TODO: handle this error properly */ + free(original_dims); + exit(1); + return; + } + + if (invert_axis) { + /* Inverted Bifurcation */ + node0 = auto_window_node(dims0); + node1 = *node; + resize_node(node1, dims1); + } else { + /* Non-Inverted Bifurcation */ + node0 = *node; + node1 = auto_window_node(dims1); + resize_node(node0, dims0); + } + + *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 crs_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 crs_node *collapse_target = (*node)->child[collapse_i]; + free(*node); + *node = collapse_target; +} diff --git a/cursetree/node.h b/cursetree/node.h index bf789c3..bf94f2b 100644 --- a/cursetree/node.h +++ b/cursetree/node.h @@ -47,5 +47,13 @@ struct crs_node { }; /* === External Interface === */ +struct crs_node *init_window_node(WINDOW *const win); +void destroy_node(struct crs_node *const node); +void resize_node(struct crs_node *const node, + struct crs_nodedims *const new_dims); + +void bifurcate_window_node(struct crs_node **const node, + const enum crs_axis axis, const int invert_axis, + const float ratio); #endif /* CURSETREE_NODE_H */ diff --git a/cursetree/tree.c b/cursetree/tree.c new file mode 100644 index 0000000..61c268b --- /dev/null +++ b/cursetree/tree.c @@ -0,0 +1,30 @@ +#include + +#include "ncrswrap.h" +#include "tree.h" + +/* + */ +static struct crs_node *init_root_node(void) { + WINDOW *rootwin; + + rootwin = root_window(); + return init_window_node(rootwin); +} + +int init_tree(struct crs_tree **const tree) { + *tree = (struct crs_tree *)malloc(sizeof(struct crs_tree)); + (*tree)->root = init_root_node(); +return EXIT_SUCCESS; +} + +void destroy_tree(struct crs_tree *const tree) { + destroy_node(tree->root); + endwin(); + free(tree); +} + +void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims) { + resize_node(tree->root, dims); +} + diff --git a/cursetree/tree.h b/cursetree/tree.h new file mode 100644 index 0000000..4b07547 --- /dev/null +++ b/cursetree/tree.h @@ -0,0 +1,15 @@ +#ifndef CURSETREE_TREE_H +#define CURSETREE_TREE_H + +#include "node.h" + +struct crs_tree { + struct crs_node *root; +}; + +/* === External Interface === */ +int init_tree(struct crs_tree **const tree); +void destroy_tree(struct crs_tree *const tree); +void resize_tree(struct crs_tree *const tree, struct crs_nodedims *const dims); + +#endif /* CURSETREE_TREE_H */