mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-08 08:04:08 +02:00
Improved style of widget for details of selected points on chart.
This commit is contained in:
parent
42fc4fbb31
commit
3425b40746
4 changed files with 157 additions and 68 deletions
|
@ -1189,16 +1189,20 @@ void ChartWidget::setupDetails() {
|
||||||
currentXLimits.min,
|
currentXLimits.min,
|
||||||
currentXLimits.max,
|
currentXLimits.max,
|
||||||
_chartData.xPercentage[nearestXIndex]);
|
_chartData.xPercentage[nearestXIndex]);
|
||||||
const auto xLeft = currentX
|
const auto widgetArea = _details.widget->width()
|
||||||
- _details.widget->width();
|
+ st::statisticsDetailsPopupPadding.left();
|
||||||
|
const auto xLeft = currentX - widgetArea;
|
||||||
const auto x = (xLeft >= 0)
|
const auto x = (xLeft >= 0)
|
||||||
? xLeft
|
? xLeft
|
||||||
: ((currentX
|
: ((currentX + widgetArea - _chartArea->width()) > 0)
|
||||||
+ _details.widget->width()
|
|
||||||
- _chartArea->width()) > 0)
|
|
||||||
? 0
|
? 0
|
||||||
: currentX;
|
: currentX;
|
||||||
_details.widget->moveToLeft(x, _chartArea->y());
|
_details.widget->moveToLeft(
|
||||||
|
std::clamp(
|
||||||
|
int(x),
|
||||||
|
_chartArea->x(),
|
||||||
|
rect::right(_chartArea) - widgetArea),
|
||||||
|
_chartArea->y());
|
||||||
_details.widget->setXIndex(nearestXIndex);
|
_details.widget->setXIndex(nearestXIndex);
|
||||||
if (_details.widget->isHidden()) {
|
if (_details.widget->isHidden()) {
|
||||||
_details.hideOnAnimationEnd = false;
|
_details.hideOnAnimationEnd = false;
|
||||||
|
|
|
@ -11,7 +11,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/effects/ripple_animation.h"
|
#include "ui/effects/ripple_animation.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "ui/widgets/shadow.h"
|
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_statistics.h"
|
#include "styles/style_statistics.h"
|
||||||
|
|
||||||
|
@ -32,6 +31,37 @@ namespace {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PaintShadow(QPainter &p, int radius, const QRect &r) {
|
||||||
|
constexpr auto kHorizontalOffset = 1;
|
||||||
|
constexpr auto kHorizontalOffset2 = 2;
|
||||||
|
constexpr auto kVerticalOffset = 2;
|
||||||
|
constexpr auto kVerticalOffset2 = 3;
|
||||||
|
constexpr auto kOpacityStep = 0.2;
|
||||||
|
constexpr auto kOpacityStep2 = 0.4;
|
||||||
|
const auto hOffset = style::ConvertScale(kHorizontalOffset);
|
||||||
|
const auto hOffset2 = style::ConvertScale(kHorizontalOffset2);
|
||||||
|
const auto vOffset = style::ConvertScale(kVerticalOffset);
|
||||||
|
const auto vOffset2 = style::ConvertScale(kVerticalOffset2);
|
||||||
|
const auto opacity = p.opacity();
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
|
||||||
|
p.setOpacity(opacity);
|
||||||
|
p.drawRoundedRect(r + QMarginsF(0, hOffset, 0, hOffset), radius, radius);
|
||||||
|
|
||||||
|
p.setOpacity(opacity * kOpacityStep);
|
||||||
|
p.drawRoundedRect(r + QMarginsF(hOffset, 0, hOffset, 0), radius, radius);
|
||||||
|
p.setOpacity(opacity * kOpacityStep2);
|
||||||
|
p.drawRoundedRect(r
|
||||||
|
+ QMarginsF(hOffset2, 0, hOffset2, 0), radius, radius);
|
||||||
|
|
||||||
|
p.setOpacity(opacity * kOpacityStep);
|
||||||
|
p.drawRoundedRect(r + QMarginsF(0, 0, 0, vOffset), radius, radius);
|
||||||
|
p.setOpacity(opacity * kOpacityStep2);
|
||||||
|
p.drawRoundedRect(r + QMarginsF(0, 0, 0, vOffset2), radius, radius);
|
||||||
|
|
||||||
|
p.setOpacity(opacity);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void PaintDetails(
|
void PaintDetails(
|
||||||
|
@ -67,7 +97,9 @@ void PaintDetails(
|
||||||
const auto innerRect = fullRect - st::statisticsDetailsPopupPadding;
|
const auto innerRect = fullRect - st::statisticsDetailsPopupPadding;
|
||||||
const auto textRect = innerRect - st::statisticsDetailsPopupMargins;
|
const auto textRect = innerRect - st::statisticsDetailsPopupMargins;
|
||||||
|
|
||||||
Ui::Shadow::paint(p, innerRect, rect.width(), st::boxRoundShadow);
|
p.setBrush(st::shadowFg);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
PaintShadow(p, st::boxRadius, innerRect);
|
||||||
Ui::FillRoundRect(p, innerRect, st::boxBg, Ui::BoxCorners);
|
Ui::FillRoundRect(p, innerRect, st::boxBg, Ui::BoxCorners);
|
||||||
|
|
||||||
const auto lineY = textRect.y();
|
const auto lineY = textRect.y();
|
||||||
|
@ -90,7 +122,7 @@ PointDetailsWidget::PointDetailsWidget(
|
||||||
const Data::StatisticalChart &chartData,
|
const Data::StatisticalChart &chartData,
|
||||||
float64 maxAbsoluteValue,
|
float64 maxAbsoluteValue,
|
||||||
bool zoomEnabled)
|
bool zoomEnabled)
|
||||||
: Ui::RippleButton(parent, st::defaultRippleAnimation)
|
: Ui::AbstractButton(parent)
|
||||||
, _zoomEnabled(zoomEnabled)
|
, _zoomEnabled(zoomEnabled)
|
||||||
, _chartData(chartData)
|
, _chartData(chartData)
|
||||||
, _textStyle(st::statisticsDetailsPopupStyle)
|
, _textStyle(st::statisticsDetailsPopupStyle)
|
||||||
|
@ -119,6 +151,7 @@ PointDetailsWidget::PointDetailsWidget(
|
||||||
p.drawLine(QLineF(s, s, w, w + s));
|
p.drawLine(QLineF(s, s, w, w + s));
|
||||||
p.drawLine(QLineF(s, s + w * 2, w, w + s));
|
p.drawLine(QLineF(s, s + w * 2, w, w + s));
|
||||||
}
|
}
|
||||||
|
invalidateCache();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,6 +195,7 @@ PointDetailsWidget::PointDetailsWidget(
|
||||||
: Rect(s);
|
: Rect(s);
|
||||||
_innerRect = fullRect - st::statisticsDetailsPopupPadding;
|
_innerRect = fullRect - st::statisticsDetailsPopupPadding;
|
||||||
_textRect = _innerRect - st::statisticsDetailsPopupMargins;
|
_textRect = _innerRect - st::statisticsDetailsPopupMargins;
|
||||||
|
invalidateCache();
|
||||||
}, lifetime());
|
}, lifetime());
|
||||||
|
|
||||||
resize(calculatedWidth, height());
|
resize(calculatedWidth, height());
|
||||||
|
@ -171,11 +205,15 @@ PointDetailsWidget::PointDetailsWidget(
|
||||||
void PointDetailsWidget::setLineAlpha(int lineId, float64 alpha) {
|
void PointDetailsWidget::setLineAlpha(int lineId, float64 alpha) {
|
||||||
for (auto &line : _lines) {
|
for (auto &line : _lines) {
|
||||||
if (line.id == lineId) {
|
if (line.id == lineId) {
|
||||||
|
if (line.alpha != alpha) {
|
||||||
line.alpha = alpha;
|
line.alpha = alpha;
|
||||||
}
|
|
||||||
}
|
|
||||||
update();
|
|
||||||
resizeHeight();
|
resizeHeight();
|
||||||
|
invalidateCache();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointDetailsWidget::resizeHeight() {
|
void PointDetailsWidget::resizeHeight() {
|
||||||
|
@ -216,6 +254,7 @@ void PointDetailsWidget::setXIndex(int xIndex) {
|
||||||
setAttribute(
|
setAttribute(
|
||||||
Qt::WA_TransparentForMouseEvents,
|
Qt::WA_TransparentForMouseEvents,
|
||||||
!clickable);
|
!clickable);
|
||||||
|
invalidateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointDetailsWidget::setAlpha(float64 alpha) {
|
void PointDetailsWidget::setAlpha(float64 alpha) {
|
||||||
|
@ -242,16 +281,53 @@ int PointDetailsWidget::lineYAt(int index) const {
|
||||||
+ std::ceil(linesHeight);
|
+ std::ceil(linesHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PointDetailsWidget::invalidateCache() {
|
||||||
|
_cache = QImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointDetailsWidget::mousePressEvent(QMouseEvent *e) {
|
||||||
|
AbstractButton::mousePressEvent(e);
|
||||||
|
const auto position = e->pos() - _innerRect.topLeft();
|
||||||
|
if (!_ripple) {
|
||||||
|
_ripple = std::make_unique<Ui::RippleAnimation>(
|
||||||
|
st::defaultRippleAnimation,
|
||||||
|
Ui::RippleAnimation::RoundRectMask(
|
||||||
|
_innerRect.size(),
|
||||||
|
st::boxRadius),
|
||||||
|
[=] { update(); });
|
||||||
|
}
|
||||||
|
_ripple->add(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PointDetailsWidget::mouseReleaseEvent(QMouseEvent *e) {
|
||||||
|
AbstractButton::mouseReleaseEvent(e);
|
||||||
|
if (_ripple) {
|
||||||
|
_ripple->lastStop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
||||||
auto p = QPainter(this);
|
auto painter = QPainter(this);
|
||||||
|
|
||||||
p.setOpacity(_alpha);
|
if (_cache.isNull()) {
|
||||||
|
_cache = QImage(
|
||||||
|
size() * style::DevicePixelRatio(),
|
||||||
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
|
_cache.fill(Qt::transparent);
|
||||||
|
|
||||||
const auto fullRect = rect();
|
auto p = QPainter(&_cache);
|
||||||
|
|
||||||
Ui::Shadow::paint(p, _innerRect, width(), st::boxRoundShadow);
|
p.setBrush(st::shadowFg);
|
||||||
|
p.setPen(Qt::NoPen);
|
||||||
|
PaintShadow(p, st::boxRadius, _innerRect);
|
||||||
Ui::FillRoundRect(p, _innerRect, st::boxBg, Ui::BoxCorners);
|
Ui::FillRoundRect(p, _innerRect, st::boxBg, Ui::BoxCorners);
|
||||||
Ui::RippleButton::paintRipple(p, _innerRect.topLeft());
|
|
||||||
|
if (_ripple) {
|
||||||
|
_ripple->paint(p, _innerRect.left(), _innerRect.top(), width());
|
||||||
|
if (_ripple->empty()) {
|
||||||
|
_ripple.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
p.setPen(st::boxTextFg);
|
p.setPen(st::boxTextFg);
|
||||||
const auto headerContext = Ui::Text::PaintContext{
|
const auto headerContext = Ui::Text::PaintContext{
|
||||||
|
@ -264,7 +340,9 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
||||||
const auto lineY = lineYAt(i);
|
const auto lineY = lineYAt(i);
|
||||||
const auto valueWidth = line.value.maxWidth();
|
const auto valueWidth = line.value.maxWidth();
|
||||||
const auto valueContext = Ui::Text::PaintContext{
|
const auto valueContext = Ui::Text::PaintContext{
|
||||||
.position = QPoint(rect::right(_textRect) - valueWidth, lineY),
|
.position = QPoint(
|
||||||
|
rect::right(_textRect) - valueWidth,
|
||||||
|
lineY),
|
||||||
.outerWidth = _textRect.width(),
|
.outerWidth = _textRect.width(),
|
||||||
.availableWidth = valueWidth,
|
.availableWidth = valueWidth,
|
||||||
};
|
};
|
||||||
|
@ -273,7 +351,7 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
||||||
.outerWidth = _textRect.width(),
|
.outerWidth = _textRect.width(),
|
||||||
.availableWidth = _textRect.width() - valueWidth,
|
.availableWidth = _textRect.width() - valueWidth,
|
||||||
};
|
};
|
||||||
p.setOpacity(line.alpha * line.alpha * _alpha);
|
p.setOpacity(line.alpha * line.alpha);
|
||||||
p.setPen(st::boxTextFg);
|
p.setPen(st::boxTextFg);
|
||||||
line.name.draw(p, nameContext);
|
line.name.draw(p, nameContext);
|
||||||
p.setPen(line.valueColor);
|
p.setPen(line.valueColor);
|
||||||
|
@ -288,15 +366,13 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
||||||
p.drawImage(x, y, _arrow);
|
p.drawImage(x, y, _arrow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (_alpha < 1.) {
|
||||||
QPoint PointDetailsWidget::prepareRippleStartPosition() const {
|
painter.setOpacity(_alpha);
|
||||||
return mapFromGlobal(QCursor::pos()) - _innerRect.topLeft();
|
}
|
||||||
|
painter.drawImage(0, 0, _cache);
|
||||||
|
if (_ripple) {
|
||||||
|
invalidateCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage PointDetailsWidget::prepareRippleMask() const {
|
|
||||||
return Ui::RippleAnimation::RoundRectMask(
|
|
||||||
_innerRect.size(),
|
|
||||||
st::boxRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -8,7 +8,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "data/data_statistics_chart.h"
|
#include "data/data_statistics_chart.h"
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/abstract_button.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class RippleAnimation;
|
||||||
|
} // namespace Ui
|
||||||
|
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
|
|
||||||
|
@ -18,7 +22,7 @@ void PaintDetails(
|
||||||
int absoluteValue,
|
int absoluteValue,
|
||||||
const QRect &rect);
|
const QRect &rect);
|
||||||
|
|
||||||
class PointDetailsWidget : public Ui::RippleButton {
|
class PointDetailsWidget : public Ui::AbstractButton {
|
||||||
public:
|
public:
|
||||||
PointDetailsWidget(
|
PointDetailsWidget(
|
||||||
not_null<Ui::RpWidget*> parent,
|
not_null<Ui::RpWidget*> parent,
|
||||||
|
@ -34,9 +38,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *e) override;
|
void paintEvent(QPaintEvent *e) override;
|
||||||
|
void mousePressEvent(QMouseEvent *e) override;
|
||||||
QImage prepareRippleMask() const override;
|
void mouseReleaseEvent(QMouseEvent *e) override;
|
||||||
QPoint prepareRippleStartPosition() const override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const bool _zoomEnabled;
|
const bool _zoomEnabled;
|
||||||
|
@ -47,6 +50,8 @@ private:
|
||||||
const QString _shortFormat;
|
const QString _shortFormat;
|
||||||
Ui::Text::String _header;
|
Ui::Text::String _header;
|
||||||
|
|
||||||
|
void invalidateCache();
|
||||||
|
|
||||||
[[nodiscard]] int lineYAt(int index) const;
|
[[nodiscard]] int lineYAt(int index) const;
|
||||||
|
|
||||||
void resizeHeight();
|
void resizeHeight();
|
||||||
|
@ -63,11 +68,15 @@ private:
|
||||||
QRect _textRect;
|
QRect _textRect;
|
||||||
QImage _arrow;
|
QImage _arrow;
|
||||||
|
|
||||||
|
QImage _cache;
|
||||||
|
|
||||||
int _xIndex = -1;
|
int _xIndex = -1;
|
||||||
float64 _alpha = 1.;
|
float64 _alpha = 1.;
|
||||||
|
|
||||||
std::vector<Line> _lines;
|
std::vector<Line> _lines;
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::RippleAnimation> _ripple;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -13,13 +13,13 @@ using "ui/widgets/widgets.style";
|
||||||
statisticsLayerOverviewMargins: margins(0px, 17px, 0px, 3px);
|
statisticsLayerOverviewMargins: margins(0px, 17px, 0px, 3px);
|
||||||
statisticsLayerMargins: margins(20px, 0px, 20px, 0px);
|
statisticsLayerMargins: margins(20px, 0px, 20px, 0px);
|
||||||
|
|
||||||
statisticsChartHeight: 150px;
|
statisticsChartHeight: 200px;
|
||||||
|
|
||||||
statisticsChartEntryPadding: margins(0px, 13px, 0px, 8px);
|
statisticsChartEntryPadding: margins(0px, 13px, 0px, 8px);
|
||||||
|
|
||||||
statisticsDetailsArrowShift: 2px;
|
statisticsDetailsArrowShift: 2px;
|
||||||
statisticsDetailsArrowStroke: 1.5;
|
statisticsDetailsArrowStroke: 1.5;
|
||||||
statisticsDetailsPopupMargins: margins(8px, 8px, 8px, 8px);
|
statisticsDetailsPopupMargins: margins(12px, 8px, 12px, 11px);
|
||||||
statisticsDetailsPopupPadding: margins(6px, 6px, 6px, 6px);
|
statisticsDetailsPopupPadding: margins(6px, 6px, 6px, 6px);
|
||||||
statisticsDetailsPopupMidLineSpace: 4px;
|
statisticsDetailsPopupMidLineSpace: 4px;
|
||||||
statisticsDetailsDotRadius: 5px;
|
statisticsDetailsDotRadius: 5px;
|
||||||
|
@ -45,10 +45,10 @@ statisticsChartFlatCheckboxCheckWidth: 4px;
|
||||||
statisticsFilterButtonsPadding: margins(0px, 6px, 0px, 0px);
|
statisticsFilterButtonsPadding: margins(0px, 6px, 0px, 0px);
|
||||||
|
|
||||||
statisticsDetailsPopupHeaderStyle: TextStyle(defaultTextStyle) {
|
statisticsDetailsPopupHeaderStyle: TextStyle(defaultTextStyle) {
|
||||||
font: font(9px semibold);
|
font: font(12px semibold);
|
||||||
}
|
}
|
||||||
statisticsDetailsPopupStyle: TextStyle(defaultTextStyle) {
|
statisticsDetailsPopupStyle: TextStyle(defaultTextStyle) {
|
||||||
font: font(8px);
|
font: font(12px);
|
||||||
}
|
}
|
||||||
statisticsDetailsBottomCaptionStyle: TextStyle(defaultTextStyle) {
|
statisticsDetailsBottomCaptionStyle: TextStyle(defaultTextStyle) {
|
||||||
font: font(10px);
|
font: font(10px);
|
||||||
|
|
Loading…
Add table
Reference in a new issue