2017-04-27 20:26:36 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2024-01-12 22:26:32 +01:00
|
|
|
#include "ruleritem.h"
|
|
|
|
#include "profilescene.h"
|
|
|
|
#include "profileview.h"
|
|
|
|
#include "zvalues.h"
|
2018-08-15 11:52:50 +02:00
|
|
|
#include "core/settings/qPrefTechnicalDetails.h"
|
2014-02-27 22:52:03 -03:00
|
|
|
|
2016-04-04 22:02:03 -07:00
|
|
|
#include "core/profile.h"
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
#include <QApplication>
|
|
|
|
|
|
|
|
static QColor handleBorderColor(Qt::red);
|
|
|
|
static QColor handleColor(0xff, 0, 0, 0x80);
|
|
|
|
static constexpr double handleRadius = 8.0;
|
|
|
|
|
|
|
|
static QColor lineColor(Qt::black);
|
|
|
|
static constexpr double lineWidth = 1.0;
|
|
|
|
|
|
|
|
static constexpr int tooltipBorder = 1;
|
|
|
|
static constexpr double tooltipBorderRadius = 2.0; // Radius of rounded corners
|
|
|
|
static QColor tooltipBorderColor(Qt::black);
|
|
|
|
static QColor tooltipColor(0xff, 0xff, 0xff, 190);
|
|
|
|
static QColor tooltipFontColor(Qt::black);
|
|
|
|
|
|
|
|
class RulerItemHandle : public ChartDiskItem
|
2014-02-27 13:28:58 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
public:
|
|
|
|
ProfileView &profileView;
|
|
|
|
double xpos;
|
|
|
|
// The first argument is passed twice, to avoid an downcast. Yes, that's silly.
|
|
|
|
RulerItemHandle(ChartView &view, ProfileView &profileView, double dpr) :
|
|
|
|
ChartDiskItem(view, ProfileZValue::RulerItem,
|
|
|
|
QPen(handleBorderColor, dpr),
|
|
|
|
QBrush(handleColor),
|
|
|
|
true),
|
|
|
|
profileView(profileView),
|
|
|
|
xpos(0.0)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
// The call chain here is weird: this calls into the ProfileScene, which then calls
|
|
|
|
// back into the RulerItem. The reason is that the ProfileScene knows the current
|
|
|
|
// dive etc. This seems more robust than storing the current dive in the subobject.
|
|
|
|
void drag(QPointF pos) override
|
|
|
|
{
|
|
|
|
xpos = pos.x();
|
|
|
|
profileView.rulerDragged();
|
|
|
|
}
|
|
|
|
};
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
// duplicate code in tooltipitem.cpp
|
|
|
|
static QFont makeFont(double dpr)
|
2014-03-07 12:08:31 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
QFont font(qApp->font());
|
|
|
|
if (dpr != 1.0) {
|
|
|
|
int pixelSize = font.pixelSize();
|
|
|
|
if (pixelSize > 0) {
|
|
|
|
pixelSize = lrint(static_cast<double>(pixelSize) * dpr);
|
|
|
|
font.setPixelSize(pixelSize);
|
|
|
|
} else {
|
|
|
|
font.setPointSizeF(font.pointSizeF() * dpr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return font;
|
2014-03-07 12:08:31 -03:00
|
|
|
}
|
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
static ChartItemPtr<RulerItemHandle> makeHandle(ProfileView &view, double dpr)
|
2014-02-27 13:28:58 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
auto res = view.createChartItem<RulerItemHandle>(view, dpr);
|
|
|
|
res->resize(handleRadius * dpr);
|
|
|
|
return res;
|
2014-02-27 13:28:58 -03:00
|
|
|
}
|
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
RulerItem::RulerItem(ProfileView &view, double dpr) :
|
|
|
|
line(view.createChartItem<ChartLineItem>(ProfileZValue::RulerItem,
|
|
|
|
lineColor, lineWidth * dpr)),
|
|
|
|
handle1(makeHandle(view, dpr)),
|
|
|
|
handle2(makeHandle(view, dpr)),
|
|
|
|
tooltip(view.createChartItem<AnimatedChartRectItem>(ProfileZValue::RulerItem,
|
|
|
|
QPen(tooltipBorderColor, lrint(tooltipBorder * dpr)),
|
|
|
|
QBrush(tooltipColor), tooltipBorderRadius * dpr,
|
|
|
|
false)),
|
|
|
|
font(makeFont(dpr)),
|
|
|
|
fm(font),
|
|
|
|
fontHeight(fm.height())
|
2014-02-27 13:28:58 -03:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-01-20 21:03:02 +01:00
|
|
|
RulerItem::~RulerItem()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
void RulerItem::setVisible(bool visible)
|
2014-02-27 13:28:58 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
line->setVisible(visible);
|
|
|
|
handle1->setVisible(visible);
|
|
|
|
handle2->setVisible(visible);
|
|
|
|
tooltip->setVisible(visible);
|
2014-02-27 13:28:58 -03:00
|
|
|
}
|
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
// Binary search to find index at time stamp
|
|
|
|
static int get_idx_at_time(const plot_info &info, int time)
|
2014-02-27 13:28:58 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
auto entry = std::lower_bound(info.entry.begin(), info.entry.end(), time,
|
|
|
|
[](const plot_data &d, int time)
|
|
|
|
{ return d.sec < time; });
|
|
|
|
return entry != info.entry.end() ? entry - info.entry.begin()
|
|
|
|
: info.entry.size() - 1;
|
2014-05-21 14:24:19 -03:00
|
|
|
}
|
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
void RulerItem::update(const dive *d, double dpr, const ProfileScene &scene, const plot_info &info, int animspeed)
|
2014-05-21 14:24:19 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
if (info.nr == 0)
|
|
|
|
return; // Nothing to display
|
2015-03-17 20:35:11 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
auto [minX, maxX] = scene.minMaxX();
|
|
|
|
auto [minY, maxY] = scene.minMaxY();
|
|
|
|
double x1 = std::clamp(handle1->xpos, minX, maxX);
|
|
|
|
double x2 = std::clamp(handle2->xpos, minX, maxX);
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
int time1 = lrint(scene.timeAt(QPointF(x1, 0.0)));
|
|
|
|
int time2 = lrint(scene.timeAt(QPointF(x2, 0.0)));
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
int idx1 = get_idx_at_time(info, time1);
|
|
|
|
int idx2 = get_idx_at_time(info, time2);
|
|
|
|
|
|
|
|
double y1 = scene.posAtDepth(info.entry[idx1].depth);
|
|
|
|
double y2 = scene.posAtDepth(info.entry[idx2].depth);
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
QPointF pos1(x1, y1);
|
|
|
|
QPointF pos2(x2, y2);
|
|
|
|
line->setLine(pos1, pos2);
|
|
|
|
handle1->setPos(pos1);
|
|
|
|
handle2->setPos(pos2);
|
2014-02-27 22:52:03 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
if (idx1 == idx2) {
|
|
|
|
tooltip->setVisible(false);
|
|
|
|
return;
|
2014-02-27 13:28:58 -03:00
|
|
|
}
|
2024-01-12 22:26:32 +01:00
|
|
|
tooltip->setVisible(true);
|
|
|
|
|
|
|
|
auto lines = compare_samples(d, info, idx1, idx2, 1);
|
|
|
|
|
|
|
|
double width = 0;
|
|
|
|
// Turn strings into QString/width pairs and increase width if needed
|
|
|
|
std::vector<std::pair<QString, int>> strings;
|
|
|
|
strings.reserve(lines.size());
|
|
|
|
for (auto &s_std: lines) {
|
|
|
|
auto s = QString::fromStdString(s_std);
|
|
|
|
int w = fm.size(Qt::TextSingleLine, s).width();
|
|
|
|
width = std::max(width, static_cast<double>(w));
|
|
|
|
strings.push_back(std::make_pair(s, w));
|
2024-03-10 23:11:23 +01:00
|
|
|
}
|
2024-01-12 22:26:32 +01:00
|
|
|
width += 6.0 * tooltipBorder * dpr;
|
|
|
|
|
|
|
|
double height = static_cast<double>(strings.size()) * fontHeight +
|
|
|
|
4.0 * tooltipBorder * dpr;
|
|
|
|
|
|
|
|
QPixmap pixmap(lrint(width), lrint(height));
|
|
|
|
pixmap.fill(Qt::transparent);
|
|
|
|
QPainter painter(&pixmap);
|
|
|
|
|
|
|
|
painter.setFont(font);
|
|
|
|
painter.setPen(QPen(tooltipFontColor)); // QPainter uses QPen to set text color!
|
|
|
|
double x = 4.0 * tooltipBorder * dpr;
|
|
|
|
double y = 2.0 * tooltipBorder * dpr;
|
|
|
|
for (auto &[s,w]: strings) {
|
|
|
|
QRectF rect(x, y, w, fontHeight);
|
|
|
|
painter.drawText(rect, s);
|
|
|
|
y += fontHeight;
|
2014-03-12 00:09:53 +02:00
|
|
|
}
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
tooltip->setPixmap(pixmap, animspeed);
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
if (pos2.x() < pos1.x())
|
|
|
|
std::swap(pos1, pos2);
|
|
|
|
double xpos = width < maxX - minX ?
|
|
|
|
std::clamp(pos1.x() + handleRadius * dpr, 0.0, maxX - width) : 0.0;
|
2014-02-27 13:28:58 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
double ypos = height < maxY - minY ?
|
|
|
|
std::clamp(pos1.y() + handleRadius * dpr, 0.0, maxY - height) : 0.0;
|
2014-02-27 16:28:19 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
tooltip->setPos(QPointF(xpos, ypos));
|
2014-02-27 14:59:41 -03:00
|
|
|
}
|
2014-05-21 12:18:05 -03:00
|
|
|
|
2024-01-12 22:26:32 +01:00
|
|
|
void RulerItem::anim(double progress)
|
2014-05-21 12:18:05 -03:00
|
|
|
{
|
2024-01-12 22:26:32 +01:00
|
|
|
tooltip->anim(progress);
|
2014-05-21 12:18:05 -03:00
|
|
|
}
|