LayerSlider.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. // Copyright (c) 2017 Ultimaker B.V.
  2. // Cura is released under the terms of the LGPLv3 or higher.
  3. import QtQuick 2.2
  4. import QtQuick.Controls 1.2
  5. import QtQuick.Layouts 1.1
  6. import QtQuick.Controls.Styles 1.1
  7. import UM 1.0 as UM
  8. import Cura 1.0 as Cura
  9. Item {
  10. id: sliderRoot
  11. // handle properties
  12. property real handleSize: 10
  13. property real handleRadius: handleSize / 2
  14. property real minimumRangeHandleSize: handleSize / 2
  15. property color upperHandleColor: "black"
  16. property color lowerHandleColor: "black"
  17. property color rangeHandleColor: "black"
  18. property color handleActiveColor: "white"
  19. property real handleLabelWidth: width
  20. property var activeHandle: upperHandle
  21. // track properties
  22. property real trackThickness: 4 // width of the slider track
  23. property real trackRadius: trackThickness / 2
  24. property color trackColor: "white"
  25. property real trackBorderWidth: 1 // width of the slider track border
  26. property color trackBorderColor: "black"
  27. // value properties
  28. property real maximumValue: 100
  29. property real minimumValue: 0
  30. property real minimumRange: 0 // minimum range allowed between min and max values
  31. property bool roundValues: true
  32. property real upperValue: maximumValue
  33. property real lowerValue: minimumValue
  34. property bool layersVisible: true
  35. function getUpperValueFromSliderHandle () {
  36. return upperHandle.getValue()
  37. }
  38. function setUpperValue (value) {
  39. upperHandle.setValue(value)
  40. updateRangeHandle()
  41. }
  42. function getLowerValueFromSliderHandle () {
  43. return lowerHandle.getValue()
  44. }
  45. function setLowerValue (value) {
  46. lowerHandle.setValue(value)
  47. updateRangeHandle()
  48. }
  49. function updateRangeHandle () {
  50. rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height)
  51. }
  52. // set the active handle to show only one label at a time
  53. function setActiveHandle (handle) {
  54. activeHandle = handle
  55. }
  56. // slider track
  57. Rectangle {
  58. id: track
  59. width: sliderRoot.trackThickness
  60. height: sliderRoot.height - sliderRoot.handleSize
  61. radius: sliderRoot.trackRadius
  62. anchors.centerIn: sliderRoot
  63. color: sliderRoot.trackColor
  64. border.width: sliderRoot.trackBorderWidth
  65. border.color: sliderRoot.trackBorderColor
  66. visible: sliderRoot.layersVisible
  67. }
  68. // Range handle
  69. Item {
  70. id: rangeHandle
  71. y: upperHandle.y + upperHandle.height
  72. width: sliderRoot.handleSize
  73. height: sliderRoot.minimumRangeHandleSize
  74. anchors.horizontalCenter: sliderRoot.horizontalCenter
  75. visible: sliderRoot.layersVisible
  76. // set the new value when dragging
  77. function onHandleDragged () {
  78. upperHandle.y = y - upperHandle.height
  79. lowerHandle.y = y + height
  80. var upperValue = sliderRoot.getUpperValueFromSliderHandle()
  81. var lowerValue = sliderRoot.getLowerValueFromSliderHandle()
  82. // set both values after moving the handle position
  83. UM.SimulationView.setCurrentLayer(upperValue)
  84. UM.SimulationView.setMinimumLayer(lowerValue)
  85. }
  86. function setValue (value) {
  87. var range = sliderRoot.upperValue - sliderRoot.lowerValue
  88. value = Math.min(value, sliderRoot.maximumValue)
  89. value = Math.max(value, sliderRoot.minimumValue + range)
  90. UM.SimulationView.setCurrentLayer(value)
  91. UM.SimulationView.setMinimumLayer(value - range)
  92. }
  93. Rectangle {
  94. width: sliderRoot.trackThickness - 2 * sliderRoot.trackBorderWidth
  95. height: parent.height + sliderRoot.handleSize
  96. anchors.centerIn: parent
  97. color: sliderRoot.rangeHandleColor
  98. }
  99. MouseArea {
  100. anchors.fill: parent
  101. drag {
  102. target: parent
  103. axis: Drag.YAxis
  104. minimumY: upperHandle.height
  105. maximumY: sliderRoot.height - (rangeHandle.height + lowerHandle.height)
  106. }
  107. onPositionChanged: parent.onHandleDragged()
  108. onPressed: sliderRoot.setActiveHandle(rangeHandle)
  109. }
  110. SimulationSliderLabel {
  111. id: rangleHandleLabel
  112. height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
  113. x: parent.x - width - UM.Theme.getSize("default_margin").width
  114. anchors.verticalCenter: parent.verticalCenter
  115. target: Qt.point(sliderRoot.width, y + height / 2)
  116. visible: sliderRoot.activeHandle == parent
  117. // custom properties
  118. maximumValue: sliderRoot.maximumValue
  119. value: sliderRoot.upperValue
  120. busy: UM.SimulationView.busy
  121. setValue: rangeHandle.setValue // connect callback functions
  122. }
  123. }
  124. // Upper handle
  125. Rectangle {
  126. id: upperHandle
  127. y: sliderRoot.height - (sliderRoot.minimumRangeHandleSize + 2 * sliderRoot.handleSize)
  128. width: sliderRoot.handleSize
  129. height: sliderRoot.handleSize
  130. anchors.horizontalCenter: sliderRoot.horizontalCenter
  131. radius: sliderRoot.handleRadius
  132. color: upperHandleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.upperHandleColor
  133. visible: sliderRoot.layersVisible
  134. function onHandleDragged () {
  135. // don't allow the lower handle to be heigher than the upper handle
  136. if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize) {
  137. lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize
  138. }
  139. // update the range handle
  140. sliderRoot.updateRangeHandle()
  141. // set the new value after moving the handle position
  142. UM.SimulationView.setCurrentLayer(getValue())
  143. }
  144. // get the upper value based on the slider position
  145. function getValue () {
  146. var result = y / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize))
  147. result = sliderRoot.maximumValue + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumValue))
  148. result = sliderRoot.roundValues ? Math.round(result) : result
  149. return result
  150. }
  151. // set the slider position based on the upper value
  152. function setValue (value) {
  153. UM.SimulationView.setCurrentLayer(value)
  154. var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
  155. var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
  156. y = newUpperYPosition
  157. // update the range handle
  158. sliderRoot.updateRangeHandle()
  159. }
  160. Keys.onUpPressed: upperHandleLabel.setValue(upperHandleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  161. Keys.onDownPressed: upperHandleLabel.setValue(upperHandleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  162. // dragging
  163. MouseArea {
  164. anchors.fill: parent
  165. drag {
  166. target: parent
  167. axis: Drag.YAxis
  168. minimumY: 0
  169. maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)
  170. }
  171. onPositionChanged: parent.onHandleDragged()
  172. onPressed: {
  173. sliderRoot.setActiveHandle(upperHandle)
  174. upperHandleLabel.forceActiveFocus()
  175. }
  176. }
  177. SimulationSliderLabel {
  178. id: upperHandleLabel
  179. height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
  180. x: parent.x - width - UM.Theme.getSize("default_margin").width
  181. anchors.verticalCenter: parent.verticalCenter
  182. target: Qt.point(sliderRoot.width, y + height / 2)
  183. visible: sliderRoot.activeHandle == parent
  184. // custom properties
  185. maximumValue: sliderRoot.maximumValue
  186. value: sliderRoot.upperValue
  187. busy: UM.SimulationView.busy
  188. setValue: upperHandle.setValue // connect callback functions
  189. }
  190. }
  191. // Lower handle
  192. Rectangle {
  193. id: lowerHandle
  194. y: sliderRoot.height - sliderRoot.handleSize
  195. width: parent.handleSize
  196. height: parent.handleSize
  197. anchors.horizontalCenter: parent.horizontalCenter
  198. radius: sliderRoot.handleRadius
  199. color: lowerHandleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.lowerHandleColor
  200. visible: sliderRoot.layersVisible
  201. function onHandleDragged () {
  202. // don't allow the upper handle to be lower than the lower handle
  203. if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize) {
  204. upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
  205. }
  206. // update the range handle
  207. sliderRoot.updateRangeHandle()
  208. // set the new value after moving the handle position
  209. UM.SimulationView.setMinimumLayer(getValue())
  210. }
  211. // get the lower value from the current slider position
  212. function getValue () {
  213. var result = (y - (sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize));
  214. result = sliderRoot.maximumValue - sliderRoot.minimumRange + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumRange))
  215. result = sliderRoot.roundValues ? Math.round(result) : result
  216. return result
  217. }
  218. // set the slider position based on the lower value
  219. function setValue (value) {
  220. UM.SimulationView.setMinimumLayer(value)
  221. var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
  222. var newLowerYPosition = Math.round((sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) + diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
  223. y = newLowerYPosition
  224. // update the range handle
  225. sliderRoot.updateRangeHandle()
  226. }
  227. Keys.onUpPressed: lowerHandleLabel.setValue(lowerHandleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  228. Keys.onDownPressed: lowerHandleLabel.setValue(lowerHandleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  229. // dragging
  230. MouseArea {
  231. anchors.fill: parent
  232. drag {
  233. target: parent
  234. axis: Drag.YAxis
  235. minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize
  236. maximumY: sliderRoot.height - parent.height
  237. }
  238. onPositionChanged: parent.onHandleDragged()
  239. onPressed: {
  240. sliderRoot.setActiveHandle(lowerHandle)
  241. lowerHandleLabel.forceActiveFocus()
  242. }
  243. }
  244. SimulationSliderLabel {
  245. id: lowerHandleLabel
  246. height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
  247. x: parent.x - width - UM.Theme.getSize("default_margin").width
  248. anchors.verticalCenter: parent.verticalCenter
  249. target: Qt.point(sliderRoot.width, y + height / 2)
  250. visible: sliderRoot.activeHandle == parent
  251. // custom properties
  252. maximumValue: sliderRoot.maximumValue
  253. value: sliderRoot.lowerValue
  254. busy: UM.SimulationView.busy
  255. setValue: lowerHandle.setValue // connect callback functions
  256. }
  257. }
  258. }