package loon.component; import loon.LSystem; import loon.LTexture; import loon.canvas.LColor; import loon.component.skin.MessageSkin; import loon.component.skin.SkinManager; import loon.font.FontSet; import loon.font.IFont; import loon.font.LFont; import loon.font.ShadowFont; import loon.opengl.GLEx; import loon.opengl.LSTRDictionary; import loon.utils.MathUtils; import loon.utils.ObjectMap; import loon.utils.StringUtils; import loon.utils.TArray; /** * 此组件功能近似LMessage,并且允许连续播放文字序列 ,设置角色头像和显示位置,差异在于,此组件不支持彩色文字设置,也就是只允许'\n'符号生效 * 而在效率上无文字缓存,所以总体帧率耗费比LMessage更大,适合动态频率高的场合使用,但是此组件多个同时存在会影响帧率 **/ /* * 以下为简单用例: * * LTexture texture = DefUI.getGameWinFrame(200, 200); LMessageBox box = new * LMessageBox(new String[] { "人间谁能看尽山色,千里孤行终归寂寞。翻天覆地炙手可热,百年之后有谁记得。", * "明月西斜遗珠何落,金乌归海乾坤并合。世事如棋造化难说,能解其中非你非我。" }, texture, 66, 66, 180, 180); * box.getMessageBox().setOffset(10, 10); add(box); box.SetClick(new * ClickListener() { * * @Override public void UpClick(LComponent comp, float x, float y) { * * } * * @Override public void DragClick(LComponent comp, float x, float y) { * * } * * @Override public void DownClick(LComponent comp, float x, float y) { * LMessageBox box = (LMessageBox) comp; box.next(); } * * @Override public void DoClick(LComponent comp) { * * } }); * * } }); */ public class LMessageBox extends LComponent implements FontSet<LMessageBox> { public static class DrawMessageBox extends AbstractBox { private final int DEFAULT_WIDTH; private final int DEFAULT_HEIGHT; LTexture imgFace; private boolean drawFace; private float faceX; private float faceY; private float faceCenterX; private float faceCenterY; private float faceWidth; private float faceHeight; private float messageX; private float messageY; private float messageWidth; private float messageHeight; private float pageX; private float pageY; private float offsetX; private float offsetY; private float _leading = 0; private String flagType = LSystem.FLAG_TAG; protected DrawMessageBox(IFont font, LTexture face, LTexture box, int w, int h) { super(font); super.init(w, h); this.DEFAULT_WIDTH = w; this.DEFAULT_HEIGHT = h; this.imgFace = face; this.drawFace = false; this._radius = 10; this._textureBox = box; } public void setFlagType(String f) { this.flagType = f; } public void reinit() { this._boxWidth = DEFAULT_WIDTH; this._boxHeight = DEFAULT_HEIGHT; this._borderW = 3f; this.messageHeight = (this._boxHeight * 0.8f); this.messageY = (this._boxHeight * 0.08f); this.setFaceDrawMode(); this.pageX = (this._boxWidth * 0.95f); this.pageY = (this._boxHeight * 0.75f); } private void setFaceDrawMode() { if (this.drawFace) { this.faceX = (this._boxWidth * 0.023f); this.faceY = 5f; this.faceWidth = (this._boxWidth * 0.19f); this.faceHeight = this.faceWidth; this.faceCenterX = (this.faceX + this.faceWidth / 2f); this.faceCenterY = (this.faceY + this.faceHeight / 2f); this.messageX = (this.faceX + this.faceWidth + this._boxWidth * 0.023f); this.messageWidth = (this._boxWidth - (this.faceX * 2f + this.faceWidth + this._boxWidth * 0.025f)); } else { this.faceX = 0; this.faceY = 0; this.faceWidth = 0; this.faceHeight = 0; this.messageX = (this._boxWidth * 0.023f); this.messageWidth = (this._boxWidth - this.messageX * 2f); } } public void draw(GLEx g, String message, int row, boolean isPage, LColor c) { draw(g, this._boxX, this._boxY, message, row, isPage, c); } private void draw(GLEx g, float x, float y, String message, int row, boolean isPage, LColor c) { this._boxX = x; this._boxY = y; drawBorder(g, this._boxX, this._boxY, c); if (this.drawFace) { drawFace(g, this._boxX + offsetX, this._boxY + offsetY); } drawMessage(g, message, this._boxX + this.messageX + offsetX, this._boxY + this.messageY + offsetY); if (isPage && flagType != null) { int size = StringUtils.charCount(message, '\n'); if (_leading > 0) { this.font.drawString( g, flagType, this._boxX + this.pageX + this.offsetX, this._boxY + this.pageY + this.font.stringHeight(message) + this.offsetY + (this.font.getSize() * 0.10f) + (size * _leading), this.fontColor); } else { this.font.drawString( g, flagType, this._boxX + this.pageX + this.offsetX, this._boxY + this.pageY + this.font.stringHeight(message) + this.offsetY + (this.font.getSize() * 0.10f), this.fontColor); } } } private void drawMessage(GLEx g, String message, float x, float y) { if (_leading > 0) { String[] texts = StringUtils.split(message, '\n'); for (int i = 0, size = texts.length; i < size; i++) { this.font.drawString(g, texts[i], x, y + (i * (font.getHeight() + _leading)), this.fontColor); } } else { this.font.drawString(g, message, x, y, this.fontColor); } } private void drawFace(GLEx g, float x, float y) { g.draw(this.imgFace, x + this.faceCenterX, y + this.faceCenterY); } public float getLeading() { return this._leading; } public void setLeading(final float leading) { this._leading = leading; } @Override public void setBoxAlpha(float alpha) { super.setBoxAlpha(alpha); } public int getMessageWidth() { return MathUtils.round(this.messageWidth); } public int getMessageHeight() { return MathUtils.round(this.messageHeight); } public void setOffset(float x, float y) { this.offsetX = x; this.offsetY = y; } public void setOffsetX(float x) { this.offsetX = x; } public void setOffsetY(float y) { this.offsetY = y; } public float getOffsetX() { return this.offsetX; } public float getOffetY() { return this.offsetY; } public boolean isFaceMode() { return this.drawFace; } public void setFaceImage(LTexture face) { String path = ""; if (this.imgFace != null) { path = this.imgFace.getSource(); } if (face != null) { this.drawFace = true; if (!path.equals(face.getSource())) { this.imgFace = face; } } else { this.drawFace = false; } setFaceDrawMode(); } public void setFaceCenterX(float x) { this.faceCenterX = x; } public void setFaceCenterY(float y) { this.faceCenterX = faceCenterY; } public float getFaceCenterX() { return this.faceCenterX; } public float getFaceCenterY() { return this.faceCenterY; } @Override public void dirty() { } } private final static ObjectMap<String, LTexture> facepools = new ObjectMap<String, LTexture>(); public static void addFaceImage(String name, LTexture tex) { facepools.put(name, tex); } public static LTexture getFaceImage(String name) { return facepools.get(name); } public static class Message { private String message; private String comment; private String face; TArray<String> lines; public Message(String text, String comm, String face, TArray<String> ls) { this.message = text; this.comment = comm; this.face = face; this.lines = ls; } public String getMessage() { return this.message; } public String getComment() { return this.comment; } public void setMessage(String message) { this.message = message; } public void setComment(String comment) { this.comment = comment; } public String getFace() { return this.face; } public void setFace(String face) { this.face = face; } @Override public String toString() { return this.message; } } private final StringBuilder _message = new StringBuilder(); private boolean _initNativeDraw = false; protected int messageIndex = 0; protected TArray<Message> _messageList; protected long typeDelayTime; protected int renderRow; protected int renderCol; protected boolean finished; protected boolean noMessage; protected boolean currentNoMessage; protected boolean stopMessage; protected boolean noPaged; protected boolean isPaged; protected int pageBlinkTime; protected final DrawMessageBox _box; protected int delay = 50; protected int pageTime = 300; private IFont _font; private String _tmpString; public LMessageBox(TArray<Message> messages, int x, int y, int width, int height) { this(messages, null, SkinManager.get().getMessageSkin().getFont(), null, x, y, width, height); } public LMessageBox(TArray<Message> messages, LTexture texture, int x, int y, int width, int height) { this(messages, null, SkinManager.get().getMessageSkin().getFont(), texture, x, y, width, height); } public LMessageBox(String[] messages, int x, int y, int width, int height) { this(messages, null, SkinManager.get().getMessageSkin().getFont(), null, null, x, y, width, height); } public LMessageBox(String[] messages, LTexture texture, IFont font, int x, int y, int width, int height) { this(messages, null, font, null, texture, x, y, width, height); } public LMessageBox(String[] messages, LTexture texture, int x, int y, int width, int height) { this(messages, null, SkinManager.get().getMessageSkin().getFont(), null, texture, x, y, width, height); } public LMessageBox(TArray<Message> messages, String typeFlag, IFont font, LTexture box, int x, int y) { this(messages, typeFlag, font, box, x, y, 0, 0); } public LMessageBox(TArray<Message> messages, String typeFlag, IFont font, LTexture box, int x, int y, int width, int height) { this(messages, typeFlag, font, box, x, y, width, height, SkinManager.get().getMessageSkin().getFontColor()); } public LMessageBox(MessageSkin skin, TArray<Message> messages,String typeFlag, int x, int y, int width, int height) { this(messages, typeFlag, skin.getFont(), skin.getBackgroundTexture(), x, y, width, height, skin.getFontColor()); } public LMessageBox(TArray<Message> messages, String typeFlag, IFont font, LTexture box, int x, int y, int width, int height, LColor color) { super(x, y, width, height); this.baseColor = color; if (box != null && width == 0 && height == 0) { this.setSize(box.getWidth(), box.getHeight()); } this._messageList = messages; StringBuilder sbr = new StringBuilder(); if (messages != null) { for (Message text : messages) { sbr.append(text.message); } } this._tmpString = sbr.toString(); if (font instanceof LFont) { this._box = new DrawMessageBox(new ShadowFont((LFont) font, _tmpString, typeFlag == null ? LSystem.FLAG_TAG : typeFlag, true), null, box, width(), height()); } else { this._box = new DrawMessageBox(font, null, box, width(), height()); } this._box.setLocation(x, y); this._font = font; } public LMessageBox(String[] messages, String typeFlag, IFont font, LTexture box, int x, int y) { this(messages, typeFlag, font, null, box, x, y, 0, 0); } public LMessageBox(String[] messages, IFont font, LTexture box, int x, int y) { this(messages, null, font, null, box, x, y, 0, 0); } public LMessageBox(String[] messages, LTexture box, int x, int y) { this(messages, null, SkinManager.get().getMessageSkin().getFont(), null, box, x, y, 0, 0); } /** * 若传递字符串数组,则只能构建统一头像位置的对话框 * * @param messages * @param typeFlag * @param font * @param face * @param box * @param x * @param y * @param width * @param height */ public LMessageBox(String[] messages, String typeFlag, IFont font, String face, LTexture box, int x, int y, int width, int height) { super(x, y, width, height); if (box != null && width == 0 && height == 0) { this.setSize(box.getWidth(), box.getHeight()); } if (messages != null) { _messageList = new TArray<LMessageBox.Message>(); for (String text : messages) { _messageList.add(new Message(text, null, face, Print .formatMessage(text, font, width()))); _tmpString += text; } } if (font instanceof LFont) { this._box = new DrawMessageBox(new ShadowFont((LFont) font, messages, typeFlag == null ? LSystem.FLAG_TAG : typeFlag, true), null, box, width(), height()); } else { this._box = new DrawMessageBox(font, null, box, width(), height()); } this._box.setLocation(getX(), getY()); if (!StringUtils.isEmpty(face)) { toFaceImage(face); } this._font = font; } @Override public void setLocation(float x, float y) { super.setLocation(x, y); if (_box != null) { this._box.setLocation(x, y); } } public float getLeading() { return this._box.getLeading(); } public void setLeading(final float leading) { this._box.setLeading(leading); } public String getString() { return this._tmpString; } public IFont getFont() { return this._font; } public LMessageBox setFont(IFont font) { this._font = font; return this; } public LMessageBox setFontColor(LColor color) { if (_box != null) { _box.setFontColor(color); } return this; } public LMessageBox setBoxAlpha(float alpha) { if (_box != null) { _box.setBoxAlpha(alpha); } return this; } public DrawMessageBox getMessageBox() { return this._box; } public LMessageBox setOffset(float x, float y) { this._box.setOffset(x, y); return this; } public LMessageBox setOffsetX(float x) { this._box.setOffsetX(x); return this; } public LMessageBox setOffsetY(float y) { this._box.setOffsetY(y); return this; } protected void updateType() { Message message = _messageList.get(messageIndex); if ((this.typeDelayTime <= 0) && (!this.finished)) { this.typeDelayTime = delay; if (this.renderCol > message.lines.get(this.renderRow).length() - 1) { if (this.renderRow >= message.lines.size - 1) { this.finished = true; this.pageBlinkTime = pageTime; } else { this.renderRow += 1; this.renderCol = 0; } } else this.renderCol += 1; } } public void reset() { messageIndex = 0; stopMessage = false; restart(); } public LMessageBox loop() { if (finished) { int size = this.messageIndex + 1; if (size < this._messageList.size) { setIndex(++this.messageIndex); restart(); } else { reset(); } } return this; } public LMessageBox next() { if (finished) { int size = this.messageIndex + 1; if (size < this._messageList.size) { setIndex(++this.messageIndex); restart(); } } return this; } public LMessageBox setIndex(int index) { int size = this.messageIndex + 1; if (size > 0 && size < this._messageList.size) { this.messageIndex = index; restart(); } return this; } public final void postSetIndex() { if (this._messageList == null) { return; } String str = this._messageList.get(this.messageIndex).getFace(); if ((str == null || "null".equals(str))) { setFaceImage(null); } else { toFaceImage(str); } restart(); pauseMessage(); } public void drawMessage(GLEx g) { if (!_initNativeDraw) { if (_font instanceof LFont) { LSTRDictionary.get().bind((LFont) _font, _tmpString); } _initNativeDraw = true; } Message message = _messageList.get(messageIndex); _message.delete(0, _message.length()); if (!message.lines.isEmpty()) { for (int i = 0; i < this.renderRow + 1; i++) { String line = message.lines.get(i); int len = 0; if (i < this.renderRow) len = line.length(); else { len = this.renderCol; } String t = line.substring(0, len); if (t.length() != 0) { if (len == line.length()) _message.append(t + "\n"); else { _message.append(t); } } } } if ((this.finished) && (!this.noPaged)) { if (this.pageBlinkTime > pageTime) { this.pageBlinkTime = 0; this.isPaged = (!this.isPaged); } } else { this.isPaged = false; } this._box.draw(g, _message.toString(), renderRow, this.isPaged, this.baseColor); } public boolean isCompleted() { return this.finished; } public void restart() { this.renderCol = 0; this.renderRow = 0; this.typeDelayTime = delay; this.pageBlinkTime = 0; this.finished = false; } public void showAll() { Message message = _messageList.get(messageIndex); if (message.lines.isEmpty()) { this.renderRow = (this.renderCol = 0); } else { this.renderRow = (message.lines.size - 1); this.renderCol = message.lines.get(this.renderRow).length(); this.finished = true; } } public void setFaceImage(LTexture texture) { this._box.setFaceImage(texture); } public void setFaceImage(LTexture texture, float x, float y) { this._box.setFaceImage(texture); this._box.setFaceCenterX(x); this._box.setFaceCenterY(y); } public LTexture getFaceImage() { return this._box.imgFace; } public void pauseMessage() { this.stopMessage = true; } public void resumeMessage() { this.stopMessage = false; } protected void toFaceImage(final String face) { if (face == null) { return; } String[] result = StringUtils.split(face, ','); int size = result.length; if (size > 0) { if (3 == size) { setFaceImage(facepools.get(result[0]), Float.valueOf(result[1]), Float.valueOf(result[2])); } else if (2 == size) { setFaceImage(facepools.get(result[0]), Float.valueOf(result[1]), Float.valueOf(result[1])); } else { setFaceImage(facepools.get(result[0])); } } } @Override public void update(long elapsedTime) { super.update(elapsedTime); this._box.setLocation(this._location); if (!this.noMessage) { Message message = _messageList.get(messageIndex); if (!StringUtils.isEmpty(message.face)) { toFaceImage(message.face); } if ((!this.stopMessage) && (!message.lines.isEmpty())) { this.typeDelayTime -= elapsedTime; updateType(); } if (this.finished) { this.pageBlinkTime += elapsedTime; } } } public int getPageTime() { return pageTime; } public void setPageTime(int pageTime) { this.pageTime = pageTime; } public int getDelay() { return delay; } public void setDelay(int time) { this.delay = time; } @Override public void createUI(GLEx g, int x, int y, LComponent component, LTexture[] buttonImage) { drawMessage(g); } @Override public String getUIName() { return "MessageBox"; } }