Improve GalleryView
This commit is contained in:
1 parent
dff16b3834
commit
ffd122c105
29 files changed
+1952
-1791
No files matched your search
+1
-1
@@ -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) {
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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();
|
||||
}
|
||||
+12
-12
@@ -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();
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
-19
@@ -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
@@ -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
|
||||
+1
-1
Submodule yorozuya updated: 41fa892da2...c1b5f4cb2e.
Reference in new issue
Block a user