blob: c09c4078f2dcd4fa6b17cd001bcd1d7b8bfedc7e [file] [log] [blame]
/*
* Copyright (C) 2009 The Android Open Source Project
*
* 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.cooliris.media;
import java.util.ArrayList;
import javax.microedition.khronos.opengles.GL11;
import android.graphics.Typeface;
import android.view.MotionEvent;
import com.cooliris.app.App;
import com.cooliris.app.Res;
public final class PathBarLayer extends Layer {
private static final StringTexture.Config sPathFormat = new StringTexture.Config();
private final ArrayList<Component> mComponents = new ArrayList<Component>();
private static final int FILL = Res.drawable.pathbar_bg;
private static final int JOIN = Res.drawable.pathbar_join;
private static final int CAP = Res.drawable.pathbar_cap;
private Component mTouchItem = null;
static {
sPathFormat.fontSize = 18f * App.PIXEL_DENSITY;
}
public PathBarLayer() {
}
public void pushLabel(int icon, String label, Runnable action) {
synchronized (mComponents) {
mComponents.add(new Component(icon, label, action, 0));
}
recomputeComponents();
}
public void setAnimatedIcons(final int[] icons) {
synchronized (mComponents) {
final int numComponents = mComponents.size();
for (int i = 0; i < numComponents; ++i) {
final Component component = mComponents.get(i);
if (component != null) {
if (component.animatedIcons != null) {
component.animatedIcons = null;
}
if (i == numComponents - 1) {
component.animatedIcons = icons;
}
}
}
}
}
public void changeLabel(String label) {
if (label == null || label.length() == 0)
return;
Component component = popLabel();
if (component != null) {
pushLabel(component.icon, label, component.action);
}
}
public String getCurrentLabel() {
final ArrayList<Component> components = mComponents;
synchronized (components) {
int lastIndex = components.size() - 1;
if (lastIndex < 0) {
return "";
}
Component retVal = components.get(lastIndex);
return retVal.origString;
}
}
public Component popLabel() {
final ArrayList<Component> components = mComponents;
synchronized (components) {
int lastIndex = components.size() - 1;
if (lastIndex < 0) {
return null;
}
Component retVal = components.get(lastIndex);
components.remove(lastIndex);
return retVal;
}
}
private static final class Component {
public String origString;
public int icon;
public Runnable action;
public StringTexture texture;
public float width;
public float animWidth;
public float x;
public int[] animatedIcons;
public float timeElapsed;
private static final float ICON_WIDTH = 38.0f;
Component(int icon, String label, Runnable action, float widthLeft) {
this.action = action;
origString = label;
this.icon = icon;
computeLabel(widthLeft);
}
public final void computeLabel(float widthLeft) {
Typeface typeface = sPathFormat.bold ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT;
String label = "";
if (origString != null) {
label = origString.substring(0, StringTexture.lengthToFit(sPathFormat.fontSize, widthLeft, typeface, origString));
if (label.length() != origString.length()) {
label += "...";
}
}
this.texture = new StringTexture(label, sPathFormat);
}
public final boolean update(float timeElapsed) {
this.timeElapsed += timeElapsed;
if (animWidth == 0.0f) {
animWidth = width;
}
animWidth = FloatUtils.animate(animWidth, width, timeElapsed);
if (animatedIcons != null && animatedIcons.length > 1)
return true;
if (animWidth == width) {
return false;
} else {
return true;
}
}
public float getIconWidth() {
return ICON_WIDTH * App.PIXEL_DENSITY;
}
}
@Override
public void generate(RenderView view, RenderView.Lists lists) {
lists.blendedList.add(this);
lists.hitTestList.add(this);
lists.updateList.add(this);
}
private void layout() {
synchronized (mComponents) {
int numComponents = mComponents.size();
for (int i = 0; i < numComponents; ++i) {
Component component = mComponents.get(i);
if (component == null)
continue;
float iconWidth = (component.icon == 0) ? 0 : component.getIconWidth();
if (iconWidth == 0) {
iconWidth = 8 * App.PIXEL_DENSITY;
}
float offset = 5 * App.PIXEL_DENSITY;
float thisComponentWidth = (i != numComponents - 1) ? iconWidth + offset : component.texture.computeTextWidth()
+ iconWidth + offset;
component.width = thisComponentWidth;
}
}
}
@Override
public boolean update(RenderView view, float timeElapsed) {
layout();
boolean retVal = false;
synchronized (mComponents) {
int numComponents = mComponents.size();
for (int i = 0; i < numComponents; i++) {
Component component = mComponents.get(i);
retVal |= component.update(timeElapsed);
}
}
return retVal;
}
@Override
public void renderBlended(RenderView view, GL11 gl) {
// Draw components.
final Texture fill = view.getResource(FILL);
final Texture join = view.getResource(JOIN);
final Texture cap = view.getResource(CAP);
final float y = mY + 3;
int x = (int) (3 * App.PIXEL_DENSITY);
float height = mHeight;
synchronized (mComponents) {
int numComponents = mComponents.size();
for (int i = 0; i < numComponents; ++i) {
Component component = mComponents.get(i);
component.x = x;
// Draw the left join if not the first component, and the fill.
// TODO: Draw the pressed background for mTouchItem.
final int width = (int) component.animWidth;
if (i != 0) {
view.draw2D(join, x - join.getWidth(), y);
if (view.bind(fill)) {
view.draw2D(x, y, 0f, width, height);
}
} else if (view.bind(fill)) {
view.draw2D(0f, y, 0f, x + width, height);
}
if (i == numComponents - 1) {
// Draw the cap on the right edge.
view.draw2D(cap, x + width, y);
}
float xOffset = 5 * App.PIXEL_DENSITY;
// Draw the label.
final int[] icons = component.animatedIcons;
// Cycles animated icons.
final int iconId = (icons != null && icons.length > 0) ? icons[(int) (component.timeElapsed * 20.0f) % icons.length]
: component.icon;
final Texture icon = view.getResource(iconId);
if (icon != null) {
view.loadTexture(icon);
view.draw2D(icon, x + xOffset, y - 2 * App.PIXEL_DENSITY);
}
if (i == numComponents - 1) {
final StringTexture texture = component.texture;
view.loadTexture(texture);
float iconWidth = component.getIconWidth();
if (texture.computeTextWidth() <= (width - iconWidth)) {
float textOffset = (iconWidth == 0) ? 8 * App.PIXEL_DENSITY : iconWidth;
view.draw2D(texture, x + textOffset, y + 5);
}
}
x += (int) (width + (21 * App.PIXEL_DENSITY + 0.5f));
}
}
}
private Component hitTestItems(float x, float y) {
if (y >= mY && y < mY + mHeight) {
synchronized (mComponents) {
int numComponents = mComponents.size();
for (int i = 0; i < numComponents; i++) {
final Component component = mComponents.get(i);
float componentx = component.x;
if (x >= componentx && x < componentx + component.width) {
return component;
}
}
}
}
return null;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final float x = event.getX();
final float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchItem = hitTestItems(x, y);
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_UP:
if (mTouchItem != null) {
mTouchItem.action.run();
}
case MotionEvent.ACTION_CANCEL:
mTouchItem = null;
break;
}
return true;
}
public void recomputeComponents() {
float width = mWidth;
width -= 20f * App.PIXEL_DENSITY;
synchronized (mComponents) {
int numComponents = mComponents.size();
for (int i = 0; i < numComponents; i++) {
Component component = mComponents.get(i);
width -= (component.getIconWidth() + 20.0f * App.PIXEL_DENSITY);
component.computeLabel(width);
}
}
}
public int getNumLevels() {
synchronized (mComponents) {
return mComponents.size();
}
}
public void clear() {
synchronized (mComponents) {
mComponents.clear();
}
}
}