bidi: add LV_LABEL_ALIGN_AUTO, LV_BIDI_DIR_AOUT/INHERIT, LV_SIGNAL_BASE_DIR_CHG

This commit is contained in:
Gabor Kiss-Vamosi
2019-10-08 16:26:55 +02:00
parent c64dc1d645
commit 6190763382
11 changed files with 211 additions and 25 deletions

View File

@@ -297,6 +297,19 @@ typedef void * lv_font_user_data_t;
/*Can break (wrap) texts on these chars*/
#define LV_TXT_BREAK_CHARS " ,.;:-_"
/* Support bidirectional texts.
* Allows mixing Left-to-Right and Right-to-Left texts.
* The direction will be processed according to the Unicode Bidirectioanl Algorithm:
* https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
#define LV_USE_BIDI 1
#if LV_USE_BIDI
/* Set the default direction. Supported values:
* `LV_BIDI_DIR_LTR` Left-to-Right
* `LV_BIDI_DIR_RTL` Right-to-Left
* `LV_BIDI_DIR_AUTO` detect texts base direction */
#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO
#endif
/*===================
* LV_OBJ SETTINGS
*==================*/

1
lvgl.h
View File

@@ -33,6 +33,7 @@ extern "C" {
#include "src/lv_font/lv_font.h"
#include "src/lv_font/lv_font_fmt_txt.h"
#include "src/lv_misc/lv_bidi.h"
#include "src/lv_objx/lv_btn.h"
#include "src/lv_objx/lv_imgbtn.h"

View File

@@ -412,6 +412,23 @@
#define LV_TXT_BREAK_CHARS " ,.;:-_"
#endif
/* Support bidirectional texts.
* Allows mixing Left-to-Right and Right-to-Left texts.
* The direction will be processed according to the Unicode Bidirectioanl Algorithm:
* https://www.w3.org/International/articles/inline-bidi-markup/uba-basics*/
#ifndef LV_USE_BIDI
#define LV_USE_BIDI 1
#endif
#if LV_USE_BIDI
/* Set the default direction. Supported values:
* `LV_BIDI_DIR_LTR` Left-to-Right
* `LV_BIDI_DIR_RTL` Right-to-Left
* `LV_BIDI_DIR_AUTO` detect texts base direction */
#ifndef LV_BIDI_BASE_DIR_DEF
#define LV_BIDI_BASE_DIR_DEF LV_BIDI_DIR_AUTO
#endif
#endif
/*===================
* LV_OBJ SETTINGS
*==================*/

View File

@@ -49,6 +49,7 @@ static void refresh_children_position(lv_obj_t * obj, lv_coord_t x_diff, lv_coor
static void report_style_mod_core(void * style_p, lv_obj_t * obj);
static void refresh_children_style(lv_obj_t * obj);
static void delete_children(lv_obj_t * obj);
static void base_dir_refr_children(lv_obj_t * obj);
static void lv_event_mark_deleted(lv_obj_t * obj);
static void lv_obj_del_async_cb(void * obj);
static bool lv_obj_design(lv_obj_t * obj, const lv_area_t * mask_p, lv_design_mode_t mode);
@@ -204,6 +205,16 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
new_obj->opa_scale_en = 0;
new_obj->opa_scale = LV_OPA_COVER;
new_obj->parent_event = 0;
#if LV_USE_BIDI
#if LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_LTR || LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_RTL || LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_AUTO
new_obj->base_dir = LV_BIDI_BASE_DIR_DEF;
#else
#error "`LV_BIDI_BASE_DIR_DEF` should be `LV_BASE_DIR_LTR` or `LV_BASE_DIR_RTL` (See lv_conf.h)"
#endif
#else
new_obj->base_dir = LV_BIDI_DIR_LTR;
#endif
new_obj->reserved = 0;
new_obj->ext_attr = NULL;
@@ -288,6 +299,12 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
new_obj->opa_scale = LV_OPA_COVER;
new_obj->opa_scale_en = 0;
new_obj->parent_event = 0;
#if LV_USE_BIDI
new_obj->base_dir = LV_BIDI_DIR_INHERIT;
#else
new_obj->base_dir = LV_BIDI_DIR_LTR;
#endif
new_obj->reserved = 0;
new_obj->ext_attr = NULL;
}
@@ -1266,6 +1283,23 @@ void lv_obj_set_parent_event(lv_obj_t * obj, bool en)
obj->parent_event = (en == true ? 1 : 0);
}
void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir)
{
if(dir != LV_BIDI_DIR_LTR && dir != LV_BIDI_DIR_RTL &&
dir != LV_BIDI_DIR_AUTO && dir != LV_BIDI_DIR_INHERIT) {
LV_LOG_WARN("lv_obj_set_base_dir: invalid base dir");
return;
}
obj->base_dir = dir;
lv_signal_send(obj, LV_SIGNAL_BASE_DIR_CHG, NULL);
/* Notify the children about the parent base dir has changed.
* (The children might have `LV_BIDI_DIR_INHERIT`)*/
base_dir_refr_children(obj);
}
/**
* Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
* @param obj pointer to an object
@@ -1931,6 +1965,25 @@ bool lv_obj_get_parent_event(const lv_obj_t * obj)
return obj->parent_event == 0 ? false : true;
}
lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj)
{
#if LV_USE_BIDI
const lv_obj_t * parent = obj;
while(parent) {
if(parent->base_dir != LV_BIDI_DIR_INHERIT) return parent->base_dir;
parent = lv_obj_get_parent(parent);
}
return LV_BIDI_BASE_DIR_DEF;
#else
return LV_BIDI_DIR_LTR;
#endif
}
/**
* Get the opa scale enable parameter
* @param obj pointer to an object
@@ -2326,6 +2379,22 @@ static void delete_children(lv_obj_t * obj)
lv_mem_free(obj); /*Free the object itself*/
}
static void base_dir_refr_children(lv_obj_t * obj)
{
lv_obj_t * child;
child = lv_obj_get_child(obj, NULL);
while(child) {
if(child->base_dir == LV_BIDI_DIR_INHERIT) {
lv_signal_send(child, LV_SIGNAL_BASE_DIR_CHG, NULL);
base_dir_refr_children(child);
}
child = lv_obj_get_child(obj, child);
}
}
static void lv_event_mark_deleted(lv_obj_t * obj)
{
lv_event_temp_data_t * t = event_temp_data_head;

View File

@@ -28,6 +28,7 @@ extern "C" {
#include "../lv_misc/lv_ll.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_log.h"
#include "../lv_misc/lv_bidi.h"
#include "../lv_hal/lv_hal.h"
/*********************
@@ -112,6 +113,7 @@ enum {
LV_SIGNAL_CORD_CHG, /**< Object coordinates/size have changed */
LV_SIGNAL_PARENT_SIZE_CHG, /**< Parent's size has changed */
LV_SIGNAL_STYLE_CHG, /**< Object's style has changed */
LV_SIGNAL_BASE_DIR_CHG, /**<The base dir has changed*/
LV_SIGNAL_REFR_EXT_DRAW_PAD, /**< Object's extra padding has changed */
LV_SIGNAL_GET_TYPE, /**< LittlevGL needs to retrieve the object's type */
@@ -124,6 +126,7 @@ enum {
LV_SIGNAL_LONG_PRESS_REP, /**< Called after `LV_INDEV_LONG_PRESS_TIME` in every `LV_INDEV_LONG_PRESS_REP_TIME` ms. Not called if dragged.*/
LV_SIGNAL_DRAG_BEGIN,
LV_SIGNAL_DRAG_END,
/*Group related*/
LV_SIGNAL_FOCUS,
LV_SIGNAL_DEFOCUS,
@@ -218,7 +221,8 @@ typedef struct _lv_obj_t
uint8_t opa_scale_en : 1; /**< 1: opa_scale is set*/
uint8_t parent_event : 1; /**< 1: Send the object's events to the parent too. */
lv_drag_dir_t drag_dir : 2; /**< Which directions the object can be dragged in */
uint8_t reserved : 6; /**< Reserved for future use*/
lv_bidi_dir_t base_dir : 2; /**< Base direction of texts related to this object */
uint8_t reserved : 3; /**< Reserved for future use*/
uint8_t protect; /**< Automatically happening actions can be prevented. 'OR'ed values from
`lv_protect_t`*/
lv_opa_t opa_scale; /**< Scale down the opacity by this factor. Effects all children as well*/
@@ -510,6 +514,7 @@ void lv_obj_set_drag_parent(lv_obj_t * obj, bool en);
*/
void lv_obj_set_parent_event(lv_obj_t * obj, bool en);
void lv_obj_set_base_dir(lv_obj_t * obj, lv_bidi_dir_t dir);
/**
* Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
* @param obj pointer to an object
@@ -849,6 +854,9 @@ bool lv_obj_get_drag_parent(const lv_obj_t * obj);
*/
bool lv_obj_get_parent_event(const lv_obj_t * obj);
lv_bidi_dir_t lv_obj_get_base_dir(const lv_obj_t * obj);
/**
* Get the opa scale enable parameter
* @param obj pointer to an object

View File

@@ -89,11 +89,11 @@ void lv_style_init(void)
lv_style_scr.body.shadow.color = LV_COLOR_GRAY;
lv_style_scr.body.shadow.type = LV_SHADOW_FULL;
lv_style_scr.body.shadow.width = 0;
LV_FONT_DECLARE(lv_font_heb_16);
lv_style_scr.text.opa = LV_OPA_COVER;
lv_style_scr.text.color = lv_color_make(0x30, 0x30, 0x30);
lv_style_scr.text.sel_color = lv_color_make(0x55, 0x96, 0xd8);
lv_style_scr.text.font = LV_FONT_DEFAULT;
lv_style_scr.text.font = &lv_font_heb_16;//LV_FONT_DEFAULT;
lv_style_scr.text.letter_space = 0;
lv_style_scr.text.line_space = 2;

View File

@@ -10,6 +10,8 @@
#include <stddef.h>
#include "lv_txt.h"
#if LV_USE_BIDI
/*********************
* DEFINES
*********************/
@@ -62,7 +64,6 @@ void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir
if(dir != LV_BIDI_DIR_NEUTRAL) break;
}
/*if there were neutrals in the beginning apply `base_dir` on them */
if(rd && str_in[rd] != '\0') lv_txt_encoded_prev(str_in, &rd);
if(rd) {
@@ -110,6 +111,21 @@ void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir
}
lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt)
{
uint32_t i = 0;
uint32_t letter;
while(txt[i] != '\0') {
letter = lv_txt_encoded_next(txt, &i);
lv_bidi_dir_t dir;
dir = lv_bidi_get_letter_dir(letter);
if(dir == LV_BIDI_DIR_RTL || dir == LV_BIDI_DIR_LTR) return dir;
}
/*If there were no strong char earlier return with the default base dir */
return LV_BIDI_BASE_DIR_DEF;
}
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter)
{
@@ -279,7 +295,6 @@ static uint32_t char_change_to_pair(uint32_t letter)
}
return letter;
}
#endif /*LV_USE_BIDI*/

View File

@@ -23,19 +23,27 @@ extern "C" {
/**********************
* TYPEDEFS
**********************/
typedef enum
enum
{
LV_BIDI_DIR_LTR,
LV_BIDI_DIR_RTL,
LV_BIDI_DIR_NEUTRAL,
LV_BIDI_DIR_WEAK,
}lv_bidi_dir_t;
/*The first 4 values are stored in `lv_obj_t` on 2 bits*/
LV_BIDI_DIR_LTR = 0x00,
LV_BIDI_DIR_RTL = 0x01,
LV_BIDI_DIR_AUTO = 0x02,
LV_BIDI_DIR_INHERIT = 0x03,
LV_BIDI_DIR_NEUTRAL = 0x20,
LV_BIDI_DIR_WEAK = 0x21,
};
typedef uint8_t lv_bidi_dir_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir);
#if LV_USE_BIDI
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir);
lv_bidi_dir_t lv_bidi_detect_base_dir(const char * txt);
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter);
bool lv_bidi_letter_is_weak(uint32_t letter);
bool lv_bidi_letter_is_rtl(uint32_t letter);
@@ -45,6 +53,8 @@ bool lv_bidi_letter_is_neutral(uint32_t letter);
* MACROS
**********************/
#endif /*LV_USE_BIDI*/
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@@ -180,7 +180,8 @@ void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options)
lv_ddlist_refr_width(ddlist);
switch(lv_label_get_align(ext->label)) {
lv_label_align_t align = lv_label_get_align(ext->label);
switch(align) {
case LV_LABEL_ALIGN_LEFT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break;
case LV_LABEL_ALIGN_CENTER: lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0); break;
case LV_LABEL_ALIGN_RIGHT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break;
@@ -621,6 +622,15 @@ static lv_res_t lv_ddlist_signal(lv_obj_t * ddlist, lv_signal_t sign, void * par
lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
if(sign == LV_SIGNAL_STYLE_CHG) {
lv_ddlist_refr_size(ddlist, 0);
} else if(sign == LV_SIGNAL_BASE_DIR_CHG) {
lv_label_align_t align = lv_label_get_align(ext->label);
switch(align) {
case LV_LABEL_ALIGN_LEFT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_LEFT_MID, 0, 0); break;
case LV_LABEL_ALIGN_CENTER: lv_obj_align(ext->label, NULL, LV_ALIGN_CENTER, 0, 0); break;
case LV_LABEL_ALIGN_RIGHT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break;
}
lv_ddlist_refr_size(ddlist, 0);
} else if(sign == LV_SIGNAL_CLEANUP) {
ext->label = NULL;

View File

@@ -13,6 +13,7 @@
#include "../lv_core/lv_group.h"
#include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_bidi.h"
/*********************
* DEFINES
@@ -88,7 +89,7 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy)
ext->static_txt = 0;
ext->recolor = 0;
ext->body_draw = 0;
ext->align = LV_LABEL_ALIGN_LEFT;
ext->align = LV_LABEL_ALIGN_AUTO;
ext->dot_end = LV_LABEL_DOT_END_INV;
ext->long_mode = LV_LABEL_LONG_EXPAND;
#if LV_USE_ANIMATION
@@ -190,14 +191,33 @@ void lv_label_set_text(lv_obj_t * label, const char * text)
if(ext->text != NULL && ext->static_txt == 0) {
lv_mem_free(ext->text);
ext->text = NULL;
#if LV_USE_BIDI
lv_mem_free(ext->text_ori);
ext->text_ori = NULL;
#endif
}
ext->text = lv_mem_alloc(len);
lv_mem_assert(ext->text);
if(ext->text == NULL) return;
#if LV_USE_BIDI == 0
strcpy(ext->text, text);
ext->static_txt = 0; /*Now the text is dynamically allocated*/
#else
ext->text_ori = lv_mem_alloc(len);
lv_mem_assert(ext->text_ori);
if(ext->text_ori == NULL) return;
strcpy(ext->text_ori, text);
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label);
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(text);
lv_bidi_process(ext->text_ori, ext->text, base_dir);
#endif
/*Now the text is dynamically allocated*/
ext->static_txt = 0;
}
lv_label_refr_text(label);
@@ -425,7 +445,22 @@ lv_label_long_mode_t lv_label_get_long_mode(const lv_obj_t * label)
lv_label_align_t lv_label_get_align(const lv_obj_t * label)
{
lv_label_ext_t * ext = lv_obj_get_ext_attr(label);
return ext->align;
lv_label_align_t align = ext->align;
if(align == LV_LABEL_ALIGN_AUTO) {
#if LV_USE_BIDI
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label);
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(ext->text);
if(base_dir == LV_BIDI_DIR_LTR) align = LV_LABEL_ALIGN_LEFT;
else if (base_dir == LV_BIDI_DIR_RTL) align = LV_LABEL_ALIGN_RIGHT;
#else
align = LV_LABEL_ALIGN_LEFT;
#endif
}
return align;
}
/**
@@ -842,14 +877,13 @@ static bool lv_label_design(lv_obj_t * label, const lv_area_t * mask, lv_design_
lv_draw_rect(&bg, mask, style, lv_obj_get_opa_scale(label));
}
/*TEST: draw a background for the label*/
// lv_draw_rect(&label->coords, mask, &lv_style_plain_color, LV_OPA_COVER);
lv_label_align_t align = lv_label_get_align(label);
lv_txt_flag_t flag = LV_TXT_FLAG_NONE;
if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;
if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;
if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;
if(ext->align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT;
if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;
if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT;
/* In ROLL mode the CENTER and RIGHT are pointless so remove them.
* (In addition they will result mis-alignment is this case)*/
@@ -947,6 +981,9 @@ static lv_res_t lv_label_signal(lv_obj_t * label, lv_signal_t sign, void * param
label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.top);
label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.bottom);
}
}
else if(sign == LV_SIGNAL_BASE_DIR_CHG) {
if(ext->static_txt == 0) lv_label_set_text(label, NULL);
} else if(sign == LV_SIGNAL_GET_TYPE) {
lv_obj_type_t * buf = param;
uint8_t i;

View File

@@ -55,6 +55,7 @@ enum {
LV_LABEL_ALIGN_LEFT, /**< Align text to left */
LV_LABEL_ALIGN_CENTER, /**< Align text to center */
LV_LABEL_ALIGN_RIGHT, /**< Align text to right */
LV_LABEL_ALIGN_AUTO, /**< Use LEFT or RIGHT depending on the direction of the text (LTR/RTL)*/
};
typedef uint8_t lv_label_align_t;
@@ -64,11 +65,16 @@ typedef struct
/*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/
/*New data for this type */
char * text; /*Text of the label*/
#if LV_USE_BIDI
char * text_ori; /*The original text. With BiDi `text` stores the characters in "bidi" ordered text*/
#endif
union
{
char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled
by the library)*/
char tmp[sizeof(char *)]; /* Directly store the characters if <=4 characters */
char tmp[LV_LABEL_DOT_NUM + 1]; /* Directly store the characters if <=4 characters */
} dot;
uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/
lv_point_t offset; /*Text draw position offset*/