diff options
| author | 2023-11-16 17:44:47 -0600 | |
|---|---|---|
| committer | 2023-11-16 17:44:47 -0600 | |
| commit | ff292c3477497e03d4cffc1467691e1e6ce54a5c (patch) | |
| tree | b7cd01d3f440dafd07bc7538c116997f7fd3ac01 /src/ui/dock.c | |
initial commit
Diffstat (limited to 'src/ui/dock.c')
| -rw-r--r-- | src/ui/dock.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/src/ui/dock.c b/src/ui/dock.c new file mode 100644 index 0000000..5b59b71 --- /dev/null +++ b/src/ui/dock.c @@ -0,0 +1,183 @@ +#include <stdlib.h> +#include <assert.h> + +#include "ui.internal.h" + +unsigned ui__dock_position_opposite(unsigned position) +{ + switch (position) + { + case UI__WINDOW_DOCK_TOP: + return UI__WINDOW_DOCK_BOTTOM; + case UI__WINDOW_DOCK_BOTTOM: + return UI__WINDOW_DOCK_TOP; + case UI__WINDOW_DOCK_LEFT: + return UI__WINDOW_DOCK_RIGHT; + case UI__WINDOW_DOCK_RIGHT: + return UI__WINDOW_DOCK_LEFT; + default: + assert(false); /* trap: this function should never be called here! */ + } +} + +void ui__dock_adjust(struct ui_window_dock *dock, unsigned flags, int *maxy, int *maxx, int *begy, int *begx) +{ + if (flags & 1) + { + if (dock->children[UI__WINDOW_DOCK_TOP]) + { + unsigned top_maxy = getmaxy(dock->children[UI__WINDOW_DOCK_TOP]->cwindow); + *maxy -= top_maxy; + *begy += top_maxy; + } + + if (dock->children[UI__WINDOW_DOCK_BOTTOM]) + { + unsigned bottom_maxy = getmaxy(dock->children[UI__WINDOW_DOCK_BOTTOM]->cwindow); + *maxy -= bottom_maxy; + } + } + + if (flags & 2) + { + if (dock->children[UI__WINDOW_DOCK_LEFT]) + { + unsigned left_maxx = getmaxx(dock->children[UI__WINDOW_DOCK_LEFT]->cwindow); + *maxx -= left_maxx; + *begx += left_maxx; + } + + if (dock->children[UI__WINDOW_DOCK_RIGHT]) + { + unsigned right_maxx = getmaxx(dock->children[UI__WINDOW_DOCK_RIGHT]->cwindow); + *maxx -= right_maxx; + } + } +} + +/* This is hand-coded to fit with the window priorities, as specified here in ascending order: + * - Top/bottom + * - Left/right + * - Center + * + * Note that other methods (layout proc namely) require this same order to be present in the values of the dock constants. */ +WINDOW *ui__dock_place_window(struct ui_window_dock *dock, unsigned position, float size) +{ + int maxy, maxx; + int begy, begx; + + int out_lines, out_cols; + int out_y, out_x; + + getmaxyx(dock->super.cwindow, maxy, maxx); + getbegyx(dock->super.cwindow, begy, begx); + + switch (position) + { + case UI__WINDOW_DOCK_TOP: + out_lines = maxy * size; + out_y = begy; + out_cols = maxx; + out_x = begx; + break; + case UI__WINDOW_DOCK_BOTTOM: + out_lines = maxy * size; + out_y = maxy - out_lines + begy; + out_cols = maxx; + out_x = begx; + break; + case UI__WINDOW_DOCK_LEFT: + ui__dock_adjust(dock, 1, &maxy, &maxx, &begy, &begx); + out_lines = maxy; + out_y = begy; + out_cols = maxx * size; + out_x = begx; + break; + case UI__WINDOW_DOCK_RIGHT: + ui__dock_adjust(dock, 1, &maxy, &maxx, &begy, &begx); + out_lines = maxy; + out_y = begy; + out_cols = maxx * size; + out_x = maxx - out_cols + begx; + break; + case UI__WINDOW_DOCK_CENTER: + ui__dock_adjust(dock, 3, &maxy, &maxx, &begy, &begx); + out_lines = maxy; + out_y = begy; + out_cols = maxx; + out_x = begx; + break; + default: + assert(false); + } + + return newwin(out_lines, out_cols, out_y, out_x); +} + +void ui__dock_add_child(struct ui_window_dock *dock, struct ui_window_base *child, unsigned position, float size) +{ + assert(!dock->children[position]); /* TODO: handle gracefully (technically invalid usage) */ + assert(!child->parent); /* TODO: take this window from its current parent */ + assert(!child->cwindow); + + child->parent = (struct ui_window_base *)dock; + dock->children[position] = child; + dock->childsizes[position] = size; + + if (position != UI__WINDOW_DOCK_CENTER) + { + unsigned opposite = ui__dock_position_opposite(position); + if (dock->children[opposite] && size + dock->childsizes[opposite] > 1) + { + dock->childsizes[position] = 1 - dock->childsizes[opposite]; + } + } + + /* now set up the window for this child */ + child->cwindow = ui__dock_place_window(dock, position, size); +} + +void ui__dock_default_draw_proc(struct ui_window_base *base) +{ + struct ui_window_dock *dock = (struct ui_window_dock *)base; + + wrefresh(dock->super.cwindow); + for (unsigned i = 0; i < UI__WINDOW_DOCK_MAX; ++i) + { + if (dock->children[i]) + ui__call_draw_proc(dock->children[i]); + } +} + +void ui__dock_default_layout_proc(struct ui_window_base *base) +{ + struct ui_window_dock *dock = (struct ui_window_dock *)base; + + /* fix the layout of children */ + for (unsigned i = 0; i < UI__WINDOW_DOCK_MAX; ++i) + { + struct ui_window_base *child = dock->children[i]; + if (!child) continue; + + delwin(child->cwindow); + child->cwindow = ui__dock_place_window(dock, i, dock->childsizes[i]); + ui__call_layout_proc(child); + } +} + +void ui__root_draw_proc(struct ui_window_base *base) +{ + struct ui_window_root *root = (struct ui_window_root *)base; + ui__dock_default_draw_proc(base); + + if (root->floating) ui__call_draw_proc(root->floating); +} + +void ui__root_layout_proc(struct ui_window_base *base) +{ + struct ui_window_root *root = (struct ui_window_root *)base; + ui__dock_default_layout_proc(base); + + /* TODO: adjust floating window position :) */ + if (root->floating) ui__call_layout_proc(root->floating); +} |
