302 lines
8.9 KiB
C
302 lines
8.9 KiB
C
#include <hikari/split.h>
|
|
|
|
#include <hikari/color.h>
|
|
#include <hikari/configuration.h>
|
|
#include <hikari/geometry.h>
|
|
#include <hikari/view.h>
|
|
|
|
const double hikari_split_scale_min = 0.1;
|
|
const double hikari_split_scale_max = 0.9;
|
|
const double hikari_split_scale_default = 0.5;
|
|
|
|
static void
|
|
flip_scale(struct hikari_split_scale *scale)
|
|
{
|
|
switch (scale->type) {
|
|
case HIKARI_SPLIT_SCALE_TYPE_FIXED:
|
|
scale->scale.fixed = 1.0 - scale->scale.fixed;
|
|
break;
|
|
|
|
case HIKARI_SPLIT_SCALE_TYPE_DYNAMIC:
|
|
scale->scale.dynamic.min = 1.0 - scale->scale.dynamic.min;
|
|
scale->scale.dynamic.max = 1.0 - scale->scale.dynamic.max;
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define SCALE(name) \
|
|
static int split_scale_##name(struct hikari_split_scale *scale, \
|
|
struct wlr_box *src, \
|
|
struct hikari_view *first) \
|
|
{ \
|
|
int gap = hikari_configuration->gap; \
|
|
struct wlr_box *geometry; \
|
|
int name = 0; \
|
|
\
|
|
switch (scale->type) { \
|
|
case HIKARI_SPLIT_SCALE_TYPE_FIXED: \
|
|
name = \
|
|
hikari_geometry_scale_fixed_##name(src, scale->scale.fixed, gap); \
|
|
break; \
|
|
\
|
|
case HIKARI_SPLIT_SCALE_TYPE_DYNAMIC: \
|
|
geometry = hikari_view_geometry(first); \
|
|
name = hikari_geometry_scale_dynamic_##name(src, \
|
|
geometry, \
|
|
scale->scale.dynamic.min, \
|
|
scale->scale.dynamic.max, \
|
|
gap); \
|
|
break; \
|
|
} \
|
|
\
|
|
assert(name != 0); \
|
|
\
|
|
return name; \
|
|
}
|
|
|
|
SCALE(width)
|
|
SCALE(height)
|
|
#undef SCALE
|
|
|
|
static struct hikari_split *
|
|
copy_split(struct hikari_split *split);
|
|
|
|
#define COPY(name, first, second) \
|
|
static struct hikari_split *copy_split_##name( \
|
|
struct hikari_split_##name *split_##name) \
|
|
{ \
|
|
struct hikari_split *first = copy_split(split_##name->first); \
|
|
struct hikari_split *second = copy_split(split_##name->second); \
|
|
\
|
|
struct hikari_split_##name *ret = \
|
|
hikari_malloc(sizeof(struct hikari_split_##name)); \
|
|
\
|
|
hikari_split_##name##_init( \
|
|
ret, &split_##name->scale, split_##name->orientation, first, second); \
|
|
\
|
|
return (struct hikari_split *)ret; \
|
|
}
|
|
|
|
COPY(vertical, left, right)
|
|
COPY(horizontal, top, bottom)
|
|
#undef COPY
|
|
|
|
static struct hikari_split *
|
|
copy_split_container(struct hikari_split_container *split_container)
|
|
{
|
|
struct hikari_split_container *ret =
|
|
hikari_malloc(sizeof(struct hikari_split_container));
|
|
|
|
hikari_split_container_init(
|
|
ret, split_container->max, split_container->layout);
|
|
|
|
return (struct hikari_split *)ret;
|
|
}
|
|
|
|
static struct hikari_split *
|
|
copy_split(struct hikari_split *split)
|
|
{
|
|
struct hikari_split *ret;
|
|
switch (split->type) {
|
|
case HIKARI_SPLIT_TYPE_VERTICAL:
|
|
ret = copy_split_vertical((struct hikari_split_vertical *)split);
|
|
break;
|
|
|
|
case HIKARI_SPLIT_TYPE_HORIZONTAL:
|
|
ret = copy_split_horizontal((struct hikari_split_horizontal *)split);
|
|
break;
|
|
|
|
case HIKARI_SPLIT_TYPE_CONTAINER:
|
|
ret = copy_split_container((struct hikari_split_container *)split);
|
|
break;
|
|
|
|
default:
|
|
ret = NULL;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
struct hikari_split *
|
|
hikari_split_copy(struct hikari_split *split)
|
|
{
|
|
return copy_split(split);
|
|
}
|
|
|
|
static struct hikari_view *
|
|
apply_split(struct hikari_split *split,
|
|
struct wlr_box *geometry,
|
|
struct hikari_view *first,
|
|
bool *center)
|
|
{
|
|
if (first == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
struct hikari_view *view = first;
|
|
switch (split->type) {
|
|
case HIKARI_SPLIT_TYPE_VERTICAL: {
|
|
struct wlr_box left, right;
|
|
struct hikari_split_vertical *split_vertical =
|
|
(struct hikari_split_vertical *)split;
|
|
|
|
int width = split_scale_width(&split_vertical->scale, geometry, first);
|
|
int gap = hikari_configuration->gap + hikari_configuration->border * 2;
|
|
|
|
hikari_geometry_split_vertical(geometry, width, gap, &left, &right);
|
|
|
|
switch (split_vertical->orientation) {
|
|
case HIKARI_VERTICAL_SPLIT_ORIENTATION_LEFT:
|
|
view = apply_split(split_vertical->left, &left, view, center);
|
|
view = apply_split(split_vertical->right, &right, view, center);
|
|
break;
|
|
|
|
case HIKARI_VERTICAL_SPLIT_ORIENTATION_RIGHT:
|
|
view = apply_split(split_vertical->right, &right, view, center);
|
|
view = apply_split(split_vertical->left, &left, view, center);
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
case HIKARI_SPLIT_TYPE_HORIZONTAL: {
|
|
struct wlr_box top, bottom;
|
|
struct hikari_split_horizontal *split_horizontal =
|
|
(struct hikari_split_horizontal *)split;
|
|
|
|
int height =
|
|
split_scale_height(&split_horizontal->scale, geometry, first);
|
|
int gap = hikari_configuration->gap + hikari_configuration->border * 2;
|
|
|
|
hikari_geometry_split_horizontal(geometry, height, gap, &top, &bottom);
|
|
|
|
switch (split_horizontal->orientation) {
|
|
case HIKARI_HORIZONTAL_SPLIT_ORIENTATION_TOP:
|
|
view = apply_split(split_horizontal->top, &top, view, center);
|
|
view = apply_split(split_horizontal->bottom, &bottom, view, center);
|
|
break;
|
|
|
|
case HIKARI_HORIZONTAL_SPLIT_ORIENTATION_BOTTOM:
|
|
view = apply_split(split_horizontal->bottom, &bottom, view, center);
|
|
view = apply_split(split_horizontal->top, &top, view, center);
|
|
break;
|
|
}
|
|
} break;
|
|
|
|
case HIKARI_SPLIT_TYPE_CONTAINER: {
|
|
struct hikari_split_container *container =
|
|
(struct hikari_split_container *)split;
|
|
container->geometry = *geometry;
|
|
view = container->layout(
|
|
view->sheet, view, geometry, container->max, center);
|
|
} break;
|
|
}
|
|
|
|
return view;
|
|
}
|
|
|
|
void
|
|
hikari_split_apply(struct hikari_split *split,
|
|
struct wlr_box *geometry,
|
|
struct hikari_view *first)
|
|
{
|
|
if (first == NULL) {
|
|
return;
|
|
}
|
|
|
|
bool center = true;
|
|
|
|
hikari_geometry_shrink(
|
|
geometry, hikari_configuration->gap + hikari_configuration->border);
|
|
|
|
apply_split(split, geometry, first, ¢er);
|
|
}
|
|
|
|
void
|
|
hikari_split_container_init(struct hikari_split_container *container,
|
|
int nr_of_views,
|
|
hikari_layout_func layout)
|
|
{
|
|
container->split.type = HIKARI_SPLIT_TYPE_CONTAINER;
|
|
container->max = nr_of_views;
|
|
container->layout = layout;
|
|
container->geometry = (struct wlr_box){ 0 };
|
|
}
|
|
|
|
void
|
|
hikari_split_vertical_init(struct hikari_split_vertical *split_vertical,
|
|
struct hikari_split_scale *scale,
|
|
enum hikari_split_vertical_orientation orientation,
|
|
struct hikari_split *left,
|
|
struct hikari_split *right)
|
|
{
|
|
split_vertical->split.type = HIKARI_SPLIT_TYPE_VERTICAL;
|
|
split_vertical->orientation = orientation;
|
|
split_vertical->left = left;
|
|
split_vertical->right = right;
|
|
|
|
memcpy(&split_vertical->scale, scale, sizeof(struct hikari_split_scale));
|
|
|
|
if (split_vertical->orientation == HIKARI_VERTICAL_SPLIT_ORIENTATION_RIGHT) {
|
|
flip_scale(&split_vertical->scale);
|
|
}
|
|
}
|
|
|
|
void
|
|
hikari_split_horizontal_init(struct hikari_split_horizontal *split_horizontal,
|
|
struct hikari_split_scale *scale,
|
|
enum hikari_split_horizontal_orientation orientation,
|
|
struct hikari_split *top,
|
|
struct hikari_split *bottom)
|
|
{
|
|
split_horizontal->split.type = HIKARI_SPLIT_TYPE_HORIZONTAL;
|
|
split_horizontal->orientation = orientation;
|
|
split_horizontal->top = top;
|
|
split_horizontal->bottom = bottom;
|
|
|
|
memcpy(&split_horizontal->scale, scale, sizeof(struct hikari_split_scale));
|
|
|
|
if (split_horizontal->orientation ==
|
|
HIKARI_HORIZONTAL_SPLIT_ORIENTATION_BOTTOM) {
|
|
flip_scale(&split_horizontal->scale);
|
|
}
|
|
}
|
|
|
|
void
|
|
hikari_split_free(struct hikari_split *split)
|
|
{
|
|
switch (split->type) {
|
|
case HIKARI_SPLIT_TYPE_VERTICAL: {
|
|
struct hikari_split_vertical *split_vertical =
|
|
(struct hikari_split_vertical *)split;
|
|
|
|
hikari_split_free(split_vertical->left);
|
|
hikari_split_free(split_vertical->right);
|
|
hikari_free(split_vertical);
|
|
} break;
|
|
|
|
case HIKARI_SPLIT_TYPE_HORIZONTAL: {
|
|
struct hikari_split_horizontal *split_horizontal =
|
|
(struct hikari_split_horizontal *)split;
|
|
|
|
hikari_split_free(split_horizontal->top);
|
|
hikari_split_free(split_horizontal->bottom);
|
|
hikari_free(split_horizontal);
|
|
} break;
|
|
|
|
case HIKARI_SPLIT_TYPE_CONTAINER: {
|
|
struct hikari_split_container *container =
|
|
(struct hikari_split_container *)split;
|
|
|
|
hikari_free(container);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
struct hikari_split *
|
|
hikari_sheet_default_split(struct hikari_sheet *sheet)
|
|
{
|
|
return hikari_configuration_lookup_layout(
|
|
hikari_configuration, 48 + sheet->nr);
|
|
}
|