aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/edje/edje_textblock.c
diff options
context:
space:
mode:
authorDaniel Hirt <hirt.danny@gmail.com>2017-10-15 17:55:20 +0300
committerCedric BAIL <cedric@osg.samsung.com>2017-11-10 10:30:04 -0800
commitc7b2372ffb35cc51415f943b7ff2895d245362bc (patch)
treec16a1438d36a17013c861e6e2f8acf7c82408cbf /src/lib/edje/edje_textblock.c
parentCanvas text: change halign/valign to use doubles (diff)
downloadefl-c7b2372ffb35cc51415f943b7ff2895d245362bc.tar.gz
Edje: move textblock handling to a separate source
Signed-off-by: Cedric BAIL <cedric@osg.samsung.com>
Diffstat (limited to '')
-rw-r--r--src/lib/edje/edje_textblock.c583
1 files changed, 583 insertions, 0 deletions
diff --git a/src/lib/edje/edje_textblock.c b/src/lib/edje/edje_textblock.c
new file mode 100644
index 0000000000..0451099fa4
--- /dev/null
+++ b/src/lib/edje/edje_textblock.c
@@ -0,0 +1,583 @@
+#include "edje_private.h"
+
+static double
+_edje_part_recalc_single_textblock_scale_range_adjust(Edje_Part_Description_Text *chosen_desc, double base_scale, double scale)
+{
+ double size, min, max;
+
+ if (chosen_desc->text.size == 0)
+ return scale;
+
+ min = base_scale * chosen_desc->text.size_range_min;
+ max = chosen_desc->text.size_range_max * base_scale;
+ size = chosen_desc->text.size * scale;
+
+ if ((size > max) && (max > 0))
+ scale = max / (double)chosen_desc->text.size;
+ else if (size < min)
+ scale = min / (double)chosen_desc->text.size;
+
+ return scale;
+}
+
+/*
+ * Legacy function for min/max calculation of textblock part.
+ * It can't calculate min/max properly in many cases.
+ *
+ * To keep backward compatibility, it will be used for old version of EDJ files.
+ * You can't see proper min/max result accroding to documents with this function.
+ */
+static void
+_edje_part_recalc_single_textblock_min_max_calc_legacy(Edje_Real_Part *ep,
+ Edje_Part_Description_Text *chosen_desc,
+ Edje_Calc_Params *params,
+ int *minw, int *minh,
+ int *maxw, int *maxh)
+{
+ Evas_Coord tw, th, ins_l, ins_r, ins_t, ins_b;
+
+ /* Legacy code for Textblock min/max calculation */
+ if ((chosen_desc->text.min_x) || (chosen_desc->text.min_y))
+ {
+ int mw = 0, mh = 0;
+
+ tw = th = 0;
+ if (!chosen_desc->text.min_x)
+ {
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(TO_INT(params->eval.w), TO_INT(params->eval.h)));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+ }
+ else
+ evas_object_textblock_size_native_get(ep->object, &tw, &th);
+ evas_object_textblock_style_insets_get(ep->object, &ins_l,
+ &ins_r, &ins_t, &ins_b);
+ mw = ins_l + tw + ins_r;
+ mh = ins_t + th + ins_b;
+ if (minw && chosen_desc->text.min_x)
+ {
+ if (mw > *minw) *minw = mw;
+ }
+ if (minh && chosen_desc->text.min_y)
+ {
+ if (mh > *minh) *minh = mh;
+ }
+ }
+
+ if ((chosen_desc->text.max_x) || (chosen_desc->text.max_y))
+ {
+ int mw = 0, mh = 0;
+
+ tw = th = 0;
+ if (!chosen_desc->text.max_x)
+ {
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(TO_INT(params->eval.w), TO_INT(params->eval.h)));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+ }
+ else
+ evas_object_textblock_size_native_get(ep->object, &tw, &th);
+ evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r,
+ &ins_t, &ins_b);
+ mw = ins_l + tw + ins_r;
+ mh = ins_t + th + ins_b;
+ if (maxw && chosen_desc->text.max_x)
+ {
+ if (mw > *maxw) *maxw = mw;
+ if (minw && (*maxw < *minw)) *maxw = *minw;
+ }
+ if (maxh && chosen_desc->text.max_y)
+ {
+ if (mh > *maxh) *maxh = mh;
+ if (minh && (*maxh < *minh)) *maxh = *minh;
+ }
+ }
+}
+
+static void
+_edje_part_recalc_single_textblock_min_max_calc(Edje_Real_Part *ep,
+ Edje_Part_Description_Text *chosen_desc,
+ Edje_Calc_Params *params,
+ int *minw, int *minh,
+ int *maxw, int *maxh)
+{
+ Evas_Coord tw, th, ins_l, ins_r, ins_t, ins_b;
+ Evas_Coord min_calc_w = 0, min_calc_h = 0;
+
+ /* min_calc_* values need to save calculated minumum size
+ * for maximum size calculation */
+ if (minw) min_calc_w = *minw;
+ if (minh) min_calc_h = *minh;
+
+ if ((chosen_desc->text.min_x) || (chosen_desc->text.min_y))
+ {
+ evas_object_textblock_style_insets_get(ep->object, &ins_l,
+ &ins_r, &ins_t, &ins_b);
+
+ tw = th = 0;
+ if (!chosen_desc->text.min_x)
+ {
+ /* text.min: 0 1
+ * text.max: X X */
+ int temp_h = TO_INT(params->eval.h);
+ int temp_w = TO_INT(params->eval.w);
+
+ if (min_calc_w > temp_w)
+ temp_w = min_calc_w;
+ if ((!chosen_desc->text.max_x) &&
+ maxw && (*maxw > -1) && (*maxw < temp_w))
+ temp_w = *maxw;
+
+ if (chosen_desc->text.max_y)
+ {
+ /* text.min: 0 1
+ * text.max: X 1 */
+ temp_h = INT_MAX / 10000;
+ }
+ else if (maxh && (*maxh > TO_INT(params->eval.h)))
+ {
+ /* text.min: 0 1
+ * text.max: X 0
+ * And there is a limit for height. */
+ temp_h = *maxh;
+ }
+
+ /* If base width for calculation is 0,
+ * don't get meaningless height for multiline */
+ if (temp_w > 0)
+ {
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(temp_w, temp_h));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+ }
+ else
+ {
+ efl_canvas_text_size_native_get(ep->object, NULL, &th);
+
+ th += ins_t + ins_b;
+ }
+ }
+ else
+ {
+ /* text.min: 1 X
+ * text.max: X X */
+ if (chosen_desc->text.min_y && (!chosen_desc->text.max_x) &&
+ maxw && (*maxw > -1))
+ {
+ /* text.min: 1 1
+ * text.max: 0 X */
+ int temp_w, temp_h;
+
+ temp_w = *maxw;
+ temp_h = INT_MAX / 10000;
+
+ if (min_calc_w > temp_w)
+ temp_w = min_calc_w;
+
+ if ((!chosen_desc->text.max_y) && maxh && (*maxh > -1))
+ {
+ /* text.min: 1 1
+ * text.max: 0 0
+ * There is limit for height. */
+ temp_h = *maxh;
+ }
+
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(temp_w, temp_h));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+
+ /* If base width for calculation is 0,
+ * don't get meaningless height for multiline */
+ if (temp_w <= 0)
+ {
+ efl_canvas_text_size_native_get(ep->object, NULL, &th);
+
+ th += ins_t + ins_b;
+ }
+ }
+ else
+ {
+ /* text.min: 1 X
+ * text.max: 1 X
+ * Or,
+ * text.min: 1 X
+ * text.max: 0 X without max width.
+ * It is a singleline Textblock. */
+ efl_canvas_text_size_native_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+
+ if (!chosen_desc->text.max_x &&
+ (maxw && (*maxw > -1) && (*maxw < tw)))
+ {
+ /* text.min: 1 0
+ * text.max: 0 X */
+ tw = *maxw;
+ }
+ }
+ }
+
+ if (tw > min_calc_w) min_calc_w = tw;
+ if (th > min_calc_h) min_calc_h = th;
+ if (chosen_desc->text.min_x && minw) *minw = min_calc_w;
+ if (chosen_desc->text.min_y && minh) *minh = min_calc_h;
+ }
+
+ if ((chosen_desc->text.max_x) || (chosen_desc->text.max_y))
+ {
+ evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r,
+ &ins_t, &ins_b);
+
+ tw = th = 0;
+ if (!chosen_desc->text.max_x)
+ {
+ /* text.min: X X
+ * text.max: 0 1 */
+ int temp_w, temp_h;
+
+ if (chosen_desc->text.min_y)
+ {
+ /* text.min: X 1
+ * text.max: 0 1
+ * Already calculated in text for height. */
+ tw = TO_INT(params->eval.w);
+ if (min_calc_w > tw)
+ tw = min_calc_w;
+
+ th = min_calc_h;
+ }
+ else
+ {
+ /* text.min: X 0
+ * text.max: 0 1 */
+ temp_w = TO_INT(params->eval.w);
+ temp_h = TO_INT(params->eval.h);
+
+ if (min_calc_w > temp_w)
+ temp_w = min_calc_w;
+ if (maxw && (*maxw > -1) && (*maxw < temp_w))
+ temp_w = *maxw;
+ if (min_calc_h > temp_h)
+ temp_h = min_calc_h;
+
+ /* If base width for calculation is 0,
+ * don't get meaningless height for multiline */
+ if (temp_w > 0)
+ {
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(temp_w, temp_h));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+ }
+ else
+ {
+ efl_canvas_text_size_native_get(ep->object, NULL, &th);
+
+ th += ins_t + ins_b;
+ }
+ }
+ }
+ else
+ {
+ /* text.max: 1 X */
+ if (chosen_desc->text.min_x)
+ {
+ /* text.min: 1 X
+ * text.max: 1 X
+ * Singleline. */
+ efl_canvas_text_size_native_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+ }
+ else
+ {
+ /* text.min: 0 X
+ * text.max: 1 X */
+ if (chosen_desc->text.max_y)
+ {
+ /* text.min: 0 X
+ * text.max: 1 1 */
+ int temp_w, temp_h;
+
+ temp_w = TO_INT(params->eval.w);
+ temp_h = TO_INT(params->eval.h);
+
+ if (min_calc_w > temp_w)
+ temp_w = min_calc_w;
+ if (min_calc_h > temp_h)
+ temp_h = min_calc_h;
+
+ if (chosen_desc->text.min_y)
+ {
+ /* text.min: 0 1
+ * text.max: 1 1
+ * There is no need to calculate it again. */
+ tw = min_calc_w;
+ th = min_calc_h;
+ }
+ else
+ {
+ /* text.min: 0 0
+ * text.max: 1 1 */
+
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(temp_w, temp_h));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+
+ /* If base width for calculation is 0,
+ * don't get meaningless height for multiline */
+ if (temp_w <= 0)
+ {
+ efl_canvas_text_size_native_get(ep->object, NULL, &th);
+
+ th += ins_t + ins_b;
+ }
+ }
+ }
+ else
+ {
+ /* text.min: 0 X
+ * text.max: 1 0 */
+ int temp_w, temp_h;
+
+ temp_w = TO_INT(params->eval.w);
+ if (min_calc_w > temp_w)
+ temp_w = min_calc_w;
+
+ temp_h = efl_gfx_size_get(ep->object).h;
+ efl_gfx_size_set(ep->object, EINA_SIZE2D(temp_w, temp_h));
+ efl_canvas_text_size_formatted_get(ep->object, &tw, &th);
+
+ tw += ins_l + ins_r;
+ th += ins_t + ins_b;
+
+ /* If base width for calculation is 0,
+ * don't get meaningless height for multiline */
+ if (temp_w <= 0)
+ {
+ efl_canvas_text_size_native_get(ep->object, NULL, &th);
+
+ th += ins_t + ins_b;
+ }
+ }
+ }
+ }
+
+ if (maxw && chosen_desc->text.max_x)
+ {
+ if (tw > *maxw) *maxw = tw;
+ if (minw && (*maxw < *minw)) *maxw = *minw;
+ }
+ if (maxh && chosen_desc->text.max_y)
+ {
+ if (th > *maxh) *maxh = th;
+ if (minh && (*maxh < *minh)) *maxh = *minh;
+ }
+ }
+}
+
+void
+_edje_part_recalc_single_textblock(FLOAT_T sc,
+ Edje *ed,
+ Edje_Real_Part *ep,
+ Edje_Part_Description_Text *chosen_desc,
+ Edje_Calc_Params *params,
+ int *minw, int *minh,
+ int *maxw, int *maxh)
+{
+ if ((ep->type != EDJE_RP_TYPE_TEXT) ||
+ (!ep->typedata.text))
+ return;
+
+ if (chosen_desc)
+ {
+ Evas_Coord tw, th;
+ const char *text = "";
+ const char *style = "";
+ Edje_Style *stl = NULL;
+ const char *tmp;
+ Eina_List *l;
+
+ if (chosen_desc->text.id_source >= 0)
+ {
+ Edje_Part_Description_Text *et;
+
+ ep->typedata.text->source = ed->table_parts[chosen_desc->text.id_source % ed->table_parts_size];
+
+ et = _edje_real_part_text_source_description_get(ep, NULL);
+ tmp = edje_string_get(&et->text.style);
+ if (tmp) style = tmp;
+ }
+ else
+ {
+ ep->typedata.text->source = NULL;
+
+ tmp = edje_string_get(&chosen_desc->text.style);
+ if (tmp) style = tmp;
+ }
+
+ if (chosen_desc->text.id_text_source >= 0)
+ {
+ Edje_Part_Description_Text *et;
+ Edje_Real_Part *rp;
+
+ ep->typedata.text->text_source = ed->table_parts[chosen_desc->text.id_text_source % ed->table_parts_size];
+
+ et = _edje_real_part_text_text_source_description_get(ep, &rp);
+ text = edje_string_get(&et->text.text);
+
+ if (rp->typedata.text->text) text = rp->typedata.text->text;
+ }
+ else
+ {
+ ep->typedata.text->text_source = NULL;
+ text = edje_string_get(&chosen_desc->text.text);
+ if (ep->typedata.text->text) text = ep->typedata.text->text;
+ }
+
+ EINA_LIST_FOREACH(ed->file->styles, l, stl)
+ {
+ if ((stl->name) && (!strcmp(stl->name, style))) break;
+ stl = NULL;
+ }
+
+ if (ep->part->scale)
+ evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+
+ if ((chosen_desc->text.fit_x) || (chosen_desc->text.fit_y))
+ {
+ double base_s = 1.0;
+ double orig_s;
+ double s = base_s;
+
+ if (ep->part->scale) base_s = TO_DOUBLE(sc);
+ efl_canvas_object_scale_set(ep->object, base_s);
+ efl_canvas_text_size_native_get(ep->object, &tw, &th);
+
+ orig_s = base_s;
+ /* Now make it bigger so calculations will be more accurate
+ * and less influenced by hinting... */
+ {
+ orig_s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s,
+ orig_s * TO_INT(params->eval.w) / tw);
+ efl_canvas_object_scale_set(ep->object, orig_s);
+ efl_canvas_text_size_native_get(ep->object, &tw, &th);
+ }
+ if (chosen_desc->text.fit_x)
+ {
+ if (tw > 0)
+ {
+ s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s,
+ orig_s * TO_INT(params->eval.w) / tw);
+ efl_canvas_object_scale_set(ep->object, s);
+ efl_canvas_text_size_native_get(ep->object, NULL, NULL);
+ }
+ }
+ if (chosen_desc->text.fit_y)
+ {
+ if (th > 0)
+ {
+ double tmp_s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s,
+ orig_s * TO_INT(params->eval.h) / th);
+ /* If we already have X fit, restrict Y to be no bigger
+ * than what we got with X. */
+ if (!((chosen_desc->text.fit_x) && (tmp_s > s)))
+ {
+ s = tmp_s;
+ }
+
+ efl_canvas_object_scale_set(ep->object, s);
+ efl_canvas_text_size_native_get(ep->object, NULL, NULL);
+ }
+ }
+
+ /* Final tuning, try going down 90% at a time, hoping it'll
+ * actually end up being correct. */
+ {
+ int i = 5; /* Tries before we give up. */
+ Evas_Coord fw, fh;
+ efl_canvas_text_size_native_get(ep->object, &fw, &fh);
+
+ /* If we are still too big, try reducing the size to
+ * 95% each try. */
+ while ((i > 0) &&
+ ((chosen_desc->text.fit_x && (fw > TO_INT(params->eval.w))) ||
+ (chosen_desc->text.fit_y && (fh > TO_INT(params->eval.h)))))
+ {
+ double tmp_s = _edje_part_recalc_single_textblock_scale_range_adjust(chosen_desc, base_s, s * 0.95);
+
+ /* Break if we are not making any progress. */
+ if (EQ(tmp_s, s))
+ break;
+ s = tmp_s;
+
+ efl_canvas_object_scale_set(ep->object, s);
+ efl_canvas_text_size_native_get(ep->object, &fw, &fh);
+ i--;
+ }
+ }
+ }
+
+ if (stl)
+ {
+ if (evas_object_textblock_style_get(ep->object) != stl->style)
+ evas_object_textblock_style_set(ep->object, stl->style);
+ // FIXME: need to account for editing
+ if (ep->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+ {
+ // do nothing - should be done elsewhere
+ }
+ else
+ {
+ evas_object_textblock_text_markup_set(ep->object, text);
+ }
+
+ if ((ed->file->efl_version.major >= 1) && (ed->file->efl_version.minor >= 19))
+ {
+ _edje_part_recalc_single_textblock_min_max_calc(ep,
+ chosen_desc,
+ params,
+ minw, minh,
+ maxw, maxh);
+ }
+ else
+ {
+ _edje_part_recalc_single_textblock_min_max_calc_legacy(ep,
+ chosen_desc,
+ params,
+ minw, minh,
+ maxw, maxh);
+ }
+ }
+
+ evas_object_textblock_valign_set(ep->object, TO_DOUBLE(chosen_desc->text.align.y));
+ }
+}
+
+void
+_edje_textblock_recalc_apply(Edje *ed, Edje_Real_Part *ep,
+ Edje_Calc_Params *params,
+ Edje_Part_Description_Text *chosen_desc)
+{
+ /* FIXME: this is just an hack. */
+ FLOAT_T sc;
+
+#if 0
+ _get_text(ep);
+#endif
+
+ sc = DIV(ed->scale, ed->file->base_scale);
+ if (EQ(sc, ZERO)) sc = DIV(_edje_scale, ed->file->base_scale);
+ if (chosen_desc->text.fit_x || chosen_desc->text.fit_y)
+ {
+ _edje_part_recalc_single_textblock(sc, ed, ep, chosen_desc, params,
+ NULL, NULL, NULL, NULL);
+ }
+}