.. meta:: :description: Plugin descriptors states temporary action handleTriggered handleChanged OrsPlugin ========= These services support the usage of plugins and contexts. Classes ------- AbstractPlugin ^^^^^^^^^^^^^^ .. automodule:: ORSServiceClass.OrsPlugin.abstractPlugin .. autoclass:: AbstractPlugin :members: OrsPlugin ^^^^^^^^^ .. automodule:: ORSServiceClass.OrsPlugin.orsPlugin .. autoclass:: OrsPlugin :show-inheritance: :members: StateDescriptor ^^^^^^^^^^^^^^^ .. automodule:: ORSServiceClass.OrsPlugin.statedescriptor .. autoclass:: StateDescriptor :members: UIDescriptor ^^^^^^^^^^^^ .. automodule:: ORSServiceClass.OrsPlugin.uidescriptor .. autoclass:: UIDescriptor :members: OrsAbstractFilterPlugin ^^^^^^^^^^^^^^^^^^^^^^^ .. automodule:: ORSServiceClass.OrsPlugin.orsabstractfilterplugin .. autoclass:: OrsAbstractFilterPlugin :members: .. _OrsPlugin_States: States ------ A *state* is a name representing a preferred group of actions to be performed when using keyboard keys, mouse buttons or a combination of these. Generally, this is used to specify the current tool. By doing so, the same keys or mouse combinations can be reused to perform different tasks. For example, the left-button mouse click can be used to perform a *Pan*, a *Zoom*, to start a ruler or to paint a ROI with a circular brush; the task performed depends on the selected tool, which is the specified state. .. note:: the word *handle* is sometimes used as a synonym for *state*. To change the state of the application, call :meth:`OrsLibraries.workingcontext.WorkingContext.setCurrentGlobalState`, as in:: WorkingContext.setCurrentGlobalState(aPluginInstance, theNewState) where ``aPluginInstance`` is a plugin instance (usually, ``self``, when this call is made in a method of the plugin implementation class), and ``theNewState`` is the string of the state to set. To get the state of the application, call :meth:`OrsLibraries.workingcontext.WorkingContext.getCurrentGlobalState`. **Specification of the cursor** A cursor icon might be specified for each defined state. This icon is set for the mouse pointer when it comes over a view. Also, the picking location on that icon can be specified with the *hotspot* specification (in *X* and *Y*). :: stateDemoCursorStateCornerTopLeft = 'stateDemoCursorStateCornerTopLeft' # The folder cursoricons contains the cursor icon file cursorPointerCornerTopLeft.png. # The folder cursoricons is contained in the same directory as the plugin implementation file. stateDescriptors = [StateDescriptor(state=stateDemoCursorStateCornerTopLeft, stateActivation='', title='DemoCursorState: CornerTopLeft', cursor=':/cursoricons/cursorPointerCornerTopLeft.png', cursorHotSpotX=0, # First pixel on the left cursorHotSpotY=0)] # First pixel on top .. _sourcecodeexample_plugin_DemoCursorState_5c5a3f069efc11e796c3448a5b5d70c0: Source code example: #. Download the :download:`compressed file `; #. Extract these files into a :ref:`plugin extension folder `; #. Start the application; #. Go to the preferences to define a key for the actions named *Pick for DemoCursorState at CornerTopLeft*, *Pick for DemoCursorState at Middle* and *Pick for DemoCursorState at CornerBottomRight*; #. Open the top level menu *Demos* to see the menu item named *Demo: open the plugin DemoCursorState*. Click on that menu item to create an instance of the plugin and open his mainform. At the same time, a ROI is created with a painting of a cross and his borders; #. Press the button *CornerTopLeft* on the plugin UI to put the state of the application in *stateDemoCursorStateCornerTopLeft*. Note, in the status bar, that the name of the current state is changed for *DemoCursorState: CornerTopLeft*. Also, the cursor is changed to show that the picking is on the top left of the mouse pointer. Press and hold the key defined earlier to start the action of *Pick for DemoCursorState at CornerTopLeft*. The light is turned green when the ROI at the pick (hotspot) location has painting, but is turned red when the ROI has no painting at that location. While holding the key, move the mouse pointer over the ROI to see the light turn from green to red, depending on the location of the pointer. The light is turned black when the key is released or if the cursor is not in the borders of the ROI; #. Do the same using the buttons *Middle* and *CornerBottomRight* to use cursors having different picking locations. **Method handleChanged** In a plugin, the method :meth:`ORSServiceClass.OrsPlugin.orsPlugin.OrsPlugin.handleChanged` is called when the state of the application is changed. This is generally used to update the UI of the plugin. .. _sourcecodeexample_plugin_DemoHandleChangedState_129e978a9fb811e78427448a5b5d70c0: Source code example: #. Download the :download:`compressed file `; #. Extract these files into a :ref:`plugin extension folder `; #. Start the application; #. Open the Preferences and look in the *Configurable Actions* section for the name *Set state A of DemoHandleChangedState*. Set an unused keyboard key for that action. Set a **different** keyboard key for the action with the name *Set state B of DemoHandleChangedState*. Apply the changes and exit the Preferences; #. Open the top level menu *Demos* to see the menu item named *Demo: open the plugin DemoHandleChangedState*. Click on that menu item to create an instance of the plugin and open his mainform. Do this again to create another instance of the plugin with his UI. Move these UIs so that both windows can be seen simultaneously; #. Press the specified action key of the action *Set state A of DemoHandleChangedState* to set this state. Note, in the status bar, that the name of the current state is changed for *DemoHandleChangedState: A*. Also, the tool button *A* is now pressed in both UIs; #. Do the same with the action key of the action *Set state B of DemoHandleChangedState*. Note that the status bar has been updated, the tool button *A* is reset and the tool button *B* is pressed; #. Switch these states using the buttons on the UI of the plugin to see the same effect. .. _OrsPlugin_States_handleTriggered: **Method handleTriggered** In a plugin, the method :meth:`ORSServiceClass.OrsPlugin.orsPlugin.OrsPlugin.handleTriggered` is called on every user input (mouse move, mouse click, key press, ...) when the current state of the application is one of those declared by the plugin. This method can be used to perform specific tasks even if no action is currently in progress. Information about the triggering event (an instance of :class:`OrsEvent.eventdata.InputEventData`) is sent in argument. This event data contains information such as the stage of execution of an action (enter, stay or exit). .. note:: If there are multiple plugins declaring the same state name, they all receive the call to ``handleTriggered``. However, this is not a common situation. .. _OrsPlugin_States_handleTriggered_actionExecutionProcedure: When an action is to be executed, the following procedure is done in order: - execution of the ``enterAction`` string of the action, then call to ``handleTriggered``. This is done once; - execution of the ``action`` string of the action, then call to ``handleTriggered``. This is done repetitively (see :func:`ORSServiceClass.decorators.infrastructure.action`); - call to ``handleTriggered``, then execution of the ``exitAction`` string of the action. This is done once. .. _sourcecodeexample_plugin_DemoHandleTriggeredState_118ffffe9fcf11e7aeee448a5b5d70c0: Source code example: #. Download the :download:`compressed file `; #. Extract these files into a :ref:`plugin extension folder `; #. Start the application; #. Go to the Preferences to define a key for the actions named *Increment counter in DemoHandleTriggeredState* and *Neutral in DemoHandleTriggeredState*. Apply the changes and exit the Preferences; #. Open the top level menu *Demos* to see the menu item named *Demo: open the plugin DemoHandleTriggeredState*. Click on that menu item to create an instance of the plugin and open his mainform. At the same time, a ROI is created with a painting of a cross and his borders; #. Because the state of the application is not yet in one defined by the plugin, the method ``handleTriggered`` is not called. The light is set as black and will remain as such even if the mouse pointer goes over the ROI; #. Press the button *A* on the UI of the plugin to set the state *DemoHandleTriggeredState: A*. The method ``handleTriggered`` is now being called at each user input, including the mouse move. Move the mouse pointer over the ROI to see the light turn from green to red, depending on the location of the pointer. The light is turned black when the cursor is not in the borders of the ROI; #. Press the specified action key of the action *Increment counter in DemoHandleTriggeredState* to start this action. This action evaluates the elapsed time between the moment it is started until it is finished. This time is shown on the UI when the action is completed. Also, a counter is incremented by 1 each time a trigger is received; #. Press the button *B* on the UI of the plugin to set the state *DemoHandleTriggeredState: B*; #. Press the specified action key of the action *Neutral in DemoHandleTriggeredState* to start this action. This action does nothing per itself, but the method ``handleTriggered`` is still reactive to the mouse pointer location over the ROI. **Temporary actions** Actions can be used to switch to a state temporarily (as long as the associated action key is pressed) and then return to the state that was the current one before the action was started. Note that this action continues to be executed until the ``exitAction`` even if that action is state-dependent and the state was changed during the ``enterAction``. While in the temporary state, other actions dependent on that temporary state can be executed. .. _sourcecodeexample_plugin_DemoTemporaryActionState_2fcb02f8a21311e79b16448a5b5d70c0: Source code example: #. Download the :download:`compressed file `; #. Extract these files into a :ref:`plugin extension folder `; #. Start the application; #. Go to the Preferences to define an unused **keyboard** key for the action *Set temporary state A of DemoTemporaryActionState*. For the action *Pick in temporary state A of DemoTemporaryActionState*, set the **same keyboard key combined with the mouse left-button**. For the action *Pick in state A of DemoTemporaryActionState*, set any key (this can be the mouse left-button). Apply the changes and exit the Preferences; #. Open the top level menu *Demos* to see the menu item named *Demo: open the plugin DemoTemporaryActionState*. Click on that menu item to create an instance of the plugin and open his mainform; #. Press the button *A* on the UI of the plugin to set the state *DemoTemporaryActionState: A*. Press the specified action key of the action *Pick in state A of DemoTemporaryActionState* to write the current cursor location in the picking information; #. Press the button *Set state Track* to set the application state as *Track*, or use any other tool button to change the state of the application. Note that the current cursor position is not updated anymore; #. Press and hold the specified action key of the action *Set temporary state A of DemoTemporaryActionState* to start this action. Note, in the status bar, that the name of the current state is changed for *DemoTemporaryActionState: A*. Also, the cursor is changed accordingly to that state definition, the button *A* in the UI of the plugin is also pressed, and the current cursor position is refreshing when the mouse pointer moves; #. Click in the main view with the left-button mouse to pick new locations and update the UI; #. Release the action key of the action *Set temporary state A of DemoTemporaryActionState* to end the temporary state switch. Note that the state is changed to the one prior to starting this temporary state switch, as shown in the status bar. **Temporary actions: switching to a state declared by another plugin** During the :ref:`execution procedure of an action `, the methods ``handleTriggered`` called are those of the plugins declaring the current state of the application *at the moment the call should be made*. .. _sourcecodeexample_plugin_DemoTemporaryActionExternalState_c2ce1878b4f911e79ff1448a5b5d70c0: Source code example: #. Download the :download:`compressed file `; #. Extract these files into a :ref:`plugin extension folder `. Note that there is 2 distinct plugins contained in the compressed file; #. Start the application; #. Go to the Preferences to define the mouse left-button for the action named *Set temporary state B of DemoTemporaryActionExternalState*. Apply the changes and exit the Preferences; #. Open the top level menu *Demos* to see the menu item named *Demo: open the plugin DemoTemporaryActionExternalState A*. Click on that menu item to create an instance of the plugin *A* and open his mainform; #. Open the top level menu *Demos* to see the menu item named *Demo: open the plugin DemoTemporaryActionExternalState B*. Click on that menu item to create an instance of the plugin *B* and open his mainform. Move that window so that both UIs can be seen simultaneously; #. Press the button *A* on the UI of the plugin *A* to set the state *DemoTemporaryActionExternalState: A*; #. Move the mouse cursor in the view. The counter of calls to ``handleTriggered`` of the plugin *A* increases on each mouse move event; #. Bring the mouse cursor on the view and press and hold the mouse left-button to start the state switch action. Do this while making sure the mouse cursor doesn't move. Note, in the status bar, that the name of the current state is changed for *DemoTemporaryActionExternalState: B*. Note also that the counter of calls to ``handleTriggered`` of the plugin *A* is reset to 0, while the counter of calls to ``handleTriggered`` of the plugin *B* increased and is showing the action stage *EnterAction*; #. Move the mouse cursor to see the counter of triggers of the action *Set temporary state B of DemoTemporaryActionExternalState* increase, due to the execution of the string of the ``Action`` stage. At the same time, the counter of calls to ``handleTriggered`` of the plugin *B* is increased and is showing the action stage *Action*; #. Release the mouse left-button to end the temporary state switch. The counter of calls to ``handleTriggered`` of the plugin *B* is increased one last time and is showing the action stage *ExitAction*. **Event consumption** The mechanism of actions (see :func:`ORSServiceClass.decorators.infrastructure.action`) rely on the principle that a state-dependent action will be taken in priority over a state-independent (*fallback*) action having the same key or mouse button. In the situation where a key or mouse button is defined only for a state-independent action, that fallback action is always executed when that key or mouse button is pressed. In the other situation where a state-dependent action is also assigned to that same key or mouse button and the application is in that state, the default behavior is to execute the state-dependent action and do nothing with the fallback action. However, the method ``handleTriggered`` of the plugin called during the *enterAction* stage of the state-dependent action can allow the fallback action to be executed by specifying that this event is **not** consumed (:meth:`OrsLibraries.workingcontext.WorkingContext.setEventConsumed`):: def handleTriggered(self, eventData): # Starting an action with any highlighted object will give them priority highlighted = WorkingContext.getCurrentEntity(self, OrsHighlightedObject) if len(highlighted) > 0 and eventData.isEnterAction(): WorkingContext.setEventConsumed(self, False) return # Continue with the processing of the event It is therefore possible, for example, to move an annotation while the current state is for painting ROIs if the action is started when the cursor is placed over that annotation. **StateActivation** The field *stateActivation*, defined for each *StateDescriptor*, is to be used with :ref:`mouse handlers `. Interface Method Argument Descriptors ------------------------------------- .. toctree:: :maxdepth: 2 InterfaceMethodArgumentDescriptors/sphinxIndexInterfaceMethodArgumentDescriptors