<commit_before>/*
 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
 * Distributed under the MIT License
 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
 */

#include "MyGUI_Precompiled.h"
#include "MyGUI_ScrollBar.h"
#include "MyGUI_InputManager.h"
#include "MyGUI_Button.h"
#include "MyGUI_ResourceSkin.h"
#include "MyGUI_ControllerRepeatClick.h"
#include "MyGUI_ControllerManager.h"

namespace MyGUI
{

	ScrollBar::ScrollBar() :
		mWidgetStart(nullptr),
		mWidgetEnd(nullptr),
		mWidgetTrack(nullptr),
		mWidgetFirstPart(nullptr),
		mWidgetSecondPart(nullptr),
		mSkinRangeStart(0),
		mSkinRangeEnd(0),
		mScrollRange(0),
		mScrollPosition(0),
		mScrollPage(0),
		mScrollViewPage(0),
		mScrollWheelPage(0),
		mEnableRepeat(true),
		mRepeatTriggerTime(0.f),
		mRepeatStepTime(0.f),
		mMinTrackSize(0),
		mMoveToClick(false),
		mVerticalAlignment(true)
	{
	}

	void ScrollBar::initialiseOverride()
	{
		Base::initialiseOverride();

		// при нуле, будет игнорировать кнопки
		mScrollPage = 1;
		mScrollViewPage = 1;
		mScrollWheelPage = 1;
		mMinTrackSize = 0;
		mSkinRangeStart = 0;
		mSkinRangeEnd = 0;

		mRepeatTriggerTime = 0.5f;
		mRepeatStepTime = 0.1f;

		///@wskin_child{ScrollBar, Button, Start} Кнопка начала диапазона.
		assignWidget(mWidgetStart, "Start");
		if (mWidgetStart != nullptr)
		{
			mWidgetStart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetStart->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetStart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		///@wskin_child{ScrollBar, Button, End} Кнопка конца диапазона.
		assignWidget(mWidgetEnd, "End");
		if (mWidgetEnd != nullptr)
		{
			mWidgetEnd->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetEnd->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetEnd->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		///@wskin_child{ScrollBar, Button, Track} Кнопка трекера.
		assignWidget(mWidgetTrack, "Track");
		if (mWidgetTrack)
		{
			mWidgetTrack->eventMouseDrag += newDelegate(this, &ScrollBar::notifyMouseDrag);
			mWidgetTrack->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetTrack->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetTrack->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
			mWidgetTrack->setVisible(false);
		}

		///@wskin_child{ScrollBar, Widget, FirstPart} Виджет первой половины прокрутки от начала до трекера, при нажатии восприницмается как прокрутка страницы.
		assignWidget(mWidgetFirstPart, "FirstPart");
		if (mWidgetFirstPart != nullptr)
		{
			mWidgetFirstPart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetFirstPart->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetFirstPart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		///@wskin_child{ScrollBar, Widget, SecondPart} Виджет второй половины прокрутки от трекера до конца, при нажатии восприницмается как прокрутка страницы.
		assignWidget(mWidgetSecondPart, "SecondPart");
		if (mWidgetSecondPart != nullptr)
		{
			mWidgetSecondPart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetSecondPart->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetSecondPart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		if (isUserString("MinTrackSize"))
			mMinTrackSize = utility::parseValue<int>(getUserString("MinTrackSize"));

		if (isUserString("TrackRangeMargins"))
			utility::parseComplex<size_t>(getUserString("TrackRangeMargins"), mSkinRangeStart, mSkinRangeEnd);

		if (mWidgetTrack != nullptr)
		{
			if (mWidgetTrack->isUserString("MinTrackSize"))
				mMinTrackSize = utility::parseValue<int>(mWidgetTrack->getUserString("MinTrackSize"));
		}
	}

	void ScrollBar::shutdownOverride()
	{
		mWidgetStart = nullptr;
		mWidgetEnd = nullptr;
		mWidgetTrack = nullptr;
		mWidgetFirstPart = nullptr;
		mWidgetSecondPart = nullptr;

		Base::shutdownOverride();
	}

	void ScrollBar::updateTrack()
	{
		if (mWidgetTrack == nullptr)
			return;

		_forcePick(mWidgetTrack);
		// размер диапазана в пикселях
		int pos = getLineSize();

		if (mVerticalAlignment)
		{
			// скрываем если диапазан маленький или места мало
			if ((mScrollRange < 2) || (pos <= mWidgetTrack->getHeight()))
			{
				mWidgetTrack->setVisible(false);
				if (nullptr != mWidgetFirstPart)
					mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), pos / 2);
				if (nullptr != mWidgetSecondPart)
					mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), pos / 2 + (int)mSkinRangeStart, mWidgetSecondPart->getWidth(), pos - pos / 2);
				return;
			}
			// если скрыт то покажем
			if (!mWidgetTrack->getVisible())
				mWidgetTrack->setVisible(true);

			// и обновляем позицию
			pos = (int)(((size_t)(pos - getTrackSize()) * mScrollPosition) / (mScrollRange - 1) + mSkinRangeStart);

			mWidgetTrack->setPosition(mWidgetTrack->getLeft(), pos);
			if (nullptr != mWidgetFirstPart)
			{
				int height = pos - mWidgetFirstPart->getTop();
				mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), height);
			}
			if (nullptr != mWidgetSecondPart)
			{
				int top = pos + mWidgetTrack->getHeight();
				int height = mWidgetSecondPart->getHeight() + mWidgetSecondPart->getTop() - top;
				mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), top, mWidgetSecondPart->getWidth(), height);
			}
		}
		else
		{
			// скрываем если диапазан маленький или места мало
			if ((mScrollRange < 2) || (pos <= mWidgetTrack->getWidth()))
			{
				mWidgetTrack->setVisible(false);
				if (nullptr != mWidgetFirstPart)
					mWidgetFirstPart->setSize(pos / 2, mWidgetFirstPart->getHeight());
				if (nullptr != mWidgetSecondPart)
					mWidgetSecondPart->setCoord(pos / 2 + (int)mSkinRangeStart, mWidgetSecondPart->getTop(), pos - pos / 2, mWidgetSecondPart->getHeight());
				return;
			}
			// если скрыт то покажем
			if (!mWidgetTrack->getVisible())
				mWidgetTrack->setVisible(true);

			// и обновляем позицию
			pos = (int)(((size_t)(pos - getTrackSize()) * mScrollPosition) / (mScrollRange - 1) + mSkinRangeStart);

			mWidgetTrack->setPosition(pos, mWidgetTrack->getTop());
			if (nullptr != mWidgetFirstPart)
			{
				int height = pos - mWidgetFirstPart->getLeft();
				mWidgetFirstPart->setSize(height, mWidgetFirstPart->getHeight());
			}
			if (nullptr != mWidgetSecondPart)
			{
				int top = pos + mWidgetTrack->getWidth();
				int height = mWidgetSecondPart->getWidth() + mWidgetSecondPart->getLeft() - top;
				mWidgetSecondPart->setCoord(top, mWidgetSecondPart->getTop(), height, mWidgetSecondPart->getHeight());
			}
		}
	}

	void ScrollBar::TrackMove(int _left, int _top)
	{
		if (mWidgetTrack == nullptr)
			return;

		const IntPoint& point = InputManager::getInstance().getLastPressedPosition(MouseButton::Left);

		if (mVerticalAlignment)
		{
			// расчитываем позицию виджета
			int start = mPreActionOffset.top + (_top - point.top);
			if (start < (int)mSkinRangeStart)
				start = (int)mSkinRangeStart;
			else if (start > (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getHeight()))
				start = (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getHeight());
			if (mWidgetTrack->getTop() != start)
				mWidgetTrack->setPosition(mWidgetTrack->getLeft(), start);

			// расчитываем положение соответствующее позиции
			// плюс пол позиции
			int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange - 1) * 2);
			// высчитываем ближайшее значение и обновляем
			pos = pos * (int)(mScrollRange - 1) / (getLineSize() - getTrackSize());

			// проверяем на выходы и изменения
			if (pos < 0)
				pos = 0;
			else if (pos >= (int)mScrollRange)
				pos = (int)mScrollRange - 1;
			if (pos == (int)mScrollPosition)
				return;

			mScrollPosition = pos;
		}
		else
		{
			// расчитываем позицию виджета
			int start = mPreActionOffset.left + (_left - point.left);
			if (start < (int)mSkinRangeStart)
				start = (int)mSkinRangeStart;
			else if (start > (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getWidth()))
				start = (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getWidth());
			if (mWidgetTrack->getLeft() != start)
				mWidgetTrack->setPosition(IntPoint(start, mWidgetTrack->getTop()));

			// расчитываем положение соответствующее позиции
			// плюс пол позиции
			int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange - 1) * 2);
			// высчитываем ближайшее значение и обновляем
			pos = pos * (int)(mScrollRange - 1) / (getLineSize() - getTrackSize());

			// проверяем на выходы и изменения
			if (pos < 0)
				pos = 0;
			else if (pos >= (int)mScrollRange)
				pos = (int)mScrollRange - 1;
			if (pos == (int)mScrollPosition)
				return;

			mScrollPosition = pos;
		}

		updateTrack();

		// отсылаем событие
		eventScrollChangePosition(this, (int)mScrollPosition);
	}

	void ScrollBar::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
	{
		// диспечерезируем нажатие своих детей как свое
		eventMouseButtonPressed(this, _left, _top, _id);

		if (MouseButton::Left != _id)
			return;

		if (mEnableRepeat && _sender != mWidgetTrack)
		{
			ControllerItem* item = ControllerManager::getInstance().createItem(ControllerRepeatClick::getClassTypeName());
			ControllerRepeatClick* controller = item->castType<ControllerRepeatClick>();
			controller->eventRepeatClick += newDelegate(this, &ScrollBar::repeatClick);
			controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime);
			ControllerManager::getInstance().addItem(_sender, controller);
		}

		if (mMoveToClick &&
			_sender != mWidgetTrack &&
			_sender != mWidgetStart &&<commit_msg>Fix scrollbar autorepeating issue with moveToClick enabled<commit_after>/*
 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
 * Distributed under the MIT License
 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
 */

#include "MyGUI_Precompiled.h"
#include "MyGUI_ScrollBar.h"
#include "MyGUI_InputManager.h"
#include "MyGUI_Button.h"
#include "MyGUI_ResourceSkin.h"
#include "MyGUI_ControllerRepeatClick.h"
#include "MyGUI_ControllerManager.h"

namespace MyGUI
{

	ScrollBar::ScrollBar() :
		mWidgetStart(nullptr),
		mWidgetEnd(nullptr),
		mWidgetTrack(nullptr),
		mWidgetFirstPart(nullptr),
		mWidgetSecondPart(nullptr),
		mSkinRangeStart(0),
		mSkinRangeEnd(0),
		mScrollRange(0),
		mScrollPosition(0),
		mScrollPage(0),
		mScrollViewPage(0),
		mScrollWheelPage(0),
		mEnableRepeat(true),
		mRepeatTriggerTime(0.f),
		mRepeatStepTime(0.f),
		mMinTrackSize(0),
		mMoveToClick(false),
		mVerticalAlignment(true)
	{
	}

	void ScrollBar::initialiseOverride()
	{
		Base::initialiseOverride();

		// при нуле, будет игнорировать кнопки
		mScrollPage = 1;
		mScrollViewPage = 1;
		mScrollWheelPage = 1;
		mMinTrackSize = 0;
		mSkinRangeStart = 0;
		mSkinRangeEnd = 0;

		mRepeatTriggerTime = 0.5f;
		mRepeatStepTime = 0.1f;

		///@wskin_child{ScrollBar, Button, Start} Кнопка начала диапазона.
		assignWidget(mWidgetStart, "Start");
		if (mWidgetStart != nullptr)
		{
			mWidgetStart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetStart->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetStart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		///@wskin_child{ScrollBar, Button, End} Кнопка конца диапазона.
		assignWidget(mWidgetEnd, "End");
		if (mWidgetEnd != nullptr)
		{
			mWidgetEnd->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetEnd->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetEnd->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		///@wskin_child{ScrollBar, Button, Track} Кнопка трекера.
		assignWidget(mWidgetTrack, "Track");
		if (mWidgetTrack)
		{
			mWidgetTrack->eventMouseDrag += newDelegate(this, &ScrollBar::notifyMouseDrag);
			mWidgetTrack->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetTrack->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetTrack->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
			mWidgetTrack->setVisible(false);
		}

		///@wskin_child{ScrollBar, Widget, FirstPart} Виджет первой половины прокрутки от начала до трекера, при нажатии восприницмается как прокрутка страницы.
		assignWidget(mWidgetFirstPart, "FirstPart");
		if (mWidgetFirstPart != nullptr)
		{
			mWidgetFirstPart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetFirstPart->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetFirstPart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		///@wskin_child{ScrollBar, Widget, SecondPart} Виджет второй половины прокрутки от трекера до конца, при нажатии восприницмается как прокрутка страницы.
		assignWidget(mWidgetSecondPart, "SecondPart");
		if (mWidgetSecondPart != nullptr)
		{
			mWidgetSecondPart->eventMouseButtonPressed += newDelegate(this, &ScrollBar::notifyMousePressed);
			mWidgetSecondPart->eventMouseButtonReleased += newDelegate(this, &ScrollBar::notifyMouseReleased);
			mWidgetSecondPart->eventMouseWheel += newDelegate(this, &ScrollBar::notifyMouseWheel);
		}

		if (isUserString("MinTrackSize"))
			mMinTrackSize = utility::parseValue<int>(getUserString("MinTrackSize"));

		if (isUserString("TrackRangeMargins"))
			utility::parseComplex<size_t>(getUserString("TrackRangeMargins"), mSkinRangeStart, mSkinRangeEnd);

		if (mWidgetTrack != nullptr)
		{
			if (mWidgetTrack->isUserString("MinTrackSize"))
				mMinTrackSize = utility::parseValue<int>(mWidgetTrack->getUserString("MinTrackSize"));
		}
	}

	void ScrollBar::shutdownOverride()
	{
		mWidgetStart = nullptr;
		mWidgetEnd = nullptr;
		mWidgetTrack = nullptr;
		mWidgetFirstPart = nullptr;
		mWidgetSecondPart = nullptr;

		Base::shutdownOverride();
	}

	void ScrollBar::updateTrack()
	{
		if (mWidgetTrack == nullptr)
			return;

		_forcePick(mWidgetTrack);
		// размер диапазана в пикселях
		int pos = getLineSize();

		if (mVerticalAlignment)
		{
			// скрываем если диапазан маленький или места мало
			if ((mScrollRange < 2) || (pos <= mWidgetTrack->getHeight()))
			{
				mWidgetTrack->setVisible(false);
				if (nullptr != mWidgetFirstPart)
					mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), pos / 2);
				if (nullptr != mWidgetSecondPart)
					mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), pos / 2 + (int)mSkinRangeStart, mWidgetSecondPart->getWidth(), pos - pos / 2);
				return;
			}
			// если скрыт то покажем
			if (!mWidgetTrack->getVisible())
				mWidgetTrack->setVisible(true);

			// и обновляем позицию
			pos = (int)(((size_t)(pos - getTrackSize()) * mScrollPosition) / (mScrollRange - 1) + mSkinRangeStart);

			mWidgetTrack->setPosition(mWidgetTrack->getLeft(), pos);
			if (nullptr != mWidgetFirstPart)
			{
				int height = pos - mWidgetFirstPart->getTop();
				mWidgetFirstPart->setSize(mWidgetFirstPart->getWidth(), height);
			}
			if (nullptr != mWidgetSecondPart)
			{
				int top = pos + mWidgetTrack->getHeight();
				int height = mWidgetSecondPart->getHeight() + mWidgetSecondPart->getTop() - top;
				mWidgetSecondPart->setCoord(mWidgetSecondPart->getLeft(), top, mWidgetSecondPart->getWidth(), height);
			}
		}
		else
		{
			// скрываем если диапазан маленький или места мало
			if ((mScrollRange < 2) || (pos <= mWidgetTrack->getWidth()))
			{
				mWidgetTrack->setVisible(false);
				if (nullptr != mWidgetFirstPart)
					mWidgetFirstPart->setSize(pos / 2, mWidgetFirstPart->getHeight());
				if (nullptr != mWidgetSecondPart)
					mWidgetSecondPart->setCoord(pos / 2 + (int)mSkinRangeStart, mWidgetSecondPart->getTop(), pos - pos / 2, mWidgetSecondPart->getHeight());
				return;
			}
			// если скрыт то покажем
			if (!mWidgetTrack->getVisible())
				mWidgetTrack->setVisible(true);

			// и обновляем позицию
			pos = (int)(((size_t)(pos - getTrackSize()) * mScrollPosition) / (mScrollRange - 1) + mSkinRangeStart);

			mWidgetTrack->setPosition(pos, mWidgetTrack->getTop());
			if (nullptr != mWidgetFirstPart)
			{
				int height = pos - mWidgetFirstPart->getLeft();
				mWidgetFirstPart->setSize(height, mWidgetFirstPart->getHeight());
			}
			if (nullptr != mWidgetSecondPart)
			{
				int top = pos + mWidgetTrack->getWidth();
				int height = mWidgetSecondPart->getWidth() + mWidgetSecondPart->getLeft() - top;
				mWidgetSecondPart->setCoord(top, mWidgetSecondPart->getTop(), height, mWidgetSecondPart->getHeight());
			}
		}
	}

	void ScrollBar::TrackMove(int _left, int _top)
	{
		if (mWidgetTrack == nullptr)
			return;

		const IntPoint& point = InputManager::getInstance().getLastPressedPosition(MouseButton::Left);

		if (mVerticalAlignment)
		{
			// расчитываем позицию виджета
			int start = mPreActionOffset.top + (_top - point.top);
			if (start < (int)mSkinRangeStart)
				start = (int)mSkinRangeStart;
			else if (start > (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getHeight()))
				start = (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getHeight());
			if (mWidgetTrack->getTop() != start)
				mWidgetTrack->setPosition(mWidgetTrack->getLeft(), start);

			// расчитываем положение соответствующее позиции
			// плюс пол позиции
			int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange - 1) * 2);
			// высчитываем ближайшее значение и обновляем
			pos = pos * (int)(mScrollRange - 1) / (getLineSize() - getTrackSize());

			// проверяем на выходы и изменения
			if (pos < 0)
				pos = 0;
			else if (pos >= (int)mScrollRange)
				pos = (int)mScrollRange - 1;
			if (pos == (int)mScrollPosition)
				return;

			mScrollPosition = pos;
		}
		else
		{
			// расчитываем позицию виджета
			int start = mPreActionOffset.left + (_left - point.left);
			if (start < (int)mSkinRangeStart)
				start = (int)mSkinRangeStart;
			else if (start > (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getWidth()))
				start = (getTrackPlaceLength() - (int)mSkinRangeEnd - mWidgetTrack->getWidth());
			if (mWidgetTrack->getLeft() != start)
				mWidgetTrack->setPosition(IntPoint(start, mWidgetTrack->getTop()));

			// расчитываем положение соответствующее позиции
			// плюс пол позиции
			int pos = start - (int)mSkinRangeStart + (getLineSize() - getTrackSize()) / (((int)mScrollRange - 1) * 2);
			// высчитываем ближайшее значение и обновляем
			pos = pos * (int)(mScrollRange - 1) / (getLineSize() - getTrackSize());

			// проверяем на выходы и изменения
			if (pos < 0)
				pos = 0;
			else if (pos >= (int)mScrollRange)
				pos = (int)mScrollRange - 1;
			if (pos == (int)mScrollPosition)
				return;

			mScrollPosition = pos;
		}

		updateTrack();

		// отсылаем событие
		eventScrollChangePosition(this, (int)mScrollPosition);
	}

	void ScrollBar::notifyMousePressed(Widget* _sender, int _left, int _top, MouseButton _id)
	{
		// диспечерезируем нажатие своих детей как свое
		eventMouseButtonPressed(this, _left, _top, _id);

		if (MouseButton::Left != _id)
			return;

		if (mEnableRepeat && _sender != mWidgetTrack
			&& ((_sender != mWidgetFirstPart && _sender != mWidgetSecondPart) || !mMoveToClick))
		{
			ControllerItem* item = ControllerManager::getInstance().createItem(ControllerRepeatClick::getClassTypeName());
			ControllerRepeatClick* controller = item->castType<ControllerRepeatClick>();
			controller->eventRepeatClick += newDelegate(this, &ScrollBar::repeatClick);
			controller->setRepeat(mRepeatTriggerTime, mRepeatStepTime);
			ControllerManager::getInstance().addItem(_sender, controller);
		}

		if (mMoveToClick &&
			_sender != mWidgetTrack &&
			_sender != mWidgetStart &&
{'fraction_non_alphanumeric': 0.1302649792367016, 'fraction_numerical': 0.004152659679651968, 'mean_word_length': 4.799598623853211, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 163, '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': '5376956', 'n_tokens_mistral': 7669, 'n_tokens_neox': 6929, 'n_words': 1269}