Saving projects
This commit is contained in:
parent
4261f07762
commit
64735fe60e
3 changed files with 182 additions and 63 deletions
170
program.odin
170
program.odin
|
|
@ -39,6 +39,10 @@ UiElementData_FloatInput :: struct {
|
|||
tag: bit_set[enum{UpdateMatrix}],
|
||||
}
|
||||
|
||||
UiElementData_TextInput :: struct {
|
||||
str: cstring,
|
||||
}
|
||||
|
||||
UiElementData_Dropdown :: struct {
|
||||
value: ^i32,
|
||||
}
|
||||
|
|
@ -56,6 +60,7 @@ UiButtonType :: enum {
|
|||
PauseTransformation,
|
||||
ResumeTransformation,
|
||||
ResetTransformation,
|
||||
SaveProjectConfirm,
|
||||
}
|
||||
|
||||
UiButtonRecalculateFinishGroup :: bit_set[UiButtonType]{
|
||||
|
|
@ -79,11 +84,21 @@ MatrixTypes :: enum {
|
|||
Rotation,
|
||||
}
|
||||
|
||||
@rodata matrix_add_hotkeys := [MatrixTypes]rl.KeyboardKey {
|
||||
.Identity = rl.KeyboardKey.I,
|
||||
.Translation = rl.KeyboardKey.T,
|
||||
.Scale = rl.KeyboardKey.S,
|
||||
.Rotation = rl.KeyboardKey.R,
|
||||
@rodata hotkey_without_modifier := [MatrixTypes]rl.KeyboardKey {
|
||||
.Identity = .I,
|
||||
.Translation = .T,
|
||||
.Scale = .S,
|
||||
.Rotation = .R,
|
||||
}
|
||||
|
||||
HotkeyWithModifier :: enum {
|
||||
Save,
|
||||
Open,
|
||||
}
|
||||
|
||||
@rodata hotkey_with_modifier := [HotkeyWithModifier]rl.KeyboardKey {
|
||||
.Save = .S,
|
||||
.Open = .O,
|
||||
}
|
||||
|
||||
FontStyle :: struct {
|
||||
|
|
@ -107,12 +122,16 @@ ProgramDialogType :: enum {
|
|||
CreateTranslationMatrix,
|
||||
CreateScaleMatrix,
|
||||
CreateRotationMatrix,
|
||||
SaveProject,
|
||||
LoadProject,
|
||||
}
|
||||
|
||||
@rodata program_dialog_messages := [ProgramDialogType]cstring {
|
||||
.CreateTranslationMatrix = "Create tranlation matrix",
|
||||
.CreateScaleMatrix = "Create scale matrix",
|
||||
.CreateRotationMatrix = "Create rotation matrix",
|
||||
.SaveProject = "Save project",
|
||||
.LoadProject = "Load project",
|
||||
}
|
||||
|
||||
ProgramMessageType :: enum {
|
||||
|
|
@ -129,9 +148,12 @@ InputFloatField :: [32]byte
|
|||
MATRIX_POOL_SIZE :: 4096
|
||||
|
||||
DIALOG_STATE_INPUT_FIELD_COUNT :: 16
|
||||
DIALOG_STATE_TEXT_INPUT_FIELD_SIZE :: 256
|
||||
DIALOG_STATE_TEXT_INPUT_FIELD_COUNT :: 8
|
||||
ProgramData_DialogState :: struct {
|
||||
input_value_strings: [DIALOG_STATE_INPUT_FIELD_COUNT]InputFloatField,
|
||||
input_values: [DIALOG_STATE_INPUT_FIELD_COUNT]f32,
|
||||
input_float_value_strings: [DIALOG_STATE_INPUT_FIELD_COUNT]InputFloatField,
|
||||
input_float_values: [DIALOG_STATE_INPUT_FIELD_COUNT]f32,
|
||||
input_text_buffers: [DIALOG_STATE_TEXT_INPUT_FIELD_SIZE][DIALOG_STATE_TEXT_INPUT_FIELD_COUNT]byte,
|
||||
}
|
||||
|
||||
Program :: struct {
|
||||
|
|
@ -202,11 +224,6 @@ program_show_dialog :: proc(program: ^Program, dialog_type: ProgramDialogType) {
|
|||
program.dialog_type = dialog_type
|
||||
}
|
||||
|
||||
program_show_mesasge :: proc(program: ^Program, message: ProgramMessageType) {
|
||||
program.state = .Message
|
||||
program.message_type = message
|
||||
}
|
||||
|
||||
program_init :: proc(allocator := context.allocator) {
|
||||
program.matrix_float_pool = make(type_of(program.matrix_float_pool), MATRIX_POOL_SIZE)
|
||||
program.matrix_value_string_pool = make(type_of(program.matrix_value_string_pool), MATRIX_POOL_SIZE)
|
||||
|
|
@ -279,21 +296,33 @@ program_update :: proc() {
|
|||
if rl.IsKeyPressed(.TAB) {
|
||||
program.ui_element_focus = ui.focus_next_element(program.ui_element_focus, ui_elements, UI_ALLOWED_FOCUS)
|
||||
}
|
||||
for hotkey, index in matrix_add_hotkeys {
|
||||
if rl.IsKeyPressed(hotkey) {
|
||||
switch index {
|
||||
case .Identity:
|
||||
program_add_identity_matrix()
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
case .Translation:
|
||||
program_show_dialog(&program, .CreateTranslationMatrix)
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
case .Scale:
|
||||
program_show_dialog(&program, .CreateScaleMatrix)
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
case .Rotation:
|
||||
program_show_dialog(&program, .CreateRotationMatrix)
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
if rl.IsKeyDown(.LEFT_CONTROL) {
|
||||
for hotkey, index in hotkey_with_modifier {
|
||||
if rl.IsKeyPressed(hotkey) {
|
||||
switch index {
|
||||
case .Save:
|
||||
program_show_dialog(&program, .SaveProject)
|
||||
case .Open:
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for hotkey, index in hotkey_without_modifier {
|
||||
if rl.IsKeyPressed(hotkey) {
|
||||
switch index {
|
||||
case .Identity:
|
||||
program_add_identity_matrix()
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
case .Translation:
|
||||
program_show_dialog(&program, .CreateTranslationMatrix)
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
case .Scale:
|
||||
program_show_dialog(&program, .CreateScaleMatrix)
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
case .Rotation:
|
||||
program_show_dialog(&program, .CreateRotationMatrix)
|
||||
program.ui_overlay_queue_focus_first = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -304,11 +333,13 @@ program_update :: proc() {
|
|||
program.ui_overlay_element_focus = ui.focus_next_element(program.ui_overlay_element_focus, ui_overlay_elements, UI_ALLOWED_FOCUS)
|
||||
}
|
||||
if rl.IsKeyDown(.ENTER) {
|
||||
vals := program.dialog_data.input_values
|
||||
vals := program.dialog_data.input_float_values
|
||||
switch program.dialog_type {
|
||||
case .CreateTranslationMatrix: program_add_translation_matrix(vals[0], vals[1], vals[2])
|
||||
case .CreateScaleMatrix: program_add_scalar_matrix(vals[0], vals[1], vals[2])
|
||||
case .CreateRotationMatrix: program_add_rotation_matrix(vals[0])
|
||||
case .SaveProject:
|
||||
case .LoadProject:
|
||||
}
|
||||
animation_update_last(&program.animation, program_get_master_matrix())
|
||||
program.state = .Normal
|
||||
|
|
@ -416,45 +447,61 @@ ui_labeled_input_float_element :: proc(label: cstring, margin: f32, value: ^f32,
|
|||
return ui.element(.InputFloat, dimensions, {margin = margin}, input_data)
|
||||
}
|
||||
|
||||
ui_labeled_input_text_element :: proc(label: cstring, margin: f32, str: []byte, allocator := context.temp_allocator) -> ^ui.Element {
|
||||
label := fmt.ctprintf("%s: ", label)
|
||||
label_element := ui.element(.Label, {}, {label = label, color = ui.col(rl.WHITE), margin = margin})
|
||||
dimensions := ui.Dimensions{ui.Size_Pixels(64.0), ui.dimensions_pixels(ui.rect_get_size(ui.get_element_outer_area(label_element^))).height}
|
||||
ui.same_line()
|
||||
input_data := new(UiElementData_TextInput, context.temp_allocator)
|
||||
input_data^ = {str = cstring(&str[0])}
|
||||
return ui.element(.InputText, dimensions, {margin = margin}, input_data)
|
||||
}
|
||||
|
||||
program_build_dialog_ui :: proc(ctx: ^ui.Context, dialog_type: ProgramDialogType) -> []ui.Element {
|
||||
size := v2{WINDOW_WIDTH, WINDOW_HEIGHT}
|
||||
container_margin := size * 0.33
|
||||
element_margin: f32 = 4.0
|
||||
dialog_data := &program.dialog_data
|
||||
|
||||
dialog_type_to_button_type := [ProgramDialogType]UiButtonType {
|
||||
.CreateTranslationMatrix = .AddTranslationMatrixConfirm,
|
||||
.CreateScaleMatrix = .AddScaleMatrixConfirm,
|
||||
.CreateRotationMatrix = .AddRotationMatrixConfirm,
|
||||
}
|
||||
button_type := dialog_type_to_button_type[program.dialog_type]
|
||||
|
||||
ui.start(ctx, V2_ZERO, {WINDOW_WIDTH, WINDOW_HEIGHT})
|
||||
ui.container_begin(ui.dimensions_auto(), {margin = container_margin, padding = 8.0})
|
||||
ui.element(.Label, {}, {label = program_dialog_messages[program.dialog_type], color = ui.col(rl.WHITE), margin = element_margin})
|
||||
switch dialog_type {
|
||||
case .CreateTranslationMatrix, .CreateScaleMatrix:
|
||||
ui.element(.Label, {}, {label = program_dialog_messages[program.dialog_type], color = ui.col(rl.WHITE), margin = element_margin})
|
||||
ui_labeled_input_float_element("X", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0])
|
||||
ui_labeled_input_float_element("Y", 4.0, &dialog_data.input_values[1], &dialog_data.input_value_strings[1])
|
||||
ui_labeled_input_float_element("Z", 4.0, &dialog_data.input_values[2], &dialog_data.input_value_strings[2])
|
||||
|
||||
ui_labeled_input_float_element("X", 4.0, &dialog_data.input_float_values[0], &dialog_data.input_float_value_strings[0])
|
||||
ui_labeled_input_float_element("Y", 4.0, &dialog_data.input_float_values[1], &dialog_data.input_float_value_strings[1])
|
||||
ui_labeled_input_float_element("Z", 4.0, &dialog_data.input_float_values[2], &dialog_data.input_float_value_strings[2])
|
||||
button_type: UiButtonType
|
||||
if dialog_type == .CreateTranslationMatrix {
|
||||
button_type = .AddTranslationMatrixConfirm
|
||||
} else {
|
||||
button_type = .AddScaleMatrixConfirm
|
||||
}
|
||||
ui_add_matrix_footer_buttons(button_type, element_margin)
|
||||
case .CreateRotationMatrix:
|
||||
ui.element(.Label, {}, {label = program_dialog_messages[program.dialog_type], color = ui.col(rl.WHITE), margin = element_margin})
|
||||
ui_labeled_input_float_element("Angle", 4.0, &dialog_data.input_values[0], &dialog_data.input_value_strings[0])
|
||||
ui_labeled_input_float_element("Angle", 4.0, &dialog_data.input_float_values[0], &dialog_data.input_float_value_strings[0])
|
||||
ui_add_matrix_footer_buttons(.AddRotationMatrixConfirm, element_margin)
|
||||
case .SaveProject:
|
||||
ui_labeled_input_text_element("Path", 4.0, dialog_data.input_text_buffers[0][:])
|
||||
ui_add_matrix_footer_buttons(.SaveProjectConfirm, element_margin)
|
||||
case .LoadProject:
|
||||
}
|
||||
button_data: ^UiElementData_Button
|
||||
button_data = new(UiElementData_Button, context.temp_allocator)
|
||||
button_data^ = {type = button_type}
|
||||
ui.element(.Button, ui.dimensions_pixels({96.0, 32.0}), {label = "Add", margin = element_margin}, button_data)
|
||||
|
||||
button_data = new(UiElementData_Button, context.temp_allocator)
|
||||
button_data^ = {type = .ExitDialog}
|
||||
ui.same_line()
|
||||
ui.element(.Button, ui.dimensions_pixels({96.0, 32.0}), {label = "Cancel", margin = element_margin}, button_data)
|
||||
ui.container_end()
|
||||
return ui.end()
|
||||
}
|
||||
|
||||
ui_add_matrix_footer_buttons :: proc(button_type_add: UiButtonType, margin: f32) {
|
||||
button_data: ^UiElementData_Button
|
||||
button_data = new(UiElementData_Button, context.temp_allocator)
|
||||
button_data^ = {type = button_type_add}
|
||||
ui.element(.Button, ui.dimensions_pixels(96.0, 32.0), {label = "Add", margin = margin}, button_data)
|
||||
|
||||
button_data = new(UiElementData_Button, context.temp_allocator)
|
||||
button_data^ = {type = .ExitDialog}
|
||||
ui.same_line()
|
||||
ui.element(.Button, ui.dimensions_pixels(96.0, 32.0), {label = "Cancel", margin = margin}, button_data)
|
||||
}
|
||||
|
||||
program_build_workspace_ui :: proc(ctx: ^ui.Context) -> (elements: []ui.Element, matrix_container: ^ui.Element) {
|
||||
ui.start(ctx, {0, 0}, {WINDOW_WIDTH, WINDOW_HEIGHT})
|
||||
top_bar_container_config := ui.ElementConfiguration {margin = 4.0}
|
||||
|
|
@ -617,15 +664,15 @@ program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: u
|
|||
case .AddScale: program_show_dialog(&program, .CreateScaleMatrix)
|
||||
case .AddRotation: program_show_dialog(&program, .CreateRotationMatrix)
|
||||
case .AddTranslationMatrixConfirm:
|
||||
inputs := program.dialog_data.input_values
|
||||
inputs := program.dialog_data.input_float_values
|
||||
program_add_translation_matrix(inputs[0], inputs[1], inputs[2])
|
||||
program.state = .Normal
|
||||
case .AddScaleMatrixConfirm:
|
||||
inputs := program.dialog_data.input_values
|
||||
inputs := program.dialog_data.input_float_values
|
||||
program_add_scalar_matrix(inputs[0], inputs[1], inputs[2])
|
||||
program.state = .Normal
|
||||
case .AddRotationMatrixConfirm:
|
||||
program_add_rotation_matrix(program.dialog_data.input_values[0])
|
||||
program_add_rotation_matrix(program.dialog_data.input_float_values[0])
|
||||
program.state = .Normal
|
||||
case .ExitDialog:
|
||||
program.state = .Normal
|
||||
|
|
@ -641,6 +688,16 @@ program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: u
|
|||
program.animation_state = .Playing
|
||||
case .ResetTransformation:
|
||||
animation_reset(&program.animation)
|
||||
case .SaveProjectConfirm:
|
||||
project := ProjectData {
|
||||
matrix_count = u32(program.matrix_count),
|
||||
matrices = program.matrix_float_pool,
|
||||
}
|
||||
if error := project_write(&project, string(program.dialog_data.input_text_buffers[0][:])); error != nil {
|
||||
// TODO (synthas): Generic error message
|
||||
} else {
|
||||
program.state = .Normal
|
||||
}
|
||||
}
|
||||
if data.type in UiButtonRecalculateFinishGroup {
|
||||
animation_update_last(&program.animation, program_get_master_matrix())
|
||||
|
|
@ -658,6 +715,11 @@ program_render_ui_and_handle_focus :: proc(ctx: ^ui.Context, focus_element_id: u
|
|||
if value_previous != data.value^ && .UpdateMatrix in data.tag {
|
||||
animation_update_last(&program.animation, program_get_master_matrix())
|
||||
}
|
||||
case .InputText:
|
||||
data := cast(^UiElementData_TextInput)element.data
|
||||
if rl.GuiTextBox(area, data.str, i32(program.font_style.size), focus_element_id == element.id) {
|
||||
focus_element_id = element.id
|
||||
}
|
||||
case .Dropdown:
|
||||
assert(element.data != nil, "Element data cannot be nil when creating a dropdown")
|
||||
data := cast(^UiElementData_Dropdown)element.data
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue