Evas
Evas is a clean display canvas API for several target display systems that can draw anti-aliased text, smooth super and sub-sampled scaled images, alpha-blend objects and much more.
It abstracts any need to know much about what the characteristics of your display system are, what graphics calls are used to draw them, and how. It deals on an object level where all you do is create and manipulate objects in a canvas and set their properties.
Evas optimizes the rendering pipeline to minimize effort in redrawing changes made to the canvas and so takes this work out of the programmers hand, saving a lot of time and energy.
It is designed to work on embedded systems all the way to large and powerful multi-cpu workstations. It can be compiled to only have the features you need for your target platform if you so wish. It has several display back-ends, allowing it display on several display systems, making it portable for cross-device and cross-platform development.
Evas is not a UI component set or a UI component toolkit, but it is their base. See Elementary for a toolkit based on Evas, Edje, Ecore and other Enlightenment technologies.
It is not dependent or aware of main loops, input or output systems. Input must be polled from various sources and fed to Evas. It does not create windows or report windows updates to your system, but draws the pixels and reports to the user the areas that are changed. These operations are ready to be used in Ecore, particularly in Ecore_Evas wrapper/helper set of functions.
Rendering Concept and Method in Evas
Evas is a canvas display library. It is markedly different from most display and windowing systems as the canvas is structural and is also a state engine, whereas most display and windowing systems are immediate mode display targets. Evas handles the logic between a structural display via its state engine, and controls the target windowing system in order to produce rendered results of the current canvas' state on the display.
Immediate mode display systems retain very little or no state. A program executes a series of commands, as in the following pseudo code.
draw line from position (0, 0) to position (100, 200); draw rectangle from position (10, 30) to position (50, 500); bitmap_handle = create_bitmap(); scale bitmap_handle to size 100 x 100; draw image bitmap_handle at position (10, 30);
The series of commands is executed by the windowing system and the results are typically displayed on the screen. Once the commands are executed, the display system does not know how to reproduce this image again, and has to be instructed by the application on how to redraw sections of the screen if needed. Each successive command is executed as instructed by the application and either emulated by software or sent to the graphics hardware on the device to be performed.
The advantage of such a system is that it is simple and gives a program tight control over how something looks and is drawn. Given the increasing complexity of displays and demands by users to have better looking interfaces, more work needs to be done at this level by the internals of UI component sets, custom display components and other programs. This means that more logic and display rendering code needs to be written again each time the application needs to figure out how to minimize redraws so that display is fast and interactive, and keep track of redraw logic.
For example, if in the scene below, the windowing system requires the application to redraw the area from 0, 0 to 50, 50 (also referred to as the "expose event"). Then the programmer calculates manually the updates and repaints it again.
Redraw from position (0, 0) to position (50, 50): // What was in area (0, 0, 50, 50)? // 1. intersection part of line (0, 0) to (100, 200)? draw line from position (0, 0) to position (25, 50); // 2. intersection part of rectangle (10, 30) to (50, 500)? draw rectangle from position (10, 30) to position (50, 50) // 3. intersection part of image at (10, 30), size 100 x 100? bitmap_subimage = subregion from position (0, 0) to position (40, 20) draw image bitmap_subimage at position (10, 30);
If all elements in the above scene are opaque, the system is doing useless paints: part of the line is behind the rectangle, and part of the rectangle is behind the image. These useless paints tend to be very costly.
Evas is a structural system in which the programmer creates and manages display objects and their properties, and as a result of this higher level state management, the canvas is able to redraw the set of objects when needed to represent the current state of the canvas.
For example, see the following pseudo code.
line_handle = create_line(); set line_handle from position (0, 0) to position (100, 200); show line_handle; rectangle_handle = create_rectangle(); move rectangle_handle to position (10, 30); resize rectangle_handle to size 40 x 470; show rectangle_handle; bitmap_handle = create_bitmap(); scale bitmap_handle to size 100 x 100; move bitmap_handle to position (10, 30); show bitmap_handle; render scene;
This looks longer, but when the display needs to be refreshed or updated, the programmer only moves, resizes, shows, hides etc. the objects that need to change. The programmer thinks at the object logic level, and the canvas software does the rest of the work, figuring out what changed in the canvas since it was last drawn, how to most efficiently redraw the canvas and its contents to reflect the current state, and doing the actual drawing of the canvas.
This allows the programmer think in a more natural way when dealing with a display, and saves time and effort of working out how to load and display images, to render given the current display system etc. Since Evas is portable across different display systems, this gives the programmer the ability to port and display the code on different display systems with little work.
Evas is a display system somewhere between a UI component set and an immediate mode display system. It retains basic display logic, but does little high-level logic such as scrollbars, sliders, push buttons etc.
For more information on the UI rendering modes (immediate and retained), see UI Rendering Mode.
Evas Object
An Evas object is the most basic visual entity used in Evas. Everything, be it a single line or a complex list of UI components, is an Evas object.
Primitive Renderable Objects
Primitive objects are the base upon which to build a complex interface: rectangles, lines, polygons, images, textblocks, and texts.
Rectangle
There is only one function to deal with rectangle objects. However, the rectangle is manipulated using the generic evas object functions.
The evas rectangle serves a number of key functions when working on Evas programs.
- background
- debugging
- clipper
Background
A common requirement of Evas programs is to have a solid color background, which can be accomplished with the following code.
Evas_Object *bg = evas_object_rectangle_add(evas_canvas); // Here we set the rectangles red, green, blue and opacity levels evas_object_color_set(bg, 255, 255, 255, 255); // opaque white background evas_object_resize(bg, WIDTH, HEIGHT); // covers full canvas evas_object_show(bg);
Debugging
When debugging visual issues with evas programs, the rectangle is a useful tool. The rectangle's simplicity means that it is easier to pinpoint issues with it than with more complex objects. A common technique to use when writing an evas program and not getting the desired visual result is to replace an object for a solid color rectangle and seeing how it interacts with the other elements. This often allows us to notice clipping, parenting or positioning issues. Once the issues are identified and corrected, the rectangle can be replaced for the original object, and in all likelihood any remaining issues are specific to that object's type.
Clipping
Clipping serves two main functions:
- limiting visibility
- applying a layer of color to an object
Text
An Evas text object shows a basic single-line single-style text.
Evas_Object *text = evas_object_text_add(evas_canvas); evas_object_text_text_set(text, "some text"); evas_object_color_set(text, 127, 0, 0, 127); evas_object_show(text);
To set the text, use evas_object_text_text_set(text, some_text). You can set the current text with evas_object_text_text_get(text).
To set the font, use evas_object_text_font_set(text, font, size):
- text: The text object
- font: The font name you want to use
- size: The font size you want to use. To query the current font, use evas_object_text_font_set(text, font, size).
To set the text style, use evas_object_text_style_set(text, style). The following styles are supported:
- EVAS_TEXT_STYLE_PLAIN: Plain, standard text
- EVAS_TEXT_STYLE_SHADOW: Text with shadow underneath
- EVAS_TEXT_STYLE_OUTLINE: Text with an outline
- EVAS_TEXT_STYLE_SOFT_OUTLINE: Text with a soft outline
- EVAS_TEXT_STYLE_GLOW: Text with a glow effect
- EVAS_TEXT_STYLE_OUTLINE_SHADOW: Text with both outline and shadow effects
- EVAS_TEXT_STYLE_FAR_SHADOW: Text with (far) shadow underneath
- EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW: Text with outline and soft shadow effects combined
- EVAS_TEXT_STYLE_SOFT_SHADOW: Text with (soft) shadow underneath
- EVAS_TEXT_STYLE_FAR_SOFT_SHADOW: Text with (far soft) shadow underneath
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_RIGHT: Shadow growing to bottom right
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM: Shadow growing to the bottom
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_BOTTOM_LEFT: Shadow growing to bottom left
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_LEFT: Shadow growing to the left
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_LEFT: Shadow growing to top left
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP: Shadow growing to the top
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_TOP_RIGHT: Shadow growing to top right
- EVAS_TEXT_STYLE_SHADOW_DIRECTION_RIGHT: Shadow growing to the right. To query the current style, use evas_object_text_style_get(text).
If the text does not fit, make an ellipsis on it by using evas_object_text_ellipsis_set(text, ellipsis). The (float) value specifies, which part of the text is shown.
- 0.0: The beginning is shown and the end trimmed.
- 1.0: The beginning is trimmed and the end shown.
- Any value in between means that both ends of the text have ellipsis and the set part is shown.
- -1.0: Ellipsis is disabled. To query the current ellipsis value, use evas_object_text_ellipsis_get(text).
When the text style is set to glow, set the glow color using evas_object_text_glow_color_set(text, r, g, b, a), where r, g, b, and a are respectively the red, green, blue, and alpha values. The effect is placed at a short distance from the text but not touching it. For glows set right at the text, use evas_object_text_glow2_color_set(text, r, g, b, a). To query the current color, use evas_object_text_glow_color_get(text, r, g, b, a), respectively evas_object_text_glow2_color_get(text, r, g, b, a).
If your text style is set to display a shadow, use evas_object_text_shadow_color_set(text, r, g, b, a), where r, g, b, and a are respectively the red, green, blue, and alpha values. To query the current color, use evas_object_text_shadow_color_get(text, r, g, b, a)
If your text style is set to display an outline, use evas_object_text_outline_color_set(text, r, g, b, a), where r, g, b, and a are respectively the red, green, blue, and alpha values. To query the current color, use evas_object_text_outline_color_get(text, r, g, b, a)
Primitive Smart Objects
A smart object is a special Evas object that provides custom functions to handle automatically clipping, hiding, moving, resizing color setting and more on child elements, for the smart object's user. They could be, for example, a group of objects that move together, or implementations of whole complex UI components, providing some intelligence and extension to simple Evas objects.
Primitive Container Objects
A container is a Smart object that holds children Evas objects in a specific fashion.
Table
A table is a smart object that packs children using a tabular layout.
table = evas_object_table_add(evas); evas_object_table_homogeneous_set(table, EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE); evas_object_table_padding_set(table, 0, 0); evas_object_resize(table, WIDTH, HEIGHT); evas_object_show(table); rect = evas_object_rectangle_add(evas); evas_object_color_set(rect, 255, 0, 0, 255); evas_object_size_hint_min_set(rect, 100, 50); evas_object_show(rect); evas_object_table_pack(table, rect, 1, 1, 2, 1); rect = evas_object_rectangle_add(d.evas); evas_object_color_set(rect, 0, 255, 0, 255); evas_object_size_hint_min_set(rect, 50, 100); evas_object_show(rect); evas_object_table_pack(table, rect, 1, 2, 1, 2); rect = evas_object_rectangle_add(d.evas); evas_object_color_set(rect, 0, 0, 255, 255); evas_object_size_hint_min_set(rect, 50, 50); evas_object_show(rect); evas_object_table_pack(table, rect, 2, 2, 1, 1); rect = evas_object_rectangle_add(d.evas); evas_object_color_set(rect, 255, 255, 0, 255); evas_object_size_hint_min_set(rect, 50, 50); evas_object_show(rect); evas_object_table_pack(table, rect, 2, 3, 1, 1);
In this example, we add a non-homogeneous table to the canvas with its padding set to 0.
We then add four different colored rectangles with different properties.
- the first one, at the first column and first line, spans two columns and one line
- the second one, at the first column and second line, spans one columns and two lines
- the third one, at the second column and second line, fits in one cell
- the fourth one, at the second column and third line, also fits in one cell
To create a table, use evas_object_table_add(evas).
To set the table layout (the cells), use evas_object_table_homogeneous_set(table, homogeneous). The following values can be homogeneous:
- EVAS_OBJECT_TABLE_HOMOGENEOUS_NONE: This default value has columns and rows calculated based on hints of individual cells. This is flexible, but much heavier on computations.
- EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE: The table size is divided equally among children, filling the whole table area. If the children have a minimum size that is larger than this (including padding), then the table overflows and is aligned respecting the alignment hint, possibly overlapping sibling cells.
- EVAS_OBJECT_TABLE_HOMOGENEOUS_ITEM: The greatest minimum cell size is used: if no element is set to expand, the contents of the table are the minimum size and the bounding box of all the children is aligned relatively to the table object using evas_object_table_align_get(). If the table area is too small to hold this minimum bounding box, then the objects keep their size and the bounding box overflows the box area, still respecting the alignment. To set the current mode, use evas_object_table_homogeneous_get(table).
The table's content alignment is set using evas_object_table_align_set(table, horizontal, vertical), where horizontal and vertical are floating values. To see them, use evas_object_table_align_get(table, horizontal, vertical).
To set the padding, use evas_object_table_padding_set(table, horizontal, vertical). To see the current value, use evas_object_table_padding_get(table, horizontal, vertical).
_To see the current column and row count, use evas_object_table_col_row_size_get(table, columns, rows).
Grid
A grid is a smart object that packs its children as with a regular grid layout.
Grids are added to the canvas with evas_object_grid_add(evas).
To change a grid's virtual resolution, use evas_object_grid_size_set(grid, width, height), to see it, use evas_object_grid_size_get(grid, width, height).
To add an object, use evas_object_grid_pack(grid, child, x, y, w, h), where
- x is the virtual X coordinate of the child
- y is the virtual y coordinate of the child
- w is the virtual width of the child
- h is the virtual height of the child
Box
A box is a simple container that sets its children objects linearly.
To add a box to your canvas, use evas_object_box_add(evas).
To add a child to the box, use
- evas_object_box_append(box, child): The child is appended.
- evas_object_box_insert_after(box, child, reference): The child is added after reference.
- evas_object_box_insert_before(box, child, reference): The child is added before reference.
- evas_object_box_insert_at(box, child, pos): The child is added at the specified position.
To set the alignment, use evas_object_box_align_set(box, horizontal, vertical).
- horizontal: 0.0 means aligned to the left, 1.0 means to the right;
- vertical: 0.0 means aligned to the top, 1.0 means to the bottom.
Evas has predefined box layouts available:
- evas_object_box_layout_horizontal();
- evas_object_box_layout_vertical();
- evas_object_box_layout_homogeneous_horizontal();
- evas_object_box_layout_homogeneous_vertical();
- evas_object_box_layout_homogeneous_max_size_horizontal();
- evas_object_box_layout_homogeneous_max_size_vertical();
- evas_object_box_layout_flow_horizontal();
- evas_object_box_layout_flow_vertical();
- evas_object_box_layout_stack().
Image Objects
Using Evas, you can create and manipulate image objects. Evas supports image loaders of various formats as plug-in modules.
The image formats that Evas supports include bmp, edj, gif, ico, jpeg, pmaps, png, psd, svg, tga, tiff, wbmp, webp, and xpm.
Figure: Evas image loader
Evas Object Image Functions
Evas has over 70 image object functions. The following functions are discussed in this document:
Evas_Object *evas_object_image_add(Evas *e); void evas_object_image_file_set(Evas_Object *obj, const char *file, const char *key); void evas_object_image_fill_set(Evas_Object *obj, int x, int y, int w, int h); void evas_object_image_filled_set(Evas *e, Eina_Bool setting); Evas_Object *evas_object_image_filled_add(Evas *e); void evas_object_image_smooth_scale_set(Evas_Object *obj, Eina_Bool smoothscale); void evas_object_image_load_size_set(Evas_Object *obj, int w, int h); void evas_object_image_data_set(Evas_Object *obj, void *data); void *evas_object_image_data_get(const Evas_Object *obj, Eina_Bool for_writing); void evas_object_image_size_set(Evas_Object *obj, int w, int h); void evas_object_image_data_update_add(Evas_Object *obj, int x, int y, int w, int h); Eina_Bool evas_object_image_save(const Evas_Object *obj, const char *file, const char *key, const char *flags);
Creating an Image Object and Setting the Image Data Source
A common use case of an image object is to set a file as the image data source. The process has 3 steps and each one involves the following API calls:
- The evas_object_image_add() function creates an image object and returns the pointer.
Evas_Object *evas_object_image_add(Evas *e);
- The evas_object_image_file_set() function sets a source file on the image object. The object fetches the image pixel data from the source file.
void evas_object_image_file_set(Evas_Object *obj, const char *file, const char *key);
- The evas_object_image_fill_set() sets how to fill the image object's area with the given pixel data.
void evas_object_image_fill_set(Evas_Object *obj, int x, int y, int w, int h);
In the following code example, the main() function creates an image object and displays it on a window. The image object size is 300x300 and the source image resolution is 100x127. The image is scaled into 300 by 300 to fill the image object area using the evas_object_image_fill_set() function.
#include <Elementary.h> int main(int argc, char **argv) { elm_init(argc, argv); // Create a window object Evas_Object *win = elm_win_add(NULL, "main", ELM_WIN_BASIC); evas_object_resize(win, 400, 400); evas_object_show(win); // Return Evas handle from window Evas *e = evas_object_evas_get(win); // Create an image object Evas_Object *img = evas_object_image_add(e); // Set a source file to fetch pixel data evas_object_image_file_set(img, "./logo.png", NULL); // Set the size and position of the image on the image object area evas_object_image_fill_set(img, 0, 0, 300, 300); evas_object_move(img, 50, 50); evas_object_resize(img, 300, 300); evas_object_show(img); elm_run(); elm_shutdown(); return 0; }
Figure: Image object display
Image Scaling
Users can decide how to fill the image object area with the given image pixel data by setting the position, width, and height of the image using the evas_object_image_fill_set() function. Without setting this information, the image is not displayed. If the size of the image is bigger than the image object area, only a sub-region of the original image is displayed. If the image is smaller than the area, images are tiled repeatedly to fill the object area.
Figure: Image scaling
evas_object_image_fill_set(obj, 50, 0, 300, 300) | evas_object_image_fill_set(obj, 0, 0, 200, 200) | evas_object_image_fill_set(obj, 0, 0, 100, 127) |
the evas_object_image_filled_set() function scales the image to fit the object area. Resizing the image object automatically triggers an internal call to the evas_object_image_fill_set() function.
void evas_object_image_filled_set(Evas *e, Eina_Bool setting);
The evas_object_image_filled_add() function creates a new image object that automatically scales its bound image to the object area. This is a helper function around the evas_object_image_add() and evas_object_image_filled_set() functions.
Evas_Object *evas_object_image_filled_add(Evas *e);
Scaled images' quality can differ according to scaling algorithms. Smooth scaling improves the image quality in the process of size reducing or enlarging. Evas runs its own smooth scaling algorithm by default and provides an API so users can disable the function.
void evas_object_image_smooth_scale_set(Evas_Object *obj, Eina_Bool smoothscale);
The algorithm is implemented using the SIMD (Single Instruction Multiple Data) vectorization in case of software rendering. It is optimized on Intel and ARM CPU through MMX and NEON command respectively.
There is a trade-off between image smoothness and rendering performance. The load gets bigger as the image gets bigger. Users can avoid such scaling overload by using the same size of the image object and the source image.
In the following code, 2 image objects are created to show the effects of smooth scaling. The one with smooth scaling applied appears softer on the screen.
#include <Elementary.h> int main(int argc, char **argv) { elm_init(argc, argv); // Create a window object Evas_Object *win = elm_win_add(NULL, "main", ELM_WIN_BASIC); evas_object_resize(win, 400, 200); evas_object_show(win); // Return Evas handle from window Evas *e = evas_object_evas_get(win); // Create an image object Evas_Object *img = evas_object_image_filled_add(e); evas_object_image_file_set(img, "./logo.png", NULL); evas_object_move(img, 0, 0); evas_object_resize(img, 200, 200); evas_object_show(img); // Create another image object Evas_Object *img2 = evas_object_image_filled_add(e); evas_object_image_file_set(img2, "./logo.png", NULL); // Disable smooth scaling evas_object_image_smooth_scale_set(img2, EINA_FALSE); evas_object_move(img2, 200, 0); evas_object_resize(img2, 200, 200); evas_object_show(img2); elm_run(); elm_shutdown(); return 0; }
Smooth scaling enabled | Smooth scaling disabled |
Evas caches scaled image data and reuses them. Users can save the memory by loading the image in the scaled size to the memory at the beginning. This option is available only for jpeg format at the moment.
void evas_object_image_load_size_set(Evas_Object *obj, int w, int h);
An example code is as follows.
#include <Elementary.h> int main(int argc, char **argv) { elm_init(argc, argv); // Create a window object Evas_Object *win = elm_win_add(NULL, "main", ELM_WIN_BASIC); evas_object_resize(win, 400, 200); evas_object_show(win); // Return Evas handle from window Evas *e = evas_object_evas_get(win); // Create an image object Evas_Object *img = evas_object_image_filled_add(e); // Load the image scaled into the object size // before evas_object_image_file_set() is called evas_object_image_load_size_set(img, 300, 300); evas_object_image_file_set(img, "./logo.png", NULL); evas_object_move(img, 50, 50); evas_object_resize(img, 300, 300); evas_object_show(img); elm_run(); elm_shutdown(); return 0; }
Setting Raw Data to Image Object
Users can set raw data to the image object manually using the evas_object_image_data_set() function instead of setting an image file as the data source. The image data should be in raw data form. In case of an 200x200 sized image with alpha channel enabled (32 bits per pixel), the size of the image data is 14000 (=200*200*4) bytes.
void evas_object_image_data_set(Evas_Object *obj, void *data);
Image objects fetch metadata such as width or height from the header of the image files. Since the raw data does not have the metadata, users must set the size of the image using the evas_object_image_size_set() function.
void evas_object_image_size_set(Evas_Object *obj, int w, int h);
The evas_object_image_data_get() function returns the data pointer of an image object and requires a parameter to determine whether the data is modified or not. If users pass EINA_TRUE for for_writing, Evas updates the image pixels in the next rendering cycle.
void *evas_object_image_data_get(const Evas_Object *obj, Eina_Bool for_writing);
The evas_object_image_data_update_add() helps to mark the updated area for rendering efficiency.
void evas_object_image_data_update_add(Evas_Object *obj, int x, int y, int w, int h);
The following example code and figure show how to specify the area to update.
evas_object_image_data_update_add(image, 100, 100, 50, 50); evas_object_image_data_update_add(image, 180, 100, 50, 50); evas_object_image_data_update_add(image, 85, 200, 160, 80);
Figure: Partial image update
The following code creates an image object and sets a source file on it. Then it implements the blur effect to the pixel data and saves them using the evas_object_image_save() function.
Eina_Bool evas_object_image_save(const Evas_Object *obj, const char *file, const char *key, const char *flags);
#include <Elementary.h> void image_blur(Evas_Object *img) { unsigned char *img_src = evas_object_image_data_get(img, EINA_TRUE); int w, h; evas_object_image_size_get(img, &w, &h); int blur_size = 4; int x, y, xx, yy; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int avg_color[3] = {0, 0, 0}; int blur_pixel_cnt = 0; for (xx = x; (xx < x + blur_size) && (xx < w); xx++) { for (yy = y; (yy < y + blur_size) && (yy < h); yy++) { int idx = (yy * w * 4) + (xx * 4); avg_color[0] += img_src[idx + 0]; avg_color[1] += img_src[idx + 1]; avg_color[2] += img_src[idx + 2]; ++blur_pixel_cnt; } } avg_color[0] /= blur_pixel_cnt; avg_color[1] /= blur_pixel_cnt; avg_color[2] /= blur_pixel_cnt; for (xx = x; (xx < x + blur_size) && (xx < w); xx++) { for (yy = y; (yy < y + blur_size) && (yy < h); yy++) { int idx = (yy * w * 4) + (xx * 4); img_src[idx + 0] = avg_color[0]; img_src[idx + 1] = avg_color[1]; img_src[idx + 2] = avg_color[2]; } } } } evas_object_image_data_update_add(img, 0, 0, w, h); } int main(int argc, char **argv) { elm_init(argc, argv); Evas_Object *win = elm_win_add(NULL, "main", ELM_WIN_BASIC); evas_object_resize(win, 200, 200); evas_object_show(win); Evas *e = evas_object_evas_get(win); Evas_Object *img = evas_object_image_filled_add(e); evas_object_image_file_set(img, "./logo.png", NULL); evas_object_resize(img, 200, 200); evas_object_show(img); image_blur(img); evas_object_image_save(img, "logo2.png", NULL, "quality=100 compress=8"); elm_run(); elm_shutdown(); return 0; }
Before | After |
Textblock Objects
Unlike basic text objects, a textblock handles complex text, managing multiple styles and multiline text based on HTML-like tags. However, these extra features are heavier on memory and processing cost.
The textblock objects is an object that shows big chunks of text. Textblock supports many features, including text formatting, automatic and manual text alignment, embedding items (icons, for example). Textblock has three important parts: the text paragraphs, the format nodes and the cursors.
To set markup to format text, use for example <font_size=50>Big!</font_size>. Set more than one style directive in one tag with <font_size=50 color=#F00>Big and Red!</font_size>. Please note that we used </font_size> although the format also included color. This is because the first format determines the matching closing tag's name. You can use anonymous tags, such as <font_size=30>Big</>, which pop any type of format, but it is advisable to use the named alternatives instead.
Textblock supports the following formats:
- font: Font description in fontconfig such as format, for example "Sans:style=Italic:lang=hi". or "Serif:style=Bold".
- font_weight: Overrides the weight defined in "font". For example, "font_weight=Bold" is the same as "font=:style=Bold". The supported weights are "normal", "thin", "ultralight", "light", "book", "medium", "semibold", "bold", "ultrabold", "black", and "extrablack".
- font_style: Overrides the style defined in "font". For example, "font_style=Italic" is the same as "font=:style=Italic". The supported styles are "normal", "oblique", and "italic".
- font_width: Overrides the width defined in "font". For example, "font_width=Condensed" is the same as "font=:style=Condensed". The supported widths are "normal", "ultracondensed", "extracondensed", "condensed", "semicondensed", "semiexpanded", "expanded", "extraexpanded", and "ultraexpanded".
- lang: Overrides the language defined in "font". For example, "lang=he" is the same as "font=:lang=he".
- font_fallbacks: A comma delimited list of fonts to try if finding the main font fails.
- font_size: The font size in points.
- font_source: The source of the font, for example an eet file.
- color: The text color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- underline_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- underline2_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- outline_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- shadow_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- glow_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- glow2_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- strikethrough_color: The color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- align: The text alignment in one of the following formats: "auto" (according to text direction), "left", "right", "center" or "middle", which take a value between 0.0 and 1.0 or a value between 0% to 100%.
- valign: The vertical text alignment in one of the following formats: "top", "bottom", "middle", "center", "baseline" or "base", which take a value between 0.0 and 1.0 or a value between 0% to 100%.
- wrap: The text wrap in one of the following formats: "word", "char", "mixed", or "none".
- left_margin: Either "reset" or a pixel value indicating the margin.
- right_margin: Either "reset" or a pixel value indicating the margin.
- underline: The style of underlining in one of the following formats: "on", "off", "single", or "double".
- strikethrough: The style of text that is either "on" or "off".
- backing_color: The background color in one of the following formats: "#RRGGBB", "#RRGGBBAA", "#RGB", or "#RGBA".
- backing: The background color enabled or disabled: "on" or "off".
- style: The style of the text in one of the following formats: "off", "none", "plain", "shadow", "outline", "soft_outline", "outline_shadow", "outline_soft_shadow", "glow", "far_shadow", "soft_shadow" or "far_soft_shadow". The direction is selected by adding "bottom_right", "bottom", "bottom_left", "left", "top_left", "top", "top_right" or "right". For example, "style=shadow,bottom_right".
- tabstops: The pixel value for tab width.
- linesize: To force a line size in pixels.
- linerelsize: Either a floating point value or a percentage indicating the wanted size of the line relative to the calculated size.
- linegap: To force a line gap in pixels.
- linerelgap: Either a floating point value or a percentage indicating the wanted size of the line relative to the calculated size.
- item: Creates an empty space that is filled by an upper layer. Use "size", "abssize", or "relsize" to define the item"s size, and an optional vsize = full/ascent to define the item's position in the line.
- linefill: Either a float value or percentage indicating how much to fill the line.
- ellipsis: A value between 0.0 and 1.0 to indicate the type of ellipsis, or -1.0 to indicate that an ellipsis is not wanted.
- password: Either "on" or "off", this is used to specifically turn replacing chars with the password mode (that is, replacement char) on and off.
Clipping Objects
Limiting Visibility
An Evas object can be clipped – in other words, its visible area is restricted with the clipper object.
It is often necessary to show only parts of an object, and while it may be possible to create an object that corresponds only to the part that must be shown (which is not always possible), it is usually easier to use a clipper. A clipper is a rectangle that defines what is visible and what is not. The way to do this is to create a solid white rectangle (by default, so you need not use evas_object_color_set()) and give it a position and size of what is wanted visible. The following code exemplifies showing the center half of my_evas_object:
Evas_Object *clipper = evas_object_rectangle_add(evas_canvas); evas_object_move(clipper, my_evas_object_x / 4, my_evas_object_y / 4); evas_object_resize(clipper, my_evas_object_width / 2, my_evas_object_height / 2); evas_object_clip_set(my_evas_object, clipper); evas_object_show(clipper);
Layer of Color
A solid white clipper does not produce a change in the color of the clipped object, only hides what is outside the clipper's area. Changing the color of an object is accomplished by using a colored clipper. Clippers with color function by multiplying the colors of the clipped object. The following code shows how to remove all the red from an object.
Evas_Object *clipper = evas_object_rectangle_add(evas); evas_object_move(clipper, my_evas_object_x, my_evas_object_y); evas_object_resize(clipper, my_evas_object_width, my_evas_object_height); evas_object_color_set(clipper, 0, 255, 255, 255); evas_object_clip_set(obj, clipper); evas_object_show(clipper);
Mapping Objects
Evas allows different transformations to be applied to all kinds of objects. These are applied by means of UV mapping. With UV mapping, one map points in the source object to a 3D space positioning at target. This allows rotation, perspective, scale, and many other effects depending on the map that is used.
Creating a Map
A map consists of a set of points, but currently only four are supported. Each of these points contains a set of canvas coordinates x and y that are used to alter the geometry of the mapped object, and a z coordinate that indicates the depth of that point. This last coordinate does not normally affect the map, but is used by several of the utility functions to calculate the right position of the point given other parameters.
The coordinates for each point are set with evas_map_point_coord_set(map, index, x, y, z). In the example below, there is a rectangle whose coordinates are (100, 100) and (300, 300).
Evas_Object *object = evas_object_rectangle_add(evas); evas_object_move(object, 100, 100); evas_object_resize(object, 200, 200); Evas_Map map = evas_map_new(4); evas_map_point_coord_set(map, 0, 100, 100, 0); evas_map_point_coord_set(map, 1, 300, 100, 0); evas_map_point_coord_set(map, 2, 300, 300, 0); evas_map_point_coord_set(map, 3, 100, 300, 0);
There are functions to ease the process.
Use evas_map_util_points_populate_from_geometry(map, x, y, w, h, z), where the map coordinates are set to the given rectangle, and z is the coordinate in the Z axis, which is the same for all points.
Evas_Object *object = evas_object_rectangle_add(evas); evas_object_move(object, 100, 100); evas_object_resize(object, 200, 200); Evas_Map map = evas_map_new(4); evas_map_util_points_populate_from_geometry(map, 100, 100, 200, 200, 0);
You can also use evas_map_util_points_populate_from_object(map, object).
Evas_Object *object = evas_object_rectangle_add(evas); evas_object_move(object, 100, 100); evas_object_resize(object, 200, 200); Evas_Map map = evas_map_new(4); evas_map_util_points_populate_from_object(map, object);
You can also use evas_map_util_points_populate_from_object_full(map, object, z), where z is the coordinate in the Z axis, which is the same for all points.
Evas_Object *object = evas_object_rectangle_add(evas); evas_object_move(object, 100, 100); evas_object_resize(object, 200, 200); Evas_Map map = evas_map_new(4); evas_map_util_points_populate_from_object_full(map, object, 0);
Manual Point Setting
Several effects are applied to an object by setting each point of the map to the right coordinates. For example, a simulated perspective is achieved as follows.
evas_map_point_coord_set(map, 0, 300, 100, 0); evas_map_point_coord_set(map, 1, 450, 120, 0); evas_map_point_coord_set(map, 2, 450, 260, 0); evas_map_point_coord_set(map, 3, 300, 300, 0);
The Z coordinate is not used when setting points by hand; thus its value is not important.
Applying a Map
Regardless of the specific way you create a map, to apply it to a specific object, use
evas_object_map_set(object, map); evas_object_map_enable_set(object, EINA_TRUE);
Basic Utility Functions
Evas provides utility functions for common transformations:
- evas_map_util_rotate(map, angle, cx, cy): This performs a rotation of the angle degrees around the center point with the coordinates (cx, cy).
- evas_map_util_zoom(map, zoomx, zoomy, cx, cy): This performs a zoomx and zoomy zoom in the X and Y directions respectively, with the center point with the coordinates (cx, cy).
For example, the following code rotates an object around its center.
int x, y, w, h; evas_object_geometry_get(object, &x, &y, &w, &h); Evas_Map *map = evas_map_new(4); evas_map_util_points_populate_from_object(map, object); evas_map_util_rotate(map, 45, x + (w / 2), y + (h / 2)); evas_object_map_set(object, map); evas_object_map_enable_set(object, EINA_TRUE); evas_map_free(m);
The following code rotates an object around the center of the window.
int w, h; evas_output_size_get(evas, &w, &h); Evas_Map *map = evas_map_new(4); evas_map_util_points_populate_from_object(map, object); evas_map_util_rotate(map, 45, w / 2, h / 2); evas_object_map_set(object, map); evas_object_map_enable_set(object, EINA_TRUE); evas_map_free(m);
3D Utility Functions
Evas provides utility functions for 3D transformations.
To make a 3D rotation, use evas_map_util_3d_rotate(map, anglex, angley, anglez, cx, cy, cz). With this code, you can set the Z coordinate of the rotation center, and the angles to rotate through around all axes.
Rotating in the 3D space does not look natural. A more natural look becomes by adding perspective to the transformation, which is done with evas_map_util_3d_perspective(map, px, py, z0, focal) on the map after its position has been set.
- px and py specify the "infinite distance" point in the 3D conversion, where all lines converge to.
- z0 specifies the Z value at which there is a 1:1 mapping between spatial coordinates and screen coordinates: any points on this Z value do not have their X and Y coordinates modified in the transform, while those further away (Z value higher) shrink into the distance, and those less than this value expand.
- focal determines the "focal length" of the camera: this is the distance in reality between the camera lens plane (the rendering results are undefined at or closer than this) and the z0 value; this function allows for some "depth" control.
Color and Lighting
Each point in a map can be set to a color, which is multiplied with the object's own color and linearly interpolated in between adjacent points. To do this, use evas_map_point_color_set(map, index, r, g, b, a) for each point of the map, or evas_map_util_points_color_set(map, r, g, b, a) to set every point into the same color.
To add lighting for the objects, which is useful with 3D transforms, use evas_map_util_3d_lighting(map, lightx, lighty, lightz, lightr, lightg, lightb, ambientr, ambientg, ambientb):
- lightx, lighty and lightz are the local light source coordinates;
- lightr, lightg and lightb are the local light source colors;
- ambientr, ambientg and ambientb are the ambient light colors. Evas sets the color of each point based on the distance to the light source, the angle with which the object is facing the light and the ambient light. The orientation of each point is important. If the map is defined counter-clockwise, the object faces away from the user and becomes obscured, since no light does not reflect from it.
Evas Engines Concept
Evas delegates most of the actual rendering work to its engines. Engines are the backends that Evas uses to render (primitive) objects on a canvas. The canvas can be the screen, or a buffer in the memory.
Evas can work with and provides multiple engines, such as (this list is non-exhaustive):
- buffer: all the rendering takes place in a buffer
- fb: the rendering takes place in the system's framebuffer
- software_x11: this is the most used, using X11
- gl_x11: this also renders to an X11 window, except that it uses OpenGL
These implement the rendering of all the basic objects by themselves, because they often can be accelerated by the hardware or backend software libraries to provide fast rendering.
If a particular engine does not have the provision for a certain primitive object, it reverts back to using a default software version.
UI Rendering Mode
Evas removes the need to know about the characteristics of your display system or what graphics calls are used to draw them and how. It deals on an object level where all you do is create and manipulate objects in a canvas, set their properties, and the rest is done for you. This rendering method is called the retained mode, whereas the immediate mode is an alternative rendering method.
Immediate Mode
The immediate mode is the most commonly used in graphics toolkit libraries, such as GTK+, GDI, and GDI+. The application is responsible for repainting the portion of the client area that is invalidated.
Figure: Immediate mode
The application commands any drawing issues as it needs, and the display system draws some GUIs. After the drawing is done, it appears in the destination. This mode allows you to have a exact control over the render cycles. However, if the draw commands are misused, unnecessary drawing can be performed or drawing never happen at all.
The following example explains the common usage of the immediate mode:
void update() { Image *img = load_image(NEW_IMG); // Switch button image to new one update_button_image(img); // Issue the invalidate area (button area) to be redrawn on the screen invalidate_area(button_x, button_y, button_w, button_h); // Move rectangle from (200, 200) to (300, 300) int rect_prev_x = rect_x; int rect_prev_y = rect_y; rectangle_x = 300; rectangle_y = 300; set_rect_position(rect_x, rect_y); // Issue the invalidate area (changed area) to be redrawn on the screen int diff_x = rect_x – rect_prev_x; int diff_y = rect_y – rect_prev_y; invalidate_area(rect_prev_x, rect_prev_y, (rect_w + diff_x), (rect_h + diff_y)); // After setting the invalidate area, request rendering to update the screen render(); // Now you can see how the button image and rectangle position are changed }
Retained Mode
A graphics system adopting the retained mode is basically responsible for responding to all repaint requests for rendering the application objects. Clients do not directly cause actual rendering, but objects are redrawn when parts of them are updated.
Figure: Retained mode
Since Evas works with the retained mode, there is no need to command any drawings. The following example shows how to write a GUI code with Evas for your application:
void create_image() { // Initialize an image object to be displayed on the screen Evas_Object *img = evas_object_image_add(e); // Set image resource evas_object_image_file_set(img, IMG, NULL); // Set image position evas_object_move(img, 100, 100); // Set image size evas_object_resize(img, 200, 200); // Set image visibility (show or hide) evas_object_show(img); } void create_rectangle() { // Initialize an rectangle object to be displayed on the screen Evas_Object *rect = evas_object_rectangle_add(e); // Set rectangle color evas_object_color_set(rect, 255, 0, 0, 255); // Set rectangle position evas_object_move(rect, 200, 200); // Set rectangle size evas_object_resize(rect, 200, 200); // Set rectangle visibility (show or hide) evas_object_show(rect); }
A few main loops later you can replace the image with another one and move the rectangle. You only need to set a new image file to the image object and move the rectangle object. Evas computes the invalidate area and redraws the image and rectangle behind the application when it's on rendering time.
void update() { // Set new image resource elm_image_file_set(img, NEW_IMG, NULL); // Set new rectangle position evas_object_move(rect, 300, 300); }
Evas Rendering
Tizen Native applications work on the ecore main loop, and the loop goes on a few steps for every frame. Evas redraws some changes in the objects when the main loop goes to the idle enterer step. If there are no changes, Evas rendering is skipped. Otherwise, Evas calculates any changed portions of all display objects and redraws them.
Figure: Evas rendering in the main loop
To minimize the rendering, Evas tracks the states of all display objects, such as position, size, visibility, and color. Even if some of these states are changed but the object is hidden by other obscured objects, it is not redrawn. In other words, Evas draws only the necessary changes in the screen.
The following figures illustrate how Evas redraws the changed area:
-
In the first example, there is a blue-color background object (a sky-blue color rectangle) and a partially hidden cloud image object. Above them, there are a red and green rectangle, and the "Hello out there" text is printed on the green rectangle.
Figure: Evas redrawing example 1
-
In the second example, some of the objects have moved (the cloud image is moved to right and the green rectangle is moved downwards).
Figure: Evas redrawing example 2
-
As a result, the third example illustrates some regions that require updates.
Figure: Evas redrawing example 3
-
Evas decides which portions are invalid and to be redrawn. The fourth example shows the cleaned portion of the screen, which is the redrawn area.
Evas redraws the content only in the redrawn portions.
Figure: Evas redrawing example 4
-
Finally, the fifth example shows how the screen is updated and the result is visible.
Figure: Evas redrawing example 5
If Evas worked in an immediate mode style, the application would need to calculate the changed areas themselves, adding extra work. With Evas, you can let Evas figure out the updates and you can yourself concentrate on the application and UI core and logic.