212 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
	
		
			5.2 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/countryinput.h"
 | |
| 
 | |
| #include "lang/lang_keys.h"
 | |
| #include "ui/widgets/scroll_area.h"
 | |
| #include "ui/widgets/multi_select.h"
 | |
| #include "ui/effects/ripple_animation.h"
 | |
| #include "ui/boxes/country_select_box.h"
 | |
| #include "ui/painter.h"
 | |
| #include "countries/countries_instance.h"
 | |
| #include "window/window_session_controller.h"
 | |
| #include "styles/style_layers.h"
 | |
| #include "styles/style_boxes.h"
 | |
| #include "styles/style_intro.h"
 | |
| 
 | |
| CountryInput::CountryInput(
 | |
| 	QWidget *parent,
 | |
| 	std::shared_ptr<Window::Show> show,
 | |
| 	const style::InputField &st)
 | |
| : RpWidget(parent)
 | |
| , _show(show)
 | |
| , _st(st)
 | |
| , _text(tr::lng_country_code(tr::now)) {
 | |
| 	resize(_st.width, _st.heightMin);
 | |
| 
 | |
| 	auto placeholderFont = _st.placeholderFont->f;
 | |
| 	placeholderFont.setStyleStrategy(QFont::PreferMatch);
 | |
| 	//auto metrics = QFontMetrics(placeholderFont);
 | |
| 	auto placeholder = QString();// metrics.elidedText(tr::lng_country_fake_ph(tr::now), Qt::ElideRight, availableWidth);
 | |
| 	if (!placeholder.isNull()) {
 | |
| 		_placeholderPath.addText(
 | |
| 			0,
 | |
| 			QFontMetrics(placeholderFont).ascent(),
 | |
| 			placeholderFont,
 | |
| 			placeholder);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CountryInput::paintEvent(QPaintEvent *e) {
 | |
| 	auto p = QPainter(this);
 | |
| 
 | |
| 	QRect r(rect().intersected(e->rect()));
 | |
| 	if (_st.textBg->c.alphaF() > 0.) {
 | |
| 		p.fillRect(r, _st.textBg);
 | |
| 	}
 | |
| 	if (_st.border) {
 | |
| 		p.fillRect(
 | |
| 			0,
 | |
| 			height() - _st.border,
 | |
| 			width(),
 | |
| 			_st.border,
 | |
| 			_st.borderFg);
 | |
| 	}
 | |
| 
 | |
| 	st::introCountryIcon.paint(
 | |
| 		p,
 | |
| 		width()
 | |
| 			- st::introCountryIcon.width()
 | |
| 			- st::introCountryIconPosition.x(),
 | |
| 		st::introCountryIconPosition.y(),
 | |
| 		width());
 | |
| 
 | |
| 	p.setFont(_st.font);
 | |
| 	p.setPen(_st.textFg);
 | |
| 	p.drawText(rect().marginsRemoved(_st.textMargins), _text, _st.textAlign);
 | |
| 	if (!_placeholderPath.isEmpty()) {
 | |
| 		auto placeholderShiftDegree = 1.;
 | |
| 		p.save();
 | |
| 		p.setClipRect(r);
 | |
| 
 | |
| 		const auto placeholderTop = anim::interpolate(
 | |
| 			0,
 | |
| 			_st.placeholderShift,
 | |
| 			placeholderShiftDegree);
 | |
| 
 | |
| 		auto r = QRect(rect() - (_st.textMargins + _st.placeholderMargins));
 | |
| 		r.moveTop(r.top() + placeholderTop);
 | |
| 		if (rtl()) {
 | |
| 			r.moveLeft(width() - r.left() - r.width());
 | |
| 		}
 | |
| 
 | |
| 		const auto placeholderScale = 1.
 | |
| 			- (1. - _st.placeholderScale) * placeholderShiftDegree;
 | |
| 		auto placeholderFg = anim::color(
 | |
| 			_st.placeholderFg,
 | |
| 			_st.placeholderFgActive,
 | |
| 			0.);
 | |
| 		placeholderFg = anim::color(
 | |
| 			placeholderFg,
 | |
| 			_st.placeholderFgError,
 | |
| 			0.);
 | |
| 
 | |
| 		PainterHighQualityEnabler hq(p);
 | |
| 		p.setPen(Qt::NoPen);
 | |
| 		p.setBrush(placeholderFg);
 | |
| 		p.translate(r.topLeft());
 | |
| 		p.scale(placeholderScale, placeholderScale);
 | |
| 		p.drawPath(_placeholderPath);
 | |
| 
 | |
| 		p.restore();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CountryInput::mouseMoveEvent(QMouseEvent *e) {
 | |
| 	bool newActive = rect().contains(e->pos());
 | |
| 	if (_active != newActive) {
 | |
| 		_active = newActive;
 | |
| 		setCursor(_active ? style::cur_pointer : style::cur_default);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CountryInput::mousePressEvent(QMouseEvent *e) {
 | |
| 	mouseMoveEvent(e);
 | |
| 	if (_active) {
 | |
| 		auto object = Box<Ui::CountrySelectBox>();
 | |
| 		const auto box = Ui::MakeWeak(object.data());
 | |
| 		_show->showBox(std::move(object), Ui::LayerOption::CloseOther);
 | |
| 		box->entryChosen(
 | |
| 		) | rpl::start_with_next([=](
 | |
| 				const Ui::CountrySelectBox::Entry &entry) {
 | |
| 			if (box) {
 | |
| 				box->closeBox();
 | |
| 			}
 | |
| 
 | |
| 			const auto &list = Countries::Instance().list();
 | |
| 			const auto infoIt = ranges::find(
 | |
| 				list,
 | |
| 				entry.iso2,
 | |
| 				&Countries::Info::iso2);
 | |
| 			if (infoIt == end(list)) {
 | |
| 				return;
 | |
| 			}
 | |
| 			const auto info = *infoIt;
 | |
| 			const auto it = ranges::find(
 | |
| 				info.codes,
 | |
| 				entry.code,
 | |
| 				&Countries::CallingCodeInfo::callingCode);
 | |
| 			if (it != end(info.codes)) {
 | |
| 				chooseCountry(
 | |
| 					&info,
 | |
| 					std::distance(begin(info.codes), it));
 | |
| 			}
 | |
| 		}, lifetime());
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void CountryInput::enterEventHook(QEnterEvent *e) {
 | |
| 	setMouseTracking(true);
 | |
| }
 | |
| 
 | |
| void CountryInput::leaveEventHook(QEvent *e) {
 | |
| 	setMouseTracking(false);
 | |
| 	_active = false;
 | |
| 	setCursor(style::cur_default);
 | |
| }
 | |
| 
 | |
| void CountryInput::onChooseCode(const QString &code) {
 | |
| 	_show->hideLayer();
 | |
| 	_chosenIso = QString();
 | |
| 	if (code.length()) {
 | |
| 		const auto &byCode = Countries::Instance().byCode();
 | |
| 		const auto i = byCode.constFind(code);
 | |
| 		if (i != byCode.cend()) {
 | |
| 			const auto info = *i;
 | |
| 			_chosenIso = info->iso2;
 | |
| 			setText(info->name);
 | |
| 		} else {
 | |
| 			setText(tr::lng_bad_country_code(tr::now));
 | |
| 		}
 | |
| 	} else {
 | |
| 		setText(tr::lng_country_code(tr::now));
 | |
| 	}
 | |
| 	update();
 | |
| }
 | |
| 
 | |
| bool CountryInput::chooseCountry(const QString &iso) {
 | |
| 	const auto &byISO2 = Countries::Instance().byISO2();
 | |
| 	const auto i = byISO2.constFind(iso);
 | |
| 	const auto info = (i != byISO2.cend()) ? (*i) : nullptr;
 | |
| 
 | |
| 	_chosenIso = QString();
 | |
| 	if (info) {
 | |
| 		chooseCountry(info, 0);
 | |
| 		return true;
 | |
| 	}
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| void CountryInput::chooseCountry(
 | |
| 		not_null<const Countries::Info*> info,
 | |
| 		int codeIndex) {
 | |
| 	_chosenIso = info->iso2;
 | |
| 	setText(info->name);
 | |
| 	_codeChanged.fire_copy(info->codes[codeIndex].callingCode);
 | |
| 	update();
 | |
| }
 | |
| 
 | |
| rpl::producer<QString> CountryInput::codeChanged() const {
 | |
| 	return _codeChanged.events();
 | |
| }
 | |
| 
 | |
| void CountryInput::setText(const QString &newText) {
 | |
| 	_text = _st.font->elided(
 | |
| 		newText,
 | |
| 		width() - _st.textMargins.left() - _st.textMargins.right());
 | |
| }
 | 
