OSDN Git Service

247d7c43bed46b6ff7d91efe0a0e0e4a4231fe12
[mikumikustudio/libgdx-mikumikustudio.git] / gdx / src / com / badlogic / gdx / scenes / scene2d / ui / Label.java
1 /*******************************************************************************\r
2  * Copyright 2011 See AUTHORS file.\r
3  * \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
7  * \r
8  *   http://www.apache.org/licenses/LICENSE-2.0\r
9  * \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
16 \r
17 package com.badlogic.gdx.scenes.scene2d.ui;\r
18 \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.HAlignment;\r
22 import com.badlogic.gdx.graphics.g2d.BitmapFont.TextBounds;\r
23 import com.badlogic.gdx.graphics.g2d.BitmapFontCache;\r
24 import com.badlogic.gdx.graphics.g2d.SpriteBatch;\r
25 import com.badlogic.gdx.scenes.scene2d.utils.Align;\r
26 import com.badlogic.gdx.scenes.scene2d.utils.Drawable;\r
27 import com.badlogic.gdx.utils.StringBuilder;\r
28 \r
29 /** A text label, with optional word wrapping.\r
30  * <p>\r
31  * The preferred size of the label is determined by the actual text bounds, unless {@link #setWrap(boolean) word wrap} is enabled.\r
32  * @author Nathan Sweet */\r
33 public class Label extends Widget {\r
34         private LabelStyle style;\r
35         private final TextBounds bounds = new TextBounds();\r
36         private final StringBuilder text = new StringBuilder();\r
37         private StringBuilder tempText;\r
38         private BitmapFontCache cache;\r
39         private int labelAlign = Align.left;\r
40         private HAlignment lineAlign = HAlignment.LEFT;\r
41         private boolean wrap;\r
42         private float lastPrefHeight;\r
43         private boolean sizeInvalid = true;\r
44         private float fontScaleX = 1, fontScaleY = 1;\r
45         private boolean ellipse;\r
46 \r
47         public Label (CharSequence text, Skin skin) {\r
48                 this(text, skin.get(LabelStyle.class));\r
49         }\r
50 \r
51         public Label (CharSequence text, Skin skin, String styleName) {\r
52                 this(text, skin.get(styleName, LabelStyle.class));\r
53         }\r
54 \r
55         /** Creates a label, using a {@link LabelStyle} that has a BitmapFont with the specified name from the skin and the specified\r
56          * color. */\r
57         public Label (CharSequence text, Skin skin, String fontName, Color color) {\r
58                 this(text, new LabelStyle(skin.getFont(fontName), color));\r
59         }\r
60 \r
61         /** Creates a label, using a {@link LabelStyle} that has a BitmapFont with the specified name and the specified color from the\r
62          * skin. */\r
63         public Label (CharSequence text, Skin skin, String fontName, String colorName) {\r
64                 this(text, new LabelStyle(skin.getFont(fontName), skin.getColor(colorName)));\r
65         }\r
66 \r
67         public Label (CharSequence text, LabelStyle style) {\r
68                 if (text != null) this.text.append(text);\r
69                 setStyle(style);\r
70                 setWidth(getPrefWidth());\r
71                 setHeight(getPrefHeight());\r
72         }\r
73 \r
74         public void setStyle (LabelStyle style) {\r
75                 if (style == null) throw new IllegalArgumentException("style cannot be null.");\r
76                 if (style.font == null) throw new IllegalArgumentException("Missing LabelStyle font.");\r
77                 this.style = style;\r
78                 cache = new BitmapFontCache(style.font, style.font.usesIntegerPositions());\r
79                 invalidateHierarchy();\r
80         }\r
81 \r
82         /** Returns the label's style. Modifying the returned style may not have an effect until {@link #setStyle(LabelStyle)} is\r
83          * called. */\r
84         public LabelStyle getStyle () {\r
85                 return style;\r
86         }\r
87 \r
88         /** @param newText May be null. */\r
89         public void setText (CharSequence newText) {\r
90                 if (newText instanceof StringBuilder) {\r
91                         if (text.equals(newText)) return;\r
92                         text.setLength(0);\r
93                         text.append((StringBuilder)newText);\r
94                 } else {\r
95                         if (newText == null) newText = "";\r
96                         if (textEquals(newText)) return;\r
97                         text.setLength(0);\r
98                         text.append(newText);\r
99                 }\r
100                 invalidateHierarchy();\r
101         }\r
102 \r
103         public boolean textEquals (CharSequence other) {\r
104                 int length = text.length;\r
105                 char[] chars = text.chars;\r
106                 if (length != other.length()) return false;\r
107                 for (int i = 0; i < length; i++)\r
108                         if (chars[i] != other.charAt(i)) return false;\r
109                 return true;\r
110         }\r
111 \r
112         public CharSequence getText () {\r
113                 return text;\r
114         }\r
115 \r
116         public void invalidate () {\r
117                 super.invalidate();\r
118                 sizeInvalid = true;\r
119         }\r
120 \r
121         private void computeSize () {\r
122                 sizeInvalid = false;\r
123                 if (wrap) {\r
124                         float width = getWidth();\r
125                         if (style.background != null) width -= style.background.getLeftWidth() + style.background.getRightWidth();\r
126                         bounds.set(cache.getFont().getWrappedBounds(text, width));\r
127                 } else\r
128                         bounds.set(cache.getFont().getMultiLineBounds(text));\r
129                 bounds.width *= fontScaleX;\r
130                 bounds.height *= fontScaleY;\r
131         }\r
132 \r
133         public void layout () {\r
134                 if (sizeInvalid) computeSize();\r
135 \r
136                 if (wrap) {\r
137                         float prefHeight = getPrefHeight();\r
138                         if (prefHeight != lastPrefHeight) {\r
139                                 lastPrefHeight = prefHeight;\r
140                                 invalidateHierarchy();\r
141                         }\r
142                 }\r
143 \r
144                 BitmapFont font = cache.getFont();\r
145                 float oldScaleX = font.getScaleX();\r
146                 float oldScaleY = font.getScaleY();\r
147                 if (fontScaleX != 1 || fontScaleY != 1) font.setScale(fontScaleX, fontScaleY);\r
148 \r
149                 float width = getWidth(), height = getHeight();\r
150                 StringBuilder text;\r
151                 if (ellipse && width < bounds.width) {\r
152                         float ellipseWidth = font.getBounds("...").width;\r
153                         text = tempText != null ? tempText : (tempText = new StringBuilder());\r
154                         text.setLength(0);\r
155                         if (width > ellipseWidth) {\r
156                                 text.append(this.text, 0, font.computeVisibleGlyphs(this.text, 0, this.text.length, width - ellipseWidth));\r
157                                 text.append("...");\r
158                         }\r
159                 } else\r
160                         text = this.text;\r
161 \r
162                 Drawable background = style.background;\r
163                 float x = 0, y = 0;\r
164                 if (background != null) {\r
165                         x = background.getLeftWidth();\r
166                         y = background.getBottomHeight();\r
167                         width -= background.getLeftWidth() + background.getRightWidth();\r
168                         height -= background.getBottomHeight() + background.getTopHeight();\r
169                 }\r
170                 if ((labelAlign & Align.top) != 0) {\r
171                         y += cache.getFont().isFlipped() ? 0 : height - bounds.height;\r
172                         y += style.font.getDescent();\r
173                 } else if ((labelAlign & Align.bottom) != 0) {\r
174                         y += cache.getFont().isFlipped() ? height - bounds.height : 0;\r
175                         y -= style.font.getDescent();\r
176                 } else\r
177                         y += (int)((height - bounds.height) / 2);\r
178                 if (!cache.getFont().isFlipped()) y += bounds.height;\r
179 \r
180                 if ((labelAlign & Align.left) == 0) {\r
181                         if ((labelAlign & Align.right) != 0)\r
182                                 x += width - bounds.width;\r
183                         else\r
184                                 x += (int)((width - bounds.width) / 2);\r
185                 }\r
186 \r
187                 if (wrap)\r
188                         cache.setWrappedText(text, x, y, bounds.width, lineAlign);\r
189                 else\r
190                         cache.setMultiLineText(text, x, y, bounds.width, lineAlign);\r
191 \r
192                 if (fontScaleX != 1 || fontScaleY != 1) font.setScale(oldScaleX, oldScaleY);\r
193         }\r
194 \r
195         public void draw (SpriteBatch batch, float parentAlpha) {\r
196                 validate();\r
197                 Color color = getColor();\r
198                 if (style.background != null) {\r
199                         batch.setColor(color.r, color.g, color.b, color.a * parentAlpha);\r
200                         style.background.draw(batch, getX(), getY(), getWidth(), getHeight());\r
201                 }\r
202                 cache.setColor(style.fontColor == null ? color : Color.tmp.set(color).mul(style.fontColor));\r
203                 cache.setPosition(getX(), getY());\r
204                 cache.draw(batch, color.a * parentAlpha);\r
205         }\r
206 \r
207         public float getPrefWidth () {\r
208                 if (wrap) return 0;\r
209                 if (sizeInvalid) computeSize();\r
210                 float width = bounds.width;\r
211                 Drawable background = style.background;\r
212                 if (background != null) width += background.getLeftWidth() + background.getRightWidth();\r
213                 return width;\r
214         }\r
215 \r
216         public float getPrefHeight () {\r
217                 if (sizeInvalid) computeSize();\r
218                 float height = bounds.height - style.font.getDescent() * 2;\r
219                 Drawable background = style.background;\r
220                 if (background != null) height += background.getTopHeight() + background.getBottomHeight();\r
221                 return height;\r
222         }\r
223 \r
224         public TextBounds getTextBounds () {\r
225                 if (sizeInvalid) computeSize();\r
226                 return bounds;\r
227         }\r
228 \r
229         /** If false, the text will only wrap where it contains newlines (\n). The preferred size of the label will be the text bounds.\r
230          * If true, the text will word wrap using the width of the label. The preferred width of the label will be 0, it is expected\r
231          * that the something external will set the width of the label. Default is false. */\r
232         public void setWrap (boolean wrap) {\r
233                 this.wrap = wrap;\r
234                 invalidateHierarchy();\r
235         }\r
236 \r
237         /** @param wrapAlign Aligns each line of text horizontally and all the text vertically.\r
238          * @see Align */\r
239         public void setAlignment (int wrapAlign) {\r
240                 setAlignment(wrapAlign, wrapAlign);\r
241         }\r
242 \r
243         /** @param labelAlign Aligns all the text with the label widget.\r
244          * @param lineAlign Aligns each line of text (left, right, or center).\r
245          * @see Align */\r
246         public void setAlignment (int labelAlign, int lineAlign) {\r
247                 this.labelAlign = labelAlign;\r
248 \r
249                 if ((lineAlign & Align.left) != 0)\r
250                         this.lineAlign = HAlignment.LEFT;\r
251                 else if ((lineAlign & Align.right) != 0)\r
252                         this.lineAlign = HAlignment.RIGHT;\r
253                 else\r
254                         this.lineAlign = HAlignment.CENTER;\r
255 \r
256                 invalidate();\r
257         }\r
258 \r
259         public void setFontScale (float fontScale) {\r
260                 this.fontScaleX = fontScale;\r
261                 this.fontScaleY = fontScale;\r
262                 invalidateHierarchy();\r
263         }\r
264 \r
265         public void setFontScale (float fontScaleX, float fontScaleY) {\r
266                 this.fontScaleX = fontScaleX;\r
267                 this.fontScaleY = fontScaleY;\r
268                 invalidateHierarchy();\r
269         }\r
270 \r
271         public float getFontScaleX () {\r
272                 return fontScaleX;\r
273         }\r
274 \r
275         public void setFontScaleX (float fontScaleX) {\r
276                 this.fontScaleX = fontScaleX;\r
277                 invalidateHierarchy();\r
278         }\r
279 \r
280         public float getFontScaleY () {\r
281                 return fontScaleY;\r
282         }\r
283 \r
284         public void setFontScaleY (float fontScaleY) {\r
285                 this.fontScaleY = fontScaleY;\r
286                 invalidateHierarchy();\r
287         }\r
288 \r
289         /** When true the text will be truncated with an ellipse if it does not fit within the width of the label. Default is false. */\r
290         public void setEllipse (boolean ellipse) {\r
291                 this.ellipse = ellipse;\r
292         }\r
293 \r
294         /** The style for a label, see {@link Label}.\r
295          * @author Nathan Sweet */\r
296         static public class LabelStyle {\r
297                 public BitmapFont font;\r
298                 /** Optional. */\r
299                 public Color fontColor;\r
300                 /** Optional. */\r
301                 public Drawable background;\r
302 \r
303                 public LabelStyle () {\r
304                 }\r
305 \r
306                 public LabelStyle (BitmapFont font, Color fontColor) {\r
307                         this.font = font;\r
308                         this.fontColor = fontColor;\r
309                 }\r
310 \r
311                 public LabelStyle (LabelStyle style) {\r
312                         this.font = style.font;\r
313                         if (style.fontColor != null) fontColor = new Color(style.fontColor);\r
314                         background = style.background;\r
315                 }\r
316         }\r
317 }\r