Improve GalleryView

This commit is contained in:
seven332 committed 2016-02-10 16:04:50 +08:00
1 parent dff16b3834
commit ffd122c105
29 files changed
+1952 -1791

No files matched your search

+1 -1
View File
@@ -23,7 +23,7 @@ android {
sourceSets {
main {
java.srcDirs = ['src/main/java', 'src/main/java-gen']
java.srcDirs += 'src/main/java-gen'
// Disable default NdkCompile task
jni.srcDirs = []
// Set new jni lib dir
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.parser.GalleryDetailUrlParser;
@@ -33,6 +34,8 @@ import com.hippo.scene.StageActivity;
public class EhUrlOpener {
private static final String TAG = EhUrlOpener.class.getSimpleName();
public static boolean openUrl(Activity activity, String url) {
if (TextUtils.isEmpty(url)) {
return false;
@@ -79,6 +82,8 @@ public class EhUrlOpener {
return true;
}
Log.i(TAG, "Can't parse url: " + url);
return false;
}
}
@@ -16,7 +16,6 @@
package com.hippo.ehviewer.client.parser;
import android.os.Environment;
import android.util.Log;
import com.hippo.ehviewer.client.EhUtils;
@@ -270,7 +269,7 @@ public class GalleryDetailParser {
if (largePreviewSet.size() == 0) {
Log.d("TAG", "largePreviewSet.size() == 0");
try {
OutputStream os = new FileOutputStream(new File(Environment.getExternalStorageDirectory(), "empty.txt"));
OutputStream os = new FileOutputStream(new File("/data/data/com.hippo.ehviewer/cache/empty.txt"));
os.write(body.getBytes("utf-8"));
os.close();
} catch (Exception e) {
@@ -19,31 +19,178 @@ package com.hippo.ehviewer.ui;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.KeyEvent;
import android.view.MotionEvent;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.ui.gl.GalleryPageView;
import com.hippo.ehviewer.ui.gl.GalleryView;
import com.hippo.gl.view.GLRootView;
import com.hippo.gl.view.GLView;
import com.hippo.util.Dpad;
public class GalleryActivity extends AppCompatActivity {
private GalleryView mGalleryView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gallery);
GLRootView glRootView = (GLRootView) findViewById(R.id.gl_root_view);
GLView contentPane = new GLView();
GLView glView = new GLView();
contentPane.addComponent(glView);
glRootView.setContentPane(contentPane);
mGalleryView = new GalleryView(this, new InvalidPageIterator(), null);
glRootView.setContentPane(mGalleryView);
}
@Override
protected void onDestroy() {
super.onDestroy();
mGalleryView = null;
}
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
switch (Dpad.getDirectionPressed(event)) {
case Dpad.LEFT:
// TODO do something
return true;
case Dpad.UP:
// TODO do something
return true;
case Dpad.RIGHT:
// TODO do something
return true;
case Dpad.DOWN:
// TODO do something
return true;
case Dpad.CENTER:
// TODO do something
return true;
}
return super.onGenericMotionEvent(event);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Check volume
if (false) { // TODO Setting.getVolumePage()
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
// TODO do something
return true;
} else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
// TODO do something
return true;
}
}
// Check keyboard and Dpad
switch (keyCode) {
case KeyEvent.KEYCODE_PAGE_UP:
// TODO do something
return true;
case KeyEvent.KEYCODE_PAGE_DOWN:
// TODO do something
return true;
case KeyEvent.KEYCODE_DPAD_LEFT:
// TODO do something
return true;
case KeyEvent.KEYCODE_DPAD_UP:
// TODO do something
return true;
case KeyEvent.KEYCODE_DPAD_RIGHT:
// TODO do something
return true;
case KeyEvent.KEYCODE_DPAD_DOWN:
// TODO do something
return true;
case KeyEvent.KEYCODE_DPAD_CENTER:
// TODO do something
return true;
case KeyEvent.KEYCODE_SPACE:
// TODO do something
return true;
case KeyEvent.KEYCODE_MENU:
// TODO do something
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// Check volume
if (false) { // TODO Setting.getVolumePage()
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
return true;
}
}
// Check keyboard and Dpad
if (keyCode == KeyEvent.KEYCODE_PAGE_UP ||
keyCode == KeyEvent.KEYCODE_PAGE_DOWN ||
keyCode == KeyEvent.KEYCODE_DPAD_LEFT ||
keyCode == KeyEvent.KEYCODE_DPAD_UP ||
keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
keyCode == KeyEvent.KEYCODE_DPAD_CENTER ||
keyCode == KeyEvent.KEYCODE_SPACE ||
keyCode == KeyEvent.KEYCODE_MENU) {
return true;
}
return super.onKeyUp(keyCode, event);
}
private class InvalidPageIterator implements GalleryView.PageIterator {
@Override
public void mark() {
}
@Override
public void reset() {
}
@Override
public boolean hasNext() {
return false;
}
@Override
public boolean hasPrevious() {
return false;
}
@Override
public boolean isValid() {
return false;
}
@Override
public void next() {
}
@Override
public void previous() {
}
@Override
public void bind(GalleryPageView view) {
}
@Override
public void unbind(GalleryPageView view) {
}
}
}
@@ -26,6 +26,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.util.Log;
import android.view.Gravity;
import android.view.MenuItem;
import android.widget.Toast;
@@ -90,6 +91,8 @@ public final class MainActivity extends StageActivity
@Override
protected void onNewIntent(Intent intent) {
Log.d("TAG", "onNewIntent");
super.onNewIntent(intent);
if (!handleIntent(intent) && intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
Toast.makeText(this, R.string.error_cannot_parse_the_url, Toast.LENGTH_SHORT).show();
@@ -97,6 +100,9 @@ public final class MainActivity extends StageActivity
}
private void onInit() {
Log.d("TAG", "onInit");
Intent intent = getIntent();
if (!handleIntent(intent)) {
if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
@@ -125,6 +131,8 @@ public final class MainActivity extends StageActivity
}
private void onRestore(Bundle savedInstanceState) {
Log.d("TAG", "onRestore");
mNavCheckedItem = savedInstanceState.getInt(KEY_NAV_CHECKED_ITEM);
}
@@ -0,0 +1,189 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
import android.content.Context;
import android.hardware.SensorManager;
import android.view.ViewConfiguration;
import android.view.animation.Interpolator;
import com.hippo.gl.anim.Animation;
class Fling extends Animation {
private static final float DECELERATION_RATE = (float) (Math.log(0.78) / Math.log(0.9));
private static final float INFLEXION = 0.35f; // Tension lines cross at (INFLEXION, 1)
private static final float START_TENSION = 0.5f;
private static final float END_TENSION = 1.0f;
private static final float P1 = START_TENSION * INFLEXION;
private static final float P2 = 1.0f - END_TENSION * (1.0f - INFLEXION);
private static final float FLING_FRICTION = ViewConfiguration.getScrollFriction();
private static final int NB_SAMPLES = 100;
private static final float[] SPLINE_POSITION = new float[NB_SAMPLES + 1];
private static final float[] SPLINE_TIME = new float[NB_SAMPLES + 1];
private float mPhysicalCoeff;
//private GalleryPageView mPage;
private int mDx;
private int mDy;
private int mLastX;
private int mLastY;
private int[] mTemp = new int[2];
static {
float x_min = 0.0f;
float y_min = 0.0f;
for (int i = 0; i < NB_SAMPLES; i++) {
final float alpha = (float) i / NB_SAMPLES;
float x_max = 1.0f;
float x, tx, coef;
while (true) {
x = x_min + (x_max - x_min) / 2.0f;
coef = 3.0f * x * (1.0f - x);
tx = coef * ((1.0f - x) * P1 + x * P2) + x * x * x;
if (Math.abs(tx - alpha) < 1E-5) break;
if (tx > alpha) x_max = x;
else x_min = x;
}
SPLINE_POSITION[i] = coef * ((1.0f - x) * START_TENSION + x) + x * x * x;
float y_max = 1.0f;
float y, dy;
while (true) {
y = y_min + (y_max - y_min) / 2.0f;
coef = 3.0f * y * (1.0f - y);
dy = coef * ((1.0f - y) * START_TENSION + y) + y * y * y;
if (Math.abs(dy - alpha) < 1E-5) break;
if (dy > alpha) y_max = y;
else y_min = y;
}
SPLINE_TIME[i] = coef * ((1.0f - y) * P1 + y * P2) + y * y * y;
}
SPLINE_POSITION[NB_SAMPLES] = SPLINE_TIME[NB_SAMPLES] = 1.0f;
}
private static final Interpolator FLING_INTERPOLATOR = new Interpolator() {
@Override
public float getInterpolation(float input) {
final int index = (int) (NB_SAMPLES * input);
float distanceCoef = 1.f;
float velocityCoef = 0.f;
if (index < NB_SAMPLES) {
final float t_inf = (float) index / NB_SAMPLES;
final float t_sup = (float) (index + 1) / NB_SAMPLES;
final float d_inf = SPLINE_POSITION[index];
final float d_sup = SPLINE_POSITION[index + 1];
velocityCoef = (d_sup - d_inf) / (t_sup - t_inf);
distanceCoef = d_inf + (input - t_inf) * velocityCoef;
}
return distanceCoef;
}
};
public Fling(Context context) {
final float ppi = context.getResources().getDisplayMetrics().density * 160.0f;
mPhysicalCoeff = SensorManager.GRAVITY_EARTH // g (m/s^2)
* 39.37f // inch/meter
* ppi
* 0.84f; // look and feel tuning
}
private double getSplineDeceleration(int velocity) {
return Math.log(INFLEXION * Math.abs(velocity) / (FLING_FRICTION * mPhysicalCoeff));
}
/* Returns the duration, expressed in milliseconds */
private int getSplineFlingDuration(int velocity) {
final double l = getSplineDeceleration(velocity);
final double decelMinusOne = DECELERATION_RATE - 1.0;
return (int) (1000.0 * Math.exp(l / decelMinusOne));
}
private double getSplineFlingDistance(int velocity) {
final double l = getSplineDeceleration(velocity);
final double decelMinusOne = DECELERATION_RATE - 1.0;
return FLING_FRICTION * mPhysicalCoeff * Math.exp(DECELERATION_RATE / decelMinusOne * l);
}
/**
* Modifies mDuration to the duration it takes to get from start to newFinal using the
* spline interpolation. The previous duration was needed to get to oldFinal.
**/
private int adjustDuration(int start, int oldFinal, int newFinal, int duration) {
final int oldDistance = oldFinal - start;
final int newDistance = newFinal - start;
final float x = Math.abs((float) newDistance / oldDistance);
final int index = (int) (NB_SAMPLES * x);
if (index < NB_SAMPLES) {
final float x_inf = (float) index / NB_SAMPLES;
final float x_sup = (float) (index + 1) / NB_SAMPLES;
final float t_inf = SPLINE_TIME[index];
final float t_sup = SPLINE_TIME[index + 1];
final float timeCoef = t_inf + (x - x_inf) / (x_sup - x_inf) * (t_sup - t_inf);
duration *= timeCoef;
}
return duration;
}
public void startFling(GalleryPageView page, int velocityX, int minX, int maxX,
int velocityY, int minY, int maxY) {
//mPage = page;
mDx = (int) (getSplineFlingDistance(velocityX) * Math.signum(velocityX));
mDy = (int) (getSplineFlingDistance(velocityY) * Math.signum(velocityY));
mLastX = 0;
mLastY = 0;
int durationX = getSplineFlingDuration(velocityX);
int durationY = getSplineFlingDuration(velocityY);
if (mDx < minX) {
durationX = adjustDuration(0, mDx, minX, durationX);
mDx = minX;
}
if (mDx > maxX) {
durationX = adjustDuration(0, mDx, maxX, durationX);
mDx = maxX;
}
if (mDy < minY) {
durationY = adjustDuration(0, mDy, minY, durationY);
mDy = minY;
}
if (mDy > maxY) {
durationY = adjustDuration(0, mDy, maxY, durationY);
mDy = maxY;
}
setDuration(Math.max(durationX, durationY));
start();
// TODO invalidate();
}
@Override
protected void onCalculate(float progress) {
int x = (int) (mDx * progress);
int y = (int) (mDy * progress);
int offsetX = x - mLastX;
int offsetY = y - mLastY;
if (offsetX != 0 || offsetY != 0) {
// TODO mPage.scroll(-offsetX, -offsetY, mTemp);
}
mLastX = x;
mLastY = y;
}
}
@@ -16,109 +16,68 @@
package com.hippo.ehviewer.ui.gl;
import android.graphics.Rect;
import android.content.Context;
import com.hippo.gl.view.GLView;
import com.hippo.gl.widget.FrameLayout;
import com.hippo.gl.widget.ScaledImageView;
import com.hippo.gl.glrenderer.TextTexture;
import com.hippo.gl.view.Gravity;
import com.hippo.gl.widget.GLFrameLayout;
import com.hippo.gl.widget.GLLinearLayout;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.gl.widget.GLTextView;
import com.hippo.gl.widget.GLTextureView;
import com.hippo.yorozuya.LayoutUtils;
public class GalleryPageView extends FrameLayout {
public class GalleryPageView extends GLFrameLayout {
public ScaledImageView mImageView;
//public LinearLayout mLinearLayout;
//public TextView mIndexView;
//public ProgressView mProgressView;
public ImageView mImage;
public GLTextView mPage;
public GLTextureView mError;
public GLProgressView mProgress;
private Rect mSeen = new Rect();
// TODO
private static TextTexture sPageTextTexture;
//private static TextTexture sTextTexture;
public GalleryPageView(Context context) {
// Add image
mImage = new ImageView();
GravityLayoutParams glp = new GravityLayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
addComponent(mImage, glp);
//public static void setTextTexture(TextTexture textTexture) {
// sTextTexture = textTexture;
//}
// Add other panel
GLLinearLayout ll = new GLLinearLayout();
ll.setOrientation(GLLinearLayout.VERTICAL);
glp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
glp.gravity = Gravity.CENTER;
addComponent(ll, glp);
public GalleryPageView() {
mImageView = new ScaledImageView();
//mLinearLayout = new LinearLayout();
//mLinearLayout.setInterval(LayoutUtils.dp2pix(context, 24)); // 12dp
//mIndexView = new TextView(sTextTexture);
//mProgressView = new ProgressView();
// mProgressView.setMinimumWidth(LayoutUtils.dp2pix(context, 56)); // 56dp
//mProgressView.setMinimumHeight(LayoutUtils.dp2pix(context, 56)); // 56dp
/*
GravityLayoutParams lp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
// Add page
mPage = new GLTextView();
mPage.setTextTexture(sPageTextTexture);
GLLinearLayout.LayoutParams lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
mLinearLayout.addComponent(mIndexView, lp);
//lp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
// LayoutParams.WRAP_CONTENT);
//lp.gravity = Gravity.CENTER_HORIZONTAL;
//mLinearLayout.addComponent(mProgressView, lp);
ll.addComponent(mPage, lp);
lp = new GravityLayoutParams(LayoutParams.WRAP_CONTENT,
// Add error
mError = new GLTextureView();
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER;
lp.gravity = Gravity.CENTER_HORIZONTAL;
ll.addComponent(mError, lp);
addComponent(mLinearLayout, lp);
*/
GLView.GravityLayoutParams lp = new GLView.GravityLayoutParams(GLView.LayoutParams.MATCH_PARENT,
GLView.LayoutParams.MATCH_PARENT);
addComponent(mImageView, lp);
// Add progress
mProgress = new GLProgressView();
mProgress.setMinimumWidth(LayoutUtils.dp2pix(context, 56)); // 56dp
mProgress.setMinimumHeight(LayoutUtils.dp2pix(context, 56)); // 56dp
lp = new GLLinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
lp.gravity = Gravity.CENTER_HORIZONTAL;
ll.addComponent(mProgress, lp);
}
private void updateSeen() {
Rect bounds = bounds();
Rect parentBounds = mParent.bounds();
mSeen.set(bounds);
if (!mSeen.intersect(0, 0, parentBounds.width(), parentBounds.height())) {
mSeen.set(0, 0, 0, 0);
} else {
mSeen.offset(-bounds.left, -bounds.top);
}
mImageView.setSeen(mSeen);
}
@Override
public void layout(int left, int top, int right, int bottom) {
super.layout(left, top, right, bottom);
updateSeen();
}
public ScaledImageView getImageView() {
return mImageView;
}
public void setAnimateState(int position) {
mImageView.setAnimateState(position);
mImageView.setAnimateState(position);
}
public boolean isLoaded() {
return mImageView.isLoaded();
}
public void setScaleOffset(@GalleryView.Scale int scale,
@GalleryView.StartPosition int startPosition, float lastScale) {
mImageView.setScaleOffset(scale, startPosition, lastScale);
}
public void scroll(int dx, int dy, int[] remain) {
mImageView.scroll(dx, dy, remain);
}
public void scale(float focusX, float focusY, float scale) {
mImageView.scale(focusX, focusY, scale);
}
public float getFitScale() {
return mImageView.getFitScale();
}
public float getScale() {
return mImageView.getScale();
public ImageView getImageView() {
return mImage;
}
}
File diff suppressed because it is too large. Load diff
@@ -16,30 +16,380 @@
package com.hippo.ehviewer.ui.gl;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.IntDef;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.Texture;
import com.hippo.gl.view.GLView;
import com.hippo.yorozuya.MathUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class ImageView extends GLView {
@IntDef({SCALE_ORIGIN, SCALE_FIT_WIDTH, SCALE_FIT_HEIGHT, SCALE_FIT, SCALE_FIXED})
@Retention(RetentionPolicy.SOURCE)
public @interface Scale {}
@IntDef({START_POSITION_TOP_LEFT, START_POSITION_TOP_RIGHT, START_POSITION_BOTTOM_LEFT,
START_POSITION_BOTTOM_RIGHT, START_POSITION_CENTER})
@Retention(RetentionPolicy.SOURCE)
public @interface StartPosition {}
// TODO adjust scale max and min accroding to image size and screen size
private static final float SCALE_MIN = 1 / 10.0f;
private static final float SCALE_MAX = 10.0f;
public static final int SCALE_ORIGIN = 0;
public static final int SCALE_FIT_WIDTH = 1;
public static final int SCALE_FIT_HEIGHT = 2;
public static final int SCALE_FIT = 3;
public static final int SCALE_FIXED = 4;
public static final int START_POSITION_TOP_LEFT = 0;
public static final int START_POSITION_TOP_RIGHT = 1;
public static final int START_POSITION_BOTTOM_LEFT = 2;
public static final int START_POSITION_BOTTOM_RIGHT = 3;
public static final int START_POSITION_CENTER = 4;
private Texture mTexture;
private RectF mDst = new RectF();
private RectF mSrcActual = new RectF();
private RectF mDstActual = new RectF();
private Rect mValidRect = new Rect();
private int mScaleMode = SCALE_FIT;
private int mStartPosition = START_POSITION_TOP_RIGHT;
private float mScaleValue = 1.0f;
private float mScale = 1.0f;
private boolean mScaleOffsetDirty = true;
private boolean mPositionInRootDirty = true;
@Override
protected int getSuggestedMinimumWidth() {
return Math.max(super.getSuggestedMinimumWidth(),
mTexture == null ? 0 : mTexture.getWidth());
}
@Override
protected int getSuggestedMinimumHeight() {
return Math.max(super.getSuggestedMinimumHeight(),
mTexture == null ? 0 : mTexture.getHeight());
}
@Override
protected void onSizeChanged(int newW, int newH, int oldW, int oldH) {
mScaleOffsetDirty = true;
mPositionInRootDirty = true;
}
@Override
protected void onPositionInRootChanged(int x, int y, int oldX, int oldY) {
mPositionInRootDirty = true;
}
public void setTexture(Texture texture) {
mTexture = texture;
mScaleOffsetDirty = true;
mPositionInRootDirty = true;
}
/**
* If target is shorter then screen, make it in screen center. If target is
* longer then parent, make sure target fill parent over
*/
private void adjustPosition() {
RectF dst = mDst;
int screenWidth = getWidth();
int screenHeight = getHeight();
float targetWidth = dst.width();
float targetHeight = dst.height();
if (targetWidth > screenWidth) {
float fixXOffset = dst.left;
if (fixXOffset > 0) {
dst.left -= fixXOffset;
dst.right -= fixXOffset;
} else if ((fixXOffset = screenWidth - dst.right) > 0) {
dst.left += fixXOffset;
dst.right += fixXOffset;
}
} else {
float left = (screenWidth - targetWidth) / 2;
dst.offsetTo(left, dst.top);
}
if (targetHeight > screenHeight) {
float fixYOffset = dst.top;
if (fixYOffset > 0) {
dst.top -= fixYOffset;
dst.bottom -= fixYOffset;
} else if ((fixYOffset = screenHeight - dst.bottom) > 0) {
dst.top += fixYOffset;
dst.bottom += fixYOffset;
}
} else {
float top = (screenHeight - targetHeight) / 2;
dst.offsetTo(dst.left, top);
}
}
public void setScaleOffset(@Scale int scaleMode, @StartPosition int startPosition, float scaleValue) {
mScaleMode = scaleMode;
mStartPosition = startPosition;
mScaleValue = scaleValue;
int screenWidth = getWidth();
int screenHeight = getHeight();
if (mTexture == null || screenWidth == 0 || screenHeight == 0) {
mScaleOffsetDirty = true;
return;
}
int textureWidth = mTexture.getWidth();
int textureHeight = mTexture.getHeight();
// Avoid zero and negative
if (textureWidth <= 0) {
textureWidth = 1;
}
if (textureHeight <= 0) {
textureHeight = 1;
}
// Set scale
float targetWidth;
float targetHeight;
switch (scaleMode) {
case SCALE_ORIGIN:
mScale = 1.0f;
targetWidth = textureWidth;
targetHeight = textureHeight;
break;
case SCALE_FIT_WIDTH:
mScale = (float) screenWidth / textureWidth;
targetWidth = screenWidth;
targetHeight = textureHeight * mScale;
break;
case SCALE_FIT_HEIGHT:
mScale = (float) screenHeight / textureHeight;
targetWidth = textureWidth * mScale;
targetHeight = screenHeight;
break;
case SCALE_FIT:
float scaleX = (float) screenWidth / textureWidth;
float scaleY = (float) screenHeight / textureHeight;
if (scaleX < scaleY) {
mScale = scaleX;
targetWidth = screenWidth;
targetHeight = textureHeight * scaleX;
} else {
mScale = scaleY;
targetWidth = textureWidth * scaleY;
targetHeight = screenHeight;
break;
}
break;
case SCALE_FIXED:
default:
mScale = scaleValue;
targetWidth = textureWidth * scaleValue;
targetHeight = textureHeight * scaleValue;
break;
}
// adjust scale, not too big, not too small
if (mScale < SCALE_MIN) {
mScale = SCALE_MIN;
targetWidth = textureWidth * SCALE_MIN;
targetHeight = textureHeight * SCALE_MIN;
} else if (mScale > SCALE_MAX) {
mScale = SCALE_MAX;
targetWidth = textureWidth * SCALE_MAX;
targetHeight = textureHeight * SCALE_MAX;
}
// Set mDst.left and mDst.right
RectF dst = mDst;
switch (startPosition) {
case START_POSITION_TOP_LEFT:
dst.left = 0;
dst.top = 0;
break;
case START_POSITION_TOP_RIGHT:
dst.left = screenWidth - targetWidth;
dst.top = 0;
break;
case START_POSITION_BOTTOM_LEFT:
dst.left = 0;
dst.top = screenHeight - targetHeight;
break;
case START_POSITION_BOTTOM_RIGHT:
dst.left = screenWidth - targetWidth;
dst.top = screenHeight - targetHeight;
break;
case START_POSITION_CENTER:
default:
dst.left = (screenWidth - targetWidth) / 2;
dst.top = (screenHeight - targetHeight) / 2;
break;
}
// Set mDst.right and mDst.bottom
dst.right = dst.left + targetWidth;
dst.bottom = dst.top + targetHeight;
// adjust position
adjustPosition();
mScaleOffsetDirty = false;
mPositionInRootDirty = true;
}
public void scroll(int dx, int dy, int[] remain) {
// Only work after layout
if (mScaleOffsetDirty) {
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
}
if (mScaleOffsetDirty) {
remain[0] = dx;
remain[1] = dy;
return;
}
RectF dst = mDst;
int screenWidth = getWidth();
int screenHeight = getHeight();
float targetWidth = dst.width();
float targetHeight = dst.height();
if (targetWidth > screenWidth) {
dst.left -= dx;
dst.right -= dx;
float fixXOffset = dst.left;
if (fixXOffset > 0) {
dst.left -= fixXOffset;
dst.right -= fixXOffset;
remain[0] = -(int) fixXOffset;
} else if ((fixXOffset = screenWidth - dst.right) > 0) {
dst.left += fixXOffset;
dst.right += fixXOffset;
remain[0] = (int) fixXOffset;
} else {
remain[0] = 0;
}
} else {
remain[0] = dx;
}
if (targetHeight > screenHeight) {
dst.top -= dy;
dst.bottom -= dy;
float fixYOffset = dst.top;
if (fixYOffset > 0) {
dst.top -= fixYOffset;
dst.bottom -= fixYOffset;
remain[1] = -(int) fixYOffset;
} else if ((fixYOffset = screenHeight - dst.bottom) > 0) {
dst.top += fixYOffset;
dst.bottom += fixYOffset;
remain[1] = (int) fixYOffset;
} else {
remain[1] = 0;
}
} else {
remain[1] = dy;
}
if (dx != remain[0] || dy != remain[1]) {
mPositionInRootDirty = true;
invalidate();
}
}
public void scale(float focusX, float focusY, float scale) {
// Only work after layout
if (mScaleOffsetDirty) {
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
}
if (mScaleOffsetDirty) {
return;
}
if ((mScale == SCALE_MAX && scale >= 1.0f) || (mScale == SCALE_MIN && scale < 1.0f)) {
return;
}
float newScale = mScale * scale;
newScale = MathUtils.clamp(newScale, SCALE_MIN, SCALE_MAX);
mScale = newScale;
RectF dst = mDst;
float left = (focusX - ((focusX - dst.left) * scale));
float top = (focusY - ((focusY - dst.top) * scale));
dst.set(left, top,
(left + (mTexture.getWidth() * newScale)),
(top + (mTexture.getHeight() * newScale)));
// adjust position
adjustPosition();
mPositionInRootDirty = true;
invalidate();
}
private void applyPositionInRoot() {
int width = mTexture.getWidth();
int height = mTexture.getHeight();
RectF dst = mDst;
RectF dstActual = mDstActual;
RectF srcActual = mSrcActual;
dstActual.set(dst);
getValidRect(mValidRect);
if (dstActual.intersect(mValidRect.left, mValidRect.top, mValidRect.right, mValidRect.bottom)) {
srcActual.left = MathUtils.lerp(0, width,
MathUtils.delerp(dst.left, dst.right, dstActual.left));
srcActual.right = MathUtils.lerp(0, width,
MathUtils.delerp(dst.left, dst.right, dstActual.right));
srcActual.top = MathUtils.lerp(0, height,
MathUtils.delerp(dst.top, dst.bottom, dstActual.top));
srcActual.bottom = MathUtils.lerp(0, height,
MathUtils.delerp(dst.top, dst.bottom, dstActual.bottom));
} else {
// Can't be seen, set src and dst empty
srcActual.setEmpty();
dstActual.setEmpty();
}
}
@Override
public void onRender(GLCanvas canvas) {
if (mTexture != null) {
Texture texture = mTexture;
if (texture == null) {
return;
}
if (mScaleOffsetDirty) {
setScaleOffset(mScaleMode, mStartPosition, mScaleValue);
}
if (mPositionInRootDirty) {
mPositionInRootDirty = false;
applyPositionInRoot();
} else {
mSrcActual.set(0, 0, texture.getWidth(), texture.getHeight());
mDstActual.set(mDst);
}
mTexture.draw(canvas, mSrcActual, mDstActual);
if (!mSrcActual.isEmpty()) {
texture.draw(canvas, mSrcActual, mDstActual);
}
}
}
@@ -0,0 +1,516 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import com.hippo.gl.anim.Animation;
import com.hippo.gl.view.GLView;
import com.hippo.gl.widget.GLEdgeView;
import com.hippo.gl.widget.GLProgressView;
import com.hippo.yorozuya.AssertUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class PagerLayoutManager extends GalleryView.LayoutManager {
private static final String TAG = PagerLayoutManager.class.getSimpleName();
@IntDef({MODE_LEFT_TO_RIGHT, MODE_RIGHT_TO_LEFT})
@Retention(RetentionPolicy.SOURCE)
private @interface Mode {}
private static final int MODE_LEFT_TO_RIGHT = 0;
private static final int MODE_RIGHT_TO_LEFT = 1;
private static final Interpolator SMOOTH_SCROLLER_INTERPOLATOR = new Interpolator() {
@Override
public float getInterpolation(float t) {
t -= 1.0f;
return t * t * t * t * t + 1.0f;
}
};
private GalleryView.PageIterator mIterator;
private GLProgressView mProgress;
private GalleryPageView mPrevious;
private GalleryPageView mCurrent;
private GalleryPageView mNext;
@Mode
private int mMode = MODE_RIGHT_TO_LEFT;
private int mOffset;
private int mInterval;
private int mProgressSpec;
private int[] mScrollRemain = new int[2];
private boolean mCanScrollBetweenPages = false;
private int mDeltaX;
private int mDeltaY;
public PagerLayoutManager(@NonNull GalleryView galleryView, int interval, int progressSize) {
super(galleryView);
mInterval = interval;
mProgressSpec = GLView.MeasureSpec.makeMeasureSpec(progressSize, GLView.MeasureSpec.EXACTLY);
}
public void setMode(@Mode int mode) {
// TODO
if (mIterator != null) {
} else {
}
}
@Override
public void onAttach(GalleryView.PageIterator iterator) {
AssertUtils.assertEquals("The PagerLayoutManager is attached", mIterator, null);
mIterator = iterator;
}
private void removeProgress() {
if (mProgress != null) {
mGalleryView.removeComponent(mProgress);
mProgress = null;
}
}
private void removePage(@NonNull GalleryPageView page) {
mGalleryView.removeComponent(page);
mIterator.unbind(page);
mGalleryView.releasePage(page);
}
private void removeAllPages() {
// Remove gallery view
if (mPrevious != null) {
removePage(mPrevious);
mPrevious = null;
}
if (mCurrent != null) {
removePage(mCurrent);
mCurrent = null;
}
if (mNext != null) {
removePage(mNext);
mNext = null;
}
}
@Override
public GalleryView.PageIterator onDetach() {
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", mIterator, null);
removeAllPages();
// Clear iterator
GalleryView.PageIterator iterator = mIterator;
mIterator = null;
return iterator;
}
private GalleryPageView getLeftPage() {
switch (mMode) {
case MODE_LEFT_TO_RIGHT:
return mPrevious;
default:
case MODE_RIGHT_TO_LEFT:
return mNext;
}
}
private void setLeftPage(GalleryPageView page) {
switch (mMode) {
case MODE_LEFT_TO_RIGHT:
mPrevious = page;
break;
default:
case MODE_RIGHT_TO_LEFT:
mNext = page;
break;
}
}
private GalleryPageView getRightPage() {
switch (mMode) {
case MODE_LEFT_TO_RIGHT:
return mNext;
default:
case MODE_RIGHT_TO_LEFT:
return mPrevious;
}
}
private void setRightPage(GalleryPageView page) {
switch (mMode) {
case MODE_LEFT_TO_RIGHT:
mNext = page;
break;
default:
case MODE_RIGHT_TO_LEFT:
mPrevious = page;
break;
}
}
@Override
public void onFill() {
GalleryView.PageIterator iterator = mIterator;
GalleryView galleryView = mGalleryView;
AssertUtils.assertNotEquals("The PagerLayoutManager is not attached", iterator, null);
int width = galleryView.getWidth();
int height = galleryView.getHeight();
if (!iterator.isValid()) {
// Remove all pages
removeAllPages();
// Ensure progress
if (mProgress == null) {
mProgress = galleryView.obtainProgress();
galleryView.addComponent(mProgress);
}
// Measure and layout progress
mProgress.measure(mProgressSpec, mProgressSpec);
int progressWidth = mProgress.getMeasuredWidth();
int progressHeight = mProgress.getMeasuredHeight();
int progressLeft = width / 2 - progressWidth / 2;
int progressTop = height / 2 - progressHeight / 2;
mProgress.layout(progressLeft, progressTop, progressLeft + progressWidth, progressTop + progressHeight);
} else {
// Remove progress
removeProgress();
// Ensure pages
if (mCurrent == null) {
mCurrent = galleryView.obtainPage();
iterator.bind(mCurrent);
galleryView.addComponent(mCurrent);
}
if (mPrevious == null && iterator.hasPrevious()) {
iterator.mark();
iterator.previous();
mPrevious = galleryView.obtainPage();
iterator.bind(mPrevious);
galleryView.addComponent(mPrevious);
iterator.reset();
}
if (mNext == null && iterator.hasNext()) {
iterator.mark();
iterator.next();
mNext = galleryView.obtainPage();
iterator.bind(mNext);
galleryView.addComponent(mNext);
iterator.reset();
}
// Measure and layout pages
int offset = mOffset;
int widthSpec = GLView.MeasureSpec.makeMeasureSpec(width, GLView.MeasureSpec.EXACTLY);
int heightSpec = GLView.MeasureSpec.makeMeasureSpec(height, GLView.MeasureSpec.EXACTLY);
if (mCurrent != null) {
mCurrent.measure(widthSpec, heightSpec);
mCurrent.layout(offset, 0, width + offset, height);
}
GalleryPageView leftPage = getLeftPage();
if (leftPage != null) {
leftPage.measure(widthSpec, heightSpec);
leftPage.layout(-mInterval - width + offset, 0, -mInterval + offset, height);
}
GalleryPageView rightPage = getRightPage();
if (rightPage != null) {
rightPage.measure(widthSpec, heightSpec);
rightPage.layout(width + mInterval + offset, 0, width + mInterval + width + offset, height);
}
}
}
@Override
public void onDown() {
mDeltaX = 0;
mDeltaY = 0;
}
@Override
public void onUp() {
mGalleryView.getEdgeView().onRelease();
}
private void pagePrevious() {
GalleryView.PageIterator iterator = mIterator;
if (!iterator.hasPrevious()) {
return;
}
iterator.previous();
if (mNext != null) {
removePage(mNext);
}
mNext = mCurrent;
mCurrent = mPrevious;
mPrevious = null;
if (iterator.hasPrevious()) {
iterator.mark();
iterator.previous();
mPrevious = mGalleryView.obtainPage();
iterator.bind(mPrevious);
mGalleryView.addComponent(mPrevious);
iterator.reset();
}
}
private void pageNext() {
GalleryView.PageIterator iterator = mIterator;
if (!iterator.hasNext()) {
return;
}
iterator.next();
if (mPrevious != null) {
removePage(mPrevious);
}
mPrevious = mCurrent;
mCurrent = mNext;
mNext = null;
if (iterator.hasNext()) {
iterator.mark();
iterator.next();
mPrevious = mGalleryView.obtainPage();
iterator.bind(mPrevious);
mGalleryView.addComponent(mPrevious);
iterator.reset();
}
}
private void pageLeft() {
switch (mMode) {
case MODE_LEFT_TO_RIGHT:
pagePrevious();
break;
default:
case MODE_RIGHT_TO_LEFT:
pageNext();
break;
}
}
private void pageRight() {
switch (mMode) {
case MODE_LEFT_TO_RIGHT:
pageNext();
break;
default:
case MODE_RIGHT_TO_LEFT:
pagePrevious();
break;
}
}
private int scrollBetweenPages(int dx) {
GalleryPageView leftPage = getLeftPage();
GalleryPageView rightPage = getRightPage();
int width = mGalleryView.getWidth();
int remain;
if (dx < 0) { // Try to show left
if (leftPage == null) {
return dx;
}
if (dx > mOffset - width - mInterval) {
remain = 0;
mOffset -= dx;
} else {
// Go to left page
pageLeft();
remain = dx + width + mInterval - mOffset;
mOffset = 0;
}
} else { // Try to show right
if (rightPage == null) {
return dx;
}
if (dx < width + mInterval + mOffset) {
remain = 0;
mOffset -= dx;
} else {
// Go to right page
pageRight();
remain = dx - width - mInterval - mOffset;
mOffset = 0;
}
}
return remain;
}
public void overScrollEdge(float x, float y, int dx, int dy) {
GLEdgeView edgeView = mGalleryView.getEdgeView();
mDeltaX += dx;
mDeltaY += dy;
if (mDeltaX < 0) {
edgeView.onPull(-mDeltaX, y, GLEdgeView.LEFT);
if (!edgeView.isFinished(GLEdgeView.RIGHT)) {
edgeView.onRelease(GLEdgeView.RIGHT);
}
} else if (mDeltaX > 0) {
edgeView.onPull(mDeltaX, y, GLEdgeView.RIGHT);
if (!edgeView.isFinished(GLEdgeView.LEFT)) {
edgeView.onRelease(GLEdgeView.LEFT);
}
}
// TODO What about top and bottom
}
@Override
public void onScroll(float dx, float dy, float totalX, float totalY, float x, float y) {
if (mCurrent == null) {
return;
}
boolean needFill = false;
boolean canImageScroll = true;
int remainX = (int) dx;
int remainY = (int) dy;
if (mGalleryView.isFirstScroll()) {
mCanScrollBetweenPages = Math.abs(dx) > Math.abs(dy) * 1.5;
}
while (remainX != 0 || remainY != 0) {
if (mOffset == 0 && canImageScroll) {
ImageView image = mCurrent.getImageView();
image.scroll(remainX, remainY, mScrollRemain);
remainX = mScrollRemain[0];
remainY = mScrollRemain[1];
canImageScroll = false;
mDeltaX = 0;
mDeltaY = 0;
} else if (remainX == 0 ||
(getLeftPage() == null && mOffset == 0 && remainX < 0) ||
(getRightPage() == null && mOffset == 0 && remainX > 0)) {
// On edge
overScrollEdge(x, y, remainX, remainY);
remainX = 0;
remainY = 0;
} else if (mCanScrollBetweenPages) {
remainX = scrollBetweenPages(remainX);
canImageScroll = true;
needFill = true;
mDeltaX = 0;
mDeltaY = 0;
} else {
Log.w(TAG, "Something wrong?");
remainX = 0;
remainY = 0;
mDeltaX = 0;
mDeltaY = 0;
}
}
if (needFill) {
mGalleryView.requestFill();
}
}
@Override
public void onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (mCurrent == null) {
return;
}
}
@Override
public void onScale(float focusX, float focusY, float scale) {
if (mCurrent == null) {
return;
}
}
@Override
public boolean onUpdateAnimation(long time) {
return false;
}
class SmoothScroller extends Animation {
private int mDx;
private int mDy;
private int mLastX;
private int mLastY;
public void startSmoothScroll(int dx, int dy, int duration) {
mDx = dx;
mDy = dy;
mLastX = 0;
mLastY = 0;
setDuration(duration);
start();
// TODO invalidate();
}
@Override
protected void onCalculate(float progress) {
int x = (int) (mDx * progress);
int y = (int) (mDy * progress);
int offsetX = x - mLastX;
while (offsetX != 0) {
int oldOffsetX = offsetX;
// TODO offsetX = scrollBetweenPagesHMode(offsetX);
// Avoid loop infinitely
if (offsetX == oldOffsetX) {
break;
} else {
// TODO mRequestFill = true;
}
}
mLastX = x;
mLastY = y;
}
}
}
@@ -0,0 +1,72 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.gl;
import android.support.annotation.NonNull;
import android.view.MotionEvent;
public class ScrollLayoutManager extends GalleryView.LayoutManager {
public ScrollLayoutManager(@NonNull GalleryView galleryView) {
super(galleryView);
}
@Override
public void onAttach(GalleryView.PageIterator iterator) {
}
@Override
public GalleryView.PageIterator onDetach() {
return null;
}
@Override
public void onFill() {
}
@Override
public void onDown() {
}
@Override
public void onUp() {
}
@Override
public void onScroll(float dx, float dy, float totalX, float totalY, float x, float y) {
}
@Override
public void onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
}
@Override
public void onScale(float focusX, float focusY, float scale) {
}
@Override
public boolean onUpdateAnimation(long time) {
return false;
}
}
@@ -20,6 +20,7 @@ import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -45,8 +46,8 @@ import android.widget.TextView;
import android.widget.Toast;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.UrlOpener;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.UrlOpener;
import com.hippo.ehviewer.client.EhCacheKeyFactory;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhRequest;
@@ -59,6 +60,7 @@ import com.hippo.ehviewer.client.data.GalleryTagGroup;
import com.hippo.ehviewer.client.data.LargePreviewSet;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.parser.RateGalleryParser;
import com.hippo.ehviewer.ui.GalleryActivity;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.Announcer;
import com.hippo.scene.SceneFragment;
@@ -863,6 +865,11 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
ListUrlBuilder lub = new ListUrlBuilder();
lub.setCategory(category);
GalleryListScene.startScene(this, lub);
} else if (mDownload == v) {
// TODO
} else if (mRead == v) {
Intent intent = new Intent(getActivity(), GalleryActivity.class);
startActivity(intent);
} else if (mInfo == v) {
Bundle args = new Bundle();
args.putParcelable(GalleryInfoScene.KEY_GALLERY_DETAIL, mGalleryDetail);
@@ -16,7 +16,6 @@
package com.hippo.ehviewer.ui.scene;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Paint;
import android.os.Bundle;
@@ -29,7 +28,6 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
@@ -42,6 +40,7 @@ import com.hippo.ehviewer.client.EhCookieStore;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.rippleold.RippleSalon;
import com.hippo.scene.Announcer;
import com.hippo.util.ActivityHelper;
import com.hippo.util.ExceptionUtils;
public final class LoginScene extends BaseScene implements EditText.OnEditorActionListener,
@@ -171,12 +170,7 @@ public final class LoginScene extends BaseScene implements EditText.OnEditorActi
mPasswordLayout.setError(null);
}
// Hide ime keyboard
View view = getActivity().getCurrentFocus();
if (view != null) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
ActivityHelper.hideSoftInput(getActivity());
mProgress.setAlpha(0.0f);
mProgress.setVisibility(View.VISIBLE);
@@ -631,9 +631,18 @@ public class GLView implements TouchOwner {
}
private boolean setBounds(int left, int top, int right, int bottom) {
boolean sizeChanged = (right - left) != (mBounds.right - mBounds.left)
|| (bottom - top) != (mBounds.bottom - mBounds.top);
mBounds.set(left, top, right, bottom);
Rect bounds = mBounds;
int oldW = bounds.right - bounds.left;
int oldH = bounds.bottom - bounds.top;
int newW = right - left;
int newH = bottom - top;
boolean sizeChanged = oldW != newW || oldH != newH;
bounds.set(left, top, right, bottom);
if (sizeChanged) {
onSizeChanged(newW, newH, oldW, oldH);
}
// Update position in root
int[] position = mPosition;
@@ -657,6 +666,9 @@ public class GLView implements TouchOwner {
return sizeChanged;
}
protected void onSizeChanged(int newW, int newH, int oldW, int oldH) {
}
protected void onPositionInRootChanged(int x, int y, int oldX, int oldY) {
}
@@ -26,7 +26,7 @@ import com.hippo.gl.glrenderer.GLCanvas;
/**
* Material design edge effect
*/
public class EdgeEffect {
public class GLEdgeEffect {
// Time it will take the effect to fully recede in ms
private static final int RECEDE_TIME = 600;
@@ -91,7 +91,7 @@ public class EdgeEffect {
/**
* Construct a new EdgeEffect with a theme appropriate for the provided context.
*/
public EdgeEffect(int color) {
public GLEdgeEffect(int color) {
mColor = color;
mInterpolator = new DecelerateInterpolator();
}
@@ -17,18 +17,18 @@
package com.hippo.gl.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.opengl.Matrix;
import android.support.annotation.IntDef;
import com.hippo.ehviewer.R;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.view.GLView;
import com.hippo.yorozuya.ResourcesUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public final class EdgeView extends GLView {
public final class GLEdgeView extends GLView {
@IntDef({TOP, LEFT, BOTTOM, RIGHT})
@Retention(RetentionPolicy.SOURCE)
@@ -50,18 +50,14 @@ public final class EdgeView extends GLView {
private static final int BOTTOM_M = BOTTOM * 16;
private static final int RIGHT_M = RIGHT * 16;
private EdgeEffect[] mEffect = new EdgeEffect[4];
private GLEdgeEffect[] mEffect = new GLEdgeEffect[4];
private float[] mMatrix = new float[4 * 16];
public EdgeView(Context context) {
final TypedArray a = context.obtainStyledAttributes(
R.styleable.Theme);
final int themeColor = a.getColor(
R.styleable.Theme_colorPrimary, 0xff666666);
a.recycle();
public GLEdgeView(Context context) {
final int themeColor = ResourcesUtils.getAttrColor(context, R.attr.colorPrimary);
int color = (themeColor & 0xffffff) | 0x33000000;
for (int i = 0; i < 4; i++) {
mEffect[i] = new EdgeEffect(color);
mEffect[i] = new GLEdgeEffect(color);
}
}
@@ -101,7 +97,7 @@ public final class EdgeView extends GLView {
@Override
public void onRender(GLCanvas canvas) {
super.render(canvas);
super.onRender(canvas);
boolean more = false;
for (int i = 0; i < 4; i++) {
canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
@@ -146,7 +142,7 @@ public final class EdgeView extends GLView {
}
public void onRelease(@Direction int direction) {
EdgeEffect edgeEffect = mEffect[direction];
GLEdgeEffect edgeEffect = mEffect[direction];
edgeEffect.onRelease();
if (!edgeEffect.isFinished()) {
invalidate();
@@ -162,4 +158,8 @@ public final class EdgeView extends GLView {
invalidate();
}
}
public boolean isFinished(int direction) {
return mEffect[direction].isFinished();
}
}
@@ -19,7 +19,7 @@ package com.hippo.gl.widget;
import com.hippo.gl.view.GLView;
import com.hippo.gl.view.Gravity;
public class FrameLayout extends GLView {
public class GLFrameLayout extends GLView {
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
@@ -1,114 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.widget;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.IntDef;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.Texture;
import com.hippo.gl.view.GLView;
import com.hippo.yorozuya.MathUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class GLImageView extends GLView {
@IntDef({SCALE_ORIGIN, SCALE_FIT_WIDTH, SCALE_FIT_HEIGHT, SCALE_FIT})
@Retention(RetentionPolicy.SOURCE)
public @interface Scale {}
@IntDef({START_POSITION_TOP_LEFT, START_POSITION_TOP_RIGHT, START_POSITION_BOTTOM_LEFT,
START_POSITION_BOTTOM_RIGHT, START_POSITION_CENTER})
@Retention(RetentionPolicy.SOURCE)
public @interface StartPosition {}
public static final int SCALE_ORIGIN = 0;
public static final int SCALE_FIT_WIDTH = 1;
public static final int SCALE_FIT_HEIGHT = 2;
public static final int SCALE_FIT = 3;
public static final int START_POSITION_TOP_LEFT = 0;
public static final int START_POSITION_TOP_RIGHT = 1;
public static final int START_POSITION_BOTTOM_LEFT = 2;
public static final int START_POSITION_BOTTOM_RIGHT = 3;
public static final int START_POSITION_CENTER = 4;
private Texture mTexture;
private RectF mDst = new RectF();
private RectF mSrcActual = new RectF();
private RectF mDstActual = new RectF();
private Rect mValidRect = new Rect();
private boolean mPositionInRootDirty = true;
private void applyPositionInRoot() {
int width = mTexture.getWidth();
int height = mTexture.getHeight();
RectF dst = mDst;
RectF dstActual = mDstActual;
RectF srcActual = mSrcActual;
dstActual.set(dst);
getValidRect(mValidRect);
if (dstActual.intersect(mValidRect.left, mValidRect.top, mValidRect.right, mValidRect.bottom)) {
srcActual.left = MathUtils.lerp(0, width,
MathUtils.delerp(dst.left, dst.right, dstActual.left));
srcActual.right = MathUtils.lerp(0, width,
MathUtils.delerp(dst.left, dst.right, dstActual.right));
srcActual.top = MathUtils.lerp(0, height,
MathUtils.delerp(dst.top, dst.bottom, dstActual.top));
srcActual.bottom = MathUtils.lerp(0, height,
MathUtils.delerp(dst.top, dst.bottom, dstActual.bottom));
} else {
// Can't be seen, set src and dst empty
srcActual.setEmpty();
dstActual.setEmpty();
}
}
@Override
protected void onPositionInRootChanged(int x, int y, int oldX, int oldY) {
mPositionInRootDirty = true;
}
@Override
public void onRender(GLCanvas canvas) {
Texture texture = mTexture;
if (texture == null) {
return;
}
if (mPositionInRootDirty) {
mPositionInRootDirty = false;
applyPositionInRoot();
} else {
mSrcActual.set(0, 0, texture.getWidth(), texture.getHeight());
mDstActual.set(mDst);
}
texture.draw(canvas, mSrcActual, mDstActual);
}
}
@@ -27,7 +27,7 @@ import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
public class LinearLayout extends GLView {
public class GLLinearLayout extends GLView {
@IntDef({HORIZONTAL, VERTICAL})
@Retention(RetentionPolicy.SOURCE)
@@ -0,0 +1,242 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.widget;
import android.graphics.Color;
import android.graphics.Path;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import com.hippo.anani.PathInterpolator;
import com.hippo.gl.anim.Animation;
import com.hippo.gl.anim.FloatAnimation;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.GLPaint;
import com.hippo.gl.view.AnimationTime;
import com.hippo.gl.view.GLView;
import java.util.ArrayList;
import java.util.List;
public class GLProgressView extends GLView {
private static final Interpolator TRIM_START_INTERPOLATOR;
private static final Interpolator TRIM_END_INTERPOLATOR;
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
static {
Path trimStartPath = new Path();
trimStartPath.moveTo(0.0f, 0.0f);
trimStartPath.lineTo(0.5f, 0.0f);
trimStartPath.cubicTo(0.7f, 0.0f, 0.6f, 1f, 1f, 1f);
TRIM_START_INTERPOLATOR = PathInterpolator.build(trimStartPath);
Path trimEndPath = new Path();
trimEndPath.moveTo(0.0f, 0.0f);
trimEndPath.cubicTo(0.2f, 0.0f, 0.1f, 1f, 0.5f, 1f);
trimEndPath.lineTo(1f, 1f);
TRIM_END_INTERPOLATOR = PathInterpolator.build(trimEndPath);
}
private GLPaint mGLPaint;
private float mCx;
private float mCy;
private float mRadiusX;
private float mRadiusY;
private float mTrimStart = 0.0f;
private float mTrimEnd = 0.0f;
private float mTrimOffset = 0.0f;
private float mTrimRotation = 0.0f;
private boolean mIndeterminate = false;
private List<Animation> mAnimations;
public GLProgressView() {
mGLPaint = new GLPaint();
mGLPaint.setColor(Color.WHITE);
mGLPaint.setBackgroundColor(Color.BLACK);
mAnimations = new ArrayList<>();
setupAnimations();
}
public void setupAnimations() {
FloatAnimation trimStart = new FloatAnimation() {
@Override
protected void onCalculate(float progress) {
super.onCalculate(progress);
mTrimStart = get();
}
};
trimStart.setRange(0.0f, 0.75f);
trimStart.setDuration(1333L);
trimStart.setInterpolator(TRIM_START_INTERPOLATOR);
trimStart.setRepeatCount(Animation.INFINITE);
FloatAnimation trimEnd = new FloatAnimation() {
@Override
protected void onCalculate(float progress) {
super.onCalculate(progress);
mTrimEnd = get();
}
};
trimEnd.setRange(0.0f, 0.75f);
trimEnd.setDuration(1333L);
trimEnd.setInterpolator(TRIM_END_INTERPOLATOR);
trimEnd.setRepeatCount(Animation.INFINITE);
FloatAnimation trimOffset = new FloatAnimation() {
@Override
protected void onCalculate(float progress) {
super.onCalculate(progress);
mTrimOffset = get();
}
};
trimOffset.setRange(0.0f, 0.25f);
trimOffset.setDuration(1333L);
trimOffset.setInterpolator(LINEAR_INTERPOLATOR);
trimOffset.setRepeatCount(Animation.INFINITE);
FloatAnimation trimRotation = new FloatAnimation() {
@Override
protected void onCalculate(float progress) {
super.onCalculate(progress);
mTrimRotation = get();
}
};
trimRotation.setRange(0.0f, 720.0f);
trimRotation.setDuration(6665L);
trimRotation.setInterpolator(LINEAR_INTERPOLATOR);
trimRotation.setRepeatCount(Animation.INFINITE);
mAnimations.add(trimStart);
mAnimations.add(trimEnd);
mAnimations.add(trimOffset);
mAnimations.add(trimRotation);
}
private void startAnimations() {
List<Animation> animations = mAnimations;
for (int i = 0, n = animations.size(); i < n; i++) {
animations.get(i).forceReset();
}
}
private void stopAnimations() {
List<Animation> animations = mAnimations;
for (int i = 0, n = animations.size(); i < n; i++) {
animations.get(i).forceStop();
}
}
@Override
protected void onLayout(boolean changeSize, int left, int top, int right,
int bottom) {
super.onLayout(changeSize, left, top, right, bottom);
int width = right - left;
int height = bottom - top;
mGLPaint.setLineWidth(Math.min(width, height) / 12.0f);
mCx = width / 2;
mCy = height / 2;
mRadiusX = width / 48.0f * 19.0f;
mRadiusY = height / 48.0f * 19.0f;
}
public void setColor(int color) {
mGLPaint.setColor(color);
invalidate();
}
public void setBgColor(int color) {
mGLPaint.setBackgroundColor(color);
invalidate();
}
public void setIndeterminate(boolean indeterminate) {
if (mIndeterminate != indeterminate) {
mIndeterminate = indeterminate;
if (indeterminate) {
startAnimations();
} else {
stopAnimations();
}
invalidate();
}
}
public boolean isIndeterminate() {
return mIndeterminate;
}
public void setProgress(float progress) {
if (!mIndeterminate) {
mTrimStart = 0.0f;
mTrimEnd = progress;
mTrimOffset = 0.0f;
mTrimRotation = 0.0f;
invalidate();
}
}
@Override
public void onRender(GLCanvas canvas) {
update();
int width = getWidth();
int height = getHeight();
int cx = width / 2;
int cy = height / 2;
float startAngle = (mTrimStart + mTrimOffset) * 360.0f - 90;
float sweepAngle = Math.max(12.0f, (mTrimEnd - mTrimStart) * 360.0f);
float rotation = mTrimRotation + startAngle;
canvas.save();
canvas.translate(cx, cy);
canvas.rotate(rotation, 0, 0, 1);
if (rotation % 180 != 0) {
canvas.translate(-cy, -cx);
} else {
canvas.translate(-cx, -cy);
}
canvas.drawArc(mCx, mCy, mRadiusX, mRadiusY, sweepAngle, mGLPaint);
canvas.restore();
}
private void update() {
boolean invalidate = false;
if (mIndeterminate) {
long currentTime = AnimationTime.get();
List<Animation> animations = mAnimations;
for (int i = 0, n = animations.size(); i < n; i++) {
invalidate |= animations.get(i).calculate(currentTime);
}
}
if (invalidate) {
invalidate();
}
}
}
@@ -17,6 +17,7 @@
package com.hippo.gl.widget;
import android.graphics.Rect;
import android.text.TextUtils;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.TextTexture;
@@ -24,7 +25,7 @@ import com.hippo.gl.view.GLView;
import com.hippo.gl.view.Gravity;
import com.hippo.yorozuya.ArrayUtils;
public class TextView extends GLView {
public class GLTextView extends GLView {
TextTexture mTextTexture;
@@ -33,26 +34,35 @@ public class TextView extends GLView {
private int mGravity = Gravity.NO_GRAVITY;
public TextView(TextTexture textTexture) {
private void generateIndexes() {
if (mTextTexture == null || TextUtils.isEmpty(mText)) {
mIndexes = ArrayUtils.EMPTY_INT_ARRAY;
} else {
mIndexes = mTextTexture.getTextIndexes(mText);
}
}
public void setTextTexture(TextTexture textTexture) {
if (mTextTexture == textTexture) {
return;
}
mTextTexture = textTexture;
generateIndexes();
requestLayout();
}
public void setText(String text) {
if (text == null) {
text = "";
}
if (!text.equals(mText)) {
int oldMinimumWidth = getSuggestedMinimumWidth();
mText = text;
mIndexes = mTextTexture.getTextIndexes(text);
if (getSuggestedMinimumWidth() != oldMinimumWidth) {
requestLayout();
} else {
invalidate();
}
if (text.equals(mText)) {
return;
}
mText = text;
generateIndexes();
requestLayout();
}
public void setGravity(int gravity) {
@@ -82,12 +92,6 @@ public class TextView extends GLView {
}
}
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
setMeasuredSize(getDefaultSize(getSuggestedMinimumWidth(), widthSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightSpec));
}
@Override
public void onRender(GLCanvas canvas) {
Rect paddings = getPaddings();
@@ -0,0 +1,73 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.widget;
import android.graphics.RectF;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.Texture;
import com.hippo.gl.view.GLView;
public class GLTextureView extends GLView {
private RectF mSrc = new RectF();
private RectF mDst = new RectF();
private Texture mTexture;
public void setTexture(Texture texture) {
mTexture = texture;
if (texture != null) {
mSrc.set(0.0f, 0.0f, texture.getWidth(), texture.getHeight());
} else {
mSrc.setEmpty();
}
}
@Override
protected int getSuggestedMinimumWidth() {
return mTexture == null ? super.getSuggestedMinimumWidth() : mTexture.getWidth() + mPaddings.width();
}
@Override
protected int getSuggestedMinimumHeight() {
return mTexture == null ? super.getSuggestedMinimumWidth() : mTexture.getHeight() + mPaddings.height();
}
@Override
public void onRender(GLCanvas canvas) {
if (mTexture == null || mSrc.isEmpty()) {
return;
}
mDst.set(mPaddings.left, mPaddings.top, getWidth() - mPaddings.right, getHeight() - mPaddings.bottom);
if (mDst.isEmpty()) {
return;
}
mTexture.draw(canvas, mSrc, mDst);
}
}
@@ -1,45 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.widget;
import android.graphics.Color;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.ImageTexture;
import com.hippo.gl.image.Image;
import com.hippo.gl.view.GLView;
public class ImageView extends GLView implements ImageTexture.Callback {
private ImageTexture mImageTexture;
public ImageView(ImageTexture imageTexture) {
mImageTexture = imageTexture;
imageTexture.setCallback(this);
setBackgroundColor(Color.WHITE);
}
@Override
public void onRender(GLCanvas canvas) {
mImageTexture.draw(canvas, 0, 0);
}
@Override
public void invalidateImage(Image image) {
invalidate();
}
}
@@ -1,413 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.widget;
import android.graphics.Rect;
import android.graphics.RectF;
import com.hippo.ehviewer.ui.gl.GalleryView;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.ImageTexture;
import com.hippo.gl.image.Image;
import com.hippo.gl.view.GLView;
import com.hippo.yorozuya.MathUtils;
public class ScaledImageView extends GLView implements ImageTexture.Callback {
// TODO adjust scale max and min accroding to image size and screen size
private static final float SCALE_MIN = 1 / 10.0f;
private static final float SCALE_MAX = 10.0f;
public static final int ANIMATE_STATE_RUN = 0;
public static final int ANIMATE_STATE_STOP = 1;
private int mAnimateState = ANIMATE_STATE_RUN;
private ImageTexture mImageTexture;
// Corresponding source is [0, 0, mTiledTexture.getWidth(), mTiledTexture.getHeight()]
private RectF mTarget = new RectF();
private RectF mSeen = new RectF();
private RectF mSourceAfterSeen = new RectF();
private RectF mTargetAfterSeen = new RectF();
private boolean mScaleOffsetDirty = true;
private boolean mSeenDirty = true;
@GalleryView.Scale
private int mScaleMode;
@GalleryView.StartPosition
private int mStartPosition;
private float mLastScale;
private float mScale = 1f;
public void setAnimateState(int animateState) {
if (mAnimateState != animateState) {
mAnimateState = animateState;
if (mImageTexture != null) {
mImageTexture.setPause(mAnimateState == ANIMATE_STATE_STOP);
}
}
}
public void setImageTexture(ImageTexture imageTexture) {
ImageTexture oldImageTexture = mImageTexture;
if (oldImageTexture != null) {
oldImageTexture.setCallback(null);
}
mImageTexture = imageTexture;
setScaleOffset(mScaleMode, mStartPosition, mLastScale);
if (mImageTexture != null) {
mImageTexture.setCallback(this);
mImageTexture.setPause(mAnimateState == ANIMATE_STATE_STOP);
}
invalidate();
}
public ImageTexture getImageTexture() {
return mImageTexture;
}
@Override
protected int getSuggestedMinimumWidth() {
return Math.max(super.getSuggestedMinimumWidth(),
mImageTexture == null ? 0 : mImageTexture.getWidth());
}
@Override
protected int getSuggestedMinimumHeight() {
return Math.max(super.getSuggestedMinimumHeight(),
mImageTexture == null ? 0 : mImageTexture.getHeight());
}
/**
* If target is shorter then screen, make it in screen center. If target is
* longer then parent, make sure target fill parent over
*/
private void adjustPosition() {
RectF target = mTarget;
int screenWidth = getWidth();
int screenHeight = getHeight();
float targetWidth = target.width();
float targetHeight = target.height();
if (targetWidth > screenWidth) {
float fixXOffset = target.left;
if (fixXOffset > 0) {
target.left -= fixXOffset;
target.right -= fixXOffset;
} else if ((fixXOffset = screenWidth - target.right) > 0) {
target.left += fixXOffset;
target.right += fixXOffset;
}
} else {
float left = (screenWidth - targetWidth) / 2;
target.offsetTo(left, target.top);
}
if (targetHeight > screenHeight) {
float fixYOffset = target.top;
if (fixYOffset > 0) {
target.top -= fixYOffset;
target.bottom -= fixYOffset;
} else if ((fixYOffset = screenHeight - target.bottom) > 0) {
target.top += fixYOffset;
target.bottom += fixYOffset;
}
} else {
float top = (screenHeight - targetHeight) / 2;
target.offsetTo(target.left, top);
}
}
public void setScaleOffset(@GalleryView.Scale int scale,
@GalleryView.StartPosition int startPosition, float lastScale) {
mScaleMode = scale;
mStartPosition = startPosition;
mLastScale = lastScale;
int screenWidth = getWidth();
int screenHeight = getHeight();
if (mImageTexture == null || screenWidth == 0 || screenHeight == 0) {
mScaleOffsetDirty = true;
return;
}
int imageWidth = mImageTexture.getWidth();
int imageHeight = mImageTexture.getHeight();
// Set scale
float targetWidth;
float targetHeight;
switch (scale) {
case GalleryView.SCALE_ORIGIN:
mScale = 1.0f;
targetWidth = imageWidth;
targetHeight = imageHeight;
break;
case GalleryView.SCALE_FIT_WIDTH:
mScale = (float) screenWidth / imageWidth;
targetWidth = screenWidth;
targetHeight = imageHeight * mScale;
break;
case GalleryView.SCALE_FIT_HEIGHT:
mScale = (float) screenHeight / imageHeight;
targetWidth = imageWidth * mScale;
targetHeight = screenHeight;
break;
case GalleryView.SCALE_FIT:
float scaleX = (float) screenWidth / imageWidth;
float scaleY = (float) screenHeight / imageHeight;
if (scaleX < scaleY) {
mScale = scaleX;
targetWidth = screenWidth;
targetHeight = imageHeight * scaleX;
} else {
mScale = scaleY;
targetWidth = imageWidth * scaleY;
targetHeight = screenHeight;
break;
}
break;
case GalleryView.SCALE_FIXED:
default:
mScale = lastScale;
targetWidth = imageWidth * lastScale;
targetHeight = imageHeight * lastScale;
break;
}
// adjust scale, not too big, not too small
if (mScale < SCALE_MIN) {
mScale = SCALE_MIN;
targetWidth = imageWidth * SCALE_MIN;
targetHeight = imageHeight * SCALE_MIN;
} else if (mScale > SCALE_MAX) {
mScale = SCALE_MAX;
targetWidth = imageWidth * SCALE_MAX;
targetHeight = imageHeight * SCALE_MAX;
}
RectF target = mTarget;
// set start position
switch (startPosition) {
case GalleryView.START_POSITION_TOP_LEFT:
target.left = 0;
target.top = 0;
break;
case GalleryView.START_POSITION_TOP_RIGHT:
target.left = screenWidth - targetWidth;
target.top = 0;
break;
case GalleryView.START_POSITION_BOTTOM_LEFT:
target.left = 0;
target.top = screenHeight - targetHeight;
break;
case GalleryView.START_POSITION_BOTTOM_RIGHT:
target.left = screenWidth - targetWidth;
target.top = screenHeight - targetHeight;
break;
case GalleryView.START_POSITION_CENTER:
default:
target.left = (screenWidth - targetWidth) / 2;
target.top = (screenHeight - targetHeight) / 2;
break;
}
target.right = target.left + targetWidth;
target.bottom = target.top + targetHeight;
// adjust position
adjustPosition();
mScaleOffsetDirty = false;
mSeenDirty = true;
}
public void scroll(int dx, int dy, int[] remain) {
if (mImageTexture == null) {
remain[0] = dx;
remain[1] = dy;
return;
}
RectF target = mTarget;
int screenWidth = getWidth();
int screenHeight = getHeight();
float targetWidth = target.width();
float targetHeight = target.height();
if (targetWidth > screenWidth) {
target.left -= dx;
target.right -= dx;
float fixXOffset = target.left;
if (fixXOffset > 0) {
target.left -= fixXOffset;
target.right -= fixXOffset;
remain[0] = -(int) fixXOffset;
} else if ((fixXOffset = screenWidth - target.right) > 0) {
target.left += fixXOffset;
target.right += fixXOffset;
remain[0] = (int) fixXOffset;
} else {
remain[0] = 0;
}
} else {
remain[0] = dx;
}
if (targetHeight > screenHeight) {
target.top -= dy;
target.bottom -= dy;
float fixYOffset = target.top;
if (fixYOffset > 0) {
target.top -= fixYOffset;
target.bottom -= fixYOffset;
remain[1] = -(int) fixYOffset;
} else if ((fixYOffset = screenHeight - target.bottom) > 0) {
target.top += fixYOffset;
target.bottom += fixYOffset;
remain[1] = (int) fixYOffset;
} else {
remain[1] = 0;
}
} else {
remain[1] = dy;
}
if (dx != remain[0] || dy != remain[1]) {
mSeenDirty = true;
invalidate();
}
}
public void scale(float focusX, float focusY, float scale) {
if (mImageTexture == null) {
return;
}
if ((mScale == SCALE_MAX && scale > 1f) || (mScale == SCALE_MIN && scale < 1f)) {
return;
}
float newScale = mScale * scale;
newScale = MathUtils.clamp(newScale, SCALE_MIN, SCALE_MAX);
mScale = newScale;
RectF target = mTarget;
float left = (focusX - ((focusX - target.left) * scale));
float top = (focusY - ((focusY - target.top) * scale));
target.set(left, top,
(left + (mImageTexture.getWidth() * newScale)),
(top + (mImageTexture.getHeight() * newScale)));
// adjust position
adjustPosition();
mSeenDirty = true;
invalidate();
}
public RectF getTargetRect() {
return mTarget;
}
public float getScale() {
return mScale;
}
public float getFitScale() {
int screenWidth = getWidth();
int screenHeight = getHeight();
if (mImageTexture == null || screenWidth == 0 || screenHeight == 0) {
return 1f;
}
int imageWidth = mImageTexture.getWidth();
int imageHeight = mImageTexture.getHeight();
float scaleX = (float) screenWidth / imageWidth;
float scaleY = (float) screenHeight / imageHeight;
if (scaleX < scaleY) {
return scaleX;
} else {
return scaleY;
}
}
public boolean isLoaded() {
return mImageTexture != null;
}
public void setSeen(Rect seen) {
mSeen.set(seen);
mSeenDirty = true;
}
public void applySeen() {
int width = mImageTexture.getWidth();
int height = mImageTexture.getHeight();
RectF target = mTarget;
RectF targetAfterSeen = mTargetAfterSeen;
RectF sourceAfterSeen = mSourceAfterSeen;
targetAfterSeen.set(target);
if (targetAfterSeen.intersect(mSeen)) {
sourceAfterSeen.left = MathUtils.lerp(0, width,
MathUtils.delerp(target.left, target.right, targetAfterSeen.left));
sourceAfterSeen.right = MathUtils.lerp(0, width,
MathUtils.delerp(target.left, target.right, targetAfterSeen.right));
sourceAfterSeen.top = MathUtils.lerp(0, height,
MathUtils.delerp(target.top, target.bottom, targetAfterSeen.top));
sourceAfterSeen.bottom = MathUtils.lerp(0, height,
MathUtils.delerp(target.top, target.bottom, targetAfterSeen.bottom));
} else {
// Can't be seen
sourceAfterSeen.set(0f, 0f, 0f, 0f);
}
}
@Override
public void onRender(GLCanvas canvas) {
if (mImageTexture != null) {
if (mScaleOffsetDirty) {
setScaleOffset(mScaleMode, mStartPosition, mLastScale);
}
if (mSeenDirty) {
applySeen();
mSeenDirty = false;
}
// Draw
if (!mSourceAfterSeen.isEmpty()) {
mImageTexture.draw(canvas, mSourceAfterSeen, mTargetAfterSeen);
}
}
}
@Override
public void invalidateImage(Image image) {
invalidate();
}
}
@@ -1,57 +0,0 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.gl.widget;
import com.hippo.gl.glrenderer.GLCanvas;
import com.hippo.gl.glrenderer.XmlResourceTexture;
import com.hippo.gl.view.GLView;
public class XmlResourceView extends GLView {
private XmlResourceTexture mTexture;
public void setTexture(XmlResourceTexture texture) {
mTexture = texture;
if (texture != null) {
int width = getWidth();
int height = getHeight();
if (width > 0 && height > 0) {
texture.setBound(width, height);
invalidate();
}
}
}
@Override
protected void onLayout(boolean changeSize, int left, int top, int right, int bottom) {
super.onLayout(changeSize, left, top, right, bottom);
if (changeSize && mTexture != null) {
mTexture.setBound(right - left, bottom - top);
}
}
@Override
public void onRender(GLCanvas canvas) {
super.onRender(canvas);
if (mTexture != null) {
canvas.drawTexture(mTexture, 0, 0, getWidth(), getHeight());
}
}
}
@@ -24,7 +24,7 @@ import okhttp3.Request;
public class ChromeRequestBuilder extends Request.Builder {
private static final String CHROME_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36";
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.103 Safari/537.36";
public ChromeRequestBuilder(String url) {
URL u;
@@ -0,0 +1,94 @@
/*
* Copyright 2016 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.util;
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.MotionEvent;
// From http://developer.android.com/training/game-controllers/controller-input.html#dpad
public class Dpad {
public static final int INVALID = -1;
public static final int UP = 0;
public static final int LEFT = 1;
public static final int RIGHT = 2;
public static final int DOWN = 3;
public static final int CENTER = 4;
public static int getDirectionPressed(InputEvent event) {
if (!isDpadDevice(event)) {
return INVALID;
}
int directionPressed = INVALID;
// If the input event is a MotionEvent, check its hat axis values.
if (event instanceof MotionEvent) {
// Use the hat axis value to find the D-pad direction
MotionEvent motionEvent = (MotionEvent) event;
float xaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_X);
float yaxis = motionEvent.getAxisValue(MotionEvent.AXIS_HAT_Y);
// Check if the AXIS_HAT_X value is -1 or 1, and set the D-pad
// LEFT and RIGHT direction accordingly.
if (Float.compare(xaxis, -1.0f) == 0) {
directionPressed = Dpad.LEFT;
} else if (Float.compare(xaxis, 1.0f) == 0) {
directionPressed = Dpad.RIGHT;
}
// Check if the AXIS_HAT_Y value is -1 or 1, and set the D-pad
// UP and DOWN direction accordingly.
else if (Float.compare(yaxis, -1.0f) == 0) {
directionPressed = Dpad.UP;
} else if (Float.compare(yaxis, 1.0f) == 0) {
directionPressed = Dpad.DOWN;
}
}
// If the input event is a KeyEvent, check its key code.
else if (event instanceof KeyEvent) {
// Use the key code to find the D-pad direction.
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_LEFT) {
directionPressed = Dpad.LEFT;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_RIGHT) {
directionPressed = Dpad.RIGHT;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_UP) {
directionPressed = Dpad.UP;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_DOWN) {
directionPressed = Dpad.DOWN;
} else if (keyEvent.getKeyCode() == KeyEvent.KEYCODE_DPAD_CENTER) {
directionPressed = Dpad.CENTER;
}
}
return directionPressed;
}
public static boolean isDpadDevice(InputEvent event) {
// Check that input comes from a device with directional pads.
if ((event.getSource() & InputDevice.SOURCE_DPAD)
!= InputDevice.SOURCE_DPAD) {
return true;
} else {
return false;
}
}
}
+6 -6
View File
@@ -1,6 +1,6 @@
#Mon Jan 18 22:31:05 CST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
#Mon Jan 18 22:31:05 CST 2016
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
Submodule yorozuya updated: 41fa892da2...c1b5f4cb2e.