Files
8bitMyGoUI/gallery/demos_data.go
T
ZacharyZhang-NY 455f5f2a05 Add chat components 321-345; named List rows, inert scroll views
Speech bubbles, a chat log that follows its end, a composer that sends
on Enter, typing dots, chat and channel lists, read receipts,
reactions, emoji and sticker pickers, mentions, date and unread rules,
system lines, member lists, user cards, a mailbox, mail reader and
letter, a notification bell, call controls, a voice meter, attachment
chips, link previews and polls.

pixel's editor takes EnterSends; display's Bubble takes a Fill and
exports EmojiSprite. data.List names its rows, which also lets typing
choose one. layout.ScrollArea and input.TextArea hold still under
Inert, and an inert scroll view leaves the Tab order until it wakes.
2026-10-12 05:02:36 -04:00

265 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package gallery
import (
"cmp"
"fmt"
"slices"
"strings"
"time"
"github.com/egoist/mygo/ui"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/data"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/display"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/icon"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/text"
)
var dataEntries = []Entry{
{151, "List", "列表", "data", "Thousands of rows, built as they scroll in. ▶ marks the chosen one.", demoList},
{152, "Table", "表格", "data", "Click a header to sort ▲, again for ▼. Odd rows are dithered.", demoTable},
{153, "Tree", "树", "data", "▸ opens, ▾ closes. Right opens, Left climbs back out.", demoTree},
{154, "Outline", "大纲", "data", "A tree of 2,000 floors that only builds what shows.", demoOutline},
{155, "GridView", "网格视图", "data", "Whole-dot cells in as many columns as fit; arrows go both ways.", demoGridView},
{156, "DescriptionList", "描述列表", "data", "Terms on the left, what they mean on the right.", demoDescriptionList},
{157, "Leaderboard", "排行榜", "data", "Medals for the top three; your row lights up.", demoLeaderboard},
{158, "Inventory", "物品栏", "data", "Arrows pick a slot. Drag one item onto another to swap them.", demoInventory},
{159, "ItemSlot", "物品格", "data", "An item with its stack, rarity edge and cooldown veil.", demoItemSlot},
{160, "Accordion", "手风琴", "data", "Open one answer and the others fold away.", demoAccordion},
{161, "Collapsible", "折叠区", "data", "One header that shows and hides what is under it.", demoCollapsible},
{162, "Carousel", "轮播", "data", "◀ ▶ turn the pages; it turns by itself unless you point at it.", demoCarousel},
{163, "Timeline", "时间线", "data", "Dated events down a line of markers.", demoTimeline},
}
type dataDemo struct {
list, row, tile, slot, page, size, carousel, hit int
sort data.Sort
tree, floor string
faq []bool
secret bool
quests, bench, party []string
bag []data.Item
rights [][]bool
filters []bool
name string
level float64
hard bool
logs int
loading time.Time
query string
}
func dataState(c *ui.Context) *dataDemo {
return ui.Local(c.Root(), demoKey("data"), func() dataDemo {
return dataDemo{size: 20, tree: "0", floor: "R1", faq: []bool{true, false, false},
quests: []string{"Find the key", "Save the cat", "Beat the boss", "Buy a potion"},
bench: []string{"Dax", "Eko", "Fay"}, party: []string{"Aria", "Brom"},
bag: []data.Item{{Sprite: icon.Potion, Name: "Potion", Count: 5}, {Sprite: icon.Drop, Name: "Ether", Count: 2, Rarity: display.Uncommon},
{Sprite: icon.Sword, Name: "Sword", Rarity: display.Rare}, {Sprite: icon.Shield, Name: "Shield", Rarity: display.Epic},
{Sprite: icon.Crown, Name: "Crown", Rarity: display.Legendary}, {Sprite: icon.Gem, Name: "Gem", Count: 12, Rarity: display.Rare},
{}, {Sprite: icon.Key, Name: "Key"}, {}, {}, {Sprite: icon.Scroll, Name: "Map scroll"}, {}},
rights: [][]bool{{true, false, false}, {false, true, false}, {true, true, true}},
filters: []bool{false, true, false, false}, name: "Aria", level: 7, logs: 20}
})
}
var horde = strings.Fields("Slime Bat Goblin Ghost Golem Imp Kobold Lich Mimic Ogre Orc Pixie Rat Skeleton Snake Spider Troll Wisp Wolf Wyrm Zombie Harpy Hydra Kraken Basilisk Djinn Gargoyle Manticore Wyvern Yeti")
func demoList(c *ui.Context, log func(string)) {
s := dataState(c)
r := data.List(c, "Monsters", len(horde), &s.list, data.ListOptions{}, func(i int) string { return horde[i] }, func(i int) {
pixel.Text(c, horde[i], pixel.TextOptions{})
})
r.Element.Width(pixel.K(c).D(140))
if r.Changed {
log("chose " + horde[s.list])
}
if r.Submitted {
log("opened " + horde[s.list])
}
}
var roster = []struct {
name, class string
lv int
}{{"Aria", "Knight", 7}, {"Brom", "Monk", 5}, {"Cyra", "Mage", 9}, {"Dax", "Thief", 4}, {"Eko", "Bard", 6},
{"Fay", "Cleric", 8}, {"Gus", "Ranger", 3}, {"Hal", "Knight", 10}, {"Ivy", "Mage", 2}, {"Jun", "Monk", 11}}
func demoTable(c *ui.Context, log func(string)) {
s := dataState(c)
order := make([]int, len(roster))
for i := range order {
order[i] = i
}
slices.SortStableFunc(order, func(a, b int) int {
x, y := roster[a], roster[b]
d := [3]int{cmp.Compare(x.name, y.name), cmp.Compare(x.class, y.class), cmp.Compare(x.lv, y.lv)}[s.sort.Column]
if s.sort.Desc {
return -d
}
return d
})
cols := []data.Column{{Title: "Name", Width: 50}, {Title: "Class", Width: 56}, {Title: "LV", Width: 30}}
r := data.Table(c, "Roster", cols, len(roster), &s.sort, &s.row, data.TableOptions{}, func(row, col int) string {
h := roster[order[row]]
return [3]string{h.name, h.class, fmt.Sprint(h.lv)}[col]
})
if r.Sorted {
log(fmt.Sprintf("sorted by %s, desc %v", cols[s.sort.Column].Title, s.sort.Desc))
}
if r.Changed {
log("chose row " + fmt.Sprint(s.row))
}
if r.Submitted {
log("opened " + roster[order[s.row]].name)
}
}
func demoTree(c *ui.Context, log func(string)) {
s := dataState(c)
roots := []data.TreeNode{
{Label: "Bag", Children: []data.TreeNode{{Label: "Potions", Children: []data.TreeNode{{Label: "Potion ×5"}, {Label: "Ether ×2"}}}, {Label: "Tent"}}},
{Label: "Key items", Children: []data.TreeNode{{Label: "Old key"}, {Label: "Map scroll"}}},
{Label: "Gold: 120"},
}
r := data.Tree(c, "Items", roots, &s.tree, data.TreeOptions{})
if r.Changed {
log("chose " + s.tree)
}
if r.Toggled {
log("opened or closed " + s.tree)
}
}
func demoOutline(c *ui.Context, log func(string)) {
s := dataState(c)
roots := make([]string, 8)
for i := range roots {
roots[i] = fmt.Sprintf("R%d", i+1)
}
children := func(k string) []string {
n := map[int]int{0: 12, 1: 20}[strings.Count(k, "/")]
var out []string
for i := range n {
out = append(out, fmt.Sprintf("%s/%d", k, i+1))
}
return out
}
label := func(k string) string {
parts := strings.Split(k, "/")
name := []string{"Region " + parts[0][1:], "Dungeon ", "Floor B"}[len(parts)-1]
if len(parts) > 1 {
name += parts[len(parts)-1]
}
return name
}
r := data.Outline(c, "World", roots, children, label, &s.floor, data.OutlineOptions{})
r.Element.Width(pixel.K(c).D(160))
if r.Changed {
log("chose " + label(s.floor))
}
if r.Submitted {
log("entered " + label(s.floor))
}
}
var tiles = []*pixel.Sprite{icon.Coin, icon.Gem, icon.Potion, icon.Sword, icon.Shield, icon.Chest, icon.Crown, icon.Scroll, icon.Flame, icon.Leaf}
func demoGridView(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := dataState(c)
r := data.GridView(c, "Loot", 200, &s.tile, data.GridViewOptions{CellWidth: 24, CellHeight: 24, Height: 100}, func(i int) {
ui.Box(c).Grow(1).AlignItems(ui.Center).Justify(ui.Center).Children(func() {
display.Icon(c, tiles[i%len(tiles)], display.IconOptions{Label: fmt.Sprintf("loot %d", i)})
})
})
r.Element.Width(k.D(200))
if r.Changed {
log(fmt.Sprintf("chose loot %d", s.tile))
}
if r.Submitted {
log(fmt.Sprintf("took loot %d", s.tile))
}
}
func demoDescriptionList(c *ui.Context, log func(string)) {
ui.Box(c).Width(pixel.K(c).D(220)).Children(func() {
data.DescriptionList(c, [][2]string{{"Class", "Knight"}, {"Weapon", "Rusty sword"},
{"Home", "Castle Town, two screens west of the cave"}, {"Motto", "It is dangerous to go alone."}}, data.DescriptionListOptions{TermWidth: 50})
})
}
func demoLeaderboard(c *ui.Context, log func(string)) {
scores := []data.Score{{Name: "ZAK", Score: 98400}, {Name: "MOM", Score: 87150}, {Name: "AAA", Score: 80000}, {Name: "BOB", Score: 64200}, {Name: "YOU", Score: 51300}, {Name: "KEN", Score: 32000}}
ui.Box(c).Width(pixel.K(c).D(160)).Children(func() {
data.Leaderboard(c, scores, data.LeaderboardOptions{Player: 4})
})
}
func demoInventory(c *ui.Context, log func(string)) {
s := dataState(c)
r := data.Inventory(c, "Bag", s.bag, &s.slot, data.InventoryOptions{})
if r.Swapped {
log("swapped slots")
}
if r.Changed {
log(fmt.Sprintf("slot %d: %s", s.slot, s.bag[s.slot].Name))
}
}
func demoItemSlot(c *ui.Context, log func(string)) {
ui.Row(c).Gap(pixel.K(c).D(6)).Children(func() {
data.ItemSlot(c, data.Item{Sprite: icon.Potion, Name: "Potion", Count: 3}, data.ItemSlotOptions{})
data.ItemSlot(c, data.Item{Sprite: icon.Crown, Name: "Crown", Rarity: display.Legendary}, data.ItemSlotOptions{Selected: true})
data.ItemSlot(c, data.Item{Sprite: icon.Bolt, Name: "Bolt scroll", Rarity: display.Rare}, data.ItemSlotOptions{Cooldown: 0.5})
data.ItemSlot(c, data.Item{Name: "Empty"}, data.ItemSlotOptions{})
})
}
func demoAccordion(c *ui.Context, log func(string)) {
s := dataState(c)
qs := []string{"How do I save?", "Where is the key?", "Can I pet the dog?"}
as := []string{"Visit any inn, or press START.", "Under the third torch.", "Yes. Always yes."}
ui.Box(c).Width(pixel.K(c).D(180)).Children(func() {
if data.Accordion(c, "Help", qs, s.faq, data.AccordionOptions{}, func(i int) {
text.Paragraph(c, as[i], text.ParagraphOptions{})
}).Changed {
log(fmt.Sprintf("open %v", s.faq))
}
})
}
func demoCollapsible(c *ui.Context, log func(string)) {
s := dataState(c)
if data.Collapsible(c, "Secret moves", &s.secret, data.CollapsibleOptions{}, func() {
pixel.Text(c, "↑ ↑ ↓ ↓ ← → ← → B A", pixel.TextOptions{})
}).Changed {
log(fmt.Sprintf("open %v", s.secret))
}
}
func demoCarousel(c *ui.Context, log func(string)) {
k := pixel.K(c)
s := dataState(c)
tips := []struct {
art *pixel.Sprite
line string
}{{icon.Heart, "Hearts heal you."}, {icon.Key, "Keys open doors."}, {icon.Coin, "Coins buy things."}}
if data.Carousel(c, "Tips", len(tips), &s.carousel, data.CarouselOptions{Every: 4}, func(i int) {
ui.Column(c).Width(k.D(120)).AlignItems(ui.Center).Gap(k.D(4)).Children(func() {
display.Icon(c, tips[i].art, display.IconOptions{Scale: 2})
pixel.Text(c, tips[i].line, pixel.TextOptions{})
})
}).Changed {
log(fmt.Sprintf("page %d", s.carousel+1))
}
}
func demoTimeline(c *ui.Context, log func(string)) {
ui.Box(c).Width(pixel.K(c).D(200)).Children(func() {
data.Timeline(c, []data.Event{{Date: "1985", Text: "A plumber jumps into a pipe."}, {Date: "1986", Text: "A boy in green finds a sword."},
{Date: "1987", Text: "A last fantasy begins."}, {Date: "1991", Text: "A blue hedgehog runs very fast."}}, data.TimelineOptions{})
})
}