# Tutorial 3: A Basic Graphical Text Editor with Buttons #

In this tutorial you will learn how to build an EFL application with several widgets, including a text box with editable text and two buttons arranged vertically, each with distinct functions.

The end result should look something like this:

![Image of what you want to achieve](image03.png)

## Prerequisites ##

You will be basing your text editor on the application you built in the [previous guide](https://www.enlightenment.org/playground/02-hello-world/gui-hello-world.md). The final program (including an expanded text box) looked like this:

```c #ifdef HAVE_CONFIG_H # include “config.h” #endif

#include <Eina.h> #include <Efl.h> #include <Elementary.h>

static void _gui_setup() {

 Eo *win, *box, *text; //*
 win = efl_add(EFL_UI_WIN_CLASS, NULL,
               efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC),
               efl_text_set(efl_added, "Hello World"),
               efl_ui_win_autodel_set(efl_added, EINA_TRUE));
box = efl_add(EFL_UI_BOX_CLASS, win,
              efl_content_set(win, efl_added),
              efl_gfx_size_hint_min_set(efl_added, EINA_SIZE2D(360, 240)));
 text = efl_add(EFL_UI_TEXT_CLASS, box,
              efl_text_set(efl_added, "Hello World!"),
              efl_pack(box, efl_added));

}

EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) {

 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
 _gui_setup();

} EFL_MAIN() ```

This program creates a window with a text box 360 pixels wide by 240 pixels high and displays the message “Hello World!” inside it.

## Step 1: Making the Text Editable ##

The first order of business is to make the text box editable. To do this change the name of the ``text`` object on line to ``editor``. Don't forget to change on line 23 too.

Next, change the definition of ``editor`` from:

```c […] editor = efl_add(EFL_UI_TEXT_CLASS, box,

           efl_text_set(efl_added, "Hello World!"),
           efl_pack(box, efl_added));

[…] ```

To:

```c […] editor = efl_add(EFL_UI_TEXT_CLASS, box,

               efl_text_set(efl_added, "Edit me"),
               efl_ui_text_interactive_editable_set(efl_added, EINA_TRUE),
               efl_ui_text_scrollable_set(efl_added, EINA_TRUE),
               efl_pack(box, efl_added));

[…] ```

By adding the ``efl_ui_text_interactive_editable_set()`` you make the text box editable. With ``efl_ui_text_scrollable_set()`` users can type more text than is available in the visible area, as they can scroll with the cursor or the <kbd>Home</kbd> and <kbd>End</kbd> keys.

NOTE:
``[…]`` in a Code Block indicates existing code which has been excluded for the sake of brevity. There is no need to type ``[…]`` into your program.

## Step 2: Adding Buttons ##

Next you're going to add two buttons. One will be an *About* button which displays text on the command line when pressed. The other will exit the program.

To add buttons, first add a new object to the variable declarations on line 12:

```c […] Eo *win, *box, *editor, *button; […] ```

You can then use the ``EFL_UI_BUTTON_CLASS`` macro to define your buttons:

```c […] button = efl_add(EFL_UI_BUTTON_CLASS, box,

               efl_text_set(efl_added, "About"),
               efl_pack(box, efl_added),
               efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                      _gui_about_clicked_cb, efl_added));

button = efl_add(EFL_UI_BUTTON_CLASS, box,

               efl_text_set(efl_added, "Quit"),
               efl_pack(box, efl_added),
               efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                      _gui_quit_clicked_cb, efl_added));

[…] ``` Use ``efl_text_set()`` to set the buttons' labels and ``efl_pack()`` to fit the buttons to the box. The ``efl_event_callback_add()`` is used to describe the event that will trigger an action. In this case, the action will be triggered when the button is clicked, as specified by ``EFL_UI_EVENT_CLICKED``. The actions the buttons trigger are defined by functions which you will have to add to your program.

In the code above line 6 tells your application to run the function ``_gui_about_clicked_cb()`` when users click the *About* button and the ``_gui_quit_clicked_cb()`` function when they click the *Quit* button. Add those two functions to your program (you can leave them empty for the moment) so you can compile it.

Your program should now look like this:

```c #ifdef HAVE_CONFIG_H # include “config.h” #endif

#include <Eina.h> #include <Efl.h> #include <Elementary.h>

static void _gui_about_clicked_cb() {

/* code */

}

static void _gui_quit_clicked_cb() {

/* code */

}

static void _gui_setup() {

 Eo *win, *box, *editor, *button;
 win = efl_add(EFL_UI_WIN_CLASS, NULL,
               efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC),
               efl_text_set(efl_added, "Basic Editor"),
               efl_ui_win_autodel_set(efl_added, EINA_TRUE));
 box = efl_add(EFL_UI_BOX_CLASS, win,
              efl_content_set(win, efl_added),
              efl_gfx_size_hint_min_set(efl_added, EINA_SIZE2D(360, 240)));
 editor = efl_add(EFL_UI_TEXT_CLASS, box,
             efl_text_set(efl_added, "Edit me"),
             efl_ui_text_interactive_editable_set(efl_added, EINA_TRUE),
             efl_ui_text_scrollable_set(efl_added, EINA_TRUE),
             efl_pack(box, efl_added));
 button = efl_add(EFL_UI_BUTTON_CLASS, box,
                  efl_text_set(efl_added, "About"),
                  efl_pack(box, efl_added),
                  efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                         _gui_about_clicked_cb, efl_added));
 button = efl_add(EFL_UI_BUTTON_CLASS, box,
                  efl_text_set(efl_added, "Quit"),
                  efl_pack(box, efl_added),
                  efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                         _gui_quit_clicked_cb, efl_added));

}

EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) {

 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
 _gui_setup();

} EFL_MAIN() ```

If you now [compile and run this program](eflinstallationguide.md#Compiling), you will see something like this:

![Editable text box with buttons](image02.png)

Note how Enlightenment splits the space in the box equally between the text box and the two buttons, assigning about a third to each. You'll learn how to organise and assign space yourself in the next section.

## Step 3: Organising Widgets ##

So far you've bundled all your elements into single box. Next you're going to create a new box exclusively for the buttons and place them side by side instead of one on top of the other. This looks much more tidy.

Add a new object called ``hbox``to the the object declaration line in ``_gui_setup()``:

```c […]

 Eo *win, *box, *hbox, *editor, *button;

[…] ```

Now write its definition between the definition of ``editor`` and the definition of your first ``button``:

```c […] hbox = efl_add(EFL_UI_BOX_CLASS, box,

            efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL),
            efl_gfx_size_hint_weight_set(efl_added, 1.0, 0.1),
            efl_pack(box, efl_added));

[…] ```

This creates a new box, with the difference that the widgets you put in it will be laid out horizontally (``efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL)``) instead of vertically, which is the default.

Note that ``hbox``is placed within ``box``. The ``editor`` text box is also in ``box``. This means they're both sharing a container. You use the the two parameters in ``efl_gfx_size_hint_weight_set()`` to establish how much space each gets. The first value (``1.0``) sets how much space the object takes up horizontally. As ``box`` is using the default layout, it is stacking widgets one on top of the other. As a result, no matter what value you enter here (values can range from ``0.0`` to ``1.0``) both ``editor`` and ``hbox`` will stretch to the full width of the ``box`` container.

The second value, ``0.1``, establishes how much space the ``hbox`` widget takes up vertically. As widgets in ``box`` are stacked vertically, changing this value will change its size and by extension that available to the buttons it contains. For example if you set it to ``1.0``, it will take up the full space it would be assigned by default which is half the height of the containing ``box`` : Remember ``box`` now contains two widgets and will assign by default half the space available to each. Setting it to ``0.1`` makes the box and any buttons it contains slightly taller than the bare minimum. Anything value in between will assign varying heights.

Next, change the buttons so their parent is ``hbox``instead of ``box``:

```c […] button = efl_add(EFL_UI_BUTTON_CLASS, hbox,

               efl_text_set(efl_added, "About"),
               efl_pack(hbox, efl_added),
               efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                      _gui_about_clicked_cb, efl_added));

button = efl_add(EFL_UI_BUTTON_CLASS, hbox,

               efl_text_set(efl_added, "Quit"),
               efl_pack(hbox, efl_added),
               efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                      _gui_quit_clicked_cb, efl_added));

[…] ```

When you [compile and run this program](TODO:eflinstallationguide.md#Compiling), you will see something like this:

![Horizontal buttons](image03.png)

## Step 4: Adding Button Functionality ##

All that's missing now is adding actions that get executed when the buttons are pressed. This means filling out the ``_gui_about_clicked_cb()`` and ``_gui_quit_clicked_cb()`` you created earlier:

```c […] static void _gui_about_clicked_cb(void *data, const Efl_Event *event EINA_UNUSED) {

 printf("Clicked About\n");

}

static void _gui_quit_clicked_cb(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) {

 efl_exit(0);

} […] ```

There is nothing complex about this code: ``_gui_about_clicked_cb()`` just prints a string to the command line and ``_gui_quit_clicked_cb()`` calls EFL's inbuilt ``efl_exit()`` function, which closes EFL applications.

The complete program is listed below::

## The Complete “basic-editor.c” Program ##

```c #ifdef HAVE_CONFIG_H # include “config.h” #endif

#include <Eina.h> #include <Efl.h> #include <Elementary.h>

static void _gui_about_clicked_cb(void *data, const Efl_Event *event EINA_UNUSED) {

 Eo *button = data;
 printf("Clicked About\n");

}

static void _gui_quit_clicked_cb(void *data EINA_UNUSED, const Efl_Event *event EINA_UNUSED) {

 efl_exit(0);

}

static void _gui_setup() {

 Eo *win, *box, *hbox, *editor, *button;
 win = efl_add(EFL_UI_WIN_CLASS, NULL,
               efl_ui_win_type_set(efl_added, EFL_UI_WIN_BASIC),
               efl_text_set(efl_added, "Hello World"),
               efl_ui_win_autodel_set(efl_added, EINA_TRUE));
 box = efl_add(EFL_UI_BOX_CLASS, win,
              efl_content_set(win, efl_added),
              efl_gfx_size_hint_min_set(efl_added, EINA_SIZE2D(360, 240)));
 editor = efl_add(EFL_UI_TEXT_CLASS, box,
                  efl_text_set(efl_added, "Edit me"),
                  efl_ui_text_interactive_editable_set(efl_added, EINA_TRUE),
                  efl_ui_text_scrollable_set(efl_added, EINA_TRUE),
                  efl_pack(box, efl_added));
 hbox = efl_add(EFL_UI_BOX_CLASS, box,
               efl_ui_direction_set(efl_added, EFL_UI_DIR_HORIZONTAL),
               efl_gfx_size_hint_weight_set(efl_added, 1.0, 0.1),
               efl_pack(box, efl_added));
 button = efl_add(EFL_UI_BUTTON_CLASS, hbox,
                  efl_text_set(efl_added, "About"),
                  efl_pack(hbox, efl_added),
                  efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                         _gui_about_clicked_cb, efl_added));
 button = efl_add(EFL_UI_BUTTON_CLASS, hbox,
                  efl_text_set(efl_added, "Quit"),
                  efl_pack(hbox, efl_added),
                  efl_event_callback_add(efl_added, EFL_UI_EVENT_CLICKED,
                                         _gui_quit_clicked_cb, efl_added));

}

EAPI_MAIN void efl_main(void *data EINA_UNUSED, const Efl_Event *ev EINA_UNUSED) {

 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
 _gui_setup();

} EFL_MAIN() ```

## Compiling and Running ##

The instructions of the [*Compile and Run* section in the EFL Installation Guide](TODO: efl-installation-guide.md#Compiling) will create an executable file called “basic-editor”. Run your program with:

``` ./basic-editor ``` You will see something like what is shown below.

![A basic GUI-based text editor with buttons.](image03.png)

Clicking on the *About* button will print the message *“Clicked About“* on the command line. Clicking *Quit* will close the program.

If anything goes wrong check out the [Troubleshooting](#Troubleshooting) section at the end of this page.

## Things to Try ##

As it stands, the editor is not terribly useful. Users cannot save their work for instance. This would certainly be something worth developing further, by implementing *Open File* and *Save* buttons.

Another issue is that when you reach the right-most edge of the window and keep typing any text you've already typed scrolls left and disappears. The cursor does not jump to a new line. Also, there is no scrollbar, which means that the only way to move back and forth along the text is by moving the cursor with the arrow keys or the <kbd>Home</kbd> and <kbd>End</kbd> keys.

You will learn how to solve all of the above issues in [the next tutorial](TODO: LINK TO FULL EDITOR TUTORIAL).

## Summary ##

The most important lessons you can take away from this tutorial are:

1. Adding new functions to widgets changes their behavior. Adding ``efl_ui_text_interactive_editable_set(efl_added, EINA_TRUE)``, for example, suddenly makes the text in a text box editable. 2. Buttons need callback functions that implement the actions that should be carried out when they are clicked. These callback functions are passed as a parameters to the buttons' ``efl_event_callback_add()`` functions. 3. Using weight hinting allows you to assign space to widgets with great precision.

## Troubleshooting ##

When you try compile the program above, you may see the following error:

``` basic-editor.c: In function ‘_gui_quit_clicked_cb’: basic-editor.c:18:14: error: macro “efl_exit” passed 1 arguments, but takes just 0

  efl_exit(0);
            ^

basic-editor.c:18:4: error: ‘efl_exit’ undeclared (first use in this function)

  efl_exit(0);
  ^

basic-editor.c:18:4: note: each undeclared identifier is reported only once for each function it appears in ```

This happens if you're using a slightly older version of EFL libraries. Resolve the issue by [downloading and using the latest version of EFL](/download).

It this isn't possible you can avoid this problem by changing the line:

```c […] efl_exit(0); […] ```

in ``_gui_quit_clicked_cb()`` to:

```c […] efl_exit(); […] ```

## Resources ##

1. [A list of useful widgets](TODO: widgets.md) 2. [Download the ``basic-editor.c`` from here](basic-editor.c)

## What's Next ##

In the [next guide](TODO: Insert correct link to next guide) you will learn how to make a a much more advanced text editor. The editor will wrap overlapping text and allow users to open and save text files.