Editor_Range :: struct {min, max: f32;}
Editor_Disabled :: struct {}
Editor_Hidden :: struct {}
-Editor_Custom_Field :: struct { func: () -> void; }
+Editor_Custom_Field :: struct { func: (v: any, x: f32, y: f32, w: f32, h: f32, field_name: str) -> void; }
editor_init :: () {
editor_font = font_lookup(.{"./assets/fonts/calibri.ttf", 18});
selected_entity_id = Entity_Nothing;
array.ensure_capacity(^save_path, 512);
- save_path.count = 512;
- s := conv.format(save_path, "./scenes/level1.scene");
- save_path.count = s.count;
+ conv.format(^save_path, "./scenes/level1.scene");
+
+ custom_editors[Color] = render_color_picker;
}
editor_shown :: () => editor_openness != 0.0f || editor_target_openness != 0.0f;
if draw_button(.{ x + w / 2, y + 40, w / 2, 40 }, "Load") {
scene->load_from_file(save_path);
}
+
+ @Cleanup // This is rather expensive to do every frame, I think?
+ dir, success := os.dir_open("./scenes");
+ entry: os.DirectoryEntry;
+ y += 80;
+ while os.dir_read(dir, ^entry) {
+ if string.ends_with(entry->name(), ".scene") {
+ if draw_button(.{ x, y, w, 40 }, entry->name(), increment=entry.identifier) {
+ buf: [1024] u8;
+ path := conv.format(buf, "./scenes/{}", entry->name());
+ scene->load_from_file(path);
+ }
+ y += 40;
+ }
+ }
+ os.dir_close(dir);
}
case .Create {
}
#local render_create_sidebar :: (x, y, w, h: f32) {
+ #persist search_value: [..] u8;
+ draw_textbox(.{x, y, w, 40}, ^search_value, placeholder="Search...");
+ h -= 40;
+ y += 40;
+
i := 0;
for^ scene.schematics.entries {
defer i += 1;
name := it.key;
+ if search_value.count != 0 {
+ if !string.contains(name, search_value) do continue;
+ }
y += 40.0f;
theme := Button_Theme.{active = active_index == i};
#local render_entity_list :: (x, y, w, h: f32) {
#persist search_value: [..] u8;
- draw_textbox(.{x, y, w, 40}, ^search_value);
+ draw_textbox(.{x, y, w, 40}, ^search_value, placeholder="Search...");
h -= 40;
y += 40;
}
}
+ member_info := type_info.get_type_info(it.type);
+
if active_index + 1 == i {
immediate_set_color(.{.4,.4,.2});
immediate_rectangle(x, y + 2, w, Field_Height + 2);
- render_field_editor(member_any, y, it.name);
+ w := sidebar_width / 2;
+ h := 200.0f;
+ x := ~~ window_width - sidebar_width;
+ render := render_field_editor;
+
+ if custom_editors[it.type] != null_proc {
+ render = custom_editors[it.type];
+ }
+
+ for it.tags {
+ if it.type == Editor_Custom_Field {
+ render = (cast(^Editor_Custom_Field) it.data).func;
+ }
+ }
+
+ render(member_any, x, y, w, h, it.name);
} elseif i % 2 == 0 {
immediate_set_color(.{.3,.3,.3});
Color.{0.4, 0.4, 0.2}
];
- if type_info.get_type_info(it.type).kind == .Struct {
+ if member_info.kind == .Struct {
new_y, new_i := render_struct_fields(member_any, i, x + Field_Height, y, w - Field_Height, h, depth + 1);
immediate_set_color(depth_colors[depth % 4]);
immediate_rectangle(x, y + Field_Height + 4, Field_Height / 2, new_y - y);
#local prepare_field_editor :: (v: any) {
array.ensure_capacity(^field_buffer, 256);
- field_buffer.count = 256;
- s := conv.format_va(field_buffer, "{\"d}", .[v]);
- field_buffer.count = s.count;
+ conv.format_va(^field_buffer, "{\"d}", .[v]);
}
-#local render_field_editor :: (v: any, y: f32, field_name: str) {
- w := sidebar_width / 2;
- h := 200.0f;
- x := ~~ window_width - sidebar_width;
+#local render_field_editor :: (v: any, x, y, w, h: f32, field_name: str) {
immediate_set_color(.{.3,.3,.3});
immediate_rectangle(x, y, w, h);
}
}
+#local render_color_picker :: (v: any, x, y, w, h: f32, field_name: str) {
+ color := cast(^Color) v.data;
+
+ immediate_set_color(.{.3, .3, .3});
+ immediate_rectangle(x, y, w, h);
+
+ draw_slider(.{x, y+0, w, 40}, ^color.r, 0, 1);
+ draw_slider(.{x, y+40, w, 40}, ^color.g, 0, 1);
+ draw_slider(.{x, y+80, w, 40}, ^color.b, 0, 1);
+
+ buf: [64] u8;
+ msg := conv.format(buf, "Red: {}", color.r);
+ font_draw_centered(editor_font, x, y+24, w, msg);
+ msg = conv.format(buf, "Green: {}", color.g);
+ font_draw_centered(editor_font, x, y+64, w, msg);
+ msg = conv.format(buf, "Blue: {}", color.b);
+ font_draw_centered(editor_font, x, y+104, w, msg);
+
+ immediate_set_color(*color);
+ immediate_rectangle(x, y+120, w, h - 120);
+}
+
#local {
background_color :: Color.{0.15, 0.15, 0.15, 1};
editor_grid_size := 16.0f; @TODO // This should be configurable
save_path: [..] u8;
+
+ custom_editors : Map(type_expr, (any, f32, f32, f32, f32, str) -> void);
}
if active_countdown > 0 {
active_countdown -= 1;
- if active_countdown == 0 do set_active_item(0);
+ if active_countdown == 0 {
+ set_active_item(0);
+ input_release_keys();
+ }
}
}
}
+//
+// Sliders
+//
+Slider_Theme :: struct {
+ use text_theme := Text_Theme.{};
+ use animation_theme := Animation_Theme.{};
+
+ box_color := Color.{ 0.1, 0.1, 0.1 };
+ box_border_color := Color.{ 0.2, 0.2, 0.2 };
+ box_border_width := 4.0f; @InPixels
+
+ bar_color := Color.{ 0.4, 0.4, 0.4 };
+ bar_hover_color := Color.{ 0, 0, 1 };
+ bar_hover_negative_color := Color.{ 1, 0, 0 }; // The color when value is less than 0
+}
+
+#local default_slider_theme := Slider_Theme.{};
+
+draw_slider :: (use r: Rect, value: ^$T, min_value: T, max_value: T, theme := ^default_slider_theme, site := #callsite, increment := 0) -> bool {
+ result := false;
+
+ hash := get_site_hash(site, increment);
+ state := get_animation(hash);
+ mx, my := mouse_get_position();
+
+ if is_hot_item(hash) {
+ if is_button_down(GLFW_MOUSE_BUTTON_LEFT) {
+ set_active_item(hash);
+ result = true;
+
+ // Animate this?
+ sx := ~~mx - x;
+
+ if T == i32 || T == i64 || T == u32 || T == u64 {
+ step_width := w / ~~math.abs(max_value - min_value);
+ percent := (sx + step_width / 2) / w;
+ *value = math.lerp(percent, min_value, max_value);
+ *value = math.clamp(*value, min_value, max_value);
+
+ } else {
+ percent := sx / w;
+ *value = math.lerp(percent, min_value, max_value);
+ *value = math.clamp(*value, min_value, max_value);
+ }
+ } else {
+ set_active_item(0);
+ }
+ }
+
+ if Rect.contains(r, .{ ~~mx, ~~my }) {
+ set_hot_item(hash);
+ }
+
+ if is_hot_item(hash) {
+ move_towards(^state.hover_time, 1.0f, theme.hover_speed);
+ } else {
+ move_towards(^state.hover_time, 0.0f, theme.hover_speed);
+ }
+
+ box_border_width := theme.box_border_width;
+
+ bar_color := theme.bar_color;
+ if *value < 0 do bar_color = color_lerp(state.hover_time, bar_color, theme.bar_hover_negative_color);
+ else do bar_color = color_lerp(state.hover_time, bar_color, theme.bar_hover_color);
+
+ immediate_set_color(theme.box_border_color);
+ immediate_rectangle(x, y, w, h);
+
+ immediate_set_color(theme.box_border_color);
+ immediate_rectangle(x + box_border_width, y + box_border_width, w - box_border_width * 2, h - box_border_width * 2);
+
+ box_width := cast(f32) (*value - min_value) / ~~(max_value - min_value);
+ box_width *= w - box_border_width * 2;
+ box_width = math.clamp(box_width, 0, w - box_border_width * 2);
+ immediate_set_color(bar_color);
+ immediate_rectangle(x + box_border_width, y + box_border_width, box_width, h - box_border_width * 2);
+
+ return result;
+}
+
//
// Textbox
//