merge bidi

This commit is contained in:
Gabor Kiss-Vamosi
2019-10-16 20:54:46 +02:00
26 changed files with 807 additions and 94 deletions

View File

@@ -196,6 +196,12 @@ typedef void * lv_img_decoder_user_data_t;
* font's bitmaps */ * font's bitmaps */
#define LV_ATTRIBUTE_LARGE_CONST #define LV_ATTRIBUTE_LARGE_CONST
/* Export integer constant to binding.
* This macro is used with constants in the form of LV_<CONST> that
* should also appear on lvgl binding API such as Micropython
*/
#define LV_EXPORT_CONST_INT(int_value)
/*=================== /*===================
* HAL settings * HAL settings
*==================*/ *==================*/
@@ -336,14 +342,27 @@ typedef void * lv_font_user_data_t;
/*Can break (wrap) texts on these chars*/ /*Can break (wrap) texts on these chars*/
#define LV_TXT_BREAK_CHARS " ,.;:-_" #define LV_TXT_BREAK_CHARS " ,.;:-_"
/* If a character is at least this long, will break wherever "prettiest" */ /* If a character is at least this long, will break wherever "prettiest" */
#define LV_TXT_LINE_BREAK_LONG_LEN 12 #define LV_TXT_LINE_BREAK_LONG_LEN 12
/* Minimum number of characters of a word to put on a line before a break */ /* Minimum number of characters of a word to put on a line before a break */
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
/* Minimum number of characters of a word to put on a line after a break */ /* Minimum number of characters of a word to put on a line after a break */
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
/* 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 0
#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
/*Change the built in (v)snprintf functions*/ /*Change the built in (v)snprintf functions*/
#define LV_SPRINTF_CUSTOM 0 #define LV_SPRINTF_CUSTOM 0

1
lvgl.h
View File

@@ -34,6 +34,7 @@ extern "C" {
#include "src/lv_font/lv_font.h" #include "src/lv_font/lv_font.h"
#include "src/lv_font/lv_font_fmt_txt.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_btn.h"
#include "src/lv_objx/lv_imgbtn.h" #include "src/lv_objx/lv_imgbtn.h"

View File

@@ -266,6 +266,14 @@
#define LV_ATTRIBUTE_LARGE_CONST #define LV_ATTRIBUTE_LARGE_CONST
#endif #endif
/* Export integer constant to binding.
* This macro is used with constants in the form of LV_<CONST> that
* should also appear on lvgl binding API such as Micropython
*/
#ifndef LV_EXPORT_CONST_INT
#define LV_EXPORT_CONST_INT(int_value)
#endif
/*=================== /*===================
* HAL settings * HAL settings
*==================*/ *==================*/
@@ -465,19 +473,36 @@
#define LV_TXT_BREAK_CHARS " ,.;:-_" #define LV_TXT_BREAK_CHARS " ,.;:-_"
#endif #endif
/* If a character is at least this long, will break wherever "prettiest" */ /* If a character is at least this long, will break wherever "prettiest" */
#ifndef LV_TXT_LINE_BREAK_LONG_LEN #ifndef LV_TXT_LINE_BREAK_LONG_LEN
#define LV_TXT_LINE_BREAK_LONG_LEN 12 #define LV_TXT_LINE_BREAK_LONG_LEN 12
#endif #endif
/* Minimum number of characters of a word to put on a line before a break */ /* Minimum number of characters of a word to put on a line before a break */
#ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN #ifndef LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN
#define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3 #define LV_TXT_LINE_BREAK_LONG_PRE_MIN_LEN 3
#endif #endif
/* Minimum number of characters of a word to put on a line after a break */ /* Minimum number of characters of a word to put on a line after a break */
#ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN #ifndef LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN
#define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3 #define LV_TXT_LINE_BREAK_LONG_POST_MIN_LEN 3
#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 0
#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 #endif
/*Change the built in (v)snprintf functions*/ /*Change the built in (v)snprintf functions*/

View File

@@ -52,6 +52,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 report_style_mod_core(void * style_p, lv_obj_t * obj);
static void refresh_children_style(lv_obj_t * obj); static void refresh_children_style(lv_obj_t * obj);
static void delete_children(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_event_mark_deleted(lv_obj_t * obj);
static void lv_obj_del_async_cb(void * obj); static void lv_obj_del_async_cb(void * obj);
static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area, lv_design_mode_t mode); static lv_design_res_t lv_obj_design(lv_obj_t * obj, const lv_area_t * clip_area, lv_design_mode_t mode);
@@ -207,6 +208,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_en = 0;
new_obj->opa_scale = LV_OPA_COVER; new_obj->opa_scale = LV_OPA_COVER;
new_obj->parent_event = 0; 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->reserved = 0;
new_obj->ext_attr = NULL; new_obj->ext_attr = NULL;
@@ -225,11 +236,22 @@ lv_obj_t * lv_obj_create(lv_obj_t * parent, const lv_obj_t * copy)
new_obj->par = parent; /*Set the parent*/ new_obj->par = parent; /*Set the parent*/
lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t)); lv_ll_init(&(new_obj->child_ll), sizeof(lv_obj_t));
#if LV_USE_BIDI
new_obj->base_dir = LV_BIDI_DIR_INHERIT;
#else
new_obj->base_dir = LV_BIDI_DIR_LTR;
#endif
/*Set coordinates left top corner of parent*/ /*Set coordinates left top corner of parent*/
new_obj->coords.x1 = parent->coords.x1;
new_obj->coords.y1 = parent->coords.y1; new_obj->coords.y1 = parent->coords.y1;
new_obj->coords.x2 = parent->coords.x1 + LV_OBJ_DEF_WIDTH;
new_obj->coords.y2 = parent->coords.y1 + LV_OBJ_DEF_HEIGHT; new_obj->coords.y2 = parent->coords.y1 + LV_OBJ_DEF_HEIGHT;
if(lv_obj_get_base_dir(new_obj) == LV_BIDI_DIR_RTL) {
new_obj->coords.x2 = parent->coords.x2;
new_obj->coords.x1 = parent->coords.x2 - LV_OBJ_DEF_WIDTH;
} else {
new_obj->coords.x1 = parent->coords.x1;
new_obj->coords.x2 = parent->coords.x1 + LV_OBJ_DEF_WIDTH;
}
new_obj->ext_draw_pad = 0; new_obj->ext_draw_pad = 0;
#if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL #if LV_USE_EXT_CLICK_AREA == LV_EXT_CLICK_AREA_FULL
@@ -292,6 +314,7 @@ 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 = LV_OPA_COVER;
new_obj->opa_scale_en = 0; new_obj->opa_scale_en = 0;
new_obj->parent_event = 0; new_obj->parent_event = 0;
new_obj->reserved = 0;
new_obj->ext_attr = NULL; new_obj->ext_attr = NULL;
} }
@@ -725,8 +748,12 @@ void lv_obj_set_size(lv_obj_t * obj, lv_coord_t w, lv_coord_t h)
lv_obj_get_coords(obj, &ori); lv_obj_get_coords(obj, &ori);
/*Set the length and height*/ /*Set the length and height*/
obj->coords.x2 = obj->coords.x1 + w - 1;
obj->coords.y2 = obj->coords.y1 + h - 1; obj->coords.y2 = obj->coords.y1 + h - 1;
if(lv_obj_get_base_dir(obj) == LV_BIDI_DIR_RTL) {
obj->coords.x1 = obj->coords.x2 - w + 1;
} else {
obj->coords.x2 = obj->coords.x1 + w - 1;
}
/*Send a signal to the object with its new coordinates*/ /*Send a signal to the object with its new coordinates*/
obj->signal_cb(obj, LV_SIGNAL_CORD_CHG, &ori); obj->signal_cb(obj, LV_SIGNAL_CORD_CHG, &ori);
@@ -1336,6 +1363,23 @@ void lv_obj_set_parent_event(lv_obj_t * obj, bool en)
obj->parent_event = (en == true ? 1 : 0); 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()`) * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
* @param obj pointer to an object * @param obj pointer to an object
@@ -1757,8 +1801,11 @@ lv_coord_t lv_obj_get_x(const lv_obj_t * obj)
lv_coord_t rel_x; lv_coord_t rel_x;
lv_obj_t * parent = lv_obj_get_parent(obj); lv_obj_t * parent = lv_obj_get_parent(obj);
if(parent) {
rel_x = obj->coords.x1 - parent->coords.x1; rel_x = obj->coords.x1 - parent->coords.x1;
} else {
rel_x = obj->coords.x1;
}
return rel_x; return rel_x;
} }
@@ -1773,8 +1820,11 @@ lv_coord_t lv_obj_get_y(const lv_obj_t * obj)
lv_coord_t rel_y; lv_coord_t rel_y;
lv_obj_t * parent = lv_obj_get_parent(obj); lv_obj_t * parent = lv_obj_get_parent(obj);
if(parent) {
rel_y = obj->coords.y1 - parent->coords.y1; rel_y = obj->coords.y1 - parent->coords.y1;
} else {
rel_y = obj->coords.y1;
}
return rel_y; return rel_y;
} }
@@ -2083,6 +2133,25 @@ bool lv_obj_get_parent_event(const lv_obj_t * obj)
return obj->parent_event == 0 ? false : true; 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 * Get the opa scale enable parameter
* @param obj pointer to an object * @param obj pointer to an object
@@ -2549,6 +2618,22 @@ static void delete_children(lv_obj_t * obj)
lv_mem_free(obj); /*Free the object itself*/ 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) static void lv_event_mark_deleted(lv_obj_t * obj)
{ {
lv_event_temp_data_t * t = event_temp_data_head; 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_ll.h"
#include "../lv_misc/lv_color.h" #include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_log.h" #include "../lv_misc/lv_log.h"
#include "../lv_misc/lv_bidi.h"
#include "../lv_hal/lv_hal.h" #include "../lv_hal/lv_hal.h"
/********************* /*********************
@@ -122,6 +123,7 @@ enum {
LV_SIGNAL_CORD_CHG, /**< Object coordinates/size have changed */ LV_SIGNAL_CORD_CHG, /**< Object coordinates/size have changed */
LV_SIGNAL_PARENT_SIZE_CHG, /**< Parent's size has changed */ LV_SIGNAL_PARENT_SIZE_CHG, /**< Parent's size has changed */
LV_SIGNAL_STYLE_CHG, /**< Object's style 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_REFR_EXT_DRAW_PAD, /**< Object's extra padding has changed */
LV_SIGNAL_GET_TYPE, /**< LittlevGL needs to retrieve the object's type */ LV_SIGNAL_GET_TYPE, /**< LittlevGL needs to retrieve the object's type */
@@ -135,6 +137,7 @@ enum {
LV_SIGNAL_DRAG_BEGIN, LV_SIGNAL_DRAG_BEGIN,
LV_SIGNAL_DRAG_THROW_BEGIN, LV_SIGNAL_DRAG_THROW_BEGIN,
LV_SIGNAL_DRAG_END, LV_SIGNAL_DRAG_END,
/*Group related*/ /*Group related*/
LV_SIGNAL_FOCUS, LV_SIGNAL_FOCUS,
LV_SIGNAL_DEFOCUS, LV_SIGNAL_DEFOCUS,
@@ -220,10 +223,9 @@ typedef struct _lv_obj_t
uint8_t top : 1; /**< 1: If the object or its children is clicked it goes to the foreground*/ uint8_t top : 1; /**< 1: If the object or its children is clicked it goes to the foreground*/
uint8_t opa_scale_en : 1; /**< 1: opa_scale is set*/ 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. */ uint8_t parent_event : 1; /**< 1: Send the object's events to the parent too. */
lv_drag_dir_t drag_dir : 3; /**< Which directions the object can be dragged in */ lv_drag_dir_t drag_dir : 3; /**< Which directions the object can be dragged in */
uint8_t reserved : 5; /**< 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 uint8_t protect; /**< Automatically happening actions can be prevented. 'OR'ed values from
`lv_protect_t`*/ `lv_protect_t`*/
lv_opa_t opa_scale; /**< Scale down the opacity by this factor. Effects all children as well*/ lv_opa_t opa_scale; /**< Scale down the opacity by this factor. Effects all children as well*/
@@ -515,6 +517,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_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()`) * Set the opa scale enable parameter (required to set opa_scale with `lv_obj_set_opa_scale()`)
* @param obj pointer to an object * @param obj pointer to an object
@@ -854,6 +857,9 @@ bool lv_obj_get_drag_parent(const lv_obj_t * obj);
*/ */
bool lv_obj_get_parent_event(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 * Get the opa scale enable parameter
* @param obj pointer to an object * @param obj pointer to an object

View File

@@ -26,6 +26,8 @@ extern "C" {
#define LV_RADIUS_CIRCLE (LV_COORD_MAX) /**< A very big radius to always draw as circle*/ #define LV_RADIUS_CIRCLE (LV_COORD_MAX) /**< A very big radius to always draw as circle*/
#define LV_STYLE_DEGUG_SENTINEL_VALUE 0x12345678 #define LV_STYLE_DEGUG_SENTINEL_VALUE 0x12345678
LV_EXPORT_CONST_INT(LV_RADIUS_CIRCLE);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/

View File

@@ -29,6 +29,9 @@ extern "C" {
#define LV_COORD_MAX ((lv_coord_t)((uint32_t)((uint32_t)1 << (8 * sizeof(lv_coord_t) - 1)) - 1000)) #define LV_COORD_MAX ((lv_coord_t)((uint32_t)((uint32_t)1 << (8 * sizeof(lv_coord_t) - 1)) - 1000))
#define LV_COORD_MIN (-LV_COORD_MAX) #define LV_COORD_MIN (-LV_COORD_MAX)
LV_EXPORT_CONST_INT(LV_COORD_MAX);
LV_EXPORT_CONST_INT(LV_COORD_MIN);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/

321
src/lv_misc/lv_bidi.c Normal file
View File

@@ -0,0 +1,321 @@
/**
* @file lv_bidi.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_bidi.h"
#include <stddef.h>
#include "lv_txt.h"
#if LV_USE_BIDI
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir);
static uint32_t get_next_paragraph(const char * txt);
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t * len);
static void rtl_reverse(char * dest, const char * src, uint32_t len);
static uint32_t char_change_to_pair(uint32_t letter);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_bidi_process(const char * str_in, char * str_out, lv_bidi_dir_t base_dir)
{
if(base_dir == LV_BIDI_DIR_AUTO) base_dir = lv_bidi_detect_base_dir(str_in);
uint32_t par_start = 0;
uint32_t par_len;
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
str_out[par_start] = str_in[par_start];
par_start ++;
}
while(str_in[par_start] != '\0') {
par_len = get_next_paragraph(&str_in[par_start]);
process_paragraph(&str_in[par_start], &str_out[par_start], par_len, base_dir);
par_start += par_len;
while(str_in[par_start] == '\n' || str_in[par_start] == '\r') {
str_out[par_start] = str_in[par_start];
par_start ++;
}
}
str_out[par_start] = '\0';
}
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 */
if(LV_BIDI_BASE_DIR_DEF == LV_BIDI_DIR_AUTO) return LV_BIDI_DIR_LTR;
else return LV_BIDI_BASE_DIR_DEF;
}
lv_bidi_dir_t lv_bidi_get_letter_dir(uint32_t letter)
{
if(lv_bidi_letter_is_rtl(letter)) return LV_BIDI_DIR_RTL;
if(lv_bidi_letter_is_neutral(letter)) return LV_BIDI_DIR_NEUTRAL;
if(lv_bidi_letter_is_weak(letter)) return LV_BIDI_DIR_WEAK;
return LV_BIDI_DIR_LTR;
}
bool lv_bidi_letter_is_weak(uint32_t letter)
{
uint32_t i = 0;
static const char weaks[] = "0123456789";
do {
uint32_t x = lv_txt_encoded_next(weaks, &i);
if(letter == x) {
return true;
}
} while(weaks[i] != '\0');
return false;
}
bool lv_bidi_letter_is_rtl(uint32_t letter)
{
if(letter >= 0x5d0 && letter <= 0x5ea) return true;
if(letter == 0x202E) return true; /*Unicode of LV_BIDI_RLO*/
// if(letter >= 'a' && letter <= 'z') return true;
return false;
}
bool lv_bidi_letter_is_neutral(uint32_t letter)
{
uint16_t i;
static const char neutrals[] = " \t\n\r.,:;'\"`!?%/\\=()[]{}<>@#&$|";
for(i = 0; neutrals[i] != '\0'; i++) {
if(letter == (uint32_t)neutrals[i]) return true;
}
return false;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void process_paragraph(const char * str_in, char * str_out, uint32_t len, lv_bidi_dir_t base_dir)
{
uint32_t run_len = 0;
lv_bidi_dir_t run_dir;
uint32_t rd = 0;
uint32_t wr;
if(base_dir == LV_BIDI_DIR_RTL) wr = len;
else wr = 0;
str_out[len] = '\0';
lv_bidi_dir_t dir = base_dir;
/*Process neutral chars in the beginning*/
while(rd < len) {
uint32_t letter = lv_txt_encoded_next(str_in, &rd);
dir = lv_bidi_get_letter_dir(letter);
if(dir != LV_BIDI_DIR_NEUTRAL && dir != LV_BIDI_DIR_WEAK) break;
}
if(rd && str_in[rd] != '\0') lv_txt_encoded_prev(str_in, &rd);
if(rd) {
if(base_dir == LV_BIDI_DIR_LTR) {
memcpy(&str_out[wr], str_in, rd);
wr += rd;
} else {
wr -= rd;
rtl_reverse(&str_out[wr], str_in, rd);
}
}
/*Get and process the runs*/
while(rd < len) {
run_dir = get_next_run(&str_in[rd], base_dir, &run_len);
if(base_dir == LV_BIDI_DIR_LTR) {
if(run_dir == LV_BIDI_DIR_LTR) memcpy(&str_out[wr], &str_in[rd], run_len);
else rtl_reverse(&str_out[wr], &str_in[rd], run_len);
wr += run_len;
} else {
wr -= run_len;
if(run_dir == LV_BIDI_DIR_LTR) memcpy(&str_out[wr], &str_in[rd], run_len);
else rtl_reverse(&str_out[wr], &str_in[rd], run_len);
}
rd += run_len;
}
}
static uint32_t get_next_paragraph(const char * txt)
{
uint32_t i = 0;
lv_txt_encoded_next(txt, &i);
while(txt[i] != '\0' && txt[i] != '\n' && txt[i] != '\r') {
lv_txt_encoded_next(txt, &i);
}
return i;
}
static lv_bidi_dir_t get_next_run(const char * txt, lv_bidi_dir_t base_dir, uint32_t * len)
{
uint32_t i = 0;
uint32_t letter;
letter = lv_txt_encoded_next(txt, NULL);
lv_bidi_dir_t dir = lv_bidi_get_letter_dir(letter);
/*Find the first strong char. Skip the neutrals*/
while(dir == LV_BIDI_DIR_NEUTRAL || dir == LV_BIDI_DIR_WEAK) {
letter = lv_txt_encoded_next(txt, &i);
dir = lv_bidi_get_letter_dir(letter);
if(txt[i] == '\0' || txt[i] == '\n' || txt[i] == '\r') {
*len = i;
return base_dir;
}
}
lv_bidi_dir_t run_dir = dir;
uint32_t i_prev = i;
uint32_t i_last_strong = i;
/*Find the next char which has different direction*/
lv_bidi_dir_t next_dir = base_dir;
while(txt[i] != '\0'&& txt[i] != '\n' && txt[i] != '\r') {
letter = lv_txt_encoded_next(txt, &i);
next_dir = lv_bidi_get_letter_dir(letter);
/*New dir found?*/
if((next_dir == LV_BIDI_DIR_RTL || next_dir == LV_BIDI_DIR_LTR) && next_dir != run_dir) {
/*Include neutrals if `run_dir == base_dir` */
if(run_dir == base_dir) *len = i_prev;
/*Exclude neutrals if `run_dir != base_dir` */
else *len = i_last_strong;
return run_dir;
}
if(next_dir != LV_BIDI_DIR_NEUTRAL) i_last_strong = i;
i_prev = i;
}
/*Handle end of of string. Apply `base_dir` on trailing neutrals*/
/*Include neutrals if `run_dir == base_dir` */
if(run_dir == base_dir) *len = i_prev;
/*Exclude neutrals if `run_dir != base_dir` */
else *len = i_last_strong;
return run_dir;
}
static void rtl_reverse(char * dest, const char * src, uint32_t len)
{
uint32_t i = len;
uint32_t wr = 0;
while(i) {
uint32_t letter = lv_txt_encoded_prev(src, &i);
/*Keep weak letters (numbers) as LTR*/
if(lv_bidi_letter_is_weak(letter)) {
uint32_t last_weak = i;
uint32_t first_weak = i;
while(i) {
letter = lv_txt_encoded_prev(src, &i);
/*No need to call `char_change_to_pair` because there not such chars here*/
/*Finish on non-weak char */
/*but treat number and currency related chars as weak*/
if(lv_bidi_letter_is_weak(letter) == false && letter != '.' && letter != ',' && letter != '$') {
lv_txt_encoded_next(src, &i); /*Rewind one letter*/
first_weak = i;
break;
}
}
if(i == 0) first_weak = 0;
memcpy(&dest[wr], &src[first_weak], last_weak - first_weak + 1);
wr += last_weak - first_weak + 1;
}
/*Simply store in reversed order*/
else {
uint32_t letter_size = lv_txt_encoded_size((const char *)&src[i]);
/*Swap arithmetical symbols*/
if(letter_size == 1) {
uint32_t new_letter = letter = char_change_to_pair(letter);
dest[wr] = (uint8_t)new_letter;
wr += 1;
}
/*Just store the letter*/
else {
memcpy(&dest[wr], &src[i], letter_size);
wr += letter_size;
}
}
}
}
static uint32_t char_change_to_pair(uint32_t letter)
{
static uint8_t left[] = {"<({["};
static uint8_t right[] = {">)}]"};
uint8_t i;
for(i = 0; left[i] != '\0'; i++) {
if(letter == left[i]) return right[i];
}
for(i = 0; right[i] != '\0'; i++) {
if(letter == right[i]) return left[i];
}
return letter;
}
#endif /*LV_USE_BIDI*/

72
src/lv_misc/lv_bidi.h Normal file
View File

@@ -0,0 +1,72 @@
/**
* @file lv_bifi.h
*
*/
#ifndef LV_BIDI_H
#define LV_BIDI_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_conf.h"
#else
#include "../../../lv_conf.h"
#endif
#include <stdbool.h>
#include <stdint.h>
/*********************
* DEFINES
*********************/
/* Special non printable strong characters.
* They can be inserted to texts to affect the run's direction*/
#define LV_BIDI_LRO "\xE2\x80\xAD" /*U+202D*/
#define LV_BIDI_RLO "\xE2\x80\xAE" /*U+202E*/
/**********************
* TYPEDEFS
**********************/
enum
{
/*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
**********************/
#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);
bool lv_bidi_letter_is_neutral(uint32_t letter);
/**********************
* MACROS
**********************/
#endif /*LV_USE_BIDI*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /*LV_BIDI_H*/

View File

@@ -26,13 +26,14 @@ extern "C" {
/*Possible log level. For compatibility declare it independently from `LV_USE_LOG`*/ /*Possible log level. For compatibility declare it independently from `LV_USE_LOG`*/
#define LV_LOG_LEVEL_TRACE 0 /**< A lot of logs to give detailed information*/ enum {
#define LV_LOG_LEVEL_INFO 1 /**< Log important events*/ LV_LOG_LEVEL_TRACE = 0, /**< A lot of logs to give detailed information*/
#define LV_LOG_LEVEL_WARN 2 /**< Log if something unwanted happened but didn't caused problem*/ LV_LOG_LEVEL_INFO = 1, /**< Log important events*/
#define LV_LOG_LEVEL_ERROR 3 /**< Only critical issue, when the system may fail*/ LV_LOG_LEVEL_WARN = 2, /**< Log if something unwanted happened but didn't caused problem*/
#define LV_LOG_LEVEL_NONE 4 /**< Do not log anything*/ LV_LOG_LEVEL_ERROR = 3, /**< Only critical issue, when the system may fail*/
#define _LV_LOG_LEVEL_NUM 5 /**< Number of log levels */ LV_LOG_LEVEL_NONE = 4, /**< Do not log anything*/
_LV_LOG_LEVEL_NUM = 5 /**< Number of log levels */
};
typedef int8_t lv_log_level_t; typedef int8_t lv_log_level_t;
#if LV_USE_LOG #if LV_USE_LOG

View File

@@ -467,7 +467,7 @@ static uint8_t lv_txt_utf8_size(const char * str)
return 3; return 3;
else if((str[0] & 0xF8) == 0xF0) else if((str[0] & 0xF8) == 0xF0)
return 4; return 4;
return 1; /*If the char was invalid step tell it's 1 byte long*/ return 0; /*If the char was invalid tell it's 1 byte long*/
} }
/** /**
@@ -644,7 +644,8 @@ static uint32_t lv_txt_utf8_get_byte_id(const char * txt, uint32_t utf8_id)
uint32_t i; uint32_t i;
uint32_t byte_cnt = 0; uint32_t byte_cnt = 0;
for(i = 0; i < utf8_id; i++) { for(i = 0; i < utf8_id; i++) {
byte_cnt += lv_txt_encoded_size(&txt[byte_cnt]); uint8_t c_size = lv_txt_encoded_size(&txt[byte_cnt]);
byte_cnt += c_size > 0 ? c_size : 1;
} }
return byte_cnt; return byte_cnt;

View File

@@ -43,6 +43,11 @@ extern "C" {
/** log2(LV_BAR_ANIM_STATE_END) used to normalize data*/ /** log2(LV_BAR_ANIM_STATE_END) used to normalize data*/
#define LV_BAR_ANIM_STATE_NORM 8 #define LV_BAR_ANIM_STATE_NORM 8
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_START);
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_END);
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_INV);
LV_EXPORT_CONST_INT(LV_BAR_ANIM_STATE_NORM);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/

View File

@@ -207,6 +207,8 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
btn_h = lv_obj_get_height(btnm)- act_y - style_bg->body.padding.bottom - 1; btn_h = lv_obj_get_height(btnm)- act_y - style_bg->body.padding.bottom - 1;
} }
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm);
/*Only deal with the non empty lines*/ /*Only deal with the non empty lines*/
if(btn_cnt != 0) { if(btn_cnt != 0) {
/*Calculate the width of all units*/ /*Calculate the width of all units*/
@@ -214,7 +216,8 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
/*Set the button size and positions and set the texts*/ /*Set the button size and positions and set the texts*/
uint16_t i; uint16_t i;
lv_coord_t act_x = style_bg->body.padding.left; lv_coord_t act_x;
lv_coord_t act_unit_w; lv_coord_t act_unit_w;
unit_act_cnt = 0; unit_act_cnt = 0;
for(i = 0; i < btn_cnt; i++) { for(i = 0; i < btn_cnt; i++) {
@@ -225,9 +228,13 @@ void lv_btnm_set_map(const lv_obj_t * btnm, const char * map[])
act_unit_w--; /*-1 because e.g. width = 100 means 101 pixels (0..100)*/ act_unit_w--; /*-1 because e.g. width = 100 means 101 pixels (0..100)*/
/*Always recalculate act_x because of rounding errors */ /*Always recalculate act_x because of rounding errors */
if(base_dir == LV_BIDI_DIR_RTL) {
act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner;
act_x = lv_obj_get_width(btnm) - style_bg->body.padding.right - act_x - act_unit_w - 1;
} else {
act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner + act_x = (unit_act_cnt * all_unit_w) / unit_cnt + i * style_bg->body.padding.inner +
style_bg->body.padding.left; style_bg->body.padding.left;
}
/* Set the button's area. /* Set the button's area.
* If inner padding is zero then use the prev. button x2 as x1 to avoid rounding * If inner padding is zero then use the prev. button x2 as x1 to avoid rounding
* errors*/ * errors*/
@@ -643,7 +650,6 @@ static lv_design_res_t lv_btnm_design(lv_obj_t * btnm, const lv_area_t * clip_ar
} }
/*Draw the object*/ /*Draw the object*/
else if(mode == LV_DESIGN_DRAW_MAIN) { else if(mode == LV_DESIGN_DRAW_MAIN) {
ancestor_design_f(btnm, clip_area, mode); ancestor_design_f(btnm, clip_area, mode);
lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm); lv_btnm_ext_t * ext = lv_obj_get_ext_attr(btnm);
@@ -664,6 +670,10 @@ static lv_design_res_t lv_btnm_design(lv_obj_t * btnm, const lv_area_t * clip_ar
lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE; lv_txt_flag_t txt_flag = LV_TXT_FLAG_NONE;
if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR; if(ext->recolor) txt_flag = LV_TXT_FLAG_RECOLOR;
#if LV_USE_BIDI
char * bidi_buf = lv_mem_alloc(64);
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(btnm);
#endif
for(btn_i = 0; btn_i < ext->btn_cnt; btn_i++, txt_i++) { for(btn_i = 0; btn_i < ext->btn_cnt; btn_i++, txt_i++) {
/*Search the next valid text in the map*/ /*Search the next valid text in the map*/
@@ -733,8 +743,22 @@ static lv_design_res_t lv_btnm_design(lv_obj_t * btnm, const lv_area_t * clip_ar
area_tmp.x2 = area_tmp.x1 + txt_size.x; area_tmp.x2 = area_tmp.x1 + txt_size.x;
area_tmp.y2 = area_tmp.y1 + txt_size.y; area_tmp.y2 = area_tmp.y1 + txt_size.y;
#if LV_USE_BIDI == 0
lv_draw_label(&area_tmp, clip_area, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, -1, -1, NULL); lv_draw_label(&area_tmp, clip_area, btn_style, opa_scale, ext->map_p[txt_i], txt_flag, NULL, -1, -1, NULL);
#else
uint32_t txt_len = strlen(ext->map_p[txt_i]) + 1;
if(txt_len > lv_mem_get_size(bidi_buf)) {
bidi_buf = lv_mem_realloc(bidi_buf, txt_len);
} }
lv_bidi_process(ext->map_p[txt_i], bidi_buf, base_dir);
lv_draw_label(&area_tmp, clip_area, btn_style, opa_scale, bidi_buf, txt_flag, NULL, -1, -1, NULL);
#endif
}
#if LV_USE_BIDI
lv_mem_free(bidi_buf);
#endif
} }
return LV_DESIGN_RES_OK; return LV_DESIGN_RES_OK;
} }

View File

@@ -31,6 +31,8 @@ extern "C" {
#define LV_BTNM_WIDTH_MASK 0x0007 #define LV_BTNM_WIDTH_MASK 0x0007
#define LV_BTNM_BTN_NONE 0xFFFF #define LV_BTNM_BTN_NONE 0xFFFF
LV_EXPORT_CONST_INT(LV_BTNM_BTN_NONE);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/

View File

@@ -34,6 +34,9 @@ extern "C" {
/**Automatically calculate the tick length*/ /**Automatically calculate the tick length*/
#define LV_CHART_TICK_LENGTH_AUTO 255 #define LV_CHART_TICK_LENGTH_AUTO 255
LV_EXPORT_CONST_INT(LV_CHART_POINT_DEF);
LV_EXPORT_CONST_INT(LV_CHART_TICK_LENGTH_AUTO);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/

View File

@@ -21,6 +21,7 @@
#include "../lv_misc/lv_area.h" #include "../lv_misc/lv_area.h"
#include "../lv_misc/lv_color.h" #include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_math.h" #include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_bidi.h"
/********************* /*********************
* DEFINES * DEFINES
@@ -366,23 +367,23 @@ static void lv_cont_layout_row(lv_obj_t * cont)
lv_align_t align; lv_align_t align;
const lv_style_t * style = lv_obj_get_style(cont); const lv_style_t * style = lv_obj_get_style(cont);
lv_coord_t vpad_corr; lv_coord_t vpad_corr;
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(cont);
switch(type) { switch(type) {
case LV_LAYOUT_ROW_T: case LV_LAYOUT_ROW_T:
vpad_corr = style->body.padding.top; vpad_corr = style->body.padding.top;
align = LV_ALIGN_IN_TOP_LEFT; align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_TOP_RIGHT : LV_ALIGN_IN_TOP_LEFT;
break; break;
case LV_LAYOUT_ROW_M: case LV_LAYOUT_ROW_M:
vpad_corr = 0; vpad_corr = 0;
align = LV_ALIGN_IN_LEFT_MID; align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_RIGHT_MID: LV_ALIGN_IN_LEFT_MID;
break; break;
case LV_LAYOUT_ROW_B: case LV_LAYOUT_ROW_B:
vpad_corr = -style->body.padding.bottom; vpad_corr = -style->body.padding.bottom;
align = LV_ALIGN_IN_BOTTOM_LEFT; align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_BOTTOM_RIGHT: LV_ALIGN_IN_BOTTOM_LEFT;
break; break;
default: default:
vpad_corr = 0; vpad_corr = 0;
align = LV_ALIGN_IN_TOP_LEFT; align = base_dir == LV_BIDI_DIR_RTL ? LV_ALIGN_IN_TOP_RIGHT : LV_ALIGN_IN_TOP_LEFT;
break; break;
} }
@@ -391,12 +392,19 @@ static void lv_cont_layout_row(lv_obj_t * cont)
lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG); lv_obj_set_protect(cont, LV_PROTECT_CHILD_CHG);
/* Align the children */ /* Align the children */
lv_coord_t last_cord = style->body.padding.left; lv_coord_t last_cord;
if(base_dir == LV_BIDI_DIR_RTL) last_cord = style->body.padding.right;
else last_cord = style->body.padding.left;
LV_LL_READ_BACK(cont->child_ll, child) LV_LL_READ_BACK(cont->child_ll, child)
{ {
if(lv_obj_get_hidden(child) != false || lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue; if(lv_obj_get_hidden(child) != false || lv_obj_is_protected(child, LV_PROTECT_POS) != false) continue;
lv_obj_align(child, cont, align, last_cord, vpad_corr); // last_cord -= lv_obj_get_width(child);
if(base_dir == LV_BIDI_DIR_RTL) lv_obj_align(child, cont, align, -last_cord, vpad_corr);
else lv_obj_align(child, cont, align, last_cord, vpad_corr);
last_cord += lv_obj_get_width(child) + style->body.padding.inner; last_cord += lv_obj_get_width(child) + style->body.padding.inner;
} }

View File

@@ -113,6 +113,11 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy)
lv_obj_set_drag(scrl, false); lv_obj_set_drag(scrl, false);
lv_page_set_scrl_fit2(new_ddlist, LV_FIT_FILL, LV_FIT_TIGHT); lv_page_set_scrl_fit2(new_ddlist, LV_FIT_FILL, LV_FIT_TIGHT);
/*Save (a later restore) the original X coordinate because it changes as the FITs applies*/
lv_coord_t x;
if(lv_obj_get_base_dir(new_ddlist) == LV_BIDI_DIR_RTL) x = lv_obj_get_x(new_ddlist) + lv_obj_get_width(new_ddlist);
else x = lv_obj_get_x(new_ddlist);
ext->label = lv_label_create(new_ddlist, NULL); ext->label = lv_label_create(new_ddlist, NULL);
lv_cont_set_fit2(new_ddlist, LV_FIT_TIGHT, LV_FIT_NONE); lv_cont_set_fit2(new_ddlist, LV_FIT_TIGHT, LV_FIT_NONE);
lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_HIDE); lv_page_set_sb_mode(new_ddlist, LV_SB_MODE_HIDE);
@@ -120,6 +125,10 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy)
lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3"); lv_ddlist_set_options(new_ddlist, "Option 1\nOption 2\nOption 3");
/*Restore the original X coordinate*/
if(lv_obj_get_base_dir(new_ddlist) == LV_BIDI_DIR_RTL) lv_obj_set_x(new_ddlist, x - lv_obj_get_width(new_ddlist));
else lv_obj_set_x(new_ddlist, x);
/*Set the default styles*/ /*Set the default styles*/
lv_theme_t * th = lv_theme_get_current(); lv_theme_t * th = lv_theme_get_current();
if(th) { if(th) {
@@ -131,6 +140,8 @@ lv_obj_t * lv_ddlist_create(lv_obj_t * par, const lv_obj_t * copy)
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SEL, &lv_style_plain_color);
lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color); lv_ddlist_set_style(new_ddlist, LV_DDLIST_STYLE_SB, &lv_style_pretty_color);
} }
} }
/*Copy an existing drop down list*/ /*Copy an existing drop down list*/
else { else {
@@ -186,7 +197,8 @@ void lv_ddlist_set_options(lv_obj_t * ddlist, const char * options)
lv_ddlist_refr_width(ddlist); 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_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_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; case LV_LABEL_ALIGN_RIGHT: lv_obj_align(ext->label, NULL, LV_ALIGN_IN_RIGHT_MID, 0, 0); break;
@@ -661,6 +673,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); lv_ddlist_ext_t * ext = lv_obj_get_ext_attr(ddlist);
if(sign == LV_SIGNAL_STYLE_CHG) { 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); lv_ddlist_refr_size(ddlist, 0);
} else if(sign == LV_SIGNAL_CLEANUP) { } else if(sign == LV_SIGNAL_CLEANUP) {
ext->label = NULL; ext->label = NULL;
@@ -980,11 +1001,20 @@ static void lv_ddlist_pos_current_option(lv_obj_t * ddlist)
*/ */
static void lv_ddlist_refr_width(lv_obj_t * ddlist) static void lv_ddlist_refr_width(lv_obj_t * ddlist)
{ {
/*Save the current x coordinate because it should be kept after the refrsh*/
lv_coord_t x;
if(lv_obj_get_base_dir(ddlist) == LV_BIDI_DIR_RTL) x = lv_obj_get_x(ddlist) + lv_obj_get_width(ddlist);
else x = lv_obj_get_x(ddlist);
/*Set the TIGHT fit horizontally the set the width to the content*/ /*Set the TIGHT fit horizontally the set the width to the content*/
lv_page_set_scrl_fit2(ddlist, LV_FIT_TIGHT, lv_page_get_scrl_fit_bottom(ddlist)); lv_page_set_scrl_fit2(ddlist, LV_FIT_TIGHT, lv_page_get_scrl_fit_bottom(ddlist));
/*Revert FILL fit to fill the parent with the options area. It allows to RIGHT/CENTER align the text*/ /*Revert FILL fit to fill the parent with the options area. It allows to RIGHT/CENTER align the text*/
lv_page_set_scrl_fit2(ddlist, LV_FIT_FILL, lv_page_get_scrl_fit_bottom(ddlist)); lv_page_set_scrl_fit2(ddlist, LV_FIT_FILL, lv_page_get_scrl_fit_bottom(ddlist));
if(lv_obj_get_base_dir(ddlist) == LV_BIDI_DIR_RTL) lv_obj_set_x(ddlist, x - lv_obj_get_width(ddlist));
else lv_obj_set_x(ddlist, x);
} }
#endif #endif

View File

@@ -131,6 +131,7 @@ lv_obj_t * lv_kb_create(lv_obj_t * par, const lv_obj_t * copy)
lv_obj_set_event_cb(new_kb, lv_kb_def_event_cb); lv_obj_set_event_cb(new_kb, lv_kb_def_event_cb);
lv_btnm_set_map(new_kb, kb_map_lc); lv_btnm_set_map(new_kb, kb_map_lc);
lv_btnm_set_ctrl_map(new_kb, kb_ctrl_lc_map); lv_btnm_set_ctrl_map(new_kb, kb_ctrl_lc_map);
lv_obj_set_base_dir(new_kb, LV_BIDI_DIR_LTR);
/*Set the default styles*/ /*Set the default styles*/
lv_theme_t * th = lv_theme_get_current(); lv_theme_t * th = lv_theme_get_current();
@@ -395,7 +396,7 @@ void lv_kb_def_event_cb(lv_obj_t * kb, lv_event_t event)
/*Add the characters to the text area if set*/ /*Add the characters to the text area if set*/
if(ext->ta == NULL) return; if(ext->ta == NULL) return;
if(strcmp(txt, "Enter") == 0) if(strcmp(txt, LV_SYMBOL_NEW_LINE) == 0)
lv_ta_add_char(ext->ta, '\n'); lv_ta_add_char(ext->ta, '\n');
else if(strcmp(txt, LV_SYMBOL_LEFT) == 0) else if(strcmp(txt, LV_SYMBOL_LEFT) == 0)
lv_ta_cursor_left(ext->ta); lv_ta_cursor_left(ext->ta);

View File

@@ -14,6 +14,7 @@
#include "../lv_core/lv_group.h" #include "../lv_core/lv_group.h"
#include "../lv_misc/lv_color.h" #include "../lv_misc/lv_color.h"
#include "../lv_misc/lv_math.h" #include "../lv_misc/lv_math.h"
#include "../lv_misc/lv_bidi.h"
#include "../lv_misc/lv_printf.h" #include "../lv_misc/lv_printf.h"
/********************* /*********************
@@ -92,7 +93,7 @@ lv_obj_t * lv_label_create(lv_obj_t * par, const lv_obj_t * copy)
ext->static_txt = 0; ext->static_txt = 0;
ext->recolor = 0; ext->recolor = 0;
ext->body_draw = 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->dot_end = LV_LABEL_DOT_END_INV;
ext->long_mode = LV_LABEL_LONG_EXPAND; ext->long_mode = LV_LABEL_LONG_EXPAND;
#if LV_USE_ANIMATION #if LV_USE_ANIMATION
@@ -204,8 +205,14 @@ void lv_label_set_text(lv_obj_t * label, const char * text)
LV_ASSERT_MEM(ext->text); LV_ASSERT_MEM(ext->text);
if(ext->text == NULL) return; if(ext->text == NULL) return;
#if LV_USE_BIDI == 0
strcpy(ext->text, text); strcpy(ext->text, text);
ext->static_txt = 0; /*Now the text is dynamically allocated*/ #else
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(label);
lv_bidi_process(text, ext->text, base_dir);
#endif
/*Now the text is dynamically allocated*/
ext->static_txt = 0;
} }
lv_label_refr_text(label); lv_label_refr_text(label);
@@ -506,7 +513,22 @@ lv_label_align_t lv_label_get_align(const lv_obj_t * label)
LV_ASSERT_OBJ(label, LV_OBJX_NAME); LV_ASSERT_OBJ(label, LV_OBJX_NAME);
lv_label_ext_t * ext = lv_obj_get_ext_attr(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;
} }
/** /**
@@ -578,7 +600,10 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t
if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;
if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;
if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;
lv_label_align_t align = lv_label_get_align(label);
if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;
if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT;
/*If the width will be expanded the set the max length to very big */ /*If the width will be expanded the set the max length to very big */
if(ext->long_mode == LV_LABEL_LONG_EXPAND) { if(ext->long_mode == LV_LABEL_LONG_EXPAND) {
@@ -610,12 +635,12 @@ void lv_label_get_letter_pos(const lv_obj_t * label, uint16_t index, lv_point_t
if(index != line_start) x += style->text.letter_space; if(index != line_start) x += style->text.letter_space;
if(ext->align == LV_LABEL_ALIGN_CENTER) { if(align == LV_LABEL_ALIGN_CENTER) {
lv_coord_t line_w; lv_coord_t line_w;
line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag);
x += lv_obj_get_width(label) / 2 - line_w / 2; x += lv_obj_get_width(label) / 2 - line_w / 2;
} else if(ext->align == LV_LABEL_ALIGN_RIGHT) { } else if(align == LV_LABEL_ALIGN_RIGHT) {
lv_coord_t line_w; lv_coord_t line_w;
line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag);
@@ -650,7 +675,10 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos)
if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;
if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;
if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;
lv_label_align_t align = lv_label_get_align(label);
if(align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER;
if(align == LV_LABEL_ALIGN_RIGHT) flag |= LV_TXT_FLAG_RIGHT;
/*If the width will be expanded set the max length to very big */ /*If the width will be expanded set the max length to very big */
if(ext->long_mode == LV_LABEL_LONG_EXPAND) { if(ext->long_mode == LV_LABEL_LONG_EXPAND) {
@@ -669,11 +697,16 @@ uint16_t lv_label_get_letter_on(const lv_obj_t * label, lv_point_t * pos)
/*Calculate the x coordinate*/ /*Calculate the x coordinate*/
lv_coord_t x = 0; lv_coord_t x = 0;
if(ext->align == LV_LABEL_ALIGN_CENTER) { if(align == LV_LABEL_ALIGN_CENTER) {
lv_coord_t line_w; lv_coord_t line_w;
line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag); line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag);
x += lv_obj_get_width(label) / 2 - line_w / 2; x += lv_obj_get_width(label) / 2 - line_w / 2;
} }
else if(align == LV_LABEL_ALIGN_RIGHT) {
lv_coord_t line_w;
line_w = lv_txt_get_width(&txt[line_start], new_line_start - line_start, font, style->text.letter_space, flag);
x += lv_obj_get_width(label) - line_w;
}
lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT; lv_txt_cmd_state_t cmd_state = LV_TXT_CMD_STATE_WAIT;
@@ -871,7 +904,18 @@ void lv_label_ins_text(lv_obj_t * label, uint32_t pos, const char * txt)
pos = lv_txt_get_encoded_length(ext->text); pos = lv_txt_get_encoded_length(ext->text);
} }
#if LV_USE_BIDI
char * bidi_buf = lv_mem_alloc(ins_len) + 1;
LV_ASSERT_MEM(bidi_buf);
if(bidi_buf == NULL) return;
lv_bidi_process(txt, bidi_buf, lv_obj_get_base_dir(label));
lv_txt_ins(ext->text, pos, bidi_buf);
lv_mem_free(bidi_buf);
#else
lv_txt_ins(ext->text, pos, txt); lv_txt_ins(ext->text, pos, txt);
#endif
lv_label_refr_text(label); lv_label_refr_text(label);
} }
@@ -947,14 +991,13 @@ static lv_design_res_t lv_label_design(lv_obj_t * label, const lv_area_t * clip_
lv_draw_rect(&bg, clip_area, style, lv_obj_get_opa_scale(label)); lv_draw_rect(&bg, clip_area, style, lv_obj_get_opa_scale(label));
} }
/*TEST: draw a background for the label*/ lv_label_align_t align = lv_label_get_align(label);
// lv_draw_rect(&label->coords, mask, &lv_style_plain_color, LV_OPA_COVER);
lv_txt_flag_t flag = LV_TXT_FLAG_NONE; lv_txt_flag_t flag = LV_TXT_FLAG_NONE;
if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR; if(ext->recolor != 0) flag |= LV_TXT_FLAG_RECOLOR;
if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND; if(ext->expand != 0) flag |= LV_TXT_FLAG_EXPAND;
if(ext->align == LV_LABEL_ALIGN_CENTER) flag |= LV_TXT_FLAG_CENTER; if(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_RIGHT) flag |= LV_TXT_FLAG_RIGHT;
/* In ROLL mode the CENTER and RIGHT are pointless so remove them. /* In ROLL mode the CENTER and RIGHT are pointless so remove them.
* (In addition they will result mis-alignment is this case)*/ * (In addition they will result mis-alignment is this case)*/
@@ -1054,6 +1097,18 @@ 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.bottom); label->ext_draw_pad = LV_MATH_MAX(label->ext_draw_pad, style->body.padding.bottom);
} }
} }
else if(sign == LV_SIGNAL_BASE_DIR_CHG) {
#if LV_USE_BIDI
if(ext->static_txt == 0) lv_label_set_text(label, NULL);
#endif
} else if(sign == LV_SIGNAL_GET_TYPE) {
lv_obj_type_t * buf = param;
uint8_t i;
for(i = 0; i < LV_MAX_ANCESTOR_NUM - 1; i++) { /*Find the last set data*/
if(buf->type[i] == NULL) break;
}
buf->type[i] = "lv_label";
}
return res; return res;
} }
@@ -1137,11 +1192,12 @@ static void lv_label_refr_text(lv_obj_t * label)
/*In roll inf. mode keep the size but start offset animations*/ /*In roll inf. mode keep the size but start offset animations*/
else if(ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) { else if(ext->long_mode == LV_LABEL_LONG_SROLL_CIRC) {
#if LV_USE_ANIMATION #if LV_USE_ANIMATION
lv_label_align_t align = lv_label_get_align(label);
lv_anim_t anim; lv_anim_t anim;
anim.var = label; anim.var = label;
anim.repeat = 1; anim.repeat = 1;
anim.playback = 0; anim.playback = 0;
anim.start = 0;
anim.act_time = -(((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) / anim.act_time = -(((lv_font_get_glyph_width(style->text.font, ' ', ' ') + style->text.letter_space) * 1000) /
ext->anim_speed) * ext->anim_speed) *
LV_LABEL_WAIT_CHAR_COUNT; LV_LABEL_WAIT_CHAR_COUNT;
@@ -1152,7 +1208,14 @@ static void lv_label_refr_text(lv_obj_t * label)
bool hor_anim = false; bool hor_anim = false;
if(size.x > lv_obj_get_width(label)) { if(size.x > lv_obj_get_width(label)) {
if(align == LV_LABEL_ALIGN_RIGHT) {
anim.end = 0;
anim.start = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT;
} else {
anim.start = 0;
anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT; anim.end = -size.x - lv_font_get_glyph_width(font, ' ', ' ') * LV_LABEL_WAIT_CHAR_COUNT;
}
anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_x; anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_x;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim); lv_anim_create(&anim);
@@ -1164,7 +1227,14 @@ static void lv_label_refr_text(lv_obj_t * label)
} }
if(size.y > lv_obj_get_height(label) && hor_anim == false) { if(size.y > lv_obj_get_height(label) && hor_anim == false) {
if(align == LV_LABEL_ALIGN_RIGHT) {
anim.end = 0;
anim.start = -size.y - (lv_font_get_line_height(font));
} else {
anim.start = 0;
anim.end = -size.y - (lv_font_get_line_height(font)); anim.end = -size.y - (lv_font_get_line_height(font));
}
anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_y; anim.exec_cb = (lv_anim_exec_xcb_t)lv_label_set_offset_y;
anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end); anim.time = lv_anim_speed_to_time(ext->anim_speed, anim.start, anim.end);
lv_anim_create(&anim); lv_anim_create(&anim);

View File

@@ -35,6 +35,10 @@ extern "C" {
#define LV_LABEL_POS_LAST 0xFFFF #define LV_LABEL_POS_LAST 0xFFFF
#define LV_LABEL_TEXT_SEL_OFF 0xFFFF #define LV_LABEL_TEXT_SEL_OFF 0xFFFF
LV_EXPORT_CONST_INT(LV_LABEL_DOT_NUM);
LV_EXPORT_CONST_INT(LV_LABEL_POS_LAST);
LV_EXPORT_CONST_INT(LV_LABEL_TEXT_SEL_OFF);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
@@ -56,6 +60,7 @@ enum {
LV_LABEL_ALIGN_LEFT, /**< Align text to left */ LV_LABEL_ALIGN_LEFT, /**< Align text to left */
LV_LABEL_ALIGN_CENTER, /**< Align text to center */ LV_LABEL_ALIGN_CENTER, /**< Align text to center */
LV_LABEL_ALIGN_RIGHT, /**< Align text to right */ 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; typedef uint8_t lv_label_align_t;
@@ -65,11 +70,12 @@ typedef struct
/*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/ /*Inherited from 'base_obj' so no inherited ext.*/ /*Ext. of ancestor*/
/*New data for this type */ /*New data for this type */
char * text; /*Text of the label*/ char * text; /*Text of the label*/
union union
{ {
char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled char * tmp_ptr; /* Pointer to the allocated memory containing the character which are replaced by dots (Handled
by the library)*/ 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; } dot;
uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/ uint16_t dot_end; /*The text end position in dot mode (Handled by the library)*/
lv_point_t offset; /*Text draw position offset*/ lv_point_t offset; /*Text draw position offset*/

View File

@@ -218,7 +218,8 @@ lv_obj_t * lv_list_add_btn(lv_obj_t * list, const void * img_src, const char * t
lv_label_set_text(label, txt); lv_label_set_text(label, txt);
lv_obj_set_click(label, false); lv_obj_set_click(label, false);
lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC); lv_label_set_long_mode(label, LV_LABEL_LONG_SROLL_CIRC);
lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad); if(lv_obj_get_base_dir(liste) == LV_BIDI_DIR_RTL) lv_obj_set_width(label, label->coords.x2 - liste->coords.x1 - btn_hor_pad);
else lv_obj_set_width(label, liste->coords.x2 - label->coords.x1 - btn_hor_pad);
if(label_signal == NULL) label_signal = lv_obj_get_signal_cb(label); if(label_signal == NULL) label_signal = lv_obj_get_signal_cb(label);
} }
#if LV_USE_GROUP #if LV_USE_GROUP

View File

@@ -871,8 +871,10 @@ static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param)
/*Automatically move children to the scrollable object*/ /*Automatically move children to the scrollable object*/
else if(sign == LV_SIGNAL_CHILD_CHG) { else if(sign == LV_SIGNAL_CHILD_CHG) {
lv_obj_t * child; lv_obj_t * child;
const lv_style_t * style = lv_page_get_style(page, LV_PAGE_STYLE_SCRL); const lv_style_t * style_bg = lv_page_get_style(page, LV_PAGE_STYLE_BG);
const lv_style_t * style_scrl = lv_page_get_style(page, LV_PAGE_STYLE_SCRL);
lv_fit_t fit_left = lv_page_get_scrl_fit_left(page); lv_fit_t fit_left = lv_page_get_scrl_fit_left(page);
lv_fit_t fit_right = lv_page_get_scrl_fit_right(page);
lv_fit_t fit_top = lv_page_get_scrl_fit_top(page); lv_fit_t fit_top = lv_page_get_scrl_fit_top(page);
child = lv_obj_get_child(page, NULL); child = lv_obj_get_child(page, NULL);
while(child != NULL) { while(child != NULL) {
@@ -880,15 +882,19 @@ static lv_res_t lv_page_signal(lv_obj_t * page, lv_signal_t sign, void * param)
lv_obj_t * tmp = child; lv_obj_t * tmp = child;
child = lv_obj_get_child(page, child); /*Get the next child before move this*/ child = lv_obj_get_child(page, child); /*Get the next child before move this*/
/* Reposition the child to take padding into account (Only if it's on (0;0) now) /* Reposition the child to take padding into account (Only if it's on (0;0) or (widht;height) coordinates now)
* It's required to keep new the object on the same coordinate if FIT is enabled.*/ * It's required to keep new the object on the same coordinate if FIT is enabled.*/
if((tmp->coords.x1 == page->coords.x1) && (fit_left == LV_FIT_TIGHT || fit_left == LV_FIT_FILL)) { if((tmp->coords.x1 == page->coords.x1) && (fit_left == LV_FIT_TIGHT || fit_left == LV_FIT_FILL)) {
tmp->coords.x1 += style->body.padding.left; tmp->coords.x1 += style_scrl->body.padding.left;
tmp->coords.x2 += style->body.padding.left; tmp->coords.x2 += style_scrl->body.padding.left;
}
else if((tmp->coords.x2 == page->coords.x2) && (fit_right == LV_FIT_TIGHT || fit_right == LV_FIT_FILL)) {
tmp->coords.x1 -= style_scrl->body.padding.right + style_bg->body.padding.right;
tmp->coords.x2 -= style_scrl->body.padding.right + style_bg->body.padding.right;
} }
if((tmp->coords.y1 == page->coords.y1) && (fit_top == LV_FIT_TIGHT || fit_top == LV_FIT_FILL)) { if((tmp->coords.y1 == page->coords.y1) && (fit_top == LV_FIT_TIGHT || fit_top == LV_FIT_FILL)) {
tmp->coords.y1 += style->body.padding.top; tmp->coords.y1 += style_scrl->body.padding.top;
tmp->coords.y2 += style->body.padding.top; tmp->coords.y2 += style_scrl->body.padding.top;
} }
lv_obj_set_parent(tmp, ext->scrl); lv_obj_set_parent(tmp, ext->scrl);
} else { } else {

View File

@@ -1850,53 +1850,53 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign, lv_
lv_indev_get_vect(click_source, &vect_act); lv_indev_get_vect(click_source, &vect_act);
if(point_act.x < 0 || point_act.y < 0) return; /*Ignore event from keypad*/ if(point_act.x < 0 || point_act.y < 0) return; /*Ignore event from keypad*/
lv_point_t relative_position; lv_point_t rel_pos;
relative_position.x = point_act.x - label_coords.x1; rel_pos.x = point_act.x - label_coords.x1;
relative_position.y = point_act.y - label_coords.y1; rel_pos.y = point_act.y - label_coords.y1;
lv_coord_t label_width = lv_obj_get_width(ext->label); lv_coord_t label_width = lv_obj_get_width(ext->label);
uint16_t index_of_char_at_position; uint16_t char_id_at_click;
#if LV_LABEL_TEXT_SEL #if LV_LABEL_TEXT_SEL
lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label); lv_label_ext_t * ext_label = lv_obj_get_ext_attr(ext->label);
bool click_outside_label; bool click_outside_label;
/*Check if the click happened on the left side of the area outside the label*/ /*Check if the click happened on the left side of the area outside the label*/
if(relative_position.x < 0) { if(rel_pos.x < 0) {
index_of_char_at_position = 0; char_id_at_click = 0;
click_outside_label = true; click_outside_label = true;
} }
/*Check if the click happened on the right side of the area outside the label*/ /*Check if the click happened on the right side of the area outside the label*/
else if(relative_position.x >= label_width) { else if(rel_pos.x >= label_width) {
index_of_char_at_position = LV_TA_CURSOR_LAST; char_id_at_click = LV_TA_CURSOR_LAST;
click_outside_label = true; click_outside_label = true;
} else { } else {
index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position); char_id_at_click = lv_label_get_letter_on(ext->label, &rel_pos);
click_outside_label = !lv_label_is_char_under_pos(ext->label, &relative_position); click_outside_label = !lv_label_is_char_under_pos(ext->label, &rel_pos);
} }
if(ext->text_sel_en) { if(ext->text_sel_en) {
if(!ext->text_sel_in_prog && !click_outside_label && sign == LV_SIGNAL_PRESSED) { if(!ext->text_sel_in_prog && !click_outside_label && sign == LV_SIGNAL_PRESSED) {
/*Input device just went down. Store the selection start position*/ /*Input device just went down. Store the selection start position*/
ext->tmp_sel_start = index_of_char_at_position; ext->tmp_sel_start = char_id_at_click;
ext->tmp_sel_end = LV_LABEL_TEXT_SEL_OFF; ext->tmp_sel_end = LV_LABEL_TEXT_SEL_OFF;
ext->text_sel_in_prog = 1; ext->text_sel_in_prog = 1;
lv_obj_set_drag(lv_page_get_scrl(ta), false); lv_obj_set_drag(lv_page_get_scrl(ta), false);
} else if(ext->text_sel_in_prog && sign == LV_SIGNAL_PRESSING) { } else if(ext->text_sel_in_prog && sign == LV_SIGNAL_PRESSING) {
/*Input device may be moving. Store the end position */ /*Input device may be moving. Store the end position */
ext->tmp_sel_end = index_of_char_at_position; ext->tmp_sel_end = char_id_at_click;
} else if(ext->text_sel_in_prog && (sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED)) { } else if(ext->text_sel_in_prog && (sign == LV_SIGNAL_PRESS_LOST || sign == LV_SIGNAL_RELEASED)) {
/*Input device is released. Check if anything was selected.*/ /*Input device is released. Check if anything was selected.*/
lv_obj_set_drag(lv_page_get_scrl(ta), true); lv_obj_set_drag(lv_page_get_scrl(ta), true);
} }
} }
if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, index_of_char_at_position); if(ext->text_sel_in_prog || sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, char_id_at_click);
if(ext->text_sel_in_prog) { if(ext->text_sel_in_prog) {
/*If the selected area has changed then update the real values and*/ /*If the selected area has changed then update the real values and*/
/*invalidate the text area.*/
/*Invalidate the text area.*/
if(ext->tmp_sel_start > ext->tmp_sel_end) { if(ext->tmp_sel_start > ext->tmp_sel_end) {
if(ext_label->txt_sel_start != ext->tmp_sel_end || ext_label->txt_sel_end != ext->tmp_sel_start) { if(ext_label->txt_sel_start != ext->tmp_sel_end || ext_label->txt_sel_end != ext->tmp_sel_start) {
ext_label->txt_sel_start = ext->tmp_sel_end; ext_label->txt_sel_start = ext->tmp_sel_end;
@@ -1923,17 +1923,17 @@ static void update_cursor_position_on_click(lv_obj_t * ta, lv_signal_t sign, lv_
} }
#else #else
/*Check if the click happened on the left side of the area outside the label*/ /*Check if the click happened on the left side of the area outside the label*/
if(relative_position.x < 0) { if(rel_pos.x < 0) {
index_of_char_at_position = 0; char_id_at_click = 0;
} }
/*Check if the click happened on the right side of the area outside the label*/ /*Check if the click happened on the right side of the area outside the label*/
else if(relative_position.x >= label_width) { else if(rel_pos.x >= label_width) {
index_of_char_at_position = LV_TA_CURSOR_LAST; char_id_at_click = LV_TA_CURSOR_LAST;
} else { } else {
index_of_char_at_position = lv_label_get_letter_on(ext->label, &relative_position); char_id_at_click = lv_label_get_letter_on(ext->label, &rel_pos);
} }
if(sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, index_of_char_at_position); if(sign == LV_SIGNAL_PRESSED) lv_ta_set_cursor_pos(ta, char_id_at_click);
#endif #endif
} }

View File

@@ -39,6 +39,8 @@ extern "C" {
*********************/ *********************/
#define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/ #define LV_TA_CURSOR_LAST (0x7FFF) /*Put the cursor after the last character*/
LV_EXPORT_CONST_INT(LV_TA_CURSOR_LAST);
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/

View File

@@ -145,20 +145,31 @@ void lv_table_set_cell_value(lv_obj_t * table, uint16_t row, uint16_t col, const
uint32_t cell = row * ext->col_cnt + col; uint32_t cell = row * ext->col_cnt + col;
lv_table_cell_format_t format; lv_table_cell_format_t format;
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(table);
/*Save the format byte*/ /*Save the format byte*/
if(ext->cell_data[cell]) { if(ext->cell_data[cell]) {
format.format_byte = ext->cell_data[cell][0]; format.format_byte = ext->cell_data[cell][0];
} }
/*Initialize the format byte*/ /*Initialize the format byte*/
else { else {
format.s.align = LV_LABEL_ALIGN_LEFT; if(base_dir == LV_BIDI_DIR_LTR) format.s.align = LV_LABEL_ALIGN_LEFT;
else if(base_dir == LV_BIDI_DIR_RTL) format.s.align = LV_LABEL_ALIGN_RIGHT;
else if(base_dir == LV_BIDI_DIR_AUTO) format.s.align = lv_bidi_detect_base_dir(txt);
format.s.right_merge = 0; format.s.right_merge = 0;
format.s.type = 0; format.s.type = 0;
format.s.crop = 0; format.s.crop = 0;
} }
ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/ ext->cell_data[cell] = lv_mem_realloc(ext->cell_data[cell], strlen(txt) + 2); /*+1: trailing '\0; +1: format byte*/
strcpy(ext->cell_data[cell] + 1, txt); /*Leave the format byte*/
#if LV_USE_BIDI == 0
strcpy(ext->cell_data[cell] + 1, txt); /*+1 to skip the format byte*/
#else
lv_bidi_process(txt, ext->cell_data[cell] + 1, base_dir);
#endif
ext->cell_data[cell][0] = format.format_byte; ext->cell_data[cell][0] = format.format_byte;
refr_size(table); refr_size(table);
} }

View File

@@ -143,7 +143,7 @@ lv_obj_t * lv_tabview_create(lv_obj_t * par, const lv_obj_t * copy)
lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_PR, th->style.tabview.btn.tgl_pr); lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_TGL_PR, th->style.tabview.btn.tgl_pr);
} else { } else {
lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, &lv_style_plain); lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BG, &lv_style_plain);
lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_transp); lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_BTN_BG, &lv_style_pretty);//transp);
lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, &lv_style_plain_color); lv_tabview_set_style(new_tabview, LV_TABVIEW_STYLE_INDIC, &lv_style_plain_color);
} }
} }
@@ -319,6 +319,10 @@ void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, lv_anim_enable_t an
ext->tab_cur = id; ext->tab_cur = id;
if(lv_obj_get_base_dir(tabview) == LV_BIDI_DIR_RTL) {
id = (ext->tab_cnt - (id + 1));
}
lv_coord_t cont_x; lv_coord_t cont_x;
switch(ext->btns_pos) { switch(ext->btns_pos) {
@@ -358,6 +362,11 @@ void lv_tabview_set_tab_act(lv_obj_t * tabview, uint16_t id, lv_anim_enable_t an
} }
#endif #endif
lv_bidi_dir_t base_dir = lv_obj_get_base_dir(tabview);
if(base_dir == LV_BIDI_DIR_RTL) id = ext->tab_cnt - id - 1;
/*Move the indicator*/ /*Move the indicator*/
const lv_style_t * tabs_style = lv_obj_get_style(ext->btns); const lv_style_t * tabs_style = lv_obj_get_style(ext->btns);
lv_coord_t indic_size; lv_coord_t indic_size;
@@ -741,7 +750,6 @@ static lv_res_t tabview_scrl_signal(lv_obj_t * tabview_scrl, lv_signal_t sign, v
if(res != LV_RES_OK) return res; if(res != LV_RES_OK) return res;
} }
return res; return res;
} }