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

gov.nasa.worldwind.render.ToolTipRenderer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.render;

import gov.nasa.worldwind.util.*;

import com.jogamp.opengl.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;

/**
 * @author dcollins
 * @version $Id: ToolTipRenderer.java 2053 2014-06-10 20:16:57Z tgaskins $
 */
public class ToolTipRenderer
{
    private boolean useSystemLookAndFeel;
    private java.awt.Font font;
    private java.awt.Color textColor;
    private java.awt.Color interiorColor;
    private java.awt.Color outlineColor;
    private double opacity;
    private double outlineWidth;
    private java.awt.Insets insets;

    public ToolTipRenderer(java.awt.Font font)
    {
        if (font == null)
        {
            String message = Logging.getMessage("nullValue.FontIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.useSystemLookAndFeel = false;
        this.font = font;
        this.textColor = java.awt.Color.WHITE;
        this.interiorColor = java.awt.Color.BLACK;
        this.outlineColor = java.awt.Color.WHITE;
        this.outlineWidth = 1;
        this.opacity = 1;
        this.insets = new java.awt.Insets(1, 1, 1, 1);
    }

    public ToolTipRenderer(boolean useSystemLookAndFeel)
    {
        this(java.awt.Font.decode("Arial-PLAIN-12"));
        this.setUseSystemLookAndFeel(useSystemLookAndFeel);
    }

    public ToolTipRenderer()
    {
        this(java.awt.Font.decode("Arial-PLAIN-12"));
    }

    public static java.awt.Color getContrastingColor(java.awt.Color color)
    {
        float[] hsbvals = new float[3];
        java.awt.Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), hsbvals);
        java.awt.Color c = Color.getHSBColor(0, 0, (hsbvals[2] + 0.5f) % 1f);
        return new java.awt.Color(c.getRed(), c.getGreen(), c.getBlue(), color.getAlpha());
    }

    public boolean isUseSystemLookAndFeel()
    {
        return this.useSystemLookAndFeel;
    }

    public void setUseSystemLookAndFeel(boolean useSystemLookAndFeel)
    {
        this.useSystemLookAndFeel = useSystemLookAndFeel;
    }

    public java.awt.Font getFont()
    {
        return this.font;
    }

    public void setFont(java.awt.Font font)
    {
        if (font == null)
        {
            String message = Logging.getMessage("nullValue.FontIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.font = font;
    }

    public Color getTextColor()
    {
        return this.textColor;
    }

    public void setTextColor(Color color)
    {
        if (color == null)
        {
            String message = Logging.getMessage("nullValue.ColorIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.textColor = color;
    }

    public Color getInteriorColor()
    {
        return this.interiorColor;
    }

    public void setInteriorColor(Color color)
    {
        if (color == null)
        {
            String message = Logging.getMessage("nullValue.ColorIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.interiorColor = color;
    }

    public Color getOutlineColor()
    {
        return this.outlineColor;
    }

    public void setOutlineColor(Color color)
    {
        if (color == null)
        {
            String message = Logging.getMessage("nullValue.ColorIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.outlineColor = color;
    }

    public double getOpacity()
    {
        return this.opacity;
    }

    public void setOpacity(double opacity)
    {
        if (opacity < 0 || opacity > 1)
        {
            String message = Logging.getMessage("generic.ArgumentOutOfRange", "opacity < 0 or opacity > 1");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.opacity = opacity;
    }

    public double getOutlineWidth()
    {
        return this.outlineWidth;
    }

    public void setOutlineWidth(double width)
    {
        if (width < 0)
        {
            String message = Logging.getMessage("generic.ArgumentOutOfRange", "width < 0");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.outlineWidth = width;
    }

    public java.awt.Insets getInsets()
    {
        // Class java.awt.Insets is known to override the method Object.clone().
        return (java.awt.Insets) this.insets.clone();
    }

    public void setInsets(java.awt.Insets insets)
    {
        if (insets == null)
        {
            String message = Logging.getMessage("nullValue.InsetsIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        // Class java.awt.Insets is known to override the method Object.clone().
        this.insets = (java.awt.Insets) insets.clone();
    }

    public void render(DrawContext dc, String text, int x, int y)
    {
        if (dc == null)
        {
            String message = Logging.getMessage("nullValue.DrawContextIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        if (text == null)
        {
            String message = Logging.getMessage("nullValue.StringIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        this.doRender(dc, text, x, y);
    }

    protected ToolTipAttributes getAttributes()
    {
        return new ToolTipAttributes(
            this.getFont(),
            this.getTextColor(),
            this.getInteriorColor(),
            this.getOutlineColor(),
            this.getOpacity(),
            this.getOpacity(),
            this.getOpacity(),
            this.getOutlineWidth(),
            this.getInsets());
    }

    protected ToolTipAttributes getSystemLookAndFeelAttributes()
    {
        Font font = UIManager.getFont("ToolTip.font");
        Color textColor = UIManager.getColor("ToolTip.foreground");
        Color interiorColor = UIManager.getColor("ToolTip.background");
        Color outlineColor = javax.swing.UIManager.getColor("ToolTip.foreground");
        double textOpacity = this.getOpacity();
        double interiorOpacity = this.getOpacity();
        double outlineOpacity = this.getOpacity();
        double outlineWidth = this.getOutlineWidth();
        Insets insets = null;

        Border border = UIManager.getBorder("ToolTip.border");
        if (border instanceof LineBorder) // Implicitly checks for non-null.
        {
            outlineColor = ((LineBorder) border).getLineColor();
            outlineWidth = ((LineBorder) border).getThickness();
        }

        if (border != null)
            insets = border.getBorderInsets(null);

        if (font == null)
            font = this.getFont();

        if (textColor == null)
            textColor = this.getTextColor();

        if (interiorColor == null)
            interiorColor = this.getInteriorColor();

        if (outlineColor == null)
            outlineColor = this.getOutlineColor();

        if (insets == null)
            insets = this.getInsets();

        return new ToolTipAttributes(font, textColor, interiorColor, outlineColor, textOpacity, interiorOpacity,
            outlineOpacity, outlineWidth, insets);
    }

    //**************************************************************//
    //********************  Rendering  *****************************//
    //**************************************************************//

    protected void doRender(DrawContext dc, String text, int x, int y)
    {
        OGLStackHandler stackHandler = new OGLStackHandler();

        this.beginRendering(dc, stackHandler);
        try
        {
            this.draw(dc, dc.getView().getViewport(), text, x, y);
        }
        finally
        {
            this.endRendering(dc, stackHandler);
        }
    }

    protected void draw(DrawContext dc, java.awt.Rectangle viewport, String text, int x, int y)
    {
        ToolTipAttributes attributes = this.isUseSystemLookAndFeel() ?
            this.getSystemLookAndFeelAttributes() : this.getAttributes();

        this.drawToolTip(dc, viewport, text, x, y, attributes);
    }

    protected void drawToolTip(DrawContext dc, java.awt.Rectangle viewport, String text, int x, int y,
        ToolTipAttributes attributes)
    {
        java.awt.geom.Rectangle2D textBounds = this.computeTextBounds(dc, text, attributes.getFont());
        java.awt.geom.Rectangle2D bgBounds = this.computeBackgroundBounds(dc,
            textBounds.getWidth(), textBounds.getHeight(), attributes.getInsets());

        java.awt.Point screenPoint = this.adjustDrawPointToViewport(x, y, bgBounds, viewport);
        java.awt.geom.Point2D textTranslation = this.computeTextTranslation(dc, textBounds, attributes.getInsets());

        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
        OGLStackHandler stackHandler = new OGLStackHandler();

        stackHandler.pushModelview(gl);
        try
        {
            gl.glTranslated(screenPoint.getX() + bgBounds.getX(), screenPoint.getY() + bgBounds.getY(), 0);
            this.drawToolTipInterior(dc, bgBounds.getWidth(), bgBounds.getHeight(), attributes);
            this.drawToolTipOutline(dc, bgBounds.getWidth(), bgBounds.getHeight(), attributes);

            gl.glTranslated(textTranslation.getX(), textTranslation.getY(), 0);
            this.drawToolTipText(dc, text, 0, 0, attributes);
        }
        finally
        {
            stackHandler.pop(gl);
        }
    }

    protected void beginRendering(DrawContext dc, OGLStackHandler stackHandler)
    {
        if (dc == null)
        {
            String message = Logging.getMessage("nullValue.DrawContextIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.

        int attribMask = GL2.GL_COLOR_BUFFER_BIT // for alpha test func and ref, blend func
            | GL2.GL_CURRENT_BIT // for current color
            | GL2.GL_ENABLE_BIT // for enable/disable
            | GL2.GL_LINE_BIT // for line width
            | GL2.GL_TRANSFORM_BIT; // for matrix mode
        stackHandler.pushAttrib(gl, attribMask);

        stackHandler.pushTextureIdentity(gl);
        stackHandler.pushProjectionIdentity(gl);
        java.awt.Rectangle viewport = dc.getView().getViewport();
        gl.glOrtho(viewport.x, viewport.x + viewport.width, viewport.y, viewport.y + viewport.height, -1, 1);
        stackHandler.pushModelviewIdentity(gl);

        // Enable the alpha test.
        gl.glEnable(GL2.GL_ALPHA_TEST);
        gl.glAlphaFunc(GL2.GL_GREATER, 0.0f);

        // Enable blending in premultiplied color mode.
        gl.glEnable(GL.GL_BLEND);
        OGLUtil.applyBlending(gl, true);

        gl.glDisable(GL.GL_CULL_FACE);
        gl.glDisable(GL.GL_DEPTH_TEST);
        gl.glDisable(GL2.GL_LIGHTING);
        gl.glDisable(GL.GL_TEXTURE_2D);
    }

    protected void endRendering(DrawContext dc, OGLStackHandler stackHandler)
    {
        if (dc == null)
        {
            String message = Logging.getMessage("nullValue.DrawContextIsNull");
            Logging.logger().fine(message);
            throw new IllegalArgumentException(message);
        }

        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.

        stackHandler.pop(gl);
    }

    //**************************************************************//
    //********************  Background Rendering  ******************//
    //**************************************************************//

    protected void drawToolTipInterior(DrawContext dc, double width, double height, ToolTipAttributes attributes)
    {
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.

        this.applyColor(dc, attributes.getInteriorColor(), attributes.getInteriorOpacity());

        // Draw a filled rectangle with the background dimensions.
        gl.glRectd(0, 0, width, height);
    }

    protected void drawToolTipOutline(DrawContext dc, double width, double height, ToolTipAttributes attributes)
    {
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.

        this.applyColor(dc, attributes.getOutlineColor(), attributes.getOutlineOpacity());
        gl.glLineWidth((float) getOutlineWidth());

        // Draw a line loop around the background rectangle. Inset the lines slightly to compensate for OpenGL's line
        // rasterization algorithm. We want the line to straddle the rectangle pixels.
        double inset = 0.5;
        gl.glBegin(GL2.GL_LINE_LOOP);
        gl.glVertex2d(inset, inset);
        gl.glVertex2d(width - inset, inset);
        gl.glVertex2d(width - inset, height - inset);
        gl.glVertex2d(inset, height - inset);
        gl.glEnd();
    }

    //**************************************************************//
    //********************  Text Rendering  ************************//
    //**************************************************************//

    protected void drawToolTipText(DrawContext dc, String text, int x, int y, ToolTipAttributes attributes)
    {
        java.awt.Color textColor = this.modulateColorOpacity(attributes.getTextColor(),
            attributes.getTextOpacity());

        TextRenderer textRenderer = this.getTextRenderer(dc, attributes.getFont());
        textRenderer.begin3DRendering();
        textRenderer.setColor(textColor);
        textRenderer.draw(text, x, y);
        textRenderer.end3DRendering();
    }

    //**************************************************************//
    //********************  Rendering Utilities  *******************//
    //**************************************************************//

    protected TextRenderer getTextRenderer(DrawContext dc, java.awt.Font font)
    {
        return OGLTextRenderer.getOrCreateTextRenderer(dc.getTextRendererCache(), font);
    }

    protected void applyColor(DrawContext dc, java.awt.Color color, double opacity)
    {
        if (dc.isPickingMode())
            return;

        double finalOpacity = opacity * (color.getAlpha() / 255.0);
        GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
        OGLUtil.applyColor(gl, color, finalOpacity, true);
    }

    protected java.awt.Color modulateColorOpacity(java.awt.Color color, double opacity)
    {
        float[] compArray = new float[4];
        color.getRGBComponents(compArray);
        compArray[3] *= (float) opacity;

        return new java.awt.Color(compArray[0], compArray[1], compArray[2], compArray[3]);
    }

    //**************************************************************//
    //********************  Bounds Computation  ********************//
    //**************************************************************//

    protected java.awt.geom.Rectangle2D computeTextBounds(DrawContext dc, String text, java.awt.Font font)
    {
        TextRenderer textRenderer = this.getTextRenderer(dc, font);
        return textRenderer.getBounds(text);
    }

    @SuppressWarnings({"UnusedDeclaration"})
    protected java.awt.geom.Point2D computeTextTranslation(DrawContext dc, java.awt.geom.Rectangle2D textBounds,
        java.awt.Insets insets)
    {
        // The text bounds are assumed to come from the return value of a call to TextRenderer.getBounds(). The bounds
        // place the origin in the upper left hand corner, with the y axis increasing downward. The y
        // coordinate in the bounds corresponds to the baseline of the leftmost character.

        return new java.awt.geom.Point2D.Double(
            insets.left - textBounds.getX(),
            insets.bottom + textBounds.getY() + textBounds.getHeight());
    }

    @SuppressWarnings({"UnusedDeclaration"})
    protected java.awt.geom.Rectangle2D computeBackgroundBounds(DrawContext dc, double width, double height,
        java.awt.Insets insets)
    {
        return new java.awt.geom.Rectangle2D.Double(
            0, 0,
            width + (insets.left + insets.right),
            height + (insets.top + insets.bottom));
    }

    protected java.awt.Point adjustDrawPointToViewport(int x, int y, java.awt.geom.Rectangle2D bounds,
        java.awt.Rectangle viewport)
    {
        if (x + bounds.getMaxX() > viewport.getWidth())
            x = (int) (viewport.getWidth() - bounds.getWidth()) - 1;
        else if (x < 0)
            x = 0;

        if (y + bounds.getMaxY() > viewport.getHeight())
            y = (int) (viewport.getHeight() - bounds.getHeight()) - 1;
        else if (y < 0)
            y = 0;

        return new java.awt.Point(x, y);
    }

    //**************************************************************//
    //********************  ToolTip Attributes  ********************//
    //**************************************************************//

    protected static class ToolTipAttributes
    {
        protected java.awt.Font font;
        protected java.awt.Color textColor;
        protected java.awt.Color interiorColor;
        protected java.awt.Color outlineColor;
        protected double textOpacity;
        protected double interiorOpacity;
        protected double outlineOpacity;
        protected double borderWidth;
        protected java.awt.Insets insets;

        public ToolTipAttributes(java.awt.Font font, java.awt.Color textColor,
            java.awt.Color interiorColor, java.awt.Color outlineColor,
            double textOpacity, double interiorOpacity, double outlineOpacity,
            double borderWidth, Insets insets)
        {
            this.font = font;
            this.textColor = textColor;
            this.interiorColor = interiorColor;
            this.outlineColor = outlineColor;
            this.textOpacity = textOpacity;
            this.interiorOpacity = interiorOpacity;
            this.outlineOpacity = outlineOpacity;
            this.borderWidth = borderWidth;
            this.insets = insets;
        }

        public java.awt.Font getFont()
        {
            return this.font;
        }

        public void setFont(java.awt.Font font)
        {
            this.font = font;
        }

        public java.awt.Color getTextColor()
        {
            return this.textColor;
        }

        public void setTextColor(java.awt.Color color)
        {
            this.textColor = color;
        }

        public java.awt.Color getInteriorColor()
        {
            return this.interiorColor;
        }

        public void setInteriorColor(java.awt.Color color)
        {
            this.interiorColor = color;
        }

        public java.awt.Color getOutlineColor()
        {
            return this.outlineColor;
        }

        public void setOutlineColor(java.awt.Color color)
        {
            this.outlineColor = color;
        }

        public double getTextOpacity()
        {
            return this.textOpacity;
        }

        public void setTextOpacity(double textOpacity)
        {
            this.textOpacity = textOpacity;
        }

        public double getInteriorOpacity()
        {
            return this.interiorOpacity;
        }

        public void setInteriorOpacity(double interiorOpacity)
        {
            this.interiorOpacity = interiorOpacity;
        }

        public double getOutlineOpacity()
        {
            return this.outlineOpacity;
        }

        public void setOutlineOpacity(double outlineOpacity)
        {
            this.outlineOpacity = outlineOpacity;
        }

        public double getBorderWidth()
        {
            return this.borderWidth;
        }

        public void setBorderWidth(double borderWidth)
        {
            this.borderWidth = borderWidth;
        }

        public java.awt.Insets getInsets()
        {
            return this.insets;
        }

        public void setInsets(java.awt.Insets insets)
        {
            this.insets = insets;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy