├── .cargo
└── config.toml
├── .github
└── workflows
│ └── deploy.yaml
├── .gitignore
├── Cargo.toml
├── README.md
├── build_web.sh
├── egui.d.lua
├── examples
├── basic.rs
├── index.html
└── script.lua
└── src
└── lib.rs
/.cargo/config.toml:
--------------------------------------------------------------------------------
1 |
2 | # primarily for deploying example to github pages
3 | [target.wasm32-unknown-emscripten]
4 | rustflags = [
5 | "-C",
6 | "link-arg=-s",
7 | "-C",
8 | "link-arg=USE_GLFW=3", # for glfw support.
9 | "-C",
10 | "link-arg=-s",
11 | "-C",
12 | "link-arg=FULL_ES2", # for opengl es 2 emulation
13 | "-C",
14 | "link-arg=-s",
15 | "-C",
16 | "link-arg=FULL_ES3", # for opengl es 3 emulation
17 | "-C",
18 | "link-arg=-s",
19 | "-C",
20 | "link-arg=MAX_WEBGL_VERSION=2 ", # to make sure that webgl2 is enabled.
21 | "-C",
22 | "link-arg=-s",
23 | "-C",
24 | "link-arg=MIN_WEBGL_VERSION=2", # to disable webgl1 completely, and use webgl2 exclusively.
25 | "-C",
26 | "link-arg=-s",
27 | "-C",
28 | "link-arg=ERROR_ON_UNDEFINED_SYMBOLS=0", # emscripten is very brittle sometimes with missing symbols. you can remove this flag if you don't have any problem with this.
29 | ]
30 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yaml:
--------------------------------------------------------------------------------
1 | name: Github Pages
2 |
3 | on: [push]
4 |
5 | permissions:
6 | contents: write
7 |
8 | jobs:
9 | build-github-pages:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - uses: actions/checkout@v2 # repo checkout
13 | - uses: mymindstorm/setup-emsdk@v13 # setup emscripten toolchain
14 | with:
15 | version: 3.1.52
16 | - uses: actions-rs/toolchain@v1 # get rust toolchain for wasm
17 | with:
18 | toolchain: stable
19 | target: wasm32-unknown-emscripten
20 | override: true
21 | - name: Check Emscripten # just to make sure that emscripten is properly installed
22 | run: emcc -v
23 | - name: Rust Cache # cache the rust build artefacts
24 | uses: Swatinem/rust-cache@v1
25 | - name: Build # bash script to build and put all required files inside a directory called "dist"
26 | run: ./build_web.sh
27 | - name: Deploy
28 | uses: JamesIves/github-pages-deploy-action@v4
29 | with:
30 | folder: dist
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/target
2 | /Cargo.lock
3 | /dist
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "luaegui"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7 |
8 | [features]
9 |
10 | [dependencies]
11 | egui = "0.26"
12 | mlua = { version = "0.9", features = ["luau-vector4"] }
13 |
14 | [dev-dependencies]
15 | egui_commonmark = "0.13"
16 |
17 | # disable default glfw features on emscripten
18 | [target.'cfg(target_arch = "wasm32")'.dev-dependencies]
19 | egui_overlay = { version = "0.8.1", default-features = false, features = [
20 | "egui_default",
21 | "three_d",
22 | ] }
23 | # enable default glfw feature (enabled by default) on non-wasm platforms.
24 | [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
25 | egui_overlay = { version = "0.8.1" }
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Unmaintained
2 | ### This repo is abandoned and you are welcome to fork it.
3 |
4 | ## Deprecation Reason: Performance
5 | 1. Due to the immediate mode nature of `egui`, the scripts need to run *every* frame (average of 60 fps atleast).
6 | 2. Ui code creates *lots* of temporary `use once` objects, which means lots of garbage collectable objects for a reasonably complex ui script. It is also expensive to create/recreate these objects every frame.
7 | 1. Builder pattern creates a struct for every container/widget. eg: `Window::new("hello")` or `RichText::new("text").color(egui.blue)` etc..
8 | 2. return values of widget `ui` fn like `Response` also create userdata objects.
9 | 3. each `&mut Ui` needs to create a new userdata object to bind that reference to.
10 | 4. Even value types like `Rect` will need to be userdata.
11 | 3. Due to a large amount of function calls between native host egui and the script, JIT also sucks at optimizing this.
12 | 4. All the closures also require jumping between host and guest scopes which have some "setup"/"teardown" costs
13 |
14 | This project might still work for some people, and I would encourage them to fork this repo.
15 | But I would like to experiment with retained mode toolkits now, where you only scripts on events.
16 |
17 |
18 |
19 | # luaegui
20 | egui bindings for mlua.
21 |
22 | Just look at the example for basic usage. You can play with the web version live at https://coderedart.github.io/luaegui/
23 |
24 | There should be a window called `Script Editor` where you can edit the lua code live within egui.
25 | After editing the code, just click the `run` button on top to execute that code in the lua vm.
26 | If there was any error, it will be printed to stdout/console(on web).
27 | Below the code editor, you can see how long the `gui_run` fn takes every frame.
28 | ### gui_run
29 | Every frame, the example will try to call the `gui_run` fn (if it exists) and gives it egui context as the argument.
30 | If the fn fails for some reason, the error will be printed to stdout/console.
31 |
32 | ### egui
33 | We provide a global table called `egui` which contains most constants + types + functions to be used by lua scripts.
34 | for example, you can create a `Window` using `local window = egui.window.new("my window title");`
35 |
36 | ### Developer Experience
37 | Because we don't really have a way to properly document host api in mlua yet, we will do this manually. For now, we provide a type definition file (WIP) `egui.d.lua`.
38 |
39 | 1. Install `Luau Language Server` extension by `JohnnyMorganz` in vscode
40 | 2. copy `egui.d.lua` file from thi repo to your lua project folder
41 | 3. In the settings Ui `luau-lsp.types.definitionFiles`, add the file `egui.d.lua`
42 | 4. Now, you have autocompletion, as well as linting (to a reasonable extent) when you want to use egui.
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/build_web.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # this script is used to build and copy the files into a directory called dist.
3 | set -ex
4 |
5 | echo "building for emscripten target"
6 | cargo build --example=basic --target=wasm32-unknown-emscripten --release
7 |
8 | echo "copying files to dist directory"
9 | mkdir -p dist
10 | cp target/wasm32-unknown-emscripten/release/examples/basic.wasm dist
11 | cp target/wasm32-unknown-emscripten/release/examples/basic.js dist
12 | cp examples/index.html dist
--------------------------------------------------------------------------------
/egui.d.lua:
--------------------------------------------------------------------------------
1 | declare class Context
2 | function clone(self): Context
3 | end
4 | declare class Response
5 | function clicked(self): boolean
6 | end
7 | declare class InnerResponse
8 | response: Response
9 | inner: any
10 | end
11 |
12 | declare class Ui
13 | function add_enabled_ui(self, enabled: boolean, uifn: (Ui) -> any): InnerResponse
14 | function add_space(self, space: number): ()
15 | function add_visible_ui(self, visible: boolean, uifn: (Ui) -> any): InnerResponse
16 |
17 | function label(self, text: string): Response
18 | function text_edit_singleline(self, text: string): Response
19 | function button(self, text: string): Response
20 |
21 | end
22 | declare class TopBottomPanel
23 | function show(self, ctx: Context, uifn: (Ui) -> any): any
24 | end
25 | declare class Window
26 | function show(self, ctx: Context, uifn: (Ui) -> any): any
27 | end
28 | declare egui: {
29 | top_bottom_panel: {
30 | top: (string) -> TopBottomPanel,
31 | bottom: (string) -> TopBottomPanel
32 | },
33 | window: {
34 | new: (string) -> Window
35 | }
36 | }
--------------------------------------------------------------------------------
/examples/basic.rs:
--------------------------------------------------------------------------------
1 | use egui_overlay::*;
2 | use mlua::Function;
3 |
4 | fn main() {
5 | fake_main();
6 | }
7 |
8 | const LUA_CODE: &str = include_str!("script.lua");
9 |
10 | struct AppData {
11 | pub script_time: std::time::Duration,
12 | pub lua: mlua::Lua,
13 | pub code: String,
14 | pub markdown_cache: egui_commonmark::CommonMarkCache,
15 | }
16 |
17 | impl EguiOverlay for AppData {
18 | fn gui_run(
19 | &mut self,
20 | egui_context: &egui::Context,
21 | _default_gfx_backend: &mut egui_render_three_d::ThreeDBackend,
22 | _glfw_backend: &mut egui_window_glfw_passthrough::GlfwBackend,
23 | ) {
24 | use egui::*;
25 | let ctx = egui_context.clone();
26 | Window::new("README").show(&ctx, |ui| {
27 | egui_commonmark::CommonMarkViewer::new("readme renderer").show(
28 | ui,
29 | &mut self.markdown_cache,
30 | README,
31 | );
32 | });
33 | Window::new("Script Editor")
34 | .min_width(400.0)
35 | .show(&ctx, |ui| {
36 | if ui.button("run").clicked() {
37 | if let Err(e) = self.lua.load(&self.code).exec() {
38 | eprintln!("lua load error: {e:?}");
39 | }
40 | }
41 | if !self.lua.globals().contains_key("gui_run").unwrap() {
42 | ui.colored_label(Color32::RED, "gui_run fn is not defined");
43 | }
44 | ui.add(
45 | egui::TextEdit::multiline(&mut self.code)
46 | .code_editor()
47 | .desired_width(400.0),
48 | );
49 | ui.horizontal(|ui| {
50 | ui.label("script execution time (micros): ");
51 | ui.label(format!("{}", self.script_time.as_micros()));
52 | });
53 | });
54 | let start = std::time::Instant::now();
55 | if let Ok(f) = self.lua.globals().get::<_, Function>("gui_run") {
56 | let c = self.lua.create_any_userdata(ctx).unwrap();
57 | let _: () = f.call(c).unwrap();
58 | }
59 | self.script_time = start.elapsed();
60 | }
61 | }
62 |
63 | fn fake_main() {
64 | let lua = mlua::Lua::new();
65 | luaegui::register_egui_bindings(&lua).unwrap();
66 | let app = AppData {
67 | lua,
68 | code: LUA_CODE.to_string(),
69 | script_time: std::time::Duration::ZERO,
70 | markdown_cache: Default::default(),
71 | };
72 | start(app)
73 | }
74 |
75 | const README: &str = include_str!("../README.md");
76 |
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/examples/script.lua:
--------------------------------------------------------------------------------
1 | my_data = {
2 | text = "my text"
3 | }
4 | -- a function to run inside the window
5 | function window_ui(ui)
6 | ui:label(my_data.text);
7 | ui:text_edit_singleline(my_data);
8 | if ui:button("cute button"):clicked() then
9 | print("cute button pressed.");
10 | end
11 | end
12 | -- will be called every frame with egui Context as arg
13 | _G.gui_run = function (ctx)
14 | local new_window = egui.window.new("my lua window");
15 | new_window:show(ctx, window_ui);
16 | end
17 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | use egui::{
2 | epaint::Shadow,
3 | load::SizedTexture,
4 | style::{Spacing, WidgetVisuals},
5 | Align, Align2, Area, CentralPanel, Color32, Context, Direction, Frame, Id, LayerId, Layout,
6 | Margin, Order, PointerButton, Pos2, Rect, RichText, Rounding, Sense, SidePanel, Stroke, Style,
7 | TextStyle, TextureHandle, TopBottomPanel, Ui, Vec2, WidgetText, Window,
8 | };
9 | use mlua::{
10 | AnyUserData, Function, Lua, MultiValue, Result, Table, UserDataFields, UserDataMethods,
11 | UserDataRef, UserDataRefMut, UserDataRegistry, Value, Vector,
12 | };
13 |
14 | trait LuaHelperTrait: Sized {
15 | fn from_lua(value: Value) -> Result;
16 | fn to_lua(value: Self, lua: &Lua) -> Result;
17 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()>;
18 | }
19 |
20 | pub fn register_egui_bindings(lua: &Lua) -> mlua::Result<()> {
21 | let et = lua.create_table()?;
22 | let egui_table = &et;
23 | Align::add_to_lua(lua, egui_table)?;
24 | Align2::add_to_lua(lua, egui_table)?;
25 | Color32::add_to_lua(lua, egui_table)?;
26 | Direction::add_to_lua(lua, egui_table)?;
27 | Id::add_to_lua(lua, egui_table)?;
28 | Margin::add_to_lua(lua, egui_table)?;
29 | PointerButton::add_to_lua(lua, egui_table)?;
30 | Pos2::add_to_lua(lua, egui_table)?;
31 | Rect::add_to_lua(lua, egui_table)?;
32 | RichText::add_to_lua(lua, egui_table)?;
33 | Rounding::add_to_lua(lua, egui_table)?;
34 | Sense::add_to_lua(lua, egui_table)?;
35 | Stroke::add_to_lua(lua, egui_table)?;
36 | TextStyle::add_to_lua(lua, egui_table)?;
37 | Vec2::add_to_lua(lua, egui_table)?;
38 | WidgetText::add_to_lua(lua, egui_table)?;
39 |
40 | add_area(lua, egui_table)?;
41 | add_context(lua, egui_table)?;
42 | add_frame(lua, egui_table)?;
43 | add_layer_id(lua, egui_table)?;
44 | add_layout(lua, egui_table)?;
45 | add_response(lua)?;
46 | add_shadow(lua, egui_table)?;
47 | add_spacing(lua, egui_table)?;
48 | add_style(lua, egui_table)?;
49 | add_ui(lua, egui_table)?;
50 | add_widget_visuals(lua, egui_table)?;
51 | add_window(lua, egui_table)?;
52 | add_central_panel(lua, egui_table)?;
53 | add_side_panel(lua, egui_table)?;
54 | add_top_bottom_panel(lua, egui_table)?;
55 | egui_table.set_readonly(true);
56 | lua.globals().set("egui", et)?;
57 | Ok(())
58 | }
59 |
60 | fn add_context(lua: &Lua, _: &Table) -> mlua::Result<()> {
61 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
62 | reg.add_method("request_repaint", |_, this, ()| {
63 | this.request_repaint();
64 | Ok(())
65 | });
66 | reg.add_method("request_repaint_after", |_, this, duration: f64| {
67 | this.request_repaint_after(std::time::Duration::from_secs_f64(duration));
68 | Ok(())
69 | });
70 | })?;
71 | Ok(())
72 | }
73 |
74 | impl LuaHelperTrait for Id {
75 | fn from_lua(value: Value) -> Result {
76 | Ok(match value {
77 | Value::Nil => Id::NULL,
78 | Value::String(s) => Id::NULL.with(s.to_str().unwrap_or_default()),
79 | Value::UserData(u) => {
80 | *u.borrow()
81 | .map_err(|_e| mlua::Error::FromLuaConversionError {
82 | from: "Value",
83 | to: "Id",
84 | message: Some(
85 | "The variant of value is not suitable for converting to Id".to_string(),
86 | ),
87 | })?
88 | }
89 | _ => {
90 | return Err(mlua::Error::FromLuaConversionError {
91 | from: "Value",
92 | to: "Id",
93 | message: Some(
94 | "The variant of value is not suitable for converting to Id".to_string(),
95 | ),
96 | })
97 | }
98 | })
99 | }
100 |
101 | fn to_lua(value: Self, lua: &Lua) -> Result {
102 | lua.create_any_userdata(value).map(Value::UserData)
103 | }
104 |
105 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
106 | let id: Table<'_> = lua.create_table()?;
107 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
108 | reg.add_method("with", |lua, this, value: Value| {
109 | lua.create_any_userdata(match value {
110 | Value::Nil => Id::NULL,
111 | Value::Boolean(b) => this.with(b),
112 | Value::Integer(b) => this.with(b),
113 | Value::String(b) => this.with(b),
114 | _ => {
115 | return Err(mlua::Error::FromLuaConversionError {
116 | from: "value",
117 | to: "hash_for_egui_id",
118 | message: None,
119 | })
120 | }
121 | })
122 | });
123 | reg.add_method("short_debug_format", |_, this, ()| {
124 | Ok(this.short_debug_format())
125 | });
126 | })?;
127 | id.set("null", lua.create_any_userdata(Id::NULL)?)?;
128 | egui_table.set("id", id)?;
129 | Ok(())
130 | }
131 | }
132 |
133 | fn add_widget_visuals(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
134 | let id = lua.create_table()?;
135 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
136 | reg.add_field_method_get("bg_fill", |lua, this| Color32::to_lua(this.bg_fill, lua));
137 | reg.add_field_method_get("weak_bg_fill", |lua, this| {
138 | Color32::to_lua(this.weak_bg_fill, lua)
139 | });
140 | reg.add_field_method_get("bg_stroke", |lua, this| Stroke::to_lua(this.bg_stroke, lua));
141 | reg.add_field_method_get("rounding", |lua, this| Rounding::to_lua(this.rounding, lua));
142 | reg.add_field_method_get("fg_stroke", |lua, this| Stroke::to_lua(this.fg_stroke, lua));
143 | reg.add_field_method_get("expansion", |_, this| Ok(this.expansion));
144 |
145 | reg.add_field_method_set("bg_fill", |_, this, value: Value| {
146 | this.bg_fill = Color32::from_lua(value)?;
147 | Ok(())
148 | });
149 | reg.add_field_method_set("weak_bg_fill", |_, this, value: Value| {
150 | this.weak_bg_fill = Color32::from_lua(value)?;
151 | Ok(())
152 | });
153 | reg.add_field_method_set("bg_stroke", |_, this, value: Value| {
154 | this.bg_stroke = Stroke::from_lua(value)?;
155 | Ok(())
156 | });
157 | reg.add_field_method_set("rounding", |_, this, value: Value| {
158 | this.rounding = Rounding::from_lua(value)?;
159 | Ok(())
160 | });
161 | reg.add_field_method_set("fg_stroke", |_, this, value: Value| {
162 | this.fg_stroke = Stroke::from_lua(value)?;
163 | Ok(())
164 | });
165 | reg.add_field_method_set("expansion", |_, this, value: f32| {
166 | this.expansion = value;
167 | Ok(())
168 | });
169 | })?;
170 | id.set("null", lua.create_any_userdata(Id::NULL)?)?;
171 | egui_table.set("id", id)?;
172 | Ok(())
173 | }
174 |
175 | fn add_layout(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
176 | let layout = lua.create_table()?;
177 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
178 | reg.add_field_method_get("main_dir", |lua, this| {
179 | Direction::to_lua(this.main_dir, lua)
180 | });
181 | reg.add_field_method_get("main_wrap", |_, this| Ok(this.main_wrap));
182 | reg.add_field_method_get("main_align", |lua, this| {
183 | Align::to_lua(this.main_align, lua)
184 | });
185 | reg.add_field_method_get("main_justify", |_, this| Ok(this.main_justify));
186 | reg.add_field_method_get("cross_align", |lua, this| {
187 | Align::to_lua(this.cross_align, lua)
188 | });
189 | reg.add_field_method_get("cross_justify", |_, this| Ok(this.cross_justify));
190 |
191 | reg.add_field_method_set("main_dir", |_, this, value: Value| {
192 | this.main_dir = Direction::from_lua(value)?;
193 | Ok(())
194 | });
195 | reg.add_field_method_set("main_wrap", |_, this, value: bool| {
196 | this.main_wrap = value;
197 | Ok(())
198 | });
199 | reg.add_field_method_set("main_align", |_, this, value: Value| {
200 | this.main_align = Align::from_lua(value)?;
201 | Ok(())
202 | });
203 | reg.add_field_method_set("main_justify", |_, this, value: bool| {
204 | this.main_justify = value;
205 | Ok(())
206 | });
207 | reg.add_field_method_set("cross_align", |_, this, value: Value| {
208 | this.cross_align = Align::from_lua(value)?;
209 | Ok(())
210 | });
211 | reg.add_field_method_set("cross_justify", |_, this, value: bool| {
212 | this.cross_justify = value;
213 | Ok(())
214 | });
215 | })?;
216 |
217 | egui_table.set("layout", layout)?;
218 | Ok(())
219 | }
220 | fn add_spacing(lua: &Lua, _egui_table: &Table) -> mlua::Result<()> {
221 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
222 | reg.add_field_method_get("item_spacing", |lua, this| {
223 | Vec2::to_lua(this.item_spacing, lua)
224 | });
225 | reg.add_field_method_get("window_margin", |lua, this| {
226 | Margin::to_lua(this.window_margin, lua)
227 | });
228 | reg.add_field_method_get("button_padding", |lua, this| {
229 | Vec2::to_lua(this.button_padding, lua)
230 | });
231 | reg.add_field_method_get("menu_margin", |lua, this| {
232 | Margin::to_lua(this.menu_margin, lua)
233 | });
234 | reg.add_field_method_get("indent", |_, this| Ok(this.indent));
235 |
236 | reg.add_field_method_get("interact_size", |lua, this| {
237 | Vec2::to_lua(this.interact_size, lua)
238 | });
239 | reg.add_field_method_get("slider_width", |_, this| Ok(this.slider_width));
240 | reg.add_field_method_get("combo_width", |_, this| Ok(this.combo_width));
241 | reg.add_field_method_get("text_edit_width", |_, this| Ok(this.text_edit_width));
242 | reg.add_field_method_get("icon_width", |_, this| Ok(this.icon_width));
243 | reg.add_field_method_get("icon_width_inner", |_, this| Ok(this.icon_width_inner));
244 | reg.add_field_method_get("icon_spacing", |_, this| Ok(this.icon_spacing));
245 | reg.add_field_method_get("tooltip_width", |_, this| Ok(this.tooltip_width));
246 | reg.add_field_method_get("indent_ends_with_horizontal_line", |_, this| {
247 | Ok(this.indent_ends_with_horizontal_line)
248 | });
249 | reg.add_field_method_get("combo_height", |_, this| Ok(this.combo_height));
250 | // reg.add_field_method_get("scroll_bar_width", |_, this| Ok(this.scroll_bar_width));
251 | // reg.add_field_method_get("scroll_handle_min_length", |_, this| {
252 | // Ok(this.scroll_handle_min_length)
253 | // });
254 | // reg.add_field_method_get("scroll_bar_inner_margin", |_, this| {
255 | // Ok(this.scroll_bar_inner_margin)
256 | // });
257 | // reg.add_field_method_get("scroll_bar_outer_margin", |_, this| {
258 | // Ok(this.scroll_bar_outer_margin)
259 | // });
260 |
261 | // reg.add_field_method_set("weak_bg_fill", |_, this, value: Value| {
262 | // this.weak_bg_fill = Color32::from_lua(value)?;
263 | // Ok(())
264 | // });
265 | // reg.add_field_method_set("bg_stroke", |_, this, value: Value| {
266 | // this.bg_stroke = Stroke::from_lua(value)?;
267 | // Ok(())
268 | // });
269 | // reg.add_field_method_set("rounding", |_, this, value: Value| {
270 | // this.rounding = Rounding::from_lua(value)?;
271 | // Ok(())
272 | // });
273 | // reg.add_field_method_set("fg_stroke", |_, this, value: Value| {
274 | // this.fg_stroke = Stroke::from_lua(value)?;
275 | // Ok(())
276 | // });
277 | // reg.add_field_method_set(
278 | // "expansion",
279 | // |_, this, value: f32| Ok(this.expansion = value),
280 | // );
281 | })?;
282 | Ok(())
283 | }
284 | fn add_response(lua: &Lua) -> mlua::Result<()> {
285 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
286 | reg.add_method("changed", |_, this, ()| Ok(this.changed()));
287 | reg.add_method("clicked", |_, this, ()| Ok(this.clicked()));
288 | reg.add_method("clicked_by", |_, this, value: Value| {
289 | Ok(this.clicked_by(PointerButton::from_lua(value)?))
290 | });
291 | reg.add_method("clicked_elsewhere", |_, this, ()| {
292 | Ok(this.clicked_elsewhere())
293 | });
294 | // reg.add_method("context_menu", |_, this, ()| Ok(this.changed()));
295 | reg.add_method("double_clicked", |_, this, ()| Ok(this.double_clicked()));
296 | reg.add_method("double_clicked_by", |_, this, value: Value| {
297 | Ok(this.double_clicked_by(PointerButton::from_lua(value)?))
298 | });
299 | reg.add_method("drag_delta", |lua, this, ()| {
300 | Ok(Vec2::to_lua(this.drag_delta(), lua))
301 | });
302 | reg.add_method("drag_released", |_, this, ()| Ok(this.drag_released()));
303 | reg.add_method("drag_released_by", |_, this, value: Value| {
304 | Ok(this.drag_released_by(PointerButton::from_lua(value)?))
305 | });
306 | reg.add_method("drag_started", |_, this, ()| Ok(this.drag_started()));
307 | reg.add_method("drag_started_by", |_, this, value: Value| {
308 | Ok(this.drag_started_by(PointerButton::from_lua(value)?))
309 | });
310 | reg.add_method("dragged", |_, this, ()| Ok(this.dragged()));
311 | reg.add_method("dragged_by", |_, this, value: Value| {
312 | Ok(this.dragged_by(PointerButton::from_lua(value)?))
313 | });
314 | reg.add_method("enabled", |_, this, ()| Ok(this.enabled()));
315 | reg.add_method("gained_focus", |_, this, ()| Ok(this.gained_focus()));
316 | reg.add_method("has_focus", |_, this, ()| Ok(this.has_focus()));
317 | reg.add_method("highlight", |lua, this, ()| {
318 | lua.create_any_userdata(this.clone().highlight())
319 | });
320 | reg.add_method("hover_pos", |lua, this, ()| {
321 | Ok(this.hover_pos().and_then(|p| Pos2::to_lua(p, lua).ok()))
322 | });
323 | reg.add_method("hovered", |_, this, ()| Ok(this.hovered()));
324 | })
325 | }
326 |
327 | fn add_ui(lua: &Lua, _egui_table: &Table) -> mlua::Result<()> {
328 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
329 | reg.add_method_mut(
330 | "add_enabled_ui",
331 | |lua, this, (enabled, add_contents): (bool, Function)| {
332 | let ir = this.add_enabled_ui(enabled, |ui| {
333 | lua.scope(|scope| {
334 | let ui = scope.create_any_userdata_ref_mut(ui)?;
335 | let result: Result = add_contents.call(ui);
336 | result
337 | })
338 | });
339 | let r = lua.create_any_userdata(ir.response)?;
340 | let mut i = ir.inner?;
341 | i.push_front(Value::UserData(r));
342 | Ok(i)
343 | },
344 | );
345 |
346 | reg.add_method_mut("add_space", |_, this, amount: f32| {
347 | this.add_space(amount);
348 | Ok(())
349 | });
350 | reg.add_method_mut(
351 | "add_visible_ui",
352 | |lua, this, (visible, add_contents): (bool, Function)| {
353 | let ir = this.add_visible_ui(visible, |ui| {
354 | lua.scope(|scope| {
355 | let ui = scope.create_any_userdata_ref_mut(ui)?;
356 | let result: Result = add_contents.call(ui);
357 | result
358 | })
359 | });
360 | let r = lua.create_any_userdata(ir.response)?;
361 | let mut i = ir.inner?;
362 | i.push_front(Value::UserData(r));
363 | Ok(i)
364 | },
365 | );
366 | reg.add_method_mut(
367 | "allocate_at_least",
368 | |lua, this, (desired_size, sense): (Value, Value)| {
369 | let (rect, resp) = this.allocate_at_least(
370 | LuaHelperTrait::from_lua(desired_size)?,
371 | LuaHelperTrait::from_lua(sense)?,
372 | );
373 |
374 | Ok((Rect::to_lua(rect, lua)?, lua.create_any_userdata(resp)?))
375 | },
376 | );
377 | reg.add_method_mut(
378 | "allocate_exact_size",
379 | |lua, this, (desired_size, sense): (Value, Value)| {
380 | let (rect, resp) = this.allocate_exact_size(
381 | LuaHelperTrait::from_lua(desired_size)?,
382 | LuaHelperTrait::from_lua(sense)?,
383 | );
384 |
385 | Ok((Rect::to_lua(rect, lua)?, lua.create_any_userdata(resp)?))
386 | },
387 | );
388 | reg.add_method_mut(
389 | "allocate_rect",
390 | |lua, this, (rect, sense): (Value, Value)| {
391 | lua.create_any_userdata(this.allocate_rect(
392 | LuaHelperTrait::from_lua(rect)?,
393 | LuaHelperTrait::from_lua(sense)?,
394 | ))
395 | },
396 | );
397 | reg.add_method_mut(
398 | "allocate_response",
399 | |lua, this, (desired_size, sense): (Value, Value)| {
400 | lua.create_any_userdata(this.allocate_response(
401 | LuaHelperTrait::from_lua(desired_size)?,
402 | LuaHelperTrait::from_lua(sense)?,
403 | ))
404 | },
405 | );
406 |
407 | reg.add_method_mut("allocate_space", |lua, this, desired_size: Value| {
408 | let (id, rect) = this.allocate_space(LuaHelperTrait::from_lua(desired_size)?);
409 | Ok((lua.create_any_userdata(id)?, Rect::to_lua(rect, lua)?))
410 | });
411 | reg.add_method_mut(
412 | "allocate_ui",
413 | |lua, this, (desired_size, add_contents): (Value, Function)| {
414 | let ir = this.allocate_ui(Vec2::from_lua(desired_size)?, |ui| {
415 | lua.scope(|scope| {
416 | let ui = scope.create_any_userdata_ref_mut(ui)?;
417 | let result: Result = add_contents.call(ui);
418 | result
419 | })
420 | });
421 | let r = lua.create_any_userdata(ir.response)?;
422 | let mut i = ir.inner?;
423 | i.push_front(Value::UserData(r));
424 | Ok(i)
425 | },
426 | );
427 | reg.add_method_mut(
428 | "allocate_ui_at_rect",
429 | |lua, this, (max_rect, add_contents): (Value, Function)| {
430 | let ir = this.allocate_ui_at_rect(Rect::from_lua(max_rect)?, |ui| {
431 | lua.scope(|scope| {
432 | let ui = scope.create_any_userdata_ref_mut(ui)?;
433 | let result: Result = add_contents.call(ui);
434 | result
435 | })
436 | });
437 | let r = lua.create_any_userdata(ir.response)?;
438 | let mut i = ir.inner?;
439 | i.push_front(Value::UserData(r));
440 | Ok(i)
441 | },
442 | );
443 | reg.add_method_mut(
444 | "allocate_ui_with_layout",
445 | |lua, this, (desired_size, layout, add_contents): (Value, UserDataRef, Function)| {
446 | let ir = this.allocate_ui_with_layout(Vec2::from_lua(desired_size)?, *layout,|ui| {
447 | lua.scope(|scope| {
448 | let ui = scope.create_any_userdata_ref_mut(ui)?;
449 | let result: Result = add_contents.call(ui);
450 | result
451 | })
452 | });
453 | let r = lua.create_any_userdata(ir.response)?;
454 | let mut i = ir.inner?;
455 | i.push_front(Value::UserData(r));
456 | Ok(i)
457 | },
458 | );
459 | reg.add_method("auto_id_with", |lua, this, value: Value| {
460 | lua.create_any_userdata(match value {
461 | Value::Boolean(b) => {
462 | this.auto_id_with(b)
463 | },
464 | Value::Integer(b) => this.auto_id_with(b),
465 | Value::String(b) => this.auto_id_with(b),
466 | _ => return Err(mlua::Error::external("value type cannot be hashed to get new id"))
467 | })
468 | });
469 | reg.add_method("available_height", |_, this, ()|Ok(this.available_height()));
470 | reg.add_method("available_rect_before_wrap", |lua, this, ()| Rect::to_lua(this.available_rect_before_wrap(), lua));
471 | reg.add_method("avaialble_size", |lua, this, ()| Vec2::to_lua(this.available_size(), lua));
472 | reg.add_method("avaialble_size_before_wrap", |lua, this, ()| Vec2::to_lua(this.available_size_before_wrap(), lua));
473 | reg.add_method("available_width", |_, this, ()|Ok(this.available_width()));
474 | reg.add_method_mut("button", |lua, this, value: Value| {
475 | lua.create_any_userdata(this.button(WidgetText::from_lua(value)?))
476 | });
477 | reg.add_method_mut(
478 | "centered_and_justified",
479 | |lua, this, add_contents: Function| {
480 | let ir = this.centered_and_justified(|ui| {
481 | lua.scope(|scope| {
482 | let ui = scope.create_any_userdata_ref_mut(ui)?;
483 | let result: Result = add_contents.call(ui);
484 | result
485 | })
486 | });
487 | let r = lua.create_any_userdata(ir.response)?;
488 | let mut i = ir.inner?;
489 | i.push_front(Value::UserData(r));
490 | Ok(i)
491 | },
492 | );
493 | reg.add_method_mut("checkbox", |lua, this, value: Table| {
494 | let mut b: bool = value.get("checked")?;
495 | let result = lua.create_any_userdata(this.checkbox(&mut b, WidgetText::from_lua(value.get("text")?)?));
496 | value.set("checked", b)?;
497 | result
498 | });
499 | reg.add_method_mut("child_ui", |lua, this, (max_rect, layout): (Value, UserDataRef)| {
500 | let ui = this.child_ui(LuaHelperTrait::from_lua(max_rect)?, *layout);
501 | lua.create_any_userdata(ui)
502 | });
503 | // requires impl Hash for Value smh
504 | // reg.add_method_mut("child_ui_with_id_source", |lua, this, (max_rect, layout): (Value, Value)| {
505 | // let ui = this.child_ui(LuaHelperTrait::from_lua(max_rect)?, LuaHelperTrait::from_lua(layout)?);
506 | // lua.create_any_userdata(ui)
507 | // });
508 | reg.add_method("clip_rect", |lua, this, ()| {
509 | Rect::to_lua(this.clip_rect(), lua)
510 | });
511 | reg.add_method_mut("close_menu", |_, this, ()| {
512 | this.close_menu();
513 | Ok(())
514 | });
515 | reg.add_method_mut("code", |lua, this, value: Value| {
516 | lua.create_any_userdata(this.code(RichText::from_lua(value)?))
517 | });
518 | reg.add_method_mut("code_editor", |lua, this, value: Table| {
519 | let mut b: String = value.get("text")?;
520 | let result = lua.create_any_userdata(this.code_editor(&mut b));
521 | value.set("text", b)?;
522 | result
523 | });
524 | // reg.add_method_mut(
525 | // "collapsing",
526 | // |lua, this, (heading, add_contents): (Value, Function)| {
527 | // let result = lua.create_table()?;
528 | // let ir = this.collapsing( WidgetText::from_lua(heading)?,|ui| {
529 | // lua.scope(|scope| {
530 | // let ui = scope.create_any_userdata_ref_mut(ui)?;
531 | // let _result: Result = add_contents.call(ui);
532 | // // some lifetime error...
533 | // Ok(())
534 | // })
535 | // });
536 | // result.set("header_response", lua.create_any_userdata(ir.header_response)?)?;
537 | // result.set("body_response", lua.create_any_userdata(ir.body_response)?)?;
538 | // result.set("body_returned", lua.create_any_userdata(ir.body_returned)?)?;
539 | // result.set("openness", lua.create_any_userdata(ir.openness)?)?;
540 | // Ok(Value::Table(result))
541 | // },
542 | // );
543 | reg.add_method_mut(
544 | "columns",
545 | |lua, this, (num, add_contents): (usize, Function)| {
546 | let ir = this.columns( num, |cols| {
547 | lua.scope(|scope| {
548 | let cols: Vec = cols.into_iter().map(|ui| scope.create_any_userdata_ref_mut(ui)).collect::>>()?;
549 | let result: Result = add_contents.call(cols);
550 | result
551 | })
552 | });
553 | ir
554 | },
555 | );
556 | reg.add_method(
557 | "ctx",
558 | |lua, this, ()| {
559 | lua.create_any_userdata(this.ctx().clone())
560 | },
561 | );
562 | reg.add_method(
563 | "cursor",
564 | |lua, this, ()| {
565 | Rect::to_lua(this.cursor(), lua)
566 | },
567 | );
568 | reg.add_method_mut(
569 | "data",
570 | |lua, this, add_contents: Function| {
571 | let ir = this.data( |reader| {
572 | lua.scope(|scope| {
573 | let reader = scope.create_any_userdata_ref(reader)?;
574 | let result: Result = add_contents.call(reader);
575 | result
576 | })
577 | });
578 | ir
579 | },
580 | );
581 | reg.add_method_mut(
582 | "data_mut",
583 | |lua, this, add_contents: Function| {
584 | let ir = this.data_mut( |reader| {
585 | lua.scope(|scope| {
586 | let reader = scope.create_any_userdata_ref_mut(reader)?;
587 | let result: Result = add_contents.call(reader);
588 | result
589 | })
590 | });
591 | ir
592 | },
593 | );
594 |
595 | // reg.add_method(
596 | // "debug_paint_cursor",
597 | // |_, this, ()| {
598 | // Ok(this.debug_paint_cursor())
599 | // },
600 | // );
601 | reg.add_method_mut("drag_angle", |lua, this, value: Table| {
602 | let mut b: f32 = value.get("value")?;
603 | let result = lua.create_any_userdata(this.drag_angle(&mut b));
604 | value.set("value", b)?;
605 | result
606 | });
607 |
608 | reg.add_method_mut("drag_angle_tau", |lua, this, value: Table| {
609 | let mut b: f32 = value.get("value")?;
610 | let result = lua.create_any_userdata(this.drag_angle_tau(&mut b));
611 | value.set("value", b)?;
612 | result
613 | });
614 | reg.add_method_mut(
615 | "end_row",
616 | |_, this, ()| {
617 | Ok(this.end_row())
618 | },
619 | );
620 |
621 | reg.add_method_mut(
622 | "expand_to_include_rect",
623 | |_, this, rect: Value| {
624 | Ok(this.expand_to_include_rect(Rect::from_lua(rect)?))
625 | },
626 | );
627 |
628 | reg.add_method_mut(
629 | "expand_to_include_x",
630 | |_, this, x: f32| {
631 | Ok(this.expand_to_include_x(x))
632 | },
633 | );
634 | reg.add_method_mut(
635 | "expand_to_include_y",
636 | |_, this, x: f32| {
637 | Ok(this.expand_to_include_y(x))
638 | },
639 | );
640 |
641 | reg.add_method_mut(
642 | "fonts",
643 | |lua, this, add_contents: Function| {
644 | let ir = this.fonts( |reader| {
645 | lua.scope(|scope| {
646 | let reader = scope.create_any_userdata_ref(reader)?;
647 | let result: Result = add_contents.call(reader);
648 | result
649 | })
650 | });
651 | ir
652 | },
653 | );
654 |
655 | reg.add_method_mut(
656 | "group",
657 | |lua, this, add_contents: Function| {
658 | let ir = this.group(|ui| {
659 | lua.scope(|scope| {
660 | let ui = scope.create_any_userdata_ref_mut(ui)?;
661 | let result: Result = add_contents.call(ui);
662 | result
663 | })
664 | });
665 | let r = lua.create_any_userdata(ir.response)?;
666 | let mut i = ir.inner?;
667 | i.push_front(Value::UserData(r));
668 | Ok(i)
669 | },
670 | );
671 | reg.add_method_mut("heading", |lua, this, value: Value| {
672 | lua.create_any_userdata(this.heading(RichText::from_lua(value)?))
673 | });
674 | reg.add_method_mut(
675 | "horizontal",
676 | |lua, this, add_contents: Function| {
677 | let ir = this.horizontal(|ui| {
678 | lua.scope(|scope| {
679 | let ui = scope.create_any_userdata_ref_mut(ui)?;
680 | let result: Result = add_contents.call(ui);
681 | result
682 | })
683 | });
684 | let r = lua.create_any_userdata(ir.response)?;
685 | let mut i = ir.inner?;
686 | i.push_front(Value::UserData(r));
687 | Ok(i)
688 | },
689 | );
690 |
691 | reg.add_method_mut(
692 | "horizontal_centered",
693 | |lua, this, add_contents: Function| {
694 | let ir = this.horizontal_centered(|ui| {
695 | lua.scope(|scope| {
696 | let ui = scope.create_any_userdata_ref_mut(ui)?;
697 | let result: Result = add_contents.call(ui);
698 | result
699 | })
700 | });
701 | let r = lua.create_any_userdata(ir.response)?;
702 | let mut i = ir.inner?;
703 | i.push_front(Value::UserData(r));
704 | Ok(i)
705 | },
706 | );
707 |
708 | reg.add_method_mut(
709 | "horizontal_top",
710 | |lua, this, add_contents: Function| {
711 | let ir = this.horizontal_top(|ui| {
712 | lua.scope(|scope| {
713 | let ui = scope.create_any_userdata_ref_mut(ui)?;
714 | let result: Result = add_contents.call(ui);
715 | result
716 | })
717 | });
718 | let r = lua.create_any_userdata(ir.response)?;
719 | let mut i = ir.inner?;
720 | i.push_front(Value::UserData(r));
721 | Ok(i)
722 | },
723 | );
724 |
725 | reg.add_method_mut(
726 | "horizontal_wrapped",
727 | |lua, this, add_contents: Function| {
728 | let ir = this.horizontal_wrapped(|ui| {
729 | lua.scope(|scope| {
730 | let ui = scope.create_any_userdata_ref_mut(ui)?;
731 | let result: Result = add_contents.call(ui);
732 | result
733 | })
734 | });
735 | let r = lua.create_any_userdata(ir.response)?;
736 | let mut i = ir.inner?;
737 | i.push_front(Value::UserData(r));
738 | Ok(i)
739 | },
740 | );
741 |
742 | reg.add_method_mut("hyperlink", |lua, this, value: String| {
743 | lua.create_any_userdata(this.hyperlink(value))
744 | });
745 |
746 | reg.add_method_mut("hyperlink_to", |lua, this, (label, url): (Value, String)| {
747 | lua.create_any_userdata(this.hyperlink_to(WidgetText::from_lua(label)?, url ))
748 | });
749 |
750 | reg.add_method("id", |lua, this, ()| lua.create_any_userdata(this.id()));
751 |
752 | reg.add_method_mut("image", |lua, this, (texture, size): (UserDataRef, Value)| {
753 | lua.create_any_userdata(this.image(SizedTexture::new(texture.id(), Vec2::from_lua(size)?) ))
754 | });
755 | reg.add_method_mut(
756 | "indent",
757 | |lua, this, (hashable, add_contents): (Value, Function)| {
758 | let ir = this.indent( LuaHashable::from_lua(hashable)?, |ui| {
759 | lua.scope(|scope| {
760 | let ui = scope.create_any_userdata_ref_mut(ui)?;
761 | let result: Result = add_contents.call(ui);
762 | result
763 | })
764 | });
765 | let r = lua.create_any_userdata(ir.response)?;
766 | let mut i = ir.inner?;
767 | i.push_front(Value::UserData(r));
768 | Ok(i)
769 | },
770 | );
771 |
772 | reg.add_method_mut(
773 | "input",
774 | |lua, this, add_contents: Function| {
775 | let ir = this.input( |reader| {
776 | lua.scope(|scope| {
777 | let reader = scope.create_any_userdata_ref(reader)?;
778 | let result: Result = add_contents.call(reader);
779 | result
780 | })
781 | });
782 | ir
783 | },
784 | );
785 | reg.add_method_mut(
786 | "input_mut",
787 | |lua, this, add_contents: Function| {
788 | let ir = this.input_mut( |reader| {
789 | lua.scope(|scope| {
790 | let reader = scope.create_any_userdata_ref_mut(reader)?;
791 | let result: Result = add_contents.call(reader);
792 | result
793 | })
794 | });
795 | ir
796 | },
797 | );
798 |
799 | reg.add_method("interact", |lua, this, (rect, id, sense): (Value, UserDataRef, Value)| {
800 | lua.create_any_userdata( this.interact(Rect::from_lua(rect)?, *id, Sense::from_lua(sense)?))
801 | });
802 |
803 | reg.add_method("interact_with_hovered", |lua, this, (rect, hovered, id, sense): (Value, bool, UserDataRef, Value)| {
804 | lua.create_any_userdata( this.interact_with_hovered(Rect::from_lua(rect)?, hovered, *id, Sense::from_lua(sense)?))
805 | });
806 | reg.add_method("is_enabled", |_, this, ()| Ok(this.is_enabled()));
807 | reg.add_method_mut("is_rect_visible", |_, this, clip_rect: Value| {
808 | Ok(this.is_rect_visible(Rect::from_lua(clip_rect)?))
809 | });
810 | reg.add_method("is_visible", |_, this, ()| Ok(this.is_visible()));
811 | reg.add_method_mut("label", |lua, this, value: Value| {
812 | lua.create_any_userdata(this.label(WidgetText::from_lua(value)?))
813 | });
814 | reg.add_method("layer_id", |lua, this, () | {
815 | lua.create_any_userdata(this.layer_id())
816 | });
817 |
818 | reg.add_method("layout", |lua, this, () | {
819 | lua.create_any_userdata(this.layout().clone())
820 | });
821 |
822 | reg.add_method_mut("link", |lua, this, value: Value| {
823 | lua.create_any_userdata(this.link(WidgetText::from_lua(value)?))
824 | });
825 |
826 | reg.add_method_mut("make_persistent_id", |lua, this, value: Value| {
827 | lua.create_any_userdata(this.make_persistent_id(LuaHashable::from_lua(value)?))
828 | });
829 |
830 | reg.add_method("max_rect", |lua, this, ()| {
831 | Rect::to_lua(this.max_rect(), lua)
832 | });
833 |
834 | reg.add_method(
835 | "memory",
836 | |lua, this, add_contents: Function| {
837 | let ir = this.memory( |reader| {
838 | lua.scope(|scope| {
839 | let reader = scope.create_any_userdata_ref(reader)?;
840 | let result: Result = add_contents.call(reader);
841 | result
842 | })
843 | });
844 | ir
845 | },
846 | );
847 | reg.add_method_mut(
848 | "memory_mut",
849 | |lua, this, add_contents: Function| {
850 | let ir = this.memory_mut( |reader| {
851 | lua.scope(|scope| {
852 | let reader = scope.create_any_userdata_ref_mut(reader)?;
853 | let result: Result = add_contents.call(reader);
854 | result
855 | })
856 | });
857 | ir
858 | },
859 | );
860 | reg.add_method_mut(
861 | "menu_button",
862 | |lua, this, (title, add_contents): (Value, Function)| {
863 | let ir = this.menu_button(WidgetText::from_lua(title)?, |ui| {
864 | lua.scope(|scope| {
865 | let ui = scope.create_any_userdata_ref_mut(ui)?;
866 | let result: Result = add_contents.call(ui);
867 | result
868 | })
869 | });
870 |
871 | let mut result = MultiValue::new();
872 | let response = lua.create_any_userdata(ir.response)?;
873 | result.push_front(Value::UserData(response));
874 | if let Some(inner) = ir.inner {
875 | let inner = inner?;
876 | for v in inner {
877 | result.push_front(v);
878 | }
879 | }
880 | Ok(result)
881 | },
882 | );
883 | reg.add_method_mut("selectable_label", |lua, ui, (selected, text): (bool, Value)| {
884 | lua.create_any_userdata(ui.selectable_label(selected, WidgetText::from_lua(text)?))
885 | });
886 | reg.add_method_mut(
887 | "set_row_height",
888 | |_, this, height: f32| {
889 | Ok(this.set_row_height(height))
890 | },
891 | );
892 | reg.add_method_mut(
893 | "output",
894 | |lua, this, add_contents: Function| {
895 | let ir = this.output( |reader| {
896 | lua.scope(|scope| {
897 | let reader = scope.create_any_userdata_ref(reader)?;
898 | let result: Result = add_contents.call(reader);
899 | result
900 | })
901 | });
902 | ir
903 | },
904 | );
905 | reg.add_method_mut(
906 | "output_mut",
907 | |lua, this, add_contents: Function| {
908 | let ir = this.output_mut( |reader| {
909 | lua.scope(|scope| {
910 | let reader = scope.create_any_userdata_ref_mut(reader)?;
911 | let result: Result = add_contents.call(reader);
912 | result
913 | })
914 | });
915 | ir
916 | },
917 | );
918 | reg.add_method(
919 | "next_widget_position",
920 | |lua, this, ()| {
921 | Pos2::to_lua(this.next_widget_position(), lua)
922 | },
923 | );
924 | reg.add_method(
925 | "painter",
926 | |lua, this, ()| {
927 | lua.create_any_userdata(this.painter().clone())
928 | },
929 | );
930 | reg.add_method_mut("text_edit_multiline", |lua, this, value: Table| {
931 | let mut b: String = value.get("text")?;
932 | let result = lua.create_any_userdata(this.text_edit_multiline(&mut b));
933 | value.set("text", b)?;
934 | result
935 | });
936 | reg.add_method_mut("text_edit_singleline", |lua, this, value: Table| {
937 | let mut b: String = value.get("text")?;
938 | let result = lua.create_any_userdata(this.text_edit_singleline(&mut b));
939 | value.set("text", b)?;
940 | result
941 | });
942 | reg.add_method_mut("set_enabled", |_, this, enabled: bool| {
943 | this.set_enabled(enabled);
944 | Ok(())
945 | });
946 |
947 | reg.add_method("wrap_text", |_, this, ()| Ok(this.wrap_text()));
948 |
949 | reg.add_method_mut("set_clip_rect", |_, this, clip_rect: Value| {
950 | this.set_clip_rect(Rect::from_lua(clip_rect)?);
951 | Ok(())
952 | });
953 | })?;
954 |
955 | Ok(())
956 | }
957 | impl LuaHelperTrait for Sense {
958 | fn from_lua(value: Value) -> Result {
959 | match value {
960 | Value::Integer(i) => {
961 | let i = i as u8;
962 | let click = 0 != (i & 1);
963 | let drag = 0 != (i & (1 << 1));
964 | let focusable = 0 != (i & (1 << 2));
965 | Ok(Self {
966 | click,
967 | drag,
968 | focusable,
969 | })
970 | }
971 | _ => Err(mlua::Error::FromLuaConversionError {
972 | from: "luavalue",
973 | to: "pointerbutton",
974 | message: None,
975 | }),
976 | }
977 | }
978 |
979 | fn to_lua(value: Self, _lua: &Lua) -> Result {
980 | let mut u = 0u8;
981 | if value.click {
982 | u &= 1;
983 | }
984 | if value.drag {
985 | u &= 1 << 1;
986 | }
987 | if value.focusable {
988 | u &= 1 << 2;
989 | }
990 | Ok(Value::Integer(u as _))
991 | }
992 |
993 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
994 | let sense = lua.create_table()?;
995 | sense.set("hover", Sense::to_lua(Sense::hover(), lua)?)?;
996 | sense.set(
997 | "focusable_noninteractive",
998 | Sense::to_lua(Sense::focusable_noninteractive(), lua)?,
999 | )?;
1000 | sense.set("click", Sense::to_lua(Sense::click(), lua)?)?;
1001 | sense.set("drag", Sense::to_lua(Sense::drag(), lua)?)?;
1002 | sense.set(
1003 | "union",
1004 | lua.create_function(|lua, (first, second): (Value, Value)| {
1005 | let first = Sense::from_lua(first)?;
1006 | let second = Sense::from_lua(second)?;
1007 | Sense::to_lua(first.union(second), lua)
1008 | })?,
1009 | )?;
1010 | sense.set(
1011 | "union",
1012 | lua.create_function(|_, value: Value| Ok(Sense::from_lua(value)?.interactive()))?,
1013 | )?;
1014 |
1015 | egui_table.set("sense", sense)?;
1016 | Ok(())
1017 | }
1018 | }
1019 | impl LuaHelperTrait for Margin {
1020 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
1021 | let margin = lua.create_table()?;
1022 | margin.set(
1023 | "same",
1024 | lua.create_function(|lua, margin: f32| Margin::to_lua(Margin::same(margin), lua))?,
1025 | )?;
1026 | margin.set(
1027 | "symmetric",
1028 | lua.create_function(|lua, (x, y): (f32, f32)| {
1029 | Margin::to_lua(Margin::symmetric(x, y), lua)
1030 | })?,
1031 | )?;
1032 | margin.set(
1033 | "sum",
1034 | lua.create_function(|lua, value: Value| {
1035 | Vec2::to_lua(Margin::from_lua(value)?.sum(), lua)
1036 | })?,
1037 | )?;
1038 | margin.set(
1039 | "left_top",
1040 | lua.create_function(|lua, value: Value| {
1041 | Vec2::to_lua(Margin::from_lua(value)?.left_top(), lua)
1042 | })?,
1043 | )?;
1044 | margin.set(
1045 | "right_bottom",
1046 | lua.create_function(|lua, value: Value| {
1047 | Vec2::to_lua(Margin::from_lua(value)?.right_bottom(), lua)
1048 | })?,
1049 | )?;
1050 | margin.set(
1051 | "is_same",
1052 | lua.create_function(|_, value: Value| Ok(Margin::from_lua(value)?.is_same()))?,
1053 | )?;
1054 |
1055 | egui_table.set("rounding", margin)?;
1056 | Ok(())
1057 | }
1058 | fn from_lua(value: Value) -> Result {
1059 | Ok(match value {
1060 | Value::Table(t) => {
1061 | let left: f32 = t.get("left")?;
1062 | let right: f32 = t.get("right")?;
1063 | let top: f32 = t.get("top")?;
1064 | let bottom: f32 = t.get("bottom")?;
1065 | Self {
1066 | left,
1067 | right,
1068 | top,
1069 | bottom,
1070 | }
1071 | }
1072 | _ => {
1073 | return Err(mlua::Error::FromLuaConversionError {
1074 | from: "luavalue",
1075 | to: "pointerbutton",
1076 | message: None,
1077 | })
1078 | }
1079 | })
1080 | }
1081 |
1082 | fn to_lua(value: Self, lua: &Lua) -> Result {
1083 | let margin = lua.create_table()?;
1084 | margin.set("left", value.left)?;
1085 | margin.set("right", value.right)?;
1086 | margin.set("top", value.top)?;
1087 | margin.set("bottom", value.bottom)?;
1088 | Ok(Value::Table(margin))
1089 | }
1090 | }
1091 | impl LuaHelperTrait for TextStyle {
1092 | fn from_lua(value: Value) -> Result {
1093 | match value {
1094 | Value::Integer(i) => Ok(match i {
1095 | 0 => Self::Small,
1096 | 1 => Self::Body,
1097 | 2 => Self::Monospace,
1098 | 3 => Self::Button,
1099 | 4 => Self::Heading,
1100 | _ => {
1101 | return Err(mlua::Error::RuntimeError(format!(
1102 | "the value {i} doesn't match any TextStyle enum variants"
1103 | )))
1104 | }
1105 | }),
1106 | Value::String(s) => Ok(Self::Name(s.to_str().unwrap_or_default().into())),
1107 | _ => {
1108 | return Err(mlua::Error::RuntimeError(format!(
1109 | "invalid type to convert to TextStyle enum variants"
1110 | )))
1111 | }
1112 | }
1113 | }
1114 |
1115 | fn to_lua(value: Self, lua: &Lua) -> Result {
1116 | Ok(match value {
1117 | TextStyle::Small => Value::Integer(0),
1118 | TextStyle::Body => Value::Integer(1),
1119 | TextStyle::Monospace => Value::Integer(2),
1120 | TextStyle::Button => Value::Integer(3),
1121 | TextStyle::Heading => Value::Integer(4),
1122 | TextStyle::Name(n) => Value::String(lua.create_string(n.as_bytes())?),
1123 | })
1124 | }
1125 |
1126 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
1127 | let text_style = lua.create_table()?;
1128 | text_style.set("small", Value::Integer(0))?;
1129 | text_style.set("body", Value::Integer(1))?;
1130 | text_style.set("monospace", Value::Integer(2))?;
1131 | text_style.set("button", Value::Integer(3))?;
1132 | text_style.set("heading", Value::Integer(4))?;
1133 | text_style.set_readonly(true);
1134 | egui_table.set("text_style", text_style)?;
1135 | Ok(())
1136 | }
1137 | }
1138 | impl LuaHelperTrait for Rounding {
1139 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
1140 | let rounding = lua.create_table()?;
1141 | rounding.set(
1142 | "same",
1143 | lua.create_function(|lua, radius: f32| Rounding::to_lua(Rounding::same(radius), lua))?,
1144 | )?;
1145 | rounding.set(
1146 | "none",
1147 | lua.create_function(|lua, ()| Rounding::to_lua(Rounding::ZERO, lua))?,
1148 | )?;
1149 | rounding.set(
1150 | "is_same",
1151 | lua.create_function(|_, rounding: Value| -> mlua::Result {
1152 | Ok(Rounding::from_lua(rounding)?.is_same())
1153 | })?,
1154 | )?;
1155 | rounding.set(
1156 | "atleast",
1157 | lua.create_function(|lua, (value, min): (Value, f32)| {
1158 | Rounding::to_lua(Rounding::from_lua(value)?.at_least(min), lua)
1159 | })?,
1160 | )?;
1161 | rounding.set(
1162 | "atmost",
1163 | lua.create_function(|lua, (value, max): (Value, f32)| {
1164 | Rounding::to_lua(Rounding::from_lua(value)?.at_most(max), lua)
1165 | })?,
1166 | )?;
1167 | egui_table.set("rounding", rounding)?;
1168 | Ok(())
1169 | }
1170 | fn from_lua(value: Value) -> Result {
1171 | Ok(match value {
1172 | Value::Table(t) => {
1173 | let nw: f32 = t.get("nw")?;
1174 | let ne: f32 = t.get("ne")?;
1175 | let sw: f32 = t.get("sw")?;
1176 | let se: f32 = t.get("se")?;
1177 | Self { nw, ne, sw, se }
1178 | }
1179 | _ => {
1180 | return Err(mlua::Error::FromLuaConversionError {
1181 | from: "luavalue",
1182 | to: "pointerbutton",
1183 | message: None,
1184 | })
1185 | }
1186 | })
1187 | }
1188 |
1189 | fn to_lua(value: Self, lua: &Lua) -> Result {
1190 | let rounding = lua.create_table()?;
1191 | rounding.set("nw", value.nw)?;
1192 | rounding.set("ne", value.ne)?;
1193 | rounding.set("sw", value.sw)?;
1194 | rounding.set("se", value.se)?;
1195 | Ok(Value::Table(rounding))
1196 | }
1197 | }
1198 | impl LuaHelperTrait for Rect {
1199 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
1200 | let rect = lua.create_table()?;
1201 | rect.set("everything", Rect::to_lua(Rect::EVERYTHING, lua)?)?;
1202 | rect.set("nothing", Rect::to_lua(Rect::NOTHING, lua)?)?;
1203 | rect.set("nan", Rect::to_lua(Rect::NAN, lua)?)?;
1204 | rect.set(
1205 | "from_min_max",
1206 | lua.create_function(|lua, (min, max): (Value, Value)| {
1207 | let min = Pos2::from_lua(min)?;
1208 | let max = Pos2::from_lua(max)?;
1209 | Rect::to_lua(Rect { min, max }, lua)
1210 | })?,
1211 | )?;
1212 | egui_table.set("stroke", rect)?;
1213 | Ok(())
1214 | }
1215 | fn from_lua(value: Value) -> Result {
1216 | Ok(match value {
1217 | Value::Table(t) => {
1218 | let min = Pos2::from_lua(t.get("min")?)?;
1219 | let max = Pos2::from_lua(t.get("max")?)?;
1220 | Rect { min, max }
1221 | }
1222 | _ => {
1223 | return Err(mlua::Error::FromLuaConversionError {
1224 | from: "luavalue",
1225 | to: "pointerbutton",
1226 | message: None,
1227 | })
1228 | }
1229 | })
1230 | }
1231 |
1232 | fn to_lua(value: Self, lua: &Lua) -> Result {
1233 | let rect = lua.create_table()?;
1234 | rect.set("min", Pos2::to_lua(value.min, lua)?)?;
1235 | rect.set("max", Pos2::to_lua(value.max, lua)?)?;
1236 | Ok(Value::Table(rect))
1237 | }
1238 | }
1239 | impl LuaHelperTrait for Color32 {
1240 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
1241 | let color32 = lua.create_table()?;
1242 | // multiply first align by 4 to push its bits to left.
1243 | // second align will fit in the 2 bits
1244 | color32.set("transparent", Color32::to_lua(Color32::TRANSPARENT, lua)?)?;
1245 | color32.set("black", Color32::to_lua(Color32::BLACK, lua)?)?;
1246 | color32.set("dark_gray", Color32::to_lua(Color32::DARK_GRAY, lua)?)?;
1247 | color32.set("gray", Color32::to_lua(Color32::GRAY, lua)?)?;
1248 | color32.set("light_gray", Color32::to_lua(Color32::LIGHT_GRAY, lua)?)?;
1249 | color32.set("white", Color32::to_lua(Color32::WHITE, lua)?)?;
1250 | color32.set("brown", Color32::to_lua(Color32::BROWN, lua)?)?;
1251 | color32.set("dark_red", Color32::to_lua(Color32::DARK_RED, lua)?)?;
1252 | color32.set("red", Color32::to_lua(Color32::RED, lua)?)?;
1253 | color32.set("light_red", Color32::to_lua(Color32::LIGHT_RED, lua)?)?;
1254 | color32.set("yellow", Color32::to_lua(Color32::YELLOW, lua)?)?;
1255 | color32.set("light_yellow", Color32::to_lua(Color32::LIGHT_YELLOW, lua)?)?;
1256 | color32.set("khaki", Color32::to_lua(Color32::KHAKI, lua)?)?;
1257 | color32.set("dark_green", Color32::to_lua(Color32::DARK_GREEN, lua)?)?;
1258 | color32.set("green", Color32::to_lua(Color32::GREEN, lua)?)?;
1259 | color32.set("light_green", Color32::to_lua(Color32::LIGHT_GREEN, lua)?)?;
1260 | color32.set("dark_blue", Color32::to_lua(Color32::DARK_BLUE, lua)?)?;
1261 | color32.set("blue", Color32::to_lua(Color32::BLUE, lua)?)?;
1262 | color32.set("light_blue", Color32::to_lua(Color32::LIGHT_BLUE, lua)?)?;
1263 | color32.set("gold", Color32::to_lua(Color32::GOLD, lua)?)?;
1264 | color32.set("debug_color", Color32::to_lua(Color32::DEBUG_COLOR, lua)?)?;
1265 | color32.set(
1266 | "placeholder_color",
1267 | Color32::to_lua(Color32::PLACEHOLDER, lua)?,
1268 | )?;
1269 |
1270 | color32.set(
1271 | "from_rgba_premultiplied",
1272 | lua.create_function(|lua, (r, g, b, a): (u8, u8, u8, u8)| {
1273 | Color32::to_lua(Color32::from_rgba_premultiplied(r, g, b, a), lua)
1274 | })?,
1275 | )?;
1276 | egui_table.set("color32", color32)?;
1277 | Ok(())
1278 | }
1279 |
1280 | fn from_lua(value: Value) -> Result {
1281 | Ok(match value {
1282 | Value::Integer(i) => {
1283 | let c = i.to_le_bytes();
1284 |
1285 | Color32::from_rgba_premultiplied(c[0], c[1], c[2], c[3])
1286 | }
1287 | _ => {
1288 | return Err(mlua::Error::FromLuaConversionError {
1289 | from: "luavalue",
1290 | to: "pointerbutton",
1291 | message: None,
1292 | })
1293 | }
1294 | })
1295 | }
1296 |
1297 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1298 | Ok(Value::Integer({
1299 | let a = value.to_array();
1300 | i32::from_le_bytes(a)
1301 | }))
1302 | }
1303 | }
1304 | impl LuaHelperTrait for Pos2 {
1305 | fn from_lua(value: Value) -> Result {
1306 | match value {
1307 | Value::Vector(v) => Ok(Self { x: v.x(), y: v.y() }),
1308 | _ => Err(mlua::Error::FromLuaConversionError {
1309 | from: "luavalue",
1310 | to: "pos2",
1311 | message: None,
1312 | }),
1313 | }
1314 | }
1315 |
1316 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1317 | Ok(Value::Vector(Vector::new(value.x, value.y, 0.0, 0.0)))
1318 | }
1319 |
1320 | fn add_to_lua(_lua: &Lua, _egui_table: &Table) -> Result<()> {
1321 | Ok(())
1322 | }
1323 | }
1324 | impl LuaHelperTrait for Stroke {
1325 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
1326 | let stroke = lua.create_table()?;
1327 | stroke.set("none", Stroke::to_lua(Stroke::NONE, lua)?)?;
1328 | stroke.set(
1329 | "new",
1330 | lua.create_function(|lua, (width, color): (f32, Value)| {
1331 | let color = Color32::from_lua(color)?;
1332 | Stroke::to_lua(Stroke { width, color }, lua)
1333 | })?,
1334 | )?;
1335 | egui_table.set("stroke", stroke)?;
1336 | Ok(())
1337 | }
1338 | fn from_lua(value: Value) -> Result {
1339 | match value {
1340 | Value::Vector(v) => {
1341 | let color = v.y().to_le_bytes();
1342 | Ok(Self {
1343 | width: v.x(),
1344 | color: Color32::from_rgba_premultiplied(color[0], color[1], color[2], color[3]),
1345 | })
1346 | }
1347 | _ => Err(mlua::Error::FromLuaConversionError {
1348 | from: "luavalue",
1349 | to: "pos2",
1350 | message: None,
1351 | }),
1352 | }
1353 | }
1354 |
1355 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1356 | let width = value.width;
1357 | let color = value.color.to_array();
1358 | let color = f32::from_le_bytes(color);
1359 | Ok(Value::Vector(Vector::new(width, color, 0.0, 0.0)))
1360 | }
1361 | }
1362 | impl LuaHelperTrait for Vec2 {
1363 | fn from_lua(value: Value) -> Result {
1364 | match value {
1365 | Value::Vector(v) => Ok(Self { x: v.x(), y: v.y() }),
1366 | _ => Err(mlua::Error::FromLuaConversionError {
1367 | from: "luavalue",
1368 | to: "pos2",
1369 | message: None,
1370 | }),
1371 | }
1372 | }
1373 |
1374 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1375 | Ok(Value::Vector(Vector::new(value.x, value.y, 0.0, 0.0)))
1376 | }
1377 |
1378 | fn add_to_lua(_lua: &Lua, _egui_table: &Table) -> Result<()> {
1379 | Ok(())
1380 | }
1381 | }
1382 | impl LuaHelperTrait for Align2 {
1383 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> mlua::Result<()> {
1384 | let align = lua.create_table()?;
1385 | // multiply first align by 4 to push its bits to left.
1386 | // second align will fit in the 2 bits
1387 | align.set("left_bottom", Value::Integer(2))?;
1388 | align.set("left_center", Value::Integer(1))?;
1389 | align.set("left_top", Value::Integer(0))?;
1390 | align.set("center_bottom", Value::Integer(6))?;
1391 | align.set("center_center", Value::Integer(5))?;
1392 | align.set("center_top", Value::Integer(4))?;
1393 | align.set("right_bottom", Value::Integer(10))?;
1394 | align.set("right_center", Value::Integer(9))?;
1395 | align.set("right_top", Value::Integer(8))?;
1396 | // align.set("center", Value::Integer(1))?;
1397 | // align.set("max", Value::Integer(2))?;
1398 | egui_table.set("align2", align)?;
1399 | Ok(())
1400 | }
1401 | fn from_lua(value: Value) -> Result {
1402 | Ok(match value {
1403 | Value::Integer(i) => match i {
1404 | 0 => Align2::LEFT_TOP,
1405 | 1 => Align2::LEFT_CENTER,
1406 | 2 => Align2::LEFT_BOTTOM,
1407 | 4 => Align2::CENTER_TOP,
1408 | 5 => Align2::CENTER_CENTER,
1409 | 6 => Align2::CENTER_BOTTOM,
1410 | 8 => Align2::RIGHT_TOP,
1411 | 9 => Align2::RIGHT_CENTER,
1412 | 10 => Align2::RIGHT_BOTTOM,
1413 | _ => {
1414 | return Err(mlua::Error::FromLuaConversionError {
1415 | from: "luavalue",
1416 | to: "pointerbutton",
1417 | message: Some("integer value out of range".to_string()),
1418 | })
1419 | }
1420 | },
1421 | _ => {
1422 | return Err(mlua::Error::FromLuaConversionError {
1423 | from: "luavalue",
1424 | to: "pointerbutton",
1425 | message: None,
1426 | })
1427 | }
1428 | })
1429 | }
1430 |
1431 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1432 | Ok(Value::Integer(match value {
1433 | Align2::LEFT_TOP => 0,
1434 | Align2::LEFT_CENTER => 1,
1435 | Align2::LEFT_BOTTOM => 2,
1436 | Align2::CENTER_TOP => 4,
1437 | Align2::CENTER_CENTER => 5,
1438 | Align2::CENTER_BOTTOM => 6,
1439 | Align2::RIGHT_TOP => 8,
1440 | Align2::RIGHT_CENTER => 9,
1441 | Align2::RIGHT_BOTTOM => 10,
1442 | }))
1443 | }
1444 | }
1445 |
1446 | impl LuaHelperTrait for Align {
1447 | fn from_lua(value: Value) -> Result {
1448 | Ok(match value {
1449 | Value::Integer(i) => match i {
1450 | 0 => Align::Min,
1451 | 1 => Align::Center,
1452 | 2 => Align::Max,
1453 | _ => {
1454 | return Err(mlua::Error::FromLuaConversionError {
1455 | from: "luavalue",
1456 | to: "pointerbutton",
1457 | message: Some("integer value out of range".to_string()),
1458 | })
1459 | }
1460 | },
1461 | _ => {
1462 | return Err(mlua::Error::FromLuaConversionError {
1463 | from: "luavalue",
1464 | to: "pointerbutton",
1465 | message: None,
1466 | })
1467 | }
1468 | })
1469 | }
1470 |
1471 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1472 | Ok(Value::Integer(match value {
1473 | Align::Min => 0,
1474 | Align::Center => 1,
1475 | Align::Max => 2,
1476 | }))
1477 | }
1478 |
1479 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
1480 | let align = lua.create_table()?;
1481 | align.set("min", Value::Integer(0))?;
1482 | align.set("center", Value::Integer(1))?;
1483 | align.set("max", Value::Integer(2))?;
1484 | egui_table.set("align", align)?;
1485 | Ok(())
1486 | }
1487 | }
1488 | impl LuaHelperTrait for PointerButton {
1489 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
1490 | let pointer_button = lua.create_table()?;
1491 | pointer_button.set("primary", Value::Integer(0))?;
1492 | pointer_button.set("secondary", Value::Integer(1))?;
1493 | pointer_button.set("middle", Value::Integer(2))?;
1494 | pointer_button.set("extra1", Value::Integer(3))?;
1495 | pointer_button.set("extra2", Value::Integer(4))?;
1496 | egui_table.set("pointer_button", pointer_button)?;
1497 | Ok(())
1498 | }
1499 | fn from_lua(value: Value) -> Result {
1500 | Ok(match value {
1501 | Value::Integer(i) => match i {
1502 | 0 => PointerButton::Primary,
1503 | 1 => PointerButton::Secondary,
1504 | 2 => PointerButton::Middle,
1505 | 3 => PointerButton::Extra1,
1506 | 4 => PointerButton::Extra2,
1507 | _ => {
1508 | return Err(mlua::Error::FromLuaConversionError {
1509 | from: "luavalue",
1510 | to: "pointerbutton",
1511 | message: Some("integer value out of range".to_string()),
1512 | })
1513 | }
1514 | },
1515 | _ => {
1516 | return Err(mlua::Error::FromLuaConversionError {
1517 | from: "luavalue",
1518 | to: "pointerbutton",
1519 | message: None,
1520 | })
1521 | }
1522 | })
1523 | }
1524 |
1525 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1526 | Ok(Value::Integer(match value {
1527 | PointerButton::Primary => 0,
1528 | PointerButton::Secondary => 1,
1529 | PointerButton::Middle => 2,
1530 | PointerButton::Extra1 => 3,
1531 | PointerButton::Extra2 => 4,
1532 | }))
1533 | }
1534 | }
1535 |
1536 | impl LuaHelperTrait for Direction {
1537 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
1538 | let direction = lua.create_table()?;
1539 | direction.set("left_to_right", Value::Integer(0))?;
1540 | direction.set("right_to_left", Value::Integer(1))?;
1541 | direction.set("top_down", Value::Integer(2))?;
1542 | direction.set("bottom_up", Value::Integer(3))?;
1543 | egui_table.set("pointer_button", direction)?;
1544 | Ok(())
1545 | }
1546 | fn from_lua(value: Value) -> Result {
1547 | Ok(match value {
1548 | Value::Integer(i) => match i {
1549 | 0 => Direction::LeftToRight,
1550 | 1 => Direction::RightToLeft,
1551 | 2 => Direction::TopDown,
1552 | 3 => Direction::BottomUp,
1553 | _ => {
1554 | return Err(mlua::Error::FromLuaConversionError {
1555 | from: "luavalue",
1556 | to: "pointerbutton",
1557 | message: Some("integer value out of range".to_string()),
1558 | })
1559 | }
1560 | },
1561 | _ => {
1562 | return Err(mlua::Error::FromLuaConversionError {
1563 | from: "luavalue",
1564 | to: "pointerbutton",
1565 | message: None,
1566 | })
1567 | }
1568 | })
1569 | }
1570 |
1571 | fn to_lua(value: Self, _lua: &Lua) -> Result {
1572 | Ok(Value::Integer(match value {
1573 | Self::LeftToRight => 0,
1574 | Self::RightToLeft => 1,
1575 | Self::TopDown => 2,
1576 | Self::BottomUp => 3,
1577 | }))
1578 | }
1579 | }
1580 | impl LuaHelperTrait for WidgetText {
1581 | fn from_lua(value: Value) -> Result {
1582 | match value {
1583 | Value::String(s) => Ok(s.to_str().unwrap_or_default().into()),
1584 | Value::UserData(u) => {
1585 | if let Ok(u) = u.borrow::() {
1586 | Ok(u.clone())
1587 | } else if let Ok(u) = u.borrow::() {
1588 | Ok(u.clone().into())
1589 | } else {
1590 | return Err(mlua::Error::FromLuaConversionError {
1591 | from: "userdata",
1592 | to: "widgettext",
1593 | message: None,
1594 | });
1595 | }
1596 | }
1597 | _ => Err(mlua::Error::FromLuaConversionError {
1598 | from: "luavalue",
1599 | to: "widgettext",
1600 | message: None,
1601 | }),
1602 | }
1603 | }
1604 |
1605 | fn to_lua(value: Self, lua: &Lua) -> Result {
1606 | Ok(mlua::Value::UserData(lua.create_any_userdata(value)?))
1607 | }
1608 |
1609 | fn add_to_lua(lua: &Lua, _egui_table: &Table) -> Result<()> {
1610 | lua.register_userdata_type(|_reg: &mut UserDataRegistry| {})?;
1611 | Ok(())
1612 | }
1613 | }
1614 |
1615 | impl LuaHelperTrait for RichText {
1616 | fn from_lua(value: Value) -> Result {
1617 | match value {
1618 | Value::String(s) => Ok(s.to_str().unwrap_or_default().into()),
1619 | Value::UserData(u) => {
1620 | if let Ok(u) = u.borrow::() {
1621 | Ok(u.clone())
1622 | } else {
1623 | Err(mlua::Error::FromLuaConversionError {
1624 | from: "userdata",
1625 | to: "widgettext",
1626 | message: None,
1627 | })
1628 | }
1629 | }
1630 | Value::Table(_t) => {
1631 | Err(mlua::Error::FromLuaConversionError {
1632 | from: "table",
1633 | to: "widgettext",
1634 | message: None,
1635 | })
1636 | // if let Ok(text) = t.get::<_, String>("text") {
1637 | // todo!()
1638 | // } else {
1639 | // return e;
1640 | // }
1641 | }
1642 | _ => Err(mlua::Error::FromLuaConversionError {
1643 | from: "luavalue",
1644 | to: "widgettext",
1645 | message: None,
1646 | }),
1647 | }
1648 | }
1649 |
1650 | fn to_lua(value: Self, lua: &Lua) -> Result {
1651 | Ok(Value::UserData(lua.create_any_userdata(value)?))
1652 | }
1653 |
1654 | fn add_to_lua(lua: &Lua, egui_table: &Table) -> Result<()> {
1655 | lua.register_userdata_type(|reg: &mut UserDataRegistry| {
1656 | reg.add_method("is_empty", |_, this, ()| Ok(this.is_empty()));
1657 | reg.add_method("text", |_, this, ()| Ok(this.text().to_string()));
1658 | reg.add_method("size", |lua, this, size: f32| {
1659 | lua.create_any_userdata(this.clone().size(size))
1660 | });
1661 | })?;
1662 | let rich_text = lua.create_table()?;
1663 | rich_text.set(
1664 | "new",
1665 | lua.create_function(|lua, text: String| lua.create_any_userdata(RichText::new(text)))?,
1666 | )?;
1667 |
1668 | egui_table.set("rich_text", rich_text)
1669 | }
1670 | }
1671 |
1672 | #[derive(Hash, Debug)]
1673 | enum LuaHashable<'lua> {
1674 | LuaString(mlua::String<'lua>),
1675 | Integer(i32),
1676 | }
1677 | impl<'lua> LuaHashable<'lua> {
1678 | fn from_lua(value: Value<'lua>) -> Result {
1679 | match value {
1680 | Value::Integer(i) => Ok(Self::Integer(i)),
1681 | Value::String(i) => Ok(Self::LuaString(i)),
1682 | _ => Err(mlua::Error::FromLuaConversionError {
1683 | from: "value",
1684 | to: "LuaHashable",
1685 | message: None,
1686 | }),
1687 | }
1688 | }
1689 | }
1690 | fn add_style(lua: &Lua, egui_table: &Table) -> Result<()> {
1691 | lua.register_userdata_type(|style: &mut UserDataRegistry