Change and Changing Events

Problem Description

In the framework, there are numerous user gestures that produce a "change" or synonymous event indicating that the gesture was successful in altering a value or modifying some aspect of the component. However, in certain cases, we would like to either:

  1. Cancel or modify the change before it is committed.
  2. Know if the change is immediate or not (if an effect plays in between the value being set and being committed with a "change" event dispatched).

In these two cases, we need a separate event or events to indicate that the gesture is "changing" the component.

Questions to be answered

  1. Should we adopt a pattern across the board for dispatching events of user gestures that cause changes to the component? Or are the use cases too broad to have just one pattern?
  2. In the case that we have multiple patterns, how should we divide the use cases and what patterns should we adopt?
  3. How should we classify different user gestures? Do we want multiple events for things like key repeats (holding down the delete key)? Or does it count as one user gesture?
  4. Which events should be cancelable?

Use Cases

ListBase

  1. We would like to be able to easily cancel the selection of an item.

TextBase/RichEditableText

  1. Text needs to be able to cancel operations on the text (inserting, cutting, pasting, etc...) as well as know when the operations are finished.

Effects

  1. If there were animations, it would be useful to know when the animation starts and finishes.

Slider (in the context of VideoPlayer)

  1. The VideoPlayer would like to pause the video while the user is dragging and the restart when the thumb is released. In this case, it would be useful to have events denoting the start and end of the user gesture.
  2. When the user clicks on the track of the scrub bar, an animation is played to move the thumb. During that period of time, the VideoPlayer would like to pause the video and suppress the playhead update from changing the value of the scrub bar. Thus, we need an event for when the user clicks on the track, and when the animation ends in order to know when to pause and when to resume the video from that point.
  3. Another interesting case is if we suppose that the VideoPlayer has a commercial in the middle of the video. In this case, we would want to block the user from dragging the thumb past the commercial section of the slider. We would need a cancelable event while they are dragging the thumb in order to stop the thumb from going past a certain value.
  4. A similar case would be if the thumb were inside the commercial section already. We would like to be able to cancel the entire user interaction immediately via a cancelable "start" event.
  5. Another use case to consider is the addition of keyboard actions on the slider. For example, we would like to be able to prevent the user from going past a commercial section while the user is holding down the right arrow key.

TitleWindow

  1. When a user is dragging a window, we may want to bound where the window can go, or implement snapping. We would need a cancelable "windowMoving" event every time the cursor moves in order to track the dragging motion.
  2. Resizing the window is similar to moving the window.
  3. Consider a window where the window contents are hidden while you drag the window. In this case, we would need events from the TitleWindow to determine the start and the end of the entire drag gesture. Again, there is a similar case for resizing.

State of the Framework

Currently, the spark framework sends out a "changing" event when a user initiates a gesture and a "change" event when the gesture is complete. In the case of a slider, this means that on the thumbPress, "changing" is dispatched and "change" is dispatched on thumbRelease. This is also true of clicking on the track. A "changing" is dispatched as the effect starts and a "change" dispatched when the effect ends. However, there could possibly be no events dispatched during the interaction (i.e. if liveDragging is off). Thus, the pattern is like this for a single user interaction:

  • changing, ...other possible events..., change

In the case of the AIR Window, it has a "moving" event that is dispatched when the user attempts to move the window. This event is cancelable and immediately followed by a "windowMove" event when the move is successful. Thus, as the user is dragging in the window around in one motion, the pattern of events looks like:

  • moving, windowMove, moving, windowMove, ...

A third place we see a pattern is with the mx DragManager (List drag and drop). In essence, there is an event signifying that the drag has begun. There are intermediary events that indicate the user wants to change/has changed something, and there is an end event to complete the gesture. The pattern looks like:

  • dragStart, (dragEnter/Over/Exit), dragDrop, dragComplete

Another area where we have a changing/change pattern is in ListBase dealing with selection. Selecting an item will cause a changing event to fire followed by a change event if the selection is not cancelled. In this case, every user gesture will cause this pair (if not cancelled) to be dispatched. TextBase and RichEditableText also use this pattern when dealing with text operations. The pattern is:

  • changing, change (on every interaction)

A last notable place where we have a separate pattern is in DataGrid. DataGrid first dispatches a cancelable "itemEditBeginning" event when a user tries to edit an item followed by "itemEditBegin" event and an "itemEditEnd" event when the editing is finished.

Affected Classes

  • TrackBase (including Slider, ScrollBar)
  • Spinner (and NumericStepper)
  • ListBase
  • TextBase/RichEditableText
  • TitleWindow

Solution Options

  1. Dispatch four separate events. Examples of the pattern of dispatches include:

    changeStart, changing, change, changing, change, ..., changeEnd

    or windowMoveStart, windowMoving, windowMove, windowMoving, windowMove, ..., windowMoveEnd

    The "changing" and "changeStart" events are cancelable. These four events would allow access at each important point in the interaction.

  2. Divide the use cases and have a different pattern for each. For instance, consider dragging a slider thumb vs. dragging a window. The pattern for dragging a slider thumb is: changing ...user drags around... change. There are no intermediary events for the slider except "valueCommit". On the other hand, the pattern for dragging a window is: windowMoving, windowMove, windowMoving, windowMove,...

  3. Allow components to drop events from the first pattern when appropriate. Components would use a subset of the changeStart, changing, change, changeEnd (or similarly named) pattern described in Option 1. Components would include certain events based on their needs although they should follow certain guidelines:
  • changing and changeStart don't have to be cancelable.
  • changing events are always followed by a change event unless canceled. Similarly, changeStart events are followed by a changeEnd unless canceled.
  • changeStart and changeEnd should be used as a pair.
  • change can be used without changing.

Below is a table describing which components need or may need certain events. = optional

Events ListBase TextBase Slider TitleWindow ScrollBar
changeStart or _insertevent_Start
changing or _insertevent_ing
change or insertevent
changeEnd or _insertevent_End

Proposed Solution

The current proposal is option 3.

The first option, being verbose in every case, would dispatch too many events and become heavyweight. The second solution breaks consistency and forces users to learn a different pattern every time. The third option allows us to use the Start and End events to deal with asynchronous actions (such as in the video player). It also allows us to use the changing and change (or similarly named) events to deal with canceling an action.

The changes with sub-tasks that would need to be made to the existing framework are as follows (in priority order):

  1. Change Slider to follow the pattern excluding the "changing" event
    • Remap changing/change events => changeStart/changeEnd. (changeStart is not cancelable)
    • Revert to dispatching change events as in Flex 3.
  2. Change ScrollBar to follow the pattern excluding the "changing" event
    • Remap changing/change events => changeStart/changeEnd. (changeStart is not cancelable)
    • Revert to dispatching change events as in Flex 3. (overlaps with Slider)
  3. (Optional) Implement cancelable "changing" event in Slider and ScrollBar
  4. (Optional) Implement cancelable "changeStart" event in Slider and ScrollBar

There are no expected changes within TitleWindow or other components. As a final thought, it would be good to keep in mind that some use cases can be solved through subclassing or through the user listening for keyboard/mouse events themselves.

Notes:

-We've implemented subtasks 1 and 2.

You must be logged in to comment.