183 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// This file is part of Desktop App Toolkit,
 | 
						|
// a set of libraries for developing nice desktop applications.
 | 
						|
//
 | 
						|
// For license and copyright information please follow this link:
 | 
						|
// https://github.com/desktop-app/legal/blob/master/LEGAL
 | 
						|
//
 | 
						|
#include "ui/click_handler.h"
 | 
						|
 | 
						|
#include "base/algorithm.h"
 | 
						|
#include "ui/text/text_entity.h"
 | 
						|
 | 
						|
#include <QtCore/QPointer>
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
ClickHandlerPtr &ClickHandlerActive() {
 | 
						|
	static auto result = ClickHandlerPtr();
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
ClickHandlerPtr &ClickHandlerPressed() {
 | 
						|
	static auto result = ClickHandlerPtr();
 | 
						|
	return result;
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 | 
						|
 | 
						|
ClickHandlerHost *ClickHandler::_activeHost = nullptr;
 | 
						|
ClickHandlerHost *ClickHandler::_pressedHost = nullptr;
 | 
						|
 | 
						|
ClickHandlerHost::~ClickHandlerHost() {
 | 
						|
	ClickHandler::hostDestroyed(this);
 | 
						|
}
 | 
						|
 | 
						|
bool ClickHandler::setActive(
 | 
						|
		const ClickHandlerPtr &p,
 | 
						|
		ClickHandlerHost *host) {
 | 
						|
	auto &active = ClickHandlerActive();
 | 
						|
	auto &pressed = ClickHandlerPressed();
 | 
						|
 | 
						|
	if (active == p) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
 | 
						|
	// emit clickHandlerActiveChanged only when there is no
 | 
						|
	// other pressed click handler currently, if there is
 | 
						|
	// this method will be called when it is unpressed
 | 
						|
	if (active) {
 | 
						|
		const auto emitClickHandlerActiveChanged = false
 | 
						|
			|| !pressed
 | 
						|
			|| (pressed == active);
 | 
						|
		const auto wasactive = base::take(active);
 | 
						|
		if (_activeHost) {
 | 
						|
			if (emitClickHandlerActiveChanged) {
 | 
						|
				_activeHost->clickHandlerActiveChanged(wasactive, false);
 | 
						|
			}
 | 
						|
			_activeHost = nullptr;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (p) {
 | 
						|
		active = p;
 | 
						|
		if ((_activeHost = host)) {
 | 
						|
			bool emitClickHandlerActiveChanged = (!pressed || pressed == active);
 | 
						|
			if (emitClickHandlerActiveChanged) {
 | 
						|
				_activeHost->clickHandlerActiveChanged(active, true);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
bool ClickHandler::clearActive(ClickHandlerHost *host) {
 | 
						|
	if (host && _activeHost != host) {
 | 
						|
		return false;
 | 
						|
	}
 | 
						|
	return setActive(ClickHandlerPtr(), host);
 | 
						|
}
 | 
						|
 | 
						|
void ClickHandler::pressed() {
 | 
						|
	auto &active = ClickHandlerActive();
 | 
						|
	auto &pressed = ClickHandlerPressed();
 | 
						|
 | 
						|
	unpressed();
 | 
						|
	if (!active) {
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	pressed = active;
 | 
						|
	if ((_pressedHost = _activeHost)) {
 | 
						|
		_pressedHost->clickHandlerPressedChanged(pressed, true);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
ClickHandlerPtr ClickHandler::unpressed() {
 | 
						|
	auto &active = ClickHandlerActive();
 | 
						|
	auto &pressed = ClickHandlerPressed();
 | 
						|
 | 
						|
	if (pressed) {
 | 
						|
		const auto activated = (active == pressed);
 | 
						|
		const auto waspressed = base::take(pressed);
 | 
						|
		if (_pressedHost) {
 | 
						|
			_pressedHost->clickHandlerPressedChanged(waspressed, false);
 | 
						|
			_pressedHost = nullptr;
 | 
						|
		}
 | 
						|
 | 
						|
		if (activated) {
 | 
						|
			return active;
 | 
						|
		} else if (active && _activeHost) {
 | 
						|
			// emit clickHandlerActiveChanged for current active
 | 
						|
			// click handler, which we didn't emit while we has
 | 
						|
			// a pressed click handler
 | 
						|
			_activeHost->clickHandlerActiveChanged(active, true);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return ClickHandlerPtr();
 | 
						|
}
 | 
						|
 | 
						|
ClickHandlerPtr ClickHandler::getActive() {
 | 
						|
	return ClickHandlerActive();
 | 
						|
}
 | 
						|
 | 
						|
ClickHandlerPtr ClickHandler::getPressed() {
 | 
						|
	return ClickHandlerPressed();
 | 
						|
}
 | 
						|
 | 
						|
bool ClickHandler::showAsActive(const ClickHandlerPtr &p) {
 | 
						|
	auto &active = ClickHandlerActive();
 | 
						|
	auto &pressed = ClickHandlerPressed();
 | 
						|
 | 
						|
	return p && (p == active) && (!pressed || (p == pressed));
 | 
						|
}
 | 
						|
 | 
						|
bool ClickHandler::showAsPressed(const ClickHandlerPtr &p) {
 | 
						|
	auto &active = ClickHandlerActive();
 | 
						|
	auto &pressed = ClickHandlerPressed();
 | 
						|
 | 
						|
	return p && (p == active) && (p == pressed);
 | 
						|
}
 | 
						|
 | 
						|
void ClickHandler::hostDestroyed(ClickHandlerHost *host) {
 | 
						|
	auto &active = ClickHandlerActive();
 | 
						|
	auto &pressed = ClickHandlerPressed();
 | 
						|
 | 
						|
	if (_activeHost == host) {
 | 
						|
		active = nullptr;
 | 
						|
		_activeHost = nullptr;
 | 
						|
	}
 | 
						|
	if (_pressedHost == host) {
 | 
						|
		pressed = nullptr;
 | 
						|
		_pressedHost = nullptr;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
auto ClickHandler::getTextEntity() const -> TextEntity {
 | 
						|
	return { EntityType::Invalid };
 | 
						|
}
 | 
						|
 | 
						|
void ClickHandler::setProperty(int id, QVariant value) {
 | 
						|
	_properties[id] = std::move(value);
 | 
						|
}
 | 
						|
 | 
						|
const QVariant &ClickHandler::property(int id) const {
 | 
						|
	static const QVariant kEmpty;
 | 
						|
	const auto i = _properties.find(id);
 | 
						|
	return (i != end(_properties)) ? i->second : kEmpty;
 | 
						|
}
 | 
						|
 | 
						|
void ActivateClickHandler(
 | 
						|
		not_null<QWidget*> guard,
 | 
						|
		ClickHandlerPtr handler,
 | 
						|
		ClickContext context) {
 | 
						|
	crl::on_main(guard, [=, weak = std::weak_ptr<ClickHandler>(handler)] {
 | 
						|
		if (const auto strong = weak.lock()) {
 | 
						|
			strong->onClick(context);
 | 
						|
		}
 | 
						|
	});
 | 
						|
}
 | 
						|
 | 
						|
void ActivateClickHandler(
 | 
						|
		not_null<QWidget*> guard,
 | 
						|
		ClickHandlerPtr handler,
 | 
						|
		Qt::MouseButton button) {
 | 
						|
	ActivateClickHandler(guard, handler, ClickContext{ button });
 | 
						|
}
 |