ENH: Allow for custom presets prefix and tooltips#1052
ENH: Allow for custom presets prefix and tooltips#1052johan-andruejol wants to merge 1 commit intoSlicer:masterfrom
Conversation
Although Slicer allowed to create custom presets for the Slice views, it did not allow the user to customize the tooltip nor the prefix that would show in the view. It is now possible to customize each of the slice views preset to have a custom prefix and/or tooltip.
| vtkErrorMacro("GetSliceOrientationPreset: invalid orientation preset name: " << name); | ||
| return NULL; | ||
| OrientationPresetType* preset = this->GetOrientationPreset(name); | ||
| return preset ? preset->Orientation : nullptr; |
There was a problem hiding this comment.
nullptr -> NULL, since we will most likely create 4.10.1 ... let's continue support c++98
| vtkErrorMacro("GetOrientationPreset: The orientation preset " | ||
| "'" << name << "' does NOT exist."); | ||
| } | ||
| return nullptr; |
| } | ||
|
|
||
| //---------------------------------------------------------------------------- | ||
| OrientationPresetType* vtkMRMLSliceNode::GetOrientationPreset(const std::string &name, bool error) |
There was a problem hiding this comment.
Instead, what do you think of displaying the error on the user side ?
There was a problem hiding this comment.
This is a protected method. It only has this option so you can query the preset existence in HasSliceOrientationPreset without an error.
|
|
||
| //---------------------------------------------------------------------------- | ||
| bool vtkMRMLSliceNode::HasSliceOrientationPreset(const std::string &name) | ||
| bool vtkMRMLSliceNode::RenameSliceOrientationPresetPrefix(const std::string &name, const std::string &prefix) |
There was a problem hiding this comment.
What about RenameSliceOrientationPresetPrefix -> SetSliceOrientationPresetPrefix ?
| std::vector< OrientationPresetType >::iterator it; | ||
| for (it = this->OrientationMatrices.begin(); it != this->OrientationMatrices.end(); ++it) | ||
| //---------------------------------------------------------------------------- | ||
| bool vtkMRMLSliceNode::RenameSliceOrientationPresetTooltip(const std::string &name, const std::string &tip) |
There was a problem hiding this comment.
RenameSliceOrientationPresetTooltip -> SetSliceOrientationPresetTooltip
| class vtkMatrix4x4; | ||
|
|
||
| /// \brief Structure to store preset orientation information. | ||
| struct OrientationPresetType |
There was a problem hiding this comment.
struct VTK_MRML_EXPORT OrientationPresetType
There was a problem hiding this comment.
Instead, I suggest to move the struct into the vtkMRMLSliceNode class, that way it will be available from python.
| /// \sa AddSliceOrientationPreset( | ||
| /// const std::string& name, vtkMatrix3x3* sliceToRAS, | ||
| /// const std::string& prefix, const std::string& tooltip) | ||
| /// \sa UpdateMatrices() |
There was a problem hiding this comment.
/// \sa GetSliceOrientationPresetPrefix()
/// \sa GetSliceOrientationPresetTooltip()
|
|
||
| /// \brief Return the preset prefix corresponding to a preset \a name. | ||
| /// | ||
| /// Returns an empty string if the preset with the given \a name doesn't exist. |
There was a problem hiding this comment.
\sa SetSliceOrientationPresetPrefix()
\sa SetSliceOrientationPresetTooltip()
| /// \sa RemoveSliceOrientationPreset(const std::string& name) | ||
| bool AddSliceOrientationPreset(const std::string& name, vtkMatrix3x3* orientationMatrix); | ||
| /// \sa RenameSliceOrientationPresetPrefix(const std::string& name, const std::string& prefix) | ||
| /// \sa RenameSliceOrientationPresetTooltip(const std::string& name, const std::string& tip) |
There was a problem hiding this comment.
Since there are no ambiguity on the signature, I suggest to reference the function without arguments ... less chance for it become out of the sync
\sa SetSliceOrientationPresetPrefix()
\sa SetSliceOrientationPresetTooltip()
|
Can you add a note about why (in what use case) you want to use these options? |
|
@pieper: Before this, the only way to modify this would have been to find the qMRMLSliderWidget for each qMRMLSliceControllerWidget and manually change each tooltip and each prefix. This would have to be repeated whenever you change layout as well. |
|
Ah - 👍 thanks! |
lassoan
left a comment
There was a problem hiding this comment.
Thank you, it will be useful to remove hardcoded offset label and slider tooltip. However, there are some concepts to be cleaned up.
Slice node should not store strings that the application must blindly display in very specific places, as we don't know how exactly the application wants to present slice views. Instead, it should store properties that the application can interpret and decide how to display.
For example, instead of storing preformatted prefix ("S: ") and tooltip ("I <-----> S"), we should just store axis labels for positive and negative directions "S" and "I". Then the application may decide to use axis labels to generate prefix and tooltip strings.
Since axis labels are already defined in the base class (vtkMRMLAbstractViewNode, Get/SetAxisLabel), it is not necessary to define labels again. We can determine the axis index from the slice normal direction (3rd column of the orientation matrix). If the normal is aligned exactly with an axis then you can use the corresponding axis labels. If it is not aligned exactly then we can use multiple directions (non-zero components of the slice normal vector; for example: LA <-----> RP; or LAI <-----> RPS) or just not use a label at all.
While we can always compute axis labels, it may be useful to specify custom axis labels for custom orientations. For example, an organ-oriented preset we might want to use "medial<----->lateral" labels instead of some automatically generated labels.
To summarize: I would recommend to replace "prefix" and "tooltip" members by "LabelAxisPositive" and "LabelAxisNegative". Generate prefix and tooltip strings in the GUI widget class. We can decide if we want to compute axis index from direction matrix to look up axis label or we always rely on "LabelAxisPositive" and "LabelAxisNegative" strings.
| /// \brief Structure to store preset orientation information. | ||
| struct OrientationPresetType | ||
| { | ||
| std::string Name; |
There was a problem hiding this comment.
Please add documentation for each member. FOr example, I don't know what "Prefix" is used for, how it is different from "Name" and why it is called prefix (prefix to what?).
| std::string Name; | ||
| vtkSmartPointer<vtkMatrix3x3> Orientation; | ||
| std::string Prefix; | ||
| std::string Tooltip; |
There was a problem hiding this comment.
"tooltip" describes too specifically how this information must be used for. Instead, the variable should be called "description" or something similar and the application could decide how to present it to the user (for example, the application can show it as a tooltip).
There was a problem hiding this comment.
@lassoan What about changing Tooltip into Description ?
There was a problem hiding this comment.
My general comment above essentially supersedes this comment. We should not store preformatted display strings here. Instead, we should just store axis labels (which by the way are optional because we already define axis labels for the 3 main axes in the abstract view node).
For example just store "S" and "I" axis labels and let the GUI widget generate "S: " prefix and "I <-----> S" tooltip.
There was a problem hiding this comment.
Agreed. It makes sense to update qMRMLViewControllerBar to generate reasonable default for Prefix, Tooltip, ...
That said, to support custom value per presets:
- for a custom preset named
Foo, add user setting entry (e.gViewControllerBar/OrientationPresets/Foo/Tooltip,ViewControllerBar/OrientationPresets/Foo/Prefix) - the qMRMLViewControllerBar would be updated to check if settings are set and associated values
Finally, if in a custom application more advanced customization are still needed, making sure the "widgets" of the viewer controller are associated with an objectName allow getting their reference and update them. (for example to hide the pin button, set prefix to empty string, ...)
There was a problem hiding this comment.
to support custom value per presets
Allowing setting custom positive/negative axis labels should be enough customization. Do you have any use case where this would not give good results?
Finally, if in a custom application more advanced customization are still needed, making sure the "widgets" of the viewer controller are associated with an objectName allow getting their reference and update them.
I agree. This would allow fine-grained customization without overcomplicating the API. For common customizations, such as hiding the pin button and adding custom buttons next to the slider, we should also add explicit method calls.
| } | ||
|
|
||
| //---------------------------------------------------------------------------- | ||
| OrientationPresetType* vtkMRMLSliceNode::GetOrientationPreset(const std::string &name, bool error) |
There was a problem hiding this comment.
I would not complicate the API with with this "bool error" flag. Since the caller can detect if a preset is not found (by getting NULL as result), it is not essential to log an error..

Although Slicer allowed to create custom presets for the Slice views, it
did not allow the user to customize the tooltip nor the prefix that would
show in the view.
It is now possible to customize each of the slice views preset to have
a custom prefix and/or tooltip.