summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2023-10-03 17:15:43 -0700
committerVito Caputo <vcaputo@pengaru.com>2023-10-03 17:15:43 -0700
commitb7b24205fc2e88278bfc6477c9f3f2eb8c59f369 (patch)
tree519b6e4856346f8dd437890007b82f077a8a11c5
parent271889386861ab8685cebddcebeaa87eea3fa417 (diff)
modules/asc: add justify= and [hv]offset= settings
justify= now supports "aligned" and "offsetted", justify=aligned being the existing behavior where you would specify halign={left,right,center} and valign={top,bottom,center}. When justify=offsetted is specified however, {valign=,halign=} are unused and instead {hoffset=,voffset=} are expected, as either hoffset=auto/voffset=auto for automagic offsetting according to the x/y coords, or explicit offsetting using -1..+1 normalized fractional values serving as coordinates within the rendered text's rectangle where to anchor the x/y coordinate. By using halign=auto,valign=auto one can carelessly vary the x/y coordinates using the taps (i.e. via rkt) without having to deal with justification concerns (modulo large texts that can't possibly fit), as the offsets will automatically adapt according to the coordinates.
-rw-r--r--src/modules/asc/asc.c202
1 files changed, 157 insertions, 45 deletions
diff --git a/src/modules/asc/asc.c b/src/modules/asc/asc.c
index d47ac6d..98455a7 100644
--- a/src/modules/asc/asc.c
+++ b/src/modules/asc/asc.c
@@ -16,29 +16,31 @@
/* This is intended primarily for diagnostic purposes or as a stand-in you'd eventually
* replace with something a more visually interesting font/style.
- *
- * TODO:
- * - Maybe add a dynamic justification mode where the h/v alignment offsets are
- * just the inverse of the normalized x/y coordinates. This requires extending
- * libs/txt to support precise offsetting when rendering as an alternative to the
- * enum'd txt_align_t variant. But it would allow a tapped x/y coordinate user to
- * sweep the coordinates edge-to-edge with the text smoothly adjusting its offset
- * throughout the sweep so it doesn't extend off-screen at the nearest edge.
*/
#define ASC_DEFAULT_STRING "Hello rototiller!"
+#define ASC_DEFAULT_JUSTIFY ASC_JUSTIFY_ALIGNED
#define ASC_DEFAULT_HALIGN TXT_HALIGN_CENTER
#define ASC_DEFAULT_VALIGN TXT_VALIGN_CENTER
+#define ASC_DEFAULT_HOFFSET "auto"
+#define ASC_DEFAULT_VOFFSET "auto"
#define ASC_DEFAULT_X 0
#define ASC_DEFAULT_Y 0
+typedef enum asc_justify_t {
+ ASC_JUSTIFY_ALIGNED,
+ ASC_JUSTIFY_OFFSETTED,
+ ASC_JUSITFY_CNT
+} asc_justify_t;
+
typedef struct asc_setup_t {
til_setup_t til_setup;
const char *string;
- txt_halign_t halign;
- txt_valign_t valign;
+ asc_justify_t justify;
+ txt_halign_t halign, valign;
+ float hoffset, voffset;
float x, y;
} asc_setup_t;
@@ -47,13 +49,16 @@ typedef struct asc_context_t {
struct {
til_tap_t x, y;
+ til_tap_t hoffset, voffset;
} taps;
struct {
float x, y;
+ float hoffset, voffset;
} vars;
float *x, *y;
+ float *hoffset, *voffset;
txt_t *txt;
} asc_context_t;
@@ -71,9 +76,22 @@ static void asc_update_taps(asc_context_t *ctxt, til_stream_t *stream)
else
ctxt->vars.y = *ctxt->y;
- /* XXX: maybe clamp to -1.0..+1.0 ? It's not a crash risk since txt_render_fragment()
+ /* XXX: maybe clamp to -1.0..+1.0 ? It's not a crash risk since txt_render_fragment_aligned()
* clips to the fragment by using ...put_pixel_checked() *shrug*
*/
+
+ if (((asc_setup_t *)ctxt->til_module_context.setup)->justify != ASC_JUSTIFY_OFFSETTED)
+ return;
+
+ if (!til_stream_tap_context(stream, &ctxt->til_module_context, NULL, &ctxt->taps.hoffset))
+ *ctxt->hoffset = ((asc_setup_t *)ctxt->til_module_context.setup)->hoffset;
+ else
+ ctxt->vars.hoffset = *ctxt->hoffset;
+
+ if (!til_stream_tap_context(stream, &ctxt->til_module_context, NULL, &ctxt->taps.voffset))
+ *ctxt->voffset = ((asc_setup_t *)ctxt->til_module_context.setup)->voffset;
+ else
+ ctxt->vars.voffset = *ctxt->voffset;
}
@@ -92,6 +110,11 @@ static til_module_context_t * asc_create_context(const til_module_t *module, til
ctxt->taps.x = til_tap_init_float(ctxt, &ctxt->x, 1, &ctxt->vars.x, "x");
ctxt->taps.y = til_tap_init_float(ctxt, &ctxt->y, 1, &ctxt->vars.y, "y");
+ if (((asc_setup_t *)setup)->justify == ASC_JUSTIFY_OFFSETTED) {
+ ctxt->taps.hoffset = til_tap_init_float(ctxt, &ctxt->hoffset, 1, &ctxt->vars.hoffset, "hoffset");
+ ctxt->taps.voffset = til_tap_init_float(ctxt, &ctxt->voffset, 1, &ctxt->vars.voffset, "voffset");
+ }
+
asc_update_taps(ctxt, stream);
return &ctxt->til_module_context;
@@ -108,13 +131,35 @@ static void asc_render_fragment(til_module_context_t *context, til_stream_t *str
til_fb_fragment_clear(fragment);
- txt_render_fragment_aligned(ctxt->txt, fragment, 0xffffffff,
- ctxt->vars.x * ((float)fragment->frame_width) * .5f + .5f * ((float)fragment->frame_width),
- ctxt->vars.y * ((float)fragment->frame_height) * .5f + .5f * ((float)fragment->frame_height),
- (txt_align_t){
- .horiz = s->halign,
- .vert = s->valign
- });
+ switch (s->justify) {
+ case ASC_JUSTIFY_ALIGNED:
+ return txt_render_fragment_aligned(ctxt->txt, fragment, 0xffffffff,
+ ctxt->vars.x * ((float)fragment->frame_width) * .5f + .5f * ((float)fragment->frame_width),
+ ctxt->vars.y * ((float)fragment->frame_height) * .5f + .5f * ((float)fragment->frame_height),
+ (txt_align_t){
+ .horiz = s->halign,
+ .vert = s->valign
+ });
+
+ case ASC_JUSTIFY_OFFSETTED: {
+ float hoffset = ctxt->vars.hoffset,
+ voffset = ctxt->vars.voffset;
+
+ if (isnan(hoffset))
+ hoffset = ctxt->vars.x;
+
+ if (isnan(voffset))
+ voffset = ctxt->vars.y;
+
+ return txt_render_fragment_offsetted(ctxt->txt, fragment, 0xffffffff,
+ ctxt->vars.x * ((float)fragment->frame_width) * .5f + .5f * ((float)fragment->frame_width),
+ ctxt->vars.y * ((float)fragment->frame_height) * .5f + .5f * ((float)fragment->frame_height),
+ hoffset, voffset);
+ }
+
+ default:
+ assert(0);
+ }
}
@@ -146,9 +191,15 @@ til_module_t asc_module = {
static int asc_setup(const til_settings_t *settings, til_setting_t **res_setting, const til_setting_desc_t **res_desc, til_setup_t **res_setup)
{
til_setting_t *string;
- til_setting_t *valign;
- til_setting_t *halign;
+ til_setting_t *justify;
+ til_setting_t *valign, *voffset;
+ til_setting_t *halign, *hoffset;
til_setting_t *x, *y;
+ const char *justify_values[] = {
+ "aligned",
+ "offsetted",
+ NULL
+ };
const char *valign_values[] = {
"center",
"top",
@@ -178,33 +229,78 @@ static int asc_setup(const til_settings_t *settings, til_setting_t **res_setting
r = til_settings_get_and_describe_setting(settings,
&(til_setting_spec_t){
- .name = "Vertical alignment",
- .key = "valign",
+ .name = "Justification",
+ .key = "justify",
/* .regex = "" TODO */
- .preferred = valign_values[ASC_DEFAULT_VALIGN],
- .values = valign_values,
+ .preferred = justify_values[ASC_DEFAULT_JUSTIFY],
+ .values = justify_values,
.annotations = NULL
},
- &valign,
+ &justify,
res_setting,
res_desc);
if (r)
return r;
- r = til_settings_get_and_describe_setting(settings,
- &(til_setting_spec_t){
- .name = "Horizontal alignment",
- .key = "halign",
- /* .regex = "" TODO */
- .preferred = halign_values[ASC_DEFAULT_HALIGN],
- .values = halign_values,
- .annotations = NULL
- },
- &halign,
- res_setting,
- res_desc);
- if (r)
- return r;
+ if (!strcasecmp(justify->value, justify_values[ASC_JUSTIFY_ALIGNED])) {
+ r = til_settings_get_and_describe_setting(settings,
+ &(til_setting_spec_t){
+ .name = "Vertical alignment",
+ .key = "valign",
+ /* .regex = "" TODO */
+ .preferred = valign_values[ASC_DEFAULT_VALIGN],
+ .values = valign_values,
+ .annotations = NULL
+ },
+ &valign,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
+ r = til_settings_get_and_describe_setting(settings,
+ &(til_setting_spec_t){
+ .name = "Horizontal alignment",
+ .key = "halign",
+ /* .regex = "" TODO */
+ .preferred = halign_values[ASC_DEFAULT_HALIGN],
+ .values = halign_values,
+ .annotations = NULL
+ },
+ &halign,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+ } else {
+ r = til_settings_get_and_describe_setting(settings,
+ &(til_setting_spec_t){
+ .name = "Vertical offset [-1.0...1.0] or 'auto'",
+ .key = "voffset",
+ /* .regex = "" TODO */
+ .preferred = ASC_DEFAULT_VOFFSET,
+ .annotations = NULL
+ },
+ &voffset,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+
+ r = til_settings_get_and_describe_setting(settings,
+ &(til_setting_spec_t){
+ .name = "Horizontal offset [-1.0...1.0] or 'auto'",
+ .key = "hoffset",
+ /* .regex = "" TODO */
+ .preferred = ASC_DEFAULT_HOFFSET,
+ .annotations = NULL
+ },
+ &hoffset,
+ res_setting,
+ res_desc);
+ if (r)
+ return r;
+ }
r = til_settings_get_and_describe_setting(settings,
&(til_setting_spec_t){
@@ -245,13 +341,29 @@ static int asc_setup(const til_settings_t *settings, til_setting_t **res_setting
if (!setup->string)
return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, string, res_setting, -ENOMEM);
- r = til_value_to_pos(halign_values, halign->value, (unsigned *)&setup->halign);
- if (r < 0)
- return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, halign, res_setting, -EINVAL);
-
- r = til_value_to_pos(valign_values, valign->value, (unsigned *)&setup->valign);
+ r = til_value_to_pos(justify_values, justify->value, (unsigned *)&setup->justify);
if (r < 0)
- return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, valign, res_setting, -EINVAL);
+ return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, justify, res_setting, -EINVAL);
+
+ if (setup->justify == ASC_JUSTIFY_ALIGNED) {
+ r = til_value_to_pos(halign_values, halign->value, (unsigned *)&setup->halign);
+ if (r < 0)
+ return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, halign, res_setting, -EINVAL);
+
+ r = til_value_to_pos(valign_values, valign->value, (unsigned *)&setup->valign);
+ if (r < 0)
+ return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, valign, res_setting, -EINVAL);
+ } else {
+ if (!strcasecmp(hoffset->value, "auto"))
+ setup->hoffset = NAN;
+ else if (sscanf(hoffset->value, "%f", &setup->hoffset) != 1)
+ return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, hoffset, res_setting, -EINVAL);
+
+ if (!strcasecmp(voffset->value, "auto"))
+ setup->voffset = NAN;
+ else if (sscanf(voffset->value, "%f", &setup->voffset) != 1)
+ return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, voffset, res_setting, -EINVAL);
+ }
if (sscanf(x->value, "%f", &setup->x) != 1)
return til_setup_free_with_failed_setting_ret_err(&setup->til_setup, x, res_setting, -EINVAL);
© All Rights Reserved