WASM_U8.set(u8_data, bufferptr);
- if (namelen >= file_data.name.length) {
+ if (nameptr != 0 && namelen <= file_data.name.length) {
var name_data = new TextEncoder().encode(file_data.name);
WASM_U8.set(name_data, nameptr);
}
use package core
-#private_file events :: package js_events
-#private_file gl :: package gl
-#private_file gfx :: package immediate_mode
-#private_file ui :: package ui
-#private_file config :: package config
-#private_file wasm :: package wasm_utils
-#private_file debug :: package debug
+#private_file {
+ events :: package js_events
+ gl :: package gl
+ gfx :: package immediate_mode
+ ui :: package ui
+ config :: package config
+ wasm :: package wasm_utils
+ debug :: package debug
+}
use package debug { init as debug_init, debug_log, draw_debug_log }
use package core.intrinsics.onyx { __initialize }
@Relocate search_buffer: string.String_Buffer;
-on_file_load_callbacks : map.Map(u32, (file_event: ^events.Event) -> void);
+on_file_load_callbacks : Map(u32, (file_event: ^events.Event) -> void);
@Relocate
Tool :: struct {
file := Active_File.{};
windows_store : alloc.pool.PoolAllocator(Application_Window);
- windows_map : map.Map(str, ^Application_Window);
+ windows_map : Map(str, ^Application_Window);
windows_sorted : [..] ^Application_Window;
window_switcher_state : Window_Switcher_State;
gl.enable(gl.BLEND);
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
- array.push(^registered_tools, .{
+ registered_tools << Tool.{
id = "load_file_info",
name = "File Info",
open = () {
- open_window("load_file_info", "Loaded file info", .{ 0, 0 }, (_: rawptr, win: ^Application_Window) {
+ open_window("load_file_info", "Loaded file info", .{ 0, 0 }, (_, win) => {
if state.has_active_file {
buffer: [512] u8;
- name_text := conv.str_format("File name: {}", ~~buffer, state.file.name);
+ name_text := conv.str_format(buffer, "File name: {}", state.file.name);
ui.draw_text(.{ 0, 0, 300, 200 }, name_text);
- size_text := conv.str_format("File size: {} bytes", ~~buffer, state.file.data.count);
+ size_text := conv.str_format(buffer, "File size: {} bytes", state.file.data.count);
ui.draw_text(.{ 0, 32, 300, 200 }, size_text);
} else {
move_window_to_top("load_file_info");
focus_window("load_file_info");
}
- });
+ };
// Dynamically load things in the binary
{
fnt_file_id : u32;
tex_file_id : u32;
- fnt_file_size := cast(u32) 0;
- tex_file_size := cast(u32) 0;
+ fnt_file_size := 0;
+ tex_file_size := 0;
}
#persist fonts_loading : [..] Loading_Font;
- font_file_loaded :: (ev: ^events.Event) {
+ font_file_loaded :: (ev) => {
lf: ^Loading_Font = null;
for ^entry: fonts_loading {
fnt_data := memory.make_slice(u8, lf.fnt_file_size);
tex_data := memory.make_slice(u8, lf.tex_file_size);
defer {
- cfree(fnt_data.data);
- cfree(tex_data.data);
+ cfree(fnt_data.data);
+ cfree(tex_data.data);
}
@ErrorHandling
needs_redraw :: () -> bool {
return ui.has_active_animation()
|| debug.debug_log_transitioning()
- || state.window_switcher_state->is_animating();
+ || state.window_switcher_state->is_animating()
+ || state.workspace_state.transform_transition > 0;
}
update :: (dt: f32) {
gl.clearColor(bg_color.r, bg_color.g, bg_color.b, bg_color.a);
gl.clear(gl.COLOR_BUFFER_BIT);
- ui.set_cursor(ui.Cursors.Default);
+ #if #defined(ui.set_cursor) { ui.set_cursor(ui.Cursors.Default); }
window_width, window_height := gfx.get_window_size();
window_rectangle := ui.Rectangle.{ 0, 0, ~~window_width, ~~window_height };
// Menu bar drawing
{
- #insert gfx.save_matrix;
-
+ gfx.save_matrix();
+
gfx.identity();
- ui.menubar(menu_bar, ^search_buffer, ~~ui.Menu_Bar_Option.[
+ ui.menubar(menu_bar, ^search_buffer, ui.Menu_Bar_Option.[
.{ label = "File" },
.{ label = "Test" },
]);
gfx.flush();
ui.end_frame();
+
+ #if config.DEBUG {
+ if needs_redraw() {
+ gfx.rect(.{~~(window_width-16),0}, .{16,16}, .{1,0,0});
+ gfx.flush();
+ }
+ }
}
-open_tool_opener :: () {
+open_tool_opener :: macro () {
mouse_pos := gfx.transform_point(^state.workspace_state.transform, .{ ui.mouse_state.x_, ui.mouse_state.y_ });
close_window("tool_opener");
open_window("tool_opener", "Tool Opener", .{ mouse_pos.x, mouse_pos.y }, init_size=.{ 200, 400 },
- draw=(_: rawptr, win: ^Application_Window) {
+ draw=(_, win) => {
window_rect := ui.Rectangle.{ 0, 0, win.window_state.size.x, win.window_state.size.y };
- ui.scrollable_region_start(window_rect, maximum_y=~~(registered_tools.count - 1) * 40.0f);
+ ui.scrollable_region_start(window_rect, .{ maximum_y=~~(registered_tools.count - 1) * 40.0f });
defer ui.scrollable_region_stop();
button_rect : ui.Rectangle;
});
}
-#private_file background_tile_texture : gfx.Texture;
-#private_file draw_background_lines :: (width: f32, height: f32, line_color := gfx.Color4.{0.2, 0.2, 0.2}, line_spacing := 32.0f) {
- gl :: package gl
+@Relocate // This should be moved to somewhere else when the code base.
+#private_file {
+ background_tile_texture : gfx.Texture;
+
+ draw_background_lines :: (width: f32, height: f32, line_color := gfx.Color4.{0.2, 0.2, 0.2}, line_spacing := 32.0f) {
+ gl :: package gl
- #insert gfx.save_matrix;
+ gfx.save_matrix();
- trans := gfx.global_renderer->get_transform();
- sx := trans.scale.x * line_spacing;
- sy := trans.scale.y * line_spacing;
- tx := -trans.translation.x / sx;
- ty := -trans.translation.y / sy;
+ trans := gfx.global_renderer->get_transform();
+ sx := trans.scale.x * line_spacing;
+ sy := trans.scale.y * line_spacing;
+ tx := -trans.translation.x / sx;
+ ty := -trans.translation.y / sy;
- gfx.identity();
- gfx.set_texture(^background_tile_texture);
- gfx.textured_rect(.{ 0, 0 }, .{ width, height }, .{ tx, ty }, .{ width / sx, height / sy }, color=line_color);
- gfx.set_texture();
+ gfx.identity();
+ gfx.set_texture(^background_tile_texture);
+ gfx.textured_rect(.{ 0, 0 }, .{ width, height }, .{ tx, ty }, .{ width / sx, height / sy }, color=line_color);
+ gfx.set_texture();
+ }
}
use package core
-#private_file events :: package js_events
-#private_file gl :: package gl
-#private_file gfx :: package immediate_mode
-#private_file ui :: package ui
-#private_file config :: package config
-#private_file wasm :: package wasm_utils
-#private_file debug :: package debug
+#private_file {
+ events :: package js_events
+ gl :: package gl
+ gfx :: package immediate_mode
+ ui :: package ui
+ config :: package config
+ wasm :: package wasm_utils
+ debug :: package debug
+}
use package debug { init as debug_init, debug_log, draw_debug_log }
use package core.intrinsics.onyx { __initialize }
package debug
use package core
-#private_file ui :: package ui
-#private_file gfx :: package immediate_mode
-#private_file config :: package config
-#private y_scroll := 0.0f;
-#private debug_log_y_offset := 0.0f;
-#private debug_log_y_offset_target := 0.0f;
+#private_file {
+ ui :: package ui
+ gfx :: package immediate_mode
+ config :: package config
+}
+
+#private {
+ y_scroll := 0.0f;
+ debug_log_y_offset := 0.0f;
+ debug_log_y_offset_target := 0.0f;
+}
init :: () {
log_buffer.line_arena = alloc.arena.make(context.allocator, 4096);
if severity < minimum_severity do return;
buffer1: [4096] u8;
- s := conv.str_format_va(format, ~~buffer1, ~~args);
+ s := conv.str_format_va(buffer1, format, args);
lines := string.split(s, #char "\n", context.temp_allocator);
line_alloc := alloc.arena.make_allocator(^log_buffer.line_arena);
if l.count == 0 do continue;
buffer2: [4096] u8;
- s = conv.str_format("[{}] {}\n", ~~buffer2, severity, l);
+ s = conv.str_format(buffer2, "[{}] {}\n", severity, l);
line := string.alloc_copy(s, line_alloc);
array.push(^log_buffer.lines, line);
use package core
-#private_file events :: package js_events
-#private_file gl :: package gl
-#private_file gfx :: package immediate_mode
-#private_file ui :: package ui
-#private_file config :: package config
-#private_file wasm :: package wasm_utils
-#private_file debug :: package debug
+#private_file {
+ events :: package js_events
+ gl :: package gl
+ gfx :: package immediate_mode
+ ui :: package ui
+ config :: package config
+ wasm :: package wasm_utils
+ debug :: package debug
+}
use package debug { init as debug_init, debug_log, draw_debug_log }
use package core.intrinsics.onyx { __initialize }
open_window :: (id: str,
- title: str,
- init_position: gfx.Vector2,
- draw: (rawptr, ^Application_Window) -> void,
- init_size := gfx.Vector2.{ 600, 600 }) {
+ title: str,
+ init_position: gfx.Vector2,
+ draw: (rawptr, ^Application_Window) -> void,
+ init_size := gfx.Vector2.{ 600, 600 },
+ draw_data := null) {
if map.has(^state.windows_map, id) {
debug_log(.Warning, "Window with id '{}' is already registered.", id);
win.window_state.title = title;
win.draw = draw;
+ win.draw_data = draw_data;
map.put(^state.windows_map, id, win);
array.push(^state.windows_sorted, win);
win := map.get(^state.windows_map, id);
- index := array.find(^state.windows_sorted, win);
+ index := array.find(state.windows_sorted, win);
assert(index >= 0, "Window not found.");
- array.transplant(^state.windows_sorted, index, state.windows_sorted.count - 1);
+ array.transplant(state.windows_sorted, index, state.windows_sorted.count - 1);
}
focus_window :: (id: str) {
window_is_open :: (id: str) -> bool {
return map.has(^state.windows_map, id);
-}
\ No newline at end of file
+}
package app
-#private_file ui :: package ui
-#private_file gfx :: package immediate_mode
-#private_file config :: package config
-#private_file math :: package core.math
-#private_file string :: package core.string
-#private_file memory :: package core.memory
-use package core.intrinsics.onyx { __initialize }
+#private_file {
+ ui :: package ui
+ gfx :: package immediate_mode
+ config :: package config
+ math :: package core.math
+ string :: package core.string
+ memory :: package core.memory
+
+ use package core.intrinsics.onyx { __initialize }
+}
Window_Switcher_State :: struct {
visibility := 0.0f;
x_scroll := 0.0f;
y_scroll := 0.0f;
- selected_index: i32 = 0;
+ selected_index := 0;
init :: (use state: ^Window_Switcher_State) {
__initialize(state);
ui.move_towards(^visibility, visibility_target, 0.08f);
if visibility == 0.0f do return;
- #insert gfx.save_matrix;
+ gfx.save_matrix();
gfx.identity();
quater_width := ui.Rectangle.width(window_rectangle) / 4;
#load "modules/ui/module"
#load "modules/js_events/module"
#load "modules/bmfont/module"
-
+
#load "src/ui/window"
#load "src/ui/menubar"
#load "src/ui/cursor"
use package immediate_mode { Color4 }
+DEBUG :: true
ONLY_REDRAW_ON_EVENTS :: true
light_color_scheme_file :: "/res/colors_light.json"
Feature_Hex_Viewer :: struct {
setup := setup;
-}
\ No newline at end of file
+}
package feature.hex_viewer
-#private_file app :: package app
-#private_file ui :: package ui
-#private_file config :: package config
+#private_file {
+ app :: package app
+ ui :: package ui
+ config :: package config
+}
use package core
use package debug { debug_log }
Hex_Viewer_State :: struct {
scrollable_region := ui.Scrollable_Region_State.{};
+
+ highlighted_line : i32 = -1; // -1 is uninitialized
+ highlighted_column : i32 = -1;
}
// Should this be global? Or should each viewer window get their own?
-#private viewer_state := Hex_Viewer_State.{};
+#private global_viewer_state := Hex_Viewer_State.{};
-window_draw :: (_: rawptr, win: ^app.Application_Window) {
+window_draw :: (use viewer_state: ^Hex_Viewer_State, win: ^app.Application_Window) {
orig_r: ui.Rectangle = .{ 0, 0, win.window_state.size.x, win.window_state.size.y };
r := orig_r;
ui.use_font(text_theme.font);
em_height := ui.get_text_height("M", text_theme.font_size) / 2;
+ line_height := em_height * 2;
win.window_state.max_size.x = (10 + 1 + 3 * 16 + 2 + 16) * em_height;
win.window_state.background_color = config.Colors.dark_background;
return;
}
+ mx, my := ui.get_mouse_position();
file_data := app.state.file.data;
{
// This is a hack to get the region to be "scrollable" without actually applying any of the scrolling effects
- ui.scrollable_region_start(r, maximum_y=em_height*~~(file_data.count / 8 - 1), state=^viewer_state.scrollable_region);
+ ui.scrollable_region_start(r, .{ maximum_y=em_height*~~(file_data.count / 8 - 1) }, state=^scrollable_region);
ui.scrollable_region_stop();
}
+
line_data: [128] u8;
- line := string.buffer_make(~~line_data);
+ line := string.buffer_make(line_data);
+
+ first_line: i32 = ~~math.floor(-scrollable_region.transform.translation.y / line_height);
+ line_count: i32 = ~~math.ceil(win.window_state.size.y / em_height);
- first_line: i32 = ~~math.floor(-viewer_state.scrollable_region.transform.translation.y / (2*em_height));
- line_count: i32 = ~~math.ceil(win.window_state.size.y / (em_height));
+ highlighted_column = -1;
+ highlighted_line = ~~math.floor(my / line_height) if ui.Rectangle.contains(r, mx, my) else -1;
+ if highlighted_line >= 0 {
+ if mx >= 10 * em_height && mx <= em_height * (9 + 3 * 16 - 0.0625f) {
+ highlighted_column = ~~math.floor((mx - 9 * em_height) / (3 * em_height));
+ }
+
+ if mx >= em_height * (9 + 3 * 16 + 2) && mx <= em_height * (9 + 3 * 16 + 2 + 16) {
+ highlighted_column = ~~math.floor((mx - (9 + 3 * 16 + 2) * em_height) / em_height);
+ }
+ }
+
+ if highlighted_line >= 0 && highlighted_line <= line_count {
+ hy := ~~highlighted_line * line_height;
+ ui.draw_rect(.{ 0, hy, r.x1, hy + line_height }, color=config.Colors.background);
+
+ if highlighted_column >= 0 {
+ cx := em_height * ~~(10 + highlighted_column * 3);
+ ui.draw_rect(.{ cx, hy, cx + em_height * 2, hy + line_height }, color=config.Colors.secondary);
+
+ cx = em_height * ~~(59 + highlighted_column);
+ ui.draw_rect(.{ cx, hy, cx + em_height, hy + line_height }, color=config.Colors.secondary);
+ }
+ }
visible_lines := first_line .. (first_line + line_count);
if i * 16 >= file_data.count do break;
offset_data: [16] u8;
- output := conv.str_format("{w8b16} ", ~~offset_data, i * 16);
+ output := conv.str_format(offset_data, "{w8b16} ", i * 16);
ui.draw_text(r, output, theme=^text_theme);
r = ui.Flow.padding(r, top=32);
}
if index >= file_data.count do break;
ch_data: [8] u8;
- output := conv.str_format("{w2b16} ", ~~ch_data, cast(u32) file_data[index]);
+ output := conv.str_format(ch_data, "{w2b16} ", cast(u32) file_data[index]);
string.buffer_append(^line, output);
}
r = ui.Flow.padding(r, top=32);
}
- r = ui.Flow.padding(orig_r, left=3*em_height*16 + 10*em_height + 32);
+ r = ui.Flow.padding(orig_r, left=3*em_height*16 + 10*em_height + em_height);
for i: visible_lines {
if i * 16 >= file_data.count do break;
if char >= 32 && char <= 126 do data[0] = char;
else do data[0] = #char ".";
- string.buffer_append(^line, ~~data);
+ string.buffer_append(^line, data);
}
ui.draw_text(r, string.buffer_to_str(^line), theme=^text_theme);
}
open_window :: () {
- app.open_window(window_id, window_name, .{ 0, 0 }, window_draw, .{ 1300, 650 });
+ app.open_window(window_id, window_name, .{ 0, 0 }, window_draw, .{ 1300, 650 }, draw_data=^global_viewer_state);
app.move_window_to_top(window_id);
app.focus_window(window_id);
-/*
- app.open_window("dummy", "DUMMY TESTING", .{ 0, 0 }, (_: rawptr, _: ^app.Application_Window) {
+ app.open_window("dummy", "DUMMY TESTING", .{ 0, 0 }, (_, win) => {
buffer: [1024] u8;
- s := conv.str_format("{p}", ~~buffer, viewer_state);
- ui.draw_text(.{0,0,0,0}, s);
+ s := conv.str_format(buffer, "{p*}", ^global_viewer_state);
+ theme := ui.default_text_theme;
+ theme.font = config.Fonts.FiraCode.index;
+ ui.draw_text(.{0,0,0,0}, s, theme=^theme);
});
-*/
}
setup :: () {
debug_log(.Debug, "Initializing hex viewer...", 0);
- array.push(^app.registered_tools, .{
+ app.registered_tools << app.Tool.{
id = window_id,
name = window_name,
open = open_window,
- });
-}
\ No newline at end of file
+ };
+}
package feature.text_editor
-#private_file app :: package app
-#private_file ui :: package ui
-#private_file config :: package config
+#private_file {
+ app :: package app
+ ui :: package ui
+ config :: package config
+}
use package core
use package debug { debug_log }
window_name :: "Text Editor"
open_text_editor :: () {
- app.open_window(window_id, window_name, .{ 0, 0 }, (_: rawptr, win: ^app.Application_Window) {
+ app.open_window(window_id, window_name, .{ 0, 0 }, (_, win) => {
if !app.state.has_active_file do return;
ui.scrollable_region_start(.{ 0, 0, win.window_state.size.x, win.window_state.size.y });
defer ui.scrollable_region_stop();
-
+
text_theme := ui.default_text_theme;
text_theme.font = config.Fonts.FiraCode.index;
ui.draw_text(.{ 0, 0, 200, 200 }, app.state.file.data, theme=^text_theme);
name = window_name,
open = open_text_editor,
});
-}
\ No newline at end of file
+}
package feature.wasm
-use package app { Application_State }
-use package debug { debug_log }
+#private_file {
+ app :: package app
+ ui :: package ui
+ config :: package config
+
+ use package core
+ use package debug { debug_log }
+}
setup :: () {
debug_log(.Info, "Wasm Loader Loaded from {}", #file);
-}
\ No newline at end of file
+}
-#private_file events :: package js_events
-#private_file config :: package config
-#private_file app :: package app
-#private_file ui :: package ui
+#private_file {
+ events :: package js_events
+ config :: package config
+ app :: package app
+ ui :: package ui
+}
main :: (args: [] cstr) {
app.init();
package ui
-#private_file iter :: package core.iter
-#private_file config :: package config
-use package core.string
+#private_file {
+ iter :: package core.iter
+ config :: package config
+
+ use package core.string
+}
Menu_Bar_Option :: struct {
label : str;
button_rect : Rectangle;
- for option: iter.enumerate(iter.from_array(options)) {
+ for option: options |> iter.from_array() |> iter.enumerate() {
button_rect, menu_rect = Flow.split_vertical(menu_rect, left_width=100);
button(button_rect, option.value.label, theme=^menu_button_theme, increment=option.index);
}
package ui
-#private_file map :: package core.map
+
+#private_file {
+ map :: package core.map
+}
// This will be stored by the end user's library.
Window_State :: struct {
window_start :: (use state: ^Window_State, site := #callsite, increment := 0) -> bool {
hash := get_site_hash(site, increment);
- animation_state := map.get(^animation_states, hash);
+ animation_state := get_animation(hash);
mx, my := get_mouse_position();
if state->get_rectangle() |> Rectangle.contains(mx, my) {
state.should_close = true;
}
- if animation_state.click_time > 0 || animation_state.hover_time > 0 {
- map.put(^animation_states, hash, animation_state);
- } else {
- map.delete(^animation_states, hash);
- }
-
gfx.push_matrix();
gfx.push_scissor(x, y, w, h);
gfx.apply_transform(.{ translation = .{ x, y }, scale = .{ 1, 1 } });
window_end :: () {
gfx.pop_scissor();
gfx.pop_matrix();
-}
\ No newline at end of file
+}
use package core
-#private_file ui :: package ui
-#private_file gfx :: package immediate_mode
-#private_file config :: package config
-#private_file wasm :: package wasm_utils
+#private_file {
+ ui :: package ui
+ gfx :: package immediate_mode
+ config :: package config
+ wasm :: package wasm_utils
+}
use package core.intrinsics.onyx { __initialize }
wasm_binary : wasm.WasmBinary;
wasm_sections : wasm.WasmSections;
- window_states : map.Map(u32, ui.Window_State);
+ window_states : Map(u32, ui.Window_State);
sidebar_expansion_target := 0.0f;
}
button_rect : ui.Rectangle;
text_rect, sidebar_rectangle = ui.Flow.split_horizontal(sidebar_rectangle, top_height=50);
- s := conv.str_format("Function count: {}\n", ~~text_buffer, wasm_sections.code_section.count);
+ s := conv.str_format(text_buffer, "Function count: {}\n", wasm_sections.code_section.count);
ui.draw_text(text_rect, s);
for i: wasm_sections.code_section.count {
button_rect, sidebar_rectangle = ui.Flow.split_horizontal(sidebar_rectangle, top_height=40);
- ui.button(button_rect, conv.str_format("Function {}", ~~text_buffer, i), increment=i);
+ ui.button(button_rect, conv.str_format(text_buffer, "Function {}", i), increment=i);
}
}