Assistant to the ToolAssistant

By Brien B.

iModel.js
iTwin.js
6 min readApr 22, 2020

--

If you have written an interactive tool for imodeljs, plan to write a tool in the future, or just use these tools, tool assistance is something to be aware of. The focus of this post is to outline some guidelines for interactive tool authors to follow to hopefully encourage some sort of consistency. The purpose is not to document the ToolAssistance api.

What is tool assistance?

You can think of tool assistance as “tool prompt 2.0”. The full tool assistance for the current state of the active tool can be accessed by clicking (or tapping) on the “prompt” field at the left side of the status bar. This dialog can be pinned open when learning a new tool and for more convenient testing.

When discussing tool assistance the sections from the following diagram will be referenced.

  1. Tool name. This is the what appears as both the tool settings title and tool assistance dialog title. It comes from the tool’s “flyover” text.
  1. Input source. Mouse and touch input are put on separate tabs. A future enhancement may be to only show the tab(s) that are appropriate.
  2. Main instruction. This is the traditional prompt field. It’s what appears in the status bar, and optionally at the cursor.
  3. Inputs. This section details what buttons, keys, and touch events are applicable to the current tool state.
  4. Option to show the main instruction at the cursor (off by default). * Currently has an open issue for playing nice with tooltip.
  • There has been some discussion of allowing a documentation link to be included as well…

Why tool assistance?

The purpose of tool assistance is communicating not easily discovered tool features without un-wieldy or lengthy prompts.

Example of traditional prompts for a tool that supports Ctrl+left click to define additional shape points beyond the required 3 points.

As you can see above, the prompt for ThirdPoint is getting long, it also doesn’t make sense for a touch screen user.

Fun fact: Did you know that the Select Elements tool supports right-drag for crossing line selection?

Is tool assistance required?

By default, the traditional tool prompt will appear as the “main instruction” if you do nothing, but it’s still recommended that you use the ToolAssistance api so that the tool icon can be specified for the main instruction.

Replace:

at a minimum with:

Applications such as Design Review will also start to require “good” tool assistance, so just including a main instruction may not suffice depending on the specific tool.

InteractiveTool responsibility

Just as with tool prompts, a sub-class of InteractiveTool is responsible for updating it’s tool assistance when:

  • It first installs — onPostInstall
  • It changes internal tool state — onDataButtonDown, onResetButtonUp, onTouchTap, etc.
  • It is unsuspended — onUnsuspend (note: NA for a ViewTool, these can’t be suspended)

I like to follow the following pattern in the tools I write:

Tool name and main instruction

The tool name should be sufficient to inform the user that the tool does, Select Elements, Measure Volume, etc. There is no reason to repeat this information in either the main instruction or inputs.

The main instruction (tool prompt) is king. The user might never open tool assistance, but they will still see the main instruction prompt on the status bar and optionally at the cursor. The main instruction needs to convey what the tool is expecting in order to advance the tool state without mention of any specific input. The main instruction is often tool specific; if I am placing a circle, I should know that the 1st point will define the circle center before I click and that the 2nd point is defining the radius, etc.

  • Main instruction is shared by both Mouse and Touch inputs, it should never refer to either, i.e. no mention of Click, Tap, or keyboard keys…
  • Some generic prompt descriptions are available in CoreTools.json. For historical reasons they are under “ElementSet”.

Inputs — A picture is worth a thousand words

Don’t include a description of the icon in the input text.

Don’t waste horizontal space (and for languages like German, vertical space due to more frequent text wrapping!). Also means that input text can often be shared by both mouse and touch.

The prompt describes what the user needs to do, the inputs describe what happens. So, clicking the left button isn’t identifying anything, you already did that by moving the mouse over something; it’s just accepting the thing you’ve identified.

  • Some generic input descriptions are available in CoreTools.json. Unless the input does something that isn’t obvious from the main instruction keep it short and sweet.

Click + Click vs. Press, drag, then release (or Click + Drag)

A common behavior for many tools that only require 2 points is to support both click + click and click + drag operation. If click + click and click + drag accomplish exactly the same thing, it’s not necessary to include both inputs as this is considered common, expected, and discoverable behavior. Only explicitly include drag input if the behavior is different from click + click.

Touch and Mouse

Mouse and Touch inputs are kept separate to keep the vertical space required for the tool assistance dialog to a minimum. It’s also unlikely that the user will need to see both at the same time. The approach I’ve taken is to create instruction arrays for mouse and touch up front, then add the mouse instruction and corresponding touch instruction (if available) together.

Touch and AccuSnap

Applications that support touch screens and have tools that enable AccuSnap need to be aware of the “touch cursor” and how it affects tool operation.

  • Default for single finger tap is onDataButtonDown/onDataButtonUp
  • Default for two finger tap is onResetButtonDown/onResetButtonUp

When a tool enables AccuSnap, the first tap event is consumed and used to display a touch scren cursor. The touch cursor provides motion events and allows for accurate snapping by an offset point that is not obscured by a finger.

Once the touch cursor is on screen, the user can drag it around to identify a point, and tap on it to accept the current point. Tapping off the touch cursor just moves it to that location and does not send data button events to the tool. Special tool assistance instructions are included to communicate the required interaction with the touch cursor.

It’s also possible to cancel or reset an operation using the touch curosr by just doing a two finger tap anywhere on the screen when the touch cursor is displayed (sends reset button events to the tool).

To make it easier to implement the tool assistance shown above for the touch cursor a method has been provided that is used as follows:

If ToolAssistance.createTouchCursorInstructions returns false, it can mean:

  • Tool hasn’t enable AccuSnap yet
  • User has disabled AccuSnap
  • Touch cursor is already on screen

What isn’t the tool’s reponsibility

  • Un-handled events passed along to IdleTool: Middle button and touch events for viewing operations.
  • keyboard shortcuts: Ctrl+Z, Ctrl+Y, etc.
  • This information should be made available elsewhere, it can not be required of every tool to include/repeat this information, that would be un-wieldy. Focus on the inputs your tool directly responds to.

Examples?

MeasureTool.ts in the frontend package is a decent example of not too complicated tool assistance. It convers tools that want point input (and support the touch cursor) as well as tools that identify elements. I do not recommend looking at SelectTool.ts, it’s inputs are overloaded and atypical.

Tool2.ts in test-apps\ui-test-app also has some good examples for creating the various types of instructions.

--

--