CircularTickmarkLabelStyle.qml 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  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.Private 1.0
  41. import QtQuick.Extras.Private 1.0
  42. import QtQuick.Extras.Private.CppUtils 1.0
  43. Style {
  44. id: circularTickmarkLabelStyle
  45. /*!
  46. The distance from the center of the control to the outer edge.
  47. */
  48. readonly property real outerRadius: Math.min(control.width, control.height) * 0.5
  49. property QtObject __protectedScope: QtObject {
  50. /*!
  51. Converts a value expressed as a percentage of \l outerRadius to
  52. a pixel value.
  53. */
  54. function toPixels(percentageOfOuterRadius) {
  55. return percentageOfOuterRadius * outerRadius;
  56. }
  57. }
  58. /*!
  59. This component defines each individual tickmark. The position of each
  60. tickmark is already set; only the size needs to be specified.
  61. */
  62. property Component tickmark: Rectangle {
  63. width: outerRadius * 0.02
  64. antialiasing: true
  65. height: outerRadius * 0.06
  66. color: "#c8c8c8"
  67. }
  68. /*!
  69. This component defines each individual minor tickmark. The position of
  70. each minor tickmark is already set; only the size needs to be specified.
  71. */
  72. property Component minorTickmark: Rectangle {
  73. width: outerRadius * 0.01
  74. antialiasing: true
  75. height: outerRadius * 0.03
  76. color: "#c8c8c8"
  77. }
  78. /*!
  79. This defines the text of each tickmark label on the gauge.
  80. */
  81. property Component tickmarkLabel: Text {
  82. font.pixelSize: Math.max(6, __protectedScope.toPixels(0.12))
  83. text: styleData.value
  84. color: "#c8c8c8"
  85. antialiasing: true
  86. horizontalAlignment: Text.AlignHCenter
  87. verticalAlignment: Text.AlignVCenter
  88. }
  89. /*! \internal */
  90. property Component panel: Item {
  91. id: panelItem
  92. implicitWidth: 250
  93. implicitHeight: 250
  94. function rangeUsed(count, stepSize) {
  95. return (((count - 1) * stepSize) / (control.maximumValue - control.minimumValue)) * control.angleRange;
  96. }
  97. readonly property real tickmarkSectionSize: rangeUsed(control.tickmarkCount, control.tickmarkStepSize) / (control.tickmarkCount - 1)
  98. readonly property real tickmarkSectionValue: (control.maximumValue - control.minimumValue) / (control.tickmarkCount - 1)
  99. readonly property real minorTickmarkSectionSize: tickmarkSectionSize / (control.minorTickmarkCount + 1)
  100. readonly property real minorTickmarkSectionValue: tickmarkSectionValue / (control.minorTickmarkCount + 1)
  101. readonly property int totalMinorTickmarkCount: {
  102. // The size of each section within two major tickmarks, expressed as a percentage.
  103. var minorSectionPercentage = 1 / (control.minorTickmarkCount + 1);
  104. // The amount of major tickmarks not able to be displayed; will be 0 if they all fit.
  105. var tickmarksNotDisplayed = control.__tickmarkCount - control.tickmarkCount;
  106. var count = control.minorTickmarkCount * (control.tickmarkCount - 1);
  107. // We'll try to display as many minor tickmarks as we can to fill up the space.
  108. count + tickmarksNotDisplayed / minorSectionPercentage;
  109. }
  110. readonly property real labelSectionSize: rangeUsed(control.labelCount, control.labelStepSize) / (control.labelCount - 1)
  111. function toPixels(percentageOfOuterRadius) {
  112. return percentageOfOuterRadius * outerRadius;
  113. }
  114. /*!
  115. Returns the angle of \a marker (in the range 0 ... n - 1, where n
  116. is the amount of markers) on the gauge where sections are of size
  117. tickmarkSectionSize.
  118. */
  119. function tickmarkAngleFromIndex(tickmarkIndex) {
  120. return tickmarkIndex * tickmarkSectionSize + control.minimumValueAngle;
  121. }
  122. function labelAngleFromIndex(labelIndex) {
  123. return labelIndex * labelSectionSize + control.minimumValueAngle;
  124. }
  125. function labelPosFromIndex(index, labelWidth, labelHeight) {
  126. return MathUtils.centerAlongCircle(outerRadius, outerRadius, labelWidth, labelHeight,
  127. MathUtils.degToRadOffset(labelAngleFromIndex(index)),
  128. outerRadius - control.labelInset)
  129. }
  130. function minorTickmarkAngleFromIndex(minorTickmarkIndex) {
  131. var baseAngle = tickmarkAngleFromIndex(Math.floor(minorTickmarkIndex / control.minorTickmarkCount));
  132. // + minorTickmarkSectionSize because we don't want the first minor tickmark to start on top of its "parent" tickmark.
  133. var relativeMinorAngle = (minorTickmarkIndex % control.minorTickmarkCount * minorTickmarkSectionSize) + minorTickmarkSectionSize;
  134. return baseAngle + relativeMinorAngle;
  135. }
  136. function tickmarkValueFromIndex(majorIndex) {
  137. return (majorIndex * tickmarkSectionValue) + control.minimumValue;
  138. }
  139. function tickmarkValueFromMinorIndex(minorIndex) {
  140. var majorIndex = Math.floor(minorIndex / control.minorTickmarkCount);
  141. var relativeMinorIndex = minorIndex % control.minorTickmarkCount;
  142. return tickmarkValueFromIndex(majorIndex) + ((relativeMinorIndex * minorTickmarkSectionValue) + minorTickmarkSectionValue);
  143. }
  144. Loader {
  145. active: control.tickmarksVisible && tickmark != null
  146. width: outerRadius * 2
  147. height: outerRadius * 2
  148. anchors.centerIn: parent
  149. sourceComponent: Repeater {
  150. id: tickmarkRepeater
  151. model: control.tickmarkCount
  152. delegate: Loader {
  153. id: tickmarkLoader
  154. objectName: "tickmark" + styleData.index
  155. x: tickmarkRepeater.width / 2
  156. y: tickmarkRepeater.height / 2
  157. transform: [
  158. Translate {
  159. y: -outerRadius + control.tickmarkInset
  160. },
  161. Rotation {
  162. angle: panelItem.tickmarkAngleFromIndex(styleData.index) - __tickmarkWidthAsAngle / 2
  163. }
  164. ]
  165. sourceComponent: tickmark
  166. property int __index: index
  167. property QtObject styleData: QtObject {
  168. readonly property alias index: tickmarkLoader.__index
  169. readonly property real value: tickmarkValueFromIndex(index)
  170. }
  171. readonly property real __tickmarkWidthAsAngle: MathUtils.radToDeg((width / (MathUtils.pi2 * outerRadius)) * MathUtils.pi2)
  172. }
  173. }
  174. }
  175. Loader {
  176. active: control.tickmarksVisible && minorTickmark != null
  177. width: outerRadius * 2
  178. height: outerRadius * 2
  179. anchors.centerIn: parent
  180. sourceComponent: Repeater {
  181. id: minorRepeater
  182. anchors.fill: parent
  183. model: totalMinorTickmarkCount
  184. delegate: Loader {
  185. id: minorTickmarkLoader
  186. objectName: "minorTickmark" + styleData.index
  187. x: minorRepeater.width / 2
  188. y: minorRepeater.height / 2
  189. transform: [
  190. Translate {
  191. y: -outerRadius + control.minorTickmarkInset
  192. },
  193. Rotation {
  194. angle: panelItem.minorTickmarkAngleFromIndex(styleData.index) - __minorTickmarkWidthAsAngle / 2
  195. }
  196. ]
  197. sourceComponent: minorTickmark
  198. property int __index: index
  199. property QtObject styleData: QtObject {
  200. readonly property alias index: minorTickmarkLoader.__index
  201. readonly property real value: tickmarkValueFromMinorIndex(index)
  202. }
  203. readonly property real __minorTickmarkWidthAsAngle: MathUtils.radToDeg((width / (MathUtils.pi2 * outerRadius)) * MathUtils.pi2)
  204. }
  205. }
  206. }
  207. Loader {
  208. id: labelLoader
  209. active: control.tickmarksVisible && tickmarkLabel != null
  210. width: outerRadius * 2
  211. height: outerRadius * 2
  212. anchors.centerIn: parent
  213. sourceComponent: Item {
  214. id: labelItem
  215. width: outerRadius * 2
  216. height: outerRadius * 2
  217. anchors.centerIn: parent
  218. Connections {
  219. target: control
  220. function onMinimumValueChanged() { valueTextModel.update() }
  221. function onMaximumValueChanged() { valueTextModel.update() }
  222. function onTickmarkStepSizeChanged() { valueTextModel.update() }
  223. function onLabelStepSizeChanged() { valueTextModel.update() }
  224. }
  225. Repeater {
  226. id: labelItemRepeater
  227. Component.onCompleted: valueTextModel.update();
  228. model: ListModel {
  229. id: valueTextModel
  230. function update() {
  231. if (control.labelStepSize === 0) {
  232. return;
  233. }
  234. // Make bigger if it's too small and vice versa.
  235. // +1 because we want to show 11 values, with, for example: 0, 10, 20... 100.
  236. var difference = control.labelCount - count;
  237. if (difference > 0) {
  238. for (; difference > 0; --difference) {
  239. append({ value: 0 });
  240. }
  241. } else if (difference < 0) {
  242. for (; difference < 0; ++difference) {
  243. remove(count - 1);
  244. }
  245. }
  246. var index = 0;
  247. for (var value = control.minimumValue;
  248. value <= control.maximumValue && index < count;
  249. value += control.labelStepSize, ++index) {
  250. setProperty(index, "value", value);
  251. }
  252. }
  253. }
  254. delegate: Loader {
  255. id: tickmarkLabelDelegateLoader
  256. objectName: "labelDelegateLoader" + index
  257. sourceComponent: tickmarkLabel
  258. x: pos.x
  259. y: pos.y
  260. readonly property point pos: panelItem.labelPosFromIndex(index, width, height);
  261. readonly property int __index: index
  262. readonly property real __value: value
  263. property QtObject styleData: QtObject {
  264. readonly property var value: index != -1 ? tickmarkLabelDelegateLoader.__value : 0
  265. readonly property alias index: tickmarkLabelDelegateLoader.__index
  266. }
  267. }
  268. }
  269. }
  270. }
  271. }
  272. }