/**
*
* Copyright 2014
*
* 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.
*
* @project loon
* @author cping
* @email:javachenpeng@yahoo.com
* @version 0.4.1
*/
package loon.component;
import loon.LRelease;
import loon.LSystem;
import loon.LTexture;
import loon.LTextures;
import loon.canvas.LColor;
import loon.component.skin.MenuSkin;
import loon.component.skin.SkinManager;
import loon.event.SysTouch;
import loon.event.Updateable;
import loon.font.FontSet;
import loon.font.IFont;
import loon.font.LFont;
import loon.geom.RectBox;
import loon.geom.Vector2f;
import loon.opengl.GLEx;
import loon.opengl.LSTRDictionary;
import loon.utils.TArray;
/**
* LGame菜单栏,用户可以隐藏大量按钮到其中,直到选中菜单时才动态展露,而非选中时则恢复隐藏.(此组件允许用户自行替换UI,
* 若setSupportScroll(true)则支持滚动)
*
* LMenu panel = new LMenu(LMenu.MOVE_LEFT, "Menu"); panel.add("ABC");
* panel.add("EFG"); panel.add("ABC"); panel.add("EFG"); panel.add("ABC");
* panel.add("EFG");
*/
public class LMenu extends LComponent implements FontSet<LMenu> {
public static interface MenuItemClick {
public void onClick(MenuItem item);
}
private class ClickMenu implements Updateable {
private MenuItemClick click;
private MenuItem item;
ClickMenu(MenuItemClick c, MenuItem i) {
this.click = c;
this.item = i;
}
@Override
public void action(Object a) {
if (click != null && item != null) {
click.onClick(item);
}
}
}
public class MenuItem implements LRelease {
LTexture texture;
LMenu parent;
int index;
String label;
public float x;
public float y;
public float yslot;
public float xslot;
public float itemWidth;
public float itemHeight;
public float offsetX;
public float offsetY;
boolean keep = false;
private boolean visible = true;
private boolean clicked = false;
private boolean localpos = false, localsize = false;
private IFont _font;
private MenuItemClick _itemclick;
MenuItem(LMenu parent, LTexture tex, String label, MenuItemClick click) {
this(SkinManager.get().getMenuSkin().getFont(), parent, tex, false,
label, click);
}
MenuItem(IFont font, LMenu parent, LTexture tex, String label,
MenuItemClick click) {
this(font, parent, tex, false, label, click);
}
MenuItem(IFont font, LMenu parent, LTexture tex, boolean keep,
String label, MenuItemClick click) {
this.texture = tex;
this.parent = parent;
if (parent != null) {
parent.add(this);
this.index = parent.items.size;
}
this.label = label;
this.keep = keep;
this._itemclick = click;
this._font = font;
if (tex == null) {
this.keep = false;
}
}
MenuItem(LMenu parent, LTexture tex, boolean keep, String label,
float x, float y, MenuItemClick click) {
this(SkinManager.get().getMenuSkin().getFont(), parent, tex, true,
label, x, y, 0, 0, click);
}
MenuItem(IFont font, LMenu parent, LTexture tex, boolean keep,
String label, float x, float y, MenuItemClick click) {
this(font, parent, tex, true, label, x, y, 0, 0, click);
}
MenuItem(IFont font, LMenu parent, LTexture tex, boolean keep,
String label, float x, float y, float w, float h,
MenuItemClick click) {
this.x = x;
this.y = y;
this.itemWidth = w;
this.itemHeight = h;
this.texture = tex;
if (w < 1 && h < 1) {
this.localsize = true;
} else {
this.localsize = false;
}
this.texture = tex;
if (x < 1 && y < 1) {
this.localpos = true;
} else {
this.localpos = false;
}
this.parent = parent;
if (parent != null) {
parent.add(this);
this.index = parent.items.size;
}
this.label = label;
this.keep = keep;
this._itemclick = click;
this._font = font;
if (tex == null) {
this.keep = false;
}
}
public boolean isVisible() {
return this.visible;
}
public void setVisible(boolean v) {
this.visible = v;
}
public MenuItem setOffsetX(float x) {
this.offsetX = x;
return this;
}
public MenuItem setOffsetY(float y) {
this.offsetY = y;
return this;
}
public MenuItem setFont(IFont font) {
this._font = font;
return this;
}
public IFont getFont() {
return this._font;
}
public void draw(GLEx g) {
if (!visible) {
return;
}
int color = g.color();
IFont font = g.getFont();
try {
boolean check = (SysTouch.isDown() || SysTouch.isDrag());
Vector2f pos = SysTouch.getLocation();
if (this.parent != null) {
if (!localpos) {
this.x = (this.parent.cellWidth * this.xslot
+ this.parent.cellWidth / this.itemWidth + this.xslot
* this.parent.paddingx)
- this.parent.item_left_offset;
this.y = (this.parent.cellHeight * this.yslot
+ this.parent.cellHeight / this.itemHeight + this.yslot
* this.parent.paddingy);
if (x > Float.MAX_VALUE) {
x = 0;
} else if (x < Float.MIN_VALUE) {
x = 0;
}
if (y > Float.MAX_VALUE) {
y = 0;
} else if (y < Float.MIN_VALUE) {
y = 0;
}
}
if (parent.type == LMenu.MOVE_RIGHT) {
float posX = parent.getScreenWidth()
- parent.main_panel_size;
this.x = posX + x;
}
if (!localsize) {
if (!this.keep || texture == null) {
this.itemWidth = this.parent.cellWidth;
this.itemHeight = this.parent.cellHeight;
} else {
this.itemWidth = this.texture.getWidth();
this.itemHeight = this.texture.getHeight();
}
}
if (bounds().contains(pos.x, pos.y) && check) {
g.setTint(0.5f, 0.5f, 0.5f, 1.0f);
if (check && (!this.clicked)) {
ClickMenu menu = new ClickMenu(this._itemclick,
this);
LSystem.load(menu);
this.clicked = true;
}
}
if (!check) {
this.clicked = false;
}
if (texture != null) {
g.draw(this.texture, this.x + 3f, this.y
+ this.parent.paddingy + this.parent.scroll,
this.itemWidth, this.itemHeight,
parent.baseColor);
}
if (this.label != null) {
font.drawString(
g,
label,
(this.x + 3f + (itemWidth / 2 - font
.stringWidth(label) / 2)) + offsetX,
(this.y + this.parent.paddingy
+ this.parent.scroll - font.getAscent() - 2)
+ offsetY, parent.fontColor);
}
} else {
if (bounds().contains(pos.x, pos.y) && (check)) {
g.setTint(0.5f, 0.5f, 0.5f, 1.0f);
if (check && (!this.clicked)) {
ClickMenu menu = new ClickMenu(this._itemclick,
this);
LSystem.load(menu);
this.clicked = true;
}
}
if (!check) {
this.clicked = false;
}
if (texture != null) {
g.draw(this.texture, this.x, this.y, this.itemWidth,
this.itemHeight, parent.baseColor);
}
if (this.label != null) {
font.drawString(
g,
this.label,
(this.x + (itemWidth / 2
- font.stringWidth(label) / 2 - font
.getAscent())) + offsetX,
(this.y - 2) + offsetY, parent.fontColor);
}
}
} finally {
g.setColor(color);
g.setFont(font);
}
}
private RectBox itemrect;
public RectBox bounds() {
if (parent.type == LMenu.MOVE_LEFT) {
if (itemrect == null) {
itemrect = new RectBox(this.x + 3f, this.y
+ this.parent.paddingy + this.parent.scroll,
this.itemWidth, this.itemHeight);
} else {
itemrect.setBounds(this.x + 3f, this.y
+ this.parent.paddingy + this.parent.scroll,
this.itemWidth, this.itemHeight);
}
} else if (parent.type == LMenu.MOVE_RIGHT) {
if (itemrect == null) {
itemrect = new RectBox(this.x + 3f, this.y
+ this.parent.paddingy + this.parent.scroll,
this.itemWidth, this.itemHeight);
} else {
itemrect.setBounds(this.x + 3f, this.y
+ this.parent.paddingy + this.parent.scroll,
this.itemWidth, this.itemHeight);
}
}
return itemrect;
}
public LMenu getParent() {
return this.parent;
}
public String getLabel() {
return this.label;
}
public float getX() {
return this.x;
}
public float getY() {
return this.y;
}
public float getWidth() {
return this.itemWidth;
}
public float getHeight() {
return this.itemHeight;
}
@Override
public void close() {
if (texture != null) {
texture.close();
texture = null;
}
}
}
private IFont font;
private float width;
private float main_panel_size;
private float tabY;
private LColor fontColor = LColor.white;
private LTexture mainpanel;
private LTexture tab;
private boolean active, supportScroll;
public int xslot;
public int yslot;
public float scroll;
public float maxscroll;
public float scrollspeed = 25f;
private LMenu selected;
private float cellWidth = 32f;
private float cellHeight = 32f;
private float paddingx = 2f;
private float paddingy = 50f;
private float alphaMenu = 0.7f;
private int rows = 1;
public final static int MOVE_LEFT = 0;
public final static int MOVE_RIGHT = 1;
private int item_left_offset = 10;
private int item_top_offset = 0;
public TArray<MenuItem> items = new TArray<MenuItem>(10);
private int tabWidth, tabHeight;
private int type = MOVE_RIGHT;
private String label;
private boolean _defUI;
public LMenu(int move_type, String label) {
this(move_type, SkinManager.get().getMenuSkin().getFont(), label, 100,
50);
}
public LMenu(int move_type, String label, int w, int h) {
this(move_type, SkinManager.get().getMenuSkin().getFont(), label, w, h);
}
public LMenu(int move_type, IFont font, String label, int width, int height) {
this(move_type, font, label, width, height, SkinManager.get()
.getMenuSkin().getTabTexture(), SkinManager.get().getMenuSkin()
.getMainTexture(), 0, 0, true);
}
public LMenu(int move_type, IFont font, String label, int width,
int height, String tabfile, String mainfile) {
this(move_type, font, label, width, height, LTextures
.loadTexture(tabfile), LTextures.loadTexture(mainfile), 0, 0,
false);
}
public LMenu(int move_type, IFont font, String label, int width,
int height, String tabfile, String mainfile, int taby, int mainsize) {
this(move_type, font, label, width, height, LTextures
.loadTexture(tabfile), LTextures.loadTexture(mainfile), taby,
mainsize, false);
}
public LMenu(int move_type, IFont font, String label, int width,
int height, LTexture tab, LTexture main, int taby) {
this(move_type, font, label, width, height, tab, main, taby, 0, false);
}
public LMenu(int move_type, IFont font, String label, int width,
int height, LTexture tab, LTexture main, int taby, int mainsize) {
this(move_type, font, label, width, height, tab, main, taby, mainsize,
false);
}
public LMenu(int move_type, IFont font, String label, int width,
int height, LTexture tab, LTexture main, int taby, int mainsize,
boolean defUI) {
this(move_type, font, label, width, height, tab, main, taby, mainsize,
defUI, SkinManager.get().getMenuSkin().getFontColor());
}
public LMenu(MenuSkin skin, int move_type, String label, int width,
int height, int taby, int mainsize, boolean defUI) {
this(move_type, skin.getFont(), label, width, height, skin
.getTabTexture(), skin.getMainTexture(), taby, mainsize, defUI,
skin.getFontColor());
}
public LMenu(int move_type, IFont font, String label, int width,
int height, LTexture tab, LTexture main, int taby, int mainsize,
boolean defUI, LColor color) {
super(0, 0, width, height);
this.fontColor = color;
this.type = move_type;
this.label = label;
this.font = font;
this.tabY = taby;
this.tab = tab;
this.mainpanel = main;
this.tabWidth = width;
this.tabHeight = height;
if (mainsize > 0) {
this.main_panel_size = mainsize;
} else {
this.main_panel_size = getScreenWidth() / 4;
}
this.main_panel_size += this.cellWidth + this.paddingx;
this._defUI = defUI;
if (type > MOVE_RIGHT) {
throw LSystem.runThrow("Type:" + type
+ ", The Menu display mode is not supported !");
}
}
private RectBox tabRec;
private RectBox tagbounds(int type) {
if (type == MOVE_LEFT) {
if (tabRec == null) {
tabRec = new RectBox(this.width, getTaby(), tabWidth, tabHeight);
} else {
tabRec.setBounds(this.width, getTaby(), tabWidth, tabHeight);
}
} else if (type == MOVE_RIGHT) {
float posX = this.getScreenWidth() - this.width - this.tabWidth;
if (tabRec == null) {
tabRec = new RectBox(posX, getTaby(), tabWidth, tabHeight);
} else {
tabRec.setBounds(posX, getTaby(), tabWidth, tabHeight);
}
}
return tabRec;
}
private RectBox mianRec;
private RectBox panelbounds(int type) {
if (type == MOVE_LEFT) {
if (mianRec == null) {
mianRec = new RectBox(0, 0, this.width, getScreenHeight());
} else {
mianRec.setBounds(0, 0, this.width, getScreenHeight());
}
} else if (type == MOVE_RIGHT) {
float posX = this.getScreenWidth() - this.width;
if (mianRec == null) {
mianRec = new RectBox(posX, 0, this.width, getScreenHeight());
} else {
mianRec.setBounds(posX, 0, this.width, getScreenHeight());
}
}
return mianRec;
}
public float getTaby() {
return this.tabY;
}
public void setTaby(float tabY) {
this.tabY = tabY;
}
public MenuItem add(String label) {
return add(label, null);
}
public MenuItem add(String label, MenuItemClick click) {
return add(new LMenu.MenuItem(this, SkinManager.get().getMenuSkin()
.getTabTexture(), label, click));
}
public MenuItem add(String label, String file, MenuItemClick click) {
return add(new LMenu.MenuItem(this, LTextures.loadTexture(file), label,
click));
}
public MenuItem add(String label, LTexture texture, MenuItemClick click) {
return add(new LMenu.MenuItem(this, texture, label, click));
}
public MenuItem add(String label, LTexture texture, float x, float y,
MenuItemClick click) {
return add(new LMenu.MenuItem(this, texture, false, label, x, y, click));
}
public MenuItem add(String label, LTexture texture, float x, float y,
float w, float h, MenuItemClick click) {
return add(new LMenu.MenuItem(font, this, texture, false, label, x, y,
w, h, click));
}
public MenuItem add(MenuItem item) {
if (this.xslot > this.main_panel_size
/ (this.cellWidth + this.paddingx * 2)) {
this.xslot = 1;
this.yslot += 1;
this.rows += 1;
}
item.xslot = this.xslot;
item.yslot = this.yslot;
this.items.add(item);
this.xslot += 1;
if (item._font != null && item._font instanceof LFont) {
LSTRDictionary.get().bind((LFont) item._font, item.label);
}
return item;
}
@Override
public synchronized void createUI(GLEx g, int x, int y,
LComponent component, LTexture[] buttonImage) {
float alpha = g.alpha();
try {
g.setAlpha(alphaMenu);
switch (type) {
case MOVE_LEFT:
if ((selected == this) || (selected == null)) {
g.draw(this.tab, this.width, getTaby(), tabWidth,
tabHeight, baseColor);
if (label != null) {
g.setAlpha(1f);
font.drawString(
g,
this.label,
this.width
+ (tabWidth / 2 - font
.stringWidth(label) / 2),
getTaby()
+ (tabHeight / 2 - font.getHeight() / 2)
- 5, fontColor);
g.setAlpha(alphaMenu);
}
}
if ((this.active) || (this.width > 0)) {
g.draw(mainpanel, 0, 0, this.width, getScreenHeight(),
baseColor);
if (this.width == this.main_panel_size) {
for (int i = 0; i < this.items.size; i++) {
this.items.get(i).draw(g);
}
}
}
break;
case MOVE_RIGHT:
if ((selected == this) || (selected == null)) {
float posX = this.getScreenWidth() - this.width
- this.tabWidth;
g.draw(this.tab, posX, getTaby(), tabWidth, tabHeight,
baseColor);
if (label != null) {
g.setAlpha(1f);
font.drawString(
g,
this.label,
posX
+ (tabWidth / 2 - font
.stringWidth(label) / 2),
getTaby()
+ (tabHeight / 2 - font.getHeight() / 2)
- 5, fontColor);
g.setAlpha(this.alphaMenu);
}
}
if ((this.active) || (this.width > 0)) {
float posX = this.getScreenWidth() - this.width;
g.draw(mainpanel, posX, 0, this.width, getScreenHeight(),
baseColor);
if (this.width == this.main_panel_size) {
for (int i = 0; i < this.items.size; i++) {
this.items.get(i).draw(g);
}
}
}
break;
}
} finally {
g.setAlpha(alpha);
}
}
private boolean mouseSelect = false;
public void update(long elapsedTime) {
if (!visible) {
return;
}
super.update(elapsedTime);
if (!this.active) {
if (tagbounds(type).contains(SysTouch.getX(), SysTouch.getY())
&& ((SysTouch.isDown() || SysTouch.isDrag()))
&& (selected == null)) {
this.active = true;
this.mouseSelect = true;
if (selected == null) {
selected = this;
}
}
if (this.width > 0) {
this.width -= 0.3f * this.width * (elapsedTime / 100f);
}
if (this.width <= 2) {
this.width = 0;
}
} else {
this.mouseSelect = true;
if (selected == this) {
this.maxscroll = ((this.paddingy + this.cellHeight) * this.rows);
if (this.scroll > this.maxscroll) {
this.scroll = this.maxscroll;
}
if (this.scroll < -this.maxscroll) {
this.scroll = (-this.maxscroll);
}
if (((tagbounds(type)
.contains(SysTouch.getX(), SysTouch.getY())) || (panelbounds(type)
.contains(SysTouch.getX(), SysTouch.getY())))) {
if (this.width < this.main_panel_size)
this.width += 0.3F
* (this.main_panel_size - this.width)
* (elapsedTime / 100f);
else {
this.width = this.main_panel_size;
}
if (this.width > this.main_panel_size - 2) {
this.width = this.main_panel_size;
}
if (input.isMoving() && supportScroll) {
if (input.getTouchDY() > 5) {
this.scroll -= this.scrollspeed
* (elapsedTime / 100f);
} else if (input.getTouchDY() < -5) {
this.scroll += this.scrollspeed
* (elapsedTime / 100f);
}
}
} else {
if (selected == this) {
selected = null;
}
this.active = false;
mouseSelect = false;
}
}
}
}
public boolean isMouseSelect() {
return mouseSelect;
}
public float getPanelWidth() {
return main_panel_size;
}
public void setPanelWidth(float w) {
this.main_panel_size = w;
}
public int getItemLeftOffset() {
return item_left_offset;
}
public void setItemLeftOffset(int left) {
this.item_left_offset = left;
}
public int getItemTopOffset() {
return item_top_offset;
}
public void setItemTopOffset(int top) {
this.item_top_offset = top;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public float getScroll() {
return scroll;
}
public void setScroll(float scroll) {
this.scroll = scroll;
}
public float getScrollspeed() {
return scrollspeed;
}
public void setScrollspeed(float scrollspeed) {
this.scrollspeed = scrollspeed;
}
public LMenu getSelected() {
return selected;
}
public float getCellWidth() {
return cellWidth;
}
public void setCellWidth(float cellWidth) {
this.cellWidth = cellWidth;
}
public float getCellHeight() {
return cellHeight;
}
public void setCellHeight(float cellHeight) {
this.cellHeight = cellHeight;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public int getXslot() {
return xslot;
}
public void setXslot(int xslot) {
this.xslot = xslot;
}
public int getYslot() {
return yslot;
}
public void setYslot(int yslot) {
this.yslot = yslot;
}
public float getMaxscroll() {
return maxscroll;
}
public void setMaxscroll(float maxscroll) {
this.maxscroll = maxscroll;
}
public float getPaddingx() {
return paddingx;
}
public void setPaddingx(float paddingx) {
this.paddingx = paddingx;
}
public float getPaddingy() {
return paddingy;
}
public void setPaddingy(float paddingy) {
this.paddingy = paddingy;
}
public int getRows() {
return rows;
}
public int getTabWidth() {
return tabWidth;
}
public int getTabHeight() {
return tabHeight;
}
public int getType() {
return type;
}
public boolean isSupportScroll() {
return supportScroll;
}
public void setSupportScroll(boolean s) {
this.supportScroll = s;
}
public void setType(int t) {
this.type = t;
}
public boolean isdefUI() {
return _defUI;
}
public float getAlphaMenu() {
return alphaMenu;
}
public void setAlphaMenu(float alphaMenu) {
this.alphaMenu = alphaMenu;
}
@Override
public String getUIName() {
return "Menu";
}
@Override
public LMenu setFont(IFont font) {
this.font = font;
return this;
}
@Override
public IFont getFont() {
return this.font;
}
public LColor getFontColor() {
return fontColor;
}
public void setFontColor(LColor fontColor) {
this.fontColor = fontColor;
}
@Override
public void close() {
super.close();
for (int i = 0, size = items.size; i < size; i++) {
MenuItem item = items.get(i);
if (item != null) {
item.close();
item = null;
}
}
items.clear();
if (!_defUI) {
if (tab != null) {
tab.close();
}
if (mainpanel != null) {
mainpanel.close();
}
}
}
}