├── .gitignore
├── LICENSE
├── README.md
├── SnowWhite
├── BusyIndicator.qml
├── Button.qml
├── CheckBox.qml
├── ComboBox.qml
├── Dial.qml
├── Frame.qml
├── Label.qml
├── ProgressBar.qml
├── RadioButton.qml
├── RangeSlider.qml
├── Slider.qml
├── SnowWhite.pri
├── SnowWhite.pro
├── SnowWhite.qml
├── SpinBox.qml
├── SplitView.qml
├── StackView.qml
├── Switch.qml
├── TextArea.qml
├── TextField.qml
├── Tumbler.qml
├── base
│ └── DashedRing.qml
├── qmldir
├── script.js
└── snowwhite.qrc
├── docs
└── README.md
├── example
├── example-1
│ ├── ColorPicker.qml
│ ├── example-1.pro
│ ├── main.cpp
│ ├── main.qml
│ ├── qml.qrc
│ ├── qtquickcontrols2.conf
│ └── resources
│ │ └── Carlito-Regular.ttf
└── example.pro
├── extra
└── preview
│ ├── preview-1.webp
│ └── preview-2.webp
└── snow-white.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | *.tmp
2 |
3 | # style template
4 | *Pending/*
5 |
6 | # qt build directory
7 | build*
8 |
9 | # qt IDE user settigns
10 | *.user
11 | *.autosave
12 |
13 | .vscode
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 smr
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # QML Snow White
2 |
3 |
4 |
5 | 
6 |
7 |
8 | **Snow White** QtQuick2 theme.
9 | *Tired of the same UI for QtQuick2?* Here is my own UI for the most common components, which you can simply utilize.
10 | You may also swap and change between color variations; the implementation is well-formed for color changes, and it is also simple to do.
11 | *If you liked these components, please consider givin a star :star2:.*
12 | ## Preview
13 |
14 |
20 |
21 | ## How to use
22 | > **Warning**
23 | > This component has only been tested on **Qt version 5.15.2** and *Windows OS* at *3840x2160 resolution* with a *scaling factor of 250 percent*; ***USAGE OF THIS COMPONENT CARRIES NO WARRANTY***.
24 | >
25 |
26 | ### Usage
27 |
28 | Clone the repository first.
29 |
30 | ```bash
31 | git clone https://github.com/SMR76/qml-snow-white.git
32 | ```
33 |
34 | Then include `SnowWhite.pri` in your project. [see example-1](example/example-1/example-1.pro#L11)
35 | ```make
36 | include('path/to/SnowWhite.pri')
37 | ```
38 |
39 | Add `qrc:/` to the engine import path. [see example-1](example/example-1/main.cpp#L17)
40 | ```cpp
41 | engine.addImportPath("qrc:/");
42 | ```
43 |
44 | And finally import the `SnowWhite` module. [see example-1](example/example-1/main.qml#L6)
45 | ```qml
46 | import SnowWhite 1.0
47 | ```
48 |
49 | If you are confused, please refer to [example-1](example/example-1/) for a clearer understanding of what you should do.
50 |
51 | ## Components
52 |
53 |
54 | Available
55 |
56 | - [x] Button
57 | - [x] Radio Button
58 | - [x] CheckBox
59 | - [x] Slider
60 | - [x] TextArea
61 | - [x] TextField
62 | - [x] ProgressBar
63 | - [x] RadioButton
64 | - [x] Switch
65 | - [x] RangeSlider
66 | - [x] SpinBox
67 | - [x] Tumbler
68 | - [x] Dial
69 | - [x] BusyIndicator *(updated)*
70 | - [x] SplitView
71 | - [x] StackView
72 | - [x] ComboBox
73 |
74 |
75 |
76 | ## Issues
77 |
78 | Please file an issue on [issues page](https://github.com/SMR76/qml-snow-white/issues) if you have any problems.
79 |
80 | ## Documentation
81 |
82 | [Documentation](docs/README.md) can be found in the `docs` directory.
--------------------------------------------------------------------------------
/SnowWhite/BusyIndicator.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 | import QtQuick.Templates 2.15 as T
3 |
4 | T.BusyIndicator {
5 | id: control
6 |
7 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
8 | implicitContentWidth + leftPadding + rightPadding)
9 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
10 | implicitContentHeight + topPadding + bottomPadding)
11 |
12 | visible: running
13 | running: false
14 | padding: 6
15 |
16 | contentItem: ShaderEffect {
17 | id: effect
18 |
19 | property real strokeWidth: 0.06
20 | property real sweepAngle: .5
21 | property color color: control.palette.button
22 |
23 | fragmentShader: "
24 | varying highp vec2 qt_TexCoord0;
25 | uniform highp float qt_Opacity;
26 | uniform highp float sweepAngle;
27 | uniform highp float strokeWidth;
28 | uniform highp float width;
29 | uniform highp vec4 color;
30 |
31 | void main() {
32 | highp vec2 coord = qt_TexCoord0 - vec2(0.5);
33 | highp float ring = smoothstep(0.0, 0.5/width, -abs(length(coord) - 0.5 + strokeWidth) + strokeWidth);
34 | gl_FragColor = color * ring;
35 | gl_FragColor *= smoothstep(0.0, 0.5/width, -atan(coord.x, coord.y) / 6.2831 - 0.48 + sweepAngle);
36 | }"
37 | }
38 |
39 | Timer {
40 | property real seed: 0
41 | running: control.running
42 | repeat: true; interval: 25 // Almost 40Hz
43 | onTriggered: {
44 | effect.rotation += 8
45 | effect.sweepAngle = 0.5 + Math.sin(seed+=0.05) / 3
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/SnowWhite/Button.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 | import QtQuick.Controls 2.15
8 | import SnowWhite 1.0
9 |
10 | T.Button {
11 | id: control
12 |
13 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
14 | implicitContentWidth + leftPadding + rightPadding)
15 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
16 | implicitContentHeight + topPadding + bottomPadding)
17 |
18 | property alias radius: background.radius
19 |
20 | padding: 6
21 | spacing: 6
22 |
23 | icon.width: 24
24 | icon.height: 24
25 | icon.color: palette.buttonText
26 |
27 | display: AbstractButton.TextOnly
28 |
29 | contentItem: Item {
30 | Grid {
31 | anchors.centerIn: parent
32 | spacing: control.display == AbstractButton.TextOnly ||
33 | control.display == AbstractButton.IconOnly ? 0 : control.spacing
34 |
35 | flow: control.display == AbstractButton.TextUnderIcon ?
36 | Grid.TopToBottom : Grid.LeftToRight
37 | layoutDirection: control.mirrored ? Qt.RightToLeft : Qt.LeftToRight
38 |
39 | opacity: control.down || control.checked ? 0.8 : 1.0
40 |
41 | Image {
42 | visible: control.display != AbstractButton.TextOnly
43 | source: control.icon.source
44 | width: control.icon.width
45 | height: control.icon.height
46 | cache: control.icon.cache
47 | }
48 |
49 | Text {
50 | visible: control.display != AbstractButton.IconOnly
51 | text: control.text
52 | font: control.font
53 | color: !control.enabled ? 'gray' :
54 | control.highlighted ? palette.highlightedText :
55 | palette.buttonText
56 | horizontalAlignment: Text.AlignHCenter
57 | }
58 | }
59 | }
60 |
61 | background: Rectangle {
62 | id: background
63 | visible: control.enabled
64 |
65 | implicitWidth: 45
66 | implicitHeight: 45
67 |
68 | radius: width * 0.2
69 | opacity: control.flat ? 0.5 : 1.0
70 |
71 | color: {
72 | const _color = control.highlighted ? palette.highlight : palette.button
73 | control.down ? Qt.lighter(_color, 1.1) : _color
74 | }
75 |
76 | border {
77 | width: control.visualFocus ? 1 :0
78 | color: palette.windowText
79 | }
80 |
81 | Behavior on border.width { NumberAnimation { duration: 75 } }
82 |
83 | Rectangle {
84 | x: (parent.width - width)/2
85 | y: (parent.height - height)/2
86 | radius: parent.radius - 0.05
87 | visible: control.checked
88 | color: 'transparent'
89 | border {
90 | color: palette.buttonText
91 | width: 1
92 | }
93 |
94 | NumberAnimation on width {
95 | running: control.checked
96 | from: control.background.width
97 | to: control.background.width - 5
98 | }
99 |
100 | NumberAnimation on height {
101 | running: control.checked
102 | from: control.background.height
103 | to: control.background.height - 5
104 | }
105 | }
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/SnowWhite/CheckBox.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.CheckBox {
9 | id: control
10 |
11 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
12 | implicitContentWidth + leftPadding + rightPadding)
13 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
14 | implicitContentHeight + topPadding + bottomPadding,
15 | implicitIndicatorHeight + topPadding + bottomPadding,
16 | indicator.height + topPadding + bottomPadding)
17 | padding: 6
18 | spacing: 6
19 |
20 | indicator: Rectangle {
21 | implicitWidth: 25
22 | implicitHeight: 25
23 |
24 | x: control.text ?
25 | (control.mirrored ?
26 | control.width - width - control.rightPadding :
27 | control.leftPadding) :
28 | control.leftPadding + (control.availableWidth - width) / 2
29 |
30 | y: control.topPadding + (control.availableHeight - height) / 2
31 |
32 | radius: 5
33 |
34 | color: 'transparent'
35 |
36 | border {
37 | color: control.visualFocus ? control.palette.highlight : control.palette.button
38 | width: 2
39 | }
40 |
41 | Rectangle {
42 | id: ibox
43 | x: (parent.width - width) / 2
44 | y: (parent.height - height) / 2
45 |
46 | color: control.palette.button
47 |
48 | radius: 3
49 |
50 | states:[
51 | State {
52 | when: control.checkState === Qt.Checked
53 | PropertyChanges {
54 | target: ibox
55 | width: control.indicator.width - 8
56 | height: control.indicator.height - 8
57 | }
58 | },
59 | State {
60 | when: control.checkState === Qt.Unchecked
61 | PropertyChanges { target: ibox; width: 0; height: 0 }
62 | },
63 | State {
64 | when: control.checkState === Qt.PartiallyChecked
65 | PropertyChanges {
66 | target: ibox
67 | width: control.indicator.width - 8
68 | height: control.indicator.height/3
69 | }
70 | }
71 | ]
72 |
73 | transitions: [
74 | Transition {
75 | from: "*"
76 | to: "*"
77 | NumberAnimation { properties: "width, height"; duration: 100 }
78 | }
79 | ]
80 | }
81 | }
82 |
83 | contentItem: Text {
84 | leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
85 | rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
86 | verticalAlignment: Text.AlignVCenter
87 | text: control.text
88 | font: control.font
89 | color: control.palette.windowText
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/SnowWhite/ComboBox.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Controls 2.15
7 | import QtQuick.Window 2.15
8 | import QtQuick.Templates 2.15 as T
9 |
10 | T.ComboBox {
11 | id: control
12 |
13 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
14 | implicitContentWidth + leftPadding + rightPadding)
15 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
16 | implicitContentHeight + topPadding + bottomPadding,
17 | implicitIndicatorHeight + topPadding + bottomPadding)
18 | leftPadding: 5 + (!control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
19 | rightPadding: 5 + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing)
20 | spacing: 5
21 |
22 | delegate: ItemDelegate {
23 | width: ListView.view.width
24 | text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData
25 | palette.text: control.palette.buttonText
26 | palette.highlightedText: control.palette.highlightedText
27 | hoverEnabled: control.hoverEnabled
28 |
29 | background: Rectangle {
30 | radius: 5
31 | color: control.palette.button
32 | opacity: control.currentIndex === index || hovered ? 1 : 0.7
33 | border.width: visualFocus ? 2 : 1
34 | border.color: control.palette.buttonText
35 |
36 | Behavior on opacity { NumberAnimation { duration: 100 } }
37 |
38 | Rectangle {
39 | x: parent.width * 0.9
40 | y: (parent.height - height)/2
41 | width: 5; height: 5; radius: width
42 | color: control.palette.buttonText
43 | visible: control.currentIndex === index
44 | }
45 | }
46 | }
47 |
48 | indicator: Text {
49 | x: control.mirrored ? control.padding : control.availableWidth + control.spacing + 4
50 | y: control.topPadding + (control.availableHeight - height)/2
51 | width: implicitWidth
52 | color: control.palette.buttonText
53 | text: "\u2261"
54 | font.pixelSize: 12
55 | font.bold: true
56 | opacity: enabled ? 1 : 0.3
57 | }
58 |
59 | contentItem: T.TextField {
60 | leftPadding: !control.mirrored ? 12 : 13
61 | rightPadding: control.mirrored ? 12 : 13
62 | topInset: 5; bottomInset: 5
63 | text: control.editable ? control.editText : control.displayText
64 |
65 | enabled: control.editable
66 | autoScroll: control.editable
67 | readOnly: !control.editable
68 | inputMethodHints: control.inputMethodHints
69 | validator: control.validator
70 | selectByMouse: control.selectTextByMouse
71 |
72 | font: control.font
73 | color: control.palette.windowText
74 | selectionColor: control.palette.highlight
75 | selectedTextColor: control.palette.highlightedText
76 | verticalAlignment: Text.AlignVCenter
77 |
78 | background: Rectangle {
79 | visible: control.enabled && control.editable && !control.flat
80 | color: control.palette.window
81 | opacity: parent.activeFocus && control.editable ? 0.9 : 0.6
82 | radius: 2
83 | Behavior on opacity { NumberAnimation { duration: 100 } }
84 | }
85 | }
86 |
87 | background: Rectangle {
88 | implicitWidth: 140
89 | implicitHeight: 40
90 |
91 | visible: !control.flat || control.down
92 | radius: 5
93 | color: control.palette.button
94 | opacity: control.down ? 0.8 : 1.0
95 |
96 | Behavior on opacity { NumberAnimation { duration: 100 } }
97 | }
98 |
99 | popup: T.Popup {
100 | y: control.height
101 | topPadding: 2
102 | width: control.width
103 | height: Math.min(contentItem.implicitHeight, control.Window.height - y - control.y) + 2
104 |
105 | contentItem: ListView {
106 | clip: true
107 | implicitHeight: contentHeight
108 | model: control.delegateModel
109 | spacing: 2
110 | currentIndex: control.highlightedIndex
111 | highlightMoveDuration: 0
112 | T.ScrollIndicator.vertical: ScrollIndicator { }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/SnowWhite/Dial.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 | import QtQuick.Controls 2.15
8 | import SnowWhite 1.0
9 |
10 | T.Dial {
11 | id: control
12 | property alias dottedRing: dottedRing
13 |
14 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
15 | implicitContentWidth + leftPadding + rightPadding)
16 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
17 | implicitContentHeight + topPadding + bottomPadding)
18 |
19 | background: Item {
20 | implicitWidth: 184
21 | implicitHeight: 184
22 |
23 | clip: true
24 |
25 | Rectangle {
26 | x: (control.availableWidth - width)/2
27 | y: (control.availableHeight - height)/2
28 |
29 | implicitWidth: parent.width - 20
30 | implicitHeight: parent.width - 20
31 |
32 | radius: width
33 |
34 | border.color: 'transparent'
35 |
36 | border.width: 1
37 | color: control.palette.button
38 | }
39 |
40 | DashedRing {
41 | id: dottedRing
42 |
43 | x: (control.availableWidth - width)/2
44 | y: (control.availableHeight - height)/2
45 |
46 | implicitWidth: parent.width - 5
47 | implicitHeight: parent.width - 5
48 |
49 | borderWidth: 2
50 | dashWidth: 2
51 | dashCount: 25
52 | palette.base: control.palette.button
53 | }
54 | }
55 |
56 | handle: Item {
57 | width: control.width
58 | height: control.height
59 |
60 | rotation: control.angle * 1.07
61 |
62 | Rectangle {
63 | x: (parent.width - width)/2
64 | y: 12
65 | width: 2; height: 20
66 | radius: width
67 | color: control.palette.buttonText
68 | }
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/SnowWhite/Frame.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.Frame {
9 | id: control
10 |
11 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
12 | contentWidth + leftPadding + rightPadding)
13 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
14 | contentHeight + topPadding + bottomPadding)
15 |
16 | padding: 6
17 |
18 | background: Rectangle {
19 | color: 'transparent'
20 | radius: 3
21 | border.width: 1
22 | border.color: control.palette.button
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SnowWhite/Label.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 | import QtQuick.Templates 2.15 as T
3 |
4 | T.Label {
5 | id: control
6 |
7 | color: control.palette.windowText
8 | linkColor: control.palette.link
9 | }
10 |
--------------------------------------------------------------------------------
/SnowWhite/ProgressBar.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.ProgressBar {
9 | id: control
10 |
11 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
12 | implicitContentWidth + leftPadding + rightPadding)
13 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
14 | implicitContentHeight + topPadding + bottomPadding)
15 |
16 | property int orientation: Qt.Horizontal
17 | padding: 2
18 |
19 | QtObject {
20 | id: orient
21 | property bool vertical: control.orientation == Qt.Vertical
22 | property bool horizontal: control.orientation == Qt.Horizontal
23 | }
24 |
25 | contentItem: Item {
26 | Rectangle {
27 | x: 2
28 | y: (parent.height - height)/2
29 | width: control.position * (parent.width - 4)
30 | height: Math.min(width, parent.height - 4)
31 |
32 | radius: Math.max(width, height)
33 | color: control.palette.button
34 | }
35 | }
36 |
37 | background: Rectangle {
38 | implicitWidth: orient.horizontal ? 200 : 18
39 | implicitHeight: orient.vertical ? 200 : 18
40 |
41 | color: 'transparent'
42 | radius: width
43 |
44 | border {
45 | color: control.palette.button
46 | width: 2
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/SnowWhite/RadioButton.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 | import SnowWhite 1.0
8 |
9 | T.RadioButton {
10 | id: control
11 |
12 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
13 | implicitContentWidth + leftPadding + rightPadding)
14 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
15 | implicitContentHeight + topPadding + bottomPadding,
16 | implicitIndicatorHeight + topPadding + bottomPadding)
17 |
18 | padding: 6
19 | spacing: 6
20 |
21 | indicator: Rectangle {
22 | implicitWidth: 25
23 | implicitHeight: 25
24 |
25 | x: control.text ?
26 | (control.mirrored ?
27 | control.width - width - control.rightPadding :
28 | control.leftPadding) :
29 | control.leftPadding + (control.availableWidth - width) / 2
30 |
31 | y: control.topPadding + (control.availableHeight - height) / 2
32 |
33 | radius: width
34 |
35 | color: 'transparent'
36 |
37 | border {
38 | color: control.visualFocus ? control.palette.highlight : control.palette.button
39 | width: 2
40 | }
41 |
42 | Rectangle {
43 | id: ibox
44 | x: (parent.width - width) / 2
45 | y: (parent.height - height) / 2
46 |
47 | width: control.checked ? parent.width - 8 : 0
48 | height: width
49 |
50 | color: palette.button
51 |
52 | radius: width
53 |
54 | Behavior on width {
55 | NumberAnimation { duration: 100 }
56 | }
57 | }
58 | }
59 |
60 | contentItem: Text {
61 | leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
62 | rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
63 | verticalAlignment: Text.AlignVCenter
64 | color: palette.windowText
65 | text: control.text
66 | font: control.font
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/SnowWhite/RangeSlider.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 | import QtQuick.Controls 2.15 as QQC
8 |
9 | T.RangeSlider {
10 | id: control
11 |
12 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
13 | first.implicitHandleWidth + leftPadding + rightPadding,
14 | second.implicitHandleWidth + leftPadding + rightPadding)
15 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
16 | first.implicitHandleHeight + topPadding + bottomPadding,
17 | second.implicitHandleHeight + topPadding + bottomPadding)
18 | padding: 6
19 |
20 | component Handler: Rectangle {
21 | property real vpos: 0
22 | x: control.leftPadding + (control.horizontal ? vpos * (control.availableWidth - width) : (control.availableWidth - width) / 2)
23 | y: control.topPadding + (!control.horizontal ? vpos * (control.availableHeight - height) : (control.availableHeight - height) / 2)
24 |
25 | implicitWidth: 20
26 | implicitHeight: 20
27 |
28 | radius: width / 2
29 | border {
30 | color: control.palette.window
31 | width: 2
32 | }
33 | }
34 |
35 | first.handle: Handler {
36 | vpos: control.first.visualPosition
37 | color: control.first.pressed ? Qt.lighter(control.palette.button, 1.1) : control.palette.button
38 | border.color: activeFocus ? control.palette.highlight : control.palette.window
39 | }
40 |
41 | second.handle: Handler {
42 | vpos: control.second.visualPosition
43 | color: control.second.pressed ? Qt.lighter(control.palette.button, 1.1) : control.palette.button
44 | border.color: activeFocus ? control.palette.highlight : control.palette.window
45 | }
46 |
47 | background: Rectangle {
48 | x: (control.width - width) / 2
49 | y: (control.height - height) / 2
50 |
51 | implicitWidth: !control.vertical ? 200 : 2
52 | implicitHeight: control.vertical ? 200 : 2
53 |
54 | width: !control.vertical ? control.availableWidth : implicitWidth
55 | height: control.vertical ? control.availableHeight : implicitHeight
56 |
57 | radius: width
58 | color: control.palette.button
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/SnowWhite/Slider.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 |
6 | import QtQuick 2.15
7 | import QtQuick.Templates 2.15 as T
8 |
9 | T.Slider {
10 | id: control
11 |
12 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
13 | implicitHandleWidth + leftPadding + rightPadding)
14 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
15 | implicitHandleHeight + topPadding + bottomPadding)
16 | padding: 6
17 |
18 | handle: Rectangle {
19 | x: control.leftPadding + (control.horizontal ? control.visualPosition * (control.availableWidth - width) : (control.availableWidth - width) / 2)
20 | y: control.topPadding + (control.horizontal ? (control.availableHeight - height) / 2 : control.visualPosition * (control.availableHeight - height))
21 |
22 | implicitWidth: 20
23 | implicitHeight: 20
24 |
25 | color: control.palette.button
26 | radius: width
27 |
28 | border {
29 | color: visualFocus ? control.palette.highlight : control.palette.window
30 | width: 2
31 | }
32 |
33 | Behavior on border.width { NumberAnimation{ duration: 100} }
34 | }
35 |
36 | background: Rectangle {
37 | x: (control.width - width) / 2
38 | y: (control.height - height) / 2
39 |
40 | implicitWidth: control.horizontal ? 200 : 2
41 | implicitHeight: control.horizontal ? 2 : 200
42 |
43 | width: control.horizontal ? control.availableWidth : implicitWidth
44 | height: control.horizontal ? implicitHeight : control.availableHeight
45 |
46 | radius: width
47 |
48 | color: control.palette.button
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/SnowWhite/SnowWhite.pri:
--------------------------------------------------------------------------------
1 | QML_IMPORT_PATH += $${PWD}/..
2 | QML2_IMPORT_PATH += $${PWD}/..
3 | QML_DESIGNER_IMPORT_PATH += $${PWD}/..
4 |
5 | RESOURCES += $${PWD}/snowwhite.qrc
6 |
--------------------------------------------------------------------------------
/SnowWhite/SnowWhite.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = lib
2 | QT += qml quick quickcontrols2
3 | CONFIG += qt plugin
4 |
5 | include(SnowWhite.pri)
6 |
7 | qmltypes.target = qmltypes
8 | qmltypes.commands = $$[QT_INSTALL_BINS]/qmlplugindump SnowWhite 1.0 $$QMAKE_RESOLVED_TARGET > $$PWD/snowwhite.qmltypes
9 | qmltypes.depends = $$QMAKE_RESOLVED_TARGET
10 |
11 | QMAKE_EXTRA_TARGETS += qmltypes
12 |
--------------------------------------------------------------------------------
/SnowWhite/SnowWhite.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | pragma Singleton
6 | import QtQuick 2.15
7 |
8 | QtObject {
9 | /**
10 | *
11 | */
12 | function blend(color1, color2) {
13 | let color = color1;
14 | color.r = (color1.r + color2.r) / 2;
15 | color.g = (color1.g + color2.g) / 2;
16 | color.b = (color1.b + color2.b) / 2;
17 | color.b = (color1.a + color2.a) / 2;
18 | return color;
19 | }
20 |
21 | function setAlpha(color, alpha) {
22 | color.a = alpha;
23 | return color;
24 | }
25 |
26 | function clamp(x, a, b) {
27 | return Math.min(Math.max(x, a), b);
28 | }
29 |
30 | function remap(value, low1, high1, low2, high2) {
31 | return low2 + (high2 - low2) * (value - low1) / (high1 - low1);
32 | }
33 |
34 | function invertColor(color) {
35 | return Qt.rgba(1.0 - color.r, 1.0 - color.g, 1.0 - color.b, 1.0);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/SnowWhite/SpinBox.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 |
6 | import QtQuick 2.15
7 | import QtQuick.Templates 2.15 as T
8 |
9 | T.SpinBox {
10 | id: control
11 |
12 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
13 | contentItem.implicitWidth + 2 * padding +
14 | up.implicitIndicatorWidth +
15 | down.implicitIndicatorWidth)
16 | implicitHeight: Math.max(implicitContentHeight + topPadding + bottomPadding,
17 | implicitBackgroundHeight,
18 | up.implicitIndicatorHeight,
19 | down.implicitIndicatorHeight)
20 |
21 | padding: 6
22 | leftPadding: padding + (control.mirrored ? (up.indicator ? up.indicator.width : 0) : (down.indicator ? down.indicator.width : 0))
23 | rightPadding: padding + (control.mirrored ? (down.indicator ? down.indicator.width : 0) : (up.indicator ? up.indicator.width : 0))
24 | font.bold: true
25 |
26 | component Indicator: Text {
27 | width: 30; height: parent.height
28 |
29 | font.pointSize: 10
30 | font.bold: true
31 |
32 | color: control.palette.button
33 | horizontalAlignment: Text.AlignHCenter
34 | verticalAlignment: Text.AlignVCenter
35 | }
36 |
37 | validator: IntValidator {
38 | locale: control.locale.name
39 | bottom: Math.min(control.from, control.to)
40 | top: Math.max(control.from, control.to)
41 | }
42 |
43 | contentItem: TextInput {
44 | text: control.displayText
45 |
46 | font: control.font
47 | color: control.palette.button
48 | selectionColor: control.palette.highlight
49 | selectedTextColor: control.palette.highlightedText
50 | horizontalAlignment: Text.AlignHCenter
51 | verticalAlignment: Text.AlignVCenter
52 |
53 | readOnly: !control.editable
54 | validator: control.validator
55 | inputMethodHints: control.inputMethodHints
56 |
57 | Rectangle {
58 | y: parent.height - height
59 | width: parent.width
60 | height: parent.readOnly ? 0 : 1
61 | color: control.palette.button
62 | }
63 | }
64 |
65 | up.indicator: Indicator {
66 | x: control.mirrored ? 0 : parent.width - width
67 | text: "+";
68 | opacity: !enabled || control.up.pressed ? 0.4 : 1
69 | }
70 |
71 | down.indicator: Indicator {
72 | x: control.mirrored ? parent.width - width : 0
73 | text: "-";
74 | opacity: !enabled || control.down.pressed ? 0.4 : 1
75 | }
76 |
77 |
78 | background: Rectangle {
79 | id: background
80 | implicitWidth: 80
81 | implicitHeight: 30
82 |
83 | radius: 5
84 | color: 'transparent'
85 | border.width: 2
86 | border.color: control.palette.button
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/SnowWhite/SplitView.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.SplitView {
9 | id: control
10 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
11 | implicitContentWidth + leftPadding + rightPadding)
12 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
13 | implicitContentHeight + topPadding + bottomPadding)
14 |
15 | handle: Rectangle {
16 | implicitWidth: control.orientation === Qt.Horizontal ? 4 : control.width
17 | implicitHeight: control.orientation === Qt.Horizontal ? control.height : 4
18 | color: control.enabled ? control.palette.button : '#aaa'
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/SnowWhite/StackView.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.StackView {
9 | id: control
10 |
11 | pushEnter: Transition {
12 | NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 700; easing.type: Easing.OutCubic }
13 | }
14 |
15 | pushExit: Transition {
16 | NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 700; easing.type: Easing.OutCubic }
17 | }
18 |
19 | popEnter : Transition {
20 | NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 700; easing.type: Easing.OutCubic }
21 | }
22 |
23 | popExit : Transition {
24 | NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 700; easing.type: Easing.OutCubic }
25 | }
26 |
27 | replaceEnter : Transition {
28 | NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 700; easing.type: Easing.OutCubic }
29 | }
30 |
31 | replaceExit : Transition {
32 | NumberAnimation { property: "opacity"; from: 1; to: 0; duration: 700; easing.type: Easing.OutCubic }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/SnowWhite/Switch.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 |
6 | import QtQuick 2.15
7 | import QtQuick.Templates 2.15 as T
8 |
9 | T.Switch {
10 | id: control
11 |
12 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
13 | implicitContentWidth + leftPadding + rightPadding)
14 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
15 | implicitContentHeight + topPadding + bottomPadding,
16 | implicitIndicatorHeight + topPadding + bottomPadding)
17 |
18 | padding: 6
19 | spacing: 6
20 |
21 | indicator: Rectangle {
22 | implicitWidth: 50
23 | implicitHeight: 25
24 |
25 | x: control.text ?
26 | (control.mirrored ?
27 | control.width - width - control.rightPadding :
28 | control.leftPadding) :
29 | control.leftPadding + (control.availableWidth - width) / 2
30 |
31 | y: control.topPadding + (control.availableHeight - height) / 2
32 |
33 | color: 'transparent'
34 |
35 | radius: 5
36 |
37 | border {
38 | color: control.visualFocus ? control.palette.highlight : control.palette.button
39 | width: 2
40 | }
41 |
42 | Rectangle {
43 | id: ibox
44 | x: Math.min(Math.max(y, control.visualPosition * parent.width - height/2), parent.width - height - y)
45 | y: 4
46 |
47 | color: control.palette.button
48 |
49 | width: {
50 | let pos = Math.abs(0.5 - (x-y)/(parent.implicitWidth - height - 2 * y));
51 | height + 8 - pos * 8 * 2
52 | }
53 | height: control.indicator.height - 8
54 |
55 | radius: 3
56 |
57 | Behavior on x {
58 | enabled: !control.down
59 | NumberAnimation{ duration: 200 }
60 | }
61 | }
62 | }
63 |
64 | contentItem: Text {
65 | leftPadding: control.indicator && !control.mirrored ? control.indicator.width + control.spacing : 0
66 | rightPadding: control.indicator && control.mirrored ? control.indicator.width + control.spacing : 0
67 | verticalAlignment: Text.AlignVCenter
68 | text: control.text
69 | font: control.font
70 | color: control.palette.windowText
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/SnowWhite/TextArea.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.TextArea {
9 | id: control
10 |
11 | implicitWidth: Math.max(contentWidth + leftPadding + rightPadding,
12 | implicitBackgroundWidth + leftInset + rightInset,
13 | placeholder.implicitWidth + leftPadding + rightPadding)
14 | implicitHeight: Math.max(contentHeight + topPadding + bottomPadding,
15 | implicitBackgroundHeight + topInset + bottomInset,
16 | placeholder.implicitHeight + topPadding + bottomPadding)
17 |
18 | padding: 6
19 | leftPadding: padding + 4
20 |
21 | color: control.palette.windowText
22 | placeholderTextColor: palette.mid
23 | selectionColor: control.palette.highlight
24 | selectedTextColor: control.palette.highlightedText
25 |
26 | Text {
27 | id: placeholder
28 | x: control.leftPadding
29 | y: control.topPadding
30 | width: control.width - (control.leftPadding + control.rightPadding)
31 | height: control.height - (control.topPadding + control.bottomPadding)
32 |
33 | text: control.placeholderText
34 | font: control.font
35 |
36 | color: control.placeholderTextColor
37 |
38 | verticalAlignment: control.verticalAlignment
39 | visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
40 | elide: Text.ElideRight
41 | renderType: control.renderType
42 | }
43 |
44 | background: Rectangle {
45 | implicitWidth: 200
46 | implicitHeight: 40
47 |
48 | opacity: control.activeFocus ? 1 : 0.5
49 | color: Qt.lighter(palette.window, palette.window.hslLightness * 2)
50 |
51 | border.color: Qt.lighter(palette.button, 0.5 + palette.window.hslLightness)
52 | border.width: 0.5
53 |
54 | Behavior on opacity { NumberAnimation { duration: 100 } }
55 |
56 | Rectangle {
57 | y: parent.height - height
58 | height: control.activeFocus ? 3 : 1
59 | width: parent.width
60 | color: control.enabled ? control.palette.button : '#aaa'
61 |
62 | Behavior on height { NumberAnimation { duration: 100 } }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/SnowWhite/TextField.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.TextField {
9 | id: control
10 |
11 | implicitWidth: implicitBackgroundWidth + leftInset + rightInset
12 | || Math.max(contentWidth, placeholder.implicitWidth) + leftPadding + rightPadding
13 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
14 | contentHeight + topPadding + bottomPadding,
15 | placeholder.implicitHeight + topPadding + bottomPadding)
16 |
17 | padding: 6
18 | leftPadding: padding + 4
19 |
20 | color: control.palette.windowText
21 | selectionColor: control.palette.highlight
22 | selectedTextColor: control.palette.highlightedText
23 | placeholderTextColor: control.palette.text
24 | verticalAlignment: TextInput.AlignVCenter
25 |
26 | Text {
27 | id: placeholder
28 | x: control.leftPadding
29 | y: control.topPadding
30 | width: control.width - (control.leftPadding + control.rightPadding)
31 | height: control.height - (control.topPadding + control.bottomPadding)
32 |
33 | text: control.placeholderText
34 | font: control.font
35 |
36 | color: control.placeholderTextColor
37 |
38 | verticalAlignment: control.verticalAlignment
39 | visible: !control.length && !control.preeditText && (!control.activeFocus || control.horizontalAlignment !== Qt.AlignHCenter)
40 | elide: Text.ElideRight
41 | renderType: control.renderType
42 | }
43 |
44 | background: Rectangle {
45 | implicitWidth: 200
46 | implicitHeight: 40
47 |
48 | opacity: control.activeFocus ? 1 : 0.5
49 | color: Qt.lighter(palette.window, palette.window.hslLightness * 2)
50 |
51 | border.color: Qt.lighter(palette.button, 0.5 + palette.window.hslLightness)
52 | border.width: 0.5
53 |
54 | Behavior on opacity { NumberAnimation { duration: 100 } }
55 |
56 | Rectangle {
57 | height: parent.height
58 | width: control.activeFocus ? 3 : 1
59 |
60 | color: control.enabled ? control.palette.button : '#00000055'
61 |
62 | Behavior on width { NumberAnimation { duration: 100 } }
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/SnowWhite/Tumbler.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Templates 2.15 as T
7 |
8 | T.Tumbler {
9 | id: control
10 |
11 | implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
12 | implicitContentWidth + leftPadding + rightPadding)
13 | implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
14 | implicitContentHeight + topPadding + bottomPadding)
15 |
16 | font.pixelSize: 12
17 | palette.text: "gray"
18 |
19 | delegate: Text {
20 | text: modelData
21 | color: control.visualFocus ? control.palette.highlightedText : control.palette.buttonText
22 | font: control.font
23 | opacity: 0.4 + Math.max(0, 1 - Math.abs(Tumbler.displacement)) * 0.6
24 | horizontalAlignment: Text.AlignHCenter
25 | verticalAlignment: Text.AlignVCenter
26 | }
27 |
28 | contentItem: PathView {
29 | id: pathview
30 | preferredHighlightBegin: 0.5
31 | preferredHighlightEnd: 0.5
32 | highlightRangeMode: PathView.StrictlyEnforceRange
33 | implicitWidth: 60
34 | implicitHeight: 80
35 | clip: true
36 | model: control.model
37 | delegate: control.delegate
38 | pathItemCount: control.visibleItemCount
39 | path: Path {
40 | startX: control.availableWidth / 2
41 | startY: 0
42 | PathLine {
43 | x: control.availableWidth / 2
44 | y: control.availableHeight
45 | }
46 | }
47 | }
48 |
49 | background: Rectangle {
50 | implicitWidth: 60
51 | implicitHeight: 80
52 | radius: 5
53 | color: control.palette.button
54 |
55 | Rectangle {
56 | y: (parent.height - height)/2
57 | x: (parent.width - width)/2
58 | width: parent.width * 0.7
59 | height: control.currentItem.height
60 | radius: 3
61 | opacity: Math.abs(pathview.offset % 1 - 0.5) * 2
62 | border.width: 1
63 | border.color: control.palette.window
64 | color: 'transparent'
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/SnowWhite/base/DashedRing.qml:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
5 | import QtQuick 2.15
6 | import QtQuick.Controls 2.15
7 |
8 | Control {
9 | id: control
10 |
11 | property real dashCount: 2
12 | property real dashWidth: 2
13 | property real borderWidth: 2
14 |
15 | ShaderEffect {
16 | id: effect
17 | width: parent.width;
18 | height: width;
19 | readonly property real count: 360 / control.dashCount
20 | readonly property real dashWidth: control.dashWidth / 2
21 | readonly property real borderWidth: control.borderWidth / width / 2
22 | readonly property real smoothstp: 0.5 / width
23 | readonly property color color: control.palette.base;
24 |
25 | fragmentShader: "
26 | varying highp vec2 qt_TexCoord0;
27 | uniform highp float qt_Opacity;
28 | uniform highp float count;
29 | uniform highp float dashWidth;
30 | uniform highp float borderWidth;
31 | uniform highp float smoothstp;
32 | uniform highp vec4 color;
33 |
34 | void main() {
35 | highp vec2 normal = qt_TexCoord0 - vec2(0.5);
36 | gl_FragColor = color;
37 | highp float ticks = smoothstep(0.0, 20 * smoothstp / count, -abs(fract(atan(normal.x, normal.y) * 57.2958 / count) - 0.5) + dashWidth / count);
38 | highp float ring = smoothstep(0.0, smoothstp, -abs(length(normal) - 0.5 + borderWidth) + borderWidth);
39 | gl_FragColor = gl_FragColor * ring * ticks;
40 | }"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/SnowWhite/qmldir:
--------------------------------------------------------------------------------
1 | module SnowWhite
2 | typeinfo snowwhite.qmltypes
3 |
4 | Script 1.0 script.js
5 |
6 | singleton SnowWhite 1.0 SnowWhite.qml
7 |
8 | DashedRing 1.0 base/DashedRing.qml
9 |
10 | Button 1.0 Button.qml
11 | BusyIndicator 1.0 BusyIndicator.qml
12 | CheckBox 1.0 CheckBox.qml
13 | Label 1.0 Label.qml
14 | ProgressBar 1.0 ProgressBar.qml
15 | RadioButton 1.0 RadioButton.qml
16 | RangeSlider 1.0 RangeSlider.qml
17 | Slider 1.0 Slider.qml
18 | SpinBox 1.0 SpinBox.qml
19 | Switch 1.0 Switch.qml
20 | TextArea 1.0 TextArea.qml
21 | TextField 1.0 TextField.qml
22 | Tumbler 1.0 Tumbler.qml
23 | HorizontalSeprator 1.0 HorizontalSeprator.qml
24 | SplitView 1.0 SplitView.qml
25 | Frame 1.0 Frame.qml
26 | Dial 1.0 Dial.qml
27 | ComboBox 1.0 ComboBox.qml
28 |
--------------------------------------------------------------------------------
/SnowWhite/script.js:
--------------------------------------------------------------------------------
1 | // Copyright (C) 2022 smr.
2 | // SPDX-License-Identifier: LGPL-3.0-only
3 | // http://s-m-r.ir
4 |
--------------------------------------------------------------------------------
/SnowWhite/snowwhite.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | base/DashedRing.qml
4 | Button.qml
5 | CheckBox.qml
6 | Label.qml
7 | SnowWhite.qml
8 | ProgressBar.qml
9 | RadioButton.qml
10 | RangeSlider.qml
11 | Slider.qml
12 | SpinBox.qml
13 | Switch.qml
14 | TextArea.qml
15 | TextField.qml
16 | Tumbler.qml
17 | BusyIndicator.qml
18 | SplitView.qml
19 | Frame.qml
20 | Dial.qml
21 | ComboBox.qml
22 | StackView.qml
23 | qmldir
24 | script.js
25 |
26 |
27 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # Documentation
2 |
3 | This file only offers documentation for the additional properties of components given by the SnowWhite theme.
4 | On [doc.qt.io](https://doc.qt.io/qt-6/qtquick-controls2-qmlmodule.html), you can find the documentation for the remaining components.
5 |
6 | ## Table Of Content
7 | - [Quick Start](#quick-start)
8 | - [Change Color Theme](#change-color-theme)
9 | - [Components](#components)
10 | + **base**
11 | * [DashedRing](#dashed-ring) `[base]`
12 | + [Button](#dial)
13 | + [Dial](#dial)
14 | + [ProgressBar](#progressbar)
15 | + [SnowWhite](#snowwhite) `[singleton]`
16 |
17 | ## Quick Start
18 |
19 | See the Usage section of the main [README](../README.md#usage) page.
20 |
21 | ## Change Color Theme
22 |
23 | To alter the color scheme of a component, update the palette properties on the parent component so that all children are affected.
24 |
25 | **button**:
26 | + `palette.button`
27 | + `palette.buttonText`
28 |
29 | **window & base**:
30 | + `palette.base`
31 | + `palette.text`
32 | + `palette.window`
33 | + `palette.windowText`
34 |
35 | **highlights**:
36 | + `palette.highlight`
37 | + `palette.highlightedText`
38 |
39 | ## Components
40 |
41 | ### Dashed Ring
42 |
43 | This is a basic component which generates a dashed ring.
44 |
45 | #### Component properties:
46 | ##### `[property]` `[real]` dashCount: 2
47 | The number of dashes on the ring is specified by this property.
48 | ##### `[property]` `[real]` borderWidth: 2
49 | This property specifies the width of the border, which can range from $0$ to $\dfrac{width}{2}$.
50 | ##### `[property]` `[real]` dashWidth: 2
51 | This property specifies the width of dashes.
52 | ##### `[property]` `[color]` palette.base
53 | This property derives from the `Control` component, which specifies the `color` of the dashes.
54 |
55 | ```qml
56 | DashedRing {
57 | width: 100
58 | height: 100
59 |
60 | borderWidth: 2
61 | dashWidth: 2
62 | dashCount: 25
63 | palette.base: 'blue'
64 | }
65 | ```
66 | ----
67 | ### Button
68 | #### Component properties:
69 | ##### `[property]` `[real]` radius
70 | This property determines the radius of background.
71 |
72 | ----
73 | ### Dial
74 | #### Component properties:
75 | ##### `[property]` `[DashedRing]` dottedRing
76 | This property refers to the [DashedRing](#dashed-ring) component used in the Dial component.
77 |
78 | ----
79 | ### ProgressBar
80 | #### Component properties:
81 | ##### `[property]` `[int]` orientation: Qt.Horizontal
82 | This property determines the orientation of the ProgressBar component.
83 | Either `Qt.Horizontal` or `Qt.Vertical` can be the value.
84 |
85 | ----
86 | ### SnowWhite
87 | #### Component functions:
88 | ##### function blend(`color` color1, `color` color2): `color`
89 | This function returns an average color from two input color RGBA values.
90 | ```javascript
91 | SnowWhite.blend(Qt.rgba(0, 0, 0, 1), Qt.rgba(1, 1, 1, 0));
92 | // Qt.rgba(.5, .5, .5, .5)
93 | ```
94 |
95 | ##### function setAlpha(`color` color, `real` alpha): `color`
96 | This function set new alpha values for given color.
97 | ```javascript
98 | SnowWhite.setAlpha(Qt.rgba(1, 1, 1, 1), 0.3); // Qt.rgba(1, 1, 1, 0.3)
99 | ```
100 |
101 | ##### function clamp(`real` x, `real` a, `real` b): `real`
102 | This functions constrain `x` to lie between `a` and `b`.
103 | ```javascript
104 | SnowWhite.clamp(1, 3, 5); // 3
105 | SnowWhite.clamp(1, 8, 5); // 5
106 | SnowWhite.clamp(1,-4, 5); // 1
107 | ```
108 |
109 | ##### function remap(`real` value, `real` low1, `real` high1, `real` low2, `real` high2): `real`
110 | This function re-maps a number from one range to another.
111 | ```javascript
112 | SnowWhite.remap(2, 1, 3, 0, 10); // 5
113 | ```
114 |
115 | ##### function invertColor(`color` color): `color`
116 | This function invert RGB values of input color.
117 | ```javascript
118 | SnowWhite.invertColor(Qt.rgba(0.2, 1, 0.5, 1)); // Qt.rgba(0.8, 0, 0.5, 1)
119 | ```
120 |
--------------------------------------------------------------------------------
/example/example-1/ColorPicker.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 | import QtQuick.Controls 2.15
3 |
4 | Item {
5 | id: control
6 | property color selectedColor: '#f5f5f5'
7 | implicitWidth: 150
8 |
9 | function setColor (value, saturation) {
10 | value = value < 0 ? 0 : value > 1 ? 1 : value;
11 | saturation = saturation < 0 ? 0 : saturation > 1 ? 1 : saturation;
12 | control.selectedColor.hsvHue = slider.value;
13 | control.selectedColor.hsvValue = value;
14 | control.selectedColor.hsvSaturation = saturation;
15 | }
16 |
17 | Column {
18 | width: parent.width
19 | Rectangle {
20 | id: colorRect
21 | width: parent.width
22 | height: width
23 |
24 | gradient: Gradient {
25 | orientation: Gradient.Horizontal
26 | GradientStop { position: 0.0; color: "white" }
27 | GradientStop { position: 1.0; color: Qt.hsva(selectedColor.hsvHue,1,1,1) }
28 | }
29 |
30 | Rectangle {
31 | anchors.fill: parent
32 | gradient: Gradient {
33 | GradientStop { position: 0.0; color: "transparent" }
34 | GradientStop { position: 1.0; color: "black" }
35 | }
36 | }
37 |
38 | Rectangle {
39 | anchors.fill: parent
40 | gradient: Gradient {
41 | GradientStop { position: 0.0; color: "transparent" }
42 | GradientStop { position: 1.0; color: "black" }
43 | }
44 | }
45 |
46 | MouseArea {
47 | anchors.fill: colorRect
48 |
49 | onPositionChanged: control.setColor(1 - mouseY/height, mouseX/width);
50 | onPressed: control.setColor(1 - mouseY/height, mouseX/width);
51 | }
52 | }
53 |
54 | Slider {
55 | id: slider
56 | width: 150;
57 | handle.width: 15;
58 | handle.height: 15;
59 | from: 0; to: 1;
60 | stepSize: 0.01;
61 |
62 | background: Rectangle {
63 | height: 5
64 | width: slider.width - (2 * x)
65 | x: slider.padding + slider.handle.width/2
66 | y: slider.height/2 - height/2
67 | color: control.selectedColor
68 | radius: height/2
69 |
70 |
71 | gradient: Gradient {
72 | orientation: Gradient.Horizontal
73 | GradientStop { position: 0.0; color: Qt.hsva(0.0,1,1,1) }
74 | GradientStop { position: 0.1; color: Qt.hsva(0.1,1,1,1) }
75 | GradientStop { position: 0.2; color: Qt.hsva(0.2,1,1,1) }
76 | GradientStop { position: 0.3; color: Qt.hsva(0.3,1,1,1) }
77 | GradientStop { position: 0.4; color: Qt.hsva(0.4,1,1,1) }
78 | GradientStop { position: 0.5; color: Qt.hsva(0.5,1,1,1) }
79 | GradientStop { position: 0.6; color: Qt.hsva(0.6,1,1,1) }
80 | GradientStop { position: 0.7; color: Qt.hsva(0.7,1,1,1) }
81 | GradientStop { position: 0.8; color: Qt.hsva(0.8,1,1,1) }
82 | GradientStop { position: 0.9; color: Qt.hsva(0.9,1,1,1) }
83 | GradientStop { position: 1.0; color: Qt.hsva(1.0,1,1,1) }
84 | }
85 | }
86 |
87 | onValueChanged: {
88 | control.selectedColor.hsvHue = value
89 | }
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/example/example-1/example-1.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = app
2 | QT += qml quick quickcontrols2
3 | CONFIG += c++11
4 | # You can make your code fail to compile if it uses deprecated APIs.
5 | # In order to do so, uncomment the following line.
6 | #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
7 |
8 | SOURCES += main.cpp
9 | RESOURCES += qml.qrc
10 |
11 | include(../../SnowWhite/SnowWhite.pri)
12 |
--------------------------------------------------------------------------------
/example/example-1/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | int main(int argc, char *argv[])
5 | {
6 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
7 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
8 | #endif
9 | QGuiApplication app(argc, argv);
10 |
11 | app.setOrganizationName("smr");
12 | app.setOrganizationDomain("smr");
13 | app.setApplicationName("example-1");
14 |
15 | QQmlApplicationEngine engine;
16 | // Path to module.
17 | engine.addImportPath("qrc:/");
18 |
19 | const QUrl url(QStringLiteral("qrc:/main.qml"));
20 | QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
21 | &app, [url](QObject *obj, const QUrl &objUrl) {
22 | if (!obj && url == objUrl)
23 | QCoreApplication::exit(-1);
24 | }, Qt::QueuedConnection);
25 | engine.load(url);
26 |
27 | return app.exec();
28 | }
29 |
--------------------------------------------------------------------------------
/example/example-1/main.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.15
2 | import QtQuick.Window 2.15
3 | import QtQuick.Controls 2.15
4 | import Qt.labs.settings 1.1
5 |
6 | import SnowWhite 1.0
7 |
8 | ApplicationWindow {
9 | id: window
10 |
11 | width: toggleButton.checked ? scrollView.contentWidth : 230
12 | height: 420
13 | visible: true
14 |
15 | palette {
16 | base: "#48abff"
17 | button: "#48abff"
18 | highlight: "#5c75f4"
19 |
20 | window: '#333'
21 | text: "#eee"
22 | windowText: "#eee"
23 |
24 | buttonText: "#fff"
25 | highlightedText: "#fff"
26 | }
27 |
28 | component ButtonColor: Button {
29 | width: 20; height: width
30 | onClicked: {
31 | window.palette.base = palette.button
32 | window.palette.button = palette.button
33 | window.palette.highlight = Qt.darker(palette.button, 1.5)
34 | }
35 | }
36 |
37 | component BackColor: Button {
38 | width: 20; height: width
39 | onClicked: {
40 | window.palette.window = palette.button
41 | window.palette.windowText = palette.buttonText
42 | }
43 | }
44 |
45 | FontLoader {
46 | id: carlito
47 | source: "resources/Carlito-Regular.ttf"
48 | }
49 |
50 | Settings {
51 | id: settings
52 | fileName: 'config.conf'
53 | property alias toggleButton: toggleButton.checked
54 | property real xScroll: scrollView.xScroll
55 | }
56 |
57 | Row {
58 | x: 5; z: 3; spacing: 2
59 | AbstractButton {
60 | id: toggleButton
61 | width: 15; height: 15
62 | checkable: true
63 | font.family: 'Cascadia Code Light'
64 | contentItem: Text {
65 | text: parent.checked ? '▶◀' : '◀▶'
66 | color: palette.button
67 | }
68 | }
69 | ButtonColor { palette.button: '#48abff'; text: '.' }
70 | ButtonColor { palette.button: '#ef476f'; text: '.' }
71 | ButtonColor { palette.button: '#ffd166'; text: '.' }
72 | ButtonColor { palette.button: '#06d6a0'; text: '.' }
73 | ButtonColor { palette.button: '#d5b9ff'; text: '.' }
74 | ButtonColor { palette.button: '#343536'; text: '.' }
75 | ButtonColor { palette.button: '#edc9aa'; text: '.' }
76 | Rectangle { color: window.palette.windowText ;width: 1; height: parent.height }
77 | BackColor { palette {button: '#f5f6f7'; buttonText: '#343536'} text: '.' }
78 | BackColor { palette {button: '#343536'; buttonText: '#f5f6f7'} text: '.' }
79 | BackColor { palette {button: '#1d1c21'; buttonText: '#ffffff'} text: '.' }
80 | }
81 |
82 | ScrollView {
83 | id: scrollView
84 |
85 | property real xScroll: ScrollBar.horizontal.position
86 | Component.onCompleted: ScrollBar.horizontal.position = settings.xScroll
87 |
88 | anchors.fill: parent
89 |
90 | contentWidth: 690
91 | contentHeight: height
92 |
93 | Grid {
94 | flow: Grid.LeftToRight
95 |
96 | rows: flow == Grid.LeftToRight ? 1 : -1
97 | columns: flow == Grid.LeftToRight ? -1 : 1
98 |
99 | padding: 25
100 | spacing: 25
101 |
102 | Column {
103 | spacing: 10
104 | Frame {
105 | Grid {
106 | rows: -1
107 | columns: 3
108 | spacing: 10
109 | Button {
110 | width: 55
111 | height: width
112 | text: "Color\npicker"
113 | font.family: carlito.name
114 | onClicked: colorPickerW.visible = true
115 | }
116 |
117 | Button {
118 | width: 55
119 | height: width
120 | text: "HL\nBtn"
121 | highlighted: true
122 | font { family: carlito.name; weight: Font.Medium; }
123 | }
124 |
125 | Button {
126 | width: 55
127 | height: width
128 | text: "Check\nBtn"
129 | checkable: true
130 | font.family: carlito.name
131 | }
132 |
133 | Button {
134 | width: 55
135 | height: width
136 | text: "Flat Btn"
137 | flat: true
138 | font.family: carlito.name
139 | }
140 |
141 | Button {
142 | width: 40
143 | height: width
144 | text: "Disabled\nBtn"
145 | enabled: false
146 | font.family: carlito.name
147 | }
148 |
149 | Button {
150 | width: 40
151 | height: width
152 | highlighted: true
153 | text: "w-40"
154 | font.family: carlito.name
155 | }
156 | }
157 | }
158 |
159 | Button {
160 | width: parent.width
161 | height: 45
162 | text: "Wide Checkable Button"
163 | checkable: true
164 | font.family: carlito.name
165 | radius: 10
166 | }
167 |
168 | Row {
169 | CheckBox {
170 | text: "Check\nbox"
171 | tristate: true
172 | font.family: carlito.name
173 | }
174 |
175 | Switch {
176 | text: "Switch"
177 | font.family: carlito.name
178 | }
179 | }
180 |
181 | Row {
182 | RadioButton {
183 | text: "Radio 1"
184 | font.family: carlito.name
185 | }
186 |
187 | RadioButton {
188 | text: "Radio 2"
189 | font.family: carlito.name
190 | }
191 | }
192 |
193 | Row {
194 | spacing: 5
195 |
196 | Text {
197 | height: 85
198 | text: "Busy Indicator \u2192"
199 | color: window.palette.windowText
200 | verticalAlignment: Text.AlignVCenter
201 | font { family: carlito.name }
202 | }
203 |
204 | Rectangle {
205 | width: 85; height: 85
206 | color: 'transparent'
207 | radius: 6
208 | border.width: 1
209 | border.color: Qt.darker(window.palette.base, 1.1)
210 |
211 | BusyIndicator {
212 | anchors.centerIn: parent
213 | width: 30
214 | height: 30
215 | running: false
216 | visible: true
217 |
218 | MouseArea {
219 | anchors.fill: parent
220 | onClicked: parent.running ^= true
221 | }
222 | }
223 | }
224 | }
225 | }
226 |
227 | Rectangle {
228 | width: 1
229 | height: window.height - 45
230 | color: '#000'
231 | opacity: 0.1
232 | }
233 |
234 | Column {
235 | spacing: 7
236 |
237 | ProgressBar {
238 | width: 180;
239 | value: slider1.value
240 | }
241 |
242 | Slider {
243 | id: slider1
244 | width: 180;
245 | value: 0.3
246 | }
247 |
248 | RangeSlider {
249 | width: 180;
250 | }
251 |
252 | SpinBox {
253 | font.family: carlito.name
254 | to: 10
255 | }
256 |
257 | Column {
258 | spacing: 10
259 | TextArea {
260 | width: 180
261 | text: 'Simple example of \nTextArea.'
262 | font.family: carlito.name
263 | }
264 |
265 | TextField {
266 | width: 180
267 | text: 'Example text field.'
268 | font.family: carlito.name
269 | }
270 | }
271 | }
272 |
273 | Rectangle {
274 | width: 1
275 | height: window.height - 45
276 | color: '#000'
277 | opacity: 0.1
278 | }
279 |
280 | Column {
281 | spacing: 5
282 | Text {
283 | width: parent.width
284 | text: "Dial"
285 | color: window.palette.windowText
286 | horizontalAlignment: Text.AlignHCenter
287 | font.family: carlito.name
288 | }
289 |
290 | Dial {
291 | x: (parent.width - width)/2
292 | width: 100
293 | height: 100
294 | }
295 |
296 | Text {
297 | topPadding: 10
298 | width: parent.width
299 | horizontalAlignment: Text.AlignHCenter
300 |
301 | text: "Tumbler"
302 | color: window.palette.windowText
303 | font.family: carlito.name
304 | }
305 |
306 | Tumbler {
307 | x: (parent.width - width)/2
308 | model: 40
309 | height: 75
310 | visibleItemCount: 3
311 | }
312 |
313 | Text {
314 | topPadding: 10
315 | width: parent.width
316 | horizontalAlignment: Text.AlignHCenter
317 | text: "ComboBox"
318 | color: window.palette.windowText
319 | font.family: carlito.name
320 | }
321 |
322 |
323 | ComboBox {
324 | id: comboBox
325 | model: 5
326 | editable: true
327 | }
328 | }
329 | }
330 | }
331 |
332 | Window {
333 | id: colorPickerW
334 | ColorPicker {
335 | id: colorPicker;
336 | onSelectedColorChanged: {
337 | window.palette.base = selectedColor
338 | window.palette.button = selectedColor
339 | window.palette.highlight = Qt.darker(selectedColor, 1.5)
340 | window.palette.buttonText = selectedColor.hslLightness < 0.7 ? '#fff' : '#333'
341 | }
342 | }
343 | title: ''
344 | flags: Qt.Tool
345 | minimumWidth: colorPicker.width
346 | minimumHeight: 200
347 | }
348 | }
349 |
--------------------------------------------------------------------------------
/example/example-1/qml.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | main.qml
4 | qtquickcontrols2.conf
5 | ColorPicker.qml
6 | resources/Carlito-Regular.ttf
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/example-1/qtquickcontrols2.conf:
--------------------------------------------------------------------------------
1 | ; This file can be edited to change the style of the application
2 | ; Read "Qt Quick Controls 2 Configuration File" for details:
3 | ; https://doc.qt.io/qt/qtquickcontrols2-configuration.html
4 |
5 |
--------------------------------------------------------------------------------
/example/example-1/resources/Carlito-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0smr/snow-white/1afa8a2d6e9bb9ecf7c30443e66d3948dc8aea5f/example/example-1/resources/Carlito-Regular.ttf
--------------------------------------------------------------------------------
/example/example.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 | SUBDIRS = \
3 | example-1 \
4 |
--------------------------------------------------------------------------------
/extra/preview/preview-1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0smr/snow-white/1afa8a2d6e9bb9ecf7c30443e66d3948dc8aea5f/extra/preview/preview-1.webp
--------------------------------------------------------------------------------
/extra/preview/preview-2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0smr/snow-white/1afa8a2d6e9bb9ecf7c30443e66d3948dc8aea5f/extra/preview/preview-2.webp
--------------------------------------------------------------------------------
/snow-white.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 | SUBDIRS = \
3 | SnowWhite \
4 | example
5 |
6 | example.depends = SnowWhite
7 |
--------------------------------------------------------------------------------