Compare commits
2 Commits
167676f478
...
d7cab085f7
Author | SHA1 | Date | |
---|---|---|---|
d7cab085f7 | |||
01c2fa3367 |
@ -186,7 +186,7 @@ fn PElemTuple? Ctx.get_elem(&ctx, Id id, ElemType type)
|
|||||||
elem.type = type;
|
elem.type = type;
|
||||||
}
|
}
|
||||||
elem.z_index = parent.z_index;
|
elem.z_index = parent.z_index;
|
||||||
elem.tree_idx = ctx.tree.add(ctx.active_div, id);
|
elem.tree_idx = ctx.tree.add(ctx.active_div, id)!;
|
||||||
return {elem, parent};
|
return {elem, parent};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,8 +17,9 @@ import std::ascii;
|
|||||||
alias Codepoint = uint;
|
alias Codepoint = uint;
|
||||||
|
|
||||||
<*
|
<*
|
||||||
@require off != null
|
@require str.ptr != null: "string pointer must be non null"
|
||||||
@require str.ptr != null
|
@param [in] str
|
||||||
|
@param [&inout] off
|
||||||
*>
|
*>
|
||||||
fn Codepoint str_to_codepoint(char[] str, usz* off)
|
fn Codepoint str_to_codepoint(char[] str, usz* off)
|
||||||
{
|
{
|
||||||
@ -81,6 +82,12 @@ struct Font {
|
|||||||
bool should_update; // should send update_atlas command, resets at frame_end()
|
bool should_update; // should send update_atlas command, resets at frame_end()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&inout] font
|
||||||
|
@param [in] name
|
||||||
|
@param [&in] path
|
||||||
|
@require height > 0, scale > 0: "height and scale must be positive non-zero"
|
||||||
|
*>
|
||||||
fn void? Font.load(&font, String name, ZString path, uint height, float scale)
|
fn void? Font.load(&font, String name, ZString path, uint height, float scale)
|
||||||
{
|
{
|
||||||
font.table.init(allocator::mem, capacity: FONT_CACHED);
|
font.table.init(allocator::mem, capacity: FONT_CACHED);
|
||||||
@ -119,6 +126,9 @@ fn void? Font.load(&font, String name, ZString path, uint height, float scale)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&inout] font
|
||||||
|
*>
|
||||||
fn Glyph*? Font.get_glyph(&font, Codepoint code)
|
fn Glyph*? Font.get_glyph(&font, Codepoint code)
|
||||||
{
|
{
|
||||||
Glyph*? gp;
|
Glyph*? gp;
|
||||||
@ -177,6 +187,9 @@ fn Glyph*? Font.get_glyph(&font, Codepoint code)
|
|||||||
return font.table.get_ref(code);
|
return font.table.get_ref(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&inout] font
|
||||||
|
*>
|
||||||
fn void Font.free(&font)
|
fn void Font.free(&font)
|
||||||
{
|
{
|
||||||
font.atlas.free();
|
font.atlas.free();
|
||||||
@ -189,17 +202,28 @@ fn void Font.free(&font)
|
|||||||
// FONT LOAD AND QUERY //
|
// FONT LOAD AND QUERY //
|
||||||
// ---------------------------------------------------------------------------------- //
|
// ---------------------------------------------------------------------------------- //
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&inout] ctx
|
||||||
|
@param [in] name
|
||||||
|
@param [&in] path
|
||||||
|
@require height > 0, scale > 0: "height and scale must be positive non-zero"
|
||||||
|
*>
|
||||||
fn void? Ctx.load_font(&ctx, String name, ZString path, uint height, float scale = 1.0)
|
fn void? Ctx.load_font(&ctx, String name, ZString path, uint height, float scale = 1.0)
|
||||||
{
|
{
|
||||||
return ctx.font.load(name, path, height, scale);
|
return ctx.font.load(name, path, height, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&in] ctx
|
||||||
|
@param [in] label
|
||||||
|
*>
|
||||||
// TODO: check if the font is present in the context
|
// TODO: check if the font is present in the context
|
||||||
fn Id Ctx.get_font_id(&ctx, String label)
|
fn Id Ctx.get_font_id(&ctx, String label) => (Id)label.hash();
|
||||||
{
|
|
||||||
return (Id)label.hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
<*
|
||||||
|
@param [&in] ctx
|
||||||
|
@param [in] name
|
||||||
|
*>
|
||||||
fn Atlas*? Ctx.get_font_atlas(&ctx, String name)
|
fn Atlas*? Ctx.get_font_atlas(&ctx, String name)
|
||||||
{
|
{
|
||||||
// TODO: use the font name, for now there is only one font
|
// TODO: use the font name, for now there is only one font
|
||||||
@ -210,6 +234,7 @@ fn Atlas*? Ctx.get_font_atlas(&ctx, String name)
|
|||||||
return &ctx.font.atlas;
|
return &ctx.font.atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<* @param [&in] font *>
|
||||||
fn int Font.line_height(&font) => (int)(font.ascender - font.descender + (float)0.5);
|
fn int Font.line_height(&font) => (int)(font.ascender - font.descender + (float)0.5);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------- //
|
// ---------------------------------------------------------------------------------- //
|
||||||
@ -229,6 +254,10 @@ struct TextSize {
|
|||||||
// width.max: the width of the string left as-is
|
// width.max: the width of the string left as-is
|
||||||
// height.min: the height of the string left as-is
|
// height.min: the height of the string left as-is
|
||||||
// height.max: the height of the string with each word broken up by a new line
|
// height.max: the height of the string with each word broken up by a new line
|
||||||
|
<*
|
||||||
|
@param [&in] ctx
|
||||||
|
@param [in] text
|
||||||
|
*>
|
||||||
fn TextSize? Ctx.measure_string(&ctx, String text)
|
fn TextSize? Ctx.measure_string(&ctx, String text)
|
||||||
{
|
{
|
||||||
if (text == "") return (TextSize){};
|
if (text == "") return (TextSize){};
|
||||||
@ -306,6 +335,10 @@ fn TextSize? Ctx.measure_string(&ctx, String text)
|
|||||||
// character's advance value
|
// character's advance value
|
||||||
// TODO: implement a "reflow" flag to toggle reflow if a character goes out of bounds
|
// TODO: implement a "reflow" flag to toggle reflow if a character goes out of bounds
|
||||||
// TODO: also return the total bounds of the laid out string
|
// TODO: also return the total bounds of the laid out string
|
||||||
|
<*
|
||||||
|
@param [&in] ctx
|
||||||
|
@param [in] text
|
||||||
|
*>
|
||||||
fn Rect? Ctx.layout_string(&ctx, String text, Rect bounds, Anchor anchor, int z_index, Color hue, isz cursor = -1)
|
fn Rect? Ctx.layout_string(&ctx, String text, Rect bounds, Anchor anchor, int z_index, Color hue, isz cursor = -1)
|
||||||
{
|
{
|
||||||
Font* font = &ctx.font;
|
Font* font = &ctx.font;
|
||||||
|
@ -88,6 +88,7 @@ struct MTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<* @param [&inout] tree *>
|
||||||
fn void MTree.init(&tree, usz size, Allocator allocator = mem)
|
fn void MTree.init(&tree, usz size, Allocator allocator = mem)
|
||||||
{
|
{
|
||||||
// round size to the nearest multiple of BITS
|
// round size to the nearest multiple of BITS
|
||||||
@ -106,6 +107,7 @@ fn void MTree.init(&tree, usz size, Allocator allocator = mem)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<* @param [&inout] tree *>
|
||||||
fn void MTree.free(&tree)
|
fn void MTree.free(&tree)
|
||||||
{
|
{
|
||||||
tree.elements = 0;
|
tree.elements = 0;
|
||||||
@ -116,7 +118,8 @@ fn void MTree.free(&tree)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn int MTree.get_free_spot(&tree)
|
<* @param [&inout] tree *>
|
||||||
|
fn int? MTree.get_free_spot(&tree)
|
||||||
{
|
{
|
||||||
foreach (idx, d: tree.used) {
|
foreach (idx, d: tree.used) {
|
||||||
if (d != $typeof(d).max) {
|
if (d != $typeof(d).max) {
|
||||||
@ -124,7 +127,7 @@ fn int MTree.get_free_spot(&tree)
|
|||||||
return spot;
|
return spot;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
unreachable("no free spots left");
|
return CAPACITY_EXCEEDED?;
|
||||||
}
|
}
|
||||||
|
|
||||||
<* @require idx >= 0 *>
|
<* @require idx >= 0 *>
|
||||||
@ -163,10 +166,13 @@ fn int MTree.last_node(&tree, int parent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
<* @require tree.elements == 0 || tree.is_used(parent) == true *>
|
<*
|
||||||
fn int MTree.add(&tree, int parent, Type t)
|
@require tree.elements == 0 || tree.is_used(parent) == true
|
||||||
|
@param [&inout] tree
|
||||||
|
*>
|
||||||
|
fn int? MTree.add(&tree, int parent, Type t)
|
||||||
{
|
{
|
||||||
int idx = tree.get_free_spot();
|
int idx = tree.get_free_spot()!;
|
||||||
int subtree = idx / BITS;
|
int subtree = idx / BITS;
|
||||||
|
|
||||||
tree.set_used(idx);
|
tree.set_used(idx);
|
||||||
@ -197,11 +203,11 @@ fn int MTree.add(&tree, int parent, Type t)
|
|||||||
}
|
}
|
||||||
// on fail we need to create another parent node
|
// on fail we need to create another parent node
|
||||||
if (!done) {
|
if (!done) {
|
||||||
int new_next = tree.get_free_spot();
|
int new_next = tree.get_free_spot()!;
|
||||||
// if the new node does not land in the same subtree as the child we cannot do
|
// if the new node does not land in the same subtree as the child we cannot do
|
||||||
// anything since the references are immutable
|
// anything since the references are immutable
|
||||||
if (new_next/BITS != subtree) {
|
if (new_next/BITS != subtree) {
|
||||||
unreachable("cannot allocate new child for parent");
|
return CAPACITY_EXCEEDED?;
|
||||||
}
|
}
|
||||||
tree.set_used(new_next);
|
tree.set_used(new_next);
|
||||||
tree.elements++;
|
tree.elements++;
|
||||||
@ -220,6 +226,7 @@ fn int MTree.add(&tree, int parent, Type t)
|
|||||||
|
|
||||||
// get the index of the n-th children of parent, -1 otherwise
|
// get the index of the n-th children of parent, -1 otherwise
|
||||||
// usage: for (int i, c; (c = tree.children_it(parent, i)) >= 0; i++) { ... }
|
// usage: for (int i, c; (c = tree.children_it(parent, i)) >= 0; i++) { ... }
|
||||||
|
<* @param [&in] tree *>
|
||||||
fn int MTree.children_it(&tree, int parent, int n)
|
fn int MTree.children_it(&tree, int parent, int n)
|
||||||
{
|
{
|
||||||
int tot_children;
|
int tot_children;
|
||||||
@ -247,6 +254,7 @@ fn int MTree.children_it(&tree, int parent, int n)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<* @param [&in] tree *>
|
||||||
fn int MTree.children_num(&tree, int parent)
|
fn int MTree.children_num(&tree, int parent)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
@ -256,6 +264,7 @@ fn int MTree.children_num(&tree, int parent)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<* @param [&in] tree *>
|
||||||
fn int MTree.subtree_size(&tree, int parent)
|
fn int MTree.subtree_size(&tree, int parent)
|
||||||
{
|
{
|
||||||
int x = tree.children_num(parent);
|
int x = tree.children_num(parent);
|
||||||
@ -266,8 +275,7 @@ fn int MTree.subtree_size(&tree, int parent)
|
|||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<* @param [&inout] tree *>
|
||||||
|
|
||||||
fn int MTree.level_order_it(&tree, int parent, int i)
|
fn int MTree.level_order_it(&tree, int parent, int i)
|
||||||
{
|
{
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@ -285,8 +293,11 @@ fn int MTree.level_order_it(&tree, int parent, int i)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<* @param [&inout] tree *>
|
||||||
fn void MTree.prune(&tree, int parent)
|
fn void MTree.prune(&tree, int parent)
|
||||||
{
|
{
|
||||||
|
if (!tree.is_used(parent)) return;
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
for (int i = 0; (c = tree.children_it(parent, i)) >= 0; i++) {
|
for (int i = 0; (c = tree.children_it(parent, i)) >= 0; i++) {
|
||||||
tree.prune(c); // prune the subtree
|
tree.prune(c); // prune the subtree
|
||||||
@ -312,16 +323,24 @@ fn void MTree.prune(&tree, int parent)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<* @require ref >= 0 , ref < tree.elem_vec.len *>
|
<*
|
||||||
|
@require ref >= 0 , ref < tree.elem_vec.len
|
||||||
|
@param [&inout] tree
|
||||||
|
*>
|
||||||
fn Type? MTree.get(&tree, int ref) @operator([])
|
fn Type? MTree.get(&tree, int ref) @operator([])
|
||||||
{
|
{
|
||||||
if (tree.is_used(ref)) return tree.elem_vec[ref];
|
if (tree.is_used(ref)) return tree.elem_vec[ref];
|
||||||
return NOT_FOUND?;
|
return NOT_FOUND?;
|
||||||
}
|
}
|
||||||
|
|
||||||
<* @require tree.is_used(ref) *>
|
<* @param [&in] tree *>
|
||||||
fn Type MTree.parentof(&tree, int ref) => tree.refs_vec[ref].parent;
|
fn Type? MTree.parentof(&tree, int ref)
|
||||||
|
{
|
||||||
|
if (!tree.is_used(ref)) return NOT_FOUND?;
|
||||||
|
return tree.refs_vec[ref].parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
<* @param [&inout] tree *>
|
||||||
fn void MTree.nuke(&tree)
|
fn void MTree.nuke(&tree)
|
||||||
{
|
{
|
||||||
foreach (idx, &b: tree.used) {
|
foreach (idx, &b: tree.used) {
|
||||||
@ -331,9 +350,10 @@ fn void MTree.nuke(&tree)
|
|||||||
tree.elements = 0;
|
tree.elements = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<* @param [&in] t *>
|
||||||
|
macro bool MTree.is_root(&t, int i) => t.is_used(i) && t.refs_vec[i].parent == -1;
|
||||||
|
|
||||||
macro bool MTree.is_root(&t, int i) => t.refs_vec[i].parent == -1;
|
<* @param [&in] tree *>
|
||||||
|
|
||||||
fn void MTree.print(&tree)
|
fn void MTree.print(&tree)
|
||||||
{
|
{
|
||||||
foreach (idx, c: tree.elem_vec) {
|
foreach (idx, c: tree.elem_vec) {
|
||||||
|
@ -1,352 +0,0 @@
|
|||||||
module vtree::faults;
|
|
||||||
faultdef CANNOT_SHRINK, INVALID_REFERENCE, TREE_FULL, REFERENCE_NOT_PRESENT, INVALID_ARGUMENT;
|
|
||||||
|
|
||||||
module vtree{ElemType};
|
|
||||||
|
|
||||||
import std::core::mem;
|
|
||||||
import std::core::mem::allocator;
|
|
||||||
import std::io;
|
|
||||||
|
|
||||||
struct VTree {
|
|
||||||
Allocator allocator;
|
|
||||||
usz elements;
|
|
||||||
ElemType[] vector; // vector of element ids
|
|
||||||
isz[] refs, ordered_refs;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
macro VTree.ref_is_valid(&tree, isz ref) => (ref >= 0 && ref < tree.refs.len);
|
|
||||||
macro VTree.ref_is_present(&tree, isz ref) => tree.refs[ref] >= 0;
|
|
||||||
macro VTree.size(&tree) => tree.refs.len;
|
|
||||||
|
|
||||||
// macro to zero an element
|
|
||||||
macro @zero()
|
|
||||||
{
|
|
||||||
$if @assignable_to(0, ElemType):
|
|
||||||
return 0;
|
|
||||||
$endif
|
|
||||||
|
|
||||||
$if @assignable_to(null, ElemType):
|
|
||||||
return null;
|
|
||||||
$endif
|
|
||||||
|
|
||||||
$if @assignable_to({}, ElemType):
|
|
||||||
return {};
|
|
||||||
$endif
|
|
||||||
|
|
||||||
//$assert true == false : ElemType.nameof +++ " is not assignable to zero or equivalent";
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void? VTree.init(&tree, usz size, Allocator allocator)
|
|
||||||
{
|
|
||||||
tree.allocator = allocator;
|
|
||||||
|
|
||||||
tree.vector = allocator::new_array(tree.allocator, ElemType, size);
|
|
||||||
defer catch { (void)allocator::free(tree.allocator, tree.vector); }
|
|
||||||
|
|
||||||
tree.refs = allocator::new_array(tree.allocator, isz, size);
|
|
||||||
defer catch { (void)allocator::free(tree.allocator, tree.refs); }
|
|
||||||
|
|
||||||
tree.ordered_refs = allocator::new_array(tree.allocator, isz, size);
|
|
||||||
defer catch { (void)allocator::free(tree.allocator, tree.ordered_refs); }
|
|
||||||
|
|
||||||
// set all refs to -1, meaning invalid (free) element
|
|
||||||
tree.refs[..] = -1;
|
|
||||||
|
|
||||||
tree.elements = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void VTree.free(&tree)
|
|
||||||
{
|
|
||||||
(void)allocator::free(tree.allocator, tree.vector);
|
|
||||||
(void)allocator::free(tree.allocator, tree.refs);
|
|
||||||
(void)allocator::free(tree.allocator, tree.ordered_refs);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void VTree.pack(&tree)
|
|
||||||
{
|
|
||||||
// TODO: add a PACKED flag to skip this
|
|
||||||
|
|
||||||
isz free_spot = -1;
|
|
||||||
for (usz i = 0; i < tree.size(); i++) {
|
|
||||||
if (tree.refs[i] == -1) {
|
|
||||||
free_spot = i;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find a item that can be packed
|
|
||||||
if (free_spot >= 0 && tree.refs[i] >= 0) {
|
|
||||||
isz old_ref = i;
|
|
||||||
|
|
||||||
// move the item
|
|
||||||
tree.vector[free_spot] = tree.vector[i];
|
|
||||||
tree.refs[free_spot] = tree.refs[i];
|
|
||||||
|
|
||||||
tree.vector[i] = {};
|
|
||||||
tree.refs[i] = -1;
|
|
||||||
|
|
||||||
// and move all references
|
|
||||||
for (usz j = 0; j < tree.size(); j++) {
|
|
||||||
if (tree.refs[j] == old_ref) {
|
|
||||||
tree.refs[j] = free_spot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark the free spot as used
|
|
||||||
free_spot = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void? VTree.resize(&tree, usz newsize)
|
|
||||||
{
|
|
||||||
// return error when shrinking with too many elements
|
|
||||||
if (newsize < tree.elements) {
|
|
||||||
return vtree::faults::CANNOT_SHRINK?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// pack the vector when shrinking to avoid data loss
|
|
||||||
if ((int)newsize < tree.size()) {
|
|
||||||
// FIXME: packing destroys all references to elements of vec
|
|
||||||
// so shrinking may cause dangling pointers
|
|
||||||
return vtree::faults::CANNOT_SHRINK?;
|
|
||||||
}
|
|
||||||
|
|
||||||
usz old_size = tree.size();
|
|
||||||
|
|
||||||
tree.vector = ((ElemType*)allocator::realloc(tree.allocator, tree.vector, newsize*ElemType.sizeof))[:newsize];
|
|
||||||
defer catch { (void)allocator::free(tree.allocator, tree.vector); }
|
|
||||||
|
|
||||||
tree.refs = ((isz*)allocator::realloc(tree.allocator, tree.refs, newsize*isz.sizeof))[:newsize];
|
|
||||||
defer catch { (void)allocator::free(tree.allocator, tree.refs); }
|
|
||||||
|
|
||||||
tree.ordered_refs = ((isz*)allocator::realloc(tree.allocator, tree.ordered_refs, newsize*isz.sizeof))[:newsize];
|
|
||||||
defer catch { (void)allocator::free(tree.allocator, tree.ordered_refs); }
|
|
||||||
|
|
||||||
if (newsize > tree.size()) {
|
|
||||||
tree.vector[old_size..newsize-1] = @zero();
|
|
||||||
tree.refs[old_size..newsize-1] = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// add an element to the tree, return it's ref
|
|
||||||
fn isz? VTree.add(&tree, ElemType elem, isz parent)
|
|
||||||
{
|
|
||||||
// invalid parent
|
|
||||||
if (!tree.ref_is_valid(parent)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no space left
|
|
||||||
if (tree.elements >= tree.size()) {
|
|
||||||
return vtree::faults::TREE_FULL?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the parent exists
|
|
||||||
// if there are no elements in the tree the first add will set the root
|
|
||||||
if (!tree.ref_is_present(parent) && tree.elements != 0) {
|
|
||||||
return vtree::faults::REFERENCE_NOT_PRESENT?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the first free spot
|
|
||||||
isz free_spot = -1;
|
|
||||||
for (usz i = 0; i < tree.size(); i++) {
|
|
||||||
if (tree.refs[i] == -1) {
|
|
||||||
free_spot = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (free_spot < 0) {
|
|
||||||
return vtree::faults::TREE_FULL?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally add the element
|
|
||||||
tree.vector[free_spot] = elem;
|
|
||||||
tree.refs[free_spot] = parent;
|
|
||||||
tree.elements++;
|
|
||||||
|
|
||||||
return free_spot;
|
|
||||||
}
|
|
||||||
|
|
||||||
// prune the tree starting from the ref
|
|
||||||
// returns the number of pruned elements
|
|
||||||
fn usz? VTree.prune(&tree, isz ref)
|
|
||||||
{
|
|
||||||
if (!tree.ref_is_valid(ref)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tree.ref_is_present(ref)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
tree.vector[ref] = @zero();
|
|
||||||
tree.refs[ref] = -1;
|
|
||||||
tree.elements--;
|
|
||||||
|
|
||||||
usz count = 1;
|
|
||||||
for (usz i = 0; tree.elements > 0 && i < tree.size(); i++) {
|
|
||||||
if (tree.refs[i] == ref) {
|
|
||||||
count += tree.prune(i)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn usz VTree.nuke(&tree)
|
|
||||||
{
|
|
||||||
tree.vector[0..] = @zero();
|
|
||||||
tree.refs[0..] = -1;
|
|
||||||
usz x = tree.elements;
|
|
||||||
tree.elements = 0;
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the size of the subtree starting from ref
|
|
||||||
fn usz? VTree.subtree_size(&tree, isz ref)
|
|
||||||
{
|
|
||||||
if (!tree.ref_is_valid(ref)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tree.ref_is_present(ref)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
usz count = 1;
|
|
||||||
for (usz i = 0; i < tree.size(); i++) {
|
|
||||||
// only root has the reference to itself
|
|
||||||
if (tree.refs[i] == ref && ref != i) {
|
|
||||||
count += tree.subtree_size(i)!;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn bool? VTree.is_root(&tree, isz node) => node == tree.parentof(node)!;
|
|
||||||
|
|
||||||
// iterate through the first level children, use a cursor like strtok_r
|
|
||||||
fn isz? VTree.children_it(&tree, isz parent, isz *cursor)
|
|
||||||
{
|
|
||||||
if (cursor == null) {
|
|
||||||
return vtree::faults::INVALID_ARGUMENT?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the cursor is out of bounds then we are done for sure
|
|
||||||
if (!tree.ref_is_valid(*cursor)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// same for the parent, if it's invalid it can't have children
|
|
||||||
if (!tree.ref_is_valid(parent) || !tree.ref_is_present(parent)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the first child, update the cursor and return the ref
|
|
||||||
for (isz i = *cursor; i < tree.size(); i++) {
|
|
||||||
if (tree.refs[i] == parent) {
|
|
||||||
*cursor = i + 1;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if no children are found return -1
|
|
||||||
*cursor = -1;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* iterates trough every leaf of the subtree in the following manner
|
|
||||||
* node [x], x: visit order
|
|
||||||
* [0]
|
|
||||||
* / | \
|
|
||||||
* / [2] [3]
|
|
||||||
* [1] |
|
|
||||||
* / \ [6]
|
|
||||||
* [4] [5]
|
|
||||||
*/
|
|
||||||
fn isz? VTree.level_order_it(&tree, isz ref, isz *cursor)
|
|
||||||
{
|
|
||||||
if (cursor == null) {
|
|
||||||
return vtree::faults::INVALID_ARGUMENT?;
|
|
||||||
}
|
|
||||||
|
|
||||||
isz[] queue = tree.ordered_refs;
|
|
||||||
|
|
||||||
// TODO: this could also be done when adding or removing elements
|
|
||||||
// first call, create a ref array ordered like we desire
|
|
||||||
if (*cursor == -1) {
|
|
||||||
*cursor = 0;
|
|
||||||
queue[..] = -1;
|
|
||||||
|
|
||||||
// iterate through the queue appending found children
|
|
||||||
isz pos, off;
|
|
||||||
do {
|
|
||||||
// printf ("ref=%d\n", ref);
|
|
||||||
for (isz i = 0; i < tree.size(); i++) {
|
|
||||||
if (tree.refs[i] == ref) {
|
|
||||||
queue[pos++] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; ref == queue[off] && off < tree.size(); off++);
|
|
||||||
ref = queue[off];
|
|
||||||
|
|
||||||
} while (tree.ref_is_valid(ref));
|
|
||||||
// This line is why tree.ordered_refs has to be size+1
|
|
||||||
queue[off + 1] = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRINT_ARR(queue, tree.size());
|
|
||||||
// return -1;
|
|
||||||
|
|
||||||
// on successive calls just iterate through the queue until we find an
|
|
||||||
// invalid ref, if the user set the cursor to -1 it means it has found what
|
|
||||||
// he needed, so free
|
|
||||||
if (*cursor < 0) {
|
|
||||||
return -1;
|
|
||||||
} else if (tree.ref_is_valid(*cursor)) {
|
|
||||||
return queue[(*cursor)++];
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn isz? VTree.parentof(&tree, isz ref)
|
|
||||||
{
|
|
||||||
if (!tree.ref_is_valid(ref)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tree.ref_is_present(ref)) {
|
|
||||||
return vtree::faults::REFERENCE_NOT_PRESENT?;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tree.refs[ref];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ElemType? VTree.get(&tree, isz ref)
|
|
||||||
{
|
|
||||||
if (!tree.ref_is_valid(ref)) {
|
|
||||||
return vtree::faults::INVALID_REFERENCE?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tree.ref_is_present(ref)) {
|
|
||||||
return vtree::faults::REFERENCE_NOT_PRESENT?;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tree.vector[ref];
|
|
||||||
}
|
|
||||||
|
|
||||||
fn void VTree.print(&tree)
|
|
||||||
{
|
|
||||||
for (isz i = 0; i < tree.size(); i++) {
|
|
||||||
if (tree.refs[i] == -1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
io::printf("[%d] {parent=%d, data=", i, tree.refs[i]);
|
|
||||||
io::print(tree.vector[i]);
|
|
||||||
io::printn("}");
|
|
||||||
}
|
|
||||||
}
|
|
@ -156,7 +156,7 @@ fn Id? Ctx.div_end(&ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the active_div returns to the parent of the current one
|
// the active_div returns to the parent of the current one
|
||||||
ctx.active_div = ctx.tree.parentof(ctx.active_div);
|
ctx.active_div = ctx.tree.parentof(ctx.active_div)!;
|
||||||
Elem* parent = ctx.get_parent()!;
|
Elem* parent = ctx.get_parent()!;
|
||||||
ctx.div_scissor = parent.bounds.pad(parent.layout.content_offset);
|
ctx.div_scissor = parent.bounds.pad(parent.layout.content_offset);
|
||||||
ctx.reset_scissor(elem.z_index)!;
|
ctx.reset_scissor(elem.z_index)!;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import std::io;
|
import std::io;
|
||||||
import vtree;
|
|
||||||
import cache;
|
import cache;
|
||||||
import ugui;
|
import ugui;
|
||||||
import std::time;
|
import std::time;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user