# subiquity design notes ## UI ### basic ground rules: 1. Subiquity is entirely usable by pressing up, down, space (or return) and the occasional bit of typing. 2. The UI never blocks. If something takes more than about 0.1s, it is done in the background, possibly with some kind of indication in the UI and the ability to cancel if appropriate. If indication is shown, it is shown for at least 1s to avoid flickering the UI. There is a helper, `wait_with_text_dialog` for this. 3. General UX principles that it is worth keeping in mind: 1. Prevent invalid use if that makes sense (e.g. unix usernames can never contain spaces, so you simply can't enter spaces in that box) 2. When rejecting input, be clear about that to the user and explain what they need to do differently (e.g. when you do try to put a space in a unix username, a message appears explaining which characters are valid). 3. Make the common case as easy as possible by doing things like thinking about which widget should be highlighted when a screen is first shown. 4. Subiquity is functional in an 80x24 terminal. It doesn't matter if it becomes unusable in a smaller terminal (although it shouldn't crash, as we support people logging in via ssh and they can resize their terminal however they like) and obviously you can get more information on a larger terminal at once, but it needs to work in 80x24. ### urwid specific ranting subiquity is built using the [urwid](http://urwid.org/) console user interface library for Python. urwid is mostly fine but has some design decisions that have meant that we're sort of slowly re-implementing pieces of it. The main one of these is that in urwid, widgets do not have a size; they inherit it from their parent widget. While this is unavoidable for the "outer" widgets (subiquity does not get to decide the size of the console it runs in!) I don't think it leads to a good appearance for things like stacked columns of buttons, which we want to fit to label length (and label length depends on which language it is being used in!). There is a similar tension around having scroll bars that are only shown when needed (scroll bars should only be shown when the contained widget "wants" to be taller than the space available for it). subiquity has a few generic facilities for handling these: * The `subiquitycore.ui.containers` module defines a `ListBox` class that automatically handles scroll bars. It is used everywhere instead of urwid's `ListBox` class (it does not support lazy construction of widgets like urwid's does). * The `subiquitycore.ui.stretchy` module defines classes for creating modal dialogs out of stacks of widgets that fit to their content (and let you say which widget to scroll if the content is too tall to fit on the screen). * The `subiquitycore.ui.width` module defines a `widget_width` function, which knows how wide a widget "wants" to be (as above, this isn't a concept urwid comes with). * The `subiquitycore.ui.table` module defines classes for creating Tables that act a little like `` elements in HTML. Subiquity also has replacements for the standard containers that handle tab cycling (i.e. tab advances to the next element and wraps around to the beginning when at the end). urwid can be extremely frustrating to work with, but usually a good UI can be implemented after sufficient swearing. ### The typical screen A subiquity screen consists of: 1. a header 2. a body area, which usually contains 1. an excerpt (which explains what this screen is for) 2. a scrollable content area 3. a stack of buttons, including "done"/"cancel" buttons for moving between screens The header has a summary line describing the current screen against an "ubuntu orange" background. The body area is where most of the action is. It follows a standard pattern described above, and the `subiquitycore.ui.utils.screen()` function makes it very easy to follow that pattern. Many screen have "sub-dialogs" (think: editing the addresses for a NIC) which can be as large as the whole body area but are often smaller. The base view class has `show_overlay`/`hide_overlay` methods for handling these. ### Custom widgets subiquity defines a few generic widgets that are used in several places. `Selector` is a bit like an html `