Calligra/Libs/Interactional Tools
Tools Framework
Requirements
- All the tools should support common gestures to change their parameters. E.g. Shift+Drag. We can add different types of drags, like Shift+Vertical Drag and Shift+Horizontal Drag, the type of drag may be recognized automatically.
- On some modifiers, like Ctrl and Space, the current tool shoud be switched to another one temporarily, like to Color Picker Tool and Pan Tool.
- Temporary switch of the painting tools by holding a key, pressing the key to switch it permanently.
- Canvas rotation should be accessible from all the tools.
- The tool's stroke and decorations should be cancelled on pressing Esc.
- Mouse Wheel should do Pan/Zoom in all the tools.
- Shortcuts should be integrated with KAction system and be configurable with common dialog.
Description
Motivation
We need two kinds of modifiers (shortcuts) for our tools system:
- External: global modifiers, those switch current tool temporarily. E.g. Pan Tool, Zoom Tool, Canvas Rotation.
- Internal: modifiers those change mode of the current tool. E.g. Shift+Drag gesture, Color Picker, other brush modification shortcuts.
The biggest problem we have there is that two levels of the modifiers implementations must know the state of the underlying implementation. That is, you cannot start a canvas panning while a freehand tool is painting on the canvas. That is why some complex system is needed.
Design
The entire system will be based on the current implementation of KoInteractionTool/KoInteractionStrategy. So, ideally, all the tools will have to ported to KoInteractionStrategy. But for not doing this huge amount of (quite inefficient) work at once, the system provides special wrappers for KoToolBase those encapsule it into a strategy.
The main class here is KoInteractionStrategyFactory. It associates a particular strategy with the key stroke. It recieves notifications from KoModifiersManager when the keys are pressed/released so it can store any key as a modifier. When the manager calls tryCreateStrategy() it checks whether all the preconditions satisfied and creates the strategy if needed.
The purpose of the manager is to filter all the mouse/key events those come to the KoManagedInteractionTool and pass them to the factories in a special order. When a key event comes it first notifies *all* the factories about this event. Then it starts iterating through the factories, checks whether current strategy (if there is one) can be superseded by any of created ones and if so calls tryCreateStrategy(). You can see this process on a sequence diagram below.
This approach solves two great problems:
- we needn't do our own key-sequence check in every tool: there is a special class KoInteractionStrategyFactory that encapsulates these checks
- thanks to currentStrategy() and canBeSupersededBy() calls we are able to do interlevel communications and know the state of the underlying tool.
Implementation of two levels of shortcuts is shown on a diagram below. The wrappers (KoInteractionToolStrategyWrapper and KoToolBaseStrategyWrapper) create a common interface for the KoModifiersManager, so it can send the event further to the tools.