semi-working vertical slider
This commit is contained in:
parent
763e9ba8d6
commit
73bc933eb5
74
src/main.c3
74
src/main.c3
@ -6,14 +6,15 @@ import rl;
|
|||||||
|
|
||||||
fn int main(String[] args)
|
fn int main(String[] args)
|
||||||
{
|
{
|
||||||
ugui::Ctx ctx;
|
ugui::Ctx ui;
|
||||||
ctx.init()!!;
|
ui.init()!!;
|
||||||
|
|
||||||
short width = 800;
|
short width = 800;
|
||||||
short height = 450;
|
short height = 450;
|
||||||
rl::set_config_flags(rl::FLAG_WINDOW_RESIZABLE);
|
rl::set_config_flags(rl::FLAG_WINDOW_RESIZABLE);
|
||||||
rl::init_window(width, height, "Ugui Test");
|
rl::init_window(width, height, "Ugui Test");
|
||||||
ctx.input_window_size(width, height)!!;
|
ui.input_window_size(width, height)!!;
|
||||||
|
rl::set_target_fps(30);
|
||||||
|
|
||||||
isz frame;
|
isz frame;
|
||||||
|
|
||||||
@ -27,61 +28,68 @@ fn int main(String[] args)
|
|||||||
if (rl::is_window_resized()) {
|
if (rl::is_window_resized()) {
|
||||||
width = (short)rl::get_screen_width();
|
width = (short)rl::get_screen_width();
|
||||||
height = (short)rl::get_screen_height();
|
height = (short)rl::get_screen_height();
|
||||||
ctx.input_window_size(width, height)!!;
|
ui.input_window_size(width, height)!!;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.input_changefocus(rl::is_window_focused());
|
ui.input_changefocus(rl::is_window_focused());
|
||||||
|
|
||||||
// FIXME: In raylib it doesn't seem to be a quick way to check if
|
rl::Vector2 mpos = rl::get_mouse_position();
|
||||||
// a mouse input event was received, so for now just use
|
ui.input_mouse_abs((short)mpos.x, (short)mpos.y);
|
||||||
// the delta information
|
|
||||||
rl::Vector2 mousedelta = rl::get_mouse_delta();
|
|
||||||
if (mousedelta.x || mousedelta.y) {
|
|
||||||
ctx.input_mouse_delta((short)mousedelta.x, (short)mousedelta.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
ugui::MouseButtons buttons;
|
ugui::MouseButtons buttons;
|
||||||
buttons.btn_left = rl::is_mouse_button_down(rl::MOUSE_BUTTON_LEFT);
|
buttons.btn_left = rl::is_mouse_button_down(rl::MOUSE_BUTTON_LEFT);
|
||||||
buttons.btn_right = rl::is_mouse_button_down(rl::MOUSE_BUTTON_RIGHT);
|
buttons.btn_right = rl::is_mouse_button_down(rl::MOUSE_BUTTON_RIGHT);
|
||||||
buttons.btn_middle = rl::is_mouse_button_down(rl::MOUSE_BUTTON_MIDDLE);
|
buttons.btn_middle = rl::is_mouse_button_down(rl::MOUSE_BUTTON_MIDDLE);
|
||||||
ctx.input_mouse_button(buttons);
|
ui.input_mouse_button(buttons);
|
||||||
/* End Input Handling */
|
/* End Input Handling */
|
||||||
|
|
||||||
/* Start UI Handling */
|
/* Start UI Handling */
|
||||||
ctx.frame_begin()!!;
|
ui.frame_begin()!!;
|
||||||
|
|
||||||
|
/*
|
||||||
// main div, fill the whole window
|
// main div, fill the whole window
|
||||||
ctx.div_begin("main", ugui::Rect{.w=ctx.width/2})!!;
|
ui.div_begin("main", ugui::Rect{.w=ui.width/2})!!;
|
||||||
{|
|
{|
|
||||||
ctx.layout_set_row()!!;
|
ui.layout_set_row()!!;
|
||||||
if (ctx.button("button0", ugui::Rect{0,0,30,30})!!.mouse_press) {
|
if (ui.button("button0", ugui::Rect{0,0,30,30})!!.mouse_press) {
|
||||||
io::printn("press button0");
|
io::printn("press button0");
|
||||||
}
|
}
|
||||||
//ctx.layout_next_column()!!;
|
//ui.layout_next_column()!!;
|
||||||
if (ctx.button("button1", ugui::Rect{0,0,30,30})!!.mouse_press) {
|
if (ui.button("button1", ugui::Rect{0,0,30,30})!!.mouse_press) {
|
||||||
io::printn("press button1");
|
io::printn("press button1");
|
||||||
}
|
}
|
||||||
//ctx.layout_next_column()!!;
|
//ui.layout_next_column()!!;
|
||||||
if (ctx.button("button2", ugui::Rect{0,0,30,30})!!.mouse_release) {
|
if (ui.button("button2", ugui::Rect{0,0,30,30})!!.mouse_release) {
|
||||||
io::printn("release button2");
|
io::printn("release button2");
|
||||||
}
|
}
|
||||||
if (ctx.slider_ver("slider", ugui::Rect{0,0,30,100})!!.update) {
|
if (ui.slider_ver("slider", ugui::Rect{0,0,30,100})!!.update) {
|
||||||
ugui::Elem* e = ctx.get_elem_by_label("slider")!!;
|
ugui::Elem* e = ui.get_elem_by_label("slider")!!;
|
||||||
io::printfn("slider: %f", e.slider.value);
|
io::printfn("slider: %f", e.slider.value);
|
||||||
}
|
}
|
||||||
|};
|
|};
|
||||||
ctx.div_end()!!;
|
ui.div_end()!!;
|
||||||
|
*/
|
||||||
ctx.div_begin("second", ugui::DIV_FILL)!!;
|
ui.div_begin("second", ugui::DIV_FILL)!!;
|
||||||
|
ugui::Elem* de = ui.get_elem_by_label("second")!!;
|
||||||
|
de.div.scroll.can_y = true;
|
||||||
{|
|
{|
|
||||||
if (ctx.slider_ver("slider_other", ugui::Rect{0,0,30,100})!!.update) {
|
ui.layout_set_column()!!;
|
||||||
ugui::Elem* e = ctx.get_elem_by_label("slider_other")!!;
|
if (ui.slider_ver("slider_other", ugui::Rect{0,0,30,100})!!.update) {
|
||||||
|
ugui::Elem* e = ui.get_elem_by_label("slider_other")!!;
|
||||||
io::printfn("other slider: %f", e.slider.value);
|
io::printfn("other slider: %f", e.slider.value);
|
||||||
}
|
}
|
||||||
|
ui.button("button10", ugui::Rect{0,0,50,50})!!;
|
||||||
|
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})!!;
|
||||||
|};
|
|};
|
||||||
ctx.div_end()!!;
|
ui.div_end()!!;
|
||||||
|
|
||||||
ctx.frame_end()!!;
|
ui.frame_end()!!;
|
||||||
/* End UI Handling */
|
/* End UI Handling */
|
||||||
|
|
||||||
/* Start UI Drawing */
|
/* Start UI Drawing */
|
||||||
@ -89,7 +97,7 @@ fn int main(String[] args)
|
|||||||
// ClearBackground(BLACK);
|
// ClearBackground(BLACK);
|
||||||
|
|
||||||
rl::Color c;
|
rl::Color c;
|
||||||
for (Cmd* cmd; (cmd = ctx.cmd_queue.dequeue() ?? null) != null;) {
|
for (Cmd* cmd; (cmd = ui.cmd_queue.dequeue() ?? null) != null;) {
|
||||||
switch (cmd.type) {
|
switch (cmd.type) {
|
||||||
case ugui::CmdType.CMD_RECT:
|
case ugui::CmdType.CMD_RECT:
|
||||||
c = rl::Color{
|
c = rl::Color{
|
||||||
@ -111,13 +119,11 @@ fn int main(String[] args)
|
|||||||
}
|
}
|
||||||
|
|
||||||
rl::end_drawing();
|
rl::end_drawing();
|
||||||
|
|
||||||
// TODO: throttle FPS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rl::close_window();
|
rl::close_window();
|
||||||
|
|
||||||
ctx.free();
|
ui.free();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
module ugui;
|
module ugui;
|
||||||
|
|
||||||
|
import std::io;
|
||||||
|
|
||||||
// draw a button, return the events on that button
|
// 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)
|
||||||
{
|
{
|
||||||
|
@ -1,9 +1,13 @@
|
|||||||
module ugui;
|
module ugui;
|
||||||
|
|
||||||
|
import std::io;
|
||||||
|
import std::core::string;
|
||||||
|
|
||||||
import vtree;
|
import vtree;
|
||||||
import cache;
|
import cache;
|
||||||
import fifo;
|
import fifo;
|
||||||
|
|
||||||
|
|
||||||
struct Rect {
|
struct Rect {
|
||||||
short x, y, w, h;
|
short x, y, w, h;
|
||||||
}
|
}
|
||||||
@ -52,10 +56,14 @@ enum DivLayout {
|
|||||||
// div element
|
// div element
|
||||||
struct Div {
|
struct Div {
|
||||||
DivLayout layout;
|
DivLayout layout;
|
||||||
bool can_scroll_x;
|
struct scroll {
|
||||||
bool can_scroll_y;
|
bool can_x;
|
||||||
isz vertical_scroll_bar;
|
bool can_y;
|
||||||
isz horizontal_scroll_bar;
|
bool on_x;
|
||||||
|
bool on_y;
|
||||||
|
float value_x;
|
||||||
|
float value_y;
|
||||||
|
}
|
||||||
Rect children_bounds;
|
Rect children_bounds;
|
||||||
Point origin_r, origin_c;
|
Point origin_r, origin_c;
|
||||||
Color color_bg;
|
Color color_bg;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module ugui;
|
module ugui;
|
||||||
|
|
||||||
|
import std::io;
|
||||||
|
|
||||||
fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
||||||
{
|
{
|
||||||
@ -29,12 +30,12 @@ fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
|||||||
.x = c_elem.bounds.x,
|
.x = c_elem.bounds.x,
|
||||||
.y = c_elem.bounds.y,
|
.y = c_elem.bounds.y,
|
||||||
};
|
};
|
||||||
c_elem.div.color_bg = uint_to_rgba(0xff0000ff);
|
|
||||||
c_elem.div.origin_r = c_elem.div.origin_c;
|
c_elem.div.origin_r = c_elem.div.origin_c;
|
||||||
c_elem.div.can_scroll_x = false;
|
c_elem.div.color_bg = uint_to_rgba(0xff0000ff);
|
||||||
c_elem.div.can_scroll_y = false;
|
c_elem.div.scroll.can_x = false;
|
||||||
c_elem.div.vertical_scroll_bar = -1;
|
c_elem.div.scroll.can_y = false;
|
||||||
c_elem.div.horizontal_scroll_bar = -1;
|
c_elem.div.scroll.value_x = 0;
|
||||||
|
c_elem.div.scroll.value_y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the background to the draw stack
|
// Add the background to the draw stack
|
||||||
@ -50,7 +51,66 @@ fn void! Ctx.div_begin(&ctx, String label, Rect size)
|
|||||||
// TODO: check active
|
// TODO: check active
|
||||||
// TODO: check resizeable
|
// TODO: check resizeable
|
||||||
|
|
||||||
// TODO: check scrollbars
|
// check and draw scroll bars
|
||||||
|
if (!rect_contains(c_elem.bounds, 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,
|
||||||
|
};
|
||||||
|
Point bc = {
|
||||||
|
.x = c_elem.bounds.x + c_elem.bounds.w,
|
||||||
|
.y = c_elem.bounds.y + c_elem.bounds.h,
|
||||||
|
};
|
||||||
|
// vertical overflow, check and draw scroll bar
|
||||||
|
if (cbc.y > bc.y && c_elem.div.scroll.can_y) {
|
||||||
|
// set the scrollbar flag, is used in layout
|
||||||
|
c_elem.div.scroll.on_y = true;
|
||||||
|
|
||||||
|
Rect vslider = {
|
||||||
|
.x = c_elem.bounds.x + c_elem.bounds.w - 10,
|
||||||
|
.y = c_elem.bounds.y,
|
||||||
|
.w = 10,
|
||||||
|
.h = c_elem.bounds.h,
|
||||||
|
};
|
||||||
|
|
||||||
|
float vh = max((float)bc.y / cbc.y, (float)0.15);
|
||||||
|
Rect vhandle = {
|
||||||
|
.x = c_elem.bounds.x + c_elem.bounds.w - 10,
|
||||||
|
.y = (short)(c_elem.bounds.y + (int)(c_elem.bounds.h*(1-vh) * c_elem.div.scroll.value_y)),
|
||||||
|
.w = 10,
|
||||||
|
.h = (short)(c_elem.bounds.h * vh),
|
||||||
|
};
|
||||||
|
|
||||||
|
c_elem.events = ctx.get_elem_events(c_elem);
|
||||||
|
if (parent.flags.has_focus && c_elem.events.mouse_hover && c_elem.events.mouse_hold && point_in_rect(ctx.input.mouse.pos, vhandle)) {
|
||||||
|
short y = (short)clamp(ctx.input.mouse.pos.y - vhandle.h/2, vslider.y, vslider.y + vslider.h - vhandle.h);
|
||||||
|
vhandle.y = y;
|
||||||
|
float v = (float)(vhandle.y-vslider.y) / (float)(vslider.h-vhandle.h);
|
||||||
|
c_elem.div.scroll.value_y = v;
|
||||||
|
c_elem.flags.updated = true;
|
||||||
|
c_elem.div.origin_c = Point{
|
||||||
|
.x = c_elem.bounds.x,
|
||||||
|
.y = c_elem.bounds.y,
|
||||||
|
};
|
||||||
|
c_elem.div.origin_r = c_elem.div.origin_c;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cmd scrl = {
|
||||||
|
.type = CMD_RECT,
|
||||||
|
.rect.rect = vslider,
|
||||||
|
.rect.color = uint_to_rgba(0x999999ff),
|
||||||
|
};
|
||||||
|
ctx.cmd_queue.enqueue(&scrl)!;
|
||||||
|
|
||||||
|
scrl.rect.rect = vhandle;
|
||||||
|
scrl.rect.color = uint_to_rgba(0x9999ffff);
|
||||||
|
ctx.cmd_queue.enqueue(&scrl)!;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
c_elem.div.scroll.on_y = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if the bounds are outside of the view then allocate space for scrollbars
|
// if the bounds are outside of the view then allocate space for scrollbars
|
||||||
DivLayout old_layout = c_elem.div.layout;
|
DivLayout old_layout = c_elem.div.layout;
|
||||||
c_elem.div.layout = LAYOUT_FLOATING;
|
c_elem.div.layout = LAYOUT_FLOATING;
|
||||||
|
@ -88,6 +88,10 @@ fn void! Ctx.frame_begin(&ctx)
|
|||||||
},
|
},
|
||||||
.div = {
|
.div = {
|
||||||
.layout = LAYOUT_ROW,
|
.layout = LAYOUT_ROW,
|
||||||
|
.children_bounds = {
|
||||||
|
.w = ctx.width,
|
||||||
|
.h = ctx.height,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.flags = c_elem.flags,
|
.flags = c_elem.flags,
|
||||||
};
|
};
|
||||||
|
@ -78,17 +78,22 @@ fn void! Ctx.layout_next_column(&ctx)
|
|||||||
// parent: parent div
|
// parent: parent div
|
||||||
// rect: the requested size
|
// rect: the requested size
|
||||||
// style: apply style
|
// style: apply style
|
||||||
|
<*
|
||||||
|
@require ctx != null
|
||||||
|
@require parent.type == ETYPE_DIV
|
||||||
|
*>
|
||||||
fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
|
fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
|
||||||
{
|
{
|
||||||
Rect placement;
|
Rect placement;
|
||||||
Point origin;
|
Point origin;
|
||||||
|
Div* div = &parent.div;
|
||||||
|
|
||||||
// 1. Select the right origin
|
// 1. Select the right origin
|
||||||
switch (parent.div.layout) {
|
switch (div.layout) {
|
||||||
case LAYOUT_ROW:
|
case LAYOUT_ROW:
|
||||||
origin = parent.div.origin_r;
|
origin = div.origin_r;
|
||||||
case LAYOUT_COLUMN:
|
case LAYOUT_COLUMN:
|
||||||
origin = parent.div.origin_c;
|
origin = div.origin_c;
|
||||||
case LAYOUT_FLOATING: // none
|
case LAYOUT_FLOATING: // none
|
||||||
default:
|
default:
|
||||||
// Error
|
// Error
|
||||||
@ -100,8 +105,8 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
|
|||||||
// 2. Calculate the placement
|
// 2. Calculate the placement
|
||||||
placement.x = (short)max(origin.x + rect.x, 0);
|
placement.x = (short)max(origin.x + rect.x, 0);
|
||||||
placement.y = (short)max(origin.y + rect.y, 0);
|
placement.y = (short)max(origin.y + rect.y, 0);
|
||||||
placement.w = rect.w > 0 ? rect.w : parent.bounds.w - (placement.x - parent.bounds.x);
|
placement.w = rect.w > 0 ? rect.w : (short)max(parent.bounds.w - (placement.x - parent.bounds.x), 0);
|
||||||
placement.h = rect.h > 0 ? rect.h : parent.bounds.h - (placement.y - parent.bounds.y);
|
placement.h = rect.h > 0 ? rect.h : (short)max(parent.bounds.h - (placement.y - parent.bounds.y), 0);
|
||||||
|
|
||||||
pl_corner.x = placement.x + placement.w;
|
pl_corner.x = placement.x + placement.w;
|
||||||
pl_corner.y = placement.y + placement.h;
|
pl_corner.y = placement.y + placement.h;
|
||||||
@ -122,28 +127,23 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 3. Update the origins of the parent
|
// 3. Update the origins of the parent
|
||||||
parent.div.origin_r = Point{
|
div.origin_r = Point{
|
||||||
.x = pl_corner.x,
|
.x = pl_corner.x,
|
||||||
.y = origin.y,
|
.y = origin.y,
|
||||||
};
|
};
|
||||||
parent.div.origin_c = Point{
|
div.origin_c = Point{
|
||||||
.x = origin.x,
|
.x = origin.x,
|
||||||
.y = pl_corner.y,
|
.y = pl_corner.y,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 4. Calculate the "scrolled" view
|
// 4. Calculate the "scrolled" view
|
||||||
Point off;
|
Point off;
|
||||||
if (parent.div.can_scroll_x && parent.div.horizontal_scroll_bar != -1) {
|
Rect* cb = &div.children_bounds;
|
||||||
Elem*! sx = ctx.get_elem_by_tree_idx(parent.div.horizontal_scroll_bar);
|
if (div.scroll.can_x && div.scroll.on_x) {
|
||||||
if (catch sx) { return Rect{}; }
|
off.x = (short)(cb.w * div.scroll.value_x);
|
||||||
// TODO: assert that the element is a slider
|
|
||||||
off.x = (short)(parent.div.children_bounds.w * sx.slider.value);
|
|
||||||
}
|
}
|
||||||
if (parent.div.can_scroll_y && parent.div.vertical_scroll_bar != -1) {
|
if (div.scroll.can_y && div.scroll.on_y) {
|
||||||
Elem*! sy = ctx.get_elem_by_tree_idx(parent.div.vertical_scroll_bar);
|
off.y = (short)((float)(cb.h - parent.bounds.h) * div.scroll.value_y);
|
||||||
if (catch sy) { return Rect{}; }
|
|
||||||
// TODO: assert that the element is a slider
|
|
||||||
off.y = (short)(parent.div.children_bounds.h * sy.slider.value);
|
|
||||||
}
|
}
|
||||||
Rect view = {
|
Rect view = {
|
||||||
.x = parent.bounds.x + off.x,
|
.x = parent.bounds.x + off.x,
|
||||||
@ -152,7 +152,26 @@ fn Rect Ctx.position_element(&ctx, Elem *parent, Rect rect, bool style = false)
|
|||||||
.h = parent.bounds.h,
|
.h = parent.bounds.h,
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: 5. check if the placement is inside the view
|
// 5. check if the placement overflows the children ounds, if so update them
|
||||||
|
if (!point_in_rect(pl_corner, *cb)) {
|
||||||
return placement;
|
if (pl_corner.y > cb.y+cb.h) {
|
||||||
|
cb.h = pl_corner.y - cb.y;
|
||||||
}
|
}
|
||||||
|
if (pl_corner.x > cb.x+cb.w) {
|
||||||
|
cb.w += pl_corner.x - (cb.x + cb.w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. check if the placement is inside the view
|
||||||
|
if (rect_collision(placement, view)) {
|
||||||
|
return Rect{
|
||||||
|
.x = placement.x - off.x,
|
||||||
|
.y = placement.y - off.y,
|
||||||
|
.w = placement.w,
|
||||||
|
.h = placement.h,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return Rect{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
module ugui;
|
module ugui;
|
||||||
|
|
||||||
|
import std::io;
|
||||||
|
|
||||||
/* handle
|
/* handle
|
||||||
* +----+-----+---------------------+
|
* +----+-----+---------------------+
|
||||||
* | |#####| |
|
* | |#####| |
|
||||||
|
Loading…
Reference in New Issue
Block a user