# The Interface Kit: BListItem

Derived from: public BArchivable

Declared in: be/interface/ListItem.h

Library: libbe.so

## Overview

A BListItem is an object that can cooperate with a BListView, including a BOutlineListView, to display one item in a list. The BListItem draws the item and keeps track of its current state. The BListView manages the list, responds to messages, provides its items with the graphics environment they need to draw, and calls upon them to draw when needed.

BListItem is an abstract class; derived classes must implement a `DrawItem()` function to draw the item. The BStringItem class is the only implementation of a BListItem available in the Interface Kit. It draws the item as a line of text.

A BListItem records some properties that are relevant only if it's part of a BOutlineListView--in particular, the level of the item in the outline and whether it's expanded (its subitems are displayable) or collapsed (its subitems are not displayable). Other properties apply to all lists--for example, whether or not the item is selected and whether it's enabled or disabled.

The class provides functions to set and return these properties. However, setting a BListItem property doesn't by itself alter the display or inform the container BView. The view communicates with the BListItem, but the item doesn't reciprocate and communicate with the BListView. Therefore, once a BListItem has been added to a list, it's generally best to manipulate it through BListView (and BOutlineListView) functions, rather than directly through its own functions.

## Creating a Custom List Item

Although much of the time all you need to draw in a list are strings (in which case you can use the BStringItem class), from time-to-time you may need to display more than a simple text string in list items--maybe you need to display multiple pieces of information per item, or maybe you want to jazz up the display with some icons.

Creating custom list items is very simple. For example, let's say you need to let the user select a city from a list, but also need to display the part of the world that each city is in. You could just use BStringItem objects with strings like "Chicago (USA)", but it might look nicer if you could lay out your list items in two colums, maybe with a splash of color:

To change the appearance of a list item, you simply override the `DrawItem()` function to draw the item's contents however you want it to look.

Here's a sample class, derived from BListItem, that does exactly that:

       class CityItem : public BListItem {
          public:
                         CityItem(char *s, int32 region = 0);
                         ~CityItem();
             virtual void   DrawItem(BView *owner, BRect frame, bool complete = false);

          private:
             char         *city;
             int32         region;
       };

The CityItem class tracks two pieces of data: a string, which is the name of the city, and a region code, which is used as an index into an array of region names, as follows:

       char *region_names[] = {
          "USA", "Asia", "Eur.", "Aust.", "Other"
       };

For convenience, we can provide named constants for these regions:

       const int32 kRegionUSA = 0;
       const int32 kRegionAsia = 1;
       const int32 kRegionEurope = 2;
       const int32 kRegionAustralia = 3;
       const int32 kRegionOther = 4;

The constructor looks like this:

       CityItem::CityItem(char *s, int32 r)
                : BListItem(){
          city = (char *) malloc(strlen(s)+1);
          strcpy(city, s);
          region = r;
       }

The constructor lets the constructor inherited from BListItem do its thing, then allocates memory for a copy of the city's name and copies the string into it. The region number is also saved.

The destructor, below, simply releases the memory used for the city name:

       CityItem::~CityItem() {
          free(city);
       }

The `DrawItem()` function does the actual work of drawing the item. `DrawItem()` receives three parameters:

- A BView, which is the view that contains the BListItem. All drawing calls you issue should be made through this BView, such as:

          owner->DrawString(item_text);

- A BRect, which is the rectangle in which the item should be drawn.

- A bool, which is `true` if the item needs to be erased and redrawn, or `false` if the item's contents can be safely redrawn without erasing the current contents.

       void CityItem::DrawItem(BView *owner, BRect frame, bool complete) {
          if (IsSelected() || complete) {
             rgb_color color;
             if (IsSelected()) {
                color = kHighlight;
             }
             else {
                color = owner->ViewColor();
             }
             owner->SetHighColor(color);
             owner->FillRect(frame);
          }

`DrawItem()` begins by checking to see if the item is selected (by calling `IsSelected()`) or if a complete redraw is required (if the complete flag is `true`). If a complete redraw is needed, we have to erase the item's background., otherwise we don't.

If we do have to erase the background, and the item is selected, we fill the frame rectangle with the highlight color, otherwise, we fill the frame rectangle with the owner's view color.

          owner->MovePenTo(frame.left+4, frame.bottom-2);
          if (IsEnabled()) {
             owner->SetHighColor(kRedColor);
          }
          else {
             owner->SetHighColor(kDimRedColor);
          }
          owner->DrawString(region_names[region]);

Then we need to draw the region name. First, we move the owner view's pen to the desired coordinates; by adding four to the left edge of the frame rectangle, we have a margin that makes the item easier to read. We offset upward from the bottom edge of the rectangle by two pixels to leave room for the descenders in the text being displayed (in reality you should adjust this based on the actual font being used; see the BFont class for more information).

If the item is enabled (selectable), we set the owner view's high color to a shade of medium red; if it's disabled, we use a lighter red color. Then we draw the region name by looking it up in the string array `region_names` and passing that string to `DrawString(`).

          owner->MovePenTo(frame.left+38, frame.bottom-2);
          if (IsEnabled()) {
             owner->SetHighColor(kBlackColor);
          }
          else {
             owner->SetHighColor(kMedGray);
          }
          owner->DrawString(city);
       }

Things are then wrapped up by moving the pen to the coordinates at which the city name should be drawn, selecting an appropriate color (black if the item is enabled, medium gray if it's disabled), and drawing the city name string.

Then you can add a CityItem to any list, like this:

       list->AddItem(new CityItem("Chicago", kRegionUSA));

## Hook Functions

`DrawItem()
` Must be implemented to draw the item.

`UpdateInfo()
` Can be implemented to update cached information.

## Constructor and Destructor

### BListItem()

          BListItem(uint32 level = 0, bool expanded = true)
          BListItem(BMessage *archive)

Marks the BListItem as being at the specified outline level and as controlling an expanded section of the outline if the expanded flag is `true` or a collapsed section if expanded is `false`. Outline levels are indicated by an index, with 0 as the outer level, 1 for one level of indentation, 2 for two levels of indentation, and so on.

Initially, the item has a width of 0.0, a height of 0.0, is enabled, and is not selected.

### ~BListItem()

          virtual ~BListItem()

Does nothing.

## Member Functions

### Archive()

          virtual status_t Archive(BMessage *archive, bool deep = true) const

Calls the inherited version of `Archive()`, then adds four pieces of information to the archive BMessage:

- The outline level of the item
- Whether the item controls a collapsed or an expanded part of the list
- Whether the item is currently selected or not
- Whether or not the item is currently enabled

See also: `BArchivable::Archive()`, `Instantiate()` static function

### Deselect() see Select()

### DrawItem()

          virtual void DrawItem(BView *owner, BRect itemRect, bool drawEverything = false) = 0

Implemented by derived classes to draw the item in the itemRect portion of the owner BView. If the drawEverything flag is `true`, this function should touch every pixel in the itemRect rectangle. If the flag is `false`, it can assume that background pixels are already the correct color. For example:

       void MyItem:DrawItem(BView *owner, BRect itemRect, bool drawEverything)
       {
          rgb_color color;

          if (IsSelected()) {
             color = my_highlight_color;
             owner->SetHighColor(color);
             owner->FillRect(itemRect);
          }
          else if (drawEverything) {
             color = owner->ViewColor();
             owner->FillRect(itemRect);
          }

          /* Actually draw the item itself here, through
           * DrawString() or whatever.
           */
          . . .
       }

`DrawItem()` should be implemented to visually reflect the state of the item, highlighting it if it's selected, dimming it if it's disabled, and so on. However, it should not consider the outline level. If the level is important, the owner BView will have already taken it into account in calculating the itemRect rectangle.

See also: `BListView::Draw()`

### Height() see SetHeight()

### IsEnabled() see SetEnabled()

### IsExpanded() see SetExpanded()

### IsSelected() see Select()

### OutlineLevel()

          uint32 OutlineLevel(void) const

Returns the outline level of the item. The greater the return value, the deeper the level. The outermost level is 0.

See also: the BOutlineListView class

### Select(), Deselect(), IsSelected()

          void Select(void)

          void Deselect(void)

          bool IsSelected(void) const

`Select()` and `Deselect()` mark the item as being selected or unselected. However, these functions don't inform the BListView of the change. To select and deselect items that have been added to a view, call the container BListView's `Select()` and `Deselect()` functions instead. Those functions update the display on-screen and mark the BListItem accordingly.

`IsSelected()` returns `true` if the item is selected and `false` if not.

See also: `BListView::Select()`, `BListView::Deselect()`

### SetEnabled(), IsEnabled()

          void SetEnabled(bool enabled)

          bool IsEnabled(void) const

`SetEnabled()` marks the BListItem as being enabled if the enabled flag is `true`, or disabled if the flag is `false`. `IsEnabled()` returns the current enabled state of the item.

`SetEnabled()` doesn't alter how the item is displayed; you must take steps to invalidate the region of the BView where the item is displayed so that `DrawItem()` will be called.

See also: `BListView::InvalidateItem()`

### SetExpanded(), IsExpanded()

          void SetExpanded(bool expanded)

          bool IsExpanded(void) const

`SetExpanded()` marks the item as controlling an expanded section of the list if the expanded flag is `true`, or as controlling a collapsed section if expanded is `false`. `IsExpanded()` returns the current state of the BListItem.

`SetExpanded()` doesn't affect the on-screen display. If the item is in a BOutlineListView in a window, it's better to call that view's `Collapse()` and `Expand()` functions so that the changes can take effect immediately.

See also: `BOutlineListView::Collapse()`

### SetHeight(), SetWidth(), Height(), Width()

          void SetHeight(float height)

          void SetWidth(float width)

          float Height(void) const

          float Width(void) const

These functions set and return the width and height of the item. The item's dimensions are adjusted when `Update()` is called.

See also: `Update()`

### Update()

          virtual void Update(BView *owner, const BFont *font)

Modifies the width of the BListItem to match the width of the owner BView where it will draw and modifies the item's height to fit the height of the BView's current font. This function is called whenever an item is assigned to a BListView (including a BOutlineListVIew) and when the owning object undergoes a change that might affect the item.

Derived classes can augment this function to record the owner BView, cache the font, query the owner about other aspects of the graphics environment, or take any other action that's required to keep the item up to date.

### Width() see SetHeight()

## Archived Fields

The `Archive()` function adds the following fields to its BMessage argument:

Field | Type code | Meaning
"_sel" | `B_BOOL_TYPE` | `true` if the item is selectable.
"_disable" | `B_BOOL_TYPE` | `true` if the item is disabled.
"_li_expanded" | `B_BOOL_TYPE` | `true` if the item is expanded.
"_li_outline_level" | `B_INT32_TYPE` | The outline level of the item.

Some of these fields may not be present if the setting they represent isn't used, or is the default value. For example, if the item is not selectable, the "_sel" field won't be found in the archive.

The Be Book, in lovely HTML, for BeOS Release 3.

Copyright © 1998 Be, Inc. All rights reserved.

Last modified March 26, 1998.