<commit_before>#include "ui_root.h"
#include "ui_widget.h"
#include "halley/core/api/audio_api.h"
#include "ui_painter.h"
#include "halley/audio/audio_position.h"
#include "halley/audio/audio_clip.h"
#include "halley/core/api/halley_api.h"
#include "halley/core/input/input_keyboard.h"
#include "halley/core/input/input_virtual.h"
#include "halley/maths/random.h"
#include "widgets/ui_tooltip.h"

using namespace Halley;

UIRoot::UIRoot(const HalleyAPI& api, Rect4f rect)
	: id("root")
	, audio(api.audio)
	, uiRect(rect)
	, dummyInput(std::make_shared<InputButtonBase>(4))
	, mouseRemap([](Vector2f p) { return p; })
{
	if (api.platform && api.platform->hasKeyboard()) {
		keyboard = api.platform->getKeyboard();
	} else {
		keyboard = api.input->getKeyboard();
	}
}

UIRoot::~UIRoot()
{
	keyPressListeners.clear();
	UIParent::clear();
}

UIRoot* UIRoot::getRoot()
{
	return this;
}

const UIRoot* UIRoot::getRoot() const
{
	return this;
}

const String& UIRoot::getId() const
{
	return id;
}

void UIRoot::setRect(Rect4f rect, Vector2f overscan)
{
	uiRect = Rect4f(rect.getTopLeft() + overscan, rect.getBottomRight() - overscan);
	this->overscan = overscan;
}

Rect4f UIRoot::getRect() const
{
	return uiRect;
}

void UIRoot::runLayout()
{
	for (auto& c: getChildren()) {
		c->layout();
	}
}

void UIRoot::update(Time t, UIInputType activeInputType, spInputDevice mouse, spInputDevice manual)
{
	auto joystickType = manual->getJoystickType();
	bool first = true;

	updateKeyboardInput();

	do {
		// Spawn new widgets
		addNewChildren(activeInputType);

		// Update input
		if (activeInputType == UIInputType::Mouse) {
			updateMouse(mouse);
		}
		updateGamepadInput(manual);

		// Update children
		for (auto& c: getChildren()) {
			c->doUpdate(first ? UIWidgetUpdateType::First : UIWidgetUpdateType::Full, t, activeInputType, joystickType);
		}
		first = false;
		removeDeadChildren();

		// Layout all widgets
		runLayout();

		// Update again, to reflect what happened >_>
		for (auto& c: getChildren()) {
			c->doUpdate(UIWidgetUpdateType::Partial, 0, activeInputType, joystickType);
		}

		// For subsequent iterations, make sure t = 0
		t = 0;
	} while (isWaitingToSpawnChildren());
}

void UIRoot::updateGamepadInputTree(const spInputDevice& input, UIWidget& widget, std::vector<UIWidget*>& inputTargets, UIGamepadInput::Priority& bestPriority, bool accepting)
{
	if (!widget.isActive()) {
		return;
	}

	if (!widget.isEnabled()) {
		accepting = false;
	}

	for (auto& c: widget.getChildren()) {
		// Depth-first
		updateGamepadInputTree(input, *c, inputTargets, bestPriority, accepting);
	}

	if (widget.gamepadInputButtons) {
		widget.gamepadInputResults.reset();
		if (accepting) {
			auto priority = widget.getInputPriority();

			if (static_cast<int>(priority) > static_cast<int>(bestPriority)) {
				bestPriority = priority;
				inputTargets.clear();
			}
			if (priority == bestPriority) {
				inputTargets.push_back(&widget);
			}
		}
	}
}

void UIRoot::updateGamepadInput(const spInputDevice& input)
{
	auto& cs = getChildren();
	std::vector<UIWidget*> inputTargets;
	UIGamepadInput::Priority bestPriority = UIGamepadInput::Priority::Lowest;

	bool accepting = true;
	for (int i = int(cs.size()); --i >= 0; ) {
		auto& c = *cs[i];
		updateGamepadInputTree(input, c, inputTargets, bestPriority, accepting);

		if (c.isMouseBlocker()) {
			accepting = false;
		}
	}

	for (auto& target: inputTargets) {
		auto& b = *target->gamepadInputButtons;
		auto& results = target->gamepadInputResults;
		results.reset();
		if (b.accept != -1) {
			results.setButton(UIGamepadInput::Button::Accept, input->isButtonPressed(b.accept), input->isButtonReleased(b.accept), input->isButtonDown(b.accept));
		}
		if (b.cancel != -1) {
			results.setButton(UIGamepadInput::Button::Cancel, input->isButtonPressed(b.cancel), input->isButtonReleased(b.cancel), input->isButtonDown(b.cancel));
		}<commit_msg>Added 'active' check for widgets blocking mouse input<commit_after>#include "ui_root.h"
#include "ui_widget.h"
#include "halley/core/api/audio_api.h"
#include "ui_painter.h"
#include "halley/audio/audio_position.h"
#include "halley/audio/audio_clip.h"
#include "halley/core/api/halley_api.h"
#include "halley/core/input/input_keyboard.h"
#include "halley/core/input/input_virtual.h"
#include "halley/maths/random.h"
#include "widgets/ui_tooltip.h"

using namespace Halley;

UIRoot::UIRoot(const HalleyAPI& api, Rect4f rect)
	: id("root")
	, audio(api.audio)
	, uiRect(rect)
	, dummyInput(std::make_shared<InputButtonBase>(4))
	, mouseRemap([](Vector2f p) { return p; })
{
	if (api.platform && api.platform->hasKeyboard()) {
		keyboard = api.platform->getKeyboard();
	} else {
		keyboard = api.input->getKeyboard();
	}
}

UIRoot::~UIRoot()
{
	keyPressListeners.clear();
	UIParent::clear();
}

UIRoot* UIRoot::getRoot()
{
	return this;
}

const UIRoot* UIRoot::getRoot() const
{
	return this;
}

const String& UIRoot::getId() const
{
	return id;
}

void UIRoot::setRect(Rect4f rect, Vector2f overscan)
{
	uiRect = Rect4f(rect.getTopLeft() + overscan, rect.getBottomRight() - overscan);
	this->overscan = overscan;
}

Rect4f UIRoot::getRect() const
{
	return uiRect;
}

void UIRoot::runLayout()
{
	for (auto& c: getChildren()) {
		c->layout();
	}
}

void UIRoot::update(Time t, UIInputType activeInputType, spInputDevice mouse, spInputDevice manual)
{
	auto joystickType = manual->getJoystickType();
	bool first = true;

	updateKeyboardInput();

	do {
		// Spawn new widgets
		addNewChildren(activeInputType);

		// Update input
		if (activeInputType == UIInputType::Mouse) {
			updateMouse(mouse);
		}
		updateGamepadInput(manual);

		// Update children
		for (auto& c: getChildren()) {
			c->doUpdate(first ? UIWidgetUpdateType::First : UIWidgetUpdateType::Full, t, activeInputType, joystickType);
		}
		first = false;
		removeDeadChildren();

		// Layout all widgets
		runLayout();

		// Update again, to reflect what happened >_>
		for (auto& c: getChildren()) {
			c->doUpdate(UIWidgetUpdateType::Partial, 0, activeInputType, joystickType);
		}

		// For subsequent iterations, make sure t = 0
		t = 0;
	} while (isWaitingToSpawnChildren());
}

void UIRoot::updateGamepadInputTree(const spInputDevice& input, UIWidget& widget, std::vector<UIWidget*>& inputTargets, UIGamepadInput::Priority& bestPriority, bool accepting)
{
	if (!widget.isActive()) {
		return;
	}

	if (!widget.isEnabled()) {
		accepting = false;
	}

	for (auto& c: widget.getChildren()) {
		// Depth-first
		updateGamepadInputTree(input, *c, inputTargets, bestPriority, accepting);
	}

	if (widget.gamepadInputButtons) {
		widget.gamepadInputResults.reset();
		if (accepting) {
			auto priority = widget.getInputPriority();

			if (static_cast<int>(priority) > static_cast<int>(bestPriority)) {
				bestPriority = priority;
				inputTargets.clear();
			}
			if (priority == bestPriority) {
				inputTargets.push_back(&widget);
			}
		}
	}
}

void UIRoot::updateGamepadInput(const spInputDevice& input)
{
	auto& cs = getChildren();
	std::vector<UIWidget*> inputTargets;
	UIGamepadInput::Priority bestPriority = UIGamepadInput::Priority::Lowest;

	bool accepting = true;
	for (int i = int(cs.size()); --i >= 0; ) {
		auto& c = *cs[i];
		updateGamepadInputTree(input, c, inputTargets, bestPriority, accepting);

		if (c.isMouseBlocker() && c.isActive()) {
			accepting = false;
		}
	}

	for (auto& target: inputTargets) {
		auto& b = *target->gamepadInputButtons;
		auto& results = target->gamepadInputResults;
		results.reset();
		if (b.accept != -1) {
			results.setButton(UIGamepadInput::Button::Accept, input->isButtonPressed(b.accept), input->isButtonReleased(b.accept), input->isButtonDown(b.accept));
		}
		if (b.cancel != -1) {
			results.setButton(UIGamepadInput::Button::Cancel, input->isButtonPressed(b.cancel), input->isButtonReleased(b.cancel), input->isButtonDown(b.cancel));
		}
{'fraction_non_alphanumeric': 0.1527601119308064, 'fraction_numerical': 0.003307046553039939, 'mean_word_length': 4.970387243735763, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6866169', 'n_tokens_mistral': 2973, 'n_tokens_neox': 2795, 'n_words': 540}