Badges for descriptive phrases

Badges

We want to generalize the icons shown next to descriptive phrases in various views so that plugins can customize both displays and controls based on context.

The first part of that work has now been merged to master. It is described in the sections below.

Badge and BadgeSet classes

The original DescriptivePhrase and PhraseContent classes exposed a fixed set of information with each phrase: object visibility and object color. The qtDescriptivePhraseDelegate would ask for this information via QModelIndex::data() and add a third piece of information: a per-object-class icon to show each object’s type. One of the difficulties with this approach was that the PhraseContent class used a decorator pattern to override the visibility icon (originally, visibility was a property held on a model entity and the same across all views; now it is a per-view setting and not stored on SMTK components at all). Because each phrase had a decorator, extra memory was used and maintaining the phrases was trickier than it should have been.

Our first merge does not remove this, but adds a Badge class that functions differently. A single instance of each Badge is held by the PhraseModel in a BadgeSet. The qtDescriptivePhraseDelegate asks for an ordered vector of badges that applie to a give QModelIndex; they are returned by pointer. This means that individual phrases do not store badge information (a big space and complexity savings).

Badges provide:

  • a method to test whether they apply to a descriptive phrase or not
  • a string holding an SVG icon to represent the badge (which may vary based on the content of the DescriptivePhrase)
  • a tooltop string describing the badge to the user
  • an action() method that user interfaces may invoke when users click on the badge.

A BadgeSet holds Badges in the order they should appear when rendering DescriptivePhrases. It is owned by the PhraseModel.

View Configuration

The second change we have made is to refactor PhraseModel a little bit to make configuration of badges (and other settings) easier. Before, view::Manager had a lot of methods to register, unregister, and create an uninitialized PhraseModel object. Now, view::Manager owns a PhraseModelFactory (which uses a new, generic Factory template) that exposes all those methods. It also forwards arguments to the PhraseModel constructor and all existing PhraseModel subclasses in SMTK now take a pointer to a view::Configuration and a view::Manager. Those constructors not only configure the PhraseModel object, they also get passed on to the BadgeSet and SubphraseGenerator classes owned by the PhraseModel.

Up Next

Our next merge will use the work above to take over rendering of all icons in descriptive phrases and handling user interaction. We have the rendering code working and are implementing badges that perform the functions currently handled by fixed functions in DescriptivePhrase and PhraseContent. We will also be removing the dead code from PhraseContent and DescriptivePhrase.

The rest of the work on Badges has been committed. The work done is described in the sections below.

Cleanup

Descriptive phrases (and particularly PhraseContent) no longer use the Decorator pattern from the Gang-of-Four book. A lot of methods in PhraseContent and DescriptivePhrase have disappeared as they are replaced by badges.

Badge rendering

The qtDescriptivePhraseDelegate now draws whatever badges apply to each phrase as needed. There are no fixed roles for things like visibiltiy or color.

New Badge Types

The following badges have been added and can serve as examples for implementing your own. Note that VisibilityBadge and MembershipBadge have some remnants from their previous life as parts of other classes, so don’t use these blindly as patterns you must follow.

Screen Shot 2020-05-20 at 01.58.38

Figure 1. On the left is the VisibilityBadge. To the right is a TypeAndColorBadge.

VisibilityBadge

This is a ParaView-specific badge that tracks the visibility of each persistent object in each representation of the active view. When the object is visible in the view (by having its block visibility set), the badge is an “open eye” icon. Otherwise the badge is a “closed eye.” Clicking on the badge will toggle the block visibility and thus the icon.

TypeAndColorBadge

This is a subclass of smtk::view::ObjectIconBadge that adds an action; clicking on the icon will pop up a Qt color-selector dialog so you can recolor the related persistent object.

MembershipBadge

This badge is used by the qtReferenceItem class to show which of the available objects in a list have been selected for membership in the smtk::attribute::ReferenceItem (or its subclasses).

Screen Shot 2020-05-20 at 02.00.07

Figure 2. The MembershipBadge in use by a qtReferenceItem.

Hi all, this merge request has made its way into SMTK. It adds actions to badges, which involves a change to the Badge API.

Badge actions

The new BadgeAction base class provides a way for user interface components to pass more information to badges. In short, the old API for Badge was

class Badge
{
public:
  virtual void action(const DescriptivePhrase*) const;
};

but is is now

class BadgeAction
{
public:
  // This method _may_ be implemented by subclasses to provide
  // context for the action (such as currently-selected phrases).
  // Subclasses may also pass other information, requiring a dynamic_cast
  // of the action to retrieve it.
  virtual void visitRelatedPhrases(std::function<bool(const DescriptivePhrase*)>)
  { /* do nothing by default */ }
};

class Badge
{
public:
  // Now badges take an action in and return true (if they can
  // take the action) or false (if they are unable to take the action).
  //
  // UI components should *always* pass a DescriptivePhrase in
  // to the action() method, even if the action will iterate over it...
  // the DescriptivePhrase passed to the action is considered the
  // _primary_ phrase (e.g., the phrase where the badge was clicked
  // or the cursor was resting at the time of a keypress/interaction).
  virtual bool action(const DescriptivePhrase*, const BadgeAction&);
};

The BadgeAction object serves as a base class for user-interface-specific functions. SMTK provides one: BadgeActionToggle, which is invoked when users click on a badge icon or press the space bar while the resource browser widget has focus. Qt widgets provide a subclass that implements the visitRelatedPhrases() method to iterate over all the currently-selected descriptive phrases. This allows the VisibilityBadge and MembershipBadge to toggle many items at once, rather than forcing users to click on each object’s visibility or membership icon.

In the future, other subclasses of BadgeAction are possible. It is up to each Badge implementation to dynamically cast the action into the types of action objects it can use. If an action is passed that a badge doesn’t understand, it should return false. If the badge consumes the action, then it should return true.