#include #include #include #include "ncrswrap.h" #include "node.h" /* Internal allocator method for ct_node structures. */ static inline struct ct_node *__alloc_node(const enum ct_nodetype type) { 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). */ struct ct_node *init_window_node(WINDOW *const win) { struct ct_node *node = __alloc_node(NODE_WINDOW); node->win = win; 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; } /* 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 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); } 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); wnoutrefresh(node->win); } 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); } } /* 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 */ 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; 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; } 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 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; }