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
67 每月下载量
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::new
或 DeclarativeApp::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