Add code components 366-385; ScrollArea Follow, editor sync
A terminal with history, a Go-colored code block, a log viewer that follows, a hex viewer, a memory map, a JSON tree, a line diff, a GAME OVER crash screen, an FPS meter, profiler bars, breakpoints, variables, command history, a shortcut list, a debug grid, a pixel editor that exports string art, a palette editor, a sprite sheet, a glyph map and a 6502 register view. layout.ScrollArea takes Follow, and ChatLog now uses it. data.TreeNode takes a Value drawn in its Slot. pixel gains Has, and Sprite.Art writes MustSprite art. pixel.Editor takes the caller's value at each input event, so a value changed between frames is never typed onto.
This commit is contained in:
42 files changed
+3415
-37
No files matched your search
@@ -0,0 +1,212 @@
|
||||
package gallery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/code"
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/input"
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
||||
)
|
||||
|
||||
var codeEntries = []Entry{
|
||||
{366, "Terminal", "终端", "code", "Type HELP. Up and Down bring back what you typed. XYZZY does nothing, as ever.", demoTerminal},
|
||||
{367, "CodeBlock", "代码块", "code", "Go, colored by slot: keywords, strings, numbers, builtins. COPY takes it all.", demoCodeBlock},
|
||||
{368, "LogViewer", "日志", "code", "Lines colored by level; pick the quietest worth seeing. It follows the newest.", demoLogViewer},
|
||||
{369, "HexViewer", "十六进制", "code", "A save file laid bare: offset, hex and ASCII. Arrows walk the bytes.", demoHexViewer},
|
||||
{370, "MemoryMap", "内存图", "code", "Each bank a block, filled as it fills. Red means start deleting sprites.", demoMemoryMap},
|
||||
{371, "JSONTree", "JSON树", "code", "JSON in its own order, types in their own colors. Right opens, Left closes.", demoJSONTree},
|
||||
{372, "DiffView", "差异", "code", "What changed between two versions, minus then plus.", demoDiffView},
|
||||
{373, "CrashScreen", "崩溃画面", "code", "GAME OVER in a blinking red frame, as the old guru had. CONTINUE when ready.", demoCrashScreen},
|
||||
{374, "FPSMeter", "帧率表", "code", "Frame times scroll by; green is on time, red is a stutter.", demoFPSMeter},
|
||||
{375, "ProfilerBars", "性能条", "code", "Where a frame's 16.7 ms went, nested like a family tree.", demoProfilerBars},
|
||||
}
|
||||
|
||||
type codeDemo struct {
|
||||
shell []string
|
||||
command string
|
||||
least code.Level
|
||||
logs []code.LogLine
|
||||
byte, pick int
|
||||
node, vr string
|
||||
crashed bool
|
||||
marks map[int]bool
|
||||
art string
|
||||
pal pixel.Palette
|
||||
frame int
|
||||
playing bool
|
||||
glyph rune
|
||||
step int
|
||||
frames []time.Duration
|
||||
last time.Time
|
||||
history []string
|
||||
}
|
||||
|
||||
func codeState(c *ui.Context) *codeDemo {
|
||||
now := pixel.K(c).Now()
|
||||
return ui.Local(c.Root(), demoKey("code"), func() codeDemo {
|
||||
return codeDemo{
|
||||
shell: []string{"8BIT-OS v1.0", "READY. TYPE HELP."}, least: code.Info,
|
||||
logs: []code.LogLine{
|
||||
{At: now.Add(-9 * time.Second), Level: code.Info, Text: "cartridge inserted"},
|
||||
{At: now.Add(-8 * time.Second), Level: code.Debug, Text: "blew on the contacts"},
|
||||
{At: now.Add(-6 * time.Second), Level: code.Warn, Text: "save battery low"},
|
||||
{At: now.Add(-3 * time.Second), Level: code.Error, Text: "princess in another castle"},
|
||||
},
|
||||
marks: map[int]bool{4: true}, art: heartArt, pal: *pixel.Current(c).Palette, glyph: 'A',
|
||||
history: []string{"load \"*\",8,1", "run", "help", "xyzzy"},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func demoTerminal(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
r := code.Terminal(c, "8BIT-OS", s.shell, &s.command, code.TerminalOptions{Width: 260})
|
||||
if r.Changed {
|
||||
log(fmt.Sprintf("input %q", s.command))
|
||||
}
|
||||
if r.Ran != "" {
|
||||
log("ran " + r.Ran)
|
||||
s.shell = append(s.shell, "$ "+r.Ran)
|
||||
switch strings.ToLower(strings.TrimSpace(r.Ran)) {
|
||||
case "help":
|
||||
s.shell = append(s.shell, "HELP LS CAT DATE CLEAR XYZZY")
|
||||
case "ls":
|
||||
s.shell = append(s.shell, "save.dat sprites/ music/ readme")
|
||||
case "cat readme":
|
||||
s.shell = append(s.shell, "IT'S DANGEROUS TO GO ALONE!")
|
||||
case "date":
|
||||
s.shell = append(s.shell, pixel.K(c).Now().Format("2006-01-02 15:04"))
|
||||
case "clear":
|
||||
s.shell = nil
|
||||
case "xyzzy":
|
||||
s.shell = append(s.shell, "NOTHING HAPPENS.")
|
||||
default:
|
||||
s.shell = append(s.shell, "SYNTAX ERROR")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const loop = `func main() {
|
||||
// One frame at a time, forever.
|
||||
hero := Hero{Name: "Aria", HP: 3}
|
||||
for frame := 0; ; frame++ {
|
||||
if hero.HP == 0 {
|
||||
panic("GAME OVER")
|
||||
}
|
||||
draw(hero, frame%60, nil, true)
|
||||
}
|
||||
}`
|
||||
|
||||
func demoCodeBlock(c *ui.Context, log func(string)) {
|
||||
if code.CodeBlock(c, "main.go", loop, code.CodeBlockOptions{}).Copied {
|
||||
log("copied main.go")
|
||||
}
|
||||
}
|
||||
|
||||
func demoLogViewer(c *ui.Context, log func(string)) {
|
||||
k := pixel.K(c)
|
||||
s := codeState(c)
|
||||
ui.Column(c).Gap(k.D(4)).Children(func() {
|
||||
if code.LogViewer(c, "Log", s.logs, &s.least, code.LogViewerOptions{Height: 80}).Changed {
|
||||
log(fmt.Sprintf("showing level %d and up", s.least))
|
||||
}
|
||||
if input.Button(c, "+ LINE", input.ButtonOptions{Size: input.Small}).Clicked {
|
||||
lv := code.Level(len(s.logs) % 4)
|
||||
s.logs = append(s.logs, code.LogLine{At: k.Now(), Level: lv, Text: fmt.Sprintf("tick %d", len(s.logs))})
|
||||
log("added a line")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var saveFile = []byte("SAVE\x01\x00\x00\x03ARIA\x00\x00\x00\x00HP\x00\x2aGOLD\x03\xe7\x00\x00\xff\xfe\x00\x10")
|
||||
|
||||
func demoHexViewer(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
if code.HexViewer(c, "save.dat", saveFile, &s.byte, code.HexViewerOptions{}).Changed {
|
||||
log(fmt.Sprintf("offset %04X", s.byte))
|
||||
}
|
||||
}
|
||||
|
||||
func demoMemoryMap(c *ui.Context, log func(string)) {
|
||||
code.MemoryMap(c, "Cartridge memory", []code.Bank{
|
||||
{Name: "ROM0", Used: 15 << 10, Size: 16 << 10}, {Name: "ROM1", Used: 9 << 10, Size: 16 << 10},
|
||||
{Name: "WRAM", Used: 3 << 10, Size: 8 << 10}, {Name: "VRAM", Used: 6 << 10, Size: 8 << 10},
|
||||
}, code.MemoryMapOptions{})
|
||||
}
|
||||
|
||||
const saveJSON = `{"player": {"name": "Aria", "level": 12, "alive": true,
|
||||
"items": ["sword", "potion", "map"], "pet": null}, "checkpoint": 3, "flags": {}}`
|
||||
|
||||
func demoJSONTree(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
if r := code.JSONTree(c, "save.json", saveJSON, &s.node, code.JSONTreeOptions{}); r.Changed || r.Toggled {
|
||||
log("at " + s.node)
|
||||
}
|
||||
}
|
||||
|
||||
func demoDiffView(c *ui.Context, log func(string)) {
|
||||
before := "speed = 4\njump = 2\nlives = 3\ncoins = 0"
|
||||
after := "speed = 4\njump = 3\nlives = 3\ncoins = 0\nwarp = true"
|
||||
code.DiffView(c, "settings.cfg", before, after, code.DiffViewOptions{})
|
||||
}
|
||||
|
||||
func demoCrashScreen(c *ui.Context, log func(string)) {
|
||||
k := pixel.K(c)
|
||||
s := codeState(c)
|
||||
if s.crashed {
|
||||
if input.Button(c, "CRASH AGAIN", input.ButtonOptions{}).Clicked {
|
||||
s.crashed = false
|
||||
log("crashed again")
|
||||
}
|
||||
return
|
||||
}
|
||||
stack := []string{"main.loot(0x3)", "main.openChest(...)", "main.main()"}
|
||||
if code.CrashScreen(c, "panic: index out of range [3] with length 3", stack, code.CrashScreenOptions{Width: 280}).Continue {
|
||||
s.crashed = true
|
||||
log("continued at " + k.Now().Format("15:04:05"))
|
||||
}
|
||||
}
|
||||
|
||||
func demoFPSMeter(c *ui.Context, log func(string)) {
|
||||
k := pixel.K(c)
|
||||
s := codeState(c)
|
||||
// Made-up frames: mostly on time, now and then a hitch.
|
||||
add := func(i int) {
|
||||
ms := 9 + 4*math.Sin(float64(i)/5)
|
||||
if i%23 == 7 {
|
||||
ms = 38
|
||||
}
|
||||
s.frames = append(s.frames[max(0, len(s.frames)-200):], time.Duration(ms*float64(time.Millisecond)))
|
||||
}
|
||||
if len(s.frames) == 0 {
|
||||
for i := range 56 {
|
||||
add(i)
|
||||
}
|
||||
}
|
||||
if !k.Reduce() {
|
||||
if t := k.Tick(c, 12); s.last.IsZero() || k.Now().Sub(s.last) >= time.Second/12 {
|
||||
s.last = k.Now()
|
||||
add(t)
|
||||
}
|
||||
}
|
||||
code.FPSMeter(c, "Frame times", s.frames, code.FPSMeterOptions{})
|
||||
}
|
||||
|
||||
func demoProfilerBars(c *ui.Context, log func(string)) {
|
||||
ms := func(f float64) time.Duration { return time.Duration(f * float64(time.Millisecond)) }
|
||||
code.ProfilerBars(c, "One frame", code.Span{Name: "frame", Length: ms(16.7), Children: []code.Span{
|
||||
{Name: "input", Length: ms(1)},
|
||||
{Name: "update", Start: ms(1), Length: ms(6), Children: []code.Span{
|
||||
{Name: "physics", Start: ms(1), Length: ms(3)}, {Name: "ai", Start: ms(4), Length: ms(2.5)},
|
||||
}},
|
||||
{Name: "render", Start: ms(7.5), Length: ms(8), Children: []code.Span{
|
||||
{Name: "sprites", Start: ms(7.5), Length: ms(5), Children: []code.Span{{Name: "dither", Start: ms(9), Length: ms(2)}}},
|
||||
{Name: "text", Start: ms(12.5), Length: ms(2)},
|
||||
}},
|
||||
}}, code.ProfilerBarsOptions{Width: 260})
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package gallery
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/egoist/mygo/ui"
|
||||
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/code"
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/input"
|
||||
"git.zacharyzhang.com/ZacharyZhang-NY/8bitMyGoUI/pixel"
|
||||
)
|
||||
|
||||
var debugEntries = []Entry{
|
||||
{376, "Breakpoints", "断点", "code", "Click a line, or press Enter on it, to stop there next time.", demoBreakpoints},
|
||||
{377, "Variables", "变量", "code", "Names, types and values; open a struct to see inside.", demoVariables},
|
||||
{378, "CommandHistory", "命令历史", "code", "Everything you typed, numbered. Enter runs it again.", demoCommandHistory},
|
||||
{379, "ShortcutList", "快捷键表", "code", "Actions beside their keycaps. Do not trust the last one.", demoShortcutList},
|
||||
{380, "DebugGrid", "调试网格", "code", "The dot grid laid over anything, with rulers in dots.", demoDebugGrid},
|
||||
{381, "PixelEditor", "像素编辑器", "code", "Pen, fill, eraser, picker. Arrows and Enter paint too. The art below is live.", demoPixelEditor},
|
||||
{382, "PaletteEditor", "调色板编辑", "code", "Sixteen colors, sixteen levels a channel, like the old chips. The preview keeps up.", demoPaletteEditor},
|
||||
{383, "SpriteSheet", "精灵表", "code", "Every frame in a grid; PLAY spins the coin.", demoSpriteSheet},
|
||||
{384, "GlyphMap", "字形表", "code", "128 code points a page; PageUp and PageDown turn it. Dots mark what the font lacks.", demoGlyphMap},
|
||||
{385, "RegisterView", "寄存器", "code", "A 6502's registers and flags. STEP runs a line; what it changed lights up.", demoRegisterView},
|
||||
}
|
||||
|
||||
const routine = `func jump(h *Hero) {
|
||||
if h.OnGround {
|
||||
h.VY = -4
|
||||
}
|
||||
h.Y += h.VY
|
||||
}`
|
||||
|
||||
func demoBreakpoints(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
if code.Breakpoints(c, "jump.go", routine, s.marks, code.BreakpointsOptions{}).Changed {
|
||||
log(fmt.Sprintf("breakpoints on %d lines", len(s.marks)))
|
||||
}
|
||||
}
|
||||
|
||||
func demoVariables(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
vars := []code.Var{
|
||||
{Name: "hero", Type: "Hero", Value: "{…}", Fields: []code.Var{
|
||||
{Name: "Name", Type: "string", Value: `"Aria"`}, {Name: "HP", Type: "int", Value: "42"},
|
||||
{Name: "Pos", Type: "Vec", Value: "{…}", Fields: []code.Var{{Name: "X", Type: "float64", Value: "12.5"}, {Name: "Y", Type: "float64", Value: "-3"}}},
|
||||
{Name: "Flying", Type: "bool", Value: "false"},
|
||||
}},
|
||||
{Name: "target", Type: "*Enemy", Value: "nil"},
|
||||
{Name: "lives", Type: "uint8", Value: "3"},
|
||||
}
|
||||
if r := code.Variables(c, "Locals", vars, &s.vr, code.VariablesOptions{Width: 220}); r.Changed || r.Toggled {
|
||||
log("at " + s.vr)
|
||||
}
|
||||
}
|
||||
|
||||
func demoCommandHistory(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
r := code.CommandHistory(c, "History", s.history, &s.pick, code.CommandHistoryOptions{Height: 70})
|
||||
if r.Rerun {
|
||||
log("rerun " + s.history[s.pick])
|
||||
} else if r.Changed {
|
||||
log("picked " + s.history[s.pick])
|
||||
}
|
||||
}
|
||||
|
||||
func demoShortcutList(c *ui.Context, log func(string)) {
|
||||
code.ShortcutList(c, "Controls", []code.Shortcut{
|
||||
{Action: "Save", Keys: []string{"Ctrl", "S"}}, {Action: "Jump", Keys: []string{"Space"}},
|
||||
{Action: "Pause", Keys: []string{"Esc"}},
|
||||
{Action: "Free gold", Keys: []string{"Alt", "F4"}},
|
||||
}, code.ShortcutListOptions{Width: 300})
|
||||
}
|
||||
|
||||
func demoDebugGrid(c *ui.Context, log func(string)) {
|
||||
k := pixel.K(c)
|
||||
code.DebugGrid(c, code.DebugGridOptions{}, func() {
|
||||
ui.Column(c).Padding(k.D(8)).Gap(k.D(6)).Children(func() {
|
||||
if input.Button(c, "ALIGNED?", input.ButtonOptions{}).Clicked {
|
||||
log("pressed on the grid")
|
||||
}
|
||||
pixel.Text(c, "Every edge on a dot.", pixel.TextOptions{})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const heartArt = `..rr..rr..
|
||||
.rrrrrrrr.
|
||||
rrlrrrrrrr
|
||||
rrrrrrrrrr
|
||||
.rrrrrrrr.
|
||||
..rrrrrr..
|
||||
...rrrr...
|
||||
....rr....
|
||||
`
|
||||
|
||||
func demoPixelEditor(c *ui.Context, log func(string)) {
|
||||
k := pixel.K(c)
|
||||
s := codeState(c)
|
||||
ui.Column(c).Gap(k.D(6)).Children(func() {
|
||||
r := code.PixelEditor(c, "Heart", &s.art, code.PixelEditorOptions{})
|
||||
if r.Changed {
|
||||
log("painted")
|
||||
}
|
||||
if r.Copied {
|
||||
log("art copied")
|
||||
}
|
||||
for _, l := range strings.Split(strings.TrimSpace(s.art), "\n") {
|
||||
pixel.Text(c, l, pixel.TextOptions{Slot: pixel.Faint})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func demoPaletteEditor(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
if code.PaletteEditor(c, "Palette copy", &s.pal, code.PaletteEditorOptions{}).Changed {
|
||||
log("palette edited")
|
||||
}
|
||||
}
|
||||
|
||||
func demoSpriteSheet(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
if code.SpriteSheet(c, "Coin", coin, &s.frame, &s.playing, code.SpriteSheetOptions{Scale: 3}).Changed {
|
||||
log(fmt.Sprintf("frame %d, playing %v", s.frame+1, s.playing))
|
||||
}
|
||||
}
|
||||
|
||||
func demoGlyphMap(c *ui.Context, log func(string)) {
|
||||
s := codeState(c)
|
||||
if code.GlyphMap(c, "Font", &s.glyph, code.GlyphMapOptions{}).Changed {
|
||||
log(fmt.Sprintf("U+%04X", s.glyph))
|
||||
}
|
||||
}
|
||||
|
||||
// program is 6502 lines and the CPU after each.
|
||||
var program = []struct {
|
||||
line string
|
||||
cpu code.CPU
|
||||
}{
|
||||
{"RESET", code.CPU{SP: 0xFD, P: 0x24, PC: 0xC000}},
|
||||
{"LDA #$3F", code.CPU{A: 0x3F, SP: 0xFD, P: 0x24, PC: 0xC002}},
|
||||
{"TAX", code.CPU{A: 0x3F, X: 0x3F, SP: 0xFD, P: 0x24, PC: 0xC003}},
|
||||
{"INX", code.CPU{A: 0x3F, X: 0x40, SP: 0xFD, P: 0x24, PC: 0xC004}},
|
||||
{"ADC #$C1", code.CPU{A: 0x00, X: 0x40, SP: 0xFD, P: 0x27, PC: 0xC006}},
|
||||
{"PHA", code.CPU{A: 0x00, X: 0x40, SP: 0xFC, P: 0x27, PC: 0xC007}},
|
||||
{"DEY", code.CPU{A: 0x00, X: 0x40, Y: 0xFF, SP: 0xFC, P: 0xA5, PC: 0xC008}},
|
||||
}
|
||||
|
||||
func demoRegisterView(c *ui.Context, log func(string)) {
|
||||
k := pixel.K(c)
|
||||
s := codeState(c)
|
||||
p := program[s.step]
|
||||
ui.Column(c).Gap(k.D(6)).Children(func() {
|
||||
pixel.Text(c, fmt.Sprintf("$%04X %s", p.cpu.PC, p.line), pixel.TextOptions{Slot: pixel.Accent})
|
||||
code.RegisterView(c, "CPU", p.cpu, code.RegisterViewOptions{})
|
||||
if input.Button(c, "STEP", input.ButtonOptions{Variant: input.Primary}).Clicked {
|
||||
s.step = (s.step + 1) % len(program)
|
||||
log(program[s.step].line)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -38,3 +38,36 @@ func TestMediaDemosLogTheirActions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCodeDemosLogTheirActions(t *testing.T) {
|
||||
quiet := map[string]bool{"COMMAND": true}
|
||||
for _, tc := range []struct {
|
||||
path string
|
||||
steps []string
|
||||
}{
|
||||
{"/c/366-terminal", []string{"COMMAND", "type:help", "key:Enter", "key:Up"}}, {"/c/367-codeblock", []string{"COPY"}},
|
||||
{"/c/368-logviewer", []string{"WARN", "+ LINE"}}, {"/c/369-hexviewer", []string{"save.dat"}},
|
||||
{"/c/371-jsontree", []string{"save.json"}}, {"/c/373-crashscreen", []string{"CONTINUE?", "CRASH AGAIN"}},
|
||||
{"/c/376-breakpoints", []string{"jump.go"}}, {"/c/377-variables", []string{"Locals"}},
|
||||
{"/c/378-commandhistory", []string{"run", "key:Enter"}}, {"/c/380-debuggrid", []string{"ALIGNED?"}},
|
||||
{"/c/381-pixeleditor", []string{"Heart", "COPY"}}, {"/c/382-paletteeditor", []string{"R"}},
|
||||
{"/c/383-spritesheet", []string{"PLAY"}}, {"/c/384-glyphmap", []string{"Font"}}, {"/c/385-registerview", []string{"STEP"}},
|
||||
} {
|
||||
a, tt := open(tc.path)
|
||||
slug := tc.path[3:]
|
||||
for _, step := range tc.steps {
|
||||
before := len(a.logs[slug])
|
||||
switch {
|
||||
case strings.HasPrefix(step, "key:"):
|
||||
tt.Key(0, letters[step[4:]])
|
||||
case strings.HasPrefix(step, "type:"):
|
||||
tt.Type(step[5:])
|
||||
default:
|
||||
click(t, tt, step)
|
||||
}
|
||||
if len(a.logs[slug]) <= before && !quiet[step] && !strings.HasPrefix(step, "type:") {
|
||||
t.Errorf("%s: %s logged nothing: %q", slug, step, a.logs[slug])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -56,7 +56,7 @@ var Categories = []Category{
|
||||
{"tabletop", "Tabletop", "桌游", icon.Crown},
|
||||
}
|
||||
|
||||
var entries = slices.Concat(foundationEntries, layoutEntries, textEntries, displayEntries, inputEntries, controlEntries, feedbackEntries, navigationEntries, dataEntries, recordEntries, overlayEntries, popupEntries, datetimeEntries, timeEntries, chartEntries, plotEntries, gameEntries, rpgEntries, screenEntries, lootEntries, fxEntries, screenFxEntries, chatEntries, mailEntries, mediaEntries, studioEntries)
|
||||
var entries = slices.Concat(foundationEntries, layoutEntries, textEntries, displayEntries, inputEntries, controlEntries, feedbackEntries, navigationEntries, dataEntries, recordEntries, overlayEntries, popupEntries, datetimeEntries, timeEntries, chartEntries, plotEntries, gameEntries, rpgEntries, screenEntries, lootEntries, fxEntries, screenFxEntries, chatEntries, mailEntries, mediaEntries, studioEntries, codeEntries, debugEntries)
|
||||
|
||||
func Entries() []Entry { return entries }
|
||||
|
||||
|
||||
Reference in new issue
Block a user