Files
android-ui-dogfooding/m3_demo.odin
T

213 lines
6.2 KiB
Odin
Raw Normal View History

2026-09-04 14:26:42 +02:00
package main
import "core:fmt"
import engine "../zephr"
// A gallery of the M3 components, laid out the way the spec's own catalogue is:
// a scrolling body under the top app bar, a navigation bar pinned to the bottom.
demo_nav_index := 0
demo_switch_a := true
demo_switch_b := false
demo_check_a := true
demo_check_b := false
demo_radio := 0
demo_slider: f32 = 0.4
demo_chip_fav := true
demo_chip_new := false
demo_progress: f32 = 0.65
@(private = "file")
section :: proc(title: string, id: engine.Id) {
engine.ui_spacer(engine.ui_px(24, 1))
engine.ui_set_next_font_size(M3_TITLE_SMALL)
engine.ui_set_next_font_weight(M3_WEIGHT_MEDIUM)
engine.ui_set_next_text_color(m3.primary)
engine.ui_text_with_id(title, id)
engine.ui_spacer(engine.ui_px(12, 1))
}
@(private = "file")
row_begin :: proc(id: engine.Id, caller := #caller_location) {
engine.ui_set_next_width(engine.ui_fill())
engine.ui_set_next_height(engine.ui_children_sum(1))
engine.ui_set_next_align_y(.Center)
open_row(id, caller)
}
@(private = "file")
gap :: proc() {
engine.ui_spacer(engine.ui_px(8, 1))
}
m3_demo_screen :: proc() {
engine.ui_set_next_width(engine.ui_percent(1, 1))
engine.ui_set_next_height(engine.ui_percent(1, 1))
engine.ui_set_next_background_color(m3.surface)
engine.ui_set_next_flags({.DrawBackground})
engine.ui_column() // pops at the end of this proc
bar := ui_app_bar({
title = "Material 3",
leading = ICON_MENU,
actions = {ICON_SEARCH, ICON_MORE_VERT},
top_inset = insets.top,
})
if bar.leading_clicked {
show_toast("menu")
}
if bar.action_clicked >= 0 {
show_toast(bar.action_clicked == 0 ? "search" : "more")
}
// Body takes the space between the bar and the nav bar, and scrolls.
engine.ui_set_next_width(engine.ui_fill())
engine.ui_set_next_height(engine.ui_fill())
open_scroll_column(1)
engine.ui_padding(16, {.Left, .Right})
// -- Buttons
section("Common buttons", 100)
row_begin(101); {
_ = m3_button("Filled", .Filled, 110)
gap()
_ = m3_button("Tonal", .Tonal, 111)
gap()
_ = m3_button("Outlined", .Outlined, 112)
close_box()
}
engine.ui_spacer(engine.ui_px(8, 1))
row_begin(102); {
_ = m3_button("Elevated", .Elevated, 113)
gap()
_ = m3_button("Text", .Text, 114)
gap()
_ = m3_button("Disabled", .Filled, 115, false)
close_box()
}
engine.ui_spacer(engine.ui_px(8, 1))
row_begin(103); {
if m3_button_icon("Add item", ICON_ADD, .Filled, 116) {
show_toast("added")
}
gap()
_ = m3_button_icon("Share", ICON_SHARE, .Outlined, 117)
close_box()
}
// -- FABs
section("FAB", 200)
row_begin(201); {
_ = m3_fab(ICON_ADD, .Small, 210)
gap()
_ = m3_fab(ICON_EDIT, .Regular, 211)
gap()
_ = m3_fab_extended("Compose", ICON_EDIT, 212)
close_box()
}
// -- Chips
section("Chips", 300)
row_begin(301); {
_ = m3_chip_assist("Assist", ICON_STAR, 310)
gap()
_ = m3_chip_filter("Favourites", &demo_chip_fav, 311)
gap()
_ = m3_chip_filter("New", &demo_chip_new, 312)
close_box()
}
// -- Selection controls
section("Selection", 400)
row_begin(401); {
_ = m3_switch(&demo_switch_a, 410)
gap()
_ = m3_switch(&demo_switch_b, 411)
gap()
_ = m3_checkbox(&demo_check_a, 412)
_ = m3_checkbox(&demo_check_b, 413)
if m3_radio(demo_radio == 0, 414) {
demo_radio = 0
}
if m3_radio(demo_radio == 1, 415) {
demo_radio = 1
}
close_box()
}
// -- Slider + progress
section("Slider", 500)
_ = m3_slider(&demo_slider, 510)
engine.ui_set_next_font_size(M3_BODY_SMALL)
engine.ui_set_next_text_color(m3.on_surface_variant)
engine.ui_text_with_id(fmt.tprintf("value %.2f", demo_slider), 511)
section("Progress", 600)
m3_progress_linear(demo_progress, 610)
// -- Cards
section("Cards", 700)
m3_card_begin(.Elevated, 710); {
engine.ui_set_next_font_size(M3_TITLE_MEDIUM)
engine.ui_set_next_font_weight(M3_WEIGHT_MEDIUM)
engine.ui_set_next_text_color(m3.on_surface)
engine.ui_text_with_id("Elevated card", 711)
engine.ui_spacer(engine.ui_px(4, 1))
engine.ui_set_next_font_size(M3_BODY_MEDIUM)
engine.ui_set_next_text_color(m3.on_surface_variant)
engine.ui_text_with_id("surfaceContainerLow", 712)
m3_card_end()
}
engine.ui_spacer(engine.ui_px(8, 1))
m3_card_begin(.Filled, 720); {
engine.ui_set_next_font_size(M3_TITLE_MEDIUM)
engine.ui_set_next_font_weight(M3_WEIGHT_MEDIUM)
engine.ui_set_next_text_color(m3.on_surface)
engine.ui_text_with_id("Filled card", 721)
m3_card_end()
}
engine.ui_spacer(engine.ui_px(8, 1))
m3_card_begin(.Outlined, 730); {
engine.ui_set_next_font_size(M3_TITLE_MEDIUM)
engine.ui_set_next_font_weight(M3_WEIGHT_MEDIUM)
engine.ui_set_next_text_color(m3.on_surface)
engine.ui_text_with_id("Outlined card", 731)
m3_card_end()
}
// -- Lists
section("List", 800)
if m3_list_item("Notifications", ICON_NOTIFICATIONS, "12", 810) {
show_toast("notifications")
}
m3_divider(811)
if m3_list_item("Bookmarks", ICON_BOOKMARK, "", 812) {
show_toast("bookmarks")
}
m3_divider(813)
if m3_list_item("Settings", ICON_SETTINGS, "", 814) {
show_toast("settings")
}
// -- Snackbar
section("Snackbar", 900)
if m3_snackbar("Item moved to trash", "Undo", 910) {
show_toast("undo")
}
engine.ui_spacer(engine.ui_px(24, 1))
// Close the scroll body so the nav bar is a sibling of it, not content
// inside it -- that is what keeps it pinned to the bottom.
close_box()
items := []M3_Nav_Item{
{ICON_HOME, "Home"},
{ICON_FAVORITE, "Saved"},
{ICON_PERSON, "Profile"},
}
if m3_nav_bar(items, &demo_nav_index, insets.bottom, 1000) {
show_toast(items[demo_nav_index].label)
}
}