How Enlightenment Gadgets Handle Sizing

This tutorial will provide further detail about aspects of Enlightenment’s new gadget system. Specifically, it will explore how sizing works in different contexts and how simple sizing policies can be leveraged to provide the best view of a gadget. Let’s start with the basics: what is sizing and why does it matter?

Gadgets work a bit different than typical application widgets where one would simply pack them into a layout or use WEIGHT and ALIGN hints to fill portions of available regions. A gadget site uses an automatic sizing algorithm to fit itself into its given location. This ensures that gadgets are always the size the user has specified while also maintaining the best sizes for the gadgets so they will look the way the author intended. Finally, it also greatly simplifies the work of gadget authors since the need to calculate exact sizes and continually adjust based on available size is no longer applicable.

Example of Gadget Sizing

Looking at the relevant code from the “Start” gadget, the gadget uses the following line for its sizing:

evas_object_size_hint_aspect_set(o, EVAS_ASPECT_CONTROL_BOTH, 1, 1);

This informs the gadget site that the gadget should always maintain a 1:1 aspect for width:height, ensuring that the correct amount of space is allocated for the gadget regardless of the size at which it is displayed in a given container. The resizing can be seen in action here.

Taking a slightly more complicated case, let’s look at the clock gadget from the same video. The following function controls its sizing:

static void
_eval_instance_size(Instance *inst)
{
   Evas_Coord mw, mh;
   int sw = 0, sh = 0;
   Evas_Object *ed = elm_layout_edje_get(inst->o_clock);

   edje_object_size_min_get(ed, &mw, &mh);

   if ((mw < 1) || (mh < 1))
     {
        if (edje_object_part_exists(ed, "e.sizer"))
          {
             edje_object_part_geometry_get(ed, "e.sizer", NULL, NULL, &mw, &mh);
          }
        else
          {
             Evas_Object *owner;

             owner = e_gadget_site_get(inst->o_clock);
             switch (e_gadget_site_orient_get(owner))
               {
                case E_GADGET_SITE_ORIENT_HORIZONTAL:
                  evas_object_geometry_get(owner, NULL, NULL, NULL, &sh);
                  break;

                case E_GADGET_SITE_ORIENT_VERTICAL:
                  evas_object_geometry_get(owner, NULL, NULL, &sw, NULL);
                  break;

                default: break;
               }

             evas_object_resize(inst->o_clock, sw, sh);
             edje_object_message_signal_process(ed);

             edje_object_parts_extends_calc(ed, NULL, NULL, &mw, &mh);
          }
     }

   if (mw < 4) mw = 4;
   if (mh < 4) mh = 4;

   if (mw < sw) mw = sw;
   if (mh < sh) mh = sh;

   evas_object_size_hint_aspect_set(inst->o_clock, EVAS_ASPECT_CONTROL_BOTH, mw, mh);
}

Breaking the Code Down

The normal path for this code to take is to get the size of the layout using edje_object_size_min_get(), and then set that as the aspect for the gadget. This will trigger when the digital clock changes its face, ensuring that all the digits receive adequate space. In the case where this size has not been calculated yet, two alternate paths are provided for creating an aspect for the gadget.

In the first path, a check for the “e.sizer” part in the layout is performed and the size of this part is used if the part exists. This is a theme-defined part that may or may not exist, so checking to see which case is currently in use is important before attempting to use this size.

If this check fails, the gadget retrieves the size of the gadget site on its non-extending axis, then resizes itself to this size and forces a recalculation to make an attempt at accurate sizing. Note: in this case it is usually guaranteed that another recalculation will be triggered soon after, so this is likely to only be a temporary size.

Regardless of the method used, an aspect hint is set for the gadget that the gadget site can then use to handle any resizing that may occur. Since the gadget receives events any time a gadget site resize occurs, it’s possible for a gadget to change its aspect hints at any time to re-aspect itself and take up more or less space depending on various scenarios.

This wraps up the mechanics of gadget sizing, but stay tuned for even more gadget-related tutorials in the future!

Author: Mike Blumenkrantz

Mike is the release manager for Enlightenment as well as a core developer of the EFL toolkit.