Lomse library. API documentation
0.30.0
|
The Interactor is the key object to interact with the document (here the name 'Interactor') and, currently, a lot of functionality is programmed for doing the most common tasks for rendition, edition and scores playback. But managing user interaction with your application GUI is something totally dependent on GUI design, platform API and framework used for building your application. As Lomse knows nothing about your application and about the operating sytem used, Lomse cannot directly handle mouse and keyboard events and manage user interaction with your application GUI. But can help to reduce the necessary coding in your application.
There are certain interaction patterns that are often used in applications. For instance: selecting objects by clicking with the mouse and dragging a selection rectangle on the rendered document; or changing the viewed part of the document by clicking with the mouse and dragging the document. And Lomse provides some support methods for helping your application to manage all these typical interaction patterns and reduce the necessary code in your application.
In Lomse, user interaction patterns are encoded by objects derived from Task base class. Lomse offers some predefined Tasks, such as TaskDragView (for dragging the View with the mouse) or TaskSelection (for selecting objects with the mouse). By using these predefined Task objects your application can be relieved of coding the supported interaction patterns.
All Task derivatives are finite state machines. The events that drive the finite state machine are mouse and keyboard events that are delegated by the Interactor to the Task. Indeed, the Task class consists of little more than a set of pure virtual functions dealing with these events.
The Task responsibility is to decide on the appropriate action for an event or sequence of events. By changing the Task object associated to the View your application can decide how Lomse will behave when receiving mouse events. A Task is associated to a View as a result of invoking method Interactor::switch_task(). Your application must invoke this method as a result of some kind of user action (perhaps a menu choice, a keyboard shortcut, or a click in the appropriate button of a palette or toolbar such as choosing a 'selection tool') that implies the user is starting some interaction protocol.
Once associated to the view, the task will continue to collect events and communicate with the Document class until its lifecycle ends. This may be as a result of completing its job, or because it was somehow cancelled. Then another task will replace it.
So, this is all you have to do:
And, basically, that is all. Lomse will handle the mouse events and will react to them as appropriate, according to the chosen Task rules. Lomse will draw a selection rectangle, change its geometry and select the objects. Or will drag the View, or will drag the selected handler for an object, or will move the object, etc. During this process, your application will receive Lomse events for repainting the window or other, depending on the case.
Example:
See page Tutorials and samples for a full application sample.
As said, all Task derivatives are finite state machines. The events that drive the finite state machine are mouse and keyboard events that are delegated by the Interactor to the Task. Indeed, the Task class consists of little more than a set of pure virtual functions dealing with these events.
To implement the finite state machine representing a task Lomse uses nested switch-case statements. This type of implementation is more compact and it is easy to understand and to follow the finite state machine without relying on state transition diagrams or tables.
The operation of any of the Tasks state machine is quite simple. When the Task is associated to the View, its method ini_task() is invoked and it places the Task in its initial state and kicks everything off. When, finally, it arrives to the 'Done' state, it remains there forever unless the Task is re-started (by invoking init_task() again).
Currently there are several predefined Task derived objects that you can use in your application. More Tasks derived clasess can be created for suporting other interaction patterns, but for now these are the existing ones:
In following subsections the transition tables for these Tasks are documented. In these transition tables:
Purpose: To move (scroll, drag) the view
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForFirstPoint | left_down | WaitingForSecondPoint | start_scroll |
WaitingForSecondPoint | move_mouse | WaitingForSecondPoint | do_scroll |
left_up | WaitingForFirstPoint | end_scroll |
Purpose: Default task when edition mode disabled. User can move mouse, and click on objects (links, buttons, etc.). Left click on one object generates on-click event. Right click does nothing. Move mouse generates mouse-in-out events, but only while no button pressed.
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForFirstPoint | left_down | WaitingForPoint2 | record_first_point |
move_mouse | WaitingForFirstPoint | mouse_in_out | |
WaitingForPoint2 | left_up | WaitingForFirstPoint | click_at_point |
Purpose: Default task when no specific task assigned. This task is oriented to initiate actions related to selecting objects: drawing a section rectangle, displaying a contextual menu, generating on-click events, and initiating a 'move object' action:
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForFirstPoint | left_down | WaitingForPoint2 | record_first_point, decide_on_switching_task |
right_down | WaitingForPoint2 | record_first_point | |
move_mouse | WaitingForFirstPoint | mouse_in_out | |
WaitingForPoint2 | move_mouse | WaitingForPoint2 | none |
left_up | WaitingForFirstPoint | none | |
right_up | WaitingForFirstPoint | select_object_at_first_point, show_contextual_menu |
decide_on_switching_task()
is a decision point for continuing in this Task (doing nothing) or switching to an specific task (TaskSelectionRectangle, TaskMoveObject or TaskSelectText).Purpose: To draw a selection rectangle and select contained objects.
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForPoint2 | move_mouse | WaitingForPoint2 | track_sel_rectangle |
left_up | RequestTaskSwitch | select_objects_or_click, witch_to_default_task | |
RequestTaskSwitch | any | RequestTaskSwitch | switch_to_default_task |
Purpose: To drag an image and, finally, move the object to end point.
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForPoint2 | move_mouse | WaitingForPoint2 | move_drag_image |
left_up | RequestTaskSwitch | move_object_or_click, switch_to_default_task | |
RequestTaskSwitch | any | RequestTaskSwitch | switch_to_default_task |
Purpose: To drag a handler.
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForPoint2 | move_mouse | WaitingForPoint2 | move_handler |
left_up | RequestTaskSwitch | move_handler_end_point, switch_to_default_task | |
RequestTaskSwitch | any | RequestTaskSwitch | switch_to_default_task |
Purpose: To insert new objects by clicking with the mouse. User moves mouse and clicks at insertion point. Object to insert is determined by active tool. Left click generates an insert event. Right click, shows contextual menu. As mouse moves without clicking, it can drag an image representing the object to insert. Also, enter box/exit box events are generated, as mouse flies over the different areas.
State Transition Table:
Current State | Event | Next State | Action |
---|---|---|---|
WaitingForFirstPoint | left_down | WaitingForPoint2Left | record_first_point |
right_down | WaitingForPoint2Right | record_first_point | |
move_mouse | WaitingForFirstPoint | mouse_drag_image | |
WaitingForPoint2Left | left_up | WaitingForFirstPoint | insert_object |
WaitingForPoint2Right | right_up | WaitingForFirstPoint | show_contextual_menu |