DialStyle.qml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2016 The Qt Company Ltd.
  4. ** Contact: https://www.qt.io/licensing/
  5. **
  6. ** This file is part of the Qt Quick Extras module of the Qt Toolkit.
  7. **
  8. ** $QT_BEGIN_LICENSE:LGPL$
  9. ** Commercial License Usage
  10. ** Licensees holding valid commercial Qt licenses may use this file in
  11. ** accordance with the commercial license agreement provided with the
  12. ** Software or, alternatively, in accordance with the terms contained in
  13. ** a written agreement between you and The Qt Company. For licensing terms
  14. ** and conditions see https://www.qt.io/terms-conditions. For further
  15. ** information use the contact form at https://www.qt.io/contact-us.
  16. **
  17. ** GNU Lesser General Public License Usage
  18. ** Alternatively, this file may be used under the terms of the GNU Lesser
  19. ** General Public License version 3 as published by the Free Software
  20. ** Foundation and appearing in the file LICENSE.LGPL3 included in the
  21. ** packaging of this file. Please review the following information to
  22. ** ensure the GNU Lesser General Public License version 3 requirements
  23. ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
  24. **
  25. ** GNU General Public License Usage
  26. ** Alternatively, this file may be used under the terms of the GNU
  27. ** General Public License version 2.0 or (at your option) the GNU General
  28. ** Public license version 3 or any later version approved by the KDE Free
  29. ** Qt Foundation. The licenses are as published by the Free Software
  30. ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
  31. ** included in the packaging of this file. Please review the following
  32. ** information to ensure the GNU General Public License requirements will
  33. ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
  34. ** https://www.gnu.org/licenses/gpl-3.0.html.
  35. **
  36. ** $QT_END_LICENSE$
  37. **
  38. ****************************************************************************/
  39. import QtQuick 2.2
  40. import QtQuick.Controls 1.4
  41. import QtQuick.Controls.Styles 1.4
  42. import QtQuick.Controls.Private 1.0
  43. import QtQuick.Extras 1.4
  44. import QtQuick.Extras.Private 1.0
  45. import QtQuick.Extras.Private.CppUtils 1.0
  46. /*!
  47. \qmltype DialStyle
  48. \inqmlmodule QtQuick.Controls.Styles
  49. \since 5.5
  50. \ingroup controlsstyling
  51. \brief Provides custom styling for Dial.
  52. You can create a custom dial by replacing the following delegates:
  53. \list
  54. \li \l background
  55. \endlist
  56. */
  57. Style {
  58. id: dialStyle
  59. /*!
  60. The \l Dial that this style is attached to.
  61. */
  62. readonly property Dial control: __control
  63. /*!
  64. The distance from the center of the dial to the outer edge of the dial.
  65. This property is useful for determining the size of the various
  66. components of the style, in order to ensure that they are scaled
  67. proportionately when the dial is resized.
  68. */
  69. readonly property real outerRadius: Math.min(control.height, control.width) / 2
  70. /*!
  71. The distance in pixels from the outside of the dial (outerRadius)
  72. to the center of the handle.
  73. */
  74. property real handleInset: (__tickmarkRadius * 4) + ((__handleRadius * 2) * 0.55)
  75. /*!
  76. The interval at which tickmarks are displayed.
  77. For example, if this property is set to \c 10,
  78. control.minimumValue to \c 0, and control.maximumValue to \c 100,
  79. the tickmarks displayed will be 0, 10, 20, etc., to 100, along
  80. the circumference of the dial.
  81. */
  82. property real tickmarkStepSize: 1
  83. /*!
  84. The distance in pixels from the outside of the dial (outerRadius) at
  85. which the outermost point of the tickmark line is drawn.
  86. */
  87. property real tickmarkInset: 0
  88. /*!
  89. The amount of tickmarks displayed by the dial, calculated from
  90. \l tickmarkStepSize and the control's
  91. \l {Dial::minimumValue}{minimumValue} and
  92. \l {Dial::maximumValue}{maximumValue}.
  93. \sa minorTickmarkCount
  94. */
  95. readonly property int tickmarkCount: control.__panel.circularTickmarkLabel.tickmarkCount
  96. /*!
  97. The amount of minor tickmarks between each tickmark.
  98. \sa tickmarkCount
  99. */
  100. property int minorTickmarkCount: 0
  101. /*!
  102. The distance in pixels from the outside of the dial (outerRadius) at
  103. which the outermost point of the minor tickmark line is drawn.
  104. */
  105. property real minorTickmarkInset: 0
  106. /*!
  107. The distance in pixels from the outside of the dial (outerRadius) at
  108. which the center of the value marker text is drawn.
  109. */
  110. property real labelInset: 0
  111. /*!
  112. The interval at which tickmark labels are displayed.
  113. For example, if this property is set to \c 10 (the default),
  114. control.minimumValue to \c 0, and control.maximumValue to \c 100, the
  115. tickmark labels displayed will be 0, 10, 20, etc., to 100,
  116. along the circumference of the dial.
  117. */
  118. property real labelStepSize: tickmarkStepSize
  119. /*!
  120. The amount of tickmark labels displayed by the dial, calculated from
  121. \l labelStepSize and the control's
  122. \l {Dial::minimumValue}{minimumValue} and
  123. \l {Dial::maximumValue}{maximumValue}.
  124. \sa tickmarkCount, minorTickmarkCount
  125. */
  126. readonly property int labelCount: control.__panel.circularTickmarkLabel.labelCount
  127. /*! \qmlmethod real DialStyle::valueToAngle(real value)
  128. Returns \a value as an angle in degrees.
  129. This function is useful for custom drawing or positioning of items in
  130. the style's components. For example, it can be used to calculate the
  131. angles at which to draw an arc around the dial indicating the safe
  132. range of values.
  133. */
  134. function valueToAngle(value) {
  135. return control.__panel.circularTickmarkLabel.valueToAngle(value);
  136. }
  137. /*! \internal */
  138. readonly property real __tickmarkRadius: outerRadius * 0.06
  139. /*! \internal */
  140. readonly property real __handleRadius: outerRadius * 0.15
  141. /*!
  142. \internal
  143. This property determines whether it is possible to change the value of
  144. the dial simply by pressing/tapping.
  145. If \c false, the user must drag to rotate the dial and hence change the
  146. value.
  147. This property is useful for touch devices, where it is easy to
  148. accidentally tap while flicking, for example.
  149. */
  150. property bool __dragToSet: Settings.hasTouchScreen && Settings.isMobile
  151. /*!
  152. The background of the dial.
  153. The implicit size of the dial is taken from this component.
  154. */
  155. property Component background: Item {
  156. id: backgroundItem
  157. implicitWidth: backgroundHelper.implicitWidth
  158. implicitHeight: backgroundHelper.implicitHeight
  159. CircularButtonStyleHelper {
  160. id: backgroundHelper
  161. control: dialStyle.control
  162. property color zeroMarkerColor: "#a8a8a8"
  163. property color zeroMarkerColorTransparent: "transparent"
  164. property real zeroMarkerLength: outerArcLineWidth * 1.25
  165. property real zeroMarkerWidth: outerArcLineWidth * 0.3
  166. smallestAxis: Math.min(backgroundItem.width, backgroundItem.height) - __tickmarkRadius * 4
  167. }
  168. Canvas {
  169. id: backgroundCanvas
  170. anchors.fill: parent
  171. readonly property real xCenter: width / 2
  172. readonly property real yCenter: height / 2
  173. onPaint: {
  174. var ctx = getContext("2d");
  175. backgroundHelper.paintBackground(ctx);
  176. }
  177. }
  178. }
  179. /*!
  180. The handle of the dial.
  181. The handle is automatically positioned within the dial, based on the
  182. \l handleInset and the implicit width and height of the handle itself.
  183. */
  184. property Component handle: Canvas {
  185. implicitWidth: __handleRadius * 2
  186. implicitHeight: __handleRadius * 2
  187. HandleStyleHelper {
  188. id: handleHelper
  189. }
  190. onPaint: {
  191. var ctx = getContext("2d");
  192. handleHelper.paintHandle(ctx, 1, 1, width - 2, height - 2);
  193. }
  194. }
  195. /*!
  196. This component defines each individual tickmark. The position of each
  197. tickmark is already set; only the
  198. \l {Item::implicitWidth}{implicitWidth} and
  199. \l {Item::implicitHeight}{implicitHeight} need to be specified.
  200. Each instance of this component has access to the following properties:
  201. \table
  202. \row \li \c {readonly property int} \b styleData.index
  203. \li The index of this tickmark.
  204. \row \li \c {readonly property real} \b styleData.value
  205. \li The value that this tickmark represents.
  206. \endtable
  207. */
  208. property Component tickmark: Rectangle {
  209. implicitWidth: outerRadius * 0.015 + (styleData.index === 0 || styleData.index === tickmarkCount ? 1 : (styleData.index) / tickmarkCount) * __tickmarkRadius * 0.75
  210. implicitHeight: implicitWidth
  211. radius: height / 2
  212. color: styleData.index === 0 ? "transparent" : Qt.rgba(0, 0, 0, 0.266)
  213. antialiasing: true
  214. border.width: styleData.index === 0 ? Math.max(1, outerRadius * 0.0075) : 0
  215. border.color: Qt.rgba(0, 0, 0, 0.266)
  216. }
  217. /*!
  218. This component defines each individual minor tickmark. The position of each
  219. minor tickmark is already set; only the
  220. \l {Item::implicitWidth}{implicitWidth} and
  221. \l {Item::implicitHeight}{implicitHeight} need to be specified.
  222. Each instance of this component has access to the following properties:
  223. \table
  224. \row \li \c {readonly property int} \b styleData.index
  225. \li The index of this tickmark.
  226. \row \li \c {readonly property real} \b styleData.value
  227. \li The value that this tickmark represents.
  228. \endtable
  229. By default, no minor tickmark is defined.
  230. */
  231. property Component minorTickmark
  232. /*!
  233. This defines the text of each tickmark label on the dial.
  234. Each instance of this component has access to the following properties:
  235. \table
  236. \row \li \c {readonly property int} \b styleData.index
  237. \li The index of this label.
  238. \row \li \c {readonly property real} \b styleData.value
  239. \li The value that this label represents.
  240. \endtable
  241. By default, no label is defined.
  242. */
  243. property Component tickmarkLabel
  244. /*! \internal */
  245. property Component panel: Item {
  246. implicitWidth: backgroundLoader.implicitWidth
  247. implicitHeight: backgroundLoader.implicitHeight
  248. property alias background: backgroundLoader.item
  249. property alias circularTickmarkLabel: circularTickmarkLabel_
  250. Loader {
  251. id: backgroundLoader
  252. sourceComponent: dialStyle.background
  253. width: outerRadius * 2
  254. height: width
  255. anchors.centerIn: parent
  256. }
  257. Loader {
  258. id: handleLoader
  259. sourceComponent: dialStyle.handle
  260. x: backgroundLoader.x + __pos.x - width / 2
  261. y: backgroundLoader.y + __pos.y - height / 2
  262. readonly property point __pos: {
  263. var radians = 0;
  264. if (control.__wrap) {
  265. radians = (control.value - control.minimumValue) /
  266. (control.maximumValue - control.minimumValue) *
  267. (MathUtils.pi2) + backgroundHelper.zeroAngle;
  268. } else {
  269. radians = -(Math.PI * 8 - (control.value - control.minimumValue) * 10 *
  270. Math.PI / (control.maximumValue - control.minimumValue)) / 6;
  271. }
  272. return MathUtils.centerAlongCircle(backgroundLoader.width / 2, backgroundLoader.height / 2,
  273. 0, 0, radians, outerRadius - handleInset)
  274. }
  275. }
  276. CircularTickmarkLabel {
  277. id: circularTickmarkLabel_
  278. anchors.fill: backgroundLoader
  279. minimumValue: control.minimumValue
  280. maximumValue: control.maximumValue
  281. stepSize: control.stepSize
  282. tickmarksVisible: control.tickmarksVisible
  283. minimumValueAngle: -150
  284. maximumValueAngle: 150
  285. tickmarkStepSize: dialStyle.tickmarkStepSize
  286. tickmarkInset: dialStyle.tickmarkInset
  287. minorTickmarkCount: dialStyle.minorTickmarkCount
  288. minorTickmarkInset: dialStyle.minorTickmarkInset
  289. labelInset: dialStyle.labelInset
  290. labelStepSize: dialStyle.labelStepSize
  291. style: CircularTickmarkLabelStyle {
  292. tickmark: dialStyle.tickmark
  293. minorTickmark: dialStyle.minorTickmark
  294. tickmarkLabel: dialStyle.tickmarkLabel
  295. }
  296. }
  297. }
  298. }