diff --git a/DESIGN.md b/DESIGN.md new file mode 100644 index 00000000..588b1feb --- /dev/null +++ b/DESIGN.md @@ -0,0 +1,225 @@ +# 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). + +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 falls + apart in a smaller terminal 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 + 3. a footer + +The header has a summary line describing the current screen against an "ubuntu +orange" background. + +The footer has a progress bar indicating how far through the install process +the user was, a blank line and the summary area. Currently the summary area +contains static content for the first few screens, but there are vague plans to +make it specific to the currently focused element. Once the install has started +but before we get to the final screen, the summary area contains a summary of +progress made by the installation. Someday soon the summary area will also +contain a button that allows you to drop to a shell at any point. + +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 `