Box example - custom layout

This example shows how to register a custom layout to be used by the Edje box part.

It will use edje_box_layout_register() for that.

To play with this example, use the keyboard modifier keys and number keys together. The Ctrl key is used for adding elements, and Shift is used for removing them. For instance, Ctrl + 3 will insert a new rectangle object in the 3rd position of the box, while Shift + 6 will try to remove the 6th element of the box.

This example is very similar to the other box example, has a structure with global data, a callback for key down events where we create or delete rectangle objects and add or remove them to/from the box part.

But the important part is the next one:

static struct _App app;

static void
custom_layout(Evas_Object *o, Evas_Object_Box_Data *p, void *data)
{
   int x, y, w, h;
   int xx, yy, ww, hh;
   int count;
   Eina_List *l;
   Evas_Object_Box_Option *opt;

   evas_object_geometry_get(o, &x, &y, &w, &h);
   count = eina_list_count(p->children);
   ww = w / (count?:1);
   hh = h / (count?:1);
   if (ww < 1) ww = 1;
   if (hh < 1) hh = 1;

   xx = x;
   yy = y;
   EINA_LIST_FOREACH(p->children, l, opt)
     {
    evas_object_move(opt->obj, xx, yy);
    xx += ww;
    yy += hh;
     }
}

This code implements our custom layout, which will position every object added to the box in a diagonal through the size of the box part. Notice that it just calculates the position and offset based on the size of the box and number of children, and then moves each child to the respective position.

Later on the main function, everything we need to do is to register this custom layout function with edje:

   edje_box_layout_register("custom_layout", custom_layout, NULL, NULL, NULL, NULL);

And use it inside the .edc file:

         part {
            name: "example/box";
            type: BOX;

            description {
               state: "default" 0.0;

               box {
                  layout: "custom_layout";
                  padding: 2 2;
                  align: 0.5 0.5;
                  min: 1 1;
               }
               rel1 {
                  relative: 0.0 0.2;
                  offset: 0 0;
                  to: "bg";
               }
               rel2 {
                  relative: 1.0 1.0;
                  offset: -1 -61;
                  to: "bg";
               }
            }
         } // example/box

The example's window should look like this picture:

edje-box2-example.png

The full source code follows:

#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define PACKAGE_EXAMPLES_DIR "."
#define __UNUSED__
#endif

#include <Ecore.h>
#include <Evas.h>
#include <Ecore_Evas.h>
#include <Edje.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

static const char *edje_file_path = PACKAGE_EXAMPLES_DIR "/box.edj";

struct _App {
   Ecore_Evas *ee;
   Evas *evas;
   Evas_Object *bg;
   Evas_Object *box;
};

static struct _App app;

static void
custom_layout(Evas_Object *o, Evas_Object_Box_Data *p, void *data)
{
   int x, y, w, h;
   int xx, yy, ww, hh;
   int count;
   Eina_List *l;
   Evas_Object_Box_Option *opt;

   evas_object_geometry_get(o, &x, &y, &w, &h);
   count = eina_list_count(p->children);
   ww = w / (count?:1);
   hh = h / (count?:1);
   if (ww < 1) ww = 1;
   if (hh < 1) hh = 1;

   xx = x;
   yy = y;
   EINA_LIST_FOREACH(p->children, l, opt)
     {
    evas_object_move(opt->obj, xx, yy);
    xx += ww;
    yy += hh;
     }
}

static Evas_Object *
new_greenie_block(Evas *e)
{
   Evas_Object *o;

   o = evas_object_rectangle_add(e);
   evas_object_resize(o, 10, 10);
   evas_object_color_set(o, 0, 255, 0, 255);
   evas_object_show(o);

   return o;
}

static void
on_keydown(void *data, Evas *evas, Evas_Object *o, void *einfo)
{
   struct _App *app = data;
   Evas_Event_Key_Down *ev = einfo;
   const Evas_Modifier *mods;

   mods = evas_key_modifier_get(evas);
   if (evas_key_modifier_is_set(mods, "Shift"))
     {
    int pos;
    Evas_Object *obj = NULL;
    pos = atoi(ev->keyname);
    obj = edje_object_part_box_remove_at(app->box, "example/box", pos);
    if (obj)
      evas_object_del(obj);
    return;
     }
   if (evas_key_modifier_is_set(mods, "Control"))
     {
    Evas_Object *o;
    int pos;
    pos = atoi(ev->keyname);
    o = new_greenie_block(app->evas);
    if (!edje_object_part_box_insert_at(app->box, "example/box", o, pos))
      edje_object_part_box_append(app->box, "example/box", o);
    return;
     }
   if (strcmp(ev->keyname, "Escape") == 0)
     ecore_main_loop_quit();
}

static Evas_Object *
box_new(Evas *evas, const char *name, int x, int y, int w, int h)
{
   Evas_Object *o;

   o = edje_object_add(evas);
   evas_object_move(o, x, y);
   evas_object_resize(o, w, h);
   if (!edje_object_file_set(o, edje_file_path, "example/group2"))
     {
    printf("error: could not load file object.\n");
     }
   evas_object_show(o);

   evas_object_name_set(o, name);

   return o;
}

static void
on_resize(Ecore_Evas *ee)
{
   int w, h;

   evas_output_viewport_get(app.evas, NULL, NULL, &w, &h);
   evas_object_resize(app.bg, w, h);
   evas_object_resize(app.box, w, h);
}

static void
on_destroy(Ecore_Evas *ee)
{
   ecore_main_loop_quit();
}

int
main(int argc, char *argv[])
{
   Ecore_Evas *ee;
   int w, h, i;
   Evas_Object *last;
   Evas_Object *o;

   evas_init();
   ecore_init();
   ecore_evas_init();
   edje_init();

   ee = ecore_evas_new(NULL, 0, 0, 640, 480, NULL);
   ecore_evas_show(ee);

   app.ee = ee;
   app.evas = ecore_evas_get(ee);

   ecore_evas_callback_resize_set(ee, on_resize);
   ecore_evas_callback_destroy_set(ee, on_destroy);

   evas_output_viewport_get(app.evas, NULL, NULL, &w, &h);

   app.bg = evas_object_rectangle_add(app.evas);
   evas_object_resize(app.bg, w, h);
   evas_object_show(app.bg);
   evas_object_focus_set(app.bg, 1);
   evas_object_event_callback_add(
      app.bg, EVAS_CALLBACK_KEY_DOWN, on_keydown, &app);

   edje_box_layout_register("custom_layout", custom_layout, NULL, NULL, NULL, NULL);

   app.box = box_new(app.evas, "box", 0, 0, w, h);

   for (i = 1; i <= 5; i++)
     {
    o = last = evas_object_rectangle_add(app.evas);
        evas_object_size_hint_min_set(o, 50, 50);
        evas_object_resize(o, 50, 50);
    evas_object_color_set(o, 255, 0, 0, 128);
    evas_object_show(o);

    if (!edje_object_part_box_append(app.box, "example/box", o))
      {
         fprintf(stderr, "error appending child object!\n");
         return 1;
      }
     }

   ecore_main_loop_begin();

   edje_shutdown();
   ecore_evas_shutdown();
   ecore_shutdown();
   evas_shutdown();


   return 0;
}