crui_lvgl 一个LVGL的DSL辅助工具的设想

设想

Target以LVGL为目标,语法以CSS为Reference。

CSS 规范

CSS规范最强大的属于CSS自身的属性很多,可以通过class和伪属性选择器对UI进行直接控制。

QML规范

ApplicationWindow {
    visible: true
    width: Constants.width
    height: Constants.height
    title: qsTr("Coffee")
    
    ApplicationFlowForm {
      id: applicationFlow
      state: "initial"

      property int animationDuration: 400

      choosingCoffee.brewButtonSelection.onClicked: {
          applicationFlow.state = "settings"
      }
    }  
    
    Image {
        id: root
        source: "images/icons/coffees/cappucino.png"
        signal clicked

        property int duration: 250
        property alias text: label.text
        MouseArea {
            anchors.fill: parent
            onClicked: root.clicked()
            onPressed: {
                glow.visible = true
                animation1.start()
                animation2.start()
            }
        }

        Rectangle {
            id: glow
            visible: false

            width: 250
            height: 250
            color: "#00000000"
            radius: 125
            scale: 1.05
            border.color: "#ffffff"
        }

        Label {
            id: label
            x: 292
            y: 252
            text: qsTr("Label")
            anchors.horizontalCenter: parent.horizontalCenter
            color: "#443224"
            font.family: Constants.fontFamily
            font.pixelSize: 28
        }
    }

}

Slint Demo

Slint本身来源于QML, flutter 等项目,吸收优化得到的Design。

import { Button } from "std-widgets.slint";
export component MainWindow inherits Window {
  height: 720px;
  width: 1200px;
  title: "Button!";
  Button { 
    height: 66px;
    width: 310px;
    icon: @image-url("../../imgs/rust.png");
    text: "I am a Button";
    clicked => {
      self.text = "Clicked!";
      self.width = 360px;
    }
  }
  
  GridLayout {
    spacing: 10px;
    padding: 4px;
    //使用Row进行行声明
    Row{
      Rectangle { background: red; }
      Rectangle { background: yellow;}
      Rectangle { background: pink; }
    }
    Row{
      Rectangle { background: white; colspan: 2; }
      Rectangle { background: green; colspan: 1; col: 2;} 
    }
    Rectangle { background: violet; colspan: 3;row:3;}
    Rectangle { background: orange; colspan: 3;row:2;}
  }
}

QML和Slint是将CSS的属性选择等能力,作为Object的属性存在,单独设定。虽然一定程度上解决了UI复用问题,但是不灵活。

QML胜在周边成熟,与Qt Object高度绑定,代码融合比较简单。Slint反而优点不伦不类,没有生态支撑,但是IDE配套做的不错,比LVGL好太多。

LVGL规范

  • Demos https://docs.lvgl.io/master/examples.html
  • Object基础属性 https://docs.lvgl.io/master/widgets/obj.html#overview
  • Theme和定制 https://docs.lvgl.io/master/overview/style.html#themes
# demo1, label
screen
    *color
    label
        *text
        *color
        
# demo2, button
screen
    button
        *pos
        *size
        *event  # <== 这里进行事件绑定  
        label
            *text
            *align
            
# demo3, flex
screen
    object1
        *size
        *align
        *flex
        button*N
            *size
            label
                *text
                *algin
    object2
        *size
        *align
        *flex
        button*N
            *size
            label
                *text
                *algin
       
# demo4, grid
screen
    object
        *grid
        *size
        *algin
        *layout_grid    
        button*N
            label
                *text
                *align     
                
# style, == class
style
    *radius
    *bg_opa
    *bg_color
    *border_width
    *border_color
    # ...

screen
    object
        *style
        image
            *algin

# theme
default_theme

theme2
    style
    
screen
    button   
        *align
        label
            *text
    button(theme2)  # change theme
        *align
        label
            *text

总结:

  1. Screen为root, 但是可以有多个,每次选一个作为default。
  2. 每个Screen有2个Layer层,但是用户一般只用top layer。(一般coding时,不用在乎这个问题)
  3. Layer(screen)内部可以自由组合 Object/Widgets, 每个Object/Widget 可以自由设定Layout为Grid/Flex/Absolute(默认)
  4. 每个Object/Widget都有默认的style(来源于默认的theme),可以自己custom style给object/widget使用。
  5. Theme是各种style的集合,也可以继承或者自己custom.
  6. 字体和图片需要转换后才能使用。中文支持需要添加中文字体。屏幕键盘默认不支持中文。

与QML/Slint比,没有DSL部分,全是C/C++ Code生成,也没有Nodejs/Go/Rust等binding部分(部分有,但不成熟)。有theme和style部分,很接近CSS的味道,但是没有DSL的加持,写起来很痛苦。

一句话:LVGL是个灵活的胖子!

想法

Idea Target

鉴于Slint和QML的授权协议,在嵌入式设备上收费,还有Rust/Qt的依赖问题,如果能有一个DSL和对应的C code tool, LVGL应该回是一个不错的选择。

所以,向借鉴Slint的VS Code插件,能不能仿照Vue、React一类的用法,将CSS和template一起渲染为C Code, 并绑定event,还支持UI的preview in design?

如果能做这样一个插件,并且提供LVGL工具库,支持UI动态Load, 这将会是一个非常不错的主意,并且对Coding有很大的帮助。

如果这个工具支持的DSL语法类似QML更好,不支持也尽量类似。

以上,于2023年11月28日。

Design

  1. [v] Kotlin DSL有类似的感觉
  2. 自己做解析,难以支持语法检查和扩展
  3. [?] 不知道QML的那种解析怎么实现的
  4. [v] template 模拟vue/json那种

参考:Groovy => Gradle

使用:Kotlin native + kts + ffi(DSL+LVGL)

  • 先实现PC平台的调用
  • 然后做一个xxx.lvgl的实时预览和代码生成
  • 然后做一个开源库,LVGL辅助库函数

deadline: 2024/06/28, name: crui_lvgl