/* * ScrollableText.java * * Created on September 22, 2005 * */ import java.awt.Font; import java.awt.Color; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Dimension; import java.awt.Point; import java.awt.Insets; import java.awt.AWTEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Vector; import org.havi.ui.*; /** * ScrollableText.java * * A text component that can function as a stand-alone * scrollable test displayer. Contains the neccessary * methods for processing user input. * */ public class ScrollableText extends HComponent{ /** The alignment styles */ public static final int ALIGN_LEFT = 0; public static final int ALIGN_RIGHT = 1; public static final int ALIGN_CENTER = 2; public static final int ALIGN_TOP = 3; public static final int ALIGN_BOTTOM = 4; /** the keys used for navigating */ public static final int UP_KEY = KeyEvent.VK_UP; public static final int DOWN_KEY = KeyEvent.VK_DOWN; public static final int PGUP_KEY = KeyEvent.VK_LEFT; public static final int PGDOWN_KEY = KeyEvent.VK_RIGHT; /** Directional consts */ public static final int DIR_UP = 1; public static final int DIR_DOWN = 2; /** Position tokens */ public static final int POS_BEGINNING = 0; public static final int POS_END = -1; /** The width of the sidescroller */ public static final int SIDESCROLLER_WIDTH = 20; /** The sidescroller show- policy */ public static final int SIDESCROLLER_ALWAYS = 0; public static final int SIDESCROLLER_NEVER = 1; public static final int SIDESCROLLER_AS_NEEDED = 2; /** Default color scheme */ private Color SCROLLER_BG = new Color(24, 93, 184); private Color SCROLLER_TAB_BG = new Color(110, 171, 102); private Color SCROLLER_ACTIVE_ARROW = new Color(110, 171, 102); private Color SCROLLER_INACTIVE_ARROW = new Color(24, 93, 184); private Color SCROLLER_ARROW_OUTLINE = Color.black; private Color SCROLLER_HIGHLIGHT = Color.white; private Color SCROLLER_SHADOW = Color.black; //private Color foreground = Color.black; //private Color background = Color.white; /** The sidescroller policy in use */ private int sidescrollerPolicy; /** Indicates if the sidescroller should be painted */ private boolean sidescroller; /* The size of the scrollbar */ private int scrollerHeight; /** The positional multiplier */ private float scrollerUnit; private static final double[] UP_ARROW_X = { 0.5, 0, 0.3, 0.3, 0.7, 0.7, 1 }; private static final double[] UP_ARROW_Y = { 0, 0.7, 0.7, 1, 1, 0.7, 0.7 }; private static final double[] DOWN_ARROW_X = { 0.3, 0.3, 0, 0.5, 1, 0.7, 0.7 }; private static final double[] DOWN_ARROW_Y = { 0, 0.3, 0.3, 1, 0.3, 0.3, 0 }; private static final int UP_ARROW = 0; private static final int DOWN_ARROW = 1; /** Variables related to the Scrollable interface */ private int scrollUnit; private int scrollBlock; private int scrollBy; private int totalHeight; /** Presentation- related values */ private String text; private int lineSpace; /** Margins */ private int rMarg; private int lMarg; private int tMarg; private int bMarg; /** The alignation style */ private int align; private int valign; /** The y- positions of the rows */ private int rowPos[]; /** The x- positions of the individual rows */ private int rowIndent[]; /** The row that is displayed on the top of the area */ private int currentRow; private int displayRows; /** The splitup of the text to paint */ private String rows[]; /** Supports transparent background */ private boolean transparent; /** Creates a new instance of ScrollableText */ public ScrollableText() { this.enableEvents(AWTEvent.KEY_EVENT_MASK); this.scrollBy = 1; } /** * The complete constructors. * Additional information should be set using the default java.awt.Component * methods; setFont(), setForeground(), setBackground(), setSize(), setLocation(); * * @param insets The margins * @param align The horizontal alignment of the text * @param valign The vertical alignment of the text * @param sidescroller The sidescroller policy */ public ScrollableText(Insets insets, int align, int valign, int sidescroller) { super(); this.enableEvents(AWTEvent.KEY_EVENT_MASK); this.align = align; this.valign = valign; this.text = text; this.sidescrollerPolicy = sidescroller; this.scrollBy = 1; this.lMarg = insets.left; this.rMarg = insets.right; this.tMarg = insets.top; this.bMarg = insets.bottom; this.transparent = true; text = ""; } /* public void setForeground(org.dvb.ui.DVBColor foreground){ this.foreground = foreground; super.setForeground(foreground); } public void setBackground(org.dvb.ui.DVBColor background){ this.background = background; super.setBackground(background); } */ /** * Changes the text within this component * @param text The new contents */ public void setText(String text) { this.currentRow = 0; this.text = text; int fontSize = 0; Font font = this.getFont(); int width = this.getSize().width; int height = this.getSize().height; //FontMetrics fm = this.getFontMetrics(new Font("SansSerif", Font.PLAIN, 24) ); FontMetrics fm = null; if (font != null) { fm = this.getFontMetrics(font); fontSize = font.getSize(); if (this.sidescrollerPolicy != SIDESCROLLER_NEVER) this.rows = convertText(text, width - (this.rMarg + this.lMarg + SIDESCROLLER_WIDTH), fm); else this.rows = convertText(text, width - (this.rMarg + this.lMarg), fm); } else { this.rows = new String[1]; this.rows[0] = text; } if (fm != null) this.lineSpace = fm.getDescent(); else this.lineSpace = (int)(fontSize/4); this.totalHeight = (fontSize + this.lineSpace) * this.rows.length; this.scrollBlock = fontSize + this.lineSpace; this.scrollUnit = fontSize + this.lineSpace; int usableHeight = height - this.tMarg - this.bMarg; if ((usableHeight < 1) || (this.scrollBlock < 1)) { this.displayRows = 0; } else { this.displayRows = usableHeight / this.scrollBlock; if (this.displayRows > this.rows.length) this.displayRows = this.rows.length; /* vertical alignment */ int valignOfs = 0; if (this.valign != ALIGN_TOP) { valignOfs = height - this.displayRows * this.scrollBlock; /* valignOfs is currently suitable for ALIGN_BOTTOM */ if (this.valign == ALIGN_CENTER) valignOfs = (int)(valignOfs/2); } /* Calculate the positions of the rows beforehand */ this.rowPos = new int[ this.displayRows ]; int posCount = fm.getAscent() + this.tMarg + valignOfs; for(int i = 0; i < this.displayRows; i++) { this.rowPos[i] = posCount; posCount += this.scrollBlock; } } float sHeight = height - (2 * SIDESCROLLER_WIDTH) - 2; /* Calculate sidescroller data */ if (this.rows.length <= this.displayRows) { this.scrollerUnit = 0; this.scrollerHeight = (int)sHeight; } else { this.scrollerUnit = (sHeight / (float)this.rows.length); this.scrollerHeight = Math.round(((float)this.displayRows * this.scrollerUnit)); } /* Make sure the scroller has some size */ if (this.scrollerHeight < 3) this.scrollerHeight = 4; switch(this.sidescrollerPolicy) { case SIDESCROLLER_ALWAYS: this.sidescroller = true; break; case SIDESCROLLER_NEVER: this.sidescroller = false; break; case SIDESCROLLER_AS_NEEDED: default: if (this.scrollerUnit > 0) this.sidescroller = true; else this.sidescroller = false; } } /** * Returns the start of a line if using the set alignation style * and the given width */ private int getIndent(int strWidth, int width) { switch(this.align) { case ALIGN_RIGHT: return width - strWidth; case ALIGN_CENTER: return (width - strWidth) / 2; default: return 0; } } /** * Small method to add a string to one Vector and it's * indentation information to the other */ private void addStr(String str, Vector strings, Vector indents, FontMetrics fm, int width) { strings.addElement(str); indents.addElement(new Integer(getIndent(fm.stringWidth(str), width))); } /** * Converts the given string into an array of String with each entry * having the width of width or less. * */ private String[] convertText(String text, int width, FontMetrics fm) { /* Check one line at a time, add it to the final */ Vector al = new Vector(); Vector inList = new Vector(); String tmp = ""; for(int i = 0; i < text.length(); i++) { char ch = text.charAt(i); /* Check for control chars */ switch(ch) { case '\n': addStr(tmp, al, inList, fm, width); tmp = ""; break; case '\t': tmp += " "; break; default: tmp += ch; try { if (fm.stringWidth(tmp) > width) { int pos = ScrollableText.getBreakPos(tmp); if (pos > 0) { addStr(tmp.substring(0, pos), al, inList, fm, width); tmp = tmp.substring(pos+1, tmp.length()); } else { /* No breaking possible; remove last character */ addStr(tmp.substring(0, tmp.length()-1), al, inList, fm, width); tmp = tmp.charAt(tmp.length()-1) + ""; } } } catch(Exception e) { System.out.println("ScrollableText.convertText exception: " + e); e.printStackTrace(System.out); String ret[] = new String[1]; ret[0] = text; return ret; } } } if (tmp.length() > 0) addStr(tmp, al, inList, fm, width); String[] ret = new String[ al.size() ]; rowIndent = new int[ inList.size() ]; for(int i = 0; i < al.size(); i++) { ret[i] = (String)al.elementAt(i); rowIndent[i] = ((Integer)inList.elementAt(i)).intValue(); } return ret; } /** * Returns the position where the given String can be * broken up according to spaces and tabs, starting from * the end of the String. * If such is not found before a newline or at all, the * resulting value will be negative. If found, the resulting * value is the position of the breaking character, which * can safely be substituted for a newline, eg. * String new = old.substring(0, ret_value) + '\n' * + old.substring(ret_value+1, old.length()); * */ private static int getBreakPos(String str) { for(int i = str.length() - 1; (i > -1) && (str.charAt(i) != '\n'); i--) { if ((str.charAt(i) == ' ') || (str.charAt(i) == '\t')) { /* A suitable position is found */ return i; } } /* Not found */ return -1; } /** * Changes the size of this component */ public void setSize(int width, int height) { super.setSize(width, height); setText(this.text); } /** * Changes the size of this component */ public void setSize(Dimension dim) { this.setSize(dim.width, dim.height); } /** * Changes the font of this component */ public void setFont(Font font) { super.setFont(font); this.setText(this.text); } /** * Sets the background of the text - supports transparent * by providing null */ public void setBackground(Color bg) { super.setBackground(bg); this.transparent = (bg == null); } /** * Sets the color scheme for the sidescroller * */ public void setScrollerColors(Color bg, Color tabBg, Color activeArrow, Color inactiveArrow, Color arrowOutline, Color highlight, Color shadow) { SCROLLER_BG = bg; SCROLLER_TAB_BG = tabBg; SCROLLER_ACTIVE_ARROW = activeArrow; SCROLLER_INACTIVE_ARROW = inactiveArrow; SCROLLER_ARROW_OUTLINE = arrowOutline; SCROLLER_HIGHLIGHT = highlight; SCROLLER_SHADOW = shadow; this.repaint(); } /** * Changes multiple properties of this component * * @param text The text to be contained within the * component. If null, the old text will * be preserved. */ public void setPresentation(int x, int y, int width, int height, int align, int valign, String text) { this.setBounds(x, y, width, height); this.align = align; this.valign = valign; if (text != null) this.text = text; setText(this.text); } /** * Changes the horizontal alignment of this component * * @param alignment One of the Horizontal alignment * constants; ALIGN_LEFT ALIGN_RIGHT ALIGN_CENTER */ public void setHorizontalAlignment(int alignment) { this.align = alignment; setText(this.text); } /** * Changes the vertical alignment of this component * @param alignment One of the Vertical alignment * constants; ALIGN_TOP ALIGN_BOTTOM ALIGN_CENTER */ public void setVerticalAlignment(int alignment) { this.valign = alignment; setText(this.text); } /** * Sets the number or rows the component should * be scrolled by with each scroll * @param rows The number of rows */ public void setScrollRows(int rows) { this.scrollUnit = rows * this.scrollBlock; this.scrollBy = rows; } /** * Scrolls the component one scrollunit in the * given direction * @param direction The direction; DIR_UP, DIR_DOWN */ public void scrollContents(int direction) { if (direction == DIR_DOWN) this.currentRow -= this.scrollBy; else this.currentRow += scrollBy; checkState(); } /** * Scrolls the component one visible page (if available) * in the given direction * @param direction The direction of the scroll */ public void scrollPage(int direction) { if (direction == DIR_DOWN) this.currentRow -= this.displayRows; else this.currentRow += this.displayRows; checkState(); } /** * Jumps to the given position (in rows) within * the contents. * @param position The position, or a special code: * POS_BEGINNING, POS_END */ public void jumpTo(int position) { switch(position) { case POS_BEGINNING: this.currentRow = 0; break; case POS_END: this.currentRow = this.rows.length; break; default: this.currentRow = position; } checkState(); } /** * Returns the total number of rows contained within * the object * @return The total number of rows */ public int getTotalScrollBlocks() { return this.rows.length; } /** * Returns the total number of rows that fits * within the components boundaries * @return The number of visible rows */ public int getVisibleScrollBlocks() { return this.displayRows; } /** * Returns the number of hidden rows above the * visible area * @return The number of not- visible, scrolled by rows */ public int getHiddenTopScrollBlocks() { return this.currentRow; } /** * Returns the number of hidden rows below the * visible area * @return The number of hidden, unviewed rows */ public int getHiddenBottomScrollBlocks() { int ret = this.rows.length - this.displayRows - this.currentRow; if (ret < 0) ret = 0; return ret; } /** * Method that does sanity- checking on presentation- related * conditions before calling paint */ private void checkState() { /* Check position */ if (this.currentRow > (this.rows.length - this.displayRows)) this.currentRow = this.rows.length - this.displayRows; if (this.currentRow < 0) this.currentRow = 0; this.repaint(); } /** * Paints the text */ public void paint(Graphics g) { if (this.isVisible()) { if (!this.transparent) { g.setColor(this.getBackground()); g.fillRect(0, 0, this.getSize().width, this.getSize().height); } g.setFont(this.getFont()); //this.setForeground(Color.b) g.setColor(this.getForeground()); //g.setColor(Color.BLACK); for(int i = 0; i < this.displayRows; i++) { g.drawString(this.rows[i+this.currentRow], this.lMarg + this.rowIndent[this.currentRow+i], this.rowPos[i]); } if (this.sidescroller) { drawScroller(g); } } } /** * Draws the scrollbar */ private void drawScroller(Graphics g) { int width = this.getSize().width; int height = this.getSize().height; int startx = width - SIDESCROLLER_WIDTH; int barSY = SIDESCROLLER_WIDTH + 2 + (int)((float)this.currentRow * this.scrollerUnit); int barEY = barSY + this.scrollerHeight-2; /* Make sure the scrollbar has some height, and is within the boundaries */ int dfix = barEY - (height - SIDESCROLLER_WIDTH - 2); if (dfix > 0) { if ((barSY - dfix) < SIDESCROLLER_WIDTH) barSY = SIDESCROLLER_WIDTH +1; else barSY = barSY - dfix; barEY = barEY - dfix; } g.setColor(SCROLLER_BG); g.fillRect(startx, 0, this.SIDESCROLLER_WIDTH, height); g.setColor(SCROLLER_TAB_BG); g.fillRect(startx+1, barSY, SIDESCROLLER_WIDTH - 2, (barEY-barSY)); g.setColor(SCROLLER_SHADOW); g.drawLine(startx, this.SIDESCROLLER_WIDTH + 1, width-1, this.SIDESCROLLER_WIDTH + 1); g.drawLine(startx, this.SIDESCROLLER_WIDTH + 1, startx, height - this.SIDESCROLLER_WIDTH - 1); g.drawLine(width-2, barSY+1, width-2, barEY); g.drawLine(startx+1, barEY, width-2, barEY); g.setColor(SCROLLER_HIGHLIGHT); g.drawLine(width-1, this.SIDESCROLLER_WIDTH + 1, width-1, height - this.SIDESCROLLER_WIDTH - 1 ); g.drawLine(startx, height - this.SIDESCROLLER_WIDTH - 1, width-1, height - this.SIDESCROLLER_WIDTH - 1); g.drawLine(startx+1, barSY, width-2, barSY); g.drawLine(startx+1, barSY, startx+1, barEY); if (getHiddenTopScrollBlocks() > 0) { drawArrow(UP_ARROW, startx, 0, SIDESCROLLER_WIDTH, SIDESCROLLER_WIDTH, SCROLLER_ACTIVE_ARROW, g); } else { drawArrow(UP_ARROW, startx, 0, SIDESCROLLER_WIDTH, SIDESCROLLER_WIDTH, SCROLLER_INACTIVE_ARROW, g); } if (getHiddenBottomScrollBlocks() > 0) { drawArrow(DOWN_ARROW, startx, height - SIDESCROLLER_WIDTH, SIDESCROLLER_WIDTH, SIDESCROLLER_WIDTH, SCROLLER_ACTIVE_ARROW, g); } else { drawArrow(DOWN_ARROW, startx, height - SIDESCROLLER_WIDTH, SIDESCROLLER_WIDTH, SIDESCROLLER_WIDTH, SCROLLER_INACTIVE_ARROW, g); } } /** * Draws an arrow in the given direction * */ private void drawArrow(int arrow, int x, int y, int width, int length, Color color, Graphics g) { int[] realX = new int[ 7 ]; int[] realY = new int[ 7 ]; double[] srcX; double[] srcY; switch(arrow){ case UP_ARROW: srcX = UP_ARROW_X; srcY = UP_ARROW_Y; break; case DOWN_ARROW: default: srcX = DOWN_ARROW_X; srcY = DOWN_ARROW_Y; break; } for(int i = 0; i < srcX.length; i++) { realX[i] = x + (int)(width * srcX[i]); } for(int i = 0; i < srcY.length; i++) { realY[i] = y + (int)(length * srcY[i]); } g.setColor(color); g.fillPolygon(realX, realY, realX.length); /* draw outline */ g.setColor(SCROLLER_ARROW_OUTLINE); g.drawPolygon(realX, realY, realX.length); } /** * Declears the scrollpanel to be focusable * */ public boolean isFocusable() { return true; } /** * Handles user input */ public void processKeyEvent(KeyEvent e) { if (this.isVisible()) { switch(e.getKeyCode()) { case UP_KEY: this.scrollContents(DIR_DOWN); break; case DOWN_KEY: this.scrollContents(DIR_UP); break; case PGUP_KEY: this.scrollPage(DIR_DOWN); break; case PGDOWN_KEY: this.scrollPage(DIR_UP); break; default: } } } }
Wednesday, November 18, 2009
A simple Xlet console for debugging log
I made this Xlet when I did Xlet programming as I feel there should be something like debug console in STB. So, I find a AWT scrollableText and modify it to be an Xlet. So, I have a debug console that can be shown on big TV screen. I can know what happen in the Xlet in real time and real STB environment. This code is a little bit rough. But it is a handy tool I like. However, I must emphasize to MHP programmer who want to use this. That is, MHP specification does not require MHP environment supports AWT API although many MHP vendor ported a JVM with AWT package into their STB. So, you don't need to be surprised if this code does not work in certain STB. But, I know this will rarely happen. Enjoy it.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment