package com.javaxyq.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JTextField; import com.javaxyq.core.SpriteFactory; import com.javaxyq.util.UIUtils; import com.javaxyq.widget.Animation; //TODO add Link /** * ���ָ�ʽ������ʱ����Ϊ��Ϣ�����������ָ�ʽ��ָ��Ϊ��#��ĸ�������ִ�Сд�� <br> * #R ��ʾ���������Ϊ��ɫ(red)<br> * #G ��ʾ���������Ϊ��ɫ(green)<br> * #B ��ʾ���������Ϊ��ɫ(blue)<br> * #K ��ʾ���������Ϊ��ɫ(black)<br> * #Y ��ʾ���������Ϊ��ɫ(yellow)<br> * #W ��ʾ���������Ϊ��ɫ(white)<br> * #b ��ʾ���������Ϊ��˸(blink)<br> * #c + �������ֻ���A-F��ĸ �Զ�����ɫ�����磺c008000=����ɫ<br> * #u + ���� + #u �������»��ߡ�<br> * #n ��������״̬�ָ�������<br> * #r ���ֻ��С�<br> * ## ���һ��#�š�<br> * #0-99 ���� * * @author ����ΰ * @history 2008-6-9 ����ΰ �½� */ public class RichLabel extends JComponent { private static final long serialVersionUID = 4898130145332371300L; private ArrayList<Object> sectionList; private long startTime; private long currTime; private static HashMap<String, Animation> faceAnimations; static { faceAnimations = new HashMap<String, Animation>(100); } public RichLabel() { this(null); } public RichLabel(String text) { sectionList = new ArrayList<Object>(); setBackground(Color.RED); setForeground(Color.BLUE); setIgnoreRepaint(true); setBorder(null); setOpaque(false); this.text = text; setSize(14 * 7, 16); parseText(text); } private void parseText(String text) { sectionList.clear(); if (text == null) return; String section; Pattern pattern = Pattern.compile("#([RGBKYWnbur#]|[1-9]\\d|[0-9]|" + "c[0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?)|" + "[^#]+"); Matcher m = pattern.matcher(text); Animation anim; while (m.find()) { section = m.group(); if (section.startsWith("#")) { anim = faceAnimations.get(section); if (anim == null && section.charAt(1) >= '0' && section.charAt(1) <= '9') { anim = SpriteFactory.loadAnimation("/resources/emoticons/" + section.substring(1) + ".was"); if (anim != null) { faceAnimations.put(section, anim); } } if (anim != null) { sectionList.add(anim); } else if (section.startsWith("#c")) { Color color = Color.decode("0x" + section.substring(2)); sectionList.add(color); } else if (section.equals("#R")) { sectionList.add(Color.RED); } else if (section.equals("#G")) { sectionList.add(Color.GREEN); } else if (section.equals("#B")) { sectionList.add(Color.BLUE); } else if (section.equals("#W")) { sectionList.add(Color.WHITE); } else if (section.equals("#K")) { sectionList.add(Color.BLACK); } else if (section.equals("#Y")) { sectionList.add(Color.YELLOW); } else if (section.equals("#r")) { // line swap sectionList.add(new Integer(-1)); } else if (section.equals("#n")) { // FIXME reset sectionList.add(Color.WHITE); // } else { // sectionList.add(section); } } else { sectionList.add(section); } } } @Override public void paint(Graphics g) { g.setFont(UIUtils.TEXT_FONT); g.setColor(Color.WHITE); if (startTime == 0) startTime = System.currentTimeMillis(); currTime = System.currentTimeMillis(); int maxwidth = getWidth(), rowWidth = 0, y = 0, rowHeight = 0; int count = sectionList.size(), start = 0, x = 0; for (int i = 0; i < count; i++) { Object obj = sectionList.get(i); if (obj instanceof String) { String str = (String) obj; FontMetrics fm = g.getFontMetrics(); rowHeight = Math.max(rowHeight, fm.getHeight()); int dx = fm.stringWidth(str); if (rowWidth + dx <= maxwidth) { rowWidth += dx; } else { Point p = paintRichText(g, x, y, maxwidth, rowHeight, start, i + 1); start = i + 1; rowWidth = p.x; rowHeight = fm.getHeight(); x = p.x; y = p.y; } } else if (obj instanceof Animation) { Animation anim = (Animation) obj; if (anim.getWidth() + rowWidth > maxwidth) { paintRichText(g, x, y, maxwidth, rowHeight, start, i); start = i; x = 0; y += rowHeight; rowWidth = anim.getWidth(); rowHeight = anim.getHeight(); } else { rowHeight = Math.max(rowHeight, anim.getHeight()); rowWidth += anim.getWidth(); } } else if (obj instanceof Integer) {// line swap paintRichText(g, x, y, maxwidth, rowHeight, start, i + 1); start = i; x = 0; y += rowHeight; rowWidth = 0; rowHeight = 0; } } paintRichText(g, x, y, maxwidth, rowHeight, start, count); } private String lastStr; private String text; private Point paintRichText(Graphics g, int x, int y, int width, int rowh, int start, int end) { if (lastStr != null) { g.drawString(lastStr, 0, y + rowh); lastStr = null; } for (int i = start; i < end; i++) { Object obj = sectionList.get(i); if (obj instanceof String) { String str = (String) obj; FontMetrics fm = g.getFontMetrics(); int len = str.length(); int begin = 0, index, dx = 0; for (index = 0; index < len;) { dx = fm.charWidth(str.charAt(index)); while (x + dx <= width) { if (++index >= len) break; dx += fm.charWidth(str.charAt(index)); } String s = str.substring(begin, index); if (i == end - 1 && index >= len && x + dx < width && sectionList.size() > end) { lastStr = s; Object nextObj = sectionList.get(end); if (nextObj instanceof Animation) { Animation anim = (Animation) nextObj; if (anim.getWidth() + x + dx > width) { g.drawString(s, x, y + rowh); lastStr = null; } } } else { g.drawString(s, x, y + rowh); } if (index < len || x + dx == width) { begin = index; x = 0; y += rowh; rowh = fm.getHeight(); } else { x += fm.stringWidth(s); } } } else if (obj instanceof Color) { g.setColor((Color) obj); } else if (obj instanceof Animation) { Animation anim = (Animation) obj; anim.updateToTime(currTime - startTime); g.drawImage(anim.getImage(), x, y + rowh - anim.getHeight(), null); x += anim.getWidth(); } } return new Point(x, y); } public static void main(String[] args) { String text = "#35����#52#rһ��#R���λ����Ρ�#B#52#r����#r��ʽ�ı�:#G���#c008000��#R��#Y��#G��#B��#R��#B#u��!#35#52#R������������"; final JFrame frame = new JFrame("GFormattedLabelText"); frame.getContentPane().setBackground(Color.GRAY); final RichLabel label = new RichLabel(text); label.setLocation(10, 10); frame.add(label); final JTextField textField = new JTextField(); textField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { label.setText(textField.getText()); } }); frame.add(textField, BorderLayout.SOUTH); frame.setSize(400, 300); frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); Thread update = new Thread() { @Override public void run() { try { while (true) { label.repaint(); sleep(100); } } catch (InterruptedException e) { e.printStackTrace(); } } }; update.setDaemon(true); update.start(); } public void setText(String text) { this.text = text; parseText(text); } public String getText() { return text; } public Dimension computeSize(int maxwidth) { if (text == null) return new Dimension(0, 0); int rowWidth = 0, y = 0, rowHeight = 0; int count = sectionList.size(), start = 0, x = 0; BufferedImage temp = new BufferedImage(maxwidth, 16, BufferedImage.TYPE_USHORT_565_RGB); Graphics g = temp.getGraphics(); g.setFont(UIUtils.TEXT_FONT); for (int i = 0; i < count; i++) { Object obj = sectionList.get(i); if (obj instanceof String) { String str = (String) obj; FontMetrics fm = g.getFontMetrics(); rowHeight = Math.max(rowHeight, fm.getHeight()); int dx = fm.stringWidth(str); if (rowWidth + dx <= maxwidth) { rowWidth += dx; } else { Point p = paintRichText(g, x, y, maxwidth, rowHeight, start, i + 1); start = i + 1; rowWidth = p.x; rowHeight = fm.getHeight(); x = p.x; y = p.y; } } else if (obj instanceof Animation) { Animation anim = (Animation) obj; if (anim.getWidth() + rowWidth > maxwidth) { paintRichText(g, x, y, maxwidth, rowHeight, start, i); start = i; x = 0; y += rowHeight; rowWidth = anim.getWidth(); rowHeight = anim.getHeight(); } else { rowHeight = Math.max(rowHeight, anim.getHeight()); rowWidth += anim.getWidth(); } } else if (obj instanceof Integer) {// line swap paintRichText(g, x, y, maxwidth, rowHeight, start, i + 1); start = i; x = 0; y += rowHeight; rowWidth = 0; rowHeight = 0; } } Point p = paintRichText(g, x, y, maxwidth, rowHeight, start, count); if (y == 0) maxwidth = p.x; return new Dimension(maxwidth, y + rowHeight + 4);//FIXME height!!1 } @Override public void paintImmediately(int x, int y, int w, int h) { //super.paintImmediately(x, y, w, h); } }