style: get button to consistently look ok in reasonable palettes

This commit is contained in:
outfoxxed 2025-01-06 19:46:57 -08:00
parent 9a1c66532b
commit ed177913b0
No known key found for this signature in database
GPG key ID: 4C88A185FB89301E
4 changed files with 143 additions and 13 deletions

View file

@ -1,10 +1,35 @@
import QtQuick
import QtQuick.Controls.Basic as T
import QtQuick.Templates as T
import org.hyprland.style.impl
// This is private and we shouldn't use it, however rewriting IconLabel would take hundreds of
// lines of C++ to end up with something worse.
import QtQuick.Controls.impl as ControlsPrivate
T.Button {
id: control
implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, implicitContentWidth + leftPadding + rightPadding)
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding)
padding: 6
spacing: 6
icon.width: 24
icon.height: 24
icon.color: control.palette.buttonText
contentItem: ControlsPrivate.IconLabel {
spacing: control.spacing
mirrored: control.mirrored
display: control.display
icon: control.icon
text: control.text
font: control.font
color: control.palette.buttonText
}
background: Rectangle {
implicitWidth: 50
implicitHeight: 30
@ -12,14 +37,26 @@ T.Button {
radius: HyprlandStyle.radius
border.width: HyprlandStyle.borderWidth
MotionBehavior on color { ColorAnimation { duration: 50 } }
color: control.down || control.checked
? Qt.tint(control.palette.button, Qt.alpha(control.palette.highlight, 0.4))
: control.flat ? "transparent" : control.palette.button
MotionBehavior on color { ColorAnimation { duration: 60 } }
color: {
let highlightTint = control.down || control.checked ? 0.3 : control.highlighted ? 0.25 : 0.0;
MotionBehavior on border.color { ColorAnimation { duration: 50 } }
border.color: control.hovered || control.highlighted || control.down || control.checked
? control.palette.highlight
: control.flat ? "transparent" : control.palette.light
if (control.flat && highlightTint)
highlightTint += 0.3;
const base = HyprlandStyle.flat(control.palette.button, control.flat);
return HyprlandStyle.overlay(base, control.palette.highlight, highlightTint);
}
MotionBehavior on border.color { ColorAnimation { duration: 60 } }
border.color: {
let highlightTint = control.down || control.checked ? 0.8 : (control.enabled && control.hovered) || control.highlighted ? 0.6 : 0.0;
if (control.flat && highlightTint)
highlightTint += 0.2;
const base = HyprlandStyle.flat(HyprlandStyle.lightenOrDarken(control.palette.button, 1.4), control.flat);
return HyprlandStyle.overlay(base, control.palette.highlight, highlightTint);
}
}
}

View file

@ -2,7 +2,44 @@ pragma Singleton
import QtQuick
QtObject {
property real radius: 8
id: root
property real borderWidth: 1
property real radius: 7
property bool reduceMotion: false
function flat(color: color, flat: bool): color {
return flat ? root.transparent(color) : color;
}
function isDark(cg: ColorGroup): bool {
return cg.windowText.hsvValue > cg.window.hsvValue;
}
function lightenOrDarken(color: color, factor: real): color {
return color.hsvValue > 0.5 ? Qt.darker(color, factor) : Qt.lighter(color, factor);
}
function overlay(base: color, tint: color, tintOpacity: real): color {
return Qt.tint(base, Qt.alpha(tint, tintOpacity));
}
function scaledColor(cg: ColorGroup, index: int): color {
switch (index * (root.isDark(cg) ? 1 : -1)) {
case -2:
return cg.light;
case -1:
return cg.midlight;
case 1:
return cg.mid;
case 2:
return cg.dark;
}
}
// ColorAnimation animates all properties of a color, instead of mixing normally, so
// transparency has to have the same RGB.
function transparent(color: color): color {
return Qt.alpha(color, 0.0);
}
}

View file

@ -2,12 +2,15 @@
#include <qguiapplication.h>
#include <qqmlapplicationengine.h>
#include <qquickstyle.h>
#include <qtenvironmentvariables.h>
int main(int argc, char** argv) {
auto app = QGuiApplication(argc, argv);
QGuiApplication::setApplicationName("Hyprland style gallery");
QQuickStyle::setStyle("org.hyprland.style");
if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE"))
QQuickStyle::setStyle("org.hyprland.style");
QQmlApplicationEngine engine;

View file

@ -5,6 +5,7 @@ import QtQuick.Controls
import org.hyprland.style.impl
ApplicationWindow {
id: window
visible: true
ScrollView {
@ -61,6 +62,55 @@ ApplicationWindow {
}
RowLayout {
ColumnLayout {
Layout.maximumWidth: 300
Label { text: "Palette" }
SystemPalette { id: activePalette; colorGroup: SystemPalette.Active }
SystemPalette { id: inactivePalette; colorGroup: SystemPalette.Inactive }
SystemPalette { id: disabledPalette; colorGroup: SystemPalette.Disabled }
component PaletteColor: Rectangle {
required property string name;
required property var cg;
implicitWidth: 50
implicitHeight: 20
color: cg[name]
}
component PaletteItem: RowLayout {
id: pi
property alias text: label.text
property string color;
Label {
id: label
Layout.fillWidth: true
}
PaletteColor { name: pi.color; cg: activePalette }
PaletteColor { name: pi.color; cg: inactivePalette }
PaletteColor { name: pi.color; cg: disabledPalette }
}
PaletteItem { text: "Light"; color: "light" }
PaletteItem { text: "Midlight"; color: "midlight" }
PaletteItem { text: "Button"; color: "button" }
PaletteItem { text: "Window"; color: "window" }
PaletteItem { text: "Mid"; color: "mid" }
PaletteItem { text: "Dark"; color: "dark" }
PaletteItem { text: "Base"; color: "base" }
PaletteItem { text: "Text"; color: "text" }
PaletteItem { text: "Button Text"; color: "buttonText" }
PaletteItem { text: "Window Text"; color: "windowText" }
PaletteItem { text: "Highli Text"; color: "highlightedText" }
PaletteItem { text: "Placeholder"; color: "placeholderText" }
PaletteItem { text: "Shadow"; color: "shadow" }
PaletteItem { text: "Highlight"; color: "highlight" }
PaletteItem { text: "Accent"; color: "accent" }
}
ColumnLayout {
Layout.maximumWidth: 200
Label { text: "Button" }
@ -71,10 +121,13 @@ ApplicationWindow {
TestButton { text: "Flat"; flat: true; }
TestButton { text: "Highlighted"; highlighted: true }
TestButton { text: "Flat Highlighted"; flat: true; highlighted: true }
TestButton { text: "Checked"; checked: true }
TestButton { text: "Flat Checked"; flat: true; checked: true }
TestButton { text: "Checked"; checkable: true; checked: true }
TestButton { text: "Flat Checked"; flat: true; checkable: true; checked: true }
TestButton { text: "Down"; down: true }
TestButton { text: "Flat Down"; flat: true; down: true }
TestButton { text: "Disabled"; enabled: false }
TestButton { text: "With Icon"; icon.name: "folder" }
TestButton { icon.name: "folder" }
}
Item { Layout.fillWidth: true }