2020-09-17 20:00:07 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-06-28 16:39:18 +00:00
|
|
|
//
|
2020-09-17 20:00:07 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-28 16:39:18 +00:00
|
|
|
// ScrollableContainer.cpp
|
|
|
|
//
|
|
|
|
// Area containing scrollable information, for example the game description
|
|
|
|
// text container in the detailed, video and grid views.
|
|
|
|
//
|
|
|
|
|
2014-06-20 01:30:09 +00:00
|
|
|
#include "components/ScrollableContainer.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
|
2019-08-08 20:16:11 +00:00
|
|
|
#include "math/Vector2i.h"
|
|
|
|
#include "renderers/Renderer.h"
|
2020-09-17 20:00:07 +00:00
|
|
|
#include "Window.h"
|
2013-07-03 01:01:58 +00:00
|
|
|
|
2020-10-17 10:16:58 +00:00
|
|
|
#define AUTO_SCROLL_RESET_DELAY 6000 // Time before resetting to top after we reach the bottom.
|
|
|
|
#define AUTO_SCROLL_DELAY 2600 // Time to wait before we start to scroll.
|
|
|
|
#define AUTO_SCROLL_SPEED 30 // Relative scrolling speed (lower is faster).
|
|
|
|
#define AUTO_WIDTH_MOD 350 // Line width modifier to use to calculate scrolling speed.
|
2020-06-28 16:39:18 +00:00
|
|
|
|
|
|
|
ScrollableContainer::ScrollableContainer(
|
|
|
|
Window* window)
|
|
|
|
: GuiComponent(window),
|
|
|
|
mAutoScrollDelay(0),
|
|
|
|
mAutoScrollSpeed(0),
|
|
|
|
mAutoScrollAccumulator(0),
|
|
|
|
mScrollPos(0, 0),
|
|
|
|
mScrollDir(0, 0),
|
|
|
|
mAutoScrollResetAccumulator(0)
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-10-28 20:24:35 +00:00
|
|
|
void ScrollableContainer::render(const Transform4x4f& parentTrans)
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
if (!isVisible())
|
|
|
|
return;
|
2013-07-03 01:01:58 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
Transform4x4f trans = parentTrans * getTransform();
|
2013-08-07 03:46:25 +00:00
|
|
|
|
2020-09-17 20:00:07 +00:00
|
|
|
Vector2i clipPos(static_cast<int>(trans.translation().x()),
|
|
|
|
static_cast<int>(trans.translation().y()));
|
2013-07-03 01:01:58 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
Vector3f dimScaled = trans * Vector3f(mSize.x(), mSize.y(), 0);
|
2020-09-17 20:00:07 +00:00
|
|
|
Vector2i clipDim(static_cast<int>((dimScaled.x()) - trans.translation().x()),
|
|
|
|
static_cast<int>((dimScaled.y()) - trans.translation().y()));
|
2013-07-10 11:29:43 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
Renderer::pushClipRect(clipPos, clipDim);
|
2013-07-03 01:01:58 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
trans.translate(-Vector3f(mScrollPos.x(), mScrollPos.y(), 0));
|
|
|
|
Renderer::setMatrix(trans);
|
2013-07-03 01:01:58 +00:00
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
GuiComponent::renderChildren(trans);
|
|
|
|
Renderer::popClipRect();
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2014-05-19 01:15:15 +00:00
|
|
|
void ScrollableContainer::setAutoScroll(bool autoScroll)
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
if (autoScroll) {
|
|
|
|
mScrollDir = Vector2f(0, 1);
|
|
|
|
mAutoScrollDelay = AUTO_SCROLL_DELAY;
|
|
|
|
mAutoScrollSpeed = AUTO_SCROLL_SPEED;
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mScrollDir = Vector2f(0, 0);
|
|
|
|
mAutoScrollDelay = 0;
|
|
|
|
mAutoScrollSpeed = 0;
|
|
|
|
mAutoScrollAccumulator = 0;
|
|
|
|
}
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 20:24:35 +00:00
|
|
|
Vector2f ScrollableContainer::getScrollPos() const
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
return mScrollPos;
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2017-10-28 20:24:35 +00:00
|
|
|
void ScrollableContainer::setScrollPos(const Vector2f& pos)
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mScrollPos = pos;
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ScrollableContainer::update(int deltaTime)
|
|
|
|
{
|
2020-09-17 20:00:07 +00:00
|
|
|
// Don't scroll if the screensaver is active or text scrolling is disabled;
|
|
|
|
if (mWindow->isScreenSaverActive() || !mWindow->getAllowTextScrolling()) {
|
|
|
|
if (mScrollPos != 0)
|
|
|
|
reset();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-10-17 10:16:58 +00:00
|
|
|
const Vector2f contentSize = getContentSize();
|
|
|
|
// Scale speed by the text width, more text per line leads to slower scrolling.
|
|
|
|
const float widthMod = contentSize.x() / AUTO_WIDTH_MOD;
|
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
if (mAutoScrollSpeed != 0) {
|
2020-10-17 10:16:58 +00:00
|
|
|
mAutoScrollAccumulator += deltaTime / widthMod;
|
2020-06-28 16:39:18 +00:00
|
|
|
|
|
|
|
while (mAutoScrollAccumulator >= mAutoScrollSpeed) {
|
|
|
|
mScrollPos += mScrollDir;
|
|
|
|
mAutoScrollAccumulator -= mAutoScrollSpeed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clip scrolling within bounds.
|
|
|
|
if (mScrollPos.x() < 0)
|
|
|
|
mScrollPos[0] = 0;
|
|
|
|
if (mScrollPos.y() < 0)
|
|
|
|
mScrollPos[1] = 0;
|
|
|
|
|
|
|
|
if (mScrollPos.x() + getSize().x() > contentSize.x()) {
|
|
|
|
mScrollPos[0] = contentSize.x() - getSize().x();
|
|
|
|
mAtEnd = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contentSize.y() < getSize().y()) {
|
|
|
|
mScrollPos[1] = 0;
|
|
|
|
}
|
|
|
|
else if (mScrollPos.y() + getSize().y() > contentSize.y()) {
|
|
|
|
mScrollPos[1] = contentSize.y() - getSize().y();
|
|
|
|
mAtEnd = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mAtEnd) {
|
|
|
|
mAutoScrollResetAccumulator += deltaTime;
|
|
|
|
if (mAutoScrollResetAccumulator >= AUTO_SCROLL_RESET_DELAY)
|
|
|
|
reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
GuiComponent::update(deltaTime);
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2020-06-28 16:39:18 +00:00
|
|
|
// This should probably return a box to allow for when controls don't start at 0,0.
|
2017-10-28 20:24:35 +00:00
|
|
|
Vector2f ScrollableContainer::getContentSize()
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
Vector2f max(0, 0);
|
|
|
|
for (unsigned int i = 0; i < mChildren.size(); i++) {
|
|
|
|
Vector2f pos(mChildren.at(i)->getPosition()[0], mChildren.at(i)->getPosition()[1]);
|
|
|
|
Vector2f bottomRight = mChildren.at(i)->getSize() + pos;
|
|
|
|
if (bottomRight.x() > max.x())
|
|
|
|
max.x() = bottomRight.x();
|
|
|
|
if (bottomRight.y() > max.y())
|
|
|
|
max.y() = bottomRight.y();
|
|
|
|
}
|
|
|
|
|
|
|
|
return max;
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2014-05-19 01:15:15 +00:00
|
|
|
void ScrollableContainer::reset()
|
2013-07-03 01:01:58 +00:00
|
|
|
{
|
2020-06-28 16:39:18 +00:00
|
|
|
mScrollPos = Vector2f(0, 0);
|
|
|
|
mAutoScrollResetAccumulator = 0;
|
|
|
|
mAutoScrollAccumulator = -mAutoScrollDelay + mAutoScrollSpeed;
|
|
|
|
mAtEnd = false;
|
2013-07-03 01:01:58 +00:00
|
|
|
}
|