Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package ru.nolesh.libgdx.extension;
- import java.io.DataInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.net.HttpURLConnection;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import com.badlogic.gdx.Gdx;
- import com.badlogic.gdx.files.FileHandle;
- import com.badlogic.gdx.graphics.Color;
- import com.badlogic.gdx.graphics.Pixmap;
- import com.badlogic.gdx.graphics.Texture;
- import com.badlogic.gdx.graphics.g2d.BitmapFont;
- import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
- import com.badlogic.gdx.graphics.g2d.SpriteBatch;
- import com.badlogic.gdx.scenes.scene2d.InputEvent;
- import com.badlogic.gdx.scenes.scene2d.InputListener;
- import com.badlogic.gdx.scenes.scene2d.ui.List.ListStyle;
- import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
- import com.badlogic.gdx.scenes.scene2d.ui.Widget;
- import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent;
- import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
- import com.badlogic.gdx.utils.GdxRuntimeException;
- import com.badlogic.gdx.utils.Pools;
- /**
- * Extended list with headers. It allows to load images from URL in lazy mode.
- * @author Nolesh
- */
- public class MyLazyImageList extends ScrollPane{
- public static final String SEPARATOR = "/*~*/";
- private static final String SEPARATOR_TEMPLATE = "/\\*~\\*/";
- private static final int MAX_THREAD_AMOUNT = 2;
- private volatile static int threadAmount;
- private MyRawList rawList;
- private boolean isEnabled;
- private String emptyLabel;
- private Texture placeholder;
- private String headers[];
- private Drawable headersBackground;
- private Color headersColor;
- private boolean useLocalStorage;
- /**
- * Constructor
- * @param items To create items use MyLazyImageListItem.formItems(names, urls)
- * @param style
- * @param listStyle
- * @param placeholder It must not be empty!
- * @param useLocalStorage If true, downloaded images are stored relative to private storage of the app.
- * Otherwise, they are stored relative to SD card root (Neends WRITE_EXTERNAL_STORAGE permission).
- */
- public MyLazyImageList(MyLazyImageListItem[] items, ScrollPaneStyle style,
- ListStyle listStyle, Texture placeholder, boolean useLocalStorage){
- super(null, style);
- isEnabled = true;
- rawList = new MyRawList(items, listStyle, this);
- setWidget(rawList);
- setWidth(rawList.getPrefWidth());
- setHeight(rawList.getPrefHeight());
- setScrollingDisabled(true, false);
- emptyLabel = "There are no any items";
- if(placeholder==null)
- throw new IllegalArgumentException("Placeholder must not be empty!");
- this.placeholder=placeholder;
- this.useLocalStorage = useLocalStorage;
- threadAmount=0;
- }
- public boolean isEnabled() {
- return isEnabled;
- }
- public void setEnabled(boolean isEnabled) {
- this.isEnabled = isEnabled;
- }
- public void setItems(MyLazyImageListItem[] items){
- rawList.setItems(items);
- }
- public void setSelectedIndex(int index){
- rawList.setSelectedIndex(index);
- }
- public int getSelectedIndex(){
- if(isEnabled) return rawList.getSelectedIndex();
- else return -1;
- }
- public String getEmptyLabel() {
- return emptyLabel;
- }
- public void setEmptyLabel(String emptyLabel) {
- this.emptyLabel = emptyLabel;
- }
- public String[] getHeaders() {
- return headers;
- }
- /**
- * Sets the headers
- * @param headers String of headers (Use SEPARATOR to concatenate headers to each other)
- * @param background - Must be not null!
- */
- public void setHeaders(String headers, Drawable background) {
- if(background==null) throw new IllegalArgumentException("Background must be not null!");
- this.headers = headers.split(SEPARATOR_TEMPLATE);
- headersBackground = background;
- }
- public Color getHeadersColor() {
- return headersColor;
- }
- public void setHeadersColor(Color headersColor) {
- this.headersColor = headersColor;
- }
- /******************** RAW LIST ************************/
- public class MyRawList extends Widget{
- private MyLazyImageList myLazyImageList;
- private ListStyle style;
- private MyLazyImageListItem[] items;
- private int selectedIndex;
- private float prefWidth, prefHeight;
- private float itemHeight;
- private float textOffsetX, textOffsetY;
- private float coefH;
- private float coefW;
- private Map<String, Texture> cache;
- private Map<String, Texture> tempCache;
- private int imageWidth = 35, imageHeight = 26;
- public MyRawList (MyLazyImageListItem[] items, ListStyle style, MyLazyImageList myLazyImageList) {
- coefH = (float)Gdx.graphics.getHeight()/320;
- coefW = (float)Gdx.graphics.getWidth()/480;
- setStyle(style);
- setItems(items);
- setWidth(getPrefWidth());
- setHeight(getPrefHeight());
- this.myLazyImageList=myLazyImageList;
- cache = new HashMap<String, Texture>();
- tempCache = new HashMap<String, Texture>();
- addListener(new InputListener() {
- public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
- if(!isEnabled) return false;
- if (pointer == 0 && button != 0) return false;
- MyRawList.this.touchDown(y);
- return true;
- }
- });
- }
- protected void setItemIntoCache(String url, Texture texture){
- cache.put(url, texture);
- }
- volatile List<String> beingDownloaded = new ArrayList<String>();
- volatile List<String> downloaded = new ArrayList<String>();
- private FileHandle getFileHandleFromURL(URL url){
- String filename = url.getFile();
- String[] splitter = filename.split("/");
- filename = splitter[splitter.length-1];
- FileHandle fileHandle = useLocalStorage ? Gdx.files.local(filename) : Gdx.files.external(filename);
- return fileHandle;
- }
- protected Texture getTexture(MyLazyImageListItem item){
- Texture texture = getTextureFromCache(item.url.toString());
- if(texture!=null){
- return texture;
- }
- FileHandle image = getFileHandleFromURL(item.url);
- if(image.exists()&&downloaded.contains(item.url.toString())
- &&!beingDownloaded.contains(item.url.toString())){
- InputStream is = image.read();
- DataInputStream dis = new DataInputStream(is);
- byte[] data = new byte[(int)image.length()];
- try {
- dis.readFully(data);
- dis.close();
- image.delete();
- Gdx.app.log("MyLazyImageList", "Size of '"+item.url.toString()+"': "+data.length);
- setItemIntoCache(item.url.toString(), new Texture(new Pixmap(data, 0, data.length)));
- return getTextureFromCache(item.url.toString());
- } catch (IOException e) {}
- }
- asyncDownloadTextureFromURL(item.url, image);
- return placeholder;
- }
- protected void clearTextureCache(int from, int to) {
- List<String> temp = new ArrayList<String>();
- for(int i = from; i<=to; i++){
- if(!temp.contains(items[i].url.toString())&&downloaded.contains(items[i].url.toString())){
- temp.add(items[i].url.toString());
- }
- }
- downloaded.clear();
- downloaded.addAll(temp);
- for(String key : downloaded){
- if(cache.containsKey(key)){
- tempCache.put(key, cache.get(key));
- }
- }
- cache.clear();
- cache.putAll(tempCache);
- tempCache.clear();
- }
- protected Texture getTextureFromCache(String url) {
- if (cache.containsKey(url)) {
- return cache.get(url);
- }
- return null;
- }
- protected void asyncDownloadTextureFromURL(final URL url, final FileHandle image) {
- if(beingDownloaded.contains(url.toString())) return;
- if(threadAmount>=MAX_THREAD_AMOUNT) return;
- threadAmount++;
- new Thread(new Runnable() {
- @Override
- public void run() {
- beingDownloaded.add(url.toString());
- Gdx.app.log("MyLazyImageList", "Downloading started: "+url.toString());
- Pixmap pixmap = syncDownloadPixmapFromURL(url);
- if(image.exists()) image.delete();
- if(pixmap==null){
- beingDownloaded.remove(url.toString());
- threadAmount--;
- return;
- }
- OutputStream stream = image.write(false);
- try {
- /**
- *TO GET PNG ENCODER CLASS FOLLOW TO: http://pastebin.com/psF60D8Q
- **/
- byte[] bytes = PNG.toPNG(pixmap);
- stream.write(bytes);
- stream.close();
- Gdx.app.log("MyLazyImageList", "Downloading stopped: "+url.toString());
- if(!downloaded.contains(url.toString()))
- downloaded.add(url.toString());
- beingDownloaded.remove(url.toString());
- } catch (IOException e) {}
- finally{
- threadAmount--;
- }
- }
- }).start();
- }
- private Pixmap syncDownloadPixmapFromURL(URL url) {
- try {
- HttpURLConnection conn= (HttpURLConnection)url.openConnection();
- conn.setDoInput(true);
- conn.connect();
- int length = conn.getContentLength();
- if(length<=0) return null;
- InputStream is = conn.getInputStream();
- DataInputStream dis = new DataInputStream(is);
- byte[] data = new byte[length];
- dis.readFully(data);
- Pixmap pixmap = new Pixmap(data, 0, data.length);
- pixmap = ImagePow2.isPow2(pixmap)?pixmap:ImagePow2.getPow2Pixmap(pixmap);
- return pixmap;
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return null;
- }
- void touchDown (float y) {
- int oldIndex = selectedIndex;
- selectedIndex = (int)((getHeight() - y) / itemHeight);
- selectedIndex = Math.max(0, selectedIndex);
- selectedIndex = Math.min(items.length - 1, selectedIndex);
- ChangeEvent changeEvent = Pools.obtain(ChangeEvent.class);
- if (fire(changeEvent)) selectedIndex = oldIndex;
- Pools.free(changeEvent);
- }
- public void setStyle (ListStyle style) {
- if (style == null) throw new IllegalArgumentException("style cannot be null.");
- this.style = style;
- if (items != null)
- setItems(items);
- else
- invalidateHierarchy();
- }
- /** Returns the list's style. Modifying the returned style may not have an effect until {@link #setStyle(ListStyle)} is called. */
- public ListStyle getStyle () {
- return style;
- }
- int startIndex = 0;
- int lastVisibleIndex = 0;
- @Override
- public void draw (SpriteBatch batch, float parentAlpha) {
- BitmapFont font = style.font;
- Drawable selectedDrawable = style.selection;
- Color fontColorSelected = style.fontColorSelected;
- Color fontColorUnselected = style.fontColorUnselected;
- float x = getX();
- float y = getY();
- Color color = getColor();
- parentAlpha*=getColor().a;
- batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
- font.setColor(fontColorUnselected.r, fontColorUnselected.g, fontColorUnselected.b, fontColorUnselected.a * parentAlpha);
- float itemY = getHeight();
- //Makes offset for headers
- if(headers!=null && !headers.equals("")){
- itemY -= itemHeight/3 + (textOffsetY/3)*coefH - font.getBounds(headers[0]).height/2;
- }
- if(items==null){
- float centerX = myLazyImageList.getWidth()/2;
- float centerY = myLazyImageList.getHeight()/2;
- font.draw(batch, emptyLabel, centerX - font.getBounds(emptyLabel).width/2,
- centerY+font.getBounds(emptyLabel).height/2);
- return;
- }
- boolean isSetLastVisibleIndex = true;
- for (int i = 0; i < items.length; i++) {
- boolean isDrawn = true;
- if(getHeight()-itemY<myLazyImageList.getScrollY()-itemHeight){
- startIndex=i;
- isDrawn=false;
- }
- if(getHeight()-itemY>myLazyImageList.getScrollY()+myLazyImageList.getHeight()){
- if(isSetLastVisibleIndex) lastVisibleIndex=i;
- isSetLastVisibleIndex = false;
- isDrawn=false;
- }
- if(isDrawn){
- if (selectedIndex == i && selectedIndex!=-1) {
- selectedDrawable.draw(batch, x, y + itemY - itemHeight, getWidth(), itemHeight);
- font.setColor(fontColorSelected.r, fontColorSelected.g,
- fontColorSelected.b, fontColorSelected.a * parentAlpha);
- }
- else{
- font.setColor(fontColorUnselected.r, fontColorUnselected.g, fontColorUnselected.b,
- fontColorUnselected.a * parentAlpha);
- }
- String[] elements = items[i].name.split(SEPARATOR_TEMPLATE);
- float equalPartWidth = getWidth()/(elements.length+1);
- for(int j=0; j<elements.length; j++){
- String shortName = cutName(font, elements[j], (int)(equalPartWidth));
- if(shortName.equals(elements[j]))
- font.draw(batch, elements[j]
- , x + textOffsetX +equalPartWidth*(j)+(equalPartWidth-font.getBounds(elements[j]).width)/2,
- y + itemY - textOffsetY*coefH - font.getBounds(items[i].showName).height/2);
- else
- font.draw(batch, shortName
- , x + textOffsetX + equalPartWidth*(j),
- y + itemY - textOffsetY*coefH - font.getBounds(items[i].showName).height/2);
- }
- Texture tempTexture = getTexture(items[i]);
- if(tempTexture!=null)
- batch.draw(tempTexture, x + textOffsetX +equalPartWidth*(elements.length)+(equalPartWidth-imageWidth)/2,
- y + itemY-textOffsetY*coefH/2-imageHeight , imageWidth, imageHeight);
- }
- itemY -= itemHeight;
- }
- //Drawing headers
- if(headers!=null && !headers.equals("")){
- float height = font.getBounds(headers[0]).height + 6*coefH;
- headersBackground.draw(batch, 0, myLazyImageList.getHeight()-height, myLazyImageList.getWidth(), height);
- float equalPartWidthForHeader = getWidth()/headers.length;
- font.setColor(headersColor==null?fontColorSelected:headersColor);
- for(int k=0; k<headers.length; k++){
- font.draw(batch, headers[k], x+ textOffsetX + equalPartWidthForHeader*(k)
- + (equalPartWidthForHeader-font.getBounds(headers[k]).width)/2,
- myLazyImageList.getHeight()-3*coefH);
- }
- }
- clearTextureCache(startIndex, lastVisibleIndex);
- }
- private String cutName(BitmapFont font, String name, int width){
- if(font.getBounds(name).width<=width) return name;
- String tempName = name;
- while(true){
- if(font.getBounds(tempName+"...").width>width){
- if(tempName.length()<3) break;
- tempName=tempName.substring(0, tempName.length()-2);
- }
- else break;
- }
- return tempName+"...";
- }
- /** @return The index of the currently selected item. The top item has an index of 0. */
- public int getSelectedIndex () {
- return selectedIndex;
- }
- public void setSelectedIndex (int index) {
- if(index==-1) { selectedIndex = -1; return; }
- if(items==null) throw new GdxRuntimeException("There are no any items!");
- if (index < -1 || index >= items.length)
- throw new GdxRuntimeException("index must be >= -1 and < " + items.length + ": " + index);
- selectedIndex = index;
- }
- /** @return The text of the currently selected item or null if the list is empty. */
- public MyLazyImageListItem getSelection () {
- if(items==null) return null;
- if (items.length == 0) return null;
- return items[selectedIndex];
- }
- /** @return The index of the item that was selected, or -1. */
- public int setSelection (String item) {
- selectedIndex = -1;
- if(items==null) return -1;
- for (int i = 0, n = items.length; i < n; i++) {
- if (items[i].equals(item)) {
- selectedIndex = i;
- break;
- }
- }
- return selectedIndex;
- }
- public void setItems (MyLazyImageListItem[] objects) {
- if(objects == null){
- items = null;
- return;
- }
- if (!(objects instanceof MyLazyImageListItem[])) {
- throw new IllegalArgumentException("Items must be instance of MyLazyImageListItem");
- }
- items = objects;
- selectedIndex = 0;
- final BitmapFont font = style.font;
- final Drawable selectedDrawable = style.selection;
- itemHeight = font.getCapHeight() - font.getDescent() * 2;
- itemHeight += selectedDrawable.getTopHeight() + selectedDrawable.getBottomHeight();
- itemHeight*=coefH;
- prefWidth += selectedDrawable.getLeftWidth() + selectedDrawable.getRightWidth();
- textOffsetX = selectedDrawable.getLeftWidth();
- textOffsetY = selectedDrawable.getTopHeight() - font.getDescent();
- prefWidth = 0;
- for (int i = 0; i < items.length; i++) {
- TextBounds bounds = font.getBounds(items[i].name);
- prefWidth = Math.max(bounds.width, prefWidth);
- }
- prefHeight = items.length * itemHeight;
- imageWidth*=coefW;
- imageHeight*=coefH;
- invalidateHierarchy();
- }
- public MyLazyImageListItem[] getItems () {
- return items;
- }
- public float getPrefWidth () {
- return prefWidth;
- }
- public float getPrefHeight () {
- return prefHeight;
- }
- }
- /************************ LIST ITEM ************************/
- public static class MyLazyImageListItem{
- private String showName;
- public String name;
- public URL url;
- public MyLazyImageListItem(String name, URL url){
- showName = name;
- this.name = name;
- this.url=url;
- }
- /**
- * Forms array of items (size of texts must be equal to size of urls)
- * @param texts If you want to have several columns, you should split them by SEPARATOR
- * @param urls URLs of the images which has to be downloaded
- * @return
- */
- public static MyLazyImageListItem[] formItems(String[] texts, URL[] urls) {
- if(texts.length!=urls.length) return null;
- MyLazyImageListItem[] listItems = new MyLazyImageListItem[texts.length];
- for (int i=0; i<texts.length; i++) {
- listItems[i] = new MyLazyImageListItem(texts[i], urls[i]);
- }
- return listItems;
- }
- }
- public static class ImagePow2 {
- static int pow2[] = {2,4,8,16,32,64,128,256,512,1024,2048,4096,8192};
- public static boolean isPow2(Pixmap pixmap){
- boolean isWidthPow2 = false, isHeightPow2 = false;
- for(int i=0; i<pow2.length; i++){
- if(pow2[i]==pixmap.getWidth()) isWidthPow2=true;
- if(pow2[i]==pixmap.getHeight()) isHeightPow2=true;
- }
- return isWidthPow2&&isHeightPow2;
- }
- private static int getPow2(int value){
- int diff = value;
- int tmp = value;
- int minVal = value;
- for(int i=0; i<pow2.length; i++){
- diff = Math.abs(value - pow2[i]);
- if(tmp>diff){
- tmp=diff;
- minVal = pow2[i];
- }
- }
- return minVal;
- }
- public static Pixmap getPow2Pixmap(Pixmap pixmap){
- int width = getPow2(pixmap.getWidth());
- int height = getPow2(pixmap.getHeight());
- Pixmap updatedPixmap = new Pixmap(width, height, pixmap.getFormat());
- updatedPixmap.drawPixmap(pixmap, 0, 0, pixmap.getWidth(), pixmap.getHeight(), 0, 0, width, height);
- return updatedPixmap;
- }
- }
- }
- /**How to use**/
- /*
- MyLazyImageList myLazyListTop100 = new MyLazyImageList(null, scrollPaneStyle, listStyle,
- new Texture(Gdx.files.internal("skins/unknown_flag.png")), false);
- myLazyListTop100.setEnabled(false);
- String splitter = MyLazyImageList.SEPARATOR;
- //MyDrawable implements Drawable
- myLazyListTop100.setHeaders("#"+splitter+"Nickname"+splitter+"Location"+splitter+"Score"+splitter+"Flag",
- new MyDrawable(new NinePatch(new Texture(Gdx.files.internal("images/background_list.png")))));
- myLazyListTop100.setHeadersColor(new Color(0, 1, 1, 1));
- myLazyListTop100.setBounds(5, 5, width, height );
- myLazyListTop100.setEnabled(false);
- myLazyListTop100.setSelectedIndex(-1);
- myLazyListTop100.setItems(null);
- myLazyListTop100.setEmptyLabel("Loading...");
- stage.addActor(myLazyListTop100);
- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement