EiffelVision accelerators

Revision as of 20:44, 3 April 2006 by Manus (Talk | contribs)

The EiffelVision2 accelerator addition Wiki page.

Overview

This page discusses the initial design of a new shortcut propagation mechanism that may be built into EiffelVision 2. The initial requirement indicated that a widget should be able to handle a shortcut accelerator and execute an action. If a widget does not handle the shortcut, the shortcut key combination will be propagate to the parent contain. This process continues until either a shortcut has been handled or the top-level windows has been reached, in which case there is no parent widget.

Proposal

During a design meeting a number of designed were proffered as designs that could be used at the EV_WIDGET level. However, through a process of elimination and evolution a design was decided upon that is simple, backwards compatible and whose interface is more akin to EiffelVision 2 action sequences used to date. The design of the interface proved important to provide backwards compatibility.

For this proposal to correctly function it is imperative that the widget who recieved focused last be given initial rights to process an accelerator key combination. The widget will then handle any unhandled accelerator key combinations by propagating it to a parent container.

It is proposed that an action sequence, similar to the action sequence for accelerators on EV_APPLICATION, be added to EV_WIDGET or EV_WIDGET_I (interface). Adding to the interface is preferable to prevent code duplication for each supported platform. EV_WIDGET(_I) would also host a feature that is responsible for receiving an accelerator key combination, for the sake of reference it will be called `process_accelerator'. `process_accelerator' will iterate the accelerator action sequence to determine if any item in the sequence matches the accelerator key combination passed to `process_accelerator'. If there is a match then agents on the action sequence item (presumably EV_ACCELERATOR) will be executed.

For propagation, the initial requirement is that any unhandled shortcut be propagated to a widget's parent container. In this case the simple detection of an item in the accelerator action sequence, on the widget, that matches the accelerator key combination passed to `process_accelerator' would suffice. However, users may want to force propagation.

The proposed solution is to extend EV_ACCELERATOR, either by adding to EV_ACCELERATOR or through sub-classing, with a propagate state flag. Again for the sake of reference it will be called `propagate_accelerator'. Clients would simple set `propagate_accelerator' if they wanted to propagate the accelerator to parent widget container.

With the addition of `propagate_accelerator' on the widget's accelerator action sequence, `process_accelerator' could have to check the state flag of any applicable accelerator action sequence item to determine if the accelerator should be propagate. The state flag should be logically OR-ed so that multiple accelerator action sequence items, matching the passed accelerator key combination to `process_accelerator', will propagate the accelerator if one item requests propagation. Failure to find an item in the accelerator action sequence should remain an cause to propagate the accelerator to the widget's parent container.

The Proposed Design

As stated, the design is simple.

 class EV_WIDGET_I
 
   -- class features elided for clarity.
 
 feature -- Agents
 
   accelerator_actions: EV_NOTIFY_ACTION_SEQUENCE
       -- Accelerator actions for `Current' widget
 
 feature {EV_WIDGET} -- Propagation
 
   process_accelerator (a_accl: EV_ACCELERATROR) is
       -- Process actions for accelerator `a_accl'.
     require
       a_accl_attached: a_accl /= Void
     do
       -- Loop through `accelerator_actions'.
       -- If an accelerator matches `a_accl' call action sequence on accelerator.
       -- Query the accelerator item in the `accelerator_actions' for the `propagate_accelerator' state flag
       -- Locigally or `propagate_accelerator' with locally scoped state flag (`should_prop').
 
       -- After loop has completed, examine `should_prop'.
       -- If true or no accelerator was found call parent widget's `process_accelerator'
     end
 
 end -- class EV_WIDGET_I

The proposed design does require a change in EV_ACCELERATOR. It was discussed if EV_ACCELERATOR should be descended and specialized, but instead EV_APPLICATION will receive a new attribute and assigner - `propagate_accelerator' and `propagate_accelerator'

 class EV_ACCELERATOR
 
   -- class features elided for clarity.
 
 feature -- Access
 
   propagate_accelerator: BOOLEAN assign set_propagate_accelerator
       -- Should accelerator be propagated to parent widgets?
 
 feature -- Status Setting
 
   enable_propagation is
       -- Enable accelerator to be propagated to parent containers.
     do
       propagate_accelerator := True
     ensure
       propagate_accelerator_set: propagate_accelerator = True
     end
 
   disable_propagation is
       -- Prevent accelerator to be propagated to parent containers.
     do
       propagate_accelerator := False
     ensure
       propagate_accelerator_set: propagate_accelerator = False
     end
 
 end -- class EV_ACCELERATOR

By the proposed design any existing application using EV_ACCELERATORs on an EV_APPLICATION should not be affected. Instead, now, of the top-level window receiving notification the last focused widget will handle the accelerator. If the widget does not handle the accelerator or the accelerator should be propagated, then the parent widget's implementation is executed. Existing developed application do not yet know about shortcut propagation so the accelerator will be propagated back until it reaches the top-level window, which as an end result exhibits the same behavior.