style: Custom DarkComboBox + DarkTab (Dracula theme throughout)
- DarkComboBox: PopupWindow dropdown with Dracula colors, replaces all std ComboBox - DarkTab: custom tab bar with purple underline, replaces std TabWidget - All 7 .slint files updated, zero std-widgets Button/ComboBox/TabWidget remaining Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
28fbf10b79
commit
4e93f4fd97
8 changed files with 166 additions and 44 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
import { ComboBox } from "std-widgets.slint";
|
|
||||||
import { Theme } from "../theme.slint";
|
import { Theme } from "../theme.slint";
|
||||||
import { DarkButton } from "dark_button.slint";
|
import { DarkButton } from "dark_button.slint";
|
||||||
import { AppState, ConnectionBridge, ConnectionState } from "../globals.slint";
|
import { AppState, ConnectionBridge, ConnectionState } from "../globals.slint";
|
||||||
|
|
|
||||||
83
ui/components/dark_combo_box.slint
Normal file
83
ui/components/dark_combo_box.slint
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { Theme } from "../theme.slint";
|
||||||
|
|
||||||
|
export component DarkComboBox inherits Rectangle {
|
||||||
|
in property <[string]> model;
|
||||||
|
in-out property <int> current-index: 0;
|
||||||
|
in-out property <string> current-value: model.length > 0 && current-index >= 0 && current-index < model.length ? model[current-index] : "";
|
||||||
|
callback selected(string);
|
||||||
|
|
||||||
|
height: 28px;
|
||||||
|
min-width: 60px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: ta.has-hover ? Theme.button-hover : Theme.button-bg;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: Theme.bg-primary;
|
||||||
|
|
||||||
|
HorizontalLayout {
|
||||||
|
padding-left: 8px;
|
||||||
|
padding-right: 6px;
|
||||||
|
spacing: 4px;
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.current-value;
|
||||||
|
color: Theme.fg-primary;
|
||||||
|
font-size: 11px;
|
||||||
|
vertical-alignment: center;
|
||||||
|
horizontal-stretch: 1;
|
||||||
|
overflow: elide;
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: "v";
|
||||||
|
color: Theme.fg-secondary;
|
||||||
|
font-size: 9px;
|
||||||
|
vertical-alignment: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ta := TouchArea {
|
||||||
|
clicked => { popup.show(); }
|
||||||
|
mouse-cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
popup := PopupWindow {
|
||||||
|
x: 0;
|
||||||
|
y: root.height;
|
||||||
|
width: root.width;
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
background: Theme.bg-primary;
|
||||||
|
border-radius: 4px;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: Theme.accent-purple;
|
||||||
|
|
||||||
|
VerticalLayout {
|
||||||
|
padding: 2px;
|
||||||
|
|
||||||
|
for item[idx] in root.model : Rectangle {
|
||||||
|
height: 26px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: item-ta.has-hover ? Theme.button-hover : idx == root.current-index ? Theme.bg-secondary : transparent;
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: item;
|
||||||
|
color: idx == root.current-index ? Theme.accent-purple : Theme.fg-primary;
|
||||||
|
font-size: 11px;
|
||||||
|
vertical-alignment: center;
|
||||||
|
horizontal-alignment: left;
|
||||||
|
x: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
item-ta := TouchArea {
|
||||||
|
clicked => {
|
||||||
|
root.current-index = idx;
|
||||||
|
root.current-value = item;
|
||||||
|
root.selected(item);
|
||||||
|
}
|
||||||
|
mouse-cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { LineEdit, ComboBox, ScrollView } from "std-widgets.slint";
|
import { LineEdit, ScrollView } from "std-widgets.slint";
|
||||||
import { Theme } from "../theme.slint";
|
import { Theme } from "../theme.slint";
|
||||||
import { DarkButton } from "dark_button.slint";
|
import { DarkButton } from "dark_button.slint";
|
||||||
|
import { DarkComboBox } from "dark_combo_box.slint";
|
||||||
import { KeySelectorBridge, KeymapBridge, KeyEntry, KeycapData } from "../globals.slint";
|
import { KeySelectorBridge, KeymapBridge, KeyEntry, KeycapData } from "../globals.slint";
|
||||||
import { KeyButton } from "key_button.slint";
|
import { KeyButton } from "key_button.slint";
|
||||||
|
|
||||||
|
|
@ -169,13 +170,13 @@ export component KeySelector inherits Rectangle {
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
Text { text: "Mod:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
Text { text: "Mod:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
||||||
mt-mod := ComboBox {
|
mt-mod := DarkComboBox {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
model: ["Ctrl", "Shift", "Alt", "GUI", "RCtrl", "RShift", "RAlt", "RGUI"];
|
model: ["Ctrl", "Shift", "Alt", "GUI", "RCtrl", "RShift", "RAlt", "RGUI"];
|
||||||
current-index: 1;
|
current-index: 1;
|
||||||
}
|
}
|
||||||
Text { text: "Key:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
Text { text: "Key:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
||||||
mt-key := ComboBox {
|
mt-key := DarkComboBox {
|
||||||
width: 70px;
|
width: 70px;
|
||||||
model: ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","Space","Enter","Esc","Tab","Bksp"];
|
model: ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","1","2","3","4","5","6","7","8","9","0","Space","Enter","Esc","Tab","Bksp"];
|
||||||
current-index: 0;
|
current-index: 0;
|
||||||
|
|
@ -201,13 +202,13 @@ export component KeySelector inherits Rectangle {
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
Text { text: "Layer:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
Text { text: "Layer:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
||||||
lt-layer := ComboBox {
|
lt-layer := DarkComboBox {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
model: ["0","1","2","3","4","5","6","7","8","9"];
|
model: ["0","1","2","3","4","5","6","7","8","9"];
|
||||||
current-index: 1;
|
current-index: 1;
|
||||||
}
|
}
|
||||||
Text { text: "Key:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
Text { text: "Key:"; color: Theme.fg-secondary; font-size: 11px; vertical-alignment: center; }
|
||||||
lt-key := ComboBox {
|
lt-key := DarkComboBox {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
model: ["Space","Enter","Esc","Bksp","Tab","A","B","C","D","E"];
|
model: ["Space","Enter","Esc","Bksp","Tab","A","B","C","D","E"];
|
||||||
current-index: 0;
|
current-index: 0;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { TabWidget } from "std-widgets.slint";
|
|
||||||
import { Theme } from "theme.slint";
|
import { Theme } from "theme.slint";
|
||||||
import { AppState, ActiveTab } from "globals.slint";
|
import { AppState, ActiveTab } from "globals.slint";
|
||||||
import { ConnectionBar } from "components/connection_bar.slint";
|
import { ConnectionBar } from "components/connection_bar.slint";
|
||||||
|
|
@ -14,6 +13,37 @@ import { TabFlasher } from "tabs/tab_flasher.slint";
|
||||||
export { AppState, Theme }
|
export { AppState, Theme }
|
||||||
export { ConnectionBridge, KeymapBridge, SettingsBridge, StatsBridge, AdvancedBridge, MacroBridge, FlasherBridge, KeySelectorBridge } from "globals.slint";
|
export { ConnectionBridge, KeymapBridge, SettingsBridge, StatsBridge, AdvancedBridge, MacroBridge, FlasherBridge, KeySelectorBridge } from "globals.slint";
|
||||||
|
|
||||||
|
component DarkTab inherits Rectangle {
|
||||||
|
in property <string> title;
|
||||||
|
in property <bool> active;
|
||||||
|
callback clicked();
|
||||||
|
|
||||||
|
height: 32px;
|
||||||
|
horizontal-stretch: 1;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: root.active ? Theme.bg-secondary : transparent;
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: root.title;
|
||||||
|
color: root.active ? Theme.fg-primary : Theme.fg-secondary;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: root.active ? 600 : 400;
|
||||||
|
horizontal-alignment: center;
|
||||||
|
vertical-alignment: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
y: parent.height - 2px;
|
||||||
|
height: 2px;
|
||||||
|
background: root.active ? Theme.accent-purple : transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
TouchArea {
|
||||||
|
clicked => { root.clicked(); }
|
||||||
|
mouse-cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export component MainWindow inherits Window {
|
export component MainWindow inherits Window {
|
||||||
title: "KaSe Controller";
|
title: "KaSe Controller";
|
||||||
preferred-width: 1000px;
|
preferred-width: 1000px;
|
||||||
|
|
@ -22,38 +52,44 @@ export component MainWindow inherits Window {
|
||||||
min-height: 450px;
|
min-height: 450px;
|
||||||
background: Theme.bg-primary;
|
background: Theme.bg-primary;
|
||||||
|
|
||||||
|
in-out property <int> current-tab: 0;
|
||||||
|
|
||||||
VerticalLayout {
|
VerticalLayout {
|
||||||
ConnectionBar { }
|
ConnectionBar { }
|
||||||
|
|
||||||
TabWidget {
|
// Tab bar
|
||||||
vertical-stretch: 1;
|
Rectangle {
|
||||||
|
height: 34px;
|
||||||
|
background: Theme.bg-primary;
|
||||||
|
|
||||||
Tab {
|
HorizontalLayout {
|
||||||
title: "Keymap";
|
padding-left: 8px;
|
||||||
TabKeymap { }
|
padding-right: 8px;
|
||||||
}
|
spacing: 2px;
|
||||||
Tab {
|
|
||||||
title: "Advanced";
|
DarkTab { title: "Keymap"; active: root.current-tab == 0; clicked => { root.current-tab = 0; } }
|
||||||
TabAdvanced { }
|
DarkTab { title: "Advanced"; active: root.current-tab == 1; clicked => { root.current-tab = 1; } }
|
||||||
}
|
DarkTab { title: "Macros"; active: root.current-tab == 2; clicked => { root.current-tab = 2; } }
|
||||||
Tab {
|
DarkTab { title: "Stats"; active: root.current-tab == 3; clicked => { root.current-tab = 3; } }
|
||||||
title: "Macros";
|
DarkTab { title: "Settings"; active: root.current-tab == 4; clicked => { root.current-tab = 4; } }
|
||||||
TabMacros { }
|
DarkTab { title: "Flash"; active: root.current-tab == 5; clicked => { root.current-tab = 5; } }
|
||||||
}
|
|
||||||
Tab {
|
|
||||||
title: "Stats";
|
|
||||||
TabStats { }
|
|
||||||
}
|
|
||||||
Tab {
|
|
||||||
title: "Settings";
|
|
||||||
TabSettings { }
|
|
||||||
}
|
|
||||||
Tab {
|
|
||||||
title: "Flash";
|
|
||||||
TabFlasher { }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tab content
|
||||||
|
Rectangle {
|
||||||
|
vertical-stretch: 1;
|
||||||
|
background: Theme.bg-secondary;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
if root.current-tab == 0 : TabKeymap { }
|
||||||
|
if root.current-tab == 1 : TabAdvanced { }
|
||||||
|
if root.current-tab == 2 : TabMacros { }
|
||||||
|
if root.current-tab == 3 : TabStats { }
|
||||||
|
if root.current-tab == 4 : TabSettings { }
|
||||||
|
if root.current-tab == 5 : TabFlasher { }
|
||||||
|
}
|
||||||
|
|
||||||
StatusBar { }
|
StatusBar { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { ComboBox, ScrollView } from "std-widgets.slint";
|
import { ScrollView } from "std-widgets.slint";
|
||||||
import { Theme } from "../theme.slint";
|
import { Theme } from "../theme.slint";
|
||||||
import { DarkButton } from "../components/dark_button.slint";
|
import { DarkButton } from "../components/dark_button.slint";
|
||||||
|
import { DarkComboBox } from "../components/dark_combo_box.slint";
|
||||||
import { AdvancedBridge, AppState, ConnectionState, KeymapBridge } from "../globals.slint";
|
import { AdvancedBridge, AppState, ConnectionState, KeymapBridge } from "../globals.slint";
|
||||||
|
|
||||||
component SectionHeader inherits Text {
|
component SectionHeader inherits Text {
|
||||||
|
|
@ -44,7 +45,7 @@ component PickButton inherits Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component ModComboBox inherits ComboBox {
|
component ModComboBox inherits DarkComboBox {
|
||||||
model: ["None", "Ctrl", "Shift", "Alt", "GUI", "RCtrl", "RShift", "RAlt", "RGUI"];
|
model: ["None", "Ctrl", "Shift", "Alt", "GUI", "RCtrl", "RShift", "RAlt", "RGUI"];
|
||||||
width: 90px;
|
width: 90px;
|
||||||
}
|
}
|
||||||
|
|
@ -300,11 +301,11 @@ export component TabAdvanced inherits Rectangle {
|
||||||
spacing: 8px;
|
spacing: 8px;
|
||||||
alignment: start;
|
alignment: start;
|
||||||
Text { text: "L1:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
Text { text: "L1:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
||||||
ComboBox { width: 50px; model: ["0","1","2","3","4","5","6","7","8","9"]; current-index <=> AdvancedBridge.tri-l1-idx; }
|
DarkComboBox { width: 50px; model: ["0","1","2","3","4","5","6","7","8","9"]; current-index <=> AdvancedBridge.tri-l1-idx; }
|
||||||
Text { text: "L2:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
Text { text: "L2:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
||||||
ComboBox { width: 50px; model: ["0","1","2","3","4","5","6","7","8","9"]; current-index <=> AdvancedBridge.tri-l2-idx; }
|
DarkComboBox { width: 50px; model: ["0","1","2","3","4","5","6","7","8","9"]; current-index <=> AdvancedBridge.tri-l2-idx; }
|
||||||
Text { text: "-> L3:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
Text { text: "-> L3:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
||||||
ComboBox { width: 50px; model: ["0","1","2","3","4","5","6","7","8","9"]; current-index <=> AdvancedBridge.tri-l3-idx; }
|
DarkComboBox { width: 50px; model: ["0","1","2","3","4","5","6","7","8","9"]; current-index <=> AdvancedBridge.tri-l3-idx; }
|
||||||
DarkButton { text: "Set"; clicked => { AdvancedBridge.set-trilayer(AdvancedBridge.tri-l1-idx, AdvancedBridge.tri-l2-idx, AdvancedBridge.tri-l3-idx); } }
|
DarkButton { text: "Set"; clicked => { AdvancedBridge.set-trilayer(AdvancedBridge.tri-l1-idx, AdvancedBridge.tri-l2-idx, AdvancedBridge.tri-l3-idx); } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { ComboBox, LineEdit } from "std-widgets.slint";
|
import { LineEdit } from "std-widgets.slint";
|
||||||
import { Theme } from "../theme.slint";
|
import { Theme } from "../theme.slint";
|
||||||
import { DarkButton } from "../components/dark_button.slint";
|
import { DarkButton } from "../components/dark_button.slint";
|
||||||
|
import { DarkComboBox } from "../components/dark_combo_box.slint";
|
||||||
import { FlasherBridge } from "../globals.slint";
|
import { FlasherBridge } from "../globals.slint";
|
||||||
|
|
||||||
export component TabFlasher inherits Rectangle {
|
export component TabFlasher inherits Rectangle {
|
||||||
|
|
@ -44,7 +45,7 @@ export component TabFlasher inherits Rectangle {
|
||||||
HorizontalLayout {
|
HorizontalLayout {
|
||||||
spacing: 8px;
|
spacing: 8px;
|
||||||
|
|
||||||
if FlasherBridge.prog-ports.length > 0 : ComboBox {
|
if FlasherBridge.prog-ports.length > 0 : DarkComboBox {
|
||||||
horizontal-stretch: 1;
|
horizontal-stretch: 1;
|
||||||
model: FlasherBridge.prog-ports;
|
model: FlasherBridge.prog-ports;
|
||||||
selected(value) => {
|
selected(value) => {
|
||||||
|
|
@ -89,7 +90,7 @@ export component TabFlasher inherits Rectangle {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBox {
|
DarkComboBox {
|
||||||
model: ["factory (0x20000)", "ota_0 (0x220000)"];
|
model: ["factory (0x20000)", "ota_0 (0x220000)"];
|
||||||
current-index <=> FlasherBridge.flash-offset-index;
|
current-index <=> FlasherBridge.flash-offset-index;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { ComboBox, ScrollView, LineEdit } from "std-widgets.slint";
|
import { ScrollView, LineEdit } from "std-widgets.slint";
|
||||||
import { Theme } from "../theme.slint";
|
import { Theme } from "../theme.slint";
|
||||||
import { DarkButton } from "../components/dark_button.slint";
|
import { DarkButton } from "../components/dark_button.slint";
|
||||||
|
import { DarkComboBox } from "../components/dark_combo_box.slint";
|
||||||
import { MacroBridge, AppState, ConnectionState, KeymapBridge } from "../globals.slint";
|
import { MacroBridge, AppState, ConnectionState, KeymapBridge } from "../globals.slint";
|
||||||
|
|
||||||
export component TabMacros inherits Rectangle {
|
export component TabMacros inherits Rectangle {
|
||||||
|
|
@ -38,7 +39,7 @@ export component TabMacros inherits Rectangle {
|
||||||
alignment: start;
|
alignment: start;
|
||||||
|
|
||||||
Text { text: "Slot:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
Text { text: "Slot:"; color: Theme.fg-secondary; font-size: 12px; vertical-alignment: center; }
|
||||||
ComboBox {
|
DarkComboBox {
|
||||||
width: 60px;
|
width: 60px;
|
||||||
model: ["0","1","2","3","4","5","6","7","8","9"];
|
model: ["0","1","2","3","4","5","6","7","8","9"];
|
||||||
current-index <=> MacroBridge.new-slot-idx;
|
current-index <=> MacroBridge.new-slot-idx;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ComboBox } from "std-widgets.slint";
|
|
||||||
import { Theme } from "../theme.slint";
|
import { Theme } from "../theme.slint";
|
||||||
|
import { DarkComboBox } from "../components/dark_combo_box.slint";
|
||||||
import { SettingsBridge } from "../globals.slint";
|
import { SettingsBridge } from "../globals.slint";
|
||||||
|
|
||||||
export component TabSettings inherits Rectangle {
|
export component TabSettings inherits Rectangle {
|
||||||
|
|
@ -46,7 +46,7 @@ export component TabSettings inherits Rectangle {
|
||||||
|
|
||||||
VerticalLayout {
|
VerticalLayout {
|
||||||
alignment: center;
|
alignment: center;
|
||||||
ComboBox {
|
DarkComboBox {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
model: SettingsBridge.available-layouts;
|
model: SettingsBridge.available-layouts;
|
||||||
current-index <=> SettingsBridge.selected-layout-index;
|
current-index <=> SettingsBridge.selected-layout-index;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue