Skip to content

Instantly share code, notes, and snippets.

@naranyala
Created June 22, 2025 09:27
Show Gist options
  • Save naranyala/09b8c02be1c8f196f972a3e644e546e1 to your computer and use it in GitHub Desktop.
Save naranyala/09b8c02be1c8f196f972a3e644e546e1 to your computer and use it in GitHub Desktop.
dashboard layout build with odin+raylib
package main
import "core:slice"
import "core:strings"
import rl "vendor:raylib"
main :: proc() {
// Initialize window
rl.InitWindow(1000, 600, "Dropdown List With Shape Names")
defer rl.CloseWindow()
rl.SetTargetFPS(60)
// UI constants
WINDOW_WIDTH :: 1000
WINDOW_HEIGHT :: 600
SIDEBAR_WIDTH :: 300
DROPDOWN_X :: 20
DROPDOWN_Y :: 20
DROPDOWN_WIDTH :: 260
DROPDOWN_HEIGHT :: 30
TEXT_SIZE :: 20
LIST_X :: 20
LIST_Y :: 120 // Moved down to avoid overlap
LIST_LINE_HEIGHT :: 25
CLICK_COOLDOWN :: 0.1 // Debounce time in seconds
DISPLAY_X :: SIDEBAR_WIDTH + 20
DISPLAY_Y :: WINDOW_HEIGHT / 2
DISPLAY_TEXT_SIZE :: 40
// UI states
show_dropdown := false
dropdown_pos := rl.Vector2{f32(DROPDOWN_X), f32(DROPDOWN_Y)}
dropdown_width: f32 = DROPDOWN_WIDTH
dropdown_height: f32 = DROPDOWN_HEIGHT
selected_dropdown := -1
last_mouse_press_time: f64 = -1 // For debouncing
selected_shape: string // Selected shape name
// Dropdown items and precomputed C strings
dropdown_items := []string{"2D Shapes", "3D Shapes"}
dropdown_cstrings: [dynamic]cstring
defer delete(dropdown_cstrings)
for item in dropdown_items {
append(&dropdown_cstrings, strings.clone_to_cstring(item))
}
// Shape lists and precomputed C strings
shape_2d := []string{"Circle", "Rectangle", "Triangle", "Line", "Ellipse", "Polygon"}
shape_3d := []string{"Cube", "Sphere", "Cylinder", "Torus", "Cone", "Plane"}
shape_2d_cstrings, shape_3d_cstrings: [dynamic]cstring
defer delete(shape_2d_cstrings)
defer delete(shape_3d_cstrings)
for item in shape_2d {
append(&shape_2d_cstrings, strings.clone_to_cstring(item))
}
for item in shape_3d {
append(&shape_3d_cstrings, strings.clone_to_cstring(item))
}
for !rl.WindowShouldClose() {
current_time := rl.GetTime()
rl.BeginDrawing()
defer rl.EndDrawing()
rl.ClearBackground(rl.RAYWHITE)
// --- Sidebar ---
rl.DrawRectangle(0, 0, SIDEBAR_WIDTH, WINDOW_HEIGHT, rl.LIGHTGRAY)
// --- Dropdown Toggle Button ---
toggle_rect := rl.Rectangle {
dropdown_pos.x,
dropdown_pos.y,
dropdown_width,
dropdown_height,
}
rl.DrawRectangleRec(toggle_rect, rl.WHITE)
toggle_text :=
selected_dropdown >= 0 ? dropdown_cstrings[selected_dropdown] : "Select Category"
rl.DrawText(
toggle_text,
cast(i32)(dropdown_pos.x + 10),
cast(i32)(dropdown_pos.y + 8),
TEXT_SIZE,
rl.DARKGRAY,
)
// --- Dropdown Items ---
dropdown_bounds := toggle_rect
dropdown_items_rects: [dynamic]rl.Rectangle
defer delete(dropdown_items_rects)
if show_dropdown {
for i in 0 ..< len(dropdown_items) {
item_y := dropdown_pos.y + f32(i + 1) * dropdown_height
item_rect := rl.Rectangle{dropdown_pos.x, item_y, dropdown_width, dropdown_height}
append(&dropdown_items_rects, item_rect)
dropdown_bounds.height += dropdown_height // Expand bounds to include items
// Highlight on hover
is_hovered := rl.CheckCollisionPointRec(rl.GetMousePosition(), item_rect)
color := is_hovered ? rl.GRAY : rl.WHITE
rl.DrawRectangleRec(item_rect, color)
rl.DrawRectangleLines(
cast(i32)item_rect.x,
cast(i32)item_rect.y,
cast(i32)item_rect.width,
cast(i32)item_rect.height,
rl.DARKGRAY,
)
rl.DrawText(
dropdown_cstrings[i],
cast(i32)(item_rect.x + 10),
cast(i32)(item_rect.y + 8),
TEXT_SIZE,
rl.DARKGRAY,
)
}
}
// --- Shape List ---
shape_list_rects: [dynamic]rl.Rectangle
defer delete(shape_list_rects)
if selected_dropdown >= 0 && selected_dropdown < len(dropdown_items) {
// Calculate dynamic list position to avoid overlap
list_start_y: i32 = LIST_Y
if show_dropdown {
// If dropdown is open, start list below the dropdown items
dropdown_bottom := dropdown_pos.y + f32(len(dropdown_items) + 1) * dropdown_height
list_start_y = cast(i32)(dropdown_bottom + 20) // Add some padding
}
selected_list: []cstring
selected_list_strings: []string
switch selected_dropdown {
case 0:
selected_list = shape_2d_cstrings[:]
selected_list_strings = shape_2d
case 1:
selected_list = shape_3d_cstrings[:]
selected_list_strings = shape_3d
case:
selected_list = {}
selected_list_strings = {}
}
for i in 0 ..< len(selected_list) {
item_rect := rl.Rectangle {
f32(LIST_X),
f32(list_start_y + cast(i32)(i * LIST_LINE_HEIGHT)),
DROPDOWN_WIDTH,
f32(LIST_LINE_HEIGHT),
}
append(&shape_list_rects, item_rect)
is_hovered := rl.CheckCollisionPointRec(rl.GetMousePosition(), item_rect)
color := is_hovered ? rl.GRAY : rl.WHITE
rl.DrawRectangleRec(item_rect, color)
rl.DrawRectangleLines(
cast(i32)item_rect.x,
cast(i32)item_rect.y,
cast(i32)item_rect.width,
cast(i32)item_rect.height,
rl.LIGHTGRAY,
)
rl.DrawText(
selected_list[i],
cast(i32)LIST_X + 10,
cast(i32)(list_start_y + cast(i32)(i * LIST_LINE_HEIGHT) + 2),
TEXT_SIZE,
rl.MAROON,
)
}
}
// --- Right Section: Display Selected Shape ---
if selected_shape != "" {
shape_cstring := strings.clone_to_cstring(selected_shape)
defer delete(shape_cstring)
rl.DrawText(shape_cstring, DISPLAY_X, DISPLAY_Y, DISPLAY_TEXT_SIZE, rl.BLACK)
} else {
rl.DrawText("Select a shape", DISPLAY_X, DISPLAY_Y, DISPLAY_TEXT_SIZE, rl.GRAY)
}
// --- Handle Input ---
if rl.IsMouseButtonPressed(rl.MouseButton.LEFT) &&
current_time >= last_mouse_press_time + CLICK_COOLDOWN {
mouse := rl.GetMousePosition()
last_mouse_press_time = current_time
// Dropdown toggle
if rl.CheckCollisionPointRec(mouse, toggle_rect) {
show_dropdown = !show_dropdown
} else if show_dropdown {
// Check dropdown item selection
dropdown_item_clicked := false
for i in 0 ..< len(dropdown_items_rects) {
if rl.CheckCollisionPointRec(mouse, dropdown_items_rects[i]) {
selected_dropdown = i
show_dropdown = false
selected_shape = "" // Reset shape selection
dropdown_item_clicked = true
break
}
}
// Close dropdown if clicked outside
if !dropdown_item_clicked {
show_dropdown = false
}
}
// Shape list selection (only if dropdown is not open)
if !show_dropdown && selected_dropdown >= 0 {
selected_list_strings: []string
switch selected_dropdown {
case 0:
selected_list_strings = shape_2d
case 1:
selected_list_strings = shape_3d
case:
selected_list_strings = {}
}
for i in 0 ..< len(shape_list_rects) {
if rl.CheckCollisionPointRec(mouse, shape_list_rects[i]) {
selected_shape = selected_list_strings[i]
break
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment