import QtQuick
import QtQuick.Controls as QQC2
import QtQuick.Layouts
import org.kde.kirigami as Kirigami
import "schedule.js" as Schedule
import "themes.js" as Themes
Kirigami.FormLayout {
id: root
twinFormLayouts: parentLayout
property alias formLayout: root
property string cfg_Pattern
property string cfg_FadeFrom
property string cfg_FadeTo
property int cfg_BokehLights
property double cfg_Speed
property int cfg_FrameRate
property bool cfg_Wordmark
property double cfg_WordmarkOpacity
property double cfg_WordmarkGlow
property bool cfg_ForegroundBokeh
property bool cfg_Glints
property bool cfg_Breathing
property bool cfg_Grain
property bool cfg_Dither
property string cfg_ThemeMode
property string cfg_Theme
property string cfg_NightTheme
property string cfg_SunriseTheme
property string cfg_DayTheme
property string cfg_SunsetTheme
property string cfg_NightPattern
property string cfg_SunrisePattern
property string cfg_DayPattern
property string cfg_SunsetPattern
property bool cfg_UseLocation
property double cfg_Latitude
property double cfg_Longitude
property string cfg_SunriseTime
property string cfg_SunsetTime
// The patterns a fade can go between; Pattern adds the fade itself.
readonly property var layers: [
{ value: "both", text: "Moire and halftone" },
{ value: "moire", text: "Moire" },
{ value: "halftone", text: "Halftone" },
{ value: "bokeh", text: "Bokeh" },
{ value: "stars", text: "Starfield" },
]
readonly property var patterns: layers.concat([{ value: "alternate", text: "Fade between two…" }])
readonly property bool followsSun: cfg_ThemeMode === "sun"
readonly property bool fading: !followsSun && cfg_Pattern === "alternate"
readonly property bool showsBokeh: followsSun
? [cfg_NightPattern, cfg_SunrisePattern, cfg_DayPattern, cfg_SunsetPattern].indexOf("bokeh") >= 0
: cfg_Pattern === "bokeh" || (fading && (cfg_FadeFrom === "bokeh" || cfg_FadeTo === "bokeh"))
component PatternBox: QQC2.ComboBox {
property var choices
property string value
signal picked(string value)
implicitContentWidthPolicy: QQC2.ComboBox.WidestText
model: choices
textRole: "text"
currentIndex: Math.max(0, choices.findIndex(p => p.value === value))
onActivated: index => picked(choices[index].value)
}
component ThemeBox: QQC2.ComboBox {
property string value
signal picked(string name)
model: Themes.names
currentIndex: Math.max(0, Themes.names.indexOf(value))
onActivated: index => picked(Themes.names[index])
}
// One phase of the day: its theme and its pattern side by side.
component PhaseRow: RowLayout {
property string theme
property string pattern
signal themePicked(string name)
signal patternPicked(string value)
visible: root.followsSun
ThemeBox { value: parent.theme; onPicked: name => parent.themePicked(name) }
PatternBox { choices: root.layers; value: parent.pattern; onPicked: v => parent.patternPicked(v) }
}
// A 0-1 setting as a slider with its percentage beside it.
component PercentSlider: RowLayout {
property double value
signal moved(double value)
QQC2.Slider {
id: slider
from: 0; to: 1; stepSize: 0.05
value: parent.value
onMoved: parent.moved(value)
}
QQC2.Label { text: Math.round(slider.value * 100) + "%" }
}
component TimeField: QQC2.TextField {
inputMask: "99:99"
validator: RegularExpressionValidator { regularExpression: /([01]\d|2[0-3]):[0-5]\d/ }
}
component DegreesField: QQC2.TextField {
property double value
signal edited(double value)
text: value.toFixed(4)
validator: DoubleValidator { bottom: -180; top: 180; decimals: 4 }
onEditingFinished: edited(Number(text))
}
// --------------------------------------------------------------- mode
QQC2.RadioButton {
Kirigami.FormData.label: "Look:"
text: "Always the same"
checked: !root.followsSun
onToggled: if (checked) root.cfg_ThemeMode = "static"
}
QQC2.RadioButton {
text: "Follow the time of day"
checked: root.followsSun
onToggled: if (checked) root.cfg_ThemeMode = "sun"
}
// ------------------------------------------------------------- static
ThemeBox {
Kirigami.FormData.label: "Theme:"
visible: !root.followsSun
value: root.cfg_Theme
onPicked: name => root.cfg_Theme = name
}
PatternBox {
Kirigami.FormData.label: "Pattern:"
visible: !root.followsSun
choices: root.patterns
value: root.cfg_Pattern
onPicked: v => root.cfg_Pattern = v
}
PatternBox {
Kirigami.FormData.label: "From:"
visible: root.fading
choices: root.layers
value: root.cfg_FadeFrom
onPicked: v => root.cfg_FadeFrom = v
}
PatternBox {
Kirigami.FormData.label: "To:"
visible: root.fading
choices: root.layers
value: root.cfg_FadeTo
onPicked: v => root.cfg_FadeTo = v
}
// ---------------------------------------------------- time of day
PhaseRow {
Kirigami.FormData.label: "Night:"
theme: root.cfg_NightTheme; pattern: root.cfg_NightPattern
onThemePicked: name => root.cfg_NightTheme = name
onPatternPicked: v => root.cfg_NightPattern = v
}
PhaseRow {
Kirigami.FormData.label: "Sunrise:"
theme: root.cfg_SunriseTheme; pattern: root.cfg_SunrisePattern
onThemePicked: name => root.cfg_SunriseTheme = name
onPatternPicked: v => root.cfg_SunrisePattern = v
}
PhaseRow {
Kirigami.FormData.label: "Day:"
theme: root.cfg_DayTheme; pattern: root.cfg_DayPattern
onThemePicked: name => root.cfg_DayTheme = name
onPatternPicked: v => root.cfg_DayPattern = v
}
PhaseRow {
Kirigami.FormData.label: "Sunset:"
theme: root.cfg_SunsetTheme; pattern: root.cfg_SunsetPattern
onThemePicked: name => root.cfg_SunsetTheme = name
onPatternPicked: v => root.cfg_SunsetPattern = v
}
// ---------------------------------------------------------- the sun
QQC2.CheckBox {
Kirigami.FormData.label: "Sun:"
visible: root.cfg_ThemeMode === "sun"
text: "Follow the real sun at a location"
checked: root.cfg_UseLocation
onToggled: root.cfg_UseLocation = checked
}
DegreesField {
Kirigami.FormData.label: "Latitude:"
visible: root.cfg_ThemeMode === "sun" && root.cfg_UseLocation
value: root.cfg_Latitude
onEdited: v => root.cfg_Latitude = Math.max(-90, Math.min(90, v))
}
DegreesField {
Kirigami.FormData.label: "Longitude:"
visible: root.cfg_ThemeMode === "sun" && root.cfg_UseLocation
value: root.cfg_Longitude
onEdited: v => root.cfg_Longitude = v
}
TimeField {
Kirigami.FormData.label: "Sunrise at:"
visible: root.cfg_ThemeMode === "sun" && !root.cfg_UseLocation
text: root.cfg_SunriseTime
onEditingFinished: if (acceptableInput) root.cfg_SunriseTime = text
}
TimeField {
Kirigami.FormData.label: "Sunset at:"
visible: root.cfg_ThemeMode === "sun" && !root.cfg_UseLocation
text: root.cfg_SunsetTime
onEditingFinished: if (acceptableInput) root.cfg_SunsetTime = text
}
QQC2.Label {
id: now
Kirigami.FormData.label: "Now:"
visible: root.followsSun
// Bumped each minute; the binding below also re-reads every
// setting describe() touches, so edits show straight away.
property int tick: 0
Timer {
interval: 60000; running: now.visible; repeat: true
onTriggered: now.tick++
}
function describe() {
var cfg = {
ThemeMode: "sun", UseLocation: root.cfg_UseLocation,
Latitude: root.cfg_Latitude, Longitude: root.cfg_Longitude,
SunriseTime: root.cfg_SunriseTime, SunsetTime: root.cfg_SunsetTime,
NightTheme: root.cfg_NightTheme, SunriseTheme: root.cfg_SunriseTheme,
DayTheme: root.cfg_DayTheme, SunsetTheme: root.cfg_SunsetTheme,
NightPattern: root.cfg_NightPattern, SunrisePattern: root.cfg_SunrisePattern,
DayPattern: root.cfg_DayPattern, SunsetPattern: root.cfg_SunsetPattern,
}
var p = Schedule.palette(cfg, new Date())
var pattern = root.layers.find(l => l.value === cfg[Schedule.key(p.label, "Pattern")])
return p.label + ": " + cfg[Schedule.key(p.label, "Theme")]
+ ", " + (pattern ? pattern.text.toLowerCase() : "")
+ (root.cfg_UseLocation ? " (sun at " + p.elevation.toFixed(1) + "°)" : "")
}
text: { tick; return describe() }
}
// ------------------------------------------------------------ shared
Item { Kirigami.FormData.isSection: true }
QQC2.SpinBox {
Kirigami.FormData.label: "Bokeh lights:"
visible: root.showsBokeh
from: 4; to: 64
value: root.cfg_BokehLights
onValueModified: root.cfg_BokehLights = value
}
RowLayout {
Kirigami.FormData.label: "Speed:"
QQC2.Slider {
id: speed
from: 0; to: 4; stepSize: 0.25
value: root.cfg_Speed
onMoved: root.cfg_Speed = value
}
QQC2.Label { text: speed.value === 0 ? "still" : speed.value + "×" }
}
QQC2.SpinBox {
Kirigami.FormData.label: "Frame rate:"
from: 5; to: 60
value: root.cfg_FrameRate
onValueModified: root.cfg_FrameRate = value
enabled: root.cfg_Speed > 0
}
QQC2.CheckBox {
Kirigami.FormData.label: "Effects:"
text: "Light glinting across the pattern"
checked: root.cfg_Glints
onToggled: root.cfg_Glints = checked
}
QQC2.CheckBox {
text: "Breathing"
checked: root.cfg_Breathing
onToggled: root.cfg_Breathing = checked
}
QQC2.CheckBox {
text: "Large lights drifting past in front"
checked: root.cfg_ForegroundBokeh
onToggled: root.cfg_ForegroundBokeh = checked
}
QQC2.CheckBox {
text: "Film grain"
checked: root.cfg_Grain
onToggled: root.cfg_Grain = checked
}
QQC2.CheckBox {
text: "Dither (smooths banding in gradients)"
checked: root.cfg_Dither
onToggled: root.cfg_Dither = checked
}
QQC2.CheckBox {
Kirigami.FormData.label: "Wordmark:"
text: "Write NEIAM in the corner"
checked: root.cfg_Wordmark
onToggled: root.cfg_Wordmark = checked
}
PercentSlider {
Kirigami.FormData.label: "Opacity:"
enabled: root.cfg_Wordmark
value: root.cfg_WordmarkOpacity
onMoved: v => root.cfg_WordmarkOpacity = v
}
PercentSlider {
Kirigami.FormData.label: "Glow:"
enabled: root.cfg_Wordmark
value: root.cfg_WordmarkGlow
onMoved: v => root.cfg_WordmarkGlow = v
}
}
neiam
/neiam-devices
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
Log in to mark this repository.
11.2 KiB · text
History
0fc5cce