The list container differs from the list widget in several ways. First it is optimised for performance instead of a memory usage, and second, the list container supports both homogenous and heterogeneous lists. In terms of implementation the list widget only uses one widget to represent all of the items in the list while the list container will create separate widgets for each visible item.
The list container widget is attached to a model. The model will be responsible for supplying the widgets for the list. The model can either be a ListContainerModel that will create the list items on demand or a TypedListModel/ListModel that contains all the pre-populated widgets.
The list container widget is implemented in terms of a set of widgets visible through a "window". Each widget in the set will represent a visible list item. For performance reasons some extra non-visible, adjacent, list items would also be populated to help live scrolls perform well. The "window" in this case is simply a container.
To better explain how the list container is implemented consider the following diagram:
List container design overview - ^ - - - - - - | I 0 I -<--|-->+ I I | - - - - - - <------=-------- Offset 0 (The zero offset can move, zero is where V I 1 I | PROP_TOPINDEX was last set via IWidget_SetProperty) + I I | - - - - - - | I 2 I | I I | - - - - - - | I 3 I | I I |<------- Window offset ___________ | | 4 | | | | | ___________ | | 5 | | | | | ___________ | | 6 | | --|---------|-- - - | ___________ | | | | 7 | | | | | | | | | ___________ | | | | 8 | | | | | | | |<--- Window size | ___________ | | | | 9 | | | | | | | | | ___________ | | | | 10 | | | --|---------|-- - ___________ I 11 I I I - - - - - -
This diagram represents a list with 12 elements. In this diagram the list items in "solid" lines (items 4-10) represent list items that have been created, and the list item in "broken" lines (items 0 - 3 and 11) represent items that haven't been created. The list was initialized with PROP_TOPINDEX set to 1 so the list's offset will start at the item with index 1. The "window"'s current position allows the user to see part of item 6, items 7 - 9 and part of item 10. If the user was to move the window so that item 11 became visible then the list container would ask it's model to provide it with item 11. In order to provide a quick start up time the list container widget only creates the list items that are required, therefore on start up it will only create the list items required to fill the visible "window".
When the user drags the list in one direction the appearance of the list scrolling will be created by moving the set of widgets, within the "window", by the same distance as the drag. Basically the "window" will act as a viewport onto the larger list. If during the dragging of the set of widgets a new row/column (not yet created) is about to become visible the list container will ask it's model to create the new row/column of widgets on the fly.
The list container also uses a cache, when a list item are no longer needed because it is "far enough" from the "window" then the list container will be put the item in the cache. When the list container has to create a list item it will first check if there is a list item of that type in the cache. Caching only applies when a ListContainerModel is attached to the list container.
The list container doesn't do any drawing itself, when it is asked to draw it simply asks each of its visible children to draw themselves.
To create a list container, an application must do the following
1) Call ISHELL_CreateInstance() with a class ID of either AEECLSID_ListContainerWidget, AEECLSID_PickListContainerWidget or AEECLSID_GridListContainer. 2) Create either an IListContainerModel, an ITypedListModel or an IListModel. 3) Call IWidget_SetModel() to attach the appropriate model to the list 4) Optionally call IWIDGET_SetRows/IWIDGET_SetCols or IWIDGET_SetHintRows/IWIDGET_SetHintCols followed by IWIDGET_GetPreferredExtent. 6) Call IWidget_SetExtent on the ListContainer with the desired extent.
The list container is implemented by a trio of similar widgets -- the list (AEECLSID_ListContainerWidget), pick (AEECLSID_PickListContainerWidget), and grid (AEECLSID_GridListContainer) widgets -- each of which is used to collect multiple, related items, either for view or for selection. These widgets share common behaviors, such as how they handle events or interact with their attached model, but differ in how they arrange the items they contain. For more information on the pick list container and the grid list container widgets see their respective files.
List Container WidgetThe list container widget lays out its items in a vertical list. For example, an application that manages baseball statistics might choose to present to the user a list of player names in alphabetic order. This list could be implemented using a list container widget that displays each item as static text. Visually, the items of a list container widget might be laid out as follows.
+-----------------------+ | List item 1 | |-----------------------| | List item 2 | |-----------------------| | List item 3 | |-----------------------| | List item 4 | |-----------------------| | List item 5 | +-----------------------+
Variable List Items
The list container supports heterogeneous lists. To build a list where each list item is represented by a widget, with a different structure, the user must supply either an ITypedListModel, or IListModel, where each item is different or supply a ILisContainerModel that returns a different type for each list index.
Event Description ----- ------------------------------------------------------------ EVT_KEY: This list container widget responds to the following EVT_KEY events. AVK_UP AVK_DOWN AVK_LEFT AVK_RIGHT -- Each of these navigation events will attempt to scroll the contents of the list, moving the contents of the list to reveal additional items. As the contents of the list move, the focus may change, causing BREW to send a ModelEvent to any object that has registered as a listener, passing EVT_MDL_FOCUS_CHANGE as the 'evCode'. AVK_SELECT -- Causes BREW to send a ModelEvent to any object that has registered as a listener, passing EVT_MDL_FOCUS_SELECT as the 'evCode'. Generally, an application interested in list selections will register a view model with a list container widget by setting the widget's PROP_VIEWMODEL property. The view model will then be notified of item selections and focus changes, and may change contents or respond to these events as necessary. The fields of the ModelEvent accompanying the EVT_MDL_FOCUS_SELECT or EVT_MDL_FOCUS_CHANGE events will contain the following information. dwParam: The index of the item that is currently selected in the list. EVT_WDG_SETPROPERTY: The list container widget responds to this event by attempting to set the property identified by the 'wParam' parameter. The list container widget allows the following properties to be set These properties are discussed below in greater detail. EVT_WDG_GETPROPERTY: The list container widget responds to this event by attempting to retrieve the property identified by the 'wParam' parameter. These properties are discussed below in greater detail. These properties are discussed below in greater detail. EVT_WDG_SETFOCUS: The list container widget responds to set focus events by automatically scrolling the current focus item into view, then passes the event through to the single child IWidget used to represent each list item. The child widget may then respond as necessary, generally redrawing itself to reflect that it now has focus. EVT_WDG_SCROLL : The list container widget supports the following scroll notifications. WSCROLL_PAGEUP WSCROLL_PAGEDOWN WSCROLL_PAGELEFT WSCROLL_PAGERIGHT WSCROLL_VPOSITION WSCROLL_HPOSITION WSCROLL_UP WSCROLL_DOWN WSCROLL_LEFT WSCROLL_RIGHT WSCROLL_VPOSITION_UP WSCROLL_VPOSITION_DOWN WSCROLL_HPOSITION_LEFT WSCROLL_HPOSITION_RIGHT
int IWidget_SetTopIndex(IWidget *pif, int index) int IWidget_SetFocusIndex(IWidget *pif, int index) int IWidget_SelectIndex(IWidget *pif, int index) int IWidget_SetCols(IWidget *pif, int v) int IWidget_SetIncrement(IWidget *pif, int v) int IWidget_RequestScrollEvent(IWidget *pif) int IWidget_SetOffsetX(IWidget *pif, int v) int IWidget_SetOffsetY(IWidget *pif, int v) int IWidget_SetTouchMode(IWidget* pif, int nTouchMode) int IWidget_SetTouchTransparencyThreshold(IWidget *pif, int nThreshold) int IWidget_SetHintRows(IWidget *pif, int v) int IWidget_SetHintCols(IWidget *pif, int v) int IWidget_SetRows(IWidget *pif, int v) int IWidget_SetCols(IWidget *pif, int v) int IWidget_ReleaseItemWidget(IWidget *pif, IWidget *piw) int IWidget_SetViewModel(IWidget *pif, IModel *pifModel) int IWidget_GetTopIndex(IWidget *pif, int *pnIndex) int IWidget_GetFocusIndex(IWidget *pif, int *pnIndex) int IWidget_GetCols(IWidget *pif, int *pnValue) int IWidget_GetViewModel(IWidget *pif, IModel **ppif) int IWidget_GetIncrement(IWidget *pif, int *pnValue) int IWidget_GetOffsetX(IWidget *pif, int *pnValue) int IWidget_GetOffsetY(IWidget *pif, int *pnValue) int IWidget_GetOrientation(IWidget *pif, int *pnOrientation) int IWidget_GetTouchMode(IWidget *pif, int *pnTouchMode) int IWidget_GetBottomIndex(IWidget *pif, int *pnIndex) int IWidget_GetTouchTransparencyThreshold(IWidget *pif, int *pnThreshold) int IWidget_GetHintRows(IWidget *pif, int *pnValue) int IWidget_GetHintCols(IWidget *pif, int *pnValue) int IWidget_GetRows(IWidget *pif, int *pnValue) int IWidget_GetItemWidget(IWidget *pif, int nIndex, IWidget **ppiw) int IWidget_GetItemState(IWidget *pif, int nIndex, int * pState) int IWidget_GetItemRect(IWidget *pif, int nIndex, AEERect *prc)
The list container supports this set of (mostly) mutually exclusive flags that dictate layout and behavior characteristics for the list, pick and grid widgets. These flags are passed in the 'dwParam' of the PROP_FLAGS property event.
When this flag is set the list will wrap as one continuous loop of items. For example, as the user scrolls to the bottom of a list, then attempts to move one item lower, the first item in the list is the next that will be displayed -- though only if the list contains more items than can be displayed within the list boundary. Likewise, when scrolling to the top of a list, the next item to be displayed prior to the first item, will be the item at the bottom. When this flag is not set, any attempt to scroll beyond the limits (top, bottom, left or right, depending on the type of list) will stop right there without wrapping.
When this flag is set, the list does not support selection and will not recognize or notify other objects of selection events. This flag takes priority over the LWF_WRAP flag and will clear that flag if an attempt is made to set both flags (i.e. LWF_WRAP will be automatically cleared if LWF_NOSELECT is set). When selection is not enabled, the net effect is a list that purposefully has a defined beginning and end.
This flag effects how the grid widget will respond to key events that attempt to move the current selection up or down. When the flag is set, up/down navigation over the items in the grid circle and wrap past the items in a single column. Therefore, a grid that has been laid out as,
+----+----+----+ | 1 | 2 | 3 | | | | | +----+----+----+ | 4 | 5 | 6 | | | | | +----+----+----+ | 7 | 8 | 9 | | | | | +----+----+----+
would see the focus cycling over items 1, 4 and 7, over and over again, scrolling into view hidden items if the content extends beyond the vertical dimensions of its boundary. When this flag is clear, the focus will stay within the current column, but will not wrap. So, in the example above, navigating down would move from item 1, to 4, then to 7 and stop there.
Like LWF_COLUMNWRAP, this flag effects how the grid widget will respond to key events that attempt to move the current selection up or down -- not limiting, however, the wrapping to a single column. Therefore, when the flag is set, up/down navigation over the same nine-item grid displayed above would see the focus cycling as follows.
1, 4, 7, 2, 5, 8, 3, 6, 9... then back to 1
Items not displayed within the dimensions of the grid widget's boundary will be scrolled into and out of view as necessary as the focus moves.
Property Value: uint32
This flag is used for list, pick, or grid widgets to be able to be scrolled pixel by pixel, instead of line by line. By default, the increment scroll size will be set to one pixel, and it can be customized using the property PROP_INCREMENT. Arrow scrolling up/down will utilize the PROP_INCREMENT set value.
This flag is used to live scroll the list, pick, or grid widget. Live scrolling starts when list receives EVT_POINTER_DOWN on the list item, followed by one or more EVT_POINTER_MOVE and followed by EVT_POINTER_UP. List will start moving with respect to EVT_POINTER_MOVE after covering certain distance. By default this distance is set to be 5 pixels, and it can be customized by using property PROPEX_MIN_LIVESCROLL_DIST. Application should also set LCF_PIXELSCROLL flag along with LCF_LIVESCROLL for a smooth live scrolling.
Required Model: The list container widget must have a model attached. The model can either be a ListContainerModel that will create the list items on demand or a TypedListModel/ListModel that contains all the pre-populated widgets.
List Container Model When the user wishes to use a ListContainerModel then they can create one using the ListContainerModelFactory. When the list container is supplied a ListContainerModel the list container will use this model to acquire the list item widgets only when the list needs them. Usage of the List Container Model is best suited for long lists or for apps where start up time is very important.
Typed List Model/List Model. When the user supplies a TypedListModel/ListModel to the list container the user must ensure that the model contains a list of pre-populated widgets. The list container will in turn use each widget in the model to represent its equivalent list item. There will be a one to one mapping between the items in the list and the widgets in the list container, the first item in the list will be represented by the first widget in the model and so forth. It is suggested that users supply a ITypedListModel/IListModel when the list is short and they dont mind the up front cost of creating all the item widgets.