📄 stringlayout.java
字号:
/* * @(#)StringLayout.java 1.23 01/08/08 * Copyright (c) 1999-2001 Sun Microsystems, Inc. All Rights Reserved. * * This software is the confidential and proprietary information of Sun * Microsystems, Inc. ("Confidential Information"). You shall not * disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into * with Sun. * * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING * THIS SOFTWARE OR ITS DERIVATIVES. */package javax.microedition.lcdui;import com.sun.midp.lcdui.Resource;/** * The StringLayout class is a Layout to handle String-only * Items with simple layout characteristics */class StringLayout implements Layout { /** The String to display */ private String str; /** An array holding linebreaks of the string */ private short[] lineBreaks = new short[2]; /** The number of lines it takes to display the string */ private int numLines; /** The width of the layout */ private int width = -1; // -1 when layout has not been done yet /** The height of the layout */ private int height; /** The maximum height of the layout */ private int maxHeight = -1; /** The Font to use for rendering */ protected Font f; /** The lineheight of the text */ protected int lineHeight; /** The width of the offset for rendering */ protected int offsetWidth; /** * isOffset is used to determine if lines starting from the second * line should be indent by 3 white spaces. This is used mainly by * an implicit list. */ private boolean isOffset; // default is false /** * clippingIndicatorLineNumber is -1 if no clipping required (default) * is the (+ve) line no. if clipping is * required. */ private int clippingIndicatorLineNumber; /** ELLIPSIS_CHAR is the string to display to indicate clipping. */ private static final String ELLIPSIS_CHAR = Resource.getString("..."); /** the width of the ellipsis in the current font */ private int widthOfEllipsisChar; /** * used to store the x-coordinate of the ellipsis when we need to display it */ private int ellipsisXOffset; /** * Create a new StringLayout * * @param str The String to display * @param font The Font to use to render the string */ StringLayout(String str, Font font) { this.str = str; f = font; lineHeight = font.getHeight(); offsetWidth = 3*f.charWidth(' '); clippingIndicatorLineNumber = -1; widthOfEllipsisChar = f.stringWidth(" ") + f.stringWidth(ELLIPSIS_CHAR); } /** * Get the width of this layout * * @return int The width of the layout */ public int getWidth() { return width; } /** * Set the width of this layout * * @param w The width of this layout * @return int The height of this layout, based on the new width */ public int setWidth(int w) { if (width != w && w >= 0) { width = w; updateLineBreaks(); } return height; } /** * Get the height of this layout * * @return int The height of this layout */ public int getHeight() { return height; } /** * Set the maximum height for this layout * * @param h The maximum height for this layout */ public void setMaxHeight(int h) { if (h < 0) { h = 0; } maxHeight = h; updateLineBreaks(); } /** * Get the lineheight for this layout * * @return int The lineheight (in pixels) of this layout */ public int getLineHeight() { return lineHeight; } /** * Paint this layout * * @param g The Graphics context to paint to * @param eraseBgrnd If True, the background should be erased * @param inverted If True, the colors should be inverted */ public void paint(Graphics g, boolean eraseBgrnd, boolean inverted) { if (numLines <= 0) { return; } int from = 0; int y = g.getClipY(); // if the start of the clip rect is outside of the StringLayout // object, no painting is needed. if (y > height) { return; } int yEnd = y + g.getClipHeight(); // if the height of the string layout to be painted is less than the // end of the clip rect, then paint up till the height only if (yEnd > height) { yEnd = height; } if (y < 0) { y = 0; } else if (y > 0) { from = y/lineHeight; if (from >= numLines) { return; } y = from * lineHeight; if (y > yEnd) { return; } } if (eraseBgrnd) { g.setColor(inverted ? Display.BG_H_COLOR : Display.ERASE_COLOR); g.fillRect(0, y, width, height); } g.setFont(f); g.setColor(inverted ? Display.FG_H_COLOR : Display.FG_COLOR); int prevIndex = from == 0 ? 0 : lineBreaks[from-1]; int i = from; // we need to use i outside the loop to // check for the last line on which to // place ellipsis for (; i < numLines && y < yEnd; ++i) { int index = lineBreaks[i]; int n = index - prevIndex; if (str.charAt(index-1) == '\n') { n--; } if (n > 0) { // indentation for 2nd line onwards if isOffset is set. int x = (i > 0 && isOffset) ? offsetWidth : 0; g.drawSubstring(str, prevIndex, n, x, y, Graphics.TOP | Graphics.LEFT); } y += lineHeight; prevIndex = index; } if ((i - 1) == clippingIndicatorLineNumber) { // we need clipping // we need to show the clipping indicator. g.drawString(ELLIPSIS_CHAR, ellipsisXOffset, y-lineHeight, Graphics.TOP | Graphics.LEFT); } } /** * Get the string of this layout * * @return String The string rendered by this layout */ String getString() { return str; } /** * Sets isOffset attribute for this layout. * If isOffset is <code>true </code> lines starting * from the second one will be indent by 3 white spaces. * * @param isOffset indicates if lines starting from the second <br> * line should be indent. */ void setOffset(boolean isOffset) { this.isOffset = isOffset; } /** * Sets the string to be wrapped. * * @param str The string to render * @return the height of the delta by which the overall height * was changed; 0 is returned if the height did not change * or if no layout was done yet */ int setString(String str) { this.str = str; if (width > 0) { int oldHeight = height; updateLineBreaks(); return height - oldHeight; } return 0; } /** * Add a line break * * @param spot The location of the break * @return int Return the new width of the layout */ private int addBreak(short spot) { if (numLines == lineBreaks.length) { short newBreaks[] = new short[lineBreaks.length + 2]; System.arraycopy(lineBreaks, 0, newBreaks, 0, lineBreaks.length); lineBreaks = newBreaks; } lineBreaks[numLines] = spot; return (isOffset ? (width - offsetWidth) : width); } /** * Update this layout's linebreaks */ private void updateLineBreaks() { clippingIndicatorLineNumber = -1; if (str == null || str.length() == 0 || width <= 0) { height = numLines = lineBreaks[0] = 0; return; } numLines = 0; int w = width; int curWidth = 0; int wordWidth = 0; int spaceIndex = 0; int numChars = str.length(); for (int i = 0; i < numChars; ++i) { char ch = str.charAt(i); int charWidth = f.charWidth(ch); if (ch == '\n') { addBreak((short)(i+1)); numLines++; curWidth = wordWidth = 0; continue; } if (ch == ' ') { spaceIndex = i; wordWidth = 0; } else { wordWidth += charWidth; } curWidth += charWidth; if (curWidth > w) { if (spaceIndex == 0) { // long word w = addBreak((short)i); curWidth = charWidth; } else { // do word wrap w = addBreak((short)(spaceIndex + 1)); curWidth = i == spaceIndex ? 0 : wordWidth; } numLines++; spaceIndex = 0; } } addBreak((short)numChars); // always "end" the last line if (numChars > 0) { numLines++; } height = numLines * lineHeight; if (maxHeight != -1 && height > maxHeight) { // find the line on which to place the clipping indicator. (0-based) clippingIndicatorLineNumber = (maxHeight / lineHeight) - 1; short startOfLine = 0; if (clippingIndicatorLineNumber > 0) { startOfLine = lineBreaks[clippingIndicatorLineNumber - 1]; } // if newLineBreak = n, the nth character is placed on the next line short newLineBreak = lineBreaks[clippingIndicatorLineNumber]; int allowedWidth = width - widthOfEllipsisChar; // get width of current portion int currWidth = f.substringWidth(str, startOfLine, newLineBreak - startOfLine); // we use the opportunity to update the line breaks // to also calculate the x coordinate of the ellipsis // when it is going to be drawn ellipsisXOffset = 0; while (currWidth < allowedWidth && newLineBreak <= numChars) { currWidth += f.charWidth(str.charAt(newLineBreak++)); } while (currWidth > allowedWidth) { currWidth -= f.charWidth(str.charAt(--newLineBreak)); } ellipsisXOffset = currWidth; // assign new lineBreak lineBreaks[clippingIndicatorLineNumber] = newLineBreak; // set height as maxHeight height = maxHeight; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -