diff --git a/demos/render/lv_demo_render.c b/demos/render/lv_demo_render.c
index 6a3a3e02b..0c0f61836 100644
--- a/demos/render/lv_demo_render.c
+++ b/demos/render/lv_demo_render.c
@@ -214,6 +214,7 @@ static lv_obj_t * box_shadow_obj_create(lv_obj_t * parent, int32_t col, int32_t
lv_obj_t * obj = lv_obj_create(parent);
lv_obj_remove_style_all(obj);
lv_obj_set_style_bg_opa(obj, LV_OPA_20, 0);
+ lv_obj_set_style_bg_color(obj, lv_color_black(), 0);
lv_obj_set_style_shadow_color(obj, lv_color_hex3(0xf00), 0);
lv_obj_set_style_opa(obj, opa_saved, 0);
lv_obj_set_size(obj, DEF_WIDTH - 20, DEF_HEIGHT - 5);
@@ -452,6 +453,7 @@ static lv_obj_t * arc_obj_create(lv_obj_t * parent, int32_t col, int32_t row, in
lv_obj_t * obj = lv_arc_create(parent);
lv_obj_remove_style_all(obj);
lv_obj_set_style_arc_width(obj, w, 0);
+ lv_obj_set_style_arc_color(obj, lv_color_white(), 0);
lv_obj_set_style_opa(obj, opa_saved, 0);
lv_arc_set_bg_angles(obj, start, end);
lv_obj_set_size(obj, DEF_HEIGHT, DEF_HEIGHT);
diff --git a/docs/overview/style-props.md b/docs/overview/style-props.md
new file mode 100644
index 000000000..89d494be4
--- /dev/null
+++ b/docs/overview/style-props.md
@@ -0,0 +1,1033 @@
+# Style properties
+
+## Size and position
+Properties related to size, position, alignment and layout of the objects.
+
+### width
+Sets the width of object. Pixel, percentage and `LV_SIZE_CONTENT` values can be used. Percentage values are relative to the width of the parent's content area.
+
+- Default Widget dependent
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### min_width
+Sets a minimal width. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### max_width
+Sets a maximal width. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area.
+
+- Default LV_COORD_MAX
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### height
+Sets the height of object. Pixel, percentage and `LV_SIZE_CONTENT` can be used. Percentage values are relative to the height of the parent's content area.
+
+- Default Widget dependent
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### min_height
+Sets a minimal height. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### max_height
+Sets a maximal height. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area.
+
+- Default LV_COORD_MAX
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### length
+Its meaning depends on the type of the widget. For example in case of lv_scale it means the length of the ticks.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### x
+Set the X coordinate of the object considering the set `align`. Pixel and percentage values can be used. Percentage values are relative to the width of the parent's content area.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### y
+Set the Y coordinate of the object considering the set `align`. Pixel and percentage values can be used. Percentage values are relative to the height of the parent's content area.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### align
+Set the alignment which tells from which point of the parent the X and Y coordinates should be interpreted. The possible values are: `LV_ALIGN_DEFAULT`, `LV_ALIGN_TOP_LEFT/MID/RIGHT`, `LV_ALIGN_BOTTOM_LEFT/MID/RIGHT`, `LV_ALIGN_LEFT/RIGHT_MID`, `LV_ALIGN_CENTER`. `LV_ALIGN_DEFAULT` means `LV_ALIGN_TOP_LEFT` with LTR base direction and `LV_ALIGN_TOP_RIGHT` with RTL base direction.
+
+- Default `LV_ALIGN_DEFAULT`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### transform_width
+Make the object wider on both sides with this value. Pixel and percentage (with `lv_pct(x)`) values can be used. Percentage values are relative to the object's width.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### transform_height
+Make the object higher on both sides with this value. Pixel and percentage (with `lv_pct(x)`) values can be used. Percentage values are relative to the object's height.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### translate_x
+Move the object with this value in X direction. Applied after layouts, aligns and other positioning. Pixel and percentage (with `lv_pct(x)`) values can be used. Percentage values are relative to the object's width.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### translate_y
+Move the object with this value in Y direction. Applied after layouts, aligns and other positioning. Pixel and percentage (with `lv_pct(x)`) values can be used. Percentage values are relative to the object's height.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### transform_scale_x
+Zoom an objects horizontally. The value 256 (or `LV_SCALE_NONE`) means normal size, 128 half size, 512 double size, and so on
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw Yes
+
+
+### transform_scale_y
+Zoom an objects vertically. The value 256 (or `LV_SCALE_NONE`) means normal size, 128 half size, 512 double size, and so on
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw Yes
+
+
+### transform_rotation
+Rotate an objects. The value is interpreted in 0.1 degree units. E.g. 450 means 45 deg.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw Yes
+
+
+### transform_pivot_x
+Set the pivot point's X coordinate for transformations. Relative to the object's top left corner'
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### transform_pivot_y
+Set the pivot point's Y coordinate for transformations. Relative to the object's top left corner'
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### transform_skew_x
+Skew an object horizontally. The value is interpreted in 0.1 degree units. E.g. 450 means 45 deg.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw Yes
+
+
+### transform_skew_y
+Skew an object vertically. The value is interpreted in 0.1 degree units. E.g. 450 means 45 deg.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw Yes
+
+
+## Padding
+Properties to describe spacing between the parent's sides and the children and among the children. Very similar to the padding properties in HTML.
+
+### pad_top
+Sets the padding on the top. It makes the content area smaller in this direction.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### pad_bottom
+Sets the padding on the bottom. It makes the content area smaller in this direction.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### pad_left
+Sets the padding on the left. It makes the content area smaller in this direction.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### pad_right
+Sets the padding on the right. It makes the content area smaller in this direction.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### pad_row
+Sets the padding between the rows. Used by the layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### pad_column
+Sets the padding between the columns. Used by the layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+## Margin
+Properties to describe spacing around an object. Very similar to the margin properties in HTML.
+
+### margin_top
+Sets the margin on the top. The object will keep this space from its siblings in layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### margin_bottom
+Sets the margin on the bottom. The object will keep this space from its siblings in layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### margin_left
+Sets the margin on the left. The object will keep this space from its siblings in layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### margin_right
+Sets the margin on the right. The object will keep this space from its siblings in layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+## Background
+Properties to describe the background color and image of the objects.
+
+### bg_color
+Set the background color of the object.
+
+- Default `0xffffff`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_opa
+Set the opacity of the background. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_TRANSP`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_grad_color
+Set the gradient color of the background. Used only if `grad_dir` is not `LV_GRAD_DIR_NONE`
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_grad_dir
+Set the direction of the gradient of the background. The possible values are `LV_GRAD_DIR_NONE/HOR/VER`.
+
+- Default `LV_GRAD_DIR_NONE`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_main_stop
+Set the point from which the background color should start for gradients. 0 means to top/left side, 255 the bottom/right side, 128 the center, and so on
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_grad_stop
+Set the point from which the background's gradient color should start. 0 means to top/left side, 255 the bottom/right side, 128 the center, and so on
+
+- Default 255
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_main_opa
+Set the opacity of the first gradient color
+
+- Default 255
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_grad_opa
+Set the opacity of the second gradient color
+
+- Default 255
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_grad
+Set the gradient definition. The pointed instance must exist while the object is alive. NULL to disable. It wraps `BG_GRAD_COLOR`, `BG_GRAD_DIR`, `BG_MAIN_STOP` and `BG_GRAD_STOP` into one descriptor and allows creating gradients with more colors too. If it's set other gradient related properties will be ignored'
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_image_src
+Set a background image. Can be a pointer to `lv_image_dsc_t`, a path to a file or an `LV_SYMBOL_...`
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### bg_image_opa
+Set the opacity of the background image. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_image_recolor
+Set a color to mix to the background image.
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_image_recolor_opa
+Set the intensity of background image recoloring. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means no mixing, 255, `LV_OPA_100` or `LV_OPA_COVER` means full recoloring, other values or LV_OPA_10, LV_OPA_20, etc are interpreted proportionally.
+
+- Default `LV_OPA_TRANSP`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### bg_image_tiled
+If enabled the background image will be tiled. The possible values are `true` or `false`.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+## Border
+Properties to describe the borders
+
+### border_color
+Set the color of the border
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### border_opa
+Set the opacity of the border. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### border_width
+Set the width of the border. Only pixel values can be used.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### border_side
+Set only which side(s) the border should be drawn. The possible values are `LV_BORDER_SIDE_NONE/TOP/BOTTOM/LEFT/RIGHT/INTERNAL`. OR-ed values can be used as well, e.g. `LV_BORDER_SIDE_TOP | LV_BORDER_SIDE_LEFT`.
+
+- Default `LV_BORDER_SIDE_NONE`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### border_post
+Sets whether the border should be drawn before or after the children are drawn. `true`: after children, `false`: before children
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+## Outline
+Properties to describe the outline. It's like a border but drawn outside of the rectangles.
+
+### outline_width
+Set the width of the outline in pixels.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### outline_color
+Set the color of the outline.
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### outline_opa
+Set the opacity of the outline. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### outline_pad
+Set the padding of the outline, i.e. the gap between object and the outline.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+## Shadow
+Properties to describe the shadow drawn under the rectangles.
+
+### shadow_width
+Set the width of the shadow in pixels. The value should be >= 0.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### shadow_offset_x
+Set an offset on the shadow in pixels in X direction.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### shadow_offset_y
+Set an offset on the shadow in pixels in Y direction.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### shadow_spread
+Make the shadow calculation to use a larger or smaller rectangle as base. The value can be in pixel to make the area larger/smaller
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### shadow_color
+Set the color of the shadow
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### shadow_opa
+Set the opacity of the shadow. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+## Image
+Properties to describe the images
+
+### image_opa
+Set the opacity of an image. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### image_recolor
+Set color to mixt to the image.
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### image_recolor_opa
+Set the intensity of the color mixing. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+## Line
+Properties to describe line-like objects
+
+### line_width
+Set the width of the lines in pixel.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### line_dash_width
+Set the width of dashes in pixel. Note that dash works only on horizontal and vertical lines
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### line_dash_gap
+Set the gap between dashes in pixel. Note that dash works only on horizontal and vertical lines
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### line_rounded
+Make the end points of the lines rounded. `true`: rounded, `false`: perpendicular line ending
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### line_color
+Set the color of the lines.
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### line_opa
+Set the opacity of the lines.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+## Arc
+TODO
+
+### arc_width
+Set the width (thickness) of the arcs in pixel.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw Yes
+
+
+### arc_rounded
+Make the end points of the arcs rounded. `true`: rounded, `false`: perpendicular line ending
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### arc_color
+Set the color of the arc.
+
+- Default `0x000000`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### arc_opa
+Set the opacity of the arcs.
+
+- Default `LV_OPA_COVER`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### arc_image_src
+Set an image from which the arc will be masked out. It's useful to display complex effects on the arcs. Can be a pointer to `lv_image_dsc_t` or a path to a file
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+## Text
+Properties to describe the properties of text. All these properties are inherited.
+
+### text_color
+Sets the color of the text.
+
+- Default `0x000000`
+- Inherited Yes
+- Layout No
+- Ext. draw No
+
+
+### text_opa
+Set the opacity of the text. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited Yes
+- Layout No
+- Ext. draw No
+
+
+### text_font
+Set the font of the text (a pointer `lv_font_t *`).
+
+- Default `LV_FONT_DEFAULT`
+- Inherited Yes
+- Layout Yes
+- Ext. draw No
+
+
+### text_letter_space
+Set the letter space in pixels
+
+- Default 0
+- Inherited Yes
+- Layout Yes
+- Ext. draw No
+
+
+### text_line_space
+Set the line space in pixels.
+
+- Default 0
+- Inherited Yes
+- Layout Yes
+- Ext. draw No
+
+
+### text_decor
+Set decoration for the text. The possible values are `LV_TEXT_DECOR_NONE/UNDERLINE/STRIKETHROUGH`. OR-ed values can be used as well.
+
+- Default `LV_TEXT_DECOR_NONE`
+- Inherited Yes
+- Layout No
+- Ext. draw No
+
+
+### text_align
+Set how to align the lines of the text. Note that it doesn't align the object itself, only the lines inside the object. The possible values are `LV_TEXT_ALIGN_LEFT/CENTER/RIGHT/AUTO`. `LV_TEXT_ALIGN_AUTO` detect the text base direction and uses left or right alignment accordingly
+
+- Default `LV_TEXT_ALIGN_AUTO`
+- Inherited Yes
+- Layout Yes
+- Ext. draw No
+
+
+## Miscellaneous
+Mixed properties for various purposes.
+
+### radius
+Set the radius on every corner. The value is interpreted in pixel (>= 0) or `LV_RADIUS_CIRCLE` for max. radius
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### clip_corner
+Enable to clip the overflowed content on the rounded corner. Can be `true` or `false`.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### opa
+Scale down all opacity values of the object by this factor. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited Yes
+- Layout No
+- Ext. draw No
+
+
+### opa_layered
+First draw the object on the layer, then scale down layer opacity factor. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
+
+- Default `LV_OPA_COVER`
+- Inherited Yes
+- Layout No
+- Ext. draw No
+
+
+### color_filter_dsc
+Mix a color to all colors of the object.
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### color_filter_opa
+The intensity of mixing of color filter.
+
+- Default `LV_OPA_TRANSP`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### anim
+The animation template for the object's animation. Should be a pointer to `lv_anim_t`. The animation parameters are widget specific, e.g. animation time could be the E.g. blink time of the cursor on the text area or scroll time of a roller. See the widgets' documentation to learn more.
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### anim_duration
+The animation duration in milliseconds. Its meaning is widget specific. E.g. blink time of the cursor on the text area or scroll time of a roller. See the widgets' documentation to learn more.
+
+- Default 0
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### transition
+An initialized `lv_style_transition_dsc_t` to describe a transition.
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### blend_mode
+Describes how to blend the colors to the background. The possible values are `LV_BLEND_MODE_NORMAL/ADDITIVE/SUBTRACTIVE/MULTIPLY`
+
+- Default `LV_BLEND_MODE_NORMAL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### layout
+Set the layout if the object. The children will be repositioned and resized according to the policies set for the layout. For the possible values see the documentation of the layouts.
+
+- Default 0
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### base_dir
+Set the base direction of the object. The possible values are `LV_BIDI_DIR_LTR/RTL/AUTO`.
+
+- Default `LV_BASE_DIR_AUTO`
+- Inherited Yes
+- Layout Yes
+- Ext. draw No
+
+
+### bitmap_mask_src
+If set a layer will be created for the widget and the layer will be masked with this A8 bitmap mask.
+
+- Default `NULL`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+### rotary_sensitivity
+Adjust the sensitivity for rotary encoders in 1/256 unit. It means, 128: slow down the rotary to half, 512: speeds up to double, 256: no change
+
+- Default `256`
+- Inherited No
+- Layout No
+- Ext. draw No
+
+
+## Flex
+Flex layout properties.
+
+### flex_flow
+Defines in which direct the flex layout should arrange the children
+
+- Default `LV_FLEX_FLOW_NONE`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### flex_main_place
+Defines how to align the children in the direction of flex flow
+
+- Default `LV_FLEX_ALIGN_NONE`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### flex_cross_place
+Defines how to align the children perpendicular to the direction of flex flow
+
+- Default `LV_FLEX_ALIGN_NONE`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### flex_track_place
+Defines how to align the tracks of the flow
+
+- Default `LV_FLEX_ALIGN_NONE`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### flex_grow
+Defines how mayn space to take proprtionally the free space of the object's trach
+
+- Default `LV_FLEX_ALIGN_ROW`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+## Grid
+Grid layout properties.
+
+### grid_column_dsc_array
+An array to describe the columns of the grid. Should be LV_GRID_TEMPLATE_LAST terminated
+
+- Default `NULL`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_column_align
+Defines how to distribute the columns
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_row_dsc_array
+An array to describe the rows of the grid. Should be LV_GRID_TEMPLATE_LAST terminated
+
+- Default `NULL`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_row_align
+Defines how to distribute the rows.
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_cell_column_pos
+Set the column in which the object should be placed
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_cell_x_align
+Set how to align the object horizontally.
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_cell_column_span
+Set how many columns the object should span. Needs to be >= 1
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_cell_row_pos
+Set the row in which the object should be placed
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_cell_y_align
+Set how to align the object vertically.
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
+
+### grid_cell_row_span
+Set how many rows the object should span. Needs to be >= 1
+
+- Default `LV_GRID_ALIGN_START`
+- Inherited No
+- Layout Yes
+- Ext. draw No
+
diff --git a/docs/overview/style-props.rst b/docs/overview/style-props.rst
index 31f127397..8cbbd8977 100644
--- a/docs/overview/style-props.rst
+++ b/docs/overview/style-props.rst
@@ -1378,6 +1378,20 @@ If set a layer will be created for the widget and the layer will be masked with
Ext. draw No
+rotary_sensitivity
+~~~~~~~~~~~~~~~~~~
+
+Adjust the sensitivity for rotary encoders in 1/256 unit. It means, 128: slow down the rotary to half, 512: speeds up to double, 256: no change
+
+.. raw:: html
+
+
+ - Default `256`
+ - Inherited Yes
+ - Layout No
+ - Ext. draw No
+
+
Flex
----
diff --git a/docs/porting/indev.rst b/docs/porting/indev.rst
index 2bab65e43..d18ca4efb 100644
--- a/docs/porting/indev.rst
+++ b/docs/porting/indev.rst
@@ -51,8 +51,41 @@ category.
}
}
+
+Mouse cursor
+~~~~~~~~~~~~
+
To set a mouse cursor use :cpp:expr:`lv_indev_set_cursor(indev, &img_cursor)`.
+Crown behavior
+~~~~~~~~~~~~~~
+
+The "Crown" is a rotary device typically found on smart watches.
+
+When the user clicks somewhere and after that turns the rotary
+the last clicked widget will be either scrolled or it's value will be incremented/decremented
+(e.g. in case of a slider).
+
+As this behavior is tightly related to the last clicked widget, the crown support is
+an extension of the pointer input device. Just set ``data->diff`` to the number of
+turned steps and LVGL will automatically send :cpp:enum:`LV_EVENT_ROTARY` or scroll the widget based on the
+``editable`` flag in the widget's class. Non-editable widgets are scrolled and for editable widgets the event is sent.
+
+To get the steps in an event callback use :cpp:func:`int32_t diff = lv_event_get_rotary_diff(e)`
+
+The rotary sensitivity can be adjusted on 2 levels:
+
+1. In the input device by the `indev->rotary_sensitvity` element (1/256 unit)
+2. By the `rotary_sensitivity` style property in the widget (1/256 unit)
+
+The final diff is calculated like this:
+
+``diff_final = diff_in * (indev_sensitivity / 256) + (widget_sensitivity / 256); ``
+
+For example, if both the indev and widget sensitivity is set to 128 (0.5), the input diff. will be
+multiplied by 0.25 (divided by 4). The value of the widget will be incremented by this value or
+the widget will be scrolled this amount of pixels.
+
Keypad or keyboard
------------------
diff --git a/lv_conf_template.h b/lv_conf_template.h
index 6b6b9212e..4ab3155da 100644
--- a/lv_conf_template.h
+++ b/lv_conf_template.h
@@ -848,11 +848,12 @@
/*Use SDL to open window on PC and handle mouse and keyboard*/
#define LV_USE_SDL 0
#if LV_USE_SDL
- #define LV_SDL_INCLUDE_PATH
- #define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT /*LV_DISPLAY_RENDER_MODE_DIRECT is recommended for best performance*/
- #define LV_SDL_BUF_COUNT 1 /*1 or 2*/
- #define LV_SDL_FULLSCREEN 0 /*1: Make the window full screen by default*/
- #define LV_SDL_DIRECT_EXIT 1 /*1: Exit the application when all SDL windows are closed*/
+ #define LV_SDL_INCLUDE_PATH
+ #define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT /*LV_DISPLAY_RENDER_MODE_DIRECT is recommended for best performance*/
+ #define LV_SDL_BUF_COUNT 1 /*1 or 2*/
+ #define LV_SDL_FULLSCREEN 0 /*1: Make the window full screen by default*/
+ #define LV_SDL_DIRECT_EXIT 1 /*1: Exit the application when all SDL windows are closed*/
+ #define LV_SDL_MOUSEWHEEL_MODE LV_SDL_MOUSEWHEEL_MODE_ENCODER /*LV_SDL_MOUSEWHEEL_MODE_ENCODER/CROWN*/
#endif
/*Use X11 to open window on Linux desktop and handle mouse and keyboard*/
diff --git a/scripts/style_api_gen.py b/scripts/style_api_gen.py
index f08d550af..fdf11a83f 100755
--- a/scripts/style_api_gen.py
+++ b/scripts/style_api_gen.py
@@ -393,6 +393,10 @@ props = [
'style_type': 'ptr', 'var_type': 'const lv_image_dsc_t *', 'default':'`NULL`', 'inherited': 0, 'layout': 0, 'ext_draw': 0,
'dsc': "If set a layer will be created for the widget and the layer will be masked with this A8 bitmap mask."},
+{'name': 'ROTARY_SENSITIVITY',
+ 'style_type': 'num', 'var_type': 'uint32_t', 'default':'`256`', 'inherited': 1, 'layout': 0, 'ext_draw': 0,
+ 'dsc': "Adjust the sensitivity for rotary encoders in 1/256 unit. It means, 128: slow down the rotary to half, 512: speeds up to double, 256: no change"},
+
{'section': 'Flex', 'dsc':'Flex layout properties.', 'guard':'LV_USE_FLEX'},
diff --git a/src/core/lv_obj_event.c b/src/core/lv_obj_event.c
index f88128adf..0553f3d77 100644
--- a/src/core/lv_obj_event.c
+++ b/src/core/lv_obj_event.c
@@ -242,6 +242,19 @@ uint32_t lv_event_get_key(lv_event_t * e)
}
}
+int32_t lv_event_get_rotary_diff(lv_event_t * e)
+{
+ if(e->code == LV_EVENT_ROTARY) {
+ int32_t * r = lv_event_get_param(e);
+ if(r) return *r;
+ else return 0;
+ }
+ else {
+ LV_LOG_WARN("Not interpreted with this event code");
+ return 0;
+ }
+}
+
lv_anim_t * lv_event_get_scroll_anim(lv_event_t * e)
{
if(e->code == LV_EVENT_SCROLL_BEGIN) {
diff --git a/src/core/lv_obj_event.h b/src/core/lv_obj_event.h
index 769b5fd2e..40a002d8a 100644
--- a/src/core/lv_obj_event.h
+++ b/src/core/lv_obj_event.h
@@ -151,6 +151,13 @@ const lv_area_t * lv_event_get_old_size(lv_event_t * e);
*/
uint32_t lv_event_get_key(lv_event_t * e);
+/**
+ * Get the signed rotary encoder diff. passed as parameter to an event. Can be used in `LV_EVENT_ROTARY`
+ * @param e pointer to an event
+ * @return the triggering key or NULL if called on an unrelated event
+ */
+int32_t lv_event_get_rotary_diff(lv_event_t * e);
+
/**
* Get the animation descriptor of a scrolling. Can be used in `LV_EVENT_SCROLL_BEGIN`
* @param e pointer to an event
diff --git a/src/core/lv_obj_style.c b/src/core/lv_obj_style.c
index 020cf3ba1..2273c0e41 100644
--- a/src/core/lv_obj_style.c
+++ b/src/core/lv_obj_style.c
@@ -320,70 +320,6 @@ void lv_obj_enable_style_refresh(bool en)
style_refr = en;
}
-static inline lv_style_value_t lv_style_prop_get_default_inlined(lv_style_prop_t prop)
-{
- const lv_color_t black = LV_COLOR_MAKE(0x00, 0x00, 0x00);
- const lv_color_t white = LV_COLOR_MAKE(0xff, 0xff, 0xff);
- switch(prop) {
- case LV_STYLE_TRANSFORM_SCALE_X:
- case LV_STYLE_TRANSFORM_SCALE_Y:
- return (lv_style_value_t) {
- .num = LV_SCALE_NONE
- };
- case LV_STYLE_BG_COLOR:
- return (lv_style_value_t) {
- .color = black
- };
- case LV_STYLE_BG_GRAD_COLOR:
- case LV_STYLE_BORDER_COLOR:
- case LV_STYLE_SHADOW_COLOR:
- case LV_STYLE_OUTLINE_COLOR:
- case LV_STYLE_ARC_COLOR:
- case LV_STYLE_LINE_COLOR:
- case LV_STYLE_TEXT_COLOR:
- case LV_STYLE_IMAGE_RECOLOR:
- return (lv_style_value_t) {
- .color = white
- };
- case LV_STYLE_OPA:
- case LV_STYLE_OPA_LAYERED:
- case LV_STYLE_BORDER_OPA:
- case LV_STYLE_TEXT_OPA:
- case LV_STYLE_IMAGE_OPA:
- case LV_STYLE_BG_GRAD_OPA:
- case LV_STYLE_BG_MAIN_OPA:
- case LV_STYLE_BG_IMAGE_OPA:
- case LV_STYLE_OUTLINE_OPA:
- case LV_STYLE_SHADOW_OPA:
- case LV_STYLE_LINE_OPA:
- case LV_STYLE_ARC_OPA:
- return (lv_style_value_t) {
- .num = LV_OPA_COVER
- };
- case LV_STYLE_BG_GRAD_STOP:
- return (lv_style_value_t) {
- .num = 255
- };
- case LV_STYLE_BORDER_SIDE:
- return (lv_style_value_t) {
- .num = LV_BORDER_SIDE_FULL
- };
- case LV_STYLE_TEXT_FONT:
- return (lv_style_value_t) {
- .ptr = LV_FONT_DEFAULT
- };
- case LV_STYLE_MAX_WIDTH:
- case LV_STYLE_MAX_HEIGHT:
- return (lv_style_value_t) {
- .num = LV_COORD_MAX
- };
- default:
- return (lv_style_value_t) {
- .ptr = 0
- };
- }
-}
-
lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_style_prop_t prop)
{
LV_ASSERT_NULL(obj)
@@ -395,7 +331,7 @@ lv_style_value_t lv_obj_get_style_prop(const lv_obj_t * obj, lv_part_t part, lv_
found = get_selector_style_prop(obj, selector, prop, &value_act);
if(found == LV_STYLE_RES_FOUND) return value_act;
- return lv_style_prop_get_default_inlined(prop);
+ return lv_style_prop_get_default(prop);
}
bool lv_obj_has_style_prop(const lv_obj_t * obj, lv_style_selector_t selector, lv_style_prop_t prop)
diff --git a/src/core/lv_obj_style_gen.c b/src/core/lv_obj_style_gen.c
index cee767287..f9b21e807 100644
--- a/src/core/lv_obj_style_gen.c
+++ b/src/core/lv_obj_style_gen.c
@@ -761,6 +761,14 @@ void lv_obj_set_style_bitmap_mask_src(lv_obj_t * obj, const lv_image_dsc_t * val
};
lv_obj_set_local_style_prop(obj, LV_STYLE_BITMAP_MASK_SRC, v, selector);
}
+
+void lv_obj_set_style_rotary_sensitivity(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_obj_set_local_style_prop(obj, LV_STYLE_ROTARY_SENSITIVITY, v, selector);
+}
#if LV_USE_FLEX
void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector)
diff --git a/src/core/lv_obj_style_gen.h b/src/core/lv_obj_style_gen.h
index c3895287e..c3bd10761 100644
--- a/src/core/lv_obj_style_gen.h
+++ b/src/core/lv_obj_style_gen.h
@@ -642,6 +642,12 @@ static inline const lv_image_dsc_t * lv_obj_get_style_bitmap_mask_src(const lv_o
return (const lv_image_dsc_t *)v.ptr;
}
+static inline uint32_t lv_obj_get_style_rotary_sensitivity(const lv_obj_t * obj, uint32_t part)
+{
+ lv_style_value_t v = lv_obj_get_style_prop(obj, part, LV_STYLE_ROTARY_SENSITIVITY);
+ return (uint32_t)v.num;
+}
+
#if LV_USE_FLEX
static inline lv_flex_flow_t lv_obj_get_style_flex_flow(const lv_obj_t * obj, uint32_t part)
{
@@ -832,6 +838,7 @@ void lv_obj_set_style_blend_mode(lv_obj_t * obj, lv_blend_mode_t value, lv_style
void lv_obj_set_style_layout(lv_obj_t * obj, uint16_t value, lv_style_selector_t selector);
void lv_obj_set_style_base_dir(lv_obj_t * obj, lv_base_dir_t value, lv_style_selector_t selector);
void lv_obj_set_style_bitmap_mask_src(lv_obj_t * obj, const lv_image_dsc_t * value, lv_style_selector_t selector);
+void lv_obj_set_style_rotary_sensitivity(lv_obj_t * obj, uint32_t value, lv_style_selector_t selector);
#if LV_USE_FLEX
void lv_obj_set_style_flex_flow(lv_obj_t * obj, lv_flex_flow_t value, lv_style_selector_t selector);
void lv_obj_set_style_flex_main_place(lv_obj_t * obj, lv_flex_align_t value, lv_style_selector_t selector);
diff --git a/src/drivers/sdl/lv_sdl_mouse.c b/src/drivers/sdl/lv_sdl_mouse.c
index 124cd1740..a6c1c692a 100644
--- a/src/drivers/sdl/lv_sdl_mouse.c
+++ b/src/drivers/sdl/lv_sdl_mouse.c
@@ -35,6 +35,9 @@ typedef struct {
int16_t last_x;
int16_t last_y;
bool left_button_down;
+#if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
+ int32_t diff;
+#endif
} lv_sdl_mouse_t;
/**********************
@@ -76,6 +79,10 @@ static void sdl_mouse_read(lv_indev_t * indev, lv_indev_data_t * data)
data->point.x = dsc->last_x;
data->point.y = dsc->last_y;
data->state = dsc->left_button_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
+#if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
+ data->enc_diff = dsc->diff;
+ dsc->diff = 0;
+#endif
}
static void release_indev_cb(lv_event_t * e)
@@ -101,7 +108,11 @@ void _lv_sdl_mouse_handler(SDL_Event * event)
case SDL_MOUSEMOTION:
win_id = event->motion.windowID;
break;
-
+#if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
+ case SDL_MOUSEWHEEL:
+ win_id = event->wheel.windowID;
+ break;
+#endif
case SDL_FINGERUP:
case SDL_FINGERDOWN:
case SDL_FINGERMOTION:
@@ -174,6 +185,17 @@ void _lv_sdl_mouse_handler(SDL_Event * event)
indev_dev->last_x = (int16_t)((float)hor_res * event->tfinger.x / zoom);
indev_dev->last_y = (int16_t)((float)ver_res * event->tfinger.y / zoom);
break;
+ case SDL_MOUSEWHEEL:
+#if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN
+#ifdef __EMSCRIPTEN__
+ /*Escripten scales it wrong*/
+ if(event->wheel.y < 0) dsc->diff++;
+ if(event->wheel.y > 0) dsc->diff--;
+#else
+ indev_dev->diff = -event->wheel.y;
+#endif /*__EMSCRIPTEN__*/
+#endif /*LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_CROWN*/
+ break;
}
lv_indev_read(indev);
}
diff --git a/src/drivers/sdl/lv_sdl_mousewheel.c b/src/drivers/sdl/lv_sdl_mousewheel.c
index c75fbc4ee..f331e3788 100644
--- a/src/drivers/sdl/lv_sdl_mousewheel.c
+++ b/src/drivers/sdl/lv_sdl_mousewheel.c
@@ -7,7 +7,7 @@
* INCLUDES
*********************/
#include "lv_sdl_mousewheel.h"
-#if LV_USE_SDL
+#if LV_USE_SDL && LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_ENCODER
#include "../../core/lv_group.h"
#include "../../indev/lv_indev_private.h"
diff --git a/src/drivers/sdl/lv_sdl_mousewheel.h b/src/drivers/sdl/lv_sdl_mousewheel.h
index 6adf6ee02..7ca34bdbb 100644
--- a/src/drivers/sdl/lv_sdl_mousewheel.h
+++ b/src/drivers/sdl/lv_sdl_mousewheel.h
@@ -14,7 +14,7 @@ extern "C" {
* INCLUDES
*********************/
#include "lv_sdl_window.h"
-#if LV_USE_SDL
+#if LV_USE_SDL && LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_ENCODER
/*********************
* DEFINES
diff --git a/src/drivers/sdl/lv_sdl_window.c b/src/drivers/sdl/lv_sdl_window.c
index 76addcc53..b4300666f 100644
--- a/src/drivers/sdl/lv_sdl_window.c
+++ b/src/drivers/sdl/lv_sdl_window.c
@@ -253,7 +253,9 @@ static void sdl_event_handler(lv_timer_t * t)
SDL_Event event;
while(SDL_PollEvent(&event)) {
_lv_sdl_mouse_handler(&event);
+#if LV_SDL_MOUSEWHEEL_MODE == LV_SDL_MOUSEWHEEL_MODE_ENCODER
_lv_sdl_mousewheel_handler(&event);
+#endif
_lv_sdl_keyboard_handler(&event);
if(event.type == SDL_WINDOWEVENT) {
diff --git a/src/drivers/sdl/lv_sdl_window.h b/src/drivers/sdl/lv_sdl_window.h
index 53c7b194b..4a3901fdc 100644
--- a/src/drivers/sdl/lv_sdl_window.h
+++ b/src/drivers/sdl/lv_sdl_window.h
@@ -23,6 +23,10 @@ extern "C" {
* DEFINES
*********************/
+/* Possible values of LV_SDL_MOUSEWHEEL_MODE */
+#define LV_SDL_MOUSEWHEEL_MODE_ENCODER 0 /* The mousewheel emulates an encoder input device*/
+#define LV_SDL_MOUSEWHEEL_MODE_CROWN 1 /* The mousewheel emulates a smart watch crown*/
+
/**********************
* TYPEDEFS
**********************/
diff --git a/src/indev/lv_indev.c b/src/indev/lv_indev.c
index 3169dd0ec..66624922c 100644
--- a/src/indev/lv_indev.c
+++ b/src/indev/lv_indev.c
@@ -43,6 +43,9 @@
/*Gesture min velocity at release before swipe (pixels)*/
#define LV_INDEV_DEF_GESTURE_MIN_VELOCITY 3
+/**< Rotary diff count will be multiplied by this and divided by 256 */
+#define LV_INDEV_DEF_ROTARY_SENSITIVITY 256
+
#if LV_INDEV_DEF_SCROLL_THROW <= 0
#warning "LV_INDEV_DEF_SCROLL_THROW must be greater than 0"
#endif
@@ -64,6 +67,7 @@ static void indev_encoder_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_button_proc(lv_indev_t * i, lv_indev_data_t * data);
static void indev_proc_press(lv_indev_t * indev);
static void indev_proc_release(lv_indev_t * indev);
+static void indev_proc_pointer_diff(lv_indev_t * indev);
static lv_obj_t * pointer_search_obj(lv_display_t * disp, lv_point_t * p);
static void indev_proc_reset_query_handler(lv_indev_t * indev);
static void indev_click_focus(lv_indev_t * indev);
@@ -130,6 +134,7 @@ lv_indev_t * lv_indev_create(void)
indev->long_press_repeat_time = LV_INDEV_DEF_LONG_PRESS_REP_TIME;
indev->gesture_limit = LV_INDEV_DEF_GESTURE_LIMIT;
indev->gesture_min_velocity = LV_INDEV_DEF_GESTURE_MIN_VELOCITY;
+ indev->rotary_sensitvity = LV_INDEV_DEF_ROTARY_SENSITIVITY;
return indev;
}
@@ -660,6 +665,10 @@ static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
i->pointer.act_point.x = data->point.x;
i->pointer.act_point.y = data->point.y;
+ i->pointer.diff = data->enc_diff;
+
+ /*Process the diff first as scrolling will be processed in indev_proc_release*/
+ indev_proc_pointer_diff(i);
if(i->state == LV_INDEV_STATE_PRESSED) {
indev_proc_press(i);
@@ -670,6 +679,7 @@ static void indev_pointer_proc(lv_indev_t * i, lv_indev_data_t * data)
i->pointer.last_point.x = i->pointer.act_point.x;
i->pointer.last_point.y = i->pointer.act_point.y;
+
}
/**
@@ -1117,8 +1127,9 @@ static void indev_proc_press(lv_indev_t * indev)
if(new_obj_searched && indev->pointer.scroll_obj) {
/*Attempt to stop scroll throw animation firstly*/
- if(!indev->scroll_throw_anim || !lv_anim_delete(indev, indev_scroll_throw_anim_cb)) {
- indev_scroll_throw_anim_reset(indev);
+ if(indev->scroll_throw_anim) {
+ lv_anim_delete(indev, indev_scroll_throw_anim_cb);
+ indev->scroll_throw_anim = NULL;
}
_lv_indev_scroll_throw_handler(indev);
@@ -1301,7 +1312,6 @@ static void indev_proc_release(lv_indev_t * indev)
lv_point_transform(&indev->pointer.scroll_throw_vect_ori, angle, scale_x, scale_y, &pivot, false);
}
}
-
}
if(scroll_obj) {
@@ -1313,6 +1323,40 @@ static void indev_proc_release(lv_indev_t * indev)
}
}
+static void indev_proc_pointer_diff(lv_indev_t * indev)
+{
+ lv_obj_t * obj = indev->pointer.last_pressed;
+ if(obj == NULL) return;
+ if(indev->pointer.diff == 0) return;
+
+ indev_obj_act = obj;
+
+ bool editable = lv_obj_is_editable(obj);
+
+ if(editable) {
+ uint32_t indev_sensitivity = indev->rotary_sensitvity;
+ uint32_t obj_sensitivity = lv_obj_get_style_rotary_sensitivity(indev_obj_act, 0);
+ int32_t diff = (int32_t)((int32_t)indev->pointer.diff * indev_sensitivity * obj_sensitivity + 32768) >> 16;
+ send_event(LV_EVENT_ROTARY, &diff);
+ }
+ else {
+
+ int32_t vect = indev->pointer.diff > 0 ? indev->scroll_limit : -indev->scroll_limit;
+ indev->pointer.vect.y = vect;
+ indev->pointer.act_obj = obj;
+ lv_obj_t * scroll_obj = lv_indev_find_scroll_obj(indev);
+ if(scroll_obj == NULL) return;
+ uint32_t indev_sensitivity = indev->rotary_sensitvity;
+ uint32_t obj_sensitivity = lv_obj_get_style_rotary_sensitivity(scroll_obj, 0);
+ int32_t diff = (int32_t)((int32_t)indev->pointer.diff * indev_sensitivity * obj_sensitivity + 32768) >> 16;
+
+ indev->pointer.scroll_throw_vect.y = diff;
+ indev->pointer.scroll_throw_vect_ori.y = diff;
+ _lv_indev_scroll_handler(indev);
+ }
+
+}
+
static lv_obj_t * pointer_search_obj(lv_display_t * disp, lv_point_t * p)
{
indev_obj_act = lv_indev_search_obj(lv_display_get_layer_sys(disp), p);
@@ -1545,7 +1589,8 @@ static lv_result_t send_event(lv_event_code_t code, void * param)
code == LV_EVENT_CLICKED ||
code == LV_EVENT_RELEASED ||
code == LV_EVENT_LONG_PRESSED ||
- code == LV_EVENT_LONG_PRESSED_REPEAT) {
+ code == LV_EVENT_LONG_PRESSED_REPEAT ||
+ code == LV_EVENT_ROTARY) {
lv_indev_send_event(indev_act, code, indev_obj_act);
if(indev_reset_check(indev_act)) return LV_RESULT_INVALID;
}
diff --git a/src/indev/lv_indev_private.h b/src/indev/lv_indev_private.h
index e2a00ff4a..96ba4739a 100644
--- a/src/indev/lv_indev_private.h
+++ b/src/indev/lv_indev_private.h
@@ -69,6 +69,9 @@ struct _lv_indev_t {
/**< Repeated trigger period in long press [ms]*/
uint16_t long_press_repeat_time;
+ /**< Rotary diff count will be multiplied by this value and divided by 256*/
+ int32_t rotary_sensitvity;
+
struct {
/*Pointer and button data*/
lv_point_t act_point; /**< Current point of input device.*/
@@ -84,6 +87,7 @@ struct _lv_indev_t {
lv_obj_t * last_pressed; /*The lastly pressed object*/
lv_area_t scroll_area;
lv_point_t gesture_sum; /*Count the gesture pixels to check LV_INDEV_DEF_GESTURE_LIMIT*/
+ int32_t diff;
/*Flags*/
lv_dir_t scroll_dir : 4;
@@ -100,14 +104,22 @@ struct _lv_indev_t {
lv_group_t * group; /**< Keypad destination group*/
const lv_point_t * btn_points; /**< Array points assigned to the button ()screen will be pressed
here by the buttons*/
-
lv_event_list_t event_list;
lv_anim_t * scroll_throw_anim;
};
+
/**********************
* GLOBAL PROTOTYPES
**********************/
+/**
+ * Find a scrollable object based on the current scroll vector in the indev.
+ * In handles scroll propagation to the parent if needed, and scroll directions too.
+ * @param indev pointer to an indev
+ * @return the found scrollable object or NULL if not found.
+ */
+lv_obj_t * lv_indev_find_scroll_obj(lv_indev_t * indev);
+
/**********************
* MACROS
**********************/
diff --git a/src/indev/lv_indev_scroll.c b/src/indev/lv_indev_scroll.c
index e6d98c83e..947bda5e6 100644
--- a/src/indev/lv_indev_scroll.c
+++ b/src/indev/lv_indev_scroll.c
@@ -22,7 +22,6 @@
/**********************
* STATIC PROTOTYPES
**********************/
-static lv_obj_t * find_scroll_obj(lv_indev_t * indev);
static void init_scroll_limits(lv_indev_t * indev);
static int32_t find_snap_point_x(const lv_obj_t * obj, int32_t min, int32_t max, int32_t ofs);
static int32_t find_snap_point_y(const lv_obj_t * obj, int32_t min, int32_t max, int32_t ofs);
@@ -51,7 +50,7 @@ void _lv_indev_scroll_handler(lv_indev_t * indev)
lv_obj_t * scroll_obj = indev->pointer.scroll_obj;
/*If there is no scroll object yet try to find one*/
if(scroll_obj == NULL) {
- scroll_obj = find_scroll_obj(indev);
+ scroll_obj = lv_indev_find_scroll_obj(indev);
if(scroll_obj == NULL) return;
init_scroll_limits(indev);
@@ -254,11 +253,7 @@ void lv_indev_scroll_get_snap_dist(lv_obj_t * obj, lv_point_t * p)
p->y = find_snap_point_y(obj, obj->coords.y1, obj->coords.y2, 0);
}
-/**********************
- * STATIC FUNCTIONS
- **********************/
-
-static lv_obj_t * find_scroll_obj(lv_indev_t * indev)
+lv_obj_t * lv_indev_find_scroll_obj(lv_indev_t * indev)
{
lv_obj_t * obj_candidate = NULL;
lv_dir_t dir_candidate = LV_DIR_NONE;
@@ -389,6 +384,10 @@ static lv_obj_t * find_scroll_obj(lv_indev_t * indev)
return obj_candidate;
}
+/**********************
+ * STATIC FUNCTIONS
+ **********************/
+
static void init_scroll_limits(lv_indev_t * indev)
{
lv_obj_t * obj = indev->pointer.scroll_obj;
diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h
index 80141a1ad..672d3a77a 100644
--- a/src/lv_conf_internal.h
+++ b/src/lv_conf_internal.h
@@ -2712,14 +2712,14 @@
#ifdef CONFIG_LV_SDL_INCLUDE_PATH
#define LV_SDL_INCLUDE_PATH CONFIG_LV_SDL_INCLUDE_PATH
#else
- #define LV_SDL_INCLUDE_PATH
+ #define LV_SDL_INCLUDE_PATH
#endif
#endif
#ifndef LV_SDL_RENDER_MODE
#ifdef CONFIG_LV_SDL_RENDER_MODE
#define LV_SDL_RENDER_MODE CONFIG_LV_SDL_RENDER_MODE
#else
- #define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT /*LV_DISPLAY_RENDER_MODE_DIRECT is recommended for best performance*/
+ #define LV_SDL_RENDER_MODE LV_DISPLAY_RENDER_MODE_DIRECT /*LV_DISPLAY_RENDER_MODE_DIRECT is recommended for best performance*/
#endif
#endif
#ifndef LV_SDL_BUF_COUNT
@@ -2730,14 +2730,14 @@
#define LV_SDL_BUF_COUNT 0
#endif
#else
- #define LV_SDL_BUF_COUNT 1 /*1 or 2*/
+ #define LV_SDL_BUF_COUNT 1 /*1 or 2*/
#endif
#endif
#ifndef LV_SDL_FULLSCREEN
#ifdef CONFIG_LV_SDL_FULLSCREEN
#define LV_SDL_FULLSCREEN CONFIG_LV_SDL_FULLSCREEN
#else
- #define LV_SDL_FULLSCREEN 0 /*1: Make the window full screen by default*/
+ #define LV_SDL_FULLSCREEN 0 /*1: Make the window full screen by default*/
#endif
#endif
#ifndef LV_SDL_DIRECT_EXIT
@@ -2748,7 +2748,14 @@
#define LV_SDL_DIRECT_EXIT 0
#endif
#else
- #define LV_SDL_DIRECT_EXIT 1 /*1: Exit the application when all SDL windows are closed*/
+ #define LV_SDL_DIRECT_EXIT 1 /*1: Exit the application when all SDL windows are closed*/
+ #endif
+ #endif
+ #ifndef LV_SDL_MOUSEWHEEL_MODE
+ #ifdef CONFIG_LV_SDL_MOUSEWHEEL_MODE
+ #define LV_SDL_MOUSEWHEEL_MODE CONFIG_LV_SDL_MOUSEWHEEL_MODE
+ #else
+ #define LV_SDL_MOUSEWHEEL_MODE LV_SDL_MOUSEWHEEL_MODE_ENCODER /*LV_SDL_MOUSEWHEEL_MODE_ENCODER/CROWN*/
#endif
#endif
#endif
diff --git a/src/misc/lv_event.h b/src/misc/lv_event.h
index 1e807819b..2eeb5cdf5 100644
--- a/src/misc/lv_event.h
+++ b/src/misc/lv_event.h
@@ -57,6 +57,7 @@ typedef enum {
LV_EVENT_SCROLL, /**< Scrolling*/
LV_EVENT_GESTURE, /**< A gesture is detected. Get the gesture with `lv_indev_get_gesture_dir(lv_indev_active());` */
LV_EVENT_KEY, /**< A key is sent to the object. Get the key with `lv_indev_get_key(lv_indev_active());`*/
+ LV_EVENT_ROTARY, /**< An encoder or wheel was rotated. Get the rotation count with `lv_event_get_rotary_diff(e);`*/
LV_EVENT_FOCUSED, /**< The object is focused*/
LV_EVENT_DEFOCUSED, /**< The object is defocused*/
LV_EVENT_LEAVE, /**< The object is defocused but still selected*/
diff --git a/src/misc/lv_style.c b/src/misc/lv_style.c
index adfb2521c..e7278434e 100644
--- a/src/misc/lv_style.c
+++ b/src/misc/lv_style.c
@@ -406,9 +406,13 @@ lv_style_value_t lv_style_prop_get_default(lv_style_prop_t prop)
return (lv_style_value_t) {
.num = LV_COORD_MAX
};
+ case LV_STYLE_ROTARY_SENSITIVITY:
+ return (lv_style_value_t) {
+ .num = 256
+ };
default:
return (lv_style_value_t) {
- .ptr = 0
+ .ptr = NULL
};
}
}
diff --git a/src/misc/lv_style.h b/src/misc/lv_style.h
index 86077987c..5c69e5989 100644
--- a/src/misc/lv_style.h
+++ b/src/misc/lv_style.h
@@ -298,8 +298,8 @@ enum _lv_style_prop_t {
LV_STYLE_TRANSFORM_PIVOT_Y = 112,
LV_STYLE_TRANSFORM_SKEW_X = 113,
LV_STYLE_TRANSFORM_SKEW_Y = 114,
-
LV_STYLE_BITMAP_MASK_SRC = 115,
+ LV_STYLE_ROTARY_SENSITIVITY = 116,
#if LV_USE_FLEX
LV_STYLE_FLEX_FLOW = 125,
diff --git a/src/misc/lv_style_gen.c b/src/misc/lv_style_gen.c
index 3fce9532f..297087534 100644
--- a/src/misc/lv_style_gen.c
+++ b/src/misc/lv_style_gen.c
@@ -949,6 +949,16 @@ void lv_style_set_bitmap_mask_src(lv_style_t * style, const lv_image_dsc_t * val
}
const lv_style_prop_t _lv_style_const_prop_id_BITMAP_MASK_SRC = LV_STYLE_BITMAP_MASK_SRC;
+
+void lv_style_set_rotary_sensitivity(lv_style_t * style, uint32_t value)
+{
+ lv_style_value_t v = {
+ .num = (int32_t)value
+ };
+ lv_style_set_prop(style, LV_STYLE_ROTARY_SENSITIVITY, v);
+}
+
+const lv_style_prop_t _lv_style_const_prop_id_ROTARY_SENSITIVITY = LV_STYLE_ROTARY_SENSITIVITY;
#if LV_USE_FLEX
void lv_style_set_flex_flow(lv_style_t * style, lv_flex_flow_t value)
diff --git a/src/misc/lv_style_gen.h b/src/misc/lv_style_gen.h
index 6ce838e1c..7aed6b7e9 100644
--- a/src/misc/lv_style_gen.h
+++ b/src/misc/lv_style_gen.h
@@ -202,6 +202,8 @@ void lv_style_set_base_dir(lv_style_t * style, lv_base_dir_t value);
LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_BASE_DIR;
void lv_style_set_bitmap_mask_src(lv_style_t * style, const lv_image_dsc_t * value);
LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_BITMAP_MASK_SRC;
+void lv_style_set_rotary_sensitivity(lv_style_t * style, uint32_t value);
+LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_ROTARY_SENSITIVITY;
#if LV_USE_FLEX
void lv_style_set_flex_flow(lv_style_t * style, lv_flex_flow_t value);
LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_FLEX_FLOW;
@@ -708,6 +710,11 @@ LV_ATTRIBUTE_EXTERN_DATA extern const lv_style_prop_t _lv_style_const_prop_id_GR
{ \
.prop_ptr = &_lv_style_const_prop_id_BITMAP_MASK_SRC, .value = { .ptr = val } \
}
+
+#define LV_STYLE_CONST_ROTARY_SENSITIVITY(val) \
+ { \
+ .prop_ptr = &_lv_style_const_prop_id_ROTARY_SENSITIVITY, .value = { .num = (int32_t)val } \
+ }
#if LV_USE_FLEX
#define LV_STYLE_CONST_FLEX_FLOW(val) \
diff --git a/src/themes/default/lv_theme_default.c b/src/themes/default/lv_theme_default.c
index a6a5eb242..66494ba92 100644
--- a/src/themes/default/lv_theme_default.c
+++ b/src/themes/default/lv_theme_default.c
@@ -75,6 +75,7 @@ typedef struct {
lv_style_t circle;
lv_style_t no_radius;
lv_style_t clip_corner;
+ lv_style_t rotary_scroll;
#if LV_THEME_DEFAULT_GROW
lv_style_t grow;
#endif
@@ -263,6 +264,7 @@ static void style_init(my_theme_t * theme)
lv_style_set_text_font(&theme->styles.scr, theme->base.font_normal);
lv_style_set_pad_row(&theme->styles.scr, PAD_SMALL);
lv_style_set_pad_column(&theme->styles.scr, PAD_SMALL);
+ lv_style_set_rotary_sensitivity(&theme->styles.scr, theme->disp_dpi / 4 * 256);
style_init_reset(&theme->styles.card);
lv_style_set_radius(&theme->styles.card, RADIUS_DEFAULT);
@@ -386,6 +388,9 @@ static void style_init(my_theme_t * theme)
style_init_reset(&theme->styles.no_radius);
lv_style_set_radius(&theme->styles.no_radius, 0);
+ style_init_reset(&theme->styles.rotary_scroll);
+ lv_style_set_rotary_sensitivity(&theme->styles.rotary_scroll, theme->disp_dpi / 4 * 256);
+
#if LV_THEME_DEFAULT_GROW
style_init_reset(&theme->styles.grow);
lv_style_set_transform_width(&theme->styles.grow, _LV_DPX_CALC(theme->disp_dpi, 3));
@@ -747,6 +752,7 @@ static void theme_apply(lv_theme_t * th, lv_obj_t * obj)
/*Tabview pages*/
else if(parent && lv_obj_check_type(lv_obj_get_parent(parent), &lv_tabview_class)) {
lv_obj_add_style(obj, &theme->styles.pad_normal, 0);
+ lv_obj_add_style(obj, &theme->styles.rotary_scroll, 0);
lv_obj_add_style(obj, &theme->styles.scrollbar, LV_PART_SCROLLBAR);
lv_obj_add_style(obj, &theme->styles.scrollbar_scrolled, LV_PART_SCROLLBAR | LV_STATE_SCROLLED);
return;
diff --git a/src/widgets/arc/lv_arc.c b/src/widgets/arc/lv_arc.c
index 994efa759..6d4383971 100644
--- a/src/widgets/arc/lv_arc.c
+++ b/src/widgets/arc/lv_arc.c
@@ -605,7 +605,7 @@ static void lv_arc_event(const lv_obj_class_t * class_p, lv_event_t * e)
else if(code == LV_EVENT_KEY) {
uint32_t c = lv_event_get_key(e);
- int16_t old_value = arc->value;
+ int32_t old_value = arc->value;
if(c == LV_KEY_RIGHT || c == LV_KEY_UP) {
lv_arc_set_value(obj, lv_arc_get_value(obj) + 1);
}
@@ -618,6 +618,16 @@ static void lv_arc_event(const lv_obj_class_t * class_p, lv_event_t * e)
if(res != LV_RESULT_OK) return;
}
}
+ else if(code == LV_EVENT_ROTARY) {
+ int32_t r = lv_event_get_rotary_diff(e);
+
+ int32_t old_value = arc->value;
+ lv_arc_set_value(obj, lv_arc_get_value(obj) + r);
+ if(old_value != arc->value) {
+ res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
+ if(res != LV_RESULT_OK) return;
+ }
+ }
else if(code == LV_EVENT_HIT_TEST) {
lv_hit_test_info_t * info = lv_event_get_param(e);
diff --git a/src/widgets/dropdown/lv_dropdown.c b/src/widgets/dropdown/lv_dropdown.c
index e99fa6e1a..c5d1c0189 100644
--- a/src/widgets/dropdown/lv_dropdown.c
+++ b/src/widgets/dropdown/lv_dropdown.c
@@ -738,6 +738,19 @@ static void lv_dropdown_event(const lv_obj_class_t * class_p, lv_event_t * e)
}
}
}
+ else if(code == LV_EVENT_ROTARY) {
+ if(!lv_dropdown_is_open(obj)) {
+ lv_dropdown_open(obj);
+ }
+ else {
+ int32_t r = lv_event_get_rotary_diff(e);
+ int32_t new_id = dropdown->sel_opt_id + r;
+ new_id = LV_CLAMP(0, new_id, (int32_t)dropdown->option_cnt - 1);
+
+ dropdown->sel_opt_id = new_id;
+ position_to_selected(obj);
+ }
+ }
else if(code == LV_EVENT_DRAW_MAIN) {
draw_main(e);
}
diff --git a/src/widgets/roller/lv_roller.c b/src/widgets/roller/lv_roller.c
index ae909c320..98ed0f3df 100644
--- a/src/widgets/roller/lv_roller.c
+++ b/src/widgets/roller/lv_roller.c
@@ -380,6 +380,16 @@ static void lv_roller_event(const lv_obj_class_t * class_p, lv_event_t * e)
}
}
}
+ else if(code == LV_EVENT_ROTARY) {
+ int32_t r = lv_event_get_rotary_diff(e);
+ int32_t new_id = roller->sel_opt_id + r;
+ new_id = LV_CLAMP(0, new_id, (int32_t)roller->option_cnt - 1);
+ if((int32_t)roller->sel_opt_id != new_id) {
+ uint32_t ori_id = roller->sel_opt_id_ori; /*lv_roller_set_selected will overwrite this*/
+ lv_roller_set_selected(obj, new_id, LV_ANIM_ON);
+ roller->sel_opt_id_ori = ori_id;
+ }
+ }
else if(code == LV_EVENT_REFR_EXT_DRAW_SIZE) {
lv_obj_t * label = get_label(obj);
lv_obj_refresh_ext_draw_size(label);
diff --git a/src/widgets/slider/lv_slider.c b/src/widgets/slider/lv_slider.c
index 1bf7cca10..2cce03ab2 100644
--- a/src/widgets/slider/lv_slider.c
+++ b/src/widgets/slider/lv_slider.c
@@ -224,6 +224,15 @@ static void lv_slider_event(const lv_obj_class_t * class_p, lv_event_t * e)
res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
if(res != LV_RESULT_OK) return;
}
+ else if(code == LV_EVENT_ROTARY) {
+ int32_t r = lv_event_get_rotary_diff(e);
+
+ if(!slider->left_knob_focus) lv_slider_set_value(obj, lv_slider_get_value(obj) + r, LV_ANIM_ON);
+ else lv_slider_set_left_value(obj, lv_slider_get_left_value(obj) + 1, LV_ANIM_ON);
+
+ res = lv_obj_send_event(obj, LV_EVENT_VALUE_CHANGED, NULL);
+ if(res != LV_RESULT_OK) return;
+ }
else if(code == LV_EVENT_DRAW_MAIN) {
draw_knob(e);
}
diff --git a/tests/src/test_cases/widgets/test_image.c b/tests/src/test_cases/widgets/test_image.c
index 52069169d..17a4d8d32 100644
--- a/tests/src/test_cases/widgets/test_image.c
+++ b/tests/src/test_cases/widgets/test_image.c
@@ -21,6 +21,7 @@ static lv_obj_t * img_create(void)
lv_obj_t * img = lv_image_create(lv_screen_active());
lv_image_set_src(img, &test_img_lvgl_logo_png);
lv_obj_set_style_bg_opa(img, LV_OPA_20, 0);
+ lv_obj_set_style_bg_color(img, lv_color_hex(0x000000), 0);
lv_obj_set_style_shadow_width(img, 10, 0);
lv_obj_set_style_shadow_color(img, lv_color_hex(0xff0000), 0);
return img;