(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:
Emile Clark-Boman 2025-09-13 23:45:56 +10:00
parent b04f0b4aa3
commit 759920a9cc
9 changed files with 476 additions and 193 deletions

View file

@ -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;
// }

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 */

View file

@ -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);
}

View file

@ -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
View 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
View 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 */

View file

@ -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);
}