u64 unique_id; \
char* name; \
Type* backing; \
+ b32 is_flags; \
})
document.addEventListener("keydown", function (ev) {
if (ev.isComposing || ev.keyCode === 229) return;
ev.preventDefault();
- push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode ]);
+
+ // NOTE: These modifiers need to match in js_events.onyx.
+ var modifiers = 0x0000;
+ if (ev.ctrlKey) modifiers |= 0x01;
+ if (ev.altKey) modifiers |= 0x02;
+ if (ev.metaKey) modifiers |= 0x04;
+ if (ev.shiftKey) modifiers |= 0x08;
+
+ push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode, modifiers ]);
+
+ var keyname = ev.code;
+ let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer);
+ let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2;
+
+ let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer);
+
+ for (var i = 0; i < keyname.length; i++) {
+ WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i);
+ }
+
+ WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length;
return false;
});
document.addEventListener("keyup", function (ev) {
if (ev.isComposing || ev.keyCode === 229) return;
ev.preventDefault();
- push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode ]);
+
+ // NOTE: These modifiers need to match in js_events.onyx.
+ var modifiers = 0x0000;
+ if (ev.ctrlKey) modifiers |= 0x01;
+ if (ev.altKey) modifiers |= 0x02;
+ if (ev.metaKey) modifiers |= 0x04;
+ if (ev.shiftKey) modifiers |= 0x08;
+
+ push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode, modifiers ]);
+
+ var keyname = ev.code;
+ let WASM_U32 = new Uint32Array(ONYX_MEMORY.buffer);
+ let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2;
+
+ let WASM_U8 = new Uint8Array(ONYX_MEMORY.buffer);
+
+ for (var i = 0; i < keyname.length; i++) {
+ WASM_U8[event_idx * 4 + (4 * 4) + i] = keyname.charCodeAt(i);
+ }
+
+ WASM_U8[event_idx * 4 + (4 * 4) + 15] = keyname.length;
+
return false;
});
KeyboardEvent :: struct {
use event : DomEvent;
- keycode : u32;
-}
-
-MouseButton :: enum {
- Left :: 0x00;
- Middle :: 0x01;
- Right :: 0x02;
+ keycode : u32; // Apparently, keyCode is deprecated on browsers now??? Stupid web standards that aren't "standards" at all.
+ modifiers : Modifiers;
+
+ // This is assuming that no single keyname is greater than 15 characters in length.
+ // A quick look at https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values makes
+ // me think that that isn't possible, but it's the web so anything is possible. 🙄
+ keyname : [15] u8;
+ keyname_count : u8;
+
+ Modifiers :: enum #flags {
+ CTRL :: 0x01;
+ ALT :: 0x02;
+ META :: 0x04;
+ SHIFT :: 0x08;
+ }
- WheelUp :: 0x03;
- WheelDown :: 0x04;
+ get_name :: (use e: ^KeyboardEvent) -> str do return str.{ ~~keyname, ~~keyname_count };
}
MouseEvent :: struct {
use event : DomEvent;
+ Button :: enum {
+ Left :: 0x00;
+ Middle :: 0x01;
+ Right :: 0x02;
+
+ WheelUp :: 0x03;
+ WheelDown :: 0x04;
+ }
+
pos_x : u32;
pos_y : u32;
- button : MouseButton;
+ button : Button;
}
ResizeEvent :: struct {
use package core.intrinsics.onyx { __zero_value }
if event_storage.event_count == 0 do return __zero_value(Event), false;
+ @CodeGeneration // This instruction (and all instructions involving Event) generate a TON of instructions because Event is a union.
event := event_storage.event_buffer[0];
for i: 0 .. Num_Buffered_Events - 2 {
default_button_theme := Button_Theme.{};
-@Themeing
button :: (use r: Rectangle, text: str, theme := ^default_button_theme, site := #callsite, increment := 0) -> bool {
- gfx.set_texture();
-
result := false;
hash := get_site_hash(site, increment);
border_width := theme.border_width;
width, height := Rectangle.dimensions(r);
+ gfx.set_texture();
gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color);
surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color);
default_checkbox_theme := Checkbox_Theme.{};
-@Themeing
checkbox :: (use r: Rectangle, value: ^bool, text: str, theme := ^default_checkbox_theme, site := #callsite, increment := 0) -> bool {
result := false;
default_radio_theme := Radio_Theme.{};
-@Themeing
radio :: (use r: Rectangle, selected: ^$T, value: T, text: str, theme := ^default_radio_theme, site := #callsite, increment := 0) -> bool {
result := false;
package ui
+use package core
+Textbox_Theme :: struct {
+ use text_theme := Text_Theme.{
+ text_color = .{ 0, 0, 0 }
+ };
-textbox :: (use r: Rectangle) -> bool {
-
+ background_color := gfx.Color4.{ 0.8, 0.8, 0.8 };
+ hover_color := gfx.Color4.{ 1.0, 1.0, 1.0 };
+ click_color := gfx.Color4.{ 0.5, 0.5, 0.7 };
+
+ border_color := gfx.Color4.{ 0.2, 0.2, 0.2 };
+ border_width := 6.0f; @InPixels
+}
+
+default_textbox_theme := Textbox_Theme.{};
+
+textbox :: (use r: Rectangle, text: str, theme := ^default_textbox_theme, site := #callsite, increment := 0) -> bool {
+ result := false;
+
+ hash := get_site_hash(site, increment);
+ animation_state := map.get(^animation_states, hash);
+
+ if Rectangle.contains(r, mouse_state.x, mouse_state.y) {
+ set_hot_item(hash);
+ }
+
+ if is_hot_item(hash) {
+ move_towards(^animation_state.hover_time, 1.0f, 0.1f); @ThemeConfiguration
+ } else {
+ move_towards(^animation_state.hover_time, 0.0f, 0.1f); @ThemeConfiguration
+ }
+
+ border_width := theme.border_width;
+ width, height := Rectangle.dimensions(r);
+
+ gfx.set_texture();
+ gfx.rect(.{ x0, y0 }, .{ width, height }, theme.border_color);
+
+ surface_color := color_lerp(animation_state.hover_time, theme.background_color, theme.hover_color);
+ surface_color = color_lerp(animation_state.click_time, surface_color, theme.click_color);
+ gfx.rect(.{ x0 + border_width, y0 + border_width }, .{ width - border_width * 2, height - border_width * 2 }, surface_color);
+
+ text_width := bmfont.get_width(^font, text, theme.font_size);
+ text_height := bmfont.get_height(^font, text, theme.font_size);
+
+ draw_text_raw(text,
+ x0 + border_width,
+ y0 + ~~ font.common.baseline * theme.font_size + (height - text_height) / 2,
+ theme.font_size, theme.text_color);
+
+ move_towards(^animation_state.click_time, 0.0f, 0.08f); @ThemeConfiguration
+
+ if animation_state.click_time > 0 || animation_state.hover_time > 0 {
+ map.put(^animation_states, hash, animation_state);
+ } else {
+ map.delete(^animation_states, hash);
+ }
}
\ No newline at end of file
This module provides several common UI components such as:
- Buttons
- Checkbox
+ - Radio buttons
- Sliders
- Textboxes
#load "./components/checkbox"
#load "./components/slider"
#load "./components/radio"
+#load "./components/textbox"
// Package inclusions that are part of all files in the "ui" package.
y: f32 = 0;
}
-mouse_state: MouseState = MouseState.{};
+mouse_state := MouseState.{};
init_ui :: () {
}
}
-@Themeing
draw_text :: (use r: Rectangle, text: str, theme := ^default_text_theme, site := #callsite) -> bool {
draw_text_raw(text, x0, y0 + ~~font.common.baseline * theme.font_size, theme.font_size, theme.text_color);
}
if ((binop_allowed[binop->operation] & effective_flags) == 0) goto bad_binaryop;
+ // NOTE: Enum flags with '&' result in a boolean value
+ if (binop->type->kind == Type_Kind_Enum && binop->type->Enum.is_flags && binop->operation == Binary_Op_And) {
+ binop->type = &basic_types[Basic_Kind_Bool];
+ }
+
if (binop->flags & Ast_Flag_Comptime) {
// NOTE: Not a binary op
*pbinop = (AstBinaryOp *) ast_reduce(context.ast_alloc, (AstTyped *) binop);
enum_type->Enum.unique_id = next_unique_id++;
enum_type->Enum.backing = enum_node->backing_type;
enum_type->Enum.name = enum_node->name;
+ enum_type->Enum.is_flags = enum_node->flags & Ast_Flag_Enum_Is_Flags;
return enum_type;
}