diff options
author | talha <sarcxd@gmail.com> | 2025-04-06 13:51:01 +0500 |
---|---|---|
committer | talha <sarcxd@gmail.com> | 2025-04-06 13:51:01 +0500 |
commit | def19703ae126fcc73f38abacc3cfd41a515302a (patch) | |
tree | 75a738503fa46d42f996a3f4f4e271aedcddb839 | |
parent | 188ea2eb92bae770dcfbdef67984986cbaf2c9ea (diff) |
Added dropdown button
-rwxr-xr-x | source/main.cpp | 330 | ||||
-rw-r--r-- | source/renderer/renderer.cpp | 3 |
2 files changed, 235 insertions, 98 deletions
diff --git a/source/main.cpp b/source/main.cpp index 2280e94..214ddff 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -532,7 +532,7 @@ struct UiButton { // @description: This is a very scrappy function that goes through the button render // logic and pre-computes items like text dimensions // It does not support, tabs and newlines -Vec2 ui_button_get_text_dims(GLRenderer renderer, char *text, r32 font_size) { +Vec2 ui_get_text_dims(GLRenderer renderer, char *text, r32 font_size) { Vec2 max_dims = Vec2{0, 0}; u32 running_index = 0; @@ -591,7 +591,7 @@ ButtonState ui_button(GameState state, UiButton button) { if (!font_size) { font_size = 0.6f * quad_size.y; } - Vec2 txt_dims = ui_button_get_text_dims(state.renderer, + Vec2 txt_dims = ui_get_text_dims(state.renderer, button.text.buffer, font_size); r32 txt_base_offsety = -5.0f*state.render_scale.y; @@ -650,6 +650,197 @@ ButtonState ui_button(GameState state, UiButton button) { return btn_state; } +struct UiDropdownButton { + r32 font_size; + Vec3 position; + Vec2 size; + b8 is_toggled; + u32 selected_option_index; + u32 option_count; + Str256 *options; + + Vec3 bgd_color_primary; + Vec3 bgd_color_secondary; + Vec3 bgd_color_hover; + Vec3 bgd_color_pressed; +}; + +Vec2 ui_center_text( + GameState state, + Str256 text, + r32 font_size, + Vec2 container_pos, + Vec2 container_size) +{ + // @step: ui position text + Vec2 text_dims = ui_get_text_dims( + state.renderer, + text.buffer, + font_size); + + r32 txt_base_offsety = -5.0f*state.render_scale.y; + Vec2 txt_center_offset = Vec2{ + (container_size.x - text_dims.x)/2.0f, + (container_size.y - text_dims.y)/2.0f + txt_base_offsety + }; + Vec2 txt_pos = container_pos + txt_center_offset; + + return txt_pos; +} + +void ui_dropdown_button(GameState state, UiDropdownButton *dropdown) { + r32 font_size = dropdown->font_size * state.render_scale.y; + + // @component: value_box + Vec3 value_pos = Vec3{ + dropdown->position.x*state.render_scale.x, + dropdown->position.y*state.render_scale.y, + dropdown->position.z + }; + + Vec2 value_size = dropdown->size*state.render_scale; + + Vec3 value_pos_adjusted = value_pos; + value_pos_adjusted.x += value_size.x/2.0f; + value_pos_adjusted.y += value_size.y/2.0f; + + gl_draw_quad( + state.renderer.quad, + &state.renderer.ui_cam, + value_pos_adjusted, + value_size, + dropdown->bgd_color_primary + ); + + // @component: toggle_button + Vec3 toggle_pos = Vec3{ + value_pos.x + value_size.x, + value_pos.y, + value_pos.z + }; + Vec2 toggle_size = Vec2{40.0f*state.render_scale.x, value_size.y}; + Vec3 toggle_pos_adjusted = toggle_pos; + toggle_pos_adjusted.x += toggle_size.x/2.0f; + toggle_pos_adjusted.y += toggle_size.y/2.0f; + + // @step: check if mouse on button + b8 is_mouse_on_button = 0; + { + Rect btn_rect = rect(toggle_pos.v2(), toggle_size); + is_mouse_on_button = ( + (state.mouse_position.x >= btn_rect.lb.x && + state.mouse_position.y >= btn_rect.lb.y) && + (state.mouse_position.x <= btn_rect.rt.x && + state.mouse_position.y <= btn_rect.rt.y) + ); + } + Vec3 toggle_color = dropdown->bgd_color_secondary; + if (is_mouse_on_button) { + if (state.mouse_down) { + toggle_color = dropdown->bgd_color_pressed; + } else if (state.mouse_up) { + dropdown->is_toggled = !dropdown->is_toggled; + } else { + toggle_color = dropdown->bgd_color_hover; + } + } + + Str256 value_text = dropdown->options[dropdown->selected_option_index]; + Vec2 value_text_pos = ui_center_text( + state, + value_text, + dropdown->font_size, + value_pos.v2(), + value_size); + + gl_draw_quad( + state.renderer.quad, + &state.renderer.ui_cam, + toggle_pos_adjusted, + toggle_size, + toggle_color + ); + gl_render_text( + &state.renderer, + value_text.buffer, + Vec3{ + value_text_pos.x, + value_text_pos.y, + value_pos.z}, + Vec3{0.0f, 0.0f, 0.0f}, + dropdown->font_size); + + // @component: dropdown_option + if (dropdown->is_toggled) { + Vec2 option_size = value_size; + for (int i = 0; i < dropdown->option_count; i++) { + Vec3 option_pos = Vec3{ + value_pos.x, + value_pos.y - (option_size.y*(i+1)), + value_pos.z + }; + Vec3 option_color = i%2 ? + Vec3{0.8f, 0.3f, 0.2f} : + Vec3{0.2f, 0.3f, 0.8f}; + + b8 is_mouse_on_option = 0; + { + Rect btn_rect = rect(option_pos.v2(), option_size); + is_mouse_on_option = ( + (state.mouse_position.x >= btn_rect.lb.x && + state.mouse_position.y >= btn_rect.lb.y) && + (state.mouse_position.x <= btn_rect.rt.x && + state.mouse_position.y <= btn_rect.rt.y)); + } + b8 is_option_clicked = 0; + if (is_mouse_on_option) { + if (state.mouse_down) { + option_color = dropdown->bgd_color_pressed; + } else if (state.mouse_up) { + option_color = dropdown->bgd_color_pressed; + is_option_clicked = 1; + } else { + option_color = dropdown->bgd_color_hover; + } + } + + if (is_option_clicked) { + dropdown->selected_option_index = i; + dropdown->is_toggled = 0; + } + + Str256 dropdown_text = dropdown->options[i]; + Vec2 txt_pos = ui_center_text( + state, + dropdown_text, + dropdown->font_size, + option_pos.v2(), + option_size); + + gl_draw_quad( + state.renderer.quad, + &state.renderer.ui_cam, + Vec3{ + option_pos.x + option_size.x/2.0f, + option_pos.y + option_size.y/2.0f, + option_pos.z}, + option_size, + option_color + ); + + gl_render_text( + &state.renderer, + dropdown_text.buffer, + Vec3{ + txt_pos.x, + txt_pos.y, + option_pos.z}, + Vec3{0.0f, 0.0f, 0.0f}, + dropdown->font_size); + } + } +} + // @section: main int main(int argc, char* argv[]) { @@ -692,7 +883,7 @@ int main(int argc, char* argv[]) SDL_WINDOWPOS_UNDEFINED, render_dims.x, render_dims.y, SDL_WINDOW_OPENGL - | SDL_WINDOW_FULLSCREEN_DESKTOP +// | SDL_WINDOW_FULLSCREEN_DESKTOP ); SDL_GLContext context = SDL_GL_CreateContext(window); @@ -807,6 +998,27 @@ int main(int argc, char* argv[]) renderer->ui_cam.view = renderer->cam_view; renderer->ui_cam.proj = renderer->cam_proj; + // ui stuff + + UiDropdownButton resolution_select = {0}; + resolution_select.font_size = 24.0f; + resolution_select.size = Vec2{120.0f, 40.0f}; + resolution_select.bgd_color_primary = Vec3{1.0f, 1.0f, 1.0f}; + resolution_select.bgd_color_secondary = Vec3{0.6f, 0.6f, 0.6f}; + resolution_select.bgd_color_hover = Vec3{0.8f, 0.8f, 0.8f}; + resolution_select.bgd_color_pressed = Vec3{0.4f, 0.4f, 0.4f}; + resolution_select.option_count = 3; + // @todo: Remove this memory allocation method + // Use a lifetime tied arena + resolution_select.options = (Str256 *)malloc( + resolution_select.option_count * + sizeof(Str256) + ); + resolution_select.selected_option_index = 1; + resolution_select.options[0] = str256("2560 x 1440"); + resolution_select.options[1] = str256("1920 x 1080"); + resolution_select.options[2] = str256("1280 x 720"); + // @thinking: level object handling // there should be a most smallest supported unit // smallest_size: 16x16 @@ -959,6 +1171,7 @@ int main(int argc, char* argv[]) game_screen = PAUSE_MENU; } else if (game_screen == SETTINGS_MENU) { game_screen = PAUSE_MENU; + // clean_up_settings_menu } else if (game_screen == PAUSE_MENU) { game_screen = GAMEPLAY; } @@ -1686,105 +1899,28 @@ int main(int argc, char* argv[]) // settings menu if (game_screen == SETTINGS_MENU) { - UiButton back_button = button; - - back_button.text = str256("Apply"); - back_button.position = Vec3{30.0f, 40.0f, entity_z[TEXT]}; + // resolution button + // + // @api: + // draw_ms_button(state) + // draw_ms_options(options) + // + // VS + // + // draw_ms_button(state, options) + u32 ms_font_size = 24.0f * state.render_scale.y; gl_render_text( renderer, "Resolution", Vec3{800, 800, entity_z[TEXT]}, - Vec3{0.0f, 0.0f, 0.0f}, 24.0f*state.render_scale.y + Vec3{0.0f, 0.0f, 0.0f}, ms_font_size ); - { - // @params - Vec3 ms_value_pos = Vec3{1000.0f, 800.0f, entity_z[TEXT]}; - Vec2 ms_value_size = Vec2{120.0f, 40.0f}; - - Vec3 ms_value_pos_adjusted = ms_value_pos; - ms_value_pos_adjusted.x += ms_value_size.x/2.0f; - ms_value_pos_adjusted.y += ms_value_size.y/2.0f; - - // draw multi select value box - gl_draw_quad( - state.renderer.quad, - &state.renderer.ui_cam, - ms_value_pos_adjusted, - ms_value_size, - Vec3{1.0f, 1.0f, 1.0f} - ); - static bool is_toggle_open = false; - { - Vec3 ms_toggle_pos = Vec3{ - ms_value_pos.x + ms_value_size.x, - ms_value_pos.y, - ms_value_pos.z - }; - Vec2 ms_toggle_size = Vec2{40.0f, ms_value_size.y}; - Vec3 ms_toggle_pos_adjusted = ms_toggle_pos; - ms_toggle_pos_adjusted.x += ms_toggle_size.x/2.0f; - ms_toggle_pos_adjusted.y += ms_toggle_size.y/2.0f; - - b8 is_mouse_on_button = 0; - { - // check_if_mouse_on_button - Rect btn_rect = rect(ms_toggle_pos.v2(), ms_toggle_size); - is_mouse_on_button = ( - (state.mouse_position.x >= btn_rect.lb.x && - state.mouse_position.y >= btn_rect.lb.y) && - (state.mouse_position.x <= btn_rect.rt.x && - state.mouse_position.y <= btn_rect.rt.y) - ); - } - Vec3 ms_toggle_color = {0.8f, 0.8f, 0.8f}; - if (is_mouse_on_button) { - if (state.mouse_down) { - // pressed - //btn_state = ButtonState::PRESSED; - ms_toggle_color = {0.8f, 0.8f, 0.8f}; - } else if (state.mouse_up) { - //btn_state = ButtonState::CLICK; - is_toggle_open = !is_toggle_open; - } else { - // hover - //btn_state = ButtonState::HOVER; - ms_toggle_color = {0.6f, 0.6f, 0.6f}; - } - } - gl_draw_quad( - state.renderer.quad, - &state.renderer.ui_cam, - ms_toggle_pos_adjusted, - ms_toggle_size, - ms_toggle_color - ); - if (is_toggle_open) { - { - // draw toggle option - Vec2 ms_option_size = Vec2{ms_value_size.x + ms_toggle_size.x, ms_value_size.y}; - Vec3 ms_option_pos = Vec3{ms_value_pos.x, ms_value_pos.y - ms_option_size.y, ms_value_pos.z}; - - gl_draw_quad( - state.renderer.quad, - &state.renderer.ui_cam, - Vec3{ms_option_pos.x + ms_option_size.x/2.0f, - ms_option_pos.y + ms_option_size.y/2.0f, - ms_option_pos.z}, - ms_option_size, - Vec3{1.0f, 0.0f, 0.0f} - ); - } - } - } - // multi-select drop down - Str256 dropdown_options[] = { - str256("2560x1440"), - str256("1920x1080"), - str256("1280x720") - }; - - - } + resolution_select.position = Vec3{ + 1000.0f, + 800.0f, + entity_z[TEXT] + }; + ui_dropdown_button(state, &resolution_select); } } diff --git a/source/renderer/renderer.cpp b/source/renderer/renderer.cpp index d61d85a..eabf57f 100644 --- a/source/renderer/renderer.cpp +++ b/source/renderer/renderer.cpp @@ -524,7 +524,8 @@ void gl_render_text( glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glUseProgram(renderer->ui_text.sp); - if (renderer->ui_cam.update) { + if (renderer->ui_cam.update) + { glUniformMatrix4fv( glGetUniformLocation( |