SliderWithColorFill.qml 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the Qt Components project.
  8. **
  9. ** $QT_BEGIN_LICENSE:BSD$
  10. ** You may use this file under the terms of the BSD license as follows:
  11. **
  12. ** "Redistribution and use in source and binary forms, with or without
  13. ** modification, are permitted provided that the following conditions are
  14. ** met:
  15. ** * Redistributions of source code must retain the above copyright
  16. ** notice, this list of conditions and the following disclaimer.
  17. ** * Redistributions in binary form must reproduce the above copyright
  18. ** notice, this list of conditions and the following disclaimer in
  19. ** the documentation and/or other materials provided with the
  20. ** distribution.
  21. ** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
  22. ** the names of its contributors may be used to endorse or promote
  23. ** products derived from this software without specific prior written
  24. ** permission.
  25. **
  26. ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  28. ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  29. ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  30. ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  31. ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  32. ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  33. ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  34. ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  35. ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  36. ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
  37. ** $QT_END_LICENSE$
  38. **
  39. ****************************************************************************/
  40. import QtQuick 1.1
  41. import com.nokia.symbian 1.1
  42. import Qt.labs.components 1.1 as QtComponents
  43. Item {
  44. id: root
  45. // Common Public API
  46. property alias stepSize: model.stepSize
  47. property alias minimumValue: model.minimumValue
  48. property alias maximumValue: model.maximumValue
  49. property alias value: model.value
  50. property int orientation: Qt.Horizontal
  51. property bool pressed: track.inputActive
  52. property bool valueIndicatorVisible: false
  53. property string valueIndicatorText: ""
  54. property alias inverted: model.inverted
  55. LayoutMirroring.enabled: false
  56. LayoutMirroring.childrenInherit: true
  57. // Symbian specific
  58. property bool platformInverted: false
  59. signal valueChanged(real value)
  60. implicitWidth: orientation == Qt.Horizontal ? 150 : privateStyle.menuItemHeight
  61. implicitHeight: orientation == Qt.Horizontal ? privateStyle.menuItemHeight : 150
  62. onActiveFocusChanged: {
  63. if (!root.activeFocus)
  64. track.activeKey = undefined
  65. }
  66. QtComponents.RangeModel {
  67. id: model
  68. value: 0.0
  69. stepSize: 0.0
  70. minimumValue: 0.0
  71. maximumValue: 1.0
  72. positionAtMinimum: 0
  73. positionAtMaximum: orientation == Qt.Horizontal ? track.width - handle.width : track.height - handle.height
  74. onValueChanged: root.valueChanged(value)
  75. }
  76. BorderImage {
  77. id: track
  78. objectName: "track"
  79. property bool tapOnTrack: false
  80. property variant activeKey
  81. property bool inputActive: handleMouseArea.pressed || !!track.activeKey
  82. onInputActiveChanged: {
  83. if (!valueIndicatorVisible)
  84. return
  85. if (inputActive)
  86. valueIndicator.show = true
  87. else
  88. indicatorTimer.restart()
  89. }
  90. states: [
  91. State {
  92. name: "Horizontal"
  93. when: orientation == Qt.Horizontal
  94. PropertyChanges {
  95. target: track
  96. height: privateStyle.sliderThickness
  97. width: undefined
  98. source: privateStyle.imagePath("qtg_fr_slider_h_track_normal", root.platformInverted)
  99. border {
  100. left: 20
  101. right: 20
  102. top: 0
  103. bottom: 0
  104. }
  105. smooth: true
  106. }
  107. AnchorChanges {
  108. target: track
  109. anchors {
  110. left: root.left
  111. right: root.right
  112. top: undefined
  113. bottom: undefined
  114. horizontalCenter: undefined
  115. verticalCenter: root.verticalCenter
  116. }
  117. }
  118. },
  119. State {
  120. name: "Vertical"
  121. when: orientation == Qt.Vertical
  122. PropertyChanges {
  123. target: track
  124. height: undefined
  125. width: privateStyle.sliderThickness
  126. source: privateStyle.imagePath("qtg_fr_slider_v_track_normal", root.platformInverted)
  127. border {
  128. left: 0
  129. right: 0
  130. top: 20
  131. bottom: 20
  132. }
  133. smooth: true
  134. }
  135. AnchorChanges {
  136. target: track
  137. anchors {
  138. left: undefined
  139. right: undefined
  140. top: root.top
  141. bottom: root.bottom
  142. horizontalCenter: root.horizontalCenter
  143. verticalCenter: undefined
  144. }
  145. }
  146. }
  147. ]
  148. anchors.leftMargin: platformStyle.paddingMedium
  149. anchors.rightMargin: platformStyle.paddingMedium
  150. anchors.topMargin: platformStyle.paddingMedium
  151. anchors.bottomMargin: platformStyle.paddingMedium
  152. BorderImage {
  153. id: fill
  154. source: "../Images/Icons/slider_red.svg"
  155. anchors.left: track.left
  156. anchors.leftMargin: 1
  157. anchors.top: track.top
  158. anchors.bottom: track.bottom
  159. width: handle.x + handle.width/2
  160. border {
  161. left: 20
  162. right: 20
  163. top: 0
  164. bottom: 0
  165. }
  166. }
  167. MouseArea {
  168. id: trackMouseArea
  169. objectName: "trackMouseArea"
  170. anchors.fill: parent
  171. onClicked: {
  172. if (track.tapOnTrack) {
  173. if (orientation == Qt.Horizontal) {
  174. if (handle.x > (mouseX - handle.width / 2)) {
  175. model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
  176. handle.x = model.position
  177. } else {
  178. model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
  179. handle.x = model.position
  180. }
  181. } else {
  182. if (handle.y > (mouseY - handle.height / 2)) {
  183. model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
  184. handle.y = model.position
  185. } else {
  186. model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
  187. handle.y = model.position
  188. }
  189. }
  190. }
  191. }
  192. Image {
  193. id: handle
  194. objectName: "handle"
  195. x: orientation == Qt.Horizontal ? (handleMouseArea.pressed ? x : model.position) : 0
  196. y: orientation == Qt.Horizontal ? 0 : (handleMouseArea.pressed ? y : model.position)
  197. sourceSize.height: platformStyle.graphicSizeSmall
  198. sourceSize.width: platformStyle.graphicSizeSmall
  199. anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
  200. anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
  201. source: {
  202. var handleIcon = "qtg_graf_slider_"
  203. + (orientation == Qt.Horizontal ? "h" : "v")
  204. + "_handle_"
  205. + (handleMouseArea.pressed ? "pressed" : "normal")
  206. privateStyle.imagePath(handleIcon, root.platformInverted)
  207. }
  208. onXChanged: valueIndicator.position()
  209. onYChanged: valueIndicator.position()
  210. MouseArea {
  211. id: handleMouseArea
  212. objectName: "handleMouseArea"
  213. height: platformStyle.graphicSizeMedium
  214. width: platformStyle.graphicSizeMedium
  215. anchors.verticalCenter: orientation == Qt.Horizontal ? parent.verticalCenter : undefined
  216. anchors.horizontalCenter: orientation == Qt.Horizontal ? undefined : parent.horizontalCenter
  217. drag.target: handle
  218. drag.axis: Drag.XandYAxis
  219. drag.minimumX: orientation == Qt.Horizontal ? model.positionAtMinimum : 0
  220. drag.maximumX: orientation == Qt.Horizontal ? model.positionAtMaximum : 0
  221. drag.minimumY: orientation == Qt.Horizontal ? 0 : model.positionAtMinimum
  222. drag.maximumY: orientation == Qt.Horizontal ? 0 : model.positionAtMaximum
  223. onPositionChanged: model.position = orientation == Qt.Horizontal ? handle.x : handle.y
  224. onPressed: privateStyle.play(Symbian.BasicSlider)
  225. onReleased: privateStyle.play(Symbian.BasicSlider)
  226. }
  227. }
  228. }
  229. }
  230. Keys.onPressed: {
  231. internal.handleKeyPressEvent(event)
  232. }
  233. Keys.onReleased: {
  234. internal.handleKeyReleaseEvent(event)
  235. }
  236. Component {
  237. id: valueIndicatorComponent
  238. ToolTip {
  239. text: root.valueIndicatorText == "" ? model.value : root.valueIndicatorText
  240. platformInverted: root.platformInverted
  241. }
  242. }
  243. Loader {
  244. id: valueIndicator
  245. property int spacing: 2 * platformStyle.paddingLarge
  246. // Must match with the "maxWidth" padding defined in ToolTip
  247. property int toolTipPadding: platformStyle.paddingLarge
  248. property bool show: false
  249. sourceComponent: valueIndicator.show ? valueIndicatorComponent : undefined
  250. onLoaded: position()
  251. function position() {
  252. if (!valueIndicatorVisible || status != Loader.Ready)
  253. return
  254. var point = null
  255. if (orientation == Qt.Horizontal) {
  256. point = root.mapFromItem(track, handle.x + handle.width / 2 - valueIndicator.item.width / 2, 0)
  257. // Check if valueIndicator will be positioned beyond the right or
  258. // left boundaries and adjust if needed to keep it fully
  259. // visible on screen. In case the valueIndicator is so wide that it
  260. // does not fit the screen, it's positioned to left of the screen.
  261. var rightStop = screen.width - toolTipPadding
  262. var valueIndicatorLeftEdge = root.mapToItem(null, point.x, 0)
  263. var valueIndicatorRightEdge = root.mapToItem(null, point.x + valueIndicator.item.width, 0)
  264. if (valueIndicatorLeftEdge.x < toolTipPadding)
  265. point.x = root.mapFromItem(null, toolTipPadding, 0).x
  266. else if (valueIndicatorRightEdge.x > rightStop)
  267. point.x = root.mapFromItem(null, rightStop - valueIndicator.item.width, 0).x
  268. valueIndicator.item.x = point.x
  269. valueIndicator.item.y = point.y - valueIndicator.spacing - valueIndicator.item.height
  270. } else {
  271. point = root.mapFromItem(track, 0, handle.y + handle.height / 2 - valueIndicator.item.height / 2)
  272. valueIndicator.item.x = point.x - valueIndicator.spacing - valueIndicator.item.width
  273. valueIndicator.item.y = point.y
  274. }
  275. }
  276. Timer {
  277. id: indicatorTimer
  278. interval: 750
  279. onTriggered: {
  280. if (!track.inputActive)
  281. valueIndicator.show = false
  282. }
  283. }
  284. }
  285. QtObject {
  286. id: internal
  287. function handleKeyPressEvent(keyEvent) {
  288. var oldValue = model.value
  289. if (orientation == Qt.Horizontal) {
  290. if (keyEvent.key == Qt.Key_Left) {
  291. model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
  292. } else if (keyEvent.key == Qt.Key_Right) {
  293. model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
  294. }
  295. } else { //Vertical
  296. if (keyEvent.key == Qt.Key_Up) {
  297. model.value = inverted ? model.value + model.stepSize : model.value - model.stepSize
  298. } else if (keyEvent.key == Qt.Key_Down) {
  299. model.value = inverted ? model.value - model.stepSize : model.value + model.stepSize
  300. }
  301. }
  302. if (oldValue != model.value)
  303. keyEvent.accepted = true
  304. if (keyEvent.accepted ||
  305. keyEvent.key == Qt.Key_Select ||
  306. keyEvent.key == Qt.Key_Return ||
  307. keyEvent.key == Qt.Key_Enter)
  308. track.activeKey = keyEvent.key
  309. }
  310. function handleKeyReleaseEvent(keyEvent) {
  311. if (track.activeKey == keyEvent.key) {
  312. if (!keyEvent.isAutoRepeat)
  313. track.activeKey = undefined
  314. keyEvent.accepted = true
  315. }
  316. }
  317. }
  318. }