layout uses x,y

This commit is contained in:
2025-07-06 20:35:15 -05:00
parent d4f0059419
commit 71c0056df4
5 changed files with 134 additions and 61 deletions

View File

@@ -36,7 +36,7 @@ var clay_base = {
spacing:0,
padding:0,
margin:0,
offset:[0,0],
offset:{x:0, y:0},
size:null,
background_color: null
};
@@ -54,6 +54,10 @@ clay.draw = function draw(size, fn, config = {})
lay_ctx.reset();
boxes = [];
var root = lay_ctx.item();
// Accept both array and object formats
if (Array.isArray(size)) {
size = {width: size[0], height: size[1]};
}
lay_ctx.set_size(root,size);
lay_ctx.set_contain(root,layout.contain.row);
root_item = root;
@@ -86,9 +90,9 @@ clay.draw = function draw(size, fn, config = {})
box.marginbox.width += margin.l+margin.r;
box.marginbox.height += margin.t+margin.b;
box.content.y *= -1;
box.content.y += size.y;
box.content.y += size.height;
box.boundingbox.y *= -1;
box.boundingbox.y += size.y;
box.boundingbox.y += size.height;
box.content.anchor_y = 1;
box.boundingbox.anchor_y = 1;
}
@@ -128,7 +132,7 @@ clay.spacer = create_view_fn({
function image_size(img)
{
return [img.rect[2]*img.texture.width, img.rect[3]*img.texture.height];
return [img.width * (img.rect?.width || 1), img.height * (img.rect?.height || 1)];
}
function add_item(config)
@@ -163,6 +167,11 @@ function add_item(config)
var item = lay_ctx.item();
lay_ctx.set_margins(item, use_config.margin);
use_config.size ??= {width:0, height:0}
// Convert array to object if needed
if (Array.isArray(use_config.size)) {
use_config.size = {width: use_config.size[0], height: use_config.size[1]};
}
lay_ctx.set_size(item,use_config.size);
lay_ctx.set_contain(item,use_config.contain);
lay_ctx.set_behave(item,use_config.behave);
@@ -195,18 +204,18 @@ clay.image = function image(path, ...configs)
{
var config = rectify_configs(configs);
var image = graphics.texture(path);
config.image = image;
config.size ??= [image.texture.width, image.texture.height];
config.image = path; // Store the path string, not the texture object
config.size ??= {width: image.width, height: image.height};
add_item(config);
}
clay.text = function text(str, ...configs)
{
var config = rectify_configs(configs);
config.size ??= [0,0];
config.size ??= {width:0, height:0};
// config.font = graphics.get_font(config.font)
var tsize = 12; //config.font.text_size(str, 0, 0, config.size.x);
config.size = config.size.map((x,i) => Math.max(x, tsize[i]));
var tsize = {width: 12, height: 12}; //config.font.text_size(str, 0, 0, config.size.width);
config.size = {width: Math.max(config.size.width, tsize.width), height: Math.max(config.size.height, tsize.height)};
config.text = str;
add_item(config);
}
@@ -236,13 +245,17 @@ clay.button = function button(str, action, config = {})
var hovered = null;
clay.newframe = function() { hovered = null; }
function point_add(a,b) {
return {x: a.x+b.x, y: a.y+b.y}
}
// mousepos given in hud coordinates
clay.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prosperon.camera.screen2hud(input.mouse.screenpos()))
clay.draw_commands = function draw_commands(cmds, pos = {x:0, y:0}, mousepos = {x:0,y:0})
{
for (var cmd of cmds) {
var config = cmd.config;
var boundingbox = geometry.rect_move(cmd.boundingbox,pos.add(config.offset));
var content = geometry.rect_move(cmd.content,pos.add(config.offset));
var boundingbox = geometry.rect_move(cmd.boundingbox,point_add(pos,config.offset));
var content = geometry.rect_move(cmd.content,point_add(pos, config.offset));
if (config.hovered && geometry.rect_point_inside(boundingbox, mousepos)) {
config.hovered.__proto__ = config;
@@ -259,7 +272,7 @@ clay.draw_commands = function draw_commands(cmds, pos = [0,0], mousepos = prospe
draw.rectangle(boundingbox, config.background_color);
if (config.text)
draw.text(config.text, content, config.font, config.font_size, config.color, config.size.x);
draw.text(config.text, content, config.font, config.font_size, config.color, config.size.width);
if (config.image)
draw.image(config.image, content, 0, config.color);
}
@@ -270,7 +283,7 @@ clay.debug_colors = dbg_colors;
dbg_colors.content = [1,0,0,0.1];
dbg_colors.boundingbox = [0,1,0,0,0.1];
dbg_colors.margin = [0,0,1,0.1];
clay.draw_debug = function draw_debug(cmds, pos = [0,0])
clay.draw_debug = function draw_debug(cmds, pos = {x:0, y:0})
{
for (var i = 0; i < cmds.length; i++) {
var cmd = cmds[i];

View File

@@ -6,7 +6,7 @@ Includes both JavaScript and C-implemented routines for creating geometry buffer
rectangle packing, etc.
`
var renderer_actor = arg[0]
var renderer_actor = arg?.[0] || null
var io = use('io')
var time = use('time')
@@ -34,7 +34,7 @@ graphics.Image = function(surfaceData) {
Object.defineProperties(graphics.Image.prototype, {
gpu: {
get: function() {
if (!this[GPU] && !this[LOADING]) {
if (!this[GPU] && !this[LOADING] && renderer_actor) {
this[LOADING] = true;
var self = this;
@@ -76,13 +76,13 @@ Object.defineProperties(graphics.Image.prototype, {
width: {
get: function() {
return this[CPU].width
return this[CPU]?.width || 0
}
},
height: {
get: function() {
return this[CPU].height
return this[CPU]?.height || 0
}
}
});
@@ -97,29 +97,44 @@ graphics.Image.prototype.unload_cpu = function() {
}
function calc_image_size(img) {
if (!img.texture || !img.rect) return
return [img.texture.width * img.rect.width, img.texture.height * img.rect.height]
if (!img.rect) return
if (img.texture) {
return [img.texture.width * img.rect.width, img.texture.height * img.rect.height]
} else if (img[CPU]) {
return [img[CPU].width * img.rect.width, img[CPU].height * img.rect.height]
}
return [0, 0]
}
function decorate_rect_px(img) {
// needs a GPU texture to measure
if (!img || !img.texture) return
// default UV rect is the whole image if none supplied
img.rect ??= {x:0, y:0, width:1, height:1} // [u0,v0,uw,vh] in 0-1
var width = 0, height = 0;
if (img.texture) {
width = img.texture.width;
height = img.texture.height;
} else if (img[CPU]) {
width = img[CPU].width;
height = img[CPU].height;
} else {
return;
}
// store pixel-space version: [x, y, w, h] in texels
img.rect_px = {
x:Math.round(img.rect.x * img.texture.width),
y:Math.round(img.rect.y * img.texture.height),
width:Math.round(img.rect.width * img.texture.width),
height:Math.round(img.rect.height * img.texture.height)
x:Math.round(img.rect.x * width),
y:Math.round(img.rect.y * height),
width:Math.round(img.rect.width * width),
height:Math.round(img.rect.height * height)
}
}
function make_handle(obj)
{
return new graphics.Image(obj);
var img = new graphics.Image(obj);
decorate_rect_px(img);
return img;
}
function wrapSurface(surf, maybeRect){
@@ -189,7 +204,15 @@ function create_image(path){
var image = {}
image.dimensions = function() {
return [this.texture.width, this.texture.height].scale([this.rect[2], this.rect[3]])
var width = 0, height = 0;
if (this.texture) {
width = this.texture.width;
height = this.texture.height;
} else if (this[CPU]) {
width = this[CPU].width;
height = this[CPU].height;
}
return [width, height].scale([this.rect[2], this.rect[3]])
}
image.dimensions[cell.DOC] = `
:return: A 2D array [width, height] that is the scaled size of this image (texture size * rect size).
@@ -224,7 +247,7 @@ graphics.texture_from_data = function(data)
var image = graphics.make_texture(data);
var img = make_handle(image)
img.gpu;
if (renderer_actor) img.gpu;
return img;
}
@@ -341,17 +364,19 @@ graphics.get_font = function get_font(path, size) {
var font = graphics.make_font(data,size)
// Load font texture via renderer actor (async)
send(renderer_actor, {
kind: "renderer",
op: "loadTexture",
data: font.surface
}, function(response) {
if (response.error) {
log.error("Failed to load font texture:", response.error);
} else {
font.texture = response;
}
});
if (renderer_actor) {
send(renderer_actor, {
kind: "renderer",
op: "loadTexture",
data: font.surface
}, function(response) {
if (response.error) {
log.error("Failed to load font texture:", response.error);
} else {
font.texture = response;
}
});
}
fontcache[fontstr] = font

View File

@@ -218,8 +218,6 @@ JSValue __##PROP##__v = JS_GetPropertyStr(JS,VALUE,#ATOM); \
TARGET = js2##TYPE(JS, __##PROP##__v); \
JS_FreeValue(JS,__##PROP##__v); }\
#define JS_SETATOM(JS, TARGET, ATOM, VALUE, TYPE) JS_SetProperty(JS, TARGET, #ATOM, TYPE##2js(JS, VALUE));
int JS_GETBOOL(JSContext *js, JSValue v, const char *prop)
{
JSValue __v = JS_GetPropertyStr(js,v,prop);
@@ -429,8 +427,23 @@ JSValue color2js(JSContext *js, colorf color)
HMM_Vec2 js2vec2(JSContext *js,JSValue v)
{
HMM_Vec2 v2;
v2.X = js_getnum_uint32(js,v,0);
v2.Y = js_getnum_uint32(js,v,1);
// Check if it's an array
if (JS_IsArray(js, v)) {
v2.X = js_getnum_uint32(js,v,0);
v2.Y = js_getnum_uint32(js,v,1);
} else {
// Try to get x,y properties from object
JSValue x_val = JS_GetPropertyStr(js, v, "x");
JSValue y_val = JS_GetPropertyStr(js, v, "y");
v2.X = js2number(js, x_val);
v2.Y = js2number(js, y_val);
JS_FreeValue(js, x_val);
JS_FreeValue(js, y_val);
}
return v2;
}
@@ -609,10 +622,10 @@ HMM_Vec2 transform_point(SDL_Renderer *ren, HMM_Vec2 in, HMM_Mat3 *t)
JSValue rect2js(JSContext *js,rect rect) {
JSValue obj = JS_NewObject(js);
JS_SETATOM(js, obj, x, rect.x, number);
JS_SETATOM(js, obj, y, rect.y, number);
JS_SETATOM(js, obj, width, rect.w, number);
JS_SETATOM(js, obj, height, rect.h, number);
JS_SetPropertyStr(js, obj, "x", number2js(js, rect.x));
JS_SetPropertyStr(js, obj, "y", number2js(js, rect.y));
JS_SetPropertyStr(js, obj, "width", number2js(js, rect.w));
JS_SetPropertyStr(js, obj, "height", number2js(js, rect.h));
return obj;
}

View File

@@ -36,16 +36,35 @@ static JSValue js_layout_set_size(JSContext *js, JSValueConst self, int argc, JS
GETLAY
GETITEM(id, argv[0])
double size[2];
JSValue width_val = JS_GetPropertyUint32(js, argv[1], 0);
JSValue height_val = JS_GetPropertyUint32(js, argv[1], 1);
JS_ToFloat64(js, &size[0], width_val);
JS_ToFloat64(js, &size[1], height_val);
JS_FreeValue(js, width_val);
JS_FreeValue(js, height_val);
if (isnan(size[0])) size[0] = 0;
if (isnan(size[1])) size[1] = 0;
lay_set_size_xy(lay, id, size[0], size[1]);
double width = 0, height = 0;
// Check if it's an array (for backwards compatibility)
if (JS_IsArray(js, argv[1])) {
JSValue width_val = JS_GetPropertyUint32(js, argv[1], 0);
JSValue height_val = JS_GetPropertyUint32(js, argv[1], 1);
JS_ToFloat64(js, &width, width_val);
JS_ToFloat64(js, &height, height_val);
JS_FreeValue(js, width_val);
JS_FreeValue(js, height_val);
} else {
// Handle object with x,y or width,height properties
JSValue width_val = JS_GetPropertyStr(js, argv[1], "width");
if (JS_IsNull(width_val)) {
width_val = JS_GetPropertyStr(js, argv[1], "x");
}
JSValue height_val = JS_GetPropertyStr(js, argv[1], "height");
if (JS_IsNull(height_val)) {
height_val = JS_GetPropertyStr(js, argv[1], "y");
}
JS_ToFloat64(js, &width, width_val);
JS_ToFloat64(js, &height, height_val);
JS_FreeValue(js, width_val);
JS_FreeValue(js, height_val);
}
if (isnan(width)) width = 0;
if (isnan(height)) height = 0;
lay_set_size_xy(lay, id, width, height);
return JS_NULL;
}

View File

@@ -7129,11 +7129,14 @@ static JSValue JS_GetPropertyValue(JSContext *ctx, JSValueConst this_obj,
} else {
slow_path:
/* ToObject() must be done before ToPropertyKey() */
atom = JS_ValueToAtom(ctx, prop);
if (JS_IsNull(this_obj)) {
JS_FreeValue(ctx, prop);
return JS_ThrowTypeError(ctx, "cannot read property of null");
JSValue ret = JS_ThrowTypeErrorAtom(ctx, "cannot read property '%s' of null", atom);
JS_FreeAtom(ctx, atom);
return ret;
}
atom = JS_ValueToAtom(ctx, prop);
JS_FreeValue(ctx, prop);
if (unlikely(atom == JS_ATOM_NULL))
return JS_EXCEPTION;