// Shared data structures export struct KeycapData { x: length, y: length, w: length, h: length, rotation: float, rotation-cx: length, rotation-cy: length, label: string, sublabel: string, keycode: int, color: color, heat: float, // 0.0 = cold, 1.0 = hottest selected: bool, index: int, } export struct LayerInfo { index: int, name: string, active: bool, } export struct PortInfo { name: string, path: string, } export enum ConnectionState { disconnected, connecting, connected } export enum ActiveTab { keymap, advanced, macros, stats, settings } // Global singletons for Rust<->Slint bridge export global AppState { in-out property connection: ConnectionState.disconnected; in-out property active-tab: ActiveTab.keymap; callback tab-changed(int); in-out property status-text: "Disconnected"; in-out property spinner-visible: false; in-out property firmware-version: ""; in-out property wpm: 0; } export global ConnectionBridge { in property <[PortInfo]> ports; in-out property selected-port: ""; callback connect(); callback disconnect(); callback refresh-ports(); } export global KeymapBridge { in property <[KeycapData]> keycaps; in property <[LayerInfo]> layers; in property content-width: 860px; in property content-height: 360px; in-out property selected-key-index: -1; in-out property active-layer: 0; in-out property selected-key-label: ""; in-out property heatmap-enabled: false; in-out property key-selector-open: false; // Target for key selector: "keymap", "combo-result", "ko-trigger", "ko-result", "leader-result" in-out property selector-target: "keymap"; callback select-key(int); callback switch-layer(int); callback change-key(int, int); callback toggle-heatmap(); callback rename-layer(int, string); // layer-index, new-name } // ---- Settings ---- export global SettingsBridge { in property <[string]> available-layouts; in-out property selected-layout-index: 0; callback change-layout(int); // OTA in-out property ota-path: ""; in property ota-progress: 0; in property ota-status: ""; in property ota-flashing: false; callback ota-browse(); callback ota-start(); // Config import/export in property config-status: ""; in property config-busy: false; in property config-progress: 0; callback config-export(); callback config-import(); } // ---- Stats ---- export struct HandBalanceData { left-pct: float, right-pct: float, total: int, } export struct FingerLoadData { name: string, pct: float, count: int, } export struct RowUsageData { name: string, pct: float, count: int, } export struct TopKeyData { name: string, finger: string, count: int, pct: float, } export struct BigramData { alt-hand-pct: float, same-hand-pct: float, sfb-pct: float, total: int, } export global StatsBridge { in property hand-balance; in property <[FingerLoadData]> finger-load; in property <[RowUsageData]> row-usage; in property <[TopKeyData]> top-keys; in property <[string]> dead-keys; in property total-presses; in property bigrams; callback refresh-stats(); } // ---- Advanced ---- export struct TapDanceAction { name: string, code: int, } export struct TapDanceData { index: int, actions: [TapDanceAction], } export struct ComboData { index: int, key1: string, key2: string, result: string, } export struct LeaderData { index: int, sequence: string, result: string, } export struct KeyOverrideData { index: int, trigger: string, result: string, } export global AdvancedBridge { in property <[TapDanceData]> tap-dances; in property <[ComboData]> combos; in property <[LeaderData]> leaders; in property <[KeyOverrideData]> key-overrides; in-out property bt-status: ""; in-out property tri-l1-idx: 1; in-out property tri-l2-idx: 2; in-out property tri-l3-idx: 3; // Combo creation: physical key positions in-out property new-combo-r1: 0; in-out property new-combo-c1: 0; in-out property new-combo-key1-name: "Pick..."; in-out property new-combo-r2: 0; in-out property new-combo-c2: 0; in-out property new-combo-key2-name: "Pick..."; in-out property new-combo-result-code: 0; in-out property new-combo-result-name: "Pick..."; // KO creation: keycodes for trigger and result in-out property new-ko-trigger-code: 0; in-out property new-ko-trigger-name: "Pick..."; in-out property new-ko-trig-ctrl: false; in-out property new-ko-trig-shift: false; in-out property new-ko-trig-alt: false; in-out property new-ko-result-code: 0; in-out property new-ko-result-name: "Pick..."; in-out property new-ko-res-ctrl: false; in-out property new-ko-res-shift: false; in-out property new-ko-res-alt: false; // Leader creation in-out property new-leader-seq0-code: 0; in-out property new-leader-seq0-name: ""; in-out property new-leader-seq1-code: 0; in-out property new-leader-seq1-name: ""; in-out property new-leader-seq2-code: 0; in-out property new-leader-seq2-name: ""; in-out property new-leader-seq3-code: 0; in-out property new-leader-seq3-name: ""; in-out property new-leader-seq-count: 0; in-out property new-leader-result-code: 0; in-out property new-leader-result-name: "Pick..."; in-out property new-leader-mod-idx: 0; // TD editing: stores which TD slot+action is being edited in-out property editing-td-index: -1; in-out property editing-td-slot: -1; // 0-3 = which action callback save-td(int, int, int, int, int); // index, a1, a2, a3, a4 (keycodes) callback edit-td-action(int, int); // td_index, action_slot -> opens popup callback refresh-advanced(); callback delete-combo(int); callback delete-leader(int); callback delete-ko(int); callback set-trilayer(int, int, int); callback bt-switch(int); callback create-combo(); // reads r1,c1,r2,c2,result from properties callback create-ko(); // reads all fields from properties callback create-leader(int, int); // result_code, result_mod_idx (sequence comes from seq0-3 properties) // TAMA in property tama-status: ""; callback tama-action(string); // "feed", "play", "sleep", "meds", "toggle" // Autoshift in property autoshift-status: ""; callback toggle-autoshift(); } // ---- Macros ---- export struct MacroData { slot: int, name: string, steps: string, } export struct MacroStepDisplay { label: string, // e.g. "A", "T 100ms" is-delay: bool, } export global MacroBridge { in property <[MacroData]> macros; in-out property new-slot-idx: 0; in-out property new-name: ""; // Visual step builder in property <[MacroStepDisplay]> new-steps; in-out property new-steps-text: ""; // built text for display callback refresh-macros(); callback save-macro(); // reads slot, name, steps from properties callback delete-macro(int); callback add-delay-step(int); // delay in ms (50, 100, 200, 500) callback add-shortcut(string); // e.g. "ctrl+c", "ctrl+shift+z" callback remove-last-step(); callback clear-steps(); } // ---- OTA / Flasher ---- export global FlasherBridge { in property <[string]> prog-ports; in-out property selected-prog-port: ""; in-out property firmware-path: ""; in-out property flash-offset-index: 1; // 0=full(0x0), 1=factory(0x20000), 2=ota_0(0x220000) in property flash-progress: 0; in property flash-status: ""; in property flashing: false; callback refresh-prog-ports(); callback browse-firmware(); callback flash(); } // ---- Layout Preview ---- export global LayoutBridge { in property <[KeycapData]> keycaps; in property content-width: 860px; in property content-height: 360px; in property status: ""; in property json-text: ""; in-out property file-path: ""; in-out property auto-refresh: false; callback load-from-file(); callback load-from-keyboard(); callback load-json(string); callback export-json(); } // ---- Matrix Test ---- export global ToolsBridge { in-out property matrix-test-active: false; in property matrix-test-status: ""; // Keycap model with live press state (reuses KeycapData, color = press state) in property <[KeycapData]> matrix-keycaps; in property matrix-content-width: 860px; in property matrix-content-height: 360px; callback toggle-matrix-test(); } // ---- Key Selector ---- export struct KeyEntry { name: string, code: int, category: string, } export global KeySelectorBridge { in property <[KeyEntry]> all-keys; in property <[KeyEntry]> cat-letters; in property <[KeyEntry]> cat-numbers; in property <[KeyEntry]> cat-modifiers; in property <[KeyEntry]> cat-nav; in property <[KeyEntry]> cat-function; in property <[KeyEntry]> cat-symbols; in property <[KeyEntry]> cat-layers; in property <[KeyEntry]> cat-special; in property <[KeyEntry]> cat-td-macro; in-out property search-text: ""; in-out property hex-input: ""; in property hex-preview: ""; callback apply-filter(string); callback select-keycode(int); callback apply-hex(string); callback apply-mt(int, int); callback apply-lt(int, int); callback preview-hex(string); // updates hex-preview }