1/* 2 SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org> 3 4 SPDX-License-Identifier: GPL-2.0-or-later 5*/ 6 7import QtQuick 2.0 8import org.kde.plasma.components 2.0 as PlasmaComponents 9import org.kde.plasma.core 2.0 as PlasmaCore 10import org.kde.plasma.configuration 2.0 11import org.kde.kquickcontrolsaddons 2.0 as KQuickControlsAddons 12 13 14PlasmaCore.FrameSvgItem { 15 id: root 16 17 //Those properties get updated by PanelConfiguration.qml whenever a value in the panel changes 18 property alias offset: offsetHandle.value 19 property alias minimumLength: minimumLengthHandle.value 20 property alias maximumLength: maximumLengthHandle.value 21 22 imagePath: "widgets/containment-controls" 23 state: "BottomEdge" 24 implicitWidth: offsetHandle.width + minimumLengthHandle.width 25 implicitHeight: offsetHandle.height + minimumLengthHandle.height 26 27 onMinimumLengthChanged: leftMinimumLengthHandle.value = minimumLength 28 onMaximumLengthChanged: leftMaximumLengthHandle.value = maximumLength 29 30 /* As offset and length have a different meaning in all alignments, the panel shifts on alignment change. 31 * This could result in wrong panel positions (e.g. panel shifted over monitor border). 32 * The fancy version would be a recalculation of all values, so that the panel stays at it's current position, 33 * but this would be error prone and complicated. As the panel alignment is rarely changed, it's not worth it. 34 * The more easy approach is just setting the panel offset to zero. This makes sure the panel has a valid position and size. 35 */ 36 Connections { 37 target: panel 38 function onAlignmentChanged() { 39 offset = 0 40 } 41 } 42 43 Component.onCompleted: { 44 offsetHandle.value = panel.offset 45 minimumLengthHandle.value = panel.minimumLength 46 maximumLengthHandle.value = panel.maximumLength 47 leftMinimumLengthHandle.value = panel.minimumLength 48 leftMaximumLengthHandle.value = panel.maximumLength 49 } 50 51 PlasmaCore.Svg { 52 id: containmentControlsSvg 53 imagePath: "widgets/containment-controls" 54 } 55 PlasmaCore.SvgItem { 56 id: centerMark 57 svg: containmentControlsSvg 58 elementId: dialogRoot.vertical ? "vertical-centerindicator" : "horizontal-centerindicator" 59 visible: panel.alignment === Qt.AlignCenter 60 width: dialogRoot.vertical ? parent.width : naturalSize.width 61 height: dialogRoot.vertical ? naturalSize.height : parent.height 62 anchors.centerIn: parent 63 } 64 65 SliderHandle { 66 id: offsetHandle 67 graphicElementName: "offsetslider" 68 onValueChanged: panel.offset = value 69 property int position: (dialogRoot.vertical) ? y : x 70 /* The maximum/minimumPosition values are needed to prevent the user from moving a panel with 71 * center alignment to the left and then drag the position handle to the left. 72 * This would make the panel to go off the monitor: 73 * |<- V -> | 74 * | -> | <- | 75 * ^move this slider to the left 76 */ 77 minimumPosition: { 78 var size = dialogRoot.vertical ? height : width 79 switch(panel.alignment){ 80 case Qt.AlignLeft: 81 return -size / 2 82 case Qt.AlignRight: 83 return leftMaximumLengthHandle.value - size / 2 84 default: 85 return panel.maximumLength / 2 - size / 2 86 } 87 } 88 //Needed for the same reason as above 89 maximumPosition: { 90 var size = dialogRoot.vertical ? height : width 91 var dialogRootSize = dialogRoot.vertical ? dialogRoot.height : dialogRoot.width 92 switch(panel.alignment){ 93 case Qt.AlignLeft: 94 return dialogRootSize - maximumLengthHandle.value - size / 2 95 case Qt.AlignRight: 96 return dialogRootSize - size / 2 97 default: 98 return dialogRootSize - panel.maximumLength / 2 - size / 2 99 } 100 } 101 } 102 103 /* The maximumPosition value for the right handles and the minimumPosition value for the left handles are 104 * needed to prevent the user from moving a panel with center alignment to the left (right) and then pull one of the 105 * right (left) sliders to the right (left). 106 * Because the left and right sliders are coupled, this would make the left (right) sliders to go off the monitor. 107 * 108 * |<- V -> | 109 * | -> | <- | 110 * ^move this slider to the right 111 * 112 * The other max/min Position values just set a minimum panel size 113 */ 114 115 SliderHandle { 116 id: minimumLengthHandle 117 alignment: panel.alignment | Qt.AlignLeft 118 visible: panel.alignment !== Qt.AlignRight 119 offset: panel.offset 120 graphicElementName: "minslider" 121 onValueChanged: panel.minimumLength = value 122 minimumPosition: offsetHandle.position + PlasmaCore.Units.gridUnit * 3 123 maximumPosition: { 124 var dialogRootSize = dialogRoot.vertical ? dialogRoot.height : dialogRoot.width 125 var size = dialogRoot.vertical ? height : width 126 panel.alignment === Qt.AlignCenter ? Math.min(dialogRootSize - size/2, dialogRootSize + offset * 2 - size/2) : dialogRootSize - size/2 127 } 128 } 129 130 SliderHandle { 131 id: maximumLengthHandle 132 alignment: panel.alignment | Qt.AlignLeft 133 visible: panel.alignment !== Qt.AlignRight 134 offset: panel.offset 135 graphicElementName: "maxslider" 136 onValueChanged: panel.maximumLength = value 137 minimumPosition: offsetHandle.position + PlasmaCore.Units.gridUnit * 3 138 maximumPosition: { 139 var dialogRootSize = dialogRoot.vertical ? dialogRoot.height : dialogRoot.width 140 var size = dialogRoot.vertical ? height : width 141 panel.alignment === Qt.AlignCenter ? Math.min(dialogRootSize - size/2, dialogRootSize + offset * 2 - size/2) : dialogRootSize - size/2 142 } 143 } 144 SliderHandle { 145 id: leftMinimumLengthHandle 146 alignment: panel.alignment | Qt.AlignRight 147 visible: panel.alignment !== Qt.AlignLeft 148 offset: panel.offset 149 graphicElementName: "minslider" 150 onValueChanged: panel.minimumLength = value 151 maximumPosition: offsetHandle.position - PlasmaCore.Units.gridUnit * 3 152 minimumPosition: { 153 var size = dialogRoot.vertical ? height : width 154 panel.alignment === Qt.AlignCenter ? Math.max(-size/2, offset*2 - size/2) : -size/2 155 } 156 } 157 SliderHandle { 158 id: leftMaximumLengthHandle 159 alignment: panel.alignment | Qt.AlignRight 160 visible: panel.alignment !== Qt.AlignLeft 161 offset: panel.offset 162 graphicElementName: "maxslider" 163 onValueChanged: panel.maximumLength = value 164 maximumPosition: offsetHandle.position - PlasmaCore.Units.gridUnit * 3 165 minimumPosition: { 166 var size = dialogRoot.vertical ? height : width 167 panel.alignment === Qt.AlignCenter ? Math.max(-size/2, offset*2 - size/2) : -size/2 168 } 169 } 170 171 states: [ 172 State { 173 name: "TopEdge" 174 PropertyChanges { 175 target: root 176 prefix: "north" 177 height: root.implicitHeight 178 } 179 AnchorChanges { 180 target: root 181 anchors { 182 top: root.parent.top 183 bottom: undefined 184 left: root.parent.left 185 right: root.parent.right 186 } 187 } 188 AnchorChanges { 189 target: offsetHandle 190 anchors { 191 top: undefined 192 bottom: root.bottom 193 left: undefined 194 right: undefined 195 } 196 } 197 AnchorChanges { 198 target: minimumLengthHandle 199 anchors { 200 top: root.top 201 bottom: undefined 202 left: undefined 203 right: undefined 204 } 205 } 206 AnchorChanges { 207 target: maximumLengthHandle 208 anchors { 209 top: undefined 210 bottom: root.bottom 211 left: undefined 212 right: undefined 213 } 214 } 215 AnchorChanges { 216 target: leftMinimumLengthHandle 217 anchors { 218 top: root.top 219 bottom: undefined 220 left: undefined 221 right: undefined 222 } 223 } 224 AnchorChanges { 225 target: leftMaximumLengthHandle 226 anchors { 227 top: undefined 228 bottom: root.bottom 229 left: undefined 230 right: undefined 231 } 232 } 233 }, 234 State { 235 name: "BottomEdge" 236 PropertyChanges { 237 target: root 238 prefix: "south" 239 height: root.implicitHeight 240 } 241 AnchorChanges { 242 target: root 243 anchors { 244 top: undefined 245 bottom: root.parent.bottom 246 left: root.parent.left 247 right: root.parent.right 248 } 249 } 250 AnchorChanges { 251 target: offsetHandle 252 anchors { 253 top: root.top 254 bottom: undefined 255 left: undefined 256 right: undefined 257 } 258 } 259 AnchorChanges { 260 target: minimumLengthHandle 261 anchors { 262 top: undefined 263 bottom: root.bottom 264 left: undefined 265 right: undefined 266 } 267 } 268 AnchorChanges { 269 target: maximumLengthHandle 270 anchors { 271 top: root.top 272 bottom: undefined 273 left: undefined 274 right: undefined 275 } 276 } 277 AnchorChanges { 278 target: leftMinimumLengthHandle 279 anchors { 280 top: undefined 281 bottom: root.bottom 282 left: undefined 283 right: undefined 284 } 285 } 286 AnchorChanges { 287 target: leftMaximumLengthHandle 288 anchors { 289 top: root.top 290 bottom: undefined 291 left: undefined 292 right: undefined 293 } 294 } 295 }, 296 State { 297 name: "LeftEdge" 298 PropertyChanges { 299 target: root 300 prefix: "west" 301 width: root.implicitWidth 302 } 303 AnchorChanges { 304 target: root 305 anchors { 306 top: root.parent.top 307 bottom: root.parent.bottom 308 left: root.parent.left 309 right: undefined 310 } 311 } 312 AnchorChanges { 313 target: offsetHandle 314 anchors { 315 top: undefined 316 bottom: undefined 317 left: undefined 318 right: root.right 319 } 320 } 321 AnchorChanges { 322 target: minimumLengthHandle 323 anchors { 324 top: undefined 325 bottom: undefined 326 left: root.left 327 right: undefined 328 } 329 } 330 AnchorChanges { 331 target: maximumLengthHandle 332 anchors { 333 top: undefined 334 bottom: undefined 335 left: undefined 336 right: root.right 337 } 338 } 339 AnchorChanges { 340 target: leftMinimumLengthHandle 341 anchors { 342 top: undefined 343 bottom: undefined 344 left: root.left 345 right: undefined 346 } 347 } 348 AnchorChanges { 349 target: leftMaximumLengthHandle 350 anchors { 351 top: undefined 352 bottom: undefined 353 left: undefined 354 right: root.right 355 } 356 } 357 }, 358 State { 359 name: "RightEdge" 360 PropertyChanges { 361 target: root 362 prefix: "east" 363 width: root.implicitWidth 364 } 365 AnchorChanges { 366 target: root 367 anchors { 368 top: root.parent.top 369 bottom: root.parent.bottom 370 left: undefined 371 right: root.parent.right 372 } 373 } 374 AnchorChanges { 375 target: offsetHandle 376 anchors { 377 top: undefined 378 bottom: undefined 379 left: parent.left 380 right: undefined 381 } 382 } 383 AnchorChanges { 384 target: minimumLengthHandle 385 anchors { 386 top: undefined 387 bottom: undefined 388 left: undefined 389 right: parent.right 390 } 391 } 392 AnchorChanges { 393 target: maximumLengthHandle 394 anchors { 395 top: undefined 396 bottom: undefined 397 left: parent.left 398 right: undefined 399 } 400 } 401 AnchorChanges { 402 target: leftMinimumLengthHandle 403 anchors { 404 top: undefined 405 bottom: undefined 406 left: undefined 407 right: parent.right 408 } 409 } 410 AnchorChanges { 411 target: leftMaximumLengthHandle 412 anchors { 413 top: undefined 414 bottom: undefined 415 left: parent.left 416 right: undefined 417 } 418 } 419 } 420 ] 421} 422