733 lines
23 KiB
C++
Executable File
733 lines
23 KiB
C++
Executable File
#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;
|
|
}
|