LayerSlider.qml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  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. {
  11. id: sliderRoot
  12. // Handle properties
  13. property real handleSize: UM.Theme.getSize("slider_handle").width
  14. property real handleRadius: handleSize / 2
  15. property real minimumRangeHandleSize: handleSize / 2
  16. property color upperHandleColor: UM.Theme.getColor("slider_handle")
  17. property color lowerHandleColor: UM.Theme.getColor("slider_handle")
  18. property color rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
  19. property color handleActiveColor: UM.Theme.getColor("slider_handle_active")
  20. property var activeHandle: upperHandle
  21. // Track properties
  22. property real trackThickness: UM.Theme.getSize("slider_groove").width // width of the slider track
  23. property real trackRadius: UM.Theme.getSize("slider_groove_radius").width
  24. property color trackColor: UM.Theme.getColor("slider_groove")
  25. // value properties
  26. property real maximumValue: 100
  27. property real minimumValue: 0
  28. property real minimumRange: 0 // minimum range allowed between min and max values
  29. property bool roundValues: true
  30. property real upperValue: maximumValue
  31. property real lowerValue: minimumValue
  32. property bool layersVisible: true
  33. property bool manuallyChanged: true // Indicates whether the value was changed manually or during simulation
  34. function getUpperValueFromSliderHandle()
  35. {
  36. return upperHandle.getValue()
  37. }
  38. function setUpperValue(value)
  39. {
  40. upperHandle.setValue(value)
  41. updateRangeHandle()
  42. }
  43. function getLowerValueFromSliderHandle()
  44. {
  45. return lowerHandle.getValue()
  46. }
  47. function setLowerValue(value)
  48. {
  49. lowerHandle.setValue(value)
  50. updateRangeHandle()
  51. }
  52. function updateRangeHandle()
  53. {
  54. rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height)
  55. }
  56. // set the active handle to show only one label at a time
  57. function setActiveHandle(handle)
  58. {
  59. activeHandle = handle
  60. }
  61. function normalizeValue(value)
  62. {
  63. return Math.min(Math.max(value, sliderRoot.minimumValue), sliderRoot.maximumValue)
  64. }
  65. // Slider track
  66. Rectangle
  67. {
  68. id: track
  69. width: sliderRoot.trackThickness
  70. height: sliderRoot.height - sliderRoot.handleSize
  71. radius: sliderRoot.trackRadius
  72. anchors.centerIn: sliderRoot
  73. color: sliderRoot.trackColor
  74. visible: sliderRoot.layersVisible
  75. }
  76. // Range handle
  77. Item
  78. {
  79. id: rangeHandle
  80. y: upperHandle.y + upperHandle.height
  81. width: sliderRoot.handleSize
  82. height: sliderRoot.minimumRangeHandleSize
  83. anchors.horizontalCenter: sliderRoot.horizontalCenter
  84. visible: sliderRoot.layersVisible
  85. // Set the new value when dragging
  86. function onHandleDragged()
  87. {
  88. sliderRoot.manuallyChanged = true
  89. upperHandle.y = y - upperHandle.height
  90. lowerHandle.y = y + height
  91. var upperValue = sliderRoot.getUpperValueFromSliderHandle()
  92. var lowerValue = sliderRoot.getLowerValueFromSliderHandle()
  93. // set both values after moving the handle position
  94. UM.SimulationView.setCurrentLayer(upperValue)
  95. UM.SimulationView.setMinimumLayer(lowerValue)
  96. }
  97. function setValueManually(value)
  98. {
  99. sliderRoot.manuallyChanged = true
  100. upperHandle.setValue(value)
  101. }
  102. function setValue(value)
  103. {
  104. var range = sliderRoot.upperValue - sliderRoot.lowerValue
  105. value = Math.min(value, sliderRoot.maximumValue)
  106. value = Math.max(value, sliderRoot.minimumValue + range)
  107. UM.SimulationView.setCurrentLayer(value)
  108. UM.SimulationView.setMinimumLayer(value - range)
  109. }
  110. Rectangle
  111. {
  112. width: sliderRoot.trackThickness
  113. height: parent.height + sliderRoot.handleSize
  114. anchors.centerIn: parent
  115. radius: sliderRoot.trackRadius
  116. color: sliderRoot.rangeHandleColor
  117. }
  118. MouseArea
  119. {
  120. anchors.fill: parent
  121. drag
  122. {
  123. target: parent
  124. axis: Drag.YAxis
  125. minimumY: upperHandle.height
  126. maximumY: sliderRoot.height - (rangeHandle.height + lowerHandle.height)
  127. }
  128. onPositionChanged: parent.onHandleDragged()
  129. onPressed: sliderRoot.setActiveHandle(rangeHandle)
  130. }
  131. SimulationSliderLabel
  132. {
  133. id: rangleHandleLabel
  134. height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
  135. x: parent.x - width - UM.Theme.getSize("default_margin").width
  136. anchors.verticalCenter: parent.verticalCenter
  137. target: Qt.point(sliderRoot.width, y + height / 2)
  138. visible: sliderRoot.activeHandle == parent
  139. // custom properties
  140. maximumValue: sliderRoot.maximumValue
  141. value: sliderRoot.upperValue
  142. busy: UM.SimulationView.busy
  143. setValue: rangeHandle.setValueManually // connect callback functions
  144. }
  145. }
  146. // Upper handle
  147. Rectangle
  148. {
  149. id: upperHandle
  150. y: sliderRoot.height - (sliderRoot.minimumRangeHandleSize + 2 * sliderRoot.handleSize)
  151. width: sliderRoot.handleSize
  152. height: sliderRoot.handleSize
  153. anchors.horizontalCenter: sliderRoot.horizontalCenter
  154. radius: sliderRoot.handleRadius
  155. color: upperHandleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.upperHandleColor
  156. visible: sliderRoot.layersVisible
  157. function onHandleDragged()
  158. {
  159. sliderRoot.manuallyChanged = true
  160. // don't allow the lower handle to be heigher than the upper handle
  161. if (lowerHandle.y - (y + height) < sliderRoot.minimumRangeHandleSize)
  162. {
  163. lowerHandle.y = y + height + sliderRoot.minimumRangeHandleSize
  164. }
  165. // update the range handle
  166. sliderRoot.updateRangeHandle()
  167. // set the new value after moving the handle position
  168. UM.SimulationView.setCurrentLayer(getValue())
  169. }
  170. // get the upper value based on the slider position
  171. function getValue()
  172. {
  173. var result = y / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize))
  174. result = sliderRoot.maximumValue + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumValue))
  175. result = sliderRoot.roundValues ? Math.round(result) : result
  176. return result
  177. }
  178. function setValueManually(value)
  179. {
  180. sliderRoot.manuallyChanged = true
  181. upperHandle.setValue(value)
  182. }
  183. // set the slider position based on the upper value
  184. function setValue(value)
  185. {
  186. // Normalize values between range, since using arrow keys will create out-of-the-range values
  187. value = sliderRoot.normalizeValue(value)
  188. UM.SimulationView.setCurrentLayer(value)
  189. var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
  190. // In case there is only one layer, the diff value results in a NaN, so this is for catching this specific case
  191. if (isNaN(diff))
  192. {
  193. diff = 0
  194. }
  195. var newUpperYPosition = Math.round(diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
  196. y = newUpperYPosition
  197. // update the range handle
  198. sliderRoot.updateRangeHandle()
  199. }
  200. Keys.onUpPressed: upperHandleLabel.setValue(upperHandleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  201. Keys.onDownPressed: upperHandleLabel.setValue(upperHandleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  202. // dragging
  203. MouseArea
  204. {
  205. anchors.fill: parent
  206. drag
  207. {
  208. target: parent
  209. axis: Drag.YAxis
  210. minimumY: 0
  211. maximumY: sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)
  212. }
  213. onPositionChanged: parent.onHandleDragged()
  214. onPressed:
  215. {
  216. sliderRoot.setActiveHandle(upperHandle)
  217. upperHandleLabel.forceActiveFocus()
  218. }
  219. }
  220. SimulationSliderLabel
  221. {
  222. id: upperHandleLabel
  223. height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
  224. x: parent.x - parent.width - width
  225. anchors.verticalCenter: parent.verticalCenter
  226. target: Qt.point(sliderRoot.width, y + height / 2)
  227. visible: sliderRoot.activeHandle == parent
  228. // custom properties
  229. maximumValue: sliderRoot.maximumValue
  230. value: sliderRoot.upperValue
  231. busy: UM.SimulationView.busy
  232. setValue: upperHandle.setValueManually // connect callback functions
  233. }
  234. }
  235. // Lower handle
  236. Rectangle
  237. {
  238. id: lowerHandle
  239. y: sliderRoot.height - sliderRoot.handleSize
  240. width: parent.handleSize
  241. height: parent.handleSize
  242. anchors.horizontalCenter: parent.horizontalCenter
  243. radius: sliderRoot.handleRadius
  244. color: lowerHandleLabel.activeFocus ? sliderRoot.handleActiveColor : sliderRoot.lowerHandleColor
  245. visible: sliderRoot.layersVisible
  246. function onHandleDragged()
  247. {
  248. sliderRoot.manuallyChanged = true
  249. // don't allow the upper handle to be lower than the lower handle
  250. if (y - (upperHandle.y + upperHandle.height) < sliderRoot.minimumRangeHandleSize)
  251. {
  252. upperHandle.y = y - (upperHandle.heigth + sliderRoot.minimumRangeHandleSize)
  253. }
  254. // update the range handle
  255. sliderRoot.updateRangeHandle()
  256. // set the new value after moving the handle position
  257. UM.SimulationView.setMinimumLayer(getValue())
  258. }
  259. // get the lower value from the current slider position
  260. function getValue()
  261. {
  262. var result = (y - (sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)) / (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize));
  263. result = sliderRoot.maximumValue - sliderRoot.minimumRange + result * (sliderRoot.minimumValue - (sliderRoot.maximumValue - sliderRoot.minimumRange))
  264. result = sliderRoot.roundValues ? Math.round(result) : result
  265. return result
  266. }
  267. function setValueManually(value)
  268. {
  269. sliderRoot.manuallyChanged = true
  270. lowerHandle.setValue(value)
  271. }
  272. // set the slider position based on the lower value
  273. function setValue(value)
  274. {
  275. // Normalize values between range, since using arrow keys will create out-of-the-range values
  276. value = sliderRoot.normalizeValue(value)
  277. UM.SimulationView.setMinimumLayer(value)
  278. var diff = (value - sliderRoot.maximumValue) / (sliderRoot.minimumValue - sliderRoot.maximumValue)
  279. // In case there is only one layer, the diff value results in a NaN, so this is for catching this specific case
  280. if (isNaN(diff))
  281. {
  282. diff = 0
  283. }
  284. var newLowerYPosition = Math.round((sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize) + diff * (sliderRoot.height - (2 * sliderRoot.handleSize + sliderRoot.minimumRangeHandleSize)))
  285. y = newLowerYPosition
  286. // update the range handle
  287. sliderRoot.updateRangeHandle()
  288. }
  289. Keys.onUpPressed: lowerHandleLabel.setValue(lowerHandleLabel.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  290. Keys.onDownPressed: lowerHandleLabel.setValue(lowerHandleLabel.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
  291. // dragging
  292. MouseArea
  293. {
  294. anchors.fill: parent
  295. drag
  296. {
  297. target: parent
  298. axis: Drag.YAxis
  299. minimumY: upperHandle.height + sliderRoot.minimumRangeHandleSize
  300. maximumY: sliderRoot.height - parent.height
  301. }
  302. onPositionChanged: parent.onHandleDragged()
  303. onPressed:
  304. {
  305. sliderRoot.setActiveHandle(lowerHandle)
  306. lowerHandleLabel.forceActiveFocus()
  307. }
  308. }
  309. SimulationSliderLabel
  310. {
  311. id: lowerHandleLabel
  312. height: sliderRoot.handleSize + UM.Theme.getSize("default_margin").height
  313. x: parent.x - parent.width - width
  314. anchors.verticalCenter: parent.verticalCenter
  315. target: Qt.point(sliderRoot.width + width, y + height / 2)
  316. visible: sliderRoot.activeHandle == parent
  317. // custom properties
  318. maximumValue: sliderRoot.maximumValue
  319. value: sliderRoot.lowerValue
  320. busy: UM.SimulationView.busy
  321. setValue: lowerHandle.setValueManually // connect callback functions
  322. }
  323. }
  324. }