diff --git a/run_tree/win32/intel/debug/lumenarium_first_win32.obj b/run_tree/win32/intel/debug/lumenarium_first_win32.obj index a1f0317..a60b65b 100644 Binary files a/run_tree/win32/intel/debug/lumenarium_first_win32.obj and b/run_tree/win32/intel/debug/lumenarium_first_win32.obj differ diff --git a/src_v2/editor/lumenarium_editor.cpp b/src_v2/editor/lumenarium_editor.cpp index 96edf05..7329a79 100644 --- a/src_v2/editor/lumenarium_editor.cpp +++ b/src_v2/editor/lumenarium_editor.cpp @@ -155,6 +155,32 @@ ed_frame_prepare(App_State* state) internal void ed_frame(App_State* state) { + UI* ui = &state->editor->ui; + + UI_Layout layout = {}; + layout.bounds_min = v2{ 500, 200 }; + layout.bounds_max = v2{ 700, 500 }; + layout.row_height = ui->font_ascent + ui->font_descent + ui->font_line_gap + 15; + layout.row_gap = 2; + layout.col_gap = 2; + layout.at = layout.bounds_min; + ui->layout = &layout; + + + ui_text(ui, lit_str("Hi there!")); + show = ui_toggle(ui, lit_str("my toggle"), show); + if (show) + { + ui_layout_row_begin(ui, 2); + { + ui_button(ui, lit_str("Sup")); + ui_button(ui, lit_str("you there")); + } + ui_layout_row_end(ui); + } + + ui_button(ui, lit_str("Hi there my good sir")); + edr_render_begin(state); ui_draw(&state->editor->ui); edr_render(state); diff --git a/src_v2/editor/lumenarium_editor_ui.cpp b/src_v2/editor/lumenarium_editor_ui.cpp index 5e397cf..647919b 100644 --- a/src_v2/editor/lumenarium_editor_ui.cpp +++ b/src_v2/editor/lumenarium_editor_ui.cpp @@ -80,6 +80,7 @@ ui_create(u32 widget_pool_cap, u32 verts_cap, Input_State* input, Allocator* a) }; ui_sprite_register(&result, (u8*)white_sprite, 4, 4, WHITE_SPRITE_ID); + ui_create_default_style_sheet(); return result; } @@ -166,7 +167,7 @@ ui_sprite_char_get_draw_cmd(UI* ui, v3 at, u32 codepoint) }; result.pmin = at; result.pmin.XY += sprite.draw_offset; - result.pmin = v3_floor(result.pmin); + result.pmin.XY = v2_floor(result.pmin.XY); result.pmax = result.pmin + dim; result.baseline_after = v3{ result.pmax.x, at.y, at.z }; @@ -208,47 +209,6 @@ global bool show = false; internal void ui_draw(UI* ui) { - UI_Widget_Desc d0 = { - { - (UIWidgetStyle_Bg), - WHITE_V4, - BLACK_V4, - WHITE_SPRITE_ID, - }, - lit_str("Hi there!"), - v2{ 32.0f, 32.0f }, - v2{ 128.0f, 64.0f }, - }; - UI_Widget_Result r0 = ui_widget_push(ui, d0); - - UI_Widget_Desc d1 = d0; - d1.style.flags |= UIWidgetStyle_Outline | UIWidgetStyle_MouseClick | UIWidgetStyle_Text; - d1.style.color_bg = PINK_V4;//{ 0.1f, 0.1f, 0.1f, 1.0f }; // - d1.style.color_fg = GREEN_V4; - d1.p_min = v2{ 512, 32 }; - d1.p_max = v2{ 640, 128 }; - d1.string = lit_str("Hello there my friend, what's going on?"); - UI_Widget_Result r1 = ui_widget_push(ui, d1); - bool clicked_r1 = has_flag(r1.flags, UIWidgetResult_MouseLeft_WentUp); - if (clicked_r1) show = !show; - - UI_Widget_Result r2 = {}; - if (show) - { - UI_Widget_Desc d2 = d1; - d1.string = lit_str("Hello There"); - d1.p_min = v2{ 560, 64 }; - d1.p_max = v2{ 700, 256 }; - r2 = ui_widget_push(ui, d1); - } - - bool clicked_r2 = has_flag(r2.flags, UIWidgetResult_MouseLeft_WentUp); - assert( - (!clicked_r1 && !clicked_r2) || - (clicked_r1 && !clicked_r2) || - (!clicked_r1 && clicked_r2) - ); - u32 widget_count = ui->widgets.free_len; r32 range_min = -10; r32 range_max = -1; @@ -434,21 +394,22 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s if (has_flag(child->desc.style.flags, UIWidgetStyle_Outline)) { ui_sprite_push(ui, bg_min, bg_max, WHITE_SPRITE_ID, color_fg); - bg_min += v3{ 3, 3, 0}; - bg_max -= v3{ 3, 3, 0}; + z_at += z_step; + bg_min += v3{ 1, 1, 0}; + bg_max -= v3{ 1, 1, 0}; + } if (has_flag(child->desc.style.flags, UIWidgetStyle_Bg)) { - z_at += z_step; bg_min.z = z_at; bg_max.z = z_at; ui_sprite_push(ui, bg_min, bg_max, desc.style.sprite, color_bg); + z_at += z_step; } - if (has_flag(child->desc.style.flags, UIWidgetStyle_Text)) + if (has_flag(child->desc.style.flags, UIWidgetStyle_TextWrap | UIWidgetStyle_TextClip)) { - z_at += z_step + z_step; r32 space_width = ui->font_space_width; r32 to_baseline = ui->font_line_gap + ui->font_ascent; v3 line_offset = { 5, 3 + to_baseline, 0 }; @@ -471,6 +432,8 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s if (cmd.baseline_after.x >= desc.p_max.x - 5) { + if (has_flag(child->desc.style.flags, UIWidgetStyle_TextClip)) break; + baseline.x = baseline_x_start; baseline.y += ui->font_ascent + ui->font_descent + ui->font_line_gap; cmd = ui_sprite_char_get_draw_cmd(ui, baseline, (u32)at); @@ -495,12 +458,101 @@ ui_widgets_to_geometry_recursive(UI* ui, UI_Widget* widget, r32 z_start, r32 z_s } /////////////////////////////////////////// -// Specific Widget Implementations +// Layout Manager -global UI_Style_Sheet ui_default_style_sheet = { +internal void +ui_layout_row_begin(UI_Layout* layout, u32 cols) +{ + layout->mode = UILayout_Rows; + layout->cols = cols; +} +internal void +ui_layout_row_begin(UI* ui, u32 cols) { ui_layout_row_begin(ui->layout, cols); } + +internal void +ui_layout_row_end(UI_Layout* layout) +{ + layout->mode = UILayout_Columns; +} +internal void +ui_layout_row_end(UI* ui) { ui_layout_row_end(ui->layout); } + +internal UI_Layout_Bounds +ui_layout_get_next(UI_Layout* layout) +{ + UI_Layout_Bounds result = {}; + switch (layout->mode) { + case UILayout_Columns: + { + result.min = layout->at; + result.max = v2{ layout->bounds_max.x, layout->at.y + layout->row_height }; + layout->at = v2{ layout->bounds_min.x, result.max.y + layout->row_gap}; + } break; + case UILayout_Rows: + { + r32 col_width = (layout->bounds_max.x - layout->bounds_min.x) / layout->cols; + col_width -= (layout->cols - 1) * layout->col_gap; + result.min = layout->at; + result.max = v2{ layout->at.x + col_width, layout->at.y + layout->row_height }; + layout->at = v2{ result.max.x + layout->col_gap, layout->at.y }; + if (layout->at.x >= layout->bounds_max.x) + { + layout->at = v2{ + layout->bounds_min.x, + layout->at.y + layout->row_height + layout->row_gap + }; + } + } break; + + invalid_default_case; } + return result; +} +internal UI_Layout_Bounds +ui_layout_get_next(UI* ui) { return ui_layout_get_next(ui->layout); } + + +/////////////////////////////////////////// +// Specific Widget Implementations +// +// These all rely on a layout manager to make calling them simpler + +global UI_Style_Sheet ui_default_style_sheet = {}; + +internal void +ui_create_default_style_sheet() +{ + ui_default_style_sheet.styles[UIWidget_Text] = { + (UIWidgetStyle_TextWrap), v4{0,0,0,0}, WHITE_V4, WHITE_SPRITE_ID + }; + ui_default_style_sheet.styles[UIWidget_Button] = { + (UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseClick), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + ui_default_style_sheet.styles[UIWidget_Toggle] = { + (UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_MouseClick), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + ui_default_style_sheet.styles[UIWidget_Menu] = ui_default_style_sheet.styles[UIWidget_Toggle]; + ui_default_style_sheet.styles[UIWidget_Dropdown] = ui_default_style_sheet.styles[UIWidget_Toggle]; + + ui_default_style_sheet.styles[UIWidget_HSlider] = { + (UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDrag), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + ui_default_style_sheet.styles[UIWidget_VSlider] = { + (UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDrag), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + ui_default_style_sheet.styles[UIWidget_HScroll] = { + (UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDrag), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + ui_default_style_sheet.styles[UIWidget_VScroll] = { + (UIWidgetStyle_TextClip | UIWidgetStyle_Bg | UIWidgetStyle_Outline | UIWidgetStyle_MouseDrag), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + + ui_default_style_sheet.styles[UIWidget_Window] = { + (UIWidgetStyle_TextWrap), BLACK_V4, WHITE_V4, WHITE_SPRITE_ID + }; + }; internal UI_Widget_Style @@ -510,15 +562,46 @@ ui_get_style(UI* ui, UI_Widget_Kind kind) return ui_default_style_sheet.styles[kind]; } +internal UI_Widget_Desc +ui_layout_next_widget(UI* ui, UI_Widget_Kind kind) +{ + UI_Layout_Bounds b = ui_layout_get_next(ui); + UI_Widget_Desc d = {}; + d.p_min = b.min; + d.p_max = b.max; + d.style = ui_get_style(ui, kind); + return d; +} + internal void ui_text(UI* ui, String string) { - + UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Text); + d.string = string; + ui_widget_push(ui, d); } internal bool ui_button(UI* ui, String string) { - return false; + UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Button); + d.string = string; + UI_Widget_Result r = ui_widget_push(ui, d); + return has_flag(r.flags, UIWidgetResult_MouseLeft_WentUp); } +internal bool +ui_toggle(UI* ui, String string, bool value) +{ + UI_Widget_Desc d = ui_layout_next_widget(ui, UIWidget_Button); + if (value) { + v4 t = d.style.color_fg; + d.style.color_fg = d.style.color_bg; + d.style.color_bg = t; + } + d.string = string; + UI_Widget_Result r = ui_widget_push(ui, d); + bool result = value; + if (has_flag(r.flags, UIWidgetResult_MouseLeft_WentUp)) result = !result; + return result; +} diff --git a/src_v2/editor/lumenarium_editor_ui.h b/src_v2/editor/lumenarium_editor_ui.h index 23eadc8..cd8be05 100644 --- a/src_v2/editor/lumenarium_editor_ui.h +++ b/src_v2/editor/lumenarium_editor_ui.h @@ -32,10 +32,11 @@ enum { UIWidgetStyle_None = 0, UIWidgetStyle_Bg = 1, - UIWidgetStyle_Text = 2, - UIWidgetStyle_Outline = 4, - UIWidgetStyle_MouseClick = 8, - UIWidgetStyle_MouseDrag = 16, + UIWidgetStyle_TextClip = 2, + UIWidgetStyle_TextWrap = 4, + UIWidgetStyle_Outline = 8, + UIWidgetStyle_MouseClick = 16, + UIWidgetStyle_MouseDrag = 32, }; // akin to a css class, could be used to style multiple @@ -119,6 +120,34 @@ struct UI_Widget_Pool UI_Widget* active_parent; }; +enum UI_Layout_Mode +{ + // each element takes up a whole row + UILayout_Columns, + + // each element takes up one column in the row. If you overflow, + // the layout manager overflows to the next row + UILayout_Rows, +}; + +struct UI_Layout +{ + v2 bounds_min; + v2 bounds_max; + r32 row_height; + r32 row_gap; + r32 col_gap; + v2 at; + UI_Layout_Mode mode; + u32 cols; +}; + +struct UI_Layout_Bounds +{ + v2 min; + v2 max; +}; + struct UI { UI_Vertex* verts; @@ -138,6 +167,8 @@ struct UI UI_Widget_Id widget_next_hot; UI_Widget_Id widget_hot; + UI_Layout* layout; + // frames since these values were set u16 widget_next_hot_frames; u16 widget_hot_frames; @@ -162,6 +193,8 @@ internal void ui_draw(UI* ui); // Widgets +internal void ui_create_default_style_sheet(); + internal UI_Widget_Id ui_widget_id_create(u32 index_in_parent, String string); internal bool ui_widget_id_equals(UI_Widget_Id a, UI_Widget_Id b); internal bool ui_widget_id_is_valid(UI_Widget_Id h); diff --git a/src_v2/lumenarium_types.h b/src_v2/lumenarium_types.h index bf829e9..91dc9c1 100644 --- a/src_v2/lumenarium_types.h +++ b/src_v2/lumenarium_types.h @@ -244,6 +244,7 @@ hash_table_find(u32* ids, u32 cap, u32 value) // Vector Extensions #define v2_to_v3(xy,z) v3{(xy).x, (xy).y, (z)} +#define v2_floor(v) v2{ floorf(v.x), floorf(v.y) } #define v3_floor(v) v3{ floorf(v.x), floorf(v.y), floorf(v.z) } //////////////////////////////////////////////