nxlayout 工具與視覺化編輯器
前面幾章的 .nxlay 面板設計檔,除了用文字編輯器手寫,PDK 還附兩個工具幫你做:
| 工具 | 是什麼 | 在 PDK 的位置 |
|---|---|---|
nxlayout.exe | 命令列工具:驗證 .nxlay、求解版面、輸出 C 標頭 | tools\x64\、tools\x86\(旁邊的 nxlayout_core.dll 要一起放) |
nxlayout_editor.exe | 視覺化編輯器:拖曳排版、即時預覽兩個版本、驗證、輸出標頭、AI 輔助 | editor\ |
不要和主程式的
F9「版面配置器」搞混。F9是使用者在主程式裡決定「畫面上放哪幾個面板、怎麼分割」用的 (見檢視選單),它排的是主程式的面板配置。 這一章的編輯器是你(Plugin 作者)設計自己那個 Widget 面板裡面有哪些控制項用的,它產出.nxlay檔,跟主程式的設定無關。
啟動與主視窗
直接執行 nxlayout_editor.exe。PDK 附的是自帶執行環境的單一檔案版本,不需要另外安裝 .NET。
第一次開啟時中間是空的,有三個入口:New blank panel(新空白面板)、Import from existing .h…(從既有的 .h 匯入)、Open sample(開範例)。
主視窗是可停靠的窗格,View 選單可以開關,Reset Layout to Default 還原預設排列:
| 窗格 | 用途 |
|---|---|
| Toolbox | 15 種控制項型別的清單,拖到畫布上新增 |
| Outline | 目前面板所有控制項的清單(ID、型別、標籤、寬度狀態) |
| Canvas | 主編輯區 |
| Inspector | 選取項目的屬性表 |
| Error List | 驗證錯誤的即時清單 |
| Preview | 視窗版/終端機版兩種真實渲染的預覽 |
| AI | 用自然語言請外部 AI 產生或修改面板(與 Inspector 同一組頁籤) |

Canvas 畫的不是示意圖,是求解器的真實輸出:編輯器與 nxlayout --solve、與主程式用的是同一份排版程式,所以你在畫布上看到的位置與工具算出來的逐格相同。
標題列的 * 表示有未存檔的變更;意外關閉後重開,會問你要不要復原上次沒存的內容;檔案在編輯器外被改動時也會問你要重新載入還是保留你的版本。
建立新面板:空白、範本精靈、匯入
三種起手方式:
- New blank panel(
File > New,Ctrl+N):輸入面板尺寸,建立一個沒有控制項的新文件。 - New from template(精靈):選一個內建範本(表單、儀表板、工具列三種),調整面板的寬與高,按
Create。只有這兩個參數。 - Import from existing .h…:把一份
nxlayout --emit-header產生的.h讀回來還原成可編輯的面板。這是從既有 C 程式進入編輯器的唯一路徑。

Toolbox:新增控制項
Toolbox 列出全部 15 種型別。新增有兩種方式:
- 拖曳:把項目拖到 Canvas 上放開,控制項出現在放開位置對應的格子。
- 雙擊:雙擊項目,控制項附加在面板目前內容的最下面一列。
新增出來的控制項預設值已經滿足驗證規則,例如 METER/SPIN/CHART 已填 NumMax = 100、GROUPBOX 已勾 Decoration 且 H = 5、
SEPARATOR/TEXTBOX/DROPDOWN 已有 Weight = 1。各型別的用途與欄位見Widget 型別詳解。


Canvas:選取、移動、調整、對齊
- 選取:單擊選一個;在空白處拖曳框選多個。
- 移動:拖曳選取中的控制項,改變它的
X與Y。 - 調整尺寸:單選一個控制項時,右下角出現實心藍色控點。水平拖曳改
MinW,垂直拖曳改H。MaxW與Weight拖不到,只能在 Inspector 輸入。 - 複製/貼上/刪除:
Ctrl+D複製選取項目、Ctrl+C/Ctrl+V剪貼簿複製貼上、Delete刪除。刪除不重新編號:被刪掉的WidgetId就空出來,不會被後來新增的控制項沿用。 - 復原/重做:
Ctrl+Z/Ctrl+Y。 - 對齊與均分(
Edit選單,作用在多選的控制項):靠左、靠右、靠上、靠下、水平置中、垂直置中、水平均分、垂直均分。 - 縮放:畫布會自動把面板放大填滿視窗(整數倍),只影響顯示;求解永遠用面板的
RefW/RefH。


Inspector:每一個屬性
Inspector 是右邊的屬性表,選了控制項顯示控制項的屬性,沒選任何控制項時顯示整個面板的屬性。 底下的說明列會顯示目前選中那個屬性的簡短說明。改了值,Canvas、Outline、Preview 立刻跟著變。
Inspector 只顯示對該型別有意義的屬性。 沒出現的屬性就是那個型別用不到。 下面每一項都寫了:作用、哪些型別看得到、範圍與意義、怎麼調整(輸入=在格子裡打數字或文字,下拉=從清單選,勾選=True/False,拖曳=在 Canvas 上直接拖)。
面板層級(沒選任何控制項時)

| 屬性 | 作用與意義 | 怎麼調整 |
|---|---|---|
RefW | 參考寬度(抽象格):這份版面是以多寬設計的。編輯器與 nxlayout --solve 預設就用它當面板寬。不要留 0:留 0 的話生存掃描會退回 20 格寬 | 輸入 |
RefH | 參考高度(抽象格)。超過這個高度的列會被求解成不可見,Outline 會標成「一定隱藏」 | 輸入 |
Guides | 欄導引線在參考寬度下的 x 位置(抽象格)。空的代表沒有導引線,控制項只靠 X 定位。最多 8 條 | 集合編輯(點右邊 (Collection) 的按鈕新增、刪除、改值) |
GuideWeight | 每條導引線那一欄的長大權重,0 代表該欄固定寬。必須是空的,或長度剛好等於 Guides | 集合編輯 |
GuideMaxW | 每一欄的寬度上限(抽象格),0 代表沒有上限。必須是空的,或長度剛好等於 Guides | 集合編輯 |
導引線是進階功能:宣告了導引線之後,同一欄的控制項可以綁到同一條線,上下對齊,並且整欄一起依權重長大。不需要就不要宣告。
控制項層級
下面這張表列出全部的控制項屬性,以及各型別哪些會出現:
| 屬性 | 出現在 | 範圍與意義 |
|---|---|---|
WidgetId | 全部 | 面板內唯一的識別碼,也是 .nxlay 裡 [w.N] 的 N。C 端的事件與 SetWidgetProp 都靠它辨認。不能重複 |
Type | 全部 | 控制項型別,決定其他哪些屬性有意義 |
Y | 全部 | 列座標(抽象格,0 起算)。Y 相同的控制項在同一列。宣告順序中 Y 不可遞減 |
X | 全部 | 欄座標(抽象格)。同一列裡後一個要放在前一個的 X + MinW 之後。就算綁了導引線也要填成與該導引線設計時位置相符,否則常會觸發「同列重疊」 |
MinW | 全部 | 最小寬度(抽象格)。面板窄到放不下就會隱藏(見Widget 模式深入) |
MaxW | 全部 | 長大上限(抽象格),0 是不設上限。非 0 時必須不小於 MinW |
Weight | 全部 | 分配剩餘寬度的權重,0 是固定寬(永遠等於 MinW) |
H | TABLE、GROUPBOX、CHART、IMAGE | 高度(抽象格)。0 是自動(延伸到下一列或面板底)。GROUPBOX 一定要明確給。TABLE 的高度其實由「到下一列的距離」決定,H 對它沒有作用 |
Label | 除了 IMAGE、CHART 以外全部 | 標籤/按鈕文字/標題,最多 31 個字元。TEXTBOX、SPIN、METER、CHOICE、FILEPICK、SEPARATOR 雖然能填,但畫面上不會畫出來 |
ItemCount | DROPDOWN、CHOICE | 選項數,0~8。選項文字由 C 端以 SetWidgetProp 的 NX_WP_ITEMS 設定 |
NumMin | METER、SPIN | 數值下限(有號整數) |
NumMax | METER、SPIN | 數值上限(有號整數)。不可為 0,而且要大於 NumMin |
NumStep | SPIN | 每次增減量,0 視為 1 |
Aux | IMAGE、FILEPICK | IMAGE 的圖檔名,或 FILEPICK 的篩選字串(例如 *.bin)。不能含 \、/、:、.. |
Optional | 全部 | 勾選=空間不夠時可以被隱藏(由後往前,與其他 Optional 控制項一起) |
Decoration | 全部 | 勾選=純裝飾:不可聚焦、不受「跨列重疊」規則限制、畫在最底層。實務上只有 GROUPBOX 需要 |
Activatable | METER、CHART、IMAGE、LABEL、VALUE | 勾選=這個原本唯讀的控制項可聚焦、可以被點,並送 ACTIVATED 事件。其他型別不合法,所以 Inspector 直接不顯示這一項 |
XGuide | 面板宣告了 Guides 時,全部 | 這個控制項那一段從哪條導引線開始;(unbound) 是不綁。下拉選單會列出 guide 0 @ x=0 這樣的選項。這只是備用方式,主要做法是在 Canvas 上拖曳吸附 |
哪些用拖曳、哪些只能輸入: X、Y 可以拖曳移動;MinW 與 H 可以拖右下角控點;
MaxW 與 Weight 沒有拖曳手勢,一定要在 Inspector 輸入。 其餘屬性都在 Inspector 輸入、下拉或勾選。
沒有出現在 Inspector 的欄位:.nxlay 裡的 flags=DISABLED、flags=PASSWORD、flags=ALIGN_RIGHT,
以及 preview_* 預覽用欄位,編輯器沒有對應的輸入格。要用它們請直接在 .nxlay 文字裡寫,編輯器重新存檔時會保留。
另外 CHART 的 NumMin/NumMax(縱軸範圍)與 Label 也不在 Inspector 裡,同樣要直接改文字。
各型別實際看到的屬性長什麼樣:






改屬性的效果:下面兩張是把按鈕的 MinW 從 8 改成 20 的前後對照,Canvas 與底下的 Preview 都跟著變寬。


Preview:視窗版與終端機版雙預覽
Preview 窗格有兩個選項:GUI(視窗版的真實 GDI 渲染)與 TUI(終端機版的真實字元格渲染)。兩者都是主程式的渲染器輸出,不是編輯器自己模擬的示意。 每個預覽同時並排畫幾種面板寬度(生存掃描),讓你在改版面前就看到窄面板下哪個控制項會消失。


Error List:驗證錯誤
每次編輯,編輯器都用和 nxlayout --solve 同一套驗證重新檢查整份文件,違規的地方列在 Error List:
| 欄位 | 內容 |
|---|---|
| Rule | 違反的規則名稱,例如 x_overlap、y_order、num_range |
| Widget | 出問題的控制項 WidgetId |
| Message | 說明(英文) |
雙擊一列會選取該控制項。 驗證只回報第一個違規,修好它才會看到下一個。

一共有 11 條版面規則,加上 .nxlay 文字本身的語法錯誤(顯示為 parse_error):
| 規則名稱 | 意思 |
|---|---|
count_limit | 一個面板最多 32 個控制項 |
y_order | Y 在宣告順序中不可遞減 |
x_overlap | 同一列相鄰的兩個控制項不可重疊:後一個的 X 要大於等於前一個的 X + MinW |
y_overlap | 不同列、水平範圍相交的控制項不可在垂直方向重疊(Decoration 的除外) |
guide_order | 同一列裡 XGuide 要依宣告順序嚴格遞增 |
guide_dup | 同一列裡兩個控制項不可綁同一條導引線 |
constraint | MaxW 非 0 時不可小於 MinW;XGuide 不可超出導引線數 |
num_range | NumMax 非 0 時要大於 NumMin;METER/SPIN 的 NumMax 不可為 0 |
id_bounds | WidgetId 不可重複;ItemCount 不可超過 8 |
groupbox_aux | GROUPBOX 的 H 不可為 0;Aux 不可含 \、/、:、.. |
activatable | Activatable 只限 METER/CHART/IMAGE/LABEL/VALUE,且不能與 Decoration 並用 |
存檔前 Error List 要是空的:有違規時編輯器拒絕存檔(會跳出 Could not save - the current document is not in a valid state 的訊息)。
所以你不會存出一份驗證不過的 .nxlay。不過拿去給 Plugin 用之前,仍建議用 nxlayout --solve 再獨立驗一次,因為檔案之後可能被手改過。
AI 面板:用自然語言產生或修改面板
AI 面板請外部的 AI 服務依你的描述產生一份 .nxlay。它接受任何相容 OpenAI Chat Completions 格式的端點;
本站的截圖是接到本機執行的 Ollama(http://127.0.0.1:11434/v1)拍的,模型名稱照實顯示在畫面上,你可以換成任何相容的端點。

設定:填 Endpoint、Model、API key。API key 用 Windows DPAPI(目前使用者範圍)加密後才存檔,只有同一個 Windows 使用者帳號在同一台機器上解得開;
Endpoint 與 Model 不是機密,明文存放。也可以用環境變數 NXLAYOUT_AI_API_KEY 提供金鑰(有設就優先使用,不會寫到磁碟)。設定都存在 %APPDATA%\NxLayoutEditor\,不會進 .nxlay、也不會進你的專案。
用法:
- 設
ref_w、ref_h(面板尺寸),在Request描述你要的面板。可以附圖(例如手繪草圖),下方顯示已附幾張。 - 想改現有的面板而不是新做一份,勾 Modify current layout:AI 會拿到目前的版面當基礎。
- 按 Generate。第一次使用會跳出同意視窗,說明你的請求(以及目前的版面與附圖)會送給你設定的外部 AI 服務,送出去等於公開,可能被對方保存或索引。同意後才會送。
- 每次送出前,按鈕下方都有一行摘要:
Will send: ... lines of current layout, N image(s), N characters of prompt,明確寫出要送什麼。Show full request 可以展開看完整的請求內容。

結果:AI 的輸出會先驗證(要通過和 Error List 一樣的規則)。沒通過就把錯誤訊息回饋給 AI 自動重試,預設最多 3 次;還是不行就顯示失敗。 連線錯誤、逾時這類失敗不會自動重試(重試也不會變好,還會白花你的 token),按 Retry 由你決定。
驗證通過的結果是一份草稿,標示 AI draft - not adopted,畫面上會顯示這次用了多少 token;此時它還沒有進到你的文件:

- Adopt:採用,草稿變成你的文件內容,這是一筆可以復原(
Ctrl+Z)的編輯。 - Discard:丟掉,什麼都沒改。
- Retry:用同樣的請求再產生一次。
AI 面板從不自己寫檔,採用之後你仍要自己存檔,存檔前也一樣要通過驗證。


存檔與匯出標頭
Ctrl+S/Ctrl+Shift+S:存成.nxlay(UTF-8、無 BOM)。File > Export to Header (.h)...:呼叫與命令列--emit-header相同的產生器,輸出一份.h(控制項陣列、面板佈局與個數巨集)。.h是產物,永遠不要手改。 你的.c用#include引進它;改了.nxlay就要重新匯出, 建置不會替你重新產生,也沒有任何東西檢查兩個檔案有沒有不同步,見第一個 Plugin 4。

命令列:nxlayout.exe
不開編輯器也能做同樣的檢查,適合自動化與 CI。PDK 的 tools\x64\ 與 tools\x86\ 各有一份,
nxlayout.exe 要和同資料夾的 nxlayout_core.dll 放在一起。 檔名 - 代表從標準輸入讀。
rem 驗證並求解,輸出 JSON。預設用 [panel] 的 ref_w / ref_h 當面板大小
nxlayout --solve hello_ic_panel.nxlay
rem 指定面板大小,檢查窄面板下有沒有控制項消失
nxlayout --solve hello_ic_panel.nxlay --w 40 --h 10
rem 用字母格顯示求解出的版面(示意,不是真實渲染)
nxlayout --ascii hello_ic_panel.nxlay --w 40 --h 10
rem 產生 C 標頭
nxlayout --emit-header hello_ic_panel.nxlay hello_ic_panel.h
rem 印出 .nxlay 格式速查卡
nxlayout --format-card--solve一律把 JSON 印到標準輸出:"ok"表示驗證有沒有通過,"errors"是錯誤(含規則名稱與說明),"widgets"是每個控制項的visible(1可見、0因為裝不下被隱藏)與位置大小。檢查有沒有控制項消失,就看有沒有"visible":0。- 結束碼:
0是成功;驗證失敗是2。規則是第一個失敗錯誤碼的絕對值,腳本只要判斷是不是 0 就夠了。 --solve沒指定--w/--h,.nxlay也沒有ref_w/ref_h時,面板尺寸是 0,工具會印警告,這時請補上--w、--h。- 還有一個
--render(輸出 RGB 影像,給截圖之類的自動化用),一般開發用不到。
一個建議的工作流程
- 用編輯器(或手寫)設計面板,Error List 清空,存成
xxx_panel.nxlay。 - 用 Preview 或
nxlayout --solve --w 40確認窄面板下重要的控制項還在。 Export to Header或nxlayout --emit-header產生xxx_panel.h。- 你的
.c#include它取得控制項編號,在init以LoadLayout載入.nxlay本身(嵌成RCDATA資源或放在 DLL 旁邊,見第一個 Plugin 4)。 - 之後要改版面:回到步驟 1,存檔後一定重新產生
.h。
除了這裡的 15 種控制項與 11 條規則,.nxlay 格式的完整規格在 PDK 的 docs\NEXUS_LAYOUT_TOOL_SDD.md,nxlayout --format-card 也印得出來。