FanItem.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  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. radius: 1
  108. anchors {
  109. top: parent.top
  110. left: verticalScala.right
  111. bottom: horizontalScala.top
  112. right: parent.right
  113. topMargin: parent.fontSize
  114. bottomMargin: 0
  115. rightMargin: parent.fontSize * 2
  116. leftMargin: 0
  117. }
  118. function scaleX(temp) {
  119. return (temp - minTemp) * width / (maxTemp - minTemp);
  120. }
  121. function scaleY(pwm) {
  122. return height - pwm * height / 255;
  123. }
  124. function scaleTemp(x) {
  125. return x / width * (maxTemp - minTemp) + minTemp;
  126. }
  127. function scalePwm(y) {
  128. return 255 - y / height * 255;
  129. }
  130. Canvas {
  131. id: curveCanvas
  132. anchors.fill: parent
  133. anchors.margins: parent.border.width
  134. renderStrategy: Canvas.Threaded
  135. renderTarget: Canvas.FramebufferObject
  136. onPaint: {
  137. var c = curveCanvas.getContext("2d");
  138. c.clearRect(0, 0, width, height);
  139. if (!fan || !fan.hasTemp) {
  140. return;
  141. }
  142. var gradient = c.createLinearGradient(0, 0, width, 0);
  143. gradient.addColorStop(0, "rgb(0, 0, 255)");
  144. gradient.addColorStop(1, "rgb(255, 0, 0)");
  145. c.fillStyle = gradient;
  146. c.lineWidth = graph.fontSize / 3;
  147. c.strokeStyle = gradient;
  148. c.lineJoin = "round";
  149. c.beginPath();
  150. if (fan.minPwm == 0) {
  151. c.moveTo(stopPoint.centerX, height);
  152. } else {
  153. c.moveTo(0, stopPoint.centerY);
  154. c.lineTo(stopPoint.centerX, stopPoint.centerY);
  155. }
  156. c.lineTo(stopPoint.centerX, stopPoint.centerY);
  157. c.lineTo(maxPoint.centerX, maxPoint.centerY);
  158. c.lineTo(width, maxPoint.centerY);
  159. c.stroke();
  160. c.lineTo(width, height);
  161. if (fan.minPwm == 0) {
  162. c.lineTo(stopPoint.centerX, height);
  163. } else {
  164. c.lineTo(0, height);
  165. }
  166. c.fill();
  167. //blend graphBackground
  168. gradient = c.createLinearGradient(0, 0, 0, height);
  169. gradient.addColorStop(0, Colors.setAlpha(graphBackground.color, 0.5));
  170. gradient.addColorStop(1, Colors.setAlpha(graphBackground.color, 0.9));
  171. c.fillStyle = gradient;
  172. c.fill();
  173. }
  174. Connections {
  175. target: fan
  176. onTempChanged: curveCanvas.requestPaint()
  177. onMinPwmChanged: curveCanvas.markDirty(Qt.rect(0, 0, stopPoint.x, stopPoint.y))
  178. }
  179. }
  180. Canvas {
  181. id: meshCanvas
  182. anchors.fill: parent
  183. anchors.margins: parent.border.width
  184. renderStrategy: Canvas.Threaded
  185. renderTarget: Canvas.FramebufferObject
  186. onPaint: {
  187. var c = meshCanvas.getContext("2d");
  188. c.clearRect(0, 0, width, height);
  189. //draw mesh
  190. c.beginPath();
  191. c.strokeStyle = Colors.setAlpha(Kirigami.Theme.textColor, 0.3);
  192. //horizontal lines
  193. for (var i=0; i<=100; i+=100/(graph.verticalScalaCount-1)) {
  194. var y = graphBackground.scaleY(i*2.55);
  195. if (i != 0 && i != 100) {
  196. for (var j=0; j<=width; j+=15) {
  197. c.moveTo(j, y);
  198. c.lineTo(Math.min(j+5, width), y);
  199. }
  200. }
  201. }
  202. //vertical lines
  203. if (graph.horIntervals.length > 1) {
  204. for (var i=1; i<graph.horIntervals.length; i++) {
  205. var x = graphBackground.scaleX(Units.toCelsius(graph.horIntervals[i], unit));
  206. for (var j=0; j<=height; j+=20) {
  207. c.moveTo(x, j);
  208. c.lineTo(x, Math.min(j+5, height));
  209. }
  210. }
  211. }
  212. c.stroke();
  213. }
  214. }
  215. StatusPoint {
  216. id: currentPwm
  217. size: graph.fontSize
  218. visible: graphBackground.contains(center) && !!fan && fan.hasTemp
  219. fan: root.fan
  220. }
  221. PwmPoint {
  222. id: stopPoint
  223. color: !!fan ? fan.hasTemp ? "blue" : Qt.tint(Kirigami.Theme.disabledTextColor, Qt.rgba(0, 0, 1, 0.5)) : "transparent"
  224. size: graph.fontSize
  225. visible: !!fan ? fan.hasTemp : false
  226. draggable: root.editable
  227. maximumX: Math.min(graphBackground.scaleX(graphBackground.scaleTemp(maxPoint.x)-1), maxPoint.x-1)
  228. minimumY: Math.max(graphBackground.scaleY(graphBackground.scalePwm(maxPoint.y)-1), maxPoint.y+1)
  229. x: !!fan && fan.hasTemp ? graphBackground.scaleX(MoreMath.bound(root.minTemp, fan.minTemp, root.maxTemp)) - width/2 : -width/2
  230. y: !!fan && fan.hasTemp ? graphBackground.scaleY(fan.minStop) - height/2 : -height/2
  231. onDragFinished: {
  232. fan.minStop = Math.round(graphBackground.scalePwm(centerY));
  233. fan.minTemp = Math.round(graphBackground.scaleTemp(centerX));
  234. if (fan.minPwm !== 0) fan.minPwm = fan.minStop;
  235. }
  236. onPositionChanged: {
  237. var left = fan.minPwm === 0 ? x : 0;
  238. var width = maxPoint.x - left;
  239. var height = y - maxPoint.y;
  240. curveCanvas.markDirty(Qt.rect(left, maxPoint.y, width, height));
  241. }
  242. }
  243. PwmPoint {
  244. id: maxPoint
  245. color: !!fan ? fan.hasTemp ? "red" : Qt.tint(Kirigami.Theme.disabledTextColor, Qt.rgba(1, 0, 0, 0.5)) : "transparent"
  246. size: graph.fontSize
  247. visible: !!fan ? fan.hasTemp : false
  248. draggable: root.editable
  249. minimumX: Math.max(graphBackground.scaleX(graphBackground.scaleTemp(stopPoint.x)+1), stopPoint.x+1)
  250. maximumY: Math.min(graphBackground.scaleY(graphBackground.scalePwm(stopPoint.y)+1), stopPoint.y-1)
  251. x: !!fan && fan.hasTemp ? graphBackground.scaleX(MoreMath.bound(root.minTemp, fan.maxTemp, root.maxTemp)) - width/2 : graphBackground.width - width/2
  252. y: !!fan && fan.hasTemp ? graphBackground.scaleY(fan.maxPwm) - height/2 : -height/2
  253. onDragFinished: {
  254. fan.maxPwm = Math.round(graphBackground.scalePwm(centerY));
  255. fan.maxTemp = Math.round(graphBackground.scaleTemp(centerX));
  256. }
  257. onPositionChanged: {
  258. var width = x - stopPoint.x;
  259. var height = stopPoint.y - y;
  260. curveCanvas.markDirty(Qt.rect(stopPoint.x, y, width, height));
  261. }
  262. }
  263. }
  264. }
  265. FanControls {
  266. id: settingsArea
  267. fan: root.fan
  268. padding: root.margin
  269. anchors {
  270. left: parent.left
  271. leftMargin: padding
  272. right: parent.right
  273. rightMargin: padding
  274. bottom: parent.bottom
  275. bottomMargin: padding
  276. }
  277. visible: root.showControls && root.height >= height + 2*margin
  278. }
  279. }