Split monolithic main.rs into domain modules: - context.rs: AppContext shared state, BgMsg enum, serial_spawn helper - models.rs: UI model builders, keycap labels, key entries, layout preview - config.rs: keyboard config export/import via binary protocol - dispatch.rs: BgMsg handler + WPM/layout timers - keymap.rs: key selection, layer switch/rename, heatmap toggle - key_selector.rs: dispatch_keycode router, apply_keycode, hex/MT/LT - macros.rs: macro CRUD, shortcut presets, step builder - advanced.rs: combos, KO, leaders, tap dance, BT, tama, autoshift - settings.rs: OTA flash, config backup, keyboard layout - flasher.rs: ESP32 bootloader flash - layout.rs: layout JSON preview, load/export - connection.rs: serial connect/disconnect, tab auto-refresh - stats.rs: stats refresh Rename logic/ → protocol/ with cleaner file names. Remove unused original-src/ directory. Fix DarkLineEdit double styling, add rename popup, macro shortcuts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
192 lines
6.1 KiB
Text
192 lines
6.1 KiB
Text
import { DarkLineEdit } from "../components/dark_line_edit.slint";
|
|
import { Theme } from "../theme.slint";
|
|
import { DarkButton } from "../components/dark_button.slint";
|
|
import { KeymapBridge, AppState, ConnectionState } from "../globals.slint";
|
|
import { KeyboardView } from "../components/keyboard_view.slint";
|
|
|
|
export component TabKeymap inherits Rectangle {
|
|
in-out property <bool> renaming: false;
|
|
|
|
VerticalLayout {
|
|
padding: 8px;
|
|
spacing: 6px;
|
|
|
|
// Main area: layers sidebar + keyboard
|
|
HorizontalLayout {
|
|
vertical-stretch: 1;
|
|
spacing: 6px;
|
|
|
|
// Layer sidebar (vertical)
|
|
VerticalLayout {
|
|
width: 90px;
|
|
spacing: 4px;
|
|
alignment: start;
|
|
|
|
Text {
|
|
text: "Layers";
|
|
color: Theme.fg-secondary;
|
|
font-size: 11px;
|
|
horizontal-alignment: center;
|
|
}
|
|
|
|
Flickable {
|
|
vertical-stretch: 1;
|
|
VerticalLayout {
|
|
spacing: 4px;
|
|
|
|
for layer[idx] in KeymapBridge.layers : Rectangle {
|
|
height: 30px;
|
|
border-radius: 4px;
|
|
background: layer.active ? Theme.accent-purple : Theme.button-bg;
|
|
|
|
Text {
|
|
text: layer.name;
|
|
color: Theme.fg-primary;
|
|
font-size: 11px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
|
|
TouchArea {
|
|
clicked => { KeymapBridge.switch-layer(layer.index); }
|
|
mouse-cursor: pointer;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if !root.renaming && AppState.connection == ConnectionState.connected : Rectangle {
|
|
height: 24px;
|
|
border-radius: 4px;
|
|
background: rename-ta.has-hover ? Theme.button-hover : Theme.button-bg;
|
|
|
|
Text {
|
|
text: "Rename";
|
|
color: Theme.fg-secondary;
|
|
font-size: 10px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
|
|
rename-ta := TouchArea {
|
|
clicked => { root.renaming = true; }
|
|
mouse-cursor: pointer;
|
|
}
|
|
}
|
|
|
|
Rectangle { vertical-stretch: 1; }
|
|
|
|
// Heatmap toggle
|
|
Rectangle {
|
|
height: 30px;
|
|
border-radius: 4px;
|
|
background: KeymapBridge.heatmap-enabled ? Theme.accent-orange : Theme.button-bg;
|
|
|
|
Text {
|
|
text: "Heatmap";
|
|
color: Theme.fg-primary;
|
|
font-size: 11px;
|
|
horizontal-alignment: center;
|
|
vertical-alignment: center;
|
|
}
|
|
|
|
TouchArea {
|
|
clicked => {
|
|
KeymapBridge.heatmap-enabled = !KeymapBridge.heatmap-enabled;
|
|
if KeymapBridge.heatmap-enabled { KeymapBridge.toggle-heatmap(); }
|
|
}
|
|
mouse-cursor: pointer;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Keyboard view
|
|
KeyboardView {
|
|
horizontal-stretch: 1;
|
|
}
|
|
}
|
|
|
|
// Selected key info bar
|
|
if KeymapBridge.selected-key-index >= 0 : Rectangle {
|
|
height: 36px;
|
|
background: Theme.bg-secondary;
|
|
border-radius: 4px;
|
|
|
|
HorizontalLayout {
|
|
padding: 8px;
|
|
spacing: 12px;
|
|
|
|
Text {
|
|
text: "Selected: " + KeymapBridge.selected-key-label;
|
|
color: Theme.accent-cyan;
|
|
font-size: 12px;
|
|
vertical-alignment: center;
|
|
}
|
|
|
|
Rectangle { horizontal-stretch: 1; }
|
|
|
|
DarkButton {
|
|
text: "Change Key...";
|
|
clicked => {
|
|
KeymapBridge.key-selector-open = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Rename popup overlay
|
|
if root.renaming : Rectangle {
|
|
background: #000000aa;
|
|
|
|
TouchArea {
|
|
clicked => { root.renaming = false; }
|
|
}
|
|
|
|
Rectangle {
|
|
width: 260px;
|
|
height: 120px;
|
|
border-radius: 8px;
|
|
background: Theme.bg-secondary;
|
|
|
|
VerticalLayout {
|
|
padding: 16px;
|
|
spacing: 12px;
|
|
alignment: center;
|
|
|
|
Text {
|
|
text: "Rename layer";
|
|
color: Theme.fg-primary;
|
|
font-size: 13px;
|
|
horizontal-alignment: center;
|
|
}
|
|
|
|
rename-input := DarkLineEdit {
|
|
placeholder-text: "New name";
|
|
accepted(text) => {
|
|
KeymapBridge.rename-layer(KeymapBridge.active-layer, text);
|
|
root.renaming = false;
|
|
}
|
|
}
|
|
|
|
HorizontalLayout {
|
|
spacing: 8px;
|
|
alignment: center;
|
|
|
|
DarkButton {
|
|
text: "Cancel";
|
|
clicked => { root.renaming = false; }
|
|
}
|
|
|
|
DarkButton {
|
|
text: "Rename";
|
|
clicked => {
|
|
KeymapBridge.rename-layer(KeymapBridge.active-layer, rename-input.text);
|
|
root.renaming = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|