Merge branch 'c3' of https://git.alemauri.eu/alema/ugui into c3
This commit is contained in:
commit
a00e39f36b
@ -9,10 +9,6 @@ module cache{Key, Value, SIZE};
|
||||
* the elements that were not recently used.
|
||||
*/
|
||||
|
||||
// FIXME: this module should really allocate all resources on an arena or temp
|
||||
// allocator, since all memory allocations are connected and freeing
|
||||
// happens at the same time
|
||||
|
||||
import std::core::mem;
|
||||
import std::core::mem::allocator;
|
||||
import std::collections::bitset;
|
||||
@ -79,6 +75,7 @@ fn Value*? Cache.search(&cache, Key id)
|
||||
}
|
||||
|
||||
/* HIT, set as recently used */
|
||||
//io::printfn("HIT: %d [%d]", entry.value, entry.key);
|
||||
cache.used[entry.value] = true;
|
||||
return &(cache.pool[entry.value]);
|
||||
}
|
||||
@ -99,16 +96,19 @@ fn void Cache.remove(&cache, Key id)
|
||||
/* If there is no free space left then just return the first position */
|
||||
fn usz Cache.get_free_spot(&cache) @private
|
||||
{
|
||||
// TODO: in the upgrade to c3 1.7.5 use @bitsof()
|
||||
const BITS = $typeof(cache.present.data[0]).sizeof*8;
|
||||
foreach (idx, d: cache.present.data) {
|
||||
if (d.clz() != BITS) {
|
||||
return idx*BITS + BITS-d.clz();
|
||||
if (d != $typeof(d).max) {
|
||||
usz spot = idx*BITS + BITS-d.clz();
|
||||
if (cache.used[spot]) unreachable("free spot is not actually free: %d", spot);
|
||||
return spot;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn Value*? Cache.insert_at(&cache, Value *g, Key id, usz index) @private
|
||||
fn Value*? Cache.insert_at(&cache, Value* g, Key id, usz index) @private
|
||||
{
|
||||
// TODO: verify index, g and id
|
||||
Value* spot;
|
||||
|
@ -97,9 +97,7 @@ macro Ctx.push_cmd(&ctx, Cmd *cmd, int z_index)
|
||||
default: return ctx.cmd_queue.enqueue(cmd);
|
||||
}
|
||||
if (cull_rect(rect, ctx.div_scissor)) {
|
||||
// io::print("NOPE: ");
|
||||
// io::print(cmd.rect.rect);
|
||||
// io::printn(cmd.z_index);
|
||||
// println("NOPE: ", cmd.rect.rect, cmd.z_index);
|
||||
// unreachable();
|
||||
return;
|
||||
}
|
||||
|
@ -165,10 +165,9 @@ macro Id @compute_id(...)
|
||||
// resets all flags except is_new which is set accordingly
|
||||
fn Elem*? Ctx.get_elem(&ctx, Id id, ElemType type)
|
||||
{
|
||||
Elem empty_elem;
|
||||
bool is_new;
|
||||
Elem* elem;
|
||||
elem = ctx.cache.get_or_insert(&empty_elem, id, &is_new)!;
|
||||
elem = ctx.cache.get_or_insert(&&(Elem){}, id, &is_new)!;
|
||||
elem.flags = (ElemFlags)0;
|
||||
elem.flags.is_new = is_new;
|
||||
elem.id = id;
|
||||
|
@ -55,27 +55,52 @@ macro Size Layout.total_height(&el)
|
||||
// Returns the width and height of a @FIT() element based on it's wanted size (min/max)
|
||||
// and the content size, this function is used to both update the parent's children size and
|
||||
// give the dimensions of a fit element
|
||||
// TODO: test and cleanup this function
|
||||
macro Point Layout.get_dimensions(&el)
|
||||
{
|
||||
Size content_width = el.children.w + el.text.width;
|
||||
Size width = el.w.combine(content_width);
|
||||
short final_width = width.greater();
|
||||
|
||||
short text_height;
|
||||
if (el.text.area != 0) {
|
||||
short text_width = (@exact(final_width) - el.children.w).combine(el.text.width).min;
|
||||
text_height = @exact((short)(el.text.area / text_width)).combine(el.text.height).min;
|
||||
// if the direction is ROW then the text is placed horizontally with the children
|
||||
if (el.dir == ROW) {
|
||||
Size content_width = el.children.w + el.text.width;
|
||||
Size width = el.w.combine(content_width);
|
||||
short final_width = width.greater();
|
||||
|
||||
short text_height;
|
||||
if (el.text.area != 0) {
|
||||
short text_width = (@exact(final_width) - el.children.w).combine(el.text.width).min;
|
||||
text_height = @exact((short)(el.text.area / text_width)).combine(el.text.height).min;
|
||||
}
|
||||
|
||||
Size content_height = el.children.h.comb_max(@exact(text_height));
|
||||
Size height = el.h.combine(content_height);
|
||||
short final_height = height.greater();
|
||||
|
||||
Point dim = {
|
||||
.x = final_width + el.content_offset.x + el.content_offset.w,
|
||||
.y = final_height + el.content_offset.y + el.content_offset.h,
|
||||
};
|
||||
return dim;
|
||||
} else {
|
||||
// if the direction is COLUMN the text and children are one on top of the other
|
||||
Size content_width = el.children.w.comb_max(el.text.width);
|
||||
Size width = el.w.combine(content_width);
|
||||
short final_width = width.greater();
|
||||
|
||||
short text_height;
|
||||
if (el.text.area != 0) {
|
||||
short text_width = @exact(final_width).combine(el.text.width).min;
|
||||
text_height = @exact((short)(el.text.area / text_width)).combine(el.text.height).min;
|
||||
}
|
||||
|
||||
Size content_height = el.children.h + @exact(text_height);
|
||||
Size height = el.h.combine(content_height);
|
||||
short final_height = height.greater();
|
||||
|
||||
Point dim = {
|
||||
.x = final_width + el.content_offset.x + el.content_offset.w,
|
||||
.y = final_height + el.content_offset.y + el.content_offset.h,
|
||||
};
|
||||
return dim;
|
||||
}
|
||||
|
||||
Size content_height = el.children.h + @exact(text_height);
|
||||
Size height = el.h.combine(content_height);
|
||||
short final_height = height.greater();
|
||||
|
||||
Point dim = {
|
||||
.x = final_width + el.content_offset.x + el.content_offset.w,
|
||||
.y = final_height + el.content_offset.y + el.content_offset.h,
|
||||
};
|
||||
return dim;
|
||||
}
|
||||
|
||||
// The content space of the element
|
||||
|
@ -30,10 +30,6 @@ struct SpriteAtlas {
|
||||
bool should_update;
|
||||
}
|
||||
|
||||
struct ElemSprite {
|
||||
Id id;
|
||||
}
|
||||
|
||||
// name: some examples are "icons" or "images"
|
||||
fn void? SpriteAtlas.init(&this, String name, AtlasType type, ushort width, ushort height)
|
||||
{
|
||||
@ -109,47 +105,3 @@ fn void? Ctx.import_sprite_file_qoi(&ctx, String name, String path, SpriteType t
|
||||
|
||||
ctx.sprite_atlas.insert(name, type, pixels, (ushort)desc.width, (ushort)desc.height, (ushort)desc.width)!;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
macro Ctx.sprite(&ctx, String name, Point off = {0,0}, ...)
|
||||
=> ctx.sprite_id(@compute_id($vasplat), name, off);
|
||||
fn void? Ctx.sprite_id(&ctx, Id id, String name, Point off)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
|
||||
Elem *parent = ctx.get_parent()!;
|
||||
Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!;
|
||||
|
||||
Style* style = ctx.styles.get_style(@str_hash("sprite"));
|
||||
Sprite* sprite = ctx.sprite_atlas.get(name)!;
|
||||
|
||||
Rect uv = { sprite.u, sprite.v, sprite.w, sprite.h };
|
||||
Rect bounds = { 0, 0, sprite.w, sprite.h };
|
||||
|
||||
elem.bounds = ctx.layout_element(parent, bounds.off(off), style);
|
||||
elem.sprite.id = ctx.get_sprite_atlas_id(name);
|
||||
|
||||
// if the bounds are null the element is outside the div view,
|
||||
// no interaction should occur so just return
|
||||
if (elem.bounds.is_null()) return;
|
||||
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
|
||||
return ctx.push_sprite(elem.bounds, uv, tex_id, parent.div.z_index)!;
|
||||
}
|
||||
|
||||
fn void? Ctx.draw_sprite_raw(&ctx, String name, Rect bounds, bool center = false)
|
||||
{
|
||||
Elem *parent = ctx.get_parent()!;
|
||||
Sprite* sprite = ctx.sprite_atlas.get(name)!;
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
|
||||
if (center) {
|
||||
Point off = {.x = (bounds.w - sprite.w) / 2, .y = (bounds.h - sprite.h) / 2};
|
||||
bounds = bounds.off(off);
|
||||
}
|
||||
|
||||
return ctx.push_sprite(bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
|
||||
}
|
||||
*/
|
@ -18,9 +18,6 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
|
||||
Style* style = ctx.styles.get_style(@str_hash("button"));
|
||||
|
||||
Sprite* sprite = icon != "" ? ctx.sprite_atlas.get(icon)! : &&(Sprite){};
|
||||
|
||||
// TODO: get min size by style
|
||||
TextSize text_size = ctx.measure_string(label)!;
|
||||
Rect icon_size = sprite.rect();
|
||||
|
||||
ushort min_size = style.size;
|
||||
@ -44,7 +41,7 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
|
||||
elem.layout.h = @fit(min_size);
|
||||
elem.layout.children.w = @exact(content_size.x);
|
||||
elem.layout.children.h = @exact(content_size.y);
|
||||
elem.layout.text = text_size;
|
||||
elem.layout.text = ctx.measure_string(label)!;
|
||||
elem.layout.content_offset = style.margin + style.border + style.padding;
|
||||
|
||||
update_parent_grow(elem, parent);
|
||||
@ -86,47 +83,82 @@ fn ElemEvents? Ctx.button_id(&ctx, Id id, String label, String icon)
|
||||
return elem.events;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
// FIXME: this should be inside the style
|
||||
macro Ctx.checkbox(&ctx, String desc, Point off, bool* active, String tick_sprite = {}, ...)
|
||||
=> ctx.checkbox_id(@compute_id($vasplat), desc, off, active, tick_sprite);
|
||||
fn void? Ctx.checkbox_id(&ctx, Id id, String description, Point off, bool* active, String tick_sprite)
|
||||
macro Ctx.checkbox(&ctx, String desc, bool* active, String tick_sprite = "", ...)
|
||||
=> ctx.checkbox_id(@compute_id($vasplat), desc, active, tick_sprite);
|
||||
fn void? Ctx.checkbox_id(&ctx, Id id, String description, bool* active, String tick_sprite)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
|
||||
Elem *parent = ctx.get_parent()!;
|
||||
Elem *elem = ctx.get_elem(id, ETYPE_BUTTON)!;
|
||||
Style* style = ctx.styles.get_style(@str_hash("checkbox"));
|
||||
|
||||
Rect size = {off.x, off.y, style.size, style.size};
|
||||
elem.bounds = ctx.layout_element(parent, size, style);
|
||||
short inner_pad = description != "" ? style.size/2 : 0;
|
||||
/*
|
||||
* |< >| style.size/2
|
||||
* +---------------------|---|-----------+
|
||||
* | | .-----. ---|--
|
||||
* | +-----------------+ ' ### ' | ^
|
||||
* | | description | | ##### | | style.size
|
||||
* | +-----------------+ . ### . | v
|
||||
* | '-----' ---|--
|
||||
* +-------------------------|-------|---+
|
||||
* |<----->| style.size
|
||||
*/
|
||||
|
||||
elem.layout.w = @fit(style.size);
|
||||
elem.layout.h = @fit(style.size);
|
||||
elem.layout.children.w = @exact(style.size + inner_pad);
|
||||
elem.layout.children.h = @exact(style.size);
|
||||
elem.layout.text = ctx.measure_string(description)!;
|
||||
elem.layout.content_offset = style.margin + style.border + style.padding;
|
||||
|
||||
// if the bounds are null the element is outside the div view,
|
||||
// no interaction should occur so just return
|
||||
if (elem.bounds.is_null()) return;
|
||||
update_parent_grow(elem, parent);
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
elem.events = ctx.get_elem_events(elem);
|
||||
if (elem.events.mouse_hover && elem.events.mouse_release) *active = !(*active);
|
||||
|
||||
|
||||
Rect content_bounds = elem.bounds.pad(elem.layout.content_offset);
|
||||
Rect text_bounds = {
|
||||
.x = content_bounds.x,
|
||||
.y = content_bounds.y,
|
||||
.w = content_bounds.w - inner_pad - style.size,
|
||||
.h = content_bounds.h
|
||||
};
|
||||
Rect check_bounds = {
|
||||
.x = content_bounds.x + text_bounds.w + inner_pad,
|
||||
.y = content_bounds.y + (content_bounds.h - style.size)/2,
|
||||
.w = style.size,
|
||||
.h = style.size,
|
||||
};
|
||||
|
||||
Style s;
|
||||
s.bg = style.bg;
|
||||
s.secondary = style.secondary;
|
||||
s.border = style.border;
|
||||
s.radius = style.radius;
|
||||
|
||||
if (tick_sprite != {}) {
|
||||
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
|
||||
ctx.layout_string(description, text_bounds, CENTER, parent.div.z_index, style.fg)!;
|
||||
if (tick_sprite != "") {
|
||||
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
|
||||
if (*active) {
|
||||
ctx.draw_sprite_raw(tick_sprite, elem.bounds, center: true)!;
|
||||
Sprite* sprite = ctx.sprite_atlas.get(tick_sprite)!;
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
ctx.push_sprite(sprite.rect().center_to(check_bounds), sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
|
||||
}
|
||||
} else {
|
||||
ctx.push_rect(elem.bounds, parent.div.z_index, style)!;
|
||||
if (*active) {
|
||||
ushort x = style.size / 4;
|
||||
Rect check = elem.bounds.add({x, x, -x*2, -x*2});
|
||||
Style s = *style;
|
||||
s.bg = s.primary;
|
||||
s.margin = s.border = s.padding = {};
|
||||
ctx.push_rect(check, parent.div.z_index, &s)!;
|
||||
s.bg = style.primary;
|
||||
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
|
||||
} else {
|
||||
ctx.push_rect(check_bounds, parent.div.z_index, &s)!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// FIXME: this should be inside the style
|
||||
macro Ctx.toggle(&ctx, String desc, Point off, bool* active)
|
||||
=> ctx.toggle_id(@compute_id($vasplat), desc, off, active);
|
||||
@ -156,5 +188,4 @@ fn void? Ctx.toggle_id(&ctx, Id id, String description, Point off, bool* active)
|
||||
s.bg = s.primary;
|
||||
s.margin = s.border = s.padding = {};
|
||||
ctx.push_rect(t, parent.div.z_index, &s)!;
|
||||
}
|
||||
*/
|
||||
}
|
@ -161,7 +161,7 @@ fn void? Ctx.div_end(&ctx)
|
||||
ctx.active_div = ctx.tree.parentof(ctx.active_div)!;
|
||||
Elem* parent = ctx.get_parent()!;
|
||||
ctx.div_scissor = parent.bounds;
|
||||
ctx.push_scissor(parent.bounds, elem.div.z_index)!;
|
||||
ctx.reset_scissor(elem.div.z_index)!;
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
}
|
27
lib/ugui.c3l/src/widgets/ugui_sprite.c3
Normal file
27
lib/ugui.c3l/src/widgets/ugui_sprite.c3
Normal file
@ -0,0 +1,27 @@
|
||||
module ugui;
|
||||
|
||||
struct ElemSprite {
|
||||
Id id;
|
||||
}
|
||||
|
||||
macro Ctx.sprite(&ctx, String name, ...)
|
||||
=> ctx.sprite_id(@compute_id($vasplat), name);
|
||||
fn void? Ctx.sprite_id(&ctx, Id id, String name)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
Elem *parent = ctx.get_parent()!;
|
||||
Elem *elem = ctx.get_elem(id, ETYPE_SPRITE)!;
|
||||
|
||||
Style* style = ctx.styles.get_style(@str_hash("sprite"));
|
||||
Sprite* sprite = ctx.sprite_atlas.get(name)!;
|
||||
elem.sprite.id = ctx.get_sprite_atlas_id(name);
|
||||
|
||||
elem.layout.w = elem.layout.children.w = @exact(sprite.w);
|
||||
elem.layout.h = elem.layout.children.h = @exact(sprite.h);
|
||||
|
||||
update_parent_grow(elem, parent);
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
Id tex_id = ctx.sprite_atlas.id;
|
||||
return ctx.push_sprite(elem.bounds, sprite.uv(), tex_id, parent.div.z_index, type: sprite.type)!;
|
||||
}
|
@ -28,7 +28,7 @@ checkbox {
|
||||
border: 2;
|
||||
padding: 1;
|
||||
radius: 10;
|
||||
size: 16;
|
||||
size: 20;
|
||||
bg: #3c3836ff;
|
||||
fg: #fbf1c7ff;
|
||||
primary: #cc241dff;
|
||||
|
13
src/main.c3
13
src/main.c3
@ -360,7 +360,7 @@ fn void calculator(ugui::Ctx* ui)
|
||||
case "c":
|
||||
len = 0;
|
||||
case "d":
|
||||
len--;
|
||||
if (len > 0) len--;
|
||||
}
|
||||
|
||||
// ui input/output
|
||||
@ -389,9 +389,7 @@ fn void calculator(ugui::Ctx* ui)
|
||||
ui.button("3")!!.mouse_press ? buffer[len++] = '3' : 0;
|
||||
ui.button("(")!!.mouse_press ? buffer[len++] = '(' : 0;
|
||||
}!!;
|
||||
|
||||
ui.@div(ugui::@exact(10), ugui::@exact(10)) {}!!;
|
||||
|
||||
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
|
||||
ui.button("x")!!.mouse_press ? buffer[len++] = '*' : 0;
|
||||
ui.button("/")!!.mouse_press ? buffer[len++] = '/' : 0;
|
||||
@ -400,7 +398,7 @@ fn void calculator(ugui::Ctx* ui)
|
||||
}!!;
|
||||
ui.@div(ugui::@fit(), ugui::@fit(), COLUMN) {
|
||||
ui.button("C")!!.mouse_press ? len = 0 : 0;
|
||||
ui.button("D")!!.mouse_press ? len-- : 0;
|
||||
ui.button("D")!!.mouse_press ? len > 0 ? len-- : 0 : 0;
|
||||
ui.button("-")!!.mouse_press ? buffer[len++] = '-' : 0;
|
||||
|
||||
// eval the expression with 'bc'
|
||||
@ -413,5 +411,12 @@ fn void calculator(ugui::Ctx* ui)
|
||||
}
|
||||
}!!;
|
||||
}!!;
|
||||
|
||||
ui.@div(ugui::@grow(), ugui::@grow(), anchor: CENTER) {
|
||||
static bool state;
|
||||
ui.checkbox("boolean", &state, "tick")!!;
|
||||
ui.sprite("tux")!!;
|
||||
}!!;
|
||||
|
||||
}!!; }!!;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user