/*
DroidFish - An Android chess program.
Copyright (C) 2015 Peter Ă–sterlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.petero.droidfish.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewParent;
/** Custom view for displaying move list.
* This is much faster than using a TextView. */
public class MoveListView extends View {
private CharSequence text = null;
private Layout layout = null;
private int layoutWidth = -1;
private TextPaint textPaint;
private Typeface defaultTypeface;
/** Constructor. */
public MoveListView(Context context, AttributeSet attrs) {
super(context, attrs);
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.density = getResources().getDisplayMetrics().density;
defaultTypeface = Typeface.create("monospace", Typeface.NORMAL);
textPaint.setTypeface(defaultTypeface);
}
/** Set text to display. */
public void setText(CharSequence text) {
if (text != this.text) {
this.text = text;
createLayout(getWidth());
requestLayout();
}
invalidate();
}
/** Set typeface and text size. If tf is null the default typeface is used. */
public void setTypeface(Typeface tf, float size) {
if (tf == null)
tf = defaultTypeface;
boolean modified = false;
if (tf != textPaint.getTypeface()) {
textPaint.setTypeface(tf);
modified = true;
}
DisplayMetrics metric = getContext().getResources().getDisplayMetrics();
size *= metric.scaledDensity;
if (size != textPaint.getTextSize()) {
textPaint.setTextSize(size);
modified = true;
}
if (modified) {
createLayout(getWidth());
requestLayout();
invalidate();
}
}
public void setTextColor(int color) {
if (color != textPaint.getColor()) {
textPaint.setColor(color);
invalidate();
}
}
/** Get line number corresponding to a character offset,
* or -1 if layout has not been created yet. */
public int getLineForOffset(int currPos) {
if (layout == null)
return -1;
return layout.getLineForOffset(currPos);
}
/** Get line height in pixels. */
public int getLineHeight() {
return textPaint.getFontMetricsInt(null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int widthMeasure = MeasureSpec.getSize(widthMeasureSpec);
int heightMeasure = MeasureSpec.getSize(heightMeasureSpec);
int width = getMeasuredWidth();
switch (MeasureSpec.getMode(widthMeasureSpec)) {
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.EXACTLY:
width = widthMeasure;
break;
case MeasureSpec.AT_MOST:
width = Math.min(width, widthMeasure);
break;
}
if (width != layoutWidth)
createLayout(width);
int height = 0;
if (layout != null) {
height = layout.getLineCount() * getLineHeight();
ViewParent p = getParent();
if (p != null)
p = p.getParent();
if (p instanceof MyRelativeLayout)
height += -getLineHeight() + ((MyRelativeLayout)p).getNewHeight();
}
switch (MeasureSpec.getMode(heightMeasureSpec)) {
case MeasureSpec.UNSPECIFIED:
break;
case MeasureSpec.EXACTLY:
height = heightMeasure;
break;
case MeasureSpec.AT_MOST:
height = Math.min(height, heightMeasure);
break;
}
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (layout != null) {
canvas.save();
canvas.translate(getPaddingLeft(), getPaddingTop());
layout.draw(canvas);
canvas.restore();
}
}
public interface OnLinkClickListener {
boolean onLinkClick(int offs);
}
private OnLinkClickListener onLinkClickListener;
public void setOnLinkClickListener(OnLinkClickListener listener) {
onLinkClickListener = listener;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getActionMasked();
boolean ret = super.onTouchEvent(event);
if ((action == MotionEvent.ACTION_UP) && (layout != null) &&
(onLinkClickListener != null)) {
int x = (int)event.getX() - getPaddingLeft() + getScrollX();
int y = (int)event.getY() - getPaddingTop() + getScrollY();
int line = layout.getLineForVertical(y);
int offs = layout.getOffsetForHorizontal(line, x);
if (onLinkClickListener.onLinkClick(offs))
return true;
}
return ret;
}
/** Create a StaticLayout corresponding to the current text. */
private void createLayout(int width) {
if (width <= 0)
return;
if (text == null) {
layout = null;
layoutWidth = -1;
} else {
layout = new StaticLayout(text, textPaint, width,
Alignment.ALIGN_NORMAL, 1.0f, 0.0f, true);
layoutWidth = width;
}
}
}