#widgets #ui #bindings #graphics #json-schema #json-file

fltk-decl

用声明性方式描述你的 fltk-rs 应用,支持热重载!

16 个版本

0.2.7 2023 年 9 月 9 日
0.2.6 2023 年 8 月 14 日
0.2.4 2023 年 5 月 26 日
0.2.3 2023 年 4 月 14 日
0.1.7 2023 年 2 月 20 日

#764 in GUI

Download history

67 每月下载量

MIT 许可证

39KB
758

fltk-decl

使用声明性语言(json5, json, yaml, xml, toml, s-exp)来描述你的 fltk-rs GUI,支持 GUI 文件的热重载。该包设计得尽可能宽松。因此,错误的键或值将被忽略。通常只有在运行时更改小部件的 id 才会导致错误!

用法

使用固定格式,使用功能

假设我们使用 json 来描述我们的 GUI,我们将拉取 fltk-decl 和 fltk。由于我们使用 json,我们将指定所需的特征。在你的 Cargo.toml

[dependencies]
fltk-decl = { version = "0.2", features = ["json"] }
fltk = "1.3.32"

对于其他格式,将 json 功能替换为你的所需功能。可能的值(json, json5, yaml, xml)。

创建一个 json 文件,我们将其命名为 gui.json

{
    "$schema": "https://raw.githubusercontent.com/MoAlyousef/fltk-decl/main/schemas/fltk-schema.json",
    "widget": "Column",
    "children": [
        {
            "widget": "Button",
            "label": "Inc",
            "fixed": 60,
            "id": "inc",
            "labelcolor": "#0000ff"

        },
        {
            "widget": "Row",
            "children": [
                {
                    "widget": "Frame",
                    "fixed": 30
                },
                {
                    "widget": "Frame",
                    "label": "0",
                    "id": "result",
                    "labelcolor": "#ff0000"
                },
                {
                    "widget": "Frame",
                    "fixed": 30
                }
            ]
        },
        {
            "widget": "Button",
            "label": "Dec",
            "fixed": 60,
            "id": "dec"
        }
    ]
}

请注意,我们指向模式以在 vscode 中获得自动完成和提示,否则它是可选的。

将其导入到你的应用中

use fltk_decl::{DeclarativeApp, Widget};

fn main() {
    // use the filetype and extension that you require.
    // `run` a callback that runs at least once, or whenever the gui file changes.
    DeclarativeApp::new_json(200, 300, "MyApp", "examples/gui.json").run(|_| {}).unwrap();
}

请注意,我们使用由 json 功能提供的 new_json。构造函数的形式为 DeclarativeApp::newDeclarativeApp::new_<feature>,例如 new_json5, new_yaml, new_xml!

处理回调

use fltk::{prelude::*, *};
use fltk_decl::{DeclarativeApp, Widget};

// use the extension you require!
const PATH: &str = "examples/gui.json";

#[derive(Clone, Copy)]
struct State {
    count: i32,
}

impl State {
    pub fn increment(&mut self, val: i32) {
        let mut result: frame::Frame = app::widget_from_id("result").unwrap();
        self.count += val;
        result.set_label(&self.count.to_string());
    }
}

fn btn_cb(b: &mut button::Button) {
    let state = app::GlobalState::<State>::get();
    let val = if b.label() == "Inc" {
        1
    } else {
        -1
    };
    state.with(move |s| s.increment(val));
}

fn main() {
    app::GlobalState::new(State { count: 0 });
    DeclarativeApp::new_json(200, 300, "MyApp", PATH)
        .run(|_win| {
            app::set_scheme(app::Scheme::Oxy);
            if let Some(mut btn) = app::widget_from_id::<button::Button>("inc") {
                btn.set_callback(btn_cb);
            }
            if let Some(mut btn) = app::widget_from_id::<button::Button>("dec") {
                btn.set_callback(btn_cb);
            }
        })
        .unwrap();
}

灵活,使用任何 serde 格式和使用加载函数(不需要功能)

假设我们使用 json 来描述我们的 GUI,我们将拉取 fltk-decl、fltk 和所需的反序列化库,在这个例子中是 serde_json:在你的 Cargo.toml

[dependencies]
fltk-decl = "0.2"
fltk = "1.3.32"
serde_json = "1"

对于其他数据格式,你可以拉取相应的反序列化库

serde_json5 = "0.1" # for json5
serde-xml-rs = "0.6" # for xml
serde_yaml = "0.9" # for yaml
toml = "0.7" # for toml
serde-lexpr = "0.1.2" # for an s-expression description

创建一个 json 文件,我们将其命名为 gui.json

{
    "$schema": "https://raw.githubusercontent.com/MoAlyousef/fltk-decl/main/schemas/fltk-schema.json",
    "widget": "Column",
    "children": [
        {
            "widget": "Button",
            "label": "Inc",
            "fixed": 60,
            "id": "inc",
            "labelcolor": "#0000ff"

        },
        {
            "widget": "Row",
            "children": [
                {
                    "widget": "Frame",
                    "fixed": 30
                },
                {
                    "widget": "Frame",
                    "label": "0",
                    "id": "result",
                    "labelcolor": "#ff0000"
                },
                {
                    "widget": "Frame",
                    "fixed": 30
                }
            ]
        },
        {
            "widget": "Button",
            "label": "Dec",
            "fixed": 60,
            "id": "dec"
        }
    ]
}

请注意,我们指向模式以在 vscode 中获得自动完成和提示,否则它是可选的。

将其导入到你的应用中

use fltk_decl::{DeclarativeApp, Widget};

// declare how you would like to deserialize
fn load_fn(path: &'static str) -> Option<Widget> {
    let s = std::fs::read_to_string(path).ok()?;
    // We want to see the serde error on the command line while we're developing
    serde_json5::from_str(&s).map_err(|e| eprintln!("{e}")).ok()
}

fn main() {
    // use the filetype and extension that you require.
    // `run` a callback that runs at least once, or whenever the gui file changes.
    DeclarativeApp::new(200, 300, "MyApp", "examples/gui.json", load_fn).run(|_| {}).unwrap();
}

处理回调

use fltk::{prelude::*, *};
use fltk_decl::{DeclarativeApp, Widget};

// use the extension you require!
const PATH: &str = "examples/gui.json";

#[derive(Clone, Copy)]
struct State {
    count: i32,
}

impl State {
    pub fn increment(&mut self, val: i32) {
        let mut result: frame::Frame = app::widget_from_id("result").unwrap();
        self.count += val;
        result.set_label(&self.count.to_string());
    }
}

fn btn_cb(b: &mut button::Button) {
    let state = app::GlobalState::<State>::get();
    let val = if b.label() == "Inc" {
        1
    } else {
        -1
    };
    state.with(move |s| s.increment(val));
}

fn load_fn(path: &'static str) -> Option<Widget> {
    let s = std::fs::read_to_string(path).ok()?;
    serde_json5::from_str(&s).map_err(|e| eprintln!("{e}")).ok()
}

fn main() {
    app::GlobalState::new(State { count: 0 });
    DeclarativeApp::new(200, 300, "MyApp", PATH, load_fn)
        .run(|_win| {
            app::set_scheme(app::Scheme::Oxy);
            if let Some(mut btn) = app::widget_from_id::<button::Button>("inc") {
                btn.set_callback(btn_cb);
            }
            if let Some(mut btn) = app::widget_from_id::<button::Button>("dec") {
                btn.set_callback(btn_cb);
            }
        })
        .unwrap();
}

其他数据格式

你可以选择 json5(以利用注释、尾随逗号和未引号的键!)

{
    // main column
    widget: "Column",
    children: [
        {
            // our button
            widget: "Button",
            label: "Click me",
            color: "#ff0000",
            id: "my_button",
        }
    ],
}

然而,你将失去 vscode 的自动完成,因为 vscode 中的 json5 扩展不支持模式。

你还可以使用 yaml(可选地,与模式一起用于自动完成和验证)

# yaml-language-server: $schema=https://raw.githubusercontent.com/MoAlyousef/fltk-decl/main/schemas/fltk-schema.yaml

widget: Column
children:
- widget: Button
  label: Inc
  fixed: 60
  id: inc
  labelcolor: "#0000ff"
- widget: Row
  children:
  - widget: Frame
    fixed: 30
  - widget: Frame
    label: '0'
    id: result
    labelcolor: "#ff0000"
  - widget: Frame
    fixed: 30
- widget: Button
  label: Dec
  fixed: 60
  id: dec

你还可以使用 xml:gui.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <widget>Column</widget>
    <children>
        <widget>Button</widget>
        <label>Click Me</label>
        <id>my_button</id>
        <labelcolor>#0000ff</labelcolor>
    </children>
</root>

或 toml!

widget = "Column"

[[children]]
widget = "Button"
label = "Click Me"
id = "my_button"

或 s-expression 格式

(
    (widget . "Column") 
    (children (
        (
            (widget . "Button") 
            (label "Inc") 
            (id "inc") 
            (fixed 60) 
            (labelcolor "#0000ff")
        )
        (
            (widget . "Frame")
            (id "result")
            (label "0")
        )
        (
            (widget . "Button") 
            (label "Dec") 
            (id "dec") 
            (fixed 60) 
            (labelcolor "#ff0000")
        )
    ))
)

支持的属性

  • widget:(必需)小部件类型(字符串)
  • label:小部件标签(字符串)
  • fixed:小部件是否固定在 Flex 内(整数)
  • x: x 坐标
  • y: y 坐标
  • w:宽度
  • h:高度
  • margin: Flex 的边距
  • left: Flex 的左侧边距
  • top: Flex 的顶部边距
  • right: Flex 的右侧边距
  • bottom: Flex 的底部边距
  • id: 小部件的ID(字符串)
  • labelcolor: 小部件的标签颜色(字符串,格式#xxxxxx)
  • color: 小部件的颜色(字符串,格式#xxxxxx)
  • selectioncolor: 小部件的选择颜色(字符串,格式#xxxxxx)
  • hide: 小部件是否隐藏(布尔值)
  • visible: 小部件是否可见(布尔值)
  • deactivate: 小部件是否已停用(布尔值)
  • resizable: 小部件是否为可调整大小的组小部件(布尔值)
  • tooltip: 小部件的提示信息(字符串)
  • image: 小部件的图像路径(字符串)
  • deimage: 小部件(停用状态)的图像路径(字符串)
  • labelfont: 标签字体(整数)
  • labelsize: 标签大小(整数)
  • align: 标签的对齐方式(整数)
  • when: 小部件的回调触发(整数)
  • frame: 小部件的框架类型(字符串)
  • downframe: 按钮的down_frame类型,针对按钮(字符串)
  • shortcut: 按钮的快捷键(字符串)
  • pad: Flex的填充(整数)
  • minimun: 估值器的最小值(浮点数)
  • maximum: 估值器的最大值(浮点数)
  • slidersize: 估值器的滑块大小(浮点数)
  • step: 估值器的步长(浮点数)
  • textcolor: 小部件的文本颜色(字符串)
  • textsize: 小部件的文本大小(整数)
  • textfont: 小部件的字体(整数)
  • children: 表示小部件子项的数组(对象数组)

支持的控件

  • Column(Flex列)
  • Row(Flex行)
  • Button(按钮)
  • CheckButton(复选按钮)
  • RadioButton(单选按钮)
  • ToggleButton(切换按钮)
  • RadioRoundButton(圆形单选按钮)
  • ReturnButton(返回按钮)
  • Frame(框架)
  • Group(组)
  • Pack(包装)
  • Tile(平铺)
  • Tabs(标签页)
  • Scroll(滚动条)
  • ColorChooser(颜色选择器)
  • TextDisplay(文本显示)
  • TextEditor(文本编辑器)
  • Input(输入框)
  • IntInput(整数输入框)
  • FloatInput(浮点数输入框)
  • SecretInput(隐藏输入框)
  • FileInput(文件输入框)
  • MultilineInput(多行输入框)
  • Output(输出框)
  • MultilineOutput(多行输出框)
  • MenuBar(菜单栏)
  • SysMenuBar(系统菜单栏)
  • Choice(选择框)
  • Slider(滑块)
  • NiceSlider(精美滑块)
  • FillSlider(填充滑块)
  • ValueSlider(值滑块)
  • Dial(旋钮)
  • LineDial(线性旋钮)
  • FillDial(填充旋钮)
  • Counter(计数器)
  • Scrollbar(滚动条)
  • Roller(滚筒)
  • Adjuster(调整器)
  • ValueInput(值输入框)
  • ValueOutput(值输出框)
  • HorSlider(水平滑块)
  • HorNiceSlider(水平精美滑块)
  • HorFillSlider(水平填充滑块)
  • HorValueSlider(水平值滑块)
  • Browser(浏览器)
  • SelectBrowser(选择浏览器)
  • HoldBrowser(保持浏览器)
  • FileBrowser(文件浏览器)
  • CheckBrowser(复选浏览器)
  • MultiBrowser(多浏览器)
  • Table(表格)
  • TableRow(表格行)
  • Tree(树形控件)
  • Spinner(旋转器)
  • Chart(图表)
  • Progress(进度条)
  • InputChoice(输入选择)
  • HelpView(帮助视图)
  • Window(窗口)
  • MenuWindow(菜单窗口)
  • GlutWindow(需要启用enable-glwindow功能)

依赖项

~14–23MB
~391K SLoC