From e105646041545ee3c8a0acc3cbac73dc36ed9e95 Mon Sep 17 00:00:00 2001 From: Jeeyong Um Date: Tue, 25 Apr 2017 16:25:11 -0700 Subject: [PATCH] edje_cc: introduce "Anchors" - easy way to set parts relationship Test Plan: compile src/examples/edc-anchors.c and run Reviewers: zmike, raster, cedric, jpeg Reviewed By: raster, jpeg Subscribers: raster, barbieri, zmike, SanghyeonLee, taxi2se, Jaehyun_Cho Differential Revision: https://phab.enlightenment.org/D4775 Signed-off-by: Cedric BAIL --- src/bin/edje/edje_cc.h | 38 ++ src/bin/edje/edje_cc_handlers.c | 601 +++++++++++++++++++++++++++++ src/examples/edje/edje-anchors.c | 58 +++ src/examples/edje/edje-anchors.edc | 58 +++ src/lib/edje/edje_calc.c | 48 ++- src/lib/edje/edje_data.c | 4 +- src/lib/edje/edje_private.h | 2 + 7 files changed, 799 insertions(+), 10 deletions(-) create mode 100644 src/examples/edje/edje-anchors.c create mode 100644 src/examples/edje/edje-anchors.edc diff --git a/src/bin/edje/edje_cc.h b/src/bin/edje/edje_cc.h index 9e47283dde..704a7fbdd5 100644 --- a/src/bin/edje/edje_cc.h +++ b/src/bin/edje/edje_cc.h @@ -164,6 +164,44 @@ struct _Edje_Part_Collection_Parser Eina_Bool inherit_only; }; +typedef enum +{ + EDJE_PART_ANCHOR_LINE_NONE, + EDJE_PART_ANCHOR_LINE_TOP, + EDJE_PART_ANCHOR_LINE_BOTTOM, + EDJE_PART_ANCHOR_LINE_LEFT, + EDJE_PART_ANCHOR_LINE_RIGHT, + EDJE_PART_ANCHOR_LINE_VERTICAL_CENTER, + EDJE_PART_ANCHOR_LINE_HORIZONTAL_CENTER +} Edje_Part_Anchor_Line; + +typedef enum +{ + EDJE_PART_ANCHOR_FILL_BOTH, + EDJE_PART_ANCHOR_FILL_HORIZONTAL, + EDJE_PART_ANCHOR_FILL_VERTICAL +} Edje_Part_Anchor_Fill; + +typedef struct +{ + union { + Edje_Part_Anchor_Line line; + Edje_Part_Anchor_Fill fill; + } base; + Eina_Bool set : 1; +} Edje_Part_Anchor; + +typedef struct +{ + Edje_Part_Anchor top; + Edje_Part_Anchor bottom; + Edje_Part_Anchor left; + Edje_Part_Anchor right; + Edje_Part_Anchor vertical_center; + Edje_Part_Anchor horizontal_center; + Edje_Part_Anchor fill; +} Edje_Part_Description_Anchors; + /* global fn calls */ void data_setup(void); void data_write(void); diff --git a/src/bin/edje/edje_cc_handlers.c b/src/bin/edje/edje_cc_handlers.c index 8c80b19c60..b38ddec37a 100644 --- a/src/bin/edje/edje_cc_handlers.c +++ b/src/bin/edje/edje_cc_handlers.c @@ -167,6 +167,8 @@ Eina_Bool script_override = EINA_FALSE; static Edje_Program *sequencing = NULL; static Eina_List *sequencing_lookups = NULL; static int *anonymous_delete = NULL; +static Edje_Part_Description_Anchors *current_anchors = NULL; +static Eina_Bool has_relatives = EINA_FALSE; Eina_List *po_files; @@ -195,6 +197,8 @@ static void _program_target_add(char *name); static void _program_after(const char *name); static void _program_free(Edje_Program *pr); +static void check_has_anchors(void); + static void st_externals_external(void); static void st_images_image(void); @@ -367,6 +371,14 @@ static void st_collections_group_parts_part_description_rel2_to_set(const char * static void st_collections_group_parts_part_description_rel2_to(void); static void st_collections_group_parts_part_description_rel2_to_x(void); static void st_collections_group_parts_part_description_rel2_to_y(void); +static void st_collections_group_parts_part_description_anchors_top(void); +static void st_collections_group_parts_part_description_anchors_bottom(void); +static void st_collections_group_parts_part_description_anchors_left(void); +static void st_collections_group_parts_part_description_anchors_right(void); +static void st_collections_group_parts_part_description_anchors_vertical_center(void); +static void st_collections_group_parts_part_description_anchors_horizontal_center(void); +static void st_collections_group_parts_part_description_anchors_fill(void); +static void st_collections_group_parts_part_description_anchors_margin(void); static void st_collections_group_parts_part_description_clip_to_id(void); static void st_collections_group_parts_part_description_size_class(void); static void st_collections_group_parts_part_description_image_normal(void); @@ -858,6 +870,14 @@ New_Statement_Handler statement_handlers[] = {"collections.group.parts.part.description.rel2.to", st_collections_group_parts_part_description_rel2_to}, {"collections.group.parts.part.description.rel2.to_x", st_collections_group_parts_part_description_rel2_to_x}, {"collections.group.parts.part.description.rel2.to_y", st_collections_group_parts_part_description_rel2_to_y}, + {"collections.group.parts.part.description.anchors.top", st_collections_group_parts_part_description_anchors_top}, + {"collections.group.parts.part.description.anchors.bottom", st_collections_group_parts_part_description_anchors_bottom}, + {"collections.group.parts.part.description.anchors.left", st_collections_group_parts_part_description_anchors_left}, + {"collections.group.parts.part.description.anchors.right", st_collections_group_parts_part_description_anchors_right}, + {"collections.group.parts.part.description.anchors.vertical_center", st_collections_group_parts_part_description_anchors_vertical_center}, + {"collections.group.parts.part.description.anchors.horizontal_center", st_collections_group_parts_part_description_anchors_horizontal_center}, + {"collections.group.parts.part.description.anchors.fill", st_collections_group_parts_part_description_anchors_fill}, + {"collections.group.parts.part.description.anchors.margin", st_collections_group_parts_part_description_anchors_margin}, {"collections.group.parts.part.description.clip_to", st_collections_group_parts_part_description_clip_to_id}, {"collections.group.parts.part.description.size_class", st_collections_group_parts_part_description_size_class}, {"collections.group.parts.part.description.image.normal", st_collections_group_parts_part_description_image_normal}, @@ -1470,6 +1490,7 @@ New_Object_Handler object_handlers[] = {"collections.group.parts.part.description.link", ob_collections_group_parts_part_description_link}, {"collections.group.parts.part.description.rel1", NULL}, {"collections.group.parts.part.description.rel2", NULL}, + {"collections.group.parts.part.description.anchors", NULL}, {"collections.group.parts.part.description.image", NULL}, /* dup */ {"collections.group.parts.part.description.image.set", ob_images_set}, /* dup */ {"collections.group.parts.part.description.image.set.image", ob_images_set_image}, /* dup */ @@ -8754,6 +8775,8 @@ st_collections_group_parts_part_description_limit(void) static void st_collections_group_parts_part_description_align(void) { + check_has_anchors(); + if (get_arg_count() == 2) { current_desc->align.x = FROM_DOUBLE(parse_float_range(0, 0.0, 1.0)); @@ -8784,6 +8807,7 @@ st_collections_group_parts_part_description_align(void) static void st_collections_group_parts_part_description_fixed(void) { + check_has_anchors(); check_arg_count(2); current_desc->fixed.w = parse_float_range(0, 0, 1); @@ -9162,6 +9186,7 @@ st_collections_group_parts_part_description_clip_to_id(void) static void st_collections_group_parts_part_description_rel1_relative(void) { + check_has_anchors(); check_arg_count(2); current_desc->rel1.relative_x = FROM_DOUBLE(parse_float(0)); @@ -9181,6 +9206,7 @@ st_collections_group_parts_part_description_rel1_relative(void) static void st_collections_group_parts_part_description_rel1_offset(void) { + check_has_anchors(); check_arg_count(2); current_desc->rel1.offset_x = parse_int(0); @@ -9211,6 +9237,7 @@ st_collections_group_parts_part_description_rel1_to_set(const char *name) static void st_collections_group_parts_part_description_rel_to(void) { + check_has_anchors(); check_arg_count(1); { @@ -9225,6 +9252,7 @@ st_collections_group_parts_part_description_rel_to(void) static void st_collections_group_parts_part_description_rel1_to(void) { + check_has_anchors(); check_arg_count(1); { @@ -9252,6 +9280,7 @@ st_collections_group_parts_part_description_rel_to_x(void) { Edje_Part_Collection *pc; + check_has_anchors(); check_arg_count(1); pc = eina_list_data_get(eina_list_last(edje_collections)); @@ -9271,6 +9300,7 @@ st_collections_group_parts_part_description_rel1_to_x(void) { Edje_Part_Collection *pc; + check_has_anchors(); check_arg_count(1); pc = eina_list_data_get(eina_list_last(edje_collections)); @@ -9301,6 +9331,7 @@ st_collections_group_parts_part_description_rel_to_y(void) { Edje_Part_Collection *pc; + check_has_anchors(); check_arg_count(1); pc = eina_list_data_get(eina_list_last(edje_collections)); @@ -9320,6 +9351,7 @@ st_collections_group_parts_part_description_rel1_to_y(void) { Edje_Part_Collection *pc; + check_has_anchors(); check_arg_count(1); pc = eina_list_data_get(eina_list_last(edje_collections)); @@ -9336,6 +9368,7 @@ st_collections_group_parts_part_description_rel1_to_y(void) static void st_collections_group_parts_part_description_rel2_relative(void) { + check_has_anchors(); check_arg_count(2); current_desc->rel2.relative_x = FROM_DOUBLE(parse_float(0)); @@ -9345,6 +9378,7 @@ st_collections_group_parts_part_description_rel2_relative(void) static void st_collections_group_parts_part_description_rel2_offset(void) { + check_has_anchors(); check_arg_count(2); current_desc->rel2.offset_x = parse_int(0); @@ -9363,6 +9397,7 @@ st_collections_group_parts_part_description_rel2_to_set(const char *name) static void st_collections_group_parts_part_description_rel2_to(void) { + check_has_anchors(); check_arg_count(1); { @@ -9378,6 +9413,7 @@ st_collections_group_parts_part_description_rel2_to_x(void) { Edje_Part_Collection *pc; + check_has_anchors(); check_arg_count(1); pc = eina_list_data_get(eina_list_last(edje_collections)); @@ -9396,6 +9432,7 @@ st_collections_group_parts_part_description_rel2_to_y(void) { Edje_Part_Collection *pc; + check_has_anchors(); check_arg_count(1); pc = eina_list_data_get(eina_list_last(edje_collections)); @@ -9409,6 +9446,568 @@ st_collections_group_parts_part_description_rel2_to_y(void) } } +/** @edcsubsection{collections_group_parts_description_anchors, + * Group.Parts.Part.Description.Anchors} */ + +/** + @page edcref + @block + anchors + @context + // This part will be expanded from the top-left corner of edje group + part { name : "part1"; + description { state: "default" 0.0; + anchors { + top: GROUP TOP; + left: GROUP; // This means 'left: GROUP LEFT;' + } + min: 50 50; + } + } + // This part will be expanded from the bottom-right corner of "part1" + // to the bottom-right + part { name: "part2"; + description { state: "default" 0.0; + anchors { + top: "part1" BOTTOM; + left: "part1"; // This means 'left: "part1" RIGHT;' + } + min: 50 50; + } + } + // This part will be expanded from the right edje of "part2" to the right + part { name: "part3"; + description { state: "default" 0.0; + anchors { + left: "part2"; + fill: "part2" VERTICAL; + } + min: 100 0; // The height will be determined by the height of "part2" + } + } + // This part will be expanded from the center of right edge of "part3" + // to the bottom-right corner of edje group + part { name: "part4"; + description { state: "default" 0.0; + anchors { + top: "part3" VERTICAL_CENTER; + left: "part3"; + right: GROUP; + bottom: GROUP; + } + } + } + @description + The anchors blocks are used to define the position of each edge of + the part's container. Anchors will change relative, align and fixed + attributes internally, so setting both of them is not allowed. + When the second parameter of position enumeration is omitted, anchoring + a part to the other part will put the part adjacent to the given part. + However, if the part is anchored to edje group, the part will be contained + inside the group. + @endblock + + @property + anchors + @parameters + [partname] [the edge of other part] + @effect + Moves an edge of the part to the position of the edge of given part or + whole edje group. (GROUP means edje group that the part belong to) + @endproperty +*/ + +static void +check_has_anchors(void) +{ + if (current_anchors) + { + ERR("parse error %s:%i. Anchors and Relatives(rel/align/fixed) cannot be used at the same time.", + file_in, line - 1); + exit(-1); + } + + has_relatives = EINA_TRUE; +} + +static void +check_has_relatives(void) +{ + if (has_relatives) + { + ERR("parse error %s:%i. Anchors and Relatives(rel/align/fixed) cannot be used at the same time.", + file_in, line - 1); + exit(-1); + } + + current_desc->offset_is_scaled = EINA_TRUE; +} + +static void +parse_anchor_line(Edje_Part_Anchor *anchor, Edje_Part_Anchor_Line undefined) +{ + int nargs; + char *name; + + nargs = get_arg_count(); + if (!nargs || (nargs > 2)) + { + ERR("parse error %s:%i. Anchors should have a name of part and base line.", + file_in, line - 1); + exit(-1); + } + + name = parse_str(0); + anchor->set = EINA_TRUE; + + if (nargs == 2) + anchor->base.line = parse_enum(1, + "TOP", EDJE_PART_ANCHOR_LINE_TOP, + "BOTTOM", EDJE_PART_ANCHOR_LINE_BOTTOM, + "LEFT", EDJE_PART_ANCHOR_LINE_LEFT, + "RIGHT", EDJE_PART_ANCHOR_LINE_RIGHT, + "VERTICAL_CENTER", EDJE_PART_ANCHOR_LINE_VERTICAL_CENTER, + "HORIZONTAL_CENTER", EDJE_PART_ANCHOR_LINE_HORIZONTAL_CENTER, + NULL); + else if (strcmp(name, "GROUP")) + anchor->base.line = undefined; +} + +static void +parse_anchor_fill(Edje_Part_Anchor *anchor) +{ + int nargs; + + nargs = get_arg_count(); + if (!nargs || (nargs > 2)) + { + ERR("parse error %s:%i. Anchors should have a name of part and base line.", + file_in, line - 1); + exit(-1); + } + + anchor->set = EINA_TRUE; + + if (nargs == 2) + anchor->base.fill = parse_enum(1, + "BOTH", EDJE_PART_ANCHOR_FILL_BOTH, + "HORIZONTAL", EDJE_PART_ANCHOR_FILL_HORIZONTAL, + "VERTICAL", EDJE_PART_ANCHOR_FILL_VERTICAL, + NULL); + else + anchor->base.fill = EDJE_PART_ANCHOR_FILL_BOTH; +} + +static void +anchor_queue_part_lookup(int *part, int *counterpart, Eina_Bool counterpart_is_set) +{ + Edje_Part_Collection *pc; + char *name; + + pc = eina_list_data_get(eina_list_last(edje_collections)); + + name = parse_str(0); + if (!strcmp(name, "GROUP")) return; + + data_queue_part_lookup(pc, name, part); + + if (!counterpart_is_set) + data_queue_part_lookup(pc, name, counterpart); + + free(name); +} + +static void +anchor_dequeue_part_lookup(int *part, Eina_Bool counterpart_is_set) +{ + Edje_Part_Collection *pc; + + pc = eina_list_data_get(eina_list_last(edje_collections)); + + if (counterpart_is_set && part) + part_lookup_del(pc, part); +} + +static void +anchor_adjust_align(FLOAT_T *align, FLOAT_T val, unsigned char *fixed, Eina_Bool counterpart_is_set) +{ + if (counterpart_is_set) + { + *align = 0.5; + *fixed = 0; + } + else + { + *align = val; + *fixed = 1; + } +} + +static void +anchor_adjust_relative(Edje_Part_Anchor_Line *lines, FLOAT_T *rel, FLOAT_T *relc, Edje_Part_Anchor_Line line, Edje_Part_Anchor_Line base, Eina_Bool counterpart_is_set) +{ + if (line == EDJE_PART_ANCHOR_LINE_NONE) + line = base; + + if (line == lines[0]) + { + *rel = FROM_DOUBLE(0.0); + if (!counterpart_is_set) + *relc = FROM_DOUBLE(0.0); + } + else if (line == lines[1]) + { + *rel = FROM_DOUBLE(1.0); + if (!counterpart_is_set) + *relc = FROM_DOUBLE(1.0); + } + else if (line == lines[2]) + { + *rel = FROM_DOUBLE(0.5); + if (!counterpart_is_set) + *relc = FROM_DOUBLE(0.5); + } + else + { + ERR("parse error %s:%i. Edje part is anchored to wrong position.", + file_in, line - 1); + exit(-1); + } +} + +static void +anchor_adjust_relative_vertical(FLOAT_T *rel, FLOAT_T *relc, Edje_Part_Anchor_Line line, Edje_Part_Anchor_Line base, Eina_Bool counterpart_is_set) +{ + static const Edje_Part_Anchor_Line lines[] = { + EDJE_PART_ANCHOR_LINE_TOP, + EDJE_PART_ANCHOR_LINE_BOTTOM, + EDJE_PART_ANCHOR_LINE_VERTICAL_CENTER + }; + + anchor_adjust_relative(lines, rel, relc, line, base, counterpart_is_set); +} + +static void +anchor_adjust_relative_horizontal(FLOAT_T *rel, FLOAT_T *relc, Edje_Part_Anchor_Line line, Edje_Part_Anchor_Line base, Eina_Bool counterpart_is_set) +{ + static const Edje_Part_Anchor_Line lines[] = { + EDJE_PART_ANCHOR_LINE_LEFT, + EDJE_PART_ANCHOR_LINE_RIGHT, + EDJE_PART_ANCHOR_LINE_HORIZONTAL_CENTER + }; + + anchor_adjust_relative(lines, rel, relc, line, base, counterpart_is_set); +} + +/** + @page edcref + @property + top + @parameters + [partname] [TOP/BOTTOM/VERTICAL_CENTER] + @effect + Causes top edge to be positioned to the edge of another part's container. + Setting to GROUP will indicate edje group instead of another part. + If bottom anchor is not set, edje part will be expanded to the bottom. + The second parameter of position enumeration can be omitted. (Default + value is BOTTOM, but TOP when the part is anchored to edje group) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_top(void) +{ + Eina_Bool counterpart_is_set; + + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + counterpart_is_set = current_anchors->bottom.set; + + parse_anchor_line(&(current_anchors->top), EDJE_PART_ANCHOR_LINE_BOTTOM); + + anchor_dequeue_part_lookup(&(current_desc->rel1.id_y), counterpart_is_set); + anchor_queue_part_lookup(&(current_desc->rel1.id_y), &(current_desc->rel2.id_y), counterpart_is_set); + + anchor_adjust_align(&(current_desc->align.y), 0.0, &(current_desc->fixed.h), counterpart_is_set); + anchor_adjust_relative_vertical(&(current_desc->rel1.relative_y), &(current_desc->rel2.relative_y), current_anchors->top.base.line, EDJE_PART_ANCHOR_LINE_TOP, counterpart_is_set); +} + +/** + @page edcref + @property + bottom + @parameters + [partname] [TOP/BOTTOM/VERTICAL_CENTER] + @effect + Causes bottom edge to be positioned to the edge of another part's container. + Setting to GROUP will indicate edje group instead of another part. + If top anchor is not set, edje part will be expanded to the top. + The second parameter of position enumeration can be omitted. (Default + value is TOP, but BOTTOM when the part is anchored to edje group) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_bottom(void) +{ + Eina_Bool counterpart_is_set; + + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + counterpart_is_set = current_anchors->top.set; + + parse_anchor_line(&(current_anchors->bottom), EDJE_PART_ANCHOR_LINE_TOP); + + anchor_dequeue_part_lookup(&(current_desc->rel2.id_y), counterpart_is_set); + anchor_queue_part_lookup(&(current_desc->rel2.id_y), &(current_desc->rel1.id_y), counterpart_is_set); + + anchor_adjust_align(&(current_desc->align.y), 1.0, &(current_desc->fixed.h), counterpart_is_set); + anchor_adjust_relative_vertical(&(current_desc->rel2.relative_y), &(current_desc->rel1.relative_y), current_anchors->bottom.base.line, EDJE_PART_ANCHOR_LINE_BOTTOM, counterpart_is_set); +} + +/** + @page edcref + @property + left + @parameters + [partname] [LEFT/RIGHT/HORIZONTAL_CENTER] + @effect + Causes left edge to be positioned to the edge of another part's container. + Setting to GROUP will indicate edje group instead of another part. + If right anchor is not set, edje part will be expanded to the right. + The second parameter of position enumeration can be omitted. (Default + value is RIGHT, but LEFT when the part is anchored to edje group) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_left(void) +{ + Eina_Bool counterpart_is_set; + + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + counterpart_is_set = current_anchors->right.set; + + parse_anchor_line(&(current_anchors->left), EDJE_PART_ANCHOR_LINE_RIGHT); + + anchor_dequeue_part_lookup(&(current_desc->rel1.id_x), counterpart_is_set); + anchor_queue_part_lookup(&(current_desc->rel1.id_x), &(current_desc->rel2.id_x), counterpart_is_set); + + anchor_adjust_align(&(current_desc->align.x), 0.0, &(current_desc->fixed.w), counterpart_is_set); + anchor_adjust_relative_horizontal(&(current_desc->rel1.relative_x), &(current_desc->rel2.relative_x), current_anchors->left.base.line, EDJE_PART_ANCHOR_LINE_LEFT, counterpart_is_set); +} + +/** + @page edcref + @property + right + @parameters + [partname] [LEFT/RIGHT/HORIZONTAL_CENTER] + @effect + Causes right edge to be positioned to the edge of another part's container. + Setting to GROUP will indicate edje group instead of another part. + If left anchor is not set, edje part will be expanded to the left. + The second parameter of position enumeration can be omitted. (Default + value is LEFT, but RIGHT when the part is anchored to edje group) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_right(void) +{ + Eina_Bool counterpart_is_set; + + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + counterpart_is_set = current_anchors->left.set; + + parse_anchor_line(&(current_anchors->right), EDJE_PART_ANCHOR_LINE_LEFT); + + anchor_dequeue_part_lookup(&(current_desc->rel2.id_x), counterpart_is_set); + anchor_queue_part_lookup(&(current_desc->rel2.id_x), &(current_desc->rel1.id_x), counterpart_is_set); + + anchor_adjust_align(&(current_desc->align.x), 1.0, &(current_desc->fixed.w), counterpart_is_set); + anchor_adjust_relative_horizontal(&(current_desc->rel2.relative_x), &(current_desc->rel1.relative_x), current_anchors->right.base.line, EDJE_PART_ANCHOR_LINE_RIGHT, counterpart_is_set); +} + +/** + @page edcref + @property + vertical_center + @parameters + [partname] [TOP/BOTTOM/VERTICAL_CENTER] + @effect + Causes (virtual) vertical center line to be positioned to the edge of + another part's container. Setting to GROUP will indicate edje group instead + of another part. + This part will be expanded vertically in both directions, so do not + set top or bottom anchor with vertical_center anchor. + The second parameter of position enumeration can be omitted. (Default + value is VERTICAL_CENTER) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_vertical_center(void) +{ + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + parse_anchor_line(&(current_anchors->vertical_center), EDJE_PART_ANCHOR_LINE_VERTICAL_CENTER); + + anchor_queue_part_lookup(&(current_desc->rel1.id_y), &(current_desc->rel2.id_y), EINA_FALSE); + + anchor_adjust_align(&(current_desc->align.y), 0.5, &(current_desc->fixed.h), EINA_FALSE); + anchor_adjust_relative_vertical(&(current_desc->rel1.relative_y), &(current_desc->rel2.relative_y), current_anchors->vertical_center.base.line, EDJE_PART_ANCHOR_LINE_VERTICAL_CENTER, EINA_FALSE); +} + +/** + @page edcref + @property + horizontal_center + @parameters + [partname] [LEFT/RIGHT/HORIZONTAL_CENTER] + @effect + Causes (virtual) horizontal center line to be positioned to the edge of + another part's container. Setting to GROUP will indicate edje group instead + of another part. + This part will be expanded horizontally in both directions, so do not + set left or right anchor with vertical_center anchor. + The second parameter of position enumeration can be omitted. (Default + value is HORIZONTAL_CENTER) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_horizontal_center(void) +{ + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + parse_anchor_line(&(current_anchors->horizontal_center), EDJE_PART_ANCHOR_LINE_HORIZONTAL_CENTER); + + anchor_queue_part_lookup(&(current_desc->rel1.id_x), &(current_desc->rel2.id_x), EINA_FALSE); + + anchor_adjust_align(&(current_desc->align.x), 0.5, &(current_desc->fixed.w), EINA_FALSE); + anchor_adjust_relative_horizontal(&(current_desc->rel1.relative_x), &(current_desc->rel2.relative_x), current_anchors->horizontal_center.base.line, EDJE_PART_ANCHOR_LINE_HORIZONTAL_CENTER, EINA_FALSE); +} + +/** + @page edcref + @property + fill + @parameters + [partname] [BOTH/HORIZONTAL/VERTICAL] + @effect + Causes the part's container to expand to the width or height of another + part's container. Setting to GROUP will indicate edje group instead of another part. + Setting horizontal fill has same effect to setting top and bottom anchors + to the same part. + (setting vertical fill means left and right anchors to the same part) + The second parameter of direction enumeration can be omitted. (Default + value is BOTH) + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_fill(void) +{ + Edje_Part_Collection *pc; + char *name; + + pc = eina_list_last_data_get(edje_collections); + + check_has_relatives(); + + if (!current_anchors) + current_anchors = mem_alloc(SZ(Edje_Part_Description_Anchors)); + + parse_anchor_fill(&(current_anchors->fill)); + + name = parse_str(0); + + switch (current_anchors->fill.base.fill) + { + case EDJE_PART_ANCHOR_FILL_BOTH: + if (strcmp("GROUP", name)) + { + data_queue_part_lookup(pc, name, &(current_desc->rel1.id_x)); + data_queue_part_lookup(pc, name, &(current_desc->rel2.id_x)); + data_queue_part_lookup(pc, name, &(current_desc->rel1.id_y)); + data_queue_part_lookup(pc, name, &(current_desc->rel2.id_y)); + } + current_desc->align.x = 0.5; + current_desc->align.y = 0.5; + current_desc->fixed.w = 0; + current_desc->fixed.h = 0; + break; + case EDJE_PART_ANCHOR_FILL_HORIZONTAL: + if (strcmp("GROUP", name)) + { + data_queue_part_lookup(pc, name, &(current_desc->rel1.id_x)); + data_queue_part_lookup(pc, name, &(current_desc->rel2.id_x)); + } + current_desc->align.x = 0.5; + current_desc->fixed.w = 0; + break; + case EDJE_PART_ANCHOR_FILL_VERTICAL: + if (strcmp("GROUP", name)) + { + data_queue_part_lookup(pc, name, &(current_desc->rel1.id_y)); + data_queue_part_lookup(pc, name, &(current_desc->rel2.id_y)); + } + current_desc->align.y = 0.5; + current_desc->fixed.h = 0; + break; + } + + free(name); +} + +/** + @page edcref + @property + margin + @parameters + [left] [right] [top] [bottom] + @effect + Affects the edge position a fixed number of pixels along each direction. + Margins will scale its size with an edje scaling factor. + @endproperty +*/ +static void +st_collections_group_parts_part_description_anchors_margin(void) +{ + check_has_relatives(); + check_arg_count(4); + + current_desc->rel1.offset_x = parse_int(0); + current_desc->rel2.offset_x = -parse_int(1) - 1; + current_desc->rel1.offset_y = parse_int(2); + current_desc->rel2.offset_y = -parse_int(3) - 1; +} + +static void +free_anchors(void) +{ + has_relatives = EINA_FALSE; + + if (!current_anchors) return; + + free(current_anchors); + current_anchors = NULL; +} + /** @edcsubsection{collections_group_parts_description_image, * Group.Parts.Part.Description.Image} */ @@ -15154,6 +15753,8 @@ edje_cc_handlers_pop_notify(const char *token) current_program = NULL; else if (current_de && (!strcmp(token, "group"))) _link_combine(); + else if (current_desc && (!strcmp(token, "description"))) + free_anchors(); } static void diff --git a/src/examples/edje/edje-anchors.c b/src/examples/edje/edje-anchors.c new file mode 100644 index 0000000000..135f0abc31 --- /dev/null +++ b/src/examples/edje/edje-anchors.c @@ -0,0 +1,58 @@ +/** + * Simple Edje example for layouting parts with anchors. + * + * You'll need at least one Evas engine built for it (excluding the + * buffer one). See stdout/stderr for output. + * + * @verbatim + * edje_cc edje-anchors.edc && gcc -o edje-anchors edje-anchors.c `pkg-config --libs --cflags evas ecore ecore-evas edje` + * @endverbatim + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#else +# define EINA_UNUSED +#endif + +#include +#include +#include +#include + +#define WIDTH 400 +#define HEIGHT 400 + +int +main(int argc, char **argv) +{ + char path[PATH_MAX] = { 0, }; + + ecore_init(); + ecore_evas_init(); + edje_init(); + + Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL); + Evas *e = ecore_evas_get(ee); + ecore_evas_show(ee); + + Evas_Object *bg = evas_object_rectangle_add(e); + evas_object_color_set(bg, 64, 64, 64, 255); + evas_object_resize(bg, WIDTH, HEIGHT); + evas_object_show(bg); + + snprintf(path, sizeof(path), "%s/edje-anchors.edj", dirname(*argv)); + + Evas_Object *edje = edje_object_add(e); + edje_object_file_set(edje, path, "main"); + evas_object_resize(edje, WIDTH, HEIGHT); + evas_object_show(edje); + + ecore_main_loop_begin(); + + edje_shutdown(); + ecore_evas_shutdown(); + ecore_shutdown(); + + return 0; +} diff --git a/src/examples/edje/edje-anchors.edc b/src/examples/edje/edje-anchors.edc new file mode 100644 index 0000000000..2d3d485e9f --- /dev/null +++ b/src/examples/edje/edje-anchors.edc @@ -0,0 +1,58 @@ +collections { + group { "main"; + parts { + rect { "rect1"; + desc { + anchors.top: GROUP TOP; + anchors.left: GROUP; // anchors.left: GROUP LEFT; + color: "#f00"; + min: 50 50; + } + } + rect { "rect2"; + desc { + anchors.top: "rect1" BOTTOM; + anchors.left: "rect1" RIGHT; + color: "#00f"; + min: 50 50; + } + } + rect { "rect3"; + desc { + anchors.left: "rect2"; // anchors.left: "rect1" RIGHT; + anchors.fill: "rect2" VERTICAL; + anchors.margin: 20 0 0 0; + color: "#0f0"; + min: 100 0; + } + } + rect { "rect4"; + desc { + anchors { + top: "rect3"; + left: "rect3"; + right: GROUP; + bottom: GROUP; + margin: 0 10 0 50; + } + } + } + rect { "rect5"; + desc { + anchors.vertical_center: "rect4"; + anchors.fill: "rect4" HORIZONTAL; + min: 0 50; + color: "#000"; + } + } + rect { "rect6"; + desc { + anchors.right: "rect5" HORIZONTAL_CENTER; + anchors.fill: "rect5" VERTICAL; + min: 30 0; + color: "#ff0"; + } + } + } + } +} diff --git a/src/lib/edje/edje_calc.c b/src/lib/edje/edje_calc.c index bf0d809c5a..37163c3a14 100644 --- a/src/lib/edje/edje_calc.c +++ b/src/lib/edje/edje_calc.c @@ -1114,42 +1114,71 @@ _edje_part_recalc_single_rel(Edje *ed, { FLOAT_T x, w; FLOAT_T y, h; + FLOAT_T offset, sc; + Eina_Bool offset_is_scaled = (desc->offset_is_scaled) && (ep->part->scale); + + if (offset_is_scaled) + { + sc = DIV(ed->scale, ed->file->base_scale); + if (EQ(sc, ZERO)) sc = DIV(_edje_scale, ed->file->base_scale); + } + + if (offset_is_scaled) + offset = SCALE(sc, desc->rel1.offset_x); + else + offset = FROM_INT(desc->rel1.offset_x); if (rel1_to_x) - x = ADD(FROM_INT(desc->rel1.offset_x + rel1_to_x->x), + x = ADD(ADD(offset, FROM_INT(rel1_to_x->x)), SCALE(desc->rel1.relative_x, rel1_to_x->w)); else - x = ADD(FROM_INT(desc->rel1.offset_x), + x = ADD(offset, SCALE(desc->rel1.relative_x, ed->w)); params->eval.x = x; + if (offset_is_scaled) + offset = SUB(SCALE(sc, desc->rel2.offset_x + 1), FROM_INT(1)); + else + offset = FROM_INT(desc->rel2.offset_x); + if (rel2_to_x) - w = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_x + rel2_to_x->x), + w = ADD(SUB(ADD(ADD(offset, FROM_INT(rel2_to_x->x)), SCALE(desc->rel2.relative_x, rel2_to_x->w)), x), FROM_INT(1)); else - w = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_x), + w = ADD(SUB(ADD(offset, SCALE(desc->rel2.relative_x, ed->w)), x), FROM_INT(1)); params->eval.w = w; + + if (offset_is_scaled) + offset = SCALE(sc, desc->rel1.offset_y); + else + offset = FROM_INT(desc->rel1.offset_y); + if (rel1_to_y) - y = ADD(FROM_INT(desc->rel1.offset_y + rel1_to_y->y), + y = ADD(ADD(offset, FROM_INT(rel1_to_y->y)), SCALE(desc->rel1.relative_y, rel1_to_y->h)); else - y = ADD(FROM_INT(desc->rel1.offset_y), + y = ADD(offset, SCALE(desc->rel1.relative_y, ed->h)); params->eval.y = y; + if (offset_is_scaled) + offset = SUB(SCALE(sc, desc->rel2.offset_y + 1), FROM_INT(1)); + else + offset = FROM_INT(desc->rel2.offset_y); + if (rel2_to_y) - h = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_y + rel2_to_y->y), + h = ADD(SUB(ADD(ADD(offset, FROM_INT(rel2_to_y->y)), SCALE(desc->rel2.relative_y, rel2_to_y->h)), y), FROM_INT(1)); else - h = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_y), + h = ADD(SUB(ADD(offset, SCALE(desc->rel2.relative_y, ed->h)), y), FROM_INT(1)); @@ -4577,6 +4606,7 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta rp1[Rel2X], rp1[Rel2Y], clip1, confine_to, threshold, p1, mmw, mmh, pos); + #ifdef EDJE_CALC_CACHE if (flags == FLAG_XY) ep->param1.state = ed->state; #endif @@ -4622,6 +4652,7 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta rp2[Rel2X], rp2[Rel2Y], clip2, confine_to, threshold, p2, mmw, mmh, pos); + #ifdef EDJE_CALC_CACHE if (flags == FLAG_XY) ep->param2->state = ed->state; #endif @@ -4705,7 +4736,6 @@ _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags, Edje_Calc_Params *sta p3->smooth = (beginning_pos) ? p1->smooth : p2->smooth; /* FIXME: do x and y separately base on flag */ - p3->final.x = INTP(p1->final.x, p2->final.x, pos); p3->final.y = INTP(p1->final.y, p2->final.y, pos); p3->final.w = INTP(p1->final.w, p2->final.w, pos); diff --git a/src/lib/edje/edje_data.c b/src/lib/edje/edje_data.c index e6d2fbb081..5e3ffe5bb4 100644 --- a/src/lib/edje/edje_data.c +++ b/src/lib/edje/edje_data.c @@ -1217,7 +1217,8 @@ _edje_edd_init(void) EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "map.zoom.x", map.zoom.x, EDJE_T_FLOAT); \ EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "map.zoom.y", map.zoom.y, EDJE_T_FLOAT); \ EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "persp.zplane", persp.zplane, EET_T_INT); \ - EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "persp.focal", persp.focal, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "persp.focal", persp.focal, EET_T_INT); \ + EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "offset_is_scaled", offset_is_scaled, EET_T_UCHAR); #ifdef HAVE_EPHYSICS #define EDJE_DATA_DESCRIPTOR_DESCRIPTION_COMMON(Edd, Type) \ @@ -1311,6 +1312,7 @@ _edje_edd_init(void) EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "map.zoom.y", Dec.map.zoom.y, EDJE_T_FLOAT); \ EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "persp.zplane", Dec.persp.zplane, EET_T_INT); \ EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "persp.focal", Dec.persp.focal, EET_T_INT); \ + EET_DATA_DESCRIPTOR_ADD_BASIC(Edd, Type, "offset_is_scaled", Dec.offset_is_scaled, EET_T_UCHAR); #ifdef HAVE_EPHYSICS #define EDJE_DATA_DESCRIPTOR_DESCRIPTION_COMMON_SUB(Edd, Type, Dec) \ diff --git a/src/lib/edje/edje_private.h b/src/lib/edje/edje_private.h index b5cd5543d3..94c994a9a7 100644 --- a/src/lib/edje/edje_private.h +++ b/src/lib/edje/edje_private.h @@ -1330,9 +1330,11 @@ struct _Edje_Part_Description_Common #endif Edje_3D_Vec align_3d; + unsigned char visible; /* is it shown */ unsigned char limit; /* 0 == no, 1 = width, 2 = height, 3 = both */ unsigned char no_render; /* no_render override @since 1.19 */ + unsigned char offset_is_scaled; }; struct _Edje_Part_Description_Spec_Fill