├── .gitignore ├── CustomBusyIndicator.qml ├── CustomBusyIndicator.qmlproject ├── CustomBusyIndicatorStyle.qml ├── LICENSE.md ├── README.md └── main.qml /.gitignore: -------------------------------------------------------------------------------- 1 | #Exclude android directories 2 | android/assets 3 | android/bin 4 | android/gen 5 | android/libs 6 | android/obj 7 | 8 | # Exclude Qt creator user files 9 | CMakeLists.txt.user 10 | *.pro.user 11 | *.qmlproject.user 12 | 13 | 14 | # Exclude temp nibs and swap files 15 | *~.nib 16 | *.swp 17 | 18 | # Exclude OS X folder attributes 19 | .DS_Store 20 | 21 | # Exclude user-specific XCode 3 and 4 files 22 | *.mode1 23 | *.mode1v3 24 | *.mode2v3 25 | *.perspective 26 | *.perspectivev3 27 | *.pbxuser 28 | *.xcworkspace 29 | xcuserdata 30 | 31 | -------------------------------------------------------------------------------- /CustomBusyIndicator.qml: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2014 Nicolas Froment 3 | 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | //============================================================================= 22 | 23 | import QtQuick 2.3 24 | import QtQuick.Controls 1.2 25 | import QtQuick.Controls.Styles 1.2 26 | 27 | BusyIndicator { 28 | id: busy 29 | property int bLines: 11 30 | property real bLength: 10 // % of the width of the control 31 | property real bWidth: 5 // % of the height of the control 32 | property real bRadius: 13 // % of the width of the control 33 | property real bCorner: 1 // between 0 and 1 34 | property real bSpeed: 100 // smaller is faster 35 | property real bTrail: 0.6 // between 0 and 1 36 | property bool bClockWise: true 37 | 38 | property real bOpacity: 0.7 39 | property string bColor: "#7B756B" 40 | property string bHighlightColor: "white" 41 | property string bBgColor: "black" 42 | 43 | style: CustomBusyIndicatorStyle { 44 | lines: control.bLines 45 | length: control.bLength 46 | width: control.bWidth 47 | radius: control.bRadius 48 | corner: control.bCorner 49 | speed: control.bSpeed 50 | trail: control.bTrail 51 | clockWise: control.bClockWise 52 | opacity: control.bOpacity 53 | color: control.bColor 54 | highlightColor: control.bHighlightColor 55 | bgColor: control.bBgColor 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /CustomBusyIndicator.qmlproject: -------------------------------------------------------------------------------- 1 | /* File generated by Qt Creator, version 2.7.0 */ 2 | 3 | import QmlProject 1.1 4 | 5 | Project { 6 | mainFile: "main.qml" 7 | 8 | /* Include .qml, .js, and image files from current directory and subdirectories */ 9 | QmlFiles { 10 | directory: "." 11 | } 12 | JavaScriptFiles { 13 | directory: "." 14 | } 15 | ImageFiles { 16 | directory: "." 17 | } 18 | /* List of plugin directories passed to QML runtime */ 19 | // importPaths: [ "../exampleplugin" ] 20 | } 21 | -------------------------------------------------------------------------------- /CustomBusyIndicatorStyle.qml: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2014 Nicolas Froment 3 | 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | //============================================================================= 22 | 23 | import QtQuick 2.3 24 | import QtQuick.Controls.Styles 1.2 25 | 26 | BusyIndicatorStyle { 27 | id: style 28 | property int lines: 11 29 | property real length: 10 // % of the width of the control 30 | property real width: 5 // % of the height of the control 31 | property real radius: 13 // % of the width of the control 32 | property real corner: 1 // between 0 and 1 33 | property real speed: 100 // smaller is faster 34 | property real trail: 0.6 // between 0 and 1 35 | property bool clockWise: true 36 | 37 | property real opacity: 0.7 38 | property string color: "#7B756B" 39 | property string highlightColor: "white" 40 | property string bgColor: "black" 41 | 42 | indicator: Rectangle { 43 | color: style.bgColor 44 | visible: control.running 45 | Repeater { 46 | id: repeat 47 | model: style.lines 48 | Rectangle { 49 | property real factor: control.width / 200 50 | color: style.color 51 | opacity: style.opacity 52 | Behavior on color { 53 | ColorAnimation { 54 | from: style.highlightColor 55 | duration: style.speed * style.lines * style.trail 56 | } 57 | } 58 | radius: style.corner * height / 2 59 | width: style.length * factor 60 | height: style.width * factor 61 | x: control.width / 2 + style.radius * factor 62 | y: control.height / 2 - height / 2 63 | transform: Rotation { 64 | origin.x: -style.radius * factor 65 | origin.y: height / 2 66 | angle: index * (360 / repeat.count) 67 | } 68 | Timer { 69 | id: reset 70 | interval: style.speed * (style.clockWise ? index : style.lines - index) 71 | onTriggered: { 72 | parent.opacity = 1 73 | parent.color = style.highlightColor 74 | reset2.start() 75 | } 76 | } 77 | Timer { 78 | id: reset2 79 | interval: style.speed 80 | onTriggered: { 81 | parent.opacity = style.opacity 82 | parent.color = style.color 83 | } 84 | } 85 | Timer { 86 | id: globalTimer // for a complete cycle 87 | interval: style.speed * style.lines 88 | onTriggered: { 89 | reset.start() 90 | } 91 | triggeredOnStart: true 92 | repeat: true 93 | } 94 | Component.onCompleted: { 95 | globalTimer.start() 96 | } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | Copyright (c) 2016 lasconic 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 5 | 6 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 7 | 8 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | See http://blog.lasconic.com/a-customized-busy-indicator-in-qt-quick -------------------------------------------------------------------------------- /main.qml: -------------------------------------------------------------------------------- 1 | //============================================================================= 2 | // Copyright (c) 2014 Nicolas Froment 3 | 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | //============================================================================= 22 | 23 | import QtQuick 2.3 24 | import QtQuick.Controls 1.2 25 | import QtQuick.Controls.Styles 1.2 26 | import QtQuick.Window 2.0 27 | 28 | ApplicationWindow { 29 | title: qsTr("Hello World") 30 | width: 400 * 2 31 | height: 400 32 | Rectangle { 33 | anchors.fill: parent 34 | color: "black" 35 | } 36 | 37 | Row { 38 | spacing: 20 39 | CustomBusyIndicator { 40 | id: busy 41 | width: 400 42 | height: 400 43 | } 44 | Rectangle { 45 | id:settings 46 | width: 400 47 | height: 400 48 | color: "black" 49 | 50 | Column { 51 | spacing: 10 52 | anchors.top: parent.top 53 | anchors.topMargin: 20 54 | anchors.leftMargin: 20 55 | Row { 56 | spacing: 10 57 | Label { 58 | text: "Lines" 59 | color: "white" 60 | width: 80 61 | } 62 | Slider { 63 | id: linesSlider 64 | minimumValue: 3 65 | maximumValue: 100 66 | value: 11 67 | stepSize: 1 68 | onValueChanged: { 69 | busy.bLines = value 70 | } 71 | } 72 | Label { 73 | text: busy.bLines = linesSlider.value 74 | color: "white" 75 | } 76 | } 77 | Row { 78 | spacing: 10 79 | Label { 80 | text: "Length" 81 | color: "white" 82 | width: 80 83 | } 84 | Slider { 85 | id: lenghtSlider 86 | minimumValue: 1 87 | maximumValue: 100 88 | value: 10 89 | stepSize: 1 90 | onValueChanged: { 91 | busy.bLength = value 92 | } 93 | } 94 | Label { 95 | text: busy.bLength = lenghtSlider.value 96 | color: "white" 97 | } 98 | } 99 | Row { 100 | spacing: 10 101 | Label { 102 | text: "Width" 103 | color: "white" 104 | width: 80 105 | } 106 | Slider { 107 | id: widthSlider 108 | minimumValue: 1 109 | maximumValue: 100 110 | value: 5 111 | stepSize: 1 112 | onValueChanged: { 113 | busy.bWidth = value 114 | } 115 | } 116 | Label { 117 | text: busy.bWidth = widthSlider.value 118 | color: "white" 119 | } 120 | } 121 | Row { 122 | spacing: 10 123 | Label { 124 | text: "Radius" 125 | color: "white" 126 | width: 80 127 | } 128 | Slider { 129 | id: radiusSlider 130 | minimumValue: 1 131 | maximumValue: 100 132 | value: 11 133 | stepSize: 1 134 | onValueChanged: { 135 | busy.bRadius = value 136 | } 137 | } 138 | Label { 139 | text: busy.bRadius = radiusSlider.value 140 | color: "white" 141 | } 142 | } 143 | Row { 144 | spacing: 10 145 | Label { 146 | text: "Corner" 147 | color: "white" 148 | width: 80 149 | } 150 | Slider { 151 | id: cornerSlider 152 | minimumValue: 0 153 | maximumValue: 1 154 | value: 1 155 | stepSize: 0.01 156 | onValueChanged: { 157 | busy.bCorner = value 158 | } 159 | } 160 | Label { 161 | text: busy.bCorner = cornerSlider.value 162 | color: "white" 163 | } 164 | } 165 | Row { 166 | spacing: 10 167 | Label { 168 | text: "Speed" 169 | color: "white" 170 | width: 80 171 | } 172 | Slider { 173 | id: speedSlider 174 | minimumValue: 10 175 | maximumValue: 800 176 | stepSize: 10 177 | value: 100 178 | onValueChanged: { 179 | busy.bSpeed = value 180 | } 181 | } 182 | Label { 183 | text: busy.bSpeed = speedSlider.value 184 | color: "white" 185 | } 186 | } 187 | Row { 188 | spacing: 10 189 | Label { 190 | text: "Trail" 191 | color: "white" 192 | width: 80 193 | } 194 | Slider { 195 | id: trailSlider 196 | minimumValue: 0 197 | maximumValue: 1 198 | value: 0.5 199 | stepSize: 0.01 200 | onValueChanged: { 201 | busy.bTrail = value 202 | } 203 | } 204 | Label { 205 | text: busy.bTrail = trailSlider.value 206 | color: "white" 207 | } 208 | } 209 | Row { 210 | CheckBox { 211 | id:checkboxClockWise 212 | checked: true 213 | onCheckedChanged: { 214 | busy.bClockWise = checked 215 | } 216 | } 217 | Label { 218 | text: "Clockwise" 219 | color: "white" 220 | } 221 | } 222 | Row { 223 | spacing: 10 224 | Label { 225 | text: "Opacity" 226 | color: "white" 227 | width: 80 228 | } 229 | Slider { 230 | id: opacitySlider 231 | minimumValue: 0 232 | maximumValue: 1 233 | value: 1 234 | stepSize: 0.01 235 | onValueChanged: { 236 | busy.bOpacity = value 237 | } 238 | } 239 | Label { 240 | text: busy.bOpacity = opacitySlider.value 241 | color: "white" 242 | } 243 | } 244 | Row { 245 | spacing: 10 246 | Label { 247 | text: "Color" 248 | color: "white" 249 | width: 80 250 | } 251 | TextField { 252 | id:colorTextField 253 | text: "#7B756B" 254 | onTextChanged: { 255 | busy.bColor = text 256 | } 257 | } 258 | } 259 | Row { 260 | spacing: 10 261 | Label { 262 | text: "Highlight" 263 | color: "white" 264 | width: 80 265 | } 266 | TextField { 267 | id:highlightColorTextField 268 | text: "white" 269 | onTextChanged: { 270 | busy.bHighlightColor = text 271 | } 272 | } 273 | } 274 | Row { 275 | spacing: 10 276 | Label { 277 | text: "Background" 278 | color: "white" 279 | width: 80 280 | } 281 | TextField { 282 | id:backgroundColorTextField 283 | text: "black" 284 | onTextChanged: { 285 | busy.bBgColor = text 286 | } 287 | } 288 | } 289 | } 290 | } 291 | } 292 | } 293 | --------------------------------------------------------------------------------