Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c1696c799f | ||
|
|
447230e688 | ||
|
|
a1aa5cbb2d | ||
|
|
dad1a0c0f1 | ||
|
|
b71e62b4d9 | ||
|
|
92dbd9a580 | ||
|
|
e3840a938a | ||
|
|
9be05aeb5c | ||
|
|
f2c694bac5 | ||
|
|
93a3c4faf5 | ||
|
|
9872d43fd6 | ||
|
|
af2026113a | ||
|
|
a111187591 | ||
|
|
1e63710e33 | ||
|
|
d18bc714fc | ||
|
|
049e160852 | ||
|
|
33ab5a1d84 | ||
|
|
9c8c1b018e | ||
|
|
b929de5206 | ||
|
|
ac4398ee2a |
+4
-6
@@ -116,7 +116,7 @@ The Style Editor (`ImGui.ShowStyleEditor()`) and the Metrics/Debugger (`ImGui.Sh
|
|||||||
|
|
||||||
### Getting Started & Integration (Roblox)
|
### Getting Started & Integration (Roblox)
|
||||||
|
|
||||||
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/imgui-luau@0.2.0"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/imgui-luau@0.3.0"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
||||||
|
|
||||||
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
||||||
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](/default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](/default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
||||||
@@ -151,7 +151,7 @@ Backend options:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `ImGui_ImplRoblox.Init(parent, render_scale)` | `render_scale` = your OS display scale renders at physical-pixel resolution (crisper, same size as desktop imgui). |
|
| `ImGui_ImplRoblox.Init(parent, render_scale)` | `render_scale` = your OS display scale renders at physical-pixel resolution (crisper, same size as desktop imgui). |
|
||||||
| `ImGui_ImplRoblox.SetRenderScale(scale)` | Change it at runtime. |
|
| `ImGui_ImplRoblox.SetRenderScale(scale)` | Change it at runtime. |
|
||||||
| `ImGui_ImplRoblox.SetRenderRate(hz)` | Max tile redraws per second (default `0` = every frame). Your code still runs every frame. |
|
| `ImGui_ImplRoblox.SetRenderRate(hz)` | Max tile redraws per second (default `60`; `0` = every frame). Your code still runs every frame. |
|
||||||
| `ImGui_ImplRoblox.SetRedrawBudget(ms)` | Max milliseconds per frame spent redrawing changed tiles (opt-in; default `0` = no limit, every change is drawn the same frame). With a budget, tiles over it keep their old pixels for a few frames, so big changes are spread over frames instead of one long frame (parts of the UI may update a frame or two apart). |
|
| `ImGui_ImplRoblox.SetRedrawBudget(ms)` | Max milliseconds per frame spent redrawing changed tiles (opt-in; default `0` = no limit, every change is drawn the same frame). With a budget, tiles over it keep their old pixels for a few frames, so big changes are spread over frames instead of one long frame (parts of the UI may update a frame or two apart). |
|
||||||
| `ImGui_ImplRoblox.SetBusyRenderRate(hz)` | Optional lower redraw rate while scrolling, resizing or moving windows (default off). |
|
| `ImGui_ImplRoblox.SetBusyRenderRate(hz)` | Optional lower redraw rate while scrolling, resizing or moving windows (default off). |
|
||||||
| `ImGui_ImplRoblox.SetProfiling(true)` | MicroProfiler (Ctrl+F6) labels for every backend stage. |
|
| `ImGui_ImplRoblox.SetProfiling(true)` | MicroProfiler (Ctrl+F6) labels for every backend stage. |
|
||||||
@@ -179,7 +179,7 @@ The cost is CPU time in Luau, so the backend is built around **not drawing**:
|
|||||||
3. **Scrolling reuses pixels.** Window content is a separate layer inside a `ClipsDescendants` frame sized to the window's visible area, positioned at the scroll offset. Scrolling moves it like dragging moves a window; only rows entering view are drawn. Decorations (title bar, borders, scrollbar) stay in their own layers.
|
3. **Scrolling reuses pixels.** Window content is a separate layer inside a `ClipsDescendants` frame sized to the window's visible area, positioned at the scroll offset. Scrolling moves it like dragging moves a window; only rows entering view are drawn. Decorations (title bar, borders, scrollbar) stay in their own layers.
|
||||||
4. **Skipping unchanged windows.** Vertices are stored in a flat Luau `buffer` (36 bytes each) instead of tables. Before any per-tile work, a window's raw vertex/index bytes are compared with last frame's; if identical, its layers are just restacked.
|
4. **Skipping unchanged windows.** Vertices are stored in a flat Luau `buffer` (36 bytes each) instead of tables. Before any per-tile work, a window's raw vertex/index bytes are compared with last frame's; if identical, its layers are just restacked.
|
||||||
5. **Fast rasterizer.** `@native` functions; axis-aligned quads (most rects and every glyph) take a span-fill path, flat rows are copied instead of re-blended, gradient rects (color pickers) are filled per row, and only real triangles (anti-aliased edges, curves) use the generic edge-function rasterizer.
|
5. **Fast rasterizer.** `@native` functions; axis-aligned quads (most rects and every glyph) take a span-fill path, flat rows are copied instead of re-blended, gradient rects (color pickers) are filled per row, and only real triangles (anti-aliased edges, curves) use the generic edge-function rasterizer.
|
||||||
6. **Redraw budget.** Changed tiles are redrawn in the frame they change. Optionally, `SetRedrawBudget(ms)` caps the redraw time per frame; tiles over it keep their old pixels and follow on the next frames. Optionally capped with `SetRenderRate(hz)` / `SetBusyRenderRate(hz)`. Your UI code and Dear ImGui's logic still run every frame, so input is never dropped.
|
6. **Redraw budget.** Changed tiles are redrawn in the frame they change. Optionally, `SetRedrawBudget(ms)` caps the redraw time per frame; tiles over it keep their old pixels and follow on the next frames. Redraws are capped at 60 per second by default (`SetRenderRate(hz)`, `0` = uncapped), optionally lower while busy with `SetBusyRenderRate(hz)`. Your UI code and Dear ImGui's logic still run every frame, so input is never dropped.
|
||||||
|
|
||||||
**Input.** Mouse and keys come from `UserInputService`. While the mouse is over Dear ImGui (`io.WantCaptureMouse`), the tiles are `Active`, so clicks and the wheel don't reach the game (camera zoom). Typing comes from key codes by default (printable ASCII). Call `ImGui_ImplRoblox.SetTextProxy(true)` to opt in to a hidden `TextBox` that holds focus while a text field is active: the OS then delivers typing (any layout), paste and copy/cut through it, and its text mirrors Dear ImGui's current selection. Fonts are TTFs rasterized by the ported stb_truetype into the font atlas, which becomes a backend texture like any image (`CreateTexture` works for your own pixels too).
|
**Input.** Mouse and keys come from `UserInputService`. While the mouse is over Dear ImGui (`io.WantCaptureMouse`), the tiles are `Active`, so clicks and the wheel don't reach the game (camera zoom). Typing comes from key codes by default (printable ASCII). Call `ImGui_ImplRoblox.SetTextProxy(true)` to opt in to a hidden `TextBox` that holds focus while a text field is active: the OS then delivers typing (any layout), paste and copy/cut through it, and its text mirrors Dear ImGui's current selection. Fonts are TTFs rasterized by the ported stb_truetype into the font atlas, which becomes a backend texture like any image (`CreateTexture` works for your own pixels too).
|
||||||
|
|
||||||
@@ -205,12 +205,10 @@ love examples/example_love
|
|||||||
|
|
||||||
Roblox stays the primary target: the Roblox build is untouched by this (no shims, `@native` kept); the LÖVE build strips `@native` and adds small `bit32`/`buffer`/`utf8`/`table` shims (the COMPAT section of [backends/imgui_impl_love.lua](/backends/imgui_impl_love.lua)). `tools/test/love/run.sh` checks that LuaJIT produces exactly the same draw data as Luau.
|
Roblox stays the primary target: the Roblox build is untouched by this (no shims, `@native` kept); the LÖVE build strips `@native` and adds small `bit32`/`buffer`/`utf8`/`table` shims (the COMPAT section of [backends/imgui_impl_love.lua](/backends/imgui_impl_love.lua)). `tools/test/love/run.sh` checks that LuaJIT produces exactly the same draw data as Luau.
|
||||||
|
|
||||||
[examples/example_shared/app.lua](/examples/example_shared/app.lua) is one UI that runs unchanged on both: `roblox.client.luau` (Rojo: `examples/example_shared/default.project.json`) and `main.lua` (`love examples/example_shared`) are the only platform code. Write shared UI code in plain Lua 5.1 syntax (no `+=`, `//`, `continue`).
|
|
||||||
|
|
||||||
#### Prebuilt releases
|
#### Prebuilt releases
|
||||||
|
|
||||||
Every push to `master` publishes a rolling `latest` release, and every `v*` tag a versioned release ([.github/workflows/release.yml](/.github/workflows/release.yml)), with:
|
Every push to `master` publishes a rolling `latest` release, and every `v*` tag a versioned release ([.github/workflows/release.yml](/.github/workflows/release.yml)), with:
|
||||||
`ImGui.luau` / `ImGui-nodemo.luau` (Roblox ModuleScript), `imgui_love.lua` / `imgui_love-nodemo.lua` (LÖVE), and `imgui-luau-roblox-*.zip` / `imgui-luau-love-*.zip` (bundle + examples).
|
`ImGui.luau` (Roblox ModuleScript), `imgui_love.lua` (LÖVE), their minified `.min` variants, and `imgui-luau-roblox-*.zip` / `imgui-luau-love-*.zip` (bundle + examples). For a library-only build without the demo, build it yourself with `--no-demo`.
|
||||||
|
|
||||||
### Differences from C++ Dear ImGui
|
### Differences from C++ Dear ImGui
|
||||||
|
|
||||||
|
|||||||
@@ -35,35 +35,27 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
python3 tools/bundle.py dist/roblox # ImGui.luau (library + demo)
|
python3 tools/bundle.py dist/roblox # ImGui.luau (library + demo)
|
||||||
python3 tools/bundle.py --no-demo dist/roblox-nodemo # ImGui.luau (library only)
|
|
||||||
python3 tools/bundle.py --target love dist/love # imgui_love.lua (library + demo)
|
python3 tools/bundle.py --target love dist/love # imgui_love.lua (library + demo)
|
||||||
python3 tools/bundle.py --target love --no-demo dist/love-nodemo
|
|
||||||
# minified variants (comments/whitespace stripped, same code): tools/minify.py
|
# minified variants (comments/whitespace stripped, same code): tools/minify.py
|
||||||
python3 tools/minify.py dist/roblox/ImGui.luau dist/ImGui.min.luau
|
python3 tools/minify.py dist/roblox/ImGui.luau dist/ImGui.min.luau
|
||||||
python3 tools/minify.py dist/roblox-nodemo/ImGui.luau dist/ImGui-nodemo.min.luau
|
|
||||||
python3 tools/minify.py dist/love/imgui_love.lua dist/imgui_love.min.lua
|
python3 tools/minify.py dist/love/imgui_love.lua dist/imgui_love.min.lua
|
||||||
python3 tools/minify.py dist/love-nodemo/imgui_love.lua dist/imgui_love-nodemo.min.lua
|
|
||||||
|
|
||||||
- name: Check
|
- name: Check
|
||||||
run: |
|
run: |
|
||||||
python3 tools/sync_github_readme.py --check
|
python3 tools/sync_github_readme.py --check
|
||||||
luau-compile --null dist/roblox/ImGui.luau
|
luau-compile --null dist/roblox/ImGui.luau
|
||||||
luau-compile --null dist/roblox-nodemo/ImGui.luau
|
|
||||||
sed 's|require(script:WaitForChild("Impl"))|nil|' dist/roblox/ImGuiTyped.luau > /tmp/ImGuiTyped.luau && luau-analyze /tmp/ImGuiTyped.luau
|
sed 's|require(script:WaitForChild("Impl"))|nil|' dist/roblox/ImGuiTyped.luau > /tmp/ImGuiTyped.luau && luau-analyze /tmp/ImGuiTyped.luau
|
||||||
luajit -bl dist/love/imgui_love.lua > /dev/null
|
luajit -bl dist/love/imgui_love.lua > /dev/null
|
||||||
luajit -bl dist/love-nodemo/imgui_love.lua > /dev/null
|
|
||||||
python3 tools/minify.py --test
|
python3 tools/minify.py --test
|
||||||
luau-compile --null dist/ImGui.min.luau
|
luau-compile --null dist/ImGui.min.luau
|
||||||
luau-compile --null dist/ImGui-nodemo.min.luau
|
|
||||||
luajit -bl dist/imgui_love.min.lua > /dev/null
|
luajit -bl dist/imgui_love.min.lua > /dev/null
|
||||||
luajit -bl dist/imgui_love-nodemo.min.lua > /dev/null
|
|
||||||
python3 tools/test/run.py --main tools/test/scripts/t_readme.luau --frames 30 --quiet --roblox --timeout 300 | tee /tmp/r.txt
|
python3 tools/test/run.py --main tools/test/scripts/t_readme.luau --frames 30 --quiet --roblox --timeout 300 | tee /tmp/r.txt
|
||||||
grep -q "README OK" /tmp/r.txt
|
grep -q "README OK" /tmp/r.txt
|
||||||
python3 tools/test/run.py --main tools/test/scripts/t_cached_window.luau --frames 130 --quiet --roblox --timeout 300 | tee /tmp/c.txt
|
python3 tools/test/run.py --main tools/test/scripts/t_cached_window.luau --frames 130 --quiet --roblox --timeout 300 | tee /tmp/c.txt
|
||||||
grep -q "CACHED OK" /tmp/c.txt
|
grep -q "CACHED OK" /tmp/c.txt
|
||||||
MINIFY=1 python3 tools/test/run.py --main tools/test/scripts/t_readme.luau --frames 30 --quiet --roblox --timeout 300 | tee /tmp/rm.txt
|
MINIFY=1 python3 tools/test/run.py --main tools/test/scripts/t_readme.luau --frames 30 --quiet --roblox --timeout 300 | tee /tmp/rm.txt
|
||||||
grep -q "README OK" /tmp/rm.txt
|
grep -q "README OK" /tmp/rm.txt
|
||||||
python3 tools/test/run.py --main tools/test/scripts/t_fixes.luau --frames 25 --quiet --roblox --timeout 300 | tee /tmp/f.txt
|
python3 tools/test/run.py --main tools/test/scripts/t_fixes.luau --frames 55 --quiet --roblox --timeout 300 | tee /tmp/f.txt
|
||||||
grep -q "FIXES OK" /tmp/f.txt
|
grep -q "FIXES OK" /tmp/f.txt
|
||||||
python3 tools/bundle.py --target love >/dev/null
|
python3 tools/bundle.py --target love >/dev/null
|
||||||
luajit tools/test/love/t_drawhash.lua 60 Widgets,Basic | tee /tmp/h.txt
|
luajit tools/test/love/t_drawhash.lua 60 Widgets,Basic | tee /tmp/h.txt
|
||||||
@@ -78,16 +70,14 @@ jobs:
|
|||||||
V="${GITHUB_REF_NAME}"
|
V="${GITHUB_REF_NAME}"
|
||||||
cd dist
|
cd dist
|
||||||
cp roblox/ImGui.luau ImGui.luau
|
cp roblox/ImGui.luau ImGui.luau
|
||||||
cp roblox-nodemo/ImGui.luau ImGui-nodemo.luau
|
|
||||||
cp love/imgui_love.lua imgui_love.lua
|
cp love/imgui_love.lua imgui_love.lua
|
||||||
cp love-nodemo/imgui_love.lua imgui_love-nodemo.lua
|
|
||||||
# Roblox: module + example LocalScript + Rojo project
|
# Roblox: module + example LocalScript + Rojo project
|
||||||
mkdir -p pkg-roblox/build && cp ImGui.luau roblox/ImGuiTyped.luau pkg-roblox/build/ && cp ../default.project.json pkg-roblox/
|
mkdir -p pkg-roblox/build && cp ImGui.luau roblox/ImGuiTyped.luau pkg-roblox/build/ && cp ../default.project.json pkg-roblox/
|
||||||
mkdir -p pkg-roblox/examples && cp -r ../examples/example_roblox ../examples/example_shared pkg-roblox/examples/
|
mkdir -p pkg-roblox/examples && cp -r ../examples/example_roblox pkg-roblox/examples/
|
||||||
(cd pkg-roblox && zip -qr ../imgui-luau-roblox-$V.zip .)
|
(cd pkg-roblox && zip -qr ../imgui-luau-roblox-$V.zip .)
|
||||||
# LÖVE: bundle + fonts + examples (run: love examples/example_love)
|
# LÖVE: bundle + fonts + examples (run: love examples/example_love)
|
||||||
mkdir -p pkg-love/build && cp imgui_love.lua pkg-love/build/ && cp -r ../fonts pkg-love/ && rm -f pkg-love/fonts/*.lua
|
mkdir -p pkg-love/build && cp imgui_love.lua pkg-love/build/ && cp -r ../fonts pkg-love/ && rm -f pkg-love/fonts/*.lua
|
||||||
mkdir -p pkg-love/examples && cp -r ../examples/example_love ../examples/example_shared pkg-love/examples/
|
mkdir -p pkg-love/examples && cp -r ../examples/example_love pkg-love/examples/
|
||||||
(cd pkg-love && zip -qr ../imgui-luau-love-$V.zip .)
|
(cd pkg-love && zip -qr ../imgui-luau-love-$V.zip .)
|
||||||
ls -la
|
ls -la
|
||||||
|
|
||||||
@@ -97,9 +87,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
files: |
|
files: |
|
||||||
dist/ImGui.luau
|
dist/ImGui.luau
|
||||||
dist/ImGui-nodemo.luau
|
|
||||||
dist/imgui_love.lua
|
dist/imgui_love.lua
|
||||||
dist/imgui_love-nodemo.lua
|
|
||||||
dist/*.min.luau
|
dist/*.min.luau
|
||||||
dist/*.min.lua
|
dist/*.min.lua
|
||||||
dist/*.zip
|
dist/*.zip
|
||||||
@@ -127,4 +115,4 @@ jobs:
|
|||||||
gh release delete latest --yes --cleanup-tag || true
|
gh release delete latest --yes --cleanup-tag || true
|
||||||
gh release create latest --latest --title "Latest build (${GITHUB_SHA::7})" \
|
gh release create latest --latest --title "Latest build (${GITHUB_SHA::7})" \
|
||||||
--notes "Automatic build of ${GITHUB_SHA} on ${GITHUB_REF_NAME}. Tag a commit v* for a versioned release." \
|
--notes "Automatic build of ${GITHUB_SHA} on ${GITHUB_REF_NAME}. Tag a commit v* for a versioned release." \
|
||||||
dist/ImGui.luau dist/ImGui-nodemo.luau dist/imgui_love.lua dist/imgui_love-nodemo.lua dist/*.min.luau dist/*.min.lua dist/*.zip
|
dist/ImGui.luau dist/imgui_love.lua dist/*.min.luau dist/*.min.lua dist/*.zip
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ The Style Editor (`ImGui.ShowStyleEditor()`) and the Metrics/Debugger (`ImGui.Sh
|
|||||||
|
|
||||||
### Getting Started & Integration (Roblox)
|
### Getting Started & Integration (Roblox)
|
||||||
|
|
||||||
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/imgui-luau@0.2.0"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/imgui-luau@0.3.0"` under `[dependencies]` in your `wally.toml`, run `wally install`, then `require(ReplicatedStorage.Packages.ImGui)`. Or from source:
|
||||||
|
|
||||||
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out) and `build/ImGuiTyped.luau`, a small typed entry module (Luau types for the public `ImGui.*` API, `ImVec2`/`ImVec4` and the flag enums) that requires `build/ImGui.luau` as its child `Impl`. The Wally package and the Rojo projects use that layout, so you get autocomplete and type errors in `--!strict` scripts. The single-file `ImGui.luau` also works on its own, just untyped.
|
||||||
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
2. Sync with [Rojo](https://rojo.space): [`default.project.json`](default.project.json) puts the module in `ReplicatedStorage.ImGui` and the example LocalScript in `StarterPlayerScripts`.
|
||||||
@@ -148,7 +148,7 @@ Backend options:
|
|||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `ImGui_ImplRoblox.Init(parent, render_scale)` | `render_scale` = your OS display scale renders at physical-pixel resolution (crisper, same size as desktop imgui). |
|
| `ImGui_ImplRoblox.Init(parent, render_scale)` | `render_scale` = your OS display scale renders at physical-pixel resolution (crisper, same size as desktop imgui). |
|
||||||
| `ImGui_ImplRoblox.SetRenderScale(scale)` | Change it at runtime. |
|
| `ImGui_ImplRoblox.SetRenderScale(scale)` | Change it at runtime. |
|
||||||
| `ImGui_ImplRoblox.SetRenderRate(hz)` | Max tile redraws per second (default `0` = every frame). Your code still runs every frame. |
|
| `ImGui_ImplRoblox.SetRenderRate(hz)` | Max tile redraws per second (default `60`; `0` = every frame). Your code still runs every frame. |
|
||||||
| `ImGui_ImplRoblox.SetRedrawBudget(ms)` | Max milliseconds per frame spent redrawing changed tiles (opt-in; default `0` = no limit, every change is drawn the same frame). With a budget, tiles over it keep their old pixels for a few frames, so big changes are spread over frames instead of one long frame (parts of the UI may update a frame or two apart). |
|
| `ImGui_ImplRoblox.SetRedrawBudget(ms)` | Max milliseconds per frame spent redrawing changed tiles (opt-in; default `0` = no limit, every change is drawn the same frame). With a budget, tiles over it keep their old pixels for a few frames, so big changes are spread over frames instead of one long frame (parts of the UI may update a frame or two apart). |
|
||||||
| `ImGui_ImplRoblox.SetBusyRenderRate(hz)` | Optional lower redraw rate while scrolling, resizing or moving windows (default off). |
|
| `ImGui_ImplRoblox.SetBusyRenderRate(hz)` | Optional lower redraw rate while scrolling, resizing or moving windows (default off). |
|
||||||
| `ImGui_ImplRoblox.SetProfiling(true)` | MicroProfiler (Ctrl+F6) labels for every backend stage. |
|
| `ImGui_ImplRoblox.SetProfiling(true)` | MicroProfiler (Ctrl+F6) labels for every backend stage. |
|
||||||
@@ -176,7 +176,7 @@ The cost is CPU time in Luau, so the backend is built around **not drawing**:
|
|||||||
3. **Scrolling reuses pixels.** Window content is a separate layer inside a `ClipsDescendants` frame sized to the window's visible area, positioned at the scroll offset. Scrolling moves it like dragging moves a window; only rows entering view are drawn. Decorations (title bar, borders, scrollbar) stay in their own layers.
|
3. **Scrolling reuses pixels.** Window content is a separate layer inside a `ClipsDescendants` frame sized to the window's visible area, positioned at the scroll offset. Scrolling moves it like dragging moves a window; only rows entering view are drawn. Decorations (title bar, borders, scrollbar) stay in their own layers.
|
||||||
4. **Skipping unchanged windows.** Vertices are stored in a flat Luau `buffer` (36 bytes each) instead of tables. Before any per-tile work, a window's raw vertex/index bytes are compared with last frame's; if identical, its layers are just restacked.
|
4. **Skipping unchanged windows.** Vertices are stored in a flat Luau `buffer` (36 bytes each) instead of tables. Before any per-tile work, a window's raw vertex/index bytes are compared with last frame's; if identical, its layers are just restacked.
|
||||||
5. **Fast rasterizer.** `@native` functions; axis-aligned quads (most rects and every glyph) take a span-fill path, flat rows are copied instead of re-blended, gradient rects (color pickers) are filled per row, and only real triangles (anti-aliased edges, curves) use the generic edge-function rasterizer.
|
5. **Fast rasterizer.** `@native` functions; axis-aligned quads (most rects and every glyph) take a span-fill path, flat rows are copied instead of re-blended, gradient rects (color pickers) are filled per row, and only real triangles (anti-aliased edges, curves) use the generic edge-function rasterizer.
|
||||||
6. **Redraw budget.** Changed tiles are redrawn in the frame they change. Optionally, `SetRedrawBudget(ms)` caps the redraw time per frame; tiles over it keep their old pixels and follow on the next frames. Optionally capped with `SetRenderRate(hz)` / `SetBusyRenderRate(hz)`. Your UI code and Dear ImGui's logic still run every frame, so input is never dropped.
|
6. **Redraw budget.** Changed tiles are redrawn in the frame they change. Optionally, `SetRedrawBudget(ms)` caps the redraw time per frame; tiles over it keep their old pixels and follow on the next frames. Redraws are capped at 60 per second by default (`SetRenderRate(hz)`, `0` = uncapped), optionally lower while busy with `SetBusyRenderRate(hz)`. Your UI code and Dear ImGui's logic still run every frame, so input is never dropped.
|
||||||
|
|
||||||
**Input.** Mouse and keys come from `UserInputService`. While the mouse is over Dear ImGui (`io.WantCaptureMouse`), the tiles are `Active`, so clicks and the wheel don't reach the game (camera zoom). Typing comes from key codes by default (printable ASCII). Call `ImGui_ImplRoblox.SetTextProxy(true)` to opt in to a hidden `TextBox` that holds focus while a text field is active: the OS then delivers typing (any layout), paste and copy/cut through it, and its text mirrors Dear ImGui's current selection. Fonts are TTFs rasterized by the ported stb_truetype into the font atlas, which becomes a backend texture like any image (`CreateTexture` works for your own pixels too).
|
**Input.** Mouse and keys come from `UserInputService`. While the mouse is over Dear ImGui (`io.WantCaptureMouse`), the tiles are `Active`, so clicks and the wheel don't reach the game (camera zoom). Typing comes from key codes by default (printable ASCII). Call `ImGui_ImplRoblox.SetTextProxy(true)` to opt in to a hidden `TextBox` that holds focus while a text field is active: the OS then delivers typing (any layout), paste and copy/cut through it, and its text mirrors Dear ImGui's current selection. Fonts are TTFs rasterized by the ported stb_truetype into the font atlas, which becomes a backend texture like any image (`CreateTexture` works for your own pixels too).
|
||||||
|
|
||||||
@@ -202,12 +202,10 @@ love examples/example_love
|
|||||||
|
|
||||||
Roblox stays the primary target: the Roblox build is untouched by this (no shims, `@native` kept); the LÖVE build strips `@native` and adds small `bit32`/`buffer`/`utf8`/`table` shims (the COMPAT section of [backends/imgui_impl_love.lua](backends/imgui_impl_love.lua)). `tools/test/love/run.sh` checks that LuaJIT produces exactly the same draw data as Luau.
|
Roblox stays the primary target: the Roblox build is untouched by this (no shims, `@native` kept); the LÖVE build strips `@native` and adds small `bit32`/`buffer`/`utf8`/`table` shims (the COMPAT section of [backends/imgui_impl_love.lua](backends/imgui_impl_love.lua)). `tools/test/love/run.sh` checks that LuaJIT produces exactly the same draw data as Luau.
|
||||||
|
|
||||||
[examples/example_shared/app.lua](examples/example_shared/app.lua) is one UI that runs unchanged on both: `roblox.client.luau` (Rojo: `examples/example_shared/default.project.json`) and `main.lua` (`love examples/example_shared`) are the only platform code. Write shared UI code in plain Lua 5.1 syntax (no `+=`, `//`, `continue`).
|
|
||||||
|
|
||||||
#### Prebuilt releases
|
#### Prebuilt releases
|
||||||
|
|
||||||
Every push to `master` publishes a rolling `latest` release, and every `v*` tag a versioned release ([.github/workflows/release.yml](.github/workflows/release.yml)), with:
|
Every push to `master` publishes a rolling `latest` release, and every `v*` tag a versioned release ([.github/workflows/release.yml](.github/workflows/release.yml)), with:
|
||||||
`ImGui.luau` / `ImGui-nodemo.luau` (Roblox ModuleScript), `imgui_love.lua` / `imgui_love-nodemo.lua` (LÖVE), and `imgui-luau-roblox-*.zip` / `imgui-luau-love-*.zip` (bundle + examples).
|
`ImGui.luau` (Roblox ModuleScript), `imgui_love.lua` (LÖVE), their minified `.min` variants, and `imgui-luau-roblox-*.zip` / `imgui-luau-love-*.zip` (bundle + examples). For a library-only build without the demo, build it yourself with `--no-demo`.
|
||||||
|
|
||||||
### Differences from C++ Dear ImGui
|
### Differences from C++ Dear ImGui
|
||||||
|
|
||||||
|
|||||||
@@ -431,6 +431,8 @@ function ImGui_ImplLOVE_Init(opts)
|
|||||||
local io = ImGui.GetIO()
|
local io = ImGui.GetIO()
|
||||||
local bd = { Time = love.timer.getTime(), Root = opts.root or "", Textures = {}, TextureCount = 0, Meshes = {}, FrameNo = 0 }
|
local bd = { Time = love.timer.getTime(), Root = opts.root or "", Textures = {}, TextureCount = 0, Meshes = {}, FrameNo = 0 }
|
||||||
io.BackendPlatformUserData = bd
|
io.BackendPlatformUserData = bd
|
||||||
|
io.BackendPlatformName = "imgui_impl_love"
|
||||||
|
io.BackendRendererName = "imgui_impl_love"
|
||||||
io.BackendFlags = bit32.bor(io.BackendFlags, ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset, ImGuiBackendFlags.HasMouseCursors)
|
io.BackendFlags = bit32.bor(io.BackendFlags, ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset, ImGuiBackendFlags.HasMouseCursors)
|
||||||
|
|
||||||
local platform_io = ImGui.GetPlatformIO()
|
local platform_io = ImGui.GetPlatformIO()
|
||||||
@@ -449,6 +451,8 @@ function ImGui_ImplLOVE_Shutdown()
|
|||||||
for _, m in pairs(bd.Meshes) do m.Mesh:release() end
|
for _, m in pairs(bd.Meshes) do m.Mesh:release() end
|
||||||
for _, t in pairs(bd.Textures) do t:release() end
|
for _, t in pairs(bd.Textures) do t:release() end
|
||||||
io.BackendPlatformUserData = nil
|
io.BackendPlatformUserData = nil
|
||||||
|
io.BackendPlatformName = nil
|
||||||
|
io.BackendRendererName = nil
|
||||||
io.BackendFlags = bit32.band(io.BackendFlags, bit32.bnot(bit32.bor(ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset, ImGuiBackendFlags.HasMouseCursors)))
|
io.BackendFlags = bit32.band(io.BackendFlags, bit32.bnot(bit32.bor(ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset, ImGuiBackendFlags.HasMouseCursors)))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1353,9 +1353,11 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
|||||||
local bd = {
|
local bd = {
|
||||||
Time = os.clock(), Gui = gui, Connections = {},
|
Time = os.clock(), Gui = gui, Connections = {},
|
||||||
Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1,
|
Textures = {}, TextureCount = 0, MouseX = -1, MouseY = -1,
|
||||||
Layers = {}, Overlays = {}, OverlayHolders = {}, OverlayShown = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 0, BusyRenderRate = 0, RedrawBudget = 0, HB = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true,
|
Layers = {}, Overlays = {}, OverlayHolders = {}, OverlayShown = {}, FrameNo = 0, Scale = render_scale or 1, TilesActive = false, RenderRate = 60, BusyRenderRate = 0, RedrawBudget = 0, HB = 0, NextRender = 0, LastPrimCount = 0, ForceRedraw = true,
|
||||||
}
|
}
|
||||||
io.BackendPlatformUserData = bd
|
io.BackendPlatformUserData = bd
|
||||||
|
io.BackendPlatformName = "imgui_impl_roblox"
|
||||||
|
io.BackendRendererName = "imgui_impl_roblox"
|
||||||
|
|
||||||
io.BackendFlags = bit32.bor(io.BackendFlags, ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset)
|
io.BackendFlags = bit32.bor(io.BackendFlags, ImGuiBackendFlags.RendererHasTextures, ImGuiBackendFlags.RendererHasVtxOffset)
|
||||||
|
|
||||||
@@ -1475,6 +1477,8 @@ function ImGui_ImplRoblox_Shutdown()
|
|||||||
bd.Gui:Destroy()
|
bd.Gui:Destroy()
|
||||||
|
|
||||||
io.BackendPlatformUserData = nil
|
io.BackendPlatformUserData = nil
|
||||||
|
io.BackendPlatformName = nil
|
||||||
|
io.BackendRendererName = nil
|
||||||
io.BackendFlags = bit32.band(io.BackendFlags, bit32.bnot(bit32.bor(
|
io.BackendFlags = bit32.band(io.BackendFlags, bit32.bnot(bit32.bor(
|
||||||
ImGuiBackendFlags.RendererHasTextures,
|
ImGuiBackendFlags.RendererHasTextures,
|
||||||
ImGuiBackendFlags.RendererHasVtxOffset
|
ImGuiBackendFlags.RendererHasVtxOffset
|
||||||
@@ -1601,7 +1605,7 @@ function ImGui_ImplRoblox_SetRedrawBudget(ms)
|
|||||||
ImGui_ImplRoblox_GetBackendData().RedrawBudget = (ms or 0) / 1000
|
ImGui_ImplRoblox_GetBackendData().RedrawBudget = (ms or 0) / 1000
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Max tile redraws per second (default 0 = every frame, limited by the redraw budget instead). imgui logic still runs every frame.
|
--- Max tile redraws per second (default 60; 0 = every frame, limited by the redraw budget instead). imgui logic still runs every frame.
|
||||||
function ImGui_ImplRoblox_SetRenderRate(hz)
|
function ImGui_ImplRoblox_SetRenderRate(hz)
|
||||||
ImGui_ImplRoblox_GetBackendData().RenderRate = hz or 0
|
ImGui_ImplRoblox_GetBackendData().RenderRate = hz or 0
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[[46, "imgui.lua"], [21389, "imgui_demo.lua"], [29807, "imgui_draw.lua"], [35745, "imgui_h.lua"], [38412, "imgui_impl_roblox.lua"], [40060, "imgui_impl_roblox_fonts.lua"], [46463, "imgui_internal.lua"], [49932, "imgui_tables.lua"], [54991, "imgui_widgets.lua"], [65631, "imstb_rectpack.lua"], [66295, "imstb_textedit.lua"], [67837, "imstb_truetype.lua"], [70625, "imstd_minstdio.lua"]]
|
[[46, "imgui.lua"], [22675, "imgui_demo.lua"], [34533, "imgui_draw.lua"], [42860, "imgui_h.lua"], [45857, "imgui_impl_roblox.lua"], [47509, "imgui_impl_roblox_fonts.lua"], [53912, "imgui_internal.lua"], [57884, "imgui_tables.lua"], [62976, "imgui_widgets.lua"], [75210, "imstb_rectpack.lua"], [75874, "imstb_textedit.lua"], [77416, "imstb_truetype.lua"], [80204, "imstd_minstdio.lua"]]
|
||||||
+15799
-6093
File diff suppressed because it is too large
Load Diff
+77
-3
@@ -6,6 +6,7 @@ export type ImVec4 = { x: number, y: number, z: number, w: number, [any]: any }
|
|||||||
export type ImGuiAPI = {
|
export type ImGuiAPI = {
|
||||||
AcceptDragDropPayload: (type: string, flags: number?) -> any,
|
AcceptDragDropPayload: (type: string, flags: number?) -> any,
|
||||||
ActivateItemByID: (...any) -> ...any,
|
ActivateItemByID: (...any) -> ...any,
|
||||||
|
AddContextHook: (...any) -> ...any,
|
||||||
AddDrawListToDrawDataEx: (...any) -> ...any,
|
AddDrawListToDrawDataEx: (...any) -> ...any,
|
||||||
AddSettingsHandler: (...any) -> ...any,
|
AddSettingsHandler: (...any) -> ...any,
|
||||||
AddUpdateViewport: (...any) -> ...any,
|
AddUpdateViewport: (...any) -> ...any,
|
||||||
@@ -13,6 +14,7 @@ export type ImGuiAPI = {
|
|||||||
ArrowButton: (str_id: string, dir: number) -> boolean,
|
ArrowButton: (str_id: string, dir: number) -> boolean,
|
||||||
ArrowButtonEx: (...any) -> ...any,
|
ArrowButtonEx: (...any) -> ...any,
|
||||||
Begin: (name: string, open: boolean?, flags: number?) -> (boolean, boolean?),
|
Begin: (name: string, open: boolean?, flags: number?) -> (boolean, boolean?),
|
||||||
|
BeginBoxSelect: (...any) -> ...any,
|
||||||
BeginChild: (...any) -> ...any,
|
BeginChild: (...any) -> ...any,
|
||||||
BeginChildEx: (...any) -> ...any,
|
BeginChildEx: (...any) -> ...any,
|
||||||
BeginColumns: (...any) -> ...any,
|
BeginColumns: (...any) -> ...any,
|
||||||
@@ -36,6 +38,7 @@ export type ImGuiAPI = {
|
|||||||
BeginMenu: (label: string, enabled: boolean?) -> boolean,
|
BeginMenu: (label: string, enabled: boolean?) -> boolean,
|
||||||
BeginMenuBar: () -> boolean,
|
BeginMenuBar: () -> boolean,
|
||||||
BeginMenuEx: (...any) -> ...any,
|
BeginMenuEx: (...any) -> ...any,
|
||||||
|
BeginMultiSelect: (flags: number, selection_size: number?, items_count: number?) -> any,
|
||||||
BeginPopup: (str_id: string, flags: number?) -> boolean,
|
BeginPopup: (str_id: string, flags: number?) -> boolean,
|
||||||
BeginPopupContextItem: (str_id: string?, popup_flags: number?) -> boolean,
|
BeginPopupContextItem: (str_id: string?, popup_flags: number?) -> boolean,
|
||||||
BeginPopupContextVoid: (str_id: string?, popup_flags: number?) -> boolean,
|
BeginPopupContextVoid: (str_id: string?, popup_flags: number?) -> boolean,
|
||||||
@@ -70,6 +73,7 @@ export type ImGuiAPI = {
|
|||||||
CalcTypematicRepeatAmount: (...any) -> ...any,
|
CalcTypematicRepeatAmount: (...any) -> ...any,
|
||||||
CalcWindowNextAutoFitSize: (...any) -> ...any,
|
CalcWindowNextAutoFitSize: (...any) -> ...any,
|
||||||
CalcWrapWidthForPos: (...any) -> ...any,
|
CalcWrapWidthForPos: (...any) -> ...any,
|
||||||
|
CallContextHooks: (...any) -> ...any,
|
||||||
Checkbox: (label: string, v: boolean?) -> (boolean, boolean?),
|
Checkbox: (label: string, v: boolean?) -> (boolean, boolean?),
|
||||||
CheckboxFlags: (...any) -> ...any,
|
CheckboxFlags: (...any) -> ...any,
|
||||||
CleanupIniSettings: (...any) -> ...any,
|
CleanupIniSettings: (...any) -> ...any,
|
||||||
@@ -109,26 +113,47 @@ export type ImGuiAPI = {
|
|||||||
DataTypeGetInfo: (...any) -> ...any,
|
DataTypeGetInfo: (...any) -> ...any,
|
||||||
DataTypeIsZero: (...any) -> ...any,
|
DataTypeIsZero: (...any) -> ...any,
|
||||||
DebugAllocHook: (...any) -> ...any,
|
DebugAllocHook: (...any) -> ...any,
|
||||||
|
DebugBreakButton: (...any) -> ...any,
|
||||||
|
DebugBreakButtonTooltip: (...any) -> ...any,
|
||||||
|
DebugBreakClearData: (...any) -> ...any,
|
||||||
|
DebugDrawCursorPos: (...any) -> ...any,
|
||||||
|
DebugDrawItemRect: (...any) -> ...any,
|
||||||
|
DebugDrawLineExtents: (...any) -> ...any,
|
||||||
|
DebugFlashStyleColor: (idx: number) -> (),
|
||||||
DebugHookIdInfo: (...any) -> ...any,
|
DebugHookIdInfo: (...any) -> ...any,
|
||||||
|
DebugLocateItem: (...any) -> ...any,
|
||||||
|
DebugLocateItemOnHover: (...any) -> ...any,
|
||||||
|
DebugLocateItemResolveWithLastItem: (...any) -> ...any,
|
||||||
DebugLog: (fmt: string, ...any) -> (),
|
DebugLog: (fmt: string, ...any) -> (),
|
||||||
|
DebugLogV: (fmt: string, ...any) -> (),
|
||||||
DebugNodeColumns: (...any) -> ...any,
|
DebugNodeColumns: (...any) -> ...any,
|
||||||
DebugNodeDockNode: (...any) -> ...any,
|
DebugNodeDockNode: (...any) -> ...any,
|
||||||
|
DebugNodeDrawCmdShowMeshAndBoundingBox: (...any) -> ...any,
|
||||||
DebugNodeDrawList: (...any) -> ...any,
|
DebugNodeDrawList: (...any) -> ...any,
|
||||||
DebugNodeFont: (...any) -> ...any,
|
DebugNodeFont: (...any) -> ...any,
|
||||||
DebugNodeFontGlyph: (...any) -> ...any,
|
DebugNodeFontGlyph: (...any) -> ...any,
|
||||||
DebugNodeFontGlyphsForSrcMask: (...any) -> ...any,
|
DebugNodeFontGlyphsForSrcMask: (...any) -> ...any,
|
||||||
|
DebugNodeInputTextState: (...any) -> ...any,
|
||||||
|
DebugNodeMultiSelectState: (...any) -> ...any,
|
||||||
|
DebugNodePlatformMonitor: (...any) -> ...any,
|
||||||
DebugNodeStorage: (...any) -> ...any,
|
DebugNodeStorage: (...any) -> ...any,
|
||||||
DebugNodeTabBar: (...any) -> ...any,
|
DebugNodeTabBar: (...any) -> ...any,
|
||||||
DebugNodeTable: (...any) -> ...any,
|
DebugNodeTable: (...any) -> ...any,
|
||||||
DebugNodeTableSettings: (...any) -> ...any,
|
DebugNodeTableSettings: (...any) -> ...any,
|
||||||
DebugNodeTexture: (...any) -> ...any,
|
DebugNodeTexture: (...any) -> ...any,
|
||||||
|
DebugNodeTypingSelectState: (...any) -> ...any,
|
||||||
DebugNodeViewport: (...any) -> ...any,
|
DebugNodeViewport: (...any) -> ...any,
|
||||||
DebugNodeWindow: (...any) -> ...any,
|
DebugNodeWindow: (...any) -> ...any,
|
||||||
DebugNodeWindowSettings: (...any) -> ...any,
|
DebugNodeWindowSettings: (...any) -> ...any,
|
||||||
DebugNodeWindowsList: (...any) -> ...any,
|
DebugNodeWindowsList: (...any) -> ...any,
|
||||||
DebugNodeWindowsListByBeginStackParent: (...any) -> ...any,
|
DebugNodeWindowsListByBeginStackParent: (...any) -> ...any,
|
||||||
|
DebugRenderKeyboardPreview: (...any) -> ...any,
|
||||||
DebugRenderViewportThumbnail: (...any) -> ...any,
|
DebugRenderViewportThumbnail: (...any) -> ...any,
|
||||||
|
DebugStartItemPicker: () -> (),
|
||||||
DebugTextEncoding: (str: string) -> (),
|
DebugTextEncoding: (str: string) -> (),
|
||||||
|
DebugTextUnformattedWithLocateItem: (...any) -> ...any,
|
||||||
|
DebugTextureIDToU64: (...any) -> ...any,
|
||||||
|
DemoMarker: (...any) -> ...any,
|
||||||
DestroyContext: (ctx: any) -> ...any,
|
DestroyContext: (ctx: any) -> ...any,
|
||||||
DestroyPlatformWindow: (...any) -> ...any,
|
DestroyPlatformWindow: (...any) -> ...any,
|
||||||
DestroyPlatformWindows: () -> (),
|
DestroyPlatformWindows: () -> (),
|
||||||
@@ -220,6 +245,7 @@ export type ImGuiAPI = {
|
|||||||
DragScalarN: (label: string, data_type: number, v: any, components: number, v_speed: number?, v_min: any, v_max: any, format: string?, flags: number?) -> ...any,
|
DragScalarN: (label: string, data_type: number, v: any, components: number, v_speed: number?, v_min: any, v_max: any, format: string?, flags: number?) -> ...any,
|
||||||
Dummy: (size: ImVec2) -> (),
|
Dummy: (size: ImVec2) -> (),
|
||||||
End: () -> (),
|
End: () -> (),
|
||||||
|
EndBoxSelect: (...any) -> ...any,
|
||||||
EndChild: () -> (),
|
EndChild: () -> (),
|
||||||
EndColumns: (...any) -> ...any,
|
EndColumns: (...any) -> ...any,
|
||||||
EndCombo: () -> (),
|
EndCombo: () -> (),
|
||||||
@@ -235,12 +261,15 @@ export type ImGuiAPI = {
|
|||||||
EndMainMenuBar: () -> (),
|
EndMainMenuBar: () -> (),
|
||||||
EndMenu: () -> (),
|
EndMenu: () -> (),
|
||||||
EndMenuBar: () -> (),
|
EndMenuBar: () -> (),
|
||||||
|
EndMultiSelect: () -> any,
|
||||||
EndPopup: () -> (),
|
EndPopup: () -> (),
|
||||||
EndTabBar: () -> (),
|
EndTabBar: () -> (),
|
||||||
EndTabItem: () -> (),
|
EndTabItem: () -> (),
|
||||||
EndTable: () -> (),
|
EndTable: () -> (),
|
||||||
EndTooltip: () -> (),
|
EndTooltip: () -> (),
|
||||||
ErrorCheckEndFrameFinalizeErrorTooltip: (...any) -> ...any,
|
ErrorCheckEndFrameFinalizeErrorTooltip: (...any) -> ...any,
|
||||||
|
ErrorCheckEndFrameSanityChecks: (...any) -> ...any,
|
||||||
|
ErrorCheckNewFrameSanityChecks: (...any) -> ...any,
|
||||||
ErrorCheckUsingSetCursorPosToExtendParentBoundaries: (...any) -> ...any,
|
ErrorCheckUsingSetCursorPosToExtendParentBoundaries: (...any) -> ...any,
|
||||||
ErrorLog: (...any) -> ...any,
|
ErrorLog: (...any) -> ...any,
|
||||||
ErrorRecoveryStoreState: (...any) -> ...any,
|
ErrorRecoveryStoreState: (...any) -> ...any,
|
||||||
@@ -259,6 +288,7 @@ export type ImGuiAPI = {
|
|||||||
FindRenderedTextEnd: (...any) -> ...any,
|
FindRenderedTextEnd: (...any) -> ...any,
|
||||||
FindSettingsHandler: (...any) -> ...any,
|
FindSettingsHandler: (...any) -> ...any,
|
||||||
FindViewportByID: (viewport_id: number) -> any,
|
FindViewportByID: (viewport_id: number) -> any,
|
||||||
|
FindViewportByPlatformHandle: (platform_handle: any) -> ...any,
|
||||||
FindWindowByID: (...any) -> ...any,
|
FindWindowByID: (...any) -> ...any,
|
||||||
FindWindowByName: (...any) -> ...any,
|
FindWindowByName: (...any) -> ...any,
|
||||||
FindWindowDisplayIndex: (...any) -> ...any,
|
FindWindowDisplayIndex: (...any) -> ...any,
|
||||||
@@ -273,7 +303,9 @@ export type ImGuiAPI = {
|
|||||||
GcAwakeTransientWindowBuffers: (...any) -> ...any,
|
GcAwakeTransientWindowBuffers: (...any) -> ...any,
|
||||||
GcCompactTransientMiscBuffers: (...any) -> ...any,
|
GcCompactTransientMiscBuffers: (...any) -> ...any,
|
||||||
GcCompactTransientWindowBuffers: (...any) -> ...any,
|
GcCompactTransientWindowBuffers: (...any) -> ...any,
|
||||||
|
GetActiveID: (...any) -> ...any,
|
||||||
GetBackgroundDrawList: (viewport: any) -> ...any,
|
GetBackgroundDrawList: (viewport: any) -> ...any,
|
||||||
|
GetBoxSelectState: (...any) -> ...any,
|
||||||
GetClipboardText: () -> any,
|
GetClipboardText: () -> any,
|
||||||
GetColorU32: (...any) -> ...any,
|
GetColorU32: (...any) -> ...any,
|
||||||
GetColumnIndex: () -> number,
|
GetColumnIndex: () -> number,
|
||||||
@@ -286,6 +318,9 @@ export type ImGuiAPI = {
|
|||||||
GetContentRegionAvail: () -> ImVec2,
|
GetContentRegionAvail: () -> ImVec2,
|
||||||
GetContentRegionMax: (...any) -> ...any,
|
GetContentRegionMax: (...any) -> ...any,
|
||||||
GetCurrentContext: () -> any,
|
GetCurrentContext: () -> any,
|
||||||
|
GetCurrentFocusScope: (...any) -> ...any,
|
||||||
|
GetCurrentTabBar: (...any) -> ...any,
|
||||||
|
GetCurrentTable: (...any) -> ...any,
|
||||||
GetCurrentWindow: (...any) -> ...any,
|
GetCurrentWindow: (...any) -> ...any,
|
||||||
GetCurrentWindowRead: (...any) -> ...any,
|
GetCurrentWindowRead: (...any) -> ...any,
|
||||||
GetCursorPos: () -> ImVec2,
|
GetCursorPos: () -> ImVec2,
|
||||||
@@ -297,7 +332,9 @@ export type ImGuiAPI = {
|
|||||||
GetDragDropPayload: () -> any,
|
GetDragDropPayload: () -> any,
|
||||||
GetDrawData: () -> any,
|
GetDrawData: () -> any,
|
||||||
GetDrawListSharedData: () -> any,
|
GetDrawListSharedData: () -> any,
|
||||||
|
GetFocusID: (...any) -> ...any,
|
||||||
GetFont: () -> any,
|
GetFont: () -> any,
|
||||||
|
GetFontBaked: () -> any,
|
||||||
GetFontSize: () -> number,
|
GetFontSize: () -> number,
|
||||||
GetFontTexUvWhitePixel: () -> ImVec2,
|
GetFontTexUvWhitePixel: () -> ImVec2,
|
||||||
GetForegroundDrawList: (viewport: any) -> ...any,
|
GetForegroundDrawList: (viewport: any) -> ...any,
|
||||||
@@ -315,6 +352,7 @@ export type ImGuiAPI = {
|
|||||||
GetItemRectMax: () -> ImVec2,
|
GetItemRectMax: () -> ImVec2,
|
||||||
GetItemRectMin: () -> ImVec2,
|
GetItemRectMin: () -> ImVec2,
|
||||||
GetItemRectSize: () -> ImVec2,
|
GetItemRectSize: () -> ImVec2,
|
||||||
|
GetItemStatusFlags: (...any) -> ...any,
|
||||||
GetKeyChordName: (...any) -> ...any,
|
GetKeyChordName: (...any) -> ...any,
|
||||||
GetKeyData: (...any) -> ...any,
|
GetKeyData: (...any) -> ...any,
|
||||||
GetKeyMagnitude2d: (...any) -> ...any,
|
GetKeyMagnitude2d: (...any) -> ...any,
|
||||||
@@ -331,7 +369,9 @@ export type ImGuiAPI = {
|
|||||||
GetMouseDragDelta: (button: number?, lock_threshold: number?) -> ImVec2,
|
GetMouseDragDelta: (button: number?, lock_threshold: number?) -> ImVec2,
|
||||||
GetMousePos: () -> ImVec2,
|
GetMousePos: () -> ImVec2,
|
||||||
GetMousePosOnOpeningCurrentPopup: () -> ImVec2,
|
GetMousePosOnOpeningCurrentPopup: () -> ImVec2,
|
||||||
|
GetMultiSelectState: (...any) -> ...any,
|
||||||
GetNavTweakPressedAmount: (...any) -> ...any,
|
GetNavTweakPressedAmount: (...any) -> ...any,
|
||||||
|
GetPixelDensity: (...any) -> ...any,
|
||||||
GetPlatformIO: () -> any,
|
GetPlatformIO: () -> any,
|
||||||
GetPopupAllowedExtentRect: (...any) -> ...any,
|
GetPopupAllowedExtentRect: (...any) -> ...any,
|
||||||
GetRoundedFontSize: (...any) -> ...any,
|
GetRoundedFontSize: (...any) -> ...any,
|
||||||
@@ -353,6 +393,7 @@ export type ImGuiAPI = {
|
|||||||
GetTopMostPopupModal: (...any) -> ...any,
|
GetTopMostPopupModal: (...any) -> ...any,
|
||||||
GetTreeNodeToLabelSpacing: () -> number,
|
GetTreeNodeToLabelSpacing: () -> number,
|
||||||
GetTypematicRepeatRate: (...any) -> ...any,
|
GetTypematicRepeatRate: (...any) -> ...any,
|
||||||
|
GetTypingSelectRequest: (...any) -> ...any,
|
||||||
GetVersion: () -> any,
|
GetVersion: () -> any,
|
||||||
GetViewportPlatformMonitor: (...any) -> ...any,
|
GetViewportPlatformMonitor: (...any) -> ...any,
|
||||||
GetWindowAlwaysWantOwnTabBar: (...any) -> ...any,
|
GetWindowAlwaysWantOwnTabBar: (...any) -> ...any,
|
||||||
@@ -360,10 +401,13 @@ export type ImGuiAPI = {
|
|||||||
GetWindowContentRegionMax: (...any) -> ...any,
|
GetWindowContentRegionMax: (...any) -> ...any,
|
||||||
GetWindowContentRegionMin: (...any) -> ...any,
|
GetWindowContentRegionMin: (...any) -> ...any,
|
||||||
GetWindowDockID: () -> number,
|
GetWindowDockID: () -> number,
|
||||||
|
GetWindowDockNode: (...any) -> ...any,
|
||||||
GetWindowDpiScale: () -> number,
|
GetWindowDpiScale: () -> number,
|
||||||
GetWindowDrawList: () -> any,
|
GetWindowDrawList: () -> any,
|
||||||
GetWindowHeight: () -> number,
|
GetWindowHeight: () -> number,
|
||||||
GetWindowPos: () -> ImVec2,
|
GetWindowPos: () -> ImVec2,
|
||||||
|
GetWindowResizeBorderID: (...any) -> ...any,
|
||||||
|
GetWindowResizeCornerID: (...any) -> ...any,
|
||||||
GetWindowScrollbarID: (...any) -> ...any,
|
GetWindowScrollbarID: (...any) -> ...any,
|
||||||
GetWindowScrollbarRect: (...any) -> ...any,
|
GetWindowScrollbarRect: (...any) -> ...any,
|
||||||
GetWindowSize: () -> ImVec2,
|
GetWindowSize: () -> ImVec2,
|
||||||
@@ -405,6 +449,7 @@ export type ImGuiAPI = {
|
|||||||
IsInNavFocusRoute: (...any) -> ...any,
|
IsInNavFocusRoute: (...any) -> ...any,
|
||||||
IsItemActivated: () -> boolean,
|
IsItemActivated: () -> boolean,
|
||||||
IsItemActive: () -> boolean,
|
IsItemActive: () -> boolean,
|
||||||
|
IsItemActiveAsInputText: (...any) -> ...any,
|
||||||
IsItemClicked: (mouse_button: number?) -> boolean,
|
IsItemClicked: (mouse_button: number?) -> boolean,
|
||||||
IsItemDeactivated: () -> boolean,
|
IsItemDeactivated: () -> boolean,
|
||||||
IsItemDeactivatedAfterEdit: () -> boolean,
|
IsItemDeactivatedAfterEdit: () -> boolean,
|
||||||
@@ -421,6 +466,7 @@ export type ImGuiAPI = {
|
|||||||
IsKeyReleased: (...any) -> ...any,
|
IsKeyReleased: (...any) -> ...any,
|
||||||
IsKeyboardKey: (...any) -> ...any,
|
IsKeyboardKey: (...any) -> ...any,
|
||||||
IsLRModKey: (...any) -> ...any,
|
IsLRModKey: (...any) -> ...any,
|
||||||
|
IsLegacyKey: (...any) -> ...any,
|
||||||
IsMouseClicked: (button: number, is_repeat: boolean?) -> boolean,
|
IsMouseClicked: (button: number, is_repeat: boolean?) -> boolean,
|
||||||
IsMouseClickedEx: (...any) -> ...any,
|
IsMouseClickedEx: (...any) -> ...any,
|
||||||
IsMouseDoubleClicked: (...any) -> ...any,
|
IsMouseDoubleClicked: (...any) -> ...any,
|
||||||
@@ -479,6 +525,10 @@ export type ImGuiAPI = {
|
|||||||
MenuItem: (...any) -> ...any,
|
MenuItem: (...any) -> ...any,
|
||||||
MenuItemEx: (...any) -> ...any,
|
MenuItemEx: (...any) -> ...any,
|
||||||
MouseButtonToKey: (...any) -> ...any,
|
MouseButtonToKey: (...any) -> ...any,
|
||||||
|
MultiSelectAddSetAll: (...any) -> ...any,
|
||||||
|
MultiSelectAddSetRange: (...any) -> ...any,
|
||||||
|
MultiSelectItemFooter: (...any) -> ...any,
|
||||||
|
MultiSelectItemHeader: (...any) -> ...any,
|
||||||
NavApplyItemToResult: (...any) -> ...any,
|
NavApplyItemToResult: (...any) -> ...any,
|
||||||
NavBiasScoringRect: (...any) -> ...any,
|
NavBiasScoringRect: (...any) -> ...any,
|
||||||
NavCalcPreferredRefPos: (...any) -> ...any,
|
NavCalcPreferredRefPos: (...any) -> ...any,
|
||||||
@@ -556,6 +606,8 @@ export type ImGuiAPI = {
|
|||||||
RadioButton: (...any) -> ...any,
|
RadioButton: (...any) -> ...any,
|
||||||
RadioButtonEx: (...any) -> ...any,
|
RadioButtonEx: (...any) -> ...any,
|
||||||
RegisterFontAtlas: (...any) -> ...any,
|
RegisterFontAtlas: (...any) -> ...any,
|
||||||
|
RegisterUserTexture: (...any) -> ...any,
|
||||||
|
RemoveContextHook: (...any) -> ...any,
|
||||||
RemoveSettingsHandler: (...any) -> ...any,
|
RemoveSettingsHandler: (...any) -> ...any,
|
||||||
Render: () -> (),
|
Render: () -> (),
|
||||||
RenderArrow: (...any) -> ...any,
|
RenderArrow: (...any) -> ...any,
|
||||||
@@ -591,6 +643,7 @@ export type ImGuiAPI = {
|
|||||||
ScaleRatioFromValueT: (...any) -> ...any,
|
ScaleRatioFromValueT: (...any) -> ...any,
|
||||||
ScaleValueFromRatioT: (...any) -> ...any,
|
ScaleValueFromRatioT: (...any) -> ...any,
|
||||||
ScaleWindowsInViewport: (...any) -> ...any,
|
ScaleWindowsInViewport: (...any) -> ...any,
|
||||||
|
ScrollToBringRectIntoView: (...any) -> ...any,
|
||||||
ScrollToItem: (...any) -> ...any,
|
ScrollToItem: (...any) -> ...any,
|
||||||
ScrollToRect: (...any) -> ...any,
|
ScrollToRect: (...any) -> ...any,
|
||||||
ScrollToRectEx: (...any) -> ...any,
|
ScrollToRectEx: (...any) -> ...any,
|
||||||
@@ -608,6 +661,7 @@ export type ImGuiAPI = {
|
|||||||
SetColorEditOptions: (...any) -> ...any,
|
SetColorEditOptions: (...any) -> ...any,
|
||||||
SetColumnOffset: (column_index: number, offset: number) -> (),
|
SetColumnOffset: (column_index: number, offset: number) -> (),
|
||||||
SetColumnWidth: (column_index: number, width: number) -> (),
|
SetColumnWidth: (column_index: number, width: number) -> (),
|
||||||
|
SetContextName: (...any) -> ...any,
|
||||||
SetCurrentContext: (ctx: any) -> ...any,
|
SetCurrentContext: (ctx: any) -> ...any,
|
||||||
SetCurrentFont: (...any) -> ...any,
|
SetCurrentFont: (...any) -> ...any,
|
||||||
SetCurrentViewport: (...any) -> ...any,
|
SetCurrentViewport: (...any) -> ...any,
|
||||||
@@ -621,6 +675,7 @@ export type ImGuiAPI = {
|
|||||||
SetItemDefaultFocus: () -> (),
|
SetItemDefaultFocus: () -> (),
|
||||||
SetItemKeyOwner: (...any) -> ...any,
|
SetItemKeyOwner: (...any) -> ...any,
|
||||||
SetItemTooltip: (fmt: string, ...any) -> (),
|
SetItemTooltip: (fmt: string, ...any) -> (),
|
||||||
|
SetItemTooltipV: (fmt: string, ...any) -> (),
|
||||||
SetKeyOwner: (...any) -> ...any,
|
SetKeyOwner: (...any) -> ...any,
|
||||||
SetKeyOwnersForKeyChord: (...any) -> ...any,
|
SetKeyOwnersForKeyChord: (...any) -> ...any,
|
||||||
SetKeyboardFocusHere: (offset: number?) -> (),
|
SetKeyboardFocusHere: (offset: number?) -> (),
|
||||||
@@ -639,6 +694,7 @@ export type ImGuiAPI = {
|
|||||||
SetNextItemColorMarker: (...any) -> ...any,
|
SetNextItemColorMarker: (...any) -> ...any,
|
||||||
SetNextItemOpen: (is_open: boolean, cond: number?) -> (),
|
SetNextItemOpen: (is_open: boolean, cond: number?) -> (),
|
||||||
SetNextItemRefVal: (...any) -> ...any,
|
SetNextItemRefVal: (...any) -> ...any,
|
||||||
|
SetNextItemSelectionUserData: (selection_user_data: any) -> (),
|
||||||
SetNextItemShortcut: (key_chord: any, flags: number?) -> (),
|
SetNextItemShortcut: (key_chord: any, flags: number?) -> (),
|
||||||
SetNextItemStorageID: (storage_id: number) -> (),
|
SetNextItemStorageID: (storage_id: number) -> (),
|
||||||
SetNextItemWidth: (item_width: number) -> (),
|
SetNextItemWidth: (item_width: number) -> (),
|
||||||
@@ -657,6 +713,7 @@ export type ImGuiAPI = {
|
|||||||
SetNextWindowSize: (size: ImVec2, cond: number?) -> (),
|
SetNextWindowSize: (size: ImVec2, cond: number?) -> (),
|
||||||
SetNextWindowSizeConstraints: (size_min: ImVec2, size_max: ImVec2, custom_callback: any, custom_callback_user_data: any) -> ...any,
|
SetNextWindowSizeConstraints: (size_min: ImVec2, size_max: ImVec2, custom_callback: any, custom_callback_user_data: any) -> ...any,
|
||||||
SetNextWindowViewport: (id: number) -> (),
|
SetNextWindowViewport: (id: number) -> (),
|
||||||
|
SetPixelDensity: (...any) -> ...any,
|
||||||
SetScrollFromPosX: (...any) -> ...any,
|
SetScrollFromPosX: (...any) -> ...any,
|
||||||
SetScrollFromPosY: (...any) -> ...any,
|
SetScrollFromPosY: (...any) -> ...any,
|
||||||
SetScrollHereX: (center_x_ratio: number?) -> (),
|
SetScrollHereX: (center_x_ratio: number?) -> (),
|
||||||
@@ -667,6 +724,7 @@ export type ImGuiAPI = {
|
|||||||
SetStateStorage: (tree: any) -> ...any,
|
SetStateStorage: (tree: any) -> ...any,
|
||||||
SetTabItemClosed: (label: string) -> (),
|
SetTabItemClosed: (label: string) -> (),
|
||||||
SetTooltip: (fmt: string, ...any) -> (),
|
SetTooltip: (fmt: string, ...any) -> (),
|
||||||
|
SetTooltipV: (fmt: string, ...any) -> (),
|
||||||
SetWindowClipRectBeforeSetChannel: (...any) -> ...any,
|
SetWindowClipRectBeforeSetChannel: (...any) -> ...any,
|
||||||
SetWindowCollapsed: (...any) -> ...any,
|
SetWindowCollapsed: (...any) -> ...any,
|
||||||
SetWindowDock: (...any) -> ...any,
|
SetWindowDock: (...any) -> ...any,
|
||||||
@@ -674,6 +732,7 @@ export type ImGuiAPI = {
|
|||||||
SetWindowFontScale: (...any) -> ...any,
|
SetWindowFontScale: (...any) -> ...any,
|
||||||
SetWindowHiddenAndSkipItemsForCurrentFrame: (...any) -> ...any,
|
SetWindowHiddenAndSkipItemsForCurrentFrame: (...any) -> ...any,
|
||||||
SetWindowHitTestHole: (...any) -> ...any,
|
SetWindowHitTestHole: (...any) -> ...any,
|
||||||
|
SetWindowParentWindowForFocusRoute: (...any) -> ...any,
|
||||||
SetWindowPos: (...any) -> ...any,
|
SetWindowPos: (...any) -> ...any,
|
||||||
SetWindowSize: (...any) -> ...any,
|
SetWindowSize: (...any) -> ...any,
|
||||||
SetWindowViewport: (...any) -> ...any,
|
SetWindowViewport: (...any) -> ...any,
|
||||||
@@ -822,6 +881,7 @@ export type ImGuiAPI = {
|
|||||||
TempInputScalar: (...any) -> ...any,
|
TempInputScalar: (...any) -> ...any,
|
||||||
TempInputText: (...any) -> ...any,
|
TempInputText: (...any) -> ...any,
|
||||||
TestKeyOwner: (...any) -> ...any,
|
TestKeyOwner: (...any) -> ...any,
|
||||||
|
TestShortcutRouting: (...any) -> ...any,
|
||||||
Text: (fmt: string, ...any) -> (),
|
Text: (fmt: string, ...any) -> (),
|
||||||
TextAligned: (...any) -> ...any,
|
TextAligned: (...any) -> ...any,
|
||||||
TextBufferToString: (buf: {number}) -> string,
|
TextBufferToString: (buf: {number}) -> string,
|
||||||
@@ -848,11 +908,17 @@ export type ImGuiAPI = {
|
|||||||
TreePop: () -> (),
|
TreePop: () -> (),
|
||||||
TreePush: (...any) -> ...any,
|
TreePush: (...any) -> ...any,
|
||||||
TreePushOverrideID: (...any) -> ...any,
|
TreePushOverrideID: (...any) -> ...any,
|
||||||
|
TypingSelectFindBestLeadingMatch: (...any) -> ...any,
|
||||||
|
TypingSelectFindMatch: (...any) -> ...any,
|
||||||
|
TypingSelectFindNextSingleCharMatch: (...any) -> ...any,
|
||||||
Unindent: (indent_w: number?) -> (),
|
Unindent: (indent_w: number?) -> (),
|
||||||
UnregisterFontAtlas: (...any) -> ...any,
|
UnregisterFontAtlas: (...any) -> ...any,
|
||||||
|
UnregisterUserTexture: (...any) -> ...any,
|
||||||
UpdateAliasKey: (...any) -> ...any,
|
UpdateAliasKey: (...any) -> ...any,
|
||||||
UpdateCurrentFontSize: (...any) -> ...any,
|
UpdateCurrentFontSize: (...any) -> ...any,
|
||||||
|
UpdateDebugToolFlashStyleColor: (...any) -> ...any,
|
||||||
UpdateDebugToolItemPathQuery: (...any) -> ...any,
|
UpdateDebugToolItemPathQuery: (...any) -> ...any,
|
||||||
|
UpdateDebugToolItemPicker: (...any) -> ...any,
|
||||||
UpdateFontsEndFrame: (...any) -> ...any,
|
UpdateFontsEndFrame: (...any) -> ...any,
|
||||||
UpdateFontsNewFrame: (...any) -> ...any,
|
UpdateFontsNewFrame: (...any) -> ...any,
|
||||||
UpdateHoveredWindowAndCaptureFlags: (...any) -> ...any,
|
UpdateHoveredWindowAndCaptureFlags: (...any) -> ...any,
|
||||||
@@ -880,20 +946,22 @@ export type ImGuiAPI = {
|
|||||||
VSliderScalar: (label: string, size: ImVec2, data_type: number, data: any, min: any, max: any, format: string?, flags: number?) -> ...any,
|
VSliderScalar: (label: string, size: ImVec2, data_type: number, data: any, min: any, max: any, format: string?, flags: number?) -> ...any,
|
||||||
Value: (...any) -> ...any,
|
Value: (...any) -> ...any,
|
||||||
WindowPosAbsToRel: (...any) -> ...any,
|
WindowPosAbsToRel: (...any) -> ...any,
|
||||||
|
WindowPosRelToAbs: (...any) -> ...any,
|
||||||
WindowRectAbsToRel: (...any) -> ...any,
|
WindowRectAbsToRel: (...any) -> ...any,
|
||||||
WindowRectRelToAbs: (...any) -> ...any,
|
WindowRectRelToAbs: (...any) -> ...any,
|
||||||
WindowSelectViewport: (...any) -> ...any,
|
WindowSelectViewport: (...any) -> ...any,
|
||||||
WindowSettingsAddSettingsHandler: (...any) -> ...any,
|
WindowSettingsAddSettingsHandler: (...any) -> ...any,
|
||||||
WindowSyncOwnedViewport: (...any) -> ...any,
|
WindowSyncOwnedViewport: (...any) -> ...any,
|
||||||
_ByteArrayToString: (...any) -> ...any,
|
_ByteArrayToString: (...any) -> ...any,
|
||||||
|
_CalcItemSizeXY: (...any) -> ...any,
|
||||||
_GetTypeFunc: (...any) -> ...any,
|
_GetTypeFunc: (...any) -> ...any,
|
||||||
_SetCurrentContext_Internal: (...any) -> ...any,
|
_SetCurrentContext_Internal: (...any) -> ...any,
|
||||||
_SetCurrentContext_Tables: (...any) -> ...any,
|
_SetCurrentContext_Tables: (...any) -> ...any,
|
||||||
_SetCurrentContext_Widgets: (...any) -> ...any,
|
_SetCurrentContext_Widgets: (...any) -> ...any,
|
||||||
[string]: any,
|
[string]: any,
|
||||||
}
|
}
|
||||||
export type ImDrawFlags = { None: number, RoundCornersTopLeft: number, RoundCornersTopRight: number, RoundCornersBottomLeft: number, RoundCornersBottomRight: number, RoundCornersNone: number, Closed: number, RoundCornersTop: number, RoundCornersBottom: number, RoundCornersLeft: number, RoundCornersRight: number, RoundCornersAll: number, RoundCornersDefault_: number, RoundCornersMask_: number, InvalidMask_: number, [string]: number }
|
export type ImDrawFlags = { None: number, RoundTopLeft: number, RoundTopRight: number, RoundBottomLeft: number, RoundBottomRight: number, RoundNone: number, Closed: number, JoinMiter: number, CapSquare: number, AAFill: number, AALines: number, AALineEnds: number, StrokeInside: number, StrokeCenter: number, StrokeCenterBiased: number, StrokeOutside: number, StrokeLegacy: number, TextNoPixelSnap: number, UseTexForRoundCorners: number, UseVtxOffset: number, AllowTexForRoundCorners_: number, RoundAll: number, RoundTop: number, RoundBottom: number, RoundLeft: number, RoundRight: number, RoundMask_: number, AllowInPushScope_: number, AllowInFrameScope_: number, StrokeMask_: number, InvalidMask_: number, RoundCornersTopLeft: number, RoundCornersTopRight: number, RoundCornersBottomLeft: number, RoundCornersBottomRight: number, RoundCornersNone: number, RoundCornersAll: number, RoundCornersTop: number, RoundCornersBottom: number, RoundCornersLeft: number, RoundCornersRight: number, [string]: number }
|
||||||
export type ImDrawListFlags = { None: number, AntiAliasedLines: number, AntiAliasedLinesUseTex: number, AntiAliasedFill: number, AllowVtxOffset: number, TextNoPixelSnap: number, [string]: number }
|
export type ImDrawListFlags = { None: number, AntiAliasedFill: number, AntiAliasedLines: number, AntiAliasedLinesUseTex: number, AllowVtxOffset: number, TextNoPixelSnap: number, [string]: number }
|
||||||
export type ImFontFlags = { None: number, NoLoadError: number, NoLoadGlyphs: number, LockBakedSizes: number, ImplicitRefSize: number, [string]: number }
|
export type ImFontFlags = { None: number, NoLoadError: number, NoLoadGlyphs: number, LockBakedSizes: number, ImplicitRefSize: number, [string]: number }
|
||||||
export type ImGuiBackendFlags = { None: number, HasGamepad: number, HasMouseCursors: number, HasSetMousePos: number, RendererHasVtxOffset: number, RendererHasTextures: number, RendererHasViewports: number, PlatformHasViewports: number, HasMouseHoveredViewport: number, HasParentViewport: number, [string]: number }
|
export type ImGuiBackendFlags = { None: number, HasGamepad: number, HasMouseCursors: number, HasSetMousePos: number, RendererHasVtxOffset: number, RendererHasTextures: number, RendererHasViewports: number, PlatformHasViewports: number, HasMouseHoveredViewport: number, HasParentViewport: number, [string]: number }
|
||||||
export type ImGuiButtonFlags = { None: number, MouseButtonLeft: number, MouseButtonRight: number, MouseButtonMiddle: number, EnableNav: number, PressedOnClick: number, PressedOnClickRelease: number, PressedOnClickReleaseAnywhere: number, PressedOnRelease: number, PressedOnDoubleClick: number, PressedOnDragDropHold: number, FlattenChildren: number, AllowOverlap: number, AlignTextBaseLine: number, NoKeyModsAllowed: number, NoHoldingActiveId: number, NoNavFocus: number, NoHoveredOnFocus: number, NoSetKeyOwner: number, NoTestKeyOwner: number, NoFocus: number, MouseButtonMask_: number, PressedOnMask_: number, PressedOnDefault_: number, NoKeyModifiers: number, [string]: number }
|
export type ImGuiButtonFlags = { None: number, MouseButtonLeft: number, MouseButtonRight: number, MouseButtonMiddle: number, EnableNav: number, PressedOnClick: number, PressedOnClickRelease: number, PressedOnClickReleaseAnywhere: number, PressedOnRelease: number, PressedOnDoubleClick: number, PressedOnDragDropHold: number, FlattenChildren: number, AllowOverlap: number, AlignTextBaseLine: number, NoKeyModsAllowed: number, NoHoldingActiveId: number, NoNavFocus: number, NoHoveredOnFocus: number, NoSetKeyOwner: number, NoTestKeyOwner: number, NoFocus: number, MouseButtonMask_: number, PressedOnMask_: number, PressedOnDefault_: number, NoKeyModifiers: number, [string]: number }
|
||||||
@@ -911,12 +979,15 @@ export type ImGuiInputTextFlags = { None: number, CharsDecimal: number, CharsHex
|
|||||||
export type ImGuiItemFlags = { None: number, NoTabStop: number, NoNav: number, NoNavDefaultFocus: number, ButtonRepeat: number, AutoClosePopups: number, AllowDuplicateId: number, Disabled: number, LiveEditOnInputText: number, LiveEditOnInputScalar: number, LiveEditOnInput: number, ReadOnly: number, MixedValue: number, NoWindowHoverableCheck: number, AllowOverlap: number, NoNavDisableMouseHover: number, NoMarkEdited: number, NoFocus: number, Inputable: number, HasSelectionUserData: number, IsMultiSelect: number, Default_: number, [string]: number }
|
export type ImGuiItemFlags = { None: number, NoTabStop: number, NoNav: number, NoNavDefaultFocus: number, ButtonRepeat: number, AutoClosePopups: number, AllowDuplicateId: number, Disabled: number, LiveEditOnInputText: number, LiveEditOnInputScalar: number, LiveEditOnInput: number, ReadOnly: number, MixedValue: number, NoWindowHoverableCheck: number, AllowOverlap: number, NoNavDisableMouseHover: number, NoMarkEdited: number, NoFocus: number, Inputable: number, HasSelectionUserData: number, IsMultiSelect: number, Default_: number, [string]: number }
|
||||||
export type ImGuiItemStatusFlags = { None: number, HoveredRect: number, HasDisplayRect: number, Edited: number, ToggledSelection: number, ToggledOpen: number, HasDeactivated: number, Deactivated: number, HoveredWindow: number, Visible: number, HasClipRect: number, HasShortcut: number, EditedInternal: number, [string]: number }
|
export type ImGuiItemStatusFlags = { None: number, HoveredRect: number, HasDisplayRect: number, Edited: number, ToggledSelection: number, ToggledOpen: number, HasDeactivated: number, Deactivated: number, HoveredWindow: number, Visible: number, HasClipRect: number, HasShortcut: number, EditedInternal: number, [string]: number }
|
||||||
export type ImGuiKey = { None: number, NamedKey_BEGIN: number, Tab: number, LeftArrow: number, RightArrow: number, UpArrow: number, DownArrow: number, PageUp: number, PageDown: number, Home: number, End: number, Insert: number, Delete: number, Backspace: number, Space: number, Enter: number, Escape: number, LeftCtrl: number, RightCtrl: number, Menu: number, K0: number, A: number, K: number, U: number, F1: number, F7: number, F13: number, F19: number, Apostrophe: number, CapsLock: number, Keypad0: number, KeypadDecimal: number, AppBack: number, AppForward: number, Oem102: number, GamepadStart: number, GamepadFaceLeft: number, GamepadDpadLeft: number, GamepadL1: number, GamepadL2: number, GamepadL3: number, GamepadLStickLeft: number, GamepadRStickLeft: number, MouseLeft: number, ReservedForModCtrl: number, NamedKey_END: number, NamedKey_COUNT: number, NavKeyboardTweakSlow: number, NavKeyboardTweakFast: number, NavGamepadTweakSlow: number, NavGamepadTweakFast: number, NavGamepadMenu: number, NavGamepadContextMenu: number, [string]: number }
|
export type ImGuiKey = { None: number, NamedKey_BEGIN: number, Tab: number, LeftArrow: number, RightArrow: number, UpArrow: number, DownArrow: number, PageUp: number, PageDown: number, Home: number, End: number, Insert: number, Delete: number, Backspace: number, Space: number, Enter: number, Escape: number, LeftCtrl: number, RightCtrl: number, Menu: number, K0: number, A: number, K: number, U: number, F1: number, F7: number, F13: number, F19: number, Apostrophe: number, CapsLock: number, Keypad0: number, KeypadDecimal: number, AppBack: number, AppForward: number, Oem102: number, GamepadStart: number, GamepadFaceLeft: number, GamepadDpadLeft: number, GamepadL1: number, GamepadL2: number, GamepadL3: number, GamepadLStickLeft: number, GamepadRStickLeft: number, MouseLeft: number, ReservedForModCtrl: number, NamedKey_END: number, NamedKey_COUNT: number, NavKeyboardTweakSlow: number, NavKeyboardTweakFast: number, NavGamepadTweakSlow: number, NavGamepadTweakFast: number, NavGamepadMenu: number, NavGamepadContextMenu: number, [string]: number }
|
||||||
|
export type ImGuiListClipperFlags = { None: number, NoSetTableRowCounters: number, [string]: number }
|
||||||
export type ImGuiMouseSource = { Mouse: number, TouchScreen: number, Pen: number, COUNT: number, [string]: number }
|
export type ImGuiMouseSource = { Mouse: number, TouchScreen: number, Pen: number, COUNT: number, [string]: number }
|
||||||
|
export type ImGuiMultiSelectFlags = { None: number, SingleSelect: number, NoSelectAll: number, NoRangeSelect: number, NoAutoSelect: number, NoAutoClear: number, NoAutoClearOnReselect: number, BoxSelect1d: number, BoxSelect2d: number, BoxSelectNoScroll: number, ClearOnEscape: number, ClearOnClickVoid: number, ScopeWindow: number, ScopeRect: number, SelectOnAuto: number, SelectOnClickAlways: number, SelectOnClickRelease: number, NavWrapX: number, NoSelectOnRightClick: number, CheckboxMode_: number, SelectOnMask_: number, SelectOnClick: number, [string]: number }
|
||||||
export type ImGuiNextItemDataFlags = { None: number, HasWidth: number, HasOpen: number, HasShortcut: number, HasRefVal: number, HasStorageID: number, HasColorMarker: number, [string]: number }
|
export type ImGuiNextItemDataFlags = { None: number, HasWidth: number, HasOpen: number, HasShortcut: number, HasRefVal: number, HasStorageID: number, HasColorMarker: number, [string]: number }
|
||||||
export type ImGuiPopupFlags = { None: number, MouseButtonLeft: number, MouseButtonRight: number, MouseButtonMiddle: number, NoReopen: number, NoOpenOverExistingPopup: number, NoOpenOverItems: number, AnyPopupId: number, AnyPopupLevel: number, AnyPopup: number, MouseButtonShift_: number, MouseButtonMask_: number, InvalidMask_: number, [string]: number }
|
export type ImGuiPopupFlags = { None: number, MouseButtonLeft: number, MouseButtonRight: number, MouseButtonMiddle: number, NoReopen: number, NoOpenOverExistingPopup: number, NoOpenOverItems: number, AnyPopupId: number, AnyPopupLevel: number, AnyPopup: number, MouseButtonShift_: number, MouseButtonMask_: number, InvalidMask_: number, [string]: number }
|
||||||
export type ImGuiSelectableFlags = { None: number, NoAutoClosePopups: number, SpanAllColumns: number, AllowDoubleClick: number, Disabled: number, AllowOverlap: number, Highlight: number, SelectOnNav: number, NoHoldingActiveID: number, SelectOnClick: number, SelectOnRelease: number, SpanAvailWidth: number, SetNavIdOnHover: number, NoPadWithHalfSpacing: number, NoSetKeyOwner: number, [string]: number }
|
export type ImGuiSelectableFlags = { None: number, NoAutoClosePopups: number, SpanAllColumns: number, AllowDoubleClick: number, Disabled: number, AllowOverlap: number, Highlight: number, SelectOnNav: number, NoHoldingActiveID: number, SelectOnClick: number, SelectOnRelease: number, SpanAvailWidth: number, SetNavIdOnHover: number, NoPadWithHalfSpacing: number, NoSetKeyOwner: number, [string]: number }
|
||||||
|
export type ImGuiSelectionRequestType = { None: number, SetAll: number, SetRange: number, [string]: number }
|
||||||
export type ImGuiSliderFlags = { None: number, Logarithmic: number, NoRoundToFormat: number, NoInput: number, WrapAround: number, ClampOnInput: number, ClampZeroRange: number, NoSpeedTweaks: number, ColorMarkers: number, InvalidMask_: number, AlwaysClamp: number, Vertical: number, ReadOnly: number, [string]: number }
|
export type ImGuiSliderFlags = { None: number, Logarithmic: number, NoRoundToFormat: number, NoInput: number, WrapAround: number, ClampOnInput: number, ClampZeroRange: number, NoSpeedTweaks: number, ColorMarkers: number, InvalidMask_: number, AlwaysClamp: number, Vertical: number, ReadOnly: number, [string]: number }
|
||||||
export type ImGuiStyleVar = { Alpha: number, DisabledAlpha: number, WindowPadding: number, WindowRounding: number, WindowBorderSize: number, WindowMinSize: number, WindowTitleAlign: number, ChildRounding: number, ChildBorderSize: number, PopupRounding: number, PopupBorderSize: number, FramePadding: number, FrameRounding: number, FrameBorderSize: number, ItemSpacing: number, ItemInnerSpacing: number, IndentSpacing: number, CellPadding: number, ScrollbarSize: number, ScrollbarRounding: number, ScrollbarPadding: number, GrabMinSize: number, GrabRounding: number, ImageRounding: number, ImageBorderSize: number, TabRounding: number, TabBorderSize: number, TabMinWidthBase: number, TabMinWidthShrink: number, TabBarBorderSize: number, TabBarOverlineSize: number, TableAngledHeadersAngle: number, TableAngledHeadersTextAlign: number, TreeLinesSize: number, TreeLinesRounding: number, MenuItemRounding: number, SelectableRounding: number, DragDropTargetRounding: number, ButtonTextAlign: number, SelectableTextAlign: number, SeparatorTextBorderSize: number, SeparatorTextAlign: number, SeparatorTextPadding: number, COUNT: number, [string]: number }
|
export type ImGuiStyleVar = { Alpha: number, DisabledAlpha: number, WindowPadding: number, WindowRounding: number, WindowBorderSize: number, WindowMinSize: number, WindowTitleAlign: number, ChildRounding: number, ChildBorderSize: number, PopupRounding: number, PopupBorderSize: number, FramePadding: number, FrameRounding: number, FrameBorderSize: number, ItemSpacing: number, ItemInnerSpacing: number, IndentSpacing: number, CellPadding: number, ScrollbarSize: number, ScrollbarRounding: number, ScrollbarPadding: number, GrabMinSize: number, GrabRounding: number, ImageRounding: number, ImageBorderSize: number, TabRounding: number, TabBorderSize: number, TabMinWidthBase: number, TabMinWidthShrink: number, TabBarBorderSize: number, TabBarOverlineSize: number, TableAngledHeadersAngle: number, TableAngledHeadersTextAlign: number, TreeLinesSize: number, TreeLinesRounding: number, MenuItemRounding: number, SelectableRounding: number, DragDropTargetRounding: number, ButtonTextAlign: number, SelectableTextAlign: number, SeparatorSize: number, SeparatorTextBorderSize: number, SeparatorTextAlign: number, SeparatorTextPadding: number, DockingSeparatorSize: number, COUNT: number, [string]: number }
|
||||||
export type ImGuiTreeNodeFlags = { None: number, Selected: number, Framed: number, AllowOverlap: number, NoTreePushOnOpen: number, NoAutoOpenOnLog: number, DefaultOpen: number, OpenOnDoubleClick: number, OpenOnArrow: number, Leaf: number, Bullet: number, FramePadding: number, SpanAvailWidth: number, SpanFullWidth: number, SpanLabelWidth: number, SpanAllColumns: number, LabelSpanAllColumns: number, NavLeftJumpsToParent: number, DrawLinesNone: number, DrawLinesFull: number, DrawLinesToNodes: number, NoNavFocus: number, ClipLabelForTrailingButton: number, UpsideDownArrow: number, CollapsingHeader: number, OpenOnMask_: number, DrawLinesMask_: number, [string]: number }
|
export type ImGuiTreeNodeFlags = { None: number, Selected: number, Framed: number, AllowOverlap: number, NoTreePushOnOpen: number, NoAutoOpenOnLog: number, DefaultOpen: number, OpenOnDoubleClick: number, OpenOnArrow: number, Leaf: number, Bullet: number, FramePadding: number, SpanAvailWidth: number, SpanFullWidth: number, SpanLabelWidth: number, SpanAllColumns: number, LabelSpanAllColumns: number, NavLeftJumpsToParent: number, DrawLinesNone: number, DrawLinesFull: number, DrawLinesToNodes: number, NoNavFocus: number, ClipLabelForTrailingButton: number, UpsideDownArrow: number, CollapsingHeader: number, OpenOnMask_: number, DrawLinesMask_: number, [string]: number }
|
||||||
export type ImGuiViewportFlags = { None: number, IsPlatformWindow: number, IsPlatformMonitor: number, OwnedByApp: number, NoDecoration: number, NoTaskBarIcon: number, NoFocusOnAppearing: number, NoFocusOnClick: number, NoInputs: number, NoRendererClear: number, NoAutoMerge: number, TopMost: number, CanHostOtherWindows: number, IsMinimized: number, IsFocused: number, [string]: number }
|
export type ImGuiViewportFlags = { None: number, IsPlatformWindow: number, IsPlatformMonitor: number, OwnedByApp: number, NoDecoration: number, NoTaskBarIcon: number, NoFocusOnAppearing: number, NoFocusOnClick: number, NoInputs: number, NoRendererClear: number, NoAutoMerge: number, TopMost: number, CanHostOtherWindows: number, IsMinimized: number, IsFocused: number, [string]: number }
|
||||||
export type ImGuiWindowFlags = { None: number, NoTitleBar: number, NoResize: number, NoMove: number, NoScrollbar: number, NoScrollWithMouse: number, NoCollapse: number, AlwaysAutoResize: number, NoBackground: number, NoSavedSettings: number, NoMouseInputs: number, MenuBar: number, HorizontalScrollbar: number, NoFocusOnAppearing: number, NoBringToFrontOnFocus: number, AlwaysVerticalScrollbar: number, AlwaysHorizontalScrollbar: number, NoNavInputs: number, NoNavFocus: number, UnsavedDocument: number, NoDocking: number, DockNodeHost: number, ChildWindow: number, Tooltip: number, Popup: number, Modal: number, ChildMenu: number, NoNav: number, NoDecoration: number, NoInputs: number, [string]: number }
|
export type ImGuiWindowFlags = { None: number, NoTitleBar: number, NoResize: number, NoMove: number, NoScrollbar: number, NoScrollWithMouse: number, NoCollapse: number, AlwaysAutoResize: number, NoBackground: number, NoSavedSettings: number, NoMouseInputs: number, MenuBar: number, HorizontalScrollbar: number, NoFocusOnAppearing: number, NoBringToFrontOnFocus: number, AlwaysVerticalScrollbar: number, AlwaysHorizontalScrollbar: number, NoNavInputs: number, NoNavFocus: number, UnsavedDocument: number, NoDocking: number, DockNodeHost: number, ChildWindow: number, Tooltip: number, Popup: number, Modal: number, ChildMenu: number, NoNav: number, NoDecoration: number, NoInputs: number, [string]: number }
|
||||||
@@ -943,10 +1014,13 @@ export type ImGuiModule = {
|
|||||||
ImGuiItemFlags: ImGuiItemFlags,
|
ImGuiItemFlags: ImGuiItemFlags,
|
||||||
ImGuiItemStatusFlags: ImGuiItemStatusFlags,
|
ImGuiItemStatusFlags: ImGuiItemStatusFlags,
|
||||||
ImGuiKey: ImGuiKey,
|
ImGuiKey: ImGuiKey,
|
||||||
|
ImGuiListClipperFlags: ImGuiListClipperFlags,
|
||||||
ImGuiMouseSource: ImGuiMouseSource,
|
ImGuiMouseSource: ImGuiMouseSource,
|
||||||
|
ImGuiMultiSelectFlags: ImGuiMultiSelectFlags,
|
||||||
ImGuiNextItemDataFlags: ImGuiNextItemDataFlags,
|
ImGuiNextItemDataFlags: ImGuiNextItemDataFlags,
|
||||||
ImGuiPopupFlags: ImGuiPopupFlags,
|
ImGuiPopupFlags: ImGuiPopupFlags,
|
||||||
ImGuiSelectableFlags: ImGuiSelectableFlags,
|
ImGuiSelectableFlags: ImGuiSelectableFlags,
|
||||||
|
ImGuiSelectionRequestType: ImGuiSelectionRequestType,
|
||||||
ImGuiSliderFlags: ImGuiSliderFlags,
|
ImGuiSliderFlags: ImGuiSliderFlags,
|
||||||
ImGuiStyleVar: ImGuiStyleVar,
|
ImGuiStyleVar: ImGuiStyleVar,
|
||||||
ImGuiTreeNodeFlags: ImGuiTreeNodeFlags,
|
ImGuiTreeNodeFlags: ImGuiTreeNodeFlags,
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[[183, "imgui.lua"], [21526, "imgui_demo.lua"], [29944, "imgui_draw.lua"], [35882, "imgui_h.lua"], [38549, "imgui_impl_love.lua"], [39089, "imgui_internal.lua"], [42558, "imgui_tables.lua"], [47617, "imgui_widgets.lua"], [58257, "imstb_rectpack.lua"], [58921, "imstb_textedit.lua"], [60463, "imstb_truetype.lua"], [63251, "imstd_minstdio.lua"]]
|
[[183, "imgui.lua"], [22812, "imgui_demo.lua"], [34670, "imgui_draw.lua"], [42997, "imgui_h.lua"], [45994, "imgui_impl_love.lua"], [46538, "imgui_internal.lua"], [50510, "imgui_tables.lua"], [55602, "imgui_widgets.lua"], [67836, "imstb_rectpack.lua"], [68500, "imstb_textedit.lua"], [70042, "imstb_truetype.lua"], [72830, "imstd_minstdio.lua"]]
|
||||||
+15797
-6091
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -65,5 +65,5 @@ there, but keep this port's existing data structures and conventions. Read the s
|
|||||||
|
|
||||||
- **ImGuiAxis is 1-based in this port** (`None=0, X=1, Y=2`; upstream `None=-1, X=0, Y=1`). Use `v[axis]` to index an ImVec2 and `3 - axis` for the other axis. `ImGuiDir` keeps upstream values (`None=-1, Left=0, Right=1, Up=2, Down=3`).
|
- **ImGuiAxis is 1-based in this port** (`None=0, X=1, Y=2`; upstream `None=-1, X=0, Y=1`). Use `v[axis]` to index an ImVec2 and `3 - axis` for the other axis. `ImGuiDir` keeps upstream values (`None=-1, Left=0, Right=1, Up=2, Down=3`).
|
||||||
- Never write `cond and nil or x` in Lua: it always evaluates `x`. Use an `if`.
|
- Never write `cond and nil or x` in Lua: it always evaluates `x`. Use an `if`.
|
||||||
- Port signature quirk: `AddRect(min, max, col, rounding, thickness, flags)` (thickness BEFORE flags; upstream has flags first). Check the port's signature before porting any draw call that takes both.\n
|
- Draw calls taking both thickness and flags use upstream's 1.92.8+ order: thickness BEFORE flags, e.g. `AddRect(min, max, col, rounding, thickness, flags)`, `PathStroke(col, thickness, flags)`, `AddPolyline(points, count, col, thickness, flags)`.
|
||||||
- C++ default arguments (e.g. `bool x = true`) must be reproduced with `if x == nil then x = true end`; a missing Lua argument is nil/falsy.
|
- C++ default arguments (e.g. `bool x = true`) must be reproduced with `if x == nil then x = true end`; a missing Lua argument is nil/falsy.
|
||||||
|
|||||||
+1982
-2021
File diff suppressed because it is too large
Load Diff
+19
-38
@@ -1,52 +1,33 @@
|
|||||||
Dear ImGui for Roblox - not yet ported / known gaps
|
Dear ImGui for Roblox - not yet ported / known gaps
|
||||||
====================================================
|
====================================================
|
||||||
Upstream reference: tools/test/upstream/ (ocornut/imgui docking branch, 1.93 WIP).
|
Upstream reference: tools/test/upstream/ (ocornut/imgui docking branch, 1.93 WIP).
|
||||||
Re-check with: python3 tools/test/missing.py [imgui|widgets|tables|draw] and python3 tools/test/undefined.py --no-demo
|
Re-check with: python3 tools/compare_upstream.py (writes docs/PORT_STATUS.txt: [ ] = not ported, [=] = replaced by a
|
||||||
(missing.py also lists names the port defines differently, e.g. the *V printf variants and DragFloat2..4 / DragInt2..4,
|
Lua equivalent, "missing:" = enum values / struct fields) and python3 tools/test/undefined.py --no-demo
|
||||||
which exist as ImGui.DragFloat2 = DragFloatN(2) etc. Those are NOT gaps.)
|
|
||||||
|
|
||||||
|
|
||||||
FEATURES NOT PORTED
|
NOT PORTED / PARTIAL
|
||||||
-------------------
|
--------------------
|
||||||
- Multi-select / box-select: BeginMultiSelect, EndMultiSelect, MultiSelectItemHeader/Footer, MultiSelectAddSetAll,
|
- ImFont::AddRemapCodepointToGlyphIndex / ImGui_ImplStbTrueType_FontSrcGetGlyphIndexFromCodepoint (the port's font
|
||||||
MultiSelectAddSetRange, SetNextItemSelectionUserData, BeginBoxSelect/EndBoxSelect, DebugNodeMultiSelectState.
|
loader still checks glyphs by codepoint; 1.93 split this into codepoint -> glyph index -> glyph).
|
||||||
(Selectable/TreeNode call sites are stubbed with TODOs; the demo "Selection State & Multi-Select" section is not ported.)
|
- ImGui_GetDefaultCompressedFontDataProggyClean/ProggyForever: AddFontFromMemoryCompressedTTF works, but the default
|
||||||
- Typing-select (type to jump in lists): GetTypingSelectRequest, TypingSelectFind*, DebugNodeTypingSelectState.
|
fonts are loaded from fonts/ instead of embedded compressed data.
|
||||||
- Examples > Assets Browser (needs multi-select + box-select).
|
- ImFontAtlasDebugLogTextureRequests, ImHashSkipUncontributingPrefix.
|
||||||
- Metrics > Tools > Item Picker (UpdateDebugToolItemPicker).
|
- DebugLogSkippedErrors / DebugDrawIdConflicts* (error-recovery and ID-conflict debug tools).
|
||||||
- DebugFlashStyleColor / UpdateDebugToolFlashStyleColor (Style Editor "?" flash button).
|
|
||||||
- DebugNodeInputTextState (Metrics > Internal state > InputText).
|
LUA LIMITATIONS
|
||||||
- BringWindowToDisplayBehind: stub, does nothing.
|
---------------
|
||||||
- ColorEdit4 / ColorPicker4: drag & drop target (dropping a color onto a color widget).
|
- ImGuiDataType.S64/U64: values are Luau doubles, exact only within +-2^53 (LLONG_MAX/ULLONG_MAX round up).
|
||||||
- ImFontAtlas:AddFontFromMemoryCompressedTTF: stub (binary_to_compressed_c fonts can't be loaded).
|
- ImDrawList::AddCallback(userdata_size > 0): the "copy" is a shallow copy of a table userdata (no raw bytes).
|
||||||
- ImGuiSizeCallbackData: SetNextWindowSizeConstraints custom callbacks only partially supported
|
|
||||||
(Examples > Constrained Resize).
|
|
||||||
- LogSetNextTextDecoration (Selectable "[ ]" decoration in log/clipboard output).
|
|
||||||
- stb_truetype: cmap high-byte mapping (some CJK fonts assert).
|
|
||||||
- Context hooks removal (RemoveContextHook), SetContextName.
|
|
||||||
- RegisterUserTexture / UnregisterUserTexture.
|
|
||||||
- ErrorCheckNewFrameSanityChecks / ErrorCheckEndFrameSanityChecks (fewer usage-error asserts than upstream).
|
|
||||||
- GetAllocatorFunctions (n/a in Luau).
|
|
||||||
|
|
||||||
WON'T DO (platform)
|
WON'T DO (platform)
|
||||||
-------------------
|
-------------------
|
||||||
- Multi-viewports / platform windows: Roblox has one window. Viewport API exists for the main viewport only.
|
- Multi-viewports / platform windows: Roblox has one window. The viewport API covers the main viewport only.
|
||||||
- Gamepad navigation via a real gamepad backend (keyboard navigation works).
|
- Gamepad navigation via a real gamepad backend (keyboard navigation works).
|
||||||
- IME / non-ASCII keyboard text input (backend sends printable ASCII only).
|
- IME / non-ASCII keyboard text input (backend sends printable ASCII only).
|
||||||
|
|
||||||
NOT VERIFIED LINE BY LINE AGAINST UPSTREAM
|
|
||||||
------------------------------------------
|
|
||||||
- Demo: Layout & Scrolling, Popups & Modal windows, Inputs & Focus.
|
|
||||||
|
|
||||||
KNOWN ISSUES
|
KNOWN ISSUES
|
||||||
------------
|
------------
|
||||||
- Tables > "Columns flags": disabling every column asserts in TableUpdateLayout (upstream asserts too).
|
- Tables > "Columns flags": disabling every column asserts in TableUpdateLayout (upstream asserts too).
|
||||||
- Style Editor > Colors uses a ListClipper (port-only change, upstream submits every row).
|
- stb_truetype: cmap format 2 (high-byte mapping) asserts (same "@TODO" as upstream stb_truetype).
|
||||||
|
- ImTriangulator differs from upstream (imgui_draw.lua, [Luau]): CCW input is reversed first and only strictly
|
||||||
PERFORMANCE IDEAS (not done)
|
counter-clockwise corners are reflex, so CCW and duplicate-point polygons triangulate differently from upstream.
|
||||||
----------------------------
|
|
||||||
- Cheaper visible ColorEdit4 rows; cheaper Begin() for child windows.
|
|
||||||
|
|
||||||
PLANNED EXTENSIONS
|
|
||||||
------------------
|
|
||||||
- ImGuizmo, ImNodes, ImGuiColorTextEdit, ImPlot, ImPlot3D (as separate extensions/, built with a --with flag).
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ setfenv(1, setmetatable({}, {
|
|||||||
|
|
||||||
local MainScale = 1.0
|
local MainScale = 1.0
|
||||||
local RenderScale = 1.0
|
local RenderScale = 1.0
|
||||||
local RenderRate = 0 -- 0 = every frame (tile redraws are limited by the redraw budget instead)
|
local RenderRate = 60 -- max tile redraws per second (0 = every frame, limited by the redraw budget instead)
|
||||||
local ThumbnailSize = 420
|
local ThumbnailSize = 420
|
||||||
local FontSize = 13.0
|
local FontSize = 13.0
|
||||||
local FontNames = { "Cousine-Regular", "DroidSans", "Karla-Regular", "ProggyTiny", "Roboto-Medium" }
|
local FontNames = { "Cousine-Regular", "DroidSans", "Karla-Regular", "ProggyTiny", "Roboto-Medium" }
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
-- One UI that runs unchanged on Roblox and LÖVE: only the Dear ImGui API is used, and the code is plain Lua 5.1
|
|
||||||
-- (no Luau-only syntax), so both Luau and LuaJIT run it. The platform launchers are roblox.client.luau and main.lua.
|
|
||||||
-- local App = require(app)(G) -- G = the table returned by the ImGui bundle
|
|
||||||
-- every frame, between ImGui.NewFrame() and ImGui.Render(): App.Frame()
|
|
||||||
return function(G)
|
|
||||||
local ImGui, ImVec2, ImVec4 = G.ImGui, G.ImVec2, G.ImVec4
|
|
||||||
local App = {
|
|
||||||
Platform = "?", -- set by the launcher ("Roblox" / "LÖVE")
|
|
||||||
ClearColor = ImVec4(0.45, 0.55, 0.60, 1.00), -- launchers may use it as the background colour
|
|
||||||
}
|
|
||||||
local show_demo, show_table = false, true
|
|
||||||
local counter, speed = 0, 1.0
|
|
||||||
local name = ImGui.NewTextBuffer("Player", 64)
|
|
||||||
local samples, t = {}, 0.0
|
|
||||||
local items = { { "Sword", 1, 120 }, { "Potion", 5, 15 }, { "Arrow", 64, 1 }, { "Shield", 1, 80 } }
|
|
||||||
|
|
||||||
function App.Frame()
|
|
||||||
local io = ImGui.GetIO()
|
|
||||||
t = t + io.DeltaTime * speed
|
|
||||||
for i = 1, 90 do samples[i] = math.sin(i / 90 * math.pi * 4 + t * 3) end
|
|
||||||
|
|
||||||
ImGui.SetNextWindowPos(ImVec2(20, 20), G.ImGuiCond.FirstUseEver)
|
|
||||||
ImGui.SetNextWindowSize(ImVec2(420, 360), G.ImGuiCond.FirstUseEver)
|
|
||||||
ImGui.Begin("Shared Example")
|
|
||||||
ImGui.Text("Running on %s (%.1f FPS)", App.Platform, io.Framerate)
|
|
||||||
ImGui.Separator()
|
|
||||||
ImGui.InputText("name", name, 64)
|
|
||||||
if ImGui.Button("Click me") then counter = counter + 1 end
|
|
||||||
ImGui.SameLine(); ImGui.Text("%s clicked %d times", ImGui.TextBufferToString(name), counter)
|
|
||||||
speed = ImGui.SliderFloat("speed", speed, 0.0, 4.0)
|
|
||||||
ImGui.ColorEdit3("background", App.ClearColor)
|
|
||||||
ImGui.PlotLines("wave", samples, nil, #samples, 0, nil, -1.0, 1.0, ImVec2(0, 60))
|
|
||||||
local _
|
|
||||||
_, show_table = ImGui.Checkbox("Inventory table", show_table)
|
|
||||||
ImGui.SameLine(); _, show_demo = ImGui.Checkbox("Demo window", show_demo)
|
|
||||||
if show_table and ImGui.BeginTable("inv", 3, bit32.bor(G.ImGuiTableFlags.Borders, G.ImGuiTableFlags.RowBg, G.ImGuiTableFlags.Sortable)) then
|
|
||||||
ImGui.TableSetupColumn("Item"); ImGui.TableSetupColumn("Count"); ImGui.TableSetupColumn("Value")
|
|
||||||
ImGui.TableHeadersRow()
|
|
||||||
for _, it in ipairs(items) do
|
|
||||||
ImGui.TableNextRow()
|
|
||||||
ImGui.TableNextColumn(); ImGui.Text(it[1])
|
|
||||||
ImGui.TableNextColumn(); ImGui.Text("%d", it[2])
|
|
||||||
ImGui.TableNextColumn(); ImGui.Text("%d", it[3])
|
|
||||||
end
|
|
||||||
ImGui.EndTable()
|
|
||||||
end
|
|
||||||
ImGui.End()
|
|
||||||
|
|
||||||
if show_demo and ImGui.ShowDemoWindow then show_demo = ImGui.ShowDemoWindow(show_demo) end
|
|
||||||
end
|
|
||||||
|
|
||||||
return App
|
|
||||||
end
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
function love.conf(t)
|
|
||||||
t.window.title = "Dear ImGui - shared example (LÖVE)"
|
|
||||||
t.window.width, t.window.height = 1280, 800
|
|
||||||
t.window.resizable = true
|
|
||||||
end
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "imgui-shared-example",
|
|
||||||
"tree": {
|
|
||||||
"$className": "DataModel",
|
|
||||||
"ReplicatedStorage": {
|
|
||||||
"ImGui": { "$path": "../../build/ImGuiTyped.luau", "Impl": { "$path": "../../build/ImGui.luau" } },
|
|
||||||
"SharedApp": { "$path": "app.lua" }
|
|
||||||
},
|
|
||||||
"StarterPlayer": {
|
|
||||||
"StarterPlayerScripts": {
|
|
||||||
"SharedExample": { "$path": "roblox.client.luau" }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
-- LÖVE launcher for app.lua: python3 tools/bundle.py --target love then love examples/example_shared
|
|
||||||
local ROOT = love.filesystem.getSource() .. "/../../" -- repo root (build/, fonts/)
|
|
||||||
local function load_bundle()
|
|
||||||
local f = assert(io.open(ROOT .. "build/imgui_love.lua", "rb"), "run: python3 tools/bundle.py --target love")
|
|
||||||
local src = f:read("*a"); f:close()
|
|
||||||
return assert(loadstring(src, "@imgui_love.lua"))()
|
|
||||||
end
|
|
||||||
|
|
||||||
local G, ImGui, App
|
|
||||||
|
|
||||||
function love.load()
|
|
||||||
G = load_bundle()
|
|
||||||
ImGui = G.ImGui
|
|
||||||
ImGui.CreateContext()
|
|
||||||
local io = ImGui.GetIO()
|
|
||||||
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.NavEnableKeyboard, G.ImGuiConfigFlags.DockingEnable)
|
|
||||||
io.IniFilename = nil
|
|
||||||
G.ImGui_ImplLove.Init({ root = ROOT })
|
|
||||||
App = love.filesystem.load("app.lua")()(G)
|
|
||||||
App.Platform = "LÖVE"
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.update(dt)
|
|
||||||
G.ImGui_ImplLove.NewFrame()
|
|
||||||
ImGui.NewFrame()
|
|
||||||
App.Frame()
|
|
||||||
ImGui.Render()
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.draw()
|
|
||||||
local c = App.ClearColor
|
|
||||||
love.graphics.clear(c.x, c.y, c.z, 1)
|
|
||||||
G.ImGui_ImplLove.RenderDrawData(ImGui.GetDrawData())
|
|
||||||
end
|
|
||||||
|
|
||||||
function love.mousemoved(x, y) G.ImGui_ImplLove.MouseMoved(x, y) end
|
|
||||||
function love.mousepressed(x, y, b) G.ImGui_ImplLove.MousePressed(x, y, b) end
|
|
||||||
function love.mousereleased(x, y, b) G.ImGui_ImplLove.MouseReleased(x, y, b) end
|
|
||||||
function love.wheelmoved(x, y) G.ImGui_ImplLove.WheelMoved(x, y) end
|
|
||||||
function love.keypressed(k) G.ImGui_ImplLove.KeyPressed(k) end
|
|
||||||
function love.keyreleased(k) G.ImGui_ImplLove.KeyReleased(k) end
|
|
||||||
function love.textinput(t) G.ImGui_ImplLove.TextInput(t) end
|
|
||||||
function love.focus(f) G.ImGui_ImplLove.Focus(f) end
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
-- Roblox launcher for app.lua (sync with examples/example_shared/default.project.json).
|
|
||||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
|
||||||
local RunService = game:GetService("RunService")
|
|
||||||
local G = require(ReplicatedStorage:WaitForChild("ImGui"))
|
|
||||||
local ImGui = G.ImGui
|
|
||||||
|
|
||||||
ImGui.CreateContext()
|
|
||||||
local io = ImGui.GetIO()
|
|
||||||
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.NavEnableKeyboard, G.ImGuiConfigFlags.DockingEnable)
|
|
||||||
G.ImGui_ImplRoblox.Init()
|
|
||||||
|
|
||||||
local App = require(ReplicatedStorage:WaitForChild("SharedApp"))(G)
|
|
||||||
App.Platform = "Roblox"
|
|
||||||
|
|
||||||
RunService.Stepped:Connect(function()
|
|
||||||
G.ImGui_ImplRoblox.NewFrame()
|
|
||||||
ImGui.NewFrame()
|
|
||||||
App.Frame()
|
|
||||||
ImGui.Render()
|
|
||||||
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
|
||||||
end)
|
|
||||||
+8236
-4796
File diff suppressed because it is too large
Load Diff
+3033
-644
File diff suppressed because it is too large
Load Diff
+397
-67
@@ -75,6 +75,14 @@ function ImU32(val) return bitAnd(val, 0xFFFFFFFF) end
|
|||||||
--- @return ImS32
|
--- @return ImS32
|
||||||
function ImS32(val) return bitAnd(val, 0xFFFFFFFF) end
|
function ImS32(val) return bitAnd(val, 0xFFFFFFFF) end
|
||||||
|
|
||||||
|
-- [Luau] 64-bit integers are stored in doubles (exact only within +-2^53): the cast just truncates toward zero like a C double->int64 cast.
|
||||||
|
--- @param val number
|
||||||
|
--- @return ImS64
|
||||||
|
function ImS64(val) if val >= 0 then return math.floor(val) end return -math.floor(-val) end
|
||||||
|
--- @param val number
|
||||||
|
--- @return ImU64
|
||||||
|
function ImU64(val) if val >= 0 then return math.floor(val) end return -math.floor(-val) end
|
||||||
|
|
||||||
--- @alias float number
|
--- @alias float number
|
||||||
--- @class double : number
|
--- @class double : number
|
||||||
|
|
||||||
@@ -155,15 +163,17 @@ ImGuiDataType =
|
|||||||
U16 = 3, -- unsigned short
|
U16 = 3, -- unsigned short
|
||||||
S32 = 4, -- int
|
S32 = 4, -- int
|
||||||
U32 = 5, -- unsigned int
|
U32 = 5, -- unsigned int
|
||||||
Float = 6, -- float
|
S64 = 6, -- long long / __int64 -- [Luau] stored in a double: exact only within +-2^53
|
||||||
Double = 7, -- double
|
U64 = 7, -- unsigned long long / unsigned __int64 -- [Luau] stored in a double: exact only within 0..2^53
|
||||||
Bool = 8, -- bool (provided for user convenience, not supported by scalar widgets)
|
Float = 8, -- float
|
||||||
String = 9, -- string (provided for user convenience, not supported by scalar widgets)
|
Double = 9, -- double
|
||||||
COUNT = 10
|
Bool = 10, -- bool (provided for user convenience, not supported by scalar widgets)
|
||||||
|
String = 11, -- string (provided for user convenience, not supported by scalar widgets)
|
||||||
|
COUNT = 12
|
||||||
}
|
}
|
||||||
-- Extend ImGuiDataType_
|
-- Extend ImGuiDataType_
|
||||||
ImGuiDataType.Pointer = 11 -- [internal]
|
ImGuiDataType.Pointer = ImGuiDataType.COUNT -- [internal]
|
||||||
ImGuiDataType.ID = 12 -- [internal]
|
ImGuiDataType.ID = ImGuiDataType.COUNT + 1 -- [internal]
|
||||||
|
|
||||||
ImTextureID_Invalid = -1
|
ImTextureID_Invalid = -1
|
||||||
|
|
||||||
@@ -194,7 +204,8 @@ ImFontAtlasFlags =
|
|||||||
None = 0,
|
None = 0,
|
||||||
NoPowerOfTwoHeight = bitLShift(1, 0), -- Don't round the height to next power of two
|
NoPowerOfTwoHeight = bitLShift(1, 0), -- Don't round the height to next power of two
|
||||||
NoMouseCursors = bitLShift(1, 1), -- Don't build software mouse cursors into the atlas (save a little texture memory)
|
NoMouseCursors = bitLShift(1, 1), -- Don't build software mouse cursors into the atlas (save a little texture memory)
|
||||||
NoBakedLines = bitLShift(1, 2) -- Don't build anti-aliased line textures into the atlas (save a little texture memory). SINCE 1.93.0 THIS PREVENTS ANTI-ALIASED LINES FROM WORKING AND WILL DISABLE THEM.
|
NoBakedLines = bitLShift(1, 2), -- Don't build anti-aliased line textures into the atlas (save a little texture memory). SINCE 1.93.0 THIS PREVENTS ANTI-ALIASED LINES FROM WORKING AND WILL DISABLE THEM.
|
||||||
|
NoBakedRoundCorners= bitLShift(1, 3), -- Don't build round corners into the atlas.
|
||||||
}
|
}
|
||||||
|
|
||||||
-- A cardinal direction
|
-- A cardinal direction
|
||||||
@@ -498,8 +509,8 @@ end
|
|||||||
--- @field UserCallbackData any
|
--- @field UserCallbackData any
|
||||||
--- @field UserCallbackDataSize int
|
--- @field UserCallbackDataSize int
|
||||||
--- @field UserCallbackDataOffset int
|
--- @field UserCallbackDataOffset int
|
||||||
local IM_DRAWCMD = {}
|
MT.ImDrawCmd = {}
|
||||||
IM_DRAWCMD.__index = IM_DRAWCMD
|
MT.ImDrawCmd.__index = MT.ImDrawCmd
|
||||||
|
|
||||||
--- @return ImDrawCmd
|
--- @return ImDrawCmd
|
||||||
--- @nodiscard
|
--- @nodiscard
|
||||||
@@ -514,11 +525,11 @@ function ImDrawCmd()
|
|||||||
UserCallbackData = nil, -- 4-8 -- Callback user data (when UserCallback != nil). If called AddCallback() with size == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > 0, this is pointing to a buffer where data is stored.
|
UserCallbackData = nil, -- 4-8 -- Callback user data (when UserCallback != nil). If called AddCallback() with size == 0, this is a copy of the AddCallback() argument. If called AddCallback() with size > 0, this is pointing to a buffer where data is stored.
|
||||||
UserCallbackDataSize = 0, -- 4 -- Size of callback user data when using storage, otherwise 0.
|
UserCallbackDataSize = 0, -- 4 -- Size of callback user data when using storage, otherwise 0.
|
||||||
UserCallbackDataOffset = 0 -- 4 -- [Internal] Offset of callback user data when using storage, otherwise -1.
|
UserCallbackDataOffset = 0 -- 4 -- [Internal] Offset of callback user data when using storage, otherwise -1.
|
||||||
}, IM_DRAWCMD)
|
}, MT.ImDrawCmd)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @return ImTextureID
|
--- @return ImTextureID
|
||||||
function IM_DRAWCMD:GetTexID()
|
function MT.ImDrawCmd:GetTexID()
|
||||||
local tex_id = (self.TexRef._TexData) and self.TexRef._TexData.TexID or self.TexRef._TexID
|
local tex_id = (self.TexRef._TexData) and self.TexRef._TexData.TexID or self.TexRef._TexID
|
||||||
if self.TexRef._TexData ~= nil then
|
if self.TexRef._TexData ~= nil then
|
||||||
IM_ASSERT(tex_id ~= ImTextureID_Invalid, "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!")
|
IM_ASSERT(tex_id ~= ImTextureID_Invalid, "ImDrawCmd is referring to ImTextureData that wasn't uploaded to graphics system. Backend must call ImTextureData::SetTexID() after handling ImTextureStatus_WantCreate request!")
|
||||||
@@ -605,7 +616,7 @@ function ImDrawListSplitter() return setmetatable({ _Current = 0, _Count = 0, _C
|
|||||||
--- @field CmdBuffer ImVector<ImDrawCmd>
|
--- @field CmdBuffer ImVector<ImDrawCmd>
|
||||||
--- @field IdxBuffer ImVector<ImDrawIdx>
|
--- @field IdxBuffer ImVector<ImDrawIdx>
|
||||||
--- @field VtxBuffer ImVector<ImDrawVert>
|
--- @field VtxBuffer ImVector<ImDrawVert>
|
||||||
--- @field Flags ImDrawListFlags
|
--- @field Flags ImDrawFlags # Current flags for drawing primitives. Alter with PushDrawFlag()/PopDrawFlag()
|
||||||
--- @field _VtxCurrentIdx unsigned_int # 1-based, generally == (VtxBuffer.Size + 1)
|
--- @field _VtxCurrentIdx unsigned_int # 1-based, generally == (VtxBuffer.Size + 1)
|
||||||
--- @field _Data ImDrawListSharedData # Pointes to shared draw data
|
--- @field _Data ImDrawListSharedData # Pointes to shared draw data
|
||||||
--- @field _VtxWritePtr unsigned_int # 1-based, points to the current writing vertex in VtxBuffer (see ImDrawVtxBuffer)
|
--- @field _VtxWritePtr unsigned_int # 1-based, points to the current writing vertex in VtxBuffer (see ImDrawVtxBuffer)
|
||||||
@@ -616,7 +627,10 @@ function ImDrawListSplitter() return setmetatable({ _Current = 0, _Count = 0, _C
|
|||||||
--- @field _ClipRectStack ImVector<ImVec4>
|
--- @field _ClipRectStack ImVector<ImVec4>
|
||||||
--- @field _TextureStack ImVector<ImTextureRef>
|
--- @field _TextureStack ImVector<ImTextureRef>
|
||||||
--- @field _CallbacksDataBuf any
|
--- @field _CallbacksDataBuf any
|
||||||
|
--- @field _DrawFlagsStack ImVector<ImDrawFlags>
|
||||||
--- @field _FringeScale float
|
--- @field _FringeScale float
|
||||||
|
--- @field _InvFringeScale float
|
||||||
|
--- @field _FringeScaleIsInteger bool
|
||||||
--- @field _OwnerName string
|
--- @field _OwnerName string
|
||||||
MT.ImDrawList = {}
|
MT.ImDrawList = {}
|
||||||
MT.ImDrawList.__index = MT.ImDrawList
|
MT.ImDrawList.__index = MT.ImDrawList
|
||||||
@@ -669,9 +683,11 @@ function ImDrawList(data)
|
|||||||
_Splitter = ImDrawListSplitter(), -- [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)
|
_Splitter = ImDrawListSplitter(), -- [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)
|
||||||
_ClipRectStack = ImVector(), -- [Internal]
|
_ClipRectStack = ImVector(), -- [Internal]
|
||||||
_TextureStack = ImVector(), -- [Internal]
|
_TextureStack = ImVector(), -- [Internal]
|
||||||
_CallbacksDataBuf = nil, -- [Internal]
|
_CallbacksDataBuf = ImVector(), -- [Internal] [Lua] copies of AddCallback() userdata (userdata_size > 0)
|
||||||
|
_DrawFlagsStack = ImVector(), -- [Internal] ImSmallStack_<ImDrawFlags,3>: capacity checked by PushDrawFlag()
|
||||||
_FringeScale = 0, -- [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content
|
_FringeScale = 1.0, -- [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content -- [Luau] 1.0 instead of memset 0 so a list used before _SetPixelDensity() still works
|
||||||
|
_InvFringeScale = 1.0, -- [internal] 1.0 / _FringeScale // FIXME: Consider renaming to _PixelDensity.
|
||||||
|
_FringeScaleIsInteger = true, -- [Internal] true if 1/_FringeScale is a whole number, used to select fast path for rendering
|
||||||
_OwnerName = nil -- Pointer to owner window's name for debugging
|
_OwnerName = nil -- Pointer to owner window's name for debugging
|
||||||
}, MT.ImDrawList)
|
}, MT.ImDrawList)
|
||||||
|
|
||||||
@@ -750,6 +766,7 @@ function ImTextureData()
|
|||||||
this.UniqueID = 0 -- w - -- [DEBUG] Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas.
|
this.UniqueID = 0 -- w - -- [DEBUG] Sequential index to facilitate identifying a texture when debugging/printing. Unique per atlas.
|
||||||
this.Status = ImTextureStatus.Destroyed -- rw rw -- ImTextureStatus.OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify!
|
this.Status = ImTextureStatus.Destroyed -- rw rw -- ImTextureStatus.OK/_WantCreate/_WantUpdates/_WantDestroy. Always use SetStatus() to modify!
|
||||||
this.BackendUserData = nil -- - rw -- Convenience storage for backend. Some backends may have enough with TexID.
|
this.BackendUserData = nil -- - rw -- Convenience storage for backend. Some backends may have enough with TexID.
|
||||||
|
this.QueueUserData = nil -- r - -- Convenience storage for a staged/multi-threaded rendering texture queue (e.g. imgui_threaded_rendering.h. See #8597). When ~= nil, core assumes the texture is referenced by the queue.
|
||||||
this.TexID = ImTextureID_Invalid -- r w -- Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function.
|
this.TexID = ImTextureID_Invalid -- r w -- Backend-specific texture identifier. Always use SetTexID() to modify! The identifier will stored in ImDrawCmd::GetTexID() and passed to backend's RenderDrawData function.
|
||||||
this.Format = 0 -- w r -- ImTextureFormat.RGBA32 (default) or ImTextureFormat.Alpha8
|
this.Format = 0 -- w r -- ImTextureFormat.RGBA32 (default) or ImTextureFormat.Alpha8
|
||||||
this.Width = 0 -- w r -- Texture width
|
this.Width = 0 -- w r -- Texture width
|
||||||
@@ -769,11 +786,14 @@ end
|
|||||||
|
|
||||||
--- @param x int
|
--- @param x int
|
||||||
--- @param y int
|
--- @param y int
|
||||||
|
function MT.ImTextureData:GetPixels() IM_ASSERT(self.Pixels ~= nil); return self.Pixels end
|
||||||
function MT.ImTextureData:GetPixelsAt(x, y)
|
function MT.ImTextureData:GetPixelsAt(x, y)
|
||||||
return self.Pixels, (x + y * self.Width) * self.BytesPerPixel + 1
|
return self.Pixels, (x + y * self.Width) * self.BytesPerPixel + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function MT.ImTextureData:GetSizeInBytes() return self.Width * self.Height * self.BytesPerPixel end
|
||||||
function MT.ImTextureData:GetPitch() return self.Width * self.BytesPerPixel end
|
function MT.ImTextureData:GetPitch() return self.Width * self.BytesPerPixel end
|
||||||
|
function MT.ImTextureData:GetTexRef() local tex_ref = ImTextureRef(); tex_ref._TexData = self; tex_ref._TexID = ImTextureID_Invalid; return tex_ref end
|
||||||
function MT.ImTextureData:GetTexID() return self.TexID end
|
function MT.ImTextureData:GetTexID() return self.TexID end
|
||||||
|
|
||||||
--- @param tex_id ImTextureID
|
--- @param tex_id ImTextureID
|
||||||
@@ -793,8 +813,8 @@ function MT.ImTextureData:SetStatus(status) self.Status = status if (status == I
|
|||||||
--- @class ImTextureRef
|
--- @class ImTextureRef
|
||||||
--- @field _TexData? ImTextureData
|
--- @field _TexData? ImTextureData
|
||||||
--- @field _TexID ImTextureID
|
--- @field _TexID ImTextureID
|
||||||
local IM_TEXTURE_REF = {}
|
MT.ImTextureRef = {}
|
||||||
IM_TEXTURE_REF.__index = IM_TEXTURE_REF
|
MT.ImTextureRef.__index = MT.ImTextureRef
|
||||||
|
|
||||||
--- @return ImTextureRef
|
--- @return ImTextureRef
|
||||||
--- @nodiscard
|
--- @nodiscard
|
||||||
@@ -803,7 +823,14 @@ function ImTextureRef(tex_id)
|
|||||||
-- Members (either are set, never both!)
|
-- Members (either are set, never both!)
|
||||||
_TexData = nil, -- A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded.
|
_TexData = nil, -- A texture, generally owned by a ImFontAtlas. Will convert to ImTextureID during render loop, after texture has been uploaded.
|
||||||
_TexID = tex_id or ImTextureID_Invalid -- _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui.Image() calls.
|
_TexID = tex_id or ImTextureID_Invalid -- _OR_ Low-level backend texture identifier, if already uploaded or created by user/app. Generally provided to e.g. ImGui.Image() calls.
|
||||||
}, IM_TEXTURE_REF)
|
}, MT.ImTextureRef)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- This is provided for consistency (but we don't actually use this)
|
||||||
|
--- @return ImTextureID
|
||||||
|
function MT.ImTextureRef:GetTexID()
|
||||||
|
IM_ASSERT(not (self._TexData ~= nil and self._TexID ~= ImTextureID_Invalid))
|
||||||
|
if self._TexData then return self._TexData.TexID else return self._TexID end
|
||||||
end
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@@ -1132,6 +1159,34 @@ function ImFontGlyph()
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Helper to build glyph ranges from text/string data. Feed your application strings/characters to it then call BuildRanges().
|
||||||
|
-- This is essentially a tightly packed of vector of 64k booleans = 8KB storage.
|
||||||
|
--- @class ImFontGlyphRangesBuilder
|
||||||
|
--- @field UsedChars ImVector<ImU32> # Store 1-bit per Unicode code point (0=unused, 1=used)
|
||||||
|
MT.ImFontGlyphRangesBuilder = {}
|
||||||
|
MT.ImFontGlyphRangesBuilder.__index = MT.ImFontGlyphRangesBuilder
|
||||||
|
|
||||||
|
--- @return ImFontGlyphRangesBuilder
|
||||||
|
--- @nodiscard
|
||||||
|
function ImFontGlyphRangesBuilder()
|
||||||
|
local this = setmetatable({ UsedChars = ImVector() }, MT.ImFontGlyphRangesBuilder)
|
||||||
|
this:Clear()
|
||||||
|
return this
|
||||||
|
end
|
||||||
|
|
||||||
|
function MT.ImFontGlyphRangesBuilder:Clear()
|
||||||
|
local size_in_bytes = (IM_UNICODE_CODEPOINT_MAX + 1) / 8
|
||||||
|
self.UsedChars:resize(size_in_bytes / 4)
|
||||||
|
local data = self.UsedChars.Data
|
||||||
|
for i = 1, self.UsedChars.Size do data[i] = 0 end
|
||||||
|
end
|
||||||
|
-- Get bit n in the array
|
||||||
|
function MT.ImFontGlyphRangesBuilder:GetBit(n) local off = bit32.rshift(n, 5); local mask = bit32.lshift(1, bit32.band(n, 31)); return bit32.band(self.UsedChars.Data[off + 1], mask) ~= 0 end
|
||||||
|
-- Set bit n in the array
|
||||||
|
function MT.ImFontGlyphRangesBuilder:SetBit(n) local off = bit32.rshift(n, 5); local mask = bit32.lshift(1, bit32.band(n, 31)); self.UsedChars.Data[off + 1] = bit32.bor(self.UsedChars.Data[off + 1], mask) end
|
||||||
|
-- Add character
|
||||||
|
function MT.ImFontGlyphRangesBuilder:AddChar(c) self:SetBit(c) end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- [SECTION] ImGuiIO
|
-- [SECTION] ImGuiIO
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@@ -1190,6 +1245,8 @@ function ImGuiIO()
|
|||||||
-- Other state maintained from data above + IO function calls
|
-- Other state maintained from data above + IO function calls
|
||||||
KeyMods = nil, -- Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame()
|
KeyMods = nil, -- Key mods flags (any of ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Alt/ImGuiMod_Super flags, same as io.KeyCtrl/KeyShift/KeyAlt/KeySuper but merged into flags). Read-only, updated by NewFrame()
|
||||||
|
|
||||||
|
BackendPlatformName = nil, -- = NULL
|
||||||
|
BackendRendererName = nil, -- = NULL
|
||||||
BackendFlags = ImGuiBackendFlags.None, -- = 0 -- See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend.
|
BackendFlags = ImGuiBackendFlags.None, -- = 0 -- See ImGuiBackendFlags_ enum. Set by backend (imgui_impl_xxx files or custom backend) to communicate features supported by the backend.
|
||||||
ConfigFlags = ImGuiConfigFlags.None, -- = 0 -- See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc.
|
ConfigFlags = ImGuiConfigFlags.None, -- = 0 -- See ImGuiConfigFlags_ enum. Set by user/application. Keyboard/Gamepad navigation options, etc.
|
||||||
DisplaySize = ImVec2(-1.0, -1.0), -- <unset> -- Main display size, in pixels (== GetMainViewport()->Size). May change every frame.
|
DisplaySize = ImVec2(-1.0, -1.0), -- <unset> -- Main display size, in pixels (== GetMainViewport()->Size). May change every frame.
|
||||||
@@ -1198,6 +1255,9 @@ function ImGuiIO()
|
|||||||
|
|
||||||
DisplayFramebufferScale = ImVec2(1.0, 1.0), -- = (1, 1) -- Main display density. For retina display where window coordinates are different from framebuffer coordinates. This will affect font density + will end up in ImDrawData::FramebufferScale.
|
DisplayFramebufferScale = ImVec2(1.0, 1.0), -- = (1, 1) -- Main display density. For retina display where window coordinates are different from framebuffer coordinates. This will affect font density + will end up in ImDrawData::FramebufferScale.
|
||||||
|
|
||||||
|
-- Font system
|
||||||
|
FontAllowUserScaling = false, -- = false -- Allow user scaling text of individual window with Ctrl+Wheel.
|
||||||
|
|
||||||
-- Main Input State
|
-- Main Input State
|
||||||
-- (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead)
|
-- (this block used to be written by backend, since 1.87 it is best to NOT write to those directly, call the AddXXX functions above instead)
|
||||||
-- (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)
|
-- (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)
|
||||||
@@ -1208,12 +1268,14 @@ function ImGuiIO()
|
|||||||
|
|
||||||
MouseDelta = ImVec2(), -- Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
|
MouseDelta = ImVec2(), -- Mouse delta. Note that this is zero if either current or previous position are invalid (-FLT_MAX,-FLT_MAX), so a disappearing/reappearing mouse won't have a huge delta.
|
||||||
|
|
||||||
MouseDown = {[0] = false, [1] = false, [2] = false}, -- Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton.COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
|
MouseDown = {[0] = false, [1] = false, [2] = false, [3] = false, [4] = false}, -- Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton.COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
|
||||||
|
|
||||||
MouseWheel = 0, -- Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold Shift to turn vertical scroll into horizontal scroll.
|
MouseWheel = 0, -- Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold Shift to turn vertical scroll into horizontal scroll.
|
||||||
MouseWheelH = 0, -- Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
|
MouseWheelH = 0, -- Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
|
||||||
|
|
||||||
MouseCtrlLeftAsRightClick = false, -- (OSX) Set to true when the current click was a Ctrl+Click that spawned a simulated right click
|
MouseCtrlLeftAsRightClick = false, -- (OSX) Set to true when the current click was a Ctrl+Click that spawned a simulated right click
|
||||||
|
MouseSource = ImGuiMouseSource.Mouse, -- Mouse actual input peripheral (Mouse/TouchScreen/Pen).
|
||||||
|
PenPressure = 0.0, -- Touch/Pen pressure (0.0f to 1.0f, should be >0.0f only when MouseDown[0] == true). Helper storage currently unused by Dear ImGui.
|
||||||
|
|
||||||
MouseWheelRequestAxisSwap = false, -- On a non-Mac system, holding Shift requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system.
|
MouseWheelRequestAxisSwap = false, -- On a non-Mac system, holding Shift requests WheelY to perform the equivalent of a WheelX event. On a Mac system this is already enforced by the system.
|
||||||
|
|
||||||
@@ -1229,6 +1291,25 @@ function ImGuiIO()
|
|||||||
ConfigDebugIniSettings = false, -- = false -- Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)
|
ConfigDebugIniSettings = false, -- = false -- Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)
|
||||||
ConfigWindowsCopyContentsWithCtrlC = false, -- = false -- [EXPERIMENTAL] Ctrl+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order.
|
ConfigWindowsCopyContentsWithCtrlC = false, -- = false -- [EXPERIMENTAL] Ctrl+C copy the contents of focused window into the clipboard. Experimental because: (1) has known issues with nested Begin/End pairs (2) text output quality varies (3) text output is in submission order rather than spatial order.
|
||||||
ConfigWindowsMoveFromTitleBarOnly = false, -- = false -- Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar.
|
ConfigWindowsMoveFromTitleBarOnly = false, -- = false -- Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar.
|
||||||
|
ConfigScrollbarScrollByPage = true, -- = true -- Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location.
|
||||||
|
ConfigInputTextCursorBlink = true, -- = true -- Enable blinking cursor (optional as some users consider it to be distracting).
|
||||||
|
ConfigInputTextEnterKeepActive = false, -- = false -- [BETA] Pressing Enter will reactivate item and select all text (single-line only). Ctrl+Enter or Shift+Enter will deactivate normally.
|
||||||
|
ConfigDragClickToInputText = false, -- = false -- [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard.
|
||||||
|
|
||||||
|
-- Keyboard/Gamepad Navigation options
|
||||||
|
ConfigNavSwapGamepadButtons = false, -- = false -- Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout.
|
||||||
|
ConfigNavMoveSetMousePos = false, -- = false -- Directional/tabbing navigation teleports the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is difficult. Will update io.MousePos and set io.WantSetMousePos=true.
|
||||||
|
ConfigNavCaptureKeyboard = true, -- = true -- Sets io.WantCaptureKeyboard when io.NavActive is set.
|
||||||
|
ConfigNavEscapeClearFocusItem = true, -- = true -- Pressing Escape can clear focused item + navigation id/highlight. Set to false if you want to always keep highlight on.
|
||||||
|
ConfigNavEscapeClearFocusWindow = false, -- = false -- Pressing Escape can clear focused window as well (super set of io.ConfigNavEscapeClearFocusItem).
|
||||||
|
|
||||||
|
-- DPI/Scaling options
|
||||||
|
ConfigDpiScaleFonts = false, -- = false -- [EXPERIMENTAL] Automatically overwrite style.FontScaleDpi when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
|
||||||
|
ConfigDpiScaleViewports = false, -- = false -- [EXPERIMENTAL] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
|
||||||
|
|
||||||
|
-- Ini Settings options
|
||||||
|
ConfigIniSettingsSaveLastUsedDate = true, -- = true -- Enable loading/saving last used day (YYYYMMDD) in some .ini struct, making things easier to audit and allowing custom tools to cleanup old data.
|
||||||
|
ConfigIniSettingsAutoDiscardMonths = 0, -- = 0 -- [BETA] Set number of months after which unused .ini entries are discarded on load. Require platform_io.Platform_SessionDate to be set. For systems supporting the feature, .ini entries without a LastUsed field will always be discarded! Please report if you are using this.
|
||||||
-- Options to configure Error Handling and how we handle recoverable errors [EXPERIMENTAL]
|
-- Options to configure Error Handling and how we handle recoverable errors [EXPERIMENTAL]
|
||||||
-- - Error recovery is provided as a way to facilitate:
|
-- - Error recovery is provided as a way to facilitate:
|
||||||
-- - Recovery after a programming error (native code or scripting language - the latter tends to facilitate iterating on code while running).
|
-- - Recovery after a programming error (native code or scripting language - the latter tends to facilitate iterating on code while running).
|
||||||
@@ -1253,6 +1334,16 @@ function ImGuiIO()
|
|||||||
-- - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
|
-- - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
|
||||||
ConfigDebugHighlightIdConflicts = false, -- Highlight and show an error message popup when multiple items have conflicting identifiers.
|
ConfigDebugHighlightIdConflicts = false, -- Highlight and show an error message popup when multiple items have conflicting identifiers.
|
||||||
ConfigDebugHighlightIdConflictsShowItemPicker = true, -- =true -- Show "Item Picker" button in aforementioned popup.
|
ConfigDebugHighlightIdConflictsShowItemPicker = true, -- =true -- Show "Item Picker" button in aforementioned popup.
|
||||||
|
ConfigDebugIsDebuggerPresent = false, -- = false -- Enable various tools calling IM_DEBUG_BREAK().
|
||||||
|
-- Tools to test correct Begin/End and BeginChild/EndChild behaviors.
|
||||||
|
ConfigDebugBeginReturnValueOnce = false, -- = false -- First-time calls to Begin()/BeginChild() will return false. NEEDS TO BE SET AT APPLICATION BOOT TIME if you don't want to miss windows.
|
||||||
|
ConfigDebugBeginReturnValueLoop = false, -- = false -- Some calls to Begin()/BeginChild() will return false. Will cycle through window depths then repeat. Suggested use: add "io.ConfigDebugBeginReturnValue = io.KeyShift" in your main loop then occasionally press SHIFT. Windows should be flickering while running.
|
||||||
|
-- Option to deactivate io.AddFocusEvent(false) handling.
|
||||||
|
ConfigDebugIgnoreFocusLoss = false, -- = false -- Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys()/io.ClearInputMouse() in input processing.
|
||||||
|
-- Option to compare < 1.93.0 rendering details vs 1.93.0 rendering details. (#9504)
|
||||||
|
-- - Equivalent to calling PushDrawFlag(ImDrawList_StrokeLegacy,true) on every draw list instances.
|
||||||
|
-- - Suggested use, e.g. io.ConfigDebugDrawListDefaultsToStrokeLegacy = io.KeyShift; // Map to SHIFT modifier
|
||||||
|
ConfigDebugDrawListDefaultsToStrokeLegacy = false, -- false -- Default all ImDrawList to ImDrawList_StrokeLegacy mode, mimicking pre-1.93.0 rendering.
|
||||||
|
|
||||||
IniFilename = "imgui.ini", -- Roblox: no disk access, only used as a flag (nil disables .ini handling)
|
IniFilename = "imgui.ini", -- Roblox: no disk access, only used as a flag (nil disables .ini handling)
|
||||||
IniSavingRate = 5.0, -- = 5.0f -- Minimum time between saving positions/sizes to .ini file, in seconds.
|
IniSavingRate = 5.0, -- = 5.0f -- Minimum time between saving positions/sizes to .ini file, in seconds.
|
||||||
@@ -1279,23 +1370,23 @@ function ImGuiIO()
|
|||||||
-- (you can visualize and interact with all options in 'Demo->Configuration')
|
-- (you can visualize and interact with all options in 'Demo->Configuration')
|
||||||
MouseDrawCursor = false, -- = false -- Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
|
MouseDrawCursor = false, -- = false -- Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
|
||||||
|
|
||||||
MouseClicked = {[0] = false, [1] = false, [2] = false}, -- Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0)
|
MouseClicked = {[0] = false, [1] = false, [2] = false, [3] = false, [4] = false}, -- Mouse button went from !Down to Down (same as MouseClickedCount[x] != 0)
|
||||||
MouseReleased = {[0] = false, [1] = false, [2] = false}, -- Mouse button went from Down to !Down
|
MouseReleased = {[0] = false, [1] = false, [2] = false, [3] = false, [4] = false}, -- Mouse button went from Down to !Down
|
||||||
MouseClickedCount = {[0] = 0, [1] = 0, [2] = 0}, -- == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down
|
MouseClickedCount = {[0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0}, -- == 0 (not clicked), == 1 (same as MouseClicked[]), == 2 (double-clicked), == 3 (triple-clicked) etc. when going from !Down to Down
|
||||||
MouseClickedLastCount = {[0] = 0, [1] = 0, [2] = 0}, -- Count successive number of clicks. Stays valid after mouse release. Reset after another click is done.
|
MouseClickedLastCount = {[0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0}, -- Count successive number of clicks. Stays valid after mouse release. Reset after another click is done.
|
||||||
MouseDownDuration = {[0] = -1, [1] = -1, [2] = -1}, -- Duration the mouse button has been down (0.0f == just clicked)
|
MouseDownDuration = {[0] = -1, [1] = -1, [2] = -1, [3] = -1, [4] = -1}, -- Duration the mouse button has been down (0.0f == just clicked)
|
||||||
MouseDownDurationPrev = {[0] = -1, [1] = -1, [2] = -1}, -- Previous time the mouse button has been down
|
MouseDownDurationPrev = {[0] = -1, [1] = -1, [2] = -1, [3] = -1, [4] = -1}, -- Previous time the mouse button has been down
|
||||||
|
|
||||||
MouseDragMaxDistanceAbs = {[0] = ImVec2(), [1] = ImVec2(), [2] = ImVec2()}, -- Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
|
MouseDragMaxDistanceAbs = {[0] = ImVec2(), [1] = ImVec2(), [2] = ImVec2(), [3] = ImVec2(), [4] = ImVec2()}, -- Maximum distance, absolute, on each axis, of how much mouse has traveled from the clicking point
|
||||||
MouseDragMaxDistanceSqr = {[0] = 0, [1] = 0, [2] = 0}, -- Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)
|
MouseDragMaxDistanceSqr = {[0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0}, -- Squared maximum distance of how much mouse has traveled from the clicking point (used for moving thresholds)
|
||||||
|
|
||||||
MouseDownOwned = {[0] = nil, [1] = nil, [2] = nil}, -- Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
|
MouseDownOwned = {[0] = nil, [1] = nil, [2] = nil, [3] = nil, [4] = nil}, -- Track if button was clicked inside a dear imgui window or over void blocked by a popup. We don't request mouse capture from the application if click started outside ImGui bounds.
|
||||||
MouseDownOwnedUnlessPopupClose = {[0] = nil, [1] = nil, [2] = nil}, -- Track if button was clicked inside a dear imgui window.
|
MouseDownOwnedUnlessPopupClose = {[0] = nil, [1] = nil, [2] = nil, [3] = nil, [4] = nil}, -- Track if button was clicked inside a dear imgui window.
|
||||||
MouseClickedTime = {[0] = 0, [1] = 0, [2] = 0}, -- Time of last click (used to figure out double-click)
|
MouseClickedTime = {[0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0}, -- Time of last click (used to figure out double-click)
|
||||||
MouseReleasedTime = {[0] = 0, [1] = 0, [2] = 0}, -- Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click).
|
MouseReleasedTime = {[0] = 0, [1] = 0, [2] = 0, [3] = 0, [4] = 0}, -- Time of last released (rarely used! but useful to handle delayed single-click when trying to disambiguate them from double-click).
|
||||||
MouseClickedPos = {[0] = ImVec2(), [1] = ImVec2(), [2] = ImVec2()}, -- Position at time of clicking
|
MouseClickedPos = {[0] = ImVec2(), [1] = ImVec2(), [2] = ImVec2(), [3] = ImVec2(), [4] = ImVec2()}, -- Position at time of clicking
|
||||||
|
|
||||||
MouseDoubleClicked = {[0] = false, [1] = false, [2] = false}, -- Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2)
|
MouseDoubleClicked = {[0] = false, [1] = false, [2] = false, [3] = false, [4] = false}, -- Has mouse button been double-clicked? (same as MouseClickedCount[x] == 2)
|
||||||
|
|
||||||
-- Inputs Behaviors
|
-- Inputs Behaviors
|
||||||
-- (other variables, ones which are expected to be tweaked within UI code, are exposed in ImGuiStyle)
|
-- (other variables, ones which are expected to be tweaked within UI code, are exposed in ImGuiStyle)
|
||||||
@@ -1463,6 +1554,7 @@ function ImGuiViewport()
|
|||||||
|
|
||||||
PlatformHandle = nil, -- void* to hold higher-level, platform window handle (e.g. HWND for Win32 backend, Uint32 WindowID for SDL, GLFWWindow* for GLFW), for FindViewportByPlatformHandle().
|
PlatformHandle = nil, -- void* to hold higher-level, platform window handle (e.g. HWND for Win32 backend, Uint32 WindowID for SDL, GLFWWindow* for GLFW), for FindViewportByPlatformHandle().
|
||||||
PlatformHandleRaw = nil, -- void* to hold lower-level, platform-native window handle (always HWND on Win32 platform, unused for other platforms).
|
PlatformHandleRaw = nil, -- void* to hold lower-level, platform-native window handle (always HWND on Win32 platform, unused for other platforms).
|
||||||
|
PlatformIconData = nil, -- [EXPERIMENTAL] Pass opaque data for Platform backend to handle.
|
||||||
PlatformWindowCreated = false -- Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created.
|
PlatformWindowCreated = false -- Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created.
|
||||||
}, MT.ImGuiViewport)
|
}, MT.ImGuiViewport)
|
||||||
end
|
end
|
||||||
@@ -1494,12 +1586,24 @@ function ImGuiPlatformIO()
|
|||||||
-- (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
|
-- (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
|
||||||
Platform_GetClipboardTextFn = nil, -- Should return nil on failure (e.g. clipboard data is not text).
|
Platform_GetClipboardTextFn = nil, -- Should return nil on failure (e.g. clipboard data is not text).
|
||||||
Platform_SetClipboardTextFn = nil,
|
Platform_SetClipboardTextFn = nil,
|
||||||
|
Platform_ClipboardUserData = nil,
|
||||||
|
|
||||||
-- Optional: Open link/folder/file in OS Shell
|
-- Optional: Open link/folder/file in OS Shell
|
||||||
-- (default to use ShellExecuteW() on Windows, system() on Linux/Mac. expected to return false on failure, but some platforms may always return true)
|
-- (default to use ShellExecuteW() on Windows, system() on Linux/Mac. expected to return false on failure, but some platforms may always return true)
|
||||||
Platform_OpenInShellFn = nil,
|
Platform_OpenInShellFn = nil,
|
||||||
Platform_OpenInShellUserData = nil,
|
Platform_OpenInShellUserData = nil,
|
||||||
|
|
||||||
|
-- Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows)
|
||||||
|
Platform_SetImeDataFn = nil, -- fun(ctx, viewport, data)
|
||||||
|
Platform_ImeUserData = nil,
|
||||||
|
|
||||||
|
-- Optional: Platform locale
|
||||||
|
-- [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point
|
||||||
|
Platform_LocaleDecimalPoint = 46, -- '.'
|
||||||
|
|
||||||
|
-- Optional: Session date
|
||||||
|
Platform_SessionDate = 0, -- Integer storing YYYYMMDD e.g. 20261231 corresponding to the beginning of application session.
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- Input - Interface with Renderer Backend
|
-- Input - Interface with Renderer Backend
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@@ -1511,6 +1615,12 @@ function ImGuiPlatformIO()
|
|||||||
-- Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure.
|
-- Written by some backends during ImGui_ImplXXXX_RenderDrawData() call to point backend_specific ImGui_ImplXXXX_RenderState* structure.
|
||||||
Renderer_RenderState = nil,
|
Renderer_RenderState = nil,
|
||||||
|
|
||||||
|
-- Optional: Standard draw callbacks (set by backends that support them)
|
||||||
|
DrawCallback_ResetRenderState = nil, -- Request to reset the graphics/render state.
|
||||||
|
DrawCallback_SetSamplerLinear = nil, -- Request backend to set texture sampling to Linear.
|
||||||
|
DrawCallback_SetSamplerNearest = nil, -- Request backend to set texture sampling to Nearest/Point.
|
||||||
|
DrawCallback_SetSamplerFromTex = nil, -- Request backend to use sampler associated to texture - only available in some backends: OpenGL2/3 and SDLRenderer3.
|
||||||
|
|
||||||
-- (Optional) Monitor list
|
-- (Optional) Monitor list
|
||||||
-- - Updated by: app/backend. Update every frame to dynamically support changing monitor or DPI configuration.
|
-- - Updated by: app/backend. Update every frame to dynamically support changing monitor or DPI configuration.
|
||||||
-- - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors.
|
-- - Used by: dear imgui to query DPI info, clamp popups/tooltips within same monitor and not have them straddle monitors.
|
||||||
@@ -1522,10 +1632,6 @@ function ImGuiPlatformIO()
|
|||||||
-- (in the future we will attempt to organize this feature to remove the need for a "main viewport")
|
-- (in the future we will attempt to organize this feature to remove the need for a "main viewport")
|
||||||
Viewports = ImVector(), -- Main viewports, followed by all secondary viewports.
|
Viewports = ImVector(), -- Main viewports, followed by all secondary viewports.
|
||||||
|
|
||||||
-- Optional: Platform locale
|
|
||||||
-- [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point
|
|
||||||
Platform_LocaleDecimalPoint = 46, -- '.'
|
|
||||||
|
|
||||||
Platform_OnChangedViewport = nil, -- (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style.
|
Platform_OnChangedViewport = nil, -- (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1687,35 +1793,90 @@ ImGuiNextItemDataFlags = {
|
|||||||
--- @enum ImDrawFlags
|
--- @enum ImDrawFlags
|
||||||
ImDrawFlags = {
|
ImDrawFlags = {
|
||||||
None = 0,
|
None = 0,
|
||||||
-- - Rounding default to ImDrawFlags.RoundCornersAll when 'rounding > 0'.
|
--ImDrawFlags_Closed = 1, // -> FLAG MOVED BELOW. Prior to 1.92.8 (May 2026): ImDrawFlags_Closed was guaranteed to be == (1<<0) == 1, for legacy compatibility reason. Hardcoded use of 1 or true should be replaced with 'ImDrawFlags_Closed'.
|
||||||
-- - So you only need to use the ImDrawFlags.RoundCornersXXX flags if you want a special configuration (e.g. a rectangle with one rounded corner).
|
|
||||||
|
-- About usage of flags:
|
||||||
|
-- - "Prim" column: 'OK' = flag can be used to configure an individual AddXXX() call.
|
||||||
|
-- - "Scope" column: 'OK' = initialized by ImGui based on Style options (e.g. whether anti-aliased is enabled) + may be modified using ImDrawList::PushDrawFlag().
|
||||||
|
-- OK(0)/OK(1) indicates whether this flag is set in the default ImGui Style settings.
|
||||||
|
|
||||||
|
-- - Rounding default to ImDrawFlags_RoundAll when 'rounding > 0'.
|
||||||
|
-- - So you only need to use the ImDrawFlags_RoundXXX flags if you want a special configuration (e.g. a rectangle with one rounded corner).
|
||||||
-- Rounding for AddRectXXX(), PathRect() ------ -- Prim/Scope?
|
-- Rounding for AddRectXXX(), PathRect() ------ -- Prim/Scope?
|
||||||
RoundCornersTopLeft = bitLShift(1, 4), -- OK -- -- Round top-left corner only (when 'rounding > 0.0f', we default to all corners).
|
RoundTopLeft = bitLShift(1, 4), -- OK -- -- Round top-left corner only (when 'rounding > 0.0f', we default to all corners).
|
||||||
RoundCornersTopRight = bitLShift(1, 5), -- OK -- -- Round top-right corner only (when 'rounding > 0.0f', we default to all corners).
|
RoundTopRight = bitLShift(1, 5), -- OK -- -- Round top-right corner only (when 'rounding > 0.0f', we default to all corners).
|
||||||
RoundCornersBottomLeft = bitLShift(1, 6), -- OK -- -- Round bottom-left corner only (when 'rounding > 0.0f', we default to all corners).
|
RoundBottomLeft = bitLShift(1, 6), -- OK -- -- Round bottom-left corner only (when 'rounding > 0.0f', we default to all corners).
|
||||||
RoundCornersBottomRight = bitLShift(1, 7), -- OK -- -- Round bottom-right corner only (when 'rounding > 0.0f', we default to all corners).
|
RoundBottomRight = bitLShift(1, 7), -- OK -- -- Round bottom-right corner only (when 'rounding > 0.0f', we default to all corners).
|
||||||
RoundCornersNone = bitLShift(1, 8), -- OK -- -- Disable rounding even when 'rounding > 0.0f'. This value is NOT zero, it is NOT an implicit flag!
|
RoundNone = bitLShift(1, 8), -- OK -- -- Disable rounding even when 'rounding > 0.0f'. This value is NOT zero, it is NOT an implicit flag!
|
||||||
|
|
||||||
-- Stroke Options ----------------------------- -- Prim/Scope?
|
-- Stroke Options ----------------------------- -- Prim/Scope?
|
||||||
Closed = bitLShift(1, 9) -- OK -- -- PathStroke(), AddPolyline(): specify that shape should be closed.
|
Closed = bitLShift(1, 9), -- OK -- -- PathStroke(), AddPolyline(): specify that shape should be closed.
|
||||||
|
JoinMiter = bitLShift(1, 10), -- OK -- -- PathStroke(), AddPolyline(): use miter joins/corners only. This assumes that the input polyline does not have corners sharper than 90 degrees. Slightly faster.
|
||||||
|
CapSquare = bitLShift(1, 11), -- OK -- -- PathStroke(), AddPolyline(): use square cap line ends.
|
||||||
|
|
||||||
|
-- About Stroke Ends:
|
||||||
|
-- - Rendering is optimized for fast pixel-perfect UI, so line ends are not anti-aliased by default. It's cheaper (we can emit less vertices).
|
||||||
|
-- - For more free-form drawings, light graphs and markers, or when using thick strokes: you can turn them on using the ImDrawFlags_AALineEnds flag.
|
||||||
|
-- - See 'Demo->Examples->Custom Rendering' to interactively toy with those flags.
|
||||||
|
-- - 'OK*' indicates using this at the AddXXX() call site is unlikely: it would only makes sense if (1) the option is disabled in style/scope and (2) you want to forcefully enable it for a single primitives. Possible but unlikely! Only supported for functions taking flags inputs.
|
||||||
|
-- Stroke/Fill Anti-aliasing ------------------ -- Prim/Scope?
|
||||||
|
AAFill = bitLShift(1, 12), -- OK* OK(1) -- Enable anti-aliasing for Filled shapes.
|
||||||
|
AALines = bitLShift(1, 13), -- OK* OK(1) -- Enable anti-aliasing for Strokes (lines, borders).
|
||||||
|
AALineEnds = bitLShift(1, 14), -- OK OK(0) -- Enable anti-aliasing for Strokes Ends. Requires AALines to also be enabled. Useful on thick strokes or for precise continuity of multiple lines. A little more costly.
|
||||||
|
--ImDrawFlags_NoAA = 1 << 15, // OK -- // Disable anti-aliasing for a given primitive.
|
||||||
|
--ImDrawFlags_NoAALineEnds = 1 << 16, // OK -- // Disable anti-aliasing ends for a given primitive.
|
||||||
|
|
||||||
|
-- About Stroke Position:
|
||||||
|
-- - Read https://github.com/ocornut/imgui/wiki/Draw-List (this guide includes a precise list of differences between 1.92.9 and 1.93.0)
|
||||||
|
-- - Read https://github.com/ocornut/imgui/wiki/Pixel-Perfect-Rendering
|
||||||
|
-- Stroke Position relative to shape outline -- -- Prim/Scope?
|
||||||
|
StrokeInside = bitLShift(1, 17), -- OK -- -- Draw stroke inside of the shape outline (default for closed shapes and AddLineH, AddLineV functions)
|
||||||
|
StrokeCenter = bitLShift(2, 17), -- OK -- -- Draw stroke at the center of the shape outline (default for paths, bezier, and AddLine functions)
|
||||||
|
StrokeCenterBiased = bitLShift(3, 17), -- OK -- -- Draw stroke at the center of the shape outline, so that half thickness rounded down will be outside, and the rest inside the shape outline. Useful for axis-aligned shapes: AddLineH, AddLineV, AddRect. Does not animate well!
|
||||||
|
StrokeOutside = bitLShift(4, 17), -- OK -- -- Draw stroke outside of the shape outline
|
||||||
|
StrokeLegacy = bitLShift(7, 17), -- OK OK(0) -- Use legacy positioning + enable JoinMiter + disable AALineEnds. Must be all bits set.
|
||||||
|
|
||||||
|
-- Other Options ------------------------------ -- Prim/Scope?
|
||||||
|
TextNoPixelSnap = bitLShift(1, 20), -- OK OK(0) -- Disable automatically snapping AddText() calls to pixel boundaries.
|
||||||
|
UseTexForRoundCorners = bitLShift(1, 21), -- -- OK(1) -- Enable using textures instead of strokes to draw rounded corners/circles where possible (faster). Used by default unless 'ImFontAtlasFlags_NoBakedRoundCorners' is enabled in the font atlas.
|
||||||
|
UseVtxOffset = bitLShift(1, 22), -- -- OK(1) -- Can emit 'VtxOffset > 0' to allow large meshes with 16-bit ImDrawIdx. Used by default when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled by the backend.
|
||||||
|
AllowTexForRoundCorners_= bitLShift(1, 23), -- -- OK(1) -- [Internal]
|
||||||
}
|
}
|
||||||
|
ImDrawFlags.RoundAll = bitOr(ImDrawFlags.RoundTopLeft, ImDrawFlags.RoundTopRight, ImDrawFlags.RoundBottomLeft, ImDrawFlags.RoundBottomRight) -- (Default!!)
|
||||||
|
ImDrawFlags.RoundTop = bitOr(ImDrawFlags.RoundTopLeft, ImDrawFlags.RoundTopRight)
|
||||||
|
ImDrawFlags.RoundBottom = bitOr(ImDrawFlags.RoundBottomLeft, ImDrawFlags.RoundBottomRight)
|
||||||
|
ImDrawFlags.RoundLeft = bitOr(ImDrawFlags.RoundBottomLeft, ImDrawFlags.RoundTopLeft)
|
||||||
|
ImDrawFlags.RoundRight = bitOr(ImDrawFlags.RoundBottomRight, ImDrawFlags.RoundTopRight)
|
||||||
|
|
||||||
ImDrawFlags.RoundCornersTop = bitOr(ImDrawFlags.RoundCornersTopLeft, ImDrawFlags.RoundCornersTopRight)
|
-- [Internal]
|
||||||
ImDrawFlags.RoundCornersBottom = bitOr(ImDrawFlags.RoundCornersBottomLeft, ImDrawFlags.RoundCornersBottomRight)
|
ImDrawFlags.RoundMask_ = bitOr(ImDrawFlags.RoundAll, ImDrawFlags.RoundNone) -- [Internal]
|
||||||
ImDrawFlags.RoundCornersLeft = bitOr(ImDrawFlags.RoundCornersBottomLeft, ImDrawFlags.RoundCornersTopLeft)
|
ImDrawFlags.AllowInPushScope_ = bitOr(ImDrawFlags.AAFill, ImDrawFlags.AALines, ImDrawFlags.AALineEnds, ImDrawFlags.StrokeLegacy, ImDrawFlags.TextNoPixelSnap, ImDrawFlags.UseTexForRoundCorners, ImDrawFlags.UseVtxOffset, ImDrawFlags.RoundMask_) -- [Internal] Values allowed in PushDrawFlag() scope.
|
||||||
ImDrawFlags.RoundCornersRight = bitOr(ImDrawFlags.RoundCornersBottomRight, ImDrawFlags.RoundCornersTopRight)
|
ImDrawFlags.AllowInFrameScope_ = bitOr(ImDrawFlags.AllowInPushScope_, ImDrawFlags.AllowTexForRoundCorners_)
|
||||||
ImDrawFlags.RoundCornersAll = bitOr(ImDrawFlags.RoundCornersTopLeft, ImDrawFlags.RoundCornersTopRight, ImDrawFlags.RoundCornersBottomLeft, ImDrawFlags.RoundCornersBottomRight) -- (Default!!)
|
ImDrawFlags.StrokeMask_ = bitLShift(0x07, 17) -- [Internal]
|
||||||
ImDrawFlags.RoundCornersDefault_ = ImDrawFlags.RoundCornersAll
|
ImDrawFlags.InvalidMask_ = 0x8000000F -- [Internal] == ~0x7FFFFFF0 == 0x8000000F. Reserved to detect misuses.
|
||||||
ImDrawFlags.RoundCornersMask_ = bitOr(ImDrawFlags.RoundCornersAll, ImDrawFlags.RoundCornersNone) -- [Internal]
|
|
||||||
ImDrawFlags.InvalidMask_ = 0x8000000F -- [Internal] == 0x8000000F. Reserved to detect misuses.
|
|
||||||
|
|
||||||
|
-- Obsolete names
|
||||||
|
-- RENAMED in 1.93.0 (Oct 2026): ImDrawFlags_RoundCornersXXXX -> ImDrawFlags_RoundXXXX.
|
||||||
|
ImDrawFlags.RoundCornersTopLeft = ImDrawFlags.RoundTopLeft
|
||||||
|
ImDrawFlags.RoundCornersTopRight = ImDrawFlags.RoundTopRight
|
||||||
|
ImDrawFlags.RoundCornersBottomLeft = ImDrawFlags.RoundBottomLeft
|
||||||
|
ImDrawFlags.RoundCornersBottomRight = ImDrawFlags.RoundBottomRight
|
||||||
|
ImDrawFlags.RoundCornersNone = ImDrawFlags.RoundNone
|
||||||
|
ImDrawFlags.RoundCornersAll = ImDrawFlags.RoundAll
|
||||||
|
ImDrawFlags.RoundCornersTop = ImDrawFlags.RoundTop
|
||||||
|
ImDrawFlags.RoundCornersBottom = ImDrawFlags.RoundBottom
|
||||||
|
ImDrawFlags.RoundCornersLeft = ImDrawFlags.RoundLeft
|
||||||
|
ImDrawFlags.RoundCornersRight = ImDrawFlags.RoundRight
|
||||||
|
|
||||||
|
-- -- RENAMED in 1.93.0: Merged ImDrawListFlags into ImDrawFlags.
|
||||||
--- @enum ImDrawListFlags
|
--- @enum ImDrawListFlags
|
||||||
ImDrawListFlags = {
|
ImDrawListFlags = {
|
||||||
None = 0,
|
None = ImDrawFlags.None,
|
||||||
AntiAliasedLines = bitLShift(1, 0),
|
AntiAliasedFill = ImDrawFlags.AAFill,
|
||||||
AntiAliasedLinesUseTex = bitLShift(1, 1),
|
AntiAliasedLines = ImDrawFlags.AALines,
|
||||||
AntiAliasedFill = bitLShift(1, 2),
|
AntiAliasedLinesUseTex = ImDrawFlags.AALines, -- No effect, anti-aliased rendering always uses textures from 1.93+
|
||||||
AllowVtxOffset = bitLShift(1, 3),
|
AllowVtxOffset = ImDrawFlags.UseVtxOffset,
|
||||||
TextNoPixelSnap = bitLShift(1, 4)
|
TextNoPixelSnap = ImDrawFlags.TextNoPixelSnap,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Font flags
|
-- Font flags
|
||||||
@@ -1857,10 +2018,12 @@ ImGuiStyleVar = {
|
|||||||
DragDropTargetRounding = 37, -- float DragDropTargetRounding
|
DragDropTargetRounding = 37, -- float DragDropTargetRounding
|
||||||
ButtonTextAlign = 38, -- ImVec2 ButtonTextAlign
|
ButtonTextAlign = 38, -- ImVec2 ButtonTextAlign
|
||||||
SelectableTextAlign = 39, -- ImVec2 SelectableTextAlign
|
SelectableTextAlign = 39, -- ImVec2 SelectableTextAlign
|
||||||
SeparatorTextBorderSize = 40, -- float SeparatorTextBorderSize
|
SeparatorSize = 40, -- float SeparatorSize
|
||||||
SeparatorTextAlign = 41, -- ImVec2 SeparatorTextAlign
|
SeparatorTextBorderSize = 41, -- float SeparatorTextBorderSize
|
||||||
SeparatorTextPadding = 42, -- ImVec2 SeparatorTextPadding
|
SeparatorTextAlign = 42, -- ImVec2 SeparatorTextAlign
|
||||||
COUNT = 43
|
SeparatorTextPadding = 43, -- ImVec2 SeparatorTextPadding
|
||||||
|
DockingSeparatorSize = 44, -- float DockingSeparatorSize
|
||||||
|
COUNT = 45
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Flags for ImGui.IsItemHovered(), ImGui.IsWindowHovered()
|
-- Flags for ImGui.IsItemHovered(), ImGui.IsWindowHovered()
|
||||||
@@ -1949,8 +2112,9 @@ ImGuiKey = {
|
|||||||
RightCtrl = 531, RightShift = 532, RightAlt = 533, RightSuper = 534,
|
RightCtrl = 531, RightShift = 532, RightAlt = 533, RightSuper = 534,
|
||||||
Menu = 535,
|
Menu = 535,
|
||||||
|
|
||||||
-- 1 ~ 9
|
-- 0 ~ 9 (upstream ImGuiKey_0..ImGuiKey_9: K0..K9 in this port, ImGuiKey["0"]..ImGuiKey["9"] are aliases)
|
||||||
K0 = 536, K1 = 537, K2 = 538, K3 = 539, K4 = 540, K5 = 541, K6 = 542, K7 = 543, K8 = 544, K9 = 545,
|
K0 = 536, K1 = 537, K2 = 538, K3 = 539, K4 = 540, K5 = 541, K6 = 542, K7 = 543, K8 = 544, K9 = 545,
|
||||||
|
["0"] = 536, ["1"] = 537, ["2"] = 538, ["3"] = 539, ["4"] = 540, ["5"] = 541, ["6"] = 542, ["7"] = 543, ["8"] = 544, ["9"] = 545,
|
||||||
|
|
||||||
A = 546, B = 547, C = 548, D = 549, E = 550, F = 551, G = 552, H = 553, I = 554, J = 555,
|
A = 546, B = 547, C = 548, D = 549, E = 550, F = 551, G = 552, H = 553, I = 554, J = 555,
|
||||||
K = 556, L = 557, M = 558, N = 559, O = 560, P = 561, Q = 562, R = 563, S = 564, T = 565,
|
K = 556, L = 557, M = 558, N = 559, O = 560, P = 561, Q = 562, R = 563, S = 564, T = 565,
|
||||||
@@ -2119,6 +2283,10 @@ ImGuiDragDropFlags = {
|
|||||||
|
|
||||||
ImGuiDragDropFlags.AcceptPeekOnly = bitOr(ImGuiDragDropFlags.AcceptBeforeDelivery, ImGuiDragDropFlags.AcceptNoDrawDefaultRect) -- For peeking ahead and inspecting the payload before delivery.
|
ImGuiDragDropFlags.AcceptPeekOnly = bitOr(ImGuiDragDropFlags.AcceptBeforeDelivery, ImGuiDragDropFlags.AcceptNoDrawDefaultRect) -- For peeking ahead and inspecting the payload before delivery.
|
||||||
|
|
||||||
|
-- Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui.
|
||||||
|
IMGUI_PAYLOAD_TYPE_COLOR_3F = "_COL3F" -- float[3]: Standard type for colors, without alpha. User code may use this type. [Port] payload.Data = { r, g, b } (1-based)
|
||||||
|
IMGUI_PAYLOAD_TYPE_COLOR_4F = "_COL4F" -- float[4]: Standard type for colors. User code may use this type. [Port] payload.Data = { r, g, b, a } (1-based)
|
||||||
|
|
||||||
-- Helpers macros to generate 32-bit encoded colors
|
-- Helpers macros to generate 32-bit encoded colors
|
||||||
IM_COL32_R_SHIFT = 0
|
IM_COL32_R_SHIFT = 0
|
||||||
IM_COL32_G_SHIFT = 8
|
IM_COL32_G_SHIFT = 8
|
||||||
@@ -2173,7 +2341,7 @@ ImGuiComboFlags = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ImGuiComboFlags.HeightMask_ = bitOr(ImGuiComboFlags.HeightSmall, ImGuiComboFlags.HeightRegular, ImGuiComboFlags.HeightLarge, ImGuiComboFlags.HeightLargest)
|
ImGuiComboFlags.HeightMask_ = bitOr(ImGuiComboFlags.HeightSmall, ImGuiComboFlags.HeightRegular, ImGuiComboFlags.HeightLarge, ImGuiComboFlags.HeightLargest)
|
||||||
ImGuiComboFlags.CustomPreview = bitLShift(1, 20)
|
ImGuiComboFlags.CustomPreview = bitLShift(1, 20) -- [Luau] obsolete: removed in 1.93.0 (BeginComboPreview() no longer needs a flag), kept as an ignored value
|
||||||
|
|
||||||
-- Flags for ImGui.Selectable()
|
-- Flags for ImGui.Selectable()
|
||||||
--- @enum ImGuiSelectableFlags
|
--- @enum ImGuiSelectableFlags
|
||||||
@@ -2295,6 +2463,7 @@ function ImGuiWindowClass()
|
|||||||
TabItemFlagsOverrideSet = 0, -- [EXPERIMENTAL] TabItem flags to set when a window of this class gets submitted into a dock node tab bar. May use with ImGuiTabItemFlags.Leading or ImGuiTabItemFlags.Trailing.
|
TabItemFlagsOverrideSet = 0, -- [EXPERIMENTAL] TabItem flags to set when a window of this class gets submitted into a dock node tab bar. May use with ImGuiTabItemFlags.Leading or ImGuiTabItemFlags.Trailing.
|
||||||
DockNodeFlagsOverrideSet = 0, -- [EXPERIMENTAL] Dock node flags to set when a window of this class is hosted by a dock node (it doesn't have to be selected!)
|
DockNodeFlagsOverrideSet = 0, -- [EXPERIMENTAL] Dock node flags to set when a window of this class is hosted by a dock node (it doesn't have to be selected!)
|
||||||
DockingAlwaysTabBar = false, -- Set to true to enforce single floating windows of this class always having their own docking node (equivalent of setting the global io.ConfigDockingAlwaysTabBar)
|
DockingAlwaysTabBar = false, -- Set to true to enforce single floating windows of this class always having their own docking node (equivalent of setting the global io.ConfigDockingAlwaysTabBar)
|
||||||
|
PlatformIconData = nil, -- void* to hold custom data structure for the OS / platform to specify an icon. Currently unused for exposed to allow experiments.
|
||||||
DockingAllowUnclassed = true -- Set to true to allow windows of this class to be docked/merged with an unclassed window. -- FIXME-DOCK: Move to DockNodeFlags override?
|
DockingAllowUnclassed = true -- Set to true to allow windows of this class to be docked/merged with an unclassed window. -- FIXME-DOCK: Move to DockNodeFlags override?
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
@@ -2418,7 +2587,8 @@ function MT.ImGuiInputTextCallbackData:InsertChars(pos, new_text)
|
|||||||
self.SelectionStart = self.CursorPos; self.SelectionEnd = self.CursorPos
|
self.SelectionStart = self.CursorPos; self.SelectionEnd = self.CursorPos
|
||||||
end
|
end
|
||||||
|
|
||||||
function MT.ImGuiInputTextCallbackData:SelectAll() self.SelectionStart = 0; self.SelectionEnd = self.BufTextLen end
|
function MT.ImGuiInputTextCallbackData:SelectAll() self.SelectionStart = 0; self.CursorPos = self.BufTextLen; self.SelectionEnd = self.BufTextLen end
|
||||||
|
function MT.ImGuiInputTextCallbackData:SetSelection(s, e) IM_ASSERT(s >= 0 and s <= self.BufTextLen); IM_ASSERT(e >= 0 and e <= self.BufTextLen); self.SelectionStart = s; self.CursorPos = e; self.SelectionEnd = e end
|
||||||
function MT.ImGuiInputTextCallbackData:ClearSelection() self.SelectionStart = self.BufTextLen; self.SelectionEnd = self.BufTextLen end
|
function MT.ImGuiInputTextCallbackData:ClearSelection() self.SelectionStart = self.BufTextLen; self.SelectionEnd = self.BufTextLen end
|
||||||
function MT.ImGuiInputTextCallbackData:HasSelection() return self.SelectionStart ~= self.SelectionEnd end
|
function MT.ImGuiInputTextCallbackData:HasSelection() return self.SelectionStart ~= self.SelectionEnd end
|
||||||
|
|
||||||
@@ -2617,6 +2787,17 @@ ImGuiTableBgTarget = { None = 0, RowBg0 = 1, RowBg1 = 2, CellBg = 3 }
|
|||||||
--- @enum ImGuiSortDirection
|
--- @enum ImGuiSortDirection
|
||||||
ImGuiSortDirection = { None = 0, Ascending = 1, Descending = 2 }
|
ImGuiSortDirection = { None = 0, Ascending = 1, Descending = 2 }
|
||||||
|
|
||||||
|
-- Resizing callback data to apply custom constraint. As enabled by SetNextWindowSizeConstraints(). Callback is called during the next Begin().
|
||||||
|
-- NB: For basic min/max size constraint on each axis you don't need to use the callback! The SetNextWindowSizeConstraints() parameters are enough.
|
||||||
|
--- @class ImGuiSizeCallbackData
|
||||||
|
--- @field UserData any Read-only. What user passed to SetNextWindowSizeConstraints(). Generally store an integer or float in here.
|
||||||
|
--- @field Pos ImVec2 Read-only. Window position, for reference.
|
||||||
|
--- @field CurrentSize ImVec2 Read-only. Current window size.
|
||||||
|
--- @field DesiredSize ImVec2 Read-write. Desired size, based on user's mouse position. Write to this field to restrain resizing.
|
||||||
|
--- @return ImGuiSizeCallbackData
|
||||||
|
function ImGuiSizeCallbackData()
|
||||||
|
return { UserData = nil, Pos = ImVec2(), CurrentSize = ImVec2(), DesiredSize = ImVec2() }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload()
|
-- Data payload for Drag and Drop operations: AcceptDragDropPayload(), GetDragDropPayload()
|
||||||
@@ -2640,6 +2821,13 @@ function ImGuiPayload_IsDelivery(p) return p.Delivery end
|
|||||||
-- [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)
|
-- [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Flags for ImGuiListClipper (currently not fully exposed in function calls: a future refactor will likely add this to ImGuiListClipper::Begin function equivalent)
|
||||||
|
--- @enum ImGuiListClipperFlags
|
||||||
|
ImGuiListClipperFlags = {
|
||||||
|
None = 0,
|
||||||
|
NoSetTableRowCounters = bitLShift(1, 0), -- [Internal] Disabled modifying table row counters. Avoid assumption that 1 clipper item == 1 table row.
|
||||||
|
}
|
||||||
|
|
||||||
-- Helper: Growable text buffer for logging/accumulating text
|
-- Helper: Growable text buffer for logging/accumulating text
|
||||||
-- (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder')
|
-- (this could be called 'ImGuiTextBuilder' / 'ImGuiStringBuilder')
|
||||||
--- @class ImGuiTextBuffer # string builder: Buf is a list of string chunks
|
--- @class ImGuiTextBuffer # string builder: Buf is a list of string chunks
|
||||||
@@ -2653,6 +2841,148 @@ function ImGuiTextBufferMT:appendf(fmt, ...) self.Buf[#self.Buf + 1] = string.fo
|
|||||||
function ImGuiTextBufferMT:c_str() return table.concat(self.Buf) end
|
function ImGuiTextBufferMT:c_str() return table.concat(self.Buf) end
|
||||||
function ImGuiTextBufferMT:size() return #self:c_str() end
|
function ImGuiTextBufferMT:size() return #self:c_str() end
|
||||||
|
|
||||||
|
-- Helpers: ImColor() implicitly converts colors to either ImU32 (packed 4x1 byte) or ImVec4 (4x1 float)
|
||||||
|
-- Prefer using IM_COL32() macros. Avoid storing ImColor! Store either u32 of ImVec4. This is not a full-featured color class.
|
||||||
|
-- **None of the ImGui API are using ImColor directly but you can use it as a convenience to pass colors in either ImU32 or ImVec4 formats. Explicitly cast to ImU32 or ImVec4 if needed.
|
||||||
|
-- [Luau] no implicit conversions: use :U32() / .Value (ImVec4). Overloads: ImColor(), ImColor(r, g, b, a) floats,
|
||||||
|
-- ImColor(ImVec4), ImColor(ImU32). The C++ int (0-255) overload can't be told apart from floats: use ImColor(IM_COL32(r, g, b, a)).
|
||||||
|
--- @class ImColor
|
||||||
|
local ImColorMT = {}
|
||||||
|
ImColorMT.__index = ImColorMT
|
||||||
|
ImColor = setmetatable({}, { __call = function(_, r, g, b, a)
|
||||||
|
local self = setmetatable({ Value = ImVec4() }, ImColorMT)
|
||||||
|
if type(r) == "table" then
|
||||||
|
ImVec4_Copy(self.Value, r)
|
||||||
|
elseif r ~= nil and g == nil then
|
||||||
|
local s = 1.0 / 255.0
|
||||||
|
self.Value.x = bit32.band(bit32.rshift(r, IM_COL32_R_SHIFT), 0xFF) * s; self.Value.y = bit32.band(bit32.rshift(r, IM_COL32_G_SHIFT), 0xFF) * s
|
||||||
|
self.Value.z = bit32.band(bit32.rshift(r, IM_COL32_B_SHIFT), 0xFF) * s; self.Value.w = bit32.band(bit32.rshift(r, IM_COL32_A_SHIFT), 0xFF) * s
|
||||||
|
elseif r ~= nil then
|
||||||
|
self.Value.x = r; self.Value.y = g; self.Value.z = b; self.Value.w = a or 1.0
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end })
|
||||||
|
function ImColorMT:U32() return ImGui.ColorConvertFloat4ToU32(self.Value) end
|
||||||
|
-- FIXME-OBSOLETE: May need to obsolete/cleanup those helpers.
|
||||||
|
function ImColorMT:SetHSV(h, s, v, a) self.Value.x, self.Value.y, self.Value.z = ImGui.ColorConvertHSVtoRGB(h, s, v); self.Value.w = a or 1.0 end
|
||||||
|
function ImColor.HSV(h, s, v, a) local r, g, b = ImGui.ColorConvertHSVtoRGB(h, s, v); return ImColor(r, g, b, a or 1.0) end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiSelectionRequestType, ImGuiSelectionRequest, ImGuiMultiSelectIO, ImGuiSelectionBasicStorage)
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Multi-selection system
|
||||||
|
-- Documentation at: https://github.com/ocornut/imgui/wiki/Multi-Select
|
||||||
|
-- - Refer to 'Demo->Widgets->Selection State & Multi-Select' for demos using this.
|
||||||
|
-- - This system implements standard multi-selection idioms (Ctrl+Mouse/Keyboard, Shift+Mouse/Keyboard, etc)
|
||||||
|
-- with support for clipper (skipping non-visible items), box-select and many other details.
|
||||||
|
-- - Selectable(), Checkbox() are supported but custom widgets may use it as well.
|
||||||
|
-- - TreeNode() is technically supported but... using this correctly is more complicated: you need some sort of linear/random access to your tree,
|
||||||
|
-- which is suited to advanced trees setups also implementing filters and clipper. We will work toward simplifying and demoing it.
|
||||||
|
-- - In the spirit of Dear ImGui design, your code owns actual selection data.
|
||||||
|
-- This is designed to allow all kinds of selection storage you may use in your application e.g. set/map/hash.
|
||||||
|
-- About ImGuiSelectionBasicStorage:
|
||||||
|
-- - This is an optional helper to store a selection state and apply selection requests.
|
||||||
|
-- - It is used by our demos and provided as a convenience to quickly implement multi-selection.
|
||||||
|
-- Usage:
|
||||||
|
-- - Identify submitted items with SetNextItemSelectionUserData(), most likely using an index into your current data-set.
|
||||||
|
-- - Store and maintain actual selection data using persistent object identifiers.
|
||||||
|
-- - Usage flow:
|
||||||
|
-- BEGIN - (1) Call BeginMultiSelect() and retrieve the ImGuiMultiSelectIO result.
|
||||||
|
-- - (2) Honor request list (SetAll/SetRange requests) by updating your selection data. Same code as Step 6.
|
||||||
|
-- - (3) [If using clipper] You need to make sure RangeSrcItem is always submitted. Calculate its index and pass to clipper:IncludeItemByIndex(). If storing indices in ImGuiSelectionUserData, a simple clipper:IncludeItemByIndex(ms_io.RangeSrcItem) call will work.
|
||||||
|
-- LOOP - (4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
|
||||||
|
-- END - (5) Call EndMultiSelect() and retrieve the ImGuiMultiSelectIO result.
|
||||||
|
-- - (6) Honor request list (SetAll/SetRange requests) by updating your selection data. Same code as Step 2.
|
||||||
|
-- If you submit all items (no clipper), Step 2 and 3 are optional and will be handled by each item themselves. It is fine to always honor those steps.
|
||||||
|
-- About ImGuiSelectionUserData:
|
||||||
|
-- - This can store an application-defined identifier (e.g. index or pointer) submitted via SetNextItemSelectionUserData().
|
||||||
|
-- - In return we store them into RangeSrcItem/RangeFirstItem/RangeLastItem and other fields in ImGuiMultiSelectIO.
|
||||||
|
-- - Most applications will store an object INDEX, hence the chosen name and type. Storing an index is natural, because
|
||||||
|
-- SetRange requests will give you two end-points and you will need to iterate/interpolate between them to update your selection.
|
||||||
|
-- - However it is perfectly possible to store a POINTER or another IDENTIFIER inside ImGuiSelectionUserData.
|
||||||
|
-- Our system never assume that you identify items by indices, it never attempts to interpolate between two values.
|
||||||
|
-- - If you enable ImGuiMultiSelectFlags.NoRangeSelect then it is guaranteed that you will never have to interpolate
|
||||||
|
-- between two ImGuiSelectionUserData, which may be a convenient way to use part of the feature with less code work.
|
||||||
|
-- - As most users will want to store an index, for convenience and to reduce confusion we use ImS64 instead of void*,
|
||||||
|
-- being syntactically easier to downcast. Feel free to reinterpret_cast and store a pointer inside.
|
||||||
|
-- [Port] ImGuiSelectionUserData is any Lua value compared with '==' (an integer index, or e.g. a table reference instead of a pointer).
|
||||||
|
-- -1 (ImGuiSelectionUserData_Invalid) is reserved. ImGuiSelectionBasicStorage/ImGuiSelectionExternalStorage require integer indices.
|
||||||
|
|
||||||
|
-- Flags for BeginMultiSelect()
|
||||||
|
--- @enum ImGuiMultiSelectFlags
|
||||||
|
ImGuiMultiSelectFlags = {
|
||||||
|
None = 0,
|
||||||
|
SingleSelect = bitLShift(1, 0), -- Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho!
|
||||||
|
NoSelectAll = bitLShift(1, 1), -- Disable Ctrl+A shortcut to select all.
|
||||||
|
NoRangeSelect = bitLShift(1, 2), -- Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is also ensure contiguous SetRange requests are not combined into one. This allows not handling interpolation in SetRange requests.
|
||||||
|
NoAutoSelect = bitLShift(1, 3), -- Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes).
|
||||||
|
NoAutoClear = bitLShift(1, 4), -- Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags.NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes).
|
||||||
|
NoAutoClearOnReselect = bitLShift(1, 5), -- Disable clearing selection when clicking/selecting an already selected item.
|
||||||
|
BoxSelect1d = bitLShift(1, 6), -- Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space.
|
||||||
|
BoxSelect2d = bitLShift(1, 7), -- Enable box-selection with varying width or varying x pos items support (e.g. different width labels, or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items.
|
||||||
|
BoxSelectNoScroll = bitLShift(1, 8), -- Disable scrolling when box-selecting and moving mouse near edges of scope.
|
||||||
|
ClearOnEscape = bitLShift(1, 9), -- Clear selection when pressing Escape while scope is focused.
|
||||||
|
ClearOnClickVoid = bitLShift(1, 10), -- Clear selection when clicking on empty location within scope.
|
||||||
|
ScopeWindow = bitLShift(1, 11), -- Scope for _BoxSelect and _ClearOnClickVoid is whole window (Default). Use if BeginMultiSelect() covers a whole window or used a single time in same window.
|
||||||
|
ScopeRect = bitLShift(1, 12), -- Scope for _BoxSelect and _ClearOnClickVoid is rectangle encompassing BeginMultiSelect()/EndMultiSelect(). Use if BeginMultiSelect() is called multiple times in same window.
|
||||||
|
SelectOnAuto = bitLShift(1, 13), -- Apply selection on mouse down when clicking on unselected item, on mouse up when clicking on selected item. (Default)
|
||||||
|
SelectOnClickAlways = bitLShift(1, 14), -- Apply selection on mouse down when clicking on any items. Prevents Drag and Drop from being used on multiple-selection, but allows e.g. BoxSelect to always reselect even when clicking inside an existing selection. (Excel style behavior)
|
||||||
|
SelectOnClickRelease = bitLShift(1, 15), -- Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection.
|
||||||
|
--RangeSelect2d = bitLShift(1, 15), -- Shift+Selection uses 2d geometry instead of linear sequence, so possible to use Shift+up/down to select vertically in grid. Analogous to what BoxSelect does.
|
||||||
|
NavWrapX = bitLShift(1, 16), -- [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one.
|
||||||
|
NoSelectOnRightClick = bitLShift(1, 17), -- Disable default right-click processing, which selects item on mouse down, and is designed for context-menus.
|
||||||
|
CheckboxMode_ = bitLShift(1, 20), -- [Internal]
|
||||||
|
}
|
||||||
|
ImGuiMultiSelectFlags.SelectOnMask_ = bit32.bor(ImGuiMultiSelectFlags.SelectOnAuto, ImGuiMultiSelectFlags.SelectOnClickAlways, ImGuiMultiSelectFlags.SelectOnClickRelease)
|
||||||
|
ImGuiMultiSelectFlags.SelectOnClick = ImGuiMultiSelectFlags.SelectOnAuto -- RENAMED in 1.92.6
|
||||||
|
|
||||||
|
-- Main IO structure returned by BeginMultiSelect()/EndMultiSelect().
|
||||||
|
-- This mainly contains a list of selection requests.
|
||||||
|
-- - Use 'Demo->Tools->Debug Log->Selection' to see requests as they happen.
|
||||||
|
-- - Some fields are only useful if your list is dynamic and allows deletion (getting post-deletion focus/state right is shown in the demo)
|
||||||
|
-- - Below: who reads/writes each fields? 'r'=read, 'w'=write, 'ms'=multi-select code, 'app'=application/user code.
|
||||||
|
--- @class ImGuiMultiSelectIO
|
||||||
|
--- @field Requests ImVector<ImGuiSelectionRequest> # ms:w, app:r / ms:w app:r // Requests to apply to your selection data. (1-based .Data)
|
||||||
|
--- @field RangeSrcItem ImGuiSelectionUserData # ms:w app:r / // (If using clipper) Begin: Source item (often the first selected item) must never be clipped: use clipper:IncludeItemByIndex() to ensure it is submitted.
|
||||||
|
--- @field NavIdItem ImGuiSelectionUserData # ms:w, app:r / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items).
|
||||||
|
--- @field NavIdSelected bool # ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId (if part of submitted items).
|
||||||
|
--- @field RangeSrcReset bool # app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection).
|
||||||
|
--- @field ItemsCount int # ms:w, app:r / app:r // 'int items_count' parameter to BeginMultiSelect() is copied here for convenience, allowing simpler calls to your ApplyRequests handler. Not used internally.
|
||||||
|
|
||||||
|
-- Selection request type
|
||||||
|
--- @enum ImGuiSelectionRequestType
|
||||||
|
ImGuiSelectionRequestType = {
|
||||||
|
None = 0,
|
||||||
|
SetAll = 1, -- Request app to clear selection (if Selected==false) or select all items (if Selected==true). We cannot set RangeFirstItem/RangeLastItem as its contents is entirely up to user (not necessarily an index)
|
||||||
|
SetRange = 2, -- Request app to select/unselect [RangeFirstItem..RangeLastItem] items (inclusive) based on value of Selected. Only EndMultiSelect() request this, app code can read after BeginMultiSelect() and it will always be false.
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Selection request item
|
||||||
|
--- @class ImGuiSelectionRequest
|
||||||
|
--- @field Type ImGuiSelectionRequestType # ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 Clear + 1 SetRange with a single-item range.
|
||||||
|
--- @field Selected bool # ms:w, app:r / ms:w, app:r // Parameter for SetAll/SetRange requests (true = select, false = unselect)
|
||||||
|
--- @field RangeDirection int # / ms:w app:r // Parameter for SetRange request: +1 when RangeFirstItem comes before RangeLastItem, -1 otherwise. Useful if you want to preserve selection order on a backward Shift+Click.
|
||||||
|
--- @field RangeFirstItem ImGuiSelectionUserData # / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom).
|
||||||
|
--- @field RangeLastItem ImGuiSelectionUserData # / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top). Inclusive!
|
||||||
|
function ImGuiSelectionRequest()
|
||||||
|
return { Type = ImGuiSelectionRequestType.None, Selected = false, RangeDirection = 0, RangeFirstItem = -1, RangeLastItem = -1 }
|
||||||
|
end
|
||||||
|
-- [Port] ImVector<ImGuiSelectionRequest> copy function: push_back() copies fields into the preallocated element (C++ copies by value),
|
||||||
|
-- so callers can push a reused scratch request without allocating.
|
||||||
|
function ImGuiSelectionRequest_Copy(t, k, v)
|
||||||
|
local dst = t[k]
|
||||||
|
dst.Type = v.Type; dst.Selected = v.Selected; dst.RangeDirection = v.RangeDirection; dst.RangeFirstItem = v.RangeFirstItem; dst.RangeLastItem = v.RangeLastItem
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @return ImGuiMultiSelectIO
|
||||||
|
function ImGuiMultiSelectIO()
|
||||||
|
return { Requests = ImVector(ImGuiSelectionRequest, ImGuiSelectionRequest_Copy), RangeSrcItem = -1, NavIdItem = -1, NavIdSelected = false, RangeSrcReset = false, ItemsCount = 0 }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage: see [SECTION] Widgets: Multi-Select helpers in imgui_widgets.lua
|
||||||
|
-- (constructors and methods are defined there, like upstream's out-of-line definitions in imgui_widgets.cpp).
|
||||||
|
|
||||||
--- @class ImGuiSettingsHandler
|
--- @class ImGuiSettingsHandler
|
||||||
--- Fns take (ctx, handler, ...) like upstream. ReadOpenFn(ctx, handler, name) returns entry; ReadLineFn(ctx, handler, entry, line);
|
--- Fns take (ctx, handler, ...) like upstream. ReadOpenFn(ctx, handler, name) returns entry; ReadLineFn(ctx, handler, entry, line);
|
||||||
--- WriteAllFn(ctx, handler, buf: ImGuiTextBuffer)
|
--- WriteAllFn(ctx, handler, buf: ImGuiTextBuffer)
|
||||||
|
|||||||
+557
-54
@@ -258,12 +258,18 @@ end
|
|||||||
|
|
||||||
function IM_ROUNDUP_TO_EVEN(n) return (ImCeil((n) / 2) * 2) end
|
function IM_ROUNDUP_TO_EVEN(n) return (ImCeil((n) / 2) * 2) end
|
||||||
function ImRsqrt(x) return (1 / ImSqrt(x)) end
|
function ImRsqrt(x) return (1 / ImSqrt(x)) end
|
||||||
|
-- Converge to more precise solution using single step of Newton-Raphson method, repeating increases precision
|
||||||
|
function ImRsqrtPrecise(x) return (1 / ImSqrt(x)) end -- [Luau] non-SSE upstream variant
|
||||||
|
|
||||||
|
function ImIsTruncated(x) return x % 1 == 0 end -- (float)(int)x == x
|
||||||
|
-- Returns true if all parameters are whole numbers.
|
||||||
|
function ImIsTruncated4(x, y, z, w) return x % 1 == 0 and y % 1 == 0 and z % 1 == 0 and w % 1 == 0 end
|
||||||
|
|
||||||
function IM_TRUNC(VAL) return math.floor(VAL) end -- Positive values only!
|
function IM_TRUNC(VAL) return math.floor(VAL) end -- Positive values only!
|
||||||
function IM_ROUND(VAL) return math.floor(VAL + 0.5) end -- Positive values only!
|
function IM_ROUND(VAL) return math.floor(VAL + 0.5) end -- Positive values only!
|
||||||
|
|
||||||
--@hoist
|
--@hoist
|
||||||
function ImFloor(f) if f >= 0 or math.floor(f) == f then return math.floor(f) else return math.floor(f) - 1 end end -- Decent replacement for floorf()
|
function ImFloor(f) return math.floor(f) end -- Decent replacement for floorf() -- [Luau] upstream: (int)f truncates, -1 for negatives == math.floor
|
||||||
|
|
||||||
-- Helpers: Bit manipulation
|
-- Helpers: Bit manipulation
|
||||||
--- @param v int
|
--- @param v int
|
||||||
@@ -386,6 +392,16 @@ end
|
|||||||
--@hoist
|
--@hoist
|
||||||
function ImSaturate(f) return ((f < 0.0 and 0.0) or (f > 1.0 and 1.0) or f) end
|
function ImSaturate(f) return ((f < 0.0 and 0.0) or (f > 1.0 and 1.0) or f) end
|
||||||
|
|
||||||
|
--- @param x float
|
||||||
|
--- @return float # Sign operator - returns -1, 0 or 1 based on sign of argument
|
||||||
|
function ImSign(x) if x < 0.0 then return -1.0 elseif x > 0.0 then return 1.0 end return 0.0 end
|
||||||
|
|
||||||
|
function ImLinearRemapClamp(s0, s1, d0, d1, x) return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0 end
|
||||||
|
|
||||||
|
--- @param c int # byte
|
||||||
|
--- @return int
|
||||||
|
function ImToUpper(c) if c >= 97 and c <= 122 then return bit32.band(c, bit32.bnot(32)) end return c end
|
||||||
|
|
||||||
IM_F32_TO_INT8_UNBOUND = function(val) return math.floor(val * 255.0 + (val >= 0 and 0.5 or -0.5)) end -- Unsaturated, for display purpose
|
IM_F32_TO_INT8_UNBOUND = function(val) return math.floor(val * 255.0 + (val >= 0 and 0.5 or -0.5)) end -- Unsaturated, for display purpose
|
||||||
IM_F32_TO_INT8_SAT = function(val) return math.floor(ImSaturate(val) * 255.0 + 0.5) end -- Saturated, always output 0..255
|
IM_F32_TO_INT8_SAT = function(val) return math.floor(ImSaturate(val) * 255.0 + 0.5) end -- Saturated, always output 0..255
|
||||||
|
|
||||||
@@ -445,6 +461,18 @@ function ImMul(lhs, rhs)
|
|||||||
return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y)
|
return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param a ImVec2
|
||||||
|
--- @param b ImVec2
|
||||||
|
--- @param c ImVec2
|
||||||
|
--- @return float
|
||||||
|
function ImTriangleArea(a, b, c) return ImFabs((a.x * (b.y - c.y)) + (b.x * (c.y - a.y)) + (c.x * (a.y - b.y))) * 0.5 end
|
||||||
|
|
||||||
|
--- @param a ImVec2
|
||||||
|
--- @param b ImVec2
|
||||||
|
--- @param c ImVec2
|
||||||
|
--- @return boolean
|
||||||
|
function ImTriangleIsClockwise(a, b, c) return ((b.x - a.x) * (c.y - b.y)) - ((c.x - b.x) * (b.y - a.y)) > 0.0 end
|
||||||
|
|
||||||
--- @param str char[]
|
--- @param str char[]
|
||||||
--- @param begin? int
|
--- @param begin? int
|
||||||
function ImStd.ImStrlen(str, begin)
|
function ImStd.ImStrlen(str, begin)
|
||||||
@@ -499,6 +527,13 @@ IMGUI_WINDOW_HARD_MIN_SIZE = 4.0
|
|||||||
IM_DRAWLIST_ARCFAST_TABLE_SIZE = 48 -- Number of samples in adaptive arc drawing lookup table.
|
IM_DRAWLIST_ARCFAST_TABLE_SIZE = 48 -- Number of samples in adaptive arc drawing lookup table.
|
||||||
IM_DRAWLIST_ARCFAST_SAMPLE_MAX = IM_DRAWLIST_ARCFAST_TABLE_SIZE -- Sample index _PathArcToFastEx() for 360 angle.
|
IM_DRAWLIST_ARCFAST_SAMPLE_MAX = IM_DRAWLIST_ARCFAST_TABLE_SIZE -- Sample index _PathArcToFastEx() for 360 angle.
|
||||||
|
|
||||||
|
IM_DRAWLIST_TEX_LINES_WIDTH_MAX = 32 -- The maximum line width to bake anti-aliased textures for.
|
||||||
|
IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH = 4 -- Calculate detailed textures for width [1..IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH]
|
||||||
|
IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT = 4 -- How many samples per integer thickness level.
|
||||||
|
IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX = 16
|
||||||
|
IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX = 4 -- 0: fill, 1-3: strokes thickness
|
||||||
|
IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT = ((IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH - 1) * IM_DRAWLIST_TEX_LINES_SAMPLE_COUNT + 1)
|
||||||
|
|
||||||
-- Macros used by Recoverable Error handling
|
-- Macros used by Recoverable Error handling
|
||||||
-- - Only dispatch error if _EXPR: evaluate as assert (similar to an assert macro).
|
-- - Only dispatch error if _EXPR: evaluate as assert (similar to an assert macro).
|
||||||
-- - The message will always be a string literal, in order to increase likelihood of being display by an assert handler.
|
-- - The message will always be a string literal, in order to increase likelihood of being display by an assert handler.
|
||||||
@@ -658,6 +693,12 @@ end
|
|||||||
--- @nodiscard
|
--- @nodiscard
|
||||||
function ImGui.WindowPosAbsToRel(window, p) local off = window.DC.CursorStartPos return ImVec2(p.x - off.x, p.y - off.y) end
|
function ImGui.WindowPosAbsToRel(window, p) local off = window.DC.CursorStartPos return ImVec2(p.x - off.x, p.y - off.y) end
|
||||||
|
|
||||||
|
--- @param window ImGuiWindow
|
||||||
|
--- @param p ImVec2
|
||||||
|
--- @return ImVec2
|
||||||
|
--- @nodiscard
|
||||||
|
function ImGui.WindowPosRelToAbs(window, p) local off = window.DC.CursorStartPos return ImVec2(p.x + off.x, p.y + off.y) end
|
||||||
|
|
||||||
--- @param c char
|
--- @param c char
|
||||||
--- @return bool # True if this character is a ' ' or '\t'
|
--- @return bool # True if this character is a ' ' or '\t'
|
||||||
function ImCharIsBlankA(c) return c == 32 or c == 9 end
|
function ImCharIsBlankA(c) return c == 32 or c == 9 end
|
||||||
@@ -665,6 +706,27 @@ function ImCharIsBlankA(c) return c == 32 or c == 9 end
|
|||||||
--- @param c char
|
--- @param c char
|
||||||
function ImCharIsBlankW(c) return c == 32 or c == 9 or c == 0x3000 end
|
function ImCharIsBlankW(c) return c == 32 or c == 9 or c == 0x3000 end
|
||||||
|
|
||||||
|
--- @param c char
|
||||||
|
function ImCharIsXdigitA(c) return (c >= 48 and c <= 57) or (c >= 65 and c <= 70) or (c >= 97 and c <= 102) end
|
||||||
|
|
||||||
|
--- @param lhs ImVec2
|
||||||
|
--- @param fail_value float
|
||||||
|
function ImInvLength(lhs, fail_value) local d = (lhs.x * lhs.x) + (lhs.y * lhs.y); if d > 0.0 then return ImRsqrt(d) end; return fail_value end
|
||||||
|
function ImRoundPositive64(f) return _Trunc(f + 0.5) end -- Positive values only.
|
||||||
|
function ImRoundSigned64(f) if f >= 0.0 then return _Trunc(f + 0.5) else return _Trunc(f - 0.5) end end
|
||||||
|
-- [Luau] C '%' truncates toward zero; math.fmod matches it
|
||||||
|
function ImModPositive(a, b) return math.fmod(a + b, b) end
|
||||||
|
function ImIsFloatAboveGuaranteedIntegerPrecision(f) return f <= -16777216 or f >= 16777216 end
|
||||||
|
|
||||||
|
-- Helper: ImVec2i (2D vector, integer) / ImVec2ih (2D vector, half-size integer, for long-term packed storage)
|
||||||
|
-- [Luau] both are plain ImVec2 holding whole numbers
|
||||||
|
function ImVec2i(x, y) return ImVec2(x or 0, y or 0) end
|
||||||
|
--- @overload fun(rhs: ImVec2): ImVec2
|
||||||
|
function ImVec2ih(x, y)
|
||||||
|
if type(x) == "table" then return ImVec2(_Trunc(x.x), _Trunc(x.y)) end
|
||||||
|
return ImVec2(x or 0, y or 0)
|
||||||
|
end
|
||||||
|
|
||||||
--- @enum ImGuiNavMoveFlags
|
--- @enum ImGuiNavMoveFlags
|
||||||
ImGuiNavMoveFlags =
|
ImGuiNavMoveFlags =
|
||||||
{
|
{
|
||||||
@@ -880,6 +942,9 @@ function IM_RECT:Add(p)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function IM_RECT:AddX(x) if self.Min.x > x then self.Min.x = x end if self.Max.x < x then self.Max.x = x end end
|
||||||
|
function IM_RECT:AddY(y) if self.Min.y > y then self.Min.y = y end if self.Max.y < y then self.Max.y = y end end
|
||||||
|
|
||||||
--- @param amount float|ImVec2
|
--- @param amount float|ImVec2
|
||||||
@native
|
@native
|
||||||
function IM_RECT:Expand(amount)
|
function IM_RECT:Expand(amount)
|
||||||
@@ -960,6 +1025,28 @@ function ImBitArraySetBit(arr, n)
|
|||||||
arr[idx] = bitOr(arr[idx], mask)
|
arr[idx] = bitOr(arr[idx], mask)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- [Luau] bit arrays are ImU32[] tables with 1-based word indices; bit indices 'n' are 1-based like the functions above
|
||||||
|
--- @param bitcount int
|
||||||
|
function ImBitArrayGetStorageSizeInBytes(bitcount) return bitLShift(bitRShift(bitcount + 31, 5), 2) end
|
||||||
|
--- @param arr ImU32[]
|
||||||
|
--- @param bitcount int
|
||||||
|
function ImBitArrayClearAllBits(arr, bitcount) for i = 1, bitRShift(bitcount + 31, 5) do arr[i] = 0 end end
|
||||||
|
function ImBitArrayTestBit(arr, n) local mask = bitLShift(1, bitAnd(n - 1, 31)); return bitAnd(arr[bitRShift(n - 1, 5) + 1], mask) ~= 0 end
|
||||||
|
function ImBitArrayClearBit(arr, n) local mask = bitLShift(1, bitAnd(n - 1, 31)); local idx = bitRShift(n - 1, 5) + 1; arr[idx] = bitAnd(arr[idx], bitNot(mask)) end
|
||||||
|
-- Works on range [n..n2)
|
||||||
|
function ImBitArraySetBitRange(arr, n, n2)
|
||||||
|
n = n - 1; n2 = n2 - 1 -- [Luau] to 0-based
|
||||||
|
n2 = n2 - 1
|
||||||
|
while n <= n2 do
|
||||||
|
local a_mod = bitAnd(n, 31)
|
||||||
|
local b_mod = ((n2 > bitOr(n, 31)) and 31 or bitAnd(n2, 31)) + 1
|
||||||
|
local mask = bitAnd(2 ^ b_mod - 1, bitNot(2 ^ a_mod - 1))
|
||||||
|
local idx = bitRShift(n, 5) + 1
|
||||||
|
arr[idx] = bitOr(arr[idx], mask)
|
||||||
|
n = bitAnd(n + 32, bitNot(31))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Bit array for named keys
|
-- Bit array for named keys
|
||||||
--- @alias ImBitArrayForNamedKeys ImBitArray
|
--- @alias ImBitArrayForNamedKeys ImBitArray
|
||||||
|
|
||||||
@@ -986,15 +1073,34 @@ function ImBitArray(BITCOUNT, OFFSET)
|
|||||||
--- @param n int # 1-based
|
--- @param n int # 1-based
|
||||||
this.SetBit = function(self, n) n = n + OFFSET; IM_ASSERT(n >= 1 and n <= BITCOUNT); ImBitArraySetBit(self.Data, n); end
|
this.SetBit = function(self, n) n = n + OFFSET; IM_ASSERT(n >= 1 and n <= BITCOUNT); ImBitArraySetBit(self.Data, n); end
|
||||||
|
|
||||||
|
--- @param n int # 1-based
|
||||||
|
this.ClearBit = function(self, n) n = n + OFFSET; IM_ASSERT(n >= 1 and n <= BITCOUNT); ImBitArrayClearBit(self.Data, n); end
|
||||||
|
--- @param n int # 1-based, range [n..n2)
|
||||||
|
this.SetBitRange = function(self, n, n2) n = n + OFFSET; n2 = n2 + OFFSET; IM_ASSERT(n >= 1 and n <= BITCOUNT and n2 > n and n2 <= BITCOUNT + 1); ImBitArraySetBitRange(self.Data, n, n2); end
|
||||||
|
|
||||||
this:ClearAllBits()
|
this:ClearAllBits()
|
||||||
|
|
||||||
return this
|
return this
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Helper: ImBitVector
|
||||||
|
-- Store 1-bit per value.
|
||||||
|
--- @class ImBitVector
|
||||||
|
--- @field Storage ImVector<ImU32>
|
||||||
|
MT.ImBitVector = {}
|
||||||
|
MT.ImBitVector.__index = MT.ImBitVector
|
||||||
|
function ImBitVector() return setmetatable({ Storage = ImVector() }, MT.ImBitVector) end
|
||||||
|
function MT.ImBitVector:Create(sz) self.Storage:resize(bitRShift(sz + 31, 5)); for i = 1, self.Storage.Size do self.Storage.Data[i] = 0 end end
|
||||||
|
function MT.ImBitVector:Clear() self.Storage:clear() end
|
||||||
|
--- @param n int # 1-based
|
||||||
|
function MT.ImBitVector:TestBit(n) IM_ASSERT(n <= bitLShift(self.Storage.Size, 5)); return IM_BITARRAY_TESTBIT(self.Storage.Data, n) end
|
||||||
|
function MT.ImBitVector:SetBit(n) IM_ASSERT(n <= bitLShift(self.Storage.Size, 5)); ImBitArraySetBit(self.Storage.Data, n) end
|
||||||
|
function MT.ImBitVector:ClearBit(n) IM_ASSERT(n <= bitLShift(self.Storage.Size, 5)); ImBitArrayClearBit(self.Storage.Data, n) end
|
||||||
|
|
||||||
-- Stateful path API, add points then finish with PathFillConvex() or PathStroke()
|
-- Stateful path API, add points then finish with PathFillConvex() or PathStroke()
|
||||||
-- - Important: filled shapes must always use clockwise winding order! The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
|
-- - Important: filled shapes must always use clockwise winding order! The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
|
||||||
-- so e.g. 'PathArcTo(center, radius, PI * -0.5, PI)' is ok, whereas 'PathArcTo(center, radius, PI, PI * -0.5)' won't have correct anti-aliasing when followed by PathFillConvex().
|
-- so e.g. 'PathArcTo(center, radius, PI * -0.5, PI)' is ok, whereas 'PathArcTo(center, radius, PI, PI * -0.5)' won't have correct anti-aliasing when followed by PathFillConvex().
|
||||||
function MT.ImDrawList:PathClear() self._Path:clear() end
|
function MT.ImDrawList:PathClear() self._Path.Size = 0 end
|
||||||
|
|
||||||
--- @param pos ImVec2
|
--- @param pos ImVec2
|
||||||
@native
|
@native
|
||||||
@@ -1015,9 +1121,11 @@ function MT.ImDrawList:PathLineToMergeDuplicate(pos)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--- @param col ImU32
|
||||||
|
--- @param flags? ImDrawFlags
|
||||||
@native
|
@native
|
||||||
function MT.ImDrawList:PathFillConvex(col)
|
function MT.ImDrawList:PathFillConvex(col, flags)
|
||||||
self:AddConvexPolyFilled(self._Path.Data, self._Path.Size, col)
|
self:AddConvexPolyFilled(self._Path.Data, self._Path.Size, col, flags)
|
||||||
self._Path.Size = 0
|
self._Path.Size = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1028,10 +1136,23 @@ function MT.ImDrawList:PathStroke(col, thickness, flags)
|
|||||||
if not thickness then thickness = 1.0 end
|
if not thickness then thickness = 1.0 end
|
||||||
if not flags then flags = 0 end
|
if not flags then flags = 0 end
|
||||||
|
|
||||||
self:AddPolyline(self._Path.Data, self._Path.Size, col, thickness, flags)
|
self:_AddPolyline(self._Path.Data, self._Path.Size, col, thickness, flags, FLT_MAX)
|
||||||
self._Path.Size = 0
|
self._Path.Size = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- General polygon
|
||||||
|
-- - Only simple polygons are supported by filling functions (no self-intersections, no holes).
|
||||||
|
-- - Concave polygon fill is more expensive than convex one: it has O(N^2) complexity. Provided as a convenience for the user but not used by the main library.
|
||||||
|
--- @param points ImVec2[] # 1-based
|
||||||
|
--- @param num_points int
|
||||||
|
--- @param col ImU32
|
||||||
|
--- @param thickness float
|
||||||
|
--- @param flags? ImDrawFlags
|
||||||
|
function MT.ImDrawList:AddPolyline(points, num_points, col, thickness, flags)
|
||||||
|
if not flags then flags = 0 end
|
||||||
|
self:_AddPolyline(points, num_points, col, thickness, flags, FLT_MAX)
|
||||||
|
end
|
||||||
|
|
||||||
--- @param col ImU32
|
--- @param col ImU32
|
||||||
function ImGui.SetNextItemColorMarker(col)
|
function ImGui.SetNextItemColorMarker(col)
|
||||||
local g = GImGui
|
local g = GImGui
|
||||||
@@ -1049,15 +1170,15 @@ end
|
|||||||
-- You may want to create your own instance of you try to ImDrawList completely without ImGui. In that case, watch out for future changes to this structure.
|
-- You may want to create your own instance of you try to ImDrawList completely without ImGui. In that case, watch out for future changes to this structure.
|
||||||
--- @class ImDrawListSharedData
|
--- @class ImDrawListSharedData
|
||||||
--- @field TexUvWhitePixel ImVec2 # UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel)
|
--- @field TexUvWhitePixel ImVec2 # UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel)
|
||||||
--- @field TexUvLines ImVec4[] # UV of anti-aliased lines in the atlas (== FontAtlas->Builder->TexUvLines)
|
--- @field TexUvLines ImVec4[] # 0-based. UV of anti-aliased lines in the atlas (== FontAtlas->Builder->TexUvLines)
|
||||||
|
--- @field TexUvCorners ImVec4[] # 0-based. UV of rounded corner (== FontAtlas->Builder->TexUvCorners)
|
||||||
--- @field FontAtlas ImFontAtlas # Current font atlas
|
--- @field FontAtlas ImFontAtlas # Current font atlas
|
||||||
--- @field Font ImFont # Current font (used for simplified AddText overload)
|
--- @field Font ImFont # Current font (used for simplified AddText overload)
|
||||||
--- @field FontSize float # Current font size (used for simplified AddText overload)
|
--- @field FontSize float # Current font size (used for simplified AddText overload)
|
||||||
--- @field FontScale float # Current font scale (== FontSize / Font->FontSize)
|
--- @field FontScale float # Current font scale (== FontSize / Font->FontSize)
|
||||||
--- @field CurveTessellationTol float
|
--- @field CurveTessellationMaxError float # Tessellation tolerance when using PathBezierCurveTo()
|
||||||
--- @field CircleTessellationMaxError float # Number of circle segments to use per pixel of radius for AddCircle() etc
|
--- @field CircleTessellationMaxError float # Number of circle segments to use per pixel of radius for AddCircle() etc
|
||||||
--- @field InitialFringeScale float
|
--- @field InitialDrawFlags ImDrawFlags # Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
|
||||||
--- @field InitialFlags ImDrawListFlags
|
|
||||||
--- @field ClipRectFullscreen? ImVec4 # Value for PushClipRectFullscreen()
|
--- @field ClipRectFullscreen? ImVec4 # Value for PushClipRectFullscreen()
|
||||||
--- @field TempBuffer ImVector<ImVec2> # Temporary write buffer
|
--- @field TempBuffer ImVector<ImVec2> # Temporary write buffer
|
||||||
--- @field DrawLists ImVector<ImDrawList> # All draw lists associated to this ImDrawListSharedData
|
--- @field DrawLists ImVector<ImDrawList> # All draw lists associated to this ImDrawListSharedData
|
||||||
@@ -1074,17 +1195,16 @@ function ImDrawListSharedData()
|
|||||||
local this = setmetatable({
|
local this = setmetatable({
|
||||||
TexUvWhitePixel = nil, -- UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel)
|
TexUvWhitePixel = nil, -- UV of white pixel in the atlas (== FontAtlas->TexUvWhitePixel)
|
||||||
TexUvLines = nil, -- UV of anti-aliased lines in the atlas (== FontAtlas->Builder->TexUvLines)
|
TexUvLines = nil, -- UV of anti-aliased lines in the atlas (== FontAtlas->Builder->TexUvLines)
|
||||||
|
TexUvCorners = nil, -- UV of rounded corner (== FontAtlas->Builder->TexUvCorners)
|
||||||
FontAtlas = nil, -- Current font atlas
|
FontAtlas = nil, -- Current font atlas
|
||||||
|
|
||||||
Font = nil, -- Current font (used for simplified AddText overload)
|
Font = nil, -- Current font (used for simplified AddText overload)
|
||||||
FontSize = 0, -- Current font size (used for simplified AddText overload)
|
FontSize = 0, -- Current font size (used for simplified AddText overload)
|
||||||
FontScale = 0, -- Current font scale (== FontSize / Font->FontSize)
|
FontScale = 0, -- Current font scale (== FontSize / Font->FontSize)
|
||||||
|
|
||||||
CurveTessellationTol = 0,
|
CurveTessellationMaxError = 0, -- Tessellation tolerance when using PathBezierCurveTo()
|
||||||
CircleTessellationMaxError = 0, -- Number of circle segments to use per pixel of radius for AddCircle() etc
|
CircleTessellationMaxError = 0, -- Number of circle segments to use per pixel of radius for AddCircle() etc
|
||||||
InitialFringeScale = 1,
|
InitialDrawFlags = 0, -- Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
|
||||||
|
|
||||||
InitialFlags = 0,
|
|
||||||
ClipRectFullscreen = nil, -- Value for PushClipRectFullscreen()
|
ClipRectFullscreen = nil, -- Value for PushClipRectFullscreen()
|
||||||
TempBuffer = ImVector(ImVec2), -- Temporary write buffer
|
TempBuffer = ImVector(ImVec2), -- Temporary write buffer
|
||||||
DrawLists = ImVector(), -- All draw lists associated to this ImDrawListSharedData
|
DrawLists = ImVector(), -- All draw lists associated to this ImDrawListSharedData
|
||||||
@@ -1127,6 +1247,10 @@ end
|
|||||||
--- @field BakedDiscardedCount int
|
--- @field BakedDiscardedCount int
|
||||||
--- @field PackIdMouseCursors ImFontAtlasRectId
|
--- @field PackIdMouseCursors ImFontAtlasRectId
|
||||||
--- @field PackIdLinesTexData ImFontAtlasRectId
|
--- @field PackIdLinesTexData ImFontAtlasRectId
|
||||||
|
--- @field PackIdLineFractTexData ImFontAtlasRectId
|
||||||
|
--- @field PackIdCornersTexData ImFontAtlasRectId
|
||||||
|
--- @field TexUvLines ImVec4[] # 0-based. UVs for baked anti-aliased lines (u0, u1, v, 1/thickness)
|
||||||
|
--- @field TexUvCorners ImVec4[] # 0-based. UVs for baked anti-aliased corners (0= fill, 1> stroke thickness)
|
||||||
MT.ImFontAtlasBuilder = {}
|
MT.ImFontAtlasBuilder = {}
|
||||||
MT.ImFontAtlasBuilder.__index = MT.ImFontAtlasBuilder
|
MT.ImFontAtlasBuilder.__index = MT.ImFontAtlasBuilder
|
||||||
|
|
||||||
@@ -1159,6 +1283,14 @@ function ImFontAtlasBuilder()
|
|||||||
-- Custom rectangle identifiers
|
-- Custom rectangle identifiers
|
||||||
this.PackIdMouseCursors = -1 -- White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
|
this.PackIdMouseCursors = -1 -- White pixel + mouse cursors. Also happen to be fallback in case of packing failure.
|
||||||
this.PackIdLinesTexData = -1
|
this.PackIdLinesTexData = -1
|
||||||
|
this.PackIdLineFractTexData = -1
|
||||||
|
this.PackIdCornersTexData = -1
|
||||||
|
|
||||||
|
-- Cached UV coordinates
|
||||||
|
this.TexUvLines = {} -- [IM_DRAWLIST_TEX_LINES_WIDTH_MAX + 1 + IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT] UVs for baked anti-aliased lines (u0, u1, v, 1/thickness) -- 0-based
|
||||||
|
this.TexUvCorners = {} -- [IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX * IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX] UVs for baked anti-aliased corners (0= fill, 1> stroke thickness) -- 0-based
|
||||||
|
for n = 0, IM_DRAWLIST_TEX_LINES_WIDTH_MAX + IM_DRAWLIST_TEX_LINES_DETAILED_WIDTH_COUNT do this.TexUvLines[n] = ImVec4() end
|
||||||
|
for n = 0, IM_DRAWLIST_TEX_CORNERS_ROUNDING_MAX * IM_DRAWLIST_TEX_CORNERS_THICKNESS_MAX - 1 do this.TexUvCorners[n] = ImVec4() end
|
||||||
|
|
||||||
return this
|
return this
|
||||||
end
|
end
|
||||||
@@ -1196,9 +1328,13 @@ end
|
|||||||
--- @param key string
|
--- @param key string
|
||||||
--- @return ImGuiStyleVarInfo
|
--- @return ImGuiStyleVarInfo
|
||||||
--- @nodiscard
|
--- @nodiscard
|
||||||
|
MT.ImGuiStyleVarInfo = {}
|
||||||
|
MT.ImGuiStyleVarInfo.__index = MT.ImGuiStyleVarInfo
|
||||||
function ImGuiStyleVarInfo(count, data_type, key)
|
function ImGuiStyleVarInfo(count, data_type, key)
|
||||||
return { Count = count, DataType = data_type, Key = key }
|
return setmetatable({ Count = count, DataType = data_type, Key = key }, MT.ImGuiStyleVarInfo)
|
||||||
end
|
end
|
||||||
|
-- [Luau] no pointers: returns the field value (number, or the live ImVec2 table) of 'parent' (e.g. ImGuiStyle)
|
||||||
|
function MT.ImGuiStyleVarInfo:GetVarPtr(parent) return parent[self.Key] end
|
||||||
|
|
||||||
-- Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
|
-- Stacked style modifier, backup of modified data so we can restore it. Data type inferred from the variable.
|
||||||
--- @class ImGuiStyleMod
|
--- @class ImGuiStyleMod
|
||||||
@@ -1313,11 +1449,11 @@ end
|
|||||||
--- @field RefVal any
|
--- @field RefVal any
|
||||||
--- @field StorageId ImGuiID
|
--- @field StorageId ImGuiID
|
||||||
--- @field ColorMarker ImU32
|
--- @field ColorMarker ImU32
|
||||||
local IMGUI_NEXT_ITEM_DATA = {}
|
MT.ImGuiNextItemData = {}
|
||||||
IMGUI_NEXT_ITEM_DATA.__index = IMGUI_NEXT_ITEM_DATA
|
MT.ImGuiNextItemData.__index = MT.ImGuiNextItemData
|
||||||
|
|
||||||
-- Also cleared manually by ItemAdd()!
|
-- Also cleared manually by ItemAdd()!
|
||||||
function IMGUI_NEXT_ITEM_DATA:ClearFlags()
|
function MT.ImGuiNextItemData:ClearFlags()
|
||||||
self.HasFlags = ImGuiNextItemDataFlags.None
|
self.HasFlags = ImGuiNextItemDataFlags.None
|
||||||
self.ItemFlagsSet = ImGuiItemFlags.None
|
self.ItemFlagsSet = ImGuiItemFlags.None
|
||||||
end
|
end
|
||||||
@@ -1340,7 +1476,7 @@ function ImGuiNextItemData()
|
|||||||
RefVal = 0, -- Not exposed yet, for ImGuiInputTextFlags.ParseEmptyAsRefVal
|
RefVal = 0, -- Not exposed yet, for ImGuiInputTextFlags.ParseEmptyAsRefVal
|
||||||
StorageId = 0, -- Set by SetNextItemStorageID()
|
StorageId = 0, -- Set by SetNextItemStorageID()
|
||||||
ColorMarker = 0 -- Set by SetNextItemColorMarker(). Not exposed yet, supported by DragScalar,SliderScalar and for ImGuiSliderFlags.ColorMarkers.
|
ColorMarker = 0 -- Set by SetNextItemColorMarker(). Not exposed yet, supported by DragScalar,SliderScalar and for ImGuiSliderFlags.ColorMarkers.
|
||||||
}, IMGUI_NEXT_ITEM_DATA)
|
}, MT.ImGuiNextItemData)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Storage for SetNexWindow** functions
|
-- Storage for SetNexWindow** functions
|
||||||
@@ -1363,10 +1499,10 @@ end
|
|||||||
--- @field BgAlphaVal number?
|
--- @field BgAlphaVal number?
|
||||||
--- @field MenuBarOffsetMinVal ImVec2?
|
--- @field MenuBarOffsetMinVal ImVec2?
|
||||||
--- @field RefreshFlagsVal int?
|
--- @field RefreshFlagsVal int?
|
||||||
local IMGUI_NEXT_WINDOW_DATA = {}
|
MT.ImGuiNextWindowData = {}
|
||||||
IMGUI_NEXT_WINDOW_DATA.__index = IMGUI_NEXT_WINDOW_DATA
|
MT.ImGuiNextWindowData.__index = MT.ImGuiNextWindowData
|
||||||
|
|
||||||
function IMGUI_NEXT_WINDOW_DATA:ClearFlags()
|
function MT.ImGuiNextWindowData:ClearFlags()
|
||||||
self.HasFlags = ImGuiNextWindowDataFlags.None
|
self.HasFlags = ImGuiNextWindowDataFlags.None
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1405,7 +1541,7 @@ function ImGuiNextWindowData()
|
|||||||
RefreshFlagsVal = nil,
|
RefreshFlagsVal = nil,
|
||||||
CacheKeySet = false, -- [Port] SetNextWindowCached()
|
CacheKeySet = false, -- [Port] SetNextWindowCached()
|
||||||
CacheKeyVal = nil
|
CacheKeyVal = nil
|
||||||
}, IMGUI_NEXT_WINDOW_DATA)
|
}, MT.ImGuiNextWindowData)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @enum ImGuiWindowBgClickFlags
|
--- @enum ImGuiWindowBgClickFlags
|
||||||
@@ -1442,6 +1578,30 @@ ImGuiLayoutType =
|
|||||||
Vertical = 1
|
Vertical = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
--- @enum ImGuiLogFlags
|
||||||
|
ImGuiLogFlags =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
OutputTTY = bitLShift(1, 0),
|
||||||
|
OutputFile = bitLShift(1, 1),
|
||||||
|
OutputBuffer = bitLShift(1, 2),
|
||||||
|
OutputClipboard = bitLShift(1, 3),
|
||||||
|
}
|
||||||
|
ImGuiLogFlags.OutputMask_ = bitOr(ImGuiLogFlags.OutputTTY, ImGuiLogFlags.OutputFile, ImGuiLogFlags.OutputBuffer, ImGuiLogFlags.OutputClipboard)
|
||||||
|
|
||||||
|
-- Flags for internal's BeginColumns(). This is an obsolete API. Prefer using BeginTable() nowadays!
|
||||||
|
--- @enum ImGuiOldColumnFlags
|
||||||
|
ImGuiOldColumnFlags =
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
NoBorder = bitLShift(1, 0), -- Disable column dividers
|
||||||
|
NoResize = bitLShift(1, 1), -- Disable resizing columns when clicking on the dividers
|
||||||
|
NoPreserveWidths = bitLShift(1, 2), -- Disable column width preservation when adjusting columns
|
||||||
|
NoForceWithinWindow = bitLShift(1, 3), -- Disable forcing columns to fit within window
|
||||||
|
GrowParentContentsSize = bitLShift(1, 4), -- Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove.
|
||||||
|
}
|
||||||
|
|
||||||
--- @enum ImGuiSeparatorFlags
|
--- @enum ImGuiSeparatorFlags
|
||||||
ImGuiSeparatorFlags =
|
ImGuiSeparatorFlags =
|
||||||
{
|
{
|
||||||
@@ -1507,11 +1667,10 @@ function ImGuiStyle()
|
|||||||
DisplayWindowPadding = ImVec2(19, 19), -- Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
|
DisplayWindowPadding = ImVec2(19, 19), -- Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
|
||||||
|
|
||||||
-- Rendering & Tessellation
|
-- Rendering & Tessellation
|
||||||
AntiAliasedLines = true, -- Enable anti-aliased lines/borders. Used at the beginning of the frame to set ImDrawListFlags.AntiAliasedLines in all draw-lists.
|
AntiAliasedLines = true, -- Enable anti-aliased lines/borders. Used at the beginning of the frame to set ImDrawFlags_AALines in all draw-lists.
|
||||||
AntiAliasedLinesUseTex = true, -- Enable anti-aliased lines/borders using textures for legacy strokes. Require backend to render with bilinear filtering (NOT point/nearest filtering).
|
AntiAliasedLineEnds = false, -- Enable anti-aliased lines/borders ends. Nicer for thick lines but more expensive. Used at the beginning of the frame to set ImDrawFlags_AALineEnds in all draw-lists.
|
||||||
AntiAliasedFill = true, -- Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Used at the beginning of the frame to set ImDrawListFlags.AntiAliasedFill in all draw-lists.
|
AntiAliasedFill = true, -- Enable anti-aliased edges around filled shapes (rounded rectangles, circles, etc.). Used at the beginning of the frame to set ImDrawFlags_AAFill in all draw-lists.
|
||||||
|
CurveTessellationMaxError = 1.12, -- Maximum error (in pixels) when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
||||||
CurveTessellationTol = 1.25, -- Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
|
|
||||||
CircleTessellationMaxError = 0.30, -- Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
|
CircleTessellationMaxError = 0.30, -- Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
|
||||||
|
|
||||||
-- Behaviors
|
-- Behaviors
|
||||||
@@ -1564,7 +1723,11 @@ function ImGuiStyle()
|
|||||||
|
|
||||||
-- [Internal]
|
-- [Internal]
|
||||||
_MainScale = 1.0,
|
_MainScale = 1.0,
|
||||||
_NextFrameFontSizeBase = 0.0
|
_NextFrameFontSizeBase = 0.0,
|
||||||
|
|
||||||
|
-- Obsolete names (#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS)
|
||||||
|
CurveTessellationTol = 0.0, -- [OBSOLETE] Old CurveTessellationTol = CurveTessellationMaxError*CurveTessellationMaxError.
|
||||||
|
AntiAliasedLinesUseTex = true, -- [OBSOLETE] Enable anti-aliased lines/borders using textures for legacy strokes. Require backend to render with bilinear filtering (NOT point/nearest filtering).
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Default theme
|
-- Default theme
|
||||||
@@ -1586,7 +1749,8 @@ function ImGuiWindowStackData()
|
|||||||
ParentLastItemDataBackup = ImGuiLastItemData(),
|
ParentLastItemDataBackup = ImGuiLastItemData(),
|
||||||
StackSizesInBegin = nil, -- Store size of various stacks for asserting
|
StackSizesInBegin = nil, -- Store size of various stacks for asserting
|
||||||
DisabledOverrideReenable = nil, -- Non-child window override disabled flag
|
DisabledOverrideReenable = nil, -- Non-child window override disabled flag
|
||||||
DisabledOverrideReenableAlphaBackup = nil
|
DisabledOverrideReenableAlphaBackup = nil,
|
||||||
|
ParentLastComboPreviewRect = ImRect(),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1608,7 +1772,10 @@ local function ImGuiComboPreviewData()
|
|||||||
BackupCursorMaxPos = ImVec2(),
|
BackupCursorMaxPos = ImVec2(),
|
||||||
BackupCursorPosPrevLine = ImVec2(),
|
BackupCursorPosPrevLine = ImVec2(),
|
||||||
BackupPrevLineTextBaseOffset = 0.0,
|
BackupPrevLineTextBaseOffset = 0.0,
|
||||||
BackupLayout = 0
|
BackupLayout = 0,
|
||||||
|
BackupWorkRectMaxX = 0.0,
|
||||||
|
BackupContentRectMaxX = 0.0,
|
||||||
|
WithinPreview = false,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1665,21 +1832,30 @@ local function ImGuiInputTextState()
|
|||||||
SelectedAllMouseLock = false, -- after a double-click to select all, we ignore further mouse drags to update selection
|
SelectedAllMouseLock = false, -- after a double-click to select all, we ignore further mouse drags to update selection
|
||||||
EditedBefore = false, -- edited since activated
|
EditedBefore = false, -- edited since activated
|
||||||
EditedThisFrame = false, -- edited this frame
|
EditedThisFrame = false, -- edited this frame
|
||||||
|
ValidatedThisFrame = false, -- validated this frame (e.g. Enter pressed)
|
||||||
|
WantReloadUserBuf = false, -- force a reload of user buf so it may be modified externally. may be automatic in future version.
|
||||||
|
LastMoveDirectionLR = ImGuiDir.Left, -- ImGuiDir_Left or ImGuiDir_Right. track last movement direction so when cursor cross over a word-wrapping boundaries we can display it on either line depending on last move.s
|
||||||
|
ReloadSelectionStart = 0,
|
||||||
|
ReloadSelectionEnd = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
return setmetatable(this, MT.ImGuiInputTextState)
|
return setmetatable(this, MT.ImGuiInputTextState)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function MT.ImGuiInputTextState:ClearText() self.TextLen = 0; self.TextA.Data[1] = 0; self:CursorClamp() end
|
||||||
|
function MT.ImGuiInputTextState:ClearFreeMemory() self.TextA:clear(); self.TextToRevertTo:clear() end
|
||||||
|
function MT.ImGuiInputTextState:GetText() if self.TextA.Data then return self.TextA.Data else return { 0 } end end -- [Luau] byte table (char[])
|
||||||
|
|
||||||
-- Internal temporary state for deactivating InputText() instances.
|
-- Internal temporary state for deactivating InputText() instances.
|
||||||
-- Store as part of ImGuiDeactivatedItemData?
|
-- Store as part of ImGuiDeactivatedItemData?
|
||||||
--- @class ImGuiInputTextDeactivatedState
|
--- @class ImGuiInputTextDeactivatedState
|
||||||
--- @field ID ImGuiID # widget id owning the text state (which just got deactivated)
|
--- @field ID ImGuiID # widget id owning the text state (which just got deactivated)
|
||||||
--- @field ElapseFrame int
|
--- @field ElapseFrame int
|
||||||
--- @field TextA ImVector<char> # text buffer
|
--- @field TextA ImVector<char> # text buffer
|
||||||
local IMGUI_INPUT_TEXT_DEACTIVATED_STATE = {}
|
MT.ImGuiInputTextDeactivatedState = {}
|
||||||
IMGUI_INPUT_TEXT_DEACTIVATED_STATE.__index = IMGUI_INPUT_TEXT_DEACTIVATED_STATE
|
MT.ImGuiInputTextDeactivatedState.__index = MT.ImGuiInputTextDeactivatedState
|
||||||
|
|
||||||
function IMGUI_INPUT_TEXT_DEACTIVATED_STATE:ClearFreeMemory()
|
function MT.ImGuiInputTextDeactivatedState:ClearFreeMemory()
|
||||||
self.ID = 0
|
self.ID = 0
|
||||||
self.ElapseFrame = 0
|
self.ElapseFrame = 0
|
||||||
self.TextA:clear()
|
self.TextA:clear()
|
||||||
@@ -1692,7 +1868,7 @@ local function ImGuiInputTextDeactivatedState()
|
|||||||
ID = 0, -- widget id owning the text state (which just got deactivated)
|
ID = 0, -- widget id owning the text state (which just got deactivated)
|
||||||
ElapseFrame = 0,
|
ElapseFrame = 0,
|
||||||
TextA = ImVector() -- text buffer
|
TextA = ImVector() -- text buffer
|
||||||
}, IMGUI_INPUT_TEXT_DEACTIVATED_STATE)
|
}, MT.ImGuiInputTextDeactivatedState)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @alias ImGuiKeyRoutingIndex ImS16
|
--- @alias ImGuiKeyRoutingIndex ImS16
|
||||||
@@ -1725,10 +1901,10 @@ end
|
|||||||
--- @field Index ImGuiKeyRoutingIndex[] # Index of first entry in Entries[]
|
--- @field Index ImGuiKeyRoutingIndex[] # Index of first entry in Entries[]
|
||||||
--- @field Entries ImVector<ImGuiKeyRoutingData>
|
--- @field Entries ImVector<ImGuiKeyRoutingData>
|
||||||
--- @field EntriesNext ImVector<ImGuiKeyRoutingData> # Double-buffer to avoid reallocation (could use a shared buffer)
|
--- @field EntriesNext ImVector<ImGuiKeyRoutingData> # Double-buffer to avoid reallocation (could use a shared buffer)
|
||||||
local _ImGuiKeyRoutingTable = {}
|
MT.ImGuiKeyRoutingTable = {}
|
||||||
_ImGuiKeyRoutingTable.__index = _ImGuiKeyRoutingTable
|
MT.ImGuiKeyRoutingTable.__index = MT.ImGuiKeyRoutingTable
|
||||||
|
|
||||||
function _ImGuiKeyRoutingTable:Clear()
|
function MT.ImGuiKeyRoutingTable:Clear()
|
||||||
for n = 1, ImGuiKey.NamedKey_COUNT do self.Index[n] = -1 end
|
for n = 1, ImGuiKey.NamedKey_COUNT do self.Index[n] = -1 end
|
||||||
self.Entries:clear()
|
self.Entries:clear()
|
||||||
self.EntriesNext:clear()
|
self.EntriesNext:clear()
|
||||||
@@ -1740,7 +1916,7 @@ local function ImGuiKeyRoutingTable()
|
|||||||
Index = {}, -- Index of first entry in Entries[]
|
Index = {}, -- Index of first entry in Entries[]
|
||||||
Entries = ImVector(),
|
Entries = ImVector(),
|
||||||
EntriesNext = ImVector() -- Double-buffer to avoid reallocation (could use a shared buffer)
|
EntriesNext = ImVector() -- Double-buffer to avoid reallocation (could use a shared buffer)
|
||||||
}, _ImGuiKeyRoutingTable)
|
}, MT.ImGuiKeyRoutingTable)
|
||||||
|
|
||||||
this:Clear()
|
this:Clear()
|
||||||
|
|
||||||
@@ -1757,12 +1933,14 @@ IMGUI_TEXT_INDEX.__index = IMGUI_TEXT_INDEX
|
|||||||
|
|
||||||
function IMGUI_TEXT_INDEX:clear() self.Offsets:clear(); self.EndOffset = 0; end
|
function IMGUI_TEXT_INDEX:clear() self.Offsets:clear(); self.EndOffset = 0; end
|
||||||
|
|
||||||
|
function IMGUI_TEXT_INDEX:size() return self.Offsets.Size end
|
||||||
|
-- [Port] 'n' is a 0-based line number like upstream (Offsets.Data is 1-based), 'base' the 1-based position of the buffer start; returns 1-based positions
|
||||||
function IMGUI_TEXT_INDEX:get_line_begin(base, n)
|
function IMGUI_TEXT_INDEX:get_line_begin(base, n)
|
||||||
return base + (self.Offsets.Size ~= 0 and self.Offsets[n] or 0)
|
return base + (self.Offsets.Size ~= 0 and self.Offsets.Data[n + 1] or 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
function IMGUI_TEXT_INDEX:get_line_end(base, n)
|
function IMGUI_TEXT_INDEX:get_line_end(base, n)
|
||||||
return base + ((n + 1 < self.Offsets.Size) and (self.Offsets[n + 1] - 1) or self.EndOffset)
|
return base + ((n + 1 < self.Offsets.Size) and (self.Offsets.Data[n + 2] - 1) or self.EndOffset)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- @return ImGuiTextIndex
|
--- @return ImGuiTextIndex
|
||||||
@@ -1808,8 +1986,23 @@ end
|
|||||||
local function ImGuiMetricsConfig()
|
local function ImGuiMetricsConfig()
|
||||||
return
|
return
|
||||||
{
|
{
|
||||||
|
ShowDebugLog = false,
|
||||||
|
ShowIDStackTool = false,
|
||||||
|
ShowWindowsRects = false,
|
||||||
|
ShowWindowsBeginOrder = false,
|
||||||
|
ShowTablesRects = false,
|
||||||
|
ShowDrawCmdMesh = true,
|
||||||
|
ShowDrawCmdBoundingBoxes = true,
|
||||||
|
ShowTextEncodingViewer = false,
|
||||||
|
ShowTextureUsedRect = false,
|
||||||
|
ShowDockingNodes = false,
|
||||||
|
ShowWindowsRectsType = -1,
|
||||||
|
ShowTablesRectsType = -1,
|
||||||
HighlightMonitorIdx = -1,
|
HighlightMonitorIdx = -1,
|
||||||
HighlightViewportID = 0,
|
HighlightViewportID = 0,
|
||||||
|
SettingsDiscardMonths = 6,
|
||||||
|
SettingsHighlightOldEntries = false,
|
||||||
|
ShowFontPreview = true,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -1824,10 +2017,10 @@ end
|
|||||||
--- @field DistBox float # Move -- Best candidate box distance to current NavId
|
--- @field DistBox float # Move -- Best candidate box distance to current NavId
|
||||||
--- @field DistCenter float # Move -- Best candidate center distance to current NavId
|
--- @field DistCenter float # Move -- Best candidate center distance to current NavId
|
||||||
--- @field DistAxial float # Move -- Best candidate axial distance to current NavId
|
--- @field DistAxial float # Move -- Best candidate axial distance to current NavId
|
||||||
local IMGUI_NAV_ITEM_DATA = {}
|
MT.ImGuiNavItemData = {}
|
||||||
IMGUI_NAV_ITEM_DATA.__index = IMGUI_NAV_ITEM_DATA
|
MT.ImGuiNavItemData.__index = MT.ImGuiNavItemData
|
||||||
|
|
||||||
function IMGUI_NAV_ITEM_DATA:Clear()
|
function MT.ImGuiNavItemData:Clear()
|
||||||
self.Window = nil
|
self.Window = nil
|
||||||
self.ID = 0
|
self.ID = 0
|
||||||
self.FocusScopeId = 0
|
self.FocusScopeId = 0
|
||||||
@@ -1840,12 +2033,170 @@ end
|
|||||||
|
|
||||||
--- @return ImGuiNavItemData
|
--- @return ImGuiNavItemData
|
||||||
local function ImGuiNavItemData()
|
local function ImGuiNavItemData()
|
||||||
local this = setmetatable({ }, IMGUI_NAV_ITEM_DATA)
|
local this = setmetatable({ }, MT.ImGuiNavItemData)
|
||||||
this.RectRel = ImRect()
|
this.RectRel = ImRect()
|
||||||
this:Clear()
|
this:Clear()
|
||||||
return this
|
return this
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [SECTION] Typing-select support
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Flags for GetTypingSelectRequest()
|
||||||
|
--- @enum ImGuiTypingSelectFlags
|
||||||
|
ImGuiTypingSelectFlags = {
|
||||||
|
None = 0,
|
||||||
|
AllowBackspace = bitLShift(1, 0), -- Backspace to delete character inputs. If using: ensure GetTypingSelectRequest() is not called more than once per frame (filter by e.g. focus state)
|
||||||
|
AllowSingleCharMode = bitLShift(1, 1), -- Allow "single char" search mode which is activated when pressing the same character multiple times.
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Returned by GetTypingSelectRequest(), designed to eventually be public.
|
||||||
|
--- @class ImGuiTypingSelectRequest
|
||||||
|
--- @field Flags ImGuiTypingSelectFlags # Flags passed to GetTypingSelectRequest()
|
||||||
|
--- @field SearchBufferLen int
|
||||||
|
--- @field SearchBuffer string # Search buffer contents (use full string. unless SingleCharMode is set, in which case use SingleCharSize).
|
||||||
|
--- @field SelectRequest bool # Set when buffer was modified this frame, requesting a selection.
|
||||||
|
--- @field SingleCharMode bool # Notify when buffer contains same character repeated, to implement special mode. In this situation it preferred to not display any on-screen search indication.
|
||||||
|
--- @field SingleCharSize int # Length in bytes of first letter codepoint (1 for ascii, 2-4 for UTF-8). If (SearchBufferLen==RepeatCharSize) only 1 letter has been input.
|
||||||
|
local function ImGuiTypingSelectRequest()
|
||||||
|
return { Flags = 0, SearchBufferLen = 0, SearchBuffer = "", SelectRequest = false, SingleCharMode = false, SingleCharSize = 0 }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Storage for GetTypingSelectRequest()
|
||||||
|
-- [Port] SearchBuffer is an immutable Lua string (C++: char[64], 63 bytes max + zero terminator). SearchBuffer[0] != 0 -> #SearchBuffer ~= 0.
|
||||||
|
--- @class ImGuiTypingSelectState
|
||||||
|
--- @field Request ImGuiTypingSelectRequest # User-facing data
|
||||||
|
--- @field SearchBuffer string # Search buffer: no need to make dynamic as this search is very transient.
|
||||||
|
--- @field FocusScope ImGuiID
|
||||||
|
--- @field LastRequestFrame int
|
||||||
|
--- @field LastRequestTime float
|
||||||
|
--- @field SingleCharModeLock bool # After a certain single char repeat count we lock into SingleCharMode. Two benefits: 1) buffer never fill, 2) we can provide an immediate SingleChar mode without timer elapsing.
|
||||||
|
MT.ImGuiTypingSelectState = {}
|
||||||
|
MT.ImGuiTypingSelectState.__index = MT.ImGuiTypingSelectState
|
||||||
|
|
||||||
|
--- @return ImGuiTypingSelectState
|
||||||
|
function ImGuiTypingSelectState()
|
||||||
|
return setmetatable({ Request = ImGuiTypingSelectRequest(), SearchBuffer = "", FocusScope = 0, LastRequestFrame = 0, LastRequestTime = 0.0, SingleCharModeLock = false }, MT.ImGuiTypingSelectState)
|
||||||
|
end
|
||||||
|
function MT.ImGuiTypingSelectState:Clear() self.SearchBuffer = ""; self.SingleCharModeLock = false end -- We preserve remaining data for easier debugging
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [SECTION] Box-select support
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- @class ImGuiBoxSelectState
|
||||||
|
--- @field ID ImGuiID
|
||||||
|
--- @field IsActive bool
|
||||||
|
--- @field IsStarting bool
|
||||||
|
--- @field IsStartedFromVoid bool # Starting click was not from an item.
|
||||||
|
--- @field IsStartedSetNavIdOnce bool
|
||||||
|
--- @field RequestClear bool
|
||||||
|
--- @field KeyMods ImGuiKeyChord # Latched key-mods for box-select logic.
|
||||||
|
--- @field StartPosRel ImVec2 # Start position in window-contents relative space (to support scrolling)
|
||||||
|
--- @field EndPosRel ImVec2 # End position in window-contents relative space
|
||||||
|
--- @field ScrollAccum ImVec2 # Scrolling accumulator (to behave at high-frame spaces)
|
||||||
|
--- @field Window ImGuiWindow?
|
||||||
|
--- @field UnclipMode bool # (Temp/Transient, here in hot area). Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select.
|
||||||
|
--- @field UnclipRect ImRect # Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets.
|
||||||
|
--- @field UnclipRects ImRect[] # Per-axis versions. [Port] 1-based: [1] = upstream [0] (X), [2] = upstream [1] (Y)
|
||||||
|
--- @field BoxSelectRectPrev ImRect # Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos)
|
||||||
|
--- @field BoxSelectRectCurr ImRect
|
||||||
|
--- @return ImGuiBoxSelectState
|
||||||
|
function ImGuiBoxSelectState()
|
||||||
|
return {
|
||||||
|
-- Active box-selection data (persistent, 1 active at a time)
|
||||||
|
ID = 0, IsActive = false, IsStarting = false, IsStartedFromVoid = false, IsStartedSetNavIdOnce = false, RequestClear = false,
|
||||||
|
KeyMods = 0,
|
||||||
|
StartPosRel = ImVec2(), EndPosRel = ImVec2(), ScrollAccum = ImVec2(),
|
||||||
|
Window = nil,
|
||||||
|
|
||||||
|
-- Temporary/Transient data
|
||||||
|
UnclipMode = false,
|
||||||
|
UnclipRect = ImRect(),
|
||||||
|
UnclipRects = { ImRect(), ImRect() },
|
||||||
|
BoxSelectRectPrev = ImRect(),
|
||||||
|
BoxSelectRectCurr = ImRect(),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [SECTION] Multi-select support
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- We always assume that -1 is an invalid value (which works for indices and pointers)
|
||||||
|
-- (ImGuiSelectionUserData_Invalid is defined above with the ImGuiSelectionUserData alias)
|
||||||
|
|
||||||
|
-- Temporary storage for multi-select
|
||||||
|
--- @class ImGuiMultiSelectTempData
|
||||||
|
--- @field IO ImGuiMultiSelectIO # MUST BE FIRST FIELD. Requests are set and returned by BeginMultiSelect()/EndMultiSelect() + written to by user during the loop.
|
||||||
|
--- @field Storage ImGuiMultiSelectState?
|
||||||
|
--- @field FocusScopeId ImGuiID # Copied from g.CurrentFocusScopeId (unless another selection scope was pushed manually)
|
||||||
|
--- @field Flags ImGuiMultiSelectFlags
|
||||||
|
--- @field ScopeRectMin ImVec2
|
||||||
|
--- @field BackupCursorMaxPos ImVec2
|
||||||
|
--- @field BoxSelectId ImGuiID
|
||||||
|
--- @field KeyMods ImGuiKeyChord
|
||||||
|
--- @field LoopRequestSetAll int # -1: no operation, 0: clear all, 1: select all.
|
||||||
|
--- @field IsEndIO bool # Set when switching IO from BeginMultiSelect() to EndMultiSelect() state.
|
||||||
|
--- @field IsFocused bool # Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
|
||||||
|
--- @field IsKeyboardSetRange bool # Set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
|
||||||
|
--- @field NavIdPassedBy bool
|
||||||
|
--- @field RangeSrcPassedBy bool # Set by the item that matches RangeSrcItem.
|
||||||
|
--- @field RangeDstPassedBy bool # Set by the item that matches NavJustMovedToId when IsSetRange is set.
|
||||||
|
--- @field IsSoleOrUnknownSelectionSize bool
|
||||||
|
MT.ImGuiMultiSelectTempData = {}
|
||||||
|
MT.ImGuiMultiSelectTempData.__index = MT.ImGuiMultiSelectTempData
|
||||||
|
|
||||||
|
--- @return ImGuiMultiSelectTempData
|
||||||
|
function ImGuiMultiSelectTempData()
|
||||||
|
local this = setmetatable({ IO = ImGuiMultiSelectIO(), ScopeRectMin = ImVec2(), BackupCursorMaxPos = ImVec2() }, MT.ImGuiMultiSelectTempData)
|
||||||
|
this:Clear()
|
||||||
|
return this
|
||||||
|
end
|
||||||
|
-- Zero-clear except IO as we preserve IO.Requests[] buffer allocation.
|
||||||
|
function MT.ImGuiMultiSelectTempData:Clear()
|
||||||
|
self:ClearIO()
|
||||||
|
self.Storage = nil
|
||||||
|
self.FocusScopeId = 0
|
||||||
|
self.Flags = 0
|
||||||
|
ImVec2_CopyV(self.ScopeRectMin, 0.0, 0.0)
|
||||||
|
ImVec2_CopyV(self.BackupCursorMaxPos, 0.0, 0.0)
|
||||||
|
self.BoxSelectId = 0
|
||||||
|
self.KeyMods = 0
|
||||||
|
self.LoopRequestSetAll = 0
|
||||||
|
self.IsEndIO = false
|
||||||
|
self.IsFocused = false
|
||||||
|
self.IsKeyboardSetRange = false
|
||||||
|
self.NavIdPassedBy = false
|
||||||
|
self.RangeSrcPassedBy = false
|
||||||
|
self.RangeDstPassedBy = false
|
||||||
|
self.IsSoleOrUnknownSelectionSize = false
|
||||||
|
end
|
||||||
|
function MT.ImGuiMultiSelectTempData:ClearIO() local io = self.IO; io.Requests:resize(0); io.RangeSrcItem = ImGuiSelectionUserData_Invalid; io.NavIdItem = ImGuiSelectionUserData_Invalid; io.NavIdSelected = false; io.RangeSrcReset = false end
|
||||||
|
|
||||||
|
-- Persistent storage for multi-select (as long as selection is alive)
|
||||||
|
--- @class ImGuiMultiSelectState
|
||||||
|
--- @field Window ImGuiWindow?
|
||||||
|
--- @field ID ImGuiID
|
||||||
|
--- @field LastFrameActive int # Last used frame-count, for GC.
|
||||||
|
--- @field LastSelectionSize int # Set by BeginMultiSelect() based on optional info provided by user. May be -1 if unknown.
|
||||||
|
--- @field RangeSelected int # -1 (don't have) or true/false
|
||||||
|
--- @field NavIdSelected int # -1 (don't have) or true/false
|
||||||
|
--- @field RangeSrcItem ImGuiSelectionUserData #
|
||||||
|
--- @field NavIdItem ImGuiSelectionUserData # SetNextItemSelectionUserData() value for NavId (if part of submitted items)
|
||||||
|
--- @return ImGuiMultiSelectState
|
||||||
|
function ImGuiMultiSelectState()
|
||||||
|
return { Window = nil, ID = 0, LastFrameActive = 0, LastSelectionSize = 0, RangeSelected = -1, NavIdSelected = -1, RangeSrcItem = ImGuiSelectionUserData_Invalid, NavIdItem = ImGuiSelectionUserData_Invalid }
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @param id ImGuiID
|
||||||
|
--- @return ImGuiBoxSelectState?
|
||||||
|
function ImGui.GetBoxSelectState(id) local g = GImGui; if id ~= 0 and g.BoxSelectState.ID == id and g.BoxSelectState.IsActive then return g.BoxSelectState end return nil end
|
||||||
|
--- @param id ImGuiID
|
||||||
|
--- @return ImGuiMultiSelectState?
|
||||||
|
function ImGui.GetMultiSelectState(id) local g = GImGui; return g.MultiSelectStorage:GetByKey(id) end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- [SECTION] ImGuiContext (main Dear ImGui context)
|
-- [SECTION] ImGuiContext (main Dear ImGui context)
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
@@ -1865,7 +2216,7 @@ end
|
|||||||
--- @field FontSize float
|
--- @field FontSize float
|
||||||
--- @field FontSizeBase float
|
--- @field FontSizeBase float
|
||||||
--- @field FontBakedScale float
|
--- @field FontBakedScale float
|
||||||
--- @field FontRasterizerDensity float
|
--- @field CurrentPixelDensity float
|
||||||
--- @field DrawListSharedData ImDrawListSharedData
|
--- @field DrawListSharedData ImDrawListSharedData
|
||||||
--- @field NextItemData ImGuiNextItemData
|
--- @field NextItemData ImGuiNextItemData
|
||||||
--- @field LastItemData ImGuiLastItemData
|
--- @field LastItemData ImGuiLastItemData
|
||||||
@@ -2052,6 +2403,7 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
KeysRoutingTable = ImGuiKeyRoutingTable(),
|
KeysRoutingTable = ImGuiKeyRoutingTable(),
|
||||||
|
|
||||||
InputEventsQueue = ImVector(), -- Input events which will be trickled/written into IO structure.
|
InputEventsQueue = ImVector(), -- Input events which will be trickled/written into IO structure.
|
||||||
|
InputEventsTrail = ImVector(), -- Past input events processed in NewFrame(). This is to allow domain-specific application to access e.g mouse/pen trail.
|
||||||
|
|
||||||
InputEventsNextMouseSource = ImGuiMouseSource.Mouse,
|
InputEventsNextMouseSource = ImGuiMouseSource.Mouse,
|
||||||
InputEventsNextEventId = 1,
|
InputEventsNextEventId = 1,
|
||||||
@@ -2092,6 +2444,7 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
ActiveIdPreviousFrame = 0,
|
ActiveIdPreviousFrame = 0,
|
||||||
|
|
||||||
ActiveIdTimer = 0.0,
|
ActiveIdTimer = 0.0,
|
||||||
|
ActiveIdSource = ImGuiInputSource.None, -- Activating source: ImGuiInputSource.Mouse OR ImGuiInputSource.Keyboard OR ImGuiInputSource.Gamepad
|
||||||
|
|
||||||
LastActiveId = 0, -- Store the last non-zero ActiveId, useful for animation.
|
LastActiveId = 0, -- Store the last non-zero ActiveId, useful for animation.
|
||||||
LastActiveIdTimer = 0.0, -- Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
|
LastActiveIdTimer = 0.0, -- Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
|
||||||
@@ -2127,6 +2480,7 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
NavHighlightItemUnderNav = false, -- Disable mouse hovering highlight. Highlight navigation focused item instead of mouse hovered item.
|
NavHighlightItemUnderNav = false, -- Disable mouse hovering highlight. Highlight navigation focused item instead of mouse hovered item.
|
||||||
NavIdIsAlive = false, -- Nav widget has been seen this frame ~~ NavRectRel is valid
|
NavIdIsAlive = false, -- Nav widget has been seen this frame ~~ NavRectRel is valid
|
||||||
NavInputSource = ImGuiInputSource.Keyboard, -- Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource.Keyboard or ImGuiInputSource.Gamepad
|
NavInputSource = ImGuiInputSource.Keyboard, -- Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource.Keyboard or ImGuiInputSource.Gamepad
|
||||||
|
NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid, -- Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data.
|
||||||
NavWindowingTarget = nil, NavWindowingTargetAnim = nil, NavWindowingListWindow = nil, -- Target window when doing Ctrl+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most!
|
NavWindowingTarget = nil, NavWindowingTargetAnim = nil, NavWindowingListWindow = nil, -- Target window when doing Ctrl+Tab (or Pad Menu + FocusPrev/Next), this window is temporarily displayed top-most!
|
||||||
NavWindowingTimer = 0.0, NavWindowingHighlightAlpha = 0.0,
|
NavWindowingTimer = 0.0, NavWindowingHighlightAlpha = 0.0,
|
||||||
NavWindowingToggleLayer = false, -- Set while Alt or GamepadMenu is held, may be cleared by other operations, and processed when releasing the key.
|
NavWindowingToggleLayer = false, -- Set while Alt or GamepadMenu is held, may be cleared by other operations, and processed when releasing the key.
|
||||||
@@ -2166,7 +2520,16 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
NavActivateId = 0, NavActivateDownId = 0, NavActivatePressedId = 0, -- ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey.Space) || IsKeyDown(ImGuiKey.Enter) || IsKeyPressed(ImGuiKey.NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItemByID()
|
NavActivateId = 0, NavActivateDownId = 0, NavActivatePressedId = 0, -- ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey.Space) || IsKeyDown(ImGuiKey.Enter) || IsKeyPressed(ImGuiKey.NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItemByID()
|
||||||
NavActivateFlags = ImGuiActivateFlags.None,
|
NavActivateFlags = ImGuiActivateFlags.None,
|
||||||
|
|
||||||
FrameCount = -1,
|
-- Navigation: record of last move request
|
||||||
|
NavJustMovedFromFocusScopeId = 0, -- Just navigated from this focus scope id (result of a successfully MoveRequest).
|
||||||
|
NavJustMovedToId = 0, -- Just navigated to this id (result of a successfully MoveRequest).
|
||||||
|
NavJustMovedToFocusScopeId = 0, -- Just navigated to this focus scope id (result of a successfully MoveRequest).
|
||||||
|
NavJustMovedToKeyMods = 0,
|
||||||
|
NavJustMovedToIsTabbing = false, -- Copy of ImGuiNavMoveFlags.IsTabbing. Maybe we should store whole flags.
|
||||||
|
NavJustMovedToIsInit = false, -- Copy of ImGuiNavMoveFlags.IsInit. Maybe we should store whole flags.
|
||||||
|
NavJustMovedToHasSelectionData = false, -- Copy of move result's ItemFlags & ImGuiItemFlags.HasSelectionUserData). Maybe we should just store ImGuiNavItemData.
|
||||||
|
|
||||||
|
FrameCount = 0,
|
||||||
|
|
||||||
FrameCountEnded = -1,
|
FrameCountEnded = -1,
|
||||||
FrameCountPlatformEnded = -1,
|
FrameCountPlatformEnded = -1,
|
||||||
@@ -2197,7 +2560,7 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
|
|
||||||
FontRefSize = 0.0,
|
FontRefSize = 0.0,
|
||||||
|
|
||||||
FontRasterizerDensity = 1.0,
|
CurrentPixelDensity = 1.0,
|
||||||
|
|
||||||
FontAtlases = ImVector(), -- List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas)
|
FontAtlases = ImVector(), -- List of font atlases used by the context (generally only contains g.IO.Fonts aka the main font atlas)
|
||||||
|
|
||||||
@@ -2226,6 +2589,8 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
MouseCursor = ImGuiMouseCursor.Arrow,
|
MouseCursor = ImGuiMouseCursor.Arrow,
|
||||||
MouseStationaryTimer = 0.0, -- Time the mouse has been stationary (with some loose heuristic)
|
MouseStationaryTimer = 0.0, -- Time the mouse has been stationary (with some loose heuristic)
|
||||||
|
|
||||||
|
TypingSelectState = ImGuiTypingSelectState(), -- State for GetTypingSelectRequest()
|
||||||
|
|
||||||
InputTextState = ImGuiInputTextState(),
|
InputTextState = ImGuiInputTextState(),
|
||||||
InputTextLineIndex = ImGuiTextIndex(), -- Temporary storage
|
InputTextLineIndex = ImGuiTextIndex(), -- Temporary storage
|
||||||
InputTextDeactivatedState = ImGuiInputTextDeactivatedState(),
|
InputTextDeactivatedState = ImGuiInputTextDeactivatedState(),
|
||||||
@@ -2244,9 +2609,16 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
DockContext = ImGuiDockContext(),
|
DockContext = ImGuiDockContext(),
|
||||||
DockNodeWindowMenuHandler = nil,
|
DockNodeWindowMenuHandler = nil,
|
||||||
DebugHoveredDockNode = nil, -- Hovered dock node.
|
DebugHoveredDockNode = nil, -- Hovered dock node.
|
||||||
CurrentTabBarStack = ImVector(), -- holds ImGuiTabBar references directly (no ImGuiPtrOrIndex needed in Lua)
|
CurrentTabBarStack = ImVector(), -- ImVector<ImGuiPtrOrIndex>
|
||||||
ShrinkWidthBuffer = ImVector(), -- ImGuiShrinkWidthItem
|
ShrinkWidthBuffer = ImVector(), -- ImGuiShrinkWidthItem
|
||||||
|
|
||||||
|
-- Multi-Select state
|
||||||
|
BoxSelectState = ImGuiBoxSelectState(),
|
||||||
|
CurrentMultiSelect = nil,
|
||||||
|
MultiSelectTempDataStacked = 0, -- Temporary multi-select data size (because we leave previous instances undestructed, we generally don't use MultiSelectTempData.Size)
|
||||||
|
MultiSelectTempData = ImVector(), -- ImVector<ImGuiMultiSelectTempData>, 1-based
|
||||||
|
MultiSelectStorage = ImPool(ImGuiMultiSelectState), -- ImPool<ImGuiMultiSelectState>
|
||||||
|
|
||||||
WindowResizeBorderExpectedRect = ImRect(), -- Expected border rect, switch to relative edit if moving
|
WindowResizeBorderExpectedRect = ImRect(), -- Expected border rect, switch to relative edit if moving
|
||||||
WindowResizeRelativeMode = false,
|
WindowResizeRelativeMode = false,
|
||||||
|
|
||||||
@@ -2269,6 +2641,7 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
|
|
||||||
DisabledAlphaBackup = 0.0, -- Backup for style.Alpha for BeginDisabled()
|
DisabledAlphaBackup = 0.0, -- Backup for style.Alpha for BeginDisabled()
|
||||||
DisabledStackSize = 0,
|
DisabledStackSize = 0,
|
||||||
|
MixedValueLabel = "-", -- Value replacement when displaying a mixed value.
|
||||||
|
|
||||||
ItemFlagsStack = ImVector(), -- Stack for PushItemFlag()/PopItemFlag() - inherited by Begin()
|
ItemFlagsStack = ImVector(), -- Stack for PushItemFlag()/PopItemFlag() - inherited by Begin()
|
||||||
GroupStack = ImVector(), -- Stack for BeginGroup()/EndGroup() - not inherited by Begin()
|
GroupStack = ImVector(), -- Stack for BeginGroup()/EndGroup() - not inherited by Begin()
|
||||||
@@ -2290,6 +2663,8 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
-- Hooks
|
-- Hooks
|
||||||
Hooks = ImVector(), -- Hooks for extensions (e.g. test engine)
|
Hooks = ImVector(), -- Hooks for extensions (e.g. test engine)
|
||||||
HookIdNext = 0, -- Next available HookId
|
HookIdNext = 0, -- Next available HookId
|
||||||
|
SessionDate = ImGuiPackedDate(), -- Packed copy of platform_io.Platform_SessionDate, when valid.
|
||||||
|
DemoMarkerCallback = nil, -- [Luau] fun(file, line, section)
|
||||||
|
|
||||||
-- Drag and Drop
|
-- Drag and Drop
|
||||||
DragDropActive = false,
|
DragDropActive = false,
|
||||||
@@ -2337,10 +2712,29 @@ function ImGuiContext(shared_font_atlas) -- TODO: tidy up / complete this struct
|
|||||||
|
|
||||||
LocalizationTable = {},
|
LocalizationTable = {},
|
||||||
|
|
||||||
|
DebugLogBuf = ImGuiTextBuffer(),
|
||||||
|
DebugLogLines = { "" }, -- [Luau] upstream DebugLogIndex: Lua array of complete lines (without '\n'), last one being filled
|
||||||
DebugLogFlags = bitOr(ImGuiDebugLogFlags.EventError, ImGuiDebugLogFlags.OutputToTTY),
|
DebugLogFlags = bitOr(ImGuiDebugLogFlags.EventError, ImGuiDebugLogFlags.OutputToTTY),
|
||||||
DebugFlashStyleColorIdx = nil,
|
DebugFlashStyleColorIdx = ImGuiCol.COUNT, -- (Keep close to ColorStack to share cache line)
|
||||||
|
DebugBeginReturnValueCullDepth = -1, -- Cycle between 0..9 then wrap around.
|
||||||
|
DebugLocateId = 0, -- Storage for DebugLocateItemOnHover() feature: this is read by ItemAdd() so we keep it in a hot/cached location
|
||||||
|
DebugLogAutoDisableFlags = ImGuiDebugLogFlags.None,
|
||||||
|
DebugLogAutoDisableFrames = 0,
|
||||||
|
DebugLocateFrames = 0, -- For DebugLocateItemOnHover(). This is used together with DebugLocateId which is in a hot/cached spot above.
|
||||||
|
DebugItemPickerActive = false, -- Item picker is active (started with DebugStartItemPicker())
|
||||||
|
DebugItemPickerMouseButton = ImGuiMouseButton.Left,
|
||||||
|
DebugItemPickerBreakId = 0, -- Will call IM_DEBUG_BREAK() when encountering this ID
|
||||||
|
DebugFlashStyleColorTime = 0.0,
|
||||||
|
DebugFlashStyleColorBackup = ImVec4(0, 0, 0, 0),
|
||||||
|
-- Same as DebugBreakClearData(). Those fields are scattered in their respective subsystem to stay in hot-data locations
|
||||||
|
DebugBreakInLocateId = false, -- Debug break in ItemAdd() call for g.DebugLocateId.
|
||||||
|
DebugBreakKeyChord = ImGuiKey.Pause, -- = ImGuiKey_Pause
|
||||||
|
DebugBreakInShortcutRouting = ImGuiKey.None, -- Set to break in SetShortcutRouting()/Shortcut() calls.
|
||||||
|
DebugBreakCallback = nil, -- [Luau] fun(ctx): called by IM_DEBUG_BREAK() (Lua can't break into a debugger)
|
||||||
|
|
||||||
DebugMetricsConfig = ImGuiMetricsConfig(),
|
DebugMetricsConfig = ImGuiMetricsConfig(),
|
||||||
|
DebugItemPathQuery = ImGuiDebugItemPathQuery(),
|
||||||
|
DebugIDStackTool = ImGuiIDStackTool(),
|
||||||
DebugHookIdInfoId = 0, -- Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool
|
DebugHookIdInfoId = 0, -- Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool
|
||||||
DebugAllocInfo = ImGuiDebugAllocInfo(),
|
DebugAllocInfo = ImGuiDebugAllocInfo(),
|
||||||
|
|
||||||
@@ -2399,10 +2793,10 @@ end
|
|||||||
--- @field WantApply bool # Set when loaded from .ini data
|
--- @field WantApply bool # Set when loaded from .ini data
|
||||||
--- @field WantDelete bool # Set to invalidate/delete the settings entry
|
--- @field WantDelete bool # Set to invalidate/delete the settings entry
|
||||||
--- @field Name string # Window name
|
--- @field Name string # Window name
|
||||||
local IMGUI_WINDOW_SETTINGS = {}
|
MT.ImGuiWindowSettings = {}
|
||||||
IMGUI_WINDOW_SETTINGS.__index = IMGUI_WINDOW_SETTINGS
|
MT.ImGuiWindowSettings.__index = MT.ImGuiWindowSettings
|
||||||
|
|
||||||
function IMGUI_WINDOW_SETTINGS:GetName()
|
function MT.ImGuiWindowSettings:GetName()
|
||||||
return self.Name
|
return self.Name
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2421,8 +2815,21 @@ function ImGuiWindowSettings()
|
|||||||
DockId = 0, -- ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none.
|
DockId = 0, -- ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none.
|
||||||
DockOrder = -1, -- Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
|
DockOrder = -1, -- Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
|
||||||
ClassId = 0, -- ID of window class if specified
|
ClassId = 0, -- ID of window class if specified
|
||||||
LastUsedDate = 0,
|
LastUsedDate = 0, -- [Luau] stored unpacked (YYYYMMDD int, 0 = invalid) instead of ImGuiPackedDate
|
||||||
}, IMGUI_WINDOW_SETTINGS)
|
}, MT.ImGuiWindowSettings)
|
||||||
|
end
|
||||||
|
|
||||||
|
--- @class ImGuiSettingsCleanupArgs
|
||||||
|
function ImGuiSettingsCleanupArgs()
|
||||||
|
return {
|
||||||
|
TypeHashFilter = 0, -- Set to restrict cleanup to a given .ini type, e.g. == ImHashStr("Window"), ImHashStr("Table"). Otherwise every types supporting Cleanup will be affected.
|
||||||
|
DiscardOlderThanMonths = 0, -- Enable to discard entries older than XX months.
|
||||||
|
DiscardWhenMissingDate = false, -- Enable to discard entries missing a date.
|
||||||
|
DiscardAll = false, -- Enable to discard all entries = same as calling ClearIniSettings() except it may be filtered.
|
||||||
|
SetCurrentSessionDateToAll = false, -- Enable to write current SessionDate to all supporting entries. // Let us know in #9460 if you use this.
|
||||||
|
SetCurrentSessionDateWhenMissingDate = false, -- Enable to write current SessionDate to all supporting entries missing a date. // Let us know in #9460 if you use this.
|
||||||
|
_DiscardOlderThanDate = 0, -- [Internal]
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.
|
-- Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.
|
||||||
@@ -2798,6 +3205,7 @@ end
|
|||||||
--- @field LastAlpha float
|
--- @field LastAlpha float
|
||||||
--- @field LastFocusedHadNavWindow bool
|
--- @field LastFocusedHadNavWindow bool
|
||||||
--- @field PlatformMonitor short
|
--- @field PlatformMonitor short
|
||||||
|
--- @field BgFgDrawListsLastFrameActive [int, int] # 1-based
|
||||||
--- @field BgFgDrawListsLastTimeActive [int, int] # 1-based
|
--- @field BgFgDrawListsLastTimeActive [int, int] # 1-based
|
||||||
--- @field BgFgDrawLists [ImDrawList, ImDrawList] # 1-based
|
--- @field BgFgDrawLists [ImDrawList, ImDrawList] # 1-based
|
||||||
--- @field DrawDataP ImDrawData
|
--- @field DrawDataP ImDrawData
|
||||||
@@ -2877,6 +3285,7 @@ function ImGuiViewportP()
|
|||||||
this.LastFocusedHadNavWindow = false -- Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow ~= nil last time the viewport was focused.
|
this.LastFocusedHadNavWindow = false -- Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow ~= nil last time the viewport was focused.
|
||||||
this.PlatformMonitor = -1
|
this.PlatformMonitor = -1
|
||||||
|
|
||||||
|
this.BgFgDrawListsLastFrameActive = {-1, -1} -- Last frame the background (1) and foreground (2) draw lists were used.
|
||||||
this.BgFgDrawListsLastTimeActive = {-1, -1} -- Timestamps for Gc.
|
this.BgFgDrawListsLastTimeActive = {-1, -1} -- Timestamps for Gc.
|
||||||
this.BgFgDrawLists = {nil, nil} -- Convenience background [1] and foreground [2] draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.
|
this.BgFgDrawLists = {nil, nil} -- Convenience background [1] and foreground [2] draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.
|
||||||
this.DrawDataP = ImDrawData()
|
this.DrawDataP = ImDrawData()
|
||||||
@@ -3138,6 +3547,8 @@ function ImGuiInputEvent()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- [Internal] Key ranges
|
-- [Internal] Key ranges
|
||||||
|
ImGuiKey_LegacyNativeKey_BEGIN = 0
|
||||||
|
ImGuiKey_LegacyNativeKey_END = 512
|
||||||
ImGuiKey_Keyboard_BEGIN = ImGuiKey.NamedKey_BEGIN
|
ImGuiKey_Keyboard_BEGIN = ImGuiKey.NamedKey_BEGIN
|
||||||
ImGuiKey_Keyboard_END = ImGuiKey.GamepadStart
|
ImGuiKey_Keyboard_END = ImGuiKey.GamepadStart
|
||||||
ImGuiKey_Gamepad_BEGIN = ImGuiKey.GamepadStart
|
ImGuiKey_Gamepad_BEGIN = ImGuiKey.GamepadStart
|
||||||
@@ -3462,5 +3873,97 @@ end
|
|||||||
--- @nodiscard
|
--- @nodiscard
|
||||||
function ImGuiFocusScopeData() return { ID = nil, WindowID = nil } end
|
function ImGuiFocusScopeData() return { ID = nil, WindowID = nil } end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [Luau] Inline struct helpers / constructors from imgui.h + imgui_internal.h
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Helper for running a block of code not more than once a frame
|
||||||
|
-- [Luau] no operator bool(): call the object, e.g. 'if once() then ... end'
|
||||||
|
MT.ImGuiOnceUponAFrame = {}
|
||||||
|
MT.ImGuiOnceUponAFrame.__index = MT.ImGuiOnceUponAFrame
|
||||||
|
MT.ImGuiOnceUponAFrame.__call = function(self) local current_frame = ImGui.GetFrameCount(); if self.RefFrame == current_frame then return false end; self.RefFrame = current_frame; return true end
|
||||||
|
function ImGuiOnceUponAFrame() return setmetatable({ RefFrame = -1 }, MT.ImGuiOnceUponAFrame) end
|
||||||
|
|
||||||
|
-- [Internal] ImGuiTextFilter item
|
||||||
|
-- [Luau] stores the item text as a Lua string (upstream: Begin pointer + Len)
|
||||||
|
--- @param buf string
|
||||||
|
--- @param b int # 1-based
|
||||||
|
--- @param e int # exclusive
|
||||||
|
function ImGuiTextFilterItem(buf, b, e) IM_ASSERT(e > b); return { Text = string.sub(buf, b, e - 1), CountInclude = 0, MatchIncludesMask = 0 } end
|
||||||
|
|
||||||
|
-- A date in YYYYMMDD format packed into 16-bits
|
||||||
|
--- @class ImGuiPackedDate
|
||||||
|
MT.ImGuiPackedDate = {}
|
||||||
|
MT.ImGuiPackedDate.__index = MT.ImGuiPackedDate
|
||||||
|
--- @param yyyymmdd? int
|
||||||
|
function ImGuiPackedDate(yyyymmdd)
|
||||||
|
local this = setmetatable({ Year = 0, Month = 0, Day = 0 }, MT.ImGuiPackedDate)
|
||||||
|
if yyyymmdd ~= nil then -- Pack
|
||||||
|
this.Year = bitAnd(math.floor(yyyymmdd / 10000) - 2000, 0x7F) -- Year since 2000 (7 bits)
|
||||||
|
this.Month = bitAnd(math.floor(yyyymmdd / 100) % 100, 0x0F) -- Month (1-12) (4 bits)
|
||||||
|
this.Day = bitAnd(yyyymmdd % 100, 0x1F) -- Day (1-31) (5 bits)
|
||||||
|
end
|
||||||
|
return this
|
||||||
|
end
|
||||||
|
function MT.ImGuiPackedDate:IsValid() return self.Year ~= 0 and self.Month ~= 0 and self.Day ~= 0 end
|
||||||
|
function MT.ImGuiPackedDate:Unpack() if self.Year ~= 0 and self.Month ~= 0 and self.Day ~= 0 then return ((self.Year + 2000) * 10000) + (self.Month * 100) + self.Day end; return 0 end -- Unpack
|
||||||
|
function MT.ImGuiPackedDate:SubtractMonths(m) while m > 0 do if self.Month == 1 then self.Year = bitAnd(self.Year - 1, 0x7F) end; self.Month = (self.Month == 1) and 12 or self.Month - 1; m = m - 1 end end -- FIXME-OPT: Stupid but enough for what we do with it.
|
||||||
|
|
||||||
|
-- Pointer or index, e.g. g.CurrentTabBarStack[]
|
||||||
|
-- [Luau] overload by argument type: number = index, otherwise pointer
|
||||||
|
function ImGuiPtrOrIndex(ptr_or_index)
|
||||||
|
if type(ptr_or_index) == "number" then return { Ptr = nil, Index = ptr_or_index } end
|
||||||
|
return { Ptr = ptr_or_index, Index = -1 }
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Note that Max is exclusive, so perhaps should be using a Begin/End convention.
|
||||||
|
--- @class ImGuiListClipperRange
|
||||||
|
MT.ImGuiListClipperRange = {}
|
||||||
|
function MT.ImGuiListClipperRange.FromIndices(min, max) return { Min = min, Max = max, PosToIndexConvert = false, PosToIndexOffsetMin = 0, PosToIndexOffsetMax = 0 } end
|
||||||
|
function MT.ImGuiListClipperRange.FromPositions(y1, y2, off_min, off_max) return { Min = _Trunc(y1), Max = _Trunc(y2), PosToIndexConvert = true, PosToIndexOffsetMin = off_min, PosToIndexOffsetMax = off_max } end
|
||||||
|
|
||||||
|
-- Temporary clipper data, buffers shared/reused between instances
|
||||||
|
--- @class ImGuiListClipperData
|
||||||
|
MT.ImGuiListClipperData = {}
|
||||||
|
MT.ImGuiListClipperData.__index = MT.ImGuiListClipperData
|
||||||
|
function ImGuiListClipperData() return setmetatable({ ListClipper = nil, LossynessOffset = 0.0, StepNo = 0, ItemsFrozen = 0, Ranges = ImVector() }, MT.ImGuiListClipperData) end
|
||||||
|
function MT.ImGuiListClipperData:Reset(clipper) self.ListClipper = clipper; self.StepNo = 0; self.ItemsFrozen = 0; self.Ranges:resize(0) end
|
||||||
|
|
||||||
|
-- [Luau] Desc holds the description string (upstream: DescOffset into ImGuiDebugItemPathQuery::ResultsDescBuf)
|
||||||
|
function ImGuiStackLevelInfo() return { ID = 0, QueryFrameCount = 0, QuerySuccess = false, DataType = -1, Desc = nil } end
|
||||||
|
-- [Luau] Results is a 1-based Lua array of ImGuiStackLevelInfo; ResultsDescBuf/ResultPathBuf are replaced by Lua strings.
|
||||||
|
function ImGuiDebugItemPathQuery() return { MainID = 0, Active = false, Complete = false, Step = 0, Results = {} } end
|
||||||
|
function ImGuiIDStackTool() return { OptHexEncodeNonAsciiChars = true, OptCopyToClipboardOnCtrlC = false, LastActiveFrame = -1, CopyToClipboardLastTime = -FLT_MAX } end
|
||||||
|
--- @enum ImGuiContextHookType
|
||||||
|
ImGuiContextHookType = { NewFramePre = 0, NewFramePost = 1, EndFramePre = 2, EndFramePost = 3, RenderPre = 4, RenderPost = 5, Shutdown = 6, PendingRemoval_ = 7 }
|
||||||
|
|
||||||
|
--- @class ImGuiContextHook
|
||||||
|
--- @field HookId ImGuiID -- A unique ID assigned by AddContextHook()
|
||||||
|
--- @field Type ImGuiContextHookType
|
||||||
|
--- @field Owner ImGuiID
|
||||||
|
--- @field Callback fun(ctx: ImGuiContext, hook: ImGuiContextHook)?
|
||||||
|
--- @field UserData any
|
||||||
|
function ImGuiContextHook() return { HookId = 0, Type = ImGuiContextHookType.NewFramePre, Owner = 0, Callback = nil, UserData = nil } end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [Luau] ImGui:: inline helpers from imgui_internal.h
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function ImGui.GetCurrentTable() local g = GImGui; return g.CurrentTable end
|
||||||
|
--- @param window ImGuiWindow
|
||||||
|
--- @param parent_window ImGuiWindow?
|
||||||
|
function ImGui.SetWindowParentWindowForFocusRoute(window, parent_window) window.ParentWindowForFocusRoute = parent_window end -- You may also use SetNextWindowClass()'s FocusRouteParentWindowId field.
|
||||||
|
function ImGui.GetPixelDensity() return GImGui.CurrentPixelDensity end
|
||||||
|
function ImGui.ScrollToBringRectIntoView(window, rect) ImGui.ScrollToRect(window, rect, ImGuiScrollFlags.KeepVisibleEdgeY) end
|
||||||
|
function ImGui.GetItemStatusFlags() local g = GImGui; return g.LastItemData.StatusFlags end
|
||||||
|
function ImGui.GetActiveID() local g = GImGui; return g.ActiveId end
|
||||||
|
function ImGui.GetFocusID() local g = GImGui; return g.NavId end
|
||||||
|
function ImGui.IsLegacyKey(key) return key >= ImGuiKey_LegacyNativeKey_BEGIN and key < ImGuiKey_LegacyNativeKey_END end
|
||||||
|
function ImGui.GetWindowDockNode() local g = GImGui; return g.CurrentWindow.DockNode end
|
||||||
|
function ImGui.GetCurrentFocusScope() local g = GImGui; return g.CurrentFocusScopeId end -- Focus scope we are outputting into, set by PushFocusScope()
|
||||||
|
function ImGui.GetCurrentTabBar() local g = GImGui; return g.CurrentTabBar end
|
||||||
|
-- This may be useful to apply workaround that a based on distinguish whenever an item is active as a text input field.
|
||||||
|
function ImGui.IsItemActiveAsInputText() local g = GImGui; return g.ActiveId ~= 0 and g.ActiveId == g.LastItemData.ID and g.InputTextState.ID == g.LastItemData.ID end
|
||||||
|
|
||||||
|
|
||||||
return true -- [Roblox] ModuleScripts must return exactly one value
|
return true -- [Roblox] ModuleScripts must return exactly one value
|
||||||
|
|||||||
+57
-24
@@ -331,9 +331,13 @@ end
|
|||||||
|
|
||||||
-- Storage for a table .ini settings
|
-- Storage for a table .ini settings
|
||||||
--- @class ImGuiTableSettings
|
--- @class ImGuiTableSettings
|
||||||
|
MT.ImGuiTableSettings = {}
|
||||||
|
MT.ImGuiTableSettings.__index = MT.ImGuiTableSettings
|
||||||
function ImGuiTableSettings()
|
function ImGuiTableSettings()
|
||||||
return { ID = 0, SaveFlags = 0, RefScale = 0.0, ColumnsCount = 0, ColumnsCountMax = 0, LastUsedDate = 0, WantApply = false, Columns = {} }
|
return setmetatable({ ID = 0, SaveFlags = 0, RefScale = 0.0, ColumnsCount = 0, ColumnsCountMax = 0, LastUsedDate = 0, WantApply = false, Columns = {} }, MT.ImGuiTableSettings)
|
||||||
end
|
end
|
||||||
|
-- [Luau] column settings are stored in a 0-based .Columns table (upstream: allocated right after the struct)
|
||||||
|
function MT.ImGuiTableSettings:GetColumnSettings() return self.Columns end
|
||||||
|
|
||||||
-- Storage data for a single column for legacy Columns() api
|
-- Storage data for a single column for legacy Columns() api
|
||||||
--- @class ImGuiOldColumnData
|
--- @class ImGuiOldColumnData
|
||||||
@@ -348,16 +352,6 @@ function ImGuiOldColumns()
|
|||||||
HostBackupClipRect = ImRect(), HostBackupParentWorkRect = ImRect(), Columns = ImVector(), Splitter = ImDrawListSplitter() }
|
HostBackupClipRect = ImRect(), HostBackupParentWorkRect = ImRect(), Columns = ImVector(), Splitter = ImDrawListSplitter() }
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Flags for internal's BeginColumns(). This is an obsolete API. Prefer using BeginTable() nowadays!
|
|
||||||
ImGuiOldColumnFlags = ImGuiOldColumnFlags or {
|
|
||||||
None = 0,
|
|
||||||
NoBorder = lshift(1, 0), -- Disable column dividers
|
|
||||||
NoResize = lshift(1, 1), -- Disable resizing columns when clicking on the dividers
|
|
||||||
NoPreserveWidths = lshift(1, 2), -- Disable column width preservation when adjusting columns
|
|
||||||
NoForceWithinWindow = lshift(1, 3), -- Disable forcing columns to fit within window
|
|
||||||
GrowParentContentsSize = lshift(1, 4), -- Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove.
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiTableColumnFlags.NoDirectResize_ = ImGuiTableColumnFlags.NoDirectResize_ or lshift(1, 30) -- [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge)
|
ImGuiTableColumnFlags.NoDirectResize_ = ImGuiTableColumnFlags.NoDirectResize_ or lshift(1, 30) -- [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge)
|
||||||
|
|
||||||
local function Rect(r) return ImRect(r.Min.x, r.Min.y, r.Max.x, r.Max.y) end
|
local function Rect(r) return ImRect(r.Min.x, r.Min.y, r.Max.x, r.Max.y) end
|
||||||
@@ -1539,7 +1533,7 @@ function ImGui.TableUpdateLayout(table_)
|
|||||||
|
|
||||||
local inner_window = table_.InnerWindow
|
local inner_window = table_.InnerWindow
|
||||||
local bs = g.BoxSelectState
|
local bs = g.BoxSelectState
|
||||||
if bs and bs.Window == inner_window and bs.UnclipMode then
|
if bs.Window == inner_window and bs.UnclipMode then
|
||||||
ImGui.TableApplyExternalUnclipRect(table_, bs.UnclipRect)
|
ImGui.TableApplyExternalUnclipRect(table_, bs.UnclipRect)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4237,6 +4231,7 @@ function ImGui.TableSaveSettings(table_)
|
|||||||
table_.SettingsOffset = SettingsTablesOffsetFromPtr(settings)
|
table_.SettingsOffset = SettingsTablesOffsetFromPtr(settings)
|
||||||
end
|
end
|
||||||
settings.ColumnsCount = table_.ColumnsCount
|
settings.ColumnsCount = table_.ColumnsCount
|
||||||
|
settings.LastUsedDate = GImGui.SessionDate:Unpack()
|
||||||
|
|
||||||
-- Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings
|
-- Serialize ImGuiTable/ImGuiTableColumn into ImGuiTableSettings/ImGuiTableColumnSettings
|
||||||
IM_ASSERT(settings.ID == table_.ID)
|
IM_ASSERT(settings.ID == table_.ID)
|
||||||
@@ -4305,6 +4300,7 @@ function ImGui.TableLoadSettings(table_)
|
|||||||
|
|
||||||
table_.SettingsLoadedFlags = settings.SaveFlags
|
table_.SettingsLoadedFlags = settings.SaveFlags
|
||||||
table_.RefScale = settings.RefScale
|
table_.RefScale = settings.RefScale
|
||||||
|
settings.LastUsedDate = GImGui.SessionDate:Unpack()
|
||||||
-- TableUpdateLayout() will then call TableLoadSettingsForColumns() to apply the data.
|
-- TableUpdateLayout() will then call TableLoadSettingsForColumns() to apply the data.
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4394,6 +4390,17 @@ function ImGui.TableLoadSettingsForColumn(column, column_settings, load_flags)
|
|||||||
column.SortDirection = column_settings.SortDirection
|
column.SortDirection = column_settings.SortDirection
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- [Luau] boolean "less than" for table.sort; takes (table, lhs column idx, rhs column idx) instead of ImGuiTableFixDisplayOrderColumnData
|
||||||
|
local function TableFixDisplayOrderComparer(table_, lhs_idx, rhs_idx)
|
||||||
|
-- Assume ImGuiTableColumnIdx == signed short, to turn -1 into a large value so that it always sort after.
|
||||||
|
local lhs_order, rhs_order = table_.Columns[lhs_idx].DisplayOrder, table_.Columns[rhs_idx].DisplayOrder
|
||||||
|
if lhs_order < 0 then lhs_order = lhs_order + 0x10000 end
|
||||||
|
if rhs_order < 0 then rhs_order = rhs_order + 0x10000 end
|
||||||
|
local order_delta = lhs_order - rhs_order
|
||||||
|
if order_delta ~= 0 then return order_delta < 0 end
|
||||||
|
return lhs_idx < rhs_idx
|
||||||
|
end
|
||||||
|
|
||||||
-- Fix invalid display order data: compact values (0,1,3 -> 0,1,2); preserve relative order (0,3,1 -> 0,2,1); deduplicate (0,4,1,1 -> 0,3,1,2)
|
-- Fix invalid display order data: compact values (0,1,3 -> 0,1,2); preserve relative order (0,3,1 -> 0,2,1); deduplicate (0,4,1,1 -> 0,3,1,2)
|
||||||
function ImGui.TableFixDisplayOrder(table_)
|
function ImGui.TableFixDisplayOrder(table_)
|
||||||
if band(table_.Flags, ImGuiTableFlags.Reorderable) == 0 then
|
if band(table_.Flags, ImGuiTableFlags.Reorderable) == 0 then
|
||||||
@@ -4408,17 +4415,7 @@ function ImGui.TableFixDisplayOrder(table_)
|
|||||||
fdo_columns[n + 1] = n
|
fdo_columns[n + 1] = n
|
||||||
end
|
end
|
||||||
-- Sort by DisplayOrder and then Index
|
-- Sort by DisplayOrder and then Index
|
||||||
-- Assume ImGuiTableColumnIdx == signed short, to turn -1 into a large value so that it always sort after.
|
table.sort(fdo_columns, function(lhs_idx, rhs_idx) return TableFixDisplayOrderComparer(table_, lhs_idx, rhs_idx) end)
|
||||||
local function key(idx)
|
|
||||||
local o = table_.Columns[idx].DisplayOrder
|
|
||||||
if o < 0 then o = o + 0x10000 end
|
|
||||||
return o
|
|
||||||
end
|
|
||||||
table.sort(fdo_columns, function(lhs_idx, rhs_idx)
|
|
||||||
local a, b = key(lhs_idx), key(rhs_idx)
|
|
||||||
if a ~= b then return a < b end
|
|
||||||
return lhs_idx < rhs_idx
|
|
||||||
end)
|
|
||||||
for n = 0, table_.ColumnsCount - 1 do
|
for n = 0, table_.ColumnsCount - 1 do
|
||||||
table_.Columns[fdo_columns[n + 1]].DisplayOrder = n
|
table_.Columns[fdo_columns[n + 1]].DisplayOrder = n
|
||||||
end
|
end
|
||||||
@@ -4427,6 +4424,27 @@ function ImGui.TableFixDisplayOrder(table_)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function TableSettingsHandler_Cleanup(ctx, handler, args)
|
||||||
|
local g = ctx
|
||||||
|
for i = 0, g.Tables:GetMapSize() - 1 do
|
||||||
|
local table_ = g.Tables:GetByIndex(i)
|
||||||
|
if table_ then
|
||||||
|
table_.SettingsOffset = -1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- [Luau] settings.LastUsedDate is stored unpacked (YYYYMMDD int, 0 = none); g.SessionDate is an ImGuiPackedDate
|
||||||
|
for _, settings in g.SettingsTables:iter() do
|
||||||
|
local is_valid = ImGuiPackedDate(settings.LastUsedDate):IsValid()
|
||||||
|
if args._DiscardOlderThanDate ~= 0 and settings.LastUsedDate < args._DiscardOlderThanDate then
|
||||||
|
settings.ID = 0
|
||||||
|
elseif args.DiscardWhenMissingDate and not is_valid then
|
||||||
|
settings.ID = 0
|
||||||
|
elseif args.SetCurrentSessionDateToAll or (args.SetCurrentSessionDateWhenMissingDate and not is_valid) then
|
||||||
|
settings.LastUsedDate = g.SessionDate:Unpack()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function ForEachTable(g, fn)
|
local function ForEachTable(g, fn)
|
||||||
for i = 0, g.Tables:GetMapSize() - 1 do
|
for i = 0, g.Tables:GetMapSize() - 1 do
|
||||||
local t = g.Tables:GetByIndex(i)
|
local t = g.Tables:GetByIndex(i)
|
||||||
@@ -4470,7 +4488,7 @@ local function TableSettingsHandler_ReadLine(ctx, handler, settings, line)
|
|||||||
local f = string.match(line, "^RefScale=([%-%d%.eE+]+)")
|
local f = string.match(line, "^RefScale=([%-%d%.eE+]+)")
|
||||||
if f then settings.RefScale = tonumber(f); return end
|
if f then settings.RefScale = tonumber(f); return end
|
||||||
local n = string.match(line, "^LastUsed=(%d+)")
|
local n = string.match(line, "^LastUsed=(%d+)")
|
||||||
if n then settings.LastUsedDate = tonumber(n); return end
|
if n then settings.LastUsedDate = ImGuiPackedDate(tonumber(n)):Unpack(); return end
|
||||||
|
|
||||||
local column_n, rest = string.match(line, "^Column (%-?%d+)(.*)$")
|
local column_n, rest = string.match(line, "^Column (%-?%d+)(.*)$")
|
||||||
if column_n then
|
if column_n then
|
||||||
@@ -4552,6 +4570,7 @@ function ImGui.TableSettingsAddSettingsHandler()
|
|||||||
ini_handler.ReadLineFn = TableSettingsHandler_ReadLine
|
ini_handler.ReadLineFn = TableSettingsHandler_ReadLine
|
||||||
ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll
|
ini_handler.ApplyAllFn = TableSettingsHandler_ApplyAll
|
||||||
ini_handler.WriteAllFn = TableSettingsHandler_WriteAll
|
ini_handler.WriteAllFn = TableSettingsHandler_WriteAll
|
||||||
|
ini_handler.CleanupFn = TableSettingsHandler_Cleanup
|
||||||
ImGui.AddSettingsHandler(ini_handler)
|
ImGui.AddSettingsHandler(ini_handler)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -4615,6 +4634,20 @@ function ImGui.TableGcCompactSettings()
|
|||||||
ForEachTable(g, function(t) t.SettingsOffset = -1 end)
|
ForEachTable(g, function(t) t.SettingsOffset = -1 end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [SECTION] Tables: Debugging
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
-- [Luau] global (upstream: static) so ImGui.DebugNodeTable() in imgui.lua can use it
|
||||||
|
|
||||||
|
function DebugNodeTableGetSizingPolicyDesc(sizing_policy)
|
||||||
|
sizing_policy = band(sizing_policy, ImGuiTableFlags.SizingMask_)
|
||||||
|
if sizing_policy == ImGuiTableFlags.SizingFixedFit then return "FixedFit" end
|
||||||
|
if sizing_policy == ImGuiTableFlags.SizingFixedSame then return "FixedSame" end
|
||||||
|
if sizing_policy == ImGuiTableFlags.SizingStretchProp then return "StretchProp" end
|
||||||
|
if sizing_policy == ImGuiTableFlags.SizingStretchSame then return "StretchSame" end
|
||||||
|
return "N/A"
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
-- [SECTION] Columns, BeginColumns, EndColumns, etc.
|
-- [SECTION] Columns, BeginColumns, EndColumns, etc.
|
||||||
-- (This is a legacy API, prefer using BeginTable/EndTable!)
|
-- (This is a legacy API, prefer using BeginTable/EndTable!)
|
||||||
|
|||||||
+1813
-219
File diff suppressed because it is too large
Load Diff
+31
-14
@@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
-- Supports:
|
-- Supports:
|
||||||
-- - %x, %X, %nx, %nX (where n is a number)
|
-- - %x, %X, %nx, %nX (where n is a number)
|
||||||
-- - %d, %nd (where n is a number)
|
-- - %d, %nd, %u, %nu (where n is a number)
|
||||||
|
-- - length modifiers h, hh, l, ll, I64 on integers: ll/I64 = 64-bit range (doubles: exact only within +-2^53)
|
||||||
-- - %f, %lf (very limited)
|
-- - %f, %lf (very limited)
|
||||||
--
|
--
|
||||||
-- Returns items_matched instead of EOF on error
|
-- Returns items_matched instead of EOF on error
|
||||||
@@ -17,6 +18,9 @@ local CHAR_0, CHAR_9 = _byte'0', _byte'9'
|
|||||||
local CHAR_a, CHAR_A = _byte'a', _byte'A'
|
local CHAR_a, CHAR_A = _byte'a', _byte'A'
|
||||||
local CHAR_d = _byte'd'
|
local CHAR_d = _byte'd'
|
||||||
local CHAR_l = _byte'l'
|
local CHAR_l = _byte'l'
|
||||||
|
local CHAR_h = _byte'h'
|
||||||
|
local CHAR_u = _byte'u'
|
||||||
|
local CHAR_I = _byte'I'
|
||||||
local CHAR_f, CHAR_F = _byte'f', _byte'F'
|
local CHAR_f, CHAR_F = _byte'f', _byte'F'
|
||||||
local CHAR_x, CHAR_X = _byte'x', _byte'X'
|
local CHAR_x, CHAR_X = _byte'x', _byte'X'
|
||||||
|
|
||||||
@@ -37,10 +41,15 @@ local function hex_digit_to_int(c)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- we force this behavior by default
|
-- we force this behavior by default
|
||||||
local function clamp_if_overflow(spec, val)
|
local function clamp_if_overflow(spec, val, is_64)
|
||||||
if spec == CHAR_d or spec == CHAR_x or spec == CHAR_X then
|
if spec == CHAR_d or spec == CHAR_x or spec == CHAR_X then
|
||||||
if val > INT_MAX then return INT_MAX end
|
local max = is_64 and 9223372036854775807 or INT_MAX
|
||||||
if val < INT_MIN then return INT_MIN end
|
local min = is_64 and -9223372036854775808 or INT_MIN
|
||||||
|
if val > max then return max end
|
||||||
|
if val < min then return min end
|
||||||
|
elseif spec == CHAR_u then
|
||||||
|
local max = is_64 and 18446744073709551615 or UINT_MAX
|
||||||
|
if val > max then return max end
|
||||||
end
|
end
|
||||||
|
|
||||||
return val
|
return val
|
||||||
@@ -104,22 +113,27 @@ local function sscanf(buffer, buffer_begin, format, result)
|
|||||||
width = math.huge
|
width = math.huge
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- length modifiers
|
||||||
|
local n_l = 0
|
||||||
|
while _byte(format, f, f) == CHAR_l or _byte(format, f, f) == CHAR_h do
|
||||||
|
if _byte(format, f, f) == CHAR_l then n_l = n_l + 1 end
|
||||||
|
f = f + 1
|
||||||
|
end
|
||||||
|
if _byte(format, f, f) == CHAR_I and string.sub(format, f, f + 2) == "I64" then
|
||||||
|
n_l = 2
|
||||||
|
f = f + 3
|
||||||
|
end
|
||||||
|
local is_64 = n_l >= 2
|
||||||
|
|
||||||
local spec = _byte(format, f, f)
|
local spec = _byte(format, f, f)
|
||||||
local base
|
local base
|
||||||
local is_float = false
|
local is_float = false
|
||||||
if spec == CHAR_x or spec == CHAR_X then
|
if spec == CHAR_x or spec == CHAR_X then
|
||||||
base = 16
|
base = 16
|
||||||
elseif spec == CHAR_d then
|
elseif spec == CHAR_d or spec == CHAR_u then
|
||||||
base = 10
|
base = 10
|
||||||
elseif spec == CHAR_f or spec == CHAR_F then
|
elseif spec == CHAR_f or spec == CHAR_F then
|
||||||
is_float = true
|
is_float = true -- TODO: distinguish %lf from %f?
|
||||||
elseif spec == CHAR_l then
|
|
||||||
f = f + 1
|
|
||||||
if _byte(format, f, f) == CHAR_f then
|
|
||||||
is_float = true -- TODO: distinguish from float?
|
|
||||||
else
|
|
||||||
return items_matched
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
return items_matched
|
return items_matched
|
||||||
end
|
end
|
||||||
@@ -197,11 +211,14 @@ local function sscanf(buffer, buffer_begin, format, result)
|
|||||||
val = val * base + sign * hex_digit_to_int(c)
|
val = val * base + sign * hex_digit_to_int(c)
|
||||||
|
|
||||||
local old_val = val
|
local old_val = val
|
||||||
val = clamp_if_overflow(spec, val)
|
val = clamp_if_overflow(spec, val, is_64)
|
||||||
if old_val ~= val then
|
if old_val ~= val then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if spec == CHAR_u and val < 0 then
|
||||||
|
val = val + (is_64 and 18446744073709551616 or 4294967296) -- unsigned wrap-around like strtoul()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result[assigned + 1] = val
|
result[assigned + 1] = val
|
||||||
|
|||||||
+107
-21
@@ -10,6 +10,7 @@
|
|||||||
# test engine. They're listed separately in the report.
|
# test engine. They're listed separately in the report.
|
||||||
import os, re, sys
|
import os, re, sys
|
||||||
from difflib import SequenceMatcher
|
from difflib import SequenceMatcher
|
||||||
|
from fnmatch import fnmatchcase
|
||||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||||
from minify import TOKEN as LUA_TOKEN
|
from minify import TOKEN as LUA_TOKEN
|
||||||
|
|
||||||
@@ -21,6 +22,62 @@ LUA_CLASS_ALIAS = {"IM_RECT": "ImRect", "IM_VECTOR": "ImVector", "IM_POOL": "ImP
|
|||||||
"ImGuiTextBufferMT": "ImGuiTextBuffer", "IMGUI_TEXT_INDEX": "ImGuiTextIndex", "IM_PAYLOAD": "ImGuiPayload",
|
"ImGuiTextBufferMT": "ImGuiTextBuffer", "IMGUI_TEXT_INDEX": "ImGuiTextIndex", "IM_PAYLOAD": "ImGuiPayload",
|
||||||
"DN": "ImGuiDockNode", "IM_VTXBUF": "ImVector"}
|
"DN": "ImGuiDockNode", "IM_VTXBUF": "ImVector"}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
# Intentional Lua replacements: [=] rows, not counted as missing. (glob over the upstream key "Class::name" / "Struct::field",
|
||||||
|
# reason, regex that must match the port sources - if the port's mechanism disappears, the entry falls back to [ ] / missing).
|
||||||
|
# Only applies when no same-named port definition / field exists.
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
REPLACED = [
|
||||||
|
# functions
|
||||||
|
("ImGuiStorage::*", "Lua table keyed by ID (e.g. window.StateStorage = {})", r"StateStorage\s*=\s*\{\}"),
|
||||||
|
("ImGuiStoragePair::*", "Lua table keyed by ID", r"StateStorage\s*=\s*\{\}"),
|
||||||
|
("PairComparerByID", "table.sort over Lua table keys", r"table\.sort\("),
|
||||||
|
("ImStr*", "Lua string library (string.find/sub/lower, immutable strings)", r"string\.find\("),
|
||||||
|
("ImMemdup", "Lua strings/tables are values, no copy needed", r"string\.find\("),
|
||||||
|
("ImFormatString*", "string.format", r"ImFormatString\s*=\s*string\.format"),
|
||||||
|
("ImText*Utf8*", "strings stay UTF-8 bytes: ImStd.ImTextCharFromUtf8 decoder + utf8 library", r"function ImStd\.ImTextCharFromUtf8"),
|
||||||
|
("MallocWrapper", "GC; IM_ALLOC = ImGui.MemAlloc", r"IM_ALLOC\s*=\s*ImGui\.MemAlloc"),
|
||||||
|
("FreeWrapper", "GC; IM_ALLOC = ImGui.MemAlloc", r"IM_ALLOC\s*=\s*ImGui\.MemAlloc"),
|
||||||
|
("ImGui::GetAllocatorFunctions", "GC, no allocator to query", r"IM_ALLOC\s*=\s*ImGui\.MemAlloc"),
|
||||||
|
("ImFileWrite", "no filesystem on Roblox: SaveIniSettingsToDisk is a no-op, use SaveIniSettingsToMemory", r"Roblox: no disk"),
|
||||||
|
("ImSwap", "Lua multiple assignment a, b = b, a", r"\b([\w.]+), ([\w.]+) = \2, \1\b"),
|
||||||
|
("ImGui::DebugCheckVersionAndDataLayout", "C++ ABI / sizeof check", None),
|
||||||
|
("TableSettingsCalcChunkSize", "sizeof; table settings are a plain ImVector", r"SettingsTables\s*=\s*ImVector\(\)"),
|
||||||
|
("ImVector::size", "v.Size field", r"function IM_VECTOR:"),
|
||||||
|
("ImVector::capacity", "v.Capacity field", r"function IM_VECTOR:"),
|
||||||
|
("ImVector::front", "v.Data[1]", r"function IM_VECTOR:"),
|
||||||
|
("ImVector::begin", "v.Data / v:iter()", r"function IM_VECTOR:iter\("),
|
||||||
|
("ImVector::end", "v.Data / v:iter()", r"function IM_VECTOR:iter\("),
|
||||||
|
("ImVector::size_in_bytes", "sizeof", None),
|
||||||
|
("ImVector::max_size", "sizeof", None),
|
||||||
|
("ImVector::clear_destruct", "GC: clear_delete / clear", r"function IM_VECTOR:clear_delete\("),
|
||||||
|
("ImVector::find", "find_index (no element pointers)", r"function IM_VECTOR:find_index\("),
|
||||||
|
("ImSpan::*", "plain Lua tables (e.g. table.Columns = {})", r"Columns = \{\}, ColumnsSize = 0"),
|
||||||
|
("ImSpanAllocator::*", "plain Lua tables, no arena", r"Columns = \{\}, ColumnsSize = 0"),
|
||||||
|
("ImStableVector::*", "ImVector (Lua references are stable)", r"BakedPool\s*=\s*ImVector\(\)"),
|
||||||
|
("ImChunkStream::*", "plain ImVector of settings tables", r"SettingsTables\s*=\s*ImVector\(\)"),
|
||||||
|
("ImPool::GetAliveCount", "pool.AliveCount field", r"\.AliveCount\)"),
|
||||||
|
("ImPool::GetBufSize", "pool.BufSize field / GetMapSize()", r"function IM_POOL:GetMapSize\(\) return self\.BufSize"),
|
||||||
|
("ImPool::TryGetMapData", "GetByIndex (removed slots hold false)", r"function IM_POOL:GetByIndex\("),
|
||||||
|
("ImGuiTextBuffer::begin", "chunk-list string builder: c_str()", r"function ImGuiTextBufferMT:c_str\("),
|
||||||
|
("ImGuiTextBuffer::end", "chunk-list string builder: c_str()", r"function ImGuiTextBufferMT:c_str\("),
|
||||||
|
("ImGuiTextBuffer::resize", "chunk-list string builder, no byte buffer", r"function ImGuiTextBufferMT:c_str\("),
|
||||||
|
("ImGuiTextBuffer::reserve", "chunk-list string builder, no byte buffer", r"function ImGuiTextBufferMT:c_str\("),
|
||||||
|
("ImGuiTextBuffer::appendfv", "appendf(fmt, ...) (Lua varargs)", r"function ImGuiTextBufferMT:appendf\("),
|
||||||
|
("ImGuiTextIndex::append", "debug log keeps a Lua line list (g.DebugLogLines)", r"g\.DebugLogLines\s*="),
|
||||||
|
# struct fields (ImSpan*/ImStableVector/ImGuiStoragePair fields: covered by the globs above)
|
||||||
|
("ImGuiTextBuffer::EmptyString", "c_str() of an empty chunk list", r"function ImGuiTextBufferMT:c_str\("),
|
||||||
|
("ImGuiWindow::NameBufLen", "window.Name is an immutable Lua string", None),
|
||||||
|
("ImGuiTextFilterItem::Begin", "item.Text substring", r"Text = string\.sub\(buf, b, e - 1\)"),
|
||||||
|
("ImGuiTextFilterItem::Len", "item.Text substring", r"Text = string\.sub\(buf, b, e - 1\)"),
|
||||||
|
("ImDrawVert::uv", "vertices packed into VtxBuffer.Buf (VTX_STRIDE bytes per vertex)", r"VTX_STRIDE\s*=\s*\d+"),
|
||||||
|
("ImDrawVert::col", "vertices packed into VtxBuffer.Buf (VTX_STRIDE bytes per vertex)", r"VTX_STRIDE\s*=\s*\d+"),
|
||||||
|
("ImGuiContext::DebugLogIndex", "Lua line list g.DebugLogLines", r"g\.DebugLogLines\s*="),
|
||||||
|
("ImGuiContext::TempKeychordName", "GetKeyChordName returns a Lua string", r"\.\. \(\(key ~= ImGuiKey\.None"),
|
||||||
|
("ImGuiContext::DragDropPayloadBuf*", "payload.Data holds the Lua value", r"payload\.Data = data"),
|
||||||
|
("ImGuiTabBar::TabsNames", "names stored on the tab (tab.Name)", r"Tab names are stored on the tab itself"),
|
||||||
|
]
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
# C++ side
|
# C++ side
|
||||||
# ---------------------------------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
@@ -63,6 +120,7 @@ def cpp_tokens(src):
|
|||||||
out.append((kind, text, line, next((x for x in reversed(stack) if x), None)))
|
out.append((kind, text, line, next((x for x in reversed(stack) if x), None)))
|
||||||
return out, sections
|
return out, sections
|
||||||
|
|
||||||
|
CPP_MACROS = {"IM_MSVC_RUNTIME_CHECKS_OFF", "IM_MSVC_RUNTIME_CHECKS_RESTORE"} # argument-less macro lines, no trailing ';'
|
||||||
CTRL = {"if", "for", "while", "switch", "catch", "sizeof", "return", "alignof", "decltype", "IM_ASSERT", "defined"}
|
CTRL = {"if", "for", "while", "switch", "catch", "sizeof", "return", "alignof", "decltype", "IM_ASSERT", "defined"}
|
||||||
|
|
||||||
def match_back(toks, i, close, open_):
|
def match_back(toks, i, close, open_):
|
||||||
@@ -173,7 +231,8 @@ def parse_cpp(fname):
|
|||||||
j += 1
|
j += 1
|
||||||
if nm: enums[nm] = (vals, line, section_at(line))
|
if nm: enums[nm] = (vals, line, section_at(line))
|
||||||
elif any(x in ("struct", "class", "union") for x in pre) and "=" not in pre:
|
elif any(x in ("struct", "class", "union") for x in pre) and "=" not in pre:
|
||||||
names = [x for x in pre if re.match(r"[A-Za-z_]\w*$", x) and x not in ("struct", "class", "union", "IMGUI_API", "typedef", "final", "public", "private", "alignas")]
|
kw = max(q for q, x in enumerate(pre) if x in ("struct", "class", "union")) # skips macro lines / template<...> before it
|
||||||
|
names = [x for x in pre[kw:] if re.match(r"[A-Za-z_]\w*$", x) and x not in ("struct", "class", "union", "IMGUI_API", "typedef", "final", "public", "private", "alignas")]
|
||||||
nm = names[0] if names else cls
|
nm = names[0] if names else cls
|
||||||
if nm and "union" not in pre: structs.setdefault(nm, ([], line, section_at(line)))
|
if nm and "union" not in pre: structs.setdefault(nm, ([], line, section_at(line)))
|
||||||
scan(i + 1, e, nm, ns)
|
scan(i + 1, e, nm, ns)
|
||||||
@@ -187,11 +246,12 @@ def parse_cpp(fname):
|
|||||||
st = toks[stmt_start:i]
|
st = toks[stmt_start:i]
|
||||||
txt = [x[1] for x in st]
|
txt = [x[1] for x in st]
|
||||||
if txt and txt[0] in ("public", "private", "protected") and len(txt) > 1 and txt[1] == ":": st, txt = st[2:], txt[2:]
|
if txt and txt[0] in ("public", "private", "protected") and len(txt) > 1 and txt[1] == ":": st, txt = st[2:], txt[2:]
|
||||||
|
while txt and txt[0] in CPP_MACROS: st, txt = st[1:], txt[1:]
|
||||||
if txt and ns == "ImGui" and cls is None and "(" in txt and txt[0] not in ("typedef", "struct", "enum", "using"):
|
if txt and ns == "ImGui" and cls is None and "(" in txt and txt[0] not in ("typedef", "struct", "enum", "using"):
|
||||||
p = txt.index("(")
|
p = txt.index("(")
|
||||||
if p > 0 and st[p - 1][0] == "name" and txt[p - 1] not in CTRL:
|
if p > 0 and st[p - 1][0] == "name" and txt[p - 1] not in CTRL:
|
||||||
decls.setdefault(txt[p - 1], (st[p - 1][2], st[p - 1][3], section_at(st[p - 1][2])))
|
decls.setdefault(txt[p - 1], (st[p - 1][2], st[p - 1][3], section_at(st[p - 1][2])))
|
||||||
elif txt and cls and txt[0] not in ("typedef", "friend", "static", "using", "enum", "struct", "class", "template", "IM_MSVC_RUNTIME_CHECKS_OFF", "IM_MSVC_RUNTIME_CHECKS_RESTORE"):
|
elif txt and cls and txt[0] not in ("typedef", "friend", "static", "using", "enum", "struct", "class", "template"):
|
||||||
eq = txt.index("=") if "=" in txt else len(txt)
|
eq = txt.index("=") if "=" in txt else len(txt)
|
||||||
pa = txt.index("(") if "(" in txt else len(txt)
|
pa = txt.index("(") if "(" in txt else len(txt)
|
||||||
if pa >= eq: # not a method declaration
|
if pa >= eq: # not a method declaration
|
||||||
@@ -268,6 +328,10 @@ def parse_lua():
|
|||||||
j += 1
|
j += 1
|
||||||
name = chain[-1]
|
name = chain[-1]
|
||||||
cls = LUA_CLASS_ALIAS.get(chain[-2], chain[-2]) if len(chain) > 1 else None
|
cls = LUA_CLASS_ALIAS.get(chain[-2], chain[-2]) if len(chain) > 1 else None
|
||||||
|
if cls and cls.endswith("MT") and len(cls) > 2: cls = cls[:-2] # method tables: function ExampleAppLogMT:AddLog()
|
||||||
|
if cls is None and re.match(r"[A-Z]\w*_[A-Z]\w*$", name) and "__" not in name: # Class_Method globals (C++ static members)
|
||||||
|
c, _, m = name.partition("_")
|
||||||
|
defs.append(PortFunc(f, c, m, line, toks[body_start:j - 1]))
|
||||||
pf = PortFunc(f, cls, name, line, toks[body_start:j - 1])
|
pf = PortFunc(f, cls, name, line, toks[body_start:j - 1])
|
||||||
bt = [x[1] for x in pf.body]
|
bt = [x[1] for x in pf.body]
|
||||||
if len(bt) >= 5 and bt[0] == "return" and bt[-3:] == ["(", "...", ")"] and all(x[0] == "name" or x[1] in (".", ":") for x in pf.body[1:-3]):
|
if len(bt) >= 5 and bt[0] == "return" and bt[-3:] == ["(", "...", ")"] and all(x[0] == "name" or x[1] in (".", ":") for x in pf.body[1:-3]):
|
||||||
@@ -372,6 +436,9 @@ def main():
|
|||||||
by_name = {}
|
by_name = {}
|
||||||
for d in sorted(defs, key=lambda d: d.alias is not None): by_name.setdefault(d.name, []).append(d)
|
for d in sorted(defs, key=lambda d: d.alias is not None): by_name.setdefault(d.name, []).append(d)
|
||||||
port_classes = {d.cls for d in defs if d.cls}
|
port_classes = {d.cls for d in defs if d.cls}
|
||||||
|
port_class_files = {}
|
||||||
|
for d in defs:
|
||||||
|
if d.cls: port_class_files.setdefault(d.cls, set()).add(d.file)
|
||||||
|
|
||||||
def find(u):
|
def find(u):
|
||||||
m = re.match(r"I?M?STB_TEXTEDIT_(\w+?)(_IMPL)?$", u.name)
|
m = re.match(r"I?M?STB_TEXTEDIT_(\w+?)(_IMPL)?$", u.name)
|
||||||
@@ -385,7 +452,9 @@ def main():
|
|||||||
if u.name == u.cls: # constructor: function ImGuiStyle() / MT.X.new
|
if u.name == u.cls: # constructor: function ImGuiStyle() / MT.X.new
|
||||||
c = [d for d in cands if d.cls is None] or [d for d in by_name.get("new", []) if d.cls == u.cls]
|
c = [d for d in cands if d.cls is None] or [d for d in by_name.get("new", []) if d.cls == u.cls]
|
||||||
return c[0] if c else None
|
return c[0] if c else None
|
||||||
if u.cls in port_classes: return None
|
if u.cls in port_classes: # only a classless helper in the class's own file (local function _grow_capacity)
|
||||||
|
loose = [d for d in cands if d.cls is None and d.file in port_class_files[u.cls]] if len(cands) == 1 else []
|
||||||
|
return loose[0] if loose else None
|
||||||
loose = [d for d in cands if d.cls in (None, "ImGui")] if len(cands) == 1 else []
|
loose = [d for d in cands if d.cls in (None, "ImGui")] if len(cands) == 1 else []
|
||||||
return loose[0] if loose else None
|
return loose[0] if loose else None
|
||||||
pref = [d for d in cands if d.cls == "ImGui"] + [d for d in cands if d.cls is None] + [d for d in cands if d.cls in ("ImStd", "ImStb")]
|
pref = [d for d in cands if d.cls == "ImGui"] + [d for d in cands if d.cls is None] + [d for d in cands if d.cls in ("ImStd", "ImStb")]
|
||||||
@@ -422,16 +491,24 @@ def main():
|
|||||||
else: structs_all[k] = v
|
else: structs_all[k] = v
|
||||||
decls_by_file[f] = decls
|
decls_by_file[f] = decls
|
||||||
|
|
||||||
tot = {"n": 0, "have": 0, "stub": 0, "size": 0, "size_have": 0, "simw": 0.0, "size_sim": 0}
|
port_src = "\n".join(open(os.path.join(ROOT, f), encoding="utf-8").read() for f in PORT_FILES)
|
||||||
|
ev_ok = {ev: ev is None or re.search(ev, port_src) is not None for _, _, ev in REPLACED}
|
||||||
|
def replaced(key):
|
||||||
|
return next((why for pat, why, ev in REPLACED if ev_ok[ev] and fnmatchcase(key, pat)), None)
|
||||||
|
|
||||||
|
tot = {"n": 0, "have": 0, "stub": 0, "size": 0, "size_have": 0, "simw": 0.0, "size_sim": 0, "repl": 0}
|
||||||
for f in CPP_FILES:
|
for f in CPP_FILES:
|
||||||
rows = []
|
rows = []
|
||||||
st = {"n": 0, "have": 0, "stub": 0, "size": 0, "size_have": 0, "simw": 0.0, "size_sim": 0}
|
st = {"n": 0, "have": 0, "stub": 0, "size": 0, "size_have": 0, "simw": 0.0, "size_sim": 0, "repl": 0}
|
||||||
for u in sorted(all_up[f], key=lambda u: u.line):
|
for u in sorted(all_up[f], key=lambda u: u.line):
|
||||||
un = norm_cpp(u.body)
|
un = norm_cpp(u.body)
|
||||||
if u.excl:
|
if u.excl:
|
||||||
rows.append((u.section, "[-]", "", u, None, u.excl)); continue
|
rows.append((u.section, "[-]", "", u, None, u.excl)); continue
|
||||||
st["n"] += 1; st["size"] += len(un)
|
|
||||||
p = find(u)
|
p = find(u)
|
||||||
|
why = replaced(u.key) if p is None else None
|
||||||
|
if why:
|
||||||
|
st["repl"] += 1; rows.append((u.section, "[=]", "", u, None, why)); continue
|
||||||
|
st["n"] += 1; st["size"] += len(un)
|
||||||
if p is None:
|
if p is None:
|
||||||
rows.append((u.section, "[ ]", "", u, None, "")); continue
|
rows.append((u.section, "[ ]", "", u, None, "")); continue
|
||||||
body = p.body
|
body = p.body
|
||||||
@@ -470,34 +547,41 @@ def main():
|
|||||||
else: missing.append(v)
|
else: missing.append(v)
|
||||||
enum_rows.append((nm, have, counted, missing))
|
enum_rows.append((nm, have, counted, missing))
|
||||||
|
|
||||||
field_rows, field_n, field_have = [], 0, 0
|
field_rows, field_n, field_have, field_repl = [], 0, 0, 0
|
||||||
for nm, (fl, line, sec) in sorted(structs_all.items()):
|
for nm, (fl, line, sec) in sorted(structs_all.items()):
|
||||||
fl = [x for x in fl if not x[2]]
|
fl = [x for x in fl if not x[2]]
|
||||||
if not fl: continue
|
repl = [x[0] for x in fl if x[0] not in lua_fields and replaced("%s::%s" % (nm, x[0]))]
|
||||||
|
fl = [x for x in fl if x[0] not in repl]
|
||||||
|
if not fl and not repl: continue
|
||||||
missing = [x[0] for x in fl if x[0] not in lua_fields]
|
missing = [x[0] for x in fl if x[0] not in lua_fields]
|
||||||
field_n += len(fl); field_have += len(fl) - len(missing)
|
field_n += len(fl); field_have += len(fl) - len(missing); field_repl += len(repl)
|
||||||
field_rows.append((nm, len(fl) - len(missing), len(fl), missing))
|
field_rows.append((nm, len(fl) - len(missing), len(fl), missing, repl))
|
||||||
|
|
||||||
api_rows = []
|
api_rows, api_repl = [], 0
|
||||||
port_names = set(by_name)
|
port_names = set(by_name)
|
||||||
for f, label in (("imgui.h", "Public API (imgui.h, namespace ImGui)"), ("imgui_internal.h", "Internal API (imgui_internal.h, namespace ImGui)")):
|
for f, label in (("imgui.h", "Public API (imgui.h, namespace ImGui)"), ("imgui_internal.h", "Internal API (imgui_internal.h, namespace ImGui)")):
|
||||||
d = {k: v for k, v in decls_by_file[f].items() if not v[1]}
|
d = {k: v for k, v in decls_by_file[f].items() if not v[1]}
|
||||||
|
r = [k for k in d if k not in port_names and replaced("ImGui::" + k)]
|
||||||
|
api_repl += len(r)
|
||||||
|
for k in r: del d[k]
|
||||||
have = [k for k in d if k in port_names]
|
have = [k for k in d if k in port_names]
|
||||||
api_rows.append((label, len(have), len(d), sorted((k for k in d if k not in port_names), key=lambda k: d[k][0]), d))
|
api_rows.append((label, len(have), len(d), sorted((k for k in d if k not in port_names), key=lambda k: d[k][0]), d))
|
||||||
|
|
||||||
# ------------------------------------------------------------------ summary (stdout + file)
|
# ------------------------------------------------------------------ summary (stdout + file)
|
||||||
head = []
|
head = []
|
||||||
head.append("%-22s %9s %9s %9s %11s %9s" % ("upstream file", "funcs", "ported", "by size", "similarity", "stubs"))
|
head.append("%-22s %9s %9s %9s %11s %9s %9s" % ("upstream file", "funcs", "ported", "by size", "similarity", "stubs", "replaced"))
|
||||||
for f, s in summary:
|
for f, s in summary:
|
||||||
head.append("%-22s %9d %9s %9s %11s %9d" % (f, s["n"], pct(s["have"], s["n"]), pct(s["size_have"], s["size"]),
|
head.append("%-22s %9d %9s %9s %11s %9d %9d" % (f, s["n"], pct(s["have"], s["n"]), pct(s["size_have"], s["size"]),
|
||||||
pct(s["simw"], s["size_sim"]), s["stub"]))
|
pct(s["simw"], s["size_sim"]), s["stub"], s["repl"]))
|
||||||
head.append("%-22s %9d %9s %9s %11s %9d" % ("TOTAL", tot["n"], pct(tot["have"], tot["n"]), pct(tot["size_have"], tot["size"]),
|
head.append("%-22s %9d %9s %9s %11s %9d %9d" % ("TOTAL", tot["n"], pct(tot["have"], tot["n"]), pct(tot["size_have"], tot["size"]),
|
||||||
pct(tot["simw"], tot["size_sim"]), tot["stub"]))
|
pct(tot["simw"], tot["size_sim"]), tot["stub"], tot["repl"]))
|
||||||
head.append("")
|
head.append("")
|
||||||
head.append("upstream code reproduced (similarity x ported size / all upstream size): %s" % pct(tot["simw"] / max(1, tot["size_sim"]) * tot["size_have"], tot["size"]))
|
head.append("upstream code reproduced (similarity x ported size / all upstream size): %s" % pct(tot["simw"] / max(1, tot["size_sim"]) * tot["size_have"], tot["size"]))
|
||||||
for label, h, n, _, _ in api_rows: head.append("%-52s %4d / %4d %s" % (label, h, n, pct(h, n)))
|
for label, h, n, _, _ in api_rows: head.append("%-52s %4d / %4d %s" % (label, h, n, pct(h, n)))
|
||||||
head.append("%-52s %4d / %4d %s" % ("Enum values (imgui.h + imgui_internal.h)", enum_have, enum_n, pct(enum_have, enum_n)))
|
head.append("%-52s %4d / %4d %s" % ("Enum values (imgui.h + imgui_internal.h)", enum_have, enum_n, pct(enum_have, enum_n)))
|
||||||
head.append("%-52s %4d / %4d %s" % ("Struct fields (imgui.h + imgui_internal.h)", field_have, field_n, pct(field_have, field_n)))
|
head.append("%-52s %4d / %4d %s" % ("Struct fields (imgui.h + imgui_internal.h)", field_have, field_n, pct(field_have, field_n)))
|
||||||
|
head.append("%d intentionally replaced by Lua equivalents [=] (%d functions, %d API declarations, %d struct fields), not counted above"
|
||||||
|
% (tot["repl"] + api_repl + field_repl, tot["repl"], api_repl, field_repl))
|
||||||
print("\n".join(head))
|
print("\n".join(head))
|
||||||
|
|
||||||
L = []
|
L = []
|
||||||
@@ -509,6 +593,7 @@ def main():
|
|||||||
L.append(" by size = same, weighted by upstream body size (tokens)")
|
L.append(" by size = same, weighted by upstream body size (tokens)")
|
||||||
L.append(" similarity = normalized token similarity of the ported bodies (difflib ratio), weighted by size")
|
L.append(" similarity = normalized token similarity of the ported bodies (difflib ratio), weighted by size")
|
||||||
L.append(" stubs = ported but (nearly) empty in the port")
|
L.append(" stubs = ported but (nearly) empty in the port")
|
||||||
|
L.append(" replaced = [=] rows: intentionally replaced by a Lua mechanism (REPLACED table), excluded from funcs")
|
||||||
L.append("Name-based matching: a renamed port function shows as [ ], a same-named one counts even if it differs. Treat as estimates.")
|
L.append("Name-based matching: a renamed port function shows as [ ], a same-named one counts even if it differs. Treat as estimates.")
|
||||||
L.append("Port-only helpers called from a ported function (same file) are inlined before comparing, since the port splits some big functions.")
|
L.append("Port-only helpers called from a ported function (same file) are inlined before comparing, since the port splits some big functions.")
|
||||||
L.append("Known low scores that are not missing code: data-driven port code (e.g. DemoWindowTables' section table), the older 1.92")
|
L.append("Known low scores that are not missing code: data-driven port code (e.g. DemoWindowTables' section table), the older 1.92")
|
||||||
@@ -516,7 +601,7 @@ def main():
|
|||||||
L.append("")
|
L.append("")
|
||||||
L += head
|
L += head
|
||||||
L.append("")
|
L.append("")
|
||||||
L.append("Legend: [x] ported (sim %) [~] stub [ ] not ported [-] excluded (c++-only / obsolete / os-specific / #if 0 / test-engine)")
|
L.append("Legend: [x] ported (sim %) [~] stub [ ] not ported [=] replaced by Lua equivalent (reason) [-] excluded (c++-only / obsolete / os-specific / #if 0 / test-engine)")
|
||||||
for f, rows in report:
|
for f, rows in report:
|
||||||
L.append("")
|
L.append("")
|
||||||
L.append("=" * 100)
|
L.append("=" * 100)
|
||||||
@@ -530,7 +615,7 @@ def main():
|
|||||||
L.append(" %s %5s %-58s %-32s %s" % (mark, sim, u.key, where, note))
|
L.append(" %s %5s %-58s %-32s %s" % (mark, sim, u.key, where, note))
|
||||||
L.append("")
|
L.append("")
|
||||||
L.append("=" * 100)
|
L.append("=" * 100)
|
||||||
L.append("API declarations not ported (by upstream line)")
|
L.append("API declarations not ported (by upstream line; [=] replacements excluded)")
|
||||||
L.append("=" * 100)
|
L.append("=" * 100)
|
||||||
for label, h, n, missing, d in api_rows:
|
for label, h, n, missing, d in api_rows:
|
||||||
L.append(""); L.append(" %s: %d / %d" % (label, h, n))
|
L.append(""); L.append(" %s: %d / %d" % (label, h, n))
|
||||||
@@ -547,10 +632,11 @@ def main():
|
|||||||
L.append(" %-40s %4d / %4d%s" % (nm, h, n, (" missing: " + ", ".join(missing)) if missing else ""))
|
L.append(" %-40s %4d / %4d%s" % (nm, h, n, (" missing: " + ", ".join(missing)) if missing else ""))
|
||||||
L.append("")
|
L.append("")
|
||||||
L.append("=" * 100)
|
L.append("=" * 100)
|
||||||
L.append("Struct fields (name found in the port / total; missing listed). Field names are matched globally, so common names may over-count.")
|
L.append("Struct fields (name found in the port / total; missing listed; [=] replaced by Lua equivalent, excluded from total). Field names are matched globally, so common names may over-count.")
|
||||||
L.append("=" * 100)
|
L.append("=" * 100)
|
||||||
for nm, h, n, missing in field_rows:
|
for nm, h, n, missing, repl in field_rows:
|
||||||
L.append(" %-40s %4d / %4d%s" % (nm, h, n, (" missing: " + ", ".join(missing)) if missing else ""))
|
L.append(" %-40s %4d / %4d%s%s" % (nm, h, n, (" missing: " + ", ".join(missing)) if missing else "",
|
||||||
|
(" [=] " + ", ".join("%s (%s)" % (x, replaced("%s::%s" % (nm, x))) for x in repl)) if repl else ""))
|
||||||
out = os.path.join(ROOT, "docs", "PORT_STATUS.txt")
|
out = os.path.join(ROOT, "docs", "PORT_STATUS.txt")
|
||||||
open(out, "w").write("\n".join(L) + "\n")
|
open(out, "w").write("\n".join(L) + "\n")
|
||||||
print("\nwrote docs/PORT_STATUS.txt")
|
print("\nwrote docs/PORT_STATUS.txt")
|
||||||
|
|||||||
Executable
+52
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# All local checks: CI's "Check" step (release.yml) + every scripted test + whole demo forced open + LÖVE.
|
||||||
|
# Usage: tools/test/check_all.sh (prints PASS/FAIL per check, exit 1 if any failed)
|
||||||
|
# HASHES=1 tools/test/check_all.sh (also prints the draw-data checksums, see hashes.sh)
|
||||||
|
cd "$(dirname "$0")/../.."
|
||||||
|
export PATH="$PATH:/nix/store/2m2ja613nndihc8qm10f2rhq6znp1nh4-luau-0.734/bin:/nix/store/4qxq4arv32ly13kl3g0m5q80gm3a35xr-luajit-2.1.1741730670/bin"
|
||||||
|
T=$(mktemp -d /tmp/imgui_check.XXXX)
|
||||||
|
R="python3 tools/test/run.py --quiet --roblox --timeout 600"
|
||||||
|
|
||||||
|
# name | expected output | command
|
||||||
|
CHECKS=(
|
||||||
|
"readme|README OK|$R --main tools/test/scripts/t_readme.luau --frames 30"
|
||||||
|
"readme-min|README OK|MINIFY=1 $R --main tools/test/scripts/t_readme.luau --frames 30"
|
||||||
|
"cached|CACHED OK|$R --main tools/test/scripts/t_cached_window.luau --frames 130"
|
||||||
|
"fixes|FIXES OK|$R --main tools/test/scripts/t_fixes.luau --frames 55"
|
||||||
|
"debugtools|DEBUGTOOLS OK|$R --main tools/test/scripts/t_debugtools.luau --frames 65"
|
||||||
|
"helpers|HELPERS OK|$R --main tools/test/scripts/t_helpers.luau --frames 45"
|
||||||
|
"multiselect|MULTISELECT OK|$R --main tools/test/scripts/t_multiselect.luau --frames 380"
|
||||||
|
"nodemo|NODEMO OK|NO_DEMO=1 $R --main tools/test/scripts/t_nodemo.luau --frames 25"
|
||||||
|
"widgets|OK|$R --main tools/test/scripts/t_widgets.luau --frames 80"
|
||||||
|
"tables|OK|$R --main tools/test/scripts/t_tables.luau --frames 150"
|
||||||
|
"tabs|scrollbtn.true|$R --main tools/test/scripts/t_tabs.luau --frames 60"
|
||||||
|
"modal|round trip ok|$R --main tools/test/scripts/t_modal.luau --frames 40"
|
||||||
|
"dock|DOCK OK|$R --main tools/test/scripts/t_dock.luau --frames 60"
|
||||||
|
"dock_close|DOCK CLOSE OK|$R --main tools/test/scripts/t_dock_close.luau --frames 60"
|
||||||
|
"dock_drag|OK|$R --main tools/test/scripts/t_dock_drag.luau --frames 80"
|
||||||
|
"dock_ini|ROUNDTRIP OK|$R --main tools/test/scripts/t_dock_ini.luau --frames 60"
|
||||||
|
"dock_move|OK|$R --main tools/test/scripts/t_dock_move.luau --frames 80"
|
||||||
|
"passthru|PASSTHRU OK|$R --main tools/test/scripts/t_passthru.luau --frames 40"
|
||||||
|
"fonts|FONTS OK|$R --main tools/test/scripts/t_fonts.luau --frames 8"
|
||||||
|
"textproxy|PROXY OK|$R --main tools/test/scripts/t_textproxy.luau --frames 30"
|
||||||
|
"style_editor|SE OK|$R --main tools/test/scripts/t_style_editor.luau --frames 20"
|
||||||
|
"style_leak|STYLE OK|$R --main tools/test/scripts/t_style_leak.luau --frames 60 --open"
|
||||||
|
"apps|APPS OK|$R --main tools/test/scripts/t_apps.luau --frames 120 --open"
|
||||||
|
"libhash|LIBHASH|NO_DEMO=1 $R --main tools/test/scripts/t_libhash.luau --frames 120"
|
||||||
|
"demo_open|DRAWHASH|$R --main tools/test/scripts/t_drawhash.luau --frames 150 --open"
|
||||||
|
"demo_random|^|python3 tools/test/run.py --roblox --timeout 600 --frames 400 --open"
|
||||||
|
"pixels|PIXELS SAME|a=\$($R --main tools/test/scripts/t_pixels.luau --frames 600 | grep -P '^PIX\t'); b=\$(RUN_FLAGS=ARG_FORCE=true $R --main tools/test/scripts/t_pixels.luau --frames 600 | grep -P '^PIX\t'); [ -n \"\$a\" ] && [ \"\$a\" = \"\$b\" ] && echo PIXELS SAME"
|
||||||
|
"shot|wrote|python3 tools/test/shot.py /tmp/imgui_shot.png --app"
|
||||||
|
"love|DRAWHASH|python3 tools/bundle.py --target love >/dev/null && luajit tools/test/love/t_drawhash.lua 60 Widgets,Basic && luajit tools/test/love/t_examples.lua"
|
||||||
|
)
|
||||||
|
|
||||||
|
run() { # $1=name $2=expect $3=cmd
|
||||||
|
bash -c "$3" > "$T/$1.txt" 2>&1; code=$?
|
||||||
|
if [ $code -eq 0 ] && grep -q "$2" "$T/$1.txt" && ! grep -qiE "error|traceback|stack begin|FAIL" "$T/$1.txt"; then echo "PASS $1"
|
||||||
|
else echo "FAIL $1 (exit $code, log $T/$1.txt)"; tail -5 "$T/$1.txt" | sed 's/^/ /'; fi
|
||||||
|
}
|
||||||
|
for c in "${CHECKS[@]}"; do IFS='|' read -r n e cmd <<< "$c"; run "$n" "$e" "$cmd" & done > "$T/summary.txt"
|
||||||
|
wait
|
||||||
|
sort "$T/summary.txt"
|
||||||
|
[ -n "$HASHES" ] && tools/test/hashes.sh
|
||||||
|
! grep -q "^FAIL" "$T/summary.txt"
|
||||||
Executable
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Draw-data checksums of the working tree vs a git rev (default HEAD), to prove a change renders identically.
|
||||||
|
# tools/test/hashes.sh [rev]
|
||||||
|
# lib = t_libhash (library only, no demo): must stay equal unless rendering is meant to change
|
||||||
|
# demo = t_drawhash with Widgets,Basic / whole demo open: changes with any demo edit
|
||||||
|
cd "$(dirname "$0")/../.."
|
||||||
|
export PATH="$PATH:/nix/store/2m2ja613nndihc8qm10f2rhq6znp1nh4-luau-0.734/bin:/nix/store/4qxq4arv32ly13kl3g0m5q80gm3a35xr-luajit-2.1.1741730670/bin"
|
||||||
|
REV=${1:-HEAD}
|
||||||
|
hashes() { # $1 = repo dir
|
||||||
|
( cd "$1"
|
||||||
|
R="python3 tools/test/run.py --quiet --roblox --timeout 600"
|
||||||
|
echo "lib $(NO_DEMO=1 $R --main "$OLDPWD/tools/test/scripts/t_libhash.luau" --frames 120 | grep -o 'LIBHASH.*')" &
|
||||||
|
echo "demo-basic $($R --main tools/test/scripts/t_drawhash.luau --frames 150 --open-only Widgets,Basic | grep -o 'DRAWHASH.*')" &
|
||||||
|
echo "demo-all $($R --main tools/test/scripts/t_drawhash.luau --frames 150 --open | grep -o 'DRAWHASH.*')" &
|
||||||
|
echo "love-basic $(python3 tools/bundle.py --target love >/dev/null; luajit tools/test/love/t_drawhash.lua 60 Widgets,Basic | grep -o 'DRAWHASH.*')" &
|
||||||
|
wait ) | tr "\t" " " | sort
|
||||||
|
}
|
||||||
|
W=$(mktemp -d /tmp/imgui_rev.XXXX)
|
||||||
|
git worktree add -q --detach "$W" "$REV"
|
||||||
|
hashes "$W" > "$W.old" & hashes . > "$W.new"; wait
|
||||||
|
git worktree remove --force "$W"
|
||||||
|
echo "check $REV working tree"
|
||||||
|
paste "$W.old" "$W.new" | awk -F'\t' '{split($1,a," "); split($2,b," "); printf "%-12s %-30s %-30s %s\n", a[1], a[3], b[3], (a[3]==b[3]?"same":"CHANGED")}'
|
||||||
@@ -4,4 +4,4 @@ set -e
|
|||||||
cd "$(dirname "$0")/../../.."
|
cd "$(dirname "$0")/../../.."
|
||||||
python3 tools/bundle.py --target love >/dev/null
|
python3 tools/bundle.py --target love >/dev/null
|
||||||
nix-shell -p luajit --run "luajit tools/test/love/t_drawhash.lua 150 Widgets,Basic && luajit tools/test/love/t_drawhash.lua 150 all && luajit tools/test/love/t_examples.lua"
|
nix-shell -p luajit --run "luajit tools/test/love/t_drawhash.lua 150 Widgets,Basic && luajit tools/test/love/t_drawhash.lua 150 all && luajit tools/test/love/t_examples.lua"
|
||||||
echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 1385106188 / 1292122782"
|
echo "expected (Luau, tools/test/scripts/t_drawhash.luau): 154977593 / 263656315"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
-- Runs examples/example_love and examples/example_shared main.lua headless under LuaJIT (mock love) for some frames.
|
-- Runs examples/example_love main.lua headless under LuaJIT (mock love) for some frames.
|
||||||
for _, ex in ipairs({ "examples/example_love", "examples/example_shared" }) do
|
for _, ex in ipairs({ "examples/example_love" }) do
|
||||||
dofile("tools/test/love/mock_love.lua")
|
dofile("tools/test/love/mock_love.lua")
|
||||||
love.filesystem.getSource = function() return ex end
|
love.filesystem.getSource = function() return ex end
|
||||||
love.filesystem.load = function(p) return assert(loadfile(ex .. "/" .. p)) end
|
love.filesystem.load = function(p) return assert(loadfile(ex .. "/" .. p)) end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.DockingEnable)
|
|||||||
G.ImGui_ImplRoblox.Init()
|
G.ImGui_ImplRoblox.Init()
|
||||||
local names = { "ShowExampleAppConsole", "ShowExampleAppLog", "ShowExampleAppLayout", "ShowExampleAppPropertyEditor", "ShowExampleAppLongText",
|
local names = { "ShowExampleAppConsole", "ShowExampleAppLog", "ShowExampleAppLayout", "ShowExampleAppPropertyEditor", "ShowExampleAppLongText",
|
||||||
"ShowExampleAppAutoResize", "ShowExampleAppConstrainedResize", "ShowExampleAppSimpleOverlay", "ShowExampleAppWindowTitles",
|
"ShowExampleAppAutoResize", "ShowExampleAppConstrainedResize", "ShowExampleAppSimpleOverlay", "ShowExampleAppWindowTitles",
|
||||||
"ShowExampleAppCustomRendering", "ShowExampleAppDocuments", "ShowExampleAppDockSpace", "ShowExampleAppFullscreen", "ShowExampleAppAssetsBrowser", "ShowExampleAppMainMenuBar" }
|
"ShowExampleAppCustomRendering", "ShowExampleAppDocuments", "ShowExampleAppDockSpace", "ShowExampleAppFullscreen", "ShowExampleAppAssetsBrowser", "ShowExampleAppMainMenuBar", "ShowExampleAppImageViewer" }
|
||||||
local tools = { "ShowMetricsWindow", "ShowDebugLogWindow", "ShowIDStackToolWindow", "ShowAboutWindow" }
|
local tools = { "ShowMetricsWindow", "ShowDebugLogWindow", "ShowIDStackToolWindow", "ShowAboutWindow" }
|
||||||
local open = {}
|
local open = {}
|
||||||
local frame = 0
|
local frame = 0
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
-- Debug tools + misc imgui.cpp ports: item picker, DebugFlashStyleColor, DebugLocateItem, context hooks, AddInputCharactersUTF8, ImBezierCubicClosestPoint
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||||
|
local ctx = ImGui.CreateContext(); G.ImGui_ImplRoblox.Init()
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
local failed = {}
|
||||||
|
local function check(ok, msg) if not ok then table.insert(failed, msg); print("FAIL " .. msg) end end
|
||||||
|
|
||||||
|
-- ImBezierCubicClosestPoint: straight-line cubic (0,0)-(30,0)-(60,0)-(90,0): closest point to (45,10) is (45,0)
|
||||||
|
local p1, p2, p3, p4 = ImVec2(0, 0), ImVec2(30, 0), ImVec2(60, 0), ImVec2(90, 0)
|
||||||
|
local cp = G.ImBezierCubicClosestPoint(p1, p2, p3, p4, ImVec2(45, 10), 20)
|
||||||
|
check(math.abs(cp.x - 45) < 1e-3 and math.abs(cp.y) < 1e-6, ("ImBezierCubicClosestPoint %g,%g"):format(cp.x, cp.y))
|
||||||
|
-- Curved: result must lie on the curve (distance to a dense sampling of the curve ~0) and beat the endpoints
|
||||||
|
local q1, q2, q3, q4 = ImVec2(0, 0), ImVec2(0, 100), ImVec2(100, 100), ImVec2(100, 0)
|
||||||
|
local target = ImVec2(50, 120)
|
||||||
|
for _, r in { G.ImBezierCubicClosestPoint(q1, q2, q3, q4, target, 64), G.ImBezierCubicClosestPointCasteljau(q1, q2, q3, q4, target, 0.25) } do
|
||||||
|
check(math.abs(r.x - 50) < 0.5 and math.abs(r.y - 75) < 0.5, ("closest point on curve %g,%g (expected ~50,75)"):format(r.x, r.y))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- AddInputCharactersUTF8 queues one Text event per codepoint
|
||||||
|
io:AddInputCharactersUTF8("a\u{e9}\u{20ac}\u{1F600}")
|
||||||
|
local chars = {}
|
||||||
|
for _, e in ctx.InputEventsQueue.Data do if e.Type == G.ImGuiInputEventType.Text then table.insert(chars, e.Text.Char) end end
|
||||||
|
-- (this build has IM_UNICODE_CODEPOINT_MAX = 0xFFFF like upstream's default ImWchar16: U+1F600 becomes IM_UNICODE_CODEPOINT_INVALID)
|
||||||
|
check(#chars == 4 and chars[1] == 0x61 and chars[2] == 0xE9 and chars[3] == 0x20AC and chars[4] == ((G.IM_UNICODE_CODEPOINT_MAX >= 0x1F600) and 0x1F600 or 0xFFFD), "AddInputCharactersUTF8 " .. table.concat(chars, ","))
|
||||||
|
|
||||||
|
-- Context hooks
|
||||||
|
local log = {}
|
||||||
|
local function hook(t, name)
|
||||||
|
local h = G.ImGuiContextHook(); h.Type = t; h.Callback = function(c, hk) table.insert(log, name) end
|
||||||
|
return ImGui.AddContextHook(ctx, h)
|
||||||
|
end
|
||||||
|
local T = G.ImGuiContextHookType
|
||||||
|
hook(T.NewFramePre, "nfpre"); hook(T.NewFramePost, "nfpost"); hook(T.RenderPre, "rpre"); local rpost = hook(T.RenderPost, "rpost")
|
||||||
|
|
||||||
|
-- Context defaults (ImGuiContext()/ImGuiIO() constructors, upstream values)
|
||||||
|
check(ctx.DebugFlashStyleColorIdx == G.ImGuiCol.COUNT and ctx.ActiveIdSource == G.ImGuiInputSource.None and io.MouseSource == G.ImGuiMouseSource.Mouse
|
||||||
|
and ctx.DebugBreakKeyChord == G.ImGuiKey.Pause and ctx.DebugItemPickerActive == false and ctx.DebugLocateId == 0 and ctx.CurrentPixelDensity == 1.0, "context defaults")
|
||||||
|
check(T.PendingRemoval_ == 7 and T.Shutdown == 6, "ImGuiContextHookType values")
|
||||||
|
check(io.BackendPlatformName == "imgui_impl_roblox" and io.BackendRendererName == "imgui_impl_roblox", "BackendPlatformName/BackendRendererName")
|
||||||
|
check((os.date == nil) == (ImGui.GetPlatformIO().Platform_SessionDate == 0), "Platform_SessionDate set from os.date() when available") -- (the test sandbox has no os.date)
|
||||||
|
ImGui.GetPlatformIO().Platform_SessionDate = 20261015 -- exercise the metrics Settings section date code
|
||||||
|
|
||||||
|
-- Style color flash
|
||||||
|
local col = ImGui.GetStyle().Colors[G.ImGuiCol.Button]
|
||||||
|
local orig = { col.x, col.y, col.z, col.w }
|
||||||
|
|
||||||
|
local f, rect, picked, broke, button_id = 0, nil, nil, 0, 0
|
||||||
|
ctx.DebugBreakCallback = function() broke += 1 end
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
f += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
if rect and f == 5 then io:AddMousePosEvent((rect[1].x + rect[2].x) / 2, (rect[1].y + rect[2].y) / 2) end
|
||||||
|
if f == 6 then ImGui.DebugStartItemPicker() end
|
||||||
|
if f == 8 then io:AddMouseButtonEvent(0, true) elseif f == 9 then io:AddMouseButtonEvent(0, false) end
|
||||||
|
ImGui.NewFrame()
|
||||||
|
if f == 1 then check(table.concat(log, " ") == "nfpre nfpost", "hooks after NewFrame: " .. table.concat(log, " ")) end
|
||||||
|
if f == 8 then picked = ctx.DebugItemPickerBreakId end
|
||||||
|
if f == 3 then ImGui.DebugFlashStyleColor(G.ImGuiCol.Button) end
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("DebugTools")
|
||||||
|
ImGui.Button("Target")
|
||||||
|
if f == 2 then local a, b = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(); rect = { ImVec2(a.x, a.y), ImVec2(b.x, b.y) } end
|
||||||
|
local target_id = ctx.LastItemData.ID
|
||||||
|
button_id = target_id
|
||||||
|
if f == 12 then ImGui.DebugLocateItem(target_id) end
|
||||||
|
if f == 13 then check(ctx.DebugLocateId == 0, "DebugLocateItem resolved by ItemAdd()") end
|
||||||
|
ImGui.DebugDrawItemRect(); ImGui.DebugDrawCursorPos(); ImGui.DebugDrawLineExtents()
|
||||||
|
ImGui.DebugTextUnformattedWithLocateItem(("id 0x%08X here"):format(target_id))
|
||||||
|
ImGui.End()
|
||||||
|
if f == 3 then -- open the metrics Settings/InputText sections
|
||||||
|
local mw = ImGui.FindWindowByName("Dear ImGui Metrics/Debugger")
|
||||||
|
for _, lbl in { "Settings", "SettingsWindows", "SettingsTables", "InputText" } do mw.DC.StateStorage[mw:GetID(lbl)] = true end
|
||||||
|
ctx.DebugMetricsConfig.SettingsHighlightOldEntries = true
|
||||||
|
end
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(400, 10), G.ImGuiCond.Always); ImGui.ShowMetricsWindow()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(400, 300), G.ImGuiCond.Always); ImGui.ShowDebugLogWindow()
|
||||||
|
if f == 4 then
|
||||||
|
local c = ImGui.GetStyle().Colors[G.ImGuiCol.Button]
|
||||||
|
check(c.w == 1.0 and ctx.DebugFlashStyleColorIdx == G.ImGuiCol.Button, "flash active")
|
||||||
|
end
|
||||||
|
ImGui.Render(); G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
if f == 1 then check(table.concat(log, " ") == "nfpre nfpost rpre rpost", "hooks after Render: " .. table.concat(log, " ")); ImGui.RemoveContextHook(ctx, rpost) end
|
||||||
|
if f == 2 then check(table.concat(log, " ") == "nfpre nfpost rpre rpost nfpre nfpost rpre", "RemoveContextHook: " .. table.concat(log, " ")) end
|
||||||
|
if f == 60 then
|
||||||
|
local c = ImGui.GetStyle().Colors[G.ImGuiCol.Button]
|
||||||
|
check(c.x == orig[1] and c.y == orig[2] and c.z == orig[3] and c.w == orig[4] and ctx.DebugFlashStyleColorIdx == G.ImGuiCol.COUNT, "flash restored color exactly")
|
||||||
|
check(picked ~= nil and picked ~= 0 and picked == button_id, ("item picker set DebugItemPickerBreakId (%s vs %s)"):format(tostring(picked), tostring(button_id)))
|
||||||
|
check(not ctx.DebugItemPickerActive and broke >= 1, ("item picker break hook called (%d)"):format(broke))
|
||||||
|
if #failed == 0 then print("DEBUGTOOLS OK") end
|
||||||
|
end
|
||||||
|
end)
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
-- Regressions vs upstream: clipboard paste filter (InputTextEx), ImParseFormatTrimDecorations (Ctrl+click temp input), ShrinkWidths tie order
|
-- Regressions vs upstream: clipboard paste filter (InputTextEx), ImParseFormatTrimDecorations (Ctrl+click temp input), ShrinkWidths tie order,
|
||||||
|
-- CalcItemSize by value, PushClipRectFullScreen (drop target outside clip rect), long TextUnformatted, PushFont/PopFont, InputTextMultiline line index (render/scroll/edit), Shortcut() default
|
||||||
|
-- args, IsWindowAppearing() on frame 1 (FrameCount starts at 0), ColorButton -> ColorEdit4 drag and drop
|
||||||
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||||
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init()
|
ImGui.CreateContext()
|
||||||
|
ImGui.GetIO().Fonts:AddFontDefault()
|
||||||
|
local font2 = ImGui.GetIO().Fonts:AddFontDefault() -- second font for the PushFont/PopFont check
|
||||||
|
G.ImGui_ImplRoblox.Init()
|
||||||
local io = ImGui.GetIO()
|
local io = ImGui.GetIO()
|
||||||
local failed = {}
|
local failed = {}
|
||||||
local function check(ok, msg) if not ok then table.insert(failed, msg); print("FAIL " .. msg) end end
|
local function check(ok, msg) if not ok then table.insert(failed, msg); print("FAIL " .. msg) end end
|
||||||
@@ -14,6 +19,12 @@ local w = {}
|
|||||||
for _, it in items do w[it.Index] = it.Width end
|
for _, it in items do w[it.Index] = it.Width end
|
||||||
check(w[3] == 100 and w[2] == 100 and w[1] == 99 and w[0] == 99, ("ShrinkWidths widths %s %s %s %s"):format(w[0], w[1], w[2], w[3]))
|
check(w[3] == 100 and w[2] == 100 and w[1] == 99 and w[0] == 99, ("ShrinkWidths widths %s %s %s %s"):format(w[0], w[1], w[2], w[3]))
|
||||||
|
|
||||||
|
check(G.ImFloor(-1.5) == -2 and G.ImFloor(-0.2) == -1 and G.ImFloor(2.7) == 2, "ImFloor negative")
|
||||||
|
|
||||||
|
local long_text = {}
|
||||||
|
for i = 1, 300 do long_text[i] = string.format("line %04d", i) end
|
||||||
|
long_text = table.concat(long_text, "\n") -- 2999 bytes
|
||||||
|
|
||||||
local function edit_text()
|
local function edit_text()
|
||||||
local st = ImGui.GetCurrentContext().InputTextState
|
local st = ImGui.GetCurrentContext().InputTextState
|
||||||
return G.ImGui._ByteArrayToString(st.TextA.Data, 1, st.TextLen + 1)
|
return G.ImGui._ByteArrayToString(st.TextA.Data, 1, st.TextLen + 1)
|
||||||
@@ -30,6 +41,12 @@ local function click(name, ctrl)
|
|||||||
end
|
end
|
||||||
local function release() io:AddMouseButtonEvent(0, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end
|
local function release() io:AddMouseButtonEvent(0, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end
|
||||||
local function key(k) io:AddKeyEvent(k, true); io:AddKeyEvent(k, false) end
|
local function key(k) io:AddKeyEvent(k, true); io:AddKeyEvent(k, false) end
|
||||||
|
local function center(name) local r = rects[name]; return (r[1].x + r[2].x) / 2, (r[1].y + r[2].y) / 2 end
|
||||||
|
local ml_text = "line1\nline2\nline3\nline4\nline5\nline6"
|
||||||
|
local mbuf = ImGui.NewTextBuffer(ml_text, 256)
|
||||||
|
local wbuf = ImGui.NewTextBuffer("a long line that has to be word wrapped several times inside the narrow box\nsecond", 256)
|
||||||
|
local shortcut_frames = {}
|
||||||
|
local cb_col, ce_col = G.ImVec4(1, 0, 0, 1), { 0, 0, 0, 1 }
|
||||||
|
|
||||||
game:GetService("RunService").Stepped:Connect(function()
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
f += 1
|
f += 1
|
||||||
@@ -42,16 +59,84 @@ game:GetService("RunService").Stepped:Connect(function()
|
|||||||
if f == 11 then click("s", true) elseif f == 12 then release() end
|
if f == 11 then click("s", true) elseif f == 12 then release() end
|
||||||
if f == 14 then key(G.ImGuiKey.Escape) end
|
if f == 14 then key(G.ImGuiKey.Escape) end
|
||||||
if f == 16 then click("d", true) elseif f == 17 then release() end
|
if f == 16 then click("d", true) elseif f == 17 then release() end
|
||||||
|
-- multi-line: click, Ctrl+End, type "x", Enter, "y"
|
||||||
|
if f == 21 then click("m") elseif f == 22 then release() end
|
||||||
|
if f == 23 then io:AddKeyEvent(G.ImGuiMod_Ctrl, true); io:AddKeyEvent(G.ImGuiKey.End, true) end
|
||||||
|
if f == 24 then io:AddKeyEvent(G.ImGuiKey.End, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end
|
||||||
|
if f == 25 then io:AddInputCharacter(string.byte("x")) end
|
||||||
|
if f == 26 then key(G.ImGuiKey.Enter) end
|
||||||
|
if f == 28 then io:AddInputCharacter(string.byte("y")) end
|
||||||
|
if f == 29 then io:AddKeyEvent(G.ImGuiMod_Ctrl, true); io:AddKeyEvent(G.ImGuiKey.A, true) end -- select all: renders the multi-line selection
|
||||||
|
if f == 30 then io:AddKeyEvent(G.ImGuiKey.A, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end
|
||||||
|
if f == 31 then key(G.ImGuiKey.Escape) end
|
||||||
|
-- Shortcut(chord) with default flags/owner
|
||||||
|
if f == 33 then io:AddKeyEvent(G.ImGuiMod_Ctrl, true); io:AddKeyEvent(G.ImGuiKey.S, true) end
|
||||||
|
if f == 34 then io:AddKeyEvent(G.ImGuiKey.S, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end
|
||||||
|
-- drag the ColorButton onto the ColorEdit4
|
||||||
|
if f == 36 then io:AddMousePosEvent(center("cb")) end
|
||||||
|
if f == 37 then io:AddMouseButtonEvent(0, true) end
|
||||||
|
if f == 38 then local x, y = center("cb"); io:AddMousePosEvent(x + 10, y + 5) end
|
||||||
|
if f == 39 then io:AddMousePosEvent(center("ce")) end
|
||||||
|
if f == 42 then io:AddMouseButtonEvent(0, false) end
|
||||||
|
-- word-wrapped multi-line: click, Ctrl+End, type "z"
|
||||||
|
if f == 45 then click("w") elseif f == 46 then release() end
|
||||||
|
if f == 47 then io:AddKeyEvent(G.ImGuiMod_Ctrl, true); io:AddKeyEvent(G.ImGuiKey.End, true) end
|
||||||
|
if f == 48 then io:AddKeyEvent(G.ImGuiKey.End, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end
|
||||||
|
if f == 49 then io:AddInputCharacter(string.byte("z")) end
|
||||||
ImGui.NewFrame()
|
ImGui.NewFrame()
|
||||||
ImGui.SetNextWindowPos(ImVec2(10, 10)); ImGui.SetNextWindowSize(ImVec2(300, 200))
|
ImGui.SetNextWindowPos(ImVec2(10, 10)); ImGui.SetNextWindowSize(ImVec2(300, 200))
|
||||||
ImGui.Begin("T")
|
ImGui.Begin("T")
|
||||||
|
if f == 1 then check(ImGui.GetFrameCount() == 1 and ImGui.IsWindowAppearing(), "IsWindowAppearing() on frame 1") end
|
||||||
|
if f == 2 then check(not ImGui.IsWindowAppearing(), "IsWindowAppearing() on frame 2") end
|
||||||
ImGui.InputText("##t", buf, 64); rects.t = rect()
|
ImGui.InputText("##t", buf, 64); rects.t = rect()
|
||||||
sf = ImGui.SliderFloat("##s", sf, 0.0, 100.0, "%.0f deg"); rects.s = rect()
|
sf = ImGui.SliderFloat("##s", sf, 0.0, 100.0, "%.0f deg"); rects.s = rect()
|
||||||
di = ImGui.DragInt("##d", di, 1, 0, 100, "%d%%"); rects.d = rect()
|
di = ImGui.DragInt("##d", di, 1, 0, 100, "%d%%"); rects.d = rect()
|
||||||
|
-- CalcItemSize takes 'size' by value: the caller's ImVec2 must not be written to
|
||||||
|
local bsz, csz = ImVec2(0, 0), ImVec2(-1, 40)
|
||||||
|
ImGui.Button("sz", bsz); check(bsz.x == 0 and bsz.y == 0, "Button wrote size_arg")
|
||||||
|
ImGui.BeginChild("c", csz); ImGui.EndChild(); check(csz.x == -1 and csz.y == 40, "BeginChild wrote size_arg")
|
||||||
|
-- drop target rect sticking out of the window clip rect pushes a full-screen clip rect
|
||||||
|
ImGui.RenderDragDropTargetRectForItem(G.ImRect(-50, -50, 900, 900))
|
||||||
|
ImGui.End()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(320, 10)); ImGui.SetNextWindowSize(ImVec2(300, 200))
|
||||||
|
ImGui.Begin("M")
|
||||||
|
ImGui.InputTextMultiline("##m", mbuf, 256, ImVec2(200, ImGui.GetTextLineHeight() * 3)); rects.m = rect()
|
||||||
|
if f == 30 then
|
||||||
|
local st = ImGui.GetCurrentContext().InputTextState
|
||||||
|
check(st.LineCount == 7, "multiline LineCount " .. tostring(st.LineCount))
|
||||||
|
local cw -- the multi-line child window: cursor on the last line scrolled it
|
||||||
|
for _, w in ImGui.GetCurrentContext().Windows.Data do if w.Name:find("^M/##m_") then cw = w end end
|
||||||
|
check(cw ~= nil and cw.Scroll.y > 0, "multiline scroll " .. tostring(cw and cw.Scroll.y))
|
||||||
|
end
|
||||||
|
ImGui.InputTextMultiline("##w", wbuf, 256, ImVec2(120, 80), G.ImGuiInputTextFlags.WordWrap); rects.w = rect()
|
||||||
|
if f == 30 then check(ImGui.GetCurrentContext().InputTextState:HasSelection(), "multiline select all") end
|
||||||
|
if ImGui.Shortcut(bit32.bor(G.ImGuiMod_Ctrl, G.ImGuiKey.S)) then shortcut_frames[f] = true end
|
||||||
|
ImGui.End()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 220)); ImGui.SetNextWindowSize(ImVec2(300, 150))
|
||||||
|
ImGui.Begin("D")
|
||||||
|
ImGui.ColorButton("cb", cb_col); rects.cb = rect()
|
||||||
|
ImGui.ColorEdit4("##ce", ce_col); rects.ce = rect()
|
||||||
|
ImGui.End()
|
||||||
|
-- TextUnformatted() > 2000 bytes (coarse-clipped long text path): each visible line renders only up to its '\n'
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(320, 220)); ImGui.SetNextWindowSize(ImVec2(300, 150))
|
||||||
|
ImGui.Begin("L")
|
||||||
|
local dl = ImGui.GetWindowDrawList()
|
||||||
|
local v0 = dl.VtxBuffer.Size
|
||||||
|
ImGui.TextUnformatted(long_text)
|
||||||
|
local nv = dl.VtxBuffer.Size - v0
|
||||||
|
if f == 3 then check(nv > 0 and nv <= 14 * 9 * 4, "long TextUnformatted vertices " .. nv) end
|
||||||
|
-- PushFont() saves the CURRENT font: PopFont() must restore it
|
||||||
|
local font1 = ImGui.GetFont()
|
||||||
|
check(font2 ~= font1, "font2 is the default font"); ImGui.PushFont(font2, 0.0); ImGui.PopFont()
|
||||||
|
if f == 3 then check(ImGui.GetFont() == font1, "PopFont() did not restore the previous font") end
|
||||||
ImGui.End()
|
ImGui.End()
|
||||||
ImGui.Render(); G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
ImGui.Render(); G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
if f == 8 then check(edit_text() == "abc\u{e9}", "paste: '" .. edit_text() .. "'") end
|
if f == 8 then check(edit_text() == "abc\u{e9}", "paste: '" .. edit_text() .. "'") end
|
||||||
if f == 13 then check(edit_text() == "45", "SliderFloat temp input: '" .. edit_text() .. "'") end
|
if f == 13 then check(edit_text() == "45", "SliderFloat temp input: '" .. edit_text() .. "'") end
|
||||||
if f == 18 then check(edit_text() == "50", "DragInt temp input: '" .. edit_text() .. "'") end
|
if f == 18 then check(edit_text() == "50", "DragInt temp input: '" .. edit_text() .. "'") end
|
||||||
if f == 20 and #failed == 0 then print("FIXES OK") end
|
if f == 30 then check(ImGui.TextBufferToString(mbuf) == ml_text .. "x\ny", "multiline buffer: '" .. ImGui.TextBufferToString(mbuf) .. "'") end
|
||||||
|
if f == 35 then check(shortcut_frames[33] and not shortcut_frames[32] and not shortcut_frames[34], "Shortcut(Ctrl+S) default args") end
|
||||||
|
if f == 44 then check(ce_col[1] == 1 and ce_col[2] == 0 and ce_col[3] == 0 and ce_col[4] == 1, ("color drop: %s %s %s %s"):format(ce_col[1], ce_col[2], ce_col[3], ce_col[4])) end
|
||||||
|
if f == 51 then check(ImGui.TextBufferToString(wbuf):sub(-7) == "secondz", "word-wrap buffer: '" .. ImGui.TextBufferToString(wbuf) .. "'") end
|
||||||
|
if f == 52 and #failed == 0 then print("FIXES OK") end
|
||||||
end)
|
end)
|
||||||
|
|||||||
@@ -0,0 +1,174 @@
|
|||||||
|
-- Font pieces: ImFontGlyphRangesBuilder, ImFont:CalcWordWrapPosition() vs TextWrapped(), IsGlyphRangeUnused(),
|
||||||
|
-- stb_decompress + Decode85 via AddFontFromMemoryCompressedBase85TTF() (same glyphs/metrics as the raw TTF).
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||||
|
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init()
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
local failed = {}
|
||||||
|
local function check(ok, msg) if not ok then table.insert(failed, msg); print("FAIL " .. msg) end end
|
||||||
|
|
||||||
|
-- GlyphRangesBuilder
|
||||||
|
local builder = G.ImFontGlyphRangesBuilder()
|
||||||
|
builder:AddText("Hello \u{e9}")
|
||||||
|
local ranges = G.ImVector()
|
||||||
|
builder:BuildRanges(ranges)
|
||||||
|
local got = table.concat(table.move(ranges.Data, 1, ranges.Size, 1, {}), ",")
|
||||||
|
check(got == "32,32,72,72,101,101,108,108,111,111,233,233,0", "BuildRanges " .. got)
|
||||||
|
builder:Clear()
|
||||||
|
builder:AddRanges(io.Fonts:GetGlyphRangesDefault())
|
||||||
|
builder:AddChar(0x41) -- already in range
|
||||||
|
ranges = G.ImVector(); builder:BuildRanges(ranges)
|
||||||
|
check(ranges.Size == 3 and ranges.Data[1] == 0x20 and ranges.Data[2] == 0xFF and ranges.Data[3] == 0, "AddRanges default")
|
||||||
|
check(builder:GetBit(0x20) and not builder:GetBit(0x1F) and not builder:GetBit(0x100), "GetBit")
|
||||||
|
|
||||||
|
-- stb-compressed + base85 ProggyClean.ttf (generated with an stb_compress-format encoder + binary_to_compressed_c's base85)
|
||||||
|
local B85 = ([==[
|
||||||
|
7])#######hV0qs#####]h?>#/:jl&Ql#v#[Zre=N=K_o(-(##mQ%##B>A0F_%#g(g/'##r[(##PF6'I</,GM*BiC$v%###s,0%J*RB8O+d68%eKRrQ(.d<BW_*vCL%###E%###:d@UC%)BE#=.>>#'####<_[FH
|
||||||
|
O97MKO->>#i6YY#i1JuB5eI`[VRUV$=.<T7oH[^ICAS5#T.>>#K####+>00FnH/5`S7g1TS->>#k%S+Hot3>MYJGiTLPUV$>eFVCUwS>#9G:;$n%###Sh(a1aA.;6BE-hAeI1=#au8eZ2D$CI[Mn20Gb?=iMPrIL
|
||||||
|
DSGkFI5>##Q+`AMB%]`ac<%##CFgn*<WFX:&M'^#3@:B#`2B2#[0b30lOj)#-####.%*=Cvf./LVSiHdaT_n#X$###csu8.r:%)34Dk>$<,;.OOMDgEKnIS7EM9>ZoSAZ$*3)qMQv//L^MkA#wmCAMUnG<-7F>HM
|
||||||
|
DHw>Pt*p+M[ul=Q<O]CPUoINNUm+p7S<oG76Mqr)twv9Mt0[0#=S&r;[email protected]+Y')$PP;vnQbxRMqJQ*OD:H-M#C]GQJ-jBPO&%^Qmus+M3@C58qNO&#sNk,%?$xu#Fle&,W6=G2,Hb;-;wcP$
|
||||||
|
tPBuuE1V:vm3SML+x0B#/Dabh^KfW-j(.`&V8WQ-2$ZtQQpp5#l,$R#=`i['#l+S#Q*IX#6GMk#op/i#:n*x#tJV0$t#F=$X6iC$1/oh$TrKb$S/kt$&,)O%=q]E%o]n[%6dRd%lGTq%_#`C&$T1_&>Y^Y&2wbq&
|
||||||
|
TB-K'@IZC'%]#V'Uv'n'[R%1(D6?c(OD1$)e>Lr(Z*24)C5Yb)R/uY)#PPj)uaFu)pEt**@7KY*j<MS*5Nki*SAC?+x/x5+ugwH+;f6w+**;8,V?'+,3Y6W,pGkM,sgEa,%5h7-QbL,-Z8sL-.[r<-r;tI-5hnl-
|
||||||
|
Cnqc-CX86.QEKF.,hI9.1W`S%mQrV[C4s&#t3&KDU+DvZ)$SpA>O*dskh5??pb?^Y44[W7m@O9&/?o&YNgT?-'aPdsd(-qA0[9_#WMT9AcO#wm%e;e3?oWq/R1,XIghlWnL4mEX_v(R^+$4:A6.*x6Y+w_,ED)`,
|
||||||
|
PIDRpbf::fN$F.N4Bv:/>80xm6wgLiuWsFXrv)AHt/sl19::#%T1?Ynm49;SFb8/N7n.a><s3T0OpXm(4@4sf)_W/WEcIZ70Ne5_QYMTBLMbT0%t4Tph<HT^;n@*>$P%O)]J/0j$)macqO]pg2V2u$&t@##5f1$#
|
||||||
|
E@%%#Uqn%#fKb&#v&U'#0WH(#@2<)#Pc/*#a=#+#qnl+#+I`,#;$S-#KTF.#[/:/#l`-0#&;w0#6lj1#oiFJ('Moe2;4HZ$mgfX-b/g/HIt71#DRT<Lq8%dM$bLDNoaVV-Pm^dOJ@6##XaYx')_#&4Za=sQ-,7&4
|
||||||
|
Oe)>Pn<<>P0]15/$[K<Lrhci9h&@2LaX:9$;$Ne?L*'?76@Vp.%XK<LdcPe6%l^>$?:b1#^QZ`*uqmV-8lt.ZRwbVRqjtH*PhBQ(-t]N-0*aYMiEVq7a=W4#`6_c)$/*JL(L-^(]$wIMlcs(UsvHv,,rbA#/2u]O
|
||||||
|
hdcHMucWU-k^n:$VGR;oFHnq7e(Q&#uDdE&];bLcqC/^daSxFNtTGw.P3w.Ln1k,O7$22%r]<WS?OY)NJ[vI:DJNGokW_'6Q;I28n8X,Okie;)sJl_fawt-$II`;-sINN$tre+MLFg;-cG,-M<vp%N`tb48]_c6s
|
||||||
|
:#^#$J?HC$,>2U%qS#n8as:jrQ=$##/)>uuN?Sq7^fV2ivEjJN-MT;-UJ;QMM=6##Cni&O1/Ut'7#[UN>+]K3M@2+8UkW1#k.WUN4DU;-j8(1$)[888aOHpgh<7r7#n8I?%R7p7tGF]u%OtlSE4$##6We'8SdfFI
|
||||||
|
WVZ>nZ6c8MPhc(.i10p7x0'.=;lxb-4r'E>qC0%%?].e;I#72LclTAO0qD>$Vvnq2h^fW-LL4OiYW-mNFJuH&O(35&85c58@<iv%VwpGMX#$*&WFjp'jZCx$5N:q8/sgd4LhC^++re_8de;m8?37w%RICm8o4wd+
|
||||||
|
*OhaW?_m.'3XYjM/gh.(xEe58>Y31#_Lx-[?u>q7:5i8K5(;mOM8#=Q'`+%&7'6i#BtxA?0KPM-1PHM&/esr7gC>B$1wGJ(>Q5t7]#:xT:tl.$Tvx;-%&26&`JT58^V_,FWN-c0F####HSI@1K<8FN&?bO'2[IfM
|
||||||
|
j'YWN,<hn3bqwJN0:kC:(Yf>et`e;)LBf68(24gj1WXW'afQfFv7V.8R02?[LUlDN3cha'&]T&#b96$2*T5s7L5jv[&tsR%3dG2M0.(58=RK=`37;ENkWl9)Y7dp7v_k;fk&Z31P>5r'ZC$M&7&i)<U/5F%<bj/:
|
||||||
|
b5vAmK4$##&J<j$&6G<QMA&D:Hbkxu.NTkM6ev.:XCF&#iR7S82tuF%k$IAOvjw:$ku0p7sTMBm9pUh$KAuu#5[,qpn%(.*;?>5SkFGm;i'72Ljb]1#+BcK:Fgs.F8`aBNT($28/7*.H1GrvqoTa2`b:EO-=sKj9
|
||||||
|
crw0#.4D.M(s<A+,DPc=mTGQ:uaAL:Wjp#(R^uw9KvsDN781]&6tgA=_$Dc%.7vcMO>m;51/tW8Y@@S/#1jn8BZT/-Y,lJa-2Ht$i=(HMv'(P8Y>4AuNb6j9hP6(d?^OE23b<Q8)H*nkb$M#1kJAqgUJSk8kK'dk
|
||||||
|
5#uk%xHA88V`;3;KicD%RE-RLwIsJ%#Et,krIK64v,N/Vn@^5+,(;eMs7jf%Pa64:0nhEYGlk%(I9x9Mk3AN9PV*1#m1OL;Y@0qb]2``]dhsp8HNDLPQ(C-M(NbS85^wek`P@'$fCAV8_hGWSE<?tO(=ZU*EK949
|
||||||
|
9ux0#2nKA=dT'^#>sR&ZePWV&-=i>RM-']:uc%4;r>8R$tZgSN$fo1#8&n/;%G7@[Jf4x+.bjq7rlBEYk>h-%(X8j9VCxj2OM:/1_>qs7fEt-$n17tQE&9A.S+Ne+3]a:%$MLp7t]Wx'>3Ks7wtpDP.%L)$Q]BDN
|
||||||
|
NOZf:iskA#j:8T@)BC[.<2N=8c4G`&EW<a&`aQd+s_Pp'a_&6(M@M.$:t1W?4@0#AKhL&OZr_G5Ndap''9nq&@EQkTL0>@$%,m/:PIh)P<e=K8`cI4;5/hu0$qVv[#aKm<Vh;BmVxk4%x3Kn9+Nkxu6Ro94fPQ:8
|
||||||
|
P_)edQ/G0MPJKU11j?NWE?N(80m^&v+J?J:DRPx^YwdHMNf4-:K3<p^FSfo7kKtWSvQjN9)v[B739$^*i-It]VKVv/>Eq3:+x&'-t0sc;>[:</nIMS2He60Vdig`&6]Hj9QO_&RvTf'&mZ]mBRJ3SabaG'?hIi.$
|
||||||
|
$./32CCP)NBxoO(9L(c%jxcp7a.-e4Y5n3-qg-a/9c639%wJ+G5X1e&?5V?-a?>Q-;4*88df9dk@]?Y'/ehS@A:R&m2_(:)QYJwTme-LEcuko$4B:T1=^J$&2(+@-]Ziu,ae_-tbUGDN`-Ra$;hhjW/v[lA3pKq^
|
||||||
|
H<;&(8#DwP3c)/-SoDu7GaHQ:AX=W%+7k,4dQ,N11A>2Bv%03M_/wU&oNi5A)(&3MslOf-.brg=5SHx#7jg]O.F`c)6jK788At1#UfqV-`K<h=Vdb-8U,$90QK@I-E8o3%$grI;4HtdX.Qs$9nga.-c;@v><=ijV
|
||||||
|
anS,,diDack,uG%(q-&>^Ep&?uTh&UIULu:N*DkDaoK>0T>R@@ho/P+uw<T8#pekXXLZ)GN?Hf,CHuU8>pTdx:O3h,p583DQa5frln2-eHrS`V[r7V<$+%Ej0HN,NbN&WQKP9p9qDP-L%r'r(Mj9P+3*GJ*2$/
|
||||||
|
4_R;-22R2$*LKj:':c_-%4+X.)=a78Q<x0#JP;'PY?=(&BgGp8r;7F%@<PWJYRkH,+GX	ePr^o1%/8JE#QUU8jn'S=uPA$TS'J)G=@>^$r?%=FY%8=cFU_Kffo7m-u8NI/5'$NF81.taNq7)?Kq^T+DB)Wg>jV
|
||||||
|
(ckS*I,1qAb-<p^7Mjf%NcuFNgX12)80EuK,1)g0jPmd;%aZp0ggZdM)j&Z$v>ZQS/U@)2.KDgU#Kk95sor>e@>(QYI<%Z*uB-x0*0K39$uQRX^T]M9_U?^?XD-:8t`MqM0pLP9BmS6(xp?e9dca,bq<3K*^w@T[
|
||||||
|
bub7%Vu;S8/G5F%0'8rVUDCnNj9%dMllOf-B)(Wf2(73)oGHH;IoZp0Q1Gp7%Wc&#v6D39^P()HBs(2';aFq72v6b6P77'&h2da<TJ_pT`rE)-rf,78tAk)>6Rm3/Zt8#QHo4`)XmW7h'<>e+2NgM9dboLavtx$$
|
||||||
|
KIK$>1fAoU4NP^0whIt7^iWx''x:Q:`PRB$lhV29)-.K<)dFu3^;mU8UO1S*KTJ/M$=Iw3qi6JN4AFoOalkGNhxNv'HM)?-0(Oh;0:aJsj[lT'5kWm83sdC%hHV7;LSb<S7du7IeKD'mS9JC9Jxr0$t8l>Pxwh9.
|
||||||
|
L,hs7Elx2)+C30*5d'q7#L?T0W#H^Zths.L2*578H]]^-nO,X&2/Z&FM9%%B8&E#>OgR?RC5'T*;Xx9RhdA7(L01H;Pk1NV87(p7Qd41#fFQ;-xe=C$uf['$C+RPs51b-<8x.4rJ;pt-aA,q7Z6QYq]s/FN6PT[%
|
||||||
|
gdf68Omx0#HA2s-tGPSIU*@w^dr,X/kJm;?T$dF#IwGP$hn1a*]p7,M.S?M9a$nx0;,Gp74,IpgKNdm'@Bt784N&:DUix*=bc^<Vh+&G[/;dFGR$=I$_Y##PPEV+8=uWd=5KWB%j&h'FPb84=_lDQ(Red/:KD/F.
|
||||||
|
-o'^#nvkQ8'FjZSZ96Y/o(,,M[jxJjk)lWNSaX%(x11$8SF=[.P8k2B>_sR8w[gJj7*:6:5`)QLb:^i?lw%rMgu>q78aq5M?^w>%IVPp7M8td=/H+s7>&d:;k:&qK=?ex%a*sYPO[+<%&K2;8;fD.$Wk@vPTlC:R
|
||||||
|
,9R>%-u#6AQ]m&6e32?%THYs%m-n58^<(0E=f2#$wonB$QB]m8R(7mMSpse*)jK29*O$90+$bk)VgB^m/i9R$)8LV4iPpdFBFX)-Q6s58&a3dX&TB59&@_[KAuJmSp13/%8Pp'5D2ZJ:j3:`f+5d+Nc2r.([59p7
|
||||||
|
6A#'v>J6u'm[2Q8CS+5rbs14$nK%B>m%6Q:`%P1):BA*N1a-A)96D3#1TCt7#IgE#U/VR=`(qQ(U:c58:RRPDZ+,58@`EdtKP>[PQd/,M9u#>9d*-g)&%B@-j<1e(>ih29via.-S?5`8FO:;B&?ch'PMk8@YG@*n
|
||||||
|
P@st7QGt-$,``wP[ZNC(uTEq70l)?[nS$i$FKgS8jJN9B<kU';c$/32mbBD$4;qeM?5R=MB:K'd@-K^&L.M'Oq4n2$SK%+dwY&(m7/HJ.emw-MLS]0)75,S32BtQ8f3;nqGb=<%Ckb69s#Z&Q^OVv-/vOp7:Mh,F
|
||||||
|
s2K1:'.vhOt3QA%7rt:(?h+G%2V:<@?O#Qqkl2$;YqE#1:xK,M&%uW)DLo;oA^4e1cnV2([,HKDk)U/dN+dP8:N-Up5d1$1LNP^=EMv^ZR7cP8$Obx%xL>p'CUH-MgU,3D7)D_0'?D_=g>d&QMFJk*7&Pp7Gt3[T
|
||||||
|
TwY+Y0v2o0DvI^#s-%g:26KE>o_`h*%L^VH1LbC=3;xji-O7r'Lf7KW4N+[&i7PW87O,i8DUjTBFRS?$UG1o*(VRd;4QG1#mpl%$>iraIcDKQ(d%g4([email protected]?^O&gCAr7t$.Ae*b8k&;1=6`d=_d'-05fD.D)E.
|
||||||
|
uFxZ(d4vQ8.(J(8.%NX-X3RpK:'oLabx4I-1q.:)0.<q0/jF88;0ESCEE8SRN0]u:kpB+$eu*a*2XTe;?@)%IZ[./$HD]BfZ1jk9iCJ32e9R78a=)c<)]<T^'Kc'@lKLKE,LNn%%cl-MpehT$W2`l2b'nj959tT'
|
||||||
|
1wv*$&9#[JNAC]&[mtvPGwA5;ckQdb`;]R$I&gjDXVfh<NTX1#a8T;-*F:`$qqu,MVqgZ$R(*@II4?uuW%QW@4LoKYVb%R8tks-$HG<f;^31ObK;lR(U@k+MLa'VIt)LE%IrM7)wU:EN&W[39ijMG%#w4g:,Xw0#
|
||||||
|
w0[588iGJ$ps_>.,umo%x+B7$S)0p71m99pnERN93)9I$)#(IM_Yd>#6x;XCg]5<-3efW85,/n1#S]C'qqvcD2n4`8u9j<-E`Y%&`Qhg*tt2e$N$t49<#oW&^a*@,$^^dk7xK)$GJP/M>KO0&ND_j9>>P&#JuF.3
|
||||||
|
S<r>I:OPE*XF>dOo#P-(I7Vj;vrlm968R,tB,cS(]FeW&&O`9$-L-5#aS-Ak*o#iSuvYmTPpq9&E*n&%lBap7aS=r7jnP7Ah-]pK>xo_N]mjvPjtJ.2/*'W$4BFQ8bN((&WpULN`$^3i'@+G%.[#.$_6>3)jr[PA
|
||||||
|
&Wp5Uk_uk%Hk@bNH`(S%T)p/MdebV$4iQr7(QMG%k%8bRfU/L.bn/mSCf>SI$`G%h9JSpB%>xsF,^-Ehgn*Q8&j]K<l(Md8m/9MmPZ4j`a4K2`eI,H:m*Zeohdc,X+fTuYcjEE%M^5t7YsvK3FWHI9$lM4#0*joT
|
||||||
|
?tM56R'Aq7$d95#n3nAI&'cm3Y(L-MnV#x'qj+l+liD.-8W;v>@wMQh=6)m$1_b-;I?Q5;7>`*6lg3G;sv&:`[JLN9w<gPqa/S/Mx@aJ%NNa,MG>gr'mKDKNrkdkasN/x0,l$q71^?Xh*X[8^PL*q%6cv58_S*1#
|
||||||
|
bX`0MITc080x^@ilsnlf[L7I%(3mLC(BZE5+?,P@)$+1#DqsJaN-U:/-u?68)p<9j7E%>i?Ia;-kH/D,v(mn8=0'.$Nu49@Bm*1#XYs5CvbQa86j-bS`c5m8RiE1#4l^&#pCa$UOs068Z1-E5RhYl$Oh%TW*)LTA
|
||||||
|
.#$]UnM;TK9(Dl%8`?6B<MiRWdaTl9'OGG.SAd[IOMvu>6E>WgZ3of$O1Up@XbS2L[OtL:aqtqK:M2j*_@-:)LF5F%sd40:3Fr_&]?'k9W@dF<A]r<J?&]lAL2j&-ntJ<(=skq7w^+Ls<q9et?<a^%+$Y98_&Zob
|
||||||
|
vsUqpARc=<ROu7c=ebbOHwO/6Pm@*Ww0]%X*io?<8IQ<iLwrMg?r?eO%E:^-aB#KWu<7b'tRLdt#'-;?A1^FEMk82bPU#-MT>uw&hMM8Ia^vr'sj#j1>f:^OuVh29)g09Tq-.78(S%?7NCU29fbbgNaEJ)<jB'4r
|
||||||
|
(OSP3WS698I9B.$?KS58QV`g$p=@`HW?U/5S&64;1n%:>7rU2`cGs_*,K)1#FCR(Q=Q7i8sDwUjLe.0M2('B$dwW88%vrv@bNOG%K8tMB`6XF-:/::;-:`6r0U=0$``Xp9Knp*-cUpeHl%w,;s+e<_3cs?-#s&r0
|
||||||
|
1B^]02M(wYNshr00dW_ZG]0a;Gx4ND*&9;-HM%VqIL6GDsDZki/S0K)KF,:pgT4,%4K]dM*x8h8WVl6`g#gG$mhmF,,i2v*wBS1MFM0`&,:PP:[J'LPk%']h5(Wxd>i9UXuQk&18(&H;%Ug'hT6S</?xNx1fa5u7
|
||||||
|
DW2QL',t`-Cx#okPutL<%cY'2pP)xPGHHiS^x6Z:R91ObU-iT9O(4m'+%2a*N9pP9(B.-bX%`XNve$U$Bht]=h6rJW<3VM%_j/'Q_7M3,ej5/-Ncf/sSl1]M(Q:['>v_Q93J04r7<,vNP%2d97xbEgJKQGVgB#r3
|
||||||
|
FO4;89*^EfckAhDPC)c<6v690M?r&(GDc^$Ki+58v&LnF)iRTRpw<8Up^,(dPss3,0Z)kT#1i]$-KIZ7LI)3S`ig1(p^^URhRi*N,%$c4L4udO(jG9%[vg2V7I(e&NY<dX,WKw#_&Yj9>hMBQ4T:r2`e0l:lJB$h
|
||||||
|
.`Pg+e]wY%jfNf$)']6K8lDKaC90I.p<3q7dQtA`Q`5?`(qQvc_6b,3O3)9gwixH-]$SR8vjMhdwMD$[V3xR&vCIpT$Vbk1f=RRblisvHe#Zq9Ske(9iR6XLQES29JsZIM-2>rDjiGr^89KO0-^'q718r_&61D58
|
||||||
|
w+r_&.lCW/6iG<-`*wQ%8DQ^OmBjE%9X`E.1EDS@#j/q'J5x8-cxfJssL4($Uflq7hxad=4O:C4K9+hER0^F9G+UQc8W:uQ&/0<A7t3fWC[J90AEOn%&:+kCUYXjd*c-^O.<(d%&0)1#XrV'POoOS$AX+q8IZ4)6
|
||||||
|
hxEFM,hSgN0aEW+x/;N3xJk0&j`S.;edM2i9D+*0GJlB$x:(29wPX&#?l%oS.cb&#`i[`*lQ/,MH@-##FEV6NTF6##$l84N1w?AO>'IAOl%4a*0Y^GM#RcGM9#ult_Ks$#B@`T.1rC$#`@`T.,Mc##T@`T.74i$#
|
||||||
|
WrG<-N2:W.2`($#irG<-<q@u-?Wd`*eC;,M6WYdM6WYdM*?`T.HEX&#`YYdM6WYdM6WYdM%w@(#.E-(#cPc-NZxtk24Y($Jt1^oD0ZKKFg`]oD+,2eGc:@bHcFx.>@nuc<)0o6D]bdUCFdg+>?Wae3;BR12A::MB
|
||||||
|
h]8;-?(DYGUq`uGNDw1B];8;-SHpw'r?Z.#K0f-#=ic+#E<x-#ZZO.#L)1/#wtu+#F:F&#;)1/#O<x-#YSq/#(ZO.#wc-2MVC/$$;^?w^Gm/aNs*p+M&fsD#*J(v#.c_V$2%@8%6=wo%:UWP&>n82'B0pi'FHPJ(
|
||||||
|
Ja1,)N#ic)R;ID*VS*&+Zla]+_.B>,cF#v,_REmh1W@`$0u68%47no%8ONP&<h/2'@*gi'DBGJ(HZ(,)Ls_c)P5@D*TMw%+XfW]+](9>,a@pu,eXPV-iq18.m3io.qKIP/ud*20#'bi0'?BJ19if,=(N^o232;D3
|
||||||
|
7Jr%4;cR]4?%4>5C=ku5GUKV6Kn,87O0do7SHDP8Wa%29[#]i9`;=J:dSt+;hlTc;l.6D<pFm%=t_M]=xw.>>&:fu>*RFV?.k'8@2-_o@6E?PA:^v1Bikur-m-VS.qE75/u^nl/#wNM0'90/1+Qgf1/jGG23,))3
|
||||||
|
7D``3;]@A4?uwx4C7XY5GO9;6Khpr6O*QS7hPn:ZKe0GMgc>c`Mq&Sn8h?YPLS-JUrBB`WH+,AO,Wm+MTm6fqOR(>PCeG`NqHn@k_;LfUox3creaQ(st)7VZ`5Quc4R>MBmeu:QS(f7eQfi:di++PfiuIoe1#Don
|
||||||
|
^w>igqOb1g:-r+DPn?VQ$(_.hbS8GDRI]1pm*m(EM(1DER=L`E2m(GVYq)>G['EYGbKAVHdW]rH0%]4ol2u4Jn>:PJsSUlJ(UFcVwl6MK%53JLTUxLpbwnWH#N#hF@0*K2,4IL2fCd<-gCd<-hCd<-iCd<-jCd<-
|
||||||
|
kCd<-lCd<-mCd<-nCd<-@Dd<-ADd<-BDd<-CDd<-DDd<-EJ)X-v0P]'Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2Gt.g2TmOh2Y#oTC$NXVCThmfGY4&>-K*IT-K*IT-K*IT-
|
||||||
|
K*IT-K*IT-K*IT-K*IT-K*IT-K*IT-K*IT-K*IT-K*IT-K*IT-K*IT-18ZI'Et,gjm,(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DPO/(DP+-XlC#m8Atkt>Ns
|
||||||
|
]==]):gsub("\n", "")
|
||||||
|
|
||||||
|
local raw_data, raw_size = G.ImStd.ImFileLoadToMemory("fonts/ProggyClean.ttf", "rb")
|
||||||
|
local raw = io.Fonts:AddFontFromMemoryTTF(raw_data, raw_size, 13.0)
|
||||||
|
local comp = io.Fonts:AddFontFromMemoryCompressedBase85TTF(B85, 13.0)
|
||||||
|
check(comp ~= nil, "AddFontFromMemoryCompressedBase85TTF returned nil")
|
||||||
|
local comp_data = comp.Sources.Data[1].FontData
|
||||||
|
local same = comp.Sources.Data[1].FontDataSize == raw_size
|
||||||
|
for n = 1, raw_size do if not same then break end same = comp_data[n] == raw_data[n] end
|
||||||
|
check(same, "decompressed bytes differ from fonts/ProggyClean.ttf")
|
||||||
|
|
||||||
|
local TEXT = "The quick brown fox jumps over the lazy dog again and again"
|
||||||
|
local W = 100
|
||||||
|
local f = 0
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
f += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
ImGui.NewFrame()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10)); ImGui.SetNextWindowSize(ImVec2(400, 300))
|
||||||
|
ImGui.Begin("Fonts")
|
||||||
|
ImGui.PushFont(raw, 13.0)
|
||||||
|
ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + W)
|
||||||
|
ImGui.TextWrapped(TEXT)
|
||||||
|
local wrapped_h = ImGui.GetItemRectSize().y
|
||||||
|
ImGui.PopTextWrapPos()
|
||||||
|
local line_h = ImGui.GetTextLineHeight()
|
||||||
|
ImGui.PopFont()
|
||||||
|
if f <= 3 then
|
||||||
|
ImGui.PushFont(comp, 13.0)
|
||||||
|
ImGui.Text("Hello \u{e9}")
|
||||||
|
ImGui.PopFont()
|
||||||
|
end
|
||||||
|
ImGui.End()
|
||||||
|
ImGui.Render(); G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
|
||||||
|
if f == 3 then
|
||||||
|
-- CalcWordWrapPosition(): same line breaks as TextWrapped(). ProggyClean 13px = 7px per char -> 14 chars per 100px line
|
||||||
|
local te = #TEXT + 1
|
||||||
|
local s, lines, breaks = 1, 0, {}
|
||||||
|
while s < te do
|
||||||
|
local e = raw:CalcWordWrapPosition(13.0, TEXT, s, te, W)
|
||||||
|
lines += 1; table.insert(breaks, e)
|
||||||
|
s = e
|
||||||
|
while s < te and TEXT:sub(s, s) == " " do s += 1 end -- ImTextCalcWordWrapNextLineStart(): skip blanks
|
||||||
|
end
|
||||||
|
check(breaks[1] == 10, "first wrap after 'The quick': " .. tostring(breaks[1])) -- "The quick" | "brown fox" | ...
|
||||||
|
check(TEXT:sub(11, breaks[2] - 1) == "brown fox", "second line '" .. TEXT:sub(11, breaks[2] - 1) .. "'")
|
||||||
|
check(wrapped_h == lines * line_h, ("TextWrapped height %s vs %d lines * %s"):format(wrapped_h, lines, line_h))
|
||||||
|
|
||||||
|
-- Compressed font: same glyphs and metrics as the raw TTF
|
||||||
|
local br, bc = raw:GetFontBaked(13.0), comp:GetFontBaked(13.0)
|
||||||
|
check(br.Ascent == bc.Ascent and br.Descent == bc.Descent, "ascent/descent")
|
||||||
|
for _, c in { 0x48, 0x65, 0x6C, 0xE9, 0x41, 0x7E } do
|
||||||
|
local gr, gc = br:FindGlyph(c), bc:FindGlyph(c)
|
||||||
|
check(gc.Visible and gc.X1 > gc.X0 and gc.Y1 > gc.Y0, "compressed glyph empty " .. c)
|
||||||
|
check(gr.AdvanceX == gc.AdvanceX and gr.X0 == gc.X0 and gr.Y0 == gc.Y0 and gr.X1 == gc.X1 and gr.Y1 == gc.Y1, "glyph metrics " .. c)
|
||||||
|
end
|
||||||
|
local str = "Hello \u{e9}"
|
||||||
|
local sr, sc = raw:CalcTextSizeA(13.0, 1e30, 0, str, 1, #str + 1), comp:CalcTextSizeA(13.0, 1e30, 0, str, 1, #str + 1)
|
||||||
|
check(sr.x == sc.x and sr.y == sc.y and sc.x > 0, "CalcTextSizeA")
|
||||||
|
check(not comp:IsGlyphRangeUnused(0, 255) and comp:IsGlyphRangeUnused(0x4E00, 0x9FFF), "IsGlyphRangeUnused")
|
||||||
|
|
||||||
|
-- AddRemapCodepoint(): '$' loads the 'A' glyph (applies to glyphs loaded afterwards: new 20px baked)
|
||||||
|
comp:AddRemapCodepoint(0x24, 0x41)
|
||||||
|
local b20 = comp:GetFontBaked(20.0)
|
||||||
|
local gd, ga = b20:FindGlyph(0x24), raw:GetFontBaked(20.0):FindGlyph(0x41)
|
||||||
|
check(gd.X0 == ga.X0 and gd.Y0 == ga.Y0 and gd.X1 == ga.X1 and gd.Y1 == ga.Y1, "AddRemapCodepoint")
|
||||||
|
|
||||||
|
-- RemoveCustomRect()
|
||||||
|
local atlas = io.Fonts
|
||||||
|
local id = atlas:AddCustomRect(8, 8)
|
||||||
|
check(atlas:GetCustomRect(id, G.ImFontAtlasRect()) == true, "AddCustomRect")
|
||||||
|
atlas:RemoveCustomRect(id)
|
||||||
|
check(not atlas:GetCustomRect(id, G.ImFontAtlasRect()), "RemoveCustomRect")
|
||||||
|
|
||||||
|
-- RemoveFont()
|
||||||
|
local nfonts, nsrc = atlas.Fonts.Size, atlas.Sources.Size
|
||||||
|
atlas:RemoveFont(comp)
|
||||||
|
check(atlas.Fonts.Size == nfonts - 1 and atlas.Sources.Size == nsrc - 1 and not atlas.Fonts:contains(comp), "RemoveFont")
|
||||||
|
|
||||||
|
-- ImFontAtlasTextureBlockFill(), ImTextureDataGetXXXName()
|
||||||
|
local tex = G.ImTextureData(); tex:Create(G.ImTextureFormat.RGBA32, 4, 4)
|
||||||
|
G.ImFontAtlasTextureBlockFill(tex, 1, 2, 2, 1, G.IM_COL32(1, 2, 3, 4))
|
||||||
|
local px = table.concat(tex.Pixels, ",", 33, 48)
|
||||||
|
check(px == "0,0,0,0,1,2,3,4,1,2,3,4,0,0,0,0" and tex.Pixels[29] == 0 and tex.Pixels[53] == 0, "TextureBlockFill " .. px)
|
||||||
|
check(G.ImTextureDataGetStatusName(tex.Status) == "WantCreate" and G.ImTextureDataGetFormatName(tex.Format) == "RGBA32", "texture names")
|
||||||
|
end
|
||||||
|
if f == 5 and #failed == 0 then print("FONTS OK") end
|
||||||
|
end)
|
||||||
@@ -0,0 +1,301 @@
|
|||||||
|
-- Small upstream helpers: ImGuiInputTextState selection API + ReloadUserBuf*, ImGuiInputTextCallbackData:SetSelection, ImDrawList AddImageQuad/PrimQuadUV/
|
||||||
|
-- CloneOutput, ImDrawData DeIndexAllBuffers/ScaleClipRects, ImBitVector/ImBitArray*, ImGuiPackedDate, ImParseFormatSanitizeForPrinting, drag cancel (ShortcutsForCancel),
|
||||||
|
-- log decorations, ImGuiDataType.S64/U64, BringWindowToDisplayBehind, ImGuiSizeCallbackData
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||||
|
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init()
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
local failed = {}
|
||||||
|
local function check(ok, msg) if not ok then table.insert(failed, msg); print("FAIL " .. msg) end end
|
||||||
|
|
||||||
|
-- Pure helpers
|
||||||
|
check(G.ImParseFormatSanitizeForPrinting("%.3f%%", nil, 32) == "%.3f", "sanitize %.3f%%")
|
||||||
|
check(G.ImParseFormatSanitizeForPrinting("%'_5.2f units", nil, 32) == "%5.2f", "sanitize stb flags: " .. G.ImParseFormatSanitizeForPrinting("%'_5.2f units", nil, 32))
|
||||||
|
local d = G.ImGuiPackedDate(20260315)
|
||||||
|
check(d:IsValid() and d:Unpack() == 20260315, "PackedDate round trip " .. d:Unpack())
|
||||||
|
d:SubtractMonths(3)
|
||||||
|
check(d:Unpack() == 20251215, "PackedDate SubtractMonths " .. d:Unpack())
|
||||||
|
check(not G.ImGuiPackedDate():IsValid() and G.ImGuiPackedDate():Unpack() == 0, "PackedDate empty")
|
||||||
|
local bv = G.ImBitVector()
|
||||||
|
bv:Create(70)
|
||||||
|
check(bv.Storage.Size == 3, "ImBitVector size")
|
||||||
|
bv:SetBit(1); bv:SetBit(70); bv:SetBit(33)
|
||||||
|
check(bv:TestBit(1) and bv:TestBit(70) and bv:TestBit(33) and not bv:TestBit(2) and not bv:TestBit(69), "ImBitVector SetBit/TestBit")
|
||||||
|
bv:ClearBit(33)
|
||||||
|
check(not bv:TestBit(33) and bv:TestBit(70), "ImBitVector ClearBit")
|
||||||
|
local arr = {}
|
||||||
|
G.ImBitArrayClearAllBits(arr, 96)
|
||||||
|
G.ImBitArraySetBitRange(arr, 3, 70) -- [3..70)
|
||||||
|
local ok_range = true
|
||||||
|
for n = 1, 96 do if G.ImBitArrayTestBit(arr, n) ~= (n >= 3 and n < 70) then ok_range = false end end
|
||||||
|
check(ok_range, "ImBitArraySetBitRange")
|
||||||
|
check(G.ImBitArrayGetStorageSizeInBytes(70) == 12, "ImBitArrayGetStorageSizeInBytes")
|
||||||
|
check(G.ImModPositive(-1, 5) == 4 and G.ImRoundSigned64(-1.5) == -2 and G.ImCharIsXdigitA(string.byte("F")), "math helpers")
|
||||||
|
|
||||||
|
local buf = ImGui.NewTextBuffer("hello world", 64)
|
||||||
|
local cbuf = ImGui.NewTextBuffer("abcdef", 64)
|
||||||
|
local cb_calls = 0
|
||||||
|
local function cb(data)
|
||||||
|
cb_calls += 1
|
||||||
|
if cb_calls == 1 then data:SetSelection(1, 3) end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
local df, rect_df = 10.0, nil
|
||||||
|
local s64_v = 2 ^ 40
|
||||||
|
local f = 0
|
||||||
|
local function center(r) return (r[1].x + r[2].x) / 2, (r[1].y + r[2].y) / 2 end
|
||||||
|
|
||||||
|
local function vtx(dl, i) -- 1-based vertex
|
||||||
|
local b, o = dl.VtxBuffer.Buf, (i - 1) * G.VTX_STRIDE
|
||||||
|
return buffer.readf64(b, o), buffer.readf64(b, o + 8), buffer.readf64(b, o + 16), buffer.readf64(b, o + 24), buffer.readu32(b, o + 32)
|
||||||
|
end
|
||||||
|
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
f += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
-- drag + Escape cancels and reverts (ShortcutsForCancel)
|
||||||
|
if f == 20 then io:AddMousePosEvent(center(rect_df)) end
|
||||||
|
if f == 21 then io:AddMouseButtonEvent(0, true) end
|
||||||
|
if f == 22 then local x, y = center(rect_df); io:AddMousePosEvent(x + 40, y) end
|
||||||
|
if f == 24 then io:AddKeyEvent(G.ImGuiKey.Escape, true) end
|
||||||
|
if f == 25 then io:AddKeyEvent(G.ImGuiKey.Escape, false) end
|
||||||
|
if f == 26 then io:AddMouseButtonEvent(0, false) end
|
||||||
|
ImGui.NewFrame()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10)); ImGui.SetNextWindowSize(ImVec2(400, 300))
|
||||||
|
ImGui.Begin("H")
|
||||||
|
if f == 2 then ImGui.SetKeyboardFocusHere() end
|
||||||
|
ImGui.InputText("##t", buf, 64)
|
||||||
|
local id = ImGui.GetItemID()
|
||||||
|
local st = ImGui.GetInputTextState(id)
|
||||||
|
if f == 5 then
|
||||||
|
check(st ~= nil, "InputText active")
|
||||||
|
if st then
|
||||||
|
st:SetSelection(3, 6)
|
||||||
|
check(st:GetSelectionStart() == 3 and st:GetSelectionEnd() == 6 and st:GetCursorPos() == 6 and st:HasSelection(), "SetSelection/Get*")
|
||||||
|
st:ClearSelection()
|
||||||
|
check(st:GetSelectionStart() == 6 and st:GetSelectionEnd() == 6 and not st:HasSelection(), "ClearSelection")
|
||||||
|
check(st:GetPreferredOffsetX() == -1, "GetPreferredOffsetX")
|
||||||
|
-- modify the user buffer externally then reload
|
||||||
|
local s = "bye"; for i = 1, #s do buf[i] = string.byte(s, i) end; buf[#s + 1] = 0
|
||||||
|
st:ReloadUserBufAndSelectAll()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if f == 7 and st then
|
||||||
|
check(G.ImGui._ByteArrayToString(st:GetText(), 1, st.TextLen + 1) == "bye", "ReloadUserBufAndSelectAll text")
|
||||||
|
check(st:GetSelectionStart() == 1 and st:GetSelectionEnd() == 4, ("ReloadUserBufAndSelectAll sel %d..%d"):format(st:GetSelectionStart(), st:GetSelectionEnd()))
|
||||||
|
st:SetSelection(2, 3); st:ReloadUserBufAndKeepSelection()
|
||||||
|
end
|
||||||
|
if f == 9 and st then
|
||||||
|
check(st:GetSelectionStart() == 2 and st:GetSelectionEnd() == 3, "ReloadUserBufAndKeepSelection")
|
||||||
|
st:ReloadUserBufAndMoveToEnd()
|
||||||
|
end
|
||||||
|
if f == 11 and st then
|
||||||
|
check(st:GetCursorPos() == 4 and not st:HasSelection(), "ReloadUserBufAndMoveToEnd " .. st:GetCursorPos())
|
||||||
|
end
|
||||||
|
-- callback SetSelection (0-based callback positions -> 1-based stb)
|
||||||
|
if f == 12 then ImGui.SetKeyboardFocusHere() end
|
||||||
|
ImGui.InputText("##c", cbuf, 64, G.ImGuiInputTextFlags.CallbackAlways, cb)
|
||||||
|
if f == 15 then
|
||||||
|
local cst = ImGui.GetInputTextState(ImGui.GetItemID())
|
||||||
|
check(cst ~= nil and cb_calls > 0 and cst:GetSelectionStart() == 2 and cst:GetSelectionEnd() == 4, "callback SetSelection " .. (cst and (cst:GetSelectionStart() .. ".." .. cst:GetSelectionEnd()) or "nil"))
|
||||||
|
end
|
||||||
|
df = ImGui.DragFloat("##df", df, 1.0)
|
||||||
|
local a, b = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(); rect_df = { ImVec2(a.x, a.y), ImVec2(b.x, b.y) }
|
||||||
|
if f == 23 then check(df ~= 10.0, "drag changed value " .. df) end
|
||||||
|
if f == 25 then check(df == 10.0 and ImGui.GetActiveID() == 0, "Escape reverts drag " .. df) end
|
||||||
|
|
||||||
|
if f == 30 then
|
||||||
|
local dl = ImGui.GetWindowDrawList()
|
||||||
|
local v0, i0 = dl.VtxBuffer.Size, dl.IdxBuffer.Size
|
||||||
|
local tex = G.ImTextureRef(1234)
|
||||||
|
dl:AddImageQuad(tex, ImVec2(10, 10), ImVec2(50, 12), ImVec2(48, 60), ImVec2(8, 58), ImVec2(0, 0), ImVec2(1, 0), ImVec2(1, 1), ImVec2(0, 1), 0xFF00FF00)
|
||||||
|
check(dl.VtxBuffer.Size == v0 + 4 and dl.IdxBuffer.Size == i0 + 6, "AddImageQuad counts")
|
||||||
|
local x, y, u, v, col = vtx(dl, v0 + 3)
|
||||||
|
check(x == 48 and y == 60 and u == 1 and v == 1 and col == 0xFF00FF00, ("PrimQuadUV vertex %s %s %s %s %x"):format(x, y, u, v, col))
|
||||||
|
local idx = dl.IdxBuffer.Data
|
||||||
|
check(idx[i0 + 1] == v0 + 1 and idx[i0 + 5] == v0 + 3 and idx[i0 + 6] == v0 + 4, "PrimQuadUV indices")
|
||||||
|
local cmin, cmax = dl:GetClipRectMin(), dl:GetClipRectMax()
|
||||||
|
check(cmax.x > cmin.x and cmax.y > cmin.y, "GetClipRectMin/Max")
|
||||||
|
|
||||||
|
local clone = dl:CloneOutput()
|
||||||
|
check(clone.VtxBuffer.Size == dl.VtxBuffer.Size and clone.IdxBuffer.Size == dl.IdxBuffer.Size and clone.CmdBuffer.Size == dl.CmdBuffer.Size
|
||||||
|
and clone.VtxBuffer.Buf ~= dl.VtxBuffer.Buf and clone.CmdBuffer.Data[1] ~= dl.CmdBuffer.Data[1], "CloneOutput copies buffers")
|
||||||
|
local cx = vtx(clone, v0 + 3)
|
||||||
|
check(cx == 48, "CloneOutput vertex data")
|
||||||
|
|
||||||
|
local dd = G.ImDrawData()
|
||||||
|
dd.CmdLists:push_back(clone)
|
||||||
|
local n_idx = clone.IdxBuffer.Size
|
||||||
|
local ex, ey = vtx(clone, clone.IdxBuffer.Data[n_idx])
|
||||||
|
dd:DeIndexAllBuffers()
|
||||||
|
check(clone.IdxBuffer.Size == 0 and clone.VtxBuffer.Size == n_idx and dd.TotalVtxCount == n_idx and dd.TotalIdxCount == 0, "DeIndexAllBuffers counts")
|
||||||
|
local lx, ly = vtx(clone, n_idx)
|
||||||
|
check(lx == ex and ly == ey, "DeIndexAllBuffers vertex data")
|
||||||
|
|
||||||
|
local cr = clone.CmdBuffer.Data[1].ClipRect
|
||||||
|
local x1, y1, z1, w1 = cr.x, cr.y, cr.z, cr.w
|
||||||
|
dd:ScaleClipRects(ImVec2(2, 3))
|
||||||
|
local cr2 = clone.CmdBuffer.Data[1].ClipRect
|
||||||
|
check(cr2.x == x1 * 2 and cr2.y == y1 * 3 and cr2.z == z1 * 2 and cr2.w == w1 * 3 and dl.CmdBuffer.Data[1].ClipRect.z == z1, "ScaleClipRects")
|
||||||
|
end
|
||||||
|
|
||||||
|
if f == 31 then
|
||||||
|
local g = ImGui.GetCurrentContext()
|
||||||
|
local style = ImGui.GetStyle()
|
||||||
|
local window = ImGui.GetCurrentWindow()
|
||||||
|
check(G.ImGuiKey["0"] == G.ImGuiKey.K0 and G.ImGuiKey["9"] == G.ImGuiKey.K9, "ImGuiKey digit aliases")
|
||||||
|
|
||||||
|
-- Style vars (enum values must match GStyleVarsInfo order)
|
||||||
|
local sv = G.ImGuiStyleVar
|
||||||
|
local b1, b2, b3 = style.SeparatorSize, style.SeparatorTextBorderSize, style.DockingSeparatorSize
|
||||||
|
ImGui.PushStyleVar(sv.SeparatorSize, 5); ImGui.PushStyleVar(sv.SeparatorTextBorderSize, 6); ImGui.PushStyleVar(sv.DockingSeparatorSize, 7)
|
||||||
|
check(style.SeparatorSize == 5 and style.SeparatorTextBorderSize == 6 and style.DockingSeparatorSize == 7, "PushStyleVar SeparatorSize/SeparatorTextBorderSize/DockingSeparatorSize")
|
||||||
|
ImGui.PushStyleVar(sv.SeparatorTextPadding, ImVec2(3, 4))
|
||||||
|
check(style.SeparatorTextPadding.x == 3 and style.SeparatorTextPadding.y == 4, "PushStyleVar SeparatorTextPadding")
|
||||||
|
ImGui.PopStyleVar(4)
|
||||||
|
check(style.SeparatorSize == b1 and style.SeparatorTextBorderSize == b2 and style.DockingSeparatorSize == b3, "PopStyleVar restores")
|
||||||
|
|
||||||
|
-- Log flags
|
||||||
|
ImGui.LogToBuffer()
|
||||||
|
check(g.LogEnabled and g.LogFlags == G.ImGuiLogFlags.OutputBuffer, "LogToBuffer sets ImGuiLogFlags.OutputBuffer")
|
||||||
|
ImGui.Text("logged")
|
||||||
|
check(string.find(g.LogBuffer:c_str(), "logged", 1, true) ~= nil, "LogToBuffer captures text")
|
||||||
|
ImGui.LogFinish()
|
||||||
|
check(g.LogFlags == G.ImGuiLogFlags.None and not g.LogEnabled, "LogFinish clears LogFlags")
|
||||||
|
|
||||||
|
-- Combo preview (no ImGuiComboFlags.CustomPreview needed since 1.93)
|
||||||
|
if ImGui.BeginCombo("##cb", "") then ImGui.EndCombo() end
|
||||||
|
local pd = g.ComboPreviewData
|
||||||
|
local work_max_x, content_max_x = window.WorkRect.Max.x, window.ContentRegionRect.Max.x
|
||||||
|
local opened = ImGui.BeginComboPreview()
|
||||||
|
check(opened and pd.WithinPreview and window.WorkRect.Max.x == pd.PreviewRect.Max.x - style.FramePadding.x and window.ContentRegionRect.Max.x == window.WorkRect.Max.x, "BeginComboPreview sets WorkRect")
|
||||||
|
if opened then
|
||||||
|
ImGui.Text("preview")
|
||||||
|
ImGui.EndComboPreview()
|
||||||
|
end
|
||||||
|
check(not pd.WithinPreview and window.WorkRect.Max.x == work_max_x and window.ContentRegionRect.Max.x == content_max_x, "EndComboPreview restores WorkRect")
|
||||||
|
if ImGui.BeginCombo("##cb2", "x", G.ImGuiComboFlags.NoPreview) then ImGui.EndCombo() end
|
||||||
|
check(not ImGui.BeginComboPreview(), "BeginComboPreview with NoPreview returns false")
|
||||||
|
|
||||||
|
-- ListClipper in a table: ImGuiListClipperFlags.NoSetTableRowCounters
|
||||||
|
local rows = {}
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(500, 10)); ImGui.SetNextWindowSize(ImVec2(300, 400))
|
||||||
|
ImGui.Begin("Clip")
|
||||||
|
for pass = 1, 2 do
|
||||||
|
if ImGui.BeginTable("##clip" .. pass, 1, G.ImGuiTableFlags.ScrollY, ImVec2(0, 60)) then
|
||||||
|
local clipper = G.ImGuiListClipper()
|
||||||
|
if pass == 2 then clipper.Flags = G.ImGuiListClipperFlags.NoSetTableRowCounters end
|
||||||
|
clipper:Begin(1000)
|
||||||
|
while clipper:Step() do
|
||||||
|
for i = clipper.DisplayStart, clipper.DisplayEnd - 1 do ImGui.TableNextRow(); ImGui.TableNextColumn(); ImGui.Text("%d", i) end
|
||||||
|
end
|
||||||
|
clipper:End()
|
||||||
|
rows[pass] = ImGui.GetCurrentTable().CurrentRow
|
||||||
|
local tbl = ImGui.GetCurrentTable()
|
||||||
|
ImGui.EndTable()
|
||||||
|
if pass == 1 then ImGui.SetNextItemOpen(true); ImGui.DebugNodeTable(tbl) end -- DebugNodeTableGetSizingPolicyDesc()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ImGui.End()
|
||||||
|
check(rows[1] ~= nil and rows[2] ~= nil and rows[1] >= 990 and rows[2] < 100, ("clipper row counters %s / NoSetTableRowCounters %s"):format(tostring(rows[1]), tostring(rows[2])))
|
||||||
|
|
||||||
|
-- .ini LastUsed dates + CleanupIniSettings()
|
||||||
|
local pio = ImGui.GetPlatformIO()
|
||||||
|
pio.Platform_SessionDate = 20261015
|
||||||
|
g.SessionDate = G.ImGuiPackedDate(pio.Platform_SessionDate) -- (normally done by NewFrame())
|
||||||
|
io.ConfigIniSettingsAutoDiscardMonths = 6
|
||||||
|
ImGui.LoadIniSettingsFromMemory("[Window][Old]\nPos=1,1\nLastUsed=20250101\n\n[Window][NoDate]\nPos=2,2\n\n[Window][Recent]\nPos=3,3\nLastUsed=20260901\n\n")
|
||||||
|
io.ConfigIniSettingsAutoDiscardMonths = 0
|
||||||
|
local function ws(name) for _, st in g.SettingsWindows.Data do if st.Name == name then return st end end; return nil end
|
||||||
|
check(ws("Old").WantDelete and ws("NoDate").WantDelete and not ws("Recent").WantDelete and ws("Recent").LastUsedDate == 20260901, "ConfigIniSettingsAutoDiscardMonths discards old/undated entries")
|
||||||
|
local args = G.ImGuiSettingsCleanupArgs()
|
||||||
|
args.SetCurrentSessionDateToAll = true
|
||||||
|
args.TypeHashFilter = G.ImHashStr("Window")
|
||||||
|
ImGui.CleanupIniSettings(args)
|
||||||
|
check(ws("Recent").LastUsedDate == 20261015, "CleanupIniSettings SetCurrentSessionDateToAll")
|
||||||
|
local ini = ImGui.SaveIniSettingsToMemory()
|
||||||
|
check(not string.find(ini, "[Window][Old]", 1, true) and string.find(ini, "[Window][Recent]\nPos=3,3\nCollapsed=0\nLastUsed=20261015\n", 1, true) ~= nil
|
||||||
|
and string.find(ini, "[Window][H]\nPos=10,10\nSize=400,300\nCollapsed=0\nLastUsed=20261015\n", 1, true) ~= nil, "LastUsed written to .ini:\n" .. ini)
|
||||||
|
io.ConfigIniSettingsSaveLastUsedDate = false
|
||||||
|
check(not string.find(ImGui.SaveIniSettingsToMemory(), "LastUsed", 1, true), "ConfigIniSettingsSaveLastUsedDate = false")
|
||||||
|
io.ConfigIniSettingsSaveLastUsedDate = true
|
||||||
|
pio.Platform_SessionDate = 0
|
||||||
|
|
||||||
|
-- Log decorations: Selectable/Button/Checkbox/MenuItem shortcut
|
||||||
|
ImGui.LogToBuffer()
|
||||||
|
ImGui.Selectable("sel item")
|
||||||
|
ImGui.Button("btn")
|
||||||
|
ImGui.Checkbox("chk", true)
|
||||||
|
ImGui.MenuItem("mi", "Ctrl+M")
|
||||||
|
local log = g.LogBuffer:c_str()
|
||||||
|
ImGui.LogFinish()
|
||||||
|
check(string.find(log, "[sel item]", 1, true) == nil and string.find(log, "sel item", 1, true) ~= nil, "Selectable logs plain label: " .. log)
|
||||||
|
check(string.find(log, "[ btn ]", 1, true) ~= nil and string.find(log, "[x]", 1, true) ~= nil and string.find(log, "mi ( Ctrl+M )", 1, true) ~= nil, "LogSetNextTextDecoration [ ]: " .. log)
|
||||||
|
|
||||||
|
-- DragScalar S64/U64 (doubles) + DataTypeFormatString
|
||||||
|
local v64, ch = ImGui.DragScalar("##s64", G.ImGuiDataType.S64, 2 ^ 40, 1.0)
|
||||||
|
check(v64 == 2 ^ 40 and ch == false, "DragScalar S64 idle")
|
||||||
|
local b64 = {}
|
||||||
|
local n = ImGui.DataTypeFormatString(b64, 64, G.ImGuiDataType.S64, -(2 ^ 40), "%lld")
|
||||||
|
check(G.ImGui._ByteArrayToString(b64, 1, n + 1) == "-1099511627776", "DataTypeFormatString S64")
|
||||||
|
n = ImGui.DataTypeFormatString(b64, 64, G.ImGuiDataType.U64, 18446744073709551615, "%llu")
|
||||||
|
check(G.ImGui._ByteArrayToString(b64, 1, n + 1) == "18446744073709551615", "DataTypeFormatString U64 max")
|
||||||
|
n = ImGui.DataTypeFormatString(b64, 64, G.ImGuiDataType.S32, -5, "%X")
|
||||||
|
check(G.ImGui._ByteArrayToString(b64, 1, n + 1) == "FFFFFFFB", "DataTypeFormatString S32 hex")
|
||||||
|
local tb = ImGui.NewTextBuffer("-123456789012", 64)
|
||||||
|
local r64, c64 = ImGui.DataTypeApplyFromText(tb, G.ImGuiDataType.S64, 0, "%lld")
|
||||||
|
check(r64 == -123456789012 and c64, "DataTypeApplyFromText S64 " .. tostring(r64))
|
||||||
|
check(ImGui.DataTypeApplyOp(G.ImGuiDataType.S64, 43, 2 ^ 62, 2 ^ 62) == 9223372036854775807, "DataTypeApplyOp S64 clamp")
|
||||||
|
check(G.ImGuiDataType.Float == 8 and G.ImGuiDataType.COUNT == 12 and ImGui.DataTypeGetInfo(G.ImGuiDataType.Float).Name == "float", "ImGuiDataType layout")
|
||||||
|
end
|
||||||
|
-- DragScalar S64: drag with the mouse
|
||||||
|
local s64_rect
|
||||||
|
s64_v = ImGui.DragScalar("##drag_s64", G.ImGuiDataType.S64, s64_v, 1.0)
|
||||||
|
do local a, b = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(); s64_rect = { ImVec2(a.x, a.y), ImVec2(b.x, b.y) } end
|
||||||
|
if f == 33 then io:AddMousePosEvent(center(s64_rect)) end
|
||||||
|
if f == 34 then io:AddMouseButtonEvent(0, true) end
|
||||||
|
if f == 35 then local x, y = center(s64_rect); io:AddMousePosEvent(x + 30, y) end
|
||||||
|
if f == 37 then io:AddMouseButtonEvent(0, false); check(s64_v > 2 ^ 40 and s64_v == math.floor(s64_v), "DragScalar S64 drag " .. s64_v) end
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
-- BringWindowToDisplayBehind
|
||||||
|
if f == 38 then
|
||||||
|
local g = ImGui.GetCurrentContext()
|
||||||
|
local wa, wb, wc = ImGui.FindWindowByName("WA"), ImGui.FindWindowByName("WB"), ImGui.FindWindowByName("WC")
|
||||||
|
local function idx(w) return ImGui.FindWindowDisplayIndex(w) end
|
||||||
|
ImGui.BringWindowToDisplayFront(wa); ImGui.BringWindowToDisplayFront(wb); ImGui.BringWindowToDisplayFront(wc)
|
||||||
|
local n0 = g.Windows.Size
|
||||||
|
ImGui.BringWindowToDisplayBehind(wc, wa) -- move forward-placed window behind: WC WA WB
|
||||||
|
check(idx(wc) + 1 == idx(wa) and idx(wa) + 1 == idx(wb) and g.Windows.Size == n0, ("BringWindowToDisplayBehind back %d %d %d"):format(idx(wa), idx(wb), idx(wc)))
|
||||||
|
ImGui.BringWindowToDisplayBehind(wa, wb) -- already directly behind: unchanged
|
||||||
|
check(idx(wc) + 1 == idx(wa) and idx(wa) + 1 == idx(wb), "BringWindowToDisplayBehind no-op")
|
||||||
|
ImGui.BringWindowToDisplayBehind(wc, wb) -- WA WC WB
|
||||||
|
check(idx(wa) + 1 == idx(wc) and idx(wc) + 1 == idx(wb) and g.Windows.Size == n0, ("BringWindowToDisplayBehind fwd %d %d %d"):format(idx(wa), idx(wb), idx(wc)))
|
||||||
|
end
|
||||||
|
for _, name in { "WA", "WB", "WC" } do
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(820, 10)); ImGui.SetNextWindowSize(ImVec2(80, 60))
|
||||||
|
ImGui.Begin(name); ImGui.End()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Size callback (Step + AspectRatio)
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 420))
|
||||||
|
if f <= 3 then ImGui.SetNextWindowSize(ImVec2(237, 160)) end
|
||||||
|
ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(G.FLT_MAX, G.FLT_MAX), function(data)
|
||||||
|
local step = data.UserData
|
||||||
|
check(data.Pos ~= nil and data.CurrentSize ~= nil and not rawequal(data.DesiredSize, data.CurrentSize), "ImGuiSizeCallbackData fields")
|
||||||
|
data.DesiredSize = ImVec2(math.floor(data.DesiredSize.x / step + 0.5) * step, math.floor(data.DesiredSize.y / step + 0.5) * step)
|
||||||
|
end, 100.0)
|
||||||
|
ImGui.Begin("Step"); local step_size = ImGui.GetWindowSize(); ImGui.End()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(300, 420))
|
||||||
|
if f <= 3 then ImGui.SetNextWindowSize(ImVec2(320, 100)) end
|
||||||
|
ImGui.SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(G.FLT_MAX, G.FLT_MAX), function(data)
|
||||||
|
data.DesiredSize.y = math.floor(data.DesiredSize.x / data.UserData)
|
||||||
|
end, 16 / 9)
|
||||||
|
ImGui.Begin("Aspect"); local asp_size = ImGui.GetWindowSize(); ImGui.End()
|
||||||
|
if f == 5 then
|
||||||
|
check(step_size.x == 200 and step_size.y == 200, ("size callback Step %gx%g"):format(step_size.x, step_size.y))
|
||||||
|
check(asp_size.x == 320 and asp_size.y == 180, ("size callback AspectRatio %gx%g"):format(asp_size.x, asp_size.y))
|
||||||
|
end
|
||||||
|
ImGui.Render(); G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
if f == 40 and #failed == 0 then print("HELPERS OK") end
|
||||||
|
end)
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
-- Library-only draw-data checksum (no demo, run with NO_DEMO=1): widgets + raw ImDrawList primitives with scripted input.
|
||||||
|
-- Must stay identical across demo edits; changes only when library rendering changes. Prints "LIBHASH <n>".
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2, ImVec4 = G.ImGui, G.ImVec2, G.ImVec4
|
||||||
|
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init(); G.ImGui_ImplRoblox.SetRenderRate(0)
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
local frame, h = 0, 0
|
||||||
|
local function mix(v) h = (h * 31 + math.floor(v * 64 + 0.5)) % 2147483647 end
|
||||||
|
local st = { b = false, f = 0.25, i = 42, c = ImVec4(0.2, 0.7, 0.4, 1.0), buf = ImGui.NewTextBuffer("hello", 64), r = 0, tab = 0, combo = 1, list = 2 }
|
||||||
|
local plot = {}
|
||||||
|
for i = 1, 40 do plot[i] = math.sin(i * 0.3) end
|
||||||
|
local poly = { ImVec2(0, 0), ImVec2(60, 10), ImVec2(30, 30), ImVec2(70, 60), ImVec2(0, 50) }
|
||||||
|
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
frame += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
io.DeltaTime = 1 / 60
|
||||||
|
io:AddMousePosEvent(20 + (frame * 37) % 560, 20 + (frame * 53) % 560)
|
||||||
|
if frame % 7 == 0 then io:AddMouseButtonEvent(0, frame % 14 == 0) end
|
||||||
|
if frame % 11 == 0 then io:AddMouseWheelEvent(0, -1) end
|
||||||
|
ImGui.NewFrame()
|
||||||
|
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(320, 560), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("Widgets")
|
||||||
|
ImGui.Text("Text %d", 123); ImGui.TextColored(ImVec4(1, 0.5, 0, 1), "Colored"); ImGui.TextWrapped("Wrapped text that is long enough to wrap around the window edge at least once.")
|
||||||
|
ImGui.Button("Button"); ImGui.SameLine(); ImGui.SmallButton("Small"); ImGui.SameLine(); ImGui.ArrowButton("##a", G.ImGuiDir.Left)
|
||||||
|
st.b = ImGui.Checkbox("Checkbox", st.b)
|
||||||
|
st.r = ImGui.RadioButton("R0", st.r, 0); ImGui.SameLine(); st.r = ImGui.RadioButton("R1", st.r, 1)
|
||||||
|
st.f = ImGui.SliderFloat("Slider", st.f, 0, 1); st.i = ImGui.DragInt("Drag", st.i, 1, 0, 100)
|
||||||
|
ImGui.InputText("Input", st.buf, 64)
|
||||||
|
ImGui.ColorEdit4("Color", st.c)
|
||||||
|
st.combo = ImGui.Combo("Combo", st.combo, { "AAA", "BBB", "CCC" })
|
||||||
|
st.list = ImGui.ListBox("List", st.list, { "one", "two", "three", "four" }, 4, 3)
|
||||||
|
ImGui.ProgressBar(0.4, ImVec2(-1, 0)); ImGui.ProgressBar(-1.0 * frame / 60, ImVec2(-1, 0), "busy")
|
||||||
|
ImGui.PlotLines("Lines", plot, nil, #plot); ImGui.PlotHistogram("Hist", plot, nil, #plot, 0, nil, -1, 1, ImVec2(0, 40))
|
||||||
|
ImGui.Bullet(); ImGui.Text("bullet"); ImGui.Separator(); ImGui.SeparatorText("Sep")
|
||||||
|
if ImGui.TreeNode("Tree") then ImGui.Text("inside"); ImGui.TreePop() end
|
||||||
|
ImGui.SetNextItemOpen(true, G.ImGuiCond.Once)
|
||||||
|
if ImGui.CollapsingHeader("Header") then
|
||||||
|
if ImGui.BeginTabBar("tabs") then
|
||||||
|
if ImGui.BeginTabItem("Tab A") then ImGui.Text("A"); ImGui.EndTabItem() end
|
||||||
|
if ImGui.BeginTabItem("Tab B") then ImGui.Text("B"); ImGui.EndTabItem() end
|
||||||
|
ImGui.EndTabBar()
|
||||||
|
end
|
||||||
|
if ImGui.BeginTable("t", 3, bit32.bor(G.ImGuiTableFlags.Borders, G.ImGuiTableFlags.RowBg, G.ImGuiTableFlags.Resizable)) then
|
||||||
|
ImGui.TableSetupColumn("One"); ImGui.TableSetupColumn("Two"); ImGui.TableSetupColumn("Three"); ImGui.TableHeadersRow()
|
||||||
|
for row = 0, 4 do ImGui.TableNextRow(); for col = 0, 2 do ImGui.TableSetColumnIndex(col); ImGui.Text("r%d c%d", row, col) end end
|
||||||
|
ImGui.EndTable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(340, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(300, 560), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("Draw")
|
||||||
|
local dl, p = ImGui.GetWindowDrawList(), ImGui.GetCursorScreenPos()
|
||||||
|
local x, y, col = p.x + 4, p.y + 4, 0xFF40C0FF
|
||||||
|
for i, th in { 1.0, 2.5, 6.0 } do
|
||||||
|
local yy = y + (i - 1) * 70
|
||||||
|
dl:AddRect(ImVec2(x, yy), ImVec2(x + 50, yy + 50), col, 10.0, th)
|
||||||
|
dl:AddRectFilled(ImVec2(x + 60, yy), ImVec2(x + 110, yy + 50), col, 10.0, G.ImDrawFlags.RoundTopLeft or G.ImDrawFlags.RoundCornersTopLeft) -- RoundCornersTopLeft: pre-1.93 revs (hashes.sh)
|
||||||
|
dl:AddCircle(ImVec2(x + 145, yy + 25), 25, col, 0, th)
|
||||||
|
dl:AddNgon(ImVec2(x + 200, yy + 25), 25, col, 6, th)
|
||||||
|
dl:AddTriangle(ImVec2(x + 230, yy + 50), ImVec2(x + 255, yy), ImVec2(x + 280, yy + 50), col, th)
|
||||||
|
dl:AddLine(ImVec2(x, yy + 60), ImVec2(x + 280, yy + 55), col, th)
|
||||||
|
end
|
||||||
|
y += 210
|
||||||
|
dl:AddBezierCubic(ImVec2(x, y), ImVec2(x + 60, y - 30), ImVec2(x + 120, y + 60), ImVec2(x + 180, y), col, 3.0)
|
||||||
|
dl:AddBezierQuadratic(ImVec2(x, y + 30), ImVec2(x + 90, y - 10), ImVec2(x + 180, y + 30), col, 2.0)
|
||||||
|
dl:AddEllipse(ImVec2(x + 230, y + 15), ImVec2(40, 15), col, 0.5, 0, 2.0)
|
||||||
|
y += 50
|
||||||
|
local pts = {}
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + v.x, y + v.y) end
|
||||||
|
dl:AddConcavePolyFilled(pts, #pts, 0xFF8080FF)
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + 100 + v.x, y + v.y) end
|
||||||
|
dl:AddPolyline(pts, #pts, col, 4.0, G.ImDrawFlags.Closed)
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + 200 + v.x, y + v.y) end
|
||||||
|
dl:AddPolyline(pts, #pts, col, 1.0, 0)
|
||||||
|
y += 80
|
||||||
|
dl:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + 100, y + 40), 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF)
|
||||||
|
dl:AddCircleFilled(ImVec2(x + 140, y + 20), 20, col)
|
||||||
|
dl:AddEllipseFilled(ImVec2(x + 210, y + 20), ImVec2(30, 15), col, 0.3)
|
||||||
|
dl:AddText(ImVec2(x, y + 50), 0xFFFFFFFF, "AddText")
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
ImGui.Render()
|
||||||
|
for _, dl in ImGui.GetDrawData().CmdLists:iter() do
|
||||||
|
local vb, id = dl.VtxBuffer.Buf, dl.IdxBuffer.Data
|
||||||
|
for i = 1, dl.VtxBuffer.Size do local o = (i - 1) * 36; mix(buffer.readf64(vb, o)); mix(buffer.readf64(vb, o + 8)); mix(buffer.readf64(vb, o + 16) * 4096); mix(buffer.readf64(vb, o + 24) * 4096); mix(buffer.readu32(vb, o + 32) / 64) end
|
||||||
|
for i = 1, dl.IdxBuffer.Size do mix(id[i]) end
|
||||||
|
for _, c in dl.CmdBuffer:iter() do mix(c.ClipRect.x); mix(c.ClipRect.y); mix(c.ClipRect.z); mix(c.ClipRect.w); mix(c.ElemCount) end
|
||||||
|
end
|
||||||
|
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
if frame == ARG_FRAMES - 1 then print("LIBHASH", h) end
|
||||||
|
end)
|
||||||
@@ -0,0 +1,265 @@
|
|||||||
|
-- Multi-select / box-select / typing-select: ImGuiSelectionBasicStorage + Selectable list (click, Ctrl+click, Shift+click, Ctrl+A,
|
||||||
|
-- Escape, box-select drag, keyboard nav + Shift, typing-select), ImGuiListClipper + IncludeItemByIndex(RangeSrcItem),
|
||||||
|
-- ImGuiSelectionExternalStorage on a bool array, checkboxes and tree nodes inside a multi-select scope.
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||||
|
local MSF = G.ImGuiMultiSelectFlags
|
||||||
|
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init()
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.NavEnableKeyboard)
|
||||||
|
local failed = {}
|
||||||
|
local function check(ok, msg) if not ok then table.insert(failed, msg); print("FAIL " .. msg) end end
|
||||||
|
|
||||||
|
local NAMES = { "Apple", "Apricot", "Banana", "Blueberry", "Cherry", "Coconut", "Date", "Durian", "Elderberry", "Fig",
|
||||||
|
"Grape", "Guava", "Kiwi", "Lemon", "Lime", "Mango", "Melon", "Orange", "Papaya", "Peach" }
|
||||||
|
local N = #NAMES
|
||||||
|
|
||||||
|
-- Iterate with GetNextSelectedItem() (sorted by key) -> "a,b,c"
|
||||||
|
local function sel_str(sel)
|
||||||
|
local out, it, id, has_more = {}, nil, 0, false
|
||||||
|
while true do
|
||||||
|
has_more, it, id = sel:GetNextSelectedItem(it)
|
||||||
|
if not has_more then break end
|
||||||
|
table.insert(out, tostring(id))
|
||||||
|
end
|
||||||
|
return table.concat(out, ",")
|
||||||
|
end
|
||||||
|
local function bools_str(t, n)
|
||||||
|
local out = {}
|
||||||
|
for i = 1, n do if t[i] then table.insert(out, tostring(i - 1)) end end
|
||||||
|
return table.concat(out, ",")
|
||||||
|
end
|
||||||
|
|
||||||
|
local sel_list = G.ImGuiSelectionBasicStorage()
|
||||||
|
local sel_clip = G.ImGuiSelectionBasicStorage()
|
||||||
|
local sel_tree = G.ImGuiSelectionBasicStorage()
|
||||||
|
local ext_bools = {}
|
||||||
|
local sel_ext = G.ImGuiSelectionExternalStorage()
|
||||||
|
sel_ext.UserData = ext_bools
|
||||||
|
sel_ext.AdapterSetItemSelected = function(self, idx, selected) self.UserData[idx + 1] = selected end
|
||||||
|
local chk_bools = {}
|
||||||
|
local sel_chk = G.ImGuiSelectionExternalStorage()
|
||||||
|
sel_chk.UserData = chk_bools
|
||||||
|
sel_chk.AdapterSetItemSelected = function(self, idx, selected) self.UserData[idx + 1] = selected end
|
||||||
|
|
||||||
|
local rects = {} -- [name] = { min, max } (copies)
|
||||||
|
local ids = {} -- [name] = item id
|
||||||
|
local function rect() local a, b = ImGui.GetItemRectMin(), ImGui.GetItemRectMax(); return { ImVec2(a.x, a.y), ImVec2(b.x, b.y) } end
|
||||||
|
local function center(name) local r = rects[name]; return (r[1].x + r[2].x) / 2, (r[1].y + r[2].y) / 2 end
|
||||||
|
local function key(k) io:AddKeyEvent(k, true); io:AddKeyEvent(k, false) end
|
||||||
|
local function mods(ctrl, shift) io:AddKeyEvent(G.ImGuiMod_Ctrl, ctrl == true); io:AddKeyEvent(G.ImGuiMod_Shift, shift == true) end
|
||||||
|
|
||||||
|
-- Schedule: each step = { input = fn (before NewFrame), check = fn (after Render) }. Steps run on consecutive frames.
|
||||||
|
local steps = {}
|
||||||
|
local function step(input, chk) table.insert(steps, { input = input, check = chk }) end
|
||||||
|
local function idle(n) for _ = 1, n or 1 do step(nil, nil) end end
|
||||||
|
-- click: press (+mods) on frame A, release on frame B, then one idle frame for EndMultiSelect requests to be applied
|
||||||
|
local function click(name, ctrl, shift)
|
||||||
|
step(function() mods(ctrl, shift); io:AddMousePosEvent(center(name)); io:AddMouseButtonEvent(0, true) end)
|
||||||
|
step(function() io:AddMouseButtonEvent(0, false) end)
|
||||||
|
step(function() mods(false, false) end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local typed_focus_idx = -1
|
||||||
|
local clip_scroll_request = false
|
||||||
|
local f = 0
|
||||||
|
|
||||||
|
idle(3)
|
||||||
|
-- 1. List: click selects one
|
||||||
|
click("L2"); step(nil, function() check(sel_str(sel_list) == "2", "click: " .. sel_str(sel_list)) end)
|
||||||
|
-- 2. Ctrl+click toggles
|
||||||
|
click("L5", true); step(nil, function() check(sel_str(sel_list) == "2,5", "ctrl+click add: " .. sel_str(sel_list)) end)
|
||||||
|
click("L2", true); step(nil, function() check(sel_str(sel_list) == "5", "ctrl+click remove: " .. sel_str(sel_list)) end)
|
||||||
|
-- 3. Shift+click range (from RangeSrc = 2, the last Ctrl+clicked item)
|
||||||
|
click("L8", false, true); step(nil, function() check(sel_str(sel_list) == "2,3,4,5,6,7,8", "shift+click range: " .. sel_str(sel_list)) end)
|
||||||
|
-- 4. Ctrl+A
|
||||||
|
step(function() io:AddKeyEvent(G.ImGuiMod_Ctrl, true); io:AddKeyEvent(G.ImGuiKey.A, true) end)
|
||||||
|
step(function() io:AddKeyEvent(G.ImGuiKey.A, false); io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end)
|
||||||
|
step(nil, function() check(sel_list.Size == N, "ctrl+A size " .. sel_list.Size) end)
|
||||||
|
-- 5. Escape clears (ClearOnEscape)
|
||||||
|
step(function() key(G.ImGuiKey.Escape) end)
|
||||||
|
step(nil, function() check(sel_list.Size == 0 and sel_str(sel_list) == "", "escape clear: " .. sel_str(sel_list)) end)
|
||||||
|
-- 6. Box-select drag (BoxSelect1d) from item 2 to item 5
|
||||||
|
step(function() io:AddMousePosEvent(center("L2")); io:AddMouseButtonEvent(0, true) end)
|
||||||
|
step(function() local x, y = center("L2"); io:AddMousePosEvent(x + 2, y + 10) end)
|
||||||
|
step(function() local x, y = center("L4"); io:AddMousePosEvent(x + 4, y) end)
|
||||||
|
step(function() local x, y = center("L5"); io:AddMousePosEvent(x + 4, y) end,
|
||||||
|
function() check(ImGui.GetCurrentContext().BoxSelectState.IsActive, "box-select active while dragging") end)
|
||||||
|
step(nil)
|
||||||
|
step(function() io:AddMouseButtonEvent(0, false) end)
|
||||||
|
step(nil, function() check(sel_str(sel_list) == "2,3,4,5", "box-select: " .. sel_str(sel_list)); check(not ImGui.GetCurrentContext().BoxSelectState.IsActive, "box-select ended") end)
|
||||||
|
-- 7. Keyboard nav: click 3, Down -> 4 (auto-select), Shift+Down x2 -> 4..6
|
||||||
|
click("L3"); step(nil, function() check(sel_str(sel_list) == "3", "click before nav: " .. sel_str(sel_list)) end)
|
||||||
|
step(function() key(G.ImGuiKey.DownArrow) end); idle(2)
|
||||||
|
step(nil, function() check(sel_str(sel_list) == "4", "nav down auto-select: " .. sel_str(sel_list)) end)
|
||||||
|
step(function() io:AddKeyEvent(G.ImGuiMod_Shift, true); key(G.ImGuiKey.DownArrow) end); idle(1)
|
||||||
|
step(function() key(G.ImGuiKey.DownArrow) end); idle(1)
|
||||||
|
step(function() io:AddKeyEvent(G.ImGuiMod_Shift, false) end); idle(1)
|
||||||
|
step(nil, function() check(sel_str(sel_list) == "4,5,6", "shift+nav range: " .. sel_str(sel_list)) end)
|
||||||
|
-- 8. Typing-select: "ch" -> Cherry (5), then single-char mode "b" "b" -> Banana (2) then Blueberry (3)
|
||||||
|
step(function() io:AddInputCharacter(string.byte("c")); io:AddInputCharacter(string.byte("h")) end); idle(2)
|
||||||
|
step(nil, function() check(ImGui.GetCurrentContext().NavId == ids.L4, "typing 'ch' -> Cherry"); check(sel_str(sel_list) == "4", "typing focus selects: " .. sel_str(sel_list)) end)
|
||||||
|
idle(120) -- TYPING_SELECT_RESET_TIMER
|
||||||
|
step(function() io:AddInputCharacter(string.byte("b")) end); idle(2)
|
||||||
|
step(nil, function() check(ImGui.GetCurrentContext().NavId == ids.L2, "typing 'b' -> Banana") end)
|
||||||
|
step(function() io:AddInputCharacter(string.byte("b")) end); idle(2)
|
||||||
|
step(nil, function() check(ImGui.GetCurrentContext().NavId == ids.L3, "typing 'bb' -> Blueberry") end)
|
||||||
|
idle(120)
|
||||||
|
|
||||||
|
-- 9. Clipper (1000 items): click 5, scroll down, Shift+click item 40 -> 5..40 (RangeSrcItem 5 kept submitted by IncludeItemByIndex)
|
||||||
|
click("C5")
|
||||||
|
-- move NavId away with Ctrl+Down (no selection change, RangeSrc stays 5) so the clipper doesn't keep item 5 alive as the nav item
|
||||||
|
step(function() io:AddKeyEvent(G.ImGuiMod_Ctrl, true); key(G.ImGuiKey.DownArrow) end); idle(1)
|
||||||
|
step(function() key(G.ImGuiKey.DownArrow) end); idle(1)
|
||||||
|
step(function() key(G.ImGuiKey.DownArrow) end); idle(1)
|
||||||
|
step(function() io:AddKeyEvent(G.ImGuiMod_Ctrl, false) end)
|
||||||
|
step(nil, function() check(sel_str(sel_clip) == "5", "clipper ctrl+nav keeps selection: " .. sel_str(sel_clip)) end)
|
||||||
|
step(function() clip_scroll_request = true end); idle(2)
|
||||||
|
step(nil, function() check(rects.C40 ~= nil and rects.C5 == nil, "clipper scrolled (item 5 not visible)") end)
|
||||||
|
click("C40", false, true)
|
||||||
|
step(nil, function() check(sel_clip.Size == 36, "clipper shift+click range size " .. sel_clip.Size); check(sel_clip:Contains(5) and sel_clip:Contains(40) and not sel_clip:Contains(4) and not sel_clip:Contains(41), "clipper range bounds") end)
|
||||||
|
|
||||||
|
-- 10. External storage on bool array: click 1, Shift+click 3, Ctrl+click 2
|
||||||
|
click("E1"); click("E3", false, true)
|
||||||
|
step(nil, function() check(bools_str(ext_bools, 10) == "1,2,3", "external storage range: " .. bools_str(ext_bools, 10)) end)
|
||||||
|
click("E2", true)
|
||||||
|
step(nil, function() check(bools_str(ext_bools, 10) == "1,3", "external storage ctrl+click: " .. bools_str(ext_bools, 10)) end)
|
||||||
|
|
||||||
|
-- 11. Checkboxes (NoAutoSelect|NoAutoClear): click 1 toggles on, Shift+click 4 -> 1..4 on, click 2 toggles off
|
||||||
|
click("K1"); step(nil, function() check(bools_str(chk_bools, 8) == "1", "checkbox click: " .. bools_str(chk_bools, 8)) end)
|
||||||
|
click("K4", false, true); step(nil, function() check(bools_str(chk_bools, 8) == "1,2,3,4", "checkbox shift+click: " .. bools_str(chk_bools, 8)) end)
|
||||||
|
click("K2"); step(nil, function() check(bools_str(chk_bools, 8) == "1,3,4", "checkbox toggle off: " .. bools_str(chk_bools, 8)) end)
|
||||||
|
|
||||||
|
-- 12. Tree nodes: click 0, Ctrl+click 2, Shift+click 4 (range from 2)
|
||||||
|
click("T0"); click("T2", true)
|
||||||
|
step(nil, function() check(sel_str(sel_tree) == "0,2", "tree ctrl+click: " .. sel_str(sel_tree)) end)
|
||||||
|
click("T4", false, true)
|
||||||
|
step(nil, function() check(sel_str(sel_tree) == "2,3,4", "tree shift+click: " .. sel_str(sel_tree)) end)
|
||||||
|
|
||||||
|
-- 13. Metrics window renders the TypingSelect / MultiSelect debug nodes
|
||||||
|
local show_metrics = false
|
||||||
|
step(function() show_metrics = true end); idle(3)
|
||||||
|
step(nil, function() if #failed == 0 then print("MULTISELECT OK") end end)
|
||||||
|
|
||||||
|
local function list_window()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10)); ImGui.SetNextWindowSize(ImVec2(200, 420))
|
||||||
|
ImGui.Begin("L")
|
||||||
|
local flags = bit32.bor(MSF.ClearOnEscape, MSF.BoxSelect1d)
|
||||||
|
local ms_io = ImGui.BeginMultiSelect(flags, sel_list.Size, N)
|
||||||
|
sel_list:ApplyRequests(ms_io)
|
||||||
|
-- typing-select
|
||||||
|
local focus_idx = -1
|
||||||
|
if ImGui.IsWindowFocused() then
|
||||||
|
local req = ImGui.GetTypingSelectRequest(G.ImGuiTypingSelectFlags.AllowSingleCharMode)
|
||||||
|
local nav_idx = (type(ms_io.NavIdItem) == "number") and ms_io.NavIdItem or -1
|
||||||
|
focus_idx = ImGui.TypingSelectFindMatch(req, N, function(_, idx) return NAMES[idx + 1] end, nil, nav_idx)
|
||||||
|
end
|
||||||
|
for n = 0, N - 1 do
|
||||||
|
if n == focus_idx then ImGui.SetKeyboardFocusHere() end
|
||||||
|
ImGui.SetNextItemSelectionUserData(n)
|
||||||
|
ImGui.Selectable(NAMES[n + 1], sel_list:Contains(n))
|
||||||
|
rects["L" .. n] = rect(); ids["L" .. n] = ImGui.GetItemID()
|
||||||
|
end
|
||||||
|
ms_io = ImGui.EndMultiSelect()
|
||||||
|
sel_list:ApplyRequests(ms_io)
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clipper_window()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(220, 10)); ImGui.SetNextWindowSize(ImVec2(200, 300))
|
||||||
|
ImGui.Begin("C")
|
||||||
|
if clip_scroll_request then ImGui.SetScrollY(ImGui.GetTextLineHeightWithSpacing() * 30); clip_scroll_request = false end
|
||||||
|
local COUNT = 1000
|
||||||
|
local ms_io = ImGui.BeginMultiSelect(MSF.ClearOnEscape, sel_clip.Size, COUNT)
|
||||||
|
sel_clip:ApplyRequests(ms_io)
|
||||||
|
local clipper = G.ImGuiListClipper()
|
||||||
|
clipper:Begin(COUNT)
|
||||||
|
if ms_io.RangeSrcItem ~= -1 then clipper:IncludeItemByIndex(ms_io.RangeSrcItem) end -- Ensure RangeSrc item is not clipped.
|
||||||
|
for k in rects do if string.sub(k, 1, 1) == "C" then rects[k] = nil end end
|
||||||
|
while clipper:Step() do
|
||||||
|
for n = clipper.DisplayStart, clipper.DisplayEnd - 1 do
|
||||||
|
ImGui.SetNextItemSelectionUserData(n)
|
||||||
|
ImGui.Selectable(("Object %04d"):format(n), sel_clip:Contains(n))
|
||||||
|
if ImGui.IsItemVisible() then rects["C" .. n] = rect() end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ms_io = ImGui.EndMultiSelect()
|
||||||
|
sel_clip:ApplyRequests(ms_io)
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function external_window()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(430, 10)); ImGui.SetNextWindowSize(ImVec2(180, 220))
|
||||||
|
ImGui.Begin("E")
|
||||||
|
local ms_io = ImGui.BeginMultiSelect(MSF.None, -1, 10)
|
||||||
|
sel_ext:ApplyRequests(ms_io)
|
||||||
|
for n = 0, 9 do
|
||||||
|
ImGui.SetNextItemSelectionUserData(n)
|
||||||
|
ImGui.Selectable("Ext " .. n, ext_bools[n + 1] == true)
|
||||||
|
rects["E" .. n] = rect()
|
||||||
|
end
|
||||||
|
ms_io = ImGui.EndMultiSelect()
|
||||||
|
sel_ext:ApplyRequests(ms_io)
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function checkbox_window()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(430, 240)); ImGui.SetNextWindowSize(ImVec2(180, 200))
|
||||||
|
ImGui.Begin("K")
|
||||||
|
local ms_io = ImGui.BeginMultiSelect(bit32.bor(MSF.NoAutoSelect, MSF.NoAutoClear, MSF.ClearOnEscape), -1, 8)
|
||||||
|
sel_chk:ApplyRequests(ms_io)
|
||||||
|
for n = 0, 7 do
|
||||||
|
ImGui.SetNextItemSelectionUserData(n)
|
||||||
|
local _, v = ImGui.Checkbox("Check " .. n, chk_bools[n + 1] == true)
|
||||||
|
rects["K" .. n] = rect()
|
||||||
|
local _ = v -- the selection is updated through requests (ApplyRequests), like upstream's demo
|
||||||
|
end
|
||||||
|
ms_io = ImGui.EndMultiSelect()
|
||||||
|
sel_chk:ApplyRequests(ms_io)
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tree_window()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(220, 320)); ImGui.SetNextWindowSize(ImVec2(200, 160))
|
||||||
|
ImGui.Begin("T")
|
||||||
|
local ms_io = ImGui.BeginMultiSelect(MSF.None, sel_tree.Size, 5)
|
||||||
|
sel_tree:ApplyRequests(ms_io)
|
||||||
|
for n = 0, 4 do
|
||||||
|
local flags = bit32.bor(G.ImGuiTreeNodeFlags.Leaf, G.ImGuiTreeNodeFlags.NoTreePushOnOpen, G.ImGuiTreeNodeFlags.SpanAvailWidth)
|
||||||
|
if sel_tree:Contains(n) then flags = bit32.bor(flags, G.ImGuiTreeNodeFlags.Selected) end
|
||||||
|
ImGui.SetNextItemSelectionUserData(n)
|
||||||
|
ImGui.TreeNodeEx("Node " .. n, flags)
|
||||||
|
rects["T" .. n] = rect()
|
||||||
|
end
|
||||||
|
ms_io = ImGui.EndMultiSelect()
|
||||||
|
sel_tree:ApplyRequests(ms_io)
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
f += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
local s = steps[f]
|
||||||
|
if s and s.input then s.input() end
|
||||||
|
ImGui.NewFrame()
|
||||||
|
list_window()
|
||||||
|
clipper_window()
|
||||||
|
external_window()
|
||||||
|
checkbox_window()
|
||||||
|
tree_window()
|
||||||
|
if show_metrics then
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(620, 10)); ImGui.SetNextWindowSize(ImVec2(400, 600))
|
||||||
|
ImGui.ShowMetricsWindow()
|
||||||
|
local ctx = ImGui.GetCurrentContext()
|
||||||
|
ImGui.Begin("DebugNodes")
|
||||||
|
ImGui.DebugNodeTypingSelectState(ctx.TypingSelectState)
|
||||||
|
for n = 0, ctx.MultiSelectStorage:GetMapSize() - 1 do
|
||||||
|
local st = ctx.MultiSelectStorage:GetByIndex(n)
|
||||||
|
if st then ImGui.SetNextItemOpen(true); ImGui.DebugNodeMultiSelectState(st) end
|
||||||
|
end
|
||||||
|
ImGui.End()
|
||||||
|
end
|
||||||
|
ImGui.Render(); G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
if s and s.check then s.check() end
|
||||||
|
end)
|
||||||
|
print(("t_multiselect: %d steps"):format(#steps))
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
-- Screenshot of a fixed scene (t_libhash's widgets + primitives, optionally the Custom Rendering example):
|
||||||
|
-- composites the ScreenGui like t_composite and prints "ROW y hex". tools/test/shot.py turns it into a PNG.
|
||||||
|
-- RUN_FLAGS: ARG_APP=true also opens ShowExampleAppCustomRendering (needs the demo).
|
||||||
|
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||||
|
local ImGui, ImVec2, ImVec4 = G.ImGui, G.ImVec2, G.ImVec4
|
||||||
|
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init(); G.ImGui_ImplRoblox.SetRenderRate(0)
|
||||||
|
local io = ImGui.GetIO()
|
||||||
|
local W, H = 1280, 760
|
||||||
|
local frame = 0
|
||||||
|
local st = { b = false, f = 0.25, i = 42, c = ImVec4(0.2, 0.7, 0.4, 1.0), buf = ImGui.NewTextBuffer("hello", 64), r = 0, tab = 0, combo = 1, list = 2 }
|
||||||
|
local plot = {}
|
||||||
|
for i = 1, 40 do plot[i] = math.sin(i * 0.3) end
|
||||||
|
local poly = { ImVec2(0, 0), ImVec2(60, 10), ImVec2(30, 30), ImVec2(70, 60), ImVec2(0, 50) }
|
||||||
|
|
||||||
|
local function composite(gui)
|
||||||
|
local screen = buffer.create(W * H * 3)
|
||||||
|
local function walk(inst, ox, oy, kx0, ky0, kx1, ky1)
|
||||||
|
local kids = inst:GetChildren()
|
||||||
|
table.sort(kids, function(a, b) return (a.ZIndex or 1) < (b.ZIndex or 1) end) -- table.sort isn't stable, but siblings with equal ZIndex never overlap here
|
||||||
|
for _, c in ipairs(kids) do
|
||||||
|
if c.Visible ~= false then
|
||||||
|
local x, y = ox + (c.Position and c.Position.X or 0), oy + (c.Position and c.Position.Y or 0)
|
||||||
|
local cx0, cy0, cx1, cy1 = kx0, ky0, kx1, ky1
|
||||||
|
if c.ClipsDescendants then
|
||||||
|
cx0, cy0 = math.max(cx0, x), math.max(cy0, y)
|
||||||
|
cx1, cy1 = math.min(cx1, x + c.Size.X), math.min(cy1, y + c.Size.Y)
|
||||||
|
end
|
||||||
|
if c.ClassName == "ImageLabel" then
|
||||||
|
local img = c.ImageContent.Object
|
||||||
|
local px, sz = img.Pixels, img.Size.X
|
||||||
|
for ty = 0, sz - 1 do
|
||||||
|
local sy = y + ty
|
||||||
|
if sy >= ky0 and sy < ky1 then
|
||||||
|
for tx = 0, sz - 1 do
|
||||||
|
local sx = x + tx
|
||||||
|
if sx >= kx0 and sx < kx1 then
|
||||||
|
local o = (ty * sz + tx) * 4
|
||||||
|
local a = buffer.readu8(px, o + 3)
|
||||||
|
if a > 0 then
|
||||||
|
local d = (sy * W + sx) * 3
|
||||||
|
local fa = a / 255
|
||||||
|
for ch = 0, 2 do
|
||||||
|
local v = buffer.readu8(px, o + ch) * fa + buffer.readu8(screen, d + ch) * (1 - fa)
|
||||||
|
buffer.writeu8(screen, d + ch, math.floor(v + 0.5))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
walk(c, x, y, cx0, cy0, cx1, cy1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
walk(gui, 0, 0, 0, 0, W, H)
|
||||||
|
return screen
|
||||||
|
end
|
||||||
|
|
||||||
|
game:GetService("RunService").Stepped:Connect(function()
|
||||||
|
frame += 1
|
||||||
|
G.ImGui_ImplRoblox.NewFrame()
|
||||||
|
io.DeltaTime = 1 / 60
|
||||||
|
ImGui.NewFrame()
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(10, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(320, 560), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("Widgets")
|
||||||
|
ImGui.Text("Text %d", 123); ImGui.TextColored(ImVec4(1, 0.5, 0, 1), "Colored"); ImGui.TextWrapped("Wrapped text that is long enough to wrap around the window edge at least once.")
|
||||||
|
ImGui.Button("Button"); ImGui.SameLine(); ImGui.SmallButton("Small"); ImGui.SameLine(); ImGui.ArrowButton("##a", G.ImGuiDir.Left)
|
||||||
|
st.b = ImGui.Checkbox("Checkbox", st.b)
|
||||||
|
st.r = ImGui.RadioButton("R0", st.r, 0); ImGui.SameLine(); st.r = ImGui.RadioButton("R1", st.r, 1)
|
||||||
|
st.f = ImGui.SliderFloat("Slider", st.f, 0, 1); st.i = ImGui.DragInt("Drag", st.i, 1, 0, 100)
|
||||||
|
ImGui.InputText("Input", st.buf, 64)
|
||||||
|
ImGui.ColorEdit4("Color", st.c)
|
||||||
|
st.combo = ImGui.Combo("Combo", st.combo, { "AAA", "BBB", "CCC" })
|
||||||
|
st.list = ImGui.ListBox("List", st.list, { "one", "two", "three", "four" }, 4, 3)
|
||||||
|
ImGui.ProgressBar(0.4, ImVec2(-1, 0)); ImGui.ProgressBar(-1.0 * frame / 60, ImVec2(-1, 0), "busy")
|
||||||
|
ImGui.PlotLines("Lines", plot, nil, #plot); ImGui.PlotHistogram("Hist", plot, nil, #plot, 0, nil, -1, 1, ImVec2(0, 40))
|
||||||
|
ImGui.Bullet(); ImGui.Text("bullet"); ImGui.Separator(); ImGui.SeparatorText("Sep")
|
||||||
|
if ImGui.TreeNode("Tree") then ImGui.Text("inside"); ImGui.TreePop() end
|
||||||
|
ImGui.SetNextItemOpen(true, G.ImGuiCond.Once)
|
||||||
|
if ImGui.CollapsingHeader("Header") then
|
||||||
|
if ImGui.BeginTabBar("tabs") then
|
||||||
|
if ImGui.BeginTabItem("Tab A") then ImGui.Text("A"); ImGui.EndTabItem() end
|
||||||
|
if ImGui.BeginTabItem("Tab B") then ImGui.Text("B"); ImGui.EndTabItem() end
|
||||||
|
ImGui.EndTabBar()
|
||||||
|
end
|
||||||
|
if ImGui.BeginTable("t", 3, bit32.bor(G.ImGuiTableFlags.Borders, G.ImGuiTableFlags.RowBg, G.ImGuiTableFlags.Resizable)) then
|
||||||
|
ImGui.TableSetupColumn("One"); ImGui.TableSetupColumn("Two"); ImGui.TableSetupColumn("Three"); ImGui.TableHeadersRow()
|
||||||
|
for row = 0, 4 do ImGui.TableNextRow(); for col = 0, 2 do ImGui.TableSetColumnIndex(col); ImGui.Text("r%d c%d", row, col) end end
|
||||||
|
ImGui.EndTable()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
ImGui.SetNextWindowPos(ImVec2(340, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(300, 560), G.ImGuiCond.Always)
|
||||||
|
ImGui.Begin("Draw")
|
||||||
|
local dl, p = ImGui.GetWindowDrawList(), ImGui.GetCursorScreenPos()
|
||||||
|
local x, y, col = p.x + 4, p.y + 4, 0xFF40C0FF
|
||||||
|
for i, th in { 1.0, 2.5, 6.0 } do
|
||||||
|
local yy = y + (i - 1) * 70
|
||||||
|
dl:AddRect(ImVec2(x, yy), ImVec2(x + 50, yy + 50), col, 10.0, th)
|
||||||
|
dl:AddRectFilled(ImVec2(x + 60, yy), ImVec2(x + 110, yy + 50), col, 10.0, G.ImDrawFlags.RoundTopLeft or G.ImDrawFlags.RoundCornersTopLeft) -- RoundCornersTopLeft: pre-1.93 revs (hashes.sh)
|
||||||
|
dl:AddCircle(ImVec2(x + 145, yy + 25), 25, col, 0, th)
|
||||||
|
dl:AddNgon(ImVec2(x + 200, yy + 25), 25, col, 6, th)
|
||||||
|
dl:AddTriangle(ImVec2(x + 230, yy + 50), ImVec2(x + 255, yy), ImVec2(x + 280, yy + 50), col, th)
|
||||||
|
dl:AddLine(ImVec2(x, yy + 60), ImVec2(x + 280, yy + 55), col, th)
|
||||||
|
end
|
||||||
|
y += 210
|
||||||
|
dl:AddBezierCubic(ImVec2(x, y), ImVec2(x + 60, y - 30), ImVec2(x + 120, y + 60), ImVec2(x + 180, y), col, 3.0)
|
||||||
|
dl:AddBezierQuadratic(ImVec2(x, y + 30), ImVec2(x + 90, y - 10), ImVec2(x + 180, y + 30), col, 2.0)
|
||||||
|
dl:AddEllipse(ImVec2(x + 230, y + 15), ImVec2(40, 15), col, 0.5, 0, 2.0)
|
||||||
|
y += 50
|
||||||
|
local pts = {}
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + v.x, y + v.y) end
|
||||||
|
dl:AddConcavePolyFilled(pts, #pts, 0xFF8080FF)
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + 100 + v.x, y + v.y) end
|
||||||
|
dl:AddPolyline(pts, #pts, col, 4.0, G.ImDrawFlags.Closed)
|
||||||
|
for i, v in poly do pts[i] = ImVec2(x + 200 + v.x, y + v.y) end
|
||||||
|
dl:AddPolyline(pts, #pts, col, 1.0, 0)
|
||||||
|
y += 80
|
||||||
|
dl:AddRectFilledMultiColor(ImVec2(x, y), ImVec2(x + 100, y + 40), 0xFF0000FF, 0xFF00FF00, 0xFFFF0000, 0xFFFFFFFF)
|
||||||
|
dl:AddCircleFilled(ImVec2(x + 140, y + 20), 20, col)
|
||||||
|
dl:AddEllipseFilled(ImVec2(x + 210, y + 20), ImVec2(30, 15), col, 0.3)
|
||||||
|
dl:AddText(ImVec2(x, y + 50), 0xFFFFFFFF, "AddText")
|
||||||
|
ImGui.End()
|
||||||
|
|
||||||
|
if ARG_APP then ImGui.SetNextWindowPos(ImVec2(650, 10), G.ImGuiCond.Always); ImGui.SetNextWindowSize(ImVec2(620, 740), G.ImGuiCond.Always); G.ShowExampleAppCustomRendering(true) end
|
||||||
|
ImGui.Render()
|
||||||
|
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||||
|
if frame == ARG_FRAMES - 1 then
|
||||||
|
local screen = composite(game:GetService("Players").LocalPlayer.PlayerGui:FindFirstChild("ImGui"))
|
||||||
|
for y = 0, H - 1 do
|
||||||
|
local t = table.create(W * 3)
|
||||||
|
for i = 0, W * 3 - 1 do t[i + 1] = string.format("%02x", buffer.readu8(screen, y * W * 3 + i)) end
|
||||||
|
print("ROW", y, table.concat(t))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Headless screenshot: tools/test/shot.py out.png [--app] (runs scripts/t_shot.luau, writes a PNG; stdlib only)"""
|
||||||
|
import os, subprocess, sys, struct, zlib
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
env = dict(os.environ, FULL_OUTPUT="1", RUN_FLAGS="ARG_APP=true" if "--app" in sys.argv else "")
|
||||||
|
out = subprocess.run([sys.executable, os.path.join(HERE, "run.py"), "--quiet", "--roblox", "--frames", "30", "--timeout", "600",
|
||||||
|
"--main", os.path.join(HERE, "scripts", "t_shot.luau")], env=env, capture_output=True, text=True).stdout
|
||||||
|
rows = {int(l.split()[1]): bytes.fromhex(l.split()[2]) for l in out.splitlines() if l.startswith("ROW")}
|
||||||
|
assert rows, out[-2000:]
|
||||||
|
w, h = len(rows[0]) // 3, len(rows)
|
||||||
|
raw = b"".join(b"\0" + rows[y] for y in range(h))
|
||||||
|
chunk = lambda t, d: struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
|
||||||
|
open(sys.argv[1], "wb").write(b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0)) + chunk(b"IDAT", zlib.compress(raw, 6)) + chunk(b"IEND", b""))
|
||||||
|
print("wrote", sys.argv[1], w, h)
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "4dbug/imgui-luau"
|
name = "4dbug/imgui-luau"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
registry = "https://github.com/UpliftGames/wally-index"
|
registry = "https://github.com/UpliftGames/wally-index"
|
||||||
realm = "shared"
|
realm = "shared"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
Reference in New Issue
Block a user