summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/sddm
diff options
context:
space:
mode:
Diffstat (limited to 'raveos-hyprland-theme/theme-data/sddm')
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/hyprland.lua2
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpegbin3317762 -> 0 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Hibernate.svg35
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password.svg2
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password2.svg22
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.bak36
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.svg13
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.bak31
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.svg10
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Suspend.svg31
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/User.svg52
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Backgrounds/rave_background.pngbin0 -> 6980459 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/BatteryIndicator.qml257
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Clock.qml81
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Input.qml754
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/KeyboardLayoutIndicator.qml237
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/LoginForm.qml89
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/NetworkIndicator.qml243
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ParticleOverlay.qml90
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/SessionButton.qml158
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ToastNotification.qml83
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/UserSwitcher.qml332
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboard.qml20
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboardButton.qml79
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Bold.ttfbin0 -> 129784 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-BoldItalic.ttfbin0 -> 135108 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBold.ttfbin0 -> 130180 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBoldItalic.ttfbin0 -> 135688 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Italic.ttfbin0 -> 135380 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Light.ttfbin0 -> 129756 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-LightItalic.ttfbin0 -> 135668 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Medium.ttfbin0 -> 129948 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-MediumItalic.ttfbin0 -> 135556 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Regular.ttfbin0 -> 129796 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBold.ttfbin0 -> 129716 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBoldItalic.ttfbin0 -> 135512 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/LICENSE674
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Main.qml378
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Previews/rave.pngbin0 -> 7068851 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/logo.pngbin0 -> 302684 bytes
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/rave.conf (renamed from raveos-hyprland-theme/theme-data/sddm/astronaut.conf)15
-rwxr-xr-xraveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/metadata.desktop15
-rw-r--r--raveos-hyprland-theme/theme-data/sddm/sddm.conf2
43 files changed, 3731 insertions, 10 deletions
diff --git a/raveos-hyprland-theme/theme-data/sddm/hyprland.lua b/raveos-hyprland-theme/theme-data/sddm/hyprland.lua
deleted file mode 100644
index 28a1d21..0000000
--- a/raveos-hyprland-theme/theme-data/sddm/hyprland.lua
+++ /dev/null
@@ -1,2 +0,0 @@
--- Minimal Hyprland config for SDDM Wayland compositor (greeter session)
--- The SDDM greeter renders on top of this compositor.
diff --git a/raveos-hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg b/raveos-hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg
deleted file mode 100644
index 17ce81d..0000000
--- a/raveos-hyprland-theme/theme-data/sddm/new-raveos-main-bg.jpeg
+++ /dev/null
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Hibernate.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Hibernate.svg
new file mode 100644
index 0000000..b877ee6
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Hibernate.svg
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 34 34"
+ height="34"
+ width="34">
+ <defs
+ id="defs2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <path
+ style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
+ d="M 17,1 C 8.163444,1 1,8.163444 1,17 1,25.836556 8.163444,33 17,33 25.836556,33 33,25.836556 33,17 33,8.163444 25.836556,1 17,1 Z m 0,1 C 25.284271,2 32,8.7157288 32,17 32,25.284271 25.284271,32 17,32 8.7157288,32 2,25.284271 2,17 2,8.7157288 8.7157288,2 17,2 Z"
+ id="path831" />
+ <path
+ id="path816"
+ d="M 17 11 C 13.686292 11 11 13.686292 11 17 C 11 20.313708 13.686292 23 17 23 C 20.313708 23 23 20.313708 23 17 C 23 13.686292 20.313708 11 17 11 z M 17 12 A 5 5 0 0 1 22 17 A 5 5 0 0 1 17 22 A 5 5 0 0 1 12 17 A 5 5 0 0 1 17 12 z "
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1.71428573;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
+</svg>
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password.svg
new file mode 100644
index 0000000..e7b0e6a
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" id="Layer_1" data-name="Layer 1" viewBox="0 0 24 24" width="512" height="512"><path d="M23.821,11.181v0C22.943,9.261,19.5,3,12,3S1.057,9.261.179,11.181a1.969,1.969,0,0,0,0,1.64C1.057,14.739,4.5,21,12,21s10.943-6.261,11.821-8.181A1.968,1.968,0,0,0,23.821,11.181ZM12,18a6,6,0,1,1,6-6A6.006,6.006,0,0,1,12,18Z"/><circle cx="12" cy="12" r="4"/></svg>
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password2.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password2.svg
new file mode 100644
index 0000000..c538c22
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Password2.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generator: Adobe Illustrator 25.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 512.19 512.19" style="enable-background:new 0 0 512.19 512.19;" xml:space="preserve" width="512" height="512">
+<g>
+ <path d="M496.543,200.771c-19.259-31.537-43.552-59.707-71.915-83.392l59.733-59.733c8.185-8.475,7.95-21.98-0.525-30.165 c-8.267-7.985-21.374-7.985-29.641,0l-64.96,65.045c-40.269-23.918-86.306-36.385-133.141-36.053 c-132.075,0-207.339,90.411-240.448,144.299c-20.862,33.743-20.862,76.379,0,110.123c19.259,31.537,43.552,59.707,71.915,83.392 l-59.733,59.733c-8.475,8.185-8.71,21.691-0.525,30.165c8.185,8.475,21.691,8.71,30.165,0.525c0.178-0.172,0.353-0.347,0.525-0.525 l65.109-65.109c40.219,23.915,86.201,36.402,132.992,36.117c132.075,0,207.339-90.411,240.448-144.299 C517.405,277.151,517.405,234.515,496.543,200.771z M128.095,255.833c-0.121-70.575,56.992-127.885,127.567-128.006 c26.703-0.046,52.75,8.275,74.481,23.793l-30.976,30.976c-13.004-7.842-27.887-12.022-43.072-12.096 c-47.128,0-85.333,38.205-85.333,85.333c0.074,15.185,4.254,30.068,12.096,43.072l-30.976,30.976 C136.414,308.288,128.096,282.394,128.095,255.833z M256.095,383.833c-26.561-0.001-52.455-8.319-74.048-23.787l30.976-30.976 c13.004,7.842,27.887,12.022,43.072,12.096c47.128,0,85.333-38.205,85.333-85.333c-0.074-15.185-4.254-30.068-12.096-43.072 l30.976-30.976c41.013,57.434,27.702,137.242-29.732,178.255C308.845,375.558,282.798,383.879,256.095,383.833z"/>
+</g>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+</svg>
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.bak b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.bak
new file mode 100644
index 0000000..7b21d73
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.bak
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ width="34"
+ height="34"
+ viewBox="0 0 34 34"
+ version="1.1"
+ id="svg8">
+ <defs
+ id="defs2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ transform="matrix(1.000593,0,0,1.0006688,0.99050505,-287.73702)">
+ <path
+ style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.00189281;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
+ d="M 19.001953,1.1308594 V 2 H 19 v 11 h 1 V 2.3359375 A 15,15 45 0 1 32,17 15,15 45 0 1 21.001953,31.455078 v 1.033203 A 16.009488,16.010701 45 0 0 33.009766,17 16.009488,16.010701 45 0 0 19.001953,1.1308594 Z M 12.998047,1.5117188 A 16.009488,16.010701 45 0 0 0.99023438,17 16.009488,16.010701 45 0 0 14.998047,32.869141 V 32 H 15 V 21 H 14 V 31.664062 A 15,15 45 0 1 2,17 15,15 45 0 1 12.998047,2.5449219 Z"
+ transform="matrix(0.70668771,-0.70663419,0.70668771,0.70663419,-8.0273788,304.53335)"
+ id="path817" />
+ </g>
+</svg>
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.svg
new file mode 100644
index 0000000..09a1738
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Reboot.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- License: PD. Made by Dariush Habibpour: https://redl.ink/dariush/links -->
+<svg width="800px" height="800px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
+<g clip-path="url(#clip0_429_11071)">
+<path d="M12 2.99982C16.9706 2.99982 21 7.02925 21 11.9998C21 16.9704 16.9706 20.9998 12 20.9998C7.02944 20.9998 3 16.9704 3 11.9998C3 9.17255 4.30367 6.64977 6.34267 4.99982" stroke="#292929" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
+<path d="M3 4.49982H7V8.49982" stroke="#292929" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
+</g>
+<defs>
+<clipPath id="clip0_429_11071">
+<rect width="24" height="24" fill="white"/>
+</clipPath>
+</defs>
+</svg> \ No newline at end of file
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.bak b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.bak
new file mode 100644
index 0000000..a19a695
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.bak
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 34 34"
+ height="34"
+ width="34">
+ <defs
+ id="defs2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <path
+ id="path822"
+ d="M 14 1 L 14 13 L 15 13 L 15 1 L 14 1 z M 19 1 L 19 13 L 20 13 L 20 1 L 19 1 z M 9 3.1855469 C 4.1702837 5.9748853 1.0026451 11.162345 1 17 C 1 25.836556 8.163444 33 17 33 C 25.836556 33 33 25.836556 33 17 C 32.99593 11.163669 29.828666 5.9780498 25 3.1894531 L 25 4.3496094 C 29.280842 7.0494632 31.988612 11.788234 32 17 C 32 25.284271 25.284271 32 17 32 C 8.7157288 32 2 25.284271 2 17 C 2.0120649 11.788824 4.7195457 7.0510246 9 4.3515625 L 9 3.1855469 z "
+ style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill" />
+</svg>
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.svg
new file mode 100644
index 0000000..274b81b
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Shutdown.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
+<svg width="800px" height="800px" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" version="1.1">
+
+ <g style="fill:none;stroke:#222222;stroke-width:12px;stroke-linecap:round;stroke-linejoin:round;">
+ <path d="m 50,10 0,35"/>
+ <path d="M 26,20 C -3,48 16,90 51,90 79,90 89,67 89,52 89,37 81,26 74,20"/>
+ </g>
+
+</svg> \ No newline at end of file
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Suspend.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Suspend.svg
new file mode 100644
index 0000000..ecd2961
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/Suspend.svg
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ id="svg8"
+ version="1.1"
+ viewBox="0 0 34 34"
+ height="34"
+ width="34">
+ <defs
+ id="defs2" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <path
+ style="opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
+ d="M 17,1 C 8.163444,1 1,8.163444 1,17 1,25.836556 8.163444,33 17,33 25.836556,33 33,25.836556 33,17 33,8.163444 25.836556,1 17,1 Z m 0,1 C 25.284271,2 32,8.7157288 32,17 32,25.284271 25.284271,32 17,32 8.7157288,32 2,25.284271 2,17 2,8.7157288 8.7157288,2 17,2 Z m -4,9 v 12 h 1 V 11 Z m 7,0 v 12 h 1 V 11 Z"
+ id="path831" />
+</svg>
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/User.svg b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/User.svg
new file mode 100644
index 0000000..f0ccc59
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Assets/User.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="28"
+ width="28"
+ id="svg12"
+ xml:space="preserve"
+ viewBox="0 0 28 28"
+ y="0px"
+ x="0px"
+ version="1.1"
+ sodipodi:docname="user.svgz"
+ inkscape:version="0.92.2 2405546, 2018-03-11"><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1440"
+ inkscape:window-height="843"
+ id="namedview8"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:zoom="3.2721019"
+ inkscape:cx="11.317087"
+ inkscape:cy="22.626613"
+ inkscape:window-x="0"
+ inkscape:window-y="22"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg12" /><metadata
+ id="metadata18"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
+ id="defs16" /><g
+ id="g6"
+ transform="scale(0.06862745)"><g
+ id="g4"><path
+ id="path2"
+ d="M 204,204 C 260.1,204 306,158.1 306,102 306,45.9 260.1,0 204,0 147.9,0 102,45.9 102,102 c 0,56.1 45.9,102 102,102 z m 0,51 C 135.15,255 0,288.15 0,357 v 51 H 408 V 357 C 408,288.15 272.85,255 204,255 Z"
+ inkscape:connector-curvature="0" /></g></g></svg> \ No newline at end of file
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Backgrounds/rave_background.png b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Backgrounds/rave_background.png
new file mode 100644
index 0000000..ed6230d
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Backgrounds/rave_background.png
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/BatteryIndicator.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/BatteryIndicator.qml
new file mode 100644
index 0000000..5497911
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/BatteryIndicator.qml
@@ -0,0 +1,257 @@
+import QtQuick 2.15
+import Qt.labs.folderlistmodel 2.15
+
+Row {
+ id: batteryIndicator
+
+ height: root.font.pointSize * 1.6
+ spacing: root.font.pointSize * 0.5
+
+ // -1 = nincs akkumulátor / nem laptop
+ property int batteryLevel: -1
+ property bool isCharging: false
+ property bool isFull: false
+ property string batteryPath: ""
+
+ visible: batteryLevel >= 0
+
+ // Ismert akksi elérési utak
+ property var tryPaths: [
+ "/sys/class/power_supply/BAT0/",
+ "/sys/class/power_supply/BAT1/",
+ "/sys/class/power_supply/BAT2/",
+ "/sys/class/power_supply/battery/",
+ "/sys/class/power_supply/BATT/"
+ ]
+
+ // Dinamikus akkumulátor kereső (pl. kontroller, UPS, egyéb külső akkuk észleléséhez)
+ FolderListModel {
+ id: powerSupplyScanner
+ folder: "file:///sys/class/power_supply"
+ showDirs: true
+ showFiles: false
+
+ onCountChanged: scan()
+ onFolderChanged: scan()
+
+ function scan() {
+ var defaults = [
+ "/sys/class/power_supply/BAT0/",
+ "/sys/class/power_supply/BAT1/",
+ "/sys/class/power_supply/BAT2/",
+ "/sys/class/power_supply/battery/",
+ "/sys/class/power_supply/BATT/"
+ ]
+ for (var i = 0; i < count; i++) {
+ var name = get(i, "fileName")
+ if (name && name !== "." && name !== "..") {
+ // Csak a tipikus laptop akkumulátor elnevezések (pl. BAT0, BAT1, BATT, battery)
+ var isLaptopBat = /^bat/i.test(name) || /^battery/i.test(name)
+ if (isLaptopBat) {
+ var fullPath = "/sys/class/power_supply/" + name + "/"
+ if (defaults.indexOf(fullPath) === -1) {
+ defaults.push(fullPath)
+ }
+ }
+ }
+ }
+ tryPaths = defaults
+ detectBattery(0)
+ }
+ }
+
+ // ── Fájl olvasó ──────────────────────────────────────────────────────────
+ function readFile(path, cb) {
+ var xhr = new XMLHttpRequest()
+ xhr.open("GET", "file://" + path, true)
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === XMLHttpRequest.DONE)
+ cb(xhr.responseText && xhr.responseText.trim() !== "" ? xhr.responseText.trim() : null)
+ }
+ xhr.send()
+ }
+
+ // ── Akkumulátor keresés és frissítés ─────────────────────────────────────
+ function detectBattery(idx) {
+ if (idx >= tryPaths.length) { batteryLevel = -1; return }
+ readFile(tryPaths[idx] + "capacity", function(cap) {
+ if (cap !== null) {
+ batteryPath = tryPaths[idx]
+ batteryLevel = Math.max(0, Math.min(100, parseInt(cap) || 0))
+ readFile(batteryPath + "status", function(st) {
+ var s = st ? st.toLowerCase() : ""
+ isFull = (s === "full")
+ isCharging = (s === "charging") || isFull
+ batteryCanvas.requestPaint()
+ })
+ } else {
+ detectBattery(idx + 1)
+ }
+ })
+ }
+
+ // ── Akkumulátor frissítés ────────────────────────────────────────────────
+ function refresh() {
+ if (batteryPath !== "") {
+ readFile(batteryPath + "capacity", function(cap) {
+ if (cap !== null) {
+ batteryLevel = Math.max(0, Math.min(100, parseInt(cap) || 0))
+ readFile(batteryPath + "status", function(st) {
+ var s = st ? st.toLowerCase() : ""
+ isFull = (s === "full")
+ isCharging = (s === "charging") || isFull
+ batteryCanvas.requestPaint()
+ })
+ }
+ })
+ } else {
+ powerSupplyScanner.scan()
+ }
+ }
+
+ Component.onCompleted: powerSupplyScanner.scan()
+
+ Timer {
+ interval: 30000
+ repeat: true
+ running: true
+ onTriggered: batteryIndicator.refresh()
+ }
+
+ // ── Szín a töltési szint alapján ─────────────────────────────────────────
+ function levelColor(lvl, charging) {
+ if (charging) return "#4ade80" // zöld – tölt
+ if (lvl > 60) return "#ffffff" // fehér – ok
+ if (lvl > 30) return "#facc15" // sárga – közepes
+ if (lvl > 15) return "#fb923c" // narancs – alacsony
+ return "#f87171" // piros – kritikus
+ }
+
+ // ── UI ───────────────────────────────────────────────────────────────────
+ Canvas {
+ id: batteryCanvas
+ width: root.font.pointSize * 3.2
+ height: root.font.pointSize * 1.6
+ anchors.verticalCenter: parent.verticalCenter
+
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.clearRect(0, 0, width, height)
+
+ // Qt Canvas nem támogatja ctx.roundRect() – saját helper
+ function rr(c, x, y, w, h, r) {
+ r = Math.min(Math.max(r, 0), Math.min(w, h) / 2)
+ c.beginPath()
+ c.moveTo(x + r, y)
+ c.arcTo(x + w, y, x + w, y + h, r)
+ c.arcTo(x + w, y + h, x, y + h, r)
+ c.arcTo(x, y + h, x, y, r)
+ c.arcTo(x, y, x + w, y, r)
+ c.closePath()
+ }
+
+ var lvl = batteryIndicator.batteryLevel
+ var charging = batteryIndicator.isCharging
+ var full = batteryIndicator.isFull
+ var col = batteryIndicator.levelColor(lvl, charging)
+
+ var bw = width * 0.84 // akksi test szélessége
+ var bh = height * 0.72 // akksi test magassága
+ var bx = 0
+ var by = (height - bh) / 2
+ var r = bh * 0.22 // sarokkerekítés
+ var tw = width * 0.07 // terminál szélessége
+ var th = bh * 0.44 // terminál magassága
+ var tx = bw // terminál x
+ var ty = (height - th) / 2
+
+ // Terminál (+ pólus)
+ rr(ctx, tx, ty, tw, th, 2)
+ ctx.fillStyle = col
+ ctx.globalAlpha = 0.7
+ ctx.fill()
+ ctx.globalAlpha = 1.0
+
+ // Keret (akksi test)
+ rr(ctx, bx, by, bw, bh, r)
+ ctx.strokeStyle = col
+ ctx.lineWidth = 1.5
+ ctx.stroke()
+
+ // Töltési szint kitöltés
+ var padding = 3
+ var fillW = Math.max(0, (bw - padding * 2) * lvl / 100)
+ if (fillW > 0) {
+ rr(ctx, bx + padding, by + padding,
+ fillW, bh - padding * 2,
+ Math.max(0, r - padding * 0.5))
+ ctx.fillStyle = col
+ ctx.globalAlpha = 0.85
+ ctx.fill()
+ ctx.globalAlpha = 1.0
+ }
+
+ // Villám jel (töltés közben)
+ if (charging && !full) {
+ var cx = bw / 2
+ var cy = height / 2
+ var s = bh * 0.52
+ ctx.beginPath()
+ ctx.moveTo(cx + s * 0.18, cy - s * 0.5)
+ ctx.lineTo(cx - s * 0.08, cy + s * 0.05)
+ ctx.lineTo(cx + s * 0.10, cy + s * 0.05)
+ ctx.lineTo(cx - s * 0.18, cy + s * 0.5)
+ ctx.lineTo(cx + s * 0.08, cy - s * 0.05)
+ ctx.lineTo(cx - s * 0.10, cy - s * 0.05)
+ ctx.closePath()
+ ctx.fillStyle = "#ffffff"
+ ctx.globalAlpha = 0.95
+ ctx.fill()
+ ctx.globalAlpha = 1.0
+ }
+
+ // Tele jel (checkbox-szerű pipával)
+ if (full) {
+ ctx.beginPath()
+ ctx.moveTo(bw * 0.32, by + bh / 2)
+ ctx.lineTo(bw * 0.46, by + bh * 0.68)
+ ctx.lineTo(bw * 0.68, by + bh * 0.28)
+ ctx.strokeStyle = "#ffffff"
+ ctx.lineWidth = 1.8
+ ctx.lineCap = "round"
+ ctx.lineJoin = "round"
+ ctx.globalAlpha = 0.95
+ ctx.stroke()
+ ctx.globalAlpha = 1.0
+ }
+ }
+ }
+
+ // Százalék szöveg
+ Text {
+ id: batteryText
+ anchors.verticalCenter: parent.verticalCenter
+ text: {
+ if (batteryIndicator.isFull) return "100%"
+ if (batteryIndicator.isCharging) return batteryIndicator.batteryLevel + "% ↑"
+ return batteryIndicator.batteryLevel + "%"
+ }
+ color: batteryIndicator.levelColor(batteryIndicator.batteryLevel, batteryIndicator.isCharging)
+ font.pointSize: root.font.pointSize * 0.82
+ font.family: root.font.family
+ font.bold: batteryIndicator.batteryLevel <= 15 && !batteryIndicator.isCharging
+
+ // Pulzáló animáció kritikus töltésnél
+ SequentialAnimation on opacity {
+ running: batteryIndicator.batteryLevel <= 15 && !batteryIndicator.isCharging
+ loops: Animation.Infinite
+ NumberAnimation { to: 0.3; duration: 700; easing.type: Easing.InOutSine }
+ NumberAnimation { to: 1.0; duration: 700; easing.type: Easing.InOutSine }
+ }
+ }
+
+ // Szint változáskor újrafest
+ onBatteryLevelChanged: batteryCanvas.requestPaint()
+ onIsChargingChanged: batteryCanvas.requestPaint()
+ onIsFullChanged: batteryCanvas.requestPaint()
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Clock.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Clock.qml
new file mode 100644
index 0000000..e9d1399
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Clock.qml
@@ -0,0 +1,81 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Based on https://github.com/MarianArlt/sddm-sugar-dark
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+Column {
+ id: clock
+
+ width: parent.width / 2
+ spacing: 8
+
+ Image {
+ id: logoImage
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ source: (config.Logo && config.Logo !== "") ? Qt.resolvedUrl("../" + config.Logo) : ""
+ fillMode: Image.PreserveAspectFit
+ width: root.font.pointSize * 13
+ height: root.font.pointSize * 13
+ visible: config.Logo && config.Logo !== ""
+ }
+
+ Label {
+ id:headerTextLabel
+
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ font.pointSize: root.font.pointSize * 2
+ color: config.HeaderTextColor
+ renderType: Text.QtRendering
+ text: config.HeaderText
+ }
+
+ Label {
+ id: timeLabel
+
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ font.pointSize: root.font.pointSize * 3.5
+ font.bold: true
+ color: config.TimeTextColor
+ renderType: Text.QtRendering
+
+ function updateTime() {
+ text = new Date().toLocaleTimeString(Qt.locale(config.Locale), config.HourFormat == "long" ? Locale.LongFormat : config.HourFormat !== "" ? config.HourFormat : Locale.ShortFormat)
+ }
+ }
+
+ Label {
+ id: dateLabel
+
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ color: config.DateTextColor
+ font.pointSize: root.font.pointSize * 0.95
+ font.bold: true
+ renderType: Text.QtRendering
+
+ function updateTime() {
+ text = new Date().toLocaleDateString(Qt.locale(config.Locale), config.DateFormat == "short" ? Locale.ShortFormat : config.DateFormat !== "" ? config.DateFormat : Locale.LongFormat)
+ }
+ }
+
+ Timer {
+ interval: 1000
+ repeat: true
+ running: true
+ onTriggered: {
+ dateLabel.updateTime()
+ timeLabel.updateTime()
+ }
+ }
+
+ Component.onCompleted: {
+ dateLabel.updateTime()
+ timeLabel.updateTime()
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Input.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Input.qml
new file mode 100644
index 0000000..47e6598
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/Input.qml
@@ -0,0 +1,754 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Based on https://github.com/MarianArlt/sddm-sugar-dark
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtQuick.Controls 2.15
+import QtQuick.Effects
+
+Column {
+ id: inputContainer
+
+ Layout.fillWidth: true
+
+ property ComboBox exposeSession: sessionSelect.exposeSession
+ property bool failed
+
+ Item {
+ id: errorMessageField
+
+ // change also in selectSession
+ height: root.font.pointSize * 2
+ width: parent.width / 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Label {
+ id: errorMessage
+
+ width: parent.width
+ horizontalAlignment: Text.AlignHCenter
+
+ text: failed ? config.TranslateLoginFailedWarning || textConstants.loginFailed + "!" : keyboard.capsLock ? config.TranslateCapslockWarning || textConstants.capslockWarning : null
+ font.pointSize: root.font.pointSize * 0.8
+ font.italic: true
+ color: config.WarningColor
+ opacity: 0
+
+ states: [
+ State {
+ name: "fail"
+ when: failed
+ PropertyChanges {
+ target: errorMessage
+ opacity: 1
+ }
+ },
+ State {
+ name: "capslock"
+ when: keyboard.capsLock
+ PropertyChanges {
+ target: errorMessage
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ PropertyAnimation {
+ properties: "opacity"
+ duration: 100
+ }
+ }
+ ]
+ }
+ }
+
+ // Profilkép + felhasználóváltó
+ Item {
+ id: avatarField
+
+ height: root.font.pointSize * 12
+ width: parent.width / 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ property string userIconPath: {
+ var icon = userModel.data(userModel.index(selectUser.currentIndex, 0), Qt.UserRole + 4)
+ return (icon && icon !== "") ? icon : ""
+ }
+
+ Column {
+ anchors.centerIn: parent
+ spacing: root.font.pointSize * 0.8
+
+ // Avatar kör
+ Rectangle {
+ id: avatarCircle
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: root.font.pointSize * 7
+ height: root.font.pointSize * 7
+ radius: width / 2
+ clip: true
+ color: Qt.rgba(0.10, 0.10, 0.15, 0.65)
+
+ // The source image (invisible)
+ Image {
+ id: avatarPhoto
+ anchors.fill: parent
+ source: avatarField.userIconPath !== "" ? avatarField.userIconPath : ""
+ fillMode: Image.PreserveAspectCrop
+ smooth: true
+ mipmap: true
+ visible: false
+ }
+
+ // The mask source
+ Item {
+ id: avatarMask
+ anchors.fill: parent
+ visible: false
+ layer.enabled: true
+ Rectangle {
+ anchors.fill: parent
+ radius: parent.width / 2
+ color: "black"
+ }
+ }
+
+ // Apply MultiEffect to mask the avatarPhoto
+ MultiEffect {
+ anchors.fill: parent
+ source: avatarPhoto
+ visible: avatarPhoto.status === Image.Ready && avatarField.userIconPath !== ""
+ maskEnabled: true
+ maskSource: avatarMask
+ maskThresholdMin: 0.5
+ maskSpreadAtMin: 1.0
+ }
+
+ Image {
+ id: avatarFallback
+ anchors.centerIn: parent
+ width: parent.width * 0.55
+ height: parent.height * 0.55
+ source: Qt.resolvedUrl("../Assets/User.svg")
+ fillMode: Image.PreserveAspectFit
+ smooth: true
+ visible: avatarField.userIconPath === "" || avatarPhoto.status !== Image.Ready
+ opacity: 0.75
+ }
+
+ // Draw the border on top of everything!
+ Rectangle {
+ anchors.fill: parent
+ radius: parent.width / 2
+ color: "transparent"
+ border.color: Qt.rgba(1, 1, 1, 0.30)
+ border.width: 2
+ }
+ }
+
+ // Felhasználóváltó gomb (csak ha több user van)
+ UserSwitcher {
+ id: userSwitcher
+ anchors.horizontalCenter: parent.horizontalCenter
+ selectedIndex: selectUser.currentIndex
+
+ onUserSwitched: function(idx, name) {
+ selectUser.currentIndex = idx
+ username.text = name
+ }
+ }
+ }
+ }
+
+
+ Item {
+ id: usernameField
+
+ height: root.font.pointSize * 4.5
+ width: parent.width / 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Button {
+ id: staticUserIcon
+
+ width: parent.height
+ height: parent.height
+ anchors.left: parent.left
+ z: 2
+ visible: userModel.count <= 1
+ enabled: false
+
+ icon.height: parent.height * 0.25
+ icon.width: parent.height * 0.25
+ icon.color: config.UserIconColor
+ icon.source: Qt.resolvedUrl("../Assets/User.svg")
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: "transparent"
+ }
+ }
+
+ ComboBox {
+ id: selectUser
+
+ width: parent.height
+ height: parent.height
+ anchors.left: parent.left
+ z: 2
+ visible: userModel.count > 1
+
+ model: userModel
+ currentIndex: model.lastIndex
+ textRole: "name"
+ hoverEnabled: true
+ onActivated: {
+ username.text = currentText;
+ }
+
+ property var popkey: config.RightToLeftLayout == "true" ? Qt.Key_Right : Qt.Key_Left
+ Keys.onPressed: function (event) {
+ if (event.key == Qt.Key_Down && !popup.opened)
+ username.forceActiveFocus();
+ if ((event.key == Qt.Key_Up || event.key == popkey) && !popup.opened)
+ popup.open();
+ }
+ KeyNavigation.down: username
+ KeyNavigation.right: username
+
+ delegate: ItemDelegate {
+ // minus padding
+ width: popupHandler.width - 20
+ anchors.horizontalCenter: popupHandler.horizontalCenter
+
+ contentItem: Text {
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ text: model.name
+ font.pointSize: root.font.pointSize * 0.8
+ font.capitalization: Font.AllLowercase
+ font.family: root.font.family
+ color: config.DropdownTextColor
+ }
+
+ background: Rectangle {
+ color: selectUser.highlightedIndex === index ? Qt.rgba(1, 1, 1, 0.15) : "transparent"
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 4 : 5
+ }
+ }
+
+ indicator: Button {
+ id: usernameIcon
+
+ width: selectUser.height * 1
+ height: parent.height
+ anchors.left: parent.left
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.leftMargin: selectUser.height * 0
+
+ icon.height: parent.height * 0.25
+ icon.width: parent.height * 0.25
+ enabled: false
+ icon.color: config.UserIconColor
+ icon.source: Qt.resolvedUrl("../Assets/User.svg")
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: "transparent"
+ }
+ }
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: "transparent"
+ }
+
+ popup: Popup {
+ id: popupHandler
+
+ implicitHeight: contentItem.implicitHeight
+ width: usernameField.width
+ y: parent.height - username.height / 3
+ x: config.RightToLeftLayout == "true" ? -loginButton.width + selectUser.width : 0
+ rightMargin: config.RightToLeftLayout == "true" ? root.padding + usernameField.width / 2 : undefined
+ padding: 10
+
+ contentItem: ListView {
+ implicitHeight: contentHeight + 20
+
+ clip: true
+ model: selectUser.popup.visible ? selectUser.delegateModel : null
+ currentIndex: selectUser.highlightedIndex
+ ScrollIndicator.vertical: ScrollIndicator {}
+ }
+
+ background: Rectangle {
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 2 : 10
+ color: Qt.rgba(1, 1, 1, 0.08)
+ border.color: Qt.rgba(1, 1, 1, 0.18)
+ border.width: 1
+ layer.enabled: true
+ }
+
+ enter: Transition {
+ NumberAnimation {
+ property: "opacity"
+ from: 0
+ to: 1
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "pressed"
+ when: selectUser.down
+ PropertyChanges {
+ target: usernameIcon
+ icon.color: Qt.lighter(config.HoverUserIconColor, 1.1)
+ }
+ },
+ State {
+ name: "hovered"
+ when: selectUser.hovered
+ PropertyChanges {
+ target: usernameIcon
+ icon.color: Qt.lighter(config.HoverUserIconColor, 1.2)
+ }
+ },
+ State {
+ name: "focused"
+ when: selectUser.activeFocus
+ PropertyChanges {
+ target: usernameIcon
+ icon.color: config.HoverUserIconColor
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ PropertyAnimation {
+ properties: "color, border.color, icon.color"
+ duration: 150
+ }
+ }
+ ]
+ }
+
+ TextField {
+ id: username
+
+ anchors.centerIn: parent
+ height: root.font.pointSize * 3
+ width: parent.width
+ horizontalAlignment: TextInput.AlignHCenter
+ z: 1
+
+ text: config.ForceLastUser == "true" ? selectUser.currentText : null
+ color: config.LoginFieldTextColor
+ font.bold: true
+ font.capitalization: config.AllowUppercaseLettersInUsernames == "false" ? Font.AllLowercase : Font.MixedCase
+ placeholderText: config.TranslatePlaceholderUsername || textConstants.userName
+ placeholderTextColor: config.PlaceholderTextColor
+ selectByMouse: true
+ renderType: Text.QtRendering
+
+ onFocusChanged: {
+ if (focus)
+ selectAll();
+ }
+
+ background: Rectangle {
+ color: username.activeFocus ? Qt.rgba(0, 0, 0, 0.35) : Qt.rgba(0, 0, 0, 0.2)
+ border.color: username.activeFocus ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(255, 255, 255, 0.12)
+ border.width: username.activeFocus ? 1.5 : 1
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 10
+ Behavior on color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+ Behavior on border.color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+ }
+
+ onAccepted: config.AllowUppercaseLettersInUsernames == "false" ? sddm.login(username.text.toLowerCase(), password.text, sessionSelect.selectedSession) : sddm.login(username.text, password.text, sessionSelect.selectedSession)
+ KeyNavigation.down: passwordIcon
+
+ states: [
+ State {
+ name: "focused"
+ when: username.activeFocus
+ PropertyChanges {
+ target: username
+ color: Qt.lighter(config.LoginFieldTextColor, 1.15)
+ }
+ }
+ ]
+ }
+ }
+
+ Item {
+ id: passwordField
+
+ height: root.font.pointSize * 4.5
+ width: parent.width / 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Button {
+ id: passwordIcon
+
+ height: parent.height
+ width: selectUser.height * 1
+ anchors.left: parent.left
+ anchors.leftMargin: selectUser.height * 0
+ anchors.verticalCenter: parent.verticalCenter
+ z: 2
+
+ icon.height: parent.height * 0.25
+ icon.width: parent.height * 0.25
+ icon.color: config.PasswordIconColor
+ icon.source: Qt.resolvedUrl("../Assets/Password2.svg")
+
+ background: Rectangle {
+ color: "transparent"
+ border.color: "transparent"
+ }
+
+ states: [
+ State {
+ name: "visiblePasswordFocused"
+ when: passwordIcon.checked && passwordIcon.activeFocus
+ PropertyChanges {
+ target: passwordIcon
+ icon.source: Qt.resolvedUrl("../Assets/Password.svg")
+ icon.color: config.HoverPasswordIconColor
+ }
+ },
+ State {
+ name: "visiblePasswordHovered"
+ when: passwordIcon.checked && passwordIcon.hovered
+ PropertyChanges {
+ target: passwordIcon
+ icon.source: Qt.resolvedUrl("../Assets/Password.svg")
+ icon.color: config.HoverPasswordIconColor
+ }
+ },
+ State {
+ name: "visiblePassword"
+ when: passwordIcon.checked
+ PropertyChanges {
+ target: passwordIcon
+ icon.source: Qt.resolvedUrl("../Assets/Password.svg")
+ }
+ },
+ State {
+ name: "hiddenPasswordFocused"
+ when: passwordIcon.enabled && passwordIcon.activeFocus
+ PropertyChanges {
+ target: passwordIcon
+ icon.source: Qt.resolvedUrl("../Assets/Password2.svg")
+ icon.color: config.HoverPasswordIconColor
+ }
+ },
+ State {
+ name: "hiddenPasswordHovered"
+ when: passwordIcon.hovered
+ PropertyChanges {
+ target: passwordIcon
+ icon.source: Qt.resolvedUrl("../Assets/Password2.svg")
+ icon.color: config.HoverPasswordIconColor
+ }
+ }
+ ]
+
+ onClicked: toggle()
+ Keys.onReturnPressed: toggle()
+ Keys.onEnterPressed: toggle()
+ KeyNavigation.down: password
+ }
+
+ TextField {
+ id: password
+
+ height: root.font.pointSize * 3
+ width: parent.width
+ anchors.centerIn: parent
+ horizontalAlignment: TextInput.AlignHCenter
+
+ font.bold: true
+ color: config.PasswordFieldTextColor
+ focus: config.PasswordFocus == "true" ? true : false
+ echoMode: passwordIcon.checked ? TextInput.Normal : TextInput.Password
+ placeholderText: config.TranslatePlaceholderPassword || textConstants.password
+ placeholderTextColor: config.PlaceholderTextColor
+ passwordCharacter: "•"
+ passwordMaskDelay: config.HideCompletePassword == "true" ? undefined : 1000
+ renderType: Text.QtRendering
+ selectByMouse: true
+
+ background: Rectangle {
+ color: password.activeFocus ? Qt.rgba(0, 0, 0, 0.35) : Qt.rgba(0, 0, 0, 0.2)
+ border.color: password.activeFocus ? Qt.rgba(255, 255, 255, 0.3) : Qt.rgba(255, 255, 255, 0.12)
+ border.width: password.activeFocus ? 1.5 : 1
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 10
+ Behavior on color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+ Behavior on border.color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+ }
+ onAccepted: config.AllowUppercaseLettersInUsernames == "false" ? sddm.login(username.text.toLowerCase(), password.text, sessionSelect.selectedSession) : sddm.login(username.text, password.text, sessionSelect.selectedSession)
+ KeyNavigation.down: loginButton
+ }
+
+ states: [
+ State {
+ name: "focused"
+ when: password.activeFocus
+ PropertyChanges {
+ target: password
+ color: Qt.lighter(config.LoginFieldTextColor, 1.15)
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ PropertyAnimation {
+ properties: "color, border.color"
+ duration: 150
+ }
+ }
+ ]
+ }
+
+ Item {
+ id: login
+
+ // important
+ // try 4 or 9 ...
+ height: root.font.pointSize * 9
+ width: parent.width / 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ visible: config.HideLoginButton == "true" ? false : true
+
+ Item {
+ id: loginButton
+
+ height: root.font.pointSize * 3
+ width: parent.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+
+ focus: true
+ activeFocusOnTab: true
+
+ property bool hovered: hoverArea.containsMouse
+ property bool down: hoverArea.pressed
+
+ signal clicked()
+
+ onClicked: config.AllowUppercaseLettersInUsernames == "false" ? sddm.login(username.text.toLowerCase(), password.text, sessionSelect.selectedSession) : sddm.login(username.text, password.text, sessionSelect.selectedSession)
+
+ Keys.onReturnPressed: clicked()
+ Keys.onEnterPressed: clicked()
+
+ KeyNavigation.down: rebootBtn
+
+ Rectangle {
+ id: buttonBackground
+ anchors.fill: parent
+
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 10
+ border.width: loginButton.activeFocus ? 1.5 : 1
+
+ border.color: loginButton.down ? Qt.rgba(21/255, 128/255, 61/255, 0.95) : (loginButton.hovered ? Qt.rgba(34/255, 197/255, 94/255, 0.85) : Qt.rgba(74/255, 222/255, 128/255, 0.65))
+
+ color: loginButton.down ? Qt.rgba(21/255, 128/255, 61/255, 0.80) : (loginButton.hovered ? Qt.rgba(34/255, 197/255, 94/255, 0.65) : Qt.rgba(74/255, 222/255, 128/255, 0.40))
+
+ Behavior on border.color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+
+ Behavior on color {
+ ColorAnimation {
+ duration: 150
+ }
+ }
+ }
+
+ Text {
+ id: loginButtonText
+ anchors.centerIn: parent
+
+ font.bold: true
+ font.pointSize: root.font.pointSize
+ font.family: root.font.family
+ color: "#ffffff"
+ text: config.TranslateLogin || textConstants.login
+ opacity: 1.0
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 150
+ }
+ }
+ }
+
+ MouseArea {
+ id: hoverArea
+ anchors.fill: parent
+ hoverEnabled: true
+ onClicked: parent.clicked()
+ }
+ }
+ }
+
+ Item {
+ id: powerButtonsRow
+
+ height: root.font.pointSize * 10
+ width: parent.width / 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Row {
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.verticalCenter: parent.verticalCenter
+ spacing: root.font.pointSize * 3
+
+ // Reboot gomb
+ Column {
+ spacing: root.font.pointSize * 0.6
+
+ RoundButton {
+ id: rebootBtn
+
+ width: root.font.pointSize * 6
+ height: root.font.pointSize * 6
+
+ activeFocusOnTab: true
+ Keys.onReturnPressed: sddm.reboot()
+ Keys.onEnterPressed: sddm.reboot()
+ KeyNavigation.right: shutdownBtn
+ hoverEnabled: true
+
+ icon.source: Qt.resolvedUrl("../Assets/Reboot.svg")
+ icon.width: root.font.pointSize * 3
+ icon.height: root.font.pointSize * 3
+ icon.color: "#ffffff"
+
+ opacity: rebootBtn.hovered || rebootBtn.activeFocus ? 1.0 : 0.75
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+
+ scale: rebootBtn.pressed ? 0.88 : 1.0
+ Behavior on scale { NumberAnimation { duration: 100 } }
+
+ background: Rectangle {
+ anchors.fill: parent
+ radius: width / 2
+ color: rebootBtn.pressed ? Qt.rgba(1, 0.45, 0.0, 0.35) : (rebootBtn.hovered ? Qt.rgba(1, 0.55, 0.0, 0.22) : "transparent")
+ border.color: "transparent"
+ border.width: 0
+ Behavior on color { ColorAnimation { duration: 150 } }
+ }
+
+ onClicked: sddm.reboot()
+ }
+
+ Text {
+ anchors.horizontalCenter: parent.children[0].horizontalCenter
+ text: config.TranslateReboot || textConstants.reboot
+ color: "#ffffff"
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+ horizontalAlignment: Text.AlignHCenter
+ opacity: rebootBtn.hovered || rebootBtn.activeFocus ? 1.0 : 0.75
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+ }
+
+ // Shutdown gomb
+ Column {
+ spacing: root.font.pointSize * 0.6
+
+ RoundButton {
+ id: shutdownBtn
+
+ width: root.font.pointSize * 6
+ height: root.font.pointSize * 6
+
+ activeFocusOnTab: true
+ Keys.onReturnPressed: sddm.powerOff()
+ Keys.onEnterPressed: sddm.powerOff()
+ KeyNavigation.left: rebootBtn
+ hoverEnabled: true
+
+ icon.source: Qt.resolvedUrl("../Assets/Shutdown.svg")
+ icon.width: root.font.pointSize * 3
+ icon.height: root.font.pointSize * 3
+ icon.color: "#ffffff"
+
+ opacity: shutdownBtn.hovered || shutdownBtn.activeFocus ? 1.0 : 0.75
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+
+ scale: shutdownBtn.pressed ? 0.88 : 1.0
+ Behavior on scale { NumberAnimation { duration: 100 } }
+
+ background: Rectangle {
+ anchors.fill: parent
+ radius: width / 2
+ color: shutdownBtn.pressed ? Qt.rgba(0.8, 0.1, 0.1, 0.40) : (shutdownBtn.hovered ? Qt.rgba(0.8, 0.1, 0.1, 0.25) : "transparent")
+ border.color: "transparent"
+ border.width: 0
+ Behavior on color { ColorAnimation { duration: 150 } }
+ }
+
+ onClicked: sddm.powerOff()
+ }
+
+ Text {
+ anchors.horizontalCenter: parent.children[0].horizontalCenter
+ text: config.TranslateShutdown || textConstants.shutdown
+ color: "#ffffff"
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+ horizontalAlignment: Text.AlignHCenter
+ opacity: shutdownBtn.hovered || shutdownBtn.activeFocus ? 1.0 : 0.75
+ Behavior on opacity { NumberAnimation { duration: 150 } }
+ }
+ }
+ }
+ }
+
+ Connections {
+ target: sddm
+ function onLoginSucceeded() {
+ }
+ function onLoginFailed() {
+ failed = true;
+ resetError.running ? resetError.stop() && resetError.start() : resetError.start();
+ }
+ }
+
+ Timer {
+ id: resetError
+ interval: 2000
+ onTriggered: failed = false
+ running: false
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/KeyboardLayoutIndicator.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/KeyboardLayoutIndicator.qml
new file mode 100644
index 0000000..0fb03be
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/KeyboardLayoutIndicator.qml
@@ -0,0 +1,237 @@
+// Keyboard Layout Indicator component
+// Displays the current locale/layout and switches between them when clicked (if multiple are available)
+
+import QtQuick 2.15
+import QtQml 2.15
+import QtQuick.Controls 2.15
+
+Item {
+ id: layoutIndicator
+
+ implicitWidth: layoutRow.implicitWidth
+ implicitHeight: layoutRow.implicitHeight
+ width: implicitWidth
+ height: implicitHeight
+
+ // Number of available layouts
+ property int layoutsCount: (typeof keyboard !== "undefined" && keyboard && keyboard.layouts) ? keyboard.layouts.length : 0
+
+ // Show if we have layout info or a valid locale fallback
+ visible: currentShortName !== ""
+
+ // Get current layout shortname (e.g. "US", "HU")
+ property string currentShortName: ""
+
+ function updateCurrentShortName() {
+ if (layoutsCount > 0) {
+ var idx = keyboard.currentLayout
+ if (idx >= 0 && idx < layoutsCount) {
+ var layoutObj = keyboard.layouts[idx]
+ if (layoutObj && layoutObj.shortName) {
+ currentShortName = layoutObj.shortName.toUpperCase()
+ return
+ }
+ }
+ }
+
+ // Fallback to config locale or system locale
+ var loc = config.Locale || Qt.locale().name
+ if (loc) {
+ var parts = loc.split("_")
+ if (parts.length > 0 && parts[0]) {
+ currentShortName = parts[0].toUpperCase()
+ return
+ }
+ }
+ currentShortName = ""
+ }
+
+ Component.onCompleted: updateCurrentShortName()
+
+ // Colors matched to the theme config
+ property color textColor: config.UserIconColor || "#ffffff"
+ property color hoverColor: config.HoverUserIconColor || "#b7cef1"
+
+ Row {
+ id: layoutRow
+ height: root.font.pointSize * 1.1
+ spacing: root.font.pointSize * 0.4
+ // Removed anchors.centerIn to prevent circular binding loop with parent width/height
+
+ // Keyboard icon
+ Canvas {
+ id: kbdCanvas
+ width: root.font.pointSize * 1.5
+ height: root.font.pointSize * 1.1
+ anchors.verticalCenter: parent.verticalCenter
+
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.clearRect(0, 0, width, height)
+
+ var canHover = layoutsCount >= 1
+ var col = (layoutMouseArea.containsMouse && canHover) ? layoutIndicator.hoverColor : layoutIndicator.textColor
+
+ ctx.strokeStyle = col
+ ctx.fillStyle = col
+ ctx.lineWidth = height * 0.08
+ ctx.lineCap = "round"
+ ctx.lineJoin = "round"
+ ctx.globalAlpha = 0.85
+
+ // Draw keyboard outline
+ var r = height * 0.15
+ var bx = ctx.lineWidth / 2
+ var by = ctx.lineWidth / 2
+ var bw = width - ctx.lineWidth
+ var bh = height - ctx.lineWidth
+
+ ctx.beginPath()
+ ctx.moveTo(bx + r, by)
+ ctx.arcTo(bx + bw, by, bx + bw, by + bh, r)
+ ctx.arcTo(bx + bw, by + bh, bx, by + bh, r)
+ ctx.arcTo(bx, by + bh, bx, by, r)
+ ctx.arcTo(bx, by, bx + bw, by, r)
+ ctx.closePath()
+ ctx.stroke()
+
+ // Draw simple key grid
+ ctx.lineWidth = height * 0.06
+ var kw = bw / 6
+ var kh = bh / 4
+ // Row 1 & 2 keys
+ for (var i = 0; i < 4; i++) {
+ ctx.fillRect(bx + kw * (i + 1), by + kh, kw * 0.6, kh * 0.6)
+ ctx.fillRect(bx + kw * (i + 0.5), by + kh * 2, kw * 0.6, kh * 0.6)
+ }
+ // Spacebar
+ ctx.fillRect(bx + kw * 1.5, by + kh * 3, kw * 3, kh * 0.6)
+
+ ctx.globalAlpha = 1.0
+ }
+
+ Connections {
+ target: layoutMouseArea
+ function onContainsMouseChanged() { kbdCanvas.requestPaint() }
+ }
+ }
+
+ // Layout Short Name (e.g. US, HU)
+ Text {
+ id: layoutText
+ anchors.verticalCenter: parent.verticalCenter
+ text: layoutIndicator.currentShortName
+
+ color: {
+ var canHover = layoutsCount >= 1
+ return (layoutMouseArea.containsMouse && canHover) ? layoutIndicator.hoverColor : layoutIndicator.textColor
+ }
+
+ font.pointSize: root.font.pointSize * 0.82
+ font.family: root.font.family
+ font.bold: true
+ }
+ }
+
+ MouseArea {
+ id: layoutMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: (layoutsCount >= 1) ? Qt.PointingHandCursor : Qt.ArrowCursor
+
+ onClicked: {
+ if (layoutsCount >= 1) {
+ layoutPopup.open()
+ }
+ }
+ }
+
+ Popup {
+ id: layoutPopup
+ y: parent.height + 5
+ x: -width / 2 + parent.width / 2
+ width: Math.max(160, layoutRow.width * 1.5)
+ padding: 5
+
+ background: Rectangle {
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 2 : 10
+ color: config.BackgroundColor || "#1a1a1a"
+ border.color: Qt.rgba(1, 1, 1, 0.20)
+ border.width: 1
+ }
+
+ contentItem: ListView {
+ id: layoutListView
+ implicitHeight: Math.min(200, contentHeight)
+ clip: true
+ model: layoutsCount
+ ScrollIndicator.vertical: ScrollIndicator { }
+
+ delegate: Rectangle {
+ id: delegateItem
+ width: parent.width
+ height: root.font.pointSize * 2
+ color: delegateMouse.containsMouse ? Qt.rgba(1, 1, 1, 0.15) : "transparent"
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 4 : 5
+
+ // Get layout object safely
+ property var layoutObj: (typeof keyboard !== "undefined" && keyboard && keyboard.layouts) ? keyboard.layouts[index] : null
+ property string shortName: layoutObj && layoutObj.shortName ? layoutObj.shortName.toUpperCase() : ""
+ property string longName: layoutObj && layoutObj.longName ? layoutObj.longName : ""
+
+ Row {
+ spacing: 8
+ anchors.fill: parent
+ anchors.leftMargin: 10
+ anchors.rightMargin: 10
+
+ Text {
+ text: delegateItem.shortName
+ color: index === keyboard.currentLayout ? (config.HoverUserIconColor || "#b7cef1") : (config.UserIconColor || "#ffffff")
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+ font.bold: true
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Text {
+ text: delegateItem.longName
+ color: index === keyboard.currentLayout ? (config.HoverUserIconColor || "#b7cef1") : (config.UserIconColor || "#ffffff")
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+ elide: Text.ElideRight
+ width: parent.width - x - 10
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+
+ MouseArea {
+ id: delegateMouse
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ keyboard.currentLayout = index
+ layoutPopup.close()
+ }
+ }
+ }
+ }
+
+ enter: Transition {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 150 }
+ }
+ exit: Transition {
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 150 }
+ }
+ }
+
+ Connections {
+ target: keyboard
+ ignoreUnknownSignals: true
+ function onCurrentLayoutChanged() {
+ kbdCanvas.requestPaint()
+ updateCurrentShortName()
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/LoginForm.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/LoginForm.qml
new file mode 100644
index 0000000..515d6b3
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/LoginForm.qml
@@ -0,0 +1,89 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Based on https://github.com/MarianArlt/sddm-sugar-dark
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import SddmComponents 2.0 as SDDM
+
+ColumnLayout {
+ id: formContainer
+ SDDM.TextConstants { id: textConstants }
+
+ property int p: config.ScreenPadding == "" ? 0 : config.ScreenPadding
+ property string a: config.FormPosition
+
+ spacing: 15
+
+ Clock {
+ id: clock
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: clock.implicitHeight
+ Layout.leftMargin: p != "0" ? a == "left" ? -p : a == "right" ? p : 0 : 0
+ }
+
+ // Akkumulátor + Hálózat jelzők
+ RowLayout {
+ id: statusRow
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.leftMargin: p != "0" ? a == "left" ? -p : a == "right" ? p : 0 : 0
+ Layout.bottomMargin: visible ? 4 : 0
+ visible: (batteryIndicator.batteryLevel >= 0) || networkIndicator.isConnected
+
+ spacing: root.font.pointSize * 1.2
+
+ BatteryIndicator {
+ id: batteryIndicator
+ Layout.alignment: Qt.AlignVCenter
+ Layout.preferredWidth: batteryIndicator.implicitWidth
+ Layout.preferredHeight: batteryIndicator.implicitHeight
+ visible: batteryIndicator.batteryLevel >= 0
+ }
+
+ NetworkIndicator {
+ id: networkIndicator
+ Layout.alignment: Qt.AlignVCenter
+ Layout.preferredWidth: networkIndicator.implicitWidth
+ Layout.preferredHeight: networkIndicator.implicitHeight
+ visible: networkIndicator.isConnected
+ }
+ }
+
+ // Billentyűzet kiosztás jelző (külön sorban, hogy akksi/wifi hiányában is látszódjon)
+ KeyboardLayoutIndicator {
+ id: keyboardLayoutIndicator
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: keyboardLayoutIndicator.implicitHeight
+ Layout.leftMargin: p != "0" ? a == "left" ? -p : a == "right" ? p : 0 : 0
+ Layout.bottomMargin: visible ? 4 : 0
+ }
+
+ Input {
+ id: input
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: input.implicitHeight
+ Layout.leftMargin: p != "0" ? a == "left" ? -p : a == "right" ? p : 0 : 0
+ Layout.topMargin: 0
+ }
+
+ SessionButton {
+ id: sessionSelect
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: sessionSelect.height
+ Layout.leftMargin: p != "0" ? a == "left" ? -p : a == "right" ? p : 0 : 0
+ }
+
+ VirtualKeyboardButton {
+ id: virtualKeyboardButton
+
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredHeight: root.font.pointSize * 2
+ Layout.leftMargin: p != "0" ? a == "left" ? -p : a == "right" ? p : 0 : 0
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/NetworkIndicator.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/NetworkIndicator.qml
new file mode 100644
index 0000000..bed97c8
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/NetworkIndicator.qml
@@ -0,0 +1,243 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+
+Row {
+ id: networkIndicator
+
+ height: root.font.pointSize * 1.6
+ spacing: root.font.pointSize * 0.5
+
+ // "none" | "wifi" | "ethernet"
+ property string netType: "none"
+ property int wifiQuality: 0 // 0-100
+ property string activeIface: ""
+ property bool isConnected: netType !== "none"
+
+ visible: isConnected
+
+ property var wifiIfaces: [
+ "wlan0","wlan1","wlp1s0","wlp2s0","wlp3s0",
+ "wlp4s0","wlp5s0","wlp6s0","wlp0s20f3"
+ ]
+ property var ethIfaces: [
+ "eth0","eth1","eno1","eno2",
+ "enp1s0","enp2s0","enp3s0","enp4s0",
+ "enp0s3","enp0s31f6","ens33","ens3","ens18"
+ ]
+
+ // ── Fájl olvasó ──────────────────────────────────────────────────────────
+ function readFile(path, cb) {
+ var xhr = new XMLHttpRequest()
+ xhr.open("GET", "file://" + path, true)
+ xhr.onreadystatechange = function() {
+ if (xhr.readyState === XMLHttpRequest.DONE) {
+ var res = xhr.responseText && xhr.responseText.trim() !== ""
+ ? xhr.responseText.trim() : null
+ cb(res)
+ }
+ }
+ xhr.send()
+ }
+
+ // ── WiFi jelerősség /proc/net/wireless-ből ───────────────────────────────
+ function readWifiSignal(iface) {
+ readFile("/proc/net/wireless", function(content) {
+ if (!content) { wifiQuality = 60; netCanvas.requestPaint(); return }
+ var lines = content.split("\n")
+ for (var i = 0; i < lines.length; i++) {
+ if (lines[i].indexOf(iface + ":") !== -1) {
+ // formátum: "wlan0: 0000 61. -49. -256 ..."
+ var parts = lines[i].trim().replace(/\./g,"").split(/\s+/)
+ // parts[2] = link quality (0–70 tartomány általában)
+ var q = parseFloat(parts[2]) || 0
+ wifiQuality = Math.min(100, Math.round(q / 70 * 100))
+ break
+ }
+ }
+ netCanvas.requestPaint()
+ })
+ }
+
+ // ── Interfész keresők ────────────────────────────────────────────────────
+ function checkWifi(idx) {
+ if (idx >= wifiIfaces.length) { checkEth(0); return }
+ readFile("/sys/class/net/" + wifiIfaces[idx] + "/operstate", function(st) {
+ if (st === "up") {
+ activeIface = wifiIfaces[idx]
+ netType = "wifi"
+ readWifiSignal(wifiIfaces[idx])
+ } else {
+ checkWifi(idx + 1)
+ }
+ })
+ }
+
+ // ── Ethernet keresés ─────────────────────────────────────────────────────
+ function checkEth(idx) {
+ if (idx >= ethIfaces.length) { netType = "none"; return }
+ readFile("/sys/class/net/" + ethIfaces[idx] + "/operstate", function(st) {
+ if (st === "up") {
+ activeIface = ethIfaces[idx]
+ netType = "ethernet"
+ netCanvas.requestPaint()
+ } else {
+ checkEth(idx + 1)
+ }
+ })
+ }
+
+ function refresh() { checkWifi(0) }
+
+ Component.onCompleted: refresh()
+
+ Timer {
+ interval: 15000
+ repeat: true
+ running: true
+ onTriggered: networkIndicator.refresh()
+ }
+
+ // ── Szín ─────────────────────────────────────────────────────────────────
+ function signalColor(q) {
+ if (q >= 65) return "#4ade80" // zöld – erős
+ if (q >= 40) return "#facc15" // sárga – közepes
+ return "#fb923c" // narancs – gyenge
+ }
+
+ // ── UI ───────────────────────────────────────────────────────────────────
+ Canvas {
+ id: netCanvas
+ width: root.font.pointSize * 2.0
+ height: root.font.pointSize * 1.6
+ anchors.verticalCenter: parent.verticalCenter
+
+ // Qt Canvas nem támogatja ctx.roundRect() – saját helper
+ function rr(c, x, y, w, h, r) {
+ r = Math.min(Math.max(r, 0), Math.min(w, h) / 2)
+ c.beginPath()
+ c.moveTo(x + r, y)
+ c.arcTo(x + w, y, x + w, y + h, r)
+ c.arcTo(x + w, y + h, x, y + h, r)
+ c.arcTo(x, y + h, x, y, r)
+ c.arcTo(x, y, x + w, y, r)
+ c.closePath()
+ }
+
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.clearRect(0, 0, width, height)
+
+ if (networkIndicator.netType === "wifi")
+ drawWifi(ctx)
+ else if (networkIndicator.netType === "ethernet")
+ drawEthernet(ctx)
+ }
+
+ // ── WiFi antenna ikon (4 ívelt sáv) ─────────────────────────────
+ function drawWifi(ctx) {
+ var q = networkIndicator.wifiQuality
+ var cx = width / 2
+ var base = height * 0.96
+ var dot = height * 0.08
+
+ // Sávok száma a minőség alapján
+ var bars = q >= 70 ? 4 : q >= 45 ? 3 : q >= 20 ? 2 : 1
+ var col = networkIndicator.signalColor(q)
+
+ var radii = [height*0.14, height*0.32, height*0.54, height*0.76]
+ var arcStart = Math.PI * 1.25
+ var arcEnd = Math.PI * 1.75
+
+ for (var i = 0; i < 4; i++) {
+ ctx.beginPath()
+ ctx.arc(cx, base, radii[i], arcStart, arcEnd)
+ ctx.strokeStyle = col
+ ctx.globalAlpha = i < bars ? 0.90 : 0.22
+ ctx.lineWidth = height * 0.10
+ ctx.lineCap = "round"
+ ctx.stroke()
+ }
+
+ // Középső pont (antenna)
+ ctx.beginPath()
+ ctx.arc(cx, base, dot, 0, Math.PI * 2)
+ ctx.fillStyle = col
+ ctx.globalAlpha = 0.95
+ ctx.fill()
+ ctx.globalAlpha = 1.0
+ }
+
+ // ── Ethernet dugó ikon ───────────────────────────────────────────
+ function drawEthernet(ctx) {
+ var col = "#4ade80"
+ var lw = height * 0.09
+ ctx.strokeStyle = col
+ ctx.fillStyle = col
+ ctx.lineWidth = lw
+ ctx.lineCap = "round"
+ ctx.lineJoin = "round"
+ ctx.globalAlpha = 0.90
+
+ var cx = width / 2
+ var cy = height / 2
+
+ // Kábel test (felső téglalap)
+ var bw = width * 0.70
+ var bh = height * 0.38
+ var bx = cx - bw / 2
+ var by = cy - height * 0.30
+ rr(ctx, bx, by, bw, bh, height * 0.06)
+ ctx.stroke()
+
+ // 3 érintkező pin a téglalapban
+ var pinW = width * 0.08
+ var pinH = height * 0.22
+ var pinY = by - pinH + lw
+ var gap = bw / 4
+ for (var p = 0; p < 3; p++) {
+ rr(ctx, bx + gap * (p + 0.5) - pinW/2, pinY, pinW, pinH, 2)
+ ctx.fill()
+ }
+
+ // Kábel vonala lefelé
+ ctx.beginPath()
+ ctx.moveTo(cx, by + bh)
+ ctx.lineTo(cx, cy + height * 0.38)
+ ctx.stroke()
+
+ // Dugó alap vonal
+ ctx.lineWidth = lw * 1.5
+ ctx.beginPath()
+ ctx.moveTo(cx - width * 0.22, cy + height * 0.38)
+ ctx.lineTo(cx + width * 0.22, cy + height * 0.38)
+ ctx.stroke()
+
+ ctx.globalAlpha = 1.0
+ }
+ }
+
+ // Felirat
+ Text {
+ id: netLabel
+ anchors.verticalCenter: parent.verticalCenter
+ text: {
+ if (networkIndicator.netType === "ethernet") return "Ethernet"
+ return networkIndicator.wifiQuality + "%"
+ }
+ color: networkIndicator.netType === "ethernet"
+ ? "#4ade80"
+ : networkIndicator.signalColor(networkIndicator.wifiQuality)
+ font.pointSize: root.font.pointSize * 0.82
+ font.family: root.font.family
+ }
+
+ onNetTypeChanged: {
+ netCanvas.requestPaint()
+ }
+ onWifiQualityChanged: {
+ netCanvas.requestPaint()
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ParticleOverlay.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ParticleOverlay.qml
new file mode 100644
index 0000000..6fa02f9
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ParticleOverlay.qml
@@ -0,0 +1,90 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+
+Canvas {
+ id: particleCanvas
+
+ anchors.fill: parent
+
+ property int particleCount: 55
+ property var particles: []
+ property real time: 0
+
+ function initParticles() {
+ var arr = []
+ for (var i = 0; i < particleCount; i++) {
+ arr.push({
+ x: Math.random() * width,
+ y: Math.random() * height,
+ vx: (Math.random() - 0.5) * 0.35,
+ vy: (Math.random() - 0.5) * 0.35,
+ baseR: Math.random() * 2.0 + 0.8,
+ hue: Math.random() * 360,
+ hueSpeed: (Math.random() - 0.5) * 0.4,
+ phase: Math.random() * Math.PI * 2,
+ opacity: Math.random() * 0.45 + 0.15,
+ glowR: Math.random() * 18 + 8
+ })
+ }
+ particles = arr
+ }
+
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.clearRect(0, 0, width, height)
+
+ for (var i = 0; i < particles.length; i++) {
+ var p = particles[i]
+ var r = p.baseR * (0.75 + 0.25 * Math.sin(p.phase + time * 2.2))
+
+ // Glow halo
+ var grd = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, p.glowR)
+ grd.addColorStop(0, "hsla(" + p.hue + ",100%,72%," + (p.opacity * 0.55) + ")")
+ grd.addColorStop(1, "hsla(" + p.hue + ",100%,72%,0)")
+ ctx.beginPath()
+ ctx.arc(p.x, p.y, p.glowR, 0, Math.PI * 2)
+ ctx.fillStyle = grd
+ ctx.fill()
+
+ // Core dot
+ ctx.beginPath()
+ ctx.arc(p.x, p.y, r, 0, Math.PI * 2)
+ ctx.fillStyle = "hsla(" + p.hue + ",100%,88%," + p.opacity + ")"
+ ctx.fill()
+ }
+ }
+
+ Timer {
+ interval: 16
+ repeat: true
+ running: true
+ onTriggered: {
+ particleCanvas.time += 0.016
+ var pts = particleCanvas.particles
+ var W = particleCanvas.width
+ var H = particleCanvas.height
+ var t = particleCanvas.time
+ for (var i = 0; i < pts.length; i++) {
+ var p = pts[i]
+ p.x += p.vx + Math.sin(t * 0.9 + p.phase) * 0.28
+ p.y += p.vy + Math.cos(t * 0.7 + p.phase) * 0.28
+ p.hue += p.hueSpeed
+ p.phase += 0.008
+ var margin = p.glowR
+ if (p.x < -margin) p.x = W + margin
+ if (p.x > W + margin) p.x = -margin
+ if (p.y < -margin) p.y = H + margin
+ if (p.y > H + margin) p.y = -margin
+ }
+ particleCanvas.requestPaint()
+ }
+ }
+
+ Component.onCompleted: {
+ // kis késleltetés hogy a méret biztosan kész legyen
+ Qt.callLater(initParticles)
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/SessionButton.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/SessionButton.qml
new file mode 100644
index 0000000..301256b
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/SessionButton.qml
@@ -0,0 +1,158 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Based on https://github.com/MarianArlt/sddm-sugar-dark
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+Item {
+ id: sessionButton
+
+ height: root.font.pointSize * 2
+ width: parent.width / 2
+
+ property var selectedSession: selectSession.currentIndex
+ property string textConstantSession
+ property int loginButtonWidth
+ property ComboBox exposeSession: selectSession
+
+ ComboBox {
+ id: selectSession
+
+ // important
+ // change also in errorMessage
+ height: root.font.pointSize * 2
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ hoverEnabled: true
+ model: sessionModel
+ currentIndex: model.lastIndex
+ textRole: "name"
+
+ Keys.onPressed: function(event) {
+ if ((event.key == Qt.Key_Left || event.key == Qt.Key_Right) && !popup.opened) {
+ popup.open();
+ }
+ }
+
+ delegate: ItemDelegate {
+ // minus padding
+ width: popupHandler.width - 20
+ anchors.horizontalCenter: popupHandler.horizontalCenter
+
+ contentItem: Text {
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+
+ text: model.name
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+ color: config.DropdownTextColor
+ }
+
+ background: Rectangle {
+ color: selectSession.highlightedIndex === index ? Qt.rgba(1, 1, 1, 0.15) : "transparent"
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 4 : 5
+ }
+ }
+
+ indicator {
+ visible: false
+ }
+
+ contentItem: Text {
+ id: displayedItem
+
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ leftPadding: root.font.pointSize * 0.8
+ rightPadding: root.font.pointSize * 0.8
+
+ text: (config.TranslateSessionSelection || "Session") + ": " + selectSession.currentText
+ color: config.SessionButtonTextColor
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+
+ Keys.onReleased: parent.popup.open()
+ }
+
+ background: Rectangle {
+ anchors.fill: parent
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 10
+ color: selectSession.down ? Qt.rgba(1, 1, 1, 0.12) : (selectSession.hovered ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(1, 1, 1, 0.04))
+ border.color: selectSession.visualFocus ? Qt.rgba(1, 1, 1, 0.60) : (selectSession.hovered ? Qt.rgba(1, 1, 1, 0.35) : Qt.rgba(1, 1, 1, 0.18))
+ border.width: selectSession.visualFocus ? 1.5 : 1
+
+ Behavior on color { ColorAnimation { duration: 150 } }
+ Behavior on border.color { ColorAnimation { duration: 150 } }
+ }
+
+ popup: Popup {
+ id: popupHandler
+
+ implicitHeight: contentItem.implicitHeight
+ width: sessionButton.width
+ y: parent.height - 1
+ x: -popupHandler.width/2 + displayedItem.width/2
+ padding: 10
+
+ contentItem: ListView {
+ implicitHeight: contentHeight + 20
+
+ clip: true
+ model: selectSession.popup.visible ? selectSession.delegateModel : null
+ currentIndex: selectSession.highlightedIndex
+ ScrollIndicator.vertical: ScrollIndicator { }
+ }
+
+ background: Rectangle {
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 2 : 10
+ color: config.BackgroundColor
+ border.color: Qt.rgba(1, 1, 1, 0.20)
+ border.width: 1
+ }
+
+ enter: Transition {
+ NumberAnimation { property: "opacity"; from: 0; to: 1 }
+ }
+ }
+
+ states: [
+ State {
+ name: "pressed"
+ when: selectSession.down
+ PropertyChanges {
+ target: displayedItem
+ color: Qt.darker(config.HoverSessionButtonTextColor, 1.1)
+ }
+ },
+ State {
+ name: "hovered"
+ when: selectSession.hovered
+ PropertyChanges {
+ target: displayedItem
+ color: Qt.lighter(config.HoverSessionButtonTextColor, 1.1)
+ }
+ },
+ State {
+ name: "focused"
+ when: selectSession.visualFocus
+ PropertyChanges {
+ target: displayedItem
+ color: config.HoverSessionButtonTextColor
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ PropertyAnimation {
+ properties: "color"
+ duration: 150
+ }
+ }
+ ]
+
+ }
+
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ToastNotification.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ToastNotification.qml
new file mode 100644
index 0000000..43817c4
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/ToastNotification.qml
@@ -0,0 +1,83 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+Item {
+ id: toastRoot
+
+ anchors.top: parent.top
+ anchors.horizontalCenter: parent.horizontalCenter
+ width: parent.width
+ height: toastRect.height + root.font.pointSize * 2
+ z: 100
+
+ property string message: ""
+ property bool showing: false
+
+ function show(msg) {
+ message = msg
+ showing = true
+ hideTimer.restart()
+ }
+
+ function hide() {
+ showing = false
+ }
+
+ Rectangle {
+ id: toastRect
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ y: toastRoot.showing ? root.font.pointSize * 2 : -height - 10
+
+ Behavior on y {
+ NumberAnimation { duration: 380; easing.type: Easing.OutBack }
+ }
+
+ width: toastRow.implicitWidth + root.font.pointSize * 3
+ height: root.font.pointSize * 3
+ radius: height / 2
+
+ color: Qt.rgba(0.75, 0.08, 0.08, 0.88)
+ border.color: Qt.rgba(1, 0.35, 0.35, 0.65)
+ border.width: 1
+
+ // Pulse animation border
+ SequentialAnimation on border.color {
+ running: toastRoot.showing
+ loops: Animation.Infinite
+ ColorAnimation { to: Qt.rgba(1, 0.5, 0.5, 0.9); duration: 600; easing.type: Easing.InOutSine }
+ ColorAnimation { to: Qt.rgba(1, 0.25, 0.25, 0.5); duration: 600; easing.type: Easing.InOutSine }
+ }
+
+ Row {
+ id: toastRow
+ anchors.centerIn: parent
+ spacing: root.font.pointSize * 0.6
+
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "⚠"
+ color: "#ff8888"
+ font.pointSize: root.font.pointSize * 0.9
+ }
+
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: toastRoot.message
+ color: "#ffffff"
+ font.pointSize: root.font.pointSize * 0.85
+ font.family: root.font.family
+ }
+ }
+ }
+
+ Timer {
+ id: hideTimer
+ interval: 3000
+ onTriggered: toastRoot.hide()
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/UserSwitcher.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/UserSwitcher.qml
new file mode 100644
index 0000000..d16c496
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/UserSwitcher.qml
@@ -0,0 +1,332 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Effects
+
+Item {
+ id: userSwitcher
+
+ // Csak akkor látható ha több mint 1 felhasználó van
+ visible: userModel.count > 1
+
+ width: switchBtn.implicitWidth + root.font.pointSize * 2
+ height: switchBtn.implicitHeight + root.font.pointSize * 0.6
+
+ // Kiválasztott felhasználó indexe (kívülről beállítható)
+ property int selectedIndex: 0
+ property string selectedName: {
+ if (userModel.count < 1) return ""
+ var n = userModel.data(userModel.index(selectedIndex, 0), Qt.UserRole + 1)
+ return n ? n : ""
+ }
+
+ signal userSwitched(int idx, string name)
+
+ // ── Segédfüggvények ───────────────────────────────────────────────────────────────────
+ function isImagePath(p) {
+ return p && p !== ""
+ }
+
+ function getUserIcon(idx) {
+ // Qt.UserRole+4 = IconRole (ebben az SDDM verziban a Home = +3)
+ var icon = userModel.data(userModel.index(idx, 0), Qt.UserRole + 4)
+ return isImagePath(icon) ? icon : ""
+ }
+
+ function getUserName(idx) {
+ return userModel.data(userModel.index(idx, 0), Qt.UserRole + 1) || ""
+ }
+
+ // ── Gomb (chip stílus) ────────────────────────────────────────────────────
+ Rectangle {
+ id: switchBtn
+ anchors.centerIn: parent
+ implicitWidth: btnRow.implicitWidth + root.font.pointSize * 1.6
+ implicitHeight: btnRow.implicitHeight + root.font.pointSize * 0.7
+ radius: implicitHeight / 2
+
+ color: btnArea.pressed
+ ? Qt.rgba(1, 1, 1, 0.18)
+ : btnArea.containsMouse
+ ? Qt.rgba(1, 1, 1, 0.12)
+ : Qt.rgba(1, 1, 1, 0.07)
+ border.color: btnArea.containsMouse
+ ? Qt.rgba(1, 1, 1, 0.45)
+ : Qt.rgba(1, 1, 1, 0.22)
+ border.width: 1
+
+ Behavior on color { ColorAnimation { duration: 150 } }
+ Behavior on border.color{ ColorAnimation { duration: 150 } }
+
+ Row {
+ id: btnRow
+ anchors.centerIn: parent
+ spacing: root.font.pointSize * 0.5
+
+ // Mini avatar kör
+ Rectangle {
+ id: miniAvatarCircle
+ width: root.font.pointSize * 1.6
+ height: root.font.pointSize * 1.6
+ radius: width / 2
+ clip: true
+ color: Qt.rgba(0.10, 0.10, 0.18, 0.70)
+ anchors.verticalCenter: parent.verticalCenter
+
+ Image {
+ id: miniPhoto
+ anchors.fill: parent
+ source: userSwitcher.getUserIcon(userSwitcher.selectedIndex)
+ fillMode: Image.PreserveAspectCrop
+ smooth: true
+ visible: false
+ }
+
+ Item {
+ id: miniMask
+ anchors.fill: parent
+ visible: false
+ layer.enabled: true
+ Rectangle {
+ anchors.fill: parent
+ radius: parent.width / 2
+ color: "black"
+ }
+ }
+
+ MultiEffect {
+ anchors.fill: parent
+ source: miniPhoto
+ visible: miniPhoto.status === Image.Ready && miniPhoto.source !== ""
+ maskEnabled: true
+ maskSource: miniMask
+ maskThresholdMin: 0.5
+ maskSpreadAtMin: 1.0
+ }
+
+ Image {
+ anchors.centerIn: parent
+ width: parent.width * 0.70
+ height: parent.height * 0.70
+ source: Qt.resolvedUrl("../Assets/User.svg")
+ fillMode: Image.PreserveAspectFit
+ visible: miniPhoto.status !== Image.Ready || miniPhoto.source === ""
+ opacity: 0.80
+ }
+ }
+
+ // Felhasználónév
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: userSwitcher.selectedName
+ color: "#ffffff"
+ font.pointSize: root.font.pointSize * 0.82
+ font.family: root.font.family
+ }
+
+ // Nyíl ikon
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: "⌄"
+ color: Qt.rgba(1, 1, 1, 0.70)
+ font.pointSize: root.font.pointSize * 0.85
+ font.family: root.font.family
+ // Csak ha több user van, akkor látszik a nyíl
+ visible: userModel.count > 1
+
+ rotation: popup.visible ? 180 : 0
+ Behavior on rotation { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } }
+ }
+ }
+
+ MouseArea {
+ id: btnArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ // Csak akkor nyit popup-ot ha több felhasználó van
+ onClicked: if (userModel.count > 1) { popup.visible ? popup.close() : popup.open() }
+ }
+ }
+
+ // ── Felhasználó-lista popup ───────────────────────────────────────────────
+ Popup {
+ id: popup
+
+ parent: Overlay.overlay
+ x: (parent.width - width) / 2
+ y: (parent.height - height) / 2
+
+ width: root.font.pointSize * 18
+ padding: root.font.pointSize * 0.6
+
+ modal: true
+ focus: true
+ closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
+
+ enter: Transition {
+ NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 200; easing.type: Easing.OutCubic }
+ NumberAnimation { property: "scale"; from: 0.92; to: 1; duration: 200; easing.type: Easing.OutCubic }
+ }
+ exit: Transition {
+ NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 160; easing.type: Easing.InCubic }
+ }
+
+ background: Rectangle {
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 16
+ color: config.BackgroundColor
+ border.color: Qt.rgba(1, 1, 1, 0.18)
+ border.width: 1
+ }
+
+ // Fejléc
+ Column {
+ width: parent.width
+ spacing: root.font.pointSize * 0.4
+
+ Text {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: "Felhasználó váltás"
+ color: Qt.rgba(1, 1, 1, 0.55)
+ font.pointSize: root.font.pointSize * 0.75
+ font.family: root.font.family
+ bottomPadding: root.font.pointSize * 0.2
+ }
+
+ // Elválasztó vonal
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: Qt.rgba(1, 1, 1, 0.12)
+ }
+
+ // Felhasználók listája
+ ListView {
+ id: userList
+ width: parent.width
+ height: Math.min(contentHeight, root.font.pointSize * 22)
+ model: userModel
+ clip: true
+ spacing: 2
+ boundsBehavior: Flickable.StopAtBounds
+
+ ScrollIndicator.vertical: ScrollIndicator { }
+
+ delegate: Rectangle {
+ id: delegateRect
+ width: userList.width
+ height: root.font.pointSize * 4
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) / 2 : 8
+
+ // Kiemelés: aktív felhasználó
+ property bool isActive: index === userSwitcher.selectedIndex
+ color: isActive
+ ? Qt.rgba(1, 1, 1, 0.12)
+ : delegateMouse.containsMouse
+ ? Qt.rgba(1, 1, 1, 0.07)
+ : "transparent"
+
+ Behavior on color { ColorAnimation { duration: 120 } }
+
+ Row {
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: root.font.pointSize * 0.7
+ spacing: root.font.pointSize * 0.8
+
+ // Avatar kör
+ Rectangle {
+ id: delegateAvatarCircle
+ width: root.font.pointSize * 3
+ height: root.font.pointSize * 3
+ radius: width / 2
+ clip: true
+ color: Qt.rgba(0.12, 0.12, 0.20, 0.80)
+ anchors.verticalCenter: parent.verticalCenter
+
+ property string iconPath: userSwitcher.getUserIcon(index)
+
+ Image {
+ id: delegatePhoto
+ anchors.fill: parent
+ source: parent.iconPath
+ fillMode: Image.PreserveAspectCrop
+ smooth: true
+ visible: false
+ }
+
+ Item {
+ id: delegateMask
+ anchors.fill: parent
+ visible: false
+ layer.enabled: true
+ Rectangle {
+ anchors.fill: parent
+ radius: parent.width / 2
+ color: "black"
+ }
+ }
+
+ MultiEffect {
+ anchors.fill: parent
+ source: delegatePhoto
+ visible: delegatePhoto.status === Image.Ready && parent.iconPath !== ""
+ maskEnabled: true
+ maskSource: delegateMask
+ maskThresholdMin: 0.5
+ maskSpreadAtMin: 1.0
+ }
+
+ Image {
+ anchors.centerIn: parent
+ width: parent.width * 0.65
+ height: parent.height * 0.65
+ source: Qt.resolvedUrl("../Assets/User.svg")
+ fillMode: Image.PreserveAspectFit
+ visible: delegatePhoto.status !== Image.Ready || parent.iconPath === ""
+ opacity: 0.75
+ }
+ }
+
+ // Felhasználónév
+ Text {
+ anchors.verticalCenter: parent.verticalCenter
+ text: userSwitcher.getUserName(index)
+ color: delegateRect.isActive ? "#ffffff" : Qt.rgba(1,1,1,0.80)
+ font.pointSize: root.font.pointSize * 0.88
+ font.family: root.font.family
+ font.bold: delegateRect.isActive
+ }
+ }
+
+ // Aktív jelző csík a bal oldalon
+ Rectangle {
+ visible: delegateRect.isActive
+ width: 3
+ height: parent.height * 0.55
+ radius: 2
+ color: Qt.rgba(74/255, 222/255, 128/255, 0.90)
+ anchors.verticalCenter: parent.verticalCenter
+ anchors.left: parent.left
+ anchors.leftMargin: 2
+ }
+
+ MouseArea {
+ id: delegateMouse
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ userSwitcher.selectedIndex = index
+ userSwitcher.userSwitched(index, userSwitcher.getUserName(index))
+ popup.close()
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboard.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboard.qml
new file mode 100644
index 0000000..b7b7a0f
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboard.qml
@@ -0,0 +1,20 @@
+import QtQuick 2.15
+import QtQuick.VirtualKeyboard
+import QtQuick.VirtualKeyboard.Settings
+
+InputPanel {
+ id: virtualKeyboard
+
+ property bool activated: false
+ visible: true
+
+ Component.onCompleted: {
+ VirtualKeyboardSettings.activeLocales = ["en_US", "hu_HU"]
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ z: -1
+ onClicked: {} // Consume clicks so they don't fall through to the background and steal focus
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboardButton.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboardButton.qml
new file mode 100644
index 0000000..90a52b8
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Components/VirtualKeyboardButton.qml
@@ -0,0 +1,79 @@
+// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 Keyitdev
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+
+Item {
+ Button {
+ id: virtualKeyboardButton
+
+ anchors.horizontalCenter: parent.horizontalCenter
+ z: 1
+ focusPolicy: Qt.TabFocus
+
+ visible: virtualKeyboard.status == Loader.Ready && config.HideVirtualKeyboard == "false"
+ checkable: true
+ onClicked: virtualKeyboard.switchState()
+
+ Keys.onReturnPressed: {
+ toggle();
+ virtualKeyboard.switchState();
+ }
+ Keys.onEnterPressed: {
+ toggle();
+ virtualKeyboard.switchState();
+ }
+
+ contentItem: Text {
+ id: virtualKeyboardButtonText
+
+ text: config.TranslateVirtualKeyboardButtonOff || "Virtual Keyboard (off)"
+ font.pointSize: root.font.pointSize * 0.8
+ font.family: root.font.family
+ color: parent.visualFocus ? config.HoverVirtualKeyboardButtonTextColor : config.VirtualKeyboardButtonTextColor
+ }
+
+ background: Rectangle {
+ id: virtualKeyboardButtonBackground
+
+ anchors.fill: parent
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 10
+ color: virtualKeyboardButton.down ? Qt.rgba(1, 1, 1, 0.12) : (virtualKeyboardButton.hovered ? Qt.rgba(1, 1, 1, 0.08) : Qt.rgba(1, 1, 1, 0.04))
+ border.color: virtualKeyboardButton.visualFocus ? Qt.rgba(1, 1, 1, 0.60) : (virtualKeyboardButton.hovered ? Qt.rgba(1, 1, 1, 0.35) : Qt.rgba(1, 1, 1, 0.18))
+ border.width: virtualKeyboardButton.visualFocus ? 1.5 : 1
+
+ Behavior on color { ColorAnimation { duration: 150 } }
+ Behavior on border.color { ColorAnimation { duration: 150 } }
+ }
+ states: [
+ State {
+ name: "HoveredAndChecked"
+ when: virtualKeyboardButton.checked && virtualKeyboardButton.hovered
+ PropertyChanges {
+ target: virtualKeyboardButtonText
+ text: config.TranslateVirtualKeyboardButtonOn || "Virtual Keyboard (on)"
+ color: config.HoverVirtualKeyboardButtonTextColor
+ }
+ },
+ State {
+ name: "checked"
+ when: virtualKeyboardButton.checked
+ PropertyChanges {
+ target: virtualKeyboardButtonText
+ text: config.TranslateVirtualKeyboardButtonOn || "Virtual Keyboard (on)"
+ }
+ },
+ State {
+ name: "hovered"
+ when: virtualKeyboardButton.hovered
+ PropertyChanges {
+ target: virtualKeyboardButtonText
+ text: config.TranslateVirtualKeyboardButtonOff || "Virtual Keyboard (off)"
+ color: config.HoverVirtualKeyboardButtonTextColor
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Bold.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Bold.ttf
new file mode 100644
index 0000000..4d8f3e5
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Bold.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-BoldItalic.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-BoldItalic.ttf
new file mode 100644
index 0000000..eba75d7
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-BoldItalic.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBold.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBold.ttf
new file mode 100644
index 0000000..db66f6a
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBold.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
new file mode 100644
index 0000000..b7611bb
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-ExtraBoldItalic.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Italic.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Italic.ttf
new file mode 100644
index 0000000..b088474
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Italic.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Light.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Light.ttf
new file mode 100644
index 0000000..d01b20c
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Light.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-LightItalic.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-LightItalic.ttf
new file mode 100644
index 0000000..0441a59
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-LightItalic.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Medium.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Medium.ttf
new file mode 100644
index 0000000..6b41918
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Medium.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-MediumItalic.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-MediumItalic.ttf
new file mode 100644
index 0000000..c84fe4f
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-MediumItalic.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Regular.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Regular.ttf
new file mode 100644
index 0000000..3a29f26
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-Regular.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBold.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBold.ttf
new file mode 100644
index 0000000..219f6e8
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBold.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBoldItalic.ttf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBoldItalic.ttf
new file mode 100644
index 0000000..259ac50
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Fonts/OpenSans/OpenSans-SemiBoldItalic.ttf
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/LICENSE b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<https://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<https://www.gnu.org/licenses/why-not-lgpl.html>.
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Main.qml b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Main.qml
new file mode 100644
index 0000000..00837d2
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Main.qml
@@ -0,0 +1,378 @@
+// Config created by gabeszm https://git.rp1.hu/gabeszm/sddm-rave-theme
+// Copyright (C) 2022-2025 gabeszm
+// Based on https://github.com/MarianArlt/sddm-sugar-dark
+// Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtQuick.Controls 2.15
+import QtQuick.Effects
+import QtMultimedia
+
+import "Components"
+
+Pane {
+ id: root
+
+ height: config.ScreenHeight || Screen.height
+ width: config.ScreenWidth || Screen.ScreenWidth
+ padding: config.ScreenPadding
+
+ LayoutMirroring.enabled: config.RightToLeftLayout == "true" ? true : Qt.application.layoutDirection === Qt.RightToLeft
+ LayoutMirroring.childrenInherit: true
+
+ palette.window: config.BackgroundColor
+ palette.highlight: config.HighlightBackgroundColor
+ palette.highlightedText: config.HighlightTextColor
+ palette.buttonText: config.HoverSystemButtonsIconsColor
+
+ font.family: config.Font
+ font.pointSize: config.FontSize !== "" ? config.FontSize : parseInt(height / 80) || 13
+
+ focus: true
+
+ property bool leftleft: config.HaveFormBackground == "true" &&
+ config.PartialBlur == "false" &&
+ config.FormPosition == "left" &&
+ config.BackgroundHorizontalAlignment == "left"
+
+ property bool leftcenter: config.HaveFormBackground == "true" &&
+ config.PartialBlur == "false" &&
+ config.FormPosition == "left" &&
+ config.BackgroundHorizontalAlignment == "center"
+
+ property bool rightright: config.HaveFormBackground == "true" &&
+ config.PartialBlur == "false" &&
+ config.FormPosition == "right" &&
+ config.BackgroundHorizontalAlignment == "right"
+
+ property bool rightcenter: config.HaveFormBackground == "true" &&
+ config.PartialBlur == "false" &&
+ config.FormPosition == "right" &&
+ config.BackgroundHorizontalAlignment == "center"
+
+ Item {
+ id: sizeHelper
+
+ height: parent.height
+ width: parent.width
+ anchors.fill: parent
+
+ Rectangle {
+ id: tintLayer
+
+ height: parent.height
+ width: parent.width
+ anchors.fill: parent
+ z: 1
+ color: config.DimBackgroundColor
+ opacity: config.DimBackground
+ }
+
+
+ Canvas {
+ id: animatedBorder
+
+ width: form.width / 2 + 60 + 6
+ height: form.height + 60 + 6
+ anchors.centerIn: form
+ z: 3
+
+ property real angle: 0
+ property real radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 20
+
+ onAngleChanged: requestPaint()
+
+ onPaint: {
+ var ctx = getContext("2d");
+ ctx.reset();
+ ctx.clearRect(0, 0, width, height);
+
+ var r = radius;
+ var x = 3;
+ var y = 3;
+ var w = width - 6;
+ var h = height - 6;
+
+ ctx.beginPath();
+ ctx.arc(x + r, y + r, r, Math.PI, 1.5 * Math.PI);
+ ctx.lineTo(x + w - r, y);
+ ctx.arc(x + w - r, y + r, r, 1.5 * Math.PI, 2 * Math.PI);
+ ctx.lineTo(x + w, y + h - r);
+ ctx.arc(x + w - r, y + h - r, r, 0, 0.5 * Math.PI);
+ ctx.lineTo(x + r, y + h);
+ ctx.arc(x + r, y + h - r, r, 0.5 * Math.PI, Math.PI);
+ ctx.closePath();
+
+ ctx.save();
+ ctx.translate(width / 2, height / 2);
+ ctx.rotate(angle);
+
+ var grad = ctx.createLinearGradient(-width / 2, -height / 2, width / 2, height / 2);
+ grad.addColorStop(0, "rgba(255, 255, 255, 0.45)");
+ grad.addColorStop(0.5, "rgba(255, 255, 255, 0.12)");
+ grad.addColorStop(1, "rgba(255, 255, 255, 0.45)");
+
+ ctx.strokeStyle = grad;
+ ctx.lineWidth = 2;
+ ctx.stroke();
+ ctx.restore();
+ }
+
+ NumberAnimation on angle {
+ loops: Animation.Infinite
+ from: 0
+ to: 2 * Math.PI
+ duration: 5000
+ }
+
+ SequentialAnimation on opacity {
+ loops: Animation.Infinite
+ NumberAnimation { from: 0.5; to: 0.9; duration: 2500; easing.type: Easing.InOutQuad }
+ NumberAnimation { from: 0.9; to: 0.5; duration: 2500; easing.type: Easing.InOutQuad }
+ }
+ }
+
+ Rectangle {
+ id: formBackground
+
+ width: form.width / 2 + 60
+ height: form.height + 60
+ anchors.centerIn: form
+ z: 4
+
+ color: Qt.rgba(1, 1, 1, 0.08)
+ border.color: Qt.rgba(1, 1, 1, 0.18)
+ border.width: 1
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 20
+ visible: true
+ }
+
+ LoginForm {
+ id: form
+
+ height: implicitHeight
+ width: parent.width / 2.5
+ anchors.left: config.FormPosition == "left" ? parent.left : undefined
+ anchors.horizontalCenter: config.FormPosition == "center" ? parent.horizontalCenter : undefined
+ anchors.right: config.FormPosition == "right" ? parent.right : undefined
+ anchors.verticalCenter: parent.verticalCenter
+ z: 5
+ }
+
+ Loader {
+ id: virtualKeyboard
+ source: "Components/VirtualKeyboard.qml"
+
+ // x * 0.4 = x / 2.5
+ width: config.KeyboardSize == "" ? parent.width * 0.4 : parent.width * config.KeyboardSize
+ anchors.left: config.VirtualKeyboardPosition == "left" ? parent.left : undefined;
+ anchors.horizontalCenter: config.VirtualKeyboardPosition == "center" ? parent.horizontalCenter : undefined;
+ anchors.right: config.VirtualKeyboardPosition == "right" ? parent.right : undefined;
+ z: 100
+
+ state: "hidden"
+ property bool keyboardActive: item ? item.active : false
+
+ function switchState() { state = state == "hidden" ? "visible" : "hidden"}
+ states: [
+ State {
+ name: "visible"
+ PropertyChanges {
+ target: virtualKeyboard
+ y: root.height - virtualKeyboard.height
+ opacity: 1
+ }
+ },
+ State {
+ name: "hidden"
+ PropertyChanges {
+ target: virtualKeyboard
+ y: root.height - root.height/4
+ opacity: 0
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "hidden"
+ to: "visible"
+ SequentialAnimation {
+ ScriptAction {
+ script: {
+ virtualKeyboard.item.activated = true;
+ Qt.inputMethod.show();
+ }
+ }
+ ParallelAnimation {
+ NumberAnimation {
+ target: virtualKeyboard
+ property: "y"
+ duration: 100
+ easing.type: Easing.OutQuad
+ }
+ OpacityAnimator {
+ target: virtualKeyboard
+ duration: 100
+ easing.type: Easing.OutQuad
+ }
+ }
+ }
+ },
+ Transition {
+ from: "visible"
+ to: "hidden"
+ SequentialAnimation {
+ ParallelAnimation {
+ NumberAnimation {
+ target: virtualKeyboard
+ property: "y"
+ duration: 100
+ easing.type: Easing.InQuad
+ }
+ OpacityAnimator {
+ target: virtualKeyboard
+ duration: 100
+ easing.type: Easing.InQuad
+ }
+ }
+ ScriptAction {
+ script: {
+ virtualKeyboard.item.activated = false;
+ Qt.inputMethod.hide();
+ }
+ }
+ }
+ }
+ ]
+ }
+
+ Image {
+ id: backgroundPlaceholderImage
+
+ z: 10
+ source: config.BackgroundPlaceholder
+ visible: false
+ }
+
+ AnimatedImage {
+ id: backgroundImage
+
+ MediaPlayer {
+ id: player
+
+ videoOutput: videoOutput
+ autoPlay: true
+ playbackRate: config.BackgroundSpeed == "" ? 1.0 : config.BackgroundSpeed
+ loops: -1
+ onPlayingChanged: {
+ console.log("Video started.")
+ backgroundPlaceholderImage.visible = false;
+ }
+ }
+
+ VideoOutput {
+ id: videoOutput
+
+ fillMode: config.CropBackground == "true" ? VideoOutput.PreserveAspectCrop : VideoOutput.PreserveAspectFit
+ anchors.fill: parent
+ }
+
+ height: parent.height
+ width: config.HaveFormBackground == "true" && config.FormPosition != "center" && config.PartialBlur != "true" ? parent.width - formBackground.width : parent.width
+ anchors.left: leftleft || leftcenter ? formBackground.right : undefined
+ anchors.right: rightright || rightcenter ? formBackground.left : undefined
+
+ horizontalAlignment: config.BackgroundHorizontalAlignment == "left" ?
+ Image.AlignLeft :
+ config.BackgroundHorizontalAlignment == "right" ?
+ Image.AlignRight : Image.AlignHCenter
+
+ verticalAlignment: config.BackgroundVerticalAlignment == "top" ?
+ Image.AlignTop :
+ config.BackgroundVerticalAlignment == "bottom" ?
+ Image.AlignBottom : Image.AlignVCenter
+
+ speed: config.BackgroundSpeed == "" ? 1.0 : config.BackgroundSpeed
+ paused: config.PauseBackground == "true" ? 1 : 0
+ fillMode: config.CropBackground == "true" ? Image.PreserveAspectCrop : Image.PreserveAspectFit
+ asynchronous: true
+ cache: true
+ clip: true
+ mipmap: true
+
+ Component.onCompleted:{
+ var fileType = config.Background.substring(config.Background.lastIndexOf(".") + 1)
+ const videoFileTypes = ["avi", "mp4", "mov", "mkv", "m4v", "webm"];
+ if (videoFileTypes.includes(fileType)) {
+ backgroundPlaceholderImage.visible = true;
+ player.source = Qt.resolvedUrl(config.Background)
+ player.play();
+ }
+ else{
+ backgroundImage.source = config.background || config.Background
+ }
+ }
+ }
+
+ MouseArea {
+ anchors.fill: backgroundImage
+ onClicked: parent.forceActiveFocus()
+ }
+
+ ShaderEffectSource {
+ id: blurMask
+
+ height: form.height + 60
+ width: form.width / 2 + 60
+ anchors.centerIn: form
+
+ sourceItem: backgroundImage
+ sourceRect: Qt.rect(x,y,width,height)
+ visible: true
+ }
+
+ ShaderEffectSource {
+ id: blurMaskItem
+
+ sourceItem: Rectangle {
+ width: blurMask.width
+ height: blurMask.height
+ radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : 20
+ color: "black"
+ }
+ hideSource: true
+ visible: false
+ }
+
+ MultiEffect {
+ id: blur
+ z: 2
+
+ height: config.FullBlur == "true" ? parent.height : blurMask.height
+ width: config.FullBlur == "true" ? parent.width : blurMask.width
+ anchors.centerIn: config.FullBlur == "true" ? backgroundImage : form
+
+ source: config.FullBlur == "true" ? backgroundImage : blurMask
+ blurEnabled: true
+ autoPaddingEnabled: false
+ blur: config.Blur == "" ? 2.5 : config.Blur
+ blurMax: config.BlurMax == "" ? 48 : config.BlurMax
+ visible: true
+
+ maskEnabled: config.FullBlur == "true" ? false : true
+ maskSource: blurMaskItem
+ }
+
+ ToastNotification {
+ id: toast
+ }
+
+ Connections {
+ target: sddm
+ function onLoginFailed() {
+ toast.show(config.TranslateLoginFailedWarning || textConstants.loginFailed + "!")
+ }
+ }
+ }
+}
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Previews/rave.png b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Previews/rave.png
new file mode 100644
index 0000000..a370463
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Previews/rave.png
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/logo.png b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/logo.png
new file mode 100644
index 0000000..9903765
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/logo.png
Binary files differ
diff --git a/raveos-hyprland-theme/theme-data/sddm/astronaut.conf b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/rave.conf
index 7fa907e..372cc23 100644
--- a/raveos-hyprland-theme/theme-data/sddm/astronaut.conf
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/Themes/rave.conf
@@ -4,7 +4,8 @@
ScreenWidth="1920"
ScreenHeight="1080"
ScreenPadding=""
-# Default 0, Options: from 0 to min(screen width/2,screen height/2).
+Logo="Themes/logo.png"
+# Default 0, Options: from 0 to min(screen width/2,screen height/2).
Font="Open Sans"
FontSize="13"
@@ -15,11 +16,11 @@ KeyboardSize="0.4"
RoundCorners="20"
-Locale=""
+Locale="hu"
# Locale for data and time format. I suggest leaving it blank.
HourFormat="HH:mm"
# Default Locale.ShortFormat.
-DateFormat="dddd d MMMM"
+DateFormat="MMMM d dddd"
# Default Locale.LongFormat.
HeaderText=""
@@ -32,7 +33,7 @@ BackgroundPlaceholder=""
# Background displayed before the actual background is loaded.
# Use only if the background is a video, otherwise leave blank.
# Connected with: Background.
-Background="Backgrounds/new-raveos-main-bg.jpeg"
+Background="Backgrounds/rave_background.png"
# Must be a relative path.
# Supports: png, jpg, jpeg, webp, gif, avi, mp4, mov, mkv, m4v, webm.
BackgroundSpeed=""
@@ -80,7 +81,7 @@ PlaceholderTextColor="#bbbbbb"
WarningColor="#343746"
LoginButtonTextColor="#ffffff"
-LoginButtonBackgroundColor="#343746"
+LoginButtonBackgroundColor="#4ADE8066"
SystemButtonsIconsColor="#F8F8F2"
SessionButtonTextColor="#F8F8F2"
VirtualKeyboardButtonTextColor="#F8F8F2"
@@ -116,12 +117,12 @@ Blur=""
HaveFormBackground="false"
# Form background is transparent if set to false.
# Connected with: PartialBlur and BackgroundColor.
-FormPosition="center"
+FormPosition="right"
# Default: left, Options: left, center, right.
#################### Virtual Keyboard ####################
-VirtualKeyboardPosition="center"
+VirtualKeyboardPosition="left"
# Default: left, Options: left, center, right.
#################### Interface Behavior ####################
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/metadata.desktop b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/metadata.desktop
new file mode 100755
index 0000000..cae4303
--- /dev/null
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm-rave-theme/metadata.desktop
@@ -0,0 +1,15 @@
+[SddmGreeterTheme]
+Name=sddm-rave-theme
+Description=sddm-rave-theme
+Author=gabeszm
+Website=https://git.rp1.hu/gabeszm/sddm-rave-theme
+License=GPL-3.0-or-later
+Type=sddm-theme
+Version=0.3
+ConfigFile=Themes/rave.conf
+Screenshot=Previews/rave.png
+MainScript=Main.qml
+TranslationsDirectory=translations
+Theme-Id=sddm-rave-theme
+Theme-API=2.0
+QtVersion=6
diff --git a/raveos-hyprland-theme/theme-data/sddm/sddm.conf b/raveos-hyprland-theme/theme-data/sddm/sddm.conf
index 56b50a7..350a465 100644
--- a/raveos-hyprland-theme/theme-data/sddm/sddm.conf
+++ b/raveos-hyprland-theme/theme-data/sddm/sddm.conf
@@ -1,5 +1,5 @@
[Theme]
-Current=sddm-astronaut-theme
+Current=sddm-rave-theme
CursorTheme=BreezeDark
CursorSize=24