⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 popup.java

📁 J2ME 3D 第一人称射击迷宫类手机游戏源码。
💻 JAVA
字号:
package myGame.gui.popup;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;

import myGame.main.Resources;

/**
 * <p>
 * The <code>Popup</code> represents a popup with text and zero or many
 * alternatives that user can select among. A popup can be shown for a specific
 * amount of time or forever, the latter case requiring a user to close the
 * popup. The choice of the alternatives can be reported by implementing a
 * <code>PopupListener</code>
 * </p>
 * <p>
 * This class contains all functionality of a popup, i.e. interaction, graphics
 * and callback.
 * </p>
 * 
 * @author YuBingxing
 */
public class Popup implements Runnable {
	/** Preset alternative containing OK */
	public static final char[][] ALT_OK;

	/** Preset alternative containing CANCEL */
	public static final char[][] ALT_CANCEL;

	/** Preset alternatives containing YES and NO */
	public static final char[][] ALT_YES_NO;

	/** Preset alternatives containing OK and CANCEL */
	public static final char[][] ALT_OK_CANCEL;

	/** Preset alternatives containing YES, NO, and CANCEL */
	public static final char[][] ALT_YES_NO_CANCEL;

	// Setup preset alternatives
	static {
		ALT_OK = new char[1][];
		ALT_OK[0] = Resources.getChars(Resources.TXT_OK);
		ALT_CANCEL = new char[1][];
		ALT_CANCEL[0] = Resources.getChars(Resources.TXT_CANCEL);
		ALT_YES_NO = new char[2][];
		ALT_YES_NO[0] = Resources.getChars(Resources.TXT_YES);
		ALT_YES_NO[1] = Resources.getChars(Resources.TXT_NO);
		ALT_OK_CANCEL = new char[2][];
		ALT_OK_CANCEL[0] = ALT_OK[0];
		ALT_OK_CANCEL[1] = ALT_CANCEL[0];
		ALT_YES_NO_CANCEL = new char[3][];
		ALT_YES_NO_CANCEL[0] = ALT_YES_NO[0];
		ALT_YES_NO_CANCEL[1] = ALT_YES_NO[1];
		ALT_YES_NO_CANCEL[2] = ALT_CANCEL[0];
	}

	/** The text to show in the popup */
	protected char[] m_text;

	/** Number of alternatives to select in popup */
	protected byte m_alternatives;

	/** Array of texts as chararrays in alternatives */
	protected char[][] m_altTexts;

	/** Time out in seconds */
	protected byte m_timeOut;

	/** Alternative reported back if timeout is reached */
	protected byte m_timeOutAlt;

	/** Current alternative index */
	protected byte m_curAlt;

	/** Listener to this popup */
	protected PopupListener m_listener;

	/** Flag indicating if popup is active */
	protected volatile boolean m_active = true;

	/** Width of popup */
	protected int m_w;

	/** Height of popup */
	protected int m_h;

	/**
	 * Indices indicating where to break the text organized as [line][0 = start
	 * char offset | 1 = char len]
	 */
	protected int[][] m_breakTextData;

	/** Number of visible text lines in popup */
	protected int m_visibleLines;

	/** Current line offset */
	protected int m_curLine;

	/** Maximum line offset */
	protected int m_maxLine;

	/** Horizontal coordinate offset of text */
	protected int m_yoffset;

	/** The life time of this popup */
	protected long m_endTime;

	// Graphical data
	protected Font m_font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_ITALIC,
			Font.SIZE_MEDIUM);

	protected int m_fontHeight = m_font.getHeight();

	protected int m_borderColor = 0xdd0000;

	protected int m_backgroundColor = 0xcc440000;

	protected int m_textColor = 0xffffff;

	protected int m_alternativeColor = 0xff2200;

	protected int m_selectedAlternativeColor = 0xffffff;

	protected static int[] m_rgbData;

	/**
	 * Space between actual popup graphics and the rectangle reported in method
	 * <code>init</code>
	 */
	protected static final int OFFSET_POPUP = 8;

	/** Space between popup edges and text content */
	protected static final int OFFSET_TEXT = 2;

	/** Space between alternative texts */
	protected static final int OFFSET_ALT = 4;

	/** Scrollbar width */
	protected static final int SB_WIDTH = 5;

	/** Textbreak constants */
	protected static final char[] TEXTBREAKS = { ' ', '?', ';', ',', '.', '!',
			':', '-', '=', '(', ')', '[', ']' };

	/** New line constant */
	protected static final char NEWLINE = '\n';

	/**
	 * Creates an uninitialized popup. Call <code>init</code> to setup this
	 * popup instance. This constructor is used for instance cache
	 * functionality.
	 */
	public Popup() {
	}

	/**
	 * Initializes this popup.
	 * 
	 * @param text
	 *            The text to show in popup.
	 * @param altTexts
	 *            The alternatives to select among or null if no choices.
	 * @param timeOut
	 *            Time out for this popup in seconds (0 means no timeout).
	 * @param defaultAlt
	 *            Index of default alternative.
	 * @param timeOutAlt
	 *            Alternative index reported on time out.
	 * @param listener
	 *            The popuplistener being reported on selection or timeout or
	 *            null if no listener.
	 * @param width
	 *            Canvas width.
	 * @param height
	 *            Canvas height.
	 */
	public void init(char[] text, char[][] altTexts, byte timeOut,
			byte defaultAlt, byte timeOutAlt, PopupListener listener,
			int width, int height) {
		// Set parameters
		m_text = text;
		m_altTexts = altTexts;
		if (altTexts != null) {
			m_alternatives = (byte) altTexts.length;
		} else {
			m_alternatives = 0;
		}
		m_timeOut = timeOut;
		m_timeOutAlt = timeOutAlt;
		m_listener = listener;
		m_curAlt = defaultAlt;
		m_w = width - (OFFSET_POPUP << 1);
		m_h = height - (OFFSET_POPUP << 1);
		m_active = true;
		if (m_timeOut > 0) {
			// Set timeout
			m_endTime = System.currentTimeMillis() + (m_timeOut * 1000);
		} else if (m_alternatives > 0) {
			// No timeout
			m_endTime = 0;
		} else {
			// This should never happen - a popup with no alternatives and no
			// timeout
			m_endTime = System.currentTimeMillis();
		}

		m_visibleLines = Math.max(1,
				((m_h - (OFFSET_TEXT << 1)) / m_fontHeight) - 1);
		int w = m_w - (OFFSET_TEXT << 1) - (SB_WIDTH << 1);
		m_curLine = 0;

		m_breakTextData = breakString(text, w);

		// Calculate height
		m_yoffset = 0;
		m_maxLine = m_breakTextData.length - m_visibleLines + 1;
		if (m_breakTextData.length < m_visibleLines) {
			int newH = m_breakTextData.length * m_fontHeight;
			if (m_alternatives > 0)
				newH += m_fontHeight;
			newH += OFFSET_TEXT + OFFSET_ALT;
			m_yoffset = (m_h - newH) >> 1;
			m_h = newH;
		}

		// Create transparent rgb buffer if needed (8 lines)
		if (m_rgbData == null || m_rgbData.length != m_w * 8) {
			m_rgbData = new int[m_w * 8];
			for (int i = 0; i < m_rgbData.length; i++) {
				m_rgbData[i] = m_backgroundColor;
			}
		}

		// Start poll thread
		new Thread(this, "PopupPoll").start();
	}

	/**
	 * Breaks specified character array and returns a break matrix by line,
	 * organized as [line][0 | 1] where 0 means starting offset in text for this
	 * line, 1 means number of characters of this line.
	 * 
	 * @param text
	 *            The string to break
	 * @param width
	 *            Width in pixels to break on
	 * @return A break index table
	 */
	protected int[][] breakString(char[] text, int width) {
		// Count text lines
		int offset = 0;
		int lines = 0;
		int newOffset;

		while (offset < text.length) {
			newOffset = findNextBreak(text, offset, text.length - offset,
					width, m_font);
			offset = newOffset;
			lines++;
		}

		int[][] indices = new int[lines][2];

		// Setting offset data
		lines = 0;
		offset = 0;
		while (offset < text.length) {
			newOffset = findNextBreak(text, offset, text.length - offset,
					width, m_font);
			indices[lines][0] = offset;
			indices[lines][1] = newOffset - offset;
			lines++;
			offset = newOffset;
		}

		return indices;
	}

	/**
	 * Returns next break when breaking a string.
	 * 
	 * @param text
	 *            The chars to calculate on
	 * @param offset
	 *            From what offset to read in chars
	 * @param len
	 *            How many characters to read
	 * @param w
	 *            Width
	 * @param f
	 *            Font
	 * @return Offset of next break or length of text if no more breaks
	 */
	public int findNextBreak(char[] text, int offset, int len, int w, Font f) {
		int breakOffset = offset;
		int textW = 0;
		int niceB = -1;
		char c;
		charLoop: while (breakOffset <= offset + len && textW < w) {
			if (breakOffset == offset + len)
				c = TEXTBREAKS[0]; // last character + 1, fake break char
			else
				c = text[breakOffset];
			if (c == NEWLINE) {
				// got a nice break here, new line
				niceB = breakOffset;
				break charLoop;
			}

			// Try finding break charachters
			breakCharLoop: for (int i = TEXTBREAKS.length - 1; i >= 0; i--) {
				if (c == TEXTBREAKS[i]) {
					niceB = breakOffset;
					break breakCharLoop;
				}
			}
			if (breakOffset == offset + len - 1) {
				// Special case, skip the last character
				niceB = breakOffset + 1;
			}
			breakOffset++;
			textW += f.charWidth(c);
		}
		if (niceB > offset && niceB < offset + len - 2
				&& (text[niceB + 1] == ' '))
			return niceB + 2; // case: special case to get rid of extra spaces
		else if (niceB > offset && niceB < offset + len)
			return niceB + 1; // case: found a nice break, use this
		else if (breakOffset > offset + 1)
			return breakOffset - 1; // case: broke due to text width too big
		else if (breakOffset == offset)
			return breakOffset + 1; // case: broken on first char, step one more
		else
			return breakOffset; // case: default
	}

	/**
	 * Paints the popup. Call this from your <code>Displayable</code>'s paint
	 * method.
	 * 
	 * @param g
	 *            Graphics context to paint on.
	 */
	public void paint(Graphics g) {
		if (m_active) {
			// draw transparent background
			for (int y = OFFSET_POPUP + m_yoffset; y < OFFSET_POPUP + m_yoffset
					+ m_h; y += 8) {
				g.drawRGB(m_rgbData, 0, m_w, OFFSET_POPUP, y, m_w, Math.min(8,
						OFFSET_POPUP + m_yoffset + m_h - y), true);
			}

			// border
			g.setColor(m_borderColor);
			g.drawRect(OFFSET_POPUP, OFFSET_POPUP + m_yoffset, m_w, m_h);

			// text
			g.setColor(m_textColor);
			g.setFont(m_font);
			int y = OFFSET_POPUP + OFFSET_TEXT + m_yoffset;
			int maxLine = Math.min(m_curLine + m_visibleLines,
					m_breakTextData.length);
			for (int i = m_curLine; i < maxLine; i++) {
				int offset = m_breakTextData[i][0];
				int len = m_breakTextData[i][1];
				if (len == 1 && m_text[offset] == NEWLINE) {
					y += m_fontHeight;
				} else {
					if (m_text[offset + len - 1] == NEWLINE) {
						len--;
					}
					g.drawChars(m_text, offset, len, OFFSET_POPUP + OFFSET_TEXT
							+ (m_w >> 1), y, Graphics.TOP | Graphics.HCENTER);
					y += m_fontHeight;
				}
			}

			// scrollbar
			if (m_visibleLines < m_breakTextData.length) {
				int sbh = m_visibleLines * m_fontHeight; // Scrollbar max
				// height
				int sbstep = ((sbh - 4) << 8) / m_maxLine; // Scrollbar height
				// * 256
				int sbX = OFFSET_POPUP + m_w - SB_WIDTH - (SB_WIDTH >> 1); // Scrollbar
				// x-coordinate
				g.setColor(m_textColor);
				g.fillRect(sbX, OFFSET_POPUP + OFFSET_TEXT
						+ ((m_curLine * sbstep) >> 8), SB_WIDTH,
						4 + (sbstep >> 8));
			}

			// alternatives
			if (m_alternatives > 0) {
				y = OFFSET_POPUP + OFFSET_TEXT + m_h + m_yoffset - OFFSET_TEXT
						- m_fontHeight;
				int dx = (m_w / (m_alternatives + 1));
				int x = OFFSET_POPUP + OFFSET_TEXT;
				for (int i = 0; i < m_alternatives; i++) {
					char[] t = m_altTexts[i];
					x += dx;
					int xx = x - (m_font.charsWidth(t, 0, t.length) >> 1);
					if (m_curAlt != i) {
						// Unselected alternative
						g.setColor(m_alternativeColor);
						g.drawChars(t, 0, t.length, xx, y, Graphics.TOP
								| Graphics.LEFT);
					} else {
						// Selected alternative
						g.setColor(m_alternativeColor);
						g.drawChars(t, 0, t.length, xx + 1, y + 1, Graphics.TOP
								| Graphics.LEFT);
						g.setColor(m_selectedAlternativeColor);
						g.drawChars(t, 0, t.length, xx, y, Graphics.TOP
								| Graphics.LEFT);
					}
				}
			}
		}
	}

	/**
	 * Handles user interaction when pressing a key. Call this from your
	 * <code>Displayable</code>'s keyPressed keyRepeated method.
	 * 
	 * @param keyCode
	 *            The keycode.
	 * @param gameCode
	 *            The gamecode.
	 */
	public void keyPressed(int keyCode, int gameCode) {
		if (m_active) {
			if (m_alternatives < 1) {
				// If no choice, any key will do
				m_active = false;
				if (m_listener != null)
					m_listener.selectedChoice(m_curAlt, false);
			} else {
				switch (gameCode) {
				// Scroll text
				case Canvas.DOWN: {
					m_curLine++;
					if (m_curLine >= m_maxLine)
						m_curLine = 0;
					break;
				}
				case Canvas.UP: {
					if (m_maxLine > 0)
						m_curLine--;
					if (m_curLine < 0)
						m_curLine = m_maxLine - 1;
					break;
				}
					// Select among choices
				case Canvas.RIGHT: {
					m_curAlt++;
					if (m_curAlt >= m_alternatives)
						m_curAlt = 0;
					break;
				}
				case Canvas.LEFT: {
					m_curAlt--;
					if (m_curAlt < 0)
						m_curAlt = (byte) (m_alternatives - 1);
					break;
				}
				case Canvas.FIRE: {
					// Select
					if (m_curAlt >= 0) {
						m_active = false;
						if (m_listener != null)
							m_listener.selectedChoice(m_curAlt, false);
					}
					break;
				}
				}
			}
		}
	}

	/**
	 * Disposes all resources held by this popup and closes it.
	 */
	public void dispose() {
		m_active = false;
		m_text = null;
		m_altTexts = null;
		m_listener = null;
		m_breakTextData = null;
		System.gc();
	}

	/**
	 * Returns whether this popup is active or not.
	 * 
	 * @return true if active, false otherwise.
	 */
	public boolean isActive() {
		return m_active;
	}

	/**
	 * Returns alternative index on timeout
	 * 
	 * @return timeout alternative
	 */
	public byte getTimeOutChoice() {
		return m_timeOutAlt;
	}

	/**
	 * Called by framework to check if popup reached its' timeout.
	 * 
	 * @return true if timeout, false otherwise.
	 */
	protected boolean pollTimeout() {
		if (m_active) {
			if (m_endTime > 0 && System.currentTimeMillis() > m_endTime) {
				m_active = false;
				if (m_listener != null) {
					m_listener.selectedChoice(m_timeOutAlt, true);
					return true;
				}
			}
		}
		return false;
	}

	// Runnable impl to poll this popup
	public void run() {
		while (isActive()) {
			// Poll popup timeout
			try {
				Thread.sleep(1000);
				pollTimeout();
			} catch (InterruptedException e) {
			}
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -