Slightly optimized footer in chart widget.
This commit is contained in:
		
							parent
							
								
									c8d5a60c74
								
							
						
					
					
						commit
						c5684e768a
					
				
					 1 changed files with 126 additions and 159 deletions
				
			
		| 
						 | 
				
			
			@ -102,6 +102,104 @@ private:
 | 
			
		|||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
 | 
			
		||||
: Ui::AbstractButton(parent)
 | 
			
		||||
, _left(Ui::CreateChild<Ui::AbstractButton>(this))
 | 
			
		||||
, _right(Ui::CreateChild<Ui::AbstractButton>(this)) {
 | 
			
		||||
	sizeValue(
 | 
			
		||||
	) | rpl::start_with_next([=](const QSize &s) {
 | 
			
		||||
		_left->resize(st::colorSliderWidth, s.height());
 | 
			
		||||
		_right->resize(st::colorSliderWidth, s.height());
 | 
			
		||||
	}, _left->lifetime());
 | 
			
		||||
	_left->paintRequest(
 | 
			
		||||
	) | rpl::start_with_next([=] {
 | 
			
		||||
		auto p = QPainter(_left);
 | 
			
		||||
		p.setOpacity(0.3);
 | 
			
		||||
		p.fillRect(_left->rect(), st::boxTextFg);
 | 
			
		||||
	}, _left->lifetime());
 | 
			
		||||
	_right->paintRequest(
 | 
			
		||||
	) | rpl::start_with_next([=] {
 | 
			
		||||
		auto p = QPainter(_right);
 | 
			
		||||
		p.setOpacity(0.3);
 | 
			
		||||
		p.fillRect(_right->rect(), st::boxTextFg);
 | 
			
		||||
	}, _right->lifetime());
 | 
			
		||||
 | 
			
		||||
	_left->move(10, 0);
 | 
			
		||||
	_right->move(50, 0);
 | 
			
		||||
 | 
			
		||||
	const auto handleDrag = [&](
 | 
			
		||||
			not_null<Ui::AbstractButton*> side,
 | 
			
		||||
			Fn<int()> leftLimit,
 | 
			
		||||
			Fn<int()> rightLimit) {
 | 
			
		||||
		side->events(
 | 
			
		||||
		) | rpl::filter([=](not_null<QEvent*> e) {
 | 
			
		||||
			return (e->type() == QEvent::MouseButtonPress)
 | 
			
		||||
				|| (e->type() == QEvent::MouseButtonRelease)
 | 
			
		||||
				|| ((e->type() == QEvent::MouseMove) && side->isDown());
 | 
			
		||||
		}) | rpl::start_with_next([=](not_null<QEvent*> e) {
 | 
			
		||||
			const auto pos = static_cast<QMouseEvent*>(e.get())->pos();
 | 
			
		||||
			switch (e->type()) {
 | 
			
		||||
			case QEvent::MouseMove: {
 | 
			
		||||
				const auto nowDiffXDirection = (pos.x() - _start.x) < 0;
 | 
			
		||||
				const auto wasDiffXDirection = _start.diffX < 0;
 | 
			
		||||
				if (base::IsCtrlPressed()) {
 | 
			
		||||
					const auto diff = (pos.x() - _start.x);
 | 
			
		||||
					_left->move(_left->x() + diff, side->y());
 | 
			
		||||
					_right->move(_right->x() + diff, side->y());
 | 
			
		||||
				} else {
 | 
			
		||||
					_start.diffX = pos.x() - _start.x;
 | 
			
		||||
					const auto nextX = std::clamp(
 | 
			
		||||
						side->x() + (pos.x() - _start.x),
 | 
			
		||||
						_start.leftLimit,
 | 
			
		||||
						_start.rightLimit);
 | 
			
		||||
					side->move(nextX, side->y());
 | 
			
		||||
				}
 | 
			
		||||
				_xPercentageLimitsChange.fire({
 | 
			
		||||
					.min = _left->x() / float64(width()),
 | 
			
		||||
					.max = rect::right(_right) / float64(width()),
 | 
			
		||||
				});
 | 
			
		||||
				if (nowDiffXDirection != wasDiffXDirection) {
 | 
			
		||||
					_directionChanges.fire({});
 | 
			
		||||
				}
 | 
			
		||||
			} break;
 | 
			
		||||
			case QEvent::MouseButtonPress: {
 | 
			
		||||
				_start.x = pos.x();
 | 
			
		||||
				_start.leftLimit = leftLimit();
 | 
			
		||||
				_start.rightLimit = rightLimit();
 | 
			
		||||
			} break;
 | 
			
		||||
			case QEvent::MouseButtonRelease: {
 | 
			
		||||
				_userInteractionFinished.fire({});
 | 
			
		||||
				_xPercentageLimitsChange.fire({
 | 
			
		||||
					.min = _left->x() / float64(width()),
 | 
			
		||||
					.max = rect::right(_right) / float64(width()),
 | 
			
		||||
				});
 | 
			
		||||
				_start = {};
 | 
			
		||||
			} break;
 | 
			
		||||
			}
 | 
			
		||||
		}, side->lifetime());
 | 
			
		||||
	};
 | 
			
		||||
	handleDrag(
 | 
			
		||||
		_left,
 | 
			
		||||
		[=] { return 0; },
 | 
			
		||||
		[=] { return _right->x() - _left->width(); });
 | 
			
		||||
	handleDrag(
 | 
			
		||||
		_right,
 | 
			
		||||
		[=] { return rect::right(_left); },
 | 
			
		||||
		[=] { return width() - _right->width(); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl::producer<Limits> ChartWidget::Footer::xPercentageLimitsChange() const {
 | 
			
		||||
	return _xPercentageLimitsChange.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl::producer<> ChartWidget::Footer::userInteractionFinished() const {
 | 
			
		||||
	return _userInteractionFinished.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl::producer<> ChartWidget::Footer::directionChanges() const {
 | 
			
		||||
	return _directionChanges.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChartWidget::ChartAnimationController::ChartAnimationController(
 | 
			
		||||
	Fn<void()> &&updateCallback)
 | 
			
		||||
: _animation(std::move(updateCallback)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -121,46 +219,26 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
 | 
			
		|||
	_lastUserInteracted = now;
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		auto minY = std::numeric_limits<float64>::max();
 | 
			
		||||
		auto maxY = 0.;
 | 
			
		||||
		auto minYIndex = 0;
 | 
			
		||||
		auto maxYIndex = 0;
 | 
			
		||||
		const auto tempXPercentage = Limits{
 | 
			
		||||
			.min = *ranges::lower_bound(
 | 
			
		||||
				chartData.xPercentage,
 | 
			
		||||
				xPercentageLimits.min),
 | 
			
		||||
			.max = *ranges::lower_bound(
 | 
			
		||||
				chartData.xPercentage,
 | 
			
		||||
				xPercentageLimits.max),
 | 
			
		||||
		const auto startXIndex = chartData.findStartIndex(
 | 
			
		||||
			_animValueXMin.to());
 | 
			
		||||
		const auto endXIndex = chartData.findEndIndex(
 | 
			
		||||
			startXIndex,
 | 
			
		||||
			_animValueXMax.to());
 | 
			
		||||
		_finalHeightLimits = {
 | 
			
		||||
			float64(FindMinValue(chartData, startXIndex, endXIndex)),
 | 
			
		||||
			float64(FindMaxValue(chartData, startXIndex, endXIndex)),
 | 
			
		||||
		};
 | 
			
		||||
		for (auto i = 0; i < chartData.xPercentage.size(); i++) {
 | 
			
		||||
			if (chartData.xPercentage[i] == tempXPercentage.min) {
 | 
			
		||||
				minYIndex = i;
 | 
			
		||||
			}
 | 
			
		||||
			if (chartData.xPercentage[i] == tempXPercentage.max) {
 | 
			
		||||
				maxYIndex = i;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		for (const auto &line : chartData.lines) {
 | 
			
		||||
			for (auto i = minYIndex; i < maxYIndex; i++) {
 | 
			
		||||
				if (line.y[i] > maxY) {
 | 
			
		||||
					maxY = line.y[i];
 | 
			
		||||
				}
 | 
			
		||||
				if (line.y[i] < minY) {
 | 
			
		||||
					minY = line.y[i];
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
	}
 | 
			
		||||
	_animValueYMin = anim::value(
 | 
			
		||||
		_animValueYMin.current(),
 | 
			
		||||
			minY);
 | 
			
		||||
		_finalHeightLimits.min);
 | 
			
		||||
	_animValueYMax = anim::value(
 | 
			
		||||
		_animValueYMax.current(),
 | 
			
		||||
			maxY);
 | 
			
		||||
		_finalHeightLimits.max);
 | 
			
		||||
 | 
			
		||||
	{
 | 
			
		||||
		auto k = (_animValueYMax.current() - _animValueYMin.current())
 | 
			
		||||
				/ float64(maxY - minY);
 | 
			
		||||
			/ float64(_finalHeightLimits.max - _finalHeightLimits.min);
 | 
			
		||||
		if (k > 1.) {
 | 
			
		||||
			k = 1. / k;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -179,19 +257,6 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
 | 
			
		|||
			_dtCurrent = { 0., 0. };
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
	{
 | 
			
		||||
		const auto startXIndex = chartData.findStartIndex(
 | 
			
		||||
			_animValueXMin.to());
 | 
			
		||||
		const auto endXIndex = chartData.findEndIndex(
 | 
			
		||||
			startXIndex,
 | 
			
		||||
			_animValueXMax.to());
 | 
			
		||||
		_finalHeightLimits = {
 | 
			
		||||
			float64(FindMinValue(chartData, startXIndex, endXIndex)),
 | 
			
		||||
			float64(FindMaxValue(chartData, startXIndex, endXIndex)),
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ChartWidget::ChartAnimationController::start() {
 | 
			
		||||
| 
						 | 
				
			
			@ -312,104 +377,6 @@ auto ChartWidget::ChartAnimationController::heightAnimationStarts() const
 | 
			
		|||
	return _heightAnimationStarts.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
 | 
			
		||||
: Ui::AbstractButton(parent)
 | 
			
		||||
, _left(Ui::CreateChild<Ui::AbstractButton>(this))
 | 
			
		||||
, _right(Ui::CreateChild<Ui::AbstractButton>(this)) {
 | 
			
		||||
	sizeValue(
 | 
			
		||||
	) | rpl::start_with_next([=](const QSize &s) {
 | 
			
		||||
		_left->resize(st::colorSliderWidth, s.height());
 | 
			
		||||
		_right->resize(st::colorSliderWidth, s.height());
 | 
			
		||||
	}, _left->lifetime());
 | 
			
		||||
	_left->paintRequest(
 | 
			
		||||
	) | rpl::start_with_next([=] {
 | 
			
		||||
		auto p = QPainter(_left);
 | 
			
		||||
		p.setOpacity(0.3);
 | 
			
		||||
		p.fillRect(_left->rect(), st::boxTextFg);
 | 
			
		||||
	}, _left->lifetime());
 | 
			
		||||
	_right->paintRequest(
 | 
			
		||||
	) | rpl::start_with_next([=] {
 | 
			
		||||
		auto p = QPainter(_right);
 | 
			
		||||
		p.setOpacity(0.3);
 | 
			
		||||
		p.fillRect(_right->rect(), st::boxTextFg);
 | 
			
		||||
	}, _right->lifetime());
 | 
			
		||||
 | 
			
		||||
	_left->move(10, 0);
 | 
			
		||||
	_right->move(50, 0);
 | 
			
		||||
 | 
			
		||||
	const auto handleDrag = [&](
 | 
			
		||||
			not_null<Ui::AbstractButton*> side,
 | 
			
		||||
			Fn<int()> leftLimit,
 | 
			
		||||
			Fn<int()> rightLimit) {
 | 
			
		||||
		side->events(
 | 
			
		||||
		) | rpl::filter([=](not_null<QEvent*> e) {
 | 
			
		||||
			return (e->type() == QEvent::MouseButtonPress)
 | 
			
		||||
				|| (e->type() == QEvent::MouseButtonRelease)
 | 
			
		||||
				|| ((e->type() == QEvent::MouseMove) && side->isDown());
 | 
			
		||||
		}) | rpl::start_with_next([=](not_null<QEvent*> e) {
 | 
			
		||||
			const auto pos = static_cast<QMouseEvent*>(e.get())->pos();
 | 
			
		||||
			switch (e->type()) {
 | 
			
		||||
			case QEvent::MouseMove: {
 | 
			
		||||
				const auto nowDiffXDirection = (pos.x() - _start.x) < 0;
 | 
			
		||||
				const auto wasDiffXDirection = _start.diffX < 0;
 | 
			
		||||
				if (base::IsCtrlPressed()) {
 | 
			
		||||
					const auto diff = (pos.x() - _start.x);
 | 
			
		||||
					_left->move(_left->x() + diff, side->y());
 | 
			
		||||
					_right->move(_right->x() + diff, side->y());
 | 
			
		||||
				} else {
 | 
			
		||||
					_start.diffX = pos.x() - _start.x;
 | 
			
		||||
					const auto nextX = std::clamp(
 | 
			
		||||
						side->x() + (pos.x() - _start.x),
 | 
			
		||||
						_start.leftLimit,
 | 
			
		||||
						_start.rightLimit);
 | 
			
		||||
					side->move(nextX, side->y());
 | 
			
		||||
				}
 | 
			
		||||
				_xPercentageLimitsChange.fire({
 | 
			
		||||
					.min = _left->x() / float64(width()),
 | 
			
		||||
					.max = rect::right(_right) / float64(width()),
 | 
			
		||||
				});
 | 
			
		||||
				if (nowDiffXDirection != wasDiffXDirection) {
 | 
			
		||||
					_directionChanges.fire({});
 | 
			
		||||
				}
 | 
			
		||||
			} break;
 | 
			
		||||
			case QEvent::MouseButtonPress: {
 | 
			
		||||
				_start.x = pos.x();
 | 
			
		||||
				_start.leftLimit = leftLimit();
 | 
			
		||||
				_start.rightLimit = rightLimit();
 | 
			
		||||
			} break;
 | 
			
		||||
			case QEvent::MouseButtonRelease: {
 | 
			
		||||
				_userInteractionFinished.fire({});
 | 
			
		||||
				_xPercentageLimitsChange.fire({
 | 
			
		||||
					.min = _left->x() / float64(width()),
 | 
			
		||||
					.max = rect::right(_right) / float64(width()),
 | 
			
		||||
				});
 | 
			
		||||
				_start = {};
 | 
			
		||||
			} break;
 | 
			
		||||
			}
 | 
			
		||||
		}, side->lifetime());
 | 
			
		||||
	};
 | 
			
		||||
	handleDrag(
 | 
			
		||||
		_left,
 | 
			
		||||
		[=] { return 0; },
 | 
			
		||||
		[=] { return _right->x() - _left->width(); });
 | 
			
		||||
	handleDrag(
 | 
			
		||||
		_right,
 | 
			
		||||
		[=] { return rect::right(_left); },
 | 
			
		||||
		[=] { return width() - _right->width(); });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl::producer<Limits> ChartWidget::Footer::xPercentageLimitsChange() const {
 | 
			
		||||
	return _xPercentageLimitsChange.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl::producer<> ChartWidget::Footer::userInteractionFinished() const {
 | 
			
		||||
	return _userInteractionFinished.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
rpl::producer<> ChartWidget::Footer::directionChanges() const {
 | 
			
		||||
	return _directionChanges.events();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
 | 
			
		||||
: Ui::RpWidget(parent)
 | 
			
		||||
, _footer(std::make_unique<Footer>(this))
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue