add more lua API functions

rust-rewrite
Patrick Cleavelin 2024-02-07 23:10:59 -06:00
parent 6f4305a92a
commit b105eb67cc
3 changed files with 336 additions and 47 deletions

View File

@ -1,30 +1,48 @@
print("Hello from lua from a file!") local WindowOpen = true
local WindowOpen = false function buffer_list_iter()
local idx = 0
return function ()
buffer_info = Editor.buffer_info_from_index(idx)
idx = idx + 1
return buffer_info, idx-1
end
end
function render_ui_window(ctx) function render_ui_window(ctx)
if WindowOpen then if WindowOpen then
canvas = UI.push_floating(ctx, "lua canvas", 0, 0) current_buffer_index = Editor.get_current_buffer_index()
UI.push_parent(ctx, canvas)
window = UI.push_rect(ctx, "fullscreen window", true, true, UI.Vertical, UI.Fill, UI.Fill) tabs = UI.push_rect(ctx, "tabs", false, true, UI.Vertical, UI.ChildrenSum, UI.Fill)
UI.push_parent(ctx, window) UI.push_parent(ctx, tabs)
if UI.button(ctx, "Click me!").clicked then for buffer_info, i in buffer_list_iter() do
print("you clicked me!") button_container = UI.push_rect(ctx, "button container"..i, false, false, UI.Horizontal, UI.ChildrenSum, UI.ChildrenSum)
end UI.push_parent(ctx, button_container)
if UI.button(ctx, "I am lua").clicked then flags = {"Clickable", "Hoverable", "DrawText", "DrawBackground"}
print("you clicked me!") if i ~= current_buffer_index then
end table.insert(flags, 1, "DrawBorder")
if UI.button(ctx, "This is another button").clicked then end
print("you clicked me!")
end if UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.PercentOfParent(25), UI.FitText).clicked then
if UI.button(ctx, "if the names of these are the same it will seg fault").clicked then Editor.set_current_buffer_from_index(i)
print("you clicked me!") end
end if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then
if UI.button(ctx, "Click me! 2").clicked then print("hahah, you can't close buffers yet silly")
print("you clicked me!") end
end UI.pop_parent(ctx)
UI.pop_parent(ctx) end
UI.pop_parent(ctx) UI.pop_parent(ctx)
-- if Tabs[CurrentTab] ~= nil then
UI.buffer(ctx, current_buffer_index)
-- else
-- UI.push_parent(ctx, UI.push_centered(ctx, "centered no files open", false, false, UI.Vertical, UI.Fill, UI.Fill))
-- if UI.button(ctx, "Open File").clicked then
-- Tabs[CurrentTab] = {0, "main.odin"}
-- end
-- UI.pop_parent(ctx)
-- end
end end
end end

View File

@ -251,7 +251,7 @@ draw :: proc(state_with_ui: ^StateWithUi) {
ui.compute_layout(state_with_ui.ui_context, { state_with_ui.state.screen_width, state_with_ui.state.screen_height }, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root); ui.compute_layout(state_with_ui.ui_context, { state_with_ui.state.screen_width, state_with_ui.state.screen_height }, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root);
ui.draw(state_with_ui.ui_context, state_with_ui.state, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root); ui.draw(state_with_ui.ui_context, state_with_ui.state, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root);
if true || state_with_ui.state.current_input_map != &state_with_ui.state.input_map { if state_with_ui.state.current_input_map != &state_with_ui.state.input_map {
longest_description := 0; longest_description := 0;
for key, action in state_with_ui.state.current_input_map.key_actions { for key, action in state_with_ui.state.current_input_map.key_actions {
if len(action.description) > longest_description { if len(action.description) > longest_description {
@ -337,7 +337,7 @@ ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^FileBuffer) -> ui.Interaction
}; };
relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator) relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator)
ui.push_parent(ctx, ui.push_box(ctx, relative_file_path, {}, .Vertical, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Fill, 0)})); ui.push_parent(ctx, ui.push_box(ctx, relative_file_path, {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill)}));
defer ui.pop_parent(ctx); defer ui.pop_parent(ctx);
interaction := ui.custom(ctx, "buffer1", draw_func, transmute(rawptr)buffer); interaction := ui.custom(ctx, "buffer1", draw_func, transmute(rawptr)buffer);
@ -936,6 +936,35 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin {
}; };
} }
lua_ui_flags :: proc(L: ^lua.State, index: i32) -> (bit_set[ui.Flag], bool) {
lua.L_checktype(L, index, i32(lua.TTABLE));
lua.len(L, index);
array_len := lua.tointeger(L, -1);
lua.pop(L, 1);
flags: bit_set[ui.Flag]
for i in 1..=array_len {
lua.rawgeti(L, index, i);
defer lua.pop(L, 1);
flag := lua.tostring(L, -1);
switch flag {
case "Clickable": flags |= {.Clickable}
case "Hoverable": flags |= {.Hoverable}
case "Scrollable": flags |= {.Scrollable}
case "DrawText": flags |= {.DrawText}
case "DrawBorder": flags |= {.DrawBorder}
case "DrawBackground": flags |= {.DrawBackground}
case "RoundedBorder": flags |= {.RoundedBorder}
case "Floating": flags |= {.Floating}
case "CustomDrawFunc": flags |= {.CustomDrawFunc}
}
}
return flags, true
}
main :: proc() { main :: proc() {
state = State { state = State {
ctx = context, ctx = context,
@ -1069,7 +1098,6 @@ main :: proc() {
lua.pushvalue(L, 2); lua.pushvalue(L, 2);
fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX));
fmt.println("LUA: attempting to add hook:", hook, "ref", fn_ref);
core.add_lua_hook(&state, plugin.Hook(hook), fn_ref); core.add_lua_hook(&state, plugin.Hook(hook), fn_ref);
return i32(lua.OK); return i32(lua.OK);
@ -1088,7 +1116,6 @@ main :: proc() {
desc := strings.clone(string(lua.L_checkstring(L, 3))); desc := strings.clone(string(lua.L_checkstring(L, 3)));
fmt.println("LUA: attempting to register:", key, "ref", fn_ref);
core.register_key_action_group(&state.input_map, plugin.Key(key), fn_ref, desc); core.register_key_action_group(&state.input_map, plugin.Key(key), fn_ref, desc);
return i32(lua.OK); return i32(lua.OK);
@ -1106,11 +1133,7 @@ main :: proc() {
key_group_len := lua.tointeger(L, -1); key_group_len := lua.tointeger(L, -1);
lua.pop(L, 1); lua.pop(L, 1);
fmt.println("num groups", key_group_len);
for i in 1..=key_group_len { for i in 1..=key_group_len {
fmt.println("LUA: index", index, "i", i);
lua.rawgeti(L, index, i); lua.rawgeti(L, index, i);
defer lua.pop(L, 1); defer lua.pop(L, 1);
@ -1122,8 +1145,6 @@ main :: proc() {
desc := strings.clone(string(lua.tostring(L, -1))); desc := strings.clone(string(lua.tostring(L, -1)));
lua.pop(L, 1); lua.pop(L, 1);
fmt.println("LUA: attempting to register:", key, desc);
switch lua.rawgeti(L, -1, 3) { switch lua.rawgeti(L, -1, 3) {
case i32(lua.TTABLE): case i32(lua.TTABLE):
if action, exists := input_map.key_actions[key]; exists { if action, exists := input_map.key_actions[key]; exists {
@ -1151,8 +1172,6 @@ main :: proc() {
case: case:
lua.pop(L, 1); lua.pop(L, 1);
} }
fmt.println("LUA: successfully registered:", key);
} }
} }
@ -1188,10 +1207,125 @@ main :: proc() {
return i32(lua.OK); return i32(lua.OK);
} }
}, },
lua.L_Reg {
"get_current_buffer_index",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
lua.pushinteger(L, lua.Integer(state.current_buffer));
return 1;
}
},
lua.L_Reg {
"set_current_buffer_from_index",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
buffer_index := int(lua.L_checkinteger(L, 1));
if buffer_index < 0 || buffer_index >= len(state.buffers) {
return i32(lua.ERRRUN);
} else {
state.current_buffer = buffer_index;
}
return i32(lua.OK);
}
},
lua.L_Reg {
"buffer_info_from_index",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
buffer_index := int(lua.L_checkinteger(L, 1));
if buffer_index < 0 || buffer_index >= len(state.buffers) {
lua.pushnil(L);
} else {
push_lua_buffer_info :: proc(L: ^lua.State, buffer: ^FileBuffer) {
lua.newtable(L);
{
lua.pushlightuserdata(L, buffer);
lua.setfield(L, -2, "buffer");
lua.newtable(L);
{
lua.pushinteger(L, lua.Integer(buffer.cursor.col));
lua.setfield(L, -2, "col");
lua.pushinteger(L, lua.Integer(buffer.cursor.line));
lua.setfield(L, -2, "line");
}
lua.setfield(L, -2, "cursor");
lua.pushstring(L, strings.clone_to_cstring(buffer.file_path, context.temp_allocator));
lua.setfield(L, -2, "full_file_path");
relative_file_path, _ := filepath.rel(state.directory, buffer.file_path, context.temp_allocator)
lua.pushstring(L, strings.clone_to_cstring(relative_file_path, context.temp_allocator));
lua.setfield(L, -2, "file_path");
}
}
push_lua_buffer_info(L, &state.buffers[buffer_index]);
}
return 1;
}
},
}; };
bbb = raw_data(editor_lib[:]); bbb = raw_data(editor_lib[:]);
get_lua_semantic_size :: proc(L: ^lua.State, index: i32) -> ui.SemanticSize {
if lua.istable(L, index) {
lua.rawgeti(L, index, 1);
semantic_kind := ui.SemanticSizeKind(lua.tointeger(L, -1));
lua.pop(L, 1);
lua.rawgeti(L, index, 2);
semantic_value := int(lua.tointeger(L, -1));
lua.pop(L, 1);
return {semantic_kind, semantic_value};
} else {
semantic_kind := ui.SemanticSizeKind(lua.L_checkinteger(L, index));
return {semantic_kind, 0};
}
}
push_lua_semantic_size_table :: proc(L: ^lua.State, size: ui.SemanticSize) {
lua.newtable(L);
{
lua.pushinteger(L, lua.Integer(i32(size.kind)));
lua.rawseti(L, -2, 1);
lua.pushinteger(L, lua.Integer(size.value));
lua.rawseti(L, -2, 2);
}
}
ui_lib := [?]lua.L_Reg { ui_lib := [?]lua.L_Reg {
lua.L_Reg {
"Exact",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
value := lua.L_checkinteger(L, 1);
push_lua_semantic_size_table(L, { ui.SemanticSizeKind.Exact, int(value) });
return 1;
}
},
lua.L_Reg {
"PercentOfParent",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
value := lua.L_checkinteger(L, 1);
push_lua_semantic_size_table(L, { ui.SemanticSizeKind.PercentOfParent, int(value) });
return 1;
}
},
lua.L_Reg { lua.L_Reg {
"push_parent", "push_parent",
proc "c" (L: ^lua.State) -> i32 { proc "c" (L: ^lua.State) -> i32 {
@ -1238,7 +1372,7 @@ main :: proc() {
x := int(lua.L_checkinteger(L, 3)); x := int(lua.L_checkinteger(L, 3));
y := int(lua.L_checkinteger(L, 4)); y := int(lua.L_checkinteger(L, 4));
box := ui.push_floating(ui_ctx, string(label), {x,y}); box := ui.push_floating(ui_ctx, strings.clone(string(label)), {x,y});
lua.pushlightuserdata(L, box); lua.pushlightuserdata(L, box);
return 1; return 1;
} }
@ -1260,11 +1394,10 @@ main :: proc() {
border := bool(lua.toboolean(L, 4)); border := bool(lua.toboolean(L, 4));
axis := ui.Axis(lua.L_checkinteger(L, 5)); axis := ui.Axis(lua.L_checkinteger(L, 5));
// TODO: check the other variants for extra data semantic_width := get_lua_semantic_size(L, 6);
semantic_width := ui.SemanticSizeKind(lua.L_checkinteger(L, 6)); semantic_height := get_lua_semantic_size(L, 7);
semantic_height := ui.SemanticSizeKind(lua.L_checkinteger(L, 7));
box := ui.push_rect(ui_ctx, string(label), background, border, axis, { {semantic_width, 0}, {semantic_height,0} }); box := ui.push_rect(ui_ctx, strings.clone(string(label)), background, border, axis, { semantic_width, semantic_height });
lua.pushlightuserdata(L, box); lua.pushlightuserdata(L, box);
return 1; return 1;
} }
@ -1272,6 +1405,57 @@ main :: proc() {
return i32(lua.ERRRUN); return i32(lua.ERRRUN);
} }
}, },
lua.L_Reg {
"push_centered",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA));
lua.pushvalue(L, 1);
ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1);
if ui_ctx != nil {
label := lua.L_checkstring(L, 2);
background := bool(lua.toboolean(L, 3));
border := bool(lua.toboolean(L, 4));
axis := ui.Axis(lua.L_checkinteger(L, 5));
semantic_width := get_lua_semantic_size(L, 6);
semantic_height := get_lua_semantic_size(L, 7);
box := ui.push_centered(ui_ctx, strings.clone(string(label)), {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, { semantic_width, semantic_height });
lua.pushlightuserdata(L, box);
return 1;
}
return i32(lua.ERRRUN);
}
},
lua.L_Reg {
"spacer",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA));
lua.pushvalue(L, 1);
ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1);
if ui_ctx != nil {
label := lua.L_checkstring(L, 2);
interaction := ui.spacer(ui_ctx, strings.clone(string(label)), semantic_size = {{.Exact, 8}, {.Fill, 0}});
lua.newtable(L);
{
lua.pushboolean(L, b32(interaction.clicked));
lua.setfield(L, -2, "clicked");
}
return 1;
}
return i32(lua.ERRRUN);
}
},
lua.L_Reg { lua.L_Reg {
"button", "button",
proc "c" (L: ^lua.State) -> i32 { proc "c" (L: ^lua.State) -> i32 {
@ -1283,7 +1467,7 @@ main :: proc() {
if ui_ctx != nil { if ui_ctx != nil {
label := lua.L_checkstring(L, 2); label := lua.L_checkstring(L, 2);
interaction := ui.button(ui_ctx, string(label)); interaction := ui.button(ui_ctx, strings.clone(string(label)));
lua.newtable(L); lua.newtable(L);
{ {
@ -1297,6 +1481,60 @@ main :: proc() {
return i32(lua.ERRRUN); return i32(lua.ERRRUN);
} }
}, },
lua.L_Reg {
"advanced_button",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA));
lua.pushvalue(L, 1);
ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1);
if ui_ctx != nil {
label := lua.L_checkstring(L, 2);
flags, err := lua_ui_flags(L, 3);
semantic_width := get_lua_semantic_size(L, 4);
semantic_height := get_lua_semantic_size(L, 5);
interaction := ui.advanced_button(ui_ctx, strings.clone(string(label)), flags, { semantic_width, semantic_height });
lua.newtable(L);
{
lua.pushboolean(L, b32(interaction.clicked));
lua.setfield(L, -2, "clicked");
}
return 1;
}
return i32(lua.ERRRUN);
}
},
lua.L_Reg {
"buffer",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
lua.L_checktype(L, 1, i32(lua.TLIGHTUSERDATA));
lua.pushvalue(L, 1);
ui_ctx := transmute(^ui.Context)lua.touserdata(L, -1);
if ui_ctx != nil {
buffer_index := int(lua.L_checkinteger(L, 2));
if buffer_index < 0 || buffer_index >= len(state.buffers) {
return i32(lua.ERRRUN);
}
ui_file_buffer(ui_ctx, &state.buffers[buffer_index]);
return i32(lua.OK);
}
return i32(lua.ERRRUN);
}
}
}; };
lua.newtable(L); lua.newtable(L);
@ -1339,6 +1577,10 @@ main :: proc() {
lua.setfield(L, -2, "Vertical"); lua.setfield(L, -2, "Vertical");
lua.pushinteger(L, lua.Integer(ui.SemanticSizeKind.Fill)); lua.pushinteger(L, lua.Integer(ui.SemanticSizeKind.Fill));
lua.setfield(L, -2, "Fill"); lua.setfield(L, -2, "Fill");
lua.pushinteger(L, lua.Integer(ui.SemanticSizeKind.ChildrenSum));
lua.setfield(L, -2, "ChildrenSum");
lua.pushinteger(L, lua.Integer(ui.SemanticSizeKind.FitText));
lua.setfield(L, -2, "FitText");
lua.L_setfuncs(L, raw_data(&ui_lib), 0); lua.L_setfuncs(L, raw_data(&ui_lib), 0);
lua.setglobal(L, "UI"); lua.setglobal(L, "UI");
@ -1369,7 +1611,7 @@ main :: proc() {
control_key_pressed: bool; control_key_pressed: bool;
for !state.should_close { for !state.should_close {
{ if true {
buffer := &state.buffers[state.current_buffer]; buffer := &state.buffers[state.current_buffer];
ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill, 100), ui.make_semantic_size(.Fill, 100)})); ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill, 100), ui.make_semantic_size(.Fill, 100)}));
@ -1479,10 +1721,6 @@ main :: proc() {
} }
} }
if state.window != nil && state.window.draw != nil {
state.window.draw(state.plugin_vtable, state.window.user_data);
}
for hook_ref in state.lua_hooks[plugin.Hook.Draw] { for hook_ref in state.lua_hooks[plugin.Hook.Draw] {
lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(hook_ref)); lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(hook_ref));
lua.pushlightuserdata(state.L, &ui_context); lua.pushlightuserdata(state.L, &ui_context);
@ -1496,6 +1734,10 @@ main :: proc() {
} }
} }
if state.window != nil && state.window.draw != nil {
state.window.draw(state.plugin_vtable, state.window.user_data);
}
{ {
ui_context.last_mouse_left_down = ui_context.mouse_left_down; ui_context.last_mouse_left_down = ui_context.mouse_left_down;
ui_context.last_mouse_right_down = ui_context.mouse_right_down; ui_context.last_mouse_right_down = ui_context.mouse_right_down;

View File

@ -49,6 +49,7 @@ Flag :: enum {
DrawText, DrawText,
DrawBorder, DrawBorder,
DrawBackground, DrawBackground,
RoundedBorder,
Floating, Floating,
CustomDrawFunc, CustomDrawFunc,
} }
@ -689,6 +690,30 @@ push_rect :: proc(ctx: ^Context, label: string, background: bool = true, border:
return push_box(ctx, label, {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, semantic_size = semantic_size); return push_box(ctx, label, {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, semantic_size = semantic_size);
} }
push_centered :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText) -> ^Box {
box: ^Box;
push_parent(ctx, push_box(ctx, label, {}, semantic_size = Fill))
{
defer pop_parent(ctx);
spacer(ctx, "left spacer");
halfway_centered := push_rect(ctx, "halfway centered", false, false, .Vertical, { semantic_size.x, {.Fill,0} });
push_parent(ctx, halfway_centered);
{
defer pop_parent(ctx);
spacer(ctx, "top spacer");
box = push_box(ctx, label, flags, axis, { {.Fill,0}, semantic_size.y });
spacer(ctx, "bottom spacer");
}
spacer(ctx, "right spacer");
}
return box;
}
label :: proc(ctx: ^Context, label: string) -> Interaction { label :: proc(ctx: ^Context, label: string) -> Interaction {
box := push_box(ctx, label, {.DrawText}); box := push_box(ctx, label, {.DrawText});
@ -696,13 +721,17 @@ label :: proc(ctx: ^Context, label: string) -> Interaction {
} }
button :: proc(ctx: ^Context, label: string) -> Interaction { button :: proc(ctx: ^Context, label: string) -> Interaction {
box := push_box(ctx, label, {.Clickable, .Hoverable, .DrawText, .DrawBorder, .DrawBackground}); return advanced_button(ctx, label);
}
advanced_button :: proc(ctx: ^Context, label: string, flags: bit_set[Flag] = {.Clickable, .Hoverable, .DrawText, .DrawBorder, .DrawBackground}, semantic_size: [2]SemanticSize = FitText) -> Interaction {
box := push_box(ctx, label, flags, semantic_size = semantic_size);
return test_box(ctx, box); return test_box(ctx, box);
} }
custom :: proc(ctx: ^Context, label: string, draw_func: CustomDrawFunc, user_data: rawptr) -> Interaction { custom :: proc(ctx: ^Context, label: string, draw_func: CustomDrawFunc, user_data: rawptr) -> Interaction {
box := push_box(ctx, label, {.DrawBorder, .CustomDrawFunc}, semantic_size = { make_semantic_size(.Fill), make_semantic_size(.Fill) }); box := push_box(ctx, label, {.CustomDrawFunc}, semantic_size = { make_semantic_size(.Fill), make_semantic_size(.Fill) });
box.custom_draw_func = draw_func; box.custom_draw_func = draw_func;
box.user_data = user_data; box.user_data = user_data;