the whole game

This commit is contained in:
2026-03-02 22:04:18 +03:00
parent 816e9060b4
commit f0617a5d22
2069 changed files with 581500 additions and 0 deletions

View File

@@ -0,0 +1,732 @@
#include "ScrollingPane.h"
#include "../../renderer/gles.h"
#include "../Gui.h"
#include "../../../util/Mth.h"
#include "../../../SharedConstants.h"
#define STR(x) (x.toString().c_str())
static const float kPenetrationDeceleration = 0.03f;
static const float kPenetrationAcceleration = 0.08f;
static const float kMaxTrackingTime = 100.0f;
static const float kAcceleration = 15;
static const float kMinVelocityForDecelerationWithPaging = 4 / 3.0f;
static const float kMinVelocityForDeceleration = 1 / 3.0f;
static const float kDesiredAnimationFrameRate = 1000.0f / 60;
static const float kDecelerationFrictionFactor = 0.95f;
static const float kMinimumVelocityToHideScrollIndicators = 0.05f;
static const float kMinimumVelocity = 0.01f;
static const float kMinimumTrackingForDrag = 5;
static const float kMinIndicatorLength = 34.0f / 3;
static const float PKScrollIndicatorEndSize = 3;
static const float PKScrollIndicatorThickness = 7.0f /3;
ScrollingPane::ScrollingPane(
int optionFlags,
const IntRectangle& boundingBox,
const IntRectangle& itemRect,
int columns,
int numItems,
float screenScale /* = 1.0f */,
const IntRectangle& itemBoundingRect /*= IntRectangle(0,0,0,0)*/ )
: flags(optionFlags),
bbox(boundingBox),
size(boundingBox),
area((float)bbox.x, (float)bbox.y, (float)(bbox.x + bbox.w), (float)(bbox.y + bbox.h)),
bboxArea(area),
itemRect(itemRect),
numItems(numItems),
screenScale(screenScale),
invScreenScale(1.0f / screenScale),
//hasItemBounding(),
px(0), py(0), fpx(0), fpy(0),
dx(0), dy(0),
dragState(-1),
dragLastDeltaTimeStamp(-1.0f),
friction(0.95f),
highlightTimer(-1),
highlightStarted(-1),
selectedId(-1),
decelerating(false),
tracking(false),
dragging(false),
pagingEnabled(false),
_scrollEnabled(true),
_timer(60),
_doStepTimer(false),
_wasDown(false),//Mouse::isButtonDown(MouseAction::ACTION_LEFT)),
_lx(-9999), _ly(-9999)
{
if (itemBoundingRect.w > 0)
itemBbox = itemBoundingRect;
else
itemBbox = itemRect;
this->columns = (columns>0)? columns : bbox.w / itemBbox.w;
if (this->columns <= 0) {
LOGW("Columns are 0! Area width is smaller than item width. Setting columns to 1.\n");
this->columns = 1;
}
//LOGI("%d, %d :: %d\n", bbox.w, itemBbox.w, this->columns);
rows = 1 + (numItems-1) / this->columns,
/*
if (columns * itemBbox.w <= bbox.w) flags |= SF_LockX;
if (rows * itemBbox.h <= bbox.h) flags |= SF_LockY;
*/
dragDeltas.reserve(128);
te_moved = 0;
te_ended = 1;
selected = new bool[numItems];
for (int i = 0; i < numItems; ++i)
selected[i] = false;
// Setup the scroll bars
vScroll.w = vScroll.h = PKScrollIndicatorThickness;
hScroll.w = hScroll.h = PKScrollIndicatorThickness;
vScroll.x = bbox.x + bbox.w - vScroll.w;
vScroll.y = 0;
hScroll.x = 0;
hScroll.y = bbox.y + bbox.h - hScroll.h;
// vScroll.alpha
// vScroll.fading = hScroll.fading = -1;
}
ScrollingPane::~ScrollingPane() {
delete[] selected;
}
//void ScrollingPane::init(Minecraft* mc, int width, int height) {
// this->mc = mc;
// this->width = width;
// this->height = height;
//}
void ScrollingPane::tick() {
if (isSet(SF_ShowScrollbar)) {
updateScrollFade(vScroll);
updateScrollFade(hScroll);
}
}
bool ScrollingPane::getGridItemFor_slow(int itemIndex, GridItem& out) {
GridItem nw = getItemForPos(0, 0, false);
GridItem se = getItemForPos((float)bbox.w - 1, (float)bbox.h - 1, false);
const float bxx = bbox.x - (fpx /*+ dx*alpha*/) + (nw.xf - nw.x);
const float byy = bbox.y - (fpy /*+ dy*alpha*/) + (nw.yf - nw.y);
int y = itemIndex / columns;
int x = itemIndex - (y * columns);
out.id = itemIndex;
out.xf = bxx + x * itemBbox.w;
out.yf = byy + y * itemBbox.h;
out.x = x;
out.y = y;
return x >= nw.x && x <= se.x
&& y >= nw.y && y <= se.y;
}
void ScrollingPane::render( int xm, int ym, float alpha ) {
// Handle user interaction first
handleUserInput();
_timer.advanceTime();
if (_doStepTimer && !te_moved) {
for (int i = 0; i < _timer.ticks; ++i)
stepThroughDecelerationAnimation(false);
this->lastFrame = getTimeMs();
}
// Render
//if (isSet(SF_Scissor)) {
// glEnable2(GL_SCISSOR_TEST);
// GLuint x = (GLuint)(screenScale * bbox.x);
// GLuint y = 480 - (GLuint)(screenScale * (bbox.y + bbox.h));
// GLuint w = (GLuint)(screenScale * bbox.w);
// GLuint h = (GLuint)(screenScale * bbox.h);
// glScissor(x, y, w, h);
// LOGI("x, y, w, h: %d, %d, %d, %d\n", x, y, w, h);
//}
std::vector<GridItem> itemsToRender;
GridItem nw = getItemForPos(0, 0, false);
GridItem se = getItemForPos((float)bbox.w - 1, (float)bbox.h - 1, false);
//LOGI("getItem: %d, %d - %d, %d\n", nw.x, nw.y, se.x, se.y);
const float bxx = bbox.x - (fpx /*+ dx*alpha*/) + (nw.xf - nw.x);
const float byy = bbox.y - (fpy /*+ dy*alpha*/) + (nw.yf - nw.y);
for (int y = nw.y; y <= se.y; ++y)
for (int x = nw.x; x <= se.x; ++x) {
int id = y * columns + x;
if (y <0 || id < 0 || id >= numItems) continue; // @todo: break rather
if (isNotSet(SF_WrapX) && (x < 0 || x >= columns)) continue; // @todo: break rather
GridItem item; //@todo: v- Does not support SF_Wrapping
item.id = id;
item.xf = bxx + x * itemBbox.w;
item.yf = byy + y * itemBbox.h;
item.x = (int)item.xf;
item.y = (int)item.yf;
//LOGI("i: %d (%.1f, %.1f)\t", id, item.xf, item.yf);
if (isSet(SF_MultiSelect)) item.selected = selected[id];
else item.selected = (id == selectedId);
itemsToRender.push_back(item);
}
renderBatch(itemsToRender, alpha);
//if (isSet(SF_Scissor))
// glDisable2(GL_SCISSOR_TEST);
}
void ScrollingPane::renderBatch(std::vector<GridItem>& items, float alpha) {
for (unsigned int i = 0; i < items.size(); ++i)
renderItem(items[i], alpha);
}
void ScrollingPane::renderItem(GridItem& item, float alpha) {
}
ScrollingPane::GridItem ScrollingPane::getItemForPos( float x, float y, bool isScreenPos ) {
// Screen relative pos (rather than ScrollingPane relative pos)
if (isScreenPos) {
x -= bbox.x;
y -= bbox.y;
}
// Add the scrolled offset
x += fpx;
y += fpy;
// Does the grid SF_Wrap around?
if (isSet(SF_WrapX)) x = fmod(x, (float)(itemBbox.w * columns));
if (isSet(SF_WrapY)) y = fmod(y, (float)(itemBbox.h * rows));
GridItem out;
out.xf = x / itemBbox.w;
out.yf = y / itemBbox.h;
out.x = (int) out.xf;
out.y = (int) out.yf;
out.id = out.y * columns + out.x;
return out;
}
void ScrollingPane::addDeltaPos(float x, float y, float dt, int a) {
if (dt <= 0)
return;
Vec3 delta = (dragLastPos - Vec3(x, y, 0)) * (1.0f / dt);
dragDeltas.push_back(delta.x);
dragDeltas.push_back(delta.y);
dragLastPos.set(x, y, 0);
dragLastDeltaTimeStamp += dt; // @attn @fix: This relies on user to be correct
//LOGI(">> delta %d: %s\n", a, STR(delta));
}
static const int PKTableViewMinTouchDurationForCellSelection = 150;
void ScrollingPane::handleUserInput() {
bool isDown = Mouse::isButtonDown(MouseAction::ACTION_LEFT);
float x = Mouse::getX() * invScreenScale;
float y = Mouse::getY() * invScreenScale;
int t = getTimeMs();
bool isInside = area.isInside(x, y);
//LOGI("inside? %d\n", isInside);
bool moved = (x != _lx || y != _ly);
_lx = x;
_ly = y;
if (te_ended > 0 && _wasDown && !isDown)
touchesEnded(x, y, t);
else if (isDown && !_wasDown && isInside)
touchesBegan(x, y, t);
else if (te_moved > 0 && moved && isDown)
touchesMoved(x, y, t);
if (highlightTimer >= 0 && isNotSet(SF_NoHoldSelect)) {
if (getTimeMs() - highlightTimer >= PKTableViewMinTouchDurationForCellSelection)
onHoldItem();
}
_wasDown = isDown;
}
Vec3& ScrollingPane::contentOffset() {
return _contentOffset;
}
void ScrollingPane::beginTracking(float x, float y, int t) { //@param 1: MouseEvent a
if (this->tracking) {
return;
}
//a.preventDefault();
this->stopDecelerationAnimation();
//this->hostingLayer.style.webkitTransitionDuration = 0;
this->adjustContentSize(); //@todo @?
this->minPoint.set((float)(this->size.w - this->adjustedContentSize.w), (float)(this->size.h - this->adjustedContentSize.h), 0); //@todo
this->snapContentOffsetToBounds(false);
this->startPosition = this->_contentOffset;
this->startTouchPosition.set(x, y, 0);
this->startTime = (float)t;
this->startTimePosition = this->contentOffset();
this->tracking = true;
this->dragging = false;
this->touchesHaveMoved = false;
//window.addEventListener(PKMoveEvent, this, true); //@todo
//window.addEventListener(PKEndEvent, this, true);
//window.addEventListener("touchcancel", this, true);
//window.addEventListener(PKEndEvent, this, false)
};
void ScrollingPane::touchesBegan(float x, float y, int t) { //@param 1: MouseEvent a
if (!this->_scrollEnabled) {
return;
}
te_ended = 1;
//if (a.eventPhase == Event.CAPTURING_PHASE) {
// if (a._manufactured) {
// return
// }
//this->highlightItem = getItemForPos(x, y, true);
// if (this.delaysContentTouches) {
// a.stopPropagation();
// this.callMethodNameAfterDelay("beginTouchesInContent", kContentTouchesDelay, a);
this->beginTracking(x, y, t);
// }
//} else {
// this.beginTracking(a)
//}
te_moved = 2;
GridItem gi = getItemForPos(x, y, true);
if (gi.id >= 0 && gi.id < numItems) {
//LOGI("Pressed down at %d (%d, %d)\n", gi.id, gi.x, gi.y);
highlightItem.id = bboxArea.isInside(x, y)? gi.id : -1;
highlightStarted = highlightTimer = bboxArea.isInside(x, y)? getTimeMs() : -1;
} else {
highlightItem.id = -1;
highlightStarted = highlightTimer = -1;
}
}
void ScrollingPane::touchesMoved(float x, float y, int t)
{
this->touchesHaveMoved = true;
//this->callSuper(d);
Vec3 e(x, y, 0);
float b = e.x - this->startTouchPosition.x;
float c = e.y - this->startTouchPosition.y;
if (!this->dragging) {
if ((Mth::abs(b) >= kMinimumTrackingForDrag && isNotSet(SF_LockX)) || (Mth::abs(c) >= kMinimumTrackingForDrag && isNotSet(SF_LockY))) {
willBeginDragging();
this->dragging = true;
this->firstDrag = true;
if (isSet(SF_ShowScrollbar)) {
if (isNotSet(SF_LockX) && (this->adjustedContentSize.w > this->size.w))
//this->hScroll.visible = true;
this->hScroll.fading = 1;
if (isNotSet(SF_LockY) && (this->adjustedContentSize.h > this->size.h))
//this->vScroll.visible = true;
this->vScroll.fading = 1;
}
}
}
if (this->dragging) {
//d.stopPropagation();
float f = isNotSet(SF_LockX) ? (this->startPosition.x + b) : this->_contentOffset.x;
float a = isNotSet(SF_LockY) ? (this->startPosition.y + c) : this->_contentOffset.y;
if (isNotSet(SF_HardLimits)) {
f -= ((f < this->minPoint.x) ? (f - this->minPoint.x) : ((f > 0) ? f : 0)) / 2;
a -= ((a < this->minPoint.y) ? (a - this->minPoint.y) : ((a > 0) ? a : 0)) / 2;
} else {
f = Mth::Min(Mth::Max(this->minPoint.x, f), 0.0f);
a = Mth::Min(Mth::Max(this->minPoint.y, a), 0.0f);
}
if (this->firstDrag) {
this->firstDrag = false;
this->startTouchPosition = e;
return;
}
this->setContentOffset(f, a);
this->lastEventTime = t;//d.timeStamp;
}
}
void ScrollingPane::touchesEnded(float x, float y, int t) {
te_ended = 0;
highlightStarted = -1;
//te_moved = 0;
//this.callSuper(a);
this->tracking = false;
if (this->dragging) {
this->dragging = false;
//a.stopPropagation();
if (t - this->lastEventTime <= kMaxTrackingTime) {
this->_contentOffsetBeforeDeceleration = this->_contentOffset;
this->startDecelerationAnimation(false);
}
if (!this->decelerating) {}
//window.removeEventListener(PKEndEvent, this, false);
didEndDragging();
}
if (!this->decelerating) {
if (fpy < 0 || fpy > bbox.h) { //@todo: for x as well (or rather, x^y)
this->_contentOffsetBeforeDeceleration = this->_contentOffset;
this->startDecelerationAnimation(true);
} else {
this->snapContentOffsetToBounds(true); //@fix
this->hideScrollIndicators();
}
}
//if (a.eventPhase == Event.BUBBLING_PHASE) { //@? @todo
// window.removeEventListener(PKEndEvent, this, false);
//// old and shaky, doesn't work good with Xperia Play (and presumably lots of others)
//if (!this->touchesHaveMoved && this->highlightItem.id >= 0) {
// _onSelect(this->highlightItem.id);
//}
if (Vec3(x, y, 0).distanceToSqr(startTouchPosition) <= 6.0f * 6.0f && this->highlightItem.id >= 0) {
_onSelect(this->highlightItem.id);
}
//}
te_moved = 0;
};
void ScrollingPane::touchesCancelled(float x, float y, int a) {
touchesEnded(x, y, a);
}
void ScrollingPane::startDecelerationAnimation( bool force )
{
Vec3 a(this->_contentOffset.x - this->startTimePosition.x, this->_contentOffset.y - this->startTimePosition.y, 0);
float b = (getTimeMs()/*event.timeStamp*/ - this->startTime) / kAcceleration;
//LOGI("starting deceleration! %s, %f\n", STR(a), b);
this->decelerationVelocity = Vec3(a.x / b, a.y / b, 0);
this->minDecelerationPoint = this->minPoint;
this->maxDecelerationPoint = Vec3(0, 0, 0);
if (this->pagingEnabled) {
this->minDecelerationPoint.x = Mth::Max(this->minPoint.x, std::floor(this->_contentOffsetBeforeDeceleration.x / this->size.w) * this->size.w);
this->minDecelerationPoint.y = Mth::Max(this->minPoint.y, std::floor(this->_contentOffsetBeforeDeceleration.y / this->size.h) * this->size.h);
this->maxDecelerationPoint.x = Mth::Min(0.0f, std::ceil(this->_contentOffsetBeforeDeceleration.x / this->size.w) * this->size.w);
this->maxDecelerationPoint.y = Mth::Min(0.0f, std::ceil(this->_contentOffsetBeforeDeceleration.y / this->size.h) * this->size.h);
}
this->penetrationDeceleration = kPenetrationDeceleration;
this->penetrationAcceleration = kPenetrationAcceleration;
if (this->pagingEnabled) {
this->penetrationDeceleration *= 5;
}
float c = this->pagingEnabled ? kMinVelocityForDecelerationWithPaging : kMinVelocityForDeceleration;
if (force || (Mth::abs(this->decelerationVelocity.x) > c || Mth::abs(this->decelerationVelocity.y) > c)) {
this->decelerating = true;
//LOGI("accelerating True - A\n");
_doStepTimer = true;
//this->decelerationTimer = this->callMethodNameAfterDelay("stepThroughDecelerationAnimation", kDesiredAnimationFrameRate); //@?
this->lastFrame = getTimeMs();
willBeginDecelerating();
}
}
void ScrollingPane::hideScrollIndicators() {
//hScroll.visible = vScroll.visible = false;
hScroll.fading = vScroll.fading = 0;
}
void ScrollingPane::stopDecelerationAnimation()
{
//LOGI("decelerating False - A\n");
this->decelerating = false;
_doStepTimer = false;
//clearTimeout(this.decelerationTimer) //@?
}
void ScrollingPane::stepThroughDecelerationAnimation(bool noAnimation) {
if (!this->decelerating) {
return;
}
int d = getTimeMs();
int k = d - this->lastFrame;
int l = noAnimation ? 0 : (int)(std::floor(0.5f + ((float)k / kDesiredAnimationFrameRate) - 1));
//LOGI("k: %d, %d %d : %d\n", d, this->lastFrame, k, l);
for (int j = 0; j < l; j++)
this->stepThroughDecelerationAnimation(true);
float g = this->contentOffset().x + this->decelerationVelocity.x;
float h = this->contentOffset().y + this->decelerationVelocity.y;
if (isSet(SF_HardLimits)) {
float a = Mth::Min(Mth::Max(this->minPoint.x, g), 0.0f);
if (a != g) {
g = a;
this->decelerationVelocity.x = 0;
}
float c = Mth::Min(Mth::Max(this->minPoint.y, h), 0.0f);
if (c != h) {
h = c;
this->decelerationVelocity.y = 0;
}
}
if (noAnimation) {
this->contentOffset().x = g;
this->contentOffset().y = h;
} else {
this->setContentOffset(g, h);
}
if (!this->pagingEnabled) {
this->decelerationVelocity.x *= kDecelerationFrictionFactor;
this->decelerationVelocity.y *= kDecelerationFrictionFactor;
}
float b = Mth::abs(this->decelerationVelocity.x);
float i = Mth::abs(this->decelerationVelocity.y);
if (!noAnimation && b <= kMinimumVelocityToHideScrollIndicators && i <= kMinimumVelocityToHideScrollIndicators) {
this->hideScrollIndicators();
if (b <= kMinimumVelocity && i <= kMinimumVelocity) {
//LOGI("decelerating False - B\n");
this->decelerating = false;
didEndDecelerating();
return;
}
}
if (!noAnimation) {
//this->decelerationTimer = this->callMethodNameAfterDelay("stepThroughDecelerationAnimation", kDesiredAnimationFrameRate)
}
//if (noAnimation) doStepTimer = false;
if (isNotSet(SF_HardLimits)) {
Vec3 e;
if (g < this->minDecelerationPoint.x) {
e.x = this->minDecelerationPoint.x - g;
} else {
if (g > this->maxDecelerationPoint.x) {
e.x = this->maxDecelerationPoint.x - g;
}
}
if (h < this->minDecelerationPoint.y) {
e.y = this->minDecelerationPoint.y - h;
} else {
if (h > this->maxDecelerationPoint.y) {
e.y = this->maxDecelerationPoint.y - h;
}
}
if (e.x != 0) {
if (e.x * this->decelerationVelocity.x <= 0) {
this->decelerationVelocity.x += e.x * this->penetrationDeceleration;
} else {
this->decelerationVelocity.x = e.x * this->penetrationAcceleration;
}
}
if (e.y != 0) {
if (e.y * this->decelerationVelocity.y <= 0) {
this->decelerationVelocity.y += e.y * this->penetrationDeceleration;
} else {
this->decelerationVelocity.y = e.y * this->penetrationAcceleration;
}
}
}
if (!noAnimation) {
this->lastFrame = d;
}
}
void ScrollingPane::setContentOffset(float x, float y) {
this->setContentOffsetWithAnimation(Vec3(x, y, 0), false);
}
void ScrollingPane::setContentOffset(Vec3 a) {
this->setContentOffsetWithAnimation(a, false);
};
void ScrollingPane::setContentOffsetWithAnimation(Vec3 b, bool doScroll) {
this->_contentOffset = b;
fpx = -this->_contentOffset.x;
fpy = -this->_contentOffset.y;
/* //@todo //@?
this->hostingLayer.style.webkitTransform = PKUtils.t(this->_contentOffset.x, this->_contentOffset.y);
if (a) {
this->scrollTransitionsNeedRemoval = true;
this->hostingLayer.style.webkitTransitionDuration = kPagingTransitionDuration
} else {
this->didScroll(false)
}
*/
if (!doScroll) {
// @todo: for scroll indicator //@?
if (isSet(SF_ShowScrollbar)) {
if (isNotSet(SF_LockX)) this->updateHorizontalScrollIndicator();
if (isNotSet(SF_LockY)) this->updateVerticalScrollIndicator();
}
}
//this->notifyPropertyChange("contentOffset")
}
void ScrollingPane::snapContentOffsetToBounds(bool a) {
bool b = false;
Vec3 c;
if (this->pagingEnabled) {
c.x = std::floor(0.5f + this->_contentOffset.x / this->size.w) * this->size.w;
c.y = std::floor(0.5f + this->_contentOffset.y / this->size.h) * this->size.h;
b = true;
} else {
if (isNotSet(SF_HardLimits)) {
c.x = Mth::Min(Mth::Max(this->minPoint.x, this->_contentOffset.x), 0.0f);
c.y = Mth::Min(Mth::Max(this->minPoint.y, this->_contentOffset.y), 0.0f);
b = (c.x != this->_contentOffset.x || c.y != this->_contentOffset.y);
}
}
if (b) {
this->setContentOffsetWithAnimation(c, a);
}
}
void ScrollingPane::adjustContentSize()
{
this->adjustedContentSize.w = Mth::Max(itemBbox.w * columns, bbox.w);
this->adjustedContentSize.h = Mth::Max(itemBbox.h * rows, bbox.h);
}
void ScrollingPane::onHoldItem() {
//LOGI("dragging, tracking %d, %d\n", !this->dragging, this->tracking);
int id = highlightItem.id;
if (id != -1 && !this->dragging && this->tracking)
_onSelect(id);
highlightTimer = -1;
//highlightItem.id = -1;
}
bool ScrollingPane::onSelect( int gridId, bool selected )
{
return selected;
}
void ScrollingPane::updateHorizontalScrollIndicator()
{
float c = (isNotSet(SF_LockX) && isSet(SF_ShowScrollbar)) ? PKScrollIndicatorEndSize * 2 : 1;
float d = Mth::Max(kMinIndicatorLength, std::floor(0.5f + (this->size.w / this->adjustedContentSize.w) * (this->size.w - c)));
float a = (-this->_contentOffset.x / (this->adjustedContentSize.w - this->size.w)) * (this->size.w - c - d);
//float b = this->size.h - PKScrollIndicatorThickness - 1;
if (this->_contentOffset.x > 0) {
d = std::floor(0.5f + Mth::Max(d - this->_contentOffset.x, PKScrollIndicatorThickness));
a = 1;
} else {
if (this->_contentOffset.x < -(this->adjustedContentSize.w - this->size.w)) {
d = std::floor(0.5f + Mth::Max(d + this->adjustedContentSize.w - this->size.w + this->contentOffset().x, PKScrollIndicatorThickness));
a = this->size.w - d - c;
}
}
this->hScroll.x = a + bbox.x;
//this->hScroll.y = b;
this->hScroll.w = d; //@property
};
void ScrollingPane::updateVerticalScrollIndicator()
{
float c = (isNotSet(SF_LockY) && isSet(SF_ShowScrollbar)) ? PKScrollIndicatorEndSize * 2 : 1;
float d = Mth::Max(kMinIndicatorLength, std::floor(0.5f + (this->size.h / this->adjustedContentSize.h) * (this->size.h - c)));
//float a = this->size.w - PKScrollIndicatorThickness - 1;
float b = (-this->_contentOffset.y / (this->adjustedContentSize.h - this->size.h)) * (this->size.h - c - d);
if (this->_contentOffset.y > 0) {
d = std::floor(0.5f + Mth::Max(d - this->_contentOffset.y, PKScrollIndicatorThickness));
b = 1;
} else {
if (this->_contentOffset.y < -(this->adjustedContentSize.h - this->size.h)) {
d = std::floor(0.5f + Mth::Max(d + this->adjustedContentSize.h - this->size.h + this->contentOffset().y, PKScrollIndicatorThickness));
b = this->size.h - d - c;
}
}
//this->vScroll.x = a;
this->vScroll.y = b + bbox.y;
this->vScroll.h = d; //@property
};
void ScrollingPane::_onSelect( int id )
{
if (isSet(SF_MultiSelect)) {
selected[id] = onSelect(id, !selected[id]);
} else {
// Change the selection, if the user wants it
// @note: There's currently no way to clear a selection
bool doSelect = onSelect(id, true);
if (id != selectedId && doSelect) {
onSelect(selectedId, false);
selectedId = id;
}
}
}
void ScrollingPane::updateScrollFade( ScrollBar& sb ) {
if (sb.fading == 1 && ((sb.alpha += 0.33f) >= 1)) {
sb.alpha = 1;
sb.fading = -1;
}
if (sb.fading == 0 && ((sb.alpha -= 0.10f) <= 0)) {
sb.alpha = 0;
sb.fading = -1;
}
}
void ScrollingPane::setSelected( int id, bool selected )
{
if (isSet(SF_MultiSelect))
this->selected[id] = selected;
else {
if (selected) selectedId = selected? id : -1;
else if (id == selectedId)
selectedId = -1;
}
}
void ScrollingPane::translate( float xo, float yo )
{
bbox.x += (int)xo;
bbox.y += (int)yo;
area._x0 += xo;
area._x1 += xo;
area._y0 += yo;
area._y1 += yo;
bboxArea._x0 += xo;
bboxArea._x1 += xo;
bboxArea._y0 += yo;
bboxArea._y1 += yo;
hScroll.x += xo;
hScroll.y += yo;
vScroll.x += xo;
vScroll.y += yo;
}
bool ScrollingPane::queryHoldTime(int* gridItem, int* heldMs) {
*gridItem = -1;
*heldMs = -1;
if (!dragging && highlightStarted >= 0) {
GridItem item = getItemForPos(_lx, _ly, true);
if (item.id == highlightItem.id) {
*gridItem = highlightItem.id;
*heldMs = getTimeMs() - highlightStarted;
return true;
} else {
highlightStarted = -1;
}
}
return false;
}