2016-01-03 19:32:36 +03:00
|
|
|
|
/* Copyright 2016 (C) Louis-Joseph Fournier
|
|
|
|
|
* louisjoseph.fournier@gmail.com
|
|
|
|
|
*
|
|
|
|
|
* This file is part of SailTuner.
|
|
|
|
|
*
|
|
|
|
|
* SailTuner is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* SailTuner is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
|
2015-12-27 14:01:07 +03:00
|
|
|
|
import QtQuick 2.0
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Meter in half circle
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Item {
|
|
|
|
|
/// current level
|
2015-12-27 14:22:24 +03:00
|
|
|
|
property double level: 0.5
|
2015-12-27 14:01:07 +03:00
|
|
|
|
/// minimum level
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property double min: -50
|
2015-12-27 14:01:07 +03:00
|
|
|
|
/// maximum level
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property double max: 50
|
2015-12-30 00:47:54 +03:00
|
|
|
|
/// numbers to write on the scale
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property variant marks: [-40, -20, 0, 20, 40]
|
2016-01-01 12:39:17 +03:00
|
|
|
|
/// interval of little marks
|
|
|
|
|
property double submarks_int: 5
|
2015-12-31 19:12:54 +03:00
|
|
|
|
/// marks regions colors
|
2016-01-01 12:22:06 +03:00
|
|
|
|
property variant region_color: ["#F88E48", "#F8DE48", "#99E882", "#F8DE48", "#F88E48"]
|
2015-12-27 14:01:07 +03:00
|
|
|
|
/// theme object
|
|
|
|
|
property QtObject theme
|
|
|
|
|
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property double r_circle_min: 0.85
|
|
|
|
|
property double r_circle_max: 1
|
|
|
|
|
|
2016-01-01 13:35:28 +03:00
|
|
|
|
property double r_arrow_base: 0.05
|
2016-01-01 17:50:20 +03:00
|
|
|
|
property double _height: width / 2
|
2016-01-01 12:39:17 +03:00
|
|
|
|
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property double amin: angle(min)
|
|
|
|
|
property double amax: angle(max)
|
|
|
|
|
|
2015-12-30 00:47:54 +03:00
|
|
|
|
/// positions helper functions
|
|
|
|
|
function angle(level) {
|
|
|
|
|
return (level - min) / (max - min) * Math.PI - Math.PI / 2
|
|
|
|
|
}
|
|
|
|
|
function getx(angle, k) {
|
|
|
|
|
return width * 0.5 + width * 0.5 * k * Math.sin(angle)
|
|
|
|
|
}
|
|
|
|
|
function gety(angle, k) {
|
|
|
|
|
// k: [0,1]
|
2016-01-01 17:50:20 +03:00
|
|
|
|
return _height - _height * k * Math.cos(angle)
|
2015-12-30 00:47:54 +03:00
|
|
|
|
}
|
2016-01-01 13:35:28 +03:00
|
|
|
|
function dist(x1, y1, x2, y2) {
|
|
|
|
|
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
|
|
|
|
|
}
|
2015-12-30 00:47:54 +03:00
|
|
|
|
|
2016-01-01 17:50:20 +03:00
|
|
|
|
// return the 2 orthoganals points from b with ref a, with dist d from b
|
|
|
|
|
function orth(ax, ay, bx, by, d) {
|
|
|
|
|
var D = dist(ax, ay, bx, by)
|
|
|
|
|
var k = d / D
|
|
|
|
|
var kx = k * (bx - ax);
|
|
|
|
|
var ky = k * (by - ay);
|
|
|
|
|
return [
|
|
|
|
|
bx + ky, by - kx,
|
|
|
|
|
bx - ky, by + kx
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-31 19:12:54 +03:00
|
|
|
|
/// objects draw
|
|
|
|
|
|
|
|
|
|
function arc(ctx, k) {
|
|
|
|
|
ctx.beginPath()
|
2016-01-02 02:11:25 +03:00
|
|
|
|
ctx.arc(width/2, height + 1, k * width / 2, 0, Math.PI, 1)
|
2015-12-31 19:12:54 +03:00
|
|
|
|
ctx.stroke()
|
2016-01-02 02:11:25 +03:00
|
|
|
|
return
|
2015-12-31 19:12:54 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function line_mark(ctx, value, r_min, r_max) {
|
|
|
|
|
var a = angle(value)
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(getx(a, r_min), gety(a, r_min))
|
|
|
|
|
ctx.lineTo(getx(a, r_max), gety(a, r_max))
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-27 14:22:24 +03:00
|
|
|
|
/// Ellipse
|
2015-12-27 14:01:07 +03:00
|
|
|
|
Canvas {
|
2015-12-27 14:22:24 +03:00
|
|
|
|
id: ellipse
|
2015-12-27 14:01:07 +03:00
|
|
|
|
anchors.fill: parent
|
2015-12-30 00:47:54 +03:00
|
|
|
|
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property double r_text: 0.92
|
|
|
|
|
|
|
|
|
|
property double l_marker: 0.035
|
2016-01-01 12:39:17 +03:00
|
|
|
|
property double h_marker: 6
|
|
|
|
|
|
|
|
|
|
property double l_submarker: 0.020
|
|
|
|
|
property double h_submarker: 2
|
|
|
|
|
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property int font_size: 20
|
2015-12-30 00:47:54 +03:00
|
|
|
|
|
2015-12-27 14:01:07 +03:00
|
|
|
|
onPaint: {
|
2015-12-27 14:22:24 +03:00
|
|
|
|
var ctx = getContext('2d');
|
2015-12-27 14:01:07 +03:00
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
ctx.lineWidth = 1
|
2015-12-31 19:12:54 +03:00
|
|
|
|
|
|
|
|
|
arc(ctx, r_circle_min)
|
|
|
|
|
arc(ctx, r_circle_max)
|
|
|
|
|
|
2015-12-30 00:47:54 +03:00
|
|
|
|
ctx.font = font_size + "px sans-serif"
|
|
|
|
|
ctx.textAlign = "center"
|
2016-01-01 12:39:17 +03:00
|
|
|
|
//ctx.fillStyle = theme.secondaryColor
|
2015-12-30 00:47:54 +03:00
|
|
|
|
|
2016-01-01 13:35:28 +03:00
|
|
|
|
// first sub marks
|
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
ctx.lineWidth = h_submarker
|
|
|
|
|
for (var j = marks[0] - submarks_int; j > min; j -= submarks_int) {
|
|
|
|
|
line_mark(ctx, j, r_circle_min - l_submarker, r_circle_min + l_submarker)
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-01 21:20:29 +03:00
|
|
|
|
ctx.fillStyle = theme.primaryColor
|
2015-12-30 00:47:54 +03:00
|
|
|
|
for (var i = 0; i < marks.length; i++) {
|
2016-01-01 12:39:17 +03:00
|
|
|
|
ctx.strokeStyle = theme.secondaryColor
|
|
|
|
|
ctx.lineWidth = h_marker
|
2015-12-31 19:12:54 +03:00
|
|
|
|
line_mark(ctx, marks[i], r_circle_min - l_marker, r_circle_min + l_marker)
|
2015-12-30 00:47:54 +03:00
|
|
|
|
var a = angle(marks[i])
|
2015-12-31 19:12:54 +03:00
|
|
|
|
ctx.fillText(marks[i], getx(a, r_text), gety(a, r_text) + 4)
|
2015-12-30 00:47:54 +03:00
|
|
|
|
ctx.strokeText()
|
2016-01-01 12:39:17 +03:00
|
|
|
|
// sub marks
|
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
ctx.lineWidth = h_submarker
|
|
|
|
|
var j_max = (i == marks.length - 1 ? max : marks[i+1])
|
|
|
|
|
for (var j = marks[i] + submarks_int; j < j_max; j += submarks_int) {
|
|
|
|
|
line_mark(ctx, j, r_circle_min - l_submarker, r_circle_min + l_submarker)
|
|
|
|
|
}
|
2015-12-30 00:47:54 +03:00
|
|
|
|
}
|
2015-12-31 19:12:54 +03:00
|
|
|
|
|
|
|
|
|
// "beetween" marks
|
|
|
|
|
ctx.lineWidth = 1
|
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
for (var i = 0; i < marks.length - 1; i++) {
|
|
|
|
|
line_mark(ctx, (marks[i] + marks[i+1])/2, r_circle_min, r_circle_max)
|
|
|
|
|
}
|
2016-01-01 12:39:17 +03:00
|
|
|
|
|
|
|
|
|
// center: arrow base
|
|
|
|
|
ctx.lineWidth = 1
|
|
|
|
|
ctx.strokeStyle = theme.secondaryColor
|
|
|
|
|
arc(ctx, r_arrow_base)
|
2016-01-01 17:50:20 +03:00
|
|
|
|
|
|
|
|
|
// bottom line
|
|
|
|
|
ctx.lineWidth = 1
|
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(0, _height - 1)
|
|
|
|
|
ctx.lineTo(width - 1, _height - 1)
|
|
|
|
|
ctx.stroke()
|
2015-12-27 14:22:24 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Canvas {
|
|
|
|
|
/// level arrow
|
|
|
|
|
id: arrow
|
|
|
|
|
anchors.fill: parent
|
2015-12-31 19:12:54 +03:00
|
|
|
|
property double k: 0.82
|
2015-12-30 00:47:54 +03:00
|
|
|
|
property double angle: parent.angle(level)
|
2015-12-27 14:22:24 +03:00
|
|
|
|
|
2016-01-01 17:50:20 +03:00
|
|
|
|
property double r_base: 0.055
|
|
|
|
|
property double r_circle_base: r_arrow_base * 0.6
|
2016-01-01 13:35:28 +03:00
|
|
|
|
property double k_head: 0.1 // arrow width factor of base
|
2016-01-01 17:50:20 +03:00
|
|
|
|
property double lref: width / 2
|
2016-01-01 13:35:28 +03:00
|
|
|
|
|
2016-01-02 02:11:25 +03:00
|
|
|
|
property bool is_line: false // simple line (true) or designed (false)
|
|
|
|
|
property bool has_gradient: false // beautiful gradient
|
|
|
|
|
|
2015-12-27 14:22:24 +03:00
|
|
|
|
onPaint: {
|
|
|
|
|
var ctx = getContext('2d');
|
2015-12-31 19:12:54 +03:00
|
|
|
|
ctx.clearRect(0,0,width,height)
|
2016-01-01 13:35:28 +03:00
|
|
|
|
|
2016-01-01 17:50:20 +03:00
|
|
|
|
ctx.lineWidth = 1
|
2016-01-02 02:11:25 +03:00
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
|
|
|
|
|
// line only
|
|
|
|
|
if (is_line) {
|
|
|
|
|
var x = getx(angle, r_arrow_base)
|
|
|
|
|
var y = gety(angle, r_arrow_base)
|
|
|
|
|
var hx = getx(angle, k)
|
|
|
|
|
var hy = gety(angle, k)
|
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.moveTo(x,y)
|
|
|
|
|
ctx.lineTo(hx,hy)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-01-01 17:50:20 +03:00
|
|
|
|
|
2016-01-01 13:35:28 +03:00
|
|
|
|
// arrow base center
|
2016-01-01 17:50:20 +03:00
|
|
|
|
var x = getx(0, r_arrow_base + r_base)
|
|
|
|
|
var y = gety(0, r_arrow_base + r_base)
|
2016-01-01 13:35:28 +03:00
|
|
|
|
// arrow base radius
|
2016-01-01 17:50:20 +03:00
|
|
|
|
var d_base = r_base * width / 2
|
2016-01-01 13:35:28 +03:00
|
|
|
|
// arrow head width
|
|
|
|
|
var d_head = d_base * k_head
|
|
|
|
|
|
2016-01-01 17:50:20 +03:00
|
|
|
|
// base internal circle
|
|
|
|
|
ctx.strokeStyle = theme.secondaryColor
|
2015-12-27 14:22:24 +03:00
|
|
|
|
ctx.beginPath()
|
2016-01-01 17:50:20 +03:00
|
|
|
|
ctx.arc(x, y + 0 *(r_base - r_circle_base) * lref, r_circle_base * lref, 0, Math.PI * 2)
|
|
|
|
|
ctx.stroke()
|
|
|
|
|
|
2016-01-01 13:35:28 +03:00
|
|
|
|
// base
|
2016-01-01 17:50:20 +03:00
|
|
|
|
ctx.beginPath()
|
|
|
|
|
ctx.strokeStyle = theme.primaryColor
|
|
|
|
|
|
2016-01-01 13:35:28 +03:00
|
|
|
|
var x1 = x - d_base * Math.cos(angle)
|
|
|
|
|
var y1 = y - d_base * Math.sin(angle)
|
|
|
|
|
ctx.moveTo(x1, y1)
|
|
|
|
|
ctx.arc(x, y, d_base, Math.PI + angle, angle, 1)
|
|
|
|
|
// head
|
|
|
|
|
var hx = getx(angle, k)
|
|
|
|
|
var hy = gety(angle, k)
|
2016-01-01 17:50:20 +03:00
|
|
|
|
var bout = orth(x, y, hx, hy, d_head)
|
|
|
|
|
ctx.lineTo(bout[2], bout[3])
|
|
|
|
|
ctx.lineTo(bout[0], bout[1])
|
2016-01-01 13:35:28 +03:00
|
|
|
|
ctx.closePath()
|
2015-12-27 14:22:24 +03:00
|
|
|
|
ctx.stroke()
|
2016-01-01 12:22:06 +03:00
|
|
|
|
|
|
|
|
|
// gradient
|
2016-01-02 02:11:25 +03:00
|
|
|
|
if (has_gradient) {
|
|
|
|
|
var middle1 = orth(x, y, x + (hx - x) * 0.7, y + (hy - y) * 0.7, d_base + (d_head - d_base) * 0.7)
|
|
|
|
|
var grd = ctx.createLinearGradient(middle1[0], middle1[1], middle1[2], middle1[3])
|
|
|
|
|
grd.addColorStop(1, 'rgba(128,128,128,0.2)')
|
|
|
|
|
grd.addColorStop(0, "transparent")
|
|
|
|
|
ctx.fillStyle = grd
|
|
|
|
|
ctx.fill()
|
2016-01-01 12:03:04 +03:00
|
|
|
|
}
|
2015-12-31 19:12:54 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-01-02 02:11:25 +03:00
|
|
|
|
/*
|
2015-12-31 19:12:54 +03:00
|
|
|
|
Behavior on level {
|
|
|
|
|
NumberAnimation {
|
|
|
|
|
duration: 50
|
|
|
|
|
easing.amplitude: max - min
|
2015-12-27 14:01:07 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-02 02:11:25 +03:00
|
|
|
|
*/
|
2015-12-31 19:12:54 +03:00
|
|
|
|
onLevelChanged: {
|
|
|
|
|
arrow.requestPaint()
|
|
|
|
|
}
|
2016-01-15 23:11:23 +03:00
|
|
|
|
|
|
|
|
|
function redraw() {
|
|
|
|
|
ellipse.requestPaint()
|
|
|
|
|
arrow.requestPaint()
|
|
|
|
|
}
|
2015-12-27 14:01:07 +03:00
|
|
|
|
}
|