Canvas image: add Efl.Canvas.Text.Factory + use in Ui.Text

This interface has a simple 'create' method to create Efl.Canvas.Object
given a key.
This is used higher-up in Ui.Text in the next commit.

Ui text: add ability to set item factories

Added API to set an item factory object.
This is similar to the previous item providers (that worked with
callbacks).

You instantiate a factory object and set it on the Ui.Text object.
Each factory implements the "create" method from
Efl.Canvas.Text.Item_Factory.

This also includes 3 public factories (Image, Emoticon and Fallback):
  - Image factory: creates images from added entries (key strings)
  - Emoticon factory: creates emoticons by querying the theme
  - Fallback: creates image, then falls back to emoticon

If no factory is set, then the fallback (internal) factory is used.

See the added "Ui.text Item Factory" test in elementary_test for an
example of usage.

@feature
This commit is contained in:
Daniel Hirt 2017-11-09 17:53:20 +02:00 committed by Cedric BAIL
parent 2eac0dd89d
commit 4a905a22a4
21 changed files with 711 additions and 161 deletions

View File

@ -50,7 +50,8 @@ elementary_images_files = \
elementary/images/pm_fill.png \
elementary/images/pt.png \
elementary/images/earth_normal.png \
elementary/images/space.png
elementary/images/space.png \
elementary/images/image_items.eet
elementary_images_glayer_files = \
elementary/images/g_layer/double_tap_1.png \

Binary file not shown.

View File

@ -45,6 +45,9 @@ elm_public_eolian_files = \
lib/elementary/efl_ui_popup_anchor.eo \
lib/elementary/efl_ui_text_editable.eo \
lib/elementary/efl_ui_text_async.eo \
lib/elementary/efl_ui_text_factory_images.eo \
lib/elementary/efl_ui_text_factory_emoticons.eo \
lib/elementary/efl_ui_text_factory_fallback.eo \
lib/elementary/efl_ui_textpath.eo \
lib/elementary/efl_ui_translatable.eo \
lib/elementary/efl_ui_clock.eo \
@ -738,6 +741,9 @@ lib_elementary_libelementary_la_SOURCES = \
lib/elementary/efl_ui_table_static.c \
lib/elementary/efl_ui_table_private.h \
lib/elementary/efl_ui_text.c \
lib/elementary/efl_ui_text_factory_images.c \
lib/elementary/efl_ui_text_factory_emoticons.c \
lib/elementary/efl_ui_text_factory_fallback.c \
lib/elementary/efl_ui_clock.c \
lib/elementary/efl_ui_clock_private.h \
lib/elementary/efl_ui_image_factory.c \

View File

@ -7,6 +7,7 @@ evas_canvas_eolian_pub_files = \
lib/evas/canvas/efl_canvas_polygon.eo \
lib/evas/canvas/efl_canvas_rectangle.eo \
lib/evas/canvas/efl_canvas_text.eo \
lib/evas/canvas/efl_canvas_text_factory.eo \
lib/evas/canvas/efl_canvas_group.eo \
lib/evas/canvas/efl_canvas_image_internal.eo \
lib/evas/canvas/evas_canvas3d_camera.eo\

View File

@ -333,6 +333,7 @@ void test_code_diff_inline(void *data, Evas_Object *obj, void *event_info);
void test_efl_ui_text(void *data, Evas_Object *obj, void *event_info);
void test_efl_ui_text_label(void *data, Evas_Object *obj, void *event_info);
void test_efl_ui_text_async(void *data, Evas_Object *obj, void *event_info);
void test_ui_text_item_factory(void *data, Evas_Object *obj, void *event_info);
void test_evas_mask(void *data, Edje_Object *obj, void *event_info);
void test_gfx_filters(void *data, Evas_Object *obj, void *event_info);
void test_evas_snapshot(void *data, Evas_Object *obj, void *event_info);
@ -834,6 +835,7 @@ add_tests:
ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text", test_efl_ui_text);
ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text Label", test_efl_ui_text_label);
ADD_TEST_EO(NULL, "Entries", "Efl.Ui.Text.Async", test_efl_ui_text_async);
ADD_TEST_EO(NULL, "Entries", "Ui.Text Item Factory", test_ui_text_item_factory);
//------------------------------//
ADD_TEST(NULL, "Advanced Entries", "Code Syntax", test_code_syntax);

View File

@ -144,8 +144,8 @@ static void
my_efl_ui_text_bt_4(void *data, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *en = data;
efl_text_cursor_object_item_insert(en, efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN),
"size=32x32 href=emoticon/evil-laugh");
efl_text_cursor_item_insert(en, efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN),
"emoticon/evil-laugh", "size=32x32");
}
static void
@ -187,6 +187,7 @@ test_efl_ui_text(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
{
Evas_Object *win, *bx, *bx2, *bx3, *bt, *en;
Efl_Text_Cursor_Cursor *main_cur, *cur;
char buf[128];
win = elm_win_util_standard_add("entry", "Entry");
elm_win_autodel_set(win, EINA_TRUE);
@ -215,9 +216,10 @@ test_efl_ui_text(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *eve
cur = efl_text_cursor_new(en);
efl_text_cursor_position_set(en, cur, 2);
efl_text_cursor_object_item_insert(en, cur, "size=32x32 href=emoticon");
efl_text_cursor_item_insert(en, cur, "emoticon/happy", "size=32x32");
efl_text_cursor_position_set(en, cur, 50);
efl_text_cursor_object_item_insert(en, cur, "size=32x32 href=emoticon");
sprintf(buf, "file://%s/images/sky_01.jpg", elm_app_data_dir_get());
efl_text_cursor_item_insert(en, cur, buf, "size=32x32");
efl_text_cursor_position_set(en, main_cur, 5);
efl_text_cursor_position_set(en, cur, 20);
@ -297,7 +299,7 @@ test_efl_ui_text_async(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, voi
elm_win_resize_object_add(win, bx);
evas_object_show(bx);
en = efl_add(EFL_UI_TEXT_ASYNC_CLASS, win,
en = efl_add(EFL_UI_TEXT_CLASS, win,
efl_text_wrap_set(efl_added, EFL_TEXT_FORMAT_WRAP_WORD),
efl_text_multiline_set(efl_added, EINA_TRUE)
);
@ -332,3 +334,196 @@ test_efl_ui_text_async(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, voi
evas_object_resize(win, 480, 320);
evas_object_show(win);
}
#define IMAGES_SZ 5
static const char *images[IMAGES_SZ] = {
"sky", "logo", "dog", "eet_rock", "eet_plant" };
static void
my_efl_ui_text_item_factory_bt_image(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
Evas_Object *en = data;
static int image_idx = 0;
image_idx = (image_idx + 1) % IMAGES_SZ;
efl_text_cursor_item_insert(en,
efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN),
images[image_idx], "size=32x32");
printf("Inserted image: key = %s\n", images[image_idx]);
}
static void
my_efl_ui_text_item_factory_bt_emoticon(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
Evas_Object *en = data;
efl_text_cursor_item_insert(en, efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN),
"emoticon/evil-laugh", "size=32x32");
}
static struct
{
const char *name;
Eo *item_factory;
} factories[3];
static void
my_efl_ui_text_item_factory_bt_change(void *data, Evas_Object *obj EINA_UNUSED,
void *event_info EINA_UNUSED)
{
Evas_Object *en = data;
static int item_factory_idx = 0;
item_factory_idx = (item_factory_idx + 1) % 3;
efl_ui_text_item_factory_set(en, factories[item_factory_idx].item_factory);
printf("Factory set to: %s\n", factories[item_factory_idx].name);
}
#define FACTORY_NONE 0
#define FACTORY_IMAGE 1
#define FACTORY_EMOTICON 2
static void
_ui_text_factory_del(void *data, const Efl_Event *ev EINA_UNUSED)
{
Eina_File *f = data;
eina_file_close(f);
efl_del(factories[FACTORY_IMAGE].item_factory);
efl_del(factories[FACTORY_EMOTICON].item_factory);
}
void
test_ui_text_item_factory(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
{
Evas_Object *win, *bx, *bx2, *bx3, *bt, *en;
Efl_Text_Cursor_Cursor *main_cur, *cur;
char buf[128];
Eina_File *f;
win = elm_win_util_standard_add("entry", "Entry");
elm_win_autodel_set(win, EINA_TRUE);
bx = elm_box_add(win);
evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_win_resize_object_add(win, bx);
evas_object_show(bx);
en = efl_add(EFL_UI_TEXT_CLASS, win,
efl_text_multiline_set(efl_added, EINA_TRUE));
factories[FACTORY_NONE].name = "None (Fallback)";
factories[FACTORY_NONE].item_factory = NULL;
factories[FACTORY_IMAGE].name = "Image Factory";
factories[FACTORY_IMAGE].item_factory =
efl_add(EFL_UI_TEXT_FACTORY_IMAGES_CLASS, win);
factories[FACTORY_EMOTICON].name = "Emoticon Factory";
factories[FACTORY_EMOTICON].item_factory =
efl_add(EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS, win);
// Test assigning file path source
sprintf(buf, "%s/images/sky_01.jpg", elm_app_data_dir_get());
efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory,
images[0], buf, NULL);
sprintf(buf, "%s/images/logo.png", elm_app_data_dir_get());
efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory,
images[1], buf, NULL);
sprintf(buf, "%s/images/mystrale.jpg", elm_app_data_dir_get());
efl_ui_text_factory_images_matches_add(factories[FACTORY_IMAGE].item_factory,
images[2], buf, NULL);
// Open EET source w/ key
sprintf(buf, "%s/images/image_items.eet", elm_app_data_dir_get());
f = eina_file_open(buf, EINA_FALSE);
if (f)
{
efl_event_callback_add(en, EFL_EVENT_DEL, _ui_text_factory_del, f);
efl_ui_text_factory_images_matches_mmap_add(
factories[FACTORY_IMAGE].item_factory,
"eet_rock", f, "rock");
efl_ui_text_factory_images_matches_mmap_add(
factories[FACTORY_IMAGE].item_factory,
"eet_plant", f, "plant");
}
else
{
printf("Error loading test file. Please review test.");
}
printf("Added Efl.Ui.Text object\n");
efl_text_set(en, "Hello world! Goodbye world! This is a test text for the"
" new UI Text widget.\xE2\x80\xA9This is the next paragraph.\nThis"
" is the next line.\nThis is Yet another line! Line and paragraph"
" separators are actually different!");
efl_text_font_set(en, "Sans", 14);
efl_text_normal_color_set(en, 255, 255, 255, 255);
main_cur = efl_text_cursor_get(en, EFL_TEXT_CURSOR_GET_MAIN);
cur = efl_text_cursor_new(en);
efl_text_cursor_position_set(en, cur, 2);
efl_text_cursor_item_insert(en, cur, "emoticon/happy", "size=32x32");
efl_text_cursor_position_set(en, cur, 50);
sprintf(buf, "file://%s/images/sky_01.jpg", elm_app_data_dir_get());
efl_text_cursor_item_insert(en, cur, buf, "size=32x32");
efl_text_cursor_position_set(en, main_cur, 5);
efl_ui_text_interactive_editable_set(en, EINA_TRUE);
efl_ui_text_scrollable_set(en, EINA_TRUE);
elm_box_pack_end(bx, en);
elm_object_focus_set(en, EINA_TRUE);
bx2 = elm_box_add(win);
elm_box_horizontal_set(bx2, EINA_TRUE);
evas_object_size_hint_weight_set(bx2, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(bx2, EVAS_HINT_FILL, EVAS_HINT_FILL);
bt = elm_button_add(win);
elm_object_text_set(bt, "Image");
evas_object_smart_callback_add(bt, "clicked",
my_efl_ui_text_item_factory_bt_image, en);
evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
elm_box_pack_end(bx2, bt);
elm_object_focus_allow_set(bt, EINA_FALSE);
evas_object_show(bt);
bt = elm_button_add(win);
elm_object_text_set(bt, "Emoticon");
evas_object_smart_callback_add(bt, "clicked",
my_efl_ui_text_item_factory_bt_emoticon, en);
evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
elm_box_pack_end(bx2, bt);
elm_object_focus_allow_set(bt, EINA_FALSE);
evas_object_show(bt);
bt = elm_button_add(win);
elm_object_text_set(bt, "Factory");
evas_object_smart_callback_add(bt, "clicked",
my_efl_ui_text_item_factory_bt_change, en);
evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, 0.0);
elm_box_pack_end(bx2, bt);
elm_object_focus_allow_set(bt, EINA_FALSE);
evas_object_show(bt);
bx3 = elm_box_add(win);
elm_box_horizontal_set(bx3, EINA_TRUE);
evas_object_size_hint_weight_set(bx3, EVAS_HINT_EXPAND, 0.0);
evas_object_size_hint_align_set(bx3, EVAS_HINT_FILL, EVAS_HINT_FILL);
elm_box_pack_end(bx, bx3);
elm_box_pack_end(bx, bx2);
evas_object_show(bx3);
evas_object_show(bx2);
evas_object_resize(win, 480, 320);
evas_object_show(win);
}

View File

@ -76,23 +76,6 @@ interface Efl.Text.Annotate {
}
return: bool; [[$true on success, $false otherwise.]]
}
object_item_geometry_get {
[[Queries a given object item for its geometry.
Note that the provided annotation should be an object item type.
@since 1.18
]]
legacy: null;
params {
@in an: ptr(const(Efl.Text.Annotate.Annotation)); [[Given annotation to query]]
@out x: int; [[X coordinate of the annotation]]
@out y: int; [[Y coordinate of the annotation]]
@out w: int; [[Width of the annotation]]
@out h: int; [[Height of the annotation]]
}
return: bool; [[$true if given annotation is an object item, $false otherwise]]
}
annotation_positions_get {
[[Sets given cursors to the start and end positions of the annotation.
@ -111,8 +94,41 @@ interface Efl.Text.Annotate {
position of the annotation in the text]]
}
}
annotation_is_item {
[[Whether this is an "item" type of annotation. Should be used before
querying the annotation's geometry, as only "item" annotations have
a geometry.
see @.cursor_item_insert
see @.item_geometry_get
@since 1.21
]]
legacy: null;
params {
annotation: ptr(Efl.Text.Annotate.Annotation); [[Given annotation]]
}
return: bool; [[$true if given annotation is an object item, $false otherwise]]
}
item_geometry_get {
[[Queries a given object item for its geometry.
Note that the provided annotation should be an object item type.
@since 1.18
]]
legacy: null;
params {
@in an: ptr(const(Efl.Text.Annotate.Annotation)); [[Given annotation to query]]
@out x: int; [[X coordinate of the annotation]]
@out y: int; [[Y coordinate of the annotation]]
@out w: int; [[Width of the annotation]]
@out h: int; [[Height of the annotation]]
}
return: bool; [[$true if given annotation is an object item, $false otherwise]]
}
// Cursor
@property cursor_object_item_annotation {
@property cursor_item_annotation {
[[The object-item annotation at the cursor's position.]]
get {
legacy: null;
@ -124,7 +140,7 @@ interface Efl.Text.Annotate {
cur: ptr(Efl.Text.Cursor.Cursor); [[Cursor object]]
}
}
cursor_object_item_insert {
cursor_item_insert {
[[Inserts a object item at specified position.
This adds a placeholder to be queried by higher-level code,
@ -134,8 +150,11 @@ interface Efl.Text.Annotate {
legacy: null;
params {
cur: ptr(Efl.Text.Cursor.Cursor); [[Cursor object]]
@in format: string; [[Format of the inserted item.
See Format styles.]]
@in item: string; [[Item key to be used in higher-up
code to query and decided what image, emoticon
etc. to embed.]]
@in format: string; [[Size format of the inserted item.
This hints how to size the item in the text.]]
}
return: ptr(Efl.Text.Annotate.Annotation); [[The annotation handle of the
inserted item.]]

View File

@ -311,6 +311,9 @@ typedef Eo Efl_Ui_Focus_Manager;
# include <efl_ui_popup_alert_scroll.eo.h>
# include <efl_ui_popup_alert_text.eo.h>
# include <efl_ui_popup_anchor.eo.h>
# include <efl_ui_text_factory_images.eo.h>
# include <efl_ui_text_factory_emoticons.eo.h>
# include <efl_ui_text_factory_fallback.eo.h>
# include <efl_ui_text_editable.eo.h>
# include <efl_ui_text_async.eo.h>
# include <efl_ui_clock.eo.h>

View File

@ -63,7 +63,8 @@ struct _Efl_Ui_Text_Data
Eina_List *sel;
Eina_List *items; /** context menu item list */
Item_Obj *item_objs;
Eina_List *item_providers;
Efl_Canvas_Text_Factory *item_factory;
Efl_Canvas_Text_Factory *item_fallback_factory;
Eina_List *markup_filters;
Ecore_Job *hov_deljob;
Mod_Api *api; // module api if supplied
@ -131,6 +132,7 @@ struct _Efl_Ui_Text_Data
Eina_Bool scroll : 1;
Eina_Bool input_panel_show_on_demand : 1;
Eina_Bool anchors_updated : 1;
Eina_Bool fallback_item_provider_disabled : 1;
};
struct _Anchor
@ -2485,43 +2487,22 @@ _entry_mouse_triple_signal_cb(void *data,
static Evas_Object *
_item_get(void *data, const char *item)
{
Eina_List *l;
Evas_Object *o;
Elm_Entry_Item_Provider *ip;
const char *style = elm_widget_style_get(data);
Evas_Object *o = NULL;
EFL_UI_TEXT_DATA_GET(data, sd);
EINA_LIST_FOREACH(sd->item_providers, l, ip)
if (item)
{
o = ip->func(ip->data, data, item);
if (o) return o;
}
if (item && !strncmp(item, "file://", 7))
{
const char *fname = item + 7;
o = evas_object_image_filled_add(evas_object_evas_get(data));
evas_object_image_file_set(o, fname, NULL);
if (evas_object_image_load_error_get(o) == EVAS_LOAD_ERROR_NONE)
if (sd->item_factory)
{
evas_object_show(o);
o = efl_canvas_text_factory_create(sd->item_factory, data, item);
}
else
else if (sd->item_fallback_factory)
{
evas_object_del(o);
o = edje_object_add(evas_object_evas_get(data));
elm_widget_theme_object_set
(data, o, "text/emoticon", "wtf", style);
o = efl_canvas_text_factory_create(sd->item_fallback_factory,
data, item);
}
return o;
}
o = edje_object_add(evas_object_evas_get(data));
if (!elm_widget_theme_object_set
(data, o, "text", item, style))
elm_widget_theme_object_set
(data, o, "text/emoticon", "wtf", style);
return o;
}
@ -3215,6 +3196,7 @@ _efl_ui_text_efl_object_constructor(Eo *obj, Efl_Ui_Text_Data *sd)
if (_elm_config->desktop_entry)
sd->sel_handler_disabled = EINA_TRUE;
sd->item_fallback_factory = efl_add(EFL_UI_TEXT_FACTORY_FALLBACK_CLASS, obj);
_create_text_cursors(obj, sd);
return obj;
@ -3224,7 +3206,6 @@ EOLIAN static void
_efl_ui_text_efl_object_destructor(Eo *obj, Efl_Ui_Text_Data *sd)
{
Elm_Entry_Context_Menu_Item *it;
Elm_Entry_Item_Provider *ip;
Elm_Entry_Markup_Filter *tf;
Eo *text_obj;
@ -3270,10 +3251,6 @@ _efl_ui_text_efl_object_destructor(Eo *obj, Efl_Ui_Text_Data *sd)
eina_stringshare_del(it->icon_group);
free(it);
}
EINA_LIST_FREE(sd->item_providers, ip)
{
free(ip);
}
EINA_LIST_FREE(sd->markup_filters, tf)
{
_filter_free(tf);
@ -3314,6 +3291,9 @@ _efl_ui_text_efl_object_destructor(Eo *obj, Efl_Ui_Text_Data *sd)
ecore_job_del(sd->deferred_decoration_job);
sd->deferred_decoration_job = NULL;
if (sd->item_factory) efl_unref(sd->item_factory);
if (sd->item_fallback_factory) efl_del(sd->item_fallback_factory);
efl_destructor(efl_super(obj, MY_CLASS));
}
@ -3539,55 +3519,6 @@ _efl_ui_text_context_menu_disabled_get(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd
return !sd->context_menu;
}
EOLIAN static void
_efl_ui_text_item_provider_append(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd, Elm_Entry_Item_Provider_Cb func, void *data)
{
Elm_Entry_Item_Provider *ip;
EINA_SAFETY_ON_NULL_RETURN(func);
ip = calloc(1, sizeof(Elm_Entry_Item_Provider));
if (!ip) return;
ip->func = func;
ip->data = data;
sd->item_providers = eina_list_append(sd->item_providers, ip);
}
EOLIAN static void
_efl_ui_text_item_provider_prepend(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd, Elm_Entry_Item_Provider_Cb func, void *data)
{
Elm_Entry_Item_Provider *ip;
EINA_SAFETY_ON_NULL_RETURN(func);
ip = calloc(1, sizeof(Elm_Entry_Item_Provider));
if (!ip) return;
ip->func = func;
ip->data = data;
sd->item_providers = eina_list_prepend(sd->item_providers, ip);
}
EOLIAN static void
_efl_ui_text_item_provider_remove(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *sd, Elm_Entry_Item_Provider_Cb func, void *data)
{
Eina_List *l;
Elm_Entry_Item_Provider *ip;
EINA_SAFETY_ON_NULL_RETURN(func);
EINA_LIST_FOREACH(sd->item_providers, l, ip)
{
if ((ip->func == func) && ((!data) || (ip->data == data)))
{
sd->item_providers = eina_list_remove_list(sd->item_providers, l);
free(ip);
return;
}
}
}
EOLIAN static Eina_Bool
_efl_ui_text_efl_file_file_set(Eo *obj, Efl_Ui_Text_Data *sd, const char *file, const char *group EINA_UNUSED)
{
@ -4927,8 +4858,7 @@ _anchors_create(Eo *obj, Efl_Ui_Text_Data *sd)
Eina_Bool is_anchor = EINA_FALSE;
Eina_Bool is_item = EINA_FALSE;
if (efl_text_object_item_geometry_get(obj, anchor,
NULL, NULL, NULL, NULL))
if (efl_text_annotation_is_item(obj, anchor))
{
is_anchor = EINA_TRUE;
is_item = EINA_TRUE;
@ -5052,7 +4982,7 @@ _anchors_update(Eo *o, Efl_Ui_Text_Data *sd)
{
rect->obj = ob;
efl_text_object_item_geometry_get(an->obj,
efl_text_item_geometry_get(an->obj,
an->annotation, &cx, &cy, &cw, &ch);
evas_object_move(rect->obj, x + cx, y + cy);
evas_object_resize(rect->obj, cw, ch);
@ -5296,6 +5226,20 @@ _efl_ui_text_move_cb(void *data, Evas *e EINA_UNUSED,
_decoration_defer_all(data);
}
static void
_efl_ui_text_item_factory_set(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *pd,
Efl_Canvas_Text_Factory *item_factory)
{
if (pd->item_factory) efl_unref(pd->item_factory);
pd->item_factory = efl_ref(item_factory);
}
static Eo *
_efl_ui_text_item_factory_get(Eo *obj EINA_UNUSED, Efl_Ui_Text_Data *pd)
{
return pd->item_factory;
}
#if 0
/* Efl.Part begin */

View File

@ -233,13 +233,12 @@ class Efl.Ui.Text (Efl.Ui.Layout, Elm.Interface_Scrollable, Efl.Ui.Clickable,
enabled: bool; [[If $enabled is $true, the return key is automatically disabled when the entry has no text.]]
}
}
item_provider_prepend {
[[This prepends a custom item provider to the list for that entry
This prepends the given callback.]]
params {
@in func: Elm_Entry_Item_Provider_Cb; [[The function called to provide the item object.]]
@in data: void_ptr @optional; [[The data passed to $func.]]
@property item_factory {
[[The factory that provides item in the text e.g.
"emoticon/happy" or "href=file://image.jpg" etc.
]]
values {
item_factory: Efl.Canvas.Text.Factory; [[Factory to create items]]
}
}
input_panel_show {
@ -252,17 +251,6 @@ class Efl.Ui.Text (Efl.Ui.Layout, Elm.Interface_Scrollable, Efl.Ui.Clickable,
selection_copy {
[[This executes a "copy" action on the selected text in the entry.]]
}
item_provider_remove {
[[This removes a custom item provider to the list for that entry
This removes the given callback. See @.item_provider_append for
more information
]]
params {
@in func: Elm_Entry_Item_Provider_Cb; [[The function called to provide the item object.]]
@in data: void_ptr @optional; [[The data passed to $func.]]
}
}
context_menu_clear {
[[This clears and frees the items in a entry's contextual (longpress)
menu.
@ -306,23 +294,6 @@ class Efl.Ui.Text (Efl.Ui.Layout, Elm.Interface_Scrollable, Efl.Ui.Clickable,
selection_cut {
[[This executes a "cut" action on the selected text in the entry.]]
}
item_provider_append {
[[This appends a custom item provider to the list for that entry
This appends the given callback. The list is walked from beginning to end
with each function called given the item href string in the text. If the
function returns an object handle other than $null (it should create an
object to do this), then this object is used to replace that item. If
not the next provider is called until one provides an item object, or the
default provider in entry does.
See also \@ref entry-items.
]]
params {
@in func: Elm_Entry_Item_Provider_Cb; [[The function called to provide the item object.]]
@in data: void_ptr @optional; [[The data passed to $func.]]
}
}
context_menu_item_add {
[[This adds an item to the entry's contextual menu.

View File

@ -0,0 +1,52 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include <Elementary_Cursor.h>
#include "elm_priv.h"
#define MY_CLASS EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS
typedef struct _Efl_Ui_Text_Factory_Emoticons_Data Efl_Ui_Text_Factory_Emoticons_Data;
struct _Efl_Ui_Text_Factory_Emoticons_Data
{
const char *name;
};
EOLIAN static Eo *
_efl_ui_text_factory_emoticons_efl_object_constructor(Eo *obj,
Efl_Ui_Text_Factory_Emoticons_Data *pd EINA_UNUSED)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
return obj;
}
EOLIAN static void
_efl_ui_text_factory_emoticons_efl_object_destructor(Eo *obj,
Efl_Ui_Text_Factory_Emoticons_Data *pd EINA_UNUSED)
{
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Canvas_Object
*_efl_ui_text_factory_emoticons_efl_canvas_text_factory_create(
Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Emoticons_Data *pd EINA_UNUSED,
Efl_Canvas_Object *object,
const char *key)
{
Eo *o;
const char *style = elm_widget_style_get(object);
o = edje_object_add(evas_object_evas_get(object));
if (!_elm_theme_object_set
(object, o, "text", key, style))
_elm_theme_object_set
(object, o, "text/emoticon", "wtf", style);
return o;
}
#include "efl_ui_text_factory_emoticons.eo.c"

View File

@ -0,0 +1,12 @@
class Efl.Ui.Text.Factory.Emoticons (Efl.Object, Efl.Canvas.Text.Factory)
{
[[Factory that creates emoticons from the current theme given a key.
@since 1.21
]]
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Canvas.Text.Factory.create;
}
}

View File

@ -0,0 +1,62 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include <Elementary_Cursor.h>
#include "elm_priv.h"
#define MY_CLASS EFL_UI_TEXT_FACTORY_FALLBACK_CLASS
typedef struct _Efl_Ui_Text_Factory_Fallback_Data Efl_Ui_Text_Factory_Fallback_Data;
struct _Efl_Ui_Text_Factory_Fallback_Data
{
Efl_Canvas_Text_Factory *emoticon_factory, *image_factory;
};
EOLIAN static Eo *
_efl_ui_text_factory_fallback_efl_object_constructor(Eo *obj,
Efl_Ui_Text_Factory_Fallback_Data *pd EINA_UNUSED)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
pd->image_factory = efl_add(EFL_UI_TEXT_FACTORY_IMAGES_CLASS, obj);
pd->emoticon_factory = efl_add(EFL_UI_TEXT_FACTORY_EMOTICONS_CLASS, obj);
return obj;
}
EOLIAN static void
_efl_ui_text_factory_fallback_efl_object_destructor(Eo *obj,
Efl_Ui_Text_Factory_Fallback_Data *pd EINA_UNUSED)
{
efl_del(pd->emoticon_factory);
efl_del(pd->image_factory);
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Canvas_Object
*_efl_ui_text_factory_fallback_efl_canvas_text_factory_create(
Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Fallback_Data *pd EINA_UNUSED,
Efl_Canvas_Object *object,
const char *key)
{
Efl_Canvas_Object *o = NULL;
// Parse the string. Can be either:
// 1. some/name - an emoticon (load from theme)
// 2. file:// - image file
if (key && !strncmp(key, "file://", 7))
{
const char *fname = key + 7;
o = efl_canvas_text_factory_create(pd->image_factory, object, fname);
}
else
{
o = efl_canvas_text_factory_create(pd->emoticon_factory, object, key);
}
return o;
}
#include "efl_ui_text_factory_fallback.eo.c"

View File

@ -0,0 +1,16 @@
class Efl.Ui.Text.Factory.Fallback (Efl.Object, Efl.Canvas.Text.Factory)
{
[[Internal factory for fallback cases.
This wraps some internal functionality:
- Contains 2 factories: image and emoticon
- Strips off "file://" prefix for image items, to be used with the image
factory.
@since 1.21
]]
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Canvas.Text.Factory.create;
}
}

View File

@ -0,0 +1,147 @@
#ifdef HAVE_CONFIG_H
# include "elementary_config.h"
#endif
#include <Elementary.h>
#include <Elementary_Cursor.h>
#include "elm_priv.h"
#define MY_CLASS EFL_UI_TEXT_FACTORY_IMAGES_CLASS
typedef struct _Efl_Ui_Text_Factory_Images_Data Efl_Ui_Text_Factory_Images_Data;
struct _Efl_Ui_Text_Factory_Images_Data
{
const char *name;
Eina_Hash *hash;
};
typedef struct
{
Eina_File *file;
const char *key;
} File_Entry;
static void
_entry_free_cb(void *data)
{
File_Entry *e = data;
eina_file_close(e->file);
eina_stringshare_del(e->key);
free(e);
}
EOLIAN static Eo *
_efl_ui_text_factory_images_efl_object_constructor(Eo *obj,
Efl_Ui_Text_Factory_Images_Data *pd EINA_UNUSED)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
pd->hash = eina_hash_string_superfast_new(_entry_free_cb);
return obj;
}
EOLIAN static void
_efl_ui_text_factory_images_efl_object_destructor(Eo *obj,
Efl_Ui_Text_Factory_Images_Data *pd EINA_UNUSED)
{
eina_hash_free(pd->hash);
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Efl_Canvas_Object *
_efl_ui_text_factory_images_efl_canvas_text_factory_create(Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Images_Data *pd EINA_UNUSED,
Efl_Canvas_Object *object,
const char *key)
{
Efl_Canvas_Object *o;
File_Entry *e;
o = efl_add(EFL_CANVAS_IMAGE_CLASS, object);
e = eina_hash_find(pd->hash, key);
if (e)
{
efl_file_mmap_set(o, e->file, e->key);
}
else
{
efl_file_set(o, key, NULL);
}
if (efl_file_load_error_get(o) != EFL_IMAGE_LOAD_ERROR_NONE)
{
efl_del(o);
o = NULL;
}
return o;
}
EOLIAN static Eina_Bool
_efl_ui_text_factory_images_matches_add(Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Images_Data *pd,
const char *name, const char *file, const char *key)
{
File_Entry *e;
Eina_File *f = eina_file_open(file, EINA_FALSE);
if (!f) return EINA_FALSE;
e = malloc(sizeof(*e));
e->file = f;
e->key = eina_stringshare_add(key);
if (!eina_hash_add(pd->hash, name, e))
{
ERR("Failed to add file path %s to key %s\n", file, key);
eina_file_close(f);
free(e);
return EINA_FALSE;
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_text_factory_images_matches_del(Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Images_Data *pd,
const char *name)
{
return eina_hash_del(pd->hash, name, NULL);
}
EOLIAN static Eina_Bool
_efl_ui_text_factory_images_matches_mmap_add(Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Images_Data *pd,
const char *name, const Eina_File *file, const char *key)
{
File_Entry *e;
Eina_File *f;
if (!file) return EINA_FALSE;
f = eina_file_dup(file);
e = malloc(sizeof(*e));
e->file = f;
e->key = eina_stringshare_add(key);
if (!eina_hash_add(pd->hash, name, e))
{
ERR("Failed to add Eina_File %p to key %s\n", file, key);
eina_file_close(f);
free(e);
return EINA_FALSE;
}
return EINA_TRUE;
}
EOLIAN static Eina_Bool
_efl_ui_text_factory_images_matches_mmap_del(Eo *obj EINA_UNUSED,
Efl_Ui_Text_Factory_Images_Data *pd,
const char *name)
{
return eina_hash_del(pd->hash, name, NULL);
}
#include "efl_ui_text_factory_images.eo.c"

View File

@ -0,0 +1,69 @@
class Efl.Ui.Text.Factory.Images (Efl.Object, Efl.Canvas.Text.Factory)
{
[[Factory that creates images given key string
The key can be either a full image path, or associated with one. The
factory will fallback if key was not matches with an image, and try
to load it as a full path.
@since 1.21
]]
methods {
matches_add {
[[Associates given name with a path of an image or EET file.
This can be used for quick retrieval (instead of
providing actual filenames.
This $file is associated with $name is considered a full file path.
see @.matches_mmap_add for mmap version
see @.matches_del
]]
params {
name: string; [[the name associated with filename]]
path: string; [[the image or EET file path]]
key: string; [[the key to use (in cases of loading an EET file]]
}
return: bool; [[$true if successful, $false otherwise]]
}
matches_del {
[[Deletes an association of $key with its respective file path.
see @.matches_add
]]
params {
key: string; [[the entry's key to delete]]
}
return: bool; [[$true if successful, $false otherwise]]
}
matches_mmap_add {
[[Associates given name with a mmap'd image or EET file and key.
see @.matches_add for string file path version
see @.matches_mmap_del
]]
params {
name: string; [[the name associated with filename]]
file: ptr(const(Eina.File)); [[the image or EET file]]
key: string; [[the key to use (in cases of loading an EET file]]
}
return: bool; [[$true if successful, $false otherwise]]
}
matches_mmap_del {
[[Deletes an association of $key with its respective file.
see @.matches_mmap_add
]]
params {
key: string; [[the entry's key to delete]]
}
return: bool; [[$true if successful, $false otherwise]]
}
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Canvas.Text.Factory.create;
}
}

View File

@ -21,6 +21,7 @@
*/
//#include "canvas/efl_canvas_text_cursor.eo.h"
#include "canvas/efl_canvas_text.eo.h"
#include "canvas/efl_canvas_text_factory.eo.h"
/**
* @}
*/

View File

@ -345,10 +345,11 @@ class Efl.Canvas.Text (Efl.Canvas.Object, Efl.Text, Efl.Text.Properties,
Efl.Text.Annotate.range_annotations_get;
Efl.Text.Annotate.annotation_insert;
Efl.Text.Annotate.annotation_del;
Efl.Text.Annotate.object_item_geometry_get;
Efl.Text.Annotate.annotation_is_item;
Efl.Text.Annotate.item_geometry_get;
Efl.Text.Annotate.annotation_positions_get;
Efl.Text.Annotate.cursor_object_item_annotation { get; }
Efl.Text.Annotate.cursor_object_item_insert;
Efl.Text.Annotate.cursor_item_annotation { get; }
Efl.Text.Annotate.cursor_item_insert;
Efl.Text.Markup.markup { set; get; }
Efl.Text.Markup.cursor_markup_insert;
Efl.Gfx.scale { set; }

View File

@ -0,0 +1,25 @@
interface Efl.Canvas.Text.Factory ()
{
[[Object factory that creates Efl.Canvas.Object objects.
Translates a given key to an object (item), to be later placed in a text
for higher level usages. The translation implementation is left to be
decided by the inheriting class, whether it is by treating the $key as an
image path, or a key associated with a real-path in a hashtable
or something else entirely.
@since 1.21
]]
methods {
create {
[[Translates a given $key to an item object, and returns the object.
The returned object should be owned by the passed $object.
]]
params {
object: Efl.Canvas.Object; [[The parent of the created object]]
key: string; [[Key that is associated to an item object]]
}
return: Efl.Canvas.Object @owned;
}
}
}

View File

@ -15123,16 +15123,24 @@ _efl_canvas_text_efl_text_annotate_range_annotations_get(Eo *eo_obj EINA_UNUSED,
}
EOLIAN static Efl_Text_Annotate_Annotation *
_efl_canvas_text_efl_text_annotate_cursor_object_item_insert(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Cursor *cur, const char *format)
_efl_canvas_text_efl_text_annotate_cursor_item_insert(Eo *eo_obj,
Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Cursor *cur,
const char *item, const char *format)
{
Eina_Strbuf *buf = eina_strbuf_new();
eina_strbuf_append_printf(buf, "%s href=%s", format, item);
Efl_Text_Annotate_Annotation *ret =
_textblock_annotation_insert(cur->obj, o, cur, cur, format, EINA_TRUE);
_textblock_annotation_insert(cur->obj, o, cur, cur,
eina_strbuf_string_get(buf), EINA_TRUE);
eina_strbuf_free(buf);
efl_event_callback_legacy_call(eo_obj, EFL_CANVAS_TEXT_EVENT_CHANGED, NULL);
return ret;
}
EOLIAN static Efl_Text_Annotate_Annotation *
_efl_canvas_text_efl_text_annotate_cursor_object_item_annotation_get(Eo *eo_obj EINA_UNUSED,
_efl_canvas_text_efl_text_annotate_cursor_item_annotation_get(Eo *eo_obj EINA_UNUSED,
Efl_Canvas_Text_Data *o EINA_UNUSED, Efl_Text_Cursor_Cursor *cur)
{
Eina_Iterator *it;
@ -15153,7 +15161,21 @@ _efl_canvas_text_efl_text_annotate_cursor_object_item_annotation_get(Eo *eo_obj
}
EOLIAN static Eina_Bool
_efl_canvas_text_efl_text_annotate_object_item_geometry_get(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED,
_efl_canvas_text_efl_text_annotate_annotation_is_item(Eo *eo_obj EINA_UNUSED,
Efl_Canvas_Text_Data *o EINA_UNUSED,
Efl_Text_Annotate_Annotation *annotation)
{
if (!annotation || (annotation->obj != eo_obj))
{
ERR("Used invalid handle or of a different object");
return EINA_FALSE;
}
return annotation->is_item;
}
EOLIAN static Eina_Bool
_efl_canvas_text_efl_text_annotate_item_geometry_get(Eo *eo_obj, Efl_Canvas_Text_Data *o EINA_UNUSED,
const Efl_Text_Annotate_Annotation *an, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
{
Efl_Text_Cursor_Cursor cur;
@ -16264,3 +16286,4 @@ _efl_canvas_text_async_layout(Eo *eo_obj EINA_UNUSED, Efl_Canvas_Text_Data *o)
}
#include "canvas/efl_canvas_text.eo.c"
#include "canvas/efl_canvas_text_factory.eo.c" // interface

View File

@ -4371,8 +4371,8 @@ START_TEST(evas_textblock_annotation)
/* Check "item" annotations */
efl_text_set(tb, "abcd");
evas_textblock_cursor_pos_set(cur, 4);
an = efl_text_cursor_object_item_insert(tb, cur, "size=16x16");
_test_check_annotation(tb, 4, 4, _COMP_PARAMS("size=16x16"));
an = efl_text_cursor_item_insert(tb, cur, "", "size=16x16");
_test_check_annotation(tb, 4, 4, _COMP_PARAMS("size=16x16 href="));
/* Check that format is not extended if it's an "object item" */
evas_textblock_cursor_pos_set(cur, 5);
@ -4417,14 +4417,14 @@ START_TEST(evas_textblock_annotation)
/* Test getting of object item */
evas_textblock_cursor_pos_set(cur, 4);
an = efl_text_cursor_object_item_annotation_get(tb, cur);
an = efl_text_cursor_item_annotation_get(tb, cur);
ck_assert(!an);
an = efl_text_cursor_object_item_insert(tb, cur, "size=16x16");
an = efl_text_cursor_item_insert(tb, cur, "", "size=16x16");
evas_textblock_cursor_pos_set(cur, 4);
an = efl_text_cursor_object_item_annotation_get(tb, cur);
an = efl_text_cursor_item_annotation_get(tb, cur);
ck_assert(an);
ck_assert_str_eq("size=16x16", efl_text_annotation_get(tb, an));
ck_assert_str_eq("size=16x16 href=", efl_text_annotation_get(tb, an));
END_TB_TEST();
}