Compare commits
9
Commits
c085571602
..
v0.1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2558c30d32 | ||
|
|
e228ed8638 | ||
|
|
28dc08e043 | ||
|
|
f63a37f07d | ||
|
|
08356b4f1f | ||
|
|
14e6da3b29 | ||
|
|
df4cf4cd80 | ||
|
|
2bef2ad43a | ||
|
|
df9f194d87 |
+40
-24
@@ -10,7 +10,7 @@ Dear ImGui for Roblox (and more)
|
||||
|
||||
A Lua/Luau port of [Dear ImGui](https://github.com/ocornut/imgui) (docking branch, 1.93 WIP). **Roblox is the primary target** (rendered with EditableImages); the same sources also run on [LÖVE](https://love2d.org) (LuaJIT, GPU renderer), and the backend layout leaves room for more. It follows the C++ source function by function, so upstream documentation, examples and the demo apply almost directly.
|
||||
|
||||
| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration) - [Backends](#backends) |
|
||||
| [The Pitch](#the-pitch) - [Usage](#usage) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration-roblox) - [How it works](#how-it-works-roblox-backend) - [Backends](#backends) |
|
||||
:----------------------------------------------------------: |
|
||||
| [Differences from C++](#differences-from-c-dear-imgui) - [Performance](#performance) - [Testing](#testing) - [Not ported yet](#not-ported-yet) |
|
||||
| [FAQ](#faq) - [Credits](#credits) - [License](#license) |
|
||||
@@ -79,27 +79,6 @@ Dear ImGui allows you to **create elaborate tools** as well as very short-lived
|
||||
|
||||
Every snippet in this README is run by [`tools/test/scripts/t_readme.luau`](/tools/test/scripts/t_readme.luau), and every image was rendered by this port with [`tools/screenshots/make.py`](/tools/screenshots/make.py).
|
||||
|
||||
### How it works (Roblox backend)
|
||||
|
||||
Dear ImGui itself never draws anything: every frame it produces `ImDrawData`, a list of textured, coloured triangles plus clip rectangles, and expects the backend to put them on screen. On desktop that is a few GPU draw calls. Roblox has no API to draw arbitrary triangles in 2D, so the Roblox backend ([backends/imgui_impl_roblox.lua](/backends/imgui_impl_roblox.lua)) does what a GPU would do, in Luau, and pushes the result into **EditableImages**.
|
||||
|
||||
**Why software rasterization?** The alternatives don't fit Dear ImGui:
|
||||
- *One GUI Instance per widget/shape* (what most Roblox UI libraries do) means re-creating, re-parenting or diffing thousands of Instances every frame, can't express anti-aliased curves, per-vertex gradients or font-atlas glyphs, and would no longer be Dear ImGui's renderer output.
|
||||
- *Rasterizing the draw data* keeps the output identical to Dear ImGui's: the same fonts, anti-aliasing, rounding and gradients, and every widget (including custom `ImDrawList` drawing) works without backend support.
|
||||
|
||||
The cost is CPU time in Luau, so the backend is built around **not drawing**:
|
||||
|
||||
1. **Layers per window.** Every draw list (one per top-level window, popup, tooltip) gets its own `Frame` with `ZIndex` following Dear ImGui's draw order. Its content is rasterized relative to the window, so **moving a window only changes the Frame's `Position`**; no pixel is redrawn or uploaded.
|
||||
2. **Tiles.** Each layer is covered by 128×128 EditableImage tiles (`ImageLabel`s). Every primitive is hashed (positions relative to the layer, UVs, colours, texture, clip) into the tiles it touches. **Only tiles whose hash changed are re-rasterized and uploaded**, and only the dirty region of those (`WritePixelsBuffer` with a sub-rectangle). A static UI uploads nothing.
|
||||
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.
|
||||
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. **Render rate.** Tiles update at most `SetRenderRate(hz)` times per second (default 60), optionally lower while scrolling/resizing (`SetBusyRenderRate`). 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). Games can't read the clipboard, so while a text field is active a hidden `TextBox` holds focus: the OS 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).
|
||||
|
||||
**Instances inside windows.** The backend can place your own Instances (e.g. a `ViewportFrame`) inside a window's layer, so they stack, clip and move with it; see the `ImGui.Embed` widget in [examples/example_roblox/main.client.luau](/examples/example_roblox/main.client.luau).
|
||||
|
||||
### Demo
|
||||
|
||||
Calling `ImGui.ShowDemoWindow()` creates a demo window that showcases a variety of features and examples. The code is in [imgui_demo.lua](/imgui_demo.lua), like upstream's `imgui_demo.cpp`. **It's strongly recommended to keep it at hand as a reference**: you can find the code for any widget you see by searching for its label.
|
||||
@@ -137,7 +116,9 @@ The Style Editor (`ImGui.ShowStyleEditor()`) and the Metrics/Debugger (`ImGui.Sh
|
||||
|
||||
### Getting Started & Integration (Roblox)
|
||||
|
||||
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out).
|
||||
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/[email protected]"` 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.
|
||||
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`.
|
||||
3. A minimal LocalScript (full version: [examples/example_roblox/main.client.luau](/examples/example_roblox/main.client.luau)):
|
||||
|
||||
@@ -182,6 +163,27 @@ io.Fonts:AddFontDefault()
|
||||
io.Fonts:AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0)
|
||||
```
|
||||
|
||||
### How it works (Roblox backend)
|
||||
|
||||
Dear ImGui itself never draws anything: every frame it produces `ImDrawData`, a list of textured, coloured triangles plus clip rectangles, and expects the backend to put them on screen. On desktop that is a few GPU draw calls. Roblox has no API to draw arbitrary triangles in 2D, so the Roblox backend ([backends/imgui_impl_roblox.lua](/backends/imgui_impl_roblox.lua)) does what a GPU would do, in Luau, and pushes the result into **EditableImages**.
|
||||
|
||||
**Why software rasterization?** The alternatives don't fit Dear ImGui:
|
||||
- *One GUI Instance per widget/shape* (what most Roblox UI libraries do) means re-creating, re-parenting or diffing thousands of Instances every frame, can't express anti-aliased curves, per-vertex gradients or font-atlas glyphs, and would no longer be Dear ImGui's renderer output.
|
||||
- *Rasterizing the draw data* keeps the output identical to Dear ImGui's: the same fonts, anti-aliasing, rounding and gradients, and every widget (including custom `ImDrawList` drawing) works without backend support.
|
||||
|
||||
The cost is CPU time in Luau, so the backend is built around **not drawing**:
|
||||
|
||||
1. **Layers per window.** Every draw list (one per top-level window, popup, tooltip) gets its own `Frame` with `ZIndex` following Dear ImGui's draw order. Its content is rasterized relative to the window, so **moving a window only changes the Frame's `Position`**; no pixel is redrawn or uploaded.
|
||||
2. **Tiles.** Each layer is covered by 128×128 EditableImage tiles (`ImageLabel`s). Every primitive is hashed (positions relative to the layer, UVs, colours, texture, clip) into the tiles it touches. **Only tiles whose hash changed are re-rasterized and uploaded**, and only the dirty region of those (`WritePixelsBuffer` with a sub-rectangle). A static UI uploads nothing.
|
||||
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.
|
||||
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. **Render rate.** Tiles update at most `SetRenderRate(hz)` times per second (default 60), optionally lower while scrolling/resizing (`SetBusyRenderRate`). 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).
|
||||
|
||||
**Instances inside windows.** The backend can place your own Instances (e.g. a `ViewportFrame`) inside a window's layer, so they stack, clip and move with it; see the `ImGui.Embed` widget in [examples/example_roblox/main.client.luau](/examples/example_roblox/main.client.luau).
|
||||
|
||||
### Backends
|
||||
|
||||
| Backend | File | Build | Renderer | Example |
|
||||
@@ -242,6 +244,20 @@ Measured headless (Luau CLI, Studio-like native code generation), demo window op
|
||||
|
||||
Most of the remaining cost is widget logic (your UI code and Dear ImGui's per-widget work), which runs every frame by design. Use `ImGuiListClipper` for long lists.
|
||||
|
||||
Windows that rarely change can opt in to caching: `ImGui.SetNextWindowCached(key)` keeps last frame's drawing and makes `Begin` return `visible = false`, so your code for that window doesn't run. It refreshes when `key` changes, while the window is hovered, focused or active (plus one frame after), and when it appears, moves, resizes, scrolls, collapses or is docked. An idle 200-widget window goes from ~2.2 ms to ~0.15 ms per frame.
|
||||
|
||||
```lua
|
||||
local stats = { version = 0, kills = 0 }
|
||||
local function StatsWindow()
|
||||
ImGui.SetNextWindowCached(stats.version) -- bump stats.version whenever stats change
|
||||
local _, visible = ImGui.Begin("Stats")
|
||||
if visible then -- false while the cached contents are reused
|
||||
ImGui.Text("Kills: %d", stats.kills)
|
||||
end
|
||||
ImGui.End()
|
||||
end
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
`tools/test/run.py` runs any LocalScript headless against a mocked Roblox (`tools/test/roblox_mock.luau`):
|
||||
@@ -283,7 +299,7 @@ Multi-select / box-select, typing-select, the Assets Browser example, the Item P
|
||||
|
||||
### AI disclosure
|
||||
|
||||
AI tools were used to assist in making this project (porting code, the Roblox and LÖVE backends, optimizations, tests and documentation). All changes were reviewed and tested by a human, and correctness is checked by the test suite (draw-data checksums against the reference behaviour, pixel comparisons, behaviour tests). Bug reports are welcome.
|
||||
AI tools were used to assist in making this project (porting code, optimizations, tests and documentation). All changes were reviewed and tested by a human, and correctness is checked by the test suite (draw-data checksums against the reference behaviour, pixel comparisons, behaviour tests). Bug reports are welcome.
|
||||
|
||||
### Credits
|
||||
|
||||
|
||||
@@ -42,10 +42,13 @@ jobs:
|
||||
python3 tools/sync_github_readme.py --check
|
||||
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
|
||||
luajit -bl dist/love/imgui_love.lua > /dev/null
|
||||
luajit -bl dist/love-nodemo/imgui_love.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
|
||||
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
|
||||
grep -q "CACHED OK" /tmp/c.txt
|
||||
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
|
||||
@@ -59,7 +62,7 @@ jobs:
|
||||
cp love/imgui_love.lua imgui_love.lua
|
||||
cp love-nodemo/imgui_love.lua imgui_love-nodemo.lua
|
||||
# Roblox: module + example LocalScript + Rojo project
|
||||
mkdir -p pkg-roblox/build && cp ImGui.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/
|
||||
(cd pkg-roblox && zip -qr ../imgui-luau-roblox-$V.zip .)
|
||||
# LÖVE: bundle + fonts + examples (run: love examples/example_love)
|
||||
@@ -80,6 +83,20 @@ jobs:
|
||||
dist/*.zip
|
||||
generate_release_notes: true
|
||||
|
||||
- name: Publish to Wally (tag)
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
env:
|
||||
WALLY_TOKEN: ${{ secrets.WALLY_TOKEN }}
|
||||
run: |
|
||||
[ -n "$WALLY_TOKEN" ] || { echo "WALLY_TOKEN not set, skipping"; exit 0; }
|
||||
grep -q "^version = \"${GITHUB_REF_NAME#v}\"" wally.toml || { echo "wally.toml version != tag"; exit 1; }
|
||||
curl -fsSL -o wally.zip https://github.com/UpliftGames/wally/releases/download/v0.3.2/wally-v0.3.2-linux.zip
|
||||
unzip -q wally.zip -d wallybin && chmod +x wallybin/wally
|
||||
mkdir -p dist/wally/src && cp wally.toml dist/wally/ && cp dist/roblox/ImGuiTyped.luau dist/wally/src/init.luau && cp dist/roblox/ImGui.luau dist/wally/src/Impl.luau
|
||||
echo '{"name":"imgui-luau","tree":{"$path":"src"}}' > dist/wally/default.project.json
|
||||
wallybin/wally login --token "$WALLY_TOKEN"
|
||||
wallybin/wally publish --project-path dist/wally
|
||||
|
||||
- name: Release (latest)
|
||||
if: "!startsWith(github.ref, 'refs/tags/v')"
|
||||
env:
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
.opencode/
|
||||
Packages/
|
||||
wally.lock
|
||||
__pycache__/
|
||||
@@ -7,7 +7,7 @@ Dear ImGui for Roblox (and more)
|
||||
|
||||
A Lua/Luau port of [Dear ImGui](https://github.com/ocornut/imgui) (docking branch, 1.93 WIP). **Roblox is the primary target** (rendered with EditableImages); the same sources also run on [LÖVE](https://love2d.org) (LuaJIT, GPU renderer), and the backend layout leaves room for more. It follows the C++ source function by function, so upstream documentation, examples and the demo apply almost directly.
|
||||
|
||||
| [The Pitch](#the-pitch) - [Usage](#usage) - [How it works](#how-it-works) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration) - [Backends](#backends) |
|
||||
| [The Pitch](#the-pitch) - [Usage](#usage) - [Demo](#demo) - [Getting Started & Integration](#getting-started--integration-roblox) - [How it works](#how-it-works-roblox-backend) - [Backends](#backends) |
|
||||
:----------------------------------------------------------: |
|
||||
| [Differences from C++](#differences-from-c-dear-imgui) - [Performance](#performance) - [Testing](#testing) - [Not ported yet](#not-ported-yet) |
|
||||
| [FAQ](#faq) - [Credits](#credits) - [License](#license) |
|
||||
@@ -76,27 +76,6 @@ Dear ImGui allows you to **create elaborate tools** as well as very short-lived
|
||||
|
||||
Every snippet in this README is run by [`tools/test/scripts/t_readme.luau`](tools/test/scripts/t_readme.luau), and every image was rendered by this port with [`tools/screenshots/make.py`](tools/screenshots/make.py).
|
||||
|
||||
### How it works (Roblox backend)
|
||||
|
||||
Dear ImGui itself never draws anything: every frame it produces `ImDrawData`, a list of textured, coloured triangles plus clip rectangles, and expects the backend to put them on screen. On desktop that is a few GPU draw calls. Roblox has no API to draw arbitrary triangles in 2D, so the Roblox backend ([backends/imgui_impl_roblox.lua](backends/imgui_impl_roblox.lua)) does what a GPU would do, in Luau, and pushes the result into **EditableImages**.
|
||||
|
||||
**Why software rasterization?** The alternatives don't fit Dear ImGui:
|
||||
- *One GUI Instance per widget/shape* (what most Roblox UI libraries do) means re-creating, re-parenting or diffing thousands of Instances every frame, can't express anti-aliased curves, per-vertex gradients or font-atlas glyphs, and would no longer be Dear ImGui's renderer output.
|
||||
- *Rasterizing the draw data* keeps the output identical to Dear ImGui's: the same fonts, anti-aliasing, rounding and gradients, and every widget (including custom `ImDrawList` drawing) works without backend support.
|
||||
|
||||
The cost is CPU time in Luau, so the backend is built around **not drawing**:
|
||||
|
||||
1. **Layers per window.** Every draw list (one per top-level window, popup, tooltip) gets its own `Frame` with `ZIndex` following Dear ImGui's draw order. Its content is rasterized relative to the window, so **moving a window only changes the Frame's `Position`**; no pixel is redrawn or uploaded.
|
||||
2. **Tiles.** Each layer is covered by 128×128 EditableImage tiles (`ImageLabel`s). Every primitive is hashed (positions relative to the layer, UVs, colours, texture, clip) into the tiles it touches. **Only tiles whose hash changed are re-rasterized and uploaded**, and only the dirty region of those (`WritePixelsBuffer` with a sub-rectangle). A static UI uploads nothing.
|
||||
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.
|
||||
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. **Render rate.** Tiles update at most `SetRenderRate(hz)` times per second (default 60), optionally lower while scrolling/resizing (`SetBusyRenderRate`). 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). Games can't read the clipboard, so while a text field is active a hidden `TextBox` holds focus: the OS 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).
|
||||
|
||||
**Instances inside windows.** The backend can place your own Instances (e.g. a `ViewportFrame`) inside a window's layer, so they stack, clip and move with it; see the `ImGui.Embed` widget in [examples/example_roblox/main.client.luau](examples/example_roblox/main.client.luau).
|
||||
|
||||
### Demo
|
||||
|
||||
Calling `ImGui.ShowDemoWindow()` creates a demo window that showcases a variety of features and examples. The code is in [imgui_demo.lua](imgui_demo.lua), like upstream's `imgui_demo.cpp`. **It's strongly recommended to keep it at hand as a reference**: you can find the code for any widget you see by searching for its label.
|
||||
@@ -134,7 +113,9 @@ The Style Editor (`ImGui.ShowStyleEditor()`) and the Metrics/Debugger (`ImGui.Sh
|
||||
|
||||
### Getting Started & Integration (Roblox)
|
||||
|
||||
1. Build the module: `python3 tools/bundle.py` writes `build/ImGui.luau` (`--no-demo` leaves the demo out).
|
||||
With [Wally](https://wally.run) ([4dbug/imgui-luau](https://wally.run/package/4dbug/imgui-luau)): add `ImGui = "4dbug/[email protected]"` 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.
|
||||
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`.
|
||||
3. A minimal LocalScript (full version: [examples/example_roblox/main.client.luau](examples/example_roblox/main.client.luau)):
|
||||
|
||||
@@ -179,6 +160,27 @@ io.Fonts:AddFontDefault()
|
||||
io.Fonts:AddFontFromFileTTF("fonts/Roboto-Medium.ttf", 16.0)
|
||||
```
|
||||
|
||||
### How it works (Roblox backend)
|
||||
|
||||
Dear ImGui itself never draws anything: every frame it produces `ImDrawData`, a list of textured, coloured triangles plus clip rectangles, and expects the backend to put them on screen. On desktop that is a few GPU draw calls. Roblox has no API to draw arbitrary triangles in 2D, so the Roblox backend ([backends/imgui_impl_roblox.lua](backends/imgui_impl_roblox.lua)) does what a GPU would do, in Luau, and pushes the result into **EditableImages**.
|
||||
|
||||
**Why software rasterization?** The alternatives don't fit Dear ImGui:
|
||||
- *One GUI Instance per widget/shape* (what most Roblox UI libraries do) means re-creating, re-parenting or diffing thousands of Instances every frame, can't express anti-aliased curves, per-vertex gradients or font-atlas glyphs, and would no longer be Dear ImGui's renderer output.
|
||||
- *Rasterizing the draw data* keeps the output identical to Dear ImGui's: the same fonts, anti-aliasing, rounding and gradients, and every widget (including custom `ImDrawList` drawing) works without backend support.
|
||||
|
||||
The cost is CPU time in Luau, so the backend is built around **not drawing**:
|
||||
|
||||
1. **Layers per window.** Every draw list (one per top-level window, popup, tooltip) gets its own `Frame` with `ZIndex` following Dear ImGui's draw order. Its content is rasterized relative to the window, so **moving a window only changes the Frame's `Position`**; no pixel is redrawn or uploaded.
|
||||
2. **Tiles.** Each layer is covered by 128×128 EditableImage tiles (`ImageLabel`s). Every primitive is hashed (positions relative to the layer, UVs, colours, texture, clip) into the tiles it touches. **Only tiles whose hash changed are re-rasterized and uploaded**, and only the dirty region of those (`WritePixelsBuffer` with a sub-rectangle). A static UI uploads nothing.
|
||||
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.
|
||||
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. **Render rate.** Tiles update at most `SetRenderRate(hz)` times per second (default 60), optionally lower while scrolling/resizing (`SetBusyRenderRate`). 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).
|
||||
|
||||
**Instances inside windows.** The backend can place your own Instances (e.g. a `ViewportFrame`) inside a window's layer, so they stack, clip and move with it; see the `ImGui.Embed` widget in [examples/example_roblox/main.client.luau](examples/example_roblox/main.client.luau).
|
||||
|
||||
### Backends
|
||||
|
||||
| Backend | File | Build | Renderer | Example |
|
||||
@@ -239,6 +241,20 @@ Measured headless (Luau CLI, Studio-like native code generation), demo window op
|
||||
|
||||
Most of the remaining cost is widget logic (your UI code and Dear ImGui's per-widget work), which runs every frame by design. Use `ImGuiListClipper` for long lists.
|
||||
|
||||
Windows that rarely change can opt in to caching: `ImGui.SetNextWindowCached(key)` keeps last frame's drawing and makes `Begin` return `visible = false`, so your code for that window doesn't run. It refreshes when `key` changes, while the window is hovered, focused or active (plus one frame after), and when it appears, moves, resizes, scrolls, collapses or is docked. An idle 200-widget window goes from ~2.2 ms to ~0.15 ms per frame.
|
||||
|
||||
```lua
|
||||
local stats = { version = 0, kills = 0 }
|
||||
local function StatsWindow()
|
||||
ImGui.SetNextWindowCached(stats.version) -- bump stats.version whenever stats change
|
||||
local _, visible = ImGui.Begin("Stats")
|
||||
if visible then -- false while the cached contents are reused
|
||||
ImGui.Text("Kills: %d", stats.kills)
|
||||
end
|
||||
ImGui.End()
|
||||
end
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
`tools/test/run.py` runs any LocalScript headless against a mocked Roblox (`tools/test/roblox_mock.luau`):
|
||||
@@ -280,7 +296,7 @@ Multi-select / box-select, typing-select, the Assets Browser example, the Item P
|
||||
|
||||
### AI disclosure
|
||||
|
||||
AI tools were used to assist in making this project (porting code, the Roblox and LÖVE backends, optimizations, tests and documentation). All changes were reviewed and tested by a human, and correctness is checked by the test suite (draw-data checksums against the reference behaviour, pixel comparisons, behaviour tests). Bug reports are welcome.
|
||||
AI tools were used to assist in making this project (porting code, optimizations, tests and documentation). All changes were reviewed and tested by a human, and correctness is checked by the test suite (draw-data checksums against the reference behaviour, pixel comparisons, behaviour tests). Bug reports are welcome.
|
||||
|
||||
### Credits
|
||||
|
||||
|
||||
@@ -1127,8 +1127,23 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Text proxy: a hidden TextBox holds focus while an imgui text field is active, so the OS gives us typing (any
|
||||
-- layout/unicode), paste (Ctrl+V) and copy/cut (Ctrl+C/X of the proxy's text = imgui's current selection).
|
||||
bd.PendingChars = {}
|
||||
|
||||
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
||||
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
||||
end
|
||||
|
||||
-- Text proxy (opt-in, ImGui_ImplRoblox.SetTextProxy(true)): a hidden TextBox holds focus while an imgui text field is
|
||||
-- active, so the OS gives us typing (any layout/unicode), paste (Ctrl+V) and copy/cut (Ctrl+C/X of imgui's selection).
|
||||
-- Off: typing comes from KeyCodes (printable ASCII), no OS clipboard.
|
||||
function ImGui_ImplRoblox_SetTextProxy(enabled)
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
if not enabled then
|
||||
if bd.Proxy then bd.Proxy:Destroy(); bd.Proxy = nil end
|
||||
proxy_focused = false
|
||||
return
|
||||
end
|
||||
if bd.Proxy then return end
|
||||
local proxy = Instance.new("TextBox")
|
||||
proxy.Name = "TextProxy"
|
||||
proxy.BackgroundTransparency = 1
|
||||
@@ -1140,12 +1155,11 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
proxy.ClearTextOnFocus = false
|
||||
proxy.TextEditable = true
|
||||
proxy.Text = ""
|
||||
proxy.Parent = gui
|
||||
bd.Proxy, bd.ProxyText, bd.PendingChars = proxy, "", {}
|
||||
proxy.Parent = bd.Gui
|
||||
bd.Proxy, bd.ProxyText = proxy, ""
|
||||
-- Clicking elsewhere (or Roblox taking focus) ends the edit, like clicking outside the field in imgui.
|
||||
-- (Text is polled in NewFrame instead of using Text changed signals: those are deferred in Roblox.)
|
||||
connect(proxy.FocusLost, function()
|
||||
if bd.ProxyDebug then print("[ImGui text proxy] FocusLost, mouse over imgui:", ImGui.GetIO().WantCaptureMouse) end
|
||||
proxy.FocusLost:Connect(function()
|
||||
if bd.ProxyReleasing then return end
|
||||
-- Roblox drops TextBox focus on any click, including clicks inside imgui (e.g. moving the cursor within the
|
||||
-- same field). Those must not end the edit: just recapture next frame. Only a click outside imgui ends it.
|
||||
@@ -1154,9 +1168,6 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
local g = ImGui.GetCurrentContext()
|
||||
if g and g.ActiveId ~= 0 and g.ActiveId == bd.ProxyActiveId then ImGui.ClearActiveID() end
|
||||
end)
|
||||
|
||||
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
||||
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
||||
end
|
||||
|
||||
function ImGui_ImplRoblox_Shutdown()
|
||||
@@ -1201,15 +1212,16 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
-- otherwise the KeyCode fallback keeps typing working.
|
||||
local proxy = bd.Proxy
|
||||
local g = ImGui.GetCurrentContext()
|
||||
local focused_box = UserInputService:GetFocusedTextBox()
|
||||
if io.WantTextInput and g.ActiveId ~= 0 then
|
||||
local focused_box = proxy and UserInputService:GetFocusedTextBox()
|
||||
if not proxy then
|
||||
-- text proxy disabled: KeyCode typing only
|
||||
elseif io.WantTextInput and g.ActiveId ~= 0 then
|
||||
if g.ActiveId ~= bd.ProxyActiveId or g.ActiveIdIsJustActivated or g.IO.MouseClicked[0] then bd.ProxyActiveId = g.ActiveId; bd.ProxyLostId = nil end -- (re)clicking a field recaptures
|
||||
local mouse_up = not (io.MouseDown[0] or io.MouseDown[1] or io.MouseDown[2])
|
||||
if focused_box ~= proxy and mouse_up and bd.ProxyLostId ~= g.ActiveId and (focused_box == nil or not focused_box:IsDescendantOf(game)) then
|
||||
bd.ProxyText = proxy.Text -- what it already holds is not new input (else re-typing it would collapse imgui's selection)
|
||||
proxy:CaptureFocus()
|
||||
focused_box = UserInputService:GetFocusedTextBox()
|
||||
if bd.ProxyDebug then print("[ImGui text proxy] CaptureFocus ->", focused_box == proxy and "focused" or ("FAILED, focused = " .. tostring(focused_box))) end
|
||||
end
|
||||
elseif focused_box == proxy then
|
||||
bd.ProxyReleasing = true
|
||||
@@ -1217,13 +1229,11 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
bd.ProxyReleasing = false
|
||||
focused_box = nil
|
||||
end
|
||||
local was_focused = proxy_focused
|
||||
proxy_focused = focused_box == proxy
|
||||
proxy_focused = proxy ~= nil and focused_box == proxy
|
||||
local used_proxy_text = false
|
||||
if proxy_focused then
|
||||
-- 1) whatever the OS put in the proxy since last frame (typing, paste, cut) replaces imgui's selection
|
||||
local text = proxy.Text
|
||||
if text ~= bd.ProxyText and bd.ProxyDebug then print("[ImGui text proxy] text", string.format("%q", text), "was", string.format("%q", tostring(bd.ProxyText))) end
|
||||
if text ~= bd.ProxyText and text ~= bd.ProxyLastRaw then -- (LastRaw: don't re-send if our reset hasn't applied yet)
|
||||
bd.ProxyLastRaw = text
|
||||
-- InputText ignores characters while Ctrl is held (upstream, so shortcuts don't type); a paste arrives with
|
||||
@@ -1259,7 +1269,6 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
proxy.Text = sel
|
||||
bd.ProxyLastRaw = nil
|
||||
bd.ProxyText = sel
|
||||
if bd.ProxyDebug then print("[ImGui text proxy] mirror selection", string.format("%q", sel)) end
|
||||
end
|
||||
-- keep imgui's selection fully selected in the proxy, so Ctrl+C copies it and typing/Ctrl+V replaces it
|
||||
local want_sel, want_cur = (#sel > 0) and 1 or -1, #sel + 1
|
||||
@@ -1275,7 +1284,6 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
if not used_proxy_text then for _, c in ipairs(pending) do io:AddInputCharacter(c) end end
|
||||
table.clear(pending)
|
||||
end
|
||||
if bd.ProxyDebug and was_focused ~= proxy_focused then print("[ImGui text proxy] proxy_focused =", proxy_focused) end
|
||||
|
||||
-- While the mouse is over imgui, make the tiles Active so Roblox stops passing clicks/wheel to the game (camera zoom etc.)
|
||||
local want = io.WantCaptureMouse
|
||||
@@ -1317,7 +1325,7 @@ ImGui_ImplRoblox = {
|
||||
SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
|
||||
SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
|
||||
SetOverlay = ImGui_ImplRoblox_SetOverlay,
|
||||
SetTextProxyDebug = function(on) ImGui_ImplRoblox_GetBackendData().ProxyDebug = on end, -- prints focus/text events
|
||||
SetTextProxy = ImGui_ImplRoblox_SetTextProxy,
|
||||
CreateTexture = ImGui_ImplRoblox_CreateTexture,
|
||||
DestroyTexture = ImGui_ImplRoblox_DestroyTexture,
|
||||
GetRenderScale = function() return ImGui_ImplRoblox_GetBackendData().Scale end,
|
||||
|
||||
@@ -1 +1 @@
|
||||
[[12, "imgui.lua"], [18472, "imgui_demo.lua"], [25757, "imgui_draw.lua"], [30995, "imgui_h.lua"], [33193, "imgui_impl_roblox.lua"], [34525, "imgui_impl_roblox_fonts.lua"], [40928, "imgui_internal.lua"], [44100, "imgui_tables.lua"], [48447, "imgui_widgets.lua"], [58202, "imstb_rectpack.lua"], [58648, "imstb_textedit.lua"], [59889, "imstb_truetype.lua"], [62357, "imstd_minstdio.lua"]]
|
||||
[[12, "imgui.lua"], [18510, "imgui_demo.lua"], [25795, "imgui_draw.lua"], [31033, "imgui_h.lua"], [33231, "imgui_impl_roblox.lua"], [34571, "imgui_impl_roblox_fonts.lua"], [40974, "imgui_internal.lua"], [44150, "imgui_tables.lua"], [48497, "imgui_widgets.lua"], [58252, "imstb_rectpack.lua"], [58698, "imstb_textedit.lua"], [59939, "imstb_truetype.lua"], [62407, "imstd_minstdio.lua"]]
|
||||
+70
-19
@@ -8857,6 +8857,26 @@ function ImGui.UpdateWindowSkipRefresh(window)
|
||||
end
|
||||
|
||||
if bit32.band(g.NextWindowData.RefreshFlagsVal, ImGuiWindowRefreshFlags.TryToAvoidRefresh) ~= 0 then
|
||||
-- [Port] SetNextWindowCached(): refresh on any change since the last refresh (and one frame after being busy)
|
||||
if g.NextWindowData.CacheKeySet then
|
||||
local function related(w) return w ~= nil and (w.RootWindow == window.RootWindow or ImGui.IsWindowWithinBeginStackOf(w.RootWindow, window)) end
|
||||
local busy = window.Appearing or window.Hidden or window.DockIsActive or related(g.HoveredWindow) or related(g.NavWindow) or related(g.ActiveIdWindow) or (g.MovingWindow ~= nil and related(g.MovingWindow))
|
||||
local c, key, ds, tex = window.CacheSnap, g.NextWindowData.CacheKeyVal, g.IO.DisplaySize, g.IO.Fonts.TexData
|
||||
if busy or c == nil or c.Busy or c.Key ~= key or c.Tex ~= tex or c.Collapsed ~= window.Collapsed
|
||||
or c.PosX ~= window.Pos.x or c.PosY ~= window.Pos.y or c.SizeX ~= window.SizeFull.x or c.SizeY ~= window.SizeFull.y
|
||||
or c.ScrollX ~= window.Scroll.x or c.ScrollY ~= window.Scroll.y or window.ScrollTarget.x < FLT_MAX or window.ScrollTarget.y < FLT_MAX
|
||||
or c.DisplayX ~= ds.x or c.DisplayY ~= ds.y then
|
||||
c = c or {}
|
||||
window.CacheSnap = c
|
||||
c.Busy, c.Key, c.Tex, c.Collapsed = busy, key, tex, window.Collapsed
|
||||
c.PosX, c.PosY, c.SizeX, c.SizeY = window.Pos.x, window.Pos.y, window.SizeFull.x, window.SizeFull.y
|
||||
c.ScrollX, c.ScrollY, c.DisplayX, c.DisplayY = window.Scroll.x, window.Scroll.y, ds.x, ds.y
|
||||
return
|
||||
end
|
||||
-- skip: widgets early-out on SkipItems and Begin() returns visible=false; End() restores it
|
||||
window.CacheSkipItemsBackup = window.SkipItems
|
||||
window.SkipItems = true
|
||||
end
|
||||
-- FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused.
|
||||
if window.Appearing then -- If currently appearing
|
||||
return
|
||||
@@ -9488,6 +9508,20 @@ function ImGui.SetNextWindowRefreshPolicy(flags)
|
||||
local g = GImGui
|
||||
g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasRefreshPolicy)
|
||||
g.NextWindowData.RefreshFlagsVal = flags
|
||||
g.NextWindowData.CacheKeySet = false
|
||||
end
|
||||
|
||||
-- [Port] Opt-in cached window (built on the refresh policy above). While nothing that could change the window
|
||||
-- happened, Begin() keeps last frame's draw list and returns visible=false, so `if visible then ... end` skips your code.
|
||||
-- It refreshes when `key` changes (pass e.g. a version number of the data shown), while the window (or a popup/child
|
||||
-- of it) is hovered, focused or active and for one frame after, and when it appears, moves, resizes, scrolls,
|
||||
-- collapses, is docked, or the display size or font atlas texture changes.
|
||||
-- Anything else that changes the contents (style, fonts, time) must be part of `key`.
|
||||
function ImGui.SetNextWindowCached(key)
|
||||
local g = GImGui
|
||||
ImGui.SetNextWindowRefreshPolicy(bit32.bor(ImGuiWindowRefreshFlags.TryToAvoidRefresh, ImGuiWindowRefreshFlags.RefreshOnHover, ImGuiWindowRefreshFlags.RefreshOnFocus))
|
||||
g.NextWindowData.CacheKeySet = true
|
||||
g.NextWindowData.CacheKeyVal = key
|
||||
end
|
||||
|
||||
function ImGui.GetWindowDpiScale()
|
||||
@@ -10690,6 +10724,10 @@ function ImGui.End()
|
||||
IM_ASSERT(window.DrawList == nil)
|
||||
window.DrawList = window.DrawListInst
|
||||
end
|
||||
if window.CacheSkipItemsBackup ~= nil then -- [Port] SetNextWindowCached()
|
||||
window.SkipItems = window.CacheSkipItemsBackup
|
||||
window.CacheSkipItemsBackup = nil
|
||||
end
|
||||
|
||||
-- Stop logging
|
||||
if g.LogWindow == window then -- FIXME: add more options for scope of logging
|
||||
@@ -34319,8 +34357,23 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Text proxy: a hidden TextBox holds focus while an imgui text field is active, so the OS gives us typing (any
|
||||
-- layout/unicode), paste (Ctrl+V) and copy/cut (Ctrl+C/X of the proxy's text = imgui's current selection).
|
||||
bd.PendingChars = {}
|
||||
|
||||
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
||||
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
||||
end
|
||||
|
||||
-- Text proxy (opt-in, ImGui_ImplRoblox.SetTextProxy(true)): a hidden TextBox holds focus while an imgui text field is
|
||||
-- active, so the OS gives us typing (any layout/unicode), paste (Ctrl+V) and copy/cut (Ctrl+C/X of imgui's selection).
|
||||
-- Off: typing comes from KeyCodes (printable ASCII), no OS clipboard.
|
||||
function ImGui_ImplRoblox_SetTextProxy(enabled)
|
||||
local bd = ImGui_ImplRoblox_GetBackendData()
|
||||
if not enabled then
|
||||
if bd.Proxy then bd.Proxy:Destroy(); bd.Proxy = nil end
|
||||
proxy_focused = false
|
||||
return
|
||||
end
|
||||
if bd.Proxy then return end
|
||||
local proxy = Instance.new("TextBox")
|
||||
proxy.Name = "TextProxy"
|
||||
proxy.BackgroundTransparency = 1
|
||||
@@ -34332,12 +34385,11 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
proxy.ClearTextOnFocus = false
|
||||
proxy.TextEditable = true
|
||||
proxy.Text = ""
|
||||
proxy.Parent = gui
|
||||
bd.Proxy, bd.ProxyText, bd.PendingChars = proxy, "", {}
|
||||
proxy.Parent = bd.Gui
|
||||
bd.Proxy, bd.ProxyText = proxy, ""
|
||||
-- Clicking elsewhere (or Roblox taking focus) ends the edit, like clicking outside the field in imgui.
|
||||
-- (Text is polled in NewFrame instead of using Text changed signals: those are deferred in Roblox.)
|
||||
connect(proxy.FocusLost, function()
|
||||
if bd.ProxyDebug then print("[ImGui text proxy] FocusLost, mouse over imgui:", ImGui.GetIO().WantCaptureMouse) end
|
||||
proxy.FocusLost:Connect(function()
|
||||
if bd.ProxyReleasing then return end
|
||||
-- Roblox drops TextBox focus on any click, including clicks inside imgui (e.g. moving the cursor within the
|
||||
-- same field). Those must not end the edit: just recapture next frame. Only a click outside imgui ends it.
|
||||
@@ -34346,9 +34398,6 @@ function ImGui_ImplRoblox_Init(parent, render_scale)
|
||||
local g = ImGui.GetCurrentContext()
|
||||
if g and g.ActiveId ~= 0 and g.ActiveId == bd.ProxyActiveId then ImGui.ClearActiveID() end
|
||||
end)
|
||||
|
||||
connect(UserInputService.WindowFocused, function() ImGui.GetIO():AddFocusEvent(true) end)
|
||||
connect(UserInputService.WindowFocusReleased, function() ImGui.GetIO():AddFocusEvent(false) end)
|
||||
end
|
||||
|
||||
function ImGui_ImplRoblox_Shutdown()
|
||||
@@ -34393,15 +34442,16 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
-- otherwise the KeyCode fallback keeps typing working.
|
||||
local proxy = bd.Proxy
|
||||
local g = ImGui.GetCurrentContext()
|
||||
local focused_box = UserInputService:GetFocusedTextBox()
|
||||
if io.WantTextInput and g.ActiveId ~= 0 then
|
||||
local focused_box = proxy and UserInputService:GetFocusedTextBox()
|
||||
if not proxy then
|
||||
-- text proxy disabled: KeyCode typing only
|
||||
elseif io.WantTextInput and g.ActiveId ~= 0 then
|
||||
if g.ActiveId ~= bd.ProxyActiveId or g.ActiveIdIsJustActivated or g.IO.MouseClicked[0] then bd.ProxyActiveId = g.ActiveId; bd.ProxyLostId = nil end -- (re)clicking a field recaptures
|
||||
local mouse_up = not (io.MouseDown[0] or io.MouseDown[1] or io.MouseDown[2])
|
||||
if focused_box ~= proxy and mouse_up and bd.ProxyLostId ~= g.ActiveId and (focused_box == nil or not focused_box:IsDescendantOf(game)) then
|
||||
bd.ProxyText = proxy.Text -- what it already holds is not new input (else re-typing it would collapse imgui's selection)
|
||||
proxy:CaptureFocus()
|
||||
focused_box = UserInputService:GetFocusedTextBox()
|
||||
if bd.ProxyDebug then print("[ImGui text proxy] CaptureFocus ->", focused_box == proxy and "focused" or ("FAILED, focused = " .. tostring(focused_box))) end
|
||||
end
|
||||
elseif focused_box == proxy then
|
||||
bd.ProxyReleasing = true
|
||||
@@ -34409,13 +34459,11 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
bd.ProxyReleasing = false
|
||||
focused_box = nil
|
||||
end
|
||||
local was_focused = proxy_focused
|
||||
proxy_focused = focused_box == proxy
|
||||
proxy_focused = proxy ~= nil and focused_box == proxy
|
||||
local used_proxy_text = false
|
||||
if proxy_focused then
|
||||
-- 1) whatever the OS put in the proxy since last frame (typing, paste, cut) replaces imgui's selection
|
||||
local text = proxy.Text
|
||||
if text ~= bd.ProxyText and bd.ProxyDebug then print("[ImGui text proxy] text", string.format("%q", text), "was", string.format("%q", tostring(bd.ProxyText))) end
|
||||
if text ~= bd.ProxyText and text ~= bd.ProxyLastRaw then -- (LastRaw: don't re-send if our reset hasn't applied yet)
|
||||
bd.ProxyLastRaw = text
|
||||
-- InputText ignores characters while Ctrl is held (upstream, so shortcuts don't type); a paste arrives with
|
||||
@@ -34451,7 +34499,6 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
proxy.Text = sel
|
||||
bd.ProxyLastRaw = nil
|
||||
bd.ProxyText = sel
|
||||
if bd.ProxyDebug then print("[ImGui text proxy] mirror selection", string.format("%q", sel)) end
|
||||
end
|
||||
-- keep imgui's selection fully selected in the proxy, so Ctrl+C copies it and typing/Ctrl+V replaces it
|
||||
local want_sel, want_cur = (#sel > 0) and 1 or -1, #sel + 1
|
||||
@@ -34467,7 +34514,6 @@ function ImGui_ImplRoblox_NewFrame()
|
||||
if not used_proxy_text then for _, c in ipairs(pending) do io:AddInputCharacter(c) end end
|
||||
table.clear(pending)
|
||||
end
|
||||
if bd.ProxyDebug and was_focused ~= proxy_focused then print("[ImGui text proxy] proxy_focused =", proxy_focused) end
|
||||
|
||||
-- While the mouse is over imgui, make the tiles Active so Roblox stops passing clicks/wheel to the game (camera zoom etc.)
|
||||
local want = io.WantCaptureMouse
|
||||
@@ -34509,7 +34555,7 @@ ImGui_ImplRoblox = {
|
||||
SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
|
||||
SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
|
||||
SetOverlay = ImGui_ImplRoblox_SetOverlay,
|
||||
SetTextProxyDebug = function(on) ImGui_ImplRoblox_GetBackendData().ProxyDebug = on end, -- prints focus/text events
|
||||
SetTextProxy = ImGui_ImplRoblox_SetTextProxy,
|
||||
CreateTexture = ImGui_ImplRoblox_CreateTexture,
|
||||
DestroyTexture = ImGui_ImplRoblox_DestroyTexture,
|
||||
GetRenderScale = function() return ImGui_ImplRoblox_GetBackendData().Scale end,
|
||||
@@ -42163,7 +42209,9 @@ function ImGuiNextWindowData()
|
||||
SizeCallbackUserData = nil,
|
||||
BgAlphaVal = nil,
|
||||
MenuBarOffsetMinVal = ImVec2(),
|
||||
RefreshFlagsVal = nil
|
||||
RefreshFlagsVal = nil,
|
||||
CacheKeySet = false, -- [Port] SetNextWindowCached()
|
||||
CacheKeyVal = nil
|
||||
}, IMGUI_NEXT_WINDOW_DATA)
|
||||
end
|
||||
|
||||
@@ -43335,6 +43383,8 @@ function ImGuiWindow(ctx, name)
|
||||
SkipItems = false,
|
||||
|
||||
SkipRefresh = false,
|
||||
CacheSnap = nil, -- [Port] SetNextWindowCached(): state at the last refresh
|
||||
CacheSkipItemsBackup = nil,
|
||||
|
||||
Appearing = false,
|
||||
|
||||
@@ -62976,6 +63026,7 @@ return {
|
||||
ImGui_ImplRoblox_SetProfiling = ImGui_ImplRoblox_SetProfiling,
|
||||
ImGui_ImplRoblox_SetRenderRate = ImGui_ImplRoblox_SetRenderRate,
|
||||
ImGui_ImplRoblox_SetRenderScale = ImGui_ImplRoblox_SetRenderScale,
|
||||
ImGui_ImplRoblox_SetTextProxy = ImGui_ImplRoblox_SetTextProxy,
|
||||
ImGui_ImplRoblox_Shutdown = ImGui_ImplRoblox_Shutdown,
|
||||
ImGui_ImplRoblox_UpdateTexture = ImGui_ImplRoblox_UpdateTexture,
|
||||
ImHashData = ImHashData,
|
||||
|
||||
@@ -0,0 +1,958 @@
|
||||
--!strict
|
||||
-- GENERATED by tools/gen_types.py - do not edit. The library is the child ModuleScript 'Impl'.
|
||||
|
||||
export type ImVec2 = { x: number, y: number, [any]: any }
|
||||
export type ImVec4 = { x: number, y: number, z: number, w: number, [any]: any }
|
||||
export type ImGuiAPI = {
|
||||
AcceptDragDropPayload: (type: string, flags: number?) -> any,
|
||||
ActivateItemByID: (...any) -> ...any,
|
||||
AddDrawListToDrawDataEx: (...any) -> ...any,
|
||||
AddSettingsHandler: (...any) -> ...any,
|
||||
AddUpdateViewport: (...any) -> ...any,
|
||||
AlignTextToFramePadding: () -> (),
|
||||
ArrowButton: (str_id: string, dir: number) -> boolean,
|
||||
ArrowButtonEx: (...any) -> ...any,
|
||||
Begin: (name: string, open: boolean?, flags: number?) -> (boolean, boolean?),
|
||||
BeginChild: (...any) -> ...any,
|
||||
BeginChildEx: (...any) -> ...any,
|
||||
BeginColumns: (...any) -> ...any,
|
||||
BeginCombo: (label: string, preview_value: string, flags: number?) -> boolean,
|
||||
BeginComboPopup: (...any) -> ...any,
|
||||
BeginComboPreview: (...any) -> ...any,
|
||||
BeginDisabled: (disabled: boolean?) -> (),
|
||||
BeginDisabledOverrideReenable: (...any) -> ...any,
|
||||
BeginDockableDragDropSource: (...any) -> ...any,
|
||||
BeginDockableDragDropTarget: (...any) -> ...any,
|
||||
BeginDocked: (...any) -> ...any,
|
||||
BeginDragDropSource: (flags: number?) -> boolean,
|
||||
BeginDragDropTarget: () -> boolean,
|
||||
BeginDragDropTargetCustom: (...any) -> ...any,
|
||||
BeginDragDropTargetViewport: (...any) -> ...any,
|
||||
BeginErrorTooltip: (...any) -> ...any,
|
||||
BeginGroup: () -> (),
|
||||
BeginItemTooltip: () -> boolean,
|
||||
BeginListBox: (label: string, size_arg: ImVec2?) -> boolean,
|
||||
BeginMainMenuBar: () -> boolean,
|
||||
BeginMenu: (label: string, enabled: boolean?) -> boolean,
|
||||
BeginMenuBar: () -> boolean,
|
||||
BeginMenuEx: (...any) -> ...any,
|
||||
BeginPopup: (str_id: string, flags: number?) -> boolean,
|
||||
BeginPopupContextItem: (str_id: string?, popup_flags: number?) -> boolean,
|
||||
BeginPopupContextVoid: (str_id: string?, popup_flags: number?) -> boolean,
|
||||
BeginPopupContextWindow: (str_id: string?, popup_flags: number?) -> boolean,
|
||||
BeginPopupEx: (...any) -> ...any,
|
||||
BeginPopupMenuEx: (...any) -> ...any,
|
||||
BeginPopupModal: (name: string, p_open: boolean?, flags: number?) -> (boolean, boolean?),
|
||||
BeginTabBar: (str_id: string, flags: number?) -> boolean,
|
||||
BeginTabBarEx: (...any) -> ...any,
|
||||
BeginTabItem: (label: string, p_open: boolean?, flags: number?) -> (boolean, boolean?),
|
||||
BeginTable: (str_id: string, columns_count: number, flags: number?, outer_size: ImVec2?, inner_width: number?) -> boolean,
|
||||
BeginTableEx: (...any) -> ...any,
|
||||
BeginTooltip: () -> boolean,
|
||||
BeginTooltipEx: (...any) -> ...any,
|
||||
BeginTooltipHidden: (...any) -> ...any,
|
||||
BeginViewportSideBar: (...any) -> ...any,
|
||||
BringWindowToDisplayBack: (...any) -> ...any,
|
||||
BringWindowToDisplayBehind: (...any) -> ...any,
|
||||
BringWindowToDisplayFront: (...any) -> ...any,
|
||||
BringWindowToFocusFront: (...any) -> ...any,
|
||||
Bullet: () -> (),
|
||||
BulletText: (fmt: string, ...any) -> (),
|
||||
Button: (label: string, size_arg: ImVec2?) -> boolean,
|
||||
ButtonBehavior: (...any) -> ...any,
|
||||
ButtonEx: (...any) -> ...any,
|
||||
CalcClipRectVisibleItemsY: (...any) -> ...any,
|
||||
CalcItemSize: (...any) -> ...any,
|
||||
CalcItemWidth: () -> number,
|
||||
CalcRoundingFlagsForRectInRect: (...any) -> ...any,
|
||||
CalcTextSize: (text: string, text_end: string?, hide_text_after_double_hash: boolean?, wrap_width: number?) -> ImVec2,
|
||||
CalcTextSizeEx: (...any) -> ...any,
|
||||
CalcTypematicRepeatAmount: (...any) -> ...any,
|
||||
CalcWindowNextAutoFitSize: (...any) -> ...any,
|
||||
CalcWrapWidthForPos: (...any) -> ...any,
|
||||
Checkbox: (label: string, v: boolean?) -> (boolean, boolean?),
|
||||
CheckboxFlags: (...any) -> ...any,
|
||||
CleanupIniSettings: (...any) -> ...any,
|
||||
ClearActiveID: (...any) -> ...any,
|
||||
ClearDragDrop: (...any) -> ...any,
|
||||
ClearIniSettings: (...any) -> ...any,
|
||||
ClearWindowSettings: (...any) -> ...any,
|
||||
CloseButton: (...any) -> ...any,
|
||||
CloseCurrentPopup: () -> (),
|
||||
ClosePopupToLevel: (...any) -> ...any,
|
||||
ClosePopupsExceptModals: (...any) -> ...any,
|
||||
ClosePopupsOverWindow: (...any) -> ...any,
|
||||
CollapseButton: (...any) -> ...any,
|
||||
CollapsingHeader: (...any) -> ...any,
|
||||
ColorButton: (desc_id: string, col: ImVec4, flags: number?, size_arg: ImVec2?) -> boolean,
|
||||
ColorConvertFloat4ToU32: (in_col: ImVec4) -> number,
|
||||
ColorConvertHSVtoRGB: (...any) -> ...any,
|
||||
ColorConvertRGBtoHSV: (...any) -> ...any,
|
||||
ColorConvertU32ToFloat4: (...any) -> ...any,
|
||||
ColorEdit3: (label: string, col: any, flags: number?) -> boolean,
|
||||
ColorEdit4: (label: string, col: any, flags: number?) -> boolean,
|
||||
ColorEditOptionsPopup: (...any) -> ...any,
|
||||
ColorPicker3: (label: string, col: any, flags: number?) -> boolean,
|
||||
ColorPicker4: (label: string, col: any, flags: number?, ref_col: any) -> boolean,
|
||||
ColorPickerOptionsPopup: (...any) -> ...any,
|
||||
ColorTooltip: (...any) -> ...any,
|
||||
Columns: (columns_count: number?, id: string?, borders: boolean?) -> (),
|
||||
Combo: (...any) -> ...any,
|
||||
ConvertSingleModFlagToKey: (...any) -> ...any,
|
||||
CreateContext: (shared_font_atlas: any) -> ...any,
|
||||
CreateNewWindowSettings: (...any) -> ...any,
|
||||
DataTypeApplyFromText: (...any) -> ...any,
|
||||
DataTypeApplyOp: (...any) -> ...any,
|
||||
DataTypeClamp: (...any) -> ...any,
|
||||
DataTypeCompare: (...any) -> ...any,
|
||||
DataTypeFormatString: (...any) -> ...any,
|
||||
DataTypeGetInfo: (...any) -> ...any,
|
||||
DataTypeIsZero: (...any) -> ...any,
|
||||
DebugAllocHook: (...any) -> ...any,
|
||||
DebugHookIdInfo: (...any) -> ...any,
|
||||
DebugLog: (fmt: string, ...any) -> (),
|
||||
DebugNodeColumns: (...any) -> ...any,
|
||||
DebugNodeDockNode: (...any) -> ...any,
|
||||
DebugNodeDrawList: (...any) -> ...any,
|
||||
DebugNodeFont: (...any) -> ...any,
|
||||
DebugNodeFontGlyph: (...any) -> ...any,
|
||||
DebugNodeFontGlyphsForSrcMask: (...any) -> ...any,
|
||||
DebugNodeStorage: (...any) -> ...any,
|
||||
DebugNodeTabBar: (...any) -> ...any,
|
||||
DebugNodeTable: (...any) -> ...any,
|
||||
DebugNodeTableSettings: (...any) -> ...any,
|
||||
DebugNodeTexture: (...any) -> ...any,
|
||||
DebugNodeViewport: (...any) -> ...any,
|
||||
DebugNodeWindow: (...any) -> ...any,
|
||||
DebugNodeWindowSettings: (...any) -> ...any,
|
||||
DebugNodeWindowsList: (...any) -> ...any,
|
||||
DebugNodeWindowsListByBeginStackParent: (...any) -> ...any,
|
||||
DebugRenderViewportThumbnail: (...any) -> ...any,
|
||||
DebugTextEncoding: (str: string) -> (),
|
||||
DestroyContext: (ctx: any) -> ...any,
|
||||
DestroyPlatformWindow: (...any) -> ...any,
|
||||
DestroyPlatformWindows: () -> (),
|
||||
DestroyViewport: (...any) -> ...any,
|
||||
DockBuilderAddNode: (...any) -> ...any,
|
||||
DockBuilderCopyDockSpace: (...any) -> ...any,
|
||||
DockBuilderCopyNode: (...any) -> ...any,
|
||||
DockBuilderCopyWindowSettings: (...any) -> ...any,
|
||||
DockBuilderDockWindow: (...any) -> ...any,
|
||||
DockBuilderFinish: (...any) -> ...any,
|
||||
DockBuilderGetCentralNode: (...any) -> ...any,
|
||||
DockBuilderGetNode: (...any) -> ...any,
|
||||
DockBuilderRemoveNode: (...any) -> ...any,
|
||||
DockBuilderRemoveNodeChildNodes: (...any) -> ...any,
|
||||
DockBuilderRemoveNodeDockedWindows: (...any) -> ...any,
|
||||
DockBuilderSetNodePos: (...any) -> ...any,
|
||||
DockBuilderSetNodeSize: (...any) -> ...any,
|
||||
DockBuilderSplitNode: (...any) -> ...any,
|
||||
DockContextAddNode: (...any) -> ...any,
|
||||
DockContextBindNodeToWindow: (...any) -> ...any,
|
||||
DockContextBuildAddWindowsToNodes: (...any) -> ...any,
|
||||
DockContextBuildNodesFromSettings: (...any) -> ...any,
|
||||
DockContextCalcDropPosForDocking: (...any) -> ...any,
|
||||
DockContextClearNodes: (...any) -> ...any,
|
||||
DockContextDeleteNode: (...any) -> ...any,
|
||||
DockContextEndFrame: (...any) -> ...any,
|
||||
DockContextFindNodeByID: (...any) -> ...any,
|
||||
DockContextGenNodeID: (...any) -> ...any,
|
||||
DockContextInitialize: (...any) -> ...any,
|
||||
DockContextNewFrameUpdateDocking: (...any) -> ...any,
|
||||
DockContextNewFrameUpdateUndocking: (...any) -> ...any,
|
||||
DockContextProcessDock: (...any) -> ...any,
|
||||
DockContextProcessUndockNode: (...any) -> ...any,
|
||||
DockContextProcessUndockWindow: (...any) -> ...any,
|
||||
DockContextPruneUnusedSettingsNodes: (...any) -> ...any,
|
||||
DockContextQueueDock: (...any) -> ...any,
|
||||
DockContextQueueNotifyRemovedNode: (...any) -> ...any,
|
||||
DockContextQueueUndockNode: (...any) -> ...any,
|
||||
DockContextQueueUndockWindow: (...any) -> ...any,
|
||||
DockContextRebuildNodes: (...any) -> ...any,
|
||||
DockContextRemoveNode: (...any) -> ...any,
|
||||
DockContextShutdown: (...any) -> ...any,
|
||||
DockNodeAddTabBar: (...any) -> ...any,
|
||||
DockNodeAddWindow: (...any) -> ...any,
|
||||
DockNodeApplyPosSizeToWindows: (...any) -> ...any,
|
||||
DockNodeBeginAmendTabBar: (...any) -> ...any,
|
||||
DockNodeCalcDropRectsAndTestMousePos: (...any) -> ...any,
|
||||
DockNodeCalcSplitRects: (...any) -> ...any,
|
||||
DockNodeCalcTabBarLayout: (...any) -> ...any,
|
||||
DockNodeEndAmendTabBar: (...any) -> ...any,
|
||||
DockNodeFindWindowByID: (...any) -> ...any,
|
||||
DockNodeGetDepth: (...any) -> ...any,
|
||||
DockNodeGetRootNode: (...any) -> ...any,
|
||||
DockNodeGetTabOrder: (...any) -> ...any,
|
||||
DockNodeGetWindowMenuButtonId: (...any) -> ...any,
|
||||
DockNodeHideHostWindow: (...any) -> ...any,
|
||||
DockNodeIsDropAllowed: (...any) -> ...any,
|
||||
DockNodeIsInHierarchyOf: (...any) -> ...any,
|
||||
DockNodeMoveChildNodes: (...any) -> ...any,
|
||||
DockNodeMoveWindows: (...any) -> ...any,
|
||||
DockNodePreviewDockRender: (...any) -> ...any,
|
||||
DockNodePreviewDockSetup: (...any) -> ...any,
|
||||
DockNodeRemoveTabBar: (...any) -> ...any,
|
||||
DockNodeRemoveWindow: (...any) -> ...any,
|
||||
DockNodeStartMouseMovingWindow: (...any) -> ...any,
|
||||
DockNodeTreeFindFallbackLeafNode: (...any) -> ...any,
|
||||
DockNodeTreeFindVisibleNodeByPos: (...any) -> ...any,
|
||||
DockNodeTreeMerge: (...any) -> ...any,
|
||||
DockNodeTreeSplit: (...any) -> ...any,
|
||||
DockNodeTreeUpdatePosSize: (...any) -> ...any,
|
||||
DockNodeTreeUpdateSplitter: (...any) -> ...any,
|
||||
DockNodeUpdate: (...any) -> ...any,
|
||||
DockNodeUpdateFlagsAndCollapse: (...any) -> ...any,
|
||||
DockNodeUpdateForRootNode: (...any) -> ...any,
|
||||
DockNodeUpdateHasCentralNodeChild: (...any) -> ...any,
|
||||
DockNodeUpdateTabBar: (...any) -> ...any,
|
||||
DockNodeUpdateVisibleFlag: (...any) -> ...any,
|
||||
DockNodeWindowMenuHandler_Default: (...any) -> ...any,
|
||||
DockNodeWindowMenuUpdate: (...any) -> ...any,
|
||||
DockSpace: (dockspace_id: number, size_arg: ImVec2?, flags: number?, window_class: any) -> number,
|
||||
DockSpaceOverViewport: (dockspace_id: number?, viewport: any, dockspace_flags: number?, window_class: any) -> number,
|
||||
DragBehavior: (...any) -> ...any,
|
||||
DragBehaviorT: (...any) -> ...any,
|
||||
DragFloat: (label: string, v: number, v_speed: number?, v_min: number?, v_max: number?, format: string?, flags: number?) -> (number, boolean),
|
||||
DragFloatRange2: (label: string, v_current_min: number, v_current_max: number, v_speed: number?, v_min: number?, v_max: number?, format: string?, format_max: string?, flags: number?) -> ...any,
|
||||
DragInt: (label: string, v: number, v_speed: number?, v_min: number?, v_max: number?, format: string?, flags: number?) -> (number, boolean),
|
||||
DragIntRange2: (label: string, v_current_min: number, v_current_max: number, v_speed: number?, v_min: number?, v_max: number?, format: string?, format_max: string?, flags: number?) -> ...any,
|
||||
DragScalar: (label: string, data_type: number, data: any, v_speed: number?, min: any, 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) -> (),
|
||||
End: () -> (),
|
||||
EndChild: () -> (),
|
||||
EndColumns: (...any) -> ...any,
|
||||
EndCombo: () -> (),
|
||||
EndComboPreview: (...any) -> ...any,
|
||||
EndDisabled: () -> (),
|
||||
EndDisabledOverrideReenable: (...any) -> ...any,
|
||||
EndDragDropSource: () -> (),
|
||||
EndDragDropTarget: () -> (),
|
||||
EndErrorTooltip: (...any) -> ...any,
|
||||
EndFrame: () -> (),
|
||||
EndGroup: () -> (),
|
||||
EndListBox: () -> (),
|
||||
EndMainMenuBar: () -> (),
|
||||
EndMenu: () -> (),
|
||||
EndMenuBar: () -> (),
|
||||
EndPopup: () -> (),
|
||||
EndTabBar: () -> (),
|
||||
EndTabItem: () -> (),
|
||||
EndTable: () -> (),
|
||||
EndTooltip: () -> (),
|
||||
ErrorCheckEndFrameFinalizeErrorTooltip: (...any) -> ...any,
|
||||
ErrorCheckUsingSetCursorPosToExtendParentBoundaries: (...any) -> ...any,
|
||||
ErrorLog: (...any) -> ...any,
|
||||
ErrorRecoveryStoreState: (...any) -> ...any,
|
||||
ErrorRecoveryTryToRecoverState: (...any) -> ...any,
|
||||
ErrorRecoveryTryToRecoverWindowState: (...any) -> ...any,
|
||||
ExtendHitBoxWhenNearViewportEdge: (...any) -> ...any,
|
||||
FindBestWindowPosForPopup: (...any) -> ...any,
|
||||
FindBestWindowPosForPopupEx: (...any) -> ...any,
|
||||
FindBlockingModal: (...any) -> ...any,
|
||||
FindBottomMostVisibleWindowWithinBeginStack: (...any) -> ...any,
|
||||
FindFrontMostVisibleChildWindow: (...any) -> ...any,
|
||||
FindHoveredViewportFromPlatformWindowStack: (...any) -> ...any,
|
||||
FindOrCreateColumns: (...any) -> ...any,
|
||||
FindPlatformMonitorForPos: (...any) -> ...any,
|
||||
FindPlatformMonitorForRect: (...any) -> ...any,
|
||||
FindRenderedTextEnd: (...any) -> ...any,
|
||||
FindSettingsHandler: (...any) -> ...any,
|
||||
FindViewportByID: (viewport_id: number) -> any,
|
||||
FindWindowByID: (...any) -> ...any,
|
||||
FindWindowByName: (...any) -> ...any,
|
||||
FindWindowDisplayIndex: (...any) -> ...any,
|
||||
FindWindowFocusIndex: (...any) -> ...any,
|
||||
FindWindowNavFocusable: (...any) -> ...any,
|
||||
FindWindowSettingsByID: (...any) -> ...any,
|
||||
FindWindowSettingsByWindow: (...any) -> ...any,
|
||||
FixupKeyChord: (...any) -> ...any,
|
||||
FocusItem: (...any) -> ...any,
|
||||
FocusTopMostWindowUnderOne: (...any) -> ...any,
|
||||
FocusWindow: (...any) -> ...any,
|
||||
GcAwakeTransientWindowBuffers: (...any) -> ...any,
|
||||
GcCompactTransientMiscBuffers: (...any) -> ...any,
|
||||
GcCompactTransientWindowBuffers: (...any) -> ...any,
|
||||
GetBackgroundDrawList: (viewport: any) -> ...any,
|
||||
GetClipboardText: () -> any,
|
||||
GetColorU32: (...any) -> ...any,
|
||||
GetColumnIndex: () -> number,
|
||||
GetColumnNormFromOffset: (...any) -> ...any,
|
||||
GetColumnOffset: (column_index: number?) -> number,
|
||||
GetColumnOffsetFromNorm: (...any) -> ...any,
|
||||
GetColumnWidth: (column_index: number?) -> number,
|
||||
GetColumnsCount: () -> number,
|
||||
GetColumnsID: (...any) -> ...any,
|
||||
GetContentRegionAvail: () -> ImVec2,
|
||||
GetContentRegionMax: (...any) -> ...any,
|
||||
GetCurrentContext: () -> any,
|
||||
GetCurrentWindow: (...any) -> ...any,
|
||||
GetCurrentWindowRead: (...any) -> ...any,
|
||||
GetCursorPos: () -> ImVec2,
|
||||
GetCursorPosX: () -> number,
|
||||
GetCursorPosY: () -> number,
|
||||
GetCursorScreenPos: () -> ImVec2,
|
||||
GetCursorStartPos: () -> ImVec2,
|
||||
GetDefaultFont: (...any) -> ...any,
|
||||
GetDragDropPayload: () -> any,
|
||||
GetDrawData: () -> any,
|
||||
GetDrawListSharedData: () -> any,
|
||||
GetFont: () -> any,
|
||||
GetFontSize: () -> number,
|
||||
GetFontTexUvWhitePixel: () -> ImVec2,
|
||||
GetForegroundDrawList: (viewport: any) -> ...any,
|
||||
GetFrameCount: () -> number,
|
||||
GetFrameHeight: () -> number,
|
||||
GetFrameHeightWithSpacing: () -> number,
|
||||
GetHoveredID: (...any) -> ...any,
|
||||
GetID: (...any) -> ...any,
|
||||
GetIDWithSeed: (...any) -> ...any,
|
||||
GetIO: () -> any,
|
||||
GetInputTextState: (...any) -> ...any,
|
||||
GetItemClickedCountWithSingleClickDelay: (mouse_button: number?, delay: number?) -> number,
|
||||
GetItemFlags: () -> number,
|
||||
GetItemID: () -> number,
|
||||
GetItemRectMax: () -> ImVec2,
|
||||
GetItemRectMin: () -> ImVec2,
|
||||
GetItemRectSize: () -> ImVec2,
|
||||
GetKeyChordName: (...any) -> ...any,
|
||||
GetKeyData: (...any) -> ...any,
|
||||
GetKeyMagnitude2d: (...any) -> ...any,
|
||||
GetKeyName: (key: number) -> any,
|
||||
GetKeyOwner: (...any) -> ...any,
|
||||
GetKeyOwnerData: (...any) -> ...any,
|
||||
GetKeyPressedAmount: (key: number, repeat_delay: number, repeat_rate: number) -> number,
|
||||
GetMainViewport: () -> any,
|
||||
GetMergedModsFromKeys: (...any) -> ...any,
|
||||
GetMetatables: (...any) -> ...any,
|
||||
GetMouseButtonFromPopupFlags: (...any) -> ...any,
|
||||
GetMouseClickedCount: (button: number) -> number,
|
||||
GetMouseCursor: () -> number,
|
||||
GetMouseDragDelta: (button: number?, lock_threshold: number?) -> ImVec2,
|
||||
GetMousePos: () -> ImVec2,
|
||||
GetMousePosOnOpeningCurrentPopup: () -> ImVec2,
|
||||
GetNavTweakPressedAmount: (...any) -> ...any,
|
||||
GetPlatformIO: () -> any,
|
||||
GetPopupAllowedExtentRect: (...any) -> ...any,
|
||||
GetRoundedFontSize: (...any) -> ...any,
|
||||
GetScale: (...any) -> ...any,
|
||||
GetScrollMaxX: () -> number,
|
||||
GetScrollMaxY: () -> number,
|
||||
GetScrollX: () -> number,
|
||||
GetScrollY: () -> number,
|
||||
GetShortcutRoutingData: (...any) -> ...any,
|
||||
GetStateStorage: () -> any,
|
||||
GetStyle: () -> any,
|
||||
GetStyleColorName: (idx: number) -> any,
|
||||
GetStyleColorVec4: (idx: number) -> ImVec4,
|
||||
GetStyleVarInfo: (...any) -> ...any,
|
||||
GetTextLineHeight: () -> number,
|
||||
GetTextLineHeightWithSpacing: () -> number,
|
||||
GetTime: () -> number,
|
||||
GetTopMostAndVisiblePopupModal: (...any) -> ...any,
|
||||
GetTopMostPopupModal: (...any) -> ...any,
|
||||
GetTreeNodeToLabelSpacing: () -> number,
|
||||
GetTypematicRepeatRate: (...any) -> ...any,
|
||||
GetVersion: () -> any,
|
||||
GetViewportPlatformMonitor: (...any) -> ...any,
|
||||
GetWindowAlwaysWantOwnTabBar: (...any) -> ...any,
|
||||
GetWindowAlwaysWantOwnViewport: (...any) -> ...any,
|
||||
GetWindowContentRegionMax: (...any) -> ...any,
|
||||
GetWindowContentRegionMin: (...any) -> ...any,
|
||||
GetWindowDockID: () -> number,
|
||||
GetWindowDpiScale: () -> number,
|
||||
GetWindowDrawList: () -> any,
|
||||
GetWindowHeight: () -> number,
|
||||
GetWindowPos: () -> ImVec2,
|
||||
GetWindowScrollbarID: (...any) -> ...any,
|
||||
GetWindowScrollbarRect: (...any) -> ...any,
|
||||
GetWindowSize: () -> ImVec2,
|
||||
GetWindowViewport: () -> any,
|
||||
GetWindowWidth: () -> number,
|
||||
Image: (tex_ref: any, image_size: ImVec2, uv0: ImVec2?, uv1: ImVec2?) -> (),
|
||||
ImageButton: (str_id: string, tex_ref: any, image_size: ImVec2, uv0: ImVec2?, uv1: ImVec2?, bg_col: ImVec4?, tint_col: ImVec4?) -> boolean,
|
||||
ImageButtonEx: (...any) -> ...any,
|
||||
ImageWithBg: (tex_ref: any, image_size: ImVec2, uv0: ImVec2?, uv1: ImVec2?, bg_col: ImVec4?, tint_col: ImVec4?) -> (),
|
||||
Indent: (indent_w: number?) -> (),
|
||||
Initialize: (...any) -> ...any,
|
||||
InputDouble: (label: string, v: number, step: number?, step_fast: number?, format: string?, flags: number?) -> (number, boolean),
|
||||
InputFloat: (label: string, v: number, step: number?, step_fast: number?, format: string?, flags: number?) -> (number, boolean),
|
||||
InputFloat2: (label: string, v: any, format: string?, flags: number?) -> boolean,
|
||||
InputFloat3: (label: string, v: any, format: string?, flags: number?) -> boolean,
|
||||
InputFloat4: (label: string, v: any, format: string?, flags: number?) -> boolean,
|
||||
InputInt: (label: string, v: number, step: number?, step_fast: number?, flags: number?) -> (number, boolean),
|
||||
InputInt2: (label: string, v: any, flags: number?) -> boolean,
|
||||
InputInt3: (label: string, v: any, flags: number?) -> boolean,
|
||||
InputInt4: (label: string, v: any, flags: number?) -> boolean,
|
||||
InputScalar: (label: string, data_type: number, data: any, step: any, step_fast: any, format: string?, flags: number?) -> ...any,
|
||||
InputScalarN: (label: string, data_type: number, data: any, components: number, step: any, step_fast: any, format: string?, flags: number?) -> ...any,
|
||||
InputText: (label: string, buf: any, buf_size: number, flags: number?, callback: any, user_data: any) -> ...any,
|
||||
InputTextDeactivateHook: (...any) -> ...any,
|
||||
InputTextEx: (...any) -> ...any,
|
||||
InputTextMultiline: (label: string, buf: any, buf_size: number, size: ImVec2?, flags: number?, callback: any, user_data: any) -> ...any,
|
||||
InputTextWithHint: (label: string, hint: string, buf: any, buf_size: number, flags: number?, callback: any, user_data: any) -> ...any,
|
||||
InvisibleButton: (str_id: string, size_arg: ImVec2, flags: number?) -> boolean,
|
||||
IsActiveIdUsingNavDir: (...any) -> ...any,
|
||||
IsAliasKey: (...any) -> ...any,
|
||||
IsAnyItemActive: () -> boolean,
|
||||
IsAnyItemFocused: () -> boolean,
|
||||
IsAnyItemHovered: () -> boolean,
|
||||
IsAnyMouseDown: () -> boolean,
|
||||
IsClippedEx: (...any) -> ...any,
|
||||
IsDragDropActive: (...any) -> ...any,
|
||||
IsDragDropPayloadBeingAccepted: (...any) -> ...any,
|
||||
IsGamepadKey: (...any) -> ...any,
|
||||
IsInNavFocusRoute: (...any) -> ...any,
|
||||
IsItemActivated: () -> boolean,
|
||||
IsItemActive: () -> boolean,
|
||||
IsItemClicked: (mouse_button: number?) -> boolean,
|
||||
IsItemDeactivated: () -> boolean,
|
||||
IsItemDeactivatedAfterEdit: () -> boolean,
|
||||
IsItemEdited: () -> boolean,
|
||||
IsItemFocused: () -> boolean,
|
||||
IsItemHovered: (flags: number?) -> boolean,
|
||||
IsItemToggledOpen: () -> boolean,
|
||||
IsItemToggledSelection: () -> boolean,
|
||||
IsItemVisible: () -> boolean,
|
||||
IsKeyChordPressed: (...any) -> ...any,
|
||||
IsKeyDown: (...any) -> ...any,
|
||||
IsKeyPressed: (key: number, is_repeat: boolean?) -> boolean,
|
||||
IsKeyPressedEx: (...any) -> ...any,
|
||||
IsKeyReleased: (...any) -> ...any,
|
||||
IsKeyboardKey: (...any) -> ...any,
|
||||
IsLRModKey: (...any) -> ...any,
|
||||
IsMouseClicked: (button: number, is_repeat: boolean?) -> boolean,
|
||||
IsMouseClickedEx: (...any) -> ...any,
|
||||
IsMouseDoubleClicked: (...any) -> ...any,
|
||||
IsMouseDown: (...any) -> ...any,
|
||||
IsMouseDragPastThreshold: (...any) -> ...any,
|
||||
IsMouseDragging: (button: number, lock_threshold: number?) -> boolean,
|
||||
IsMouseHoveringRect: (r_min: ImVec2, r_max: ImVec2, clip: boolean?) -> boolean,
|
||||
IsMouseKey: (...any) -> ...any,
|
||||
IsMousePosValid: (mouse_pos: any) -> boolean,
|
||||
IsMouseReleased: (...any) -> ...any,
|
||||
IsMouseReleasedWithDelay: (button: number, delay: number?) -> boolean,
|
||||
IsNamedKey: (...any) -> ...any,
|
||||
IsNamedKeyOrMod: (...any) -> ...any,
|
||||
IsPopupOpen: (id: string, popup_flags: number?) -> boolean,
|
||||
IsPopupOpenRequestForItem: (...any) -> ...any,
|
||||
IsPopupOpenRequestForWindow: (...any) -> ...any,
|
||||
IsRectVisible: (...any) -> ...any,
|
||||
IsViewportAbove: (...any) -> ...any,
|
||||
IsWindowAbove: (...any) -> ...any,
|
||||
IsWindowActiveAndVisible: (...any) -> ...any,
|
||||
IsWindowAppearing: () -> boolean,
|
||||
IsWindowChildOf: (...any) -> ...any,
|
||||
IsWindowCollapsed: () -> boolean,
|
||||
IsWindowContentHoverable: (...any) -> ...any,
|
||||
IsWindowDocked: () -> boolean,
|
||||
IsWindowFocused: (flags: number?) -> boolean,
|
||||
IsWindowHovered: (flags: number?) -> boolean,
|
||||
IsWindowInBeginStack: (...any) -> ...any,
|
||||
IsWindowNavFocusable: (...any) -> ...any,
|
||||
IsWindowWithinBeginStackOf: (...any) -> ...any,
|
||||
ItemAdd: (...any) -> ...any,
|
||||
ItemHandleShortcut: (...any) -> ...any,
|
||||
ItemHoverable: (...any) -> ...any,
|
||||
ItemSize: (...any) -> ...any,
|
||||
KeepAliveID: (...any) -> ...any,
|
||||
LabelText: (label: string, fmt: string, ...any) -> (),
|
||||
ListBox: (...any) -> ...any,
|
||||
LoadIniSettingsFromDisk: (ini_filename: string) -> (),
|
||||
LoadIniSettingsFromMemory: (ini_data: string, ini_size: number?) -> (),
|
||||
LocalizeGetMsg: (...any) -> ...any,
|
||||
LocalizeRegisterEntries: (...any) -> ...any,
|
||||
LogBegin: (...any) -> ...any,
|
||||
LogButtons: () -> (),
|
||||
LogFinish: () -> (),
|
||||
LogRenderedText: (...any) -> ...any,
|
||||
LogSetNextTextDecoration: (...any) -> ...any,
|
||||
LogText: (fmt: string, ...any) -> (),
|
||||
LogToBuffer: (...any) -> ...any,
|
||||
LogToClipboard: (auto_open_depth: number?) -> (),
|
||||
LogToFile: (auto_open_depth: number?, filename: string?) -> (),
|
||||
LogToTTY: (auto_open_depth: number?) -> (),
|
||||
MarkIniSettingsDirty: (...any) -> ...any,
|
||||
MarkItemEdited: (...any) -> ...any,
|
||||
MemAlloc: (...any) -> ...any,
|
||||
MemFree: (...any) -> ...any,
|
||||
MenuItem: (...any) -> ...any,
|
||||
MenuItemEx: (...any) -> ...any,
|
||||
MouseButtonToKey: (...any) -> ...any,
|
||||
NavApplyItemToResult: (...any) -> ...any,
|
||||
NavBiasScoringRect: (...any) -> ...any,
|
||||
NavCalcPreferredRefPos: (...any) -> ...any,
|
||||
NavCalcPreferredRefPosSource: (...any) -> ...any,
|
||||
NavClearPreferredPosForAxis: (...any) -> ...any,
|
||||
NavEndFrame: (...any) -> ...any,
|
||||
NavHighlightActivated: (...any) -> ...any,
|
||||
NavInitRequestApplyResult: (...any) -> ...any,
|
||||
NavInitWindow: (...any) -> ...any,
|
||||
NavMoveRequestApplyResult: (...any) -> ...any,
|
||||
NavMoveRequestButNoResultYet: (...any) -> ...any,
|
||||
NavMoveRequestCancel: (...any) -> ...any,
|
||||
NavMoveRequestForward: (...any) -> ...any,
|
||||
NavMoveRequestResolveWithLastItem: (...any) -> ...any,
|
||||
NavMoveRequestResolveWithPastTreeNode: (...any) -> ...any,
|
||||
NavMoveRequestSubmit: (...any) -> ...any,
|
||||
NavMoveRequestTryWrapping: (...any) -> ...any,
|
||||
NavProcessItem: (...any) -> ...any,
|
||||
NavProcessItemForTabbingRequest: (...any) -> ...any,
|
||||
NavRestoreLastChildNavWindow: (...any) -> ...any,
|
||||
NavRestoreLayer: (...any) -> ...any,
|
||||
NavSaveLastChildNavWindowIntoParent: (...any) -> ...any,
|
||||
NavScoreItem: (...any) -> ...any,
|
||||
NavUpdate: (...any) -> ...any,
|
||||
NavUpdateAnyRequestFlag: (...any) -> ...any,
|
||||
NavUpdateCancelRequest: (...any) -> ...any,
|
||||
NavUpdateContextMenuRequest: (...any) -> ...any,
|
||||
NavUpdateCreateMoveRequest: (...any) -> ...any,
|
||||
NavUpdateCreateTabbingRequest: (...any) -> ...any,
|
||||
NavUpdateCurrentWindowIsScrollPushableX: (...any) -> ...any,
|
||||
NavUpdatePageUpPageDown: (...any) -> ...any,
|
||||
NavUpdateWindowing: (...any) -> ...any,
|
||||
NavUpdateWindowingApplyFocus: (...any) -> ...any,
|
||||
NavUpdateWindowingOverlay: (...any) -> ...any,
|
||||
NavUpdateWindowingTarget: (...any) -> ...any,
|
||||
NewFrame: () -> (),
|
||||
NewLine: () -> (),
|
||||
NewTextBuffer: (str: string, size: number?) -> {number},
|
||||
NextColumn: () -> (),
|
||||
OpenPopup: (...any) -> ...any,
|
||||
OpenPopupEx: (...any) -> ...any,
|
||||
OpenPopupOnItemClick: (str_id: string?, popup_flags: number?) -> boolean,
|
||||
PayloadIsDataType: (...any) -> ...any,
|
||||
PlotEx: (...any) -> ...any,
|
||||
PlotHistogram: (...any) -> ...any,
|
||||
PlotLines: (...any) -> ...any,
|
||||
PopClipRect: () -> (),
|
||||
PopColumnsBackground: (...any) -> ...any,
|
||||
PopFocusScope: (...any) -> ...any,
|
||||
PopFont: () -> (),
|
||||
PopID: () -> (),
|
||||
PopItemFlag: () -> (),
|
||||
PopItemWidth: () -> (),
|
||||
PopPasswordFont: (...any) -> ...any,
|
||||
PopStyleColor: (count: number?) -> (),
|
||||
PopStyleVar: (count: number?) -> (),
|
||||
PopTextWrapPos: () -> (),
|
||||
ProgressBar: (fraction: number, size_arg: ImVec2?, overlay: string?) -> (),
|
||||
PushClipRect: (clip_rect_min: ImVec2, clip_rect_max: ImVec2, intersect_with_current_clip_rect: boolean) -> (),
|
||||
PushColumnClipRect: (...any) -> ...any,
|
||||
PushColumnsBackground: (...any) -> ...any,
|
||||
PushFocusScope: (...any) -> ...any,
|
||||
PushFont: (font: any, font_size_base: number) -> ...any,
|
||||
PushID: (...any) -> ...any,
|
||||
PushItemFlag: (option: number, enabled: boolean) -> (),
|
||||
PushItemWidth: (item_width: number) -> (),
|
||||
PushMultiItemsWidths: (...any) -> ...any,
|
||||
PushOverrideID: (...any) -> ...any,
|
||||
PushPasswordFont: (...any) -> ...any,
|
||||
PushStyleColor: (...any) -> ...any,
|
||||
PushStyleVar: (...any) -> ...any,
|
||||
PushStyleVarX: (idx: number, val_x: number) -> (),
|
||||
PushStyleVarY: (idx: number, val_y: number) -> (),
|
||||
PushTextWrapPos: (wrap_local_pos_x: number?) -> (),
|
||||
RadioButton: (...any) -> ...any,
|
||||
RadioButtonEx: (...any) -> ...any,
|
||||
RegisterFontAtlas: (...any) -> ...any,
|
||||
RemoveSettingsHandler: (...any) -> ...any,
|
||||
Render: () -> (),
|
||||
RenderArrow: (...any) -> ...any,
|
||||
RenderArrowDockMenu: (...any) -> ...any,
|
||||
RenderArrowPointingAt: (...any) -> ...any,
|
||||
RenderBullet: (...any) -> ...any,
|
||||
RenderCheckMark: (...any) -> ...any,
|
||||
RenderColorComponentMarker: (...any) -> ...any,
|
||||
RenderColorRectWithAlphaCheckerboard: (...any) -> ...any,
|
||||
RenderDimmedBackgroundBehindWindow: (...any) -> ...any,
|
||||
RenderDimmedBackgrounds: (...any) -> ...any,
|
||||
RenderDragDropTargetRectEx: (...any) -> ...any,
|
||||
RenderDragDropTargetRectForItem: (...any) -> ...any,
|
||||
RenderDragDropTargetRectForViewport: (...any) -> ...any,
|
||||
RenderFrame: (...any) -> ...any,
|
||||
RenderFrameBorder: (...any) -> ...any,
|
||||
RenderMouseCursor: (...any) -> ...any,
|
||||
RenderNavCursor: (...any) -> ...any,
|
||||
RenderPlatformWindowsDefault: (platform_render_arg: any, renderer_render_arg: any) -> ...any,
|
||||
RenderRectFilledInRangeH: (...any) -> ...any,
|
||||
RenderRectFilledWithHole: (...any) -> ...any,
|
||||
RenderText: (...any) -> ...any,
|
||||
RenderTextClipped: (...any) -> ...any,
|
||||
RenderTextClippedEx: (...any) -> ...any,
|
||||
RenderTextEllipsis: (...any) -> ...any,
|
||||
RenderTextWrapped: (...any) -> ...any,
|
||||
RenderViewportsThumbnails: (...any) -> ...any,
|
||||
ResetMouseDragDelta: (button: number?) -> (),
|
||||
RoundScalarWithFormatT: (...any) -> ...any,
|
||||
SameLine: (offset_from_start_x: number?, spacing_w: number?) -> (),
|
||||
SaveIniSettingsToDisk: (ini_filename: string) -> (),
|
||||
SaveIniSettingsToMemory: (...any) -> ...any,
|
||||
ScaleRatioFromValueT: (...any) -> ...any,
|
||||
ScaleValueFromRatioT: (...any) -> ...any,
|
||||
ScaleWindowsInViewport: (...any) -> ...any,
|
||||
ScrollToItem: (...any) -> ...any,
|
||||
ScrollToRect: (...any) -> ...any,
|
||||
ScrollToRectEx: (...any) -> ...any,
|
||||
Scrollbar: (...any) -> ...any,
|
||||
ScrollbarEx: (...any) -> ...any,
|
||||
Selectable: (...any) -> ...any,
|
||||
Separator: () -> (),
|
||||
SeparatorEx: (...any) -> ...any,
|
||||
SeparatorText: (label: string) -> (),
|
||||
SeparatorTextEx: (...any) -> ...any,
|
||||
SetActiveID: (...any) -> ...any,
|
||||
SetActiveIdUsingAllKeyboardKeys: (...any) -> ...any,
|
||||
SetAllocatorFunctions: (alloc_func: any, free_func: any, user_data: any) -> ...any,
|
||||
SetClipboardText: (text: string) -> (),
|
||||
SetColorEditOptions: (...any) -> ...any,
|
||||
SetColumnOffset: (column_index: number, offset: number) -> (),
|
||||
SetColumnWidth: (column_index: number, width: number) -> (),
|
||||
SetCurrentContext: (ctx: any) -> ...any,
|
||||
SetCurrentFont: (...any) -> ...any,
|
||||
SetCurrentViewport: (...any) -> ...any,
|
||||
SetCursorPos: (local_pos: ImVec2) -> (),
|
||||
SetCursorPosX: (x: number) -> (),
|
||||
SetCursorPosY: (y: number) -> (),
|
||||
SetCursorScreenPos: (pos: ImVec2) -> (),
|
||||
SetDragDropPayload: (type: string, data: any, data_size: number, cond: number?) -> boolean,
|
||||
SetFocusID: (...any) -> ...any,
|
||||
SetHoveredID: (...any) -> ...any,
|
||||
SetItemDefaultFocus: () -> (),
|
||||
SetItemKeyOwner: (...any) -> ...any,
|
||||
SetItemTooltip: (fmt: string, ...any) -> (),
|
||||
SetKeyOwner: (...any) -> ...any,
|
||||
SetKeyOwnersForKeyChord: (...any) -> ...any,
|
||||
SetKeyboardFocusHere: (offset: number?) -> (),
|
||||
SetLastItemData: (...any) -> ...any,
|
||||
SetLastItemDataForChildWindowItem: (...any) -> ...any,
|
||||
SetLastItemDataForWindow: (...any) -> ...any,
|
||||
SetMouseCursor: (cursor_type: number) -> (),
|
||||
SetNavCursorVisible: (visible: boolean) -> (),
|
||||
SetNavCursorVisibleAfterMove: (...any) -> ...any,
|
||||
SetNavFocusScope: (...any) -> ...any,
|
||||
SetNavID: (...any) -> ...any,
|
||||
SetNavWindow: (...any) -> ...any,
|
||||
SetNextFrameWantCaptureKeyboard: (want: boolean) -> (),
|
||||
SetNextFrameWantCaptureMouse: (want: boolean) -> (),
|
||||
SetNextItemAllowOverlap: () -> (),
|
||||
SetNextItemColorMarker: (...any) -> ...any,
|
||||
SetNextItemOpen: (is_open: boolean, cond: number?) -> (),
|
||||
SetNextItemRefVal: (...any) -> ...any,
|
||||
SetNextItemShortcut: (key_chord: any, flags: number?) -> (),
|
||||
SetNextItemStorageID: (storage_id: number) -> (),
|
||||
SetNextItemWidth: (item_width: number) -> (),
|
||||
SetNextWindowBgAlpha: (alpha: number) -> (),
|
||||
SetNextWindowCached: (key: any) -> (),
|
||||
SetNextWindowChildFlags: (...any) -> ...any,
|
||||
SetNextWindowClass: (window_class: any) -> (),
|
||||
SetNextWindowCollapsed: (collapsed: boolean, cond: number?) -> (),
|
||||
SetNextWindowContentSize: (size: ImVec2) -> (),
|
||||
SetNextWindowDockID: (id: number, cond: number?) -> (),
|
||||
SetNextWindowFlags: (...any) -> ...any,
|
||||
SetNextWindowFocus: () -> (),
|
||||
SetNextWindowPos: (pos: ImVec2, cond: number?, pivot: ImVec2?) -> (),
|
||||
SetNextWindowRefreshPolicy: (...any) -> ...any,
|
||||
SetNextWindowScroll: (scroll: ImVec2) -> (),
|
||||
SetNextWindowSize: (size: ImVec2, cond: number?) -> (),
|
||||
SetNextWindowSizeConstraints: (size_min: ImVec2, size_max: ImVec2, custom_callback: any, custom_callback_user_data: any) -> ...any,
|
||||
SetNextWindowViewport: (id: number) -> (),
|
||||
SetScrollFromPosX: (...any) -> ...any,
|
||||
SetScrollFromPosY: (...any) -> ...any,
|
||||
SetScrollHereX: (center_x_ratio: number?) -> (),
|
||||
SetScrollHereY: (center_y_ratio: number?) -> (),
|
||||
SetScrollX: (...any) -> ...any,
|
||||
SetScrollY: (...any) -> ...any,
|
||||
SetShortcutRouting: (...any) -> ...any,
|
||||
SetStateStorage: (tree: any) -> ...any,
|
||||
SetTabItemClosed: (label: string) -> (),
|
||||
SetTooltip: (fmt: string, ...any) -> (),
|
||||
SetWindowClipRectBeforeSetChannel: (...any) -> ...any,
|
||||
SetWindowCollapsed: (...any) -> ...any,
|
||||
SetWindowDock: (...any) -> ...any,
|
||||
SetWindowFocus: (...any) -> ...any,
|
||||
SetWindowFontScale: (...any) -> ...any,
|
||||
SetWindowHiddenAndSkipItemsForCurrentFrame: (...any) -> ...any,
|
||||
SetWindowHitTestHole: (...any) -> ...any,
|
||||
SetWindowPos: (...any) -> ...any,
|
||||
SetWindowSize: (...any) -> ...any,
|
||||
SetWindowViewport: (...any) -> ...any,
|
||||
ShadeVertsLinearColorGradientKeepAlpha: (...any) -> ...any,
|
||||
ShadeVertsLinearUV: (...any) -> ...any,
|
||||
ShadeVertsTransformPos: (...any) -> ...any,
|
||||
Shortcut: (...any) -> ...any,
|
||||
ShowAboutWindow: (p_open: boolean?) -> ...any,
|
||||
ShowDebugLogWindow: (p_open: boolean?) -> ...any,
|
||||
ShowDemoWindow: (p_open: boolean?) -> ...any,
|
||||
ShowFontAtlas: (...any) -> ...any,
|
||||
ShowFontSelector: (label: string) -> (),
|
||||
ShowIDStackToolWindow: (p_open: boolean?) -> ...any,
|
||||
ShowMetricsWindow: (p_open: boolean?) -> ...any,
|
||||
ShowStyleEditor: (ref: any) -> ...any,
|
||||
ShowStyleSelector: (label: string) -> boolean,
|
||||
ShowUserGuide: () -> (),
|
||||
ShrinkWidths: (...any) -> ...any,
|
||||
Shutdown: (...any) -> ...any,
|
||||
SliderAngle: (label: string, v_rad: number, v_degrees_min: number?, v_degrees_max: number?, format: string?, flags: number?) -> (number, boolean),
|
||||
SliderBehavior: (...any) -> ...any,
|
||||
SliderBehaviorT: (...any) -> ...any,
|
||||
SliderFloat: (label: string, v: number, v_min: number, v_max: number, format: string?, flags: number?) -> (number, boolean),
|
||||
SliderFloat2: (label: string, v: any, v_min: number, v_max: number, format: string?, flags: number?) -> boolean,
|
||||
SliderFloat3: (label: string, v: any, v_min: number, v_max: number, format: string?, flags: number?) -> boolean,
|
||||
SliderFloat4: (label: string, v: any, v_min: number, v_max: number, format: string?, flags: number?) -> boolean,
|
||||
SliderInt: (label: string, v: number, v_min: number, v_max: number, format: string?, flags: number?) -> (number, boolean),
|
||||
SliderInt2: (label: string, v: any, v_min: number, v_max: number, format: string?, flags: number?) -> boolean,
|
||||
SliderInt3: (label: string, v: any, v_min: number, v_max: number, format: string?, flags: number?) -> boolean,
|
||||
SliderInt4: (label: string, v: any, v_min: number, v_max: number, format: string?, flags: number?) -> boolean,
|
||||
SliderScalar: (label: string, data_type: number, data: any, min: any, max: any, format: string?, flags: number?) -> ...any,
|
||||
SliderScalarN: (label: string, data_type: number, v: any, components: number, v_min: any, v_max: any, format: string?, flags: number?) -> ...any,
|
||||
SmallButton: (label: string) -> boolean,
|
||||
Spacing: () -> (),
|
||||
SplitterBehavior: (...any) -> ...any,
|
||||
StartMouseMovingWindow: (...any) -> ...any,
|
||||
StartMouseMovingWindowOrNode: (...any) -> ...any,
|
||||
StopMouseMovingWindow: (...any) -> ...any,
|
||||
StyleColorsClassic: (dst: any) -> ...any,
|
||||
StyleColorsDark: (dst: any) -> ...any,
|
||||
StyleColorsLight: (dst: any) -> ...any,
|
||||
TabBarAddTab: (...any) -> ...any,
|
||||
TabBarCalcMaxTabWidth: (...any) -> ...any,
|
||||
TabBarCalcTabID: (...any) -> ...any,
|
||||
TabBarCloseTab: (...any) -> ...any,
|
||||
TabBarFindByID: (...any) -> ...any,
|
||||
TabBarFindMostRecentlySelectedTabForActiveWindow: (...any) -> ...any,
|
||||
TabBarFindTabByID: (...any) -> ...any,
|
||||
TabBarFindTabByOrder: (...any) -> ...any,
|
||||
TabBarGetCurrentTab: (...any) -> ...any,
|
||||
TabBarGetTabName: (...any) -> ...any,
|
||||
TabBarGetTabOrder: (...any) -> ...any,
|
||||
TabBarGetTabPos: (...any) -> ...any,
|
||||
TabBarLayout: (...any) -> ...any,
|
||||
TabBarProcessReorder: (...any) -> ...any,
|
||||
TabBarQueueFocus: (...any) -> ...any,
|
||||
TabBarQueueReorder: (...any) -> ...any,
|
||||
TabBarQueueReorderFromMousePos: (...any) -> ...any,
|
||||
TabBarRemove: (...any) -> ...any,
|
||||
TabBarRemoveTab: (...any) -> ...any,
|
||||
TabBarScrollClamp: (...any) -> ...any,
|
||||
TabBarScrollToTab: (...any) -> ...any,
|
||||
TabBarScrollingButtons: (...any) -> ...any,
|
||||
TabBarTabListPopupButton: (...any) -> ...any,
|
||||
TabItemBackground: (...any) -> ...any,
|
||||
TabItemButton: (label: string, flags: number?) -> boolean,
|
||||
TabItemCalcSize: (...any) -> ...any,
|
||||
TabItemEx: (...any) -> ...any,
|
||||
TabItemLabelAndCloseButton: (...any) -> ...any,
|
||||
TabItemSpacing: (...any) -> ...any,
|
||||
TableAngledHeadersRow: () -> (),
|
||||
TableAngledHeadersRowEx: (...any) -> ...any,
|
||||
TableApplyExternalUnclipRect: (...any) -> ...any,
|
||||
TableApplyQueuedRequests: (...any) -> ...any,
|
||||
TableBeginCell: (...any) -> ...any,
|
||||
TableBeginContextMenuPopup: (...any) -> ...any,
|
||||
TableBeginInitMemory: (...any) -> ...any,
|
||||
TableBeginRow: (...any) -> ...any,
|
||||
TableCalcMaxColumnWidth: (...any) -> ...any,
|
||||
TableDrawBorders: (...any) -> ...any,
|
||||
TableDrawDefaultContextMenu: (...any) -> ...any,
|
||||
TableEndCell: (...any) -> ...any,
|
||||
TableEndRow: (...any) -> ...any,
|
||||
TableFindByID: (...any) -> ...any,
|
||||
TableFixColumnSortDirection: (...any) -> ...any,
|
||||
TableFixDisplayOrder: (...any) -> ...any,
|
||||
TableGcCompactSettings: (...any) -> ...any,
|
||||
TableGcCompactTransientBuffers: (...any) -> ...any,
|
||||
TableGetBoundSettings: (...any) -> ...any,
|
||||
TableGetCellBgRect: (...any) -> ...any,
|
||||
TableGetColumnCount: () -> number,
|
||||
TableGetColumnFlags: (column_n: number?) -> number,
|
||||
TableGetColumnIndex: () -> number,
|
||||
TableGetColumnName: (...any) -> ...any,
|
||||
TableGetColumnNextSortDirection: (...any) -> ...any,
|
||||
TableGetColumnResizeID: (...any) -> ...any,
|
||||
TableGetColumnWidthAuto: (...any) -> ...any,
|
||||
TableGetHeaderAngledMaxLabelWidth: (...any) -> ...any,
|
||||
TableGetHeaderRowHeight: (...any) -> ...any,
|
||||
TableGetHoveredColumn: () -> number,
|
||||
TableGetHoveredRow: (...any) -> ...any,
|
||||
TableGetInstanceData: (...any) -> ...any,
|
||||
TableGetInstanceID: (...any) -> ...any,
|
||||
TableGetRowIndex: () -> number,
|
||||
TableGetSortSpecs: () -> any,
|
||||
TableHeader: (label: string) -> (),
|
||||
TableHeadersRow: () -> (),
|
||||
TableInitColumnDefaults: (...any) -> ...any,
|
||||
TableLoadSettings: (...any) -> ...any,
|
||||
TableLoadSettingsForColumn: (...any) -> ...any,
|
||||
TableLoadSettingsForColumns: (...any) -> ...any,
|
||||
TableMergeDrawChannels: (...any) -> ...any,
|
||||
TableNextColumn: () -> boolean,
|
||||
TableNextRow: (row_flags: number?, row_min_height: number?) -> (),
|
||||
TableOpenContextMenu: (...any) -> ...any,
|
||||
TablePopBackgroundChannel: (...any) -> ...any,
|
||||
TablePopColumnChannel: (...any) -> ...any,
|
||||
TablePushBackgroundChannel: (...any) -> ...any,
|
||||
TablePushColumnChannel: (...any) -> ...any,
|
||||
TableQueueSetColumnDisplayOrder: (...any) -> ...any,
|
||||
TableReconcileColumns: (...any) -> ...any,
|
||||
TableRemove: (...any) -> ...any,
|
||||
TableResetSettings: (...any) -> ...any,
|
||||
TableSaveSettings: (...any) -> ...any,
|
||||
TableSetBgColor: (target: number, color: number, column_n: number?) -> (),
|
||||
TableSetColumnDisplayOrder: (...any) -> ...any,
|
||||
TableSetColumnEnabled: (column_n: number, enabled: boolean) -> (),
|
||||
TableSetColumnIndex: (column_n: number) -> boolean,
|
||||
TableSetColumnSortDirection: (...any) -> ...any,
|
||||
TableSetColumnWidth: (...any) -> ...any,
|
||||
TableSetColumnWidthAutoAll: (...any) -> ...any,
|
||||
TableSetColumnWidthAutoSingle: (...any) -> ...any,
|
||||
TableSettingsAddSettingsHandler: (...any) -> ...any,
|
||||
TableSettingsCreate: (...any) -> ...any,
|
||||
TableSettingsFindByID: (...any) -> ...any,
|
||||
TableSetupColumn: (label: string, flags: number?, init_width_or_weight: number?, user_data: number?) -> (),
|
||||
TableSetupDrawChannels: (...any) -> ...any,
|
||||
TableSetupScrollFreeze: (columns: number, rows: number) -> (),
|
||||
TableSortSpecsBuild: (...any) -> ...any,
|
||||
TableSortSpecsSanitize: (...any) -> ...any,
|
||||
TableUpdateBorders: (...any) -> ...any,
|
||||
TableUpdateColumnsWeightFromWidth: (...any) -> ...any,
|
||||
TableUpdateLayout: (...any) -> ...any,
|
||||
TeleportMousePos: (...any) -> ...any,
|
||||
TempInputIsActive: (...any) -> ...any,
|
||||
TempInputScalar: (...any) -> ...any,
|
||||
TempInputText: (...any) -> ...any,
|
||||
TestKeyOwner: (...any) -> ...any,
|
||||
Text: (fmt: string, ...any) -> (),
|
||||
TextAligned: (...any) -> ...any,
|
||||
TextBufferToString: (buf: {number}) -> string,
|
||||
TextColored: (col: ImVec4, fmt: string, ...any) -> (),
|
||||
TextDisabled: (fmt: string, ...any) -> (),
|
||||
TextEx: (...any) -> ...any,
|
||||
TextLink: (label: string) -> boolean,
|
||||
TextLinkOpenURL: (label: string, url: string?) -> boolean,
|
||||
TextUnformatted: (text: string, text_end: string?) -> (),
|
||||
TextV: (fmt: string, ...any) -> (),
|
||||
TextWrapped: (fmt: string, ...any) -> (),
|
||||
TranslateWindow: (...any) -> ...any,
|
||||
TranslateWindowsInViewport: (...any) -> ...any,
|
||||
TreeNode: (...any) -> ...any,
|
||||
TreeNodeBehavior: (...any) -> ...any,
|
||||
TreeNodeDrawLineToChildNode: (...any) -> ...any,
|
||||
TreeNodeDrawLineToTreePop: (...any) -> ...any,
|
||||
TreeNodeEx: (...any) -> ...any,
|
||||
TreeNodeExV: (...any) -> ...any,
|
||||
TreeNodeGetOpen: (storage_id: number) -> boolean,
|
||||
TreeNodeSetOpen: (...any) -> ...any,
|
||||
TreeNodeUpdateNextOpen: (...any) -> ...any,
|
||||
TreeNodeV: (...any) -> ...any,
|
||||
TreePop: () -> (),
|
||||
TreePush: (...any) -> ...any,
|
||||
TreePushOverrideID: (...any) -> ...any,
|
||||
Unindent: (indent_w: number?) -> (),
|
||||
UnregisterFontAtlas: (...any) -> ...any,
|
||||
UpdateAliasKey: (...any) -> ...any,
|
||||
UpdateCurrentFontSize: (...any) -> ...any,
|
||||
UpdateDebugToolItemPathQuery: (...any) -> ...any,
|
||||
UpdateFontsEndFrame: (...any) -> ...any,
|
||||
UpdateFontsNewFrame: (...any) -> ...any,
|
||||
UpdateHoveredWindowAndCaptureFlags: (...any) -> ...any,
|
||||
UpdateInputEvents: (...any) -> ...any,
|
||||
UpdateKeyRoutingTable: (...any) -> ...any,
|
||||
UpdateKeyboardInputs: (...any) -> ...any,
|
||||
UpdateMouseInputs: (...any) -> ...any,
|
||||
UpdateMouseMovingWindowEndFrame: (...any) -> ...any,
|
||||
UpdateMouseMovingWindowNewFrame: (...any) -> ...any,
|
||||
UpdateMouseWheel: (...any) -> ...any,
|
||||
UpdatePlatformWindows: () -> (),
|
||||
UpdateSettings: (...any) -> ...any,
|
||||
UpdateTexturesEndFrame: (...any) -> ...any,
|
||||
UpdateTexturesNewFrame: (...any) -> ...any,
|
||||
UpdateTryMergeWindowIntoHostViewport: (...any) -> ...any,
|
||||
UpdateTryMergeWindowIntoHostViewports: (...any) -> ...any,
|
||||
UpdateViewportPlatformMonitor: (...any) -> ...any,
|
||||
UpdateViewportsEndFrame: (...any) -> ...any,
|
||||
UpdateViewportsNewFrame: (...any) -> ...any,
|
||||
UpdateWindowInFocusOrderList: (...any) -> ...any,
|
||||
UpdateWindowParentAndRootLinks: (...any) -> ...any,
|
||||
UpdateWindowSkipRefresh: (...any) -> ...any,
|
||||
VSliderFloat: (label: string, size: ImVec2, v: number, v_min: number, v_max: number, format: string?, flags: number?) -> (number, boolean),
|
||||
VSliderInt: (label: string, size: ImVec2, v: number, v_min: number, v_max: number, format: string?, flags: number?) -> (number, boolean),
|
||||
VSliderScalar: (label: string, size: ImVec2, data_type: number, data: any, min: any, max: any, format: string?, flags: number?) -> ...any,
|
||||
Value: (...any) -> ...any,
|
||||
WindowPosAbsToRel: (...any) -> ...any,
|
||||
WindowRectAbsToRel: (...any) -> ...any,
|
||||
WindowRectRelToAbs: (...any) -> ...any,
|
||||
WindowSelectViewport: (...any) -> ...any,
|
||||
WindowSettingsAddSettingsHandler: (...any) -> ...any,
|
||||
WindowSyncOwnedViewport: (...any) -> ...any,
|
||||
_ByteArrayToString: (...any) -> ...any,
|
||||
_GetTypeFunc: (...any) -> ...any,
|
||||
_SetCurrentContext_Internal: (...any) -> ...any,
|
||||
_SetCurrentContext_Tables: (...any) -> ...any,
|
||||
_SetCurrentContext_Widgets: (...any) -> ...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 ImDrawListFlags = { None: number, AntiAliasedLines: number, AntiAliasedLinesUseTex: number, AntiAliasedFill: number, AllowVtxOffset: number, TextNoPixelSnap: 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 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 ImGuiChildFlags = { None: number, Borders: number, AlwaysUseWindowPadding: number, ResizeX: number, ResizeY: number, AutoResizeX: number, AutoResizeY: number, AlwaysAutoResize: number, FrameStyle: number, NavFlattened: number, ResizeBoth: number, ResizeXAndY: number, [string]: number }
|
||||
export type ImGuiCol = { Text: number, TextDisabled: number, WindowBg: number, ChildBg: number, PopupBg: number, Border: number, BorderShadow: number, FrameBg: number, FrameBgHovered: number, FrameBgActive: number, TitleBg: number, TitleBgActive: number, TitleBgCollapsed: number, MenuBarBg: number, ScrollbarBg: number, ScrollbarGrab: number, ScrollbarGrabHovered: number, ScrollbarGrabActive: number, CheckMark: number, CheckboxSelectedBg: number, SliderGrab: number, SliderGrabActive: number, Button: number, ButtonHovered: number, ButtonActive: number, Header: number, HeaderHovered: number, HeaderActive: number, Separator: number, SeparatorHovered: number, SeparatorActive: number, ResizeGrip: number, ResizeGripHovered: number, ResizeGripActive: number, InputTextCursor: number, TabHovered: number, Tab: number, TabSelected: number, TabSelectedOverline: number, TabDimmed: number, TabDimmedSelected: number, TabDimmedSelectedOverline: number, DockingPreview: number, DockingEmptyBg: number, PlotLines: number, PlotLinesHovered: number, PlotHistogram: number, PlotHistogramHovered: number, TableHeaderBg: number, TableBorderStrong: number, TableBorderLight: number, TableRowBg: number, TableRowBgAlt: number, TextLink: number, TextSelectedBg: number, TreeLines: number, DragDropTarget: number, DragDropTargetBg: number, UnsavedMarker: number, NavCursor: number, NavWindowingHighlight: number, NavWindowingDimBg: number, ModalWindowDimBg: number, COUNT: number, [string]: number }
|
||||
export type ImGuiColorEditFlags = { None: number, NoAlpha: number, NoPicker: number, NoOptions: number, NoSmallPreview: number, NoInputs: number, NoTooltip: number, NoLabel: number, NoSidePreview: number, NoDragDrop: number, NoBorder: number, NoColorMarkers: number, AlphaOpaque: number, AlphaNoBg: number, AlphaPreviewHalf: number, AlphaBar: number, HDR: number, DisplayRGB: number, DisplayHSV: number, DisplayHex: number, Uint8: number, Float: number, PickerHueBar: number, PickerHueWheel: number, PickerNoRotate: number, InputRGB: number, InputHSV: number, DefaultOptions_: number, AlphaMask_: number, DisplayMask_: number, DataTypeMask_: number, PickerMask_: number, InputMask_: number, [string]: number }
|
||||
export type ImGuiComboFlags = { None: number, PopupAlignLeft: number, HeightSmall: number, HeightRegular: number, HeightLarge: number, HeightLargest: number, NoArrowButton: number, NoPreview: number, WidthFitPreview: number, HeightMask_: number, CustomPreview: number, [string]: number }
|
||||
export type ImGuiCond = { None: number, Always: number, Once: number, FirstUseEver: number, Appearing: number, [string]: number }
|
||||
export type ImGuiConfigFlags = { None: number, NavEnableKeyboard: number, NavEnableGamepad: number, NoMouse: number, NoMouseCursorChange: number, NoKeyboard: number, DockingEnable: number, ViewportsEnable: number, IsSRGB: number, IsTouchScreen: number, [string]: number }
|
||||
export type ImGuiDragDropFlags = { None: number, SourceNoPreviewTooltip: number, SourceNoDisableHover: number, SourceNoHoldToOpenOthers: number, SourceAllowNullID: number, SourceExtern: number, PayloadAutoExpire: number, PayloadNoCrossContext: number, PayloadNoCrossProcess: number, AcceptBeforeDelivery: number, AcceptNoDrawDefaultRect: number, AcceptNoPreviewTooltip: number, AcceptDrawAsHovered: number, AcceptPeekOnly: number, [string]: number }
|
||||
export type ImGuiFocusedFlags = { None: number, ChildWindows: number, RootWindow: number, AnyWindow: number, NoPopupHierarchy: number, DockHierarchy: number, RootAndChildWindows: number, [string]: number }
|
||||
export type ImGuiHoveredFlags = { None: number, ChildWindows: number, RootWindow: number, AnyWindow: number, NoPopupHierarchy: number, DockHierarchy: number, AllowWhenBlockedByPopup: number, AllowWhenBlockedByActiveItem: number, AllowWhenOverlappedByItem: number, AllowWhenOverlappedByWindow: number, AllowWhenDisabled: number, NoNavOverride: number, ForTooltip: number, Stationary: number, DelayNone: number, DelayShort: number, DelayNormal: number, NoSharedDelay: number, AllowWhenOverlapped: number, RectOnly: number, RootAndChildWindows: number, DelayMask_: number, AllowedMaskForIsWindowHovered: number, AllowedMaskForIsItemHovered: number, [string]: number }
|
||||
export type ImGuiInputFlags = { None: number, Repeat: number, RouteActive: number, RouteFocused: number, RouteGlobal: number, RouteAlways: number, RouteOverFocused: number, RouteOverActive: number, RouteUnlessBgFocused: number, RouteFromRootWindow: number, Tooltip: number, RepeatRateDefault: number, RepeatRateNavMove: number, RepeatRateNavTweak: number, RepeatUntilRelease: number, RepeatUntilKeyModsChange: number, RepeatUntilKeyModsChangeFromNone: number, RepeatUntilOtherKeyPress: number, LockThisFrame: number, LockUntilRelease: number, CondHovered: number, CondActive: number, CondDefault_: number, RepeatRateMask_: number, RepeatUntilMask_: number, RepeatMask_: number, CondMask_: number, RouteTypeMask_: number, RouteOptionsMask_: number, SupportedByIsKeyPressed: number, SupportedByIsMouseClicked: number, SupportedByShortcut: number, SupportedBySetNextItemShortcut: number, SupportedBySetKeyOwner: number, SupportedBySetItemKeyOwner: number, [string]: number }
|
||||
export type ImGuiInputTextFlags = { None: number, CharsDecimal: number, CharsHexadecimal: number, CharsScientific: number, CharsUppercase: number, CharsNoBlank: number, AllowTabInput: number, EnterReturnsTrue: number, EscapeClearsAll: number, CtrlEnterForNewLine: number, ReadOnly: number, Password: number, AlwaysOverwrite: number, AutoSelectAll: number, ParseEmptyRefVal: number, DisplayEmptyRefVal: number, NoHorizontalScroll: number, NoUndoRedo: number, ElideLeft: number, CallbackCompletion: number, CallbackHistory: number, CallbackAlways: number, CallbackCharFilter: number, CallbackResize: number, CallbackEdit: number, WordWrap: number, Multiline: number, TempInput: number, LocalizeDecimalPoint: 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 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 ImGuiMouseSource = { Mouse: number, TouchScreen: number, Pen: number, COUNT: 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 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 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 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 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 ImGuiModule = {
|
||||
ImGui: ImGuiAPI,
|
||||
ImVec2: (x: number?, y: number?, z: number?, w: number?) -> ImVec2,
|
||||
ImVec4: (x: number?, y: number?, z: number?, w: number?) -> ImVec4,
|
||||
ImDrawFlags: ImDrawFlags,
|
||||
ImDrawListFlags: ImDrawListFlags,
|
||||
ImFontFlags: ImFontFlags,
|
||||
ImGuiBackendFlags: ImGuiBackendFlags,
|
||||
ImGuiButtonFlags: ImGuiButtonFlags,
|
||||
ImGuiChildFlags: ImGuiChildFlags,
|
||||
ImGuiCol: ImGuiCol,
|
||||
ImGuiColorEditFlags: ImGuiColorEditFlags,
|
||||
ImGuiComboFlags: ImGuiComboFlags,
|
||||
ImGuiCond: ImGuiCond,
|
||||
ImGuiConfigFlags: ImGuiConfigFlags,
|
||||
ImGuiDragDropFlags: ImGuiDragDropFlags,
|
||||
ImGuiFocusedFlags: ImGuiFocusedFlags,
|
||||
ImGuiHoveredFlags: ImGuiHoveredFlags,
|
||||
ImGuiInputFlags: ImGuiInputFlags,
|
||||
ImGuiInputTextFlags: ImGuiInputTextFlags,
|
||||
ImGuiItemFlags: ImGuiItemFlags,
|
||||
ImGuiItemStatusFlags: ImGuiItemStatusFlags,
|
||||
ImGuiKey: ImGuiKey,
|
||||
ImGuiMouseSource: ImGuiMouseSource,
|
||||
ImGuiNextItemDataFlags: ImGuiNextItemDataFlags,
|
||||
ImGuiPopupFlags: ImGuiPopupFlags,
|
||||
ImGuiSelectableFlags: ImGuiSelectableFlags,
|
||||
ImGuiSliderFlags: ImGuiSliderFlags,
|
||||
ImGuiStyleVar: ImGuiStyleVar,
|
||||
ImGuiTreeNodeFlags: ImGuiTreeNodeFlags,
|
||||
ImGuiViewportFlags: ImGuiViewportFlags,
|
||||
ImGuiWindowFlags: ImGuiWindowFlags,
|
||||
[string]: any,
|
||||
}
|
||||
|
||||
return (require(script:WaitForChild("Impl")) :: any) :: ImGuiModule
|
||||
@@ -1 +1 @@
|
||||
[[149, "imgui.lua"], [18609, "imgui_demo.lua"], [25894, "imgui_draw.lua"], [31132, "imgui_h.lua"], [33330, "imgui_impl_love.lua"], [33870, "imgui_internal.lua"], [37042, "imgui_tables.lua"], [41389, "imgui_widgets.lua"], [51144, "imstb_rectpack.lua"], [51590, "imstb_textedit.lua"], [52831, "imstb_truetype.lua"], [55299, "imstd_minstdio.lua"]]
|
||||
[[149, "imgui.lua"], [18647, "imgui_demo.lua"], [25932, "imgui_draw.lua"], [31170, "imgui_h.lua"], [33368, "imgui_impl_love.lua"], [33908, "imgui_internal.lua"], [37084, "imgui_tables.lua"], [41431, "imgui_widgets.lua"], [51186, "imstb_rectpack.lua"], [51632, "imstb_textedit.lua"], [52873, "imstb_truetype.lua"], [55341, "imstd_minstdio.lua"]]
|
||||
+43
-1
@@ -8994,6 +8994,26 @@ function ImGui.UpdateWindowSkipRefresh(window)
|
||||
end
|
||||
|
||||
if bit32.band(g.NextWindowData.RefreshFlagsVal, ImGuiWindowRefreshFlags.TryToAvoidRefresh) ~= 0 then
|
||||
-- [Port] SetNextWindowCached(): refresh on any change since the last refresh (and one frame after being busy)
|
||||
if g.NextWindowData.CacheKeySet then
|
||||
local function related(w) return w ~= nil and (w.RootWindow == window.RootWindow or ImGui.IsWindowWithinBeginStackOf(w.RootWindow, window)) end
|
||||
local busy = window.Appearing or window.Hidden or window.DockIsActive or related(g.HoveredWindow) or related(g.NavWindow) or related(g.ActiveIdWindow) or (g.MovingWindow ~= nil and related(g.MovingWindow))
|
||||
local c, key, ds, tex = window.CacheSnap, g.NextWindowData.CacheKeyVal, g.IO.DisplaySize, g.IO.Fonts.TexData
|
||||
if busy or c == nil or c.Busy or c.Key ~= key or c.Tex ~= tex or c.Collapsed ~= window.Collapsed
|
||||
or c.PosX ~= window.Pos.x or c.PosY ~= window.Pos.y or c.SizeX ~= window.SizeFull.x or c.SizeY ~= window.SizeFull.y
|
||||
or c.ScrollX ~= window.Scroll.x or c.ScrollY ~= window.Scroll.y or window.ScrollTarget.x < FLT_MAX or window.ScrollTarget.y < FLT_MAX
|
||||
or c.DisplayX ~= ds.x or c.DisplayY ~= ds.y then
|
||||
c = c or {}
|
||||
window.CacheSnap = c
|
||||
c.Busy, c.Key, c.Tex, c.Collapsed = busy, key, tex, window.Collapsed
|
||||
c.PosX, c.PosY, c.SizeX, c.SizeY = window.Pos.x, window.Pos.y, window.SizeFull.x, window.SizeFull.y
|
||||
c.ScrollX, c.ScrollY, c.DisplayX, c.DisplayY = window.Scroll.x, window.Scroll.y, ds.x, ds.y
|
||||
return
|
||||
end
|
||||
-- skip: widgets early-out on SkipItems and Begin() returns visible=false; End() restores it
|
||||
window.CacheSkipItemsBackup = window.SkipItems
|
||||
window.SkipItems = true
|
||||
end
|
||||
-- FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused.
|
||||
if window.Appearing then -- If currently appearing
|
||||
return
|
||||
@@ -9625,6 +9645,20 @@ function ImGui.SetNextWindowRefreshPolicy(flags)
|
||||
local g = GImGui
|
||||
g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasRefreshPolicy)
|
||||
g.NextWindowData.RefreshFlagsVal = flags
|
||||
g.NextWindowData.CacheKeySet = false
|
||||
end
|
||||
|
||||
-- [Port] Opt-in cached window (built on the refresh policy above). While nothing that could change the window
|
||||
-- happened, Begin() keeps last frame's draw list and returns visible=false, so `if visible then ... end` skips your code.
|
||||
-- It refreshes when `key` changes (pass e.g. a version number of the data shown), while the window (or a popup/child
|
||||
-- of it) is hovered, focused or active and for one frame after, and when it appears, moves, resizes, scrolls,
|
||||
-- collapses, is docked, or the display size or font atlas texture changes.
|
||||
-- Anything else that changes the contents (style, fonts, time) must be part of `key`.
|
||||
function ImGui.SetNextWindowCached(key)
|
||||
local g = GImGui
|
||||
ImGui.SetNextWindowRefreshPolicy(bit32.bor(ImGuiWindowRefreshFlags.TryToAvoidRefresh, ImGuiWindowRefreshFlags.RefreshOnHover, ImGuiWindowRefreshFlags.RefreshOnFocus))
|
||||
g.NextWindowData.CacheKeySet = true
|
||||
g.NextWindowData.CacheKeyVal = key
|
||||
end
|
||||
|
||||
function ImGui.GetWindowDpiScale()
|
||||
@@ -10827,6 +10861,10 @@ function ImGui.End()
|
||||
IM_ASSERT(window.DrawList == nil)
|
||||
window.DrawList = window.DrawListInst
|
||||
end
|
||||
if window.CacheSkipItemsBackup ~= nil then -- [Port] SetNextWindowCached()
|
||||
window.SkipItems = window.CacheSkipItemsBackup
|
||||
window.CacheSkipItemsBackup = nil
|
||||
end
|
||||
|
||||
-- Stop logging
|
||||
if g.LogWindow == window then -- FIXME: add more options for scope of logging
|
||||
@@ -35105,7 +35143,9 @@ function ImGuiNextWindowData()
|
||||
SizeCallbackUserData = nil,
|
||||
BgAlphaVal = nil,
|
||||
MenuBarOffsetMinVal = ImVec2(),
|
||||
RefreshFlagsVal = nil
|
||||
RefreshFlagsVal = nil,
|
||||
CacheKeySet = false, -- [Port] SetNextWindowCached()
|
||||
CacheKeyVal = nil
|
||||
}, IMGUI_NEXT_WINDOW_DATA)
|
||||
end
|
||||
|
||||
@@ -36277,6 +36317,8 @@ function ImGuiWindow(ctx, name)
|
||||
SkipItems = false,
|
||||
|
||||
SkipRefresh = false,
|
||||
CacheSnap = nil, -- [Port] SetNextWindowCached(): state at the last refresh
|
||||
CacheSkipItemsBackup = nil,
|
||||
|
||||
Appearing = false,
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"tree": {
|
||||
"$className": "DataModel",
|
||||
"ReplicatedStorage": {
|
||||
"ImGui": { "$path": "build/ImGui.luau" }
|
||||
"ImGui": { "$path": "build/ImGuiTyped.luau", "Impl": { "$path": "build/ImGui.luau" } }
|
||||
},
|
||||
"StarterPlayer": {
|
||||
"StarterPlayerScripts": {
|
||||
|
||||
@@ -45,7 +45,6 @@ KNOWN ISSUES
|
||||
|
||||
PERFORMANCE IDEAS (not done)
|
||||
----------------------------
|
||||
- Opt-in cached windows (skip user code for idle windows).
|
||||
- Cheaper visible ColorEdit4 rows; cheaper Begin() for child windows.
|
||||
|
||||
PLANNED EXTENSIONS
|
||||
|
||||
@@ -1,336 +1,495 @@
|
||||
-- LocalScript. Build the library first: `python3 tools/bundle.py` -> build/ImGui.luau (see default.project.json)
|
||||
|
||||
local ReplicatedStorage = game:GetService("ReplicatedStorage")
|
||||
local RunService = game:GetService("RunService")
|
||||
local AssetService = game:GetService("AssetService")
|
||||
|
||||
local G = require(ReplicatedStorage:WaitForChild("ImGui"))
|
||||
local ExampleImageViewerData, ExampleImageViewer_DrawOptions, ExampleImageViewer_DrawCanvas = G.ExampleImageViewerData, G.ExampleImageViewer_DrawOptions, G.ExampleImageViewer_DrawCanvas
|
||||
|
||||
local ImGui, ImVec4, ImGuiConfigFlags, ImGui_ImplRoblox = G.ImGui, G.ImVec4, G.ImGuiConfigFlags, G.ImGui_ImplRoblox
|
||||
local BaseEnvironment = getfenv()
|
||||
setfenv(1, setmetatable({}, {
|
||||
__index = function(_, Key)
|
||||
local Value = G[Key]
|
||||
if Value ~= nil then
|
||||
return Value
|
||||
end
|
||||
return BaseEnvironment[Key]
|
||||
end,
|
||||
}))
|
||||
|
||||
local main_scale = 1.0
|
||||
-- Roblox UI points are multiplied by the OS display scale (e.g. 150%), which makes imgui look large.
|
||||
-- Set this to your display scale to render imgui at physical-pixel resolution (same size as a desktop imgui app).
|
||||
local render_scale = 1.0
|
||||
local clear_color = ImVec4(0.45, 0.55, 0.60, 1.00)
|
||||
local show_demo_window = true
|
||||
local show_another_window = false
|
||||
local f = 0.0
|
||||
local counter = 0
|
||||
local MainScale = 1.0
|
||||
local RenderScale = 1.0
|
||||
local RenderRate = 60
|
||||
local ThumbnailSize = 420
|
||||
local FontSize = 13.0
|
||||
local FontNames = { "Cousine-Regular", "DroidSans", "Karla-Regular", "ProggyTiny", "Roboto-Medium" }
|
||||
|
||||
local State = {
|
||||
ClearColor = ImVec4(0.45, 0.55, 0.60, 1.00),
|
||||
ShowDemoWindow = true,
|
||||
ShowAnotherWindow = false,
|
||||
Float = 0.0,
|
||||
Counter = 0,
|
||||
}
|
||||
|
||||
local Spinner = {
|
||||
Show = true,
|
||||
Speed = 1.0,
|
||||
Angle = 0.0,
|
||||
Color = ImVec4(0.80, 0.65, 0.97, 1.0),
|
||||
}
|
||||
|
||||
ImGui.CreateContext()
|
||||
|
||||
local io = ImGui.GetIO()
|
||||
io.ConfigFlags = bit32.bor(io.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard, ImGuiConfigFlags.DockingEnable)
|
||||
local IO = ImGui.GetIO()
|
||||
IO.ConfigFlags = bit32.bor(IO.ConfigFlags, ImGuiConfigFlags.NavEnableKeyboard, ImGuiConfigFlags.DockingEnable)
|
||||
|
||||
-- Catppuccin Mocha, Mauve accent (https://catppuccin.com/palette)
|
||||
local function StyleColorsCatppuccinMocha(style)
|
||||
local function hex(h, a)
|
||||
return ImVec4(bit32.extract(h, 16, 8) / 255, bit32.extract(h, 8, 8) / 255, bit32.extract(h, 0, 8) / 255, a or 1.0)
|
||||
end
|
||||
local crust, mantle, base = 0x11111b, 0x181825, 0x1e1e2e
|
||||
local surface0, surface1, surface2 = 0x313244, 0x45475a, 0x585b70
|
||||
local overlay0, overlay2, text = 0x6c7086, 0x9399b2, 0xcdd6f4
|
||||
local mauve, lavender = 0xcba6f7, 0xb4befe
|
||||
local C, c = G.ImGuiCol, style.Colors
|
||||
local function set(idx, h, a) c[idx] = hex(h, a) end
|
||||
set(C.Text, text); set(C.TextDisabled, overlay0)
|
||||
set(C.WindowBg, base); set(C.ChildBg, base, 0.0)
|
||||
set(C.PopupBg, mantle, 0.98); set(C.Border, surface1); set(C.BorderShadow, crust, 0.0)
|
||||
set(C.FrameBg, surface0); set(C.FrameBgHovered, surface1); set(C.FrameBgActive, surface2)
|
||||
set(C.TitleBg, mantle); set(C.TitleBgActive, crust); set(C.TitleBgCollapsed, mantle, 0.75)
|
||||
set(C.MenuBarBg, mantle)
|
||||
set(C.ScrollbarBg, mantle); set(C.ScrollbarGrab, surface1)
|
||||
set(C.ScrollbarGrabHovered, surface2); set(C.ScrollbarGrabActive, overlay0)
|
||||
set(C.CheckMark, mauve); set(C.SliderGrab, mauve, 0.8); set(C.SliderGrabActive, mauve)
|
||||
set(C.Button, surface0); set(C.ButtonHovered, surface1); set(C.ButtonActive, mauve, 0.6)
|
||||
set(C.Header, surface0); set(C.HeaderHovered, surface1); set(C.HeaderActive, mauve, 0.5)
|
||||
set(C.Separator, surface1); set(C.SeparatorHovered, mauve, 0.7); set(C.SeparatorActive, mauve)
|
||||
set(C.ResizeGrip, mauve, 0.2); set(C.ResizeGripHovered, mauve, 0.6); set(C.ResizeGripActive, mauve, 0.9)
|
||||
set(C.InputTextCursor, text)
|
||||
set(C.TabHovered, surface2); set(C.Tab, surface0)
|
||||
set(C.TabSelected, surface1); set(C.TabSelectedOverline, mauve)
|
||||
set(C.TabDimmed, mantle); set(C.TabDimmedSelected, surface0); set(C.TabDimmedSelectedOverline, overlay0)
|
||||
set(C.DockingPreview, mauve, 0.7); set(C.DockingEmptyBg, crust)
|
||||
set(C.PlotLines, overlay2); set(C.PlotLinesHovered, mauve)
|
||||
set(C.PlotHistogram, mauve, 0.8); set(C.PlotHistogramHovered, lavender)
|
||||
set(C.TableHeaderBg, surface0); set(C.TableBorderStrong, surface1); set(C.TableBorderLight, surface0)
|
||||
set(C.TableRowBg, base, 0.0); set(C.TableRowBgAlt, surface0, 0.3)
|
||||
set(C.TextLink, mauve); set(C.TextSelectedBg, mauve, 0.35)
|
||||
set(C.TreeLines, surface2)
|
||||
set(C.DragDropTarget, mauve, 0.9)
|
||||
set(C.NavCursor, lavender); set(C.NavWindowingHighlight, lavender, 0.7)
|
||||
set(C.NavWindowingDimBg, crust, 0.5); set(C.ModalWindowDimBg, crust, 0.6)
|
||||
-- catppuccin mocha mauve https://catppuccin.com/palette
|
||||
local function StyleColorsCatppuccinMocha(Style)
|
||||
local function Hex(Value, Alpha)
|
||||
return ImVec4(
|
||||
bit32.extract(Value, 16, 8) / 255,
|
||||
bit32.extract(Value, 8, 8) / 255,
|
||||
bit32.extract(Value, 0, 8) / 255,
|
||||
Alpha or 1.0
|
||||
)
|
||||
end
|
||||
|
||||
local style = ImGui.GetStyle()
|
||||
StyleColorsCatppuccinMocha(style)
|
||||
style:ScaleAllSizes(main_scale)
|
||||
style.FontScaleDpi = main_scale
|
||||
local Crust, Mantle, Base = 0x11111b, 0x181825, 0x1e1e2e
|
||||
local Surface0, Surface1, Surface2 = 0x313244, 0x45475a, 0x585b70
|
||||
local Overlay0, Overlay2, Text = 0x6c7086, 0x9399b2, 0xcdd6f4
|
||||
local Mauve, Lavender = 0xcba6f7, 0xb4befe
|
||||
|
||||
-- Fonts: ProggyClean stays the default (added first); the rest show up in Style Editor > Fonts
|
||||
io.Fonts:AddFontDefault()
|
||||
for _, name in ipairs({ "Cousine-Regular", "DroidSans", "Karla-Regular", "ProggyTiny", "Roboto-Medium" }) do
|
||||
io.Fonts:AddFontFromFileTTF("fonts/" .. name .. ".ttf", 13.0)
|
||||
local Entries = {
|
||||
{ "Text", Text },
|
||||
{ "TextDisabled", Overlay0 },
|
||||
|
||||
{ "WindowBg", Base },
|
||||
{ "ChildBg", Base, 0.0 },
|
||||
{ "PopupBg", Mantle, 0.98 },
|
||||
{ "Border", Surface1 },
|
||||
{ "BorderShadow", Crust, 0.0 },
|
||||
|
||||
{ "FrameBg", Surface0 },
|
||||
{ "FrameBgHovered", Surface1 },
|
||||
{ "FrameBgActive", Surface2 },
|
||||
|
||||
{ "TitleBg", Mantle },
|
||||
{ "TitleBgActive", Crust },
|
||||
{ "TitleBgCollapsed", Mantle, 0.75 },
|
||||
{ "MenuBarBg", Mantle },
|
||||
|
||||
{ "ScrollbarBg", Mantle },
|
||||
{ "ScrollbarGrab", Surface1 },
|
||||
{ "ScrollbarGrabHovered", Surface2 },
|
||||
{ "ScrollbarGrabActive", Overlay0 },
|
||||
|
||||
{ "CheckMark", Mauve },
|
||||
{ "SliderGrab", Mauve, 0.8 },
|
||||
{ "SliderGrabActive", Mauve },
|
||||
|
||||
{ "Button", Surface0 },
|
||||
{ "ButtonHovered", Surface1 },
|
||||
{ "ButtonActive", Mauve, 0.6 },
|
||||
|
||||
{ "Header", Surface0 },
|
||||
{ "HeaderHovered", Surface1 },
|
||||
{ "HeaderActive", Mauve, 0.5 },
|
||||
|
||||
{ "Separator", Surface1 },
|
||||
{ "SeparatorHovered", Mauve, 0.7 },
|
||||
{ "SeparatorActive", Mauve },
|
||||
|
||||
{ "ResizeGrip", Mauve, 0.2 },
|
||||
{ "ResizeGripHovered", Mauve, 0.6 },
|
||||
{ "ResizeGripActive", Mauve, 0.9 },
|
||||
|
||||
{ "InputTextCursor", Text },
|
||||
|
||||
{ "Tab", Surface0 },
|
||||
{ "TabHovered", Surface2 },
|
||||
{ "TabSelected", Surface1 },
|
||||
{ "TabSelectedOverline", Mauve },
|
||||
{ "TabDimmed", Mantle },
|
||||
{ "TabDimmedSelected", Surface0 },
|
||||
{ "TabDimmedSelectedOverline", Overlay0 },
|
||||
|
||||
{ "DockingPreview", Mauve, 0.7 },
|
||||
{ "DockingEmptyBg", Crust },
|
||||
|
||||
{ "PlotLines", Overlay2 },
|
||||
{ "PlotLinesHovered", Mauve },
|
||||
{ "PlotHistogram", Mauve, 0.8 },
|
||||
{ "PlotHistogramHovered", Lavender },
|
||||
|
||||
{ "TableHeaderBg", Surface0 },
|
||||
{ "TableBorderStrong", Surface1 },
|
||||
{ "TableBorderLight", Surface0 },
|
||||
{ "TableRowBg", Base, 0.0 },
|
||||
{ "TableRowBgAlt", Surface0, 0.3 },
|
||||
|
||||
{ "TextLink", Mauve },
|
||||
{ "TextSelectedBg", Mauve, 0.35 },
|
||||
{ "TreeLines", Surface2 },
|
||||
{ "DragDropTarget", Mauve, 0.9 },
|
||||
|
||||
{ "NavCursor", Lavender },
|
||||
{ "NavWindowingHighlight", Lavender, 0.7 },
|
||||
{ "NavWindowingDimBg", Crust, 0.5 },
|
||||
{ "ModalWindowDimBg", Crust, 0.6 },
|
||||
}
|
||||
|
||||
for _, Entry in ipairs(Entries) do
|
||||
local Name, Color, Alpha = Entry[1], Entry[2], Entry[3]
|
||||
Style.Colors[ImGuiCol[Name]] = Hex(Color, Alpha)
|
||||
end
|
||||
end
|
||||
|
||||
ImGui_ImplRoblox.Init(nil, render_scale)
|
||||
ImGui_ImplRoblox.SetRenderRate(60) -- tile redraws per second; imgui logic + your code still run every frame
|
||||
-- ImGui_ImplRoblox.SetBusyRenderRate(30) -- optional: lower redraw rate while scrolling/resizing/moving windows
|
||||
ImGui_ImplRoblox.SetProfiling(true) -- MicroProfiler (Ctrl+F6) labels; turn off when not profiling
|
||||
local Style = ImGui.GetStyle()
|
||||
StyleColorsCatppuccinMocha(Style)
|
||||
Style:ScaleAllSizes(MainScale)
|
||||
Style.FontScaleDpi = MainScale
|
||||
|
||||
IO.Fonts:AddFontDefault()
|
||||
for _, Name in ipairs(FontNames) do
|
||||
IO.Fonts:AddFontFromFileTTF("fonts/" .. Name .. ".ttf", FontSize)
|
||||
end
|
||||
|
||||
ImGui_ImplRoblox.Init(nil, RenderScale)
|
||||
ImGui_ImplRoblox.SetRenderRate(RenderRate)
|
||||
-- ImGui_ImplRoblox.SetBusyRenderRate(30) -- Optional: lower redraw rate while scrolling/resizing/moving windows
|
||||
-- ImGui_ImplRoblox.SetProfiling(true) -- MicroProfiler labels; turn off when not profiling
|
||||
-- ImGui_ImplRoblox.SetTextProxy(true) -- Optional: hidden TextBox for OS typing (any layout), paste and copy/cut
|
||||
|
||||
local function ProfileBegin(Name)
|
||||
if ImGui_ImplRoblox.IsProfiling() then
|
||||
debug.profilebegin(Name)
|
||||
end
|
||||
end
|
||||
|
||||
local function ProfileEnd()
|
||||
if ImGui_ImplRoblox.IsProfiling() then
|
||||
debug.profileend()
|
||||
end
|
||||
end
|
||||
|
||||
local function P(name) if ImGui_ImplRoblox.IsProfiling() then debug.profilebegin(name) end end
|
||||
local function PE() if ImGui_ImplRoblox.IsProfiling() then debug.profileend() end end
|
||||
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
-- Custom widget: ImGui.Embed(id, size, flags, init) -> Frame
|
||||
-- Reserves a widget-sized area in the current window and shows a real Frame there, so any Instances (UI, a
|
||||
-- ViewportFrame, ...) can live inside an imgui window. Immediate-mode friendly:
|
||||
-- * one Frame per id (per window, through the ID stack, like any widget); `init(frame)` runs only when it is created
|
||||
-- * call it every frame the Frame should be visible; when it isn't called (window closed/collapsed, tab or tree node
|
||||
-- closed, scrolled fully out of view) the Frame is hidden, never destroyed, so your Instances keep their state
|
||||
-- * size uses imgui sizing (ImVec2(-1, h) = fill width, 0 = default), style gives padding/rounding/background/border
|
||||
-- * returns the Frame: edit properties, add or remove children any time
|
||||
-- ImGui.DestroyEmbed(id) removes it for good (call while the same window is current, like the widget itself).
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
local EmbedFlags = {
|
||||
None = 0,
|
||||
NoClip = 1, -- don't clip to the window's content area (still moves/hides/stacks with the window)
|
||||
NoBackground = 2, -- no FrameBg behind the Frame
|
||||
NoBorder = 4, -- no style border
|
||||
NoPadding = 8, -- no FramePadding inside the Frame (UIPadding)
|
||||
NoRounding = 16, -- no FrameRounding corners (UICorner)
|
||||
NoClip = 1, -- Don't clip to the window's content area (still moves/hides/stacks with the window)
|
||||
NoBackground = 2, -- No FrameBg behind the Frame
|
||||
NoBorder = 4, -- No style border
|
||||
NoPadding = 8, -- No FramePadding inside the Frame (UIPadding)
|
||||
NoRounding = 16, -- No FrameRounding corners (UICorner)
|
||||
}
|
||||
|
||||
G.ImGuiEmbedFlags = EmbedFlags
|
||||
|
||||
local embeds = {} -- [ImGuiID] = { Frame, Padding, Corner }
|
||||
local Embeds = {}
|
||||
|
||||
function ImGui.Embed(id, size, flags, init)
|
||||
flags = flags or EmbedFlags.None
|
||||
local window = ImGui.GetCurrentWindow()
|
||||
local gid = window:GetID(id)
|
||||
local e = embeds[gid]
|
||||
if not e then
|
||||
local frame = Instance.new("Frame")
|
||||
frame.Name = tostring(id)
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.BorderSizePixel = 0
|
||||
frame.Visible = false
|
||||
e = { Frame = frame, Padding = Instance.new("UIPadding"), Corner = Instance.new("UICorner") }
|
||||
e.Padding.Parent = frame
|
||||
e.Corner.Parent = frame
|
||||
embeds[gid] = e
|
||||
if init then init(frame) end
|
||||
end
|
||||
if window.SkipItems then return e.Frame end
|
||||
|
||||
local style = ImGui.GetStyle()
|
||||
local sz = ImGui.CalcItemSize(size or G.ImVec2(0, 0), ImGui.CalcItemWidth(), ImGui.GetFrameHeight() * 4)
|
||||
local p = window.DC.CursorPos
|
||||
local bb = G.ImRect(p.x, p.y, p.x + sz.x, p.y + sz.y)
|
||||
ImGui.ItemSize(sz)
|
||||
if not ImGui.ItemAdd(bb, gid) then return e.Frame end -- fully clipped: not submitted -> hidden this frame
|
||||
|
||||
local rounding = bit32.band(flags, EmbedFlags.NoRounding) == 0 and style.FrameRounding or 0
|
||||
if bit32.band(flags, EmbedFlags.NoBackground) == 0 then
|
||||
ImGui.RenderFrame(bb.Min, bb.Max, ImGui.GetColorU32(G.ImGuiCol.FrameBg), bit32.band(flags, EmbedFlags.NoBorder) == 0, rounding)
|
||||
elseif bit32.band(flags, EmbedFlags.NoBorder) == 0 then
|
||||
ImGui.RenderFrameBorder(bb.Min, bb.Max, rounding)
|
||||
local function HasFlag(Flags, Flag)
|
||||
return bit32.band(Flags, Flag) ~= 0
|
||||
end
|
||||
|
||||
-- style -> Instances (only written when changed)
|
||||
local scale = ImGui_ImplRoblox.GetRenderScale()
|
||||
local px, py = 0, 0
|
||||
if bit32.band(flags, EmbedFlags.NoPadding) == 0 then px, py = style.FramePadding.x / scale, style.FramePadding.y / scale end
|
||||
if e.PX ~= px or e.PY ~= py then
|
||||
e.PX, e.PY = px, py
|
||||
e.Padding.PaddingLeft, e.Padding.PaddingRight = UDim.new(0, px), UDim.new(0, px)
|
||||
e.Padding.PaddingTop, e.Padding.PaddingBottom = UDim.new(0, py), UDim.new(0, py)
|
||||
end
|
||||
if e.R ~= rounding then e.R = rounding; e.Corner.CornerRadius = UDim.new(0, rounding / scale) end
|
||||
local function CreateEmbed(Id)
|
||||
local Frame = Instance.new("Frame")
|
||||
Frame.Name = tostring(Id)
|
||||
Frame.BackgroundTransparency = 1
|
||||
Frame.BorderSizePixel = 0
|
||||
Frame.Visible = false
|
||||
|
||||
ImGui_ImplRoblox.SetOverlay(e.Frame, bb.Min.x, bb.Min.y, sz.x, sz.y, bit32.band(flags, EmbedFlags.NoClip) == 0)
|
||||
return e.Frame
|
||||
local Padding = Instance.new("UIPadding")
|
||||
Padding.Parent = Frame
|
||||
|
||||
local Corner = Instance.new("UICorner")
|
||||
Corner.Parent = Frame
|
||||
|
||||
return { Frame = Frame, Padding = Padding, Corner = Corner }
|
||||
end
|
||||
|
||||
function ImGui.DestroyEmbed(id)
|
||||
local gid = ImGui.GetCurrentWindow():GetID(id)
|
||||
local e = embeds[gid]
|
||||
if e then e.Frame:Destroy(); embeds[gid] = nil end
|
||||
function ImGui.Embed(Id, Size, Flags, Init)
|
||||
Flags = Flags or EmbedFlags.None
|
||||
|
||||
local Window = ImGui.GetCurrentWindow()
|
||||
local GuiId = Window:GetID(Id)
|
||||
|
||||
local Embed = Embeds[GuiId]
|
||||
if not Embed then
|
||||
Embed = CreateEmbed(Id)
|
||||
Embeds[GuiId] = Embed
|
||||
|
||||
if Init then
|
||||
Init(Embed.Frame)
|
||||
end
|
||||
end
|
||||
|
||||
-- Example: Decal Viewer. Loads a decal/image asset's pixels into an imgui texture and shows it in the demo's
|
||||
-- image viewer (zoom with the wheel, drag to pan, toggleable pixel grid).
|
||||
local AssetService = game:GetService("AssetService")
|
||||
local MarketplaceService = game:GetService("MarketplaceService")
|
||||
local decal = { input = ImGui.NewTextBuffer("", 32), status = "Enter a decal or image id", tex = nil, w = 0, h = 0, loading = false,
|
||||
viewer = ExampleImageViewerData(), show = true }
|
||||
|
||||
-- A Decal asset wraps an Image asset with a different id; the image is almost always uploaded just before it
|
||||
-- (same creator, id slightly lower). ponytail: heuristic scan of 10 ids, InsertService:LoadAsset when owned is exact.
|
||||
local function ResolveImageId(id)
|
||||
local ok, info = pcall(MarketplaceService.GetProductInfo, MarketplaceService, id)
|
||||
if not ok then return nil, "GetProductInfo failed: " .. tostring(info) end
|
||||
if info.AssetTypeId == 1 then return id end -- already an Image
|
||||
if info.AssetTypeId ~= 13 then return nil, "asset is not a decal or image" end
|
||||
for cand = id - 1, id - 10, -1 do
|
||||
local ok2, ci = pcall(MarketplaceService.GetProductInfo, MarketplaceService, cand)
|
||||
if ok2 and ci.AssetTypeId == 1 and ci.Creator and info.Creator and ci.Creator.Id == info.Creator.Id then return cand end
|
||||
end
|
||||
return nil, "couldn't find the decal's image id (try the image id directly)"
|
||||
if Window.SkipItems then
|
||||
return Embed.Frame
|
||||
end
|
||||
|
||||
local function LoadDecal(id)
|
||||
decal.loading = true
|
||||
decal.status = "Loading " .. id .. "..."
|
||||
local EmbedStyle = ImGui.GetStyle()
|
||||
local ItemSize = ImGui.CalcItemSize(
|
||||
Size or ImVec2(0, 0),
|
||||
ImGui.CalcItemWidth(),
|
||||
ImGui.GetFrameHeight() * 4
|
||||
)
|
||||
local CursorPos = Window.DC.CursorPos
|
||||
local BoundingBox = ImRect(CursorPos.x, CursorPos.y, CursorPos.x + ItemSize.x, CursorPos.y + ItemSize.y)
|
||||
|
||||
ImGui.ItemSize(ItemSize)
|
||||
if not ImGui.ItemAdd(BoundingBox, GuiId) then
|
||||
return Embed.Frame
|
||||
end
|
||||
|
||||
local Rounding = HasFlag(Flags, EmbedFlags.NoRounding) and 0 or EmbedStyle.FrameRounding
|
||||
local ShowBorder = not HasFlag(Flags, EmbedFlags.NoBorder)
|
||||
|
||||
if not HasFlag(Flags, EmbedFlags.NoBackground) then
|
||||
ImGui.RenderFrame(
|
||||
BoundingBox.Min,
|
||||
BoundingBox.Max,
|
||||
ImGui.GetColorU32(ImGuiCol.FrameBg),
|
||||
ShowBorder,
|
||||
Rounding
|
||||
)
|
||||
elseif ShowBorder then
|
||||
ImGui.RenderFrameBorder(BoundingBox.Min, BoundingBox.Max, Rounding)
|
||||
end
|
||||
|
||||
local Scale = ImGui_ImplRoblox.GetRenderScale()
|
||||
local PaddingX, PaddingY = 0, 0
|
||||
|
||||
if not HasFlag(Flags, EmbedFlags.NoPadding) then
|
||||
PaddingX = EmbedStyle.FramePadding.x / Scale
|
||||
PaddingY = EmbedStyle.FramePadding.y / Scale
|
||||
end
|
||||
|
||||
if Embed.PaddingX ~= PaddingX or Embed.PaddingY ~= PaddingY then
|
||||
Embed.PaddingX, Embed.PaddingY = PaddingX, PaddingY
|
||||
|
||||
local Padding = Embed.Padding
|
||||
Padding.PaddingLeft = UDim.new(0, PaddingX)
|
||||
Padding.PaddingRight = UDim.new(0, PaddingX)
|
||||
Padding.PaddingTop = UDim.new(0, PaddingY)
|
||||
Padding.PaddingBottom = UDim.new(0, PaddingY)
|
||||
end
|
||||
|
||||
if Embed.Rounding ~= Rounding then
|
||||
Embed.Rounding = Rounding
|
||||
Embed.Corner.CornerRadius = UDim.new(0, Rounding / Scale)
|
||||
end
|
||||
|
||||
ImGui_ImplRoblox.SetOverlay(
|
||||
Embed.Frame,
|
||||
BoundingBox.Min.x,
|
||||
BoundingBox.Min.y,
|
||||
ItemSize.x,
|
||||
ItemSize.y,
|
||||
not HasFlag(Flags, EmbedFlags.NoClip)
|
||||
)
|
||||
|
||||
return Embed.Frame
|
||||
end
|
||||
|
||||
function ImGui.DestroyEmbed(Id)
|
||||
local GuiId = ImGui.GetCurrentWindow():GetID(Id)
|
||||
local Embed = Embeds[GuiId]
|
||||
|
||||
if Embed then
|
||||
Embed.Frame:Destroy()
|
||||
Embeds[GuiId] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local Decal = {
|
||||
Show = true,
|
||||
Input = ImGui.NewTextBuffer("", 32),
|
||||
Status = "Enter a decal or image id",
|
||||
Loading = false,
|
||||
Texture = nil,
|
||||
Width = 0,
|
||||
Height = 0,
|
||||
Viewer = ExampleImageViewerData(),
|
||||
}
|
||||
|
||||
local function LoadDecal(Id)
|
||||
Decal.Loading = true
|
||||
Decal.Status = "Loading " .. Id .. "..."
|
||||
|
||||
task.spawn(function()
|
||||
local image_id, err = ResolveImageId(id)
|
||||
decal.thumb = nil
|
||||
if image_id then
|
||||
-- 1) the image itself (needs permission), 2) its 420x420 thumbnail (may be allowed when 1 isn't)
|
||||
local ok, img = pcall(AssetService.CreateEditableImageAsync, AssetService, Content.fromUri("rbxassetid://" .. image_id))
|
||||
if not ok then
|
||||
local ok2, img2 = pcall(AssetService.CreateEditableImageAsync, AssetService, Content.fromUri("rbxthumb://type=Asset&id=" .. id .. "&w=420&h=420"))
|
||||
if ok2 then ok, img = true, img2 end
|
||||
local Uri = string.format("rbxthumb://type=Asset&id=%d&w=%d&h=%d", Id, ThumbnailSize, ThumbnailSize)
|
||||
local Success, Result = pcall(AssetService.CreateEditableImageAsync, AssetService, Content.fromUri(Uri))
|
||||
|
||||
if Success then
|
||||
local Size = Result.Size
|
||||
local Pixels = Result:ReadPixelsBuffer(Vector2.zero, Size)
|
||||
Result:Destroy()
|
||||
|
||||
if Decal.Texture then
|
||||
ImGui_ImplRoblox.DestroyTexture(Decal.Texture)
|
||||
end
|
||||
if ok then
|
||||
local size = img.Size
|
||||
local pixels = img:ReadPixelsBuffer(Vector2.zero, size)
|
||||
img:Destroy()
|
||||
if decal.tex then ImGui_ImplRoblox.DestroyTexture(decal.tex) end
|
||||
decal.thumb = nil
|
||||
decal.tex, decal.w, decal.h = ImGui_ImplRoblox.CreateTexture(pixels, size.X, size.Y), size.X, size.Y
|
||||
decal.viewer.ViewReset = true
|
||||
decal.status = string.format("Image %d: %dx%d", image_id, size.X, size.Y)
|
||||
|
||||
Decal.Texture = ImGui_ImplRoblox.CreateTexture(Pixels, Size.X, Size.Y)
|
||||
Decal.Width, Decal.Height = Size.X, Size.Y
|
||||
Decal.Viewer.ViewReset = true
|
||||
Decal.Status = string.format("Thumbnail %d: %dx%d", Id, Size.X, Size.Y)
|
||||
else
|
||||
-- 3) no pixel access: Roblox still displays any asset, so show its thumbnail in an ImageLabel (no grid)
|
||||
decal.thumb = "rbxthumb://type=Asset&id=" .. id .. "&w=420&h=420"
|
||||
decal.status = "No pixel access (asset not owned by this experience's creator): display only, no zoom/grid"
|
||||
Decal.Status = "Failed to load thumbnail: " .. tostring(Result)
|
||||
end
|
||||
else
|
||||
decal.thumb = "rbxthumb://type=Asset&id=" .. id .. "&w=420&h=420"
|
||||
decal.status = (err or "") .. " - showing thumbnail"
|
||||
end
|
||||
decal.loading = false
|
||||
|
||||
Decal.Loading = false
|
||||
end)
|
||||
end
|
||||
|
||||
local function ShowDecalViewer()
|
||||
if not decal.show then return end
|
||||
decal.show = ImGui.Begin("Decal Viewer", decal.show)
|
||||
if not Decal.Show then
|
||||
return
|
||||
end
|
||||
|
||||
Decal.Show = ImGui.Begin("Decal Viewer", Decal.Show)
|
||||
|
||||
ImGui.SetNextItemWidth(ImGui.GetFontSize() * 12)
|
||||
local enter = ImGui.InputTextWithHint("##id", "decal id", decal.input, 32, G.ImGuiInputTextFlags.CharsDecimal + G.ImGuiInputTextFlags.EnterReturnsTrue)
|
||||
local EnterPressed = ImGui.InputTextWithHint(
|
||||
"##id",
|
||||
"decal id",
|
||||
Decal.Input,
|
||||
32,
|
||||
ImGuiInputTextFlags.CharsDecimal + ImGuiInputTextFlags.EnterReturnsTrue
|
||||
)
|
||||
|
||||
ImGui.SameLine()
|
||||
ImGui.BeginDisabled(decal.loading)
|
||||
if (ImGui.Button("Load") or enter) and not decal.loading then
|
||||
local id = tonumber(ImGui.TextBufferToString(decal.input))
|
||||
if id then LoadDecal(id) else decal.status = "Not a number" end
|
||||
ImGui.BeginDisabled(Decal.Loading)
|
||||
if (ImGui.Button("Load") or EnterPressed) and not Decal.Loading then
|
||||
local Id = tonumber(ImGui.TextBufferToString(Decal.Input))
|
||||
if Id and Id == math.floor(Id) then
|
||||
LoadDecal(Id)
|
||||
else
|
||||
Decal.Status = "Not a valid id"
|
||||
end
|
||||
end
|
||||
ImGui.EndDisabled()
|
||||
ImGui.SameLine(); ImGui.TextDisabled(decal.status)
|
||||
if decal.thumb then
|
||||
local avail = ImGui.GetContentRegionAvail()
|
||||
local frame = ImGui.Embed("decal_thumb", G.ImVec2(-1, math.max(avail.y, 50)), G.ImGuiEmbedFlags.None, function(f)
|
||||
local img = Instance.new("ImageLabel")
|
||||
img.Name = "Image"
|
||||
img.Size = UDim2.fromScale(1, 1)
|
||||
img.BackgroundTransparency = 1
|
||||
img.ScaleType = Enum.ScaleType.Fit
|
||||
img.Parent = f
|
||||
end)
|
||||
if frame.Image.Image ~= decal.thumb then frame.Image.Image = decal.thumb end
|
||||
elseif decal.tex then
|
||||
ExampleImageViewer_DrawOptions(decal.viewer)
|
||||
local avail = ImGui.GetContentRegionAvail()
|
||||
ExampleImageViewer_DrawCanvas(decal.viewer, G.ImVec2(math.max(avail.x, 50), math.max(avail.y, 50)), decal.tex, decal.w, decal.h)
|
||||
|
||||
ImGui.SameLine()
|
||||
ImGui.TextDisabled(Decal.Status)
|
||||
|
||||
if Decal.Texture then
|
||||
ExampleImageViewer_DrawOptions(Decal.Viewer)
|
||||
|
||||
local Available = ImGui.GetContentRegionAvail()
|
||||
ExampleImageViewer_DrawCanvas(
|
||||
Decal.Viewer,
|
||||
ImVec2(math.max(Available.x, 50), math.max(Available.y, 50)),
|
||||
Decal.Texture,
|
||||
Decal.Width,
|
||||
Decal.Height
|
||||
)
|
||||
end
|
||||
|
||||
ImGui.End()
|
||||
end
|
||||
|
||||
-- Example: a ViewportFrame with a spinning part, edited live from imgui widgets
|
||||
local spin_speed = 1.0
|
||||
local part_color = ImVec4(0.80, 0.65, 0.97, 1.0)
|
||||
local spin_angle = 0.0
|
||||
local show_viewport_window = true
|
||||
|
||||
RunService.Stepped:Connect(function()
|
||||
P("ImGui frame")
|
||||
ImGui_ImplRoblox.NewFrame()
|
||||
P("ImGui.NewFrame"); ImGui.NewFrame(); PE()
|
||||
P("ImGui UI")
|
||||
|
||||
-- Dockspace covering the whole screen; the centre stays transparent so the game shows through
|
||||
ImGui.DockSpaceOverViewport(0, nil, G.ImGuiDockNodeFlags.PassthruCentralNode)
|
||||
|
||||
if show_demo_window then
|
||||
ImGui.ShowDemoWindow()
|
||||
end
|
||||
|
||||
do
|
||||
local function ShowHelloWindow()
|
||||
ImGui.Begin("Hello, world!")
|
||||
|
||||
ImGui.Text("This is some useful text.")
|
||||
local _
|
||||
_, show_demo_window = ImGui.Checkbox("Demo Window", show_demo_window)
|
||||
_, show_another_window = ImGui.Checkbox("Another Window", show_another_window)
|
||||
|
||||
f = ImGui.SliderFloat("float", f, 0.0, 1.0)
|
||||
ImGui.ColorEdit3("clear color", clear_color)
|
||||
local _
|
||||
_, State.ShowDemoWindow = ImGui.Checkbox("Demo Window", State.ShowDemoWindow)
|
||||
_, State.ShowAnotherWindow = ImGui.Checkbox("Another Window", State.ShowAnotherWindow)
|
||||
|
||||
State.Float = ImGui.SliderFloat("float", State.Float, 0.0, 1.0)
|
||||
ImGui.ColorEdit3("clear color", State.ClearColor)
|
||||
|
||||
if ImGui.Button("Button") then
|
||||
counter = counter + 1
|
||||
State.Counter += 1
|
||||
end
|
||||
ImGui.SameLine()
|
||||
ImGui.Text("counter = %d", counter)
|
||||
ImGui.Text("counter = %d", State.Counter)
|
||||
|
||||
ImGui.Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0 / io.Framerate, io.Framerate)
|
||||
ImGui.Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0 / IO.Framerate, IO.Framerate)
|
||||
|
||||
ImGui.End()
|
||||
end
|
||||
|
||||
if show_another_window then
|
||||
show_another_window = ImGui.Begin("Another Window", show_another_window)
|
||||
local function ShowAnotherWindow()
|
||||
if not State.ShowAnotherWindow then
|
||||
return
|
||||
end
|
||||
|
||||
State.ShowAnotherWindow = ImGui.Begin("Another Window", State.ShowAnotherWindow)
|
||||
|
||||
ImGui.Text("Hello from another window!")
|
||||
if ImGui.Button("Close Me") then
|
||||
show_another_window = false
|
||||
State.ShowAnotherWindow = false
|
||||
end
|
||||
|
||||
ImGui.End()
|
||||
end
|
||||
|
||||
PE()
|
||||
local function CreateSpinnerViewport(Container)
|
||||
local Viewport = Instance.new("ViewportFrame")
|
||||
Viewport.Size = UDim2.fromScale(1, 1)
|
||||
Viewport.BackgroundTransparency = 1
|
||||
Viewport.Parent = Container
|
||||
|
||||
local Camera = Instance.new("Camera")
|
||||
Camera.CFrame = CFrame.lookAt(Vector3.new(0, 2, 6), Vector3.zero)
|
||||
Camera.Parent = Viewport
|
||||
Viewport.CurrentCamera = Camera
|
||||
|
||||
local Part = Instance.new("Part")
|
||||
Part.Name = "Spinner"
|
||||
Part.Size = Vector3.new(2, 2, 2)
|
||||
Part.Parent = Viewport
|
||||
end
|
||||
|
||||
local function ShowViewportWindow()
|
||||
if not Spinner.Show then
|
||||
return
|
||||
end
|
||||
|
||||
Spinner.Show = ImGui.Begin("Viewport", Spinner.Show)
|
||||
|
||||
Spinner.Speed = ImGui.SliderFloat("speed", Spinner.Speed, 0.0, 5.0)
|
||||
ImGui.ColorEdit3("color", Spinner.Color)
|
||||
|
||||
local Frame = ImGui.Embed("viewport", ImVec2(-1, 220), EmbedFlags.None, CreateSpinnerViewport)
|
||||
|
||||
Spinner.Angle += Spinner.Speed * IO.DeltaTime
|
||||
|
||||
local Part = Frame.ViewportFrame.Spinner
|
||||
Part.CFrame = CFrame.Angles(0.4, Spinner.Angle, 0)
|
||||
Part.Color = Color3.new(Spinner.Color.x, Spinner.Color.y, Spinner.Color.z)
|
||||
|
||||
ImGui.End()
|
||||
end
|
||||
|
||||
RunService.Stepped:Connect(function()
|
||||
ProfileBegin("ImGui frame")
|
||||
ImGui_ImplRoblox.NewFrame()
|
||||
|
||||
ProfileBegin("ImGui.NewFrame")
|
||||
ImGui.NewFrame()
|
||||
ProfileEnd()
|
||||
|
||||
ProfileBegin("ImGui UI")
|
||||
ImGui.DockSpaceOverViewport(0, nil, ImGuiDockNodeFlags.PassthruCentralNode)
|
||||
|
||||
if State.ShowDemoWindow then
|
||||
-- For reference: https://github.com/4DBug/imgui-luau/blob/master/imgui_demo.lua
|
||||
ImGui.ShowDemoWindow()
|
||||
end
|
||||
|
||||
ShowHelloWindow()
|
||||
ShowAnotherWindow()
|
||||
ShowDecalViewer()
|
||||
ShowViewportWindow()
|
||||
ProfileEnd()
|
||||
|
||||
if show_viewport_window then
|
||||
show_viewport_window = ImGui.Begin("Viewport", show_viewport_window)
|
||||
spin_speed = ImGui.SliderFloat("speed", spin_speed, 0.0, 5.0)
|
||||
ImGui.ColorEdit3("color", part_color)
|
||||
local frame = ImGui.Embed("viewport", G.ImVec2(-1, 220), G.ImGuiEmbedFlags.None, function(f)
|
||||
-- runs once
|
||||
local vpf = Instance.new("ViewportFrame")
|
||||
vpf.Size = UDim2.fromScale(1, 1)
|
||||
vpf.BackgroundTransparency = 1
|
||||
vpf.Parent = f
|
||||
local cam = Instance.new("Camera")
|
||||
cam.CFrame = CFrame.lookAt(Vector3.new(0, 2, 6), Vector3.new(0, 0, 0))
|
||||
cam.Parent = vpf
|
||||
vpf.CurrentCamera = cam
|
||||
local part = Instance.new("Part")
|
||||
part.Name = "Spinner"
|
||||
part.Size = Vector3.new(2, 2, 2)
|
||||
part.Parent = vpf
|
||||
end)
|
||||
-- every frame: edit what was created once
|
||||
spin_angle += spin_speed * io.DeltaTime
|
||||
local part = frame.ViewportFrame.Spinner
|
||||
part.CFrame = CFrame.Angles(0.4, spin_angle, 0)
|
||||
part.Color = Color3.new(part_color.x, part_color.y, part_color.z)
|
||||
ImGui.Text("Frames created: 1 (same Frame every frame)")
|
||||
ImGui.End()
|
||||
end
|
||||
ProfileBegin("ImGui.Render")
|
||||
ImGui.EndFrame()
|
||||
ImGui.Render()
|
||||
ProfileEnd()
|
||||
|
||||
P("ImGui.Render"); ImGui.EndFrame(); ImGui.Render(); PE()
|
||||
ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||
PE()
|
||||
ProfileEnd()
|
||||
end)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"tree": {
|
||||
"$className": "DataModel",
|
||||
"ReplicatedStorage": {
|
||||
"ImGui": { "$path": "../../build/ImGui.luau" },
|
||||
"ImGui": { "$path": "../../build/ImGuiTyped.luau", "Impl": { "$path": "../../build/ImGui.luau" } },
|
||||
"SharedApp": { "$path": "app.lua" }
|
||||
},
|
||||
"StarterPlayer": {
|
||||
|
||||
@@ -8846,6 +8846,26 @@ function ImGui.UpdateWindowSkipRefresh(window)
|
||||
end
|
||||
|
||||
if bit32.band(g.NextWindowData.RefreshFlagsVal, ImGuiWindowRefreshFlags.TryToAvoidRefresh) ~= 0 then
|
||||
-- [Port] SetNextWindowCached(): refresh on any change since the last refresh (and one frame after being busy)
|
||||
if g.NextWindowData.CacheKeySet then
|
||||
local function related(w) return w ~= nil and (w.RootWindow == window.RootWindow or ImGui.IsWindowWithinBeginStackOf(w.RootWindow, window)) end
|
||||
local busy = window.Appearing or window.Hidden or window.DockIsActive or related(g.HoveredWindow) or related(g.NavWindow) or related(g.ActiveIdWindow) or (g.MovingWindow ~= nil and related(g.MovingWindow))
|
||||
local c, key, ds, tex = window.CacheSnap, g.NextWindowData.CacheKeyVal, g.IO.DisplaySize, g.IO.Fonts.TexData
|
||||
if busy or c == nil or c.Busy or c.Key ~= key or c.Tex ~= tex or c.Collapsed ~= window.Collapsed
|
||||
or c.PosX ~= window.Pos.x or c.PosY ~= window.Pos.y or c.SizeX ~= window.SizeFull.x or c.SizeY ~= window.SizeFull.y
|
||||
or c.ScrollX ~= window.Scroll.x or c.ScrollY ~= window.Scroll.y or window.ScrollTarget.x < FLT_MAX or window.ScrollTarget.y < FLT_MAX
|
||||
or c.DisplayX ~= ds.x or c.DisplayY ~= ds.y then
|
||||
c = c or {}
|
||||
window.CacheSnap = c
|
||||
c.Busy, c.Key, c.Tex, c.Collapsed = busy, key, tex, window.Collapsed
|
||||
c.PosX, c.PosY, c.SizeX, c.SizeY = window.Pos.x, window.Pos.y, window.SizeFull.x, window.SizeFull.y
|
||||
c.ScrollX, c.ScrollY, c.DisplayX, c.DisplayY = window.Scroll.x, window.Scroll.y, ds.x, ds.y
|
||||
return
|
||||
end
|
||||
-- skip: widgets early-out on SkipItems and Begin() returns visible=false; End() restores it
|
||||
window.CacheSkipItemsBackup = window.SkipItems
|
||||
window.SkipItems = true
|
||||
end
|
||||
-- FIXME-IDLE: Tests for e.g. mouse clicks or keyboard while focused.
|
||||
if window.Appearing then -- If currently appearing
|
||||
return
|
||||
@@ -9477,6 +9497,20 @@ function ImGui.SetNextWindowRefreshPolicy(flags)
|
||||
local g = GImGui
|
||||
g.NextWindowData.HasFlags = bit32.bor(g.NextWindowData.HasFlags, ImGuiNextWindowDataFlags.HasRefreshPolicy)
|
||||
g.NextWindowData.RefreshFlagsVal = flags
|
||||
g.NextWindowData.CacheKeySet = false
|
||||
end
|
||||
|
||||
-- [Port] Opt-in cached window (built on the refresh policy above). While nothing that could change the window
|
||||
-- happened, Begin() keeps last frame's draw list and returns visible=false, so `if visible then ... end` skips your code.
|
||||
-- It refreshes when `key` changes (pass e.g. a version number of the data shown), while the window (or a popup/child
|
||||
-- of it) is hovered, focused or active and for one frame after, and when it appears, moves, resizes, scrolls,
|
||||
-- collapses, is docked, or the display size or font atlas texture changes.
|
||||
-- Anything else that changes the contents (style, fonts, time) must be part of `key`.
|
||||
function ImGui.SetNextWindowCached(key)
|
||||
local g = GImGui
|
||||
ImGui.SetNextWindowRefreshPolicy(bit32.bor(ImGuiWindowRefreshFlags.TryToAvoidRefresh, ImGuiWindowRefreshFlags.RefreshOnHover, ImGuiWindowRefreshFlags.RefreshOnFocus))
|
||||
g.NextWindowData.CacheKeySet = true
|
||||
g.NextWindowData.CacheKeyVal = key
|
||||
end
|
||||
|
||||
function ImGui.GetWindowDpiScale()
|
||||
@@ -10679,6 +10713,10 @@ function ImGui.End()
|
||||
IM_ASSERT(window.DrawList == nil)
|
||||
window.DrawList = window.DrawListInst
|
||||
end
|
||||
if window.CacheSkipItemsBackup ~= nil then -- [Port] SetNextWindowCached()
|
||||
window.SkipItems = window.CacheSkipItemsBackup
|
||||
window.CacheSkipItemsBackup = nil
|
||||
end
|
||||
|
||||
-- Stop logging
|
||||
if g.LogWindow == window then -- FIXME: add more options for scope of logging
|
||||
|
||||
+5
-1
@@ -1236,7 +1236,9 @@ function ImGuiNextWindowData()
|
||||
SizeCallbackUserData = nil,
|
||||
BgAlphaVal = nil,
|
||||
MenuBarOffsetMinVal = ImVec2(),
|
||||
RefreshFlagsVal = nil
|
||||
RefreshFlagsVal = nil,
|
||||
CacheKeySet = false, -- [Port] SetNextWindowCached()
|
||||
CacheKeyVal = nil
|
||||
}, IMGUI_NEXT_WINDOW_DATA)
|
||||
end
|
||||
|
||||
@@ -2408,6 +2410,8 @@ function ImGuiWindow(ctx, name)
|
||||
SkipItems = false,
|
||||
|
||||
SkipRefresh = false,
|
||||
CacheSnap = nil, -- [Port] SetNextWindowCached(): state at the last refresh
|
||||
CacheSkipItemsBackup = nil,
|
||||
|
||||
Appearing = false,
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
# Why: ModuleScripts don't share globals, and the setfenv() alternative turns off Luau's fast paths / native codegen.
|
||||
# Each source file becomes a function in __FILES; IM_INCLUDE(name) runs it once and caches the result.
|
||||
# The module returns a table with every global the library defines (ImGui, ImVec2, ImGuiConfigFlags, ImGui_ImplRoblox, ...).
|
||||
# Roblox target also writes ImGuiTyped.luau (types + require(script.Impl), see tools/gen_types.py).
|
||||
import os, re
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
@@ -64,4 +65,8 @@ NAME = "imgui_love.lua" if LOVE else "ImGui.luau"
|
||||
open(os.path.join(OUT, NAME), "w").write("\n".join(out) + "\n")
|
||||
import json
|
||||
json.dump(linemap, open(os.path.join(OUT, NAME.rsplit(".", 1)[0] + ".linemap.json"), "w"))
|
||||
if not LOVE:
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from gen_types import wrapper
|
||||
open(os.path.join(OUT, "ImGuiTyped.luau"), "w").write(wrapper(FILES))
|
||||
print("wrote build/%s (%d files, %d exports)" % (NAME, len(FILES), len(names)))
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
#!/usr/bin/env python3
|
||||
# Typed entry module for the Roblox build: bundle.py writes build/ImGuiTyped.luau = Luau types + `require(script.Impl)`,
|
||||
# where Impl is the untouched build/ImGui.luau (the bundle itself is too large for Luau's type inference to finish,
|
||||
# so the types live in this small wrapper instead). Library sources and the LÖVE build are not affected.
|
||||
# Public ImGui.* signatures come from upstream imgui.h (namespace ImGui), mapped onto the port's own parameter lists.
|
||||
# Anything ambiguous (overloads, char* buffers, arrays, multiple out-params, count mismatch) falls back to `any`,
|
||||
# so the types never reject code that runs. Enum tables (ImGuiWindowFlags, ImGuiCol, ...) get their exact keys.
|
||||
# Self-check: python3 tools/gen_types.py (prints a few signatures)
|
||||
import os, re
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
NUM = re.compile(r"^(int|float|double|unsigned int|unsigned short|short|size_t|ImU32|ImS32|ImU64|ImS64|ImWchar|ImGuiID|Im\w*Flags|ImGui(Col|Cond|StyleVar|Key|MouseButton|MouseCursor|Dir|DataType|SortDirection|TableBgTarget|Axis))$")
|
||||
VEC = {"ImVec2": "ImVec2", "ImVec4": "ImVec4"}
|
||||
|
||||
def lua_type(ctype):
|
||||
t = re.sub(r"\bconst\b|&", "", ctype).strip()
|
||||
t = re.sub(r"\s+", " ", t)
|
||||
if t == "char*": return "string" if "const" in ctype else None
|
||||
if t == "bool": return "boolean"
|
||||
if NUM.match(t): return "number"
|
||||
return VEC.get(t)
|
||||
|
||||
def split_params(s):
|
||||
out, depth, cur = [], 0, ""
|
||||
for ch in s:
|
||||
if ch in "([": depth += 1
|
||||
if ch in ")]": depth -= 1
|
||||
if ch == "," and depth == 0: out.append(cur); cur = ""
|
||||
else: cur += ch
|
||||
if cur.strip(): out.append(cur)
|
||||
return [p.strip() for p in out]
|
||||
|
||||
def upstream_decls():
|
||||
src = open(os.path.join(ROOT, "tools", "test", "upstream", "imgui.h")).read()
|
||||
body = src[src.index("namespace ImGui\n"):src.index("} // namespace ImGui")]
|
||||
decls = {}
|
||||
for m in re.finditer(r"IMGUI_API\s+([\w\s\*&]+?)\s*\b(\w+)\((.*?)\)\s*(?:IM_FMT\w+\(\d+\))?\s*;", body):
|
||||
decls.setdefault(m.group(2), []).append((m.group(1).strip(), split_params(m.group(3)) if m.group(3).strip() not in ("", "void") else []))
|
||||
return decls
|
||||
|
||||
LOOSE = "(...any) -> ...any"
|
||||
PORT_ONLY = { # port additions that aren't in imgui.h
|
||||
"SetNextWindowCached": "(key: any) -> ()",
|
||||
"NewTextBuffer": "(str: string, size: number?) -> {number}",
|
||||
"TextBufferToString": "(buf: {number}) -> string",
|
||||
}
|
||||
|
||||
def signature(port_params, ret, cparams):
|
||||
if any(p == "..." for p in cparams):
|
||||
if port_params and port_params[-1] == "...": port_params = port_params[:-1]
|
||||
cparams = [p for p in cparams if p != "..."]; vararg = True
|
||||
else: vararg = False
|
||||
if len(port_params) != len(cparams): return LOOSE
|
||||
args, outs = [], []
|
||||
for name, cp in zip(port_params, cparams):
|
||||
decl, _, default = cp.partition("=")
|
||||
m = re.match(r"(.*?)\b(\w+)\s*(\[\w*\])?\s*$", decl.strip())
|
||||
if not m: return LOOSE
|
||||
ctype, array = m.group(1).strip(), m.group(3)
|
||||
if "(*" in cp: return LOOSE
|
||||
ptr = ctype.endswith("*") and not re.search(r"\bchar\s*\*$", ctype)
|
||||
if array: t = None; outs.append("array")
|
||||
elif ptr and re.search(r"\bconst\b", ctype): t = None # input array (e.g. ColorPicker4 ref_col)
|
||||
elif ptr:
|
||||
t = lua_type(ctype[:-1])
|
||||
if t in ("boolean", "number"): outs.append(t)
|
||||
else: t = None; outs.append("other")
|
||||
else: t = lua_type(ctype)
|
||||
if name == "...": args.append("...any"); continue
|
||||
opt = "?" if (default.strip() or (ptr and t == "boolean")) else ""
|
||||
args.append("%s: %s%s" % (name, t or "any", opt if t else ""))
|
||||
if vararg: args.append("...any")
|
||||
r = re.sub(r"\bconst\b|&|IMGUI_API", "", ret).strip()
|
||||
if r == "void": rt = "...any" if outs else "()"
|
||||
elif r == "bool":
|
||||
scal = [o for o in outs if o != "array"]
|
||||
if not scal: rt = "boolean"
|
||||
elif len(scal) == 1 and scal[0] == "boolean": rt = "(boolean, boolean?)"
|
||||
elif len(scal) == 1 and scal[0] == "number": rt = "(number, boolean)"
|
||||
else: rt = "...any"
|
||||
else:
|
||||
rt = lua_type(r) or "any"
|
||||
if outs: rt = "...any"
|
||||
return "(%s) -> %s" % (", ".join(args), rt)
|
||||
|
||||
def port_functions(files):
|
||||
fns = {}
|
||||
for src in files.values():
|
||||
for m in re.finditer(r"^function ImGui\.(\w+)\((.*?)\)", src, re.M):
|
||||
fns[m.group(1)] = [p.strip() for p in m.group(2).split(",") if p.strip()]
|
||||
return fns
|
||||
|
||||
def enums(files):
|
||||
src = files.get("imgui_h.lua", "")
|
||||
out = {}
|
||||
for m in re.finditer(r"^(Im\w+) = \{\n(.*?)^\}", src, re.M | re.S):
|
||||
keys = re.findall(r"^\s+(\w+)\s*=", m.group(2), re.M)
|
||||
if keys: out[m.group(1)] = keys
|
||||
for f in files.values(): # keys added later (ImGuiKey letters in loops are covered by the indexer below)
|
||||
for name, key in re.findall(r"^\s*(Im\w+)\.(\w+)\s*=", f, re.M):
|
||||
if name in out and key not in out[name]: out[name].append(key)
|
||||
return out
|
||||
|
||||
def types_header(files):
|
||||
decls, fns = upstream_decls(), port_functions(files)
|
||||
lines = ["export type ImVec2 = { x: number, y: number, [any]: any }",
|
||||
"export type ImVec4 = { x: number, y: number, z: number, w: number, [any]: any }",
|
||||
"export type ImGuiAPI = {"]
|
||||
for name in sorted(fns):
|
||||
d = decls.get(name)
|
||||
sig = PORT_ONLY.get(name) or (signature(fns[name], *d[0]) if d and len(d) == 1 else LOOSE)
|
||||
lines.append(" %s: %s," % (name, sig))
|
||||
lines += [" [string]: any,", "}"]
|
||||
for name, keys in sorted(enums(files).items()):
|
||||
lines.append("export type %s = { %s, [string]: number }" % (name, ", ".join("%s: number" % k for k in keys)))
|
||||
return lines + module_type(set(enums(files)))
|
||||
|
||||
def wrapper(files):
|
||||
return "\n".join(["--!strict", "-- GENERATED by tools/gen_types.py - do not edit. The library is the child ModuleScript 'Impl'.", ""]
|
||||
+ types_header(files) + ["", "return (require(script:WaitForChild(\"Impl\")) :: any) :: ImGuiModule", ""])
|
||||
|
||||
def module_type(enum_names):
|
||||
# the bundle is too large for Luau to infer, so its return value is cast to this explicit type
|
||||
lines = ["export type ImGuiModule = {", " ImGui: ImGuiAPI,"]
|
||||
lines += [" %s: (x: number?, y: number?, z: number?, w: number?) -> %s," % (n, n) for n in ("ImVec2", "ImVec4")]
|
||||
lines += [" %s: %s," % (n, n) for n in sorted(enum_names)]
|
||||
return lines + [" [string]: any,", "}"]
|
||||
|
||||
if __name__ == "__main__":
|
||||
import glob
|
||||
files = {os.path.basename(f): open(f).read() for f in glob.glob(os.path.join(ROOT, "*.lua"))}
|
||||
lines = types_header(files)
|
||||
for l in lines:
|
||||
if re.match(r" (Begin|Checkbox|SliderFloat|SliderFloat3|Text|Button|Combo|GetCursorPos|InputText|DragFloatRange2):", l): print(l)
|
||||
loose = sum(LOOSE in l for l in lines); print("%d functions, %d loose" % (sum(l.startswith(" ") for l in lines), loose))
|
||||
@@ -0,0 +1,58 @@
|
||||
-- SetNextWindowCached: the same scripted scenario runs twice, window "Win##A" uncached then "Win##B" cached.
|
||||
-- Every frame the window's draw list must hash identically in both phases, while B's body runs far less often.
|
||||
-- run: python3 tools/test/run.py --main tools/test/scripts/t_cached_window.luau --frames 130 --quiet --roblox
|
||||
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||
ImGui.CreateContext()
|
||||
G.ImGui_ImplRoblox.Init()
|
||||
G.ImGui_ImplRoblox.SetRenderRate(0)
|
||||
local io = ImGui.GetIO()
|
||||
local P = 60 -- frames per phase
|
||||
local frame, hashes, runs = 0, {}, { A = 0, B = 0 }
|
||||
|
||||
local function hash(dl)
|
||||
local h = 0
|
||||
local function mix(v) h = (h * 31 + math.floor(v * 64 + 0.5)) % 2147483647 end
|
||||
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
|
||||
return h
|
||||
end
|
||||
|
||||
game:GetService("RunService").Stepped:Connect(function()
|
||||
frame += 1
|
||||
if frame > 2 * P then return end
|
||||
local phase = frame <= P and "A" or "B"
|
||||
local t = (frame - 1) % P + 1 -- frame within the phase
|
||||
G.ImGui_ImplRoblox.NewFrame()
|
||||
io.DeltaTime = 1 / 60
|
||||
-- mouse: away, over the button (hover highlight), away again
|
||||
if t >= 20 and t < 26 then io:AddMousePosEvent(60, 75) else io:AddMousePosEvent(700, 500) end
|
||||
local key = math.floor(t / 15) -- data version: changes at t = 15, 30, 45
|
||||
ImGui.NewFrame()
|
||||
if t == 3 then ImGui.SetWindowFocus(nil) end -- focused -> unfocused title bar must not stay stale
|
||||
if t == 1 then ImGui.SetNextWindowFocus() end
|
||||
ImGui.SetNextWindowPos(ImVec2(20, 20), G.ImGuiCond.Always)
|
||||
ImGui.SetNextWindowSize(ImVec2(220, 140), G.ImGuiCond.Always)
|
||||
if phase == "B" then ImGui.SetNextWindowCached(key) end
|
||||
local _, visible = ImGui.Begin("Win##" .. phase)
|
||||
if visible then
|
||||
runs[phase] += 1
|
||||
ImGui.Button("Button")
|
||||
ImGui.Text("value %d", key)
|
||||
ImGui.SliderFloat("slider", key * 0.1, 0, 1)
|
||||
end
|
||||
ImGui.End()
|
||||
ImGui.Render()
|
||||
local h = hash(ImGui.FindWindowByName("Win##" .. phase).DrawList)
|
||||
if phase == "A" then hashes[t] = h
|
||||
elseif h ~= hashes[t] then error(("frame %d: cached draw list differs from uncached"):format(t)) end
|
||||
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||
if frame == 2 * P then
|
||||
print(("runs: uncached %d, cached %d"):format(runs.A, runs.B))
|
||||
assert(runs.A == P, "uncached window must run every frame")
|
||||
assert(runs.B < P / 3, "cached window ran too often")
|
||||
print("CACHED OK")
|
||||
end
|
||||
end)
|
||||
@@ -124,12 +124,24 @@ local function MyTool()
|
||||
end
|
||||
-- [/snippet]
|
||||
|
||||
-- [snippet:cached]
|
||||
local stats = { version = 0, kills = 0 }
|
||||
local function StatsWindow()
|
||||
ImGui.SetNextWindowCached(stats.version) -- bump stats.version whenever stats change
|
||||
local _, visible = ImGui.Begin("Stats")
|
||||
if visible then -- false while the cached contents are reused
|
||||
ImGui.Text("Kills: %d", stats.kills)
|
||||
end
|
||||
ImGui.End()
|
||||
end
|
||||
-- [/snippet]
|
||||
|
||||
local frame = 0
|
||||
RunService.Stepped:Connect(function()
|
||||
frame += 1
|
||||
G.ImGui_ImplRoblox.NewFrame()
|
||||
ImGui.NewFrame()
|
||||
MyFirstTool(); MyTool(); Conventions(); MenusAndTable(); Plot(); CustomDrawing()
|
||||
MyFirstTool(); MyTool(); Conventions(); MenusAndTable(); Plot(); CustomDrawing(); StatsWindow()
|
||||
ImGui.Render()
|
||||
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
|
||||
if frame == 20 then
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
|
||||
local ImGui, ImVec2 = G.ImGui, G.ImVec2
|
||||
local UIS = game:GetService("UserInputService")
|
||||
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init()
|
||||
ImGui.CreateContext(); G.ImGui_ImplRoblox.Init(); G.ImGui_ImplRoblox.SetTextProxy(true)
|
||||
local io = ImGui.GetIO()
|
||||
local buf = ImGui.NewTextBuffer("", 64)
|
||||
local proxy
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "4dbug/imgui-luau"
|
||||
version = "0.1.2"
|
||||
registry = "https://github.com/UpliftGames/wally-index"
|
||||
realm = "shared"
|
||||
license = "MIT"
|
||||
description = "Dear ImGui (docking branch) ported to Luau for Roblox"
|
||||
repository = "https://github.com/4DBug/imgui-luau"
|
||||
|
||||
[dependencies]
|
||||
Reference in New Issue
Block a user