Commit e25e6420 authored by Leander Schulten's avatar Leander Schulten
Browse files

UI/UX: In the settings tab you can now customize the theme. Use this theme in...

UI/UX: In the settings tab you can now customize the theme. Use this theme in the main window and the color dialog. The TextUnderline of TextInputFields is still "lightgreen". The Theme settings are stored in the per user settings of the OS.
Closes #55
parent 2cbc5277
Pipeline #191743 passed with stage
in 4 minutes and 59 seconds
......@@ -81,5 +81,6 @@
<file>qml/components/ColorDialog.qml</file>
<file>qml/components/ColorSlider.qml</file>
<file>qml/AudioEventsView.qml</file>
<file>qml/ModifyThemePane.qml</file>
</qresource>
</RCC>
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Layouts 1.12
import custom.licht 1.0
import "components"
GridLayout {
id: root
columns: 2
RowLayout{
Layout.columnSpan: 2
Label{
Layout.leftMargin: 10
Layout.fillWidth: true
text: "Theme:"
}
ComboBox{
model: ["Light", "Dark"]
currentIndex: Settings.theme
onCurrentIndexChanged: Settings.theme = currentIndex
}
Button{
text: "Reset this theme"
Layout.rightMargin: 10
onClicked: {
Settings.accentColor = undefined;
Settings.accentMaterial = undefined;
Settings.accentShade = undefined;
Settings.foregroundColor = undefined;
Settings.foregroundMaterial = undefined;
Settings.foregroundShade = undefined;
Settings.backgroundColor = undefined;
Settings.backgroundMaterial = undefined;
Settings.backgroundShade = undefined;
}
}
}
TabBar{
id: target
Layout.columnSpan: 2
Layout.fillWidth: true
position: TabBar.Footer
TabButton{
text: "Accent"
}
TabButton{
text: "Foreground"
}
TabButton{
text: "Background"
}
}
function updateColor(){
let color;
if(!colorSelection.isMaterialColor){
color = colorSelection.getColor(colorSelection.currentIndex);
}else{
if(shade.currentIndex === 0){
color = Material.color(colorSelection.materialIndex);
}else{
color = Material.color(colorSelection.materialIndex, shade.currentIndex - 1);
}
}
switch(target.currentIndex){
case 0: Settings.accentColor = color; break;
case 1: Settings.foregroundColor = color; break;
case 2: Settings.backgroundColor = color; break;
}
}
ListView{
property color customColor;
onCustomColorChanged: {
switch(target.currentIndex){
case 0: Settings.accentColor = customColor; break;
case 1: Settings.foregroundColor = customColor; break;
case 2: Settings.backgroundColor = customColor; break;
}
}
readonly property int numOwn: 1
property bool isMaterialColor: currentIndex >= numOwn
property int materialIndex: currentIndex - numOwn
function getColor(index){
switch(index){
case 0: return customColor;
default: return Material.color(index - numOwn);
}
}
function updateCurrentIndex(){
switch(target.currentIndex){
case 0:
customColor = Settings.accentColor;
currentIndex = Settings.accentMaterial >= 0 ? Settings.accentMaterial + numOwn : 0;
return;
case 1:
customColor = Settings.foregroundColor;
currentIndex = Settings.foregroundMaterial >= 0 ? Settings.foregroundMaterial + numOwn : 0;
return;
case 2:
customColor = Settings.backgroundColor;
currentIndex = Settings.backgroundMaterial >= 0 ? Settings.backgroundMaterial + numOwn : 0;
return;
}
console.error("Error in ModifyThemePane at customColor.currentIndex: ...")
}
Component.onCompleted: {
Settings.themeChanged.connect(updateCurrentIndex);
Settings.accentMaterialChanged.connect(updateCurrentIndex);
Settings.backgroundMaterialChanged.connect(updateCurrentIndex);
Settings.foregroundMaterialChanged.connect(updateCurrentIndex);
target.currentIndexChanged.connect(updateCurrentIndex);
updateCurrentIndex();
}
keyNavigationEnabled: true
Layout.fillHeight: true
Layout.preferredWidth: root.width/2
clip: true
id: colorSelection
model: ["Custom", "Red", "Pink", "Purple", "Deep Purple", "Indigo", "Blue", "Light Blue", "Cyan", "Teal", "Green", "Light Green", "Lime", "Yellow", "Amber", "Orange", "Deep Orange", "Brown", "Grey", "Blue Grey"]
delegate: RadioDelegate{
width: colorSelection.width
background: Rectangle{
color: colorSelection.getColor(index)
}
text: modelData;
checked: colorSelection.currentIndex === index;
onClicked: {
colorSelection.currentIndex = index;
switch(target.currentIndex){
case 0: Settings.accentMaterial = index - colorSelection.numOwn; break;
case 1: Settings.foregroundMaterial = index - colorSelection.numOwn; break;
case 2: Settings.backgroundMaterial = index - colorSelection.numOwn; break;
}
root.updateColor();
}
}
maximumFlickVelocity: 600
boundsBehavior: Flickable.DragOverBounds
}
Item{
Layout.fillHeight: true
Layout.preferredWidth: root.width/2
RowLayout{
visible: !colorSelection.isMaterialColor
anchors.fill: parent
anchors.rightMargin: 15
ColorSlider{
Layout.fillHeight: true
Layout.preferredWidth: parent.width/3-2
orientation: Gradient.Vertical
value: colorSelection.customColor.hsvHue
onValueChanged: if(!colorSelection.isMaterialColor)colorSelection.customColor.hsvHue = value;
gradient: Gradient{
GradientStop{ position: 0/360; color: Qt.hsva( 0/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 60/360; color: Qt.hsva( 60/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 120/360; color: Qt.hsva(120/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 180/360; color: Qt.hsva(180/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 240/360; color: Qt.hsva(240/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 300/360; color: Qt.hsva(300/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 360/360; color: Qt.hsva(360/360,colorSelection.customColor.hsvSaturation,colorSelection.customColor.hsvValue,1);}
}
}
ColorSlider{
Layout.fillHeight: true
Layout.preferredWidth: parent.width/3-2
orientation: Gradient.Vertical
value: colorSelection.customColor.hsvSaturation
onValueChanged: if(!colorSelection.isMaterialColor)colorSelection.customColor.hsvSaturation = value;
gradient: Gradient{
GradientStop{ position: 0; color: Qt.hsva(colorSelection.customColor.hsvHue,0,colorSelection.customColor.hsvValue,1);}
GradientStop{ position: 1; color: Qt.hsva(colorSelection.customColor.hsvHue,1,colorSelection.customColor.hsvValue,1);}
}
}
ColorSlider{
Layout.fillHeight: true
Layout.preferredWidth: parent.width/3-2
orientation: Gradient.Vertical
value: colorSelection.customColor.hsvValue
onValueChanged: if(!colorSelection.isMaterialColor)colorSelection.customColor.hsvValue = value;
gradient: Gradient{
GradientStop{ position: 0; color: Qt.hsva(colorSelection.customColor.hsvHue,colorSelection.customColor.hsvSaturation,0,1);}
GradientStop{ position: 1; color: Qt.hsva(colorSelection.customColor.hsvHue,colorSelection.customColor.hsvSaturation,1,1);}
}
}
}
ListView{
visible: colorSelection.isMaterialColor
anchors.fill: parent
enabled: colorSelection.currentIndex !== 0
keyNavigationEnabled: true
function updateCurrentIndex(){
switch(target.currentIndex){
case 0: currentIndex = Settings.accentShade >= 0 ? Settings.accentShade + 1 : 0; return;
case 1: currentIndex = Settings.foregroundShade >= 0 ? Settings.foregroundShade + 1 : 0; return;
case 2: currentIndex = Settings.backgroundShade >= 0 ? Settings.backgroundShade + 1 : 0; return;
}
console.error("Error in ModifyThemePane at customColor.currentIndex: ...")
}
Component.onCompleted: {
Settings.themeChanged.connect(updateCurrentIndex);
Settings.accentShadeChanged.connect(updateCurrentIndex);
Settings.backgroundShadeChanged.connect(updateCurrentIndex);
Settings.foregroundShadeChanged.connect(updateCurrentIndex);
target.currentIndexChanged.connect(updateCurrentIndex);
}
clip: true
id: shade
model: ["Default", "Shade 50", "Shade 100", "Shade 200", "Shade 300", "Shade 400", "Shade 500", "Shade 600", "Shade 700", "Shade 800", "Shade 900", "Shade A100", "Shade A200", "Shade A400", "Shade A700"]
delegate: RadioDelegate{
width: shade.width
background: Rectangle{
color: colorSelection.currentIndex === 0 && root.Material.theme>=0 ? "white" : index === 0 ? Material.color(colorSelection.materialIndex) : Material.color(colorSelection.materialIndex, index - 1);
}
text: modelData;
checked: shade.currentIndex === index;
onClicked: {
shade.currentIndex = index;
switch(target.currentIndex){
case 0: Settings.accentShade = index - colorSelection.numOwn; break;
case 1: Settings.foregroundShade = index - colorSelection.numOwn; break;
case 2: Settings.backgroundShade = index - colorSelection.numOwn; break;
}
root.updateColor();
}
}
maximumFlickVelocity: 600
boundsBehavior: Flickable.DragOverBounds
}
}
}
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Layouts 1.12
import QtQuick.Dialogs 1.3
import QtQuick.Window 2.12
import "components"
Pane{
......@@ -112,6 +114,14 @@ Pane{
currentIndex: AudioManager.currentCaptureDevice
onDownChanged: if(down)AudioManager.updateCaptureDeviceList()
}
Label{
Layout.fillWidth: true
text: "Theme:"
}
Button{
text: "Modify Theme and appearance"
onClicked: modifyThemeWindow.show()
}
}
FileDialog{
property var callback;
......@@ -130,4 +140,17 @@ Pane{
}
}
}
Window{
id: modifyThemeWindow
flags: Qt.WindowStaysOnTopHint | Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
title: "Modify Theme"
color: pane.Material.background
width: 350
height: 350
Material.theme: Settings.theme
ModifyThemePane{
id: pane
anchors.fill: parent
}
}
}
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Controls 2.12
import QtQuick.Controls.Material 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
import custom.licht 1.0
Window {
id: root
......@@ -20,6 +22,11 @@ Window {
signal colorSelected(color selectedColor);
onClosing: colorSelected(currentColor);
Material.background: Settings.backgroundColor
Material.foreground: Settings.foregroundColor
Material.accent: Settings.accentColor
Material.theme: Settings.theme
color: Settings.backgroundColor
ColumnLayout{
anchors.fill: parent
......
......@@ -15,7 +15,10 @@ ApplicationWindow {
height: 480
title: qsTr("Lichtsteuerung")
Material.background: Settings.backgroundColor
Material.foreground: Settings.foregroundColor
Material.accent: Settings.accentColor
Material.theme: Settings.theme
Item{
anchors.fill: parent
......
......@@ -2,14 +2,48 @@
#define SETTINGS_H
#include "modules/compiler.h"
#include <QColor>
#include <QDir>
#include <QFile>
#include <QObject>
#include <QSettings>
#include <optional>
class Settings : public QObject
{
#define MAKE_STRING(s) #s
#define ThemeColorProperty(type, paramType, name, defaultLight, defaultDark) \
private: \
Q_PROPERTY(type name READ get##name WRITE set##name NOTIFY name##Changed RESET reset##name) \
public: \
type get##name() { \
if (getTheme() == 0) { \
if (auto v = value(QStringLiteral(MAKE_STRING(light##name))); !v.isNull()) { \
return v.value<type>(); \
} \
return defaultLight; \
} \
if (auto v = value(QStringLiteral(MAKE_STRING(dark##name))); !v.isNull()) { \
return v.value<type>(); \
} \
return defaultDark; \
} \
void set##name(paramType c) { \
if (getTheme() == 0) { \
if (c != get##name()) { \
setValue(QStringLiteral(MAKE_STRING(light##name)), c); \
emit name##Changed(); \
} \
} \
if (c != get##name()) { \
setValue(QStringLiteral(MAKE_STRING(dark##name)), c); \
emit name##Changed(); \
} \
} \
void reset##name() { set##name(getTheme() == 0 ? (defaultLight) : (defaultDark)); } \
Q_SIGNALS: \
void name##Changed();
class Settings : public QObject {
Q_OBJECT
QSettings settings;
std::optional<QSettings> localSettings;
......@@ -20,6 +54,7 @@ class Settings : public QObject
Q_PROPERTY(QString compilerFlags READ getCompilerFlags WRITE setCompilerFlags NOTIFY compilerFlagsChanged)
Q_PROPERTY(QString compilerLibraryFlags READ getCompilerLibraryFlags WRITE setCompilerLibraryFlags NOTIFY compilerLibraryFlagsChanged)
Q_PROPERTY(QString includePath READ getIncludePath WRITE setIncludePath NOTIFY includePathChanged)
Q_PROPERTY(int theme READ getTheme WRITE setTheme NOTIFY themeChanged)
Q_PROPERTY(unsigned int updatePauseInMs READ getUpdatePauseInMs WRITE setUpdatePauseInMs NOTIFY updatePauseInMsChanged)
static inline QFileInfo localSettingsFile;
public:
......@@ -112,9 +147,34 @@ public:
Modules::Compiler::compilerLibraryFlags = _compilerLibraryFlags; emit compilerLibraryFlagsChanged();
}
}
QString getCompilerLibraryFlags() const {
return Modules::Compiler::compilerLibraryFlags;
QString getCompilerLibraryFlags() const { return Modules::Compiler::compilerLibraryFlags; }
void setTheme(int theme) {
if (theme != getTheme()) {
setValue(QStringLiteral("theme"), theme);
emit themeChanged();
emit foregroundColorChanged();
emit foregroundMaterialChanged();
emit foregroundShadeChanged();
emit backgroundColorChanged();
emit backgroundMaterialChanged();
emit backgroundShadeChanged();
emit accentColorChanged();
emit accentMaterialChanged();
emit accentShadeChanged();
}
}
int getTheme() { return value(QStringLiteral("theme")).toInt(); }
ThemeColorProperty(QColor, const QColor &, foregroundColor, QColor(Qt::black), QColor(0xfa, 0xfa, 0xfa))
ThemeColorProperty(int, int, foregroundMaterial, -1, -1)
ThemeColorProperty(int, int, foregroundShade, -1, -1)
ThemeColorProperty(QColor, const QColor &, backgroundColor, QColor(0xfa, 0xfa, 0xfa), QColor(0x30, 0x30, 0x30))
ThemeColorProperty(int, int, backgroundMaterial, -1, -1)
ThemeColorProperty(int, int, backgroundShade, -1, -1)
ThemeColorProperty(QColor, const QColor &, accentColor, QColor(0xE9, 0x1E, 0x63), QColor(0xF4, 0x8F, 0xB1))
ThemeColorProperty(int, int, accentMaterial, 1, 1)
ThemeColorProperty(int, int, accentShade, -1, -1)
signals:
void jsonSettingsFilePathChanged();
void driverFilePathChanged();
......@@ -124,6 +184,7 @@ signals:
void compilerFlagsChanged();
void compilerLibraryFlagsChanged();
void includePathChanged();
void themeChanged();
public slots:
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment