diff --git a/packages/eez-studio-types/index.d.ts b/packages/eez-studio-types/index.d.ts index 94ce31b9..b701e9eb 100644 --- a/packages/eez-studio-types/index.d.ts +++ b/packages/eez-studio-types/index.d.ts @@ -756,8 +756,12 @@ export interface IWasmFlowRuntime { _lvglSetTimelinePosition(timelinePosition: number): void; _lvglClearTimeline(): void; _lvglGetFlowState(flowState: number, userWidgetComponentIndexOrPageIndex: number): number; + _lvglSetScrollBarMode(obj: number, mode: number); _lvglSetScrollDir(obj: number, dir: number); + _lvglSetScrollSnapX(obj: number, align: number); + _lvglSetScrollSnapY(obj: number, align: number); + _lvglTabviewSetActive(obj: number, tab_id: number, anim_en: number); _lvglTabviewGetTabBar(obj: number, index: number); _lvglTabviewGetTabContent(obj: number, index: number); diff --git a/packages/project-editor/flow/runtime/cpp/lvgl-runtime/common/src/studio_api.cpp b/packages/project-editor/flow/runtime/cpp/lvgl-runtime/common/src/studio_api.cpp index b2e03ec5..5b81ec53 100644 --- a/packages/project-editor/flow/runtime/cpp/lvgl-runtime/common/src/studio_api.cpp +++ b/packages/project-editor/flow/runtime/cpp/lvgl-runtime/common/src/studio_api.cpp @@ -1120,6 +1120,14 @@ EM_PORT_API(void) lvglSetScrollDir(lv_obj_t *obj, lv_dir_t dir) { lv_obj_set_scroll_dir(obj, dir); } +EM_PORT_API(void) lvglSetScrollSnapX(lv_obj_t *obj, lv_scroll_snap_t align) { + lv_obj_set_scroll_snap_x(obj, align); +} + +EM_PORT_API(void) lvglSetScrollSnapY(lv_obj_t *obj, lv_scroll_snap_t align) { + lv_obj_set_scroll_snap_y(obj, align); +} + EM_PORT_API(void) lvglTabviewSetActive(lv_obj_t *obj, uint32_t tab_id, lv_anim_enable_t anim_en) { #if LVGL_VERSION_MAJOR >= 9 lv_tabview_set_active(obj, tab_id, anim_en); diff --git a/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.js b/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.js index 75ab567e..d7fc0de3 100644 --- a/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.js +++ b/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.js @@ -4831,6 +4831,8 @@ var _lvglSetTimelinePosition = Module['_lvglSetTimelinePosition'] = createExport var _lvglClearTimeline = Module['_lvglClearTimeline'] = createExportWrapper('lvglClearTimeline'); var _lvglSetScrollBarMode = Module['_lvglSetScrollBarMode'] = createExportWrapper('lvglSetScrollBarMode'); var _lvglSetScrollDir = Module['_lvglSetScrollDir'] = createExportWrapper('lvglSetScrollDir'); +var _lvglSetScrollSnapX = Module['_lvglSetScrollSnapX'] = createExportWrapper('lvglSetScrollSnapX'); +var _lvglSetScrollSnapY = Module['_lvglSetScrollSnapY'] = createExportWrapper('lvglSetScrollSnapY'); var _lvglTabviewSetActive = Module['_lvglTabviewSetActive'] = createExportWrapper('lvglTabviewSetActive'); var _lvglTabviewGetTabBar = Module['_lvglTabviewGetTabBar'] = createExportWrapper('lvglTabviewGetTabBar'); var _lvglTabviewGetTabContent = Module['_lvglTabviewGetTabContent'] = createExportWrapper('lvglTabviewGetTabContent'); diff --git a/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.wasm b/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.wasm index 4283b1e4..6f91eb0c 100644 Binary files a/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.wasm and b/packages/project-editor/flow/runtime/lvgl_runtime_v9.0.wasm differ diff --git a/packages/project-editor/lvgl/lvgl-constants.ts b/packages/project-editor/lvgl/lvgl-constants.ts index 19552ecc..de4275ee 100644 --- a/packages/project-editor/lvgl/lvgl-constants.ts +++ b/packages/project-editor/lvgl/lvgl-constants.ts @@ -247,6 +247,20 @@ export const LV_ANIM_ON = 1; //////////////////////////////////////////////////////////////////////////////// +const LV_SCROLL_SNAP_NONE = 0; +const LV_SCROLL_SNAP_START = 1; +const LV_SCROLL_SNAP_END = 2; +const LV_SCROLL_SNAP_CENTER = 3; + +export const LVGL_SCROLL_SNAP: { [key: string]: number } = { + none: LV_SCROLL_SNAP_NONE, + start: LV_SCROLL_SNAP_START, + end: LV_SCROLL_SNAP_END, + center: LV_SCROLL_SNAP_CENTER +}; + +//////////////////////////////////////////////////////////////////////////////// + export const LVGL_FLAG_CODES = { HIDDEN: 1 << 0, // Make the object hidden. (Like it wasn't there at all) CLICKABLE: 1 << 1, // Make the object clickable by the input devices diff --git a/packages/project-editor/lvgl/widgets/Base.tsx b/packages/project-editor/lvgl/widgets/Base.tsx index 753b474f..3707c8cc 100644 --- a/packages/project-editor/lvgl/widgets/Base.tsx +++ b/packages/project-editor/lvgl/widgets/Base.tsx @@ -88,7 +88,8 @@ import { LVGL_STATE_CODES, LVGL_REACTIVE_STATES, LVGL_REACTIVE_FLAGS, - LV_EVENT_CHECKED_STATE_CHANGED + LV_EVENT_CHECKED_STATE_CHANGED, + LVGL_SCROLL_SNAP } from "project-editor/lvgl/lvgl-constants"; import { LVGLPropertyInfo } from "project-editor/lvgl/style-catalog"; @@ -228,6 +229,8 @@ export class LVGLWidget extends Widget { widgetFlags: string; flagScrollbarMode: string; flagScrollDirection: string; + scrollSnapX: string; + scrollSnapY: string; checkedState: string | boolean; checkedStateType: LVGLPropertyType; @@ -467,6 +470,56 @@ export class LVGLWidget extends Widget { enumDisallowUndefined: false, propertyGridGroup: flagsGroup }, + { + name: "scrollSnapX", + displayName: "Scroll snap X", + type: PropertyType.Enum, + enumItems: [ + { + id: "none", + label: "NONE" + }, + { + id: "start", + label: "START" + }, + { + id: "end", + label: "END" + }, + { + id: "center", + label: "CENTER" + } + ], + enumDisallowUndefined: false, + propertyGridGroup: flagsGroup + }, + { + name: "scrollSnapY", + displayName: "Scroll snap Y", + type: PropertyType.Enum, + enumItems: [ + { + id: "none", + label: "NONE" + }, + { + id: "start", + label: "START" + }, + { + id: "end", + label: "END" + }, + { + id: "center", + label: "CENTER" + } + ], + enumDisallowUndefined: false, + propertyGridGroup: flagsGroup + }, ...makeLvglExpressionProperty( "checkedState", "boolean", @@ -881,6 +934,8 @@ export class LVGLWidget extends Widget { heightUnit: "px", flagScrollbarMode: "", flagScrollDirection: "", + scrollSnapX: "", + scrollSnapY: "", hiddenFlagType: "literal", clickableFlagType: "literal", checkedStateType: "literal", @@ -1013,6 +1068,8 @@ export class LVGLWidget extends Widget { clickableFlagType: observable, flagScrollbarMode: observable, flagScrollDirection: observable, + scrollSnapX: observable, + scrollSnapY: observable, checkedState: observable, checkedStateType: observable, disabledState: observable, @@ -1369,6 +1426,20 @@ export class LVGLWidget extends Widget { ); } + if (this.scrollSnapX) { + runtime.wasm._lvglSetScrollSnapX( + obj, + LVGL_SCROLL_SNAP[this.scrollSnapX] + ); + } + + if (this.scrollSnapY) { + runtime.wasm._lvglSetScrollSnapY( + obj, + LVGL_SCROLL_SNAP[this.scrollSnapY] + ); + } + // add/clear states { const added = @@ -1648,7 +1719,19 @@ export class LVGLWidget extends Widget { if (this.flagScrollDirection) { build.line( - `lv_obj_set_scroll_dir(obj, LV_DIR_${this.flagScrollDirection.toUpperCase()});` + `lv_obj_set_scroll_snap_x(obj, LV_DIR_${this.flagScrollDirection.toUpperCase()});` + ); + } + + if (this.scrollSnapX) { + build.line( + `lv_obj_set_scroll_snap_x(obj, LV_SCROLL_SNAP_${this.scrollSnapX.toUpperCase()});` + ); + } + + if (this.scrollSnapY) { + build.line( + `lv_obj_set_scroll_snap_y(obj, LV_SCROLL_SNAP_${this.scrollSnapY.toUpperCase()});` ); }