MyGo
Outline

Collections

Outline

A tree of any size, as a list or a table.

Outline

ui.Outline shows a tree of items, as AppKit's outline view and Finder's list view: items at the top, and below each item open its children, indented, with an arrow that opens and closes it. The app gives the items at the top and children, which returns an item's, nil for one without any; the outline builds only the rows in view, as a list does, so trees of any size are as fast as small ones.

type fileTree struct {
	children map[string][]string // the paths in each directory
	files    ui.OutlineState[string]
	row      int
}

func (app *fileTree) view(c *ui.Context) {
	app.files.List.Selected = &app.row
	ui.Outline(c, &app.files, []string{"/"}, func(dir string) []string {
		return app.children[dir] // nil for a file
	}, func(path string) {
		ui.Text(c, filepath.Base(path))
	}).Grow(1)
	chosen := app.files.Item(app.row)
	// …
}

Outline state

Its state, an OutlineState, holds the rows' ListState, which chooses rows as a list's does (Selected, Selection), and the items Open, a Selection of the items showing their children. The rows' keys are the items, so their choice and state follow them as items open and close above them. Rows, Item and Depth read the rows shown. Indent is the width each level adds before a row's arrow, the theme's Space(4) when zero; it must not be negative. Prefix builds the start of the rows instead (rows of your own).

Opening and closing

  • A click on an item's arrow opens or closes it; Option-click (Alt-click) opens or closes all inside it too.
  • While the outline has the focus, Right opens the item chosen or goes to its first child, and Left closes it or goes to its parent; with Option on macOS and Shift elsewhere, as in GTK, they open and close all inside.
  • Closing an item whose child was chosen chooses the item.

Rows of your own

Prefix, a function of the OutlineState, builds the start of each row in place of the indentation and the arrow, for rows of a look of your own, as a JSON viewer's or a file tree's with lines along its levels: its OutlineRow says how deep the row's item is (Depth), whether it has children (Branch) and whether they show (Open), and Arrow makes the box that opens and closes it, as the outline's arrow does, which you size and draw. The rows then have neither padding nor a gap, and center what they hold; the keys, the choice and assistive technology are the outline's.

app.files.Prefix = func(r ui.OutlineRow) {
	ui.Box(c).Width(16 * float32(r.Depth)).Shrink(0)
	arrow := r.Arrow().Size(20, 28).Center()
	if r.Branch {
		arrow.Children(func() {
			icon := ui.Icon(c, chevron)
			if r.Open {
				icon.Rotate(90)
			}
		})
	}
}

In columns

ui.OutlineTable is the same in a table's columns, the first of which shows the arrows, indented as the items are deep: the columns are a table's, which the user sorts, resizes and moves.

ui.OutlineTable(c, &app.files, cols, roots, children, func(path string, col int) {
	switch col {
	case 0:
		ui.Text(c, filepath.Base(path)).SingleLine()
	case 1:
		ui.Text(c, app.size(path))
	}
})

Accessibility

Assistive technology sees a tree, or a table with rows that open and close, whose rows say their level, whether they open, and whether they are open, and which of all the rows they are; it opens and closes them as the arrows do.