All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codename1.ui.plaf.DefaultLookAndFeel Maven / Gradle / Ivy

There is a newer version: 7.0.167
Show newest version
/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores
 * CA 94065 USA or visit www.oracle.com if you need additional information or
 * have any questions.
 */
package com.codename1.ui.plaf;

import com.codename1.components.InfiniteProgress;
import com.codename1.io.Util;
import com.codename1.ui.geom.Dimension;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Button;
import com.codename1.ui.CN;
import com.codename1.ui.ComboBox;
import com.codename1.ui.Component;
import com.codename1.ui.ComponentSelector;
import com.codename1.ui.ComponentSelector.ComponentClosure;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.Label;
import com.codename1.ui.List;
import com.codename1.ui.TextArea;
import com.codename1.ui.list.ListCellRenderer;
import com.codename1.ui.list.ListModel;
import com.codename1.ui.Font;
import com.codename1.ui.FontImage;
import com.codename1.ui.Form;
import com.codename1.ui.Stroke;
import com.codename1.ui.TextSelection;
import com.codename1.ui.TextSelection.Char;
import com.codename1.ui.TextSelection.Span;
import com.codename1.ui.TextSelection.Spans;
import com.codename1.ui.animations.Animation;
import com.codename1.ui.events.FocusListener;
import com.codename1.ui.geom.GeneralPath;
import com.codename1.ui.geom.Rectangle;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.BoxLayout;
import com.codename1.ui.util.Resources;

/**
 * Used to render the default look of Codename One
 *
 * @author Chen Fishbein
 * @deprecated this class is still crucial for some features in Codename One. The deprecation is here to indicate 
 * our desire to reduce usage/reliance on this class. 
 */
public class DefaultLookAndFeel extends LookAndFeel implements FocusListener {
    private Image[] chkBoxImages = null;
    private Image comboImage = null;
    private Image[] rButtonImages = null;
    private Image[] chkBoxImagesFocus = null;
    private Image[] rButtonImagesFocus = null;
    private boolean tickWhenFocused = true;
    private char passwordChar = '\u25CF'; 
    
    //used for the pull to refresh feature
    private Container pull;
    private Component updating;
    private Component pullDown;
    private Component releaseToRefresh;
    
    
    /** Creates a new instance of DefaultLookAndFeel */
    public DefaultLookAndFeel(UIManager manager) {
        super(manager);
    }

    /**
     * {@inheritDoc}
     */
    public void bind(Component cmp) {
        if (tickWhenFocused && cmp instanceof Label) {
            ((Label) cmp).addFocusListener(this);
        }
    }

    /**
     * This method allows to set all Labels, Buttons, CheckBoxes, RadioButtons
     * to start ticking when the text is too long. 
     * @param tickWhenFocused
     */
    public void setTickWhenFocused(boolean tickWhenFocused) {
        this.tickWhenFocused = tickWhenFocused;
    }

    /**
     * This method allows to set all Labels, Buttons, CheckBoxes, RadioButtons
     * to start ticking when the text is too long.
     * @return  tickWhenFocused
     */
    public boolean isTickWhenFocused() {
        return tickWhenFocused;
    }

    /**
     * Sets images for checkbox checked/unchecked modes
     * 
     * @param checkedX the image to draw in order to represent a checked checkbox
     * @param uncheckedX the image to draw in order to represent an uncheck checkbox
     */
    public void setCheckBoxImages(Image checkedX, Image uncheckedX) {
        setCheckBoxImages(checkedX, uncheckedX, checkedX, uncheckedX);
    }

    /**
     * Sets images for checkbox checked/unchecked modes
     *
     * @param checkedX the image to draw in order to represent a checked checkbox
     * @param uncheckedX the image to draw in order to represent an uncheck checkbox
     * @param disabledChecked same as checked for the disabled state
     * @param disabledUnchecked same as unchecked for the disabled state
     */
    public void setCheckBoxImages(Image checkedX, Image uncheckedX, Image disabledChecked, Image disabledUnchecked) {
        if (checkedX == null || uncheckedX == null) {
            chkBoxImages = null;
        } else {
            if(disabledUnchecked == null) {
                disabledUnchecked = uncheckedX;
            }
            if(disabledChecked == null) {
                disabledChecked = checkedX;
            }
            chkBoxImages = new Image[]{uncheckedX, checkedX, disabledUnchecked, disabledChecked};
        }
    }

    /**
     * Sets images for checkbox when in focused mode
     *
     * @param checkedX the image to draw in order to represent a checked checkbox
     * @param uncheckedX the image to draw in order to represent an uncheck checkbox
     * @param disabledChecked same as checked for the disabled state
     * @param disabledUnchecked same as unchecked for the disabled state
     */
    public void setCheckBoxFocusImages(Image checkedX, Image uncheckedX, Image disabledChecked, Image disabledUnchecked) {
        if (checkedX == null || uncheckedX == null) {
            chkBoxImagesFocus = null;
        } else {
            if(disabledUnchecked == null) {
                disabledUnchecked = uncheckedX;
            }
            if(disabledChecked == null) {
                disabledChecked = checkedX;
            }
            chkBoxImagesFocus = new Image[]{uncheckedX, checkedX, disabledUnchecked, disabledChecked};
        }
    }

    /**
     * Sets image for the combo box dropdown drawing
     * 
     * @param picker picker image
     */
    public void setComboBoxImage(Image picker) {
        comboImage = picker;
    }

    /**
     * Sets images for radio button selected/unselected modes
     * 
     * @param selected the image to draw in order to represent a selected radio button
     * @param unselected the image to draw in order to represent an unselected radio button
     */
    public void setRadioButtonImages(Image selected, Image unselected) {
        if (selected == null || unselected == null) {
            rButtonImages = null;
        } else {
            rButtonImages = new Image[]{unselected, selected};
        }
    }

    /**
     * Sets images for radio button selected/unselected modes
     *
     * @param selected the image to draw in order to represent a selected radio button
     * @param unselected the image to draw in order to represent an unselected radio button
     * @param disabledSelected same as selected for the disabled state
     * @param disabledUnselected same as unselected for the disabled state
     */
    public void setRadioButtonImages(Image selected, Image unselected, Image disabledSelected, Image disabledUnselected) {
        if (selected == null || unselected == null) {
            rButtonImages = null;
        } else {
            if(disabledUnselected == null) {
                disabledUnselected = unselected;
            }
            if(disabledSelected == null) {
                disabledSelected = selected;
            }
            rButtonImages = new Image[]{unselected, selected, disabledUnselected, disabledSelected};
        }
    }

    /**
     * Sets images for radio button selected/unselected and disabled modes, when the radio button has focus, these are entirely optional
     *
     * @param selected the image to draw in order to represent a selected radio button
     * @param unselected the image to draw in order to represent an unselected radio button
     * @param disabledSelected same as selected for the disabled state
     * @param disabledUnselected same as unselected for the disabled state
     */
    public void setRadioButtonFocusImages(Image selected, Image unselected, Image disabledSelected, Image disabledUnselected) {
        if (selected == null || unselected == null) {
            rButtonImagesFocus = null;
        } else {
            if(disabledUnselected == null) {
                disabledUnselected = unselected;
            }
            if(disabledSelected == null) {
                disabledSelected = selected;
            }
            rButtonImagesFocus = new Image[]{unselected, selected, disabledUnselected, disabledSelected};
        }
    }
    
    /**
     * Sets the password character to display in the TextArea and the TextField
     * @param the char to display
     */ 
    public void setPasswordChar(char c){
        passwordChar = c;
    }

    /**
     * Returns the images used to represent the radio button (selected followed by unselected).
     * 
     * @return images representing the radio button or null for using the default drawing
     */
    public Image[] getRadioButtonImages() {
        return rButtonImages;
    }

    /**
     * Returns the images used to represent the radio button when in focused mode
     *
     * @return images representing the radio button or null for using the default drawing
     */
    public Image[] getRadioButtonFocusImages() {
        return rButtonImagesFocus;
    }

    /**
     * Returns the images used to represent the checkbox (selected followed by unselected).
     *
     * @return images representing the check box or null for using the default drawing
     */
    public Image[] getCheckBoxImages() {
        return chkBoxImages;
    }

    /**
     * Returns the images used to represent the checkbox when focused
     *
     * @return images representing the check box or null for using the default drawing
     */
    public Image[] getCheckBoxFocusImages() {
        return chkBoxImagesFocus;
    }

    /**
     * {@inheritDoc}
     * @deprecated this method is no longer used by the implementation, we shifted code away to improve performance
     */
    public void drawButton(Graphics g, Button b) {
        drawComponent(g, b, b.getIconFromState(), null, 0);
    }

    /**
     * {@inheritDoc}
     */
    public void drawCheckBox(Graphics g, Button cb) {
        if (chkBoxImages != null) {
            Image x;
            if(chkBoxImagesFocus != null && chkBoxImagesFocus[0] != null && cb.hasFocus() && Display.getInstance().shouldRenderSelection(cb)) {
                if(cb.isEnabled()) {
                    x = chkBoxImagesFocus[cb.isSelected() ? 1 : 0];
                } else {
                    x = chkBoxImagesFocus[cb.isSelected() ? 3 : 2];
                }
            } else {
                if(cb.isEnabled()) {
                    x = chkBoxImages[cb.isSelected() ? 1 : 0];
                } else {
                    x = chkBoxImages[cb.isSelected() ? 3 : 2];
                }
            }
            drawComponent(g, cb, cb.getIconFromState(), x, 0);
        } else {
            Style style = cb.getStyle();

            // checkbox square needs to be the height and width of the font height even
            // when no text is in the check box this is a good indication of phone DPI
            int height = cb.getStyle().getFont().getHeight();

            drawComponent(g, cb, cb.getIconFromState(), null, height);

            int gradientColor;
            g.setColor(style.getFgColor());

            gradientColor = style.getBgColor();

            int width = height;

            int rectWidth = scaleCoordinate(12f, 16, width);
            int tX = cb.getX();
            if (cb.isRTL()) {
            	tX = tX + cb.getWidth() - style.getPaddingLeft(cb.isRTL()) - rectWidth;
            } else {
            	tX += style.getPaddingLeft(cb.isRTL());
            }

            int tY = cb.getY() + style.getPaddingTop() + (cb.getHeight() - style.getPaddingTop() - style.getPaddingBottom()) / 2 - height / 2;
            g.translate(tX, tY);
            int x = scaleCoordinate(1.04f, 16, width);
            int y = scaleCoordinate(4.0f, 16, height);
            int rectHeight = scaleCoordinate(12f, 16, height);

            // brighten or darken the color slightly
            int destColor = findDestColor(gradientColor);

            g.fillLinearGradient(gradientColor, destColor, x + 1, y + 1, rectWidth - 2, rectHeight - 1, false);
            int alpha = g.concatenateAlpha(style.getFgAlpha());
            g.drawRoundRect(x, y, rectWidth, rectHeight, 5, 5);
            g.setAlpha(alpha);
            if (cb.isSelected()) {
                int color = g.getColor();
                g.setColor(0x111111);
                g.translate(0, 1);
                fillCheckbox(g, width, height);
                g.setColor(color);
                g.translate(0, -1);
                fillCheckbox(g, width, height);
            }
            g.translate(-tX, -tY);
        }
    }

    private static void fillCheckbox(Graphics g, int width, int height) {
        int x1 = scaleCoordinate(2.0450495f, 16, width);
        int y1 = scaleCoordinate(9.4227722f, 16, height);
        int x2 = scaleCoordinate(5.8675725f, 16, width);
        int y2 = scaleCoordinate(13.921746f, 16, height);
        int x3 = scaleCoordinate(5.8675725f, 16, width);
        int y3 = scaleCoordinate(11f, 16, height);
        g.fillTriangle(x1, y1, x2, y2, x3, y3);

        x1 = scaleCoordinate(14.38995f, 16, width);
        y1 = scaleCoordinate(0, 16, height);
        g.fillTriangle(x1, y1, x2, y2, x3, y3);
    }

    private static int round(float x) {
        int rounded = (int) x;
        if (x - rounded > 0.5f) {
            return rounded + 1;
        }
        return rounded;
    }

    /**
     * Takes a floating point coordinate on a virtual axis and rusterizes it to 
     * a coordinate in the pixel surface. This is a very simple algorithm since
     * anti-aliasing isn't supported.
     * 
     * @param coordinate a position in a theoretical plain
     * @param plain the amount of space in the theoretical plain
     * @param pixelSize the amount of pixels available on the screen
     * @return the pixel which we should color
     */
    private static int scaleCoordinate(float coordinate, float plain, int pixelSize) {
        return round(coordinate / plain * pixelSize);
    }

    /**
     * {@inheritDoc}
     * @deprecated this method is no longer used by the implementation, we shifted code away to improve performance
     */
    public void drawLabel(Graphics g, Label l) {
        drawComponent(g, l, l.getMaskedIcon(), null, 0);
    }
    
    public Span calculateLabelSpan(TextSelection sel, Label l) {
        Image icon = l.getMaskedIcon();
        Image stateIcon = null;
        int preserveSpaceForState = 0;
        //setFG(g, l);

        int gap = l.getGap();
        int stateIconSize = 0;
        int stateIconYPosition = 0;
        String text = l.getText();
        Style style = l.getStyle();
        int cmpX = l.getX();
        int cmpY = l.getY();
        int cmpHeight = l.getHeight();
        int cmpWidth = l.getWidth();

        boolean rtl = l.isRTL();
        int leftPadding = style.getPaddingLeft(rtl);
        int rightPadding = style.getPaddingRight(rtl);
        int topPadding = style.getPaddingTop();
        int bottomPadding = style.getPaddingBottom();
        
        Font font = style.getFont();
        int fontHeight = 0;
        if (text == null) {
            text = "";
        }
        if(text.length() > 0){
            fontHeight = font.getHeight();
        }
        
        int x = cmpX + leftPadding;
        int y = cmpY + topPadding;
        boolean opposite = false;
        if (stateIcon != null) {
            stateIconSize = stateIcon.getWidth(); //square image width == height
            preserveSpaceForState = stateIconSize + gap;
            stateIconYPosition = cmpY + topPadding
                    + (cmpHeight - topPadding
                    - bottomPadding) / 2 - stateIconSize / 2;
            int tX = cmpX;
            if (((Button) l).isOppositeSide()) {
                if (rtl) {
                    tX += leftPadding;
                } else {
                    tX = tX + cmpWidth - leftPadding - stateIconSize;
                }
                cmpWidth -= leftPadding - stateIconSize;
                preserveSpaceForState = 0;
                opposite = true;
            } else {
                x = cmpX + leftPadding + preserveSpaceForState;
                if (rtl) {
                    tX = tX + cmpWidth - leftPadding - stateIconSize;
                } else {
                    tX += leftPadding;
                }
            }

            //g.drawImage(stateIcon, tX, stateIconYPosition);
        }

        //default for bottom left alignment
        int align = reverseAlignForBidi(l, style.getAlignment());

        int textPos= reverseAlignForBidi(l, l.getTextPosition());

        //set initial x,y position according to the alignment and textPosition
        if (align == Component.LEFT) {
            switch (textPos) {
                case Label.LEFT:
                case Label.RIGHT:
                    y = y + (cmpHeight - (topPadding + bottomPadding + Math.max(((icon != null) ? icon.getHeight() : 0), fontHeight))) / 2;
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    y = y + (cmpHeight - (topPadding + bottomPadding + ((icon != null) ? icon.getHeight() + gap : 0) + fontHeight)) / 2;
                    break;
            }
        } else if (align == Component.CENTER) {
            switch (textPos) {
                case Label.LEFT:
                case Label.RIGHT:
                    x = x + (cmpWidth - (preserveSpaceForState +
                            leftPadding +
                            rightPadding +
                            ((icon != null) ? icon.getWidth() + l.getGap() : 0) +
                            l.getStringWidth(font))) / 2;
                    if(!opposite){
                        x = Math.max(x, cmpX + leftPadding + preserveSpaceForState);
                    }else{
                        x = Math.min(x, cmpX + leftPadding + preserveSpaceForState);                    
                    }
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            Math.max(((icon != null) ? icon.getHeight() : 0),
                            fontHeight))) / 2;
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    x = x + (cmpWidth - (preserveSpaceForState + leftPadding +
                            rightPadding +
                            Math.max(((icon != null) ? icon.getWidth() : 0),
                            l.getStringWidth(font)))) / 2;
                    if(!opposite){
                        x = Math.max(x, cmpX + leftPadding + preserveSpaceForState);
                    }else{
                        x = Math.min(x, cmpX + leftPadding + preserveSpaceForState);                    
                    }
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            ((icon != null) ? icon.getHeight() + gap : 0) +
                            fontHeight)) / 2;
                    break;
            }
        } else if (align == Component.RIGHT) {
            switch (textPos) {
                case Label.LEFT:
                case Label.RIGHT:
                    x = cmpX + cmpWidth - rightPadding -
                            ( ((icon != null) ? (icon.getWidth() + gap) : 0) +
                            l.getStringWidth(font));
                    if(l.isRTL()) {
                        if(!opposite){
                            x = Math.max(x - preserveSpaceForState, cmpX + leftPadding);
                        }else{
                            x = Math.min(x - preserveSpaceForState, cmpX + leftPadding);                        
                        }
                    } else {
                        if(!opposite){
                            x = Math.max(x, cmpX + leftPadding + preserveSpaceForState);
                        }else{
                            x = Math.min(x, cmpX + leftPadding + preserveSpaceForState);                        
                        }
                    }
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            Math.max(((icon != null) ? icon.getHeight() : 0),
                            fontHeight))) / 2;
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    x = cmpX + cmpWidth - rightPadding -
                             (Math.max(((icon != null) ? (icon.getWidth()) : 0),
                            l.getStringWidth(font)));
                    if(!opposite){
                        x = Math.max(x, cmpX + leftPadding + preserveSpaceForState);
                    }else{
                        x = Math.min(x, cmpX + leftPadding + preserveSpaceForState);                    
                    }
                    
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            ((icon != null) ? icon.getHeight() + gap : 0) + fontHeight)) / 2;
                    break;
            }
        }


        int textSpaceW = cmpWidth - rightPadding - leftPadding;

        if (icon != null && (textPos == Label.RIGHT || textPos == Label.LEFT)) {
            textSpaceW = textSpaceW - icon.getWidth();
        }

        if (stateIcon != null) {
            textSpaceW = textSpaceW - stateIconSize;
        } else {
            textSpaceW = textSpaceW - preserveSpaceForState;
        }

        if (icon == null) { // no icon only string 
            return calculateSpanForLabelString(sel, l, text, x, y, textSpaceW);
        } else {
            int strWidth = l.getStringWidth(font);
            int iconWidth = icon.getWidth();
            int iconHeight = icon.getHeight();
            int iconStringWGap;
            int iconStringHGap;

            switch (textPos) {
                case Label.LEFT:
                    if (iconHeight > fontHeight) {
                        iconStringHGap = (iconHeight - fontHeight) / 2;
                        return calculateSpanForLabelStringValign(sel, l, text, x, y, iconStringHGap, iconHeight, textSpaceW, fontHeight);
                    } else {
                        iconStringHGap = (fontHeight - iconHeight) / 2;
                        //strWidth = drawLabelString(l, text, x, y, textSpaceW);
                        return calculateSpanForLabelString(sel, l, text, x, y, textSpaceW);
                        //g.drawImage(icon, x + strWidth + gap, y + iconStringHGap);
                    }

                case Label.RIGHT:
                    if (iconHeight > fontHeight) {
                        iconStringHGap = (iconHeight - fontHeight) / 2;
                        //g.drawImage(icon, x, y);
                        return calculateSpanForLabelStringValign(sel, l, text, x + iconWidth + gap, y, iconStringHGap, iconHeight, textSpaceW, fontHeight);
                    } else {
                        iconStringHGap = (fontHeight - iconHeight) / 2;
                        //g.drawImage(icon, x, y + iconStringHGap);
                        return calculateSpanForLabelString(sel, l, text, x + iconWidth + gap, y, textSpaceW);
                    }

                case Label.BOTTOM:
                    if (iconWidth > strWidth) { //center align the smaller

                        iconStringWGap = (iconWidth - strWidth) / 2;
                        //g.drawImage(icon, x, y);
                        return calculateSpanForLabelString(sel, l, text, x + iconStringWGap, y + iconHeight + gap, textSpaceW);
                    } else {
                        iconStringWGap = (Math.min(strWidth, textSpaceW) - iconWidth) / 2;
                        //g.drawImage(icon, x + iconStringWGap, y);
                        
                        return calculateSpanForLabelString(sel, l, text, x, y + iconHeight + gap, textSpaceW);
                    }

                case Label.TOP:
                    if (iconWidth > strWidth) { //center align the smaller

                        iconStringWGap = (iconWidth - strWidth) / 2;
                        return calculateSpanForLabelString(sel, l, text, x + iconStringWGap, y, textSpaceW);
                        //g.drawImage(icon, x, y + fontHeight + gap);
                    } else {
                        iconStringWGap = (Math.min(strWidth, textSpaceW) - iconWidth) / 2;
                        return calculateSpanForLabelString(sel, l, text, x, y, textSpaceW);
                        //g.drawImage(icon, x + iconStringWGap, y + fontHeight + gap);
                    }

            }
        }
        return sel.newSpan(l);
    }

    /**
     * {@inheritDoc}
     */
    public void drawRadioButton(Graphics g, Button rb) {
        if (rButtonImages != null) {
            Image x;
            if(rButtonImagesFocus != null && rButtonImagesFocus[0] != null && rb.hasFocus() && Display.getInstance().shouldRenderSelection(rb)) {
                if(rb.isEnabled()) {
                    x = rButtonImagesFocus[rb.isSelected() ? 1 : 0];
                } else {
                    x = rButtonImagesFocus[rb.isSelected() ? 3 : 2];
                }
            } else {
                if(rb.isEnabled()) {
                    x = rButtonImages[rb.isSelected() ? 1 : 0];
                } else {
                    x = rButtonImages[rb.isSelected() ? 3 : 2];
                }
            }
            drawComponent(g, rb, rb.getIconFromState(), x, 0);
        } else {
            Style style = rb.getStyle();

            // radio button radius needs to be of the size of the font height even
            // when no text is in the radio button this is a good indication of phone DPI
            int height = rb.getStyle().getFont().getHeight();

            drawComponent(g, rb, rb.getIconFromState(), null, height + rb.getGap());
            g.setColor(style.getFgColor());
            int x = rb.getX();
            if (rb.isRTL()) {
            	x = x + rb.getWidth() - style.getPaddingLeft(rb.isRTL()) - height;
            } else {
            	x += style.getPaddingLeft(rb.isRTL());
            }

            int y = rb.getY();

            // center the RadioButton
            y += Math.max(0, rb.getHeight() / 2 - height / 2);
            int alpha = g.concatenateAlpha(style.getFgAlpha());
            g.drawArc(x, y, height, height, 0, 360);
            g.setAlpha(alpha);
            if (rb.isSelected()) {
                int color = g.getColor();
                int destColor = findDestColor(color);
                g.fillRadialGradient(color, destColor, x + 3, y + 3, height - 5, height - 5);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void drawComboBox(Graphics g, List cb) {
        int border = 2;
        Style style = cb.getStyle();
        int leftPadding = style.getPaddingLeft(cb.isRTL());
        int rightPadding = style.getPaddingRight(cb.isRTL());

        setFG(g, cb);

        ListModel model = cb.getModel();
        ListCellRenderer renderer = cb.getRenderer();
        Object value = model.getItemAt(model.getSelectedIndex());
        Image comboBoxImage = ((ComboBox)cb).getComboBoxImage() != null ? ((ComboBox)cb).getComboBoxImage() : comboImage;                
        int comboImageWidth;
        if (comboBoxImage != null) {
            comboImageWidth = comboBoxImage.getWidth();
        } else {
            comboImageWidth = style.getFont().getHeight();
        }
        
        int cellX = cb.getX() + style.getPaddingTop();
        if(cb.isRTL()){
            cellX += comboImageWidth;
        }
        
        if (model.getSize() > 0) {
            Component cmp = renderer.getListCellRendererComponent(cb, value, model.getSelectedIndex(), cb.hasFocus());
            cmp.setX(cellX);
            cmp.setY(cb.getY() + style.getPaddingTop());
            cmp.setWidth(cb.getWidth() - comboImageWidth - rightPadding - leftPadding);
            cmp.setHeight(cb.getHeight() - style.getPaddingTop() - style.getPaddingBottom());
            cmp.paint(g);
        }

        g.setColor(style.getBgColor());
        int y = cb.getY();
        int height = cb.getHeight();
        int width = comboImageWidth + border;
        int x = cb.getX();
        if (cb.isRTL()) {
        	x += leftPadding;
        } else {
        	x += cb.getWidth() - comboImageWidth - rightPadding;
        }

        if (comboBoxImage != null) {
            g.drawImage(comboBoxImage, x, y + height / 2 - comboBoxImage.getHeight() / 2);
        } else {
            int color = g.getColor();

            // brighten or darken the color slightly
            int destColor = findDestColor(color);

            if (style.getBgTransparency() > 0) {
                g.fillLinearGradient(g.getColor(), destColor, x, y, width, height, false);
            }
            g.setColor(color);
            int alpha = g.concatenateAlpha(style.getFgAlpha());
            g.drawRect(x, y, width, height - 1);
            g.setAlpha(alpha);
            width--;
            height--;

            //g.drawRect(x, y, width, height);
            g.translate(x + 1, y + 1);
            g.setColor(0x111111);
            int x1 = scaleCoordinate(2.5652081f, 16, width);
            int y1 = scaleCoordinate(4.4753664f, 16, height);
            int x2 = scaleCoordinate(8.2872691f, 16, width);
            int y2 = scaleCoordinate(10f, 16, height);
            int x3 = scaleCoordinate(13.516078f, 16, width);
            int y3 = y1;
            g.fillTriangle(x1, y1, x2, y2, x3, y3);
            g.translate(-1, -1);
            g.setColor(style.getFgColor());
            alpha = g.concatenateAlpha(style.getFgAlpha());
            g.fillTriangle(x1, y1, x2, y2, x3, y3);
            g.setAlpha(alpha);
            g.translate(-x, -y);
        }

    }

    /**
     * Finds a suitable destination color for gradient values
     */
    private int findDestColor(int color) {
        // brighten or darken the color slightly
        int sourceR = color >> 16 & 0xff;
        int sourceG = color >> 8 & 0xff;
        int sourceB = color & 0xff;
        if (sourceR > 128 && sourceG > 128 && sourceB > 128) {
            // darken
            sourceR = Math.max(sourceR >> 1, 0);
            sourceG = Math.max(sourceG >> 1, 0);
            sourceB = Math.max(sourceB >> 1, 0);
        } else {
            // special case for black, since all channels are 0 it can't be brightened properly...
            if(color == 0) {
                return 0x222222;
            }
            
            // brighten
            sourceR = Math.min(sourceR << 1, 0xff);
            sourceG = Math.min(sourceG << 1, 0xff);
            sourceB = Math.min(sourceB << 1, 0xff);
        }
        return ((sourceR << 16) & 0xff0000) | ((sourceG << 8) & 0xff00) | (sourceB & 0xff);
    }

    /**
     * {@inheritDoc}
     */
    public void drawList(Graphics g, List l) {
    }
    
    private int getSelectionHeight(Font f) {
        return f.getHeight() + (int)(f.getHeight() * 0.2);
        //return f.getHeight() + f.getDescent();
    }
    
    private void append(TextSelection sel, Component l, Span span, String text, Font f, int posOffset, int x, int y, int h) {
        int len = text.length();
        int xPos = 0;
        int curPos = 1;
        //int h = f.getHeight() + (int)(f.getHeight() * 0.25);
        //y -= (int)(f.getHeight() * 0.25);
        //int tx = l.getAbsoluteX() - sel.getSelectionRoot().getAbsoluteX() - l.getX();
        //int ty = l.getAbsoluteY() - sel.getSelectionRoot().getAbsoluteY() - l.getY();
        while (curPos <= len) {
            int newXpos = f.stringWidth(text.substring(0, curPos));
            Char next = sel.newChar(posOffset + curPos-1, x + xPos, y, newXpos - xPos, h);
            span.add(next);
            xPos = newXpos;
            curPos++;
        }
    }

    @Override
    public Spans calculateTextAreaSpan(TextSelection sel, TextArea ta) {
        Spans out = sel.newSpans();
        //setFG(g, ta);
        //Span out = sel.newSpan(ta);
        int line = ta.getLines();
        //int oX = g.getClipX();
        //int oY = g.getClipY();
        //int oWidth = g.getClipWidth();
        //int oHeight = g.getClipHeight();
        Font f = ta.getStyle().getFont();
        int fontHeight = f.getHeight();

        int align = reverseAlignForBidi(ta);

        int leftPadding = ta.getStyle().getPaddingLeft(ta.isRTL());
        int rightPadding = ta.getStyle().getPaddingRight(ta.isRTL());
        int topPadding = ta.getStyle().getPaddingTop();
        switch (ta.getVerticalAlignment()) {
            case Component.CENTER :
                topPadding += Math.max(0, (ta.getInnerHeight() - (ta.getRowsGap() + fontHeight) * line)/2);
                break;
            case Component.BOTTOM :
                topPadding += Math.max(0, (ta.getInnerHeight() - (ta.getRowsGap() + fontHeight) * line));
        }
        //boolean shouldBreak = false;
        int posOffset = 0;
        int lastRowBottom = 0;
        for (int i = 0; i < line; i++) {
            Span rowSpan = sel.newSpan(ta);
            int x = ta.getX() + leftPadding;
            int y = ta.getY() +  topPadding +
                    (ta.getRowsGap() + fontHeight) * i;
            int adjustedY = Math.max(y, lastRowBottom);
            int yDiff = adjustedY - y;
            y = adjustedY;
            
            //if(Rectangle.intersects(x, y, ta.getWidth(), fontHeight, oX, oY, oWidth, oHeight)) {
                
                String rowText = (String) ta.getTextAt(i);
                //display ******** if it is a password field
                String displayText = "";
                if ((ta.getConstraint() & TextArea.PASSWORD) != 0) {
                    int rlen = rowText.length();
                    for (int j = 0; j < rlen; j++) {
                        displayText += passwordChar;
                    }
                } else {
                    displayText = rowText;
                }
                posOffset = ta.getText().indexOf(rowText, posOffset);
                switch(align) {
                    case Component.RIGHT:
                		x = ta.getX() + ta.getWidth() - rightPadding - f.stringWidth(displayText);
                        break;
                    case Component.CENTER:
                        x+= (ta.getWidth()-leftPadding-rightPadding-f.stringWidth(displayText))/2;
                        break;
                }
                //int nextY = ta.getY() +  topPadding + (ta.getRowsGap() + fontHeight) * (i + 2);
                //if this is the last line to display and there is more content and isEndsWith3Points() is true
                //add "..." at the last row
                if(ta.isEndsWith3Points() && ta.getGrowLimit() == (i + 1) && ta.getGrowLimit() != line){
                    if(displayText.length() > 3){
                        displayText = displayText.substring(0, displayText.length() - 3);
                    }
                    //g.drawString(displayText + "...", x, y ,ta.getStyle().getTextDecoration()); 
                    append(sel, ta, rowSpan, displayText + "...", f, posOffset, x, y, getSelectionHeight(f) - yDiff);
                    lastRowBottom = rowSpan.getBounds().getY() + rowSpan.getBounds().getHeight();
                    rowSpan = rowSpan.translate(ta.getAbsoluteX() - sel.getSelectionRoot().getAbsoluteX() - ta.getX(), ta.getAbsoluteY() - sel.getSelectionRoot().getAbsoluteY() - ta.getY());
                    out.add(rowSpan);
                    return out;
                }else{            
                    //g.drawString(displayText, x, y ,ta.getStyle().getTextDecoration());
                    append(sel, ta, rowSpan, displayText, f, posOffset, x, y, getSelectionHeight(f) - yDiff);
                    lastRowBottom = rowSpan.getBounds().getY() + rowSpan.getBounds().getHeight();
                    rowSpan = rowSpan.translate(ta.getAbsoluteX() - sel.getSelectionRoot().getAbsoluteX() - ta.getX(), ta.getAbsoluteY() - sel.getSelectionRoot().getAbsoluteY() - ta.getY());
                    out.add(rowSpan);
                }
                posOffset += displayText.length();
                //shouldBreak = true;
            //}else{
            //    if(shouldBreak){
            //        break;
            //    }
            //}
        }
        return out;
    }
    
    /**
     * {@inheritDoc}
     */
    public void drawTextArea(Graphics g, TextArea ta) {
        setFG(g, ta);
        int alpha = g.concatenateAlpha(ta.getStyle().getFgAlpha());

        int line = ta.getLines();
        int oX = g.getClipX();
        int oY = g.getClipY();
        int oWidth = g.getClipWidth();
        int oHeight = g.getClipHeight();
        Font f = ta.getStyle().getFont();
        int fontHeight = f.getHeight();

        int align = reverseAlignForBidi(ta);

        int leftPadding = ta.getStyle().getPaddingLeft(ta.isRTL());
        int rightPadding = ta.getStyle().getPaddingRight(ta.isRTL());
        int topPadding = ta.getStyle().getPaddingTop();
        switch (ta.getVerticalAlignment()) {
            case Component.CENTER :
                topPadding += Math.max(0, (ta.getInnerHeight() - ta.getRowsGap()*(line-1) - fontHeight* line)/2);
                break;
            case Component.BOTTOM :
                topPadding += Math.max(0, (ta.getInnerHeight() - ta.getRowsGap()*(line-1) - fontHeight* line));
        }
        boolean shouldBreak = false;
        
        for (int i = 0; i < line; i++) {
            int x = ta.getX() + leftPadding;
            int y = ta.getY() +  topPadding +
                    (ta.getRowsGap() + fontHeight) * i;
            if(Rectangle.intersects(x, y, ta.getWidth(), fontHeight, oX, oY, oWidth, oHeight)) {
                
                String rowText = (String) ta.getTextAt(i);
                //display ******** if it is a password field
                String displayText = "";
                if ((ta.getConstraint() & TextArea.PASSWORD) != 0) {
                    int rlen = rowText.length();
                    for (int j = 0; j < rlen; j++) {
                        displayText += passwordChar;
                    }
                } else {
                    displayText = rowText;
                }

                switch(align) {
                    case Component.RIGHT:
                		x = ta.getX() + ta.getWidth() - rightPadding - f.stringWidth(displayText);
                        break;
                    case Component.CENTER:
                        x+= (ta.getWidth()-leftPadding-rightPadding-f.stringWidth(displayText))/2;
                        break;
                }
                int nextY = ta.getY() +  topPadding + (ta.getRowsGap() + fontHeight) * (i + 2);
                //if this is the last line to display and there is more content and isEndsWith3Points() is true
                //add "..." at the last row
                if(ta.isEndsWith3Points() && ta.getGrowLimit() == (i + 1) && ta.getGrowLimit() != line){
                    if(displayText.length() > 3){
                        displayText = displayText.substring(0, displayText.length() - 3);
                    }
                    g.drawString(displayText + "...", x, y ,ta.getStyle().getTextDecoration());                
                    return;
                }else{            
                    g.drawString(displayText, x, y ,ta.getStyle().getTextDecoration());
                }
                shouldBreak = true;
            }else{
                if(shouldBreak){
                    break;
                }
            }
        }
        g.setAlpha(alpha);
    }

    private static final Image[] threeImageCache = new Image[3];
    /**
     * {@inheritDoc}
     */
    public Dimension getButtonPreferredSize(Button b) {
        threeImageCache[0] = b.getMaskedIcon();
        threeImageCache[1] = b.getRolloverIcon();
        threeImageCache[2] = b.getPressedIcon();
        return getPreferredSize(b, threeImageCache, null);
    }

    /**
     * {@inheritDoc}
     */
    public Dimension getCheckBoxPreferredSize(Button cb) {
        if(cb.isToggle()) {
            return getButtonPreferredSize(cb);
        }
        threeImageCache[0] = cb.getMaskedIcon();
        threeImageCache[1] = cb.getRolloverIcon();
        threeImageCache[2] = cb.getPressedIcon();
        if (chkBoxImages != null) {
            return getPreferredSize(cb, threeImageCache, chkBoxImages[0]);
        }
        Dimension d = getPreferredSize(cb, threeImageCache, null);

        // checkbox square needs to be the height and width of the font height even
        // when no text is in the check box this is a good indication of phone DPI
        int checkBoxSquareSize = cb.getStyle().getFont().getHeight();

        // allow for checkboxes without a string within them
        d.setHeight(Math.max(checkBoxSquareSize, d.getHeight()));

        d.setWidth(d.getWidth() + checkBoxSquareSize + cb.getGap());
        return d;
    }

    private static final Image[] oneImageCache = new Image[1];
    
    /**
     * {@inheritDoc}
     */
    public Dimension getLabelPreferredSize(Label l) {
        oneImageCache[0] = l.getMaskedIcon();
        return getPreferredSize(l, oneImageCache, null);
    }

    /**
     * {@inheritDoc}
     */
    private Dimension getPreferredSize(Label l, Image[] icons, Image stateImage) {
        int prefW = 0;
        int prefH = 0;

        Style style = l.getStyle();
        int gap = l.getGap();
        int ilen = icons.length;
        for (int i = 0; i < ilen; i++) {
            Image icon = icons[i];
            if (icon != null) {
                prefW = Math.max(prefW, icon.getWidth());
                prefH = Math.max(prefH, icon.getHeight());
            }
        }
        String text = l.getText();
        Font font = style.getFont();
        if (font == null) {
            System.out.println("Missing font for " + l);
            font = Font.getDefaultFont();
        }
        if (text != null && text.length() > 0) {
            //add the text size
            switch (l.getTextPosition()) {
                case Label.LEFT:
                case Label.RIGHT:
                    prefW += font.stringWidth(text);
                    prefH = Math.max(prefH, font.getHeight());
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    prefW = Math.max(prefW, font.stringWidth(text));
                    prefH += font.getHeight();
                    break;
            }
        }
        //add the state image(relevant for CheckBox\RadioButton)
        if (stateImage != null) {
            prefW += (stateImage.getWidth() + gap);
            prefH = Math.max(prefH, stateImage.getHeight());
        }


        if (icons[0] != null && text != null && text.length() > 0) {
            switch (l.getTextPosition()) {
                case Label.LEFT:
                case Label.RIGHT:
                    prefW += gap;
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    prefH += gap;
                    break;
            }
        }

        if(l.isShowEvenIfBlank()) {
            prefH += style.getVerticalPadding();
            prefW += style.getHorizontalPadding();
        } else {
            if (prefH != 0) {
                prefH += style.getVerticalPadding();
            }
            if (prefW != 0) {
                prefW += style.getHorizontalPadding();
            }
        }

        if(style.getBorder() != null) {
            prefW = Math.max(style.getBorder().getMinimumWidth(), prefW);
            prefH = Math.max(style.getBorder().getMinimumHeight(), prefH);
        } 
        if(isBackgroundImageDetermineSize() && style.getBgImage() != null) {
            prefW = Math.max(style.getBgImage().getWidth(), prefW);
            prefH = Math.max(style.getBgImage().getHeight(), prefH);
        }

        return new Dimension(prefW, prefH);
    }

    /**
     * {@inheritDoc}
     */
    public Dimension getListPreferredSize(List l) {
        Dimension d = getListPreferredSizeImpl(l);
        Style style = l.getStyle();
        if(style.getBorder() != null) {
            d.setWidth(Math.max(style.getBorder().getMinimumWidth(), d.getWidth()));
            d.setHeight(Math.max(style.getBorder().getMinimumHeight(), d.getHeight()));
        }
        return d;
    }

    private Dimension getListPreferredSizeImpl(List l) {
        int width = 0;
        int height = 0;
        int selectedHeight;
        int selectedWidth;
        ListModel model = l.getModel();
        int numOfcomponents = Math.max(model.getSize(), l.getMinElementHeight());
        numOfcomponents = Math.min(numOfcomponents, l.getMaxElementHeight());
        Object prototype = l.getRenderingPrototype();

        Style unselectedEntryStyle = null;
        Style selectedEntryStyle;
        if(prototype != null) {
            ListCellRenderer renderer = l.getRenderer();
            Component cmp = renderer.getListCellRendererComponent(l, prototype, 0, false);
            height = cmp.getPreferredH();
            width = cmp.getPreferredW();
            unselectedEntryStyle = cmp.getStyle();
            cmp = renderer.getListCellRendererComponent(l, prototype, 0, true);

            selectedEntryStyle = cmp.getStyle();
            selectedHeight = Math.max(height, cmp.getPreferredH());
            selectedWidth = Math.max(width, cmp.getPreferredW());
        } else {
            int hightCalcComponents = Math.min(l.getListSizeCalculationSampleCount(), numOfcomponents);
            Object dummyProto = l.getRenderingPrototype();
            if(model.getSize() > 0 && dummyProto == null) {
                dummyProto = model.getItemAt(0);
            }
            ListCellRenderer renderer = l.getRenderer();
            for (int i = 0; i < hightCalcComponents; i++) {
                Object value;
                if(i < model.getSize()) {
                    value = model.getItemAt(i);
                } else {
                    value = dummyProto;
                }
                Component cmp = renderer.getListCellRendererComponent(l, value, i, false);
                if(cmp instanceof Container) {
                    cmp.setShouldCalcPreferredSize(true);
                }
                unselectedEntryStyle = cmp.getStyle();

                height = Math.max(height, cmp.getPreferredH());
                width = Math.max(width, cmp.getPreferredW());
            }
            selectedEntryStyle = unselectedEntryStyle;
            selectedHeight = height;
            selectedWidth = width;
            if (model.getSize() > 0) {
                Object value = model.getItemAt(0);
                Component cmp = renderer.getListCellRendererComponent(l, value, 0, true);
                if(cmp instanceof Container) {
                    cmp.setShouldCalcPreferredSize(true);
                }

                selectedHeight = Math.max(height, cmp.getPreferredH());
                selectedWidth = Math.max(width, cmp.getPreferredW());
                selectedEntryStyle = cmp.getStyle();
            }
        }
        if(unselectedEntryStyle != null) {
            selectedWidth += selectedEntryStyle.getMarginLeftNoRTL() + selectedEntryStyle.getMarginRightNoRTL();
            selectedHeight += selectedEntryStyle.getMarginTop() + selectedEntryStyle.getMarginBottom();
            width += unselectedEntryStyle.getMarginLeftNoRTL() + unselectedEntryStyle.getMarginRightNoRTL();
            height += unselectedEntryStyle.getMarginTop() + unselectedEntryStyle.getMarginBottom();
        }

        Style lStyle = l.getStyle();
        int verticalPadding = lStyle.getPaddingTop() + lStyle.getPaddingBottom();
        int horizontalPadding = lStyle.getPaddingRightNoRTL() + lStyle.getPaddingLeftNoRTL() + l.getSideGap();

        if (numOfcomponents == 0) {
            return new Dimension(horizontalPadding, verticalPadding);
        }

        // If combobox without ever importing the ComboBox class dependency
        if(l.getOrientation() > List.HORIZONTAL) {
            int boxWidth = l.getStyle().getFont().getHeight() + 2;
            return new Dimension(boxWidth + selectedWidth + horizontalPadding, selectedHeight + verticalPadding);
        } else {
            if (l.getOrientation() == List.VERTICAL) {
                return new Dimension(selectedWidth + horizontalPadding, selectedHeight + (height + l.getItemGap()) * (numOfcomponents - 1) + verticalPadding);
            } else {
                return new Dimension(selectedWidth + (width + l.getItemGap()) * (numOfcomponents - 1) + horizontalPadding, selectedHeight + verticalPadding);
            }
        }
    }
    
    /**
     * {@inheritDoc}
     */
    public Dimension getRadioButtonPreferredSize(Button rb) {
        if(rb.isToggle()) {
            return getButtonPreferredSize(rb);
        }
        threeImageCache[0] = rb.getMaskedIcon();
        threeImageCache[1] = rb.getRolloverIcon();
        threeImageCache[2] = rb.getPressedIcon();
        if (rButtonImages != null) {
            return getPreferredSize(rb, threeImageCache, rButtonImages[0]);
        }
        Dimension d = getPreferredSize(rb, threeImageCache, null);

        // radio button radius needs to be of the size of the font height even
        // when no text is in the radio button this is a good indication of phone DPI
        int height = rb.getStyle().getFont().getHeight();

        // allow for radio buttons without a string within them
        d.setHeight(Math.max(height, d.getHeight()));

        if(rButtonImages != null && rButtonImages.length > 0) {
            d.setWidth(rButtonImages[0].getWidth() + d.getWidth() + rb.getGap());
        } else {
            d.setWidth(d.getWidth() + height + rb.getGap());
        }
        return d;
    }

    /**
     * {@inheritDoc}
     */
    public Dimension getTextAreaSize(TextArea ta, boolean pref) {
        int prefW = 0;
        int prefH = 0;
        Style style = ta.getStyle();
        Font f = style.getFont();

        //if this is a text field the preferred size should be the text width
        if (ta.getRows() == 1) {
            prefW = f.stringWidth(ta.getText());
        } else {
            prefW = f.charWidth(TextArea.getWidestChar()) * ta.getColumns();
        }
        int rows;
        if(pref) {
            rows = ta.getActualRows();
        } else {
            rows = ta.getLines();
        }
        prefH = (f.getHeight() + ta.getRowsGap()) * rows;
        if(!ta.isActAsLabel()) {
            int columns = ta.getColumns();
            String str = "";
            for (int iter = 0; iter < columns; iter++) {
                str += TextArea.getWidestChar();
            }
            if(columns > 0) {
                prefW = Math.max(prefW, f.stringWidth(str));
            }
        }
        prefH = Math.max(prefH, rows * f.getHeight());

        prefW += style.getPaddingRightNoRTL() + style.getPaddingLeftNoRTL();
        prefH += style.getPaddingTop() + style.getPaddingBottom();
        if(style.getBorder() != null) {
            prefW = Math.max(style.getBorder().getMinimumWidth(), prefW);
            prefH = Math.max(style.getBorder().getMinimumHeight(), prefH);
        }
        if(isBackgroundImageDetermineSize() && style.getBgImage() != null) {
            prefW = Math.max(style.getBgImage().getWidth(), prefW);
            prefH = Math.max(style.getBgImage().getHeight(), prefH);
        }

        return new Dimension(prefW, prefH);
    }

    /**
     * Reverses alignment in the case of bidi
     */
    private int reverseAlignForBidi(Component c) {
        return reverseAlignForBidi(c, c.getStyle().getAlignment());
    }

    /**
     * Reverses alignment in the case of bidi
     */
    public static int reverseAlignForBidi(Component c, int align) {
        if(c.isRTL()) {
            switch(align) {
                case Component.RIGHT:
                    return Component.LEFT;
                case Component.LEFT:
                    return Component.RIGHT;
            }
        }
        return align;
    }

    private void drawComponent(Graphics g, Label l, Image icon, Image stateIcon, int preserveSpaceForState) {
        setFG(g, l);
        int alpha = g.concatenateAlpha(l.getStyle().getFgAlpha());
        int gap = l.getGap();
        int stateIconSize = 0;
        int stateIconYPosition = 0;
        String text = l.getText();
        Style style = l.getStyle();
        int cmpX = l.getX();
        int cmpY = l.getY();
        int cmpHeight = l.getHeight();
        int cmpWidth = l.getWidth();

        boolean rtl = l.isRTL();
        int leftPadding = style.getPaddingLeft(rtl);
        int rightPadding = style.getPaddingRight(rtl);
        int topPadding = style.getPaddingTop();
        int bottomPadding = style.getPaddingBottom();
        
        Font font = style.getFont();
        int fontHeight = 0;
        if (text == null) {
            text = "";
        }
        if(text.length() > 0){
            fontHeight = font.getHeight();
        }
        
        int x = cmpX + leftPadding;
        int y = cmpY + topPadding;
        boolean opposite = false;
        boolean stateButtonOnLeft = false;
        if (stateIcon != null) {
            stateIconSize = stateIcon.getWidth(); //square image width == height
            preserveSpaceForState = stateIconSize + gap;
            stateIconYPosition = cmpY + topPadding
                    + (cmpHeight - topPadding
                    - bottomPadding) / 2 - stateIconSize / 2;
            int tX = cmpX;
            if (((Button) l).isOppositeSide()) {
                if (rtl) {
                    tX += leftPadding;
                    stateButtonOnLeft = true;
                    x = cmpX + leftPadding + preserveSpaceForState;
                } else {
                    tX = tX + cmpWidth - leftPadding - stateIconSize;
                }
                //cmpWidth -= leftPadding - stateIconSize;
                //preserveSpaceForState = 0;
                opposite = true;
            } else {
                
                if (rtl) {
                    tX = tX + cmpWidth - leftPadding - stateIconSize;
                } else {
                    x = cmpX + leftPadding + preserveSpaceForState;
                    tX += leftPadding;
                    stateButtonOnLeft = true;
                }
            }

            g.drawImage(stateIcon, tX, stateIconYPosition);
        }

        //default for bottom left alignment
        int align = reverseAlignForBidi(l, style.getAlignment());

        int textPos= reverseAlignForBidi(l, l.getTextPosition());

        //set initial x,y position according to the alignment and textPosition
        if (align == Component.LEFT) {
            switch (textPos) {
                case Label.LEFT:
                case Label.RIGHT:
                    y = y + (cmpHeight - (topPadding + bottomPadding + Math.max(((icon != null) ? icon.getHeight() : 0), fontHeight))) / 2;
                    if (textPos == Label.RIGHT && stateIcon == null) {
                        x += preserveSpaceForState;
                    }
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    y = y + (cmpHeight - (topPadding + bottomPadding + ((icon != null) ? icon.getHeight() + gap : 0) + fontHeight)) / 2;
                    break;
            }
        } else if (align == Component.CENTER) {
            switch (textPos) {
                case Label.LEFT:
                case Label.RIGHT:
                    x = x + (cmpWidth - (preserveSpaceForState +
                            leftPadding +
                            rightPadding +
                            ((icon != null) ? icon.getWidth() + l.getGap() : 0) +
                            l.getStringWidth(font))) / 2;
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            Math.max(((icon != null) ? icon.getHeight() : 0),
                            fontHeight))) / 2;
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    x = x + (cmpWidth - (preserveSpaceForState + leftPadding +
                            rightPadding +
                            Math.max(((icon != null) ? icon.getWidth() + l.getGap() : 0),
                            l.getStringWidth(font)))) / 2;
                    if(!opposite){
                        x = Math.max(x, cmpX + leftPadding + preserveSpaceForState);
                    }else{
                        x = Math.min(x, cmpX + leftPadding + preserveSpaceForState);                    
                    }
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            ((icon != null) ? icon.getHeight() + gap : 0) +
                            fontHeight)) / 2;
                    break;
            }
        } else if (align == Component.RIGHT) {
            switch (textPos) {
                case Label.LEFT:
                case Label.RIGHT:
                    x = cmpX + cmpWidth - rightPadding -
                            ( ((icon != null) ? (icon.getWidth() + gap) : 0) +
                            l.getStringWidth(font));
                    x = stateButtonOnLeft ? x : x - preserveSpaceForState;

                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            Math.max(((icon != null) ? icon.getHeight() : 0),
                            fontHeight))) / 2;
                    break;
                case Label.BOTTOM:
                case Label.TOP:
                    x = cmpX + cmpWidth - rightPadding -
                             (Math.max(((icon != null) ? (icon.getWidth()) : 0),
                            l.getStringWidth(font)));
                    if(!opposite){
                        x = Math.max(x, cmpX + leftPadding + preserveSpaceForState);
                    }else{
                        x = Math.min(x, cmpX + leftPadding + preserveSpaceForState);                    
                    }
                    
                    y = y + (cmpHeight - (topPadding +
                            bottomPadding +
                            ((icon != null) ? icon.getHeight() + gap : 0) + fontHeight)) / 2;
                    break;
            }
        }


        int textSpaceW = cmpWidth - rightPadding - leftPadding;
        int textSpaceX = cmpX + leftPadding;
        

        if (icon != null && (textPos == Label.RIGHT || textPos == Label.LEFT)) {
            textSpaceW = textSpaceW - icon.getWidth();
            textSpaceX = (textPos == Label.RIGHT) ? textSpaceX + icon.getWidth() :
                    textSpaceX;
        }

        textSpaceW = textSpaceW - preserveSpaceForState;
        textSpaceX = stateButtonOnLeft ? textSpaceX + preserveSpaceForState : textSpaceX;

        if (icon == null) { // no icon only string 
            drawLabelString(g, l, text, x, y, textSpaceX, textSpaceW);
        } else {
            int strWidth = l.getStringWidth(font);
            int iconWidth = icon.getWidth();
            int iconHeight = icon.getHeight();
            int iconStringWGap;
            int iconStringHGap;

            switch (textPos) {
                case Label.LEFT:
                    if (iconHeight > fontHeight) {
                        iconStringHGap = (iconHeight - fontHeight) / 2;
                        strWidth = drawLabelStringValign(g, l, text, x, y, iconStringHGap, iconHeight, textSpaceX, textSpaceW, fontHeight);

                        g.drawImage(icon, x + strWidth + gap, y);
                    } else {
                        strWidth = drawLabelString(g, l, text, x, y, textSpaceX, textSpaceW);
                        drawLabelImageValign(g, l, icon, x + strWidth + gap, y, fontHeight, iconHeight);
                    }
                    break;
                case Label.RIGHT:
                    if (iconHeight > fontHeight) {
                        iconStringHGap = (iconHeight - fontHeight) / 2;
                        g.drawImage(icon, x, y);
                        drawLabelStringValign(g, l, text, x + iconWidth + gap, y, iconStringHGap, iconHeight, textSpaceX, textSpaceW, fontHeight);
                    } else {
                        drawLabelImageValign(g, l, icon, x, y, fontHeight, iconHeight);
                        drawLabelString(g, l, text, x + iconWidth + gap, y, textSpaceX, textSpaceW);
                    }
                    break;
                case Label.BOTTOM:
                    if (iconWidth > strWidth) { //center align the smaller

                        iconStringWGap = (iconWidth - strWidth) / 2;
                        g.drawImage(icon, x, y);
                        drawLabelString(g, l, text, x + iconStringWGap, y + iconHeight + gap, textSpaceX, textSpaceW);
                    } else {
                        iconStringWGap = (Math.min(strWidth, textSpaceW) - iconWidth) / 2;
                        g.drawImage(icon, x + iconStringWGap, y);
                        
                        drawLabelString(g, l, text, x, y + iconHeight + gap, textSpaceX, textSpaceW);
                    }
                    break;
                case Label.TOP:
                    if (iconWidth > strWidth) { //center align the smaller

                        iconStringWGap = (iconWidth - strWidth) / 2;
                        drawLabelString(g, l, text, x + iconStringWGap, y, textSpaceX, textSpaceW);
                        g.drawImage(icon, x, y + fontHeight + gap);
                    } else {
                        iconStringWGap = (Math.min(strWidth, textSpaceW) - iconWidth) / 2;
                        drawLabelString(g, l, text, x, y, textSpaceX, textSpaceW);
                        g.drawImage(icon, x + iconStringWGap, y + fontHeight + gap);
                    }
                    break;
            }
        }
        
        String badgeText = l.getBadgeText();
        if (badgeText != null && badgeText.length() > 0) {
            
            Component badgeCmp = l.getBadgeStyleComponent();
            int badgePaddingTop = CN.convertToPixels(1);
            int badgePaddingBottom = badgePaddingTop;
            int badgePaddingLeft = badgePaddingTop;
            int badgePaddingRight = badgePaddingTop;
            int fgColor = 0xffffff;
            int bgColor = 0x666666;
            int strokeColor = bgColor;
            Font badgeFont = null;
            Style badgeStyle;
            if (badgeCmp == null) {
                badgeStyle = l.getUIManager().getComponentStyle("Badge");
                
            } else {
                badgeStyle = badgeCmp.getStyle();
            }
            if (badgeStyle != null) {
                fgColor = badgeStyle.getFgColor();
                bgColor = badgeStyle.getBgColor();
                if (badgeStyle.getBorder() instanceof RoundBorder) {
                    strokeColor = ((RoundBorder)badgeStyle.getBorder()).getStrokeColor();
                } else {
                    strokeColor = bgColor;
                }
                badgeFont = badgeStyle.getFont();
                badgePaddingTop = badgeStyle.getPaddingTop();
                badgePaddingBottom = badgeStyle.getPaddingBottom();
                badgePaddingLeft = badgeStyle.getPaddingLeftNoRTL();
                badgePaddingRight = badgeStyle.getPaddingRightNoRTL();
            }
            if (badgeFont == null) {
                if (Font.isNativeFontSchemeSupported()) {
                    badgeFont = Font.createTrueTypeFont(Font.NATIVE_MAIN_LIGHT).derive(fontHeight/2, 0);
                } else {
                    badgeFont = Font.createSystemFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
                }
            } 
            
            int badgeFontHeight = badgeFont.getHeight();
            int badgeTextWidth = badgeFont.stringWidth(badgeText);
            GeneralPath path = new GeneralPath();
            
            Rectangle rect = new Rectangle(
                    cmpX + cmpWidth - badgeTextWidth - badgePaddingLeft - badgePaddingRight, 
                    cmpY, 
                    badgePaddingLeft + badgePaddingRight + badgeTextWidth, 
                    badgePaddingTop+badgePaddingBottom+badgeFontHeight
            );
            if (rect.getWidth() < rect.getHeight()) {
                rect.setX(cmpX + cmpWidth - rect.getHeight());
                rect.setWidth(rect.getHeight());
            }

            path.moveTo(rect.getX() + rect.getHeight()/2, rect.getY());
            path.lineTo(rect.getX() + rect.getWidth() - rect.getHeight()/2, rect.getY());
            path.arcTo(rect.getX() + rect.getWidth() - rect.getHeight()/2, rect.getY() + rect.getHeight() / 2, rect.getX() + rect.getWidth() - rect.getHeight()/2, rect.getY() + rect.getHeight(), true);
            path.lineTo(rect.getX() + rect.getHeight()/2, rect.getY() + rect.getHeight());
            path.arcTo(rect.getX() + rect.getHeight()/2, rect.getY() + rect.getHeight()/2, rect.getX() + rect.getHeight()/2, rect.getY(), true);
            path.closePath();
            
            int col = g.getColor();
            boolean antialias = g.isAntiAliased();
            g.setAntiAliased(true);
            g.setColor(bgColor);
            
            
            g.fillShape(path);
            if (bgColor != strokeColor) {
                g.setColor(strokeColor);
                int alpha2 = g.concatenateAlpha(badgeStyle.getFgAlpha());
                g.drawShape(path, new Stroke(1, Stroke.CAP_SQUARE, Stroke.JOIN_MITER, 1f));
                g.setAlpha(alpha2);
            }
            
            
            g.setColor(fgColor);
            g.setFont(badgeFont);
            int alpha2 = g.concatenateAlpha(badgeStyle.getFgAlpha());
            g.drawString(badgeText, rect.getX() + rect.getWidth()/2 - badgeTextWidth/2, rect.getY() + badgePaddingTop);
            g.setAlpha(alpha2);
            
            
            g.setColor(col);
            g.setAntiAliased(antialias);
            
            
            
            
            
        }
        g.setAlpha(alpha);
    }

    private void drawLabelImageValign(Graphics g, Label l, Image icon, int x, int y, int fontHeight, int iconHeight) {
        int iconStringHGap = (fontHeight - iconHeight) / 2;
        //int strWidth = drawLabelString(g, l, text, x, y, textSpaceX, textSpaceW);
        switch (l.getVerticalAlignment()) {
            case Component.TOP:
                g.drawImage(icon, x, y + iconStringHGap);
                break;
            case Component.BOTTOM:
                g.drawImage(icon, x, y + fontHeight - iconHeight);
                break;
            case Component.BASELINE:
                Font iconFont = l.getIconStyleComponent().getStyle().getFont();
                Font textFont = l.getStyle().getFont();
                if (iconFont == null) {
                    iconFont = Font.getDefaultFont();
                }
                if (textFont == null) {
                    textFont = Font.getDefaultFont();
                }
                iconStringHGap = textFont.getAscent() - iconFont.getAscent();
                g.drawImage(icon, x, y + iconStringHGap);
                break;
            default:
                g.drawImage(icon, x, y + iconStringHGap);

        }
    }
    
    /**
     * Implements the drawString for the text component and adjust the valign
     * assuming the icon is in one of the sides
     */
    private int drawLabelStringValign(Graphics g, Label l, String str, int x, int y,
            int iconStringHGap, int iconHeight, int textSpaceX, int textSpaceW, int fontHeight) {
        if (str.length() == 0) {
            return 0;
        }
        switch (l.getVerticalAlignment()) {
            case Component.TOP:
                return drawLabelString(g, l, str, x, y, textSpaceX, textSpaceW);
            case Component.CENTER:
                return drawLabelString(g, l, str, x, y + iconHeight / 2 - fontHeight / 2, textSpaceX, textSpaceW);
            case Component.BASELINE:
                Font iconFont = l.getIconStyleComponent().getStyle().getFont();
                Font textFont = l.getStyle().getFont();
                if (iconFont == null) {
                    iconFont = Font.getDefaultFont();
                }
                if (textFont == null) {
                    textFont = Font.getDefaultFont();
                }
                int ascentDiff = iconFont.getAscent() - textFont.getAscent();
                return drawLabelString(g, l, str, x, y + ascentDiff, textSpaceX, textSpaceW);
                
            default:
                return drawLabelString(g, l, str, x, y + iconStringHGap, textSpaceX, textSpaceW);
        }
    }
    
    private Span calculateSpanForLabelStringValign(TextSelection sel, Label l, String str, int x, int y,
            int iconStringHGap, int iconHeight, int textSpaceW, int fontHeight) {
        switch (l.getVerticalAlignment()) {
            case Component.TOP:
                return calculateSpanForLabelString(sel, l, str, x, y, textSpaceW);
            case Component.CENTER:
                return calculateSpanForLabelString(sel, l, str, x, y + iconHeight / 2 - fontHeight / 2, textSpaceW);
            case Component.BASELINE:
                Font iconFont = l.getIconStyleComponent().getStyle().getFont();
                Font textFont = l.getStyle().getFont();
                if (iconFont == null) {
                    iconFont = Font.getDefaultFont();
                }
                if (textFont == null) {
                    textFont = Font.getDefaultFont();
                }
                int ascentDiff = iconFont.getAscent() - textFont.getAscent();
                return calculateSpanForLabelString(sel, l, str, x, y + ascentDiff, textSpaceW);
            default:
                return calculateSpanForLabelString(sel, l, str, x, y + iconStringHGap, textSpaceW);
        }
    }

    /**
     * Implements the drawString for the text component and adjust the valign
     * assuming the icon is in one of the sides
     */
    private int drawLabelString(Graphics g, Label l, String text, int x, int y, int textSpaceX, int textSpaceW) {
        if (text.length() == 0) {
            return 0;
        }
        Style style = l.getStyle();

        int cx = g.getClipX();
        int cy = g.getClipY();
        int cw = g.getClipWidth();
        int ch = g.getClipHeight();
        //g.pushClip();
        g.clipRect(textSpaceX, cy, textSpaceW, ch);

        if (l.isTickerRunning()) {
            Font font = style.getFont();
            if (l.getShiftText() > 0) {
                if (l.getShiftText() > textSpaceW) {
                    l.setShiftText(x - l.getX() - l.getStringWidth(font));
                }
            } else if (l.getShiftText() + l.getStringWidth(font) < 0) {
                l.setShiftText(textSpaceW);
            }
        }
        int drawnW = drawLabelText(g, l, text, x, y, textSpaceW);

        g.setClip(cx, cy, cw, ch);
        //g.popClip();

        return drawnW;
    }
    
    private Span calculateSpanForLabelString(TextSelection sel, Label l, String text, int x, int y, int textSpaceW) {
        Style style = l.getStyle();

        

        if (l.isTickerRunning()) {
            Font font = style.getFont();
            if (l.getShiftText() > 0) {
                if (l.getShiftText() > textSpaceW) {
                    l.setShiftText(x - l.getX() - l.getStringWidth(font));
                }
            } else if (l.getShiftText() + l.getStringWidth(font) < 0) {
                l.setShiftText(textSpaceW);
            }
        }
        return calculateSpanForLabelText(sel, l, text, x, y, textSpaceW);

    }

    /**
     * Draws the text of a label
     * 
     * @param g graphics context
     * @param l label component
     * @param text the text for the label
     * @param x position for the label
     * @param y position for the label
     * @param textSpaceW the width available for the component
     * @return the space used by the drawing
     */
    protected int drawLabelText(Graphics g, Label l, String text, int x, int y, int textSpaceW) {
        Style style = l.getStyle();
        Font f = style.getFont();
        boolean rtl = l.isRTL();
        boolean isTickerRunning = l.isTickerRunning();
        int txtW = l.getStringWidth(f);
        if ((!isTickerRunning) || rtl) {
            //if there is no space to draw the text add ... at the end
            if (txtW > textSpaceW && textSpaceW > 0) {
            	// Handling of adding 3 points and in fact all text positioning when the text is bigger than
            	// the allowed space is handled differently in RTL, this is due to the reverse algorithm
            	// effects - i.e. when the text includes both Hebrew/Arabic and English/numbers then simply
            	// trimming characters from the end of the text (as done with LTR) won't do.
            	// Instead we simple reposition the text, and draw the 3 points, this is quite simple, but
            	// the downside is that a part of a letter may be shown here as well.

            	if (rtl) {
                	if ((!isTickerRunning) && (l.isEndsWith3Points())) {
	            		String points = "...";
	                	int pointsW = f.stringWidth(points);
	            		g.drawString(points, l.getShiftText() + x, y,l.getStyle().getTextDecoration());
	            		g.clipRect(pointsW+l.getShiftText() + x, y, textSpaceW - pointsW, f.getHeight());
                	}
            		//x = x - txtW + textSpaceW;
                } else {
                    if (l.isEndsWith3Points()) {
                        String points = "...";
                        int index = 1;
                        int widest = f.charWidth('W');
                        int pointsW = f.stringWidth(points);
                        int tlen = text.length();
                        while (fastCharWidthCheck(text, index, textSpaceW - pointsW, widest, f) && index < tlen){
                            index++;
                        }
                        text = text.substring(0, Math.min(text.length(), Math.max(1, index-1))) + points;
                        txtW =  f.stringWidth(text);
                    }
                }
            }
        }

        g.drawString(text, l.getShiftText() + x, y,style.getTextDecoration());
        return Math.min(txtW, textSpaceW);
    }

    private boolean fastCharWidthCheck(String s, int length, int width, int charWidth, Font f) {
        if(length * charWidth < width) {
            return true;
        }
        length = Math.min(s.length(), length);
        return f.substringWidth(s, 0, length) < width;
    }
    
    /**
     * {@inheritDoc}
     */
    public Dimension getComboBoxPreferredSize(List cb) {
        Dimension d = getListPreferredSize(cb);
        Image comboBoxImage = ((ComboBox)cb).getComboBoxImage() != null ? ((ComboBox)cb).getComboBoxImage() : comboImage;
        if(comboBoxImage != null) {
            d.setWidth(d.getWidth() + comboBoxImage.getWidth());
            d.setHeight(Math.max(d.getHeight(), comboBoxImage.getHeight()));
        }
        return d;
    }


    /**
     * Similar to getText() but works properly with password fields
     */
    protected String getTextFieldString(TextArea ta) {
        String txt = ta.getText();
        String text;
        if(ta.isSingleLineTextArea()){
            text = txt;
        }else{
            text = (String) ta.getTextAt(ta.getCursorY());
            if(ta.getCursorPosition() + text.length() < txt.length()){
                char c = txt.charAt(ta.getCursorPosition() + text.length());
                if(c == '\n'){
                    text += "\n";
                }else if(c == ' '){
                    text += " ";            
                }
            }
        }
        
        String displayText = "";
        if ((ta.getConstraint() & TextArea.PASSWORD) != 0) {
            // show the last character in a password field
            if (ta.isPendingCommit()) {
                if (text.length() > 0) {
                    int tlen = text.length();
                    for (int j = 0; j < tlen - 1; j++) {
                        displayText += passwordChar;
                    }
                    displayText += text.charAt(text.length() - 1);
                }
            } else {
                for (int j = 0; j < text.length(); j++) {
                    displayText += passwordChar;
                }
            }
        } else {
            displayText = text;
        }
        return displayText;
    }
    
    public Spans calculateTextFieldSpan(TextSelection sel, TextArea ta) {
        //setFG(g, ta);
        Span out = sel.newSpan(ta);
        // display ******** if it is a password field
        String displayText = getTextFieldString(ta);

        Style style = ta.getStyle();
        int x = 0;
        int cursorCharPosition = ta.hasFocus() ? ta.getCursorPosition() : 0;//ta.getCursorX();        
        Font f = style.getFont();
        int cursorX = 0;
        int xPos = 0;
        
        int align = reverseAlignForBidi(ta);
        int displayX = 0;

        String inputMode = ta.getInputMode();
        int inputModeWidth = f.stringWidth(inputMode);

        // QWERTY devices don't quite have an input mode hide it also when we have a VK
        if(!Display.getInstance().platformUsesInputMode() || ta.isQwertyInput() || Display.getInstance().isVirtualKeyboardShowing()) {
            inputMode = "";
            inputModeWidth = 0;
        }
        if (ta.isSingleLineTextArea()) {
            // there is currently no support for CENTER aligned text fields
            if (align == Component.LEFT) {
                if (cursorCharPosition > 0) {
                    cursorCharPosition = Math.min(displayText.length(), 
                        cursorCharPosition);
                    xPos = f.stringWidth(displayText.substring(0, cursorCharPosition));
                    cursorX = ta.getX() + style.getPaddingLeft(ta.isRTL()) + xPos;

                    // no point in showing the input mode when there is only one input mode...
                    if (inputModeWidth > 0 && ta.getInputModeOrder() != null && ta.getInputModeOrder().length == 1) {
                        inputModeWidth = 0;
                    }
                    if (ta.isEnableInputScroll()) {
                        if (ta.getWidth() > (f.getHeight() * 2) && cursorX >= ta.getWidth() - inputModeWidth - style.getPaddingLeft(ta.isRTL())) {
                            if (x + xPos >= ta.getWidth() - inputModeWidth - style.getPaddingLeft(ta.isRTL()) * 2) {
                                x=ta.getWidth() - inputModeWidth - style.getPaddingLeft(ta.isRTL()) * 2 - xPos - 1;
                            }
                        }
                    }
                }
                displayX = ta.getX() + x + style.getPaddingLeft(ta.isRTL());
            } else {
                x = 0;
                cursorX = getTextFieldCursorX(ta);
                int baseX = ta.getX() + style.getPaddingLeftNoRTL() + inputModeWidth;
                int endX = ta.getX() + ta.getWidth() - style.getPaddingRightNoRTL();

                if (cursorX < baseX) {
                    x = baseX - cursorX;
                } else {
                    if (cursorX > endX) {
                        x = endX - cursorX;
                    }
                }

                displayX = ta.getX() + ta.getWidth() - style.getPaddingRightNoRTL() - style.getPaddingLeftNoRTL() - f.stringWidth(displayText) + x;
            }

            //int cx = g.getClipX();
            //int cy = g.getClipY();
            //int cw = g.getClipWidth();
            //int ch = g.getClipHeight();
            //int clipx = ta.getX() + style.getPaddingLeft(ta.isRTL());
            //int clipw = ta.getWidth() - style.getPaddingLeft(ta.isRTL()) - style.getPaddingRight(ta.isRTL());
            //g.pushClip();
            //g.clipRect(clipx, cy, clipw, ch);

            //int xOffset = 0;
            //int len = displayText.length();
            //int charH = f.getHeight();
            int h = getSelectionHeight(f);
            switch(ta.getVerticalAlignment()) {
                case Component.BOTTOM:
                    //g.drawString(displayText, displayX, ta.getY() + ta.getHeight() - style.getPaddingBottom() - f.getHeight(), style.getTextDecoration());
                    append(sel, ta, out, displayText, f, 0, displayX, ta.getY() + ta.getHeight() - style.getPaddingBottom() - h, h);
                   // c = sel.newChar(i, charX, ta.getY() + ta.getHeight() - style.getPaddingBottom() - f.getHeight(), charW , charH);
                    break;
                case Component.CENTER:
                    //g.drawString(displayText, displayX, ta.getY() + ta.getHeight() / 2  - f.getHeight() / 2, style.getTextDecoration());
                    //c = sel.newChar(i, charX, ta.getY() + ta.getHeight() / 2  - f.getHeight() / 2, charW, charH);
                    append(sel, ta, out, displayText, f, 0, displayX,  ta.getY() + ta.getHeight() / 2  - h / 2, h);
                    break;
                default:
                    //g.drawString(displayText, displayX, ta.getY() + style.getPaddingTop(), style.getTextDecoration());
                    //c = sel.newChar(i, charX, ta.getY() + style.getPaddingTop(), charW, charH);
                    append(sel, ta, out, displayText, f, 0, displayX,  ta.getY() + style.getPaddingTop(), h);
                    break;
            }
            
            
            //g.setClip(cx, cy, cw, ch);
            //g.popClip();
            out = out.translate(ta.getAbsoluteX() - sel.getSelectionRoot().getAbsoluteX() - ta.getX(), ta.getAbsoluteY() - sel.getSelectionRoot().getAbsoluteY() - ta.getY());
            Spans spansOut = sel.newSpans();
            spansOut.add(out);
            return spansOut;
            
        } else {
            //drawTextArea(g, ta);
            return calculateTextAreaSpan(sel, ta);
        }
        
    }
    
    
    /**
     * {@inheritDoc}
     */
    public void drawTextField(Graphics g, TextArea ta) {
        setFG(g, ta);
        int alpha = g.concatenateAlpha(ta.getStyle().getFgAlpha());
        // display ******** if it is a password field
        String displayText = getTextFieldString(ta);

        Style style = ta.getStyle();
        int x = 0;
        int cursorCharPosition = ta.hasFocus() ? ta.getCursorPosition() : 0;//ta.getCursorX();        
        Font f = style.getFont();
        int cursorX = 0;
        int xPos = 0;
        
        int align = reverseAlignForBidi(ta);
        int displayX = 0;

        String inputMode = ta.getInputMode();
        int inputModeWidth = f.stringWidth(inputMode);

        // QWERTY devices don't quite have an input mode hide it also when we have a VK
        if(!Display.getInstance().platformUsesInputMode() || ta.isQwertyInput() || Display.getInstance().isVirtualKeyboardShowing()) {
            inputMode = "";
            inputModeWidth = 0;
        }
        if (ta.isSingleLineTextArea()) {
            // there is currently no support for CENTER aligned text fields
            if (align == Component.LEFT) {
                if (cursorCharPosition > 0) {
                    cursorCharPosition = Math.min(displayText.length(), 
                        cursorCharPosition);
                    xPos = f.stringWidth(displayText.substring(0, cursorCharPosition));
                    cursorX = ta.getX() + style.getPaddingLeft(ta.isRTL()) + xPos;

                    // no point in showing the input mode when there is only one input mode...
                    if (inputModeWidth > 0 && ta.getInputModeOrder() != null && ta.getInputModeOrder().length == 1) {
                        inputModeWidth = 0;
                    }
                    if (ta.isEnableInputScroll()) {
                        if (ta.getWidth() > (f.getHeight() * 2) && cursorX >= ta.getWidth() - inputModeWidth - style.getPaddingLeft(ta.isRTL())) {
                            if (x + xPos >= ta.getWidth() - inputModeWidth - style.getPaddingLeft(ta.isRTL()) * 2) {
                                x=ta.getWidth() - inputModeWidth - style.getPaddingLeft(ta.isRTL()) * 2 - xPos - 1;
                            }
                        }
                    }
                }
                displayX = ta.getX() + x + style.getPaddingLeft(ta.isRTL());
            } else {
                x = 0;
                cursorX = getTextFieldCursorX(ta);
                int baseX = ta.getX() + style.getPaddingLeftNoRTL() + inputModeWidth;
                int endX = ta.getX() + ta.getWidth() - style.getPaddingRightNoRTL();

                if (cursorX < baseX) {
                    x = baseX - cursorX;
                } else {
                    if (cursorX > endX) {
                        x = endX - cursorX;
                    }
                }

                displayX = ta.getX() + ta.getWidth() - style.getPaddingRightNoRTL() - style.getPaddingLeftNoRTL() - f.stringWidth(displayText) + x;
            }

            int cx = g.getClipX();
            int cy = g.getClipY();
            int cw = g.getClipWidth();
            int ch = g.getClipHeight();
            int clipx = ta.getX() + style.getPaddingLeft(ta.isRTL());
            int clipw = ta.getWidth() - style.getPaddingLeft(ta.isRTL()) - style.getPaddingRight(ta.isRTL());
            //g.pushClip();
            g.clipRect(clipx, cy, clipw, ch);

            switch(ta.getVerticalAlignment()) {
                case Component.BOTTOM:
                    g.drawString(displayText, displayX, ta.getY() + ta.getHeight() - style.getPaddingBottom() - f.getHeight(), style.getTextDecoration());
                    break;
                case Component.CENTER:
                    g.drawString(displayText, displayX, ta.getY() + ta.getHeight() / 2  - f.getHeight() / 2, style.getTextDecoration());
                    break;
                default:
                    g.drawString(displayText, displayX, ta.getY() + style.getPaddingTop(), style.getTextDecoration());
                    break;
            }
            g.setClip(cx, cy, cw, ch);
            //g.popClip();
            
        } else {
            drawTextArea(g, ta);
        }
        // no point in showing the input mode when there is only one input mode...
        if(inputModeWidth > 0 && ta.getInputModeOrder() != null && ta.getInputModeOrder().length > 1) {
            
            if (ta.handlesInput() && ta.getWidth() / 2 > inputModeWidth) {
            	
                int drawXPos = ta.getX() + style.getPaddingLeft(ta.isRTL());
                if((!ta.isRTL() && style.getAlignment() == Component.LEFT) ||
                    (ta.isRTL() && style.getAlignment() == Component.RIGHT)) {
                    drawXPos = drawXPos + ta.getWidth() - inputModeWidth - style.getPaddingRightNoRTL() - style.getPaddingLeftNoRTL();
                } 
                g.setColor(style.getFgColor());
                int inputIndicatorY = ta.getY()+ ta.getScrollY() + ta.getHeight() -  
                        style.getPaddingBottom() - 
                        f.getHeight();
                g.fillRect(drawXPos, inputIndicatorY, inputModeWidth,
                        f.getHeight(), (byte) 140);
                g.setColor(style.getBgColor());
                g.drawString(inputMode, drawXPos, inputIndicatorY);
            }
        }
        g.setAlpha(alpha);
    }


    /**
     * Returns true if the given character is an RTL character or a space
     * character
     *
     * @param c character to test
     * @return true if bidi is active and this is a
     */
	private boolean isRTLOrWhitespace(char c) {
        return (Display.getInstance().isRTL(c)) || c == ' ';
    }

    /**
     * Calculates the position of the text field cursor within the string
     */
    private int getTextFieldCursorX(TextArea ta) {
        Style style = ta.getStyle();
        Font f = style.getFont();

        // display ******** if it is a password field
        String displayText = getTextFieldString(ta);
        String inputMode = ta.getInputMode();
        int inputModeWidth = f.stringWidth(inputMode);
        // QWERTY devices don't quite have an input mode hide it also when we have a VK
        if(ta.isQwertyInput() || Display.getInstance().isVirtualKeyboardShowing()) {
            inputMode = "";
            inputModeWidth = 0;
        }

        int xPos = 0;
        int cursorCharPosition = ta.getCursorX();
        int cursorX=0;
        int x = 0;

        if (reverseAlignForBidi(ta) == Component.RIGHT) {
        	if (Display.getInstance().isBidiAlgorithm()) {
                //char[] dest = displayText.toCharArray();
                cursorCharPosition = Display.getInstance().getCharLocation(displayText, cursorCharPosition-1);

                if (cursorCharPosition==-1) {
                    xPos = f.stringWidth(displayText);
                } else {
                    displayText = Display.getInstance().convertBidiLogicalToVisual(displayText);
                    if (!isRTLOrWhitespace((displayText.charAt(cursorCharPosition)))) {
                        cursorCharPosition++;
                    }
                    xPos = f.stringWidth(displayText.substring(0, cursorCharPosition));
                } 
        	}
        	int displayX = ta.getX() + ta.getWidth() - style.getPaddingLeft(ta.isRTL()) - f.stringWidth(displayText);
        	cursorX = displayX + xPos;
        	x=0;
        } else {
            if (cursorCharPosition > 0) {
                cursorCharPosition = Math.min(displayText.length(), 
                        cursorCharPosition);
                xPos = f.stringWidth(displayText.substring(0, cursorCharPosition));
            }
            cursorX = ta.getX() + style.getPaddingLeft(ta.isRTL()) + xPos;

            if (ta.isSingleLineTextArea() && ta.getWidth() > (f.getHeight() * 2) && cursorX >= ta.getWidth() - inputModeWidth  -style.getPaddingLeft(ta.isRTL())) {
                if (x + xPos >= ta.getWidth() - inputModeWidth - style.getPaddingLeftNoRTL() - style.getPaddingRightNoRTL()) {
                    x = ta.getWidth() - inputModeWidth - style.getPaddingLeftNoRTL() - style.getPaddingRightNoRTL() - xPos -1;
                }
            }
        }

        return cursorX+x;
    }

    /**
     * {@inheritDoc}
     */
    public Dimension getTextFieldPreferredSize(TextArea ta) {
        return getTextAreaSize(ta, true);
    }

    /**
     * {@inheritDoc}
     */
     public void drawTextFieldCursor(Graphics g, TextArea ta) {
         Style style = ta.getStyle();
         Font f = style.getFont();


        int cursorY;
        if(ta.isSingleLineTextArea()) {
            switch(ta.getVerticalAlignment()) {
                case Component.BOTTOM:
                    cursorY = ta.getY() + ta.getHeight() -  f.getHeight();
                    break;
                case Component.CENTER:
                    cursorY = ta.getY() + ta.getHeight() / 2 -  f.getHeight() / 2;
                    break;
                default:
                    cursorY = ta.getY() + style.getPaddingTop();
                    break;
            }
         } else {
            cursorY = ta.getY() + style.getPaddingTop() + ta.getCursorY() * (ta.getRowsGap() + f.getHeight());
         }
    	int cursorX = getTextFieldCursorX(ta);

        int align = reverseAlignForBidi(ta);
		int x=0;
        if (align==Component.RIGHT) {
            String inputMode = ta.getInputMode();
            int inputModeWidth = f.stringWidth(inputMode);

    		int baseX=ta.getX()+style.getPaddingLeftNoRTL()+inputModeWidth;
    		if (cursorX getPullToRefreshHeight()) {
                cmpToDraw = releaseToRefresh;
            } else {
                cmpToDraw = pullDown;
            }
        }

        if (pull.getComponentAt(0) != updating && cmpToDraw != pull.getComponentAt(0)) {
            
            parentForm.registerAnimated(new Animation() {

                int counter = 0;
                Image i;
                
                {
                    i = UIManager.getInstance().getThemeImageConstant("pullToRefreshImage");
                    if(i == null) {
                        i = getDefaultRefreshIcon();
                    }
                }
 
                public boolean animate() {
                    counter++;

                    if (pull.getComponentAt(0) == releaseToRefresh) {
                        ((Label) releaseToRefresh).setIcon(i.rotate(180 - (180 / 6)*counter));
                    } else {
                        ((Label) pullDown).setIcon(i.rotate(180 *counter/ 6));
                    }
                    if (counter == 6) {
                        ((Label) releaseToRefresh).setIcon(i);
                        ((Label) pullDown).setIcon(i.rotate(180));                        
                        parentForm.deregisterAnimated(this);
                    }
                    
                    // Placing the repaint inside a callSerially() because repaint directly
                    // inside animate causes painting artifacts in many instances
                    CN.callSerially(new Runnable() {
                        public void run() {
                            cmp.repaint(cmp.getAbsoluteX(), cmp.getAbsoluteY()-getPullToRefreshHeight(), cmp.getWidth(), 
                            getPullToRefreshHeight());
                        }
                    });
                    
                    
                    
                    return false;
                }

                public void paint(Graphics g) {
                }
            });
            
        }
        if(pull.getComponentAt(0) != cmpToDraw 
                && cmpToDraw instanceof Label 
                && (pull.getComponentAt(0) instanceof Label)){
            ((Label)cmpToDraw).setIcon(((Label)pull.getComponentAt(0)).getIcon());
        }
        Component current = pull.getComponentAt(0);
        if(current != cmpToDraw) {
            pull.replace(current, cmpToDraw, null);
        }

        pull.setWidth(cmp.getWidth());
        pull.setX(cmp.getAbsoluteX());
        pull.setY(cmp.getY() -scrollY - getPullToRefreshHeight());
        pull.layoutContainer();
        
        // We need to make the InfiniteProgress to animate, otherwise the progress
        // just stays static.
        ComponentSelector.select("*", pull).each(new ComponentClosure() {
            

            @Override
            public void call(Component c) {
                if (c instanceof InfiniteProgress) {
                    ((InfiniteProgress)c).animate(true);
                } else {
                    c.animate();
                }
            }
        });
        pull.paintComponent(g);

    }

    /**
     * {@inheritDoc}
     */
    public int getPullToRefreshHeight() {
        if (pull == null) {
            BorderLayout bl = new BorderLayout();
            bl.setCenterBehavior(BorderLayout.CENTER_BEHAVIOR_CENTER_ABSOLUTE);
            pull = new Container(bl);
        }
        if (pullDown == null) {
            pullDown = new Label(getUIManager().localize("pull.down", "Pull down to refresh..."));
            pullDown.setUIID("PullToRefresh");
            
            Image i = UIManager.getInstance().getThemeImageConstant("pullToRefreshImage");
            if(i == null) {
                i = getDefaultRefreshIcon();
            }
            i = i.rotate(180);
            ((Label) pullDown).setIcon(i);
        }
        if (releaseToRefresh == null) {
            releaseToRefresh = new Label(getUIManager().localize("pull.release", "Release to refresh..."));
            releaseToRefresh.setUIID("PullToRefresh");
            Image i = UIManager.getInstance().getThemeImageConstant("pullToRefreshImage");
            if(i == null) {
                i = getDefaultRefreshIcon();
            }
            ((Label) releaseToRefresh).setIcon(i);
        }
        if (updating == null) {
            updating = new Container(new BoxLayout(BoxLayout.X_AXIS));
            ((Container) updating).addComponent(new InfiniteProgress());
            Label l = new Label(getUIManager().localize("pull.refresh", "Updating..."));
            l.setUIID("PullToRefresh");
            ((Container) updating).addComponent(l);

            pull.getUnselectedStyle().setPadding(0, 0, 0 , 0);
            pull.getUnselectedStyle().setMargin(0, 0, 0 , 0);
            pull.addComponent(BorderLayout.CENTER, updating);
            pull.layoutContainer();
            pull.setHeight(Math.max(pullDown.getPreferredH(), pull.getPreferredH()));
        }
        String s = UIManager.getInstance().getThemeConstant("pullToRefreshHeight", null);
        if(s != null) {
            float f = Util.toFloatValue(s);
            if(f > 0) {
                return Display.getInstance().convertToPixels(f);
            }
        }
        return pull.getHeight();
    }
     

    /**
     * {@inheritDoc}
     */
    public void focusGained(Component cmp) {
        if(cmp instanceof Label) {
            Label l = (Label) cmp;
            if (l.isTickerEnabled() && l.shouldTickerStart() && Display.getInstance().shouldRenderSelection(cmp)) {
                ((Label) cmp).startTicker(getTickerSpeed(), true);
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void focusLost(Component cmp) {
        if(cmp instanceof Label) {
            Label l = (Label) cmp;
            if (l.isTickerRunning()) {
                l.stopTicker();
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public void refreshTheme(boolean b) {
        chkBoxImages = null;
        comboImage = null;
        rButtonImages = null;
        chkBoxImagesFocus = null;
        rButtonImagesFocus = null;
        super.refreshTheme(b);
        UIManager m = getUIManager();
        Image combo = m.getThemeImageConstant("comboImage");
        if(combo != null) {
            setComboBoxImage(combo);
        } else {
            if(Font.isNativeFontSchemeSupported()) {
                Style c = UIManager.getInstance().createStyle("ComboBox.", "", false);
                combo = FontImage.createMaterial(FontImage.MATERIAL_ARROW_DROP_DOWN, c);
                setComboBoxImage(combo);
            }
        }
        updateCheckBoxConstants(m, false, "");
        updateCheckBoxConstants(m, true, "Focus");
        updateRadioButtonConstants(m, false, "");
        updateRadioButtonConstants(m, true, "Focus");        
    }
    
    private void updateCheckBoxConstants(UIManager m, boolean focus, String append) {
        Image checkSel = m.getThemeImageConstant("checkBoxChecked" + append + "Image");
        if(checkSel != null) {
            Image checkUnsel = m.getThemeImageConstant("checkBoxUnchecked" + append + "Image");
            if(checkUnsel != null) {
                Image disUnsel = m.getThemeImageConstant("checkBoxUncheckDis" + append + "Image");
                Image disSel = m.getThemeImageConstant("checkBoxCheckDis" + append + "Image");
                if(disSel == null) {
                    disSel = checkSel;
                }
                if(disUnsel == null) {
                    disUnsel = checkUnsel;
                }
                if(focus) {
                    setCheckBoxFocusImages(checkSel, checkUnsel, disSel, disUnsel);
                } else {
                    setCheckBoxImages(checkSel, checkUnsel, disSel, disUnsel);
                }
            }
            if(checkUnsel != null) {
                if(focus) {
                    setCheckBoxFocusImages(checkSel, checkUnsel, checkSel, checkUnsel);
                } else {
                    setCheckBoxImages(checkSel, checkUnsel);
                }
            }
        } else {
            if(!Font.isTrueTypeFileSupported()) {
                return;
            }
            UIManager uim = UIManager.getInstance();
            Style unsel = uim.createStyle("CheckBox.", "", false);
            Style sel = uim.createStyle("CheckBox.", "sel#", true);
            Style dis = uim.createStyle("CheckBox.", "dis#", false);
            FontImage checkedDis = FontImage.createMaterial(FontImage.MATERIAL_CHECK_BOX, dis);
            FontImage uncheckedDis = FontImage.createMaterial(FontImage.MATERIAL_CHECK_BOX_OUTLINE_BLANK, sel);
            if(focus) {
                FontImage checkedSelected = FontImage.createMaterial(FontImage.MATERIAL_CHECK_BOX, sel);
                FontImage uncheckedSelected = FontImage.createMaterial(FontImage.MATERIAL_CHECK_BOX_OUTLINE_BLANK, sel);
                setCheckBoxFocusImages(checkedSelected, uncheckedSelected, checkedDis, uncheckedDis);
            } else {
                FontImage checkedUnselected = FontImage.createMaterial(FontImage.MATERIAL_CHECK_BOX, unsel);
                FontImage uncheckedUnselected = FontImage.createMaterial(FontImage.MATERIAL_CHECK_BOX_OUTLINE_BLANK, unsel);
                setCheckBoxImages(checkedUnselected, uncheckedUnselected, checkedDis, uncheckedDis);
            }            
        }
    }

    private void updateRadioButtonConstants(UIManager m, boolean focus, String append) {
        Image radioSel = m.getThemeImageConstant("radioSelected" + append + "Image");
        if(radioSel != null) {
            Image radioUnsel = m.getThemeImageConstant("radioUnselected" + append + "Image");
            if(radioUnsel != null) {
                Image disUnsel = m.getThemeImageConstant("radioUnselectedDis" + append + "Image");
                Image disSel = m.getThemeImageConstant("radioSelectedDis" + append + "Image");
                if(disUnsel == null) {
                    disUnsel = radioUnsel;
                }
                if(disSel == null) {
                    disSel = radioSel;
                }
                if(focus) {
                    setRadioButtonFocusImages(radioSel, radioUnsel, disSel, disUnsel);
                } else {
                    setRadioButtonImages(radioSel, radioUnsel, disSel, disUnsel);
                }
            }
        } else {
            if(!Font.isTrueTypeFileSupported()) {
                return;
            }
            UIManager uim = UIManager.getInstance();
            Style unsel = uim.createStyle("RadioButton.", "", false);
            Style sel = uim.createStyle("RadioButton.", "sel#", true);
            Style dis = uim.createStyle("RadioButton.", "dis#", false);
            FontImage checkedDis = FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_CHECKED, dis);
            FontImage uncheckedDis = FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_UNCHECKED, sel);
            if(focus) {
                FontImage checkedSelected = FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_CHECKED, sel);
                FontImage uncheckedSelected = FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_UNCHECKED, sel);
                setRadioButtonFocusImages(checkedSelected, uncheckedSelected, checkedDis, uncheckedDis);
            } else {
                FontImage checkedUnselected = FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_CHECKED, unsel);
                FontImage uncheckedUnselected = FontImage.createMaterial(FontImage.MATERIAL_RADIO_BUTTON_UNCHECKED, unsel);
                setRadioButtonImages(checkedUnselected, uncheckedUnselected, checkedDis, uncheckedDis);
            }
        }
    }

   
    public Span calculateSpanForLabelText(TextSelection sel, Label l, String text, int x, int y, int textSpaceW) {
        
        Span span = sel.newSpan(l);
        Style style = l.getStyle();
        Font f = style.getFont();
        int h = f.getHeight() + (int)(f.getHeight() * 0.25);
        y -= (int)(f.getHeight() * 0.25);
        boolean rtl = l.isRTL();
        boolean isTickerRunning = l.isTickerRunning();
        int txtW = l.getStringWidth(f);
        int curPos = text.length();
        if ((!isTickerRunning) || rtl) {
            //if there is no space to draw the text add ... at the end
            if (txtW > textSpaceW && textSpaceW > 0) {
            	// Handling of adding 3 points and in fact all text positioning when the text is bigger than
            	// the allowed space is handled differently in RTL, this is due to the reverse algorithm
            	// effects - i.e. when the text includes both Hebrew/Arabic and English/numbers then simply
            	// trimming characters from the end of the text (as done with LTR) won't do.
            	// Instead we simple reposition the text, and draw the 3 points, this is quite simple, but
            	// the downside is that a part of a letter may be shown here as well.

            	if (rtl) {
                	if ((!isTickerRunning) && (l.isEndsWith3Points())) {
	            		String points = "...";
	                	int pointsW = f.stringWidth(points);
                                //xPos = f.stringWidth(displayText.substring(0, cursorCharPosition));
	            		//g.drawString(points, l.getShiftText() + x, y,l.getStyle().getTextDecoration());
	            		//g.clipRect(pointsW+l.getShiftText() + x, y, textSpaceW - pointsW, f.getHeight());
                                Char nextChar = sel.newChar(curPos, pointsW+l.getShiftText() + x, y, textSpaceW - pointsW, h);
                                span.add(nextChar);
                	}
            		x = x - txtW + textSpaceW;
                } else {
                    if (l.isEndsWith3Points()) {
                        String points = "...";
                        int index = 1;
                        int widest = f.charWidth('W');
                        int pointsW = f.stringWidth(points);
                        int tlen = text.length();
                        while (fastCharWidthCheck(text, index, textSpaceW - pointsW, widest, f) && index < tlen){
                            index++;
                        }
                        text = text.substring(0, Math.min(text.length(), Math.max(1, index-1))) + points;
                        txtW =  f.stringWidth(text);
                    }
                }
            }
        }

        int len = text.length();
        int xPos = 0;
        curPos = 1;
        while (curPos <= len) {
            int newXpos = f.stringWidth(text.substring(0, curPos));
            Char next = sel.newChar(curPos-1, l.getShiftText() + x + xPos, y, newXpos - xPos, h);
            span.add(next);
            xPos = newXpos;
            curPos++;
        }
        //System.out.println("Span: "+span);
        return span.translate(l.getAbsoluteX() - sel.getSelectionRoot().getAbsoluteX() - l.getX(), l.getAbsoluteY() - sel.getSelectionRoot().getAbsoluteY() - l.getY());
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy