idk some stuff
This commit is contained in:
parent
c1a7b4fcdb
commit
c0e9565bf6
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
*.a
|
||||
build/*
|
||||
**/.ccls-cache
|
||||
perf.data*
|
||||
|
1
TODO
1
TODO
@ -9,6 +9,7 @@
|
||||
[ ] Do not redraw if there was no update (no layout and no draw)
|
||||
[ ] Better handling of the active and focused widgets, try
|
||||
to maintain focus until mouse release (fix scroll bars)
|
||||
[ ] Clip element bounds to parent div, specifically text
|
||||
|
||||
## Commands
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
//"RAYGUI_CUSTOM_ICONS",
|
||||
],
|
||||
// Authors, optionally with email.
|
||||
"authors": [ "John Doe <ale@shitposting.expert>" ],
|
||||
"authors": [ "Alessandro Mauri <ale@shitposting.expert>" ],
|
||||
// Version using semantic versioning.
|
||||
"version": "0.1.0",
|
||||
// Sources compiled for all targets.
|
||||
|
BIN
resources/hack-nerd.ttf
Normal file
BIN
resources/hack-nerd.ttf
Normal file
Binary file not shown.
30
src/main.c3
30
src/main.c3
@ -70,7 +70,7 @@ fn int main(String[] args)
|
||||
{
|
||||
ugui::Ctx ui;
|
||||
ui.init()!!;
|
||||
ui.load_font("font1", "/usr/share/fonts/TTF/HackNerdFontMono-Regular.ttf", 16)!!;
|
||||
ui.load_font("font1", "resources/hack-nerd.ttf", 16)!!;
|
||||
|
||||
short width = 800;
|
||||
short height = 450;
|
||||
@ -123,7 +123,7 @@ fn int main(String[] args)
|
||||
{|
|
||||
|
||||
ui.layout_set_row()!!;
|
||||
if (ui.button("button0", ugui::Rect{0,0,30,30})!!.mouse_press) {
|
||||
if (ui.button("button0", ugui::Rect{0,0,30,30}, toggle)!!.mouse_press) {
|
||||
io::printn("press button0");
|
||||
toggle = !toggle;
|
||||
ui.force_update()!!;
|
||||
@ -147,9 +147,7 @@ fn int main(String[] args)
|
||||
|};
|
||||
ui.div_end()!!;
|
||||
|
||||
ui.div_begin("second", ugui::DIV_FILL)!!;
|
||||
ugui::Elem* de = ui.get_elem_by_label("second")!!;
|
||||
de.div.scroll.can_y = true;
|
||||
ui.div_begin("second", ugui::DIV_FILL, scroll_y: true)!!;
|
||||
{|
|
||||
ui.layout_set_column()!!;
|
||||
if (ui.slider_ver("slider_other", ugui::Rect{0,0,30,100})!!.update) {
|
||||
@ -160,10 +158,12 @@ fn int main(String[] args)
|
||||
ui.button("button11", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button12", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button13", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button14", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button15", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button16", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button17", ugui::Rect{0,0,50,50})!!;
|
||||
if (toggle) {
|
||||
ui.button("button14", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button15", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button16", ugui::Rect{0,0,50,50})!!;
|
||||
ui.button("button17", ugui::Rect{0,0,50,50})!!;
|
||||
}
|
||||
|};
|
||||
ui.div_end()!!;
|
||||
|
||||
@ -172,13 +172,13 @@ fn int main(String[] args)
|
||||
TimeStats uts = ui_times.get_stats();
|
||||
|
||||
ui.layout_set_floating()!!;
|
||||
ui.div_begin("fps", ugui::Rect{0, ui.height-50, 200, 50})!!;
|
||||
ui.div_begin("fps", ugui::Rect{0, ui.height-60, 200, 60})!!;
|
||||
{|
|
||||
ui.layout_set_row()!!;
|
||||
ui.text_unbounded("ui avg", string::tformat("ui avg: %s", uts.avg))!!;
|
||||
ui.text_unbounded("ui avg", string::tformat("ui avg: %s\ndraw avg: %s\nTOT: %s", uts.avg, dts.avg, uts.avg+dts.avg))!!;
|
||||
|
||||
ui.layout_next_row()!!;
|
||||
ui.text_unbounded("draw avg", string::tformat("draw avg: %s", dts.avg))!!;
|
||||
//ui.layout_next_row()!!;
|
||||
//ui.text_unbounded("draw avg", string::tformat("draw avg: %s", dts.avg))!!;
|
||||
|
||||
//ui.force_update()!!;
|
||||
|};
|
||||
@ -187,7 +187,7 @@ fn int main(String[] args)
|
||||
ui.frame_end()!!;
|
||||
/* End UI Handling */
|
||||
ui_times.push(clock.mark());
|
||||
ui_times.print_stats();
|
||||
//ui_times.print_stats();
|
||||
|
||||
/* Start UI Drawing */
|
||||
rl::begin_drawing();
|
||||
@ -253,7 +253,7 @@ fn int main(String[] args)
|
||||
}
|
||||
}
|
||||
draw_times.push(clock.mark());
|
||||
draw_times.print_stats();
|
||||
//draw_times.print_stats();
|
||||
rl::end_drawing();
|
||||
/* End Drawing */
|
||||
|
||||
|
@ -2,8 +2,21 @@ module ugui;
|
||||
|
||||
import std::io;
|
||||
|
||||
// button element
|
||||
struct ElemButton {
|
||||
Color color;
|
||||
bool active;
|
||||
}
|
||||
|
||||
const Elem BUTTON_DEFAULTS = {
|
||||
.type = ETYPE_BUTTON,
|
||||
.button = {
|
||||
.color = uint_to_rgba(0x0000ffff),
|
||||
},
|
||||
};
|
||||
|
||||
// draw a button, return the events on that button
|
||||
fn ElemEvents! Ctx.button(&ctx, String label, Rect size)
|
||||
fn ElemEvents! Ctx.button(&ctx, String label, Rect size, bool state = false)
|
||||
{
|
||||
Id id = label.hash();
|
||||
|
||||
@ -12,29 +25,39 @@ fn ElemEvents! Ctx.button(&ctx, String label, Rect size)
|
||||
// add it to the tree
|
||||
ctx.tree.add(id, ctx.active_div)!;
|
||||
|
||||
// 1. Fill the element fields
|
||||
// this resets the flags
|
||||
c_elem.type = ETYPE_BUTTON;
|
||||
Color bg_color = uint_to_rgba(0x0000ffff);
|
||||
bool needs_layout = c_elem.flags.is_new || parent.flags.updated;
|
||||
|
||||
// if the element is new or the parent was updated then redo layout
|
||||
if (c_elem.flags.is_new || parent.flags.updated) {
|
||||
// 2. Layout
|
||||
c_elem.bounds = ctx.position_element(parent, size, true);
|
||||
|
||||
// TODO: 3. Fill the button specific fields
|
||||
if (c_elem.flags.is_new) {
|
||||
*c_elem = BUTTON_DEFAULTS;
|
||||
} else if (c_elem.type != ETYPE_BUTTON) {
|
||||
return UgError.WRONG_ELEMENT_TYPE?;
|
||||
}
|
||||
|
||||
// if the element is new or the parent was updated then redo layout
|
||||
if (needs_layout) {
|
||||
c_elem.bounds = ctx.position_element(parent, size, true);
|
||||
}
|
||||
|
||||
// if the bounds are null the element is outside the div view,
|
||||
// no interaction should occur so just return
|
||||
if (c_elem.bounds.is_null()) { return ElemEvents{}; }
|
||||
|
||||
c_elem.events = ctx.get_elem_events(c_elem);
|
||||
if (parent.flags.has_focus) {
|
||||
if (c_elem.events.mouse_hover) {
|
||||
if (c_elem.events.mouse_hover) {
|
||||
if (parent.flags.has_focus) {
|
||||
c_elem.flags.has_focus = true;
|
||||
bg_color = uint_to_rgba(0x00ff00ff);
|
||||
c_elem.button.color = uint_to_rgba(0x00ff00ff);
|
||||
}
|
||||
} else {
|
||||
c_elem.button.color = uint_to_rgba(0x0000ffff);
|
||||
}
|
||||
|
||||
if (state) {
|
||||
c_elem.button.color = uint_to_rgba(0xff00ffff);
|
||||
}
|
||||
|
||||
// Draw the button
|
||||
ctx.push_rect(c_elem.bounds, bg_color, do_border: true, do_radius: true)!;
|
||||
ctx.push_rect(c_elem.bounds, c_elem.button.color, do_border: true, do_radius: true)!;
|
||||
|
||||
return c_elem.events;
|
||||
}
|
||||
|
@ -135,7 +135,8 @@ fn void! Ctx.push_string(&ctx, Rect bounds, String text)
|
||||
.w = gp.w,
|
||||
.h = gp.h,
|
||||
};
|
||||
if (rect_collision(gb, bounds)) {
|
||||
// push the sprite only if it collides with the bounds
|
||||
if (gb.collides(bounds)) {
|
||||
ctx.push_sprite(gb, gt, texture_id)!;
|
||||
}
|
||||
line_len += gp.adv;
|
||||
@ -173,4 +174,4 @@ fn void! Ctx.push_scissor(&ctx, Rect rect)
|
||||
.scissor.rect = rect,
|
||||
};
|
||||
ctx.cmd_queue.enqueue(&sc)!;
|
||||
}
|
||||
}
|
||||
|
@ -47,28 +47,6 @@ bitstruct ElemEvents : uint {
|
||||
bool update : 7;
|
||||
}
|
||||
|
||||
enum DivLayout {
|
||||
LAYOUT_ROW,
|
||||
LAYOUT_COLUMN,
|
||||
LAYOUT_FLOATING,
|
||||
}
|
||||
|
||||
// div element
|
||||
struct ElemDiv {
|
||||
DivLayout layout;
|
||||
struct scroll {
|
||||
bool can_x;
|
||||
bool can_y;
|
||||
bool on_x;
|
||||
bool on_y;
|
||||
float value_x;
|
||||
float value_y;
|
||||
}
|
||||
Rect children_bounds;
|
||||
Point origin_r, origin_c;
|
||||
Color color_bg;
|
||||
}
|
||||
|
||||
// slider element
|
||||
struct ElemSlider {
|
||||
float value;
|
||||
@ -88,6 +66,7 @@ struct Elem {
|
||||
ElemType type;
|
||||
union {
|
||||
ElemDiv div;
|
||||
ElemButton button;
|
||||
ElemSlider slider;
|
||||
ElemText text;
|
||||
}
|
||||
@ -107,14 +86,15 @@ fault UgError {
|
||||
INVALID_SIZE,
|
||||
EVENT_UNSUPPORTED,
|
||||
UNEXPECTED_ELEMENT,
|
||||
WRONG_ELEMENT_TYPE,
|
||||
}
|
||||
|
||||
macro uint_to_rgba(uint u) {
|
||||
macro Color uint_to_rgba(uint $u) {
|
||||
return Color{
|
||||
.r = (char)((u >> 24) & 0xff),
|
||||
.g = (char)((u >> 16) & 0xff),
|
||||
.b = (char)((u >> 8) & 0xff),
|
||||
.a = (char)((u >> 0) & 0xff)
|
||||
.r = (char)(($u >> 24) & 0xff),
|
||||
.g = (char)(($u >> 16) & 0xff),
|
||||
.b = (char)(($u >> 8) & 0xff),
|
||||
.a = (char)(($u >> 0) & 0xff)
|
||||
};
|
||||
}
|
||||
|
||||
@ -179,12 +159,12 @@ macro point_in_rect(Point p, Rect r)
|
||||
}
|
||||
|
||||
// return true if rect a contains b
|
||||
macro rect_contains(Rect a, Rect b)
|
||||
macro bool Rect.contains(Rect a, Rect b)
|
||||
{
|
||||
return (a.x <= b.x && a.y <= b.y && a.x+a.w >= b.x+b.w && a.y+a.h >= b.y+b.h);
|
||||
}
|
||||
|
||||
macro rect_intersection(Rect a, Rect b)
|
||||
macro Rect Rect.intersection(Rect a, Rect b)
|
||||
{
|
||||
return Rect{
|
||||
.x = (short)max(a.x, b.x),
|
||||
@ -195,7 +175,9 @@ macro rect_intersection(Rect a, Rect b)
|
||||
}
|
||||
|
||||
// rect intersection not null
|
||||
macro rect_collision(Rect a, Rect b)
|
||||
macro bool Rect.collides(Rect a, Rect b)
|
||||
{
|
||||
return !(a.x > b.x+b.w || a.x+a.w < b.x || a.y > b.y+b.h || a.y+a.h < b.y);
|
||||
}
|
||||
|
||||
macro bool Rect.is_null(r) => r.x == 0 && r.y == 0 && r.x == 0 && r.w == 0;
|
||||
|
@ -2,7 +2,39 @@ module ugui;
|
||||
|
||||
import std::io;
|
||||
|
||||
fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
||||
enum DivLayout {
|
||||
LAYOUT_ROW,
|
||||
LAYOUT_COLUMN,
|
||||
LAYOUT_FLOATING,
|
||||
}
|
||||
|
||||
// div element
|
||||
struct ElemDiv {
|
||||
DivLayout layout;
|
||||
struct scroll {
|
||||
bool can_x;
|
||||
bool can_y;
|
||||
bool on_x;
|
||||
bool on_y;
|
||||
float value_x;
|
||||
float value_y;
|
||||
}
|
||||
Rect children_bounds;
|
||||
Point origin_r, origin_c;
|
||||
Color bgcolor;
|
||||
}
|
||||
|
||||
const Elem DIV_DEFAULTS = {
|
||||
.type = ETYPE_DIV,
|
||||
.div = {
|
||||
.scroll.can_x = false,
|
||||
.scroll.can_y = false,
|
||||
.scroll.value_x = 0,
|
||||
.scroll.value_y = 0,
|
||||
},
|
||||
};
|
||||
|
||||
fn void! Ctx.div_begin(&ctx, String label, Rect size, bool scroll_x = false, bool scroll_y = false)
|
||||
{
|
||||
Id id = label.hash();
|
||||
|
||||
@ -11,21 +43,22 @@ fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
||||
isz div_node = ctx.tree.add(id, ctx.active_div)!;
|
||||
ctx.active_div = div_node;
|
||||
|
||||
// 1. Fill the element fields
|
||||
c_elem.type = ETYPE_DIV;
|
||||
bool needs_layout = c_elem.flags.is_new || parent.flags.updated;
|
||||
|
||||
if (c_elem.flags.is_new) {
|
||||
*c_elem = DIV_DEFAULTS;
|
||||
} else if (c_elem.type != ETYPE_DIV) {
|
||||
return UgError.WRONG_ELEMENT_TYPE?;
|
||||
}
|
||||
c_elem.div.scroll.can_x = scroll_x;
|
||||
c_elem.div.scroll.can_y = scroll_y;
|
||||
|
||||
// do layout and update flags only if the element was updated
|
||||
if (c_elem.flags.is_new || parent.flags.updated) {
|
||||
if (needs_layout) {
|
||||
// 2. layout the element
|
||||
c_elem.bounds = ctx.position_element(parent, size);
|
||||
if (c_elem.flags.is_new) {
|
||||
c_elem.div.children_bounds = c_elem.bounds;
|
||||
c_elem.div.color_bg = ctx.style.bgcolor;
|
||||
c_elem.div.scroll.can_x = false;
|
||||
c_elem.div.scroll.can_y = false;
|
||||
c_elem.div.scroll.value_x = 0;
|
||||
c_elem.div.scroll.value_y = 0;
|
||||
}
|
||||
c_elem.div.children_bounds = c_elem.bounds;
|
||||
c_elem.div.bgcolor = ctx.style.bgcolor;
|
||||
|
||||
// 3. Mark the element as updated
|
||||
c_elem.flags.updated = true;
|
||||
@ -39,14 +72,14 @@ fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
||||
}
|
||||
|
||||
// Add the background to the draw stack
|
||||
bool do_border = parent.div.layout == LAYOUT_FLOATING;
|
||||
ctx.push_rect(c_elem.bounds, c_elem.div.color_bg, do_border: do_border)!;
|
||||
bool do_border = parent.div.layout == LAYOUT_FLOATING;
|
||||
ctx.push_rect(c_elem.bounds, c_elem.div.bgcolor, do_border: do_border)!;
|
||||
|
||||
// TODO: check active
|
||||
// TODO: check resizeable
|
||||
|
||||
// check and draw scroll bars
|
||||
if (!rect_contains(c_elem.bounds, c_elem.div.children_bounds)) {
|
||||
if (!c_elem.bounds.contains(c_elem.div.children_bounds)) {
|
||||
Point cbc = {
|
||||
.x = c_elem.div.children_bounds.x + c_elem.div.children_bounds.w,
|
||||
.y = c_elem.div.children_bounds.y + c_elem.div.children_bounds.h,
|
||||
|
@ -124,7 +124,7 @@ fn void! Ctx.frame_end(&ctx)
|
||||
root.div.layout = LAYOUT_ROW;
|
||||
|
||||
// 1. clear the tree
|
||||
ctx.tree.prune(0)!;
|
||||
ctx.tree.nuke();
|
||||
|
||||
// 2. clear input fields
|
||||
bool f = ctx.input.events.force_update;
|
||||
|
@ -163,7 +163,7 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
|
||||
}
|
||||
|
||||
// 6. check if the placement is inside the view
|
||||
if (rect_collision(placement, view)) {
|
||||
if (placement.collides(view)) {
|
||||
return Rect{
|
||||
.x = placement.x - off.x,
|
||||
.y = placement.y - off.y,
|
||||
|
11
src/vtree.c3
11
src/vtree.c3
@ -27,7 +27,7 @@ macro @zero()
|
||||
$if $assignable(0, ElemType):
|
||||
return 0;
|
||||
$else
|
||||
return ElemType{0};
|
||||
return ElemType{};
|
||||
$endif
|
||||
}
|
||||
|
||||
@ -186,6 +186,15 @@ fn usz! VTree.prune(&tree, isz ref)
|
||||
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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user