154 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			154 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
This file is part of Telegram Desktop,
 | 
						|
the official desktop application for the Telegram messaging service.
 | 
						|
 | 
						|
For license and copyright information please follow this link:
 | 
						|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
 | 
						|
*/
 | 
						|
#include "ui/boxes/time_picker_box.h"
 | 
						|
 | 
						|
#include "base/event_filter.h"
 | 
						|
#include "lang/lang_keys.h"
 | 
						|
#include "ui/layers/generic_box.h"
 | 
						|
#include "ui/effects/animation_value.h"
 | 
						|
#include "ui/ui_utility.h"
 | 
						|
#include "ui/widgets/vertical_drum_picker.h"
 | 
						|
#include "styles/style_chat_helpers.h"
 | 
						|
#include "styles/style_layers.h"
 | 
						|
 | 
						|
namespace Ui {
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
constexpr auto kMinYScale = 0.2;
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
std::vector<TimeId> DefaultTimePickerValues() {
 | 
						|
	return {
 | 
						|
		(60 * 15),
 | 
						|
		(60 * 30),
 | 
						|
		(3600 * 1),
 | 
						|
		(3600 * 2),
 | 
						|
		(3600 * 3),
 | 
						|
		(3600 * 4),
 | 
						|
		(3600 * 8),
 | 
						|
		(3600 * 12),
 | 
						|
		(86400 * 1),
 | 
						|
		(86400 * 2),
 | 
						|
		(86400 * 3),
 | 
						|
		(86400 * 7 * 1),
 | 
						|
		(86400 * 7 * 2),
 | 
						|
		(86400 * 31 * 1),
 | 
						|
		(86400 * 31 * 2),
 | 
						|
		(86400 * 31 * 3),
 | 
						|
	};
 | 
						|
}
 | 
						|
 | 
						|
Fn<TimeId()> TimePickerBox(
 | 
						|
		not_null<GenericBox*> box,
 | 
						|
		std::vector<TimeId> values,
 | 
						|
		std::vector<QString> phrases,
 | 
						|
		TimeId startValue) {
 | 
						|
	Expects(phrases.size() == values.size());
 | 
						|
 | 
						|
	const auto startIndex = [&, &v = startValue] {
 | 
						|
		const auto it = ranges::lower_bound(values, v);
 | 
						|
		if (it == begin(values)) {
 | 
						|
			return 0;
 | 
						|
		}
 | 
						|
		const auto left = *(it - 1);
 | 
						|
		const auto right = *it;
 | 
						|
		const auto shift = (std::abs(v - left) < std::abs(v - right))
 | 
						|
			? -1
 | 
						|
			: 0;
 | 
						|
		return int(std::distance(begin(values), it - shift));
 | 
						|
	}();
 | 
						|
 | 
						|
	const auto content = box->addRow(object_ptr<Ui::FixedHeightWidget>(
 | 
						|
		box,
 | 
						|
		st::historyMessagesTTLPickerHeight));
 | 
						|
 | 
						|
	const auto font = st::boxTextFont;
 | 
						|
	const auto maxPhraseWidth = [&] {
 | 
						|
		// We have to use QFontMetricsF instead of
 | 
						|
		// FontData::width for more precise calculation.
 | 
						|
		const auto mf = QFontMetricsF(font->f);
 | 
						|
		const auto maxPhrase = ranges::max_element(
 | 
						|
			phrases,
 | 
						|
			std::less<>(),
 | 
						|
			[&](const QString &s) { return mf.horizontalAdvance(s); });
 | 
						|
		return std::ceil(mf.horizontalAdvance(*maxPhrase));
 | 
						|
	}();
 | 
						|
	const auto itemHeight = st::historyMessagesTTLPickerItemHeight;
 | 
						|
	auto paintCallback = [=](
 | 
						|
			QPainter &p,
 | 
						|
			int index,
 | 
						|
			float64 y,
 | 
						|
			float64 distanceFromCenter,
 | 
						|
			int outerWidth) {
 | 
						|
		const auto r = QRectF(0, y, outerWidth, itemHeight);
 | 
						|
		const auto progress = std::abs(distanceFromCenter);
 | 
						|
		const auto revProgress = 1. - progress;
 | 
						|
		p.save();
 | 
						|
		p.translate(r.center());
 | 
						|
		const auto yScale = kMinYScale
 | 
						|
			+ (1. - kMinYScale) * anim::easeOutCubic(1., revProgress);
 | 
						|
		p.scale(1., yScale);
 | 
						|
		p.translate(-r.center());
 | 
						|
		p.setOpacity(revProgress);
 | 
						|
		p.setFont(font);
 | 
						|
		p.setPen(st::defaultFlatLabel.textFg);
 | 
						|
		p.drawText(r, phrases[index], style::al_center);
 | 
						|
		p.restore();
 | 
						|
	};
 | 
						|
 | 
						|
	const auto picker = Ui::CreateChild<Ui::VerticalDrumPicker>(
 | 
						|
		content,
 | 
						|
		std::move(paintCallback),
 | 
						|
		phrases.size(),
 | 
						|
		itemHeight,
 | 
						|
		startIndex);
 | 
						|
 | 
						|
	content->sizeValue(
 | 
						|
	) | rpl::start_with_next([=](const QSize &s) {
 | 
						|
		picker->resize(maxPhraseWidth, s.height());
 | 
						|
		picker->moveToLeft((s.width() - picker->width()) / 2, 0);
 | 
						|
	}, content->lifetime());
 | 
						|
 | 
						|
	content->paintRequest(
 | 
						|
	) | rpl::start_with_next([=](const QRect &r) {
 | 
						|
		auto p = QPainter(content);
 | 
						|
 | 
						|
		p.fillRect(r, Qt::transparent);
 | 
						|
 | 
						|
		const auto lineRect = QRect(
 | 
						|
			0,
 | 
						|
			content->height() / 2,
 | 
						|
			content->width(),
 | 
						|
			st::defaultInputField.borderActive);
 | 
						|
		p.fillRect(lineRect.translated(0, itemHeight / 2), st::activeLineFg);
 | 
						|
		p.fillRect(lineRect.translated(0, -itemHeight / 2), st::activeLineFg);
 | 
						|
	}, content->lifetime());
 | 
						|
 | 
						|
	base::install_event_filter(content, [=](not_null<QEvent*> e) {
 | 
						|
		if ((e->type() == QEvent::MouseButtonPress)
 | 
						|
			|| (e->type() == QEvent::MouseButtonRelease)
 | 
						|
			|| (e->type() == QEvent::MouseMove)) {
 | 
						|
			picker->handleMouseEvent(static_cast<QMouseEvent*>(e.get()));
 | 
						|
		} else if (e->type() == QEvent::Wheel) {
 | 
						|
			picker->handleWheelEvent(static_cast<QWheelEvent*>(e.get()));
 | 
						|
		}
 | 
						|
		return base::EventFilterResult::Continue;
 | 
						|
	});
 | 
						|
	base::install_event_filter(box, [=](not_null<QEvent*> e) {
 | 
						|
		if (e->type() == QEvent::KeyPress) {
 | 
						|
			picker->handleKeyEvent(static_cast<QKeyEvent*>(e.get()));
 | 
						|
		}
 | 
						|
		return base::EventFilterResult::Continue;
 | 
						|
	});
 | 
						|
 | 
						|
	return [=] { return values[picker->index()]; };
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Ui
 |