previous chapter contents page top page next chapter

ListView

August 29, 1994

Defined in ListView.Def 
Inherits from GridView, AcceptsTyping



Class Description

A list view is a grid view that displays an object list. Class ListView implements the functions of the abstract class GridView. List views show up everywhere in Magic Cap: they display lists of messages in the in box, they display choice lists in choice boxes, and they are the directories in the Hallway and Downtown.

Remember that if the documentation and the software (especially the definition files) disagree, always trust the software.

Using a ListView Object

List views come in two basic flavors: the flavor that takes some action when you touch an item in it, and the flavor that just lets you make a selection. The second flavor usually appears with an "accept" button. List views appear as pieces of many different user interfaces in Magic Cap; exactly how you'll use the list view depends on how it's presented.

Programming Information

Instantiate: sometimes
Subclass: sometimes
Call its methods: rarely

You will probably not need to call any of the methods of class ListView. Just put your list view objects into place in your object definition files and set their flags appropriately. You might need to create custom subclasses of class ListView if none of the provided subclasses meet your needs. Methods you might override when you subclass are described later in this chapter.

Methods defined by class ListView

Class ListView defines the following methods:

Method Description
Matching list items to cells
CellToIndex Given a row and column, return the index of the list item to put in that cell
IndexToCell Given an index into the list, calculate the row and column of the cell it will be displayed in
ValueAt Given a list item, return the value to be displayed in the list view
Manipulating objects in cells
DeleteSelection Remove the item in the selected cell from the view's list
EditName Bring up the name editor for the selected object
GoTo Go to the selected object if possible
TouchedObject Do the appropriate thing when an item in the view is tapped
Confirm Accept current state of listView (does nothing unless overridden)
TapObject Simulate a tap on a line of the list view
framework methods
AboutToHide, AboutToShow Overridden to handle observing the view's list
AdjustSize Overridden to include displayed list in size calculation
Draw Overridden to draw scroll arrows if necessary
DrawCell Overridden to respect list view flags
DrawRow Overridden to handle items that don't fit in the view
Editable Overridden to return true only if keyboardScroll flag is set
MaximumScrollOffset Overridden to turn off horizontal scrolling
TextInfo Overridden to use summaryString field and number of items in list to construct a text info string
MatchText Overridden to step through the view's list looking for a match
Notice Overridden to request a redraw of the view if the list changes
RowCount Overridden to calculate and return the number of rows required to display all the items in the list view
List, SetList Get and set the list to be displayed by the view
Touch Overridden to handle selecting touched cell and tapping on scroll arrows
TypeKeys Overridden to move the selection to the next row starting with or after the typed character

Methods you might override

When you create a subclass of class ListView, you might override these methods under the following circumstances:

Method When to override
TouchedObject If tapping an item in your list view subclass should do something special
DrawCell To customize the way your list view's cells are drawn
RowHeight If your rows need to be tall
Confirm To accept current state of ListView
Swallow To allow your list view to swallow certain kinds of morsels

Fields defined by class ListView

Class ListView defines the following fields:

Field Type Description
inherited from SingleLinkable:
next Object next item in view list
inherited from Linkable:
previous Object previous item in view list
inherited from Viewable:
superview Viewable container for this object
subview Viewable first object contained by this object
relativeOrigin Dot origin relative to superview
contentSize Dot size of content rectangle
viewFlags Unsigned property settings
labelStyle TextStyle text style of viewable's label
color Unsigned color of viewable's content
altColor Unsigned alternative color (used only by Control and DrawShadowedImage)
shadow Shadow shadow drawn with object
sound Sound sound associated with object
inherited from HasBorder:
border Border the gridview's border
inherited from ScrollableByMicron:
scrollOffset Dot stores the list view's scroll position
inherited from GridView:
gridFlags Flags flags that control grid view behavior
cellTextStyle TextStyle text style used to display list view entries (also determines row height)
columnTitles Text a text object that contains \n delimited column titles
emptyMessage Text message shown if the list view is empty (that is, the row count is 0 and there are no row lines)
selectedColumn Unsigned selected column
selectedRow Unsigned selected row
titleTextStyle TextStyle used for column and row titles
defined by ListView:
list FixedList the list displayed by the list view
summaryString Text a string used in constructing a summary of the list view's contents

As with grid view objects, each column of a list view needs four extra data fields to describe it. Append the column number to the field names. The four fields are:

offsetn The position of the left edge of this column, expressed as the number of microns from the left edge of the list view.
keyn The key to pass to TextInfo (if you've set the valueIsTextInfo column flag) or to Attribute (if you've set the valueIsAttribute column flag) when constructing a string to display in the list view. See the section on attribute codes later in this chapter for a list of possible codes.
typen The type of the data displayed in this column. The type is passed to ValueToText, which uses the information to construct a string for the list view to display. See the section on type codes later in this chapter for a list of possible types.
flagsn Additional flags that control how the column is displayed and specify what kind of information is in the column. See the column information flags description later in this chapter for more information on the available flags.

Include one set of each of these fields for each column in your list view. For example, a list view with three columns would include 12 extra fields in its instance definition.

Here's how class ListView fills in each of its cells with a value from its fixed list:

  1. The CellToIndex method converts the cell's row and column numbers into an index into the fixed list. List view flags like the useListElementPerCell flag can affect this conversion.

  2. The ValueAt method extracts the interesting value from the object at position index in the list. You specify the interesting value with the column flags and key fields. For example, the flags field can specify that the interesting value is an attribute, or is the object's text info. The column key further describes the value. The key is passed to one of the methods of class Object, like Attribute or TextInfo. (See the description of the available column flags for more information.)

  3. Finally, the value is converted to a string with ValueToText. List views display strings, but your data won't always be in string format to start with. The type of your data is specified by the column's type field. The type is passed to ValueToText as the typeNumber parameter.

Class Object defines the TextInfo and Attribute methods. For complete descriptions of these methods, please see the chapter on class Object. Class Utilities defines the ValueToText method. See the chapter on class Utilities for a list of the type numbers used by ValueToText.


Version note: Unfortunately, the chapter on class Object is out of date, and the chapter on class Utilities doesn't yet exist. To get a list of type numbers for ValueToText, see the file Utilities.h. What promise the future holds!


Here's an example of a list view with two columns:

Instance ListView 'Biking to work: a debate' 135;
           next: nilObject;
       previous: nilObject;
      superview: (Scene 'BookExamples' 8);
        subview: nilObject;
 relativeOrigin: <-4.0,-45.0>;
    contentSize: <437.0,126.0>;

      viewFlags: 0x70110000;
     labelStyle: iJot12;
          color: 0xFF000000;
       altColor: 0xFF000000;
         shadow: nilObject;
          sound: nilObject;
         border: nilObject;
   scrollOffset: <0.0,0.0>;
      gridFlags: 0x12320000;
  cellTextStyle: iBook10; 
   columnTitles: (Text 136);
   emptyMessage: (Text 137);
 selectedColumn: 0;
    selectedRow: 0;
 titleTextStyle: iSign12;
           list: (ObjectList 'Reasons' 139);
  summaryString: (Text 138);
        offset1: <8.0>;
           key1: 0;
          type1: 3.s;
         flags1: 2.s;
        offset2: <200.0>;
           key2: 0;
          type2: 3.s;
         flags2: 2.s; 
End Instance;

Instance Text 136;
           text: 'Pro\nCon';
End Instance;

Instance Text 137;
           text: 'No arguments.';
End Instance;

Instance Text 138;
           text: 'about biking to work.';
End Instance;

Instance ObjectList 'Reasons' 139;
         length: 9;
          entry: (Text 140);
          entry: (Text 141);
          entry: (Text 161);
          entry: (Text 142);
          entry: (Text 143);
          entry: nilObject;
          entry: (Text 144);
          entry: (Text 145);
          entry: nilObject;
End Instance;

Instance Text 140;
           text: 'You\'ll get fit.';
End Instance;

Instance Text 141;
           text: 'You\'ll get sweaty.';
End Instance;

Instance Text 142;
           text: 'It\'s relaxing.';
End Instance;

Instance Text 143;
           text: 'It takes longer than driving.';
End Instance;

Instance Text 144;
           text: 'You\'ll save money.';
End Instance;

Instance Text 145;
           text: 'You might get rained on.';
End Instance;

Both columns have their flags field set to 2, so they both display the text info of the list element they contain. Since both columns display text, they're both type IDString, 3.

Here's what this list view looks like:

If the list field were nilObject, or contained an empty object list, the example list view would look like this:

List views display the text object in the emptyMessage field when they're empty. The empty message uses a bold variety of the text style given in the cellTextStyle field.

Constants used by class ListView

This section describes four kinds of constants used by class ListView: grid flags, column information flags, attribute codes, and type codes.

Grid flags

Set these flags in the gridFlags field of your list view objects. Class ListView inherits this field from class GridView, and uses all the grid flags defined by GridView. The flags described in this section are used only by class ListView and its subclasses, and aren't part of the basic behavior of grid views.

selectMode

#define selectModeMask0x80000000

Set this flag if you'd like users to select items in your list view. If this flag is set, class ListView's Touch method just selects the list item touched by the user. If this flag isn't set, ListView_Touch calls TouchedObject with the object the user just touched.

useContainerList

#define useContainerListMask 0x20000000

Set this flag if your list view should use its enclosing card's list (or its superview's list, if it isn't enclosed in a card). The List method checks this flag. If it's set, ListView_List will pass along the List call to the list view's superview or enclosing card.

keyboardScroll

#define keyboardScrollMask0x08000000

Set this flag if your list view should scroll to the next line matching a typed character. This flag is probably useful only if your list view displays its items in alphabetical order. The Editable method returns true if this flag is set. The TypeKeys method does nothing if it isn't.

scrollToSelected

#define scrollToSelectedMask 0x04000000

Set this flag if the current scene should scroll to a particular location when the location's entry in the list is selected. For example, directory listings like the ones in the hallway and downtown use this flag to scroll to the entrance that matches a tapped list entry.

The TouchedObject method checks this flag.

useClassList

#define useClassListMask0x00400000

If this flag is set, the AboutToShow method won't start observing the list view's list. The List method will return ClassList_. You will probably never set this flag unless you're writing a class browser hack.

menuResizeH

#define menuResizeHMask0x00100000

Set this flag if your list view should adjust its width to accomodate its widest entry. The AdjustSize method checks this flag.

alwaysOneSelected

#define alwaysOneSelectedMask0x00080000

Set this flag if one of the items in your list view must always be selected. If there's no other selection, the AboutToShow method will automatically select the first list entry.

The AboutToShow and SetSelected methods check this flag.

setCurrentContact

#define setCurrentContactMask0x00040000

Set this flag if the iCurrentContact indexical should be kept in synch with your list view's selection. You'll find yourself setting this flag often for list views that list people or address cards.

The AboutToShow methods checks this flag. If the flag is set, AboutToShow checks the iCurrentContact indexical. AboutToShow sets the list view's selection to be the current contact, if a current contact exists. If one doesn't exist, AboutToShow sets iCurrentContact to the list view's selection.

The SetSelected method also checks this flag. If it's set, SetSelected updates the iCurrentContact indexical to the current list view selection. The Touch method does the same.

dontTrack

#define dontTrackMask0x00020000

Set this flag if your list view should not track touches or change its selection because of a touch. You'll find this flag handy if your list view just displays an informative list that you don't expect your users to interact with.

The Touch method checks this flag. If it's set, Touch returns without doing anything.

showRemaining

#define showRemainingMask0x00010000

Set this flag if the last line of your list view should display the number of items that won't fit on the screen. You won't want to set this flag if you've set the listViewArrow flag.

The DrawRow method checks this flag. If it's set, and the list is too long too fit in the view, DrawRow puts the string "(and n more)" into the last line of the list view. It draws the string using the same text style the rest of the list uses.

Here are two list views, identical save for size, that both set this flag:

useListElementPerCell

#define useListElementPerCell0x00000400

Set this flag if your list view should map list elements to cells in the view instead of mapping to rows. The CellToIndex and IndexToCell methods check this flag in the process of mapping cell locations to list indices.

Here's an example of a list view that sets the per cell flag:

Here's how the same list view looks with the per cell flag turned off:

These two views both use the same object list, but the top one puts one list item into each cell. The bottom list puts one list item into each row. When the per cell flag isn't set, CellToIndex returns the row number as the list index to use to fill in each cell. So both columns in a row will display the same list element.

You will want to set this flag for list views with multiple columns where each cell should display a different object in your list. Don't set it when you want all columns in a row to display the same object, such as when each column displays a different attribute of the object.

useItemSelected

#define useItemSelected0x00000040

Set this flag you're using list views to implement menus for choice boxes. That is, the system uses this flag to do just that, but you probably won't need to use it yourself.

Class TargetedListView uses this flag. Plain ListView objects or objects from other subclasses of ListView will not respect this flag.

The TouchedObject method checks this flag. If it's set, TouchedObject calls ItemSelected on the list view's target (which will probably be a choice box), passing the row number of the selection as the theIndex parameter.

emboldenGroups

#define emboldenGroupsMask0x00000010

Set this flag if your list view should use a boldface font to display the names of groups. If your list view is a PeopleList object, you'll probably want to set this flag. The DrawCell method checks this flag.

confirmOnSelect

#define confirmOnSelectMask0x00000008 

Set this flag if the list view should call Confirm on itself every time its selection changes. ListView_Touch checks this flag when a new selection is made, and calls Confirm if its set.

If you've set this flag, be sure you've also subclassed ListView and overridden Confirm.

listViewArrow

#define listViewArrowMask0x00000002 

Set this flag if your list view should display scroll arrows when its list is too long to fit. You won't want to use this flag if you're using the show remaining flag.

Instead of setting this flag, you could put scroll arrow objects into your list view yourself. Putting in arrows yourself uses more memory and is slightly slower than setting the listViewArrow flag. You'll want to roll your own scroll arrows if the automatically chosen arrow positions aren't to your liking.

The AdjustSize method checks this flag, and adds space in the list view for scroll arrows if necessary. The Draw method also checks this flag and draws the required scroll arrows. The Touch method handles touches on scroll arrows.

Column information flags

Set these flags in the flagsn extra field to control how the list view draws column n. The first four flags specify the kind of information the column should display, and the second four specify how the column should be drawn.

valueIsAttribute

#define valueIsAttribute0x0001

Set this flag if your list contains objects and this column should display an attribute of those objects. Use the column key field to specify the number of the attribute to display.

If this flag is set, ValueAt will return the result of this call:

Attribute(object, key);

where the key parameter is the value in the column's key field.

valueIsTextInfo

#define valueIsTextInfo0x0002

list contains objects, return TextInfo(object, key) */

Set this flag if your list contains objects and this column should display the text info of each object. Use the column's key field to specify the kind of text information you want. For a list of keys understood by TextInfo, see the chapter on class Object and the list in the next section of this chapter.

If you don't set either valueIsAttribute or valueIsTextInfo, ValueAt will return the object itself as the value.

valueIsEditable

#define valueIsEditable0x0004

This flag is currently unused. Please don't set it. (If you set it, it will have no effect.)

valueIsAbbreviated

#define valueIsAbbreviated0x0040

The ValueAt method checks this flag. If it's set, ValueAt calls TextInfo with the abbrevFlag parameter set to true. Not all classes that implement TextInfo use the abbrevFlag parameter.

The next four flags affect how the column is drawn. The DrawCell method checks them and changes a cell's text style appropriately.

omitColumnLine

#define omitColumnLine0x0008

Set this flag to suppress all lines between columns.


Version note: This flag is unimplemented in Magic Cap 1.0.


forceCentered

#define forceCentered0x0010

Set this flag if you want to force the column contents to be centered.

forceRightAligned

#define forceRightAligned0x0020

Set this flag if you want to force this column's contents to be aligned with the column's right edge.

allowSpillRight

#define allowSpillRight0x0080

Set this flag if this column should spill over to the right if the column to the right is empty. Here are two list views, identical save for the column flags for the middle columns:

The first one doesn't set the allowSpillRight flag. Its middle column is too small, so most of its text is hidden. The second does set the allowSpillRight flag. Its text spills over into the empty "Padding" column. The third list view also sets the spill right flag for the second column, but the third column isn't empty. Columns won't spill over into space that isn't empty.

Key Codes

The key codes determine which attribute or kind of text info of an object should be displayed in the current column. To display an object's attribute, set the valueIsAttribute column flag and use the attribute number in the key field. To display an object's text info, set the valueIsTextInfo column flag and put the text info code into the key field. This section lists text info codes.

For example, suppose you have a view displaying a list of telecards. If column 4 has has this code:

         key4: 3;

column 4 will display the subject of each telecard.

The available text info codes are:

Attribute Number Description
kSenderName 1 the name of a card's sender, in last,first order with disambiguating integer if necessary
kReceiverName 2 the name of a card's receiver, in last,first order with disambiguating integer if necessary
kSubject 3 the subject of a telecard
kDateSent 4 the date a card was sent
kDateReceived 5 the date a card was received
kTypeDescription 6 text description of item type (such as, "Postcard to Mom")
kTypeIcon 7 icon for item type
kSenderOrReceiver 8 if WasSent, senderName else receiverName
kDuration 9 duration of call
kDateTimeSent 10 show both date and time
kContactLocation 11 location of contact (i.e. Home phone)
kOrderedSwitch 12 for OrderListView, the switch that sez whether item is ordered
kContactPhoneNumber 13 phone number of contact location
kPhoneAreaCode 14 area code
kPhonePrefix 15 dialing prefix
kPhoneLocalTolls 16 local tolls of NumberingPlan
kSelectedSwitch 17 for LocationListView, the switch that indicates selected item
kContentDescription 18 content description for ContentListView_
kCheckboxColumn 19 placeholder for checkbox column in CheckboxListView_
kDisplayNameUnflipped 20 first, last with disambiguating integer if necessary
kSizeInKBytes 21 the size of the object in kilobytes

Here's an example of a list view that uses these key codes to display different attributes of an object in different columns. This object is a of a subclass of class ListView, class SummaryListView.

Instance SummaryListView 1451;
           next: (ScrollArrow 11614);
       previous: nilObject;
      superview: (Scene 'Mailbox report' 1329);
        subview: nilObject;
 relativeOrigin: <0.0,-23.0>;
    contentSize: <480.0,210.0>;
      viewFlags: 0x100E0000;
     labelStyle: iBook12;
          color: 0xFF000000;
       altColor: 0xFF000000;
         shadow: nilObject;
          sound: nilObject;
         border: iBorderBlack1;

   scrollOffset: <0.0,0.0>;
      gridFlags: 0x11200100;
  cellTextStyle: iBook12;
   columnTitles: (Text 11612);
   emptyMessage: (Text 9127);
 selectedColumn: 0;
    selectedRow: 0;
 titleTextStyle: iBook12Bold;
           list: (SummaryStack 9125);
  summaryString: nilObject;
    checkImage1: iRoundCheckMarkOff;
    checkImage2: iRoundXOff;
     checkAttribute1: operation_IsCollected;
     checkAttribute2: operation_IsDeleted;
     ignoreAttribute: operation_IsForwarded;
        offset1: <5.0>;
           key1: 7;     // kTypeIcon
          type1: 3.w;   // irrelevant
         flags1: 2.w;   // irrelevant
        offset2: <42.0>;
           key2: operation_OriginatorName;  // kSenderName
          type2: 7.w;   // typeIDObject
         flags2: 1.w;   // valueIsAttribute
        offset3: <168.0>;
           key3: 4;     // kDateSent
          type3: 3.w;
         flags3: 66.w; //valueIsTextInfo|valueIsAbbreviated
        offset4: <235.0>;
           key4: 21;    // kSizeInKBytes
          type4: 3.w;
         flags4: 34.w; //valueIsTextInfo | forceRightAligned
        offset5: <271.0>;
           key5: 0;     // empty column for spacing
          type5: 0.w;   // typeIDNone
         flags5: 1.w;   // valueIsAttribute
        offset5: <276.0>;
           key5: operation_Subject;  // kSubject
          type5: 7.w;   // typeIDObject
         flags5: 1.w;   // = valueIsAttribute
        offset5: <394.0>;
           key5: 19;    // kCheckboxColumn
          type5: 0.w;   // typeIDObject
         flags5: 0.w;                        
        offset5: <427.0>;
           key5: 22;    // kCheckbox2Column
          type5: 7.w;   // typeIDObject
         flags5: 1.w;   // valueIsAttribute
End Instance;

Type Codes

List views display strings, but your data won't always be in string format to start with. Specify the type of your data in each column's type field. The type is passed to ValueToText as the typeNumber parameter.

These are the type codes you can use in the column type extra field:

#define typeIDNone                0
#define typeIDFlags               1
#define typeIDBoolean             2
#define typeIDString              3
#define typeIDDouble              4
#define typeIDPoint               5
#define typeIDRect                6
#define typeIDObject              7
#define typeIDMicron              8
#define typeIDDot                 9
#define typeIDBox                10
#define typeIDPixelDot           11
#define typeIDPixelBox           12
#define typeIDSignedByte         13
#define typeIDSigned             14
#define typeID7BitCharacters     15
#define typeIDPointer            16
#define typeIDSignedShort        17
#define typeIDFixed              19
#define typeIDCharactersPointer  20
#define typeIDUnsignedByte       21
#define typeIDUnsigned           22
#define typeIDUnsignedShort      23
#define typeIDCharacters    24
#define typeIDCharacter     25
#define typeIDLiteral            26

You can also find this list in the file Generic.h.

Method Descriptions

TouchedObject

operation TouchedObject(touchInput: TouchInput; object: Object; column: 
Unsigned; row: Unsigned)

Call: rarely
Override: sometimes

The system calls TouchedObject from ListView_Touch if the selectMode flag is not set. The system calls Touch when the user taps a cell of the list view.

The touchInput parameter is passed along unchanged from the original Touch call. The object parameter is the object in the touched cell. The column and row parameters are the column and row numbers of the touched cell.

Override TouchedObject if tapping an item in your list view subclass should do something special. For example, you might want to go to a special destination when an object is touched. Or you might want to play a special sound.

ListView_TouchedObject already handles a number of special cases where touching an item in a list view should have an effect. Those special cases are:

If the item is none of the above, TouchedObject calls the item's GoTo methods.

DrawCell

operation DrawCell(canvas: Canvas; clip: Path; column: Unsigned; row: 
Unsigned; bounds: Box)

Call: rarely
Override: sometimes

The system calls DrawCell on each cell of the list view while drawing it. Override DrawCell if you need to customize the way your list view's cells are drawn.

RowHeight

operation RowHeight(row: Unsigned): Micron

Call: rarely
Override: sometimes

The system calls RowHeight while drawing a list view. The row parameter is the number of the row to check. RowHeight returns the height of the given row in microns. Class ListView doesn't override RowHeight. Class GridView defines RowHeight to return the height of the cell's text style.

Override RowHeight if your rows are taller than their text style. For example, you might using a custom subclass of ListView to display images in addition to text.

Confirm

operation Confirm(), safe, common, noFail

Call: rarely
Override: sometimes

Override Confirm to do any work you need to accept current state of a ListView. For example, you might be using a custom subclass of ListView to allow your user to select an item from a list. When the user taps an "accept" button, you could call Confirm on the list view to ensure that the selection is valid.

If the list view's confirmOnSelect flag is set, the SetSelected and Touch methods will also call Confirm.

Swallow

operation Swallow(morsel: Object; where: Dot; realSwallow: Boolean): 
Boolean

Call: rarely
Override: sometimes

Override Swallow to allow your list view to swallow certain kinds of morsels.

In your override, you probably want to call the inherited Swallow method for all other kinds of morsels. Do so with code that looks like this:

/* call inherited for all uninteresting morsels */
if (!Implements(morsel, InterestingMorselClass_))
    return InheritedSwallow(self, morsel, where, 
           realSwallow);
/* go on to process interesting morsels */

See Viewable_Swallow for more information on the Swallow method's parameters and return value.