Merge branch 'c3' of https://git.alemauri.eu/alema/ugui.c3l into c3
This commit is contained in:
commit
e193109570
165
LICENSE
165
LICENSE
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
4
TODO
4
TODO
@ -44,6 +44,9 @@
|
||||
content, the background color is applied starting from the border. Right now push_rect() offsets
|
||||
the background rect by both border and padding
|
||||
[x] Investigate why the debug pointer (cyan rectangle) disappears...
|
||||
[ ] Selectable divs
|
||||
[ ] Selectable text
|
||||
[ ] Copy buffer
|
||||
|
||||
## Layout
|
||||
|
||||
@ -71,6 +74,7 @@
|
||||
[x] Use containing_rect() in position_element() to skip some computing and semplify the function
|
||||
[x] Rename position_element() to layout_element()
|
||||
[x] Make functions to mark rows/columns as full, to fix the calculator demo
|
||||
[ ] Grids
|
||||
|
||||
## Input
|
||||
|
||||
|
||||
@ -162,7 +162,7 @@ macro Id @compute_id(...)
|
||||
{
|
||||
Id id = (Id)$$LINE.hash() ^ (Id)@str_hash($$FILE);
|
||||
$for var $i = 0; $i < $vacount; $i++:
|
||||
id ^= (Id)$vaconst[$i].hash();
|
||||
id ^= (Id)$vaexpr[$i].hash();
|
||||
$endfor
|
||||
return id;
|
||||
}
|
||||
@ -276,7 +276,9 @@ fn void? Ctx.frame_end(&ctx)
|
||||
}
|
||||
|
||||
// 2. clear input fields
|
||||
Point mdelta = ctx.current_input.mouse.pos - ctx.input.mouse.pos;
|
||||
ctx.input = ctx.current_input;
|
||||
ctx.input.mouse.delta = mdelta;
|
||||
ctx.current_input.events = {};
|
||||
ctx.current_input.mouse.scroll = {};
|
||||
ctx.current_input.mouse.updated = BTN_NONE;
|
||||
|
||||
@ -93,6 +93,7 @@ fn void? Ctx.input_window_size(&ctx, short width, short height)
|
||||
ctx.current_input.events.resize = ctx.width != width || ctx.height != height;
|
||||
ctx.width = width;
|
||||
ctx.height = height;
|
||||
if (ctx.current_input.events.resize) ctx.skip_frame = true;
|
||||
}
|
||||
|
||||
// Window gained/lost focus
|
||||
|
||||
@ -20,6 +20,18 @@ enum Anchor {
|
||||
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 {
|
||||
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
|
||||
@ -39,7 +51,7 @@ struct Layout {
|
||||
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
|
||||
// give the dimensions of a fit element
|
||||
// TODO: test and cleanup this function
|
||||
@ -104,8 +116,8 @@ macro Point Layout.get_dimensions(&el)
|
||||
macro Point Elem.content_space(&e)
|
||||
{
|
||||
return {
|
||||
.x = e.bounds.w - e.layout.content_offset.x - e.layout.content_offset.w,
|
||||
.y = e.bounds.h - e.layout.content_offset.y - e.layout.content_offset.h,
|
||||
.x = (short)max(e.bounds.w - e.layout.content_offset.x - e.layout.content_offset.w, 0),
|
||||
.y = (short)max(e.bounds.h - e.layout.content_offset.y - e.layout.content_offset.h, 0),
|
||||
};
|
||||
}
|
||||
|
||||
@ -132,12 +144,6 @@ fn void update_parent_size(Elem* child, Elem* parent)
|
||||
}
|
||||
}
|
||||
|
||||
fn void update_children_bounds(Elem* child, Elem* parent)
|
||||
{
|
||||
if (child.layout.absolute) return;
|
||||
parent.children_bounds = containing_rect(child.bounds + parent.layout.scroll_offset, parent.bounds);
|
||||
}
|
||||
|
||||
macro Rect Elem.content_bounds(&elem) => elem.bounds.pad(elem.layout.content_offset);
|
||||
|
||||
// Assign the width and height of an element in the directions that it doesn't need to grow
|
||||
@ -168,7 +174,7 @@ fn void resolve_grow_elements(Elem* e, Elem* p)
|
||||
if (e.layout.absolute) { // absolute children do not need to share space
|
||||
e.bounds.w = p.content_space().x;
|
||||
} else if (p.layout.dir == ROW) { // grow along the axis, divide the parent size
|
||||
short slot = (short)((p.content_space().x - p.layout.occupied) / p.layout.grow_children);
|
||||
short slot = (short)max(((p.content_space().x - p.layout.occupied) / p.layout.grow_children), 0);
|
||||
e.bounds.w = slot;
|
||||
p.layout.grow_children--;
|
||||
p.layout.occupied += slot;
|
||||
@ -182,7 +188,7 @@ fn void resolve_grow_elements(Elem* e, Elem* p)
|
||||
if (e.layout.absolute) { // absolute children do not need to share space
|
||||
e.bounds.h = p.content_space().y;
|
||||
} else if (p.layout.dir == COLUMN) { // grow along the axis, divide the parent size
|
||||
short slot = (short)((p.content_space().y - p.layout.occupied) / p.layout.grow_children);
|
||||
short slot = (short)max(((p.content_space().y - p.layout.occupied) / p.layout.grow_children), 0);
|
||||
e.bounds.h = slot;
|
||||
p.layout.grow_children--;
|
||||
p.layout.occupied += slot;
|
||||
@ -205,7 +211,7 @@ fn void resolve_placement(Elem* c, Elem* p)
|
||||
// if the element has absolute position assign the origin and do not update the parent
|
||||
if (cl.absolute) {
|
||||
c.bounds.x = p.bounds.x + pl.content_offset.x + cl.origin.x;
|
||||
c.bounds.y = p.bounds.x + pl.content_offset.x + cl.origin.y;
|
||||
c.bounds.y = p.bounds.y + pl.content_offset.y + cl.origin.y;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -295,6 +301,23 @@ fn void resolve_placement(Elem* c, Elem* p)
|
||||
pl.origin.y += c.bounds.h;
|
||||
default: unreachable("unknown layout direction");
|
||||
}
|
||||
|
||||
// update the parent children_bounds
|
||||
// FIXME: this causes scollbars to flicker in/out during resize because the current frames children_bounds are updated
|
||||
// with the previous' frame child bounds. It would be better to implement another pass during layout.
|
||||
// FIXME: this long way around to compute the children bounds works and reduces flickering, but it is very ugly
|
||||
Rect ncb = c.children_bounds;
|
||||
ncb.x = c.bounds.x;
|
||||
ncb.y = c.bounds.y;
|
||||
Rect cb = containing_rect(c.bounds, ncb);
|
||||
Point o = p.layout.scroll_offset;
|
||||
p.children_bounds = containing_rect(cb + o, p.children_bounds);
|
||||
|
||||
// reset the children bounds
|
||||
c.children_bounds = {
|
||||
.x = c.bounds.x,
|
||||
.y = c.bounds.y
|
||||
};
|
||||
}
|
||||
|
||||
fn void? Ctx.layout_element_tree(&ctx)
|
||||
@ -330,10 +353,8 @@ fn void? Ctx.layout_element_tree(&ctx)
|
||||
Elem* c = ctx.find_elem(ctx.tree.get(ch))!;
|
||||
if (ctx.tree.is_root(ch)) {
|
||||
resolve_placement(p, &&{});
|
||||
update_children_bounds(p, &&{});
|
||||
} else {
|
||||
resolve_placement(c, p);
|
||||
update_children_bounds(c, p);
|
||||
}
|
||||
|
||||
// FIXME: this stuff would be better elsewhere but we are already iteraring through all
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module ugui;
|
||||
|
||||
import std::math;
|
||||
|
||||
// ---------------------------------------------------------------------------------- //
|
||||
// RECTANGLE //
|
||||
@ -244,8 +244,6 @@ macro uint Color.to_uint(c) => c.r | (c.g << 8) | (c.b << 16) | (c.a << 24);
|
||||
// SIZE //
|
||||
// ---------------------------------------------------------------------------------- //
|
||||
|
||||
macro short short.add_no_of(short a, short b) => (short)max(min((int)a + (int)b, short.max), short.min) @inline;
|
||||
|
||||
struct Size {
|
||||
short min, max;
|
||||
}
|
||||
@ -258,8 +256,8 @@ macro bool Size.@is_grow(s) => (s.min == 0 && s.max == 0);
|
||||
macro bool Size.@is_exact(s) => (s.min == s.max && s.min != 0);
|
||||
macro bool Size.@is_fit(s) => (s.min != s.max);
|
||||
|
||||
macro Size Size.add(a, Size b) @operator_s(+) => {.min = a.min.add_no_of(b.min), .max = a.max.add_no_of(b.max)};
|
||||
macro Size Size.sub(a, Size b) @operator_s(-) => {.min = a.min.add_no_of(-b.min), .max = a.max.add_no_of(-b.max)};
|
||||
macro Size Size.add(a, Size b) @operator_s(+) => {.min = a.min.sat_add(b.min), .max = a.max.sat_add(b.max)};
|
||||
macro Size Size.sub(a, Size b) @operator_s(-) => {.min = a.min.sat_sub(b.min), .max = a.max.sat_sub(b.max)};
|
||||
|
||||
macro Size Size.combine(a, Size b) => {.min = max(a.min, b.min), .max = min(a.max, b.max)};
|
||||
macro Size Size.comb_max(a, Size b) => {.min = max(a.min, b.min), .max = max(a.max, b.max)};
|
||||
|
||||
@ -15,31 +15,34 @@ struct ElemDiv {
|
||||
bool on;
|
||||
float value;
|
||||
}
|
||||
ResizeAnchor resize_anchor;
|
||||
ResizeAnchor resize_now;
|
||||
ResizeDirection resized; // the element has been manually resized
|
||||
Point resize_size;
|
||||
}
|
||||
|
||||
|
||||
macro Ctx.@center(&ctx, LayoutDirection dir = ROW, ...; @body())
|
||||
{
|
||||
ctx.@div(@grow(), @grow(), dir, CENTER) {
|
||||
return ctx.@div(@grow(), @grow(), dir, CENTER) {
|
||||
@body();
|
||||
}!;
|
||||
}
|
||||
|
||||
macro Ctx.@row(&ctx, Anchor anchor = TOP_LEFT, ...; @body())
|
||||
{
|
||||
ctx.@div(@fit(), @fit(), ROW, anchor: anchor) {
|
||||
return ctx.@div(@fit(), @fit(), ROW, anchor: anchor) {
|
||||
@body();
|
||||
}!;
|
||||
}
|
||||
|
||||
macro Ctx.@column(&ctx, Anchor anchor = TOP_LEFT, ...; @body())
|
||||
{
|
||||
ctx.@div(@fit(), @fit(), COLUMN, anchor: anchor) {
|
||||
return ctx.@div(@fit(), @fit(), COLUMN, anchor: anchor) {
|
||||
@body();
|
||||
}!;
|
||||
}
|
||||
|
||||
|
||||
// useful macro to start and end a div, capturing the trailing block
|
||||
macro Ctx.@div(&ctx,
|
||||
Size width = @grow, Size height = @grow,
|
||||
@ -47,25 +50,26 @@ macro Ctx.@div(&ctx,
|
||||
Anchor anchor = TOP_LEFT,
|
||||
bool absolute = false, Point off = {},
|
||||
bool scroll_x = false, bool scroll_y = false,
|
||||
ResizeAnchor resize = {},
|
||||
...;
|
||||
@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();
|
||||
return ctx.div_end()!;
|
||||
}
|
||||
|
||||
macro Ctx.div_begin(&ctx,
|
||||
Size width = @grow(), Size height = @grow(),
|
||||
LayoutDirection dir = ROW,
|
||||
Anchor anchor = TOP_LEFT,
|
||||
bool absolute = false, Point off = {},
|
||||
bool scroll_x = false, bool scroll_y = false,
|
||||
LayoutDirection dir, Anchor anchor,
|
||||
bool absolute, Point off,
|
||||
bool scroll_x, bool scroll_y,
|
||||
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,
|
||||
@ -74,7 +78,8 @@ fn void? Ctx.div_begin_id(&ctx,
|
||||
LayoutDirection dir,
|
||||
Anchor anchor,
|
||||
bool absolute, Point off,
|
||||
bool scroll_x, bool scroll_y
|
||||
bool scroll_x, bool scroll_y,
|
||||
ResizeAnchor resize
|
||||
)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
@ -87,7 +92,21 @@ fn void? Ctx.div_begin_id(&ctx,
|
||||
|
||||
elem.div.scroll_x.enabled = scroll_x;
|
||||
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
|
||||
elem.layout = {
|
||||
.w = width,
|
||||
@ -105,8 +124,8 @@ fn void? Ctx.div_begin_id(&ctx,
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), elem.z_index, style)!;
|
||||
|
||||
// update the ctx scissor, it HAS to be after drawing the background
|
||||
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.z_index)!;
|
||||
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset).max({0,0,0,0});
|
||||
ctx.push_scissor(ctx.div_scissor, elem.z_index)!;
|
||||
|
||||
//elem.events = ctx.get_elem_events(elem);
|
||||
|
||||
@ -155,16 +174,73 @@ fn Id? Ctx.div_end(&ctx)
|
||||
elem.div.scroll_x.value = math::clamp(elem.div.scroll_x.value, 0.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
ctx.scrollbar(vsid_raw, &elem.div.scroll_x.value, max((float)bc.x / cbc.x, (float)0.15), false)!;
|
||||
ctx.scrollbar(hsid_raw, &elem.div.scroll_x.value, max((float)bc.x / cbc.x, (float)0.15), false)!;
|
||||
elem.layout.scroll_offset.x = (short)(elem.div.scroll_x.value*(float)(elem.children_bounds.w-elem.bounds.w));
|
||||
} else {
|
||||
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
|
||||
ctx.active_div = ctx.tree.parentof(ctx.active_div)!;
|
||||
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).max({0,0,0,0});
|
||||
ctx.reset_scissor(elem.z_index)!;
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
@ -172,6 +248,21 @@ fn Id? Ctx.div_end(&ctx)
|
||||
return elem.id;
|
||||
}
|
||||
|
||||
<* @param[&inout] state *>
|
||||
macro Ctx.@popup(&ctx, bool* state,
|
||||
Point pos,
|
||||
Size width, Size height,
|
||||
LayoutDirection dir = ROW, Anchor anchor = TOP_LEFT,
|
||||
bool scroll_x = false, bool scroll_y = false,
|
||||
...; @body())
|
||||
{
|
||||
if (*state) {
|
||||
*state = ctx.popup_begin(pos, width, height, dir, anchor, scroll_x, scroll_y)!;
|
||||
@body();
|
||||
ctx.div_end()!;
|
||||
}
|
||||
}
|
||||
|
||||
macro bool? Ctx.popup_begin(&ctx, Point pos,
|
||||
Size width, Size height,
|
||||
LayoutDirection dir = ROW, Anchor anchor = TOP_LEFT,
|
||||
@ -221,8 +312,8 @@ fn bool? Ctx.popup_begin_id(&ctx,
|
||||
ctx.push_rect(elem.bounds.pad(style.margin), elem.z_index, style)!;
|
||||
|
||||
// update the ctx scissor, it HAS to be after drawing the background
|
||||
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_scissor(elem.bounds.pad(elem.layout.content_offset), elem.z_index)!;
|
||||
ctx.div_scissor = elem.bounds.pad(elem.layout.content_offset).max({0,0,0,0});
|
||||
ctx.push_scissor(ctx.div_scissor, elem.z_index)!;
|
||||
|
||||
//elem.events = ctx.get_elem_events(elem);
|
||||
|
||||
@ -232,6 +323,5 @@ fn bool? Ctx.popup_begin_id(&ctx,
|
||||
}
|
||||
|
||||
// TODO: check active
|
||||
// TODO: check resizeable
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1,16 +1,56 @@
|
||||
module ugui;
|
||||
|
||||
|
||||
macro Ctx.separator(&ctx, int width, int height, ...)
|
||||
macro Ctx.separator(&ctx, Size width, Size height, ...)
|
||||
=> ctx.separator_id(@compute_id($vasplat), width, height);
|
||||
fn void? Ctx.separator_id(&ctx, Id id, int width, int height)
|
||||
fn void? Ctx.separator_id(&ctx, Id id, Size width, Size height)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
Elem* parent, elem;
|
||||
ctx.get_elem(id, ETYPE_NONE)!.unpack(&elem, &parent);
|
||||
|
||||
elem.layout.w = @exact((short)width);
|
||||
elem.layout.h = @exact((short)height);
|
||||
elem.layout.w = width;
|
||||
elem.layout.h = height;
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
}
|
||||
|
||||
|
||||
macro Ctx.hor_line(&ctx, ...)
|
||||
=> ctx.hor_line_id(@compute_id($vasplat));
|
||||
fn void? Ctx.hor_line_id(&ctx, Id id)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
Elem* parent, elem;
|
||||
ctx.get_elem(id, ETYPE_NONE)!.unpack(&elem, &parent);
|
||||
Style* style = ctx.styles.get_style(@str_hash("separator"));
|
||||
|
||||
elem.layout.w = @grow();
|
||||
elem.layout.h = @exact(style.size);
|
||||
elem.layout.content_offset = style.margin + style.border + style.padding;
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
Rect r = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_rect(r, elem.z_index, style)!;
|
||||
}
|
||||
|
||||
|
||||
macro Ctx.ver_line(&ctx, ...)
|
||||
=> ctx.ver_line_id(@compute_id($vasplat));
|
||||
fn void? Ctx.ver_line_id(&ctx, Id id)
|
||||
{
|
||||
id = ctx.gen_id(id)!;
|
||||
Elem* parent, elem;
|
||||
ctx.get_elem(id, ETYPE_NONE)!.unpack(&elem, &parent);
|
||||
Style* style = ctx.styles.get_style(@str_hash("separator"));
|
||||
|
||||
elem.layout.w = @exact(style.size);
|
||||
elem.layout.h = @grow();
|
||||
elem.layout.content_offset = style.margin + style.border + style.padding;
|
||||
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
Rect r = elem.bounds.pad(elem.layout.content_offset);
|
||||
ctx.push_rect(r, elem.z_index, style)!;
|
||||
}
|
||||
@ -140,23 +140,22 @@ fn void? Ctx.scrollbar(&ctx, Id id, float *value, float handle_percent, bool ver
|
||||
Style* style = ctx.styles.get_style(@str_hash("scrollbar"));
|
||||
|
||||
Rect pb = parent.bounds.pad(parent.layout.content_offset);
|
||||
elem.bounds.x = vertical ? pb.bottom_right().x - style.size: pb.x;
|
||||
elem.bounds.y = vertical ? pb.y : pb.bottom_right().y - style.size;
|
||||
if (vertical) {
|
||||
elem.layout.w = @exact(style.size);
|
||||
elem.layout.h = @grow();
|
||||
elem.bounds.x -= style.margin.x + style.margin.w + style.border.x + style.border.w;
|
||||
elem.layout.origin.x = pb.w - style.size;
|
||||
elem.layout.origin.y = 0;
|
||||
} else {
|
||||
elem.layout.w = @grow();
|
||||
elem.layout.h = @exact(style.size);
|
||||
elem.bounds.y -= style.margin.y + style.margin.h + style.border.y + style.border.h;
|
||||
elem.layout.origin.x = 0;
|
||||
elem.layout.origin.y = pb.h - style.size;
|
||||
}
|
||||
elem.layout.content_offset = style.margin + style.border + style.padding;
|
||||
elem.layout.absolute = true;
|
||||
update_parent_size(elem, parent);
|
||||
|
||||
Rect content_bounds = elem.bounds.pad(elem.layout.content_offset);
|
||||
//elem.events = ctx.get_elem_events(elem);
|
||||
|
||||
short o = vertical ? content_bounds.y : content_bounds.x;
|
||||
short m = vertical ? ctx.input.mouse.pos.y : ctx.input.mouse.pos.x;
|
||||
|
||||
@ -21,8 +21,8 @@ fn void? Ctx.sprite_id(&ctx, Id id, String name, short size = 0)
|
||||
short height = sprite.h;
|
||||
if (size > 0) {
|
||||
if (sprite.w >= sprite.h) {
|
||||
width = size;
|
||||
height = (short)(size * (float)height/width);
|
||||
width = size;
|
||||
} else {
|
||||
width = (short)(size * (float)width/height);
|
||||
height = size;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user