FanItem.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  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 "colors.js" as Colors
  26. Item {
  27. id: root
  28. property QtObject fan
  29. property int margin: Kirigami.Units.smallSpacing
  30. property bool showControls: true
  31. property bool editable: true
  32. readonly property QtObject systemdCom: Fancontrol.Base.hasSystemdCommunicator ? Fancontrol.Base.systemdCom : null
  33. readonly property QtObject tempModel: Fancontrol.Base.tempModel
  34. readonly property real minTemp: Fancontrol.Base.minTemp
  35. readonly property real maxTemp: Fancontrol.Base.maxTemp
  36. onMinTempChanged: {
  37. meshCanvas.requestPaint();
  38. curveCanvas.requestPaint();
  39. }
  40. onMaxTempChanged: {
  41. meshCanvas.requestPaint();
  42. curveCanvas.requestPaint();
  43. }
  44. onFanChanged: curveCanvas.requestPaint()
  45. Item {
  46. id: graph
  47. property int fontSize: MoreMath.bound(8, height / 20 + 1, 16)
  48. property int verticalScalaCount: height > Kirigami.Units.gridUnit * 30 ? 11 : 6
  49. property var horIntervals: MoreMath.intervals(root.minTemp, root.maxTemp, 10)
  50. anchors {
  51. left: parent.left
  52. right: parent.right
  53. top: parent.top
  54. bottom: root.showControls ? settingsArea.top : parent.bottom
  55. bottomMargin: root.margin
  56. }
  57. visible: graphBackground.height > 0 && graphBackground.width > 0
  58. Item {
  59. id: verticalScala
  60. anchors {
  61. top: graphBackground.top
  62. bottom: graphBackground.bottom
  63. left: parent.left
  64. }
  65. width: MoreMath.maxWidth(children) + graph.fontSize / 3
  66. Repeater {
  67. id: verticalRepeater
  68. model: graph.verticalScalaCount
  69. Text {
  70. x: verticalScala.width - implicitWidth - graph.fontSize / 3
  71. y: graphBackground.height - graphBackground.height / (graph.verticalScalaCount - 1) * index - graph.fontSize * 2 / 3
  72. horizontalAlignment: Text.AlignRight
  73. color: Kirigami.Theme.textColor
  74. text: Number(index * (100 / (graph.verticalScalaCount - 1))).toLocaleString(Qt.locale(), 'f', 0) + Qt.locale().percent
  75. font.pixelSize: graph.fontSize
  76. }
  77. }
  78. }
  79. Item {
  80. id: horizontalScala
  81. anchors {
  82. right: graphBackground.right
  83. bottom: parent.bottom
  84. left: graphBackground.left
  85. }
  86. height: graph.fontSize * 2
  87. Repeater {
  88. model: graph.horIntervals.length;
  89. Text {
  90. x: graphBackground.scaleX(graph.horIntervals[index]) - width/2
  91. y: horizontalScala.height / 2 - implicitHeight / 2
  92. color: Kirigami.Theme.textColor
  93. text: Number(graph.horIntervals[index]).toLocaleString() + i18n("°C")
  94. font.pixelSize: graph.fontSize
  95. }
  96. }
  97. }
  98. Rectangle {
  99. id: graphBackground
  100. Kirigami.Theme.colorSet: Kirigami.Theme.View
  101. color: Kirigami.Theme.backgroundColor
  102. border.color: Kirigami.Theme.textColor
  103. border.width: 2
  104. anchors {
  105. top: parent.top
  106. left: verticalScala.right
  107. bottom: horizontalScala.top
  108. right: parent.right
  109. topMargin: parent.fontSize
  110. rightMargin: parent.fontSize * 2
  111. }
  112. function scaleX(temp) {
  113. return (temp - minTemp) * width / (maxTemp - minTemp);
  114. }
  115. function scaleY(pwm) {
  116. return height - pwm * height / 255;
  117. }
  118. function scaleTemp(x) {
  119. return x / width * (maxTemp - minTemp) + minTemp;
  120. }
  121. function scalePwm(y) {
  122. return 255 - y / height * 255;
  123. }
  124. Canvas {
  125. id: curveCanvas
  126. anchors.fill: parent
  127. anchors.margins: parent.border.width
  128. renderStrategy: Canvas.Threaded
  129. // renderTarget: Canvas.FramebufferObject
  130. onPaint: {
  131. var c = curveCanvas.getContext("2d");
  132. c.clearRect(0, 0, width, height);
  133. if (!fan || !fan.hasTemp) {
  134. return;
  135. }
  136. var gradient = c.createLinearGradient(0, 0, width, 0);
  137. gradient.addColorStop(0, "rgb(0, 0, 255)");
  138. gradient.addColorStop(1, "rgb(255, 0, 0)");
  139. c.fillStyle = gradient;
  140. c.lineWidth = graph.fontSize / 3;
  141. c.strokeStyle = gradient;
  142. c.lineJoin = "round";
  143. c.beginPath();
  144. if (fan.minPwm == 0) {
  145. c.moveTo(stopPoint.centerX, height);
  146. } else {
  147. c.moveTo(0, stopPoint.centerY);
  148. c.lineTo(stopPoint.centerX, stopPoint.centerY);
  149. }
  150. c.lineTo(stopPoint.centerX, stopPoint.centerY);
  151. c.lineTo(maxPoint.centerX, maxPoint.centerY);
  152. c.lineTo(width, maxPoint.centerY);
  153. c.stroke();
  154. c.lineTo(width, height);
  155. if (fan.minPwm == 0) {
  156. c.lineTo(stopPoint.centerX, height);
  157. } else {
  158. c.lineTo(0, height);
  159. }
  160. c.fill();
  161. //blend graphBackground
  162. gradient = c.createLinearGradient(0, 0, 0, height);
  163. gradient.addColorStop(0, Colors.setAlpha(graphBackground.color, 0.5));
  164. gradient.addColorStop(1, Colors.setAlpha(graphBackground.color, 0.9));
  165. c.fillStyle = gradient;
  166. c.fill();
  167. }
  168. Connections {
  169. target: fan
  170. onTempChanged: curveCanvas.requestPaint()
  171. onMinPwmChanged: curveCanvas.markDirty(Qt.rect(0, 0, stopPoint.x, stopPoint.y))
  172. }
  173. }
  174. Canvas {
  175. id: meshCanvas
  176. anchors.fill: parent
  177. anchors.margins: parent.border.width
  178. renderStrategy: Canvas.Threaded
  179. // renderTarget: Canvas.FramebufferObject
  180. onPaint: {
  181. var c = meshCanvas.getContext("2d");
  182. c.clearRect(0, 0, width, height);
  183. //draw mesh
  184. c.beginPath();
  185. c.strokeStyle = Colors.setAlpha(Kirigami.Theme.textColor, 0.3);
  186. //horizontal lines
  187. for (var i=0; i<=100; i+=100/(graph.verticalScalaCount-1)) {
  188. var y = graphBackground.scaleY(i*2.55);
  189. if (i != 0 && i != 100) {
  190. for (var j=0; j<=width; j+=15) {
  191. c.moveTo(j, y);
  192. c.lineTo(Math.min(j+5, width), y);
  193. }
  194. }
  195. }
  196. //vertical lines
  197. if (graph.horIntervals.length > 1) {
  198. for (var i=1; i<graph.horIntervals.length; i++) {
  199. var x = graphBackground.scaleX(graph.horIntervals[i]);
  200. for (var j=0; j<=height; j+=20) {
  201. c.moveTo(x, j);
  202. c.lineTo(x, Math.min(j+5, height));
  203. }
  204. }
  205. }
  206. c.stroke();
  207. }
  208. }
  209. StatusPoint {
  210. id: currentPwm
  211. size: graph.fontSize
  212. visible: graphBackground.contains(center) && !!fan && fan.hasTemp
  213. fan: root.fan
  214. }
  215. PwmPoint {
  216. id: stopPoint
  217. color: !!fan ? fan.hasTemp ? "blue" : Qt.tint(Kirigami.Theme.disabledTextColor, Qt.rgba(0, 0, 1, 0.5)) : "transparent"
  218. size: graph.fontSize
  219. visible: !!fan ? fan.hasTemp : false
  220. draggable: root.editable
  221. maximumX: Math.min(graphBackground.scaleX(graphBackground.scaleTemp(maxPoint.x)-1), maxPoint.x-1)
  222. minimumY: Math.max(graphBackground.scaleY(graphBackground.scalePwm(maxPoint.y)-1), maxPoint.y+1)
  223. x: !!fan && fan.hasTemp ? graphBackground.scaleX(MoreMath.bound(root.minTemp, fan.minTemp, root.maxTemp)) - width/2 : -width/2
  224. y: !!fan && fan.hasTemp ? graphBackground.scaleY(fan.minStop) - height/2 : -height/2
  225. onDragFinished: {
  226. fan.minStop = Math.round(graphBackground.scalePwm(centerY));
  227. fan.minTemp = Math.round(graphBackground.scaleTemp(centerX));
  228. if (fan.minPwm !== 0) fan.minPwm = fan.minStop;
  229. }
  230. onPositionChanged: {
  231. var left = fan.minPwm === 0 ? x : 0;
  232. var width = maxPoint.x - left;
  233. var height = y - maxPoint.y;
  234. curveCanvas.markDirty(Qt.rect(left, maxPoint.y, width, height));
  235. }
  236. }
  237. PwmPoint {
  238. id: maxPoint
  239. color: !!fan ? fan.hasTemp ? "red" : Qt.tint(Kirigami.Theme.disabledTextColor, Qt.rgba(1, 0, 0, 0.5)) : "transparent"
  240. size: graph.fontSize
  241. visible: !!fan ? fan.hasTemp : false
  242. draggable: root.editable
  243. minimumX: Math.max(graphBackground.scaleX(graphBackground.scaleTemp(stopPoint.x)+1), stopPoint.x+1)
  244. maximumY: Math.min(graphBackground.scaleY(graphBackground.scalePwm(stopPoint.y)+1), stopPoint.y-1)
  245. x: !!fan && fan.hasTemp ? graphBackground.scaleX(MoreMath.bound(root.minTemp, fan.maxTemp, root.maxTemp)) - width/2 : graphBackground.width - width/2
  246. y: !!fan && fan.hasTemp ? graphBackground.scaleY(fan.maxPwm) - height/2 : -height/2
  247. onDragFinished: {
  248. fan.maxPwm = Math.round(graphBackground.scalePwm(centerY));
  249. fan.maxTemp = Math.round(graphBackground.scaleTemp(centerX));
  250. }
  251. onPositionChanged: {
  252. var width = x - stopPoint.x;
  253. var height = stopPoint.y - y;
  254. curveCanvas.markDirty(Qt.rect(stopPoint.x, y, width, height));
  255. }
  256. }
  257. }
  258. }
  259. FanControls {
  260. id: settingsArea
  261. fan: root.fan
  262. padding: root.margin
  263. anchors {
  264. left: parent.left
  265. leftMargin: padding
  266. right: parent.right
  267. rightMargin: padding
  268. bottom: parent.bottom
  269. bottomMargin: padding
  270. }
  271. visible: root.showControls && root.height >= height + 2*margin
  272. }
  273. }