FanItem.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. /*
  2. * Copyright (C) 2015 Malte Veerman <malte.veerman@gmail.com>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU Lesser General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. *
  18. */
  19. import QtQuick 2.6
  20. import QtQuick.Controls 2.1
  21. import QtQuick.Layouts 1.2
  22. import org.kde.kirigami 2.3 as Kirigami
  23. import Fancontrol.Qml 1.0 as Fancontrol
  24. import "math.js" as MoreMath
  25. import "units.js" as Units
  26. import "colors.js" as Colors
  27. Item {
  28. id: root
  29. property QtObject fan
  30. property int margin: Kirigami.Units.smallSpacing
  31. property bool showControls: true
  32. property bool editable: true
  33. readonly property QtObject systemdCom: Fancontrol.Base.hasSystemdCommunicator ? Fancontrol.Base.systemdCom : null
  34. readonly property QtObject tempModel: Fancontrol.Base.tempModel
  35. readonly property real minTemp: Fancontrol.Base.minTemp
  36. readonly property real maxTemp: Fancontrol.Base.maxTemp
  37. readonly property string unit: Fancontrol.Base.unit
  38. readonly property real convertedMinTemp: Units.fromCelsius(minTemp, unit)
  39. readonly property real convertedMaxTemp: Units.fromCelsius(maxTemp, unit)
  40. onConvertedMinTempChanged: {
  41. meshCanvas.requestPaint();
  42. curveCanvas.requestPaint();
  43. }
  44. onConvertedMaxTempChanged: {
  45. meshCanvas.requestPaint();
  46. curveCanvas.requestPaint();
  47. }
  48. onFanChanged: curveCanvas.requestPaint()
  49. Item {
  50. id: graph
  51. property int fontSize: MoreMath.bound(8, height / 20 + 1, 16)
  52. property int verticalScalaCount: height > Kirigami.Units.gridUnit * 30 ? 11 : 6
  53. property var horIntervals: MoreMath.intervals(root.convertedMinTemp, root.convertedMaxTemp, 10)
  54. anchors {
  55. left: parent.left
  56. right: parent.right
  57. top: parent.top
  58. bottom: root.showControls ? settingsArea.top : parent.bottom
  59. bottomMargin: root.margin
  60. }
  61. visible: graphBackground.height > 0 && graphBackground.width > 0
  62. Item {
  63. id: verticalScala
  64. anchors {
  65. top: graphBackground.top
  66. bottom: graphBackground.bottom
  67. left: parent.left
  68. }
  69. width: MoreMath.maxWidth(children) + graph.fontSize / 3
  70. Repeater {
  71. id: verticalRepeater
  72. model: graph.verticalScalaCount
  73. Text {
  74. x: verticalScala.width - implicitWidth - graph.fontSize / 3
  75. y: graphBackground.height - graphBackground.height / (graph.verticalScalaCount - 1) * index - graph.fontSize * 2 / 3
  76. horizontalAlignment: Text.AlignRight
  77. color: Kirigami.Theme.textColor
  78. text: Number(index * (100 / (graph.verticalScalaCount - 1))).toLocaleString(Qt.locale(), 'f', 0) + Qt.locale().percent
  79. font.pixelSize: graph.fontSize
  80. }
  81. }
  82. }
  83. Item {
  84. id: horizontalScala
  85. anchors {
  86. right: graphBackground.right
  87. bottom: parent.bottom
  88. left: graphBackground.left
  89. }
  90. height: graph.fontSize * 2
  91. Repeater {
  92. model: graph.horIntervals.length;
  93. Text {
  94. x: graphBackground.scaleX(Units.toCelsius(graph.horIntervals[index], unit)) - width/2
  95. y: horizontalScala.height / 2 - implicitHeight / 2
  96. color: Kirigami.Theme.textColor
  97. text: Number(graph.horIntervals[index]).toLocaleString() + i18n(unit)
  98. font.pixelSize: graph.fontSize
  99. }
  100. }
  101. }
  102. Rectangle {
  103. id: graphBackground
  104. color: Kirigami.Theme.backgroundColor
  105. border.color: Kirigami.Theme.textColor
  106. border.width: 2
  107. anchors {
  108. top: parent.top
  109. left: verticalScala.right
  110. bottom: horizontalScala.top
  111. right: parent.right
  112. topMargin: parent.fontSize
  113. rightMargin: parent.fontSize * 2
  114. }
  115. function scaleX(temp) {
  116. return (temp - minTemp) * width / (maxTemp - minTemp);
  117. }
  118. function scaleY(pwm) {
  119. return height - pwm * height / 255;
  120. }
  121. function scaleTemp(x) {
  122. return x / width * (maxTemp - minTemp) + minTemp;
  123. }
  124. function scalePwm(y) {
  125. return 255 - y / height * 255;
  126. }
  127. Canvas {
  128. id: curveCanvas
  129. anchors.fill: parent
  130. anchors.margins: parent.border.width
  131. renderStrategy: Canvas.Threaded
  132. renderTarget: Canvas.FramebufferObject
  133. onPaint: {
  134. var c = curveCanvas.getContext("2d");
  135. c.clearRect(0, 0, width, height);
  136. if (!fan || !fan.hasTemp) {
  137. return;
  138. }
  139. var gradient = c.createLinearGradient(0, 0, width, 0);
  140. gradient.addColorStop(0, "rgb(0, 0, 255)");
  141. gradient.addColorStop(1, "rgb(255, 0, 0)");
  142. c.fillStyle = gradient;
  143. c.lineWidth = graph.fontSize / 3;
  144. c.strokeStyle = gradient;
  145. c.lineJoin = "round";
  146. c.beginPath();
  147. if (fan.minPwm == 0) {
  148. c.moveTo(stopPoint.centerX, height);
  149. } else {
  150. c.moveTo(0, stopPoint.centerY);
  151. c.lineTo(stopPoint.centerX, stopPoint.centerY);
  152. }
  153. c.lineTo(stopPoint.centerX, stopPoint.centerY);
  154. c.lineTo(maxPoint.centerX, maxPoint.centerY);
  155. c.lineTo(width, maxPoint.centerY);
  156. c.stroke();
  157. c.lineTo(width, height);
  158. if (fan.minPwm == 0) {
  159. c.lineTo(stopPoint.centerX, height);
  160. } else {
  161. c.lineTo(0, height);
  162. }
  163. c.fill();
  164. //blend graphBackground
  165. gradient = c.createLinearGradient(0, 0, 0, height);
  166. gradient.addColorStop(0, Colors.setAlpha(graphBackground.color, 0.5));
  167. gradient.addColorStop(1, Colors.setAlpha(graphBackground.color, 0.9));
  168. c.fillStyle = gradient;
  169. c.fill();
  170. }
  171. Connections {
  172. target: fan
  173. onTempChanged: curveCanvas.requestPaint()
  174. onMinPwmChanged: curveCanvas.markDirty(Qt.rect(0, 0, stopPoint.x, stopPoint.y))
  175. }
  176. }
  177. Canvas {
  178. id: meshCanvas
  179. anchors.fill: parent
  180. anchors.margins: parent.border.width
  181. renderStrategy: Canvas.Threaded
  182. renderTarget: Canvas.FramebufferObject
  183. onPaint: {
  184. var c = meshCanvas.getContext("2d");
  185. c.clearRect(0, 0, width, height);
  186. //draw mesh
  187. c.beginPath();
  188. c.strokeStyle = Colors.setAlpha(Kirigami.Theme.textColor, 0.3);
  189. //horizontal lines
  190. for (var i=0; i<=100; i+=100/(graph.verticalScalaCount-1)) {
  191. var y = graphBackground.scaleY(i*2.55);
  192. if (i != 0 && i != 100) {
  193. for (var j=0; j<=width; j+=15) {
  194. c.moveTo(j, y);
  195. c.lineTo(Math.min(j+5, width), y);
  196. }
  197. }
  198. }
  199. //vertical lines
  200. if (graph.horIntervals.length > 1) {
  201. for (var i=1; i<graph.horIntervals.length; i++) {
  202. var x = graphBackground.scaleX(Units.toCelsius(graph.horIntervals[i], unit));
  203. for (var j=0; j<=height; j+=20) {
  204. c.moveTo(x, j);
  205. c.lineTo(x, Math.min(j+5, height));
  206. }
  207. }
  208. }
  209. c.stroke();
  210. }
  211. }
  212. StatusPoint {
  213. id: currentPwm
  214. size: graph.fontSize
  215. visible: graphBackground.contains(center) && !!fan && fan.hasTemp
  216. fan: root.fan
  217. }
  218. PwmPoint {
  219. id: stopPoint
  220. color: !!fan ? fan.hasTemp ? "blue" : Qt.tint(Kirigami.Theme.disabledTextColor, Qt.rgba(0, 0, 1, 0.5)) : "transparent"
  221. size: graph.fontSize
  222. visible: !!fan ? fan.hasTemp : false
  223. draggable: root.editable
  224. maximumX: Math.min(graphBackground.scaleX(graphBackground.scaleTemp(maxPoint.x)-1), maxPoint.x-1)
  225. minimumY: Math.max(graphBackground.scaleY(graphBackground.scalePwm(maxPoint.y)-1), maxPoint.y+1)
  226. x: !!fan && fan.hasTemp ? graphBackground.scaleX(MoreMath.bound(root.minTemp, fan.minTemp, root.maxTemp)) - width/2 : -width/2
  227. y: !!fan && fan.hasTemp ? graphBackground.scaleY(fan.minStop) - height/2 : -height/2
  228. onDragFinished: {
  229. fan.minStop = Math.round(graphBackground.scalePwm(centerY));
  230. fan.minTemp = Math.round(graphBackground.scaleTemp(centerX));
  231. if (fan.minPwm !== 0) fan.minPwm = fan.minStop;
  232. }
  233. onPositionChanged: {
  234. var left = fan.minPwm === 0 ? x : 0;
  235. var width = maxPoint.x - left;
  236. var height = y - maxPoint.y;
  237. curveCanvas.markDirty(Qt.rect(left, maxPoint.y, width, height));
  238. }
  239. }
  240. PwmPoint {
  241. id: maxPoint
  242. color: !!fan ? fan.hasTemp ? "red" : Qt.tint(Kirigami.Theme.disabledTextColor, Qt.rgba(1, 0, 0, 0.5)) : "transparent"
  243. size: graph.fontSize
  244. visible: !!fan ? fan.hasTemp : false
  245. draggable: root.editable
  246. minimumX: Math.max(graphBackground.scaleX(graphBackground.scaleTemp(stopPoint.x)+1), stopPoint.x+1)
  247. maximumY: Math.min(graphBackground.scaleY(graphBackground.scalePwm(stopPoint.y)+1), stopPoint.y-1)
  248. x: !!fan && fan.hasTemp ? graphBackground.scaleX(MoreMath.bound(root.minTemp, fan.maxTemp, root.maxTemp)) - width/2 : graphBackground.width - width/2
  249. y: !!fan && fan.hasTemp ? graphBackground.scaleY(fan.maxPwm) - height/2 : -height/2
  250. onDragFinished: {
  251. fan.maxPwm = Math.round(graphBackground.scalePwm(centerY));
  252. fan.maxTemp = Math.round(graphBackground.scaleTemp(centerX));
  253. }
  254. onPositionChanged: {
  255. var width = x - stopPoint.x;
  256. var height = stopPoint.y - y;
  257. curveCanvas.markDirty(Qt.rect(stopPoint.x, y, width, height));
  258. }
  259. }
  260. }
  261. }
  262. FanControls {
  263. id: settingsArea
  264. fan: root.fan
  265. padding: root.margin
  266. anchors {
  267. left: parent.left
  268. leftMargin: padding
  269. right: parent.right
  270. rightMargin: padding
  271. bottom: parent.bottom
  272. bottomMargin: padding
  273. }
  274. visible: root.showControls && root.height >= height + 2*margin
  275. }
  276. }