package com.junerking.ui.actor;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.junerking.ui.UIResourcesMgr;
import com.junerking.ui.UISettings;
public class UIScrollView extends UIWidgetGroup {
protected float max_y_height, max_scrolly;
protected int cols, max_col = 1;
protected OrthographicCamera camera;
public UIScrollView() {
super();
transform = true;
clear();
}
public UIScrollView(String name) {
super(name);
transform = true;
clear();
}
public void clear() {
super.clear();
max_scrolly = 0;
max_y_height = 0;
cols = 0;
}
@Override
public void addActor(UIWidget item) {
super.addActor(item);
// item.y = max_y_height + bound.y;
// item.x = bound.x + cols * item.getWidth();
// if (++cols == max_col) {
// cols = 0;
// max_y_height += item.getHeight();
// }
max_y_height = Math.max(max_y_height, item.y + item.getHeight());
max_scrolly = Math.max(max_scrolly, max_y_height - bound.height);
relative_y = -max_scrolly;
}
public void setCamera(OrthographicCamera camera) {
this.camera = camera;
}
private float padding_side_bar;
private TextureRegion sidebar_region;
public void setSideBar(TextureRegion textureRegion, float padding_side_bar) {
this.padding_side_bar = padding_side_bar;
this.sidebar_region = textureRegion;
}
@Override
public void draw(SpriteBatch sprite_batch, float parent_alpha) {
// if (child_list.size() == 0)
// return;
if (camera == null && getStage() != null) {
camera = (OrthographicCamera) getStage().getCamera();
}
applyTransform(sprite_batch, computeTransform());
ScissorStack.calculateScissors(camera, sprite_batch.getTransformMatrix(), bound, scissor_rect);
if (UISettings.DEBUG) {
sprite_batch.end();
sprite_batch.begin();
sprite_batch.draw(UIResourcesMgr.getInstance().getDebugRegion(), bound.x, bound.y, bound.width,
bound.height);
}
if (scissor_rect.width < 1 || scissor_rect.height < 1) {
resetTransform(sprite_batch);
return;
}
ScissorStack.pushScissors(scissor_rect);
for (int i = 0, n = child_list.size(); i < n; i++) {
final UIWidget item = child_list.get(i);
if (!item.visible)
continue;
float pre_x = item.x;
float pre_y = item.y;
float position_y = item.y + relative_y;
if (position_y + item.getHeight() < bound.y || position_y > bound.y + bound.height)
continue;
item.setPosition(item.x, position_y);
item.draw(sprite_batch, parent_alpha);
item.setPosition(pre_x, pre_y);
}
sprite_batch.flush();
ScissorStack.popScissors();
drawSideBar(sprite_batch, parent_alpha);
resetTransform(sprite_batch);
}
protected void drawSideBar(SpriteBatch sprite_batch, float parent_alpha) {
if (sidebar_region == null || max_y_height < bound.height)
return;
float sidebar_x = bound.x + bound.width - padding_side_bar + relative_x;
float sidebar_y;
float sidebar_height = bound.height / 2;
if (relative_y >= 0) {
sidebar_y = bound.y + 3;
sidebar_height = Math.max(10, (1 - relative_y / bound.height) * sidebar_region.getRegionHeight());
} else if (relative_y > -max_scrolly) {
sidebar_y = (-relative_y / max_scrolly) * (bound.height - 6 - sidebar_region.getRegionHeight()) + bound.y
+ 3;
sidebar_height = sidebar_region.getRegionHeight();
} else {
sidebar_height = Math.max(10,
(1 + (relative_y + max_scrolly) / bound.height) * sidebar_region.getRegionHeight());
sidebar_y = bound.y + bound.height - sidebar_height - 3;
}
sprite_batch.setColor(parent_alpha, parent_alpha, parent_alpha, parent_alpha);
sprite_batch.draw(sidebar_region, sidebar_x, sidebar_y, sidebar_region.getRegionWidth(), sidebar_height);
sprite_batch.setColor(1.0f, 1.0f, 1.0f, 1.0f);
}
public void init() {
relative_y = 0;
running = double_running = false;
}
private boolean running = false;
private boolean double_running = false;
@Override
public void act(float timeSpan) {
super.act(timeSpan);
if (running) {//fling
float ax = last_vy < 0 ? 1f : -1f;
float newvel = last_vy + ax * timeSpan;
relative_y += newvel * timeSpan;
if (newvel * last_vy <= 0.0f) {
running = false;
if (relative_y > 0 || relative_y < -max_scrolly) {
double_running = true;
}
} else {
last_vy = newvel;
}
}
if (double_running) {//回退
if (relative_y > 0) {
relative_y -= (relative_y) / 5;
} else if (relative_y < -max_scrolly) {
relative_y -= (relative_y + max_scrolly) / 5;
} else {
double_running = false;
}
}
forceScrollBound();
}
protected void forceScrollBound() {
if (relative_y < -bound.height - max_scrolly)
relative_y = -bound.height - max_scrolly;
if (relative_y > bound.height)
relative_y = bound.height;
if (relative_y < -max_scrolly) {
last_vy = -0.01f;
} else if (relative_y > 0) {
last_vy = 0.01f;
}
}
public float getRelativeX() {
return relative_x;
}
public float getRelativeY() {
return relative_y;
}
public float getMaxScrollHeight() {
return max_scrolly;
}
protected float relative_y, relative_x, base_y, last_vy, last_ry;
private long lastTimeStamp;
protected float down_x, down_y;
public final float xeps = 5f, yeps = 10f;
private UIWidget lastTouchedChild = null;
public boolean dispatchTouchEvent(InputEvent event, float x, float y, int pointer, boolean up) {
x -= this.x;
y -= this.y;
for (int i = child_list.size() - 1; i >= 0; i--) {
UIWidget child = child_list.get(i);
if (!child.visible)
continue;
float xx = x - child.x;
float yy = y - child.y - relative_y;
UIWidget result = (UIWidget) child.hit(xx, yy, true);
if (result == null)
continue;
if (up) {
if (lastTouchedChild != result) {
lastTouchedChild.touchUp(Integer.MIN_VALUE, 0, pointer);
} else {
lastTouchedChild.touchUp(0, 0, pointer);
}
} else {
if (result.touchDown(event, xx, yy, pointer)) {
lastTouchedChild = result;
return true;
}
}
}
lastTouchedChild = null;
return false;
}
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer) {
down_x = x;
down_y = y;
boolean has_touch_focus = dispatchTouchEvent(event, x - relative_x, y - relative_y, pointer, false);
if (!has_touch_focus) {
lastTimeStamp = System.currentTimeMillis();
base_y = y;
last_vy = 0;
last_ry = relative_y;
running = false;
double_running = false;
}
return true;
}
@Override
public boolean touchDragged(float x, float y, int pointer) {
if (lastTouchedChild != null) {
if ((Math.abs(down_x - x) > xeps || Math.abs(down_y - y) > yeps)) {
lastTouchedChild.touchUp(Integer.MIN_VALUE, 0, pointer);
lastTouchedChild = null;
lastTimeStamp = System.currentTimeMillis();
base_y = y;
last_vy = 0;
last_ry = relative_y;
running = false;
double_running = false;
}
} else {
updateDrag(y, System.currentTimeMillis());
}
return true;
}
@Override
public void touchUp(float x, float y, int pointer) {
if (lastTouchedChild != null) {
dispatchTouchEvent(null, x - relative_x, y - relative_y, pointer, true);
return;
}
updateDrag(y, System.currentTimeMillis());
running = true;
return;
}
public void updateDrag(float y, long eventTime) {
relative_y += y - base_y;
base_y = y;
long timeSpan = eventTime - lastTimeStamp;
if (timeSpan != 0)
last_vy = last_vy * 0.6f + (relative_y - last_ry) / (timeSpan) * 0.4f;
last_ry = relative_y;
lastTimeStamp += timeSpan;
}
private Rectangle scissor_rect = new Rectangle();
protected Rectangle bound = new Rectangle();
public void setBound(float x, float y, float width, float height) {
this.bound.x = x;
this.bound.y = y;
this.bound.width = width;
this.bound.height = height;
}
@Override
public Actor hit(float x, float y, boolean touchable) {
if (x < bound.x || y < bound.y || x > bound.width + bound.x || y > bound.height + bound.y) {
return null;
}
return this;
}
}