Page MenuHomePhabricator

Updated 1,182 Days AgoPublic

Current problems and theire solutions

A focusable item can contain focusable objects

This makes navigation with right left top down not possible.
Solution: Items are getting hybrid, this means they are just focusable if there is NO focusable content. they can mark themself selected once a child element of them got focused.

Focus just jumps across widgets in some containers

The new Focus system calculates the rigth left directions in a central place, so debugging there what happens to your elements is a way to debug the issue, and to improve the calculation

No chance to revert your last operation

If you move focus by acident to one direction you will not end up in the same item when you move into the complement direction.

API leaks implementation details

The current api in elm.widget leaks the implementation how the focus works.


UI Levels

A Level in a ui is a plane where a bunch of related UI elements are interacting with each other. For example:

The blue rect indicates the level of the scroller, the red rect the level of the window. A Inwin for example creates another level, also a menu, a hover selector, a ctxpopup etc.
Each level contains its own private graph of elements.

Interaction items

A scroller is like a embedded level in another level. Which means the border elements of the scroller should be in the graph of the upper level. These elements are called Interaction Items.

History stack

The history stack is a stack of elements once a element is focused it is set to the top of the stack.

Focused state

A item can be called focused if its the top element of the history stack


Manager Object

There will be a managerobject where you can (un)register items and move the focus.
Once a item is regsitered it is moved to a list of elements which needs to be computed before the graph is complete.
If the graph needs to be complete (when move is called for example) this list gets computed.
If one of the elements is moved during theire time beeing registered they are also moved to the list.

Computation details

If a element overlaps geometry-wise with another element they cannot be in relation to each other. Its a really bad ui if there are elements overlapping. The focus movment of right left top down cannot be very intuitive.
The following picture illustrates how the distance is computed. Only one dimension is taken into account. So for the y dimension only the y coordinates are relevant.
If a few elements are having the same distance to one element, all of them are getting into relation with the one element.


If the focus is moved and the direction has more than one item in the relation, the highest node in the history stack which is part of those item will be taken as movement.
If there is none, the first element of the list will be used.
If there is just one element in the direction this element will be taken.

Redirect property

As we saw above ther eare levels which need to interact with each other. I want to keep a single entry point to move the focus (makes everything easier for keybindings etc.). So once the focus moved to a different Level by focusing a interaction item the Manager object of the different level can set itself as redirect property in the manager in the upper level.
After this is done all move requests are sent to this manager. If the property is NULL the upper manager will compute the requests again himself.

Api for now

enum Efl.Ui.Focus.Direction{
    right = 0,
    left = 1,
    down = 2,
    up = 3,
    next = 4,
    prev = 5,
    last = 6

class Efl.Ui.Focus.Manager (Eo.Base) {
    methods {
        move {
            [[Move the focus into the given direction]]
            params {
                direction : Efl.Ui.Focus.Direction; [[The direction to move to]]
            return : Efl.Ui.Focus.Object*; [[The element which is now focused]]
        register {
            [[Register a new item in the graph

              The manager does not manager if it is focusable or not.
            params {
                child : Efl.Ui.Focus.Object*; [[The object to register]]
            return : bool; [[$true if it was successfull $false if not]]
        unregister {
            [[unregister the given item from the graph]]
            params {
                child : Efl.Ui.Focus.Object*;
        @property redirect {
            [[Add a another manager as redirect element.

              If this value is set all move requests are redirected to this manager object.
              Set it to $null once nothing should be redirected anymore.]]
            values {
                redirect : Efl.Ui.Focus.Manager*;
    implements {

Theoretical idea

Each app can contain mutliple layers of element interactions. The main window is a level, the content elements of a scroller is such a level.

Each level has a set of elements. These elements are NOT interacting or just at the border. At the border means only those elements which are not fully connected in the graph (have a right left top down relation) should be integrated with the "outer" graph. After one of those border elements is selected, we can set the new graph as redirect, so the scroller-manager is not looking for the movements. Once a borderelement is again focused, and a direction is chocen which is not known to the scroller-manager the redirect is unset, and the relation from the mainwindow graph is used.

A window with a scroller. The content border elements of the scroller should be also in the graph of the mainwindow.

Types of focuswidgets


The widget needs to get focus to key keyboardinput or just to indicate that its currently selected


It deals with keyboardinput / indicating that its selected, but its getting the inputs / the interacting because its having a child elements which can be focused


Its a mixture between Active and Passive. Once its having a focusable child its getting into passive mode, if there is none its in active mode.

Last Author
Last Edited
May 29 2016, 3:27 AM
subodh6129, singh.amitesh, DaveMDS