port UI layout to lua + fun animations + fix memory leaks + add dragging support

rust-rewrite
Patrick Cleavelin 2024-02-09 16:33:38 -06:00
parent b105eb67cc
commit f602c3a493
10 changed files with 435 additions and 801 deletions

View File

@ -1,10 +1,8 @@
all: editor all: editor
editor: src/*.odin grep odin_highlighter buffer_search editor: src/*.odin grep odin_highlighter
odin build src/ -out:bin/editor -lld odin build src/ -out:bin/editor -lld
buffer_search:
odin build plugins/buffer_search/ -build-mode:dll -no-entry-point -out:bin/buffer_search
odin_highlighter: odin_highlighter:
odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter

View File

@ -1,234 +0,0 @@
// A simple window to view/search open buffers
package buffer_search;
import "core:runtime"
import "core:fmt"
import "core:path/filepath"
import p "../../src/plugin"
import "../../src/theme"
Plugin :: p.Plugin;
Iterator :: p.Iterator;
BufferIter :: p.BufferIter;
BufferIndex :: p.BufferIndex;
Key :: p.Key;
BufferListWindow :: struct {
selected_index: int,
}
@export
OnInitialize :: proc "c" (plugin: Plugin) {
context = runtime.default_context();
fmt.println("builtin buffer search plugin initialized!");
plugin.register_input_group(nil, .SPACE, proc "c" (plugin: Plugin, input_map: rawptr) {
plugin.register_input(input_map, .B, open_buffer_window, "show list of open buffers");
});
}
@export
OnExit :: proc "c" (plugin: Plugin) {
context = runtime.default_context();
}
open_buffer_window :: proc "c" (plugin: Plugin) {
context = runtime.default_context();
window := new(BufferListWindow);
window^ = BufferListWindow {};
plugin.create_window(window, proc "c" (plugin: Plugin, input_map: rawptr) {
plugin.register_input(input_map, .K, proc "c" (plugin: Plugin) {
context = runtime.default_context();
win := cast(^BufferListWindow)plugin.get_window();
if win != nil {
if win.selected_index > 0 {
win.selected_index -= 1;
} else {
win.selected_index = plugin.buffer.get_num_buffers()-1;
}
}
}, "move selection up");
plugin.register_input(input_map, .J, proc "c" (plugin: Plugin) {
context = runtime.default_context();
win := cast(^BufferListWindow)plugin.get_window();
if win != nil {
if win.selected_index < plugin.buffer.get_num_buffers()-1 {
win.selected_index += 1;
} else {
win.selected_index = 0;
}
}
}, "move selection down");
plugin.register_input(input_map, .ENTER, proc "c" (plugin: Plugin) {
context = runtime.default_context();
win := cast(^BufferListWindow)plugin.get_window();
if win != nil {
plugin.buffer.set_current_buffer(win.selected_index);
}
plugin.request_window_close();
}, "switch to buffer")
}, draw_buffer_window, free_buffer_window, nil);
}
free_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) {
context = runtime.default_context();
win := cast(^BufferListWindow)plugin.get_window();
if win == nil {
return;
}
free(win);
}
buffer_list_iter :: proc(plugin: Plugin, buffer_index: ^int) -> (int, int, bool) {
if buffer_index^ == -1 {
return 0, 0, false;
}
index := plugin.iter.get_buffer_list_iter(buffer_index);
return index, 0, true;
}
draw_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) {
context = runtime.default_context();
runtime.free_all(context.temp_allocator);
win := cast(^BufferListWindow)win;
if win == nil {
return;
}
screen_width := plugin.get_screen_width();
screen_height := plugin.get_screen_height();
directory := string(plugin.get_current_directory());
canvas := plugin.ui.floating(plugin.ui.ui_context, "buffer search canvas", {0,0});
plugin.ui.push_parent(plugin.ui.ui_context, canvas);
{
defer plugin.ui.pop_parent(plugin.ui.ui_context);
plugin.ui.spacer(plugin.ui.ui_context, "left spacer");
centered_container := plugin.ui.rect(plugin.ui.ui_context, "centered container", false, false, .Vertical, {{4, 75}, {3, 0}});
plugin.ui.push_parent(plugin.ui.ui_context, centered_container);
{
defer plugin.ui.pop_parent(plugin.ui.ui_context);
plugin.ui.spacer(plugin.ui.ui_context, "top spacer");
ui_window := plugin.ui.rect(plugin.ui.ui_context, "buffer search window", true, true, .Horizontal, {{3, 0}, {4, 75}});
plugin.ui.push_parent(plugin.ui.ui_context, ui_window);
{
defer plugin.ui.pop_parent(plugin.ui.ui_context);
buffer_list_view := plugin.ui.rect(plugin.ui.ui_context, "buffer list view", false, false, .Vertical, {{4, 60}, {3, 0}});
plugin.ui.push_parent(plugin.ui.ui_context, buffer_list_view);
{
defer plugin.ui.pop_parent(plugin.ui.ui_context);
_buffer_index := 0;
for index in buffer_list_iter(plugin, &_buffer_index) {
buffer := plugin.buffer.get_buffer_info_from_index(index);
relative_file_path, _ := filepath.rel(directory, string(buffer.file_path), context.temp_allocator)
text := fmt.ctprintf("%s:%d", relative_file_path, buffer.cursor.line+1);
if index == win.selected_index {
plugin.ui.button(plugin.ui.ui_context, text);
} else {
plugin.ui.label(plugin.ui.ui_context, text);
}
}
}
buffer_preview := plugin.ui.rect(plugin.ui.ui_context, "buffer preview", true, false, .Horizontal, {{3, 0}, {3, 0}});
plugin.ui.push_parent(plugin.ui.ui_context, buffer_preview);
{
defer plugin.ui.pop_parent(plugin.ui.ui_context);
plugin.ui.buffer_from_index(plugin.ui.ui_context, win.selected_index, false);
}
}
plugin.ui.spacer(plugin.ui.ui_context, "bottom spacer");
}
plugin.ui.spacer(plugin.ui.ui_context, "right spacer");
}
/*
screen_width := plugin.get_screen_width();
screen_height := plugin.get_screen_height();
source_font_width := plugin.get_font_width();
source_font_height := plugin.get_font_height();
win_rec := [4]f32 {
f32(screen_width/8),
f32(screen_height/8),
f32(screen_width - screen_width/4),
f32(screen_height - screen_height/4),
};
plugin.draw_rect(
i32(win_rec.x),
i32(win_rec.y),
i32(win_rec.z),
i32(win_rec.w),
.Background4
);
win_margin := [2]f32 { f32(source_font_width), f32(source_font_height) };
buffer_prev_width := (win_rec.z - win_margin.x*2) / 2;
buffer_prev_height := win_rec.w - win_margin.y*2;
glyph_buffer_width := int(buffer_prev_width) / source_font_width - 1;
glyph_buffer_height := int(buffer_prev_height) / source_font_height;
directory := string(plugin.get_current_directory());
plugin.draw_rect(
i32(win_rec.x + win_rec.z / 2),
i32(win_rec.y + win_margin.y),
i32(buffer_prev_width),
i32(buffer_prev_height),
.Background2,
);
_buffer_index := 0;
for index in buffer_list_iter(plugin, &_buffer_index) {
buffer := plugin.buffer.get_buffer_info_from_index(index);
relative_file_path, _ := filepath.rel(directory, string(buffer.file_path), context.temp_allocator)
text := fmt.ctprintf("%s:%d", relative_file_path, buffer.cursor.line+1);
text_width := len(text) * source_font_width;
if index == win.selected_index {
plugin.draw_buffer_from_index(
index,
int(win_rec.x + win_margin.x + win_rec.z / 2),
int(win_rec.y + win_margin.y),
glyph_buffer_width,
glyph_buffer_height,
false);
plugin.draw_rect(
i32(win_rec.x + win_margin.x),
i32(win_rec.y + win_margin.y) + i32(index * source_font_height),
i32(text_width),
i32(source_font_height),
.Background2,
);
}
plugin.draw_text(
text,
win_rec.x + win_margin.x, win_rec.y + win_margin.y + f32(index * source_font_height),
.Foreground2
);
runtime.free_all(context.temp_allocator);
}
*/
}

View File

@ -1,65 +0,0 @@
local WindowOpen = true
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)
if WindowOpen then
current_buffer_index = Editor.get_current_buffer_index()
tabs = UI.push_rect(ctx, "tabs", false, true, UI.Vertical, UI.ChildrenSum, UI.Fill)
UI.push_parent(ctx, tabs)
for buffer_info, i in buffer_list_iter() do
button_container = UI.push_rect(ctx, "button container"..i, false, false, UI.Horizontal, UI.ChildrenSum, UI.ChildrenSum)
UI.push_parent(ctx, button_container)
flags = {"Clickable", "Hoverable", "DrawText", "DrawBackground"}
if i ~= current_buffer_index then
table.insert(flags, 1, "DrawBorder")
end
if UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.PercentOfParent(25), UI.FitText).clicked then
Editor.set_current_buffer_from_index(i)
end
if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then
print("hahah, you can't close buffers yet silly")
end
UI.pop_parent(ctx)
end
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
function handle_buffer_input()
print("you inputted into a buffer")
end
function OnInit()
print("Test lua plugin initialized")
Editor.register_key_group({
{Editor.Key.T, "Open Test UI", (
function ()
WindowOpen = not WindowOpen
end
)},
})
Editor.register_hook(Editor.Hook.OnDraw, render_ui_window)
Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input)
end

160
plugins/lua/view.lua Normal file
View File

@ -0,0 +1,160 @@
local BufferSearchOpen = false
local BufferSearchOpenElapsed = 0
local CurrentPreviewBufferIndex = Editor.get_current_buffer_index()
local BufferSearchIndex = 0
local SideBarWidth = 128
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 centered(ctx, label, axis, width, height, body)
UI.push_parent(ctx, UI.push_rect(ctx, label, false, false, UI.Horizontal, UI.Fill, UI.Fill))
UI.spacer(ctx, "left spacer")
UI.push_parent(ctx, UI.push_rect(ctx, "halfway centered", false, false, UI.Vertical, width, UI.Fill))
UI.spacer(ctx, "top spacer")
UI.push_parent(ctx, UI.push_rect(ctx, "centered container", false, false, axis, UI.Fill, height))
body()
UI.pop_parent(ctx)
UI.spacer(ctx, "bottom spacer")
UI.pop_parent(ctx)
UI.spacer(ctx, "right spacer")
UI.pop_parent(ctx)
end
function render_ui_window(ctx)
current_buffer_index = Editor.get_current_buffer_index()
numFrames = 7
CurrentPreviewBufferIndex = current_buffer_index
tabs = UI.push_rect(ctx, "tabs", false, false, UI.Vertical, UI.Exact(SideBarWidth), UI.Fill)
UI.push_parent(ctx, tabs)
UI.push_rect(ctx, "padded top open files", false, false, UI.Horizontal, UI.Fill, UI.Exact(8))
UI.push_parent(ctx, UI.push_rect(ctx, "padded open files", false, false, UI.Horizontal, UI.Fill, UI.ChildrenSum))
UI.push_rect(ctx, "padded top open files", false, false, UI.Horizontal, UI.Exact(8), UI.Fill)
UI.label(ctx, "Open Files")
UI.pop_parent(ctx)
UI.push_rect(ctx, "padded bottom open files", false, false, UI.Horizontal, UI.Fill, UI.Exact(8))
for buffer_info, i in buffer_list_iter() do
button_container = UI.push_rect(ctx, "button container"..i, false, false, UI.Horizontal, UI.Fill, UI.ChildrenSum)
UI.push_parent(ctx, button_container)
flags = {"Clickable", "Hoverable", "DrawText"}
if i == current_buffer_index then
table.insert(flags, 1, "DrawBackground")
end
if UI.advanced_button(ctx, " x ", flags, UI.FitText, UI.FitText).clicked then
print("hahah, you can't close buffers yet silly")
end
tab_button_interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText)
if tab_button_interaction.clicked then
Editor.set_current_buffer_from_index(i)
end
if tab_button_interaction.hovering then
CurrentPreviewBufferIndex = i
end
UI.pop_parent(ctx)
end
UI.spacer(ctx, "below tabs spacer")
UI.pop_parent(ctx)
if UI.advanced_button(ctx, "side bar grab handle", {"DrawBorder", "Hoverable"}, UI.Exact(16), UI.Fill).dragging then
x,y = UI.get_mouse_pos(ctx)
SideBarWidth = x-8
-- TODO: use some math.max function
if SideBarWidth < 128 then
SideBarWidth = 128
end
end
UI.buffer(ctx, CurrentPreviewBufferIndex)
render_buffer_search(ctx)
end
function render_buffer_search(ctx)
if BufferSearchOpen or BufferSearchOpenElapsed > 0 then
if BufferSearchOpen and BufferSearchOpenElapsed < numFrames then
BufferSearchOpenElapsed = BufferSearchOpenElapsed + 1
elseif not BufferSearchOpen and BufferSearchOpenElapsed > 0 then
BufferSearchOpenElapsed = BufferSearchOpenElapsed - 1
end
end
if BufferSearchOpen or BufferSearchOpenElapsed > 0 then
window_percent = 75
if BufferSearchOpenElapsed > 0 then
window_percent = ((BufferSearchOpenElapsed/numFrames) * 75)
end
UI.push_parent(ctx, UI.push_floating(ctx, "buffer search canvas", 0, 0))
centered(ctx, "buffer search window", UI.Horizontal, UI.PercentOfParent(window_percent), UI.PercentOfParent(window_percent), (
function ()
UI.push_parent(ctx, UI.push_rect(ctx, "window", true, true, UI.Horizontal, UI.Fill, UI.Fill))
UI.push_parent(ctx, UI.push_rect(ctx, "buffer list", false, false, UI.Vertical, UI.Fill, UI.Fill))
for buffer_info, i in buffer_list_iter() do
flags = {"DrawText"}
if i == BufferSearchIndex then
table.insert(flags, 1, "DrawBorder")
end
interaction = UI.advanced_button(ctx, " "..buffer_info.file_path.." ", flags, UI.Fill, UI.FitText)
end
UI.pop_parent(ctx)
UI.buffer(ctx, BufferSearchIndex)
UI.pop_parent(ctx)
end
))
UI.pop_parent(ctx)
end
end
function handle_buffer_input()
-- print("you inputted into a buffer")
end
function OnInit()
print("Main View plugin initialized")
Editor.register_key_group({
{Editor.Key.Space, "", {
{Editor.Key.B, "Buffer Search", (
function ()
BufferSearchOpen = true
BufferSearchIndex = 0
end
),
{
{Editor.Key.Escape, "Close Window", (
function ()
Editor.request_window_close()
BufferSearchOpen = false
end
)},
{Editor.Key.Enter, "Switch to Buffer", (
function ()
Editor.set_current_buffer_from_index(BufferSearchIndex)
Editor.request_window_close()
BufferSearchOpen = false
end
)},
-- TODO: don't scroll past buffers
{Editor.Key.K, "Move Selection Up", (function () BufferSearchIndex = BufferSearchIndex - 1 end)},
{Editor.Key.J, "Move Selection Down", (function () BufferSearchIndex = BufferSearchIndex + 1 end)},
}}
}}
})
Editor.register_hook(Editor.Hook.OnDraw, render_ui_window)
Editor.register_hook(Editor.Hook.OnBufferInput, handle_buffer_input)
end

View File

@ -37,8 +37,9 @@ close_window_and_free :: proc(state: ^State) {
free(state.window); free(state.window);
state.window = nil; state.window = nil;
state.current_input_map = &state.input_map;
} }
state.current_input_map = &state.input_map;
} }
LuaHookRef :: i32; LuaHookRef :: i32;
@ -92,7 +93,11 @@ add_lua_hook :: proc(state: ^State, hook: plugin.Hook, hook_ref: LuaHookRef) {
runtime.append(&state.lua_hooks[hook], hook_ref); runtime.append(&state.lua_hooks[hook], hook_ref);
} }
LuaEditorAction :: i32;
LuaEditorAction :: struct {
fn_ref: i32,
maybe_input_map: InputMap,
};
PluginEditorAction :: proc "c" (plugin: plugin.Plugin); PluginEditorAction :: proc "c" (plugin: plugin.Plugin);
EditorAction :: proc(state: ^State); EditorAction :: proc(state: ^State);
InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputMap} InputGroup :: union {LuaEditorAction, PluginEditorAction, EditorAction, InputMap}

View File

@ -771,10 +771,8 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho
// draw cursor // draw cursor
if state.mode == .Normal { if state.mode == .Normal {
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4); draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Background4);
//raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), i32(state.source_font_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Background4));
} else if state.mode == .Insert { } else if state.mode == .Insert {
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green); draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Green);
// raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), i32(state.source_font_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Green));
num_line_break := 0; num_line_break := 0;
line_length := 0; line_length := 0;
@ -795,7 +793,6 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho
} }
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Blue); draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Blue);
//raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), i32(state.source_font_width), i32(state.source_font_height), theme.get_palette_raylib_color(.Blue));
} }
for j in 0..<buffer.glyph_buffer_height { for j in 0..<buffer.glyph_buffer_height {
@ -803,7 +800,6 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho
if show_line_numbers { if show_line_numbers {
draw_text(state, fmt.tprintf("%d", begin + j + 1), x, text_y); draw_text(state, fmt.tprintf("%d", begin + j + 1), x, text_y);
//raylib.DrawTextEx(font, raylib.TextFormat("%d", begin + j + 1), raylib.Vector2 { f32(x), f32(text_y) }, f32(state.source_font_height), 0, theme.get_palette_raylib_color(.Background4));
} }
for i in 0..<buffer.glyph_buffer_width { for i in 0..<buffer.glyph_buffer_width {
@ -813,7 +809,6 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho
if glyph.codepoint == 0 { break; } if glyph.codepoint == 0 { break; }
draw_codepoint(state, rune(glyph.codepoint), text_x, text_y, glyph.color); draw_codepoint(state, rune(glyph.codepoint), text_x, text_y, glyph.color);
//raylib.DrawTextCodepoint(font, rune(glyph.codepoint), raylib.Vector2 { f32(text_x), f32(text_y) }, f32(state.source_font_height), theme.get_palette_raylib_color(glyph.color));
} }
} }
} }

View File

@ -64,7 +64,7 @@ do_normal_mode :: proc(state: ^State, buffer: ^FileBuffer) {
// TODO: use buffer list in state // TODO: use buffer list in state
do_insert_mode :: proc(state: ^State, buffer: ^FileBuffer) { do_insert_mode :: proc(state: ^State, buffer: ^FileBuffer) {
key := 0; // raylib.GetCharPressed(); key := 0;
for key > 0 { for key > 0 {
if key >= 32 && key <= 125 && len(buffer.input_buffer) < 1024-1 { if key >= 32 && key <= 125 && len(buffer.input_buffer) < 1024-1 {
@ -75,39 +75,10 @@ do_insert_mode :: proc(state: ^State, buffer: ^FileBuffer) {
} }
} }
key = 0; // raylib.GetCharPressed(); key = 0;
} }
// if raylib.IsKeyPressed(.ENTER) {
// append(&buffer.input_buffer, '\n');
// }
// if raylib.IsKeyPressed(.ESCAPE) {
// state.mode = .Normal;
// core.insert_content(buffer, buffer.input_buffer[:]);
// runtime.clear(&buffer.input_buffer);
// return;
// }
// if raylib.IsKeyPressed(.BACKSPACE) {
// core.delete_content(buffer, 1);
// for hook_proc in state.hooks[plugin.Hook.BufferInput] {
// hook_proc(state.plugin_vtable, buffer);
// }
// }
} }
// switch_to_buffer :: proc(state: ^State, item: ^ui.MenuBarItem) {
// for buffer, index in state.buffers {
// if strings.compare(buffer.file_path, item.text) == 0 {
// state.current_buffer = index;
// break;
// }
// }
// }
register_default_leader_actions :: proc(input_map: ^core.InputMap) { register_default_leader_actions :: proc(input_map: ^core.InputMap) {
core.register_key_action(input_map, .Q, proc(state: ^State) { core.register_key_action(input_map, .Q, proc(state: ^State) {
state.current_input_map = &state.input_map; state.current_input_map = &state.input_map;
@ -163,26 +134,19 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) {
// Scale font size // Scale font size
{ {
core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State) { core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State) {
fmt.print("You pressed <C>-MINUS", state.source_font_height, " ");
if state.source_font_height > 16 { if state.source_font_height > 16 {
state.source_font_height -= 2; state.source_font_height -= 2;
state.source_font_width = state.source_font_height / 2; state.source_font_width = state.source_font_height / 2;
state.font_atlas = core.gen_font_atlas(state, "/System/Library/Fonts/Supplemental/Andale Mono.ttf"); state.font_atlas = core.gen_font_atlas(state, "/System/Library/Fonts/Supplemental/Andale Mono.ttf");
//state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0);
//raylib.SetTextureFilter(state.font.texture, .BILINEAR);
} }
fmt.println(state.source_font_height); fmt.println(state.source_font_height);
}, "increase font size"); }, "increase font size");
core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State) { core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State) {
fmt.println("You pressed <C>-EQUAL");
state.source_font_height += 2; state.source_font_height += 2;
state.source_font_width = state.source_font_height / 2; state.source_font_width = state.source_font_height / 2;
state.font_atlas = core.gen_font_atlas(state, "/System/Library/Fonts/Supplemental/Andale Mono.ttf"); state.font_atlas = core.gen_font_atlas(state, "/System/Library/Fonts/Supplemental/Andale Mono.ttf");
//state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0);
//raylib.SetTextureFilter(state.font.texture, .BILINEAR);
}, "decrease font size"); }, "decrease font size");
} }
@ -482,21 +446,11 @@ init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin {
context = state.ctx; context = state.ctx;
core.draw_rect(&state, int(x), int(y), int(width), int(height), color); core.draw_rect(&state, int(x), int(y), int(width), int(height), color);
//raylib.DrawRectangle(x, y, width, height, theme.get_palette_raylib_color(color));
}, },
draw_text = proc "c" (text: cstring, x: f32, y: f32, color: theme.PaletteColor) { draw_text = proc "c" (text: cstring, x: f32, y: f32, color: theme.PaletteColor) {
context = state.ctx; context = state.ctx;
core.draw_text(&state, string(text), int(x), int(y), color); core.draw_text(&state, string(text), int(x), int(y), color);
// for codepoint, index in text {
// raylib.DrawTextCodepoint(
// state.font,
// rune(codepoint),
// raylib.Vector2 { x + f32(index * state.source_font_width), y },
// f32(state.source_font_height),
// theme.get_palette_raylib_color(color)
// );
// }
}, },
draw_buffer_from_index = proc "c" (buffer_index: int, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool) { draw_buffer_from_index = proc "c" (buffer_index: int, x: int, y: int, glyph_buffer_width: int, glyph_buffer_height: int, show_line_numbers: bool) {
context = state.ctx; context = state.ctx;
@ -1103,24 +1057,6 @@ main :: proc() {
return i32(lua.OK); return i32(lua.OK);
} }
}, },
lua.L_Reg {
"register_key_action",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
key := lua.L_checkinteger(L, 1);
lua.L_checktype(L, 2, i32(lua.TFUNCTION));
lua.pushvalue(L, 2);
fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX));
desc := strings.clone(string(lua.L_checkstring(L, 3)));
core.register_key_action_group(&state.input_map, plugin.Key(key), fn_ref, desc);
return i32(lua.OK);
}
},
lua.L_Reg { lua.L_Reg {
"register_key_group", "register_key_group",
proc "c" (L: ^lua.State) -> i32 { proc "c" (L: ^lua.State) -> i32 {
@ -1167,7 +1103,15 @@ main :: proc() {
case i32(lua.TFUNCTION): case i32(lua.TFUNCTION):
fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX)); fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX));
core.register_key_action_group(input_map, key, fn_ref, desc);
if lua.rawgeti(L, -1, 4) == i32(lua.TTABLE) {
maybe_input_map := core.new_input_map();
table_to_action(L, lua.gettop(L), &maybe_input_map);
core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, maybe_input_map }, desc);
} else {
core.register_key_action_group(input_map, key, core.LuaEditorAction { fn_ref, core.InputMap {} }, desc);
}
case: case:
lua.pop(L, 1); lua.pop(L, 1);
@ -1177,32 +1121,15 @@ main :: proc() {
table_to_action(L, 1, state.current_input_map); table_to_action(L, 1, state.current_input_map);
return i32(lua.OK);
}
},
lua.L_Reg {
"request_window_close",
proc "c" (L: ^lua.State) -> i32 {
context = state.ctx;
// key := plugin.Key(lua.L_checkinteger(L, 1)); core.request_window_close(&state);
// lua.L_checktype(L, 2, i32(lua.TFUNCTION));
// lua.pushvalue(L, 2);
// fn_ref := lua.L_ref(L, i32(lua.REGISTRYINDEX));
// desc := strings.clone(string(lua.L_checkstring(L, 3)));
// fmt.println("LUA: attempting to register:", key, "ref", fn_ref);
// if action, exists := state.current_input_map.key_actions[key]; exists {
// switch value in action.action {
// case core.LuaEditorAction:
// fmt.eprintln("Plugin attempted to register input group on existing key action (added from Lua)");
// case core.PluginEditorAction:
// fmt.eprintln("Plugin attempted to register input group on existing key action (added from Plugin)");
// case core.EditorAction:
// fmt.eprintln("Plugin attempted to register input group on existing key action");
// case core.InputMap:
// input_map := &(&state.current_input_map.key_actions[key]).action.(core.InputMap);
// core.register_key_action_group(input_map, key, fn_ref, desc);
// }
// } else {
// core.register_key_action(state.current_input_map, key, core.new_input_map(), desc);
// }
return i32(lua.OK); return i32(lua.OK);
} }
@ -1303,13 +1230,43 @@ main :: proc() {
} }
} }
push_lua_box_interaction :: proc(L: ^lua.State, interaction: ui.Interaction) {
lua.newtable(L);
{
lua.pushboolean(L, b32(interaction.clicked));
lua.setfield(L, -2, "clicked");
lua.pushboolean(L, b32(interaction.hovering));
lua.setfield(L, -2, "hovering");
lua.pushboolean(L, b32(interaction.dragging));
lua.setfield(L, -2, "dragging");
}
}
ui_lib := [?]lua.L_Reg { ui_lib := [?]lua.L_Reg {
lua.L_Reg {
"get_mouse_pos",
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 { return i32(lua.ERRRUN); }
lua.pushinteger(L, lua.Integer(ui_ctx.mouse_x));
lua.pushinteger(L, lua.Integer(ui_ctx.mouse_y));
return 2;
}
},
lua.L_Reg { lua.L_Reg {
"Exact", "Exact",
proc "c" (L: ^lua.State) -> i32 { proc "c" (L: ^lua.State) -> i32 {
context = state.ctx; context = state.ctx;
value := lua.L_checkinteger(L, 1); value := lua.L_checknumber(L, 1);
push_lua_semantic_size_table(L, { ui.SemanticSizeKind.Exact, int(value) }); push_lua_semantic_size_table(L, { ui.SemanticSizeKind.Exact, int(value) });
return 1; return 1;
@ -1320,7 +1277,7 @@ main :: proc() {
proc "c" (L: ^lua.State) -> i32 { proc "c" (L: ^lua.State) -> i32 {
context = state.ctx; context = state.ctx;
value := lua.L_checkinteger(L, 1); value := lua.L_checknumber(L, 1);
push_lua_semantic_size_table(L, { ui.SemanticSizeKind.PercentOfParent, int(value) }); push_lua_semantic_size_table(L, { ui.SemanticSizeKind.PercentOfParent, int(value) });
return 1; return 1;
@ -1372,7 +1329,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, strings.clone(string(label)), {x,y}); box := ui.push_floating(ui_ctx, strings.clone(string(label), context.temp_allocator), {x,y});
lua.pushlightuserdata(L, box); lua.pushlightuserdata(L, box);
return 1; return 1;
} }
@ -1397,7 +1354,7 @@ main :: proc() {
semantic_width := get_lua_semantic_size(L, 6); semantic_width := get_lua_semantic_size(L, 6);
semantic_height := get_lua_semantic_size(L, 7); semantic_height := get_lua_semantic_size(L, 7);
box := ui.push_rect(ui_ctx, strings.clone(string(label)), background, border, axis, { semantic_width, semantic_height }); box := ui.push_rect(ui_ctx, strings.clone(string(label), context.temp_allocator), background, border, axis, { semantic_width, semantic_height });
lua.pushlightuserdata(L, box); lua.pushlightuserdata(L, box);
return 1; return 1;
} }
@ -1423,7 +1380,7 @@ main :: proc() {
semantic_width := get_lua_semantic_size(L, 6); semantic_width := get_lua_semantic_size(L, 6);
semantic_height := get_lua_semantic_size(L, 7); 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 }); box := ui.push_centered(ui_ctx, strings.clone(string(label), context.temp_allocator), {.DrawBackground if background else nil, .DrawBorder if border else nil}, axis, { semantic_width, semantic_height });
lua.pushlightuserdata(L, box); lua.pushlightuserdata(L, box);
return 1; return 1;
} }
@ -1442,14 +1399,30 @@ main :: proc() {
if ui_ctx != nil { if ui_ctx != nil {
label := lua.L_checkstring(L, 2); label := lua.L_checkstring(L, 2);
interaction := ui.spacer(ui_ctx, strings.clone(string(label)), semantic_size = {{.Exact, 8}, {.Fill, 0}}); interaction := ui.spacer(ui_ctx, strings.clone(string(label), context.temp_allocator), semantic_size = {{.Fill, 0}, {.Fill, 0}});
lua.newtable(L); push_lua_box_interaction(L, interaction)
{
lua.pushboolean(L, b32(interaction.clicked)); return 1;
lua.setfield(L, -2, "clicked");
} }
return i32(lua.ERRRUN);
}
},
lua.L_Reg {
"label",
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.label(ui_ctx, strings.clone(string(label), context.temp_allocator));
push_lua_box_interaction(L, interaction)
return 1; return 1;
} }
@ -1467,13 +1440,8 @@ 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, strings.clone(string(label))); interaction := ui.button(ui_ctx, strings.clone(string(label), context.temp_allocator));
push_lua_box_interaction(L, interaction)
lua.newtable(L);
{
lua.pushboolean(L, b32(interaction.clicked));
lua.setfield(L, -2, "clicked");
}
return 1; return 1;
} }
@ -1497,13 +1465,8 @@ main :: proc() {
semantic_width := get_lua_semantic_size(L, 4); semantic_width := get_lua_semantic_size(L, 4);
semantic_height := get_lua_semantic_size(L, 5); semantic_height := get_lua_semantic_size(L, 5);
interaction := ui.advanced_button(ui_ctx, strings.clone(string(label)), flags, { semantic_width, semantic_height }); interaction := ui.advanced_button(ui_ctx, strings.clone(string(label), context.temp_allocator), flags, { semantic_width, semantic_height });
push_lua_box_interaction(L, interaction)
lua.newtable(L);
{
lua.pushboolean(L, b32(interaction.clicked));
lua.setfield(L, -2, "clicked");
}
return 1; return 1;
} }
@ -1540,6 +1503,9 @@ main :: proc() {
lua.newtable(L); lua.newtable(L);
{ {
lua.newtable(L); lua.newtable(L);
lua.pushinteger(L, lua.Integer(plugin.Key.B));
lua.setfield(L, -2, "B");
lua.pushinteger(L, lua.Integer(plugin.Key.T)); lua.pushinteger(L, lua.Integer(plugin.Key.T));
lua.setfield(L, -2, "T"); lua.setfield(L, -2, "T");
@ -1552,6 +1518,21 @@ main :: proc() {
lua.pushinteger(L, lua.Integer(plugin.Key.M)); lua.pushinteger(L, lua.Integer(plugin.Key.M));
lua.setfield(L, -2, "M"); lua.setfield(L, -2, "M");
lua.pushinteger(L, lua.Integer(plugin.Key.K));
lua.setfield(L, -2, "K");
lua.pushinteger(L, lua.Integer(plugin.Key.J));
lua.setfield(L, -2, "J");
lua.pushinteger(L, lua.Integer(plugin.Key.Q));
lua.setfield(L, -2, "Q");
lua.pushinteger(L, lua.Integer(plugin.Key.ESCAPE));
lua.setfield(L, -2, "Escape");
lua.pushinteger(L, lua.Integer(plugin.Key.ENTER));
lua.setfield(L, -2, "Enter");
lua.pushinteger(L, lua.Integer(plugin.Key.SPACE)); lua.pushinteger(L, lua.Integer(plugin.Key.SPACE));
lua.setfield(L, -2, "Space"); lua.setfield(L, -2, "Space");
} }
@ -1586,7 +1567,7 @@ main :: proc() {
lua.setglobal(L, "UI"); lua.setglobal(L, "UI");
} }
if lua.L_dofile(L, "plugins/lua/lib.lua") == i32(lua.OK) { if lua.L_dofile(L, "plugins/lua/view.lua") == i32(lua.OK) {
lua.pop(L, lua.gettop(L)); lua.pop(L, lua.gettop(L));
} else { } else {
err := lua.tostring(L, lua.gettop(L)); err := lua.tostring(L, lua.gettop(L));
@ -1611,115 +1592,110 @@ main :: proc() {
control_key_pressed: bool; control_key_pressed: bool;
for !state.should_close { for !state.should_close {
if true { // if false {
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)}));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
{ // {
ui.push_parent(&ui_context, ui.push_box(&ui_context, "top_nav", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)})); // ui.push_parent(&ui_context, ui.push_box(&ui_context, "top_nav", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)}));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
if ui.label(&ui_context, "Editor").clicked { // if ui.label(&ui_context, "Editor").clicked {
fmt.println("you clicked the button"); // fmt.println("you clicked the button");
} // }
ui.push_box( // ui.push_box(
&ui_context, // &ui_context,
"nav spacer", // "nav spacer",
{.DrawBackground}, // {.DrawBackground},
semantic_size = { // semantic_size = {
ui.make_semantic_size(.Exact, 16), // ui.make_semantic_size(.Exact, 16),
ui.make_semantic_size(.Exact, state.source_font_height) // ui.make_semantic_size(.Exact, state.source_font_height)
} // }
); // );
if ui.label(&ui_context, "Buffers").clicked { // if ui.label(&ui_context, "Buffers").clicked {
fmt.println("you clicked the button"); // fmt.println("you clicked the button");
} // }
} // }
{ // {
ui.push_parent(&ui_context, ui.push_box(&ui_context, "deezbuffer", {}, .Horizontal, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Fill, 0)})); // ui.push_parent(&ui_context, ui.push_box(&ui_context, "deezbuffer", {}, .Horizontal, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Fill, 0)}));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
{ // {
ui.push_parent(&ui_context, ui.push_box(&ui_context, "left side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)})); // ui.push_parent(&ui_context, ui.push_box(&ui_context, "left side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)}));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
{ // {
if ui_file_buffer(&ui_context, &state.buffers[0]).clicked { // if ui_file_buffer(&ui_context, &state.buffers[0]).clicked {
state.current_buffer = 0; // state.current_buffer = 0;
} // }
} // }
{ // {
if ui_file_buffer(&ui_context, &state.buffers[0+1]).clicked { // if ui_file_buffer(&ui_context, &state.buffers[0+1]).clicked {
state.current_buffer = 1; // state.current_buffer = 1;
} // }
} // }
{ // {
if ui_file_buffer(&ui_context, &state.buffers[0+2]).clicked { // if ui_file_buffer(&ui_context, &state.buffers[0+2]).clicked {
state.current_buffer = 2; // state.current_buffer = 2;
} // }
} // }
} // }
{ // {
ui.push_parent(&ui_context, ui.push_box(&ui_context, "right side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)})); // ui.push_parent(&ui_context, ui.push_box(&ui_context, "right side", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill), ui.make_semantic_size(.Fill, 0)}));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
{ // {
if ui_file_buffer(&ui_context, &state.buffers[state.current_buffer]).clicked { // if ui_file_buffer(&ui_context, &state.buffers[state.current_buffer]).clicked {
state.current_buffer = 3; // state.current_buffer = 3;
} // }
} // }
} // }
} // }
{ // {
ui.push_parent(&ui_context, ui.push_box(&ui_context, "bottom stats", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)})); // ui.push_parent(&ui_context, ui.push_box(&ui_context, "bottom stats", {.DrawBackground}, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.Exact, state.source_font_height)}));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
label := ""; // label := "";
if state.mode == .Insert { // if state.mode == .Insert {
label = "INSERT"; // label = "INSERT";
} else if state.mode == .Normal { // } else if state.mode == .Normal {
label = "NORMAL"; // label = "NORMAL";
} // }
if ui.label(&ui_context, label).clicked { // if ui.label(&ui_context, label).clicked {
fmt.println("you clicked the button"); // fmt.println("you clicked the button");
} // }
ui.spacer(&ui_context, "mode spacer", semantic_size = {ui.make_semantic_size(.Exact, 16), ui.make_semantic_size(.Fill)}); // ui.spacer(&ui_context, "mode spacer", semantic_size = {ui.make_semantic_size(.Exact, 16), ui.make_semantic_size(.Fill)});
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.label(&ui_context, relative_file_path); // ui.label(&ui_context, relative_file_path);
ui.spacer(&ui_context, "stats inbetween"); // ui.spacer(&ui_context, "stats inbetween");
{ // {
ui.push_parent(&ui_context, ui.push_box(&ui_context, "center info", {}, semantic_size = ui.ChildrenSum)); // ui.push_parent(&ui_context, ui.push_box(&ui_context, "center info", {}, semantic_size = ui.ChildrenSum));
defer ui.pop_parent(&ui_context); // defer ui.pop_parent(&ui_context);
line_info_text := fmt.tprintf( // line_info_text := fmt.tprintf(
//"Line: %d, Col: %d, Len: %d --- Slice Index: %d, Content Index: %d", // //"Line: %d, Col: %d, Len: %d --- Slice Index: %d, Content Index: %d",
"Line: %d, Col: %d", // "Line: %d, Col: %d",
buffer.cursor.line + 1, // buffer.cursor.line + 1,
buffer.cursor.col + 1, // buffer.cursor.col + 1,
//core.file_buffer_line_length(buffer, buffer.cursor.index), // //core.file_buffer_line_length(buffer, buffer.cursor.index),
// buffer.cursor.index.slice_index, // // buffer.cursor.index.slice_index,
// buffer.cursor.index.content_index, // // buffer.cursor.index.content_index,
); // );
ui.label(&ui_context, line_info_text); // ui.label(&ui_context, line_info_text);
mouse_pos_str := fmt.tprintf("x,y: [%d,%d]", ui_context.mouse_x, ui_context.mouse_y); // mouse_pos_str := fmt.tprintf("x,y: [%d,%d]", ui_context.mouse_x, ui_context.mouse_y);
ui.label(&ui_context, mouse_pos_str); // ui.label(&ui_context, mouse_pos_str);
} // }
// }
//ui.spacer(&ui_context, "frame time spacer"); // }
//frame_time := (60.0/f32(raylib.GetFPS())) * 10;
//frame_time_text := raylib.TextFormat("frame time: %fms", frame_time);
//ui.label(&ui_context, "lol have to figure out how to get the frame time");
}
}
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));
@ -1779,8 +1755,7 @@ main :: proc() {
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists { if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
switch value in action.action { switch value in action.action {
case core.LuaEditorAction: case core.LuaEditorAction:
fmt.println("trying to call lua registered function:", value); lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value.fn_ref));
lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value));
if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) {
err := lua.tostring(L, lua.gettop(L)); err := lua.tostring(L, lua.gettop(L));
lua.pop(L, lua.gettop(L)); lua.pop(L, lua.gettop(L));
@ -1789,6 +1764,10 @@ main :: proc() {
} else { } else {
lua.pop(L, lua.gettop(L)); lua.pop(L, lua.gettop(L));
} }
if value.maybe_input_map.ctrl_key_actions != nil {
}
case core.PluginEditorAction: case core.PluginEditorAction:
value(state.plugin_vtable); value(state.plugin_vtable);
case core.EditorAction: case core.EditorAction:
@ -1801,7 +1780,7 @@ main :: proc() {
if action, exists := state.current_input_map.key_actions[key]; exists { if action, exists := state.current_input_map.key_actions[key]; exists {
switch value in action.action { switch value in action.action {
case core.LuaEditorAction: case core.LuaEditorAction:
lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value)); lua.rawgeti(state.L, lua.REGISTRYINDEX, lua.Integer(value.fn_ref));
if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) { if lua.pcall(state.L, 0, 0, 0) != i32(lua.OK) {
err := lua.tostring(L, lua.gettop(L)); err := lua.tostring(L, lua.gettop(L));
lua.pop(L, lua.gettop(L)); lua.pop(L, lua.gettop(L));
@ -1810,6 +1789,11 @@ main :: proc() {
} else { } else {
lua.pop(L, lua.gettop(L)); lua.pop(L, lua.gettop(L));
} }
if value.maybe_input_map.key_actions != nil {
ptr_action := &(&state.current_input_map.key_actions[key]).action.(core.LuaEditorAction)
state.current_input_map = (&ptr_action.maybe_input_map)
}
case core.PluginEditorAction: case core.PluginEditorAction:
value(state.plugin_vtable); value(state.plugin_vtable);
case core.EditorAction: case core.EditorAction:

View File

@ -98,7 +98,7 @@ light_palette := []u32 {
get_palette_color :: proc(palette_color: PaletteColor) -> [4]u8 { get_palette_color :: proc(palette_color: PaletteColor) -> [4]u8 {
color: [4]u8; color: [4]u8;
c := palette[palette_color]; c := light_palette[palette_color];
for i in 0..<4 { for i in 0..<4 {
color[i] = u8((c >> (8*u32(3-i)))&0xff); color[i] = u8((c >> (8*u32(3-i)))&0xff);
} }

View File

@ -40,6 +40,7 @@ Key :: struct {
Interaction :: struct { Interaction :: struct {
hovering: bool, hovering: bool,
clicked: bool, clicked: bool,
dragging: bool,
} }
Flag :: enum { Flag :: enum {
@ -115,11 +116,11 @@ init :: proc(renderer: ^sdl2.Renderer) -> Context {
gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key { gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key {
key_label := "" key_label := ""
if ctx != nil && (ctx.current_parent == nil || len(ctx.current_parent.key.label) < 1) { if ctx != nil && (ctx.current_parent == nil || len(ctx.current_parent.key.label) < 1) {
key_label = strings.clone(label); key_label = label;
} else if ctx != nil { } else if ctx != nil {
key_label = fmt.aprintf("%s:%s", ctx.current_parent.key.label, label); key_label = fmt.tprintf("%s:%s", ctx.current_parent.key.label, label);
} else { } else {
key_label = fmt.aprintf("%s",label); key_label = fmt.tprintf("%s",label);
} }
return Key { return Key {
@ -233,15 +234,22 @@ test_box :: proc(ctx: ^Context, box: ^Box) -> Interaction {
hovering = true; hovering = true;
} }
if hovering { if hovering || box.active > 0 {
box.hot += 1; box.hot += 1;
} else { } else {
box.hot = 0; box.hot = 0;
} }
if hovering && mouse_is_clicked {
box.active += 1;
} else if !ctx.mouse_left_down {
box.active = 0;
}
return Interaction { return Interaction {
hovering = hovering, hovering = hovering || box.active > 0,
clicked = hovering && mouse_is_clicked, clicked = hovering && mouse_is_clicked,
dragging = box.active > 0
}; };
} }
@ -327,7 +335,7 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font
} }
if .Floating in box.flags { if .Floating in box.flags {
// box.computed_pos = {0,0}; box.computed_pos = {0,0};
} else if box.prev != nil { } else if box.prev != nil {
prev := prev_non_floating_sibling(ctx, box); prev := prev_non_floating_sibling(ctx, box);
@ -343,34 +351,18 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font
} else { } else {
switch box.semantic_size.x.kind { switch box.semantic_size.x.kind {
case .FitText: { case .FitText: {
// TODO: don't use hardcoded font size
box.computed_size.x = len(box.label) * font_width; box.computed_size.x = len(box.label) * font_width;
} }
case .Exact: { case .Exact: {
box.computed_size.x = box.semantic_size.x.value; box.computed_size.x = box.semantic_size.x.value;
} }
case .ChildrenSum: { case .ChildrenSum: {
//compute_children = false;
post_compute_size[int(Axis.Horizontal)] = true; post_compute_size[int(Axis.Horizontal)] = true;
// box.computed_size.x = 0;
// iter := BoxIter { box.first, 0 };
// for child in iterate_box(&iter) {
// compute_layout(canvas_size, font_width, font_height, child);
// switch box.axis {
// case .Horizontal: {
// box.computed_size.x += child.computed_size.x;
// }
// case .Vertical: {
// if child.computed_size.x > box.computed_size.x {
// box.computed_size.x = child.computed_size.x;
// }
// }
// }
// }
} }
case .Fill: { case .Fill: {
if .Floating in box.flags {
box.computed_size.x = ancestor_size(ctx, box, .Horizontal);
}
} }
case .PercentOfParent: { case .PercentOfParent: {
box.computed_size.x = int(f32(ancestor_size(ctx, box, .Horizontal))*(f32(box.semantic_size.x.value)/100.0)); box.computed_size.x = int(f32(ancestor_size(ctx, box, .Horizontal))*(f32(box.semantic_size.x.value)/100.0));
@ -378,52 +370,18 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font
} }
switch box.semantic_size.y.kind { switch box.semantic_size.y.kind {
case .FitText: { case .FitText: {
// TODO: don't use hardcoded font size
box.computed_size.y = font_height; box.computed_size.y = font_height;
} }
case .Exact: { case .Exact: {
box.computed_size.y = box.semantic_size.y.value; box.computed_size.y = box.semantic_size.y.value;
} }
case .ChildrenSum: { case .ChildrenSum: {
//compute_children = false;
post_compute_size[Axis.Vertical] = true; post_compute_size[Axis.Vertical] = true;
// should_post_compute := false;
// number_of_fills := 0;
// box.computed_size.y = 0;
// parent_size := ancestor_size(box, .Vertical);
// iter := BoxIter { box.first, 0 };
// for child in iterate_box(&iter) {
// compute_layout(canvas_size, font_width, font_height, child);
// if child.semantic_size.y.kind == .Fill {
// number_of_fills += 1;
// should_post_compute := true;
// }
// switch box.axis {
// case .Horizontal: {
// if child.computed_size.y > box.computed_size.y {
// box.computed_size.y = child.computed_size.y;
// }
// }
// case .Vertical: {
// box.computed_size.y += child.computed_size.y;
// }
// }
// }
// if should_post_compute {
// iter := BoxIter { box.first, 0 };
// for child in iterate_box(&iter) {
// if compute_layout(canvas_size, font_width, font_height, child) {
// child.computed_size.y = (parent_size - box.computed_size.y) / number_of_fills;
// }
// }
// }
} }
case .Fill: { case .Fill: {
if .Floating in box.flags {
box.computed_size.y = ancestor_size(ctx, box, .Vertical);
}
} }
case .PercentOfParent: { case .PercentOfParent: {
box.computed_size.y = int(f32(ancestor_size(ctx, box, .Vertical))*(f32(box.semantic_size.y.value)/100.0)); box.computed_size.y = int(f32(ancestor_size(ctx, box, .Vertical))*(f32(box.semantic_size.y.value)/100.0));
@ -433,7 +391,6 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font
if compute_children { if compute_children {
iter := BoxIter { box.first, 0 }; iter := BoxIter { box.first, 0 };
should_post_compute := false;
child_size: [2]int = {0,0}; child_size: [2]int = {0,0};
// NOTE: the number of fills for the opposite axis of this box needs to be 1 // NOTE: the number of fills for the opposite axis of this box needs to be 1
@ -451,31 +408,22 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font
compute_layout(ctx, canvas_size, font_width, font_height, child); compute_layout(ctx, canvas_size, font_width, font_height, child);
if child.semantic_size[box.axis].kind == .Fill { if child.semantic_size[box.axis].kind == .Fill {
number_of_fills[box.axis] += 1; number_of_fills[box.axis] += 1;
should_post_compute = true;
} else { } else {
child_size[box.axis] += child.computed_size[box.axis]; child_size[box.axis] += child.computed_size[box.axis];
} }
} }
if true || should_post_compute { iter = BoxIter { box.first, 0 };
iter := BoxIter { box.first, 0 };
for child in iterate_box(&iter) { for child in iterate_box(&iter) {
if !(.Floating in child.flags) {
for axis in 0..<2 { for axis in 0..<2 {
if child.semantic_size[axis].kind == .Fill { if child.semantic_size[axis].kind == .Fill {
if false && child_size[axis] >= our_size[axis] {
child.computed_size[axis] = our_size[axis] / number_of_fills[axis];
} else {
child.computed_size[axis] = (our_size[axis] - child_size[axis]) / number_of_fills[axis]; child.computed_size[axis] = (our_size[axis] - child_size[axis]) / number_of_fills[axis];
} }
} }
} }
compute_layout(ctx, canvas_size, font_width, font_height, child); compute_layout(ctx, canvas_size, font_width, font_height, child);
if child.label == "2" {
fmt.println(child.label, child.computed_size, box.label, our_size, child_size, number_of_fills);
}
}
} }
} }
@ -546,19 +494,10 @@ push_clip :: proc(ctx: ^Context, pos: [2]int, size: [2]int) {
i32(rect.size.y) i32(rect.size.y)
}); });
// raylib.BeginScissorMode(
// i32(rect.pos.x),
// i32(rect.pos.y),
// i32(rect.size.x),
// i32(rect.size.y)
// );
append(&ctx.clips, rect); append(&ctx.clips, rect);
} }
pop_clip :: proc(ctx: ^Context) { pop_clip :: proc(ctx: ^Context) {
//raylib.EndScissorMode();
if len(ctx.clips) > 0 { if len(ctx.clips) > 0 {
rect := pop(&ctx.clips); rect := pop(&ctx.clips);
@ -568,12 +507,6 @@ pop_clip :: proc(ctx: ^Context) {
i32(rect.size.x), i32(rect.size.x),
i32(rect.size.y) i32(rect.size.y)
}); });
// raylib.BeginScissorMode(
// i32(rect.pos.x),
// i32(rect.pos.y),
// i32(rect.size.x),
// i32(rect.size.y)
// );
} else { } else {
sdl2.RenderSetClipRect(ctx.renderer, nil); sdl2.RenderSetClipRect(ctx.renderer, nil);
} }
@ -582,9 +515,8 @@ pop_clip :: proc(ctx: ^Context) {
draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: int, box: ^Box) { draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: int, box: ^Box) {
if box == nil { return; } if box == nil { return; }
// NOTE: for some reason if you place this right before the
// for loop, the clipping only works for the first child. Compiler bug?
push_clip(ctx, box.computed_pos, box.computed_size); push_clip(ctx, box.computed_pos, box.computed_size);
{
defer pop_clip(ctx); defer pop_clip(ctx);
if .Hoverable in box.flags && box.hot > 0 { if .Hoverable in box.flags && box.hot > 0 {
@ -596,8 +528,7 @@ draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: in
box.computed_size.y, box.computed_size.y,
.Background2 .Background2
); );
} } else if .DrawBackground in box.flags {
else if .DrawBackground in box.flags {
core.draw_rect( core.draw_rect(
state, state,
box.computed_pos.x, box.computed_pos.x,
@ -608,16 +539,6 @@ draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: in
); );
} }
if .DrawBorder in box.flags {
core.draw_rect_outline(
state,
box.computed_pos.x,
box.computed_pos.y,
box.computed_size.x,
box.computed_size.y,
.Background4
);
}
if .DrawText in box.flags { if .DrawText in box.flags {
core.draw_text(state, box.label, box.computed_pos.x, box.computed_pos.y); core.draw_text(state, box.label, box.computed_pos.x, box.computed_pos.y);
} }
@ -630,6 +551,21 @@ draw :: proc(ctx: ^Context, state: ^core.State, font_width: int, font_height: in
for child in iterate_box(&iter) { for child in iterate_box(&iter) {
draw(ctx, state, font_width, font_height, child); draw(ctx, state, font_width, font_height, child);
} }
}
push_clip(ctx, box.computed_pos, box.computed_size);
defer pop_clip(ctx);
if .DrawBorder in box.flags {
core.draw_rect_outline(
state,
box.computed_pos.x,
box.computed_pos.y,
box.computed_size.x,
box.computed_size.y,
.Background4
);
}
} }
BoxIter :: struct { BoxIter :: struct {
@ -693,19 +629,19 @@ push_rect :: proc(ctx: ^Context, label: string, background: bool = true, border:
push_centered :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText) -> ^Box { push_centered :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText) -> ^Box {
box: ^Box; box: ^Box;
push_parent(ctx, push_box(ctx, label, {}, semantic_size = Fill)) push_parent(ctx, push_box(ctx, label, {}, semantic_size = { {.Fill,0}, semantic_size.y }))
{ {
defer pop_parent(ctx); defer pop_parent(ctx);
spacer(ctx, "left spacer"); spacer(ctx, "left spacer");
halfway_centered := push_rect(ctx, "halfway centered", false, false, .Vertical, { semantic_size.x, {.Fill,0} }); halfway_centered := push_rect(ctx, "halfway centered", false, false, .Vertical, { {.Fill, 0}, {.Fill,0} });
push_parent(ctx, halfway_centered); push_parent(ctx, halfway_centered);
{ {
defer pop_parent(ctx); defer pop_parent(ctx);
spacer(ctx, "top spacer"); spacer(ctx, "top spacer");
box = push_box(ctx, label, flags, axis, { {.Fill,0}, semantic_size.y }); box = push_box(ctx, label, flags, axis, FitText);
spacer(ctx, "bottom spacer"); spacer(ctx, "bottom spacer");
} }
spacer(ctx, "right spacer"); spacer(ctx, "right spacer");

View File

@ -4,148 +4,3 @@ import "core:math"
import "../core" import "../core"
import "../theme" import "../theme"
// MenuBarItemOnClick :: proc(state: ^core.State, item: ^MenuBarItem);
//
// text_padding :: 4;
//
// MenuBarItem :: struct {
// text: string,
// selected: bool,
// sub_items: []MenuBarItem,
// on_click: MenuBarItemOnClick,
// }
//
// MenuBarState :: struct {
// items: []MenuBarItem,
// }
//
// draw_menu_bar_item :: proc(state: ^core.State, item: ^MenuBarItem, x, y: i32, parent_width, parent_height: i32, font_height: int, horizontal: bool = false) {
// foreground_color := theme.PaletteColor.Foreground3;
// if horizontal {
// if item.selected {
// foreground_color = theme.PaletteColor.Background4;
// } else {
// foreground_color = theme.PaletteColor.Foreground4;
// }
// }
//
// item_text := raylib.TextFormat("%s", item.text);
// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x;
//
// raylib.DrawRectangle(x, y, parent_width, i32(font_height), theme.get_palette_raylib_color(foreground_color));
// raylib.DrawTextEx(state.font, item_text, raylib.Vector2 { f32(x + text_padding), f32(y) }, f32(font_height), 0, theme.get_palette_raylib_color(.Background1));
//
// if item.selected {
// // TODO: change to parent_width
// largest_sub_item: int
// for sub_item in item.sub_items {
// largest_sub_item = math.max(len(sub_item.text), largest_sub_item);
// }
//
// this_width := i32(largest_sub_item * state.source_font_width + text_padding*2);
// sub_list_x := x;
// if horizontal {
// sub_list_x += parent_width;
// }
// for _, index in item.sub_items {
// sub_item := &item.sub_items[index];
// item_text := raylib.TextFormat("%s", sub_item.text);
// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x;
//
// index_offset := 1;
// if horizontal {
// index_offset = 0;
// }
// item_y := y + i32(font_height * (index+index_offset));
// draw_menu_bar_item(state, sub_item, sub_list_x, item_y, this_width, 0, font_height, true);
// }
// }
// }
//
// draw_menu_bar :: proc(state: ^core.State, data: ^MenuBarState, x, y: i32, parent_width, parent_height: i32, font_height: int) {
// raylib.DrawRectangle(x, y, parent_width, i32(font_height), theme.get_palette_raylib_color(.Background3));
//
// raylib.DrawTextEx(state.font, "Editor", raylib.Vector2 { f32(x), f32(y) }, f32(font_height), 0, theme.get_palette_raylib_color(.Foreground1));
//
// x := x + i32((len("Editor") + 4) * state.source_font_width);
//
// for _, index in data.items {
// item := &data.items[index];
// item_text := raylib.TextFormat("%s", item.text);
// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x;
//
// item_x := x + (i32(item_width) + text_padding*2) * i32(index);
// draw_menu_bar_item(state, item, item_x, y, i32(item_width + text_padding*2), i32(font_height), font_height);
// }
// }
//
// test_menu_item :: proc(state: ^core.State, item: ^MenuBarItem, rect: raylib.Rectangle, mouse_pos: raylib.Vector2, mouse_has_clicked: bool, font_height: int, horizontal: bool) -> bool {
// if raylib.CheckCollisionPointRec(mouse_pos, rect) {
// item.selected = true;
//
// if item.on_click != nil && mouse_has_clicked {
// item.on_click(state, item);
// }
// } else if item.selected {
// largest_sub_item: int
// for sub_item in item.sub_items {
// largest_sub_item = math.max(len(sub_item.text), largest_sub_item);
// }
//
// this_width := i32(largest_sub_item * state.source_font_width + text_padding*2);
// sub_list_x := rect.x;
// if horizontal {
// sub_list_x += rect.width;
// }
//
// has_sub_item_selected := false;
// for _, index in item.sub_items {
// sub_item := &item.sub_items[index];
// item_text := raylib.TextFormat("%s", sub_item.text);
// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x;
//
// index_offset := 1;
// if horizontal {
// index_offset = 0;
// }
// item_y := rect.y + f32(font_height * (index+index_offset));
//
// sub_rec := raylib.Rectangle {
// x = sub_list_x,
// y = item_y,
// width = f32(this_width),
// height = f32(font_height),
// };
//
// if test_menu_item(state, sub_item, sub_rec, mouse_pos, mouse_has_clicked, font_height, true) {
// has_sub_item_selected = true;
// }
// }
//
// item.selected = has_sub_item_selected;
// } else {
// item.selected = false;
// }
//
// return item.selected;
// }
//
// test_menu_bar :: proc(state: ^core.State, menu_bar: ^MenuBarState, x, y: i32, mouse_pos: raylib.Vector2, mouse_has_clicked: bool, font_height: int) {
// x := x + i32((len("Editor") + 4) * state.source_font_width);
//
// for _, index in menu_bar.items {
// item := &menu_bar.items[index];
// item_text := raylib.TextFormat("%s", item.text);
// item_width := raylib.MeasureTextEx(state.font, item_text, f32(font_height), 0).x;
//
// item_rec := raylib.Rectangle {
// x = f32(x) + (item_width + f32(text_padding*2)) * f32(index),
// y = f32(y),
// width = f32(item_width + text_padding*2),
// height = f32(font_height),
// };
//
// test_menu_item(state, item, item_rec, mouse_pos, mouse_has_clicked, font_height, false);
// }
// }