1 /*******************************************************************************
\r
2 * Copyright 2011 See AUTHORS file.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
15 ******************************************************************************/
\r
17 package com.badlogic.gdx.scenes.scene2d.ui;
\r
19 import com.badlogic.gdx.graphics.Color;
\r
20 import com.badlogic.gdx.graphics.g2d.BitmapFont;
\r
21 import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;
\r
22 import com.badlogic.gdx.graphics.g2d.NinePatch;
\r
23 import com.badlogic.gdx.graphics.g2d.SpriteBatch;
\r
24 import com.badlogic.gdx.math.Rectangle;
\r
25 import com.badlogic.gdx.scenes.scene2d.ActorEvent;
\r
26 import com.badlogic.gdx.scenes.scene2d.ActorListener;
\r
27 import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener.ChangeEvent;
\r
28 import com.badlogic.gdx.scenes.scene2d.utils.Cullable;
\r
29 import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
\r
30 import com.badlogic.gdx.utils.GdxRuntimeException;
\r
32 /** A list (aka list box) displays textual items and highlights the currently selected item.
\r
34 * The preferred size of the list is determined by the text bounds of the items and the size of the {@link ListStyle#selection}.
\r
35 * @author mzechner */
\r
36 public class List extends Widget implements Cullable {
\r
37 private ListStyle style;
\r
38 private String[] items;
\r
39 private int selectedIndex;
\r
40 private Rectangle cullingArea;
\r
41 private float prefWidth, prefHeight;
\r
42 private float itemHeight;
\r
43 private float textOffsetX, textOffsetY;
\r
45 public List (Skin skin) {
\r
46 this(new Object[0], skin);
\r
49 public List (Object[] items, Skin skin) {
\r
50 this(items, skin.get(ListStyle.class));
\r
53 public List (Object[] items, ListStyle style) {
\r
56 setWidth(getPrefWidth());
\r
57 setHeight(getPrefHeight());
\r
59 addListener(new ActorListener() {
\r
60 public boolean touchDown (ActorEvent event, float x, float y, int pointer, int button) {
\r
61 if (pointer != 0) return false;
\r
62 List.this.touchDown(y);
\r
68 void touchDown (float y) {
\r
69 int oldIndex = selectedIndex;
\r
70 selectedIndex = (int)((getHeight() - y) / itemHeight);
\r
71 selectedIndex = Math.max(0, selectedIndex);
\r
72 selectedIndex = Math.min(items.length - 1, selectedIndex);
\r
73 if (fire(new ChangeEvent())) selectedIndex = oldIndex;
\r
76 public void setStyle (ListStyle style) {
\r
77 if (style == null) throw new IllegalArgumentException("style cannot be null.");
\r
82 invalidateHierarchy();
\r
85 /** Returns the list's style. Modifying the returned style may not have an effect until {@link #setStyle(ListStyle)} is called. */
\r
86 public ListStyle getStyle () {
\r
91 public void draw (SpriteBatch batch, float parentAlpha) {
\r
92 BitmapFont font = style.font;
\r
93 Drawable selectedDrawable = style.selection;
\r
94 Color fontColorSelected = style.fontColorSelected;
\r
95 Color fontColorUnselected = style.fontColorUnselected;
\r
97 Color color = getColor();
\r
98 batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);
\r
103 font.setColor(fontColorUnselected.r, fontColorUnselected.g, fontColorUnselected.b, fontColorUnselected.a * parentAlpha);
\r
104 float itemY = getHeight();
\r
105 for (int i = 0; i < items.length; i++) {
\r
106 if (cullingArea == null || (itemY - itemHeight <= cullingArea.y + cullingArea.height && itemY >= cullingArea.y)) {
\r
107 if (selectedIndex == i) {
\r
108 selectedDrawable.draw(batch, x, y + itemY - itemHeight, Math.max(prefWidth, getWidth()), itemHeight);
\r
109 font.setColor(fontColorSelected.r, fontColorSelected.g, fontColorSelected.b, fontColorSelected.a * parentAlpha);
\r
111 font.draw(batch, items[i], x + textOffsetX, y + itemY - textOffsetY);
\r
112 if (selectedIndex == i) {
\r
113 font.setColor(fontColorUnselected.r, fontColorUnselected.g, fontColorUnselected.b, fontColorUnselected.a
\r
116 } else if (itemY < cullingArea.y) {
\r
119 itemY -= itemHeight;
\r
123 /** @return The index of the currently selected item. The top item has an index of 0. */
\r
124 public int getSelectedIndex () {
\r
125 return selectedIndex;
\r
128 public void setSelectedIndex (int index) {
\r
129 if (index < 0 || index >= items.length)
\r
130 throw new GdxRuntimeException("index must be >= 0 and < " + items.length + ": " + index);
\r
131 selectedIndex = index;
\r
134 /** @return The text of the currently selected item or null if the list is empty. */
\r
135 public String getSelection () {
\r
136 if (items.length == 0) return null;
\r
137 return items[selectedIndex];
\r
140 /** @return The index of the item that was selected, or -1. */
\r
141 public int setSelection (String item) {
\r
142 selectedIndex = -1;
\r
143 for (int i = 0, n = items.length; i < n; i++) {
\r
144 if (items[i].equals(item)) {
\r
149 return selectedIndex;
\r
152 public void setItems (Object[] objects) {
\r
153 if (objects == null) throw new IllegalArgumentException("items cannot be null.");
\r
155 if (!(objects instanceof String[])) {
\r
156 String[] strings = new String[objects.length];
\r
157 for (int i = 0, n = objects.length; i < n; i++)
\r
158 strings[i] = String.valueOf(objects[i]);
\r
161 items = (String[])objects;
\r
165 final BitmapFont font = style.font;
\r
166 final Drawable selectedDrawable = style.selection;
\r
168 itemHeight = font.getCapHeight() - font.getDescent() * 2;
\r
169 itemHeight += selectedDrawable.getTopHeight() + selectedDrawable.getBottomHeight();
\r
170 prefWidth += selectedDrawable.getLeftWidth() + selectedDrawable.getRightWidth();
\r
171 textOffsetX = selectedDrawable.getLeftWidth();
\r
172 textOffsetY = selectedDrawable.getTopHeight() - font.getDescent();
\r
175 for (int i = 0; i < items.length; i++) {
\r
176 TextBounds bounds = font.getBounds(items[i]);
\r
177 prefWidth = Math.max(bounds.width, prefWidth);
\r
179 prefHeight = items.length * itemHeight;
\r
181 invalidateHierarchy();
\r
184 public String[] getItems () {
\r
188 public float getPrefWidth () {
\r
192 public float getPrefHeight () {
\r
196 public void setCullingArea (Rectangle cullingArea) {
\r
197 this.cullingArea = cullingArea;
\r
200 /** The style for a list, see {@link List}.
\r
202 * @author Nathan Sweet */
\r
203 static public class ListStyle {
\r
204 public BitmapFont font;
\r
205 public Color fontColorSelected = new Color(1, 1, 1, 1);
\r
206 public Color fontColorUnselected = new Color(1, 1, 1, 1);
\r
207 public Drawable selection;
\r
209 public ListStyle () {
\r
212 public ListStyle (BitmapFont font, Color fontColorSelected, Color fontColorUnselected, Drawable selection) {
\r
214 this.fontColorSelected.set(fontColorSelected);
\r
215 this.fontColorUnselected.set(fontColorUnselected);
\r
216 this.selection = selection;
\r
219 public ListStyle (ListStyle style) {
\r
220 this.font = style.font;
\r
221 this.fontColorSelected.set(style.fontColorSelected);
\r
222 this.fontColorUnselected.set(style.fontColorUnselected);
\r
223 this.selection = style.selection;
\r