Working with Galleries

The ribbons that are used by many Microsoft Office applications use galleries for easier visual selection of items. The WordPad application (and thus the TextPad sample application) contains a single gallery for selecting a paragraph list style:

List Gallery

TUICommandCollection

Galleries are represented by a TUICommandCollection object (as are Combo Boxes and the Quick Access Toolbar). This class has the following additional properties:

  • Categories: the items in a gallery can be organized into categories. If you want to use categories, then you need to populate this collection with objects of type TUIGalleryCollectionItem (or derived). You need to set these properties for each category:
    • LabelText: the caption of the category.
    • CategoryId: a numeric identifier for the category. Items with this CategoryId will be
      placed in this category.
  • Items: a collection of the items in the gallery. Again, each item should be an object of type TUIGalleryCollectionItem (or derived), and has the following properties:
    • LabelText: the caption of the item (if captions are shown) or the tooltip that is displayed when the user hovers the mouse over the item.
    • CategoryId: the ID of the category into which to place this item, or -1 (default) if no categories are used or if the item does not belong in a category.
    • Image: the image to use for the item (or nil if no image is used).
    • Command: if the gallery is authored to contain commands (instead of items), you need to create a TUICommand object and assign it to this property.
  • SelectedItem: the index of the currently selected item. For Split Button Galleries, the index will be -1 if the button (top) part of the split button was clicked. For Combo Boxes, the index will be -1 if no item is selected, or text is entered in the Combo Box.
  • Text (only used for Combo Boxes): the text entered into the Combo Box.
  • RepresentativeString (only used for Combo Boxes): this string is used by the Ribbon Framework to query the
    width of the Combo Box. Set this to the longest string you forecast. The string is never displayed, so it could contain any characters you want. It is just used to calculate the width of the control: the longer the
    string, the wider the control.
  • Checked (only for Split-Button Galleries): whether the button is checked or not.

There is a single OnSelect event that is fired when the user selects an item in the gallery.

Gallery Resources

The WordPad template (and TextPad sample) comes with images for the gallery items. You will find these in the "Ribbon\Res\Galleries" subdirectory. WordPad is High-DPI aware, so it provided multiple versions of each image:

ListNumbered_096.bmp ListNumbered_120.bmp ListNumbered_144.bmp
ListNumbered_096.bmp      ListNumbered_120.bmp      ListNumbered_144.bmp

The "_096" version will be used for standard resolutions (up to 96 dpi). The "_120" version will be used for 97-120 dpi displays. And the "_144" version will be used when the display resolution is set to more than 120 dpi.

You will need to create a resource file for these images. The TextPad sample uses the following resource script file (Galleries.rc):

Galleries.rc Resource Script
LIST_NONE_096 BITMAP "Ribbon\\Res\\Galleries\\ListNone_096.bmp"
LIST_NONE_120 BITMAP "Ribbon\\Res\\Galleries\\ListNone_120.bmp"
LIST_NONE_144 BITMAP "Ribbon\\Res\\Galleries\\ListNone_144.bmp"
LIST_BULLETS_096 BITMAP "Ribbon\\Res\\Galleries\\ListBullets_096.bmp"
LIST_BULLETS_120 BITMAP "Ribbon\\Res\\Galleries\\ListBullets_120.bmp"
LIST_BULLETS_144 BITMAP "Ribbon\\Res\\Galleries\\ListBullets_144.bmp"
LIST_NUMBERED_096 BITMAP "Ribbon\\Res\\Galleries\\ListNumbered_096.bmp"
LIST_NUMBERED_120 BITMAP "Ribbon\\Res\\Galleries\\ListNumbered_120.bmp"
LIST_NUMBERED_144 BITMAP "Ribbon\\Res\\Galleries\\ListNumbered_144.bmp"
LIST_ROMANLOWER_096 BITMAP "Ribbon\\Res\\Galleries\\ListRomanLower_096.bmp"
LIST_ROMANLOWER_120 BITMAP "Ribbon\\Res\\Galleries\\ListRomanLower_120.bmp"
LIST_ROMANLOWER_144 BITMAP "Ribbon\\Res\\Galleries\\ListRomanLower_144.bmp"
LIST_ROMANUPPER_096 BITMAP "Ribbon\\Res\\Galleries\\ListRomanUpper_096.bmp"
LIST_ROMANUPPER_120 BITMAP "Ribbon\\Res\\Galleries\\ListRomanUpper_120.bmp"
LIST_ROMANUPPER_144 BITMAP "Ribbon\\Res\\Galleries\\ListRomanUpper_144.bmp"
LIST_LOWERCASE_096 BITMAP "Ribbon\\Res\\Galleries\\ListLowerCase_096.bmp"
LIST_LOWERCASE_120 BITMAP "Ribbon\\Res\\Galleries\\ListLowerCase_120.bmp"
LIST_LOWERCASE_144 BITMAP "Ribbon\\Res\\Galleries\\ListLowerCase_144.bmp"
LIST_UPPERCASE_096 BITMAP "Ribbon\\Res\\Galleries\\ListUpperCase_096.bmp"
LIST_UPPERCASE_120 BITMAP "Ribbon\\Res\\Galleries\\ListUpperCase_120.bmp"
LIST_UPPERCASE_144 BITMAP "Ribbon\\Res\\Galleries\\ListUpperCase_144.bmp"

You need to add this file to your Delphi project (using "Project | Add To Project..."). However, when you build the Delphi project now, you will get the following error message:

[BRCC32 Error] Galleries.rc(1): Invalid bitmap format

The Resource Compiler that Delphi uses by default can not handle 32-bit Bitmap files. Fortunately, when can let Delphi use the Microsoft Resource Compiler, which does not have any problems with this:

  • Go to "Project | Options...".
  • Select the "Resource Compiler" node.
  • Set "Resource compiler to use" to "Windows SDK Resource Compiler".

Now the project will build without problems.

Populating the Gallery

With the resources linked to the project, we can populate the List Style Gallery resource like this:

Populating the List Style Gallery
procedure TFormMain.PopulateListGallery;
const
  RESOURCE_NAMES: array [0..6] of String = ('NONE', 'BULLETS', 'NUMBERED',
    'LOWERCASE', 'UPPERCASE', 'ROMANLOWER', 'ROMANUPPER');
  LABELS: array [0..6] of String = ('None', 'Bullet', 'Numbering',
    'Alphabet - Lower case', 'Alphabet - Upper case',
    'Roman Numeral - Lower case', 'Roman Numeral - Upper case');
var
  I, Dpi: Integer;
  ResourceName: String;
  Item: TUIGalleryCollectionItem;
begin
  Dpi := Screen.PixelsPerInch;
  if (Dpi> 120) then
    Dpi := 144
  else if (Dpi > 96) then
    Dpi := 120
  else
    Dpi := 96;

  for I := 0 to 6 do
  begin
    ResourceName := Format('LIST_%s_%.3d', [RESOURCE_NAMES[I], Dpi]);
    Item := TUIGalleryCollectionItem.Create;
    Item.LabelText := LABELS[I];
    Item.Image := TUIImage.Create(HInstance, ResourceName);
    FCmdList.Items.Add(Item);
  end;
end;

We use Screen.PixelsPerInch to query the display resolution. We will use this to select the correct version of the image resource to load (for example "LIST_BULLETS_120" when the resolution is between 96 and 120 dpi).

As you can see, we create a TUIGalleryCollectionItem object for each item. We set its Image property by creating a TUIImage object using the application instance and the resource name. Note that the Image property is of type IUIImage (which is implemented by TUIImage). So you don't need to take care of destroying the image.

Also, as soon as you add the item to the Items collection, the collection becomes owner of the item. So you shouldn't free the items yourself.

Good Luck!

This concludes the tutorial. Check out the TextPad sample application if you need some more implementation details. It is not a complete WordPad clone but it will provide some insights into how the Ribbon is used.

Now, start creating your own Ribbon applications. Good luck!