summaryrefslogtreecommitdiff
path: root/docs/tutorial
diff options
context:
space:
mode:
authorIan Ward <ian@excess.org>2012-09-22 20:31:01 -0400
committerIan Ward <ian@excess.org>2012-09-22 20:31:01 -0400
commitdaefdead5fad770775aa584fc61ea55ef3e8ac89 (patch)
tree9af532ce1c5c32542f2fa20a311055c40984975f /docs/tutorial
parent9e73e7756f277a5edd6954043729d03fb47c8ca2 (diff)
downloadurwid-daefdead5fad770775aa584fc61ea55ef3e8ac89.tar.gz
docs: move some sections from tutorial to widget manual page
--HG-- branch : feature-sphinx rename : docs/tutorial/wanat.py => docs/manual/wanat.py rename : docs/tutorial/wanat_multi.py => docs/manual/wanat_multi.py rename : docs/tutorial/wanat_new.py => docs/manual/wanat_new.py rename : docs/tutorial/wcur1.py => docs/manual/wcur1.py rename : docs/tutorial/wcur2.py => docs/manual/wcur2.py rename : docs/tutorial/wmod.py => docs/manual/wmod.py rename : docs/tutorial/wsel.py => docs/manual/wsel.py
Diffstat (limited to 'docs/tutorial')
-rw-r--r--docs/tutorial/index.rst385
-rw-r--r--docs/tutorial/wanat.py22
-rw-r--r--docs/tutorial/wanat_multi.py17
-rw-r--r--docs/tutorial/wanat_new.py17
-rw-r--r--docs/tutorial/wcur1.py35
-rw-r--r--docs/tutorial/wcur2.py7
-rw-r--r--docs/tutorial/wmod.py15
-rw-r--r--docs/tutorial/wsel.py34
8 files changed, 0 insertions, 532 deletions
diff --git a/docs/tutorial/index.rst b/docs/tutorial/index.rst
index 24de181..1e2ef2b 100644
--- a/docs/tutorial/index.rst
+++ b/docs/tutorial/index.rst
@@ -331,390 +331,5 @@ default decorations
.. image:: menu43.png
.. image:: menu44.png
-.. _zen-listbox:
-
-Zen of ListBox
-==============
-
-ListBox Focus and Scrolling
----------------------------
-
-The :class:`ListBox` is a box widget that contains flow widgets.
-Its contents are displayed stacked vertically, and the
-:class:`ListBox` allows the user to scroll through its content.
-One of the flow widgets displayed in the :class:`ListBox` is the
-focus widget. The :class:`ListBox` passes key presses to the
-focus widget to allow the user to interact with it. If the focus widget does
-not handle a keypress then the :class:`ListBox` may handle the
-keypress by scrolling and/or selecting another widget to become the focus
-widget.
-
-The :class:`ListBox` tries to do the most sensible thing when
-scrolling and changing focus. When the widgets displayed are all
-:class:`Text` widgets or other unselectable widgets then the
-:class:`ListBox` will behave like a web browser does when the
-user presses *UP*, *DOWN*, *PAGE UP* and *PAGE DOWN*: new text is immediately
-scrolled in from the top or bottom. The :class:`ListBox` chooses
-one of the visible widgets as its focus widget when scrolling. When scrolling
-up the :class:`ListBox` chooses the topmost widget as the focus,
-and when scrolling down the :class:`ListBox` chooses the
-bottommost widget as the focus.
-
-When all the widgets displayed are not selectable the user would typically have
-no way to tell which widget is in focus, but if we wrap the widgets with
-:class:`AttrWrap` we can see what is happening while the
-focus changes:
-
-.. literalinclude:: lbscr.py
- :linenos:
-
-.. image:: lbscr1.png
-.. image:: lbscr2.png
-.. image:: lbscr3.png
-.. image:: lbscr4.png
-.. image:: lbscr5.png
-.. image:: lbscr6.png
-
-The :class:`ListBox` remembers the location of the widget in
-focus as either an "offset" or an "inset". An offset is the number of rows
-between the top of the :class:`ListBox` and the beginning of the
-focus widget. An offset of zero corresponds to a widget with its top aligned
-with the top of the :class:`ListBox`. An inset is the fraction
-of rows of the focus widget that are "above" the top of the
-:class:`ListBox` and not visible. The
-:class:`ListBox` uses this method of remembering the focus
-widget location so that when the :class:`ListBox` is resized the
-text displayed will stay roughly aligned with the top of the
-:class:`ListBox`.
-
-.. image:: lbscr7.png
-.. image:: lbscr8.png
-.. image:: lbscr9.png
-
-When there are selectable widgets in the :class:`ListBox` the
-focus will move between the selectable widgets, skipping the unselectable
-widgets. The :class:`ListBox` will try to scroll all the rows of
-a selectable widget into view so that the user can see the new focus widget in
-its entirety. This behavior can be used to bring more than a single widget into
-view by using composite widgets to combine a selectable widget with other
-widgets that should be displayed at the same time.
-
-
-Dynamic ListBox with ListWalker
--------------------------------
-
-While the :class:`ListBox` stores the location of its focus
-widget, it does not directly store the actual focus widget or other contents of
-the :class:`ListBox`. The storage of a
-:class:`ListBox`'s content is delegated to a "List Walker"
-object. If a list of widgets is passed to the :class:`ListBox`
-constructor then it creates a :class:`SimpleListWalker` object
-to manage the list.
-
-When the :class:`ListBox` is `rendering a canvas`_ or `handling
-input`_ it will:
-
-.. _rendering a canvas: :meth:`ListBox.render`
-.. _handling input: :meth:`ListBox.keypress`
-
-1. Call the :meth:`get_focus` method of its list walker object. This method
- will return the focus widget and a position object.
-2. Optionally call the :meth:`get_prev` method of its List Walker object one or
- more times, initially passing the focus position and then passing the new
- position returned on each successive call. This method will return the
- widget and position object "above" the position passed.
-3. Optionally call the :meth:`get_next` method of its List Walker object one or
- more times, similarly, to collect widgets and position objects "below" the
- focus position.
-4. Optionally call the :meth:`set_focus` method passing one of the position
- objects returned in the previous steps.
-
-This is the only way the :class:`ListBox` accesses its contents,
-and it will not store copies of any of the widgets or position objects beyond
-the current rendering or input handling operation.
-
-The :class:`SimpleListWalker` stores a list of widgets, and uses
-integer indexes into this list as its position objects. It stores the focus
-position as an integer, so if you insert a widget into the list above the focus
-position then you need to remember to increment the focus position in the
-:class:`SimpleListWalker` object or the contents of the
-:class:`ListBox` will shift.
-
-A custom List Walker object may be passed to the
-:class:`ListBox` constructor instead of a plain list of widgets.
-List Walker objects must implement the :ref:`list-walker-interface`.
-
-The fib.py_ example program demonstrates a custom list walker that doesn't
-store any widgets. It uses a tuple of two successive Fibonacci numbers as its
-position objects and it generates Text widgets to display the numbers on the
-fly. The result is a :class:`ListBox` that can scroll through an
-unending list of widgets.
-
-The edit.py_ example program demonstrates a custom list walker that loads lines
-from a text file only as the user scrolls them into view. This allows even
-huge files to be opened almost instantly.
-
-The browse.py_ example program demonstrates a custom list walker that uses a
-tuple of strings as position objects, one for the parent directory and one for
-the file selected. The widgets are cached in a separate class that is accessed
-using a dictionary indexed by parent directory names. This allows the
-directories to be read only as required. The custom list walker also allows
-directories to be hidden from view when they are "collapsed".
-
-.. _fib.py: http://excess.org/urwid/browser/examples/fib.py
-.. _edit.py: http://excess.org/urwid/browser/examples/edit.py
-.. _browse.py: http://excess.org/urwid/browser/examples/browse.py
-
-
-Setting the Focus
------------------
-
-The easiest way to change the current :class:`ListBox` focus is
-to call the :meth:`ListBox.set_focus` method. This method doesn't
-require that you know the :class:`ListBox`'s current dimensions
-``(maxcol, maxrow)``. It will wait until the next call to either keypress or
-render to complete setting the offset and inset values using the dimensions
-passed to that method.
-
-The position object passed to :meth:`set_focus` must be compatible with the
-List Walker object that the :class:`ListBox` is using. For
-:class:`SimpleListWalker` the position is the integer index of
-the widget within the list.
-
-The *coming_from* parameter should be set if you know that the old position is
-"above" or "below" the previous position. When the
-:class:`ListBox` completes setting the offset and inset values
-it tries to find the old widget among the visible widgets. If the old widget is
-still visible, if will try to avoid causing the :class:`ListBox`
-contents to scroll up or down from its previous position. If the widget is not
-visible, then the :class:`ListBox` will:
-
-* Display the new focus at the bottom of the :class:`ListBox` if
- *coming_from* is "above".
-* Display the new focus at the top of the :class:`ListBox` if
- *coming_from* is "below".
-* Display the new focus in the middle of the :class:`ListBox` if
- coming_from is ``None``.
-
-If you know exactly where you want to display the new focus widget within the
-:class:`ListBox` you may call
-:meth:`ListBox.set_focus_valign`. This method lets you specify
-the *top*, *bottom*, *middle*, a relative position or the exact number of rows
-from the top or bottom of the :class:`ListBox`.
-
-
-Combining Widgets
-=================
-
-
-Piling Widgets
---------------
-
-:class:`Pile` widgets are used to combine multiple widgets by
-stacking them vertically. A Pile can manage selectable widgets by keeping track
-of which widget is in focus and it can handle moving the focus between widgets
-when the user presses the *UP* and *DOWN* keys. A Pile will also work well when
-used within a :class:`ListBox`.
-
-A Pile is selectable only if its focus widget is selectable. If you create a
-Pile containing one Text widget and one Edit widget the Pile will choose the
-Edit widget as its default focus widget. To change the pile's focus widget you
-can call :meth:`Pile.set_focus`.
-
-
-Dividing into Columns
----------------------
-
-:class:`Columns` widgets may be used to arrange either flow
-widgets or box widgets horizontally into columns. Columns widgets will manage
-selectable widgets by keeping track of which column is in focus and it can
-handle moving the focus between columns when the user presses the *LEFT* and
-*RIGHT* keys. Columns widgets also work well when used within a
-:class:`ListBox`.
-
-Columns widgets are selectable only if the column in focus is selectable. If a
-focus column is not specified the first selectable widget will be chosen as the
-focus column. The :meth:`Columns.set_focus` method may be used
-to select the focus column.
-
-
-``GridFlow`` Arrangment
------------------------
-
-The :class:`GridFlow` widget is a flow widget designed for use
-with :class:`Button`, :class:`CheckBox` and
-:class:`RadioButton` widgets. It renders all the widgets it
-contains the same width and it arranges them from left to right and top to
-bottom.
-
-The GridFlow widget uses Pile, Columns, Padding and Divider widgets to build a
-display widget that will handle the keyboard input and rendering. When the
-GridFlow widget is resized it regenerates the display widget to accommodate the
-new space.
-
-
-``Overlay`` widgets
--------------------
-
-The :class:`Overlay` widget is a box widget that contains two
-other box widgets. The bottom widget is rendered the full size of the Overlay
-widget and the top widget is placed on top, obscuring an area of the bottom
-widget. This widget can be used to create effects such as overlapping "windows"
-or pop-up menus.
-
-The Overlay widget always treats the top widget as the one in focus. All
-keyboard input will be passed to the top widget.
-
-If you want to use a flow flow widget for the top widget, first wrap the flow
-widget with a :class:`Filler` widget.
-
-
-
-.. _creating-custom-widgets:
-
-Creating Custom Widgets
-=======================
-
-
-Modifying Existing Widgets
---------------------------
-
-The easiest way to create a custom widget is to modify an existing widget.
-This can be done by either subclassing the original widget or by wrapping it.
-Subclassing is appropriate when you need to interact at a very low level with
-the original widget, such as if you are creating a custom edit widget with
-different behavior than the usual Edit widgets. If you are creating a custom
-widget that doesn't need tight coupling with the original widget, such as a
-widget that displays customer address information, then wrapping is more
-appropriate.
-
-The :class:`WidgetWrap` class simplifies wrapping existing
-widgets. You can create a custom widget simply by creating a subclass of
-WidgetWrap and passing a widget into WidgetWrap's constructor.
-
-This is an example of a custom widget that uses WidgetWrap:
-
-.. literalinclude:: wmod.py
- :linenos:
-
-The above code creates a group of RadioButtons and provides a method to
-query the state of the buttons.
-
-Wrapped widgets may also override the standard widget methods. These methods
-are described in following sections.
-
-Anatomy of a Widget
--------------------
-
-Any object that follows the `Widget interface definition`_ may be used as a
-widget. Box widgets must implement selectable_ and render_ methods, and flow
-widgets must implement selectable, render and rows_ methods.
-
-.. _Widget interface definition: :class:`Widget`
-.. _selectable: :meth:`Widget.selectable`
-.. _render: :meth:`Widget.render`
-.. _rows: :meth:`Widget.rows`
-
-.. literalinclude:: wanat.py
- :linenos:
-The above code implements two widget classes. Pudding is a flow widget and
-BoxPudding is a box widget. Pudding will render as much "Pudding" as will fit
-in a single row, and BoxPudding will render as much "Pudding" as will fit into
-the entire area given.
-Note that the rows and render methods' focus parameter must have a default
-value of False. Also note that for flow widgets the number of rows returned by
-the rows method must match the number of rows rendered by the render method.
-
-In most cases it is easier to let other widgets handle the rendering and row
-calculations for you:
-
-.. literalinclude:: wanat_new.py
- :linenos:
-
-The NewPudding class behaves the same way as the Pudding class above, but in
-NewPudding you can change the way the widget appears by modifying only the
-display_widget method, whereas in the Pudding class you may have to modify both
-the render and rows methods.
-
-To improve the efficiency of your Urwid application you should be careful of
-how long your rows methods take to execute. The rows methods may be called many
-times as part of input handling and rendering operations. If you are using a
-display widget that is time consuming to create you should consider caching it
-to reduce its impact on performance.
-
-It is possible to create a widget that will behave as either a flow widget or
-box widget depending on what is required:
-
-.. literalinclude:: wanat_multi.py
- :linenos:
-
-MultiPudding will work in place of either Pudding or BoxPudding above. The
-number of elements in the size tuple determines whether the containing widget
-is expecting a flow widget or a box widget.
-
-
-Creating a Selectable Widget
-----------------------------
-
-Selectable widgets such as Edit and Button widgets allow the user to interact
-with the application. A widget is selectable if its selectable method returns
-True. Selectable widgets must implement the keypress_ method to handle keyboard
-input.
-
-.. _keypress: :meth:`Widget.keypress`
-
-.. literalinclude:: wsel.py
-
-The SelectablePudding widget will display its contents in uppercase when it is
-in focus, and it allows the user to "eat" the pudding by pressing each of the
-letters *P*, *U*, *D*, *D*, *I*, *N* and *G* on the keyboard. When the user has
-"eaten" all the pudding the widget will reset to its initial state.
-
-Note that keys that are unhandled in the keypress method are returned so that
-another widget may be able to handle them. This is a good convention to follow
-unless you have a very good reason not to. In this case the *UP* and *DOWN*
-keys are returned so that if this widget is in a
-:class:`ListBox` the :class:`ListBox` will behave
-as the user expects and change the focus or scroll the
-:class:`ListBox`.
-
-Widget Displaying the Cursor
-----------------------------
-
-Widgets that display the cursor must implement the get_cursor_coords_ method.
-Similar to the rows method for flow widgets, this method lets other widgets
-make layout decisions without rendering the entire widget. The
-:class:`ListBox` widget in particular uses get_cursor_coords to
-make sure that the cursor is visible within its focus widget.
-
-.. _get_cursor_coords: :meth:`Widget.get_cursor_coords`
-
-.. literalinclude:: wcur1.py
- :linenos:
-
-CursorPudding will let the user move the cursor through the widget by pressing
-*LEFT* and *RIGHT*. The cursor must only be added to the canvas when the widget
-is in focus. The get_cursor_coords method must always return the same cursor
-coordinates that render does.
-
-A widget displaying a cursor may choose to implement get_pref_col. This method
-returns the preferred column for the cursor, and is called when the focus is
-moving up or down off this widget.
-
-.. _get_pref_col: :meth:`Widget.get_pref_col`
-
-Another optional method is move_cursor_to_coords_. This method allows other
-widgets to try to position the cursor within this widget. The
-:class:`ListBox` widget uses :meth:`move_cursor_to_coords` when
-changing focus and when the user pressed *PAGE UP* or *PAGE DOWN*. This method
-must return ``True`` on success and ``False`` on failure. If the cursor may be
-placed at any position within the row specified (not only at the exact column
-specified) then this method must move the cursor to that position and return
-``True``.
-
-.. _move_cursor_to_coords: :meth:`Widget.move_cursor_to_coords`
-
-.. literalinclude:: wcur2.py
- :linenos:
diff --git a/docs/tutorial/wanat.py b/docs/tutorial/wanat.py
deleted file mode 100644
index 723eb90..0000000
--- a/docs/tutorial/wanat.py
+++ /dev/null
@@ -1,22 +0,0 @@
-import urwid
-
-class Pudding(urwid.Widget):
- _sizing = frozenset(['flow'])
-
- def rows(self, size, focus=False):
- return 1
-
- def render(self, size, focus=False):
- (maxcol,) = size
- num_pudding = maxcol / len("Pudding")
- return urwid.TextCanvas(["Pudding" * num_pudding], maxcol=maxcol)
-
-
-class BoxPudding(urwid.Widget):
- _sizing = frozenset(['box'])
-
- def render(self, size, focus=False):
- (maxcol, maxrow) = size
- num_pudding = maxcol / len("Pudding")
- return urwid.TextCanvas(["Pudding" * num_pudding] * maxrow,
- maxcol=maxcol)
diff --git a/docs/tutorial/wanat_multi.py b/docs/tutorial/wanat_multi.py
deleted file mode 100644
index b6d6943..0000000
--- a/docs/tutorial/wanat_multi.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import urwid
-
-class MultiPudding(urwid.Widget):
- _sizing = frozenset(['flow', 'box'])
-
- def rows(self, size, focus=False):
- return 1
-
- def render(self, size, focus=False):
- if len(size) == 1:
- (maxcol,) = size
- maxrow = 1
- else:
- (maxcol, maxrow) = size
- num_pudding = maxcol / len("Pudding")
- return urwid.TextCanvas(["Pudding" * num_pudding] * maxrow,
- maxcol=maxcol)
diff --git a/docs/tutorial/wanat_new.py b/docs/tutorial/wanat_new.py
deleted file mode 100644
index 5a597b9..0000000
--- a/docs/tutorial/wanat_new.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import urwid
-
-class NewPudding(urwid.Widget):
- _sizing = frozenset(['flow'])
-
- def rows(self, size, focus=False):
- w = self.display_widget(size, focus)
- return w.rows(size, focus)
-
- def render(self, size, focus=False):
- w = self.display_widget(size, focus)
- return w.render(size, focus)
-
- def display_widget(self, size, focus):
- (maxcol,) = size
- num_pudding = maxcol / len("Pudding")
- return urwid.Text("Pudding" * num_pudding)
diff --git a/docs/tutorial/wcur1.py b/docs/tutorial/wcur1.py
deleted file mode 100644
index 6bf97f7..0000000
--- a/docs/tutorial/wcur1.py
+++ /dev/null
@@ -1,35 +0,0 @@
-import urwid
-
-class CursorPudding(urwid.Widget):
- _sizing = frozenset(['flow'])
- _selectable = True
-
- def __init__(self):
- self.cursor_col = 0
-
- def rows(self, size, focus=False):
- return 1
-
- def render(self, size, focus=False):
- (maxcol,) = size
- num_pudding = maxcol / len("Pudding")
- cursor = None
- if focus:
- cursor = self.get_cursor_coords(size)
- return urwid.TextCanvas(["Pudding" * num_pudding], [], cursor, maxcol)
-
- def get_cursor_coords(self, size):
- (maxcol,) = size
- col = min(self.cursor_col, maxcol - 1)
- return col, 0
-
- def keypress(self, size, key):
- (maxcol, ) = size
- if key == 'left':
- col = self.cursor_col - 1
- elif key == 'right':
- col = self.cursor_col + 1
- else:
- return key
- self.cursor_x = max(0, min(maxcol - 1, col))
- self._invalidate()
diff --git a/docs/tutorial/wcur2.py b/docs/tutorial/wcur2.py
deleted file mode 100644
index 1225419..0000000
--- a/docs/tutorial/wcur2.py
+++ /dev/null
@@ -1,7 +0,0 @@
- def get_pref_col(self, (maxcol,)):
- return self.cursor_x
-
- def move_cursor_to_coords(self, (maxcol,), col, row):
- assert row == 0
- self.cursor_x = col
- return True
diff --git a/docs/tutorial/wmod.py b/docs/tutorial/wmod.py
deleted file mode 100644
index a066a49..0000000
--- a/docs/tutorial/wmod.py
+++ /dev/null
@@ -1,15 +0,0 @@
-import urwid
-
-class QuestionnaireItem(urwid.WidgetWrap):
- def __init__(self):
- self.options = []
- unsure = urwid.RadioButton(self.options, u"Unsure")
- yes = urwid.RadioButton(self.options, u"Yes")
- no = urwid.RadioButton(self.options, u"No")
- display_widget = urwid.GridFlow([unsure, yes, no], 15, 3, 1, 'left')
- urwid.WidgetWrap.__init__(self, display_widget)
-
- def get_state(self):
- for o in self.options:
- if o.get_state() is True:
- return o.get_label()
diff --git a/docs/tutorial/wsel.py b/docs/tutorial/wsel.py
deleted file mode 100644
index 15683d8..0000000
--- a/docs/tutorial/wsel.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import urwid
-
-class SelectablePudding(urwid.Widget):
- _sizing = frozenset(['flow'])
- _selectable = True
-
- def __init__(self):
- self.pudding = "pudding"
-
- def rows(self, size, focus=False):
- return 1
-
- def render(self, size, focus=False):
- (maxcol,) = size
- num_pudding = maxcol / len(self.pudding)
- pudding = self.pudding
- if focus:
- pudding = pudding.upper()
- return urwid.TextCanvas([pudding * num_pudding],
- maxcol=maxcol)
-
- def keypress(self, size, key):
- (maxcol,) = size
- if len(key) > 1:
- return key
- if key.lower() in self.pudding:
- # remove letter from pudding
- n = self.pudding.index(key.lower())
- self.pudding = self.pudding[:n] + self.pudding[n+1:]
- if not self.pudding:
- self.pudding = "pudding"
- self._invalidate()
- else:
- return key