Panel UI (NpUi)
NpUi is a small builder that describes panel content. The plugin only lists rows, and the editor draws them with controls that look the same as the built-in panels. You do not need to know Godot.
NpUi is used in two places.
| Registration point | Field | Where it appears |
|---|---|---|
AddContentTab | Build | Bottom area panel (open from the Window menu) |
AddMode | Panel | Tools panel while in that mode |
Builder methods
Section titled “Builder methods”Every method returns the same NpUi, so you chain calls with .. Rows are laid out from top to bottom in the order you write them.
| Method | What is drawn | On change |
|---|---|---|
Title(string text) | Bold group title | — |
Label(string text) | One line of text (wraps) | — |
Label(Func<string> text) | Live text. Reread every 0.5 seconds while visible | — |
Button(string text, Action click, string tooltip = "") | Button | click when pressed |
Text(string label, string initial, Action<string> changed) | Name + text field | changed on every keystroke |
Number(string label, double initial, double min, double max, double step, Action<double> changed) | Name + number field (up/down buttons) | changed every time the value changes |
Check(string label, bool initial, Action<bool> changed) | Checkbox | changed when toggled |
Separator() | Horizontal separator | — |
Live text
Section titled “Live text”Label(() => …) calls the function again every 0.5 seconds while the panel is visible and updates the text.
- It is also reread immediately when the panel becomes visible again and right after a button is pressed.
- The function is called every 0.5 seconds. Keep it light. Do not include computations that scan the whole world (
Bounds·Blocks()). - Show light values such as
CountBlocks(), or values you keep in your own fields. - If the function throws, the plugin is isolated.
When panels are built
Section titled “When panels are built”| Registration point | When it is built |
|---|---|
Build of AddContentTab | Once, when the plugin is enabled |
Panel of AddMode | Once, when that mode panel is first shown |
A panel, once built, is not rebuilt. So initial for Number · Text · Check is the value at the moment it is built. Show values that change later with Label(() => …). To use saved settings as a field’s initial value, read Settings first at the start of Register.
Example: settings panel
Section titled “Example: settings panel”private int _width = 3;private bool _lamps = true;private int _built;
public void Register(INpEditorHost host){ _width = host.Settings.GetInt("width", 3); // read first so the field's initial value is correct _lamps = host.Settings.GetBool("lamps", true);
host.AddContentTab(new NpContentTab("panel", "도로", () => new NpUi() .Title("도로 만들기") .Number("폭", _width, 1, 9, 1, v => { _width = (int)v; host.Settings.SetInt("width", _width); }) .Check("가로등", _lamps, v => { _lamps = v; host.Settings.SetBool("lamps", v); }) .Label(() => $"깐 도로 {_built}개 · 월드 블록 {host.World.CountBlocks():N0}") .Separator() .Button("선택 영역에 깔기", () => { if (host.World.Selection is not { } b) { host.Message("먼저 영역을 고르세요"); return; } _built++; // … lay the road with World.Edit … }, "선택 상자 바닥에 도로를 깝니다")));}To see the panel, turn on 도로 in the Window menu.
Tips / cautions
Section titled “Tips / cautions”- Do not put emoji or pictographic characters in on-screen text. Pictographic characters in the panel title (the
Labelfield) are stripped on screen. - Callbacks (
click·changed) are called on the editor main thread. You can callWorld.Editfrom them. - If a callback throws, the plugin is isolated. The panel disappears as the plugin is unloaded.
- Icon buttons, collapsible groups, lists and color pickers are not available yet.
- Text that is not in the editor’s translation table is not translated and appears as-is. If you need multiple languages, the plugin chooses the text itself.