mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-14 00:40:55 +00:00
[ui] Add functions for flow-based automatic layout
This should be suitable for laying out text objects with word-wrap, where each view is a "word" or break between "words". This should be useful for any other objects that could benefit from similar layout rules. All eight flows are supported left-right-top-down (English and most European languages), right-left-top-down (Arabic and similar), top-down-right-left (Chinese, Japanese, Korean), top-down-left-right, as well as bottom-up variants of those four. More work is needed for support of things like views being centered on the flow line rather than on one edge (depends on flow direction), offset views, and others. Suppression of "spaces" at the beginning of a line is supported but not tested.
This commit is contained in:
parent
31945c6e01
commit
378584f41d
4 changed files with 511 additions and 0 deletions
|
@ -64,6 +64,7 @@ typedef enum {
|
||||||
grav_southwest, ///< +ve X right, +ve Y up, -X left, -ve Y down
|
grav_southwest, ///< +ve X right, +ve Y up, -X left, -ve Y down
|
||||||
grav_west, ///< +ve X right, +ve Y down, -X left, -ve Y up
|
grav_west, ///< +ve X right, +ve Y down, -X left, -ve Y up
|
||||||
grav_northwest, ///< +ve X right, +ve Y down, -X left, -ve Y up
|
grav_northwest, ///< +ve X right, +ve Y down, -X left, -ve Y up
|
||||||
|
grav_flow, ///< controlled by view_flow
|
||||||
} grav_t;
|
} grav_t;
|
||||||
|
|
||||||
extern struct exprtype_s grav_t_type;
|
extern struct exprtype_s grav_t_type;
|
||||||
|
@ -96,6 +97,7 @@ struct view_s {
|
||||||
unsigned visible:1; ///< If false, view_draw() skips this view.
|
unsigned visible:1; ///< If false, view_draw() skips this view.
|
||||||
unsigned resize_x:1; ///< If true, view's width follows parent's.
|
unsigned resize_x:1; ///< If true, view's width follows parent's.
|
||||||
unsigned resize_y:1; ///< If true, view's height follows parent's.
|
unsigned resize_y:1; ///< If true, view's height follows parent's.
|
||||||
|
unsigned bol_suppress:1; ///< If true, view_flow skips at start of line.
|
||||||
view_t *parent; ///< The parent view.
|
view_t *parent; ///< The parent view.
|
||||||
view_t **children; ///< The child views.
|
view_t **children; ///< The child views.
|
||||||
int num_children; ///< Number of child views in view.
|
int num_children; ///< Number of child views in view.
|
||||||
|
@ -254,6 +256,15 @@ void view_setgeometry (view_t *view, int xp, int yp, int xl, int yl);
|
||||||
*/
|
*/
|
||||||
void view_setgravity (view_t *view, grav_t grav);
|
void view_setgravity (view_t *view, grav_t grav);
|
||||||
|
|
||||||
|
void view_flow_right_down (view_t *view);
|
||||||
|
void view_flow_right_up (view_t *view);
|
||||||
|
void view_flow_left_down (view_t *view);
|
||||||
|
void view_flow_left_up (view_t *view);
|
||||||
|
void view_flow_down_right (view_t *view);
|
||||||
|
void view_flow_up_right (view_t *view);
|
||||||
|
void view_flow_down_left (view_t *view);
|
||||||
|
void view_flow_up_left (view_t *view);
|
||||||
|
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
#endif//__QF_ui_view_h
|
#endif//__QF_ui_view_h
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
libs_ui_tests = \
|
libs_ui_tests = \
|
||||||
|
libs/ui/test/test-flow \
|
||||||
libs/ui/test/test-txtbuffer \
|
libs/ui/test/test-txtbuffer \
|
||||||
libs/ui/test/test-vrect
|
libs/ui/test/test-vrect
|
||||||
|
|
||||||
|
@ -6,6 +7,10 @@ TESTS += $(libs_ui_tests)
|
||||||
|
|
||||||
check_PROGRAMS += $(libs_ui_tests)
|
check_PROGRAMS += $(libs_ui_tests)
|
||||||
|
|
||||||
|
libs_ui_test_test_flow_SOURCES=libs/ui/test/test-flow.c
|
||||||
|
libs_ui_test_test_flow_LDADD=libs/ui/libQFui.la
|
||||||
|
libs_ui_test_test_flow_DEPENDENCIES=libs/ui/libQFui.la
|
||||||
|
|
||||||
libs_ui_test_test_txtbuffer_SOURCES=libs/ui/test/test-txtbuffer.c
|
libs_ui_test_test_txtbuffer_SOURCES=libs/ui/test/test-txtbuffer.c
|
||||||
libs_ui_test_test_txtbuffer_LDADD=libs/ui/libQFui.la
|
libs_ui_test_test_txtbuffer_LDADD=libs/ui/libQFui.la
|
||||||
libs_ui_test_test_txtbuffer_DEPENDENCIES=libs/ui/libQFui.la
|
libs_ui_test_test_txtbuffer_DEPENDENCIES=libs/ui/libQFui.la
|
||||||
|
|
284
libs/ui/test/test-flow.c
Normal file
284
libs/ui/test/test-flow.c
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include "config.h"
|
||||||
|
#endif
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "QF/ui/view.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
struct {
|
||||||
|
int xlen, ylen;
|
||||||
|
};
|
||||||
|
int bol_suppress;
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
int xpos, ypos;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
int xrel, yrel;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
int xabs, yabs;
|
||||||
|
};
|
||||||
|
} expect;
|
||||||
|
} testdata_t;
|
||||||
|
|
||||||
|
#define array_size(array) (sizeof (array) / sizeof(array[0]))
|
||||||
|
|
||||||
|
static testdata_t right_down_views[] = {
|
||||||
|
{{ 48, 8}, 0, { { 0, 0}, { 0, 0}, { 8, 16} }}, // 0
|
||||||
|
{{128, 8}, 0, { { 48, 0}, { 48, 0}, { 56, 16} }},
|
||||||
|
{{ 64, 8}, 0, { {176, 0}, {176, 0}, {184, 16} }},
|
||||||
|
|
||||||
|
{{ 32, 8}, 0, { { 0, 0}, { 0, 8}, { 8, 24} }}, // 3
|
||||||
|
{{224, 8}, 0, { { 32, 0}, { 32, 8}, { 40, 24} }},
|
||||||
|
|
||||||
|
{{ 64, 8}, 0, { { 0, 0}, { 0, 16}, { 8, 32} }}, // 5
|
||||||
|
{{ 64, 8}, 0, { { 64, 0}, { 64, 16}, { 72, 32} }},
|
||||||
|
{{ 64, 8}, 0, { {128, 0}, {128, 16}, {136, 32} }},
|
||||||
|
{{ 32, 8}, 0, { {192, 0}, {192, 16}, {200, 32} }},
|
||||||
|
|
||||||
|
{{288, 8}, 0, { { 0, 0}, { 0, 24}, { 8, 40} }}, // 9
|
||||||
|
|
||||||
|
{{ 48, 8}, 0, { { 0, 0}, { 0, 32}, { 8, 48} }}, // 10
|
||||||
|
{{128, 8}, 0, { { 48, 0}, { 48, 32}, { 56, 48} }},
|
||||||
|
{{ 64, 8}, 0, { {176, 0}, {176, 32}, {184, 48} }},
|
||||||
|
};
|
||||||
|
#define right_down_count array_size(right_down_views)
|
||||||
|
|
||||||
|
static testdata_t right_up_views[] = {
|
||||||
|
{{ 48, 8}, 0, { { 0, 0}, { 0,248}, { 8,264} }}, // 0
|
||||||
|
{{128, 8}, 0, { { 48, 0}, { 48,248}, { 56,264} }},
|
||||||
|
{{ 64, 8}, 0, { {176, 0}, {176,248}, {184,264} }},
|
||||||
|
|
||||||
|
{{ 32, 8}, 0, { { 0, 0}, { 0,240}, { 8,256} }}, // 3
|
||||||
|
{{224, 8}, 0, { { 32, 0}, { 32,240}, { 40,256} }},
|
||||||
|
|
||||||
|
{{ 64, 8}, 0, { { 0, 0}, { 0,232}, { 8,248} }}, // 5
|
||||||
|
{{ 64, 8}, 0, { { 64, 0}, { 64,232}, { 72,248} }},
|
||||||
|
{{ 64, 8}, 0, { {128, 0}, {128,232}, {136,248} }},
|
||||||
|
{{ 32, 8}, 0, { {192, 0}, {192,232}, {200,248} }},
|
||||||
|
|
||||||
|
{{288, 8}, 0, { { 0, 0}, { 0,224}, { 8,240} }}, // 9
|
||||||
|
|
||||||
|
{{ 48, 8}, 0, { { 0, 0}, { 0,216}, { 8,232} }}, // 10
|
||||||
|
{{128, 8}, 0, { { 48, 0}, { 48,216}, { 56,232} }},
|
||||||
|
{{ 64, 8}, 0, { {176, 0}, {176,216}, {184,232} }},
|
||||||
|
};
|
||||||
|
#define right_up_count array_size(right_up_views)
|
||||||
|
|
||||||
|
static testdata_t left_down_views[] = {
|
||||||
|
{{ 48, 8}, 0, { {208, 0}, {208, 0}, {216, 16} }}, // 0
|
||||||
|
{{128, 8}, 0, { { 80, 0}, { 80, 0}, { 88, 16} }},
|
||||||
|
{{ 64, 8}, 0, { { 16, 0}, { 16, 0}, { 24, 16} }},
|
||||||
|
|
||||||
|
{{ 32, 8}, 0, { {224, 0}, {224, 8}, {232, 24} }}, // 3
|
||||||
|
{{224, 8}, 0, { { 0, 0}, { 0, 8}, { 8, 24} }},
|
||||||
|
|
||||||
|
{{ 64, 8}, 0, { {192, 0}, {192, 16}, {200, 32} }}, // 5
|
||||||
|
{{ 64, 8}, 0, { {128, 0}, {128, 16}, {136, 32} }},
|
||||||
|
{{ 64, 8}, 0, { { 64, 0}, { 64, 16}, { 72, 32} }},
|
||||||
|
{{ 32, 8}, 0, { { 32, 0}, { 32, 16}, { 40, 32} }},
|
||||||
|
|
||||||
|
{{288, 8}, 0, { {-32, 0}, {-32, 24}, {-24, 40} }}, // 9
|
||||||
|
|
||||||
|
{{ 48, 8}, 0, { {208, 0}, {208, 32}, {216, 48} }}, // 10
|
||||||
|
{{128, 8}, 0, { { 80, 0}, { 80, 32}, { 88, 48} }},
|
||||||
|
{{ 64, 8}, 0, { { 16, 0}, { 16, 32}, { 24, 48} }},
|
||||||
|
};
|
||||||
|
#define left_down_count array_size(left_down_views)
|
||||||
|
|
||||||
|
static testdata_t left_up_views[] = {
|
||||||
|
{{ 48, 8}, 0, { {208, 0}, {208,248}, {216,264} }}, // 0
|
||||||
|
{{128, 8}, 0, { { 80, 0}, { 80,248}, { 88,264} }},
|
||||||
|
{{ 64, 8}, 0, { { 16, 0}, { 16,248}, { 24,264} }},
|
||||||
|
|
||||||
|
{{ 32, 8}, 0, { {224, 0}, {224,240}, {232,256} }}, // 3
|
||||||
|
{{224, 8}, 0, { { 0, 0}, { 0,240}, { 8,256} }},
|
||||||
|
|
||||||
|
{{ 64, 8}, 0, { {192, 0}, {192,232}, {200,248} }}, // 5
|
||||||
|
{{ 64, 8}, 0, { {128, 0}, {128,232}, {136,248} }},
|
||||||
|
{{ 64, 8}, 0, { { 64, 0}, { 64,232}, { 72,248} }},
|
||||||
|
{{ 32, 8}, 0, { { 32, 0}, { 32,232}, { 40,248} }},
|
||||||
|
|
||||||
|
{{288, 8}, 0, { {-32, 0}, {-32,224}, {-24,240} }}, // 9
|
||||||
|
|
||||||
|
{{ 48, 8}, 0, { {208, 0}, {208,216}, {216,232} }}, // 10
|
||||||
|
{{128, 8}, 0, { { 80, 0}, { 80,216}, { 88,232} }},
|
||||||
|
{{ 64, 8}, 0, { { 16, 0}, { 16,216}, { 24,232} }},
|
||||||
|
};
|
||||||
|
#define left_up_count array_size(left_up_views)
|
||||||
|
|
||||||
|
static testdata_t down_right_views[] = {
|
||||||
|
{{ 8, 48}, 0, { { 0, 0}, { 0, 0}, { 8, 16} }}, // 0
|
||||||
|
{{ 8,128}, 0, { { 0, 48}, { 0, 48}, { 8, 64} }},
|
||||||
|
{{ 8, 64}, 0, { { 0,176}, { 0,176}, { 8,192} }},
|
||||||
|
|
||||||
|
{{ 8, 32}, 0, { { 0, 0}, { 8, 0}, { 16, 16} }}, // 3
|
||||||
|
{{ 8,224}, 0, { { 0, 32}, { 8, 32}, { 16, 48} }},
|
||||||
|
|
||||||
|
{{ 8, 64}, 0, { { 0, 0}, { 16, 0}, { 24, 16} }}, // 5
|
||||||
|
{{ 8, 64}, 0, { { 0, 64}, { 16, 64}, { 24, 80} }},
|
||||||
|
{{ 8, 64}, 0, { { 0,128}, { 16,128}, { 24,144} }},
|
||||||
|
{{ 8, 32}, 0, { { 0,192}, { 16,192}, { 24,208} }},
|
||||||
|
|
||||||
|
{{ 8,288}, 0, { { 0, 0}, { 24, 0}, { 32, 16} }}, // 9
|
||||||
|
|
||||||
|
{{ 8, 48}, 0, { { 0, 0}, { 32, 0}, { 40, 16} }}, // 10
|
||||||
|
{{ 8,128}, 0, { { 0, 48}, { 32, 48}, { 40, 64} }},
|
||||||
|
{{ 8, 64}, 0, { { 0,176}, { 32,176}, { 40,192} }},
|
||||||
|
};
|
||||||
|
#define down_right_count array_size(down_right_views)
|
||||||
|
|
||||||
|
static testdata_t up_right_views[] = {
|
||||||
|
{{ 8, 48}, 0, { { 0,208}, { 0,208}, { 8,224} }}, // 0
|
||||||
|
{{ 8,128}, 0, { { 0, 80}, { 0, 80}, { 8, 96} }},
|
||||||
|
{{ 8, 64}, 0, { { 0, 16}, { 0, 16}, { 8, 32} }},
|
||||||
|
|
||||||
|
{{ 8, 32}, 0, { { 0,224}, { 8,224}, { 16,240} }}, // 3
|
||||||
|
{{ 8,224}, 0, { { 0, 0}, { 8, 0}, { 16, 16} }},
|
||||||
|
|
||||||
|
{{ 8, 64}, 0, { { 0,192}, { 16,192}, { 24,208} }}, // 5
|
||||||
|
{{ 8, 64}, 0, { { 0,128}, { 16,128}, { 24,144} }},
|
||||||
|
{{ 8, 64}, 0, { { 0, 64}, { 16, 64}, { 24, 80} }},
|
||||||
|
{{ 8, 32}, 0, { { 0, 32}, { 16, 32}, { 24, 48} }},
|
||||||
|
|
||||||
|
{{ 8,288}, 0, { { 0,-32}, { 24,-32}, { 32,-16} }}, // 9
|
||||||
|
|
||||||
|
{{ 8, 48}, 0, { { 0,208}, { 32,208}, { 40,224} }}, // 10
|
||||||
|
{{ 8,128}, 0, { { 0, 80}, { 32, 80}, { 40, 96} }},
|
||||||
|
{{ 8, 64}, 0, { { 0, 16}, { 32, 16}, { 40, 32} }},
|
||||||
|
};
|
||||||
|
#define up_right_count array_size(up_right_views)
|
||||||
|
|
||||||
|
static testdata_t down_left_views[] = {
|
||||||
|
{{ 8, 48}, 0, { { 0, 0}, {248, 0}, {256, 16} }}, // 0
|
||||||
|
{{ 8,128}, 0, { { 0, 48}, {248, 48}, {256, 64} }},
|
||||||
|
{{ 8, 64}, 0, { { 0,176}, {248,176}, {256,192} }},
|
||||||
|
|
||||||
|
{{ 8, 32}, 0, { { 0, 0}, {240, 0}, {248, 16} }}, // 3
|
||||||
|
{{ 8,224}, 0, { { 0, 32}, {240, 32}, {248, 48} }},
|
||||||
|
|
||||||
|
{{ 8, 64}, 0, { { 0, 0}, {232, 0}, {240, 16} }}, // 5
|
||||||
|
{{ 8, 64}, 0, { { 0, 64}, {232, 64}, {240, 80} }},
|
||||||
|
{{ 8, 64}, 0, { { 0,128}, {232,128}, {240,144} }},
|
||||||
|
{{ 8, 32}, 0, { { 0,192}, {232,192}, {240,208} }},
|
||||||
|
|
||||||
|
{{ 8,288}, 0, { { 0, 0}, {224, 0}, {232, 16} }}, // 9
|
||||||
|
|
||||||
|
{{ 8, 48}, 0, { { 0, 0}, {216, 0}, {224, 16} }}, // 10
|
||||||
|
{{ 8,128}, 0, { { 0, 48}, {216, 48}, {224, 64} }},
|
||||||
|
{{ 8, 64}, 0, { { 0,176}, {216,176}, {224,192} }},
|
||||||
|
};
|
||||||
|
#define down_left_count array_size(down_left_views)
|
||||||
|
|
||||||
|
static testdata_t up_left_views[] = {
|
||||||
|
{{ 8, 48}, 0, { { 0,208}, {248,208}, {256,224} }}, // 0
|
||||||
|
{{ 8,128}, 0, { { 0, 80}, {248, 80}, {256, 96} }},
|
||||||
|
{{ 8, 64}, 0, { { 0, 16}, {248, 16}, {256, 32} }},
|
||||||
|
|
||||||
|
{{ 8, 32}, 0, { { 0,224}, {240,224}, {248,240} }}, // 3
|
||||||
|
{{ 8,224}, 0, { { 0, 0}, {240, 0}, {248, 16} }},
|
||||||
|
|
||||||
|
{{ 8, 64}, 0, { { 0,192}, {232,192}, {240,208} }}, // 5
|
||||||
|
{{ 8, 64}, 0, { { 0,128}, {232,128}, {240,144} }},
|
||||||
|
{{ 8, 64}, 0, { { 0, 64}, {232, 64}, {240, 80} }},
|
||||||
|
{{ 8, 32}, 0, { { 0, 32}, {232, 32}, {240, 48} }},
|
||||||
|
|
||||||
|
{{ 8,288}, 0, { { 0,-32}, {224,-32}, {232,-16} }}, // 9
|
||||||
|
|
||||||
|
{{ 8, 48}, 0, { { 0,208}, {216,208}, {224,224} }}, // 10
|
||||||
|
{{ 8,128}, 0, { { 0, 80}, {216, 80}, {224, 96} }},
|
||||||
|
{{ 8, 64}, 0, { { 0, 16}, {216, 16}, {224, 32} }},
|
||||||
|
};
|
||||||
|
#define up_left_count array_size(up_left_views)
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_view (view_t *view)
|
||||||
|
{
|
||||||
|
printf ("%s[%3d %3d %3d %3d %3d %3d %3d %3d]\n",
|
||||||
|
view->parent ? " " : "****",
|
||||||
|
view->xpos, view->ypos, view->xlen, view->ylen,
|
||||||
|
view->xrel, view->yrel, view->xabs, view->yabs);
|
||||||
|
view_draw (view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
test_flow (testdata_t *child_views, int count, void (*flow) (view_t *))
|
||||||
|
{
|
||||||
|
view_t *flow_view = view_new (0, 0, 256, 256, grav_northwest);
|
||||||
|
flow_view->setgeometry = flow;
|
||||||
|
flow_view->draw = print_view;
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
testdata_t *td = &child_views[i];
|
||||||
|
view_t *child = view_new (0, 0, td->xlen, td->ylen, grav_flow);
|
||||||
|
child->bol_suppress = td->bol_suppress;
|
||||||
|
child->draw = print_view;
|
||||||
|
view_add (flow_view, child);
|
||||||
|
}
|
||||||
|
|
||||||
|
view_move (flow_view, 8, 16);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < flow_view->num_children; i++) {
|
||||||
|
testdata_t *td = &child_views[i];
|
||||||
|
view_t *child = flow_view->children[i];
|
||||||
|
if (child->xpos != td->expect.xpos
|
||||||
|
|| child->ypos != td->expect.ypos
|
||||||
|
|| child->xrel != td->expect.xrel
|
||||||
|
|| child->yrel != td->expect.yrel
|
||||||
|
|| child->xabs != td->expect.xabs
|
||||||
|
|| child->yabs != td->expect.yabs) {
|
||||||
|
ret = 1;
|
||||||
|
printf ("child %d misflowed:\n"
|
||||||
|
" [%3d %3d %3d %3d %3d %3d]\n", i,
|
||||||
|
td->expect.xpos, td->expect.ypos,
|
||||||
|
td->expect.xrel, td->expect.yrel,
|
||||||
|
td->expect.xabs, td->expect.yabs);
|
||||||
|
print_view (child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (test_flow (right_down_views, right_down_count, view_flow_right_down)) {
|
||||||
|
printf ("right-down failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
if (test_flow (right_up_views, right_up_count, view_flow_right_up)) {
|
||||||
|
printf ("right-up failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
if (test_flow (left_down_views, left_down_count, view_flow_left_down)) {
|
||||||
|
printf ("left-down failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
if (test_flow (left_up_views, left_up_count, view_flow_left_up)) {
|
||||||
|
printf ("left-up failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (test_flow (down_right_views, down_right_count, view_flow_down_right)) {
|
||||||
|
printf ("down-right failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
if (test_flow (up_right_views, up_right_count, view_flow_up_right)) {
|
||||||
|
printf ("up-right failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
if (test_flow (down_left_views, down_left_count, view_flow_down_left)) {
|
||||||
|
printf ("down-left failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
if (test_flow (up_left_views, up_left_count, view_flow_up_left)) {
|
||||||
|
printf ("up-left failed\n");
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
211
libs/ui/view.c
211
libs/ui/view.c
|
@ -40,6 +40,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "QF/cexpr.h"
|
#include "QF/cexpr.h"
|
||||||
|
#include "QF/mathlib.h"
|
||||||
#include "QF/ui/view.h"
|
#include "QF/ui/view.h"
|
||||||
|
|
||||||
static exprenum_t grav_t_enum;
|
static exprenum_t grav_t_enum;
|
||||||
|
@ -133,6 +134,8 @@ setgeometry (view_t *view)
|
||||||
view->xrel = view->xpos;
|
view->xrel = view->xpos;
|
||||||
view->yrel = view->ypos;
|
view->yrel = view->ypos;
|
||||||
break;
|
break;
|
||||||
|
case grav_flow:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
view->xabs = par->xabs + view->xrel;
|
view->xabs = par->xabs + view->xrel;
|
||||||
view->yabs = par->yabs + view->yrel;
|
view->yabs = par->yabs + view->yrel;
|
||||||
|
@ -284,3 +287,211 @@ view_setgravity (view_t *view, grav_t grav)
|
||||||
view->gravity = grav;
|
view->gravity = grav;
|
||||||
setgeometry (view);
|
setgeometry (view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct flowline_s {
|
||||||
|
struct flowline_s *next;
|
||||||
|
int first_child;
|
||||||
|
int child_count;
|
||||||
|
int cursor;
|
||||||
|
int height;
|
||||||
|
} flowline_t;
|
||||||
|
|
||||||
|
#define NEXT_LINE(line, child_index) \
|
||||||
|
do { \
|
||||||
|
line->next = alloca (sizeof (flowline_t)); \
|
||||||
|
memset (line->next, 0, sizeof (flowline_t)); \
|
||||||
|
line = line->next; \
|
||||||
|
line->first_child = child_index; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static void
|
||||||
|
flow_right (view_t *view, void (*set_rows) (view_t *, flowline_t *))
|
||||||
|
{
|
||||||
|
flowline_t flowline = {};
|
||||||
|
flowline_t *line = &flowline;
|
||||||
|
for (int i = 0; i < view->num_children; i++) {
|
||||||
|
view_t *child = view->children[i];
|
||||||
|
if (line->cursor && line->cursor + child->xlen > view->xlen) {
|
||||||
|
NEXT_LINE(line, i);
|
||||||
|
}
|
||||||
|
child->xpos = line->cursor;
|
||||||
|
if (child->xpos || !child->bol_suppress) {
|
||||||
|
line->cursor += child->xlen;
|
||||||
|
}
|
||||||
|
line->height = max (child->ylen, line->height);
|
||||||
|
line->child_count++;
|
||||||
|
}
|
||||||
|
set_rows (view, &flowline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
flow_left (view_t *view, void (*set_rows) (view_t *, flowline_t *))
|
||||||
|
{
|
||||||
|
flowline_t flowline = {};
|
||||||
|
flowline_t *line = &flowline;
|
||||||
|
line->cursor = view->xlen;
|
||||||
|
for (int i = 0; i < view->num_children; i++) {
|
||||||
|
view_t *child = view->children[i];
|
||||||
|
if (line->cursor < view->xlen && line->cursor - child->xlen < 0) {
|
||||||
|
NEXT_LINE(line, i);
|
||||||
|
line->cursor = view->xlen;
|
||||||
|
}
|
||||||
|
if (child->xpos < view->xlen || !child->bol_suppress) {
|
||||||
|
line->cursor -= child->xlen;
|
||||||
|
}
|
||||||
|
child->xpos = line->cursor;
|
||||||
|
line->height = max (child->ylen, line->height);
|
||||||
|
line->child_count++;
|
||||||
|
}
|
||||||
|
set_rows (view, &flowline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
flow_down (view_t *view, void (*set_rows) (view_t *, flowline_t *))
|
||||||
|
{
|
||||||
|
flowline_t flowline = {};
|
||||||
|
flowline_t *line = &flowline;
|
||||||
|
for (int i = 0; i < view->num_children; i++) {
|
||||||
|
view_t *child = view->children[i];
|
||||||
|
if (line->cursor && line->cursor + child->ylen > view->ylen) {
|
||||||
|
NEXT_LINE(line, i);
|
||||||
|
}
|
||||||
|
child->ypos = line->cursor;
|
||||||
|
if (child->ypos || !child->bol_suppress) {
|
||||||
|
line->cursor += child->ylen;
|
||||||
|
}
|
||||||
|
line->height = max (child->xlen, line->height);
|
||||||
|
line->child_count++;
|
||||||
|
}
|
||||||
|
set_rows (view, &flowline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
flow_up (view_t *view, void (*set_rows) (view_t *, flowline_t *))
|
||||||
|
{
|
||||||
|
flowline_t flowline = {};
|
||||||
|
flowline_t *line = &flowline;
|
||||||
|
line->cursor = view->ylen;
|
||||||
|
for (int i = 0; i < view->num_children; i++) {
|
||||||
|
view_t *child = view->children[i];
|
||||||
|
if (line->cursor < view->ylen && line->cursor - child->ylen < 0) {
|
||||||
|
NEXT_LINE(line, i);
|
||||||
|
line->cursor = view->ylen;
|
||||||
|
}
|
||||||
|
if (child->ypos < view->ylen || !child->bol_suppress) {
|
||||||
|
line->cursor -= child->ylen;
|
||||||
|
}
|
||||||
|
child->ypos = line->cursor;
|
||||||
|
line->height = max (child->xlen, line->height);
|
||||||
|
line->child_count++;
|
||||||
|
}
|
||||||
|
set_rows (view, &flowline);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_rows_down (view_t *view, flowline_t *flowlines)
|
||||||
|
{
|
||||||
|
int cursor = 0;
|
||||||
|
for (flowline_t *line = flowlines; line; line = line->next) {
|
||||||
|
cursor += line->height;
|
||||||
|
for (int i = 0; i < line->child_count; i++) {
|
||||||
|
view_t *child = view->children[line->first_child + i];
|
||||||
|
|
||||||
|
child->xrel = child->xpos;
|
||||||
|
child->yrel = cursor + child->ypos - child->ylen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_rows_up (view_t *view, flowline_t *flowlines)
|
||||||
|
{
|
||||||
|
int cursor = view->ylen;
|
||||||
|
for (flowline_t *line = flowlines; line; line = line->next) {
|
||||||
|
for (int i = 0; i < line->child_count; i++) {
|
||||||
|
view_t *child = view->children[line->first_child + i];
|
||||||
|
|
||||||
|
child->xrel = child->xpos;
|
||||||
|
child->yrel = cursor + child->ypos - child->ylen;
|
||||||
|
}
|
||||||
|
cursor -= line->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_columns_right (view_t *view, flowline_t *flowlines)
|
||||||
|
{
|
||||||
|
int cursor = 0;
|
||||||
|
for (flowline_t *line = flowlines; line; line = line->next) {
|
||||||
|
for (int i = 0; i < line->child_count; i++) {
|
||||||
|
view_t *child = view->children[line->first_child + i];
|
||||||
|
|
||||||
|
child->xrel = cursor + child->xpos;
|
||||||
|
child->yrel = child->ypos;
|
||||||
|
}
|
||||||
|
cursor += line->height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_columns_left (view_t *view, flowline_t *flowlines)
|
||||||
|
{
|
||||||
|
int cursor = view->xlen;
|
||||||
|
for (flowline_t *line = flowlines; line; line = line->next) {
|
||||||
|
cursor -= line->height;
|
||||||
|
for (int i = 0; i < line->child_count; i++) {
|
||||||
|
view_t *child = view->children[line->first_child + i];
|
||||||
|
|
||||||
|
child->xrel = cursor + child->xpos;
|
||||||
|
child->yrel = child->ypos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_right_down (view_t *view)
|
||||||
|
{
|
||||||
|
flow_right (view, set_rows_down);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_right_up (view_t *view)
|
||||||
|
{
|
||||||
|
flow_right (view, set_rows_up);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_left_down (view_t *view)
|
||||||
|
{
|
||||||
|
flow_left (view, set_rows_down);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_left_up (view_t *view)
|
||||||
|
{
|
||||||
|
flow_left (view, set_rows_up);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_down_right (view_t *view)
|
||||||
|
{
|
||||||
|
flow_down (view, set_columns_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_up_right (view_t *view)
|
||||||
|
{
|
||||||
|
flow_up (view, set_columns_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_down_left (view_t *view)
|
||||||
|
{
|
||||||
|
flow_down (view, set_columns_left);
|
||||||
|
}
|
||||||
|
|
||||||
|
VISIBLE void
|
||||||
|
view_flow_up_left (view_t *view)
|
||||||
|
{
|
||||||
|
flow_up (view, set_columns_left);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue