User Interface Focus Programming Guide

When using a keyboard instead of a mouse or a touch screen, you need to understand the concept of Focus: a graphical indicator of the widget currently selected, which you can move around using the cursor keys, for example.

EFL handles the focus of your application in a way which works in most situations. This guide shows you how focus is handled in EFL and how to tweak it to your needs in those rare circumstances where this isn't the case.

Prerequisites

Understanding the Focus

Graphical User Interfaces (GUIs) are typically made of widgets arranged on a window. Some widgets are meant to convey information to the user, like labels or progress bars. Some are meant to receive information from the user such as text boxes or sliders and some are meant to execute commands, like buttons.

To act on a widget, you first need to activate it using a mouse: the widget under the mouse pointer is activated when you click on it. Similarly, when you're using a touch screen, the widget under your finger is activated when you press it.

Things are not so straightforward when you use a keyboard. To begin with, a keyboard requires a widget to be the selected widget. You also have keys (typically the Tab or the Cursor keys) that allow you to change the selected widget and keys (typically Enter or the Space) to activate it.

The selected widget is said to have the Focus and is shown with some sort of highlight to distinguish it from other widgets. Changing the focus from one widget to another using the keyboard is called Focus Navigation.

Focus Management in EFL

When developing applications with EFL, you normally don't have to worry about focus management. You can just build your GUI by adding and arranging widgets and focus works out of the box. It is worth understanding how EFL does this though, in case you aren't satisfied with the focus navigation it provides.

There are 6 commands for Focus navigation: 4 directional (Up, Down, Left, Right) and 2 ordinal (Previous and Next).

When EFL receives a directional focus navigation command (typically through a cursor key) it does its best to move the focus to the widget closest to the currently selected one, moving in the requested direction as it appears on the screen.

When EFL receives an ordinal focus navigation command (typically though the Tab or Shift+Tab keys) it moves the focus to the next (or previous) widget in the focus hierarchy. This hierarchy is built as you add widgets to your GUI, so the order in which you add the widgets matters.

As you add widgets to your GUI, the focusable ones are added to a list (not all widgets can be selected, like text labels, for example). Ordinal commands then move the focus through this list. If a widget is a container for other widgets (like Box), focus will move through its children before moving out of the container and onto its siblings.

The bottom line is that you must add widgets to your GUI in the same order in which you want the user to navigate them. The order in which the widgets are added has no other impact, so it is worth doing to make your GUI more keyboard-friendly.

Setting the Focus on a Widget

Sometimes you may want to bypass EFL's default behavior and programmatically set the focus to a particular widget, for example, on an [OK] button once enough information has been added to a form.

To achieve this use the Efl.Ui.Focus.Util class. It has a single method called efl_ui_focus_util_focus() which receives as a parameter the widget to which you want to move the focus.

When using this method the widget currently selected will lose the focus and the one you passed will gain the focus. During this process, all focus-related events will be emitted (see the next section).

This method can only be used on widgets implementing the Efl.Ui.Focus.User and Efl.Ui.Focus.Object interfaces but most widgets inherit from Elm.Widget which already does this, so you don't have to worry.

Here's an usage example based on the EFL examples repository reference/c/ui/src/focus_main.c:

   button = efl_add(EFL_UI_BUTTON_CLASS, hbox,
                    efl_text_set(efl_added, "OK"),
                    efl_pack(hbox, efl_added),
                    efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                           _gui_ok_cb, efl_added));
 
   efl_ui_focus_util_focus(EFL_UI_FOCUS_UTIL_CLASS, button);

NOTE: Since efl_ui_focus_util_focus() is a class method its first parameter is not an Eo Object but an Eo Class, which must always be the EFL_UI_FOCUS_UTIL_CLASS.

Reacting to Focus Changes

Every time a widget gains or loses the focus, it emits the event EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED. You can then retrieve the current focused state of the widget through the focus property using efl_ui_focus_object_focus_get().

Here's an usage example based on the EFL examples repository reference/c/ui/src/focus_main.c:

   static void
   _focus_changed(void *data EINA_UNUSED, const Efl_Event *event)
   {
      printf("Current widget state is %d\n",
             efl_ui_focus_object_focus_get(event->object));
   }
 
   static void
   _gui_setup()
   {
      button = efl_add(EFL_UI_BUTTON_CLASS, hbox,
                       efl_text_set(efl_added, "OK"),
                       efl_pack(hbox, efl_added),
                       efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                              _gui_ok_cb, efl_added),
                       efl_event_callback_add(efl_added, EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED,
                                              _focus_changed, NULL));
   }

Summary

  • Add widgets to your GUI in the same order in which you want your users to navigate them.

  • Manually set the focus to a widget using efl_ui_focus_util_focus().

  • Track focus changes by listening to the event EFL_UI_FOCUS_OBJECT_EVENT_FOCUS_CHANGED.

Further Reading

Introduction to Eo
Explains how to create and destroy EFL objects.
Multiple Inheritance with Eolian
Explains what are Eolian interfaces.
Events Programming Guide
Explains how events and event callbacks are handled in EFL.
EFL API Reference guide
Detailed documentation on the EFL API.
EFL Examples Repository
Usage example of the focus API.