resizeable divs

This commit is contained in:
Alessandro Mauri 2025-12-04 19:44:46 +01:00
parent c04f63f7be
commit 60bec17d36
3 changed files with 101 additions and 10 deletions

4
TODO
View File

@ -44,6 +44,9 @@
content, the background color is applied starting from the border. Right now push_rect() offsets content, the background color is applied starting from the border. Right now push_rect() offsets
the background rect by both border and padding the background rect by both border and padding
[x] Investigate why the debug pointer (cyan rectangle) disappears... [x] Investigate why the debug pointer (cyan rectangle) disappears...
[ ] Selectable divs
[ ] Selectable text
[ ] Copy buffer
## Layout ## Layout
@ -71,6 +74,7 @@
[x] Use containing_rect() in position_element() to skip some computing and semplify the function [x] Use containing_rect() in position_element() to skip some computing and semplify the function
[x] Rename position_element() to layout_element() [x] Rename position_element() to layout_element()
[x] Make functions to mark rows/columns as full, to fix the calculator demo [x] Make functions to mark rows/columns as full, to fix the calculator demo
[ ] Grids
## Input ## Input

View File

@ -20,6 +20,18 @@ enum Anchor {
CENTER CENTER
} }
bitstruct ResizeDirection : char {
bool x : 0;
bool y : 1;
}
bitstruct ResizeAnchor : char {
bool top : 0;
bool bottom : 1;
bool left : 2;
bool right : 3;
}
struct Layout { struct Layout {
Size w, h; // size of the CONTENT, does not include margin, border and padding Size w, h; // size of the CONTENT, does not include margin, border and padding
struct children { // the children size includes the children's margin/border/pading struct children { // the children size includes the children's margin/border/pading
@ -39,7 +51,7 @@ struct Layout {
Rect content_offset; // combined effect of margin, border and padding Rect content_offset; // combined effect of margin, border and padding
} }
// Returns the width and height of a @FIT() element based on it's wanted size (min/max) // 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 // and the content size, this function is used to both update the parent's children size and
// give the dimensions of a fit element // give the dimensions of a fit element
// TODO: test and cleanup this function // TODO: test and cleanup this function

View File

@ -15,6 +15,10 @@ struct ElemDiv {
bool on; bool on;
float value; float value;
} }
ResizeAnchor resize_anchor;
ResizeAnchor resize_now;
ResizeDirection resized; // the element has been manually resized
Point resize_size;
} }
@ -39,7 +43,6 @@ macro Ctx.@column(&ctx, Anchor anchor = TOP_LEFT, ...; @body())
}!; }!;
} }
// useful macro to start and end a div, capturing the trailing block // useful macro to start and end a div, capturing the trailing block
macro Ctx.@div(&ctx, macro Ctx.@div(&ctx,
Size width = @grow, Size height = @grow, Size width = @grow, Size height = @grow,
@ -47,25 +50,26 @@ macro Ctx.@div(&ctx,
Anchor anchor = TOP_LEFT, Anchor anchor = TOP_LEFT,
bool absolute = false, Point off = {}, bool absolute = false, Point off = {},
bool scroll_x = false, bool scroll_y = false, bool scroll_x = false, bool scroll_y = false,
ResizeAnchor resize = {},
...; ...;
@body() @body()
) )
{ {
ctx.div_begin(width, height, dir, anchor, absolute, off, scroll_x, scroll_y, $vasplat)!; ctx.div_begin(width, height, dir, anchor, absolute, off, scroll_x, scroll_y, resize, $vasplat)!;
@body(); @body();
return ctx.div_end()!; return ctx.div_end()!;
} }
macro Ctx.div_begin(&ctx, macro Ctx.div_begin(&ctx,
Size width = @grow(), Size height = @grow(), Size width = @grow(), Size height = @grow(),
LayoutDirection dir = ROW, LayoutDirection dir, Anchor anchor,
Anchor anchor = TOP_LEFT, bool absolute, Point off,
bool absolute = false, Point off = {}, bool scroll_x, bool scroll_y,
bool scroll_x = false, bool scroll_y = false, ResizeAnchor resize,
... ...
) )
{ {
return ctx.div_begin_id(@compute_id($vasplat), width, height, dir, anchor, absolute, off, scroll_x, scroll_y); return ctx.div_begin_id(@compute_id($vasplat), width, height, dir, anchor, absolute, off, scroll_x, scroll_y, resize);
} }
fn void? Ctx.div_begin_id(&ctx, fn void? Ctx.div_begin_id(&ctx,
@ -74,7 +78,8 @@ fn void? Ctx.div_begin_id(&ctx,
LayoutDirection dir, LayoutDirection dir,
Anchor anchor, Anchor anchor,
bool absolute, Point off, bool absolute, Point off,
bool scroll_x, bool scroll_y bool scroll_x, bool scroll_y,
ResizeAnchor resize
) )
{ {
id = ctx.gen_id(id)!; id = ctx.gen_id(id)!;
@ -87,6 +92,20 @@ fn void? Ctx.div_begin_id(&ctx,
elem.div.scroll_x.enabled = scroll_x; elem.div.scroll_x.enabled = scroll_x;
elem.div.scroll_y.enabled = scroll_y; elem.div.scroll_y.enabled = scroll_y;
elem.div.resize_anchor = resize;
// check if the div is resizeable
bool resized = elem.div.resized && (resize != (ResizeAnchor){});
if (resize != (ResizeAnchor){}) {
// if the element was not resized yet then the size is as-specified
// if the element was resized the size is the same as the last frame
if (elem.div.resized.x == true) {
width = @exact(elem.div.resize_size.x);
}
if (elem.div.resized.y == true) {
height = @exact(elem.div.resize_size.y);
}
}
// update layout with correct info // update layout with correct info
elem.layout = { elem.layout = {
@ -161,6 +180,63 @@ fn Id? Ctx.div_end(&ctx)
elem.div.scroll_x.value = 0; elem.div.scroll_x.value = 0;
} }
// check resize action
/*
* top border
* +-------------------------------------------+
* | +---------------------------------------+ |
* | | | |
* | | | |
* | | | |
* | | | |
* left | | | | right
* border | | | | border
* | | | |
* | | | |
* | | | |
* | | | |
* | +---------------------------------------+ |
* +-------------------------------------------+
* bottom border
*/
if (elem.div.resize_anchor != (ResizeAnchor){}) {
Rect b = elem.bounds;
Rect s = style.border + style.margin + style.padding;
Rect b_l = {.x = b.x, .y = b.y, .w = s.x, .h = b.h};
Rect b_r = {.x = b.x+b.w-s.w, .y = b.y, .w = s.w, .h = b.h};
Rect b_t = {.x = b.x, .y = b.y, .w = b.w, .h = s.y};
Rect b_b = {.x = b.x, .y = b.y+b.h, .w = b.w, .h = s.h};
Rect content_bounds = elem.bounds.pad(elem.layout.content_offset);
Point m = ctx.input.mouse.pos;
if (elem.events.mouse_hover && elem.events.mouse_press) {
if (elem.div.resize_anchor.right && m.in_rect(b_r)) elem.div.resize_now.right = true;
if (elem.div.resize_anchor.left && m.in_rect(b_l)) elem.div.resize_now.left = true;
if (elem.div.resize_anchor.top && m.in_rect(b_t)) elem.div.resize_now.top = true;
if (elem.div.resize_anchor.bottom && m.in_rect(b_b)) elem.div.resize_now.bottom = true;
} else if (ctx.is_mouse_released(BTN_ANY)) {
elem.div.resize_now = {};
}
if (elem.div.resize_now.right == true) {
elem.div.resized.x = true;
elem.div.resize_size.x = content_bounds.w - (elem.bounds.x + elem.bounds.w - m.x);
}
if (elem.div.resize_now.bottom == true) {
elem.div.resized.y = true;
elem.div.resize_size.y = content_bounds.h - (elem.bounds.y + elem.bounds.h - m.y);
}
if (elem.div.resize_now.left == true) {
elem.div.resized.x = true;
elem.div.resize_size.x = content_bounds.w - (elem.bounds.x - m.x);
}
if (elem.div.resize_now.top == true) {
elem.div.resized.y = true;
elem.div.resize_size.y = content_bounds.h - (elem.bounds.y - m.y);
}
}
// 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()!;
@ -247,6 +323,5 @@ fn bool? Ctx.popup_begin_id(&ctx,
} }
// TODO: check active // TODO: check active
// TODO: check resizeable
return true; return true;
} }