Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ dmod_add_library(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}
)

dmod_link_modules(${DMOD_MODULE_NAME}
dmvsi@>=0.5
dmvsi@>=0.6
dmvs_js@>=0.1
)

Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ What's reported and left out:
A class changes only the look of its element; what it moves around it
stays.

**Talking to the application.** A page is shown by an application on
dmodOS; `dmod` (dmvs_js) is the channel between them -
`dmod.prop()`, `get()`, `set()`, `onchange()`, `emit()`. One thing more is
said in HTML: `data-dmod-width="name"` makes an element as wide as the
integer property `name` says - its laid out width times the property over
`data-dmod-scale` (1000: per mille; `data-dmod-value` its initial value when
no script makes the property). What is in the element is painted at its
whole width and cut at the property's end: a progress bar the application
moves. In a browser the page's own `dmod.js` does it.

## Resources

Style sheets, fonts and images are files next to the page; a URL is read
Expand Down
20 changes: 17 additions & 3 deletions src/layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -701,10 +701,14 @@ static int32_t place_line(conv_t* c, node_t* block, item_t* items, uint32_t from
static int32_t layout_inline(conv_t* c, node_t* block, node_t* first, node_t* stop, int32_t x0, int32_t y0, int32_t avail,
int32_t cb_h, bool* first_baseline_set)
{
item_t* storage = arena_alloc(&c->arena, MAX_ITEMS * sizeof(item_t));
/* (on the heap, not the arena: a page lays out its inline content many times - flex measures) */
item_t* storage = Dmod_Malloc(MAX_ITEMS * sizeof(item_t));
items_t it = { c, storage, 0, true };
if (storage == NULL)
{
c->arena.failed = true;
return 0;
}
/* The children from `first` up to `stop`, as if they were all of a parent */
node_t holder;
memset(&holder, 0, sizeof(holder));
Expand Down Expand Up @@ -741,6 +745,7 @@ static int32_t layout_inline(conv_t* c, node_t* block, node_t* first, node_t* st
it.items[i].node->box.container = block;
}
}
Dmod_Free(storage);
return 0;
}

Expand Down Expand Up @@ -784,6 +789,7 @@ static int32_t layout_inline(conv_t* c, node_t* block, node_t* first, node_t* st
if (end == it.count)
break;
}
Dmod_Free(storage);
return y - y0;
}

Expand Down Expand Up @@ -868,10 +874,13 @@ static bool replaced_size(conv_t* c, node_t* n, int32_t* w, int32_t* h)

static int32_t intrinsic_items(conv_t* c, node_t* n, bool max_content)
{
item_t* storage = arena_alloc(&c->arena, MAX_ITEMS * sizeof(item_t));
item_t* storage = Dmod_Malloc(MAX_ITEMS * sizeof(item_t)); /* (on the heap: see layout_inline()) */
items_t it = { c, storage, 0, true };
if (storage == NULL)
{
c->arena.failed = true;
return 0;
}
inline_items(&it, n, 0, AUTO_SIZE, true, max_content, 0);
int32_t best = 0, line = 0, word = 0;
for (uint32_t i = 0; i < it.count; i++)
Expand Down Expand Up @@ -899,6 +908,7 @@ static int32_t intrinsic_items(conv_t* c, node_t* n, bool max_content)
word = 0;
}
}
Dmod_Free(storage);
return max32(best, max_content ? line : word);
}

Expand Down Expand Up @@ -1087,10 +1097,13 @@ static int32_t layout_flex(conv_t* c, node_t* n, int32_t x0, int32_t y0, int32_t
int32_t main_avail = row ? cw : ch;
len_t gap_len = row ? st->column_gap : st->row_gap;
int32_t gap = (gap_len.kind == LEN_SET) ? len_resolve(gap_len, max32(main_avail, 0)) : 0;
flex_item_t* items = arena_alloc(&c->arena, MAX_FLEX * sizeof(flex_item_t));
flex_item_t* items = Dmod_Malloc(MAX_FLEX * sizeof(flex_item_t)); /* (on the heap: see layout_inline()) */
uint32_t count = 0;
if (items == NULL)
{
c->arena.failed = true;
return 0;
}

for (node_t* k = n->first; k != NULL; k = k->next)
{
Expand Down Expand Up @@ -1334,6 +1347,7 @@ static int32_t layout_flex(conv_t* c, node_t* n, int32_t x0, int32_t y0, int32_t
baseline_set = true;
}
}
Dmod_Free(items);
if (row)
return (ch != AUTO_SIZE) ? ch : line_cross;
return (ch != AUTO_SIZE) ? ch : used;
Expand Down
87 changes: 86 additions & 1 deletion src/script.c
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ static bool has_class(const node_t* n, const char* name)
}

/* The states laid out, kept for painting their looks (c->states) */
#define MAX_STATES 48u
#define MAX_STATES 96u

typedef struct
{
Expand Down Expand Up @@ -1831,6 +1831,86 @@ static void texts(script_t* sc, node_t* n, uint32_t depth)
}
}

/*
* data-dmod-width="name": the element's width follows the property `name`
* of the view (dmod.prop(), or made here) - the width it is laid out at
* times the property over data-dmod-scale (1000: per mille). What is in it
* is painted at its whole width and cut where the property puts its end
* (a progress bar). The application that shows the view sets the property.
*/

/* The integer property `name`: one the scripts made, else a new one at `initial` */
static dmvsi_var_t prop_var(conv_t* c, const char* name, int32_t initial)
{
dmvsi_var_info_t info;
for (dmvsi_var_t v = 1; dmvsi_var_info(c->doc, v, &info) == 0; v++)
{
const char* prop = dmvsi_var_prop(c->doc, v);
if (prop != NULL && strcmp(prop, name) == 0)
return (info.kind == DMVSI_VAR_INT) ? v : 0;
}
dmvsi_var_t v = dmvsi_add_var(c->doc, name, initial);
if (v != 0 && dmvsi_set_prop(c->doc, v, name) != 0)
return 0;
return v;
}

static int32_t attr_number(const node_t* e, const char* name, int32_t otherwise)
{
const char* a = node_attr(e, name);
if (a == NULL || *a == '\0')
return otherwise;
int32_t v = 0;
bool negative = *a == '-';
for (a += negative ? 1 : 0; *a >= '0' && *a <= '9'; a++)
v = v * 10 + (*a - '0');
return negative ? -v : v;
}

static int bind_widths(conv_t* c, node_t* n, uint32_t depth)
{
for (node_t* e = n->first; e != NULL && depth < 200U; e = e->next)
{
if (e->kind != NODE_ELEMENT)
continue;
const char* name = node_attr(e, "data-dmod-width");
if (name != NULL && *name != '\0' && e->box.placed)
{
int32_t scale = attr_number(e, "data-dmod-scale", 1000);
int32_t w = e->box.w / DMVSI_UNIT;
dmvsi_var_t prop = prop_var(c, name, attr_number(e, "data-dmod-value", 0));
dmvsi_var_info_t info;
if (prop == 0 || scale <= 0 || dmvsi_var_info(c->doc, prop, &info) != 0)
{
WARN(c, "data-dmod-width of #%s: \"%s\" is no integer property - not converted\n", label_of(e), name);
continue;
}
if (e->dynamic == NULL && (e->dynamic = arena_alloc(&c->arena, sizeof(dynamic_t))) == NULL)
return -ENOMEM;
char label[48];
Dmod_SnPrintf(label, sizeof(label), "%s_w", label_of(e));
int64_t now = (int64_t)info.initial * w / scale;
dmvsi_var_t px = dmvsi_add_var(c->doc, label, (int32_t)((now < 0) ? 0 : (now > w) ? w : now));
/* On a change: px = clamp(prop, 0, scale) * w / scale */
dmvsi_action_t a[5];
memset(a, 0, sizeof(a));
a[0].kind = DMVSI_ACT_SET; a[0].var = px; a[0].operand = prop;
a[1].kind = DMVSI_ACT_MAX; a[1].var = px; a[1].value = 0;
a[2].kind = DMVSI_ACT_MIN; a[2].var = px; a[2].value = scale;
a[3].kind = DMVSI_ACT_MUL; a[3].var = px; a[3].value = w;
a[4].kind = DMVSI_ACT_DIV; a[4].var = px; a[4].value = scale;
dmvsi_handler_t h = (px != 0) ? dmvsi_add_handler(c->doc, a, 5) : 0;
if (h == 0 || dmvsi_on_change(c->doc, prop, h) != 0)
return -ENOMEM;
e->dynamic->bind[DMVSI_BIND_W] = px;
}
int ret = bind_widths(c, e, depth + 1U);
if (ret != 0)
return ret;
}
return 0;
}

int script_compile(conv_t* c)
{
script_t* sc = Dmod_Malloc(sizeof(*sc));
Expand All @@ -1847,7 +1927,10 @@ int script_compile(conv_t* c)
find_scripts(sc, c->document, programs, 0);
int status = 0;
if (programs->count == 0)
{
status = bind_widths(c, c->document, 0); /* (no scripts: only what the application sets) */
goto done;
}

dmvs_js_host_t host;
memset(&host, 0, sizeof(host));
Expand Down Expand Up @@ -1891,6 +1974,8 @@ int script_compile(conv_t* c)
status = expand_held(sc);
if (status == 0)
status = lay_out_changes(sc);
if (status == 0)
status = bind_widths(c, c->document, 0);
if (status == 0)
status = make_src_variants(sc);
if (status == 0)
Expand Down
2 changes: 1 addition & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ dmod_add_test(${DMOD_MODULE_NAME} ${DMOD_MODULE_VERSION}

# dmvs_js: dmvs_html needs it loaded to convert a page's scripts
dmod_link_modules(${DMOD_MODULE_NAME}
dmvsi@>=0.5
dmvsi@>=0.6
dmvs_js@>=0.1
)

Expand Down
Loading