Work on automatically generating UI for editing struct
This commit is contained in:
parent
467a24766f
commit
977bb107dc
@ -194,7 +194,7 @@ tick_level_editor :: () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
draw_level_editor :: () {
|
draw_level_editor :: () {
|
||||||
draw_sky(*get_level_editor_camera());
|
draw_sky(*get_level_editor_camera(), *world.conf);
|
||||||
cam := get_level_editor_camera();
|
cam := get_level_editor_camera();
|
||||||
mvp := create_viewproj(*cam);
|
mvp := create_viewproj(*cam);
|
||||||
|
|
||||||
@ -244,5 +244,7 @@ draw_level_editor_ui :: (theme: *GR.Overall_Theme) {
|
|||||||
if current_tab == {
|
if current_tab == {
|
||||||
case .TACOMA;
|
case .TACOMA;
|
||||||
draw_tacoma_tab(theme, r);
|
draw_tacoma_tab(theme, r);
|
||||||
|
case .INFO;
|
||||||
|
autoedit(r, *world.conf, theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/main.jai
14
src/main.jai
@ -1,4 +1,10 @@
|
|||||||
#import "Basic"()(MEMORY_DEBUGGER=true);
|
MEM_DEBUG :: false;
|
||||||
|
|
||||||
|
#if MEM_DEBUG {
|
||||||
|
#import "Basic"()(MEMORY_DEBUGGER=true);
|
||||||
|
} else {
|
||||||
|
#import "Basic";
|
||||||
|
}
|
||||||
#import "Math";
|
#import "Math";
|
||||||
#import "Input";
|
#import "Input";
|
||||||
#import "Hash_Table";
|
#import "Hash_Table";
|
||||||
@ -129,9 +135,9 @@ frame :: () {
|
|||||||
sg_commit();
|
sg_commit();
|
||||||
|
|
||||||
input_per_frame_event_and_flag_update();
|
input_per_frame_event_and_flag_update();
|
||||||
|
#if MEM_DEBUG {
|
||||||
|
memory_visualizer_per_frame_update();
|
||||||
// memory_visualizer_per_frame_update();
|
}
|
||||||
|
|
||||||
profiler_update();
|
profiler_update();
|
||||||
reset_temporary_storage();
|
reset_temporary_storage();
|
||||||
|
|||||||
134
src/ui/autoedit.jai
Normal file
134
src/ui/autoedit.jai
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#scope_file
|
||||||
|
|
||||||
|
#import "String";
|
||||||
|
|
||||||
|
autoedit_scrolls : Table(u64, float);
|
||||||
|
|
||||||
|
loc_to_key :: (line: s32) -> string {
|
||||||
|
print("Creating key: %\n", line);
|
||||||
|
return tprint("%", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
Autoedit_Conf :: struct {
|
||||||
|
Kind :: enum {
|
||||||
|
COLOR;
|
||||||
|
SLIDER;
|
||||||
|
DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
kind: Kind = .DEFAULT;
|
||||||
|
|
||||||
|
min: string = "0";
|
||||||
|
max: string = "100";
|
||||||
|
step: string = "1";
|
||||||
|
}
|
||||||
|
|
||||||
|
note_to_autoedit_conf :: (notes: []string) -> Autoedit_Conf {
|
||||||
|
if notes.count == 0 {
|
||||||
|
return .{kind = .DEFAULT};
|
||||||
|
}
|
||||||
|
|
||||||
|
note := notes[0];
|
||||||
|
note_parts := split(note,",");
|
||||||
|
|
||||||
|
assert(note_parts.count > 0, "Note has to have a part");
|
||||||
|
if note_parts[0] == "Slider" {
|
||||||
|
assert(note_parts.count == 4, "Slider must have min, max and step.");
|
||||||
|
return .{
|
||||||
|
kind = .SLIDER,
|
||||||
|
min = note_parts[1],
|
||||||
|
max = note_parts[2],
|
||||||
|
step = note_parts[3]
|
||||||
|
};
|
||||||
|
} else if note_parts[0] == "Color" {
|
||||||
|
return .{kind = .COLOR};
|
||||||
|
} else if note_parts[0] == "Input" {
|
||||||
|
if note_parts.count == 1 {
|
||||||
|
return .{
|
||||||
|
kind = .DEFAULT
|
||||||
|
};
|
||||||
|
} else if note_parts.count == 3 {
|
||||||
|
return .{
|
||||||
|
kind = .DEFAULT,
|
||||||
|
min = note_parts[1],
|
||||||
|
max = note_parts[2]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
assert(false, "Input must have either 1 or 3 parts");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input_code_from_type_and_notes :: (name: string, type: *Type_Info, notes: []string) -> string {
|
||||||
|
autoconf := note_to_autoedit_conf(notes);
|
||||||
|
builder : String_Builder;
|
||||||
|
print_to_builder(*builder, "GR.label(r, \"%\", *t_label_left(theme));\n", name);
|
||||||
|
print_to_builder(*builder, "r.y += r.h;\n");
|
||||||
|
|
||||||
|
if type == type_info(float) || type == type_info(s32) {
|
||||||
|
if autoconf.kind == .SLIDER {
|
||||||
|
print_to_builder(*builder, "GR.slider(r, *value.%, %, %, %, *theme.slider_theme);\n", name, autoconf.min, autoconf.max, autoconf.step);
|
||||||
|
} else {
|
||||||
|
print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%), *value.%, %, %, *number_theme);\n", name, name, autoconf.min, autoconf.max);
|
||||||
|
}
|
||||||
|
} else if type == type_info(Vector3) {
|
||||||
|
if autoconf.kind == .DEFAULT {
|
||||||
|
print_to_builder(*builder, "{\n");
|
||||||
|
print_to_builder(*builder, "orig_w := r.w; orig_x := r.x; r.w = r.w / 3;\n");
|
||||||
|
print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%.x), *value.%.x, 0, 100, *number_theme);\n", name, name);
|
||||||
|
print_to_builder(*builder, "r.x += r.w;\n");
|
||||||
|
print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%.y), *value.%.y, 0, 100, *number_theme);\n", name, name);
|
||||||
|
print_to_builder(*builder, "r.x += r.w;\n");
|
||||||
|
print_to_builder(*builder, "GR.number_input(r, tprint(\"\%\", value.%.z), *value.%.z, 0, 100, *number_theme);\n", name, name);
|
||||||
|
print_to_builder(*builder, "r.w = orig_w; r.x = orig_x;\n");
|
||||||
|
print_to_builder(*builder, "}\n");
|
||||||
|
} else if autoconf.kind == .COLOR {
|
||||||
|
print_to_builder(*builder, "if GR.button(r, \"Edit color\", *t_button_color(theme, .{value.%.x, value.%.y, value.%.z, 1.0})) then cur_edit_color = *value.%;\n", name, name, name, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
print_to_builder(*builder, "r.y += r.h;\n");
|
||||||
|
return builder_to_string(*builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_edit_color : *Vector3 = null;
|
||||||
|
color_edit_already_active : bool = false;
|
||||||
|
|
||||||
|
#scope_export
|
||||||
|
// Generates code automatically to edit a struct consisting of simple fields.
|
||||||
|
autoedit :: (rect: GR.Rect, value: *$T, theme: *GR.Overall_Theme, identifier: s32 = 0, loc := #caller_location) {
|
||||||
|
hash := GR.get_hash(loc, identifier);
|
||||||
|
scroll_val := find_or_add(*autoedit_scrolls, hash);
|
||||||
|
|
||||||
|
number_theme : GR.Number_Input_Theme;
|
||||||
|
generate_autoedit_code :: () -> string {
|
||||||
|
builder : String_Builder;
|
||||||
|
ti := type_info(T);
|
||||||
|
#assert #run type_info(T).type == .STRUCT "Autoedit only works for structs";
|
||||||
|
for ti.members {
|
||||||
|
print_to_builder(*builder, "%\n", input_code_from_type_and_notes(it.name, it.type, it.notes));
|
||||||
|
}
|
||||||
|
return builder_to_string(*builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
region, r := GR.begin_scrollable_region(rect, *theme.scrollable_region_theme);
|
||||||
|
r.y -= scroll_val.*;
|
||||||
|
r.h = ui_h(4,0);
|
||||||
|
|
||||||
|
if !cur_edit_color {
|
||||||
|
#insert #run generate_autoedit_code();
|
||||||
|
color_edit_already_active = false;
|
||||||
|
} else {
|
||||||
|
r.h = ui_h(50,0);
|
||||||
|
applied, drag, state := GR.color_picker(r, cur_edit_color);
|
||||||
|
|
||||||
|
if !color_edit_already_active {
|
||||||
|
GR.set_original_and_current_color_rgb(state, cur_edit_color.*);
|
||||||
|
color_edit_already_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if applied then cur_edit_color = null;
|
||||||
|
}
|
||||||
|
r.y += ui_h(8,0);
|
||||||
|
GR.end_scrollable_region(region, r.x + r.w, r.y, scroll_val);
|
||||||
|
}
|
||||||
@ -25,3 +25,9 @@ t_button_selectable :: (theme: *GR.Overall_Theme, active: bool) -> GR.Button_The
|
|||||||
|
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t_button_color :: (theme: *GR.Overall_Theme, color: Vector4) -> GR.Button_Theme {
|
||||||
|
t := theme.button_theme;
|
||||||
|
t.surface_color = color;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ GR :: #import "GetRect_LeftHanded"()(Type_Indicator = Ui_Type_Indicator);
|
|||||||
Input :: #import "Input";
|
Input :: #import "Input";
|
||||||
|
|
||||||
#load "component_themes.jai";
|
#load "component_themes.jai";
|
||||||
|
#load "autoedit.jai";
|
||||||
|
|
||||||
// vw is 1/100 of view width
|
// vw is 1/100 of view width
|
||||||
vw : float;
|
vw : float;
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
World_Config :: struct {
|
World_Config :: struct {
|
||||||
skyBase : Vector3 = .{0.38, 0.81, 0.95};
|
// All of the @Notes are for the autoedit functionality.
|
||||||
skyTop : Vector3 = .{0.17, 0.4, 0.95};
|
skyBase : Vector3 = .{0.38, 0.81, 0.95}; @Color
|
||||||
sunDisk : Vector3 = .{1.0, 1.0, 1.0};
|
skyTop : Vector3 = .{0.17, 0.4, 0.95}; @Color
|
||||||
horizonHalo : Vector3 = .{1.0, 1.0, 1.0};
|
sunDisk : Vector3 = .{1.0, 1.0, 1.0}; @Color
|
||||||
sunHalo : Vector3 = .{1.0, 1.0, 1.0};
|
horizonHalo : Vector3 = .{1.0, 1.0, 1.0}; @Color
|
||||||
sunLightColor : Vector3 = .{1.0, 1.0, 1.0};
|
sunHalo : Vector3 = .{1.0, 1.0, 1.0}; @Color
|
||||||
|
sunLightColor : Vector3 = .{1.0, 1.0, 1.0}; @Color
|
||||||
sunPosition : Vector3 = #run normalize(Vector3.{0.2, 0.3, 0.4});
|
sunPosition : Vector3 = #run normalize(Vector3.{0.2, 0.3, 0.4});
|
||||||
sunIntensity : float = 2.0;
|
sunIntensity : float = 2.0; @Slider,0,10,0.5
|
||||||
|
|
||||||
hasClouds : s32 = 1;
|
hasClouds : s32 = 1; @Slider,0,1,1
|
||||||
|
|
||||||
hasPlane : s32 = 0;
|
hasPlane : s32 = 0; @Slider,0,1,1
|
||||||
planeHeight : float = 0.0;
|
planeHeight : float = 0.0; @Slider,-100,100,1
|
||||||
planeType : s32 = 0;
|
planeType : s32 = 0; @Slider,0,2,1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copies over all the fields of our world config into a given shader type.
|
// Copies over all the fields of our world config into a given shader type.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user