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

eu.hansolo.steelseries.gauges.AbstractRadial Maven / Gradle / Ivy

package eu.hansolo.steelseries.gauges;


/**
 *
 * @author hansolo
 */
public abstract class AbstractRadial extends AbstractGauge implements Lcd
{
    //       
    protected static final float ANGLE_CONST = 1f / 360f;
    private final java.awt.Rectangle INNER_BOUNDS;
    private final java.awt.Rectangle GAUGE_BOUNDS;
    private final java.awt.GraphicsConfiguration GFX_CONF;
    // Frame type related
    private eu.hansolo.steelseries.tools.Direction tickmarkDirection;            
    // LED related variables
    private java.awt.geom.Point2D ledPosition;
    // LCD related variables    
    private String lcdUnitString;        
    private double lcdValue;             
    private org.pushingpixels.trident.Timeline lcdTimeline;
    // Animation related variables
    private org.pushingpixels.trident.Timeline timeline;
    private final org.pushingpixels.trident.ease.TimelineEase STANDARD_EASING;
    private final org.pushingpixels.trident.ease.TimelineEase RETURN_TO_ZERO_EASING;
    private org.pushingpixels.trident.callback.TimelineCallback timelineCallback;    
    // 
    
    // 
    public AbstractRadial()
    {
        super();                
        lcdValue = 0;                    
        lcdTimeline = new org.pushingpixels.trident.Timeline(this);
        lcdUnitString = getUnitString(); 
        ledPosition = new java.awt.geom.Point2D.Double(0.6, 0.4);
        INNER_BOUNDS = new java.awt.Rectangle(getPreferredSize());
        GAUGE_BOUNDS = new java.awt.Rectangle(getPreferredSize());
        GFX_CONF = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        tickmarkDirection = eu.hansolo.steelseries.tools.Direction.CLOCKWISE;                                      
        timeline = new org.pushingpixels.trident.Timeline(this);        
        STANDARD_EASING = new org.pushingpixels.trident.ease.Spline(0.5f);            
        RETURN_TO_ZERO_EASING = new org.pushingpixels.trident.ease.Sine();        
    }
    // 
    
    //           
    /**
     * Returns the enum that defines the type of the gauge
     * FG_TYPE1    a quarter gauge (90 deg)
     * FG_TYPE2    a two quarter gauge (180 deg)
     * FG_TYPE3    a three quarter gauge (270 deg)
     * TYPE4    a four quarter gauge (300 deg)
     * @return the type of the gauge (90, 180, 270 or 300 deg)
     */
    public eu.hansolo.steelseries.tools.GaugeType getGaugeType()
    {
        return getModel().getGaugeType();
    }
    
    /**
     * Sets the type of the gauge
     * FG_TYPE1    a quarter gauge (90 deg)
     * FG_TYPE2    a two quarter gauge (180 deg)
     * FG_TYPE3    a three quarter gauge (270 deg)
     * TYPE4    a four quarter gauge (300 deg) 
     * @param GAUGE_TYPE 
     */
    public void setGaugeType(final eu.hansolo.steelseries.tools.GaugeType GAUGE_TYPE)
    {
        getModel().setGaugeType(GAUGE_TYPE);                
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns the type of frame that is used for the radial gauge.
     * It could be round our square.
     * @return the type of frame that will be used for the radial gauge.
     */
    public eu.hansolo.steelseries.tools.FrameType getFrameType()        
    {
        return getModel().getFrameType();
    }
    
    /**
     * Defines the type of frame that will be used for the radial gauge.
     * It could be round our square.
     * @param FRAME_TYPE 
     */
    public void setFrameType(final eu.hansolo.steelseries.tools.FrameType FRAME_TYPE)
    {
        getModel().setFrameType(FRAME_TYPE);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns the type of foreground that is used for the radial gauge.
     * There are three types available.
     * @return the type of foreground that is will be used for the radial gauge
     */
    public eu.hansolo.steelseries.tools.ForegroundType getForegroundType()
    {
        return getModel().getForegroundType();
    }
    
    /**
     * Defines the type of foreground that will be used for the radial gauge.
     * There area three types available.
     * @param FOREGROUND_TYPE 
     */
    public void setForegroundType(final eu.hansolo.steelseries.tools.ForegroundType FOREGROUND_TYPE)
    {
        getModel().setForegroundType(FOREGROUND_TYPE);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
                
    /**
     * Uses trident animation library to animate
     * the setting of the value.
     * The method plays a defined trident timeline
     * that calls the setValue(double value) method
     * with a given easing behaviour and duration.
     * You should always use this method to set the
     * gauge to a given value.
     * @param VALUE
     */
    public void setValueAnimated(final double VALUE)
    {           
        if (isEnabled())
        {
            if (timeline.getState() != org.pushingpixels.trident.Timeline.TimelineState.IDLE)
            {
                timeline.abort();
            }

            //double overallRange = getMaxValue() - getMinValue();
            //double range = Math.abs(getValue() - VALUE);
            //double fraction = range / overallRange;
            
            if (!isAutoResetToZero())            
            {               
                timeline.removeCallback(timelineCallback);
                timeline = new org.pushingpixels.trident.Timeline(this);
                timeline.addPropertyToInterpolate("value", getValue(), VALUE);
                timeline.setEase(STANDARD_EASING);
                //TIMELINE.setDuration((long) (getStdTimeToValue() * fraction));
                timeline.setDuration(getStdTimeToValue());
                timelineCallback = new org.pushingpixels.trident.callback.TimelineCallback()
                {
                    @Override
                    public void onTimelineStateChanged(final org.pushingpixels.trident.Timeline.TimelineState OLD_STATE, final org.pushingpixels.trident.Timeline.TimelineState NEW_STATE, final float OLD_VALUE, final float NEW_VALUE)
                    {
                        if (NEW_STATE == org.pushingpixels.trident.Timeline.TimelineState.IDLE)
                        {
                            repaint(getInnerBounds());
                        }

                        // Check if current value exceeds maxMeasuredValue
                        if (getValue() > getMaxMeasuredValue())
                        {
                            setMaxMeasuredValue(getValue());
                        }
                    }

                    @Override
                    public void onTimelinePulse(final float OLD_VALUE, final float NEW_VALUE)
                    {                
                        // Check if current value exceeds maxMeasuredValue
                        if (getValue() > getMaxMeasuredValue())
                        {
                            setMaxMeasuredValue(getValue());
                        }

                        // Check if current value exceeds minMeasuredValue
                        if (getValue() < getMinMeasuredValue())
                        {
                            setMinMeasuredValue(getValue());
                        }
                    }
                };
                timeline.addCallback(timelineCallback);   
                timeline.play();
            }
            else
            {
                final org.pushingpixels.trident.TimelineScenario AUTOZERO_SCENARIO = new org.pushingpixels.trident.TimelineScenario.Sequence();

                final org.pushingpixels.trident.Timeline TIMELINE_TO_VALUE = new org.pushingpixels.trident.Timeline(this);
                TIMELINE_TO_VALUE.addPropertyToInterpolate("value", getValue(), VALUE);
                TIMELINE_TO_VALUE.setEase(RETURN_TO_ZERO_EASING);
                //TIMELINE_TO_VALUE.setDuration((long) (getRtzTimeToValue() * fraction));
                TIMELINE_TO_VALUE.setDuration(getRtzTimeToValue());
                TIMELINE_TO_VALUE.addCallback(new org.pushingpixels.trident.callback.TimelineCallback()
                {
                    @Override
                    public void onTimelineStateChanged(org.pushingpixels.trident.Timeline.TimelineState oldState, org.pushingpixels.trident.Timeline.TimelineState newState, float oldValue, float newValue)
                    {
                        if (oldState == org.pushingpixels.trident.Timeline.TimelineState.PLAYING_FORWARD && newState == org.pushingpixels.trident.Timeline.TimelineState.DONE)
                        {
                            // Set the peak value and start the timer
                            getModel().setPeakValue(getValue());
                            getModel().setPeakValueVisible(true);
                            if (getPeakTimer().isRunning())
                            {
                                stopPeakTimer();
                            }
                            startPeakTimer();

                            // Check if current value exceeds maxMeasuredValue
                            if (getValue() > getMaxMeasuredValue())
                            {
                                setMaxMeasuredValue(getValue());
                            }
                        }
                    }

                    @Override
                    public void onTimelinePulse(float oldValue, float newValue)
                    {                        
                        // Check if current value exceeds maxMeasuredValue
                        if (getValue() > getMaxMeasuredValue())
                        {
                            setMaxMeasuredValue(getValue());
                        }

                        // Check if current value exceeds minMeasuredValue
                        if (getValue() < getMinMeasuredValue())
                        {
                            setMinMeasuredValue(getValue());
                        }
                    }
                });

                final org.pushingpixels.trident.Timeline TIMELINE_TO_ZERO = new org.pushingpixels.trident.Timeline(this);
                TIMELINE_TO_ZERO.addPropertyToInterpolate("value", VALUE, 0.0);
                TIMELINE_TO_ZERO.setEase(RETURN_TO_ZERO_EASING);
                //TIMELINE_TO_ZERO.setDuration((long) (getRtzTimeBackToZero() * fraction));
                TIMELINE_TO_ZERO.setDuration(getRtzTimeBackToZero());

                AUTOZERO_SCENARIO.addScenarioActor(TIMELINE_TO_VALUE);
                AUTOZERO_SCENARIO.addScenarioActor(TIMELINE_TO_ZERO);

//                AUTOZERO_SCENARIO.addCallback(new org.pushingpixels.trident.callback.TimelineScenarioCallback()
//                {
//                    @Override
//                    public void onTimelineScenarioDone()
//                    {
//                    }
//                });

                AUTOZERO_SCENARIO.play();
            }                     
        }
    }
   
    /**
     * Returns the step between the tickmarks
     * @return returns double value that represents the stepsize between the tickmarks
     */
    public double getAngleStep()
    {
        return getModel().getAngleStep();
    }
           
    /**
     * Returns the angle area where no tickmarks will be drawn
     * @return the angle area where no tickmarks will be drawn
     */
    public double getFreeAreaAngle()
    {
        return getModel().getFreeAreaAngle();
    }
        
    public double getRotationOffset()
    {
        return getModel().getRotationOffset();
    }
    
    public double getTickmarkOffset()
    {
        return getModel().getTickmarkOffset();
    }
    
    public int getMaxNoOfMinorTicks()
    {
        return getModel().getMaxNoOfMinorTicks();
    }
    
    public void setMaxNoOfMinorTicks(final int MAX_NO_OF_MINOR_TICKS)
    {
        getModel().setMaxNoOfMinorTicks(MAX_NO_OF_MINOR_TICKS);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    public int getMaxNoOfMajorTicks()
    {
        return getModel().getMaxNoOfMajorTicks();
    }
    
    public void setMaxNoOfMajorTicks(final int MAX_NO_OF_MAJOR_TICKS)
    {
        getModel().setMaxNoOfMajorTicks(MAX_NO_OF_MAJOR_TICKS);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns the current position of the gauge threshold led
     * @return the current position of the gauge threshold led
     */
    @Override
    public java.awt.geom.Point2D getLedPosition()
    {
        return ledPosition;
    }
    
    /**
     * Sets the position of the gauge threshold led to the given values
     * @param X
     * @param Y 
     */
    @Override
    public void setLedPosition(final double X, final double Y)
    {
        ledPosition.setLocation(X, Y);
        repaint(getInnerBounds());
    }
    
    /**
     * Sets the position of the gauge threshold led to the given values
     * @param LED_POSITION 
     */
    public void setLedPosition(final java.awt.geom.Point2D LED_POSITION)
    {
        ledPosition.setLocation(LED_POSITION);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns the direction of the tickmark labels.
     * CLOCKWISE is the standard and counts the labels like on a analog clock
     * COUNTER_CLOCKWISE could be useful for gauges like Radial1Square in SOUTH_EAST orientation
     * @return the direction of the tickmark counting
     */
    public eu.hansolo.steelseries.tools.Direction getTickmarkDirection()
    {
        return tickmarkDirection;
    }
    
    /**
     * Sets the direction of the tickmark label counting.
     * CLOCKWISE will count in clockwise direction
     * COUNTER_CLOCKWISE will count the opposite way
     * @param DIRECTION
     */
    public void setTickmarkDirection(final eu.hansolo.steelseries.tools.Direction DIRECTION)
    {
        this.tickmarkDirection = DIRECTION;        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns the type of the pointer
     * FG_TYPE1 (standard version) or FG_TYPE2
     * @return the type of the pointer
     */
    public eu.hansolo.steelseries.tools.PointerType getPointerType()
    {
        return getModel().getPointerType();
    }

    /**
     * Sets the type of the pointer
     * @param POINTER_TYPE type of the pointer
     *     eu.hansolo.steelseries.tools.PointerType.TYPE1 (default)
     *     eu.hansolo.steelseries.tools.PointerType.TYPE2
     *     eu.hansolo.steelseries.tools.PointerType.TYPE3
     *     eu.hansolo.steelseries.tools.PointerType.TYPE4
     */
    public void setPointerType(final eu.hansolo.steelseries.tools.PointerType POINTER_TYPE)
    {
        getModel().setPointerType(POINTER_TYPE);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    /**
     * Returns the color of the pointer
     * @return the selected color of the pointer
     */
    public eu.hansolo.steelseries.tools.ColorDef getPointerColor()
    {
        return getModel().getPointerColor();
    }

    /**
     * Sets the color of the pointer
     * @param POINTER_COLOR
     */
    public void setPointerColor(final eu.hansolo.steelseries.tools.ColorDef POINTER_COLOR)
    {
        getModel().setPointerColor(POINTER_COLOR);        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }        

    /**
     * Returns the color from which the custom pointer color will be calculated
     * @return the color from which the custom pointer color will be calculated
     */
    public java.awt.Color getCustomPointerColor()
    {
        return getModel().getCustomPointerColor();
    }
    
    /**
     * Sets the color from which the custom pointer color is calculated
     * @param COLOR 
     */
    public void setCustomPointerColor(final java.awt.Color COLOR)
    {
        getModel().setCustomPointerColorObject(new eu.hansolo.steelseries.tools.CustomColorDef(COLOR));        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns the object that represents the custom pointer color
     * @return the object that represents the custom pointer color
     */
    public eu.hansolo.steelseries.tools.CustomColorDef getCustomPointerColorObject()
    {
        return getModel().getCustomPointerColorObject();
    }
    
    /**
     * Returns the type of the knob
     * @return the type of the knob
     */
    public eu.hansolo.steelseries.tools.KnobType getKnobType()
    {
        return getModel().getKnobType();
    }
    
    /**
     * Sets the type of the knob
     * @param KNOB_TYPE 
     */
    public void setKnobType(final eu.hansolo.steelseries.tools.KnobType KNOB_TYPE)
    {
        getModel().setKnobType(KNOB_TYPE);        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
        
    /**
     * Returns the visibility of the lcd display
     * @return true if the lcd display is visible
     */
    public boolean isLcdVisible()
    {
        return getModel().isLcdVisible();
    }
    
    /**
     * Enables or disables the visibility of the lcd display
     * @param LCD_VISIBLE 
     */
    public void setLcdVisible(final boolean LCD_VISIBLE)
    {
        getModel().setLcdVisible(LCD_VISIBLE);        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    /**
     * Returns true if the arc that represents the range of measured values is visible
     * @return true if the arc that represents the range of measured values is visible
     */
    public boolean isRangeOfMeasuredValuesVisible()
    {
        return getModel().isRangeOfMeasuredValuesVisible();
    }
    
    /**
     * Enables / disables the visibility of the arc that represents the range of measured values
     * @param RANGE_OF_MEASURED_VALUES_VISIBLE 
     */
    public void setRangeOfMeasuredValuesVisible(final boolean RANGE_OF_MEASURED_VALUES_VISIBLE)
    {
        getModel().setRangeOfMeasuredValuesVisible(RANGE_OF_MEASURED_VALUES_VISIBLE);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    @Override
    public boolean isValueCoupled()
    {
        return getModel().isValueCoupled();        
    }
    
    @Override
    public void setValueCoupled(final boolean VALUE_COUPLED)
    {
        getModel().setValueCoupled(VALUE_COUPLED);        
        repaint(getInnerBounds());
    }
    
    @Override
    public double getLcdValue()
    {
        return this.lcdValue;
    }

    @Override
    public void setLcdValue(final double LCD_VALUE)
    {
        this.lcdValue = LCD_VALUE;
        repaint(getInnerBounds());
    }

    @Override
    public void setLcdValueAnimated(final double LCD_VALUE)
    {        
        if (lcdTimeline.getState() == org.pushingpixels.trident.Timeline.TimelineState.PLAYING_FORWARD || lcdTimeline.getState() == org.pushingpixels.trident.Timeline.TimelineState.PLAYING_REVERSE)
        {
            lcdTimeline.abort();
        }
        lcdTimeline = new org.pushingpixels.trident.Timeline(this);
        lcdTimeline.addPropertyToInterpolate("lcdValue", this.lcdValue, LCD_VALUE);
        lcdTimeline.setEase(new org.pushingpixels.trident.ease.Spline(0.5f));
  
        lcdTimeline.play();
    }

    @Override
    public String getLcdUnitString()
    {
        return lcdUnitString;
    }

    @Override
    public void setLcdUnitString(final String UNIT_STRING)
    {
        this.lcdUnitString = UNIT_STRING;        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public boolean isLcdUnitStringVisible()
    {
        return getModel().isLcdUnitStringVisible();        
    }

    @Override
    public void setLcdUnitStringVisible(final boolean UNIT_STRING_VISIBLE)
    {
        getModel().setLcdUnitStringVisible(UNIT_STRING_VISIBLE);        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public boolean isDigitalFont()
    {
        return getModel().isDigitalFontEnabled();        
    }

    @Override
    public void setDigitalFont(final boolean DIGITAL_FONT)
    {
        getModel().setDigitalFontEnabled(DIGITAL_FONT);        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public boolean isCustomLcdUnitFontEnabled()
    {
        return getModel().isCustomLcdUnitFontEnabled();        
    }

    @Override
    public void setCustomLcdUnitFontEnabled(final boolean USE_CUSTOM_LCD_UNIT_FONT)
    {
        getModel().setCustomLcdUnitFontEnabled(USE_CUSTOM_LCD_UNIT_FONT);        
        repaint(getInnerBounds());
    }

    @Override
    public java.awt.Font getCustomLcdUnitFont()
    {
        return getModel().getCustomLcdUnitFont();        
    }

    @Override
    public void setCustomLcdUnitFont(final java.awt.Font CUSTOM_LCD_UNIT_FONT)
    {
        getModel().setCustomLcdUnitFont(CUSTOM_LCD_UNIT_FONT);        
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public int getLcdDecimals()
    {
        return getModel().getLcdDecimals();        
    }

    @Override
    public void setLcdDecimals(final int DECIMALS)
    {
        getModel().setLcdDecimals(DECIMALS);        
        repaint(getInnerBounds());
    }

    @Override
    public eu.hansolo.steelseries.tools.LcdColor getLcdColor()
    {
        return getModel().getLcdColor();
    }

    @Override
    public void setLcdColor(final eu.hansolo.steelseries.tools.LcdColor LCD_COLOR)
    {
        getModel().setLcdColor(LCD_COLOR);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public java.awt.Paint getCustomLcdBackground()
    {
        return getModel().getCustomLcdBackground();
    }
    
    @Override
    public void setCustomLcdBackground(final java.awt.Paint CUSTOM_LCD_BACKGROUND)
    {
        getModel().setCustomLcdBackground(CUSTOM_LCD_BACKGROUND);         
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    @Override
    public java.awt.Color getCustomLcdForeground()
    {
        return getModel().getCustomLcdForeground();
    }
    
    @Override
    public void setCustomLcdForeground(final java.awt.Color CUSTOM_LCD_FOREGROUND)
    {
        getModel().setCustomLcdForeground(CUSTOM_LCD_FOREGROUND);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    @Override
    public String formatLcdValue(final double VALUE)
    {
        final StringBuilder DEC_BUFFER = new StringBuilder(16);
        DEC_BUFFER.append("0");

        if (getModel().getLcdDecimals() > 0)
        {
            DEC_BUFFER.append(".");
        }

        for (int i = 0; i < getModel().getLcdDecimals(); i++)
        {
            DEC_BUFFER.append("0");
        }

        if(getModel().isLcdScientificFormatEnabled())
        {
            DEC_BUFFER.append("E0");
        }

        DEC_BUFFER.trimToSize();
        final java.text.DecimalFormat DEC_FORMAT = new java.text.DecimalFormat(DEC_BUFFER.toString(), new java.text.DecimalFormatSymbols(java.util.Locale.US));

        return DEC_FORMAT.format(VALUE);
    }

    @Override
    public boolean isLcdScientificFormat()
    {
        return getModel().isLcdScientificFormatEnabled();        
    }

    @Override
    public void setLcdScientificFormat(boolean LCD_SCIENTIFIC_FORMAT)
    {
        getModel().setLcdScientificFormatEnabled(LCD_SCIENTIFIC_FORMAT);        
        repaint(getInnerBounds());
    }
    
    @Override
    public java.awt.Font getLcdValueFont()
    {
        return getModel().getLcdValueFont();        
    }
    
    @Override
    public void setLcdValueFont(final java.awt.Font LCD_VALUE_FONT)
    {        
        getModel().setLcdValueFont(LCD_VALUE_FONT);
        repaint(getInnerBounds());
    }
    
    @Override
    public java.awt.Font getLcdUnitFont()
    {
        return getModel().getLcdUnitFont();
    }
    
    @Override
    public void setLcdUnitFont(final java.awt.Font LCD_UNIT_FONT)
    {
        getModel().setLcdUnitFont(LCD_UNIT_FONT);
        repaint(getInnerBounds());
    }
    // 

    //             
    /**
     * Returns a radial gradient paint that will be used as overlay for the track or section image
     * to achieve some kind of a 3d effect.
     * @param WIDTH
     * @param RADIUS_FACTOR : 0.38f for the standard radial gauge
     * @return a radial gradient paint that will be used as overlay for the track or section image
     */
    protected java.awt.RadialGradientPaint create_3D_RADIAL_GRADIENT(final int WIDTH, final float RADIUS_FACTOR)
    {
        final float[] FRACTIONS =
        {
            0.0f,
            0.89f,
            0.955f,
            1.0f
        };
        
        final java.awt.Color[] COLORS =
        {
            new java.awt.Color(0.0f, 0.0f, 0.0f, 0.0f),
            new java.awt.Color(0.0f, 0.0f, 0.0f, 0.3f),
            new java.awt.Color(1.0f, 1.0f, 1.0f, 0.6f),
            new java.awt.Color(0.0f, 0.0f, 0.0f, 0.4f)
        };
        
        final java.awt.geom.Point2D GRADIENT_CENTER = new java.awt.geom.Point2D.Double(WIDTH / 2.0, WIDTH / 2.0);
                        
        return new java.awt.RadialGradientPaint(GRADIENT_CENTER, WIDTH * RADIUS_FACTOR, FRACTIONS, COLORS);
    }
    
    /**
     * Returns the frame image with the currently active framedesign
     * with the given width and the current frame type.
     * @param WIDTH
     * @return buffered image containing the frame in the active frame design
     */
    protected java.awt.image.BufferedImage create_FRAME_Image(final int WIDTH)
    {
        switch (getFrameType())
        {
            case ROUND:
                return FRAME_FACTORY.createRadialFrame(WIDTH, getFrameDesign(), getCustomFrameDesign(), isFrame3dEffectVisible());                
            case SQUARE:
                return FRAME_FACTORY.createLinearFrame(WIDTH, getFrameDesign(), getCustomFrameDesign(), isFrame3dEffectVisible());
            default:
                return FRAME_FACTORY.createRadialFrame(WIDTH, getFrameDesign(), getCustomFrameDesign(), isFrame3dEffectVisible());
        }
    }
    
    /**
     * Returns the background image with the currently active backgroundcolor
     * with the given width without a title and a unit string.
     * @param WIDTH
     * @return the background image that is used
     */
    protected java.awt.image.BufferedImage create_BACKGROUND_Image(final int WIDTH)
    {
        return create_BACKGROUND_Image(WIDTH, "", "");
    }

    /**
     * Returns the background image with the currently active backgroundcolor
     * with the given width, title and unitstring.
     * @param WIDTH
     * @param TITLE
     * @param UNIT_STRING 
     * @return buffered image containing the background with the selected background design
     */
    protected java.awt.image.BufferedImage create_BACKGROUND_Image(final int WIDTH, final String TITLE, final String UNIT_STRING)
    {        
        return create_BACKGROUND_Image(WIDTH, TITLE, UNIT_STRING, null);
    }

    /**
     * Returns the background image with the currently active backgroundcolor
     * with the given width, title and unitstring.
     * @param WIDTH
     * @param TITLE
     * @param UNIT_STRING
     * @param image
     * @return buffered image containing the background with the selected background design
     */
    protected java.awt.image.BufferedImage create_BACKGROUND_Image(final int WIDTH, final String TITLE, final String UNIT_STRING, java.awt.image.BufferedImage image)
    {
        if (WIDTH <= 0)
        {
            return null;
        }
        
        if (image == null)
        {
            image = GFX_CONF.createCompatibleImage(WIDTH, WIDTH, java.awt.Transparency.TRANSLUCENT);
        }        
            
        final java.awt.Graphics2D G2 = image.createGraphics();
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);

        final int IMAGE_WIDTH = image.getWidth();
        final int IMAGE_HEIGHT = image.getHeight();
        
        switch(getFrameType())
        {                            
            case SQUARE:
                BACKGROUND_FACTORY.createLinearBackground(WIDTH, WIDTH, getBackgroundColor(), getModel().getCustomBackground(), image);
                break;
            case ROUND:
                
            default:                
                BACKGROUND_FACTORY.createRadialBackground(WIDTH, getBackgroundColor(), getModel().getCustomBackground(), image);
                break;
        }

        // Draw the custom layer if selected
        if (isCustomLayerVisible())
        {
            G2.drawImage(UTIL.getScaledInstance(getCustomLayer(), IMAGE_WIDTH, IMAGE_HEIGHT, java.awt.RenderingHints.VALUE_INTERPOLATION_BICUBIC), 0, 0, null);
        }

        final java.awt.font.FontRenderContext RENDER_CONTEXT = new java.awt.font.FontRenderContext(null, true, true);

        if (!TITLE.isEmpty())
        {
            // Use custom label color if selected
            if (isLabelColorFromThemeEnabled())
            {
                G2.setColor(getModel().getBackgroundColor().LABEL_COLOR);
            }
            else
            {
                G2.setColor(getModel().getLabelColor());
            }

            // Use custom font if selected
            if (isTitleAndUnitFontEnabled())
            {
                G2.setFont(new java.awt.Font(getTitleAndUnitFont().getFamily(), 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            else
            {
                G2.setFont(new java.awt.Font("Verdana", 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            final java.awt.font.TextLayout TITLE_LAYOUT = new java.awt.font.TextLayout(TITLE, G2.getFont(), RENDER_CONTEXT);
            final java.awt.geom.Rectangle2D TITLE_BOUNDARY = TITLE_LAYOUT.getBounds();
            G2.drawString(TITLE, (float) ((IMAGE_WIDTH - TITLE_BOUNDARY.getWidth()) / 2.0), 0.3f * IMAGE_HEIGHT + TITLE_LAYOUT.getAscent() - TITLE_LAYOUT.getDescent());
        }

        if (!UNIT_STRING.isEmpty())
        {
            // Use custom label color if selected
            if (isLabelColorFromThemeEnabled())
            {
                G2.setColor(getModel().getBackgroundColor().LABEL_COLOR);
            }
            else
            {
                G2.setColor(getModel().getLabelColor());
            }

            // Use custom font if selected
            if (isTitleAndUnitFontEnabled())
            {
                G2.setFont(new java.awt.Font(getTitleAndUnitFont().getFamily(), 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            else
            {
                G2.setFont(new java.awt.Font("Verdana", 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            final java.awt.font.TextLayout UNIT_LAYOUT = new java.awt.font.TextLayout(UNIT_STRING, G2.getFont(), RENDER_CONTEXT);
            final java.awt.geom.Rectangle2D UNIT_BOUNDARY = UNIT_LAYOUT.getBounds();
            G2.drawString(UNIT_STRING, (float) ((IMAGE_WIDTH - UNIT_BOUNDARY.getWidth()) / 2.0), 0.38f * IMAGE_HEIGHT + UNIT_LAYOUT.getAscent() - UNIT_LAYOUT.getDescent());
        }

        G2.dispose();

        return image;
    }
    
    /**
     * Returns the image with the given title and unitstring.
     * @param WIDTH
     * @param TITLE
     * @param UNIT_STRING
     * @return the image with the given title and unitstring.
     */
    protected java.awt.image.BufferedImage create_TITLE_Image(final int WIDTH, final String TITLE, final String UNIT_STRING)
    {        
        return create_TITLE_Image(WIDTH, TITLE, UNIT_STRING, null);
    }

    /**
     * Returns the image with the given title and unitstring.
     * @param WIDTH
     * @param TITLE
     * @param UNIT_STRING
     * @param image
     * @return the image with the given title and unitstring.
     */
    protected java.awt.image.BufferedImage create_TITLE_Image(final int WIDTH, final String TITLE, final String UNIT_STRING, java.awt.image.BufferedImage image)
    {     
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(1, 1, java.awt.Transparency.TRANSLUCENT);
        }
        
        if (image == null)
        {
            image = GFX_CONF.createCompatibleImage(WIDTH, WIDTH, java.awt.Transparency.TRANSLUCENT);
        }
        
        final java.awt.Graphics2D G2 = image.createGraphics();
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);

        final int IMAGE_WIDTH = image.getWidth();
        final int IMAGE_HEIGHT = image.getHeight();

        final java.awt.font.FontRenderContext RENDER_CONTEXT = new java.awt.font.FontRenderContext(null, true, true);

        if (!TITLE.isEmpty())
        {
            // Use custom label color if selected
            if (isLabelColorFromThemeEnabled())
            {
                G2.setColor(getBackgroundColor().LABEL_COLOR);
            }
            else
            {
                G2.setColor(getLabelColor());
            }

            // Use custom font if selected
            if (isTitleAndUnitFontEnabled())
            {
                G2.setFont(new java.awt.Font(getTitleAndUnitFont().getFamily(), getTitleAndUnitFont().getStyle(), getTitleAndUnitFont().getSize()));
            }
            else
            {
                G2.setFont(new java.awt.Font("Verdana", 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            final java.awt.font.TextLayout TITLE_LAYOUT = new java.awt.font.TextLayout(TITLE, G2.getFont(), RENDER_CONTEXT);
            final java.awt.geom.Rectangle2D TITLE_BOUNDARY = TITLE_LAYOUT.getBounds();
            G2.drawString(TITLE, (float) ((IMAGE_WIDTH - TITLE_BOUNDARY.getWidth()) / 2.0), 0.3f * IMAGE_HEIGHT + TITLE_LAYOUT.getAscent() - TITLE_LAYOUT.getDescent());
        }

        if (!UNIT_STRING.isEmpty())
        {
            // Use custom label color if selected
            if (isLabelColorFromThemeEnabled())
            {
                G2.setColor(getBackgroundColor().LABEL_COLOR);
            }
            else
            {
                G2.setColor(getLabelColor());
            }

            // Use custom font if selected
            if (isTitleAndUnitFontEnabled())
            {
                G2.setFont(new java.awt.Font(getTitleAndUnitFont().getFamily(), 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            else
            {
                G2.setFont(new java.awt.Font("Verdana", 0, (int) (0.04672897196261682 * IMAGE_WIDTH)));
            }
            final java.awt.font.TextLayout UNIT_LAYOUT = new java.awt.font.TextLayout(UNIT_STRING, G2.getFont(), RENDER_CONTEXT);
            final java.awt.geom.Rectangle2D UNIT_BOUNDARY = UNIT_LAYOUT.getBounds();
            G2.drawString(UNIT_STRING, (float) ((IMAGE_WIDTH - UNIT_BOUNDARY.getWidth()) / 2.0), 0.37f * IMAGE_HEIGHT + UNIT_LAYOUT.getAscent() - UNIT_LAYOUT.getDescent());
        }

        G2.dispose();

        return image;
    }
    
    /**
     * Returns the image with the given lcd color.
     * @param WIDTH
     * @param HEIGHT
     * @param LCD_COLOR
     * @param CUSTOM_LCD_BACKGROUND 
     * @return buffered image containing the lcd with the selected lcd color
     */
    protected java.awt.image.BufferedImage create_LCD_Image(final int WIDTH, final int HEIGHT, final eu.hansolo.steelseries.tools.LcdColor LCD_COLOR, final java.awt.Paint CUSTOM_LCD_BACKGROUND)
    {        
        return create_LCD_Image(new java.awt.geom.Rectangle2D.Double(0, 0, WIDTH, HEIGHT), LCD_COLOR, CUSTOM_LCD_BACKGROUND, null);
    }
    
    /**
     * Returns the image with the given lcd color.
     * @param BOUNDS 
     * @param LCD_COLOR
     * @param CUSTOM_LCD_BACKGROUND 
     * @param IMAGE 
     * @return buffered image containing the lcd with the selected lcd color
     */
    protected java.awt.image.BufferedImage create_LCD_Image(final java.awt.geom.Rectangle2D BOUNDS, final eu.hansolo.steelseries.tools.LcdColor LCD_COLOR, final java.awt.Paint CUSTOM_LCD_BACKGROUND, final java.awt.image.BufferedImage IMAGE)
    {                
        return LCD_FACTORY.create_LCD_Image(BOUNDS, LCD_COLOR, CUSTOM_LCD_BACKGROUND, IMAGE);                                
    }
    
    /**
     * Returns the track image with a given values. The gradient will be created by drawing
     * a series of lines and varies the color of the lines. The linewidth will be calculated
     * from the size of the component and from the gaugeType.
     * @param WIDTH
     * @param FREE_AREA_ANGLE
     * @param ROTATION_OFFSET
     * @param MIN_VALUE
     * @param MAX_VALUE
     * @param ANGLE_STEP
     * @param TRACK_START
     * @param TRACK_SECTION
     * @param TRACK_STOP
     * @param TRACK_START_COLOR
     * @param TRACK_SECTION_COLOR
     * @param TRACK_STOP_COLOR
     * @param RADIUS_FACTOR
     * @param CENTER
     * @param DIRECTION
     * @param OFFSET
     * @return a buffered image that represents the image of the track
     */
    protected java.awt.image.BufferedImage create_TRACK_Image(final int WIDTH, final double FREE_AREA_ANGLE, final double ROTATION_OFFSET, final double MIN_VALUE, final double MAX_VALUE, final double ANGLE_STEP, final double TRACK_START, final double TRACK_SECTION, final double TRACK_STOP, final java.awt.Color TRACK_START_COLOR, final java.awt.Color TRACK_SECTION_COLOR, final java.awt.Color TRACK_STOP_COLOR, final float RADIUS_FACTOR, final java.awt.geom.Point2D CENTER, final eu.hansolo.steelseries.tools.Direction DIRECTION, final java.awt.geom.Point2D OFFSET)
    {        
        return create_TRACK_Image(WIDTH, FREE_AREA_ANGLE, ROTATION_OFFSET, MIN_VALUE, MAX_VALUE, ANGLE_STEP, TRACK_START, TRACK_SECTION, TRACK_STOP, TRACK_START_COLOR, TRACK_SECTION_COLOR, TRACK_STOP_COLOR, RADIUS_FACTOR, CENTER, DIRECTION, OFFSET, null);
    }

    /**
     * Returns the track image with a given values. The gradient will be created by drawing
     * a series of lines and varies the color of the lines. The linewidth will be calculated
     * from the size of the component and from the gaugeType.
     * @param WIDTH
     * @param FREE_AREA_ANGLE
     * @param ROTATION_OFFSET
     * @param MIN_VALUE
     * @param MAX_VALUE
     * @param ANGLE_STEP
     * @param TRACK_START
     * @param TRACK_SECTION
     * @param TRACK_STOP
     * @param TRACK_START_COLOR
     * @param TRACK_SECTION_COLOR
     * @param TRACK_STOP_COLOR
     * @param RADIUS_FACTOR
     * @param CENTER
     * @param DIRECTION
     * @param OFFSET
     * @param image
     * @return a buffered image that represents the image of the track
     */
    protected java.awt.image.BufferedImage create_TRACK_Image(final int WIDTH, final double FREE_AREA_ANGLE, final double ROTATION_OFFSET, final double MIN_VALUE, final double MAX_VALUE, final double ANGLE_STEP, final double TRACK_START, final double TRACK_SECTION, final double TRACK_STOP, final java.awt.Color TRACK_START_COLOR, final java.awt.Color TRACK_SECTION_COLOR, final java.awt.Color TRACK_STOP_COLOR, final float RADIUS_FACTOR, final java.awt.geom.Point2D CENTER, final eu.hansolo.steelseries.tools.Direction DIRECTION, final java.awt.geom.Point2D OFFSET, java.awt.image.BufferedImage image)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(1, 1, java.awt.Transparency.TRANSLUCENT);
        }

        if (image == null)
        {
            image = GFX_CONF.createCompatibleImage(WIDTH, WIDTH, java.awt.Transparency.TRANSLUCENT);
        }
        final java.awt.Graphics2D G2 = image.createGraphics();
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);        
        G2.setRenderingHint(java.awt.RenderingHints.KEY_STROKE_CONTROL, java.awt.RenderingHints.VALUE_STROKE_PURE);        
        final int IMAGE_WIDTH = image.getWidth();
        //final int IMAGE_HEIGHT = IMAGE.getHeight();

        if (OFFSET != null)
        {
            G2.translate(OFFSET.getX(), OFFSET.getY());
        }

        // Definitions
        float lineWidth;
        switch (getGaugeType())
        {
            case TYPE1:
                lineWidth = (float) Math.toDegrees(Math.PI / 2.0 - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            case TYPE2:
                lineWidth = (float) Math.toDegrees(Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            case TYPE3:
                lineWidth = (float) Math.toDegrees(1.5 * Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            case TYPE4:
                lineWidth = (float) Math.toDegrees(2.0 * Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            default:
                lineWidth = (float) Math.toDegrees(2.0 * Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
        }                
        if (lineWidth < 0.25f)
        {
            lineWidth = 0.25f;
        }
        final java.awt.BasicStroke STD_STROKE = new java.awt.BasicStroke(lineWidth, java.awt.BasicStroke.CAP_ROUND, java.awt.BasicStroke.JOIN_BEVEL);
                        
        final int TRACK_WIDTH = (int) (0.04 * WIDTH);

        final float RADIUS = IMAGE_WIDTH * RADIUS_FACTOR;

        // Define the lines
        final java.awt.geom.Point2D INNER_POINT = new java.awt.geom.Point2D.Double();
        final java.awt.geom.Point2D OUTER_POINT = new java.awt.geom.Point2D.Double();
        final java.awt.geom.Line2D TICK = new java.awt.geom.Line2D.Double();

        double sinValue = 0;
        double cosValue = 0;

        // Calculate the start, section and stop values dependend of the ticklabel direction
        final double TRACK_START_ANGLE;
        final double TRACK_SECTION_ANGLE;
        final double TRACK_STOP_ANGLE;

        final double ALPHA_START;
        final double ALPHA_SECTION;
        final double ALPHA_STOP;

        java.awt.Color currentColor;

        switch (DIRECTION)
        {
            case COUNTER_CLOCKWISE:
                TRACK_START_ANGLE = ((MAX_VALUE - TRACK_STOP) * ANGLE_STEP);
                TRACK_SECTION_ANGLE = ((MAX_VALUE - TRACK_SECTION) * ANGLE_STEP);
                TRACK_STOP_ANGLE = ((MAX_VALUE - TRACK_START) * ANGLE_STEP);

                ALPHA_START = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0) - TRACK_START_ANGLE; 
                ALPHA_SECTION = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0) - TRACK_SECTION_ANGLE;
                ALPHA_STOP = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0) - TRACK_STOP_ANGLE;
                currentColor = TRACK_STOP_COLOR;
                break;

            case CLOCKWISE:

            default:
                TRACK_START_ANGLE = (TRACK_START * ANGLE_STEP);
                TRACK_SECTION_ANGLE = (TRACK_SECTION * ANGLE_STEP);
                TRACK_STOP_ANGLE = (TRACK_STOP * ANGLE_STEP);

                ALPHA_START = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0) - TRACK_START_ANGLE; 
                ALPHA_SECTION = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0) - TRACK_SECTION_ANGLE;
                ALPHA_STOP = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0) - TRACK_STOP_ANGLE;
                currentColor = TRACK_START_COLOR;
                break;
        }
        
        // Define the stepsize between each line of the track so that it will work on small ranges like on large ranges
        final double RANGE_FACTOR = 1000 / (MAX_VALUE - MIN_VALUE) < 10 ? 10 : 1000 / (MAX_VALUE - MIN_VALUE);
        final double FRACTION_STEP = 1 / RANGE_FACTOR;
        
        G2.setStroke(STD_STROKE);           
        float fraction = 0;
        // Draw track from TRACK_START to TRACK_SECTION
        for (double alpha = ALPHA_START; Double.compare(alpha, ALPHA_SECTION) >= 0; alpha -= (ANGLE_STEP / RANGE_FACTOR), fraction += FRACTION_STEP)
        {
            sinValue = Math.sin(alpha);
            cosValue = Math.cos(alpha);
            switch(DIRECTION)
            {
                case CLOCKWISE:                    
                    currentColor = UTIL.getColorFromFraction(TRACK_START_COLOR, TRACK_SECTION_COLOR, (int) (TRACK_SECTION - TRACK_START), (int) (fraction));
                    break;

                case COUNTER_CLOCKWISE:                    
                    currentColor = UTIL.getColorFromFraction(TRACK_STOP_COLOR, TRACK_SECTION_COLOR, (int) (TRACK_STOP - TRACK_SECTION), (int) (fraction));
                    break;
            }
            
            G2.setColor(currentColor);
            INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TRACK_WIDTH) * sinValue, CENTER.getY() + (RADIUS - TRACK_WIDTH) * cosValue);
            OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);            
            
            TICK.setLine(INNER_POINT, OUTER_POINT);
            
            G2.draw(TICK);
        }

        // Draw track from TRACK_SECTION to TRACK_STOP
        fraction = 0;
        for (double alpha = ALPHA_SECTION; Double.compare(alpha, ALPHA_STOP) >= 0; alpha -= (ANGLE_STEP / RANGE_FACTOR), fraction += FRACTION_STEP)
        {
            sinValue = Math.sin(alpha);
            cosValue = Math.cos(alpha);
            switch(DIRECTION)
            {
                case CLOCKWISE:                    
                    currentColor = UTIL.getColorFromFraction(TRACK_SECTION_COLOR, TRACK_STOP_COLOR, (int) (TRACK_STOP - TRACK_SECTION), (int) (fraction));
                    break;
                case COUNTER_CLOCKWISE:                    
                    currentColor = UTIL.getColorFromFraction(TRACK_SECTION_COLOR, TRACK_START_COLOR, (int) (TRACK_SECTION - TRACK_START), (int) (fraction));
                    break;
            }

            G2.setColor(currentColor);
            INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TRACK_WIDTH) * sinValue, CENTER.getY() + (RADIUS - TRACK_WIDTH) * cosValue);
            OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);

            TICK.setLine(INNER_POINT, OUTER_POINT);

            G2.draw(TICK);
        }

        G2.dispose();
        
        return image;
    }
       
    /**
     * Returns the image of the posts for the pointer
     * @param WIDTH
     * @param POSITIONS
     * @return the post image that is used
     */
    protected java.awt.image.BufferedImage create_POSTS_Image(final int WIDTH, final eu.hansolo.steelseries.tools.PostPosition... POSITIONS)
    {        
        return create_POSTS_Image(WIDTH, null, POSITIONS);
    }

    /**
     * Returns the image of the posts for the pointer
     * @param WIDTH
     * @param POSITIONS
     * @param image
     * @return the post image that is used
     */
    protected java.awt.image.BufferedImage create_POSTS_Image(final int WIDTH, java.awt.image.BufferedImage image, final eu.hansolo.steelseries.tools.PostPosition... POSITIONS)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(1, 1, java.awt.Transparency.TRANSLUCENT);
        }

        if (image == null)
        {
            image = GFX_CONF.createCompatibleImage(WIDTH, WIDTH, java.awt.Transparency.TRANSLUCENT);
        }
        final java.awt.Graphics2D G2 = image.createGraphics();
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);

        final int IMAGE_WIDTH = image.getWidth();
        final int IMAGE_HEIGHT = image.getHeight();

        //final java.awt.image.BufferedImage CENTER_KNOB = create_KNOB_Image((int) (WIDTH * 0.09));
        final java.awt.image.BufferedImage SINGLE_POST = create_KNOB_Image((int) Math.ceil(WIDTH * 0.03738316893577576));
        
        final java.util.List POST_POSITION_LIST = java.util.Arrays.asList(POSITIONS);

        // Draw center knob
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.CENTER))
        {       
            switch (getKnobType())
            {
                case SMALL_STD_KNOB:                    
                    //G2.drawImage(KNOB_FACTORY.create_KNOB_Image((int) Math.ceil(IMAGE_WIDTH * 0.08411216735839844), eu.hansolo.steelseries.tools.KnobType.SMALL_STD_KNOB), (int) Math.ceil(IMAGE_WIDTH * 0.4579439163208008), (int) Math.ceil(IMAGE_WIDTH * 0.4579439163208008), null);
                    
                    final java.awt.geom.Ellipse2D CENTER_KNOB_FRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4579439163208008, IMAGE_HEIGHT * 0.4579439163208008, IMAGE_WIDTH * 0.08411216735839844, IMAGE_HEIGHT * 0.08411216735839844);
                    final java.awt.geom.Point2D CENTER_KNOB_FRAME_START = new java.awt.geom.Point2D.Double(0, CENTER_KNOB_FRAME.getBounds2D().getMinY());
                    final java.awt.geom.Point2D CENTER_KNOB_FRAME_STOP = new java.awt.geom.Point2D.Double(0, CENTER_KNOB_FRAME.getBounds2D().getMaxY());
                    final float[] CENTER_KNOB_FRAME_FRACTIONS =
                    {
                        0.0f,
                        0.46f,
                        1.0f
                    };
                    final java.awt.Color[] CENTER_KNOB_FRAME_COLORS =
                    {
                        new java.awt.Color(180, 180, 180, 255),
                        new java.awt.Color(63, 63, 63, 255),
                        new java.awt.Color(40, 40, 40, 255)
                    };

                    final java.awt.LinearGradientPaint CENTER_KNOB_FRAME_GRADIENT = new java.awt.LinearGradientPaint(CENTER_KNOB_FRAME_START, CENTER_KNOB_FRAME_STOP, CENTER_KNOB_FRAME_FRACTIONS, CENTER_KNOB_FRAME_COLORS);
                    G2.setPaint(CENTER_KNOB_FRAME_GRADIENT);
                    G2.fill(CENTER_KNOB_FRAME);

                    final java.awt.geom.Ellipse2D CENTER_KNOB_MAIN = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4672897160053253, IMAGE_HEIGHT * 0.4672897160053253, IMAGE_WIDTH * 0.06542053818702698, IMAGE_HEIGHT * 0.06542053818702698);
                    final java.awt.geom.Point2D CENTER_KNOB_MAIN_START = new java.awt.geom.Point2D.Double(0, CENTER_KNOB_MAIN.getBounds2D().getMinY());
                    final java.awt.geom.Point2D CENTER_KNOB_MAIN_STOP = new java.awt.geom.Point2D.Double(0, CENTER_KNOB_MAIN.getBounds2D().getMaxY());
                    final float[] CENTER_KNOB_MAIN_FRACTIONS =
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CENTER_KNOB_MAIN_COLORS =
                    {
                        new java.awt.Color(217, 217, 217, 255),
                        new java.awt.Color(191, 191, 191, 255)
                    };

                    final java.awt.LinearGradientPaint CENTER_KNOB_MAIN_GRADIENT = new java.awt.LinearGradientPaint(CENTER_KNOB_MAIN_START, CENTER_KNOB_MAIN_STOP, CENTER_KNOB_MAIN_FRACTIONS, CENTER_KNOB_MAIN_COLORS);
                    G2.setPaint(CENTER_KNOB_MAIN_GRADIENT);
                    G2.fill(CENTER_KNOB_MAIN);

                    final java.awt.geom.Ellipse2D CENTER_KNOB_INNERSHADOW = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4672897160053253, IMAGE_HEIGHT * 0.4672897160053253, IMAGE_WIDTH * 0.06542053818702698, IMAGE_HEIGHT * 0.06542053818702698);
                    final java.awt.geom.Point2D CENTER_KNOB_INNERSHADOW_CENTER = new java.awt.geom.Point2D.Double((0.4953271028037383 * IMAGE_WIDTH), (0.49065420560747663 * IMAGE_HEIGHT));
                    final float[] CENTER_KNOB_INNERSHADOW_FRACTIONS =
                    {
                        0.0f,
                        0.75f,
                        0.76f,
                        1.0f
                    };
                    final java.awt.Color[] CENTER_KNOB_INNERSHADOW_COLORS =
                    {
                        new java.awt.Color(0, 0, 0, 0),
                        new java.awt.Color(0, 0, 0, 0),
                        new java.awt.Color(0, 0, 0, 1),
                        new java.awt.Color(0, 0, 0, 51)
                    };
                    final java.awt.RadialGradientPaint CENTER_KNOB_INNERSHADOW_GRADIENT = new java.awt.RadialGradientPaint(CENTER_KNOB_INNERSHADOW_CENTER, (float) (0.03271028037383177 * IMAGE_WIDTH), CENTER_KNOB_INNERSHADOW_FRACTIONS, CENTER_KNOB_INNERSHADOW_COLORS);
                    G2.setPaint(CENTER_KNOB_INNERSHADOW_GRADIENT);
                    G2.fill(CENTER_KNOB_INNERSHADOW);
                    break;

                case BIG_STD_KNOB:
                    //G2.drawImage(KNOB_FACTORY.create_KNOB_Image((int) Math.ceil(IMAGE_WIDTH * 0.1214953362941742), eu.hansolo.steelseries.tools.KnobType.BIG_STD_KNOB), (int) Math.ceil(IMAGE_WIDTH * 0.4392523467540741), (int) Math.ceil(IMAGE_WIDTH * 0.4392523467540741), null);
                    final java.awt.geom.Ellipse2D BIGCENTER_BACKGROUNDFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4392523467540741, IMAGE_HEIGHT * 0.4392523467540741, IMAGE_WIDTH * 0.1214953362941742, IMAGE_HEIGHT * 0.1214953362941742);
                    final java.awt.geom.Point2D BIGCENTER_BACKGROUNDFRAME_START = new java.awt.geom.Point2D.Double(0, BIGCENTER_BACKGROUNDFRAME.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGCENTER_BACKGROUNDFRAME_STOP = new java.awt.geom.Point2D.Double(0, BIGCENTER_BACKGROUNDFRAME.getBounds2D().getMaxY() );
                    final float[] BIGCENTER_BACKGROUNDFRAME_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] BIGCENTER_BACKGROUNDFRAME_COLORS = 
                    {
                        new java.awt.Color(129, 133, 136, 255),
                        new java.awt.Color(61, 61, 73, 255)
                    };
                    final java.awt.LinearGradientPaint BIGCENTER_BACKGROUNDFRAME_GRADIENT = new java.awt.LinearGradientPaint(BIGCENTER_BACKGROUNDFRAME_START, BIGCENTER_BACKGROUNDFRAME_STOP, BIGCENTER_BACKGROUNDFRAME_FRACTIONS, BIGCENTER_BACKGROUNDFRAME_COLORS);
                    G2.setPaint(BIGCENTER_BACKGROUNDFRAME_GRADIENT);
                    G2.fill(BIGCENTER_BACKGROUNDFRAME);

                    final java.awt.geom.Ellipse2D BIGCENTER_BACKGROUND = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.44392523169517517, IMAGE_HEIGHT * 0.44392523169517517, IMAGE_WIDTH * 0.11214950680732727, IMAGE_HEIGHT * 0.11214950680732727);
                    final java.awt.geom.Point2D BIGCENTER_BACKGROUND_START = new java.awt.geom.Point2D.Double(0, BIGCENTER_BACKGROUND.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGCENTER_BACKGROUND_STOP = new java.awt.geom.Point2D.Double(0, BIGCENTER_BACKGROUND.getBounds2D().getMaxY() );
                    final float[] BIGCENTER_BACKGROUND_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] BIGCENTER_BACKGROUND_COLORS = 
                    {
                        new java.awt.Color(26, 27, 32, 255),
                        new java.awt.Color(96, 97, 102, 255)
                    };
                    final java.awt.LinearGradientPaint BIGCENTER_BACKGROUND_GRADIENT = new java.awt.LinearGradientPaint(BIGCENTER_BACKGROUND_START, BIGCENTER_BACKGROUND_STOP, BIGCENTER_BACKGROUND_FRACTIONS, BIGCENTER_BACKGROUND_COLORS);
                    G2.setPaint(BIGCENTER_BACKGROUND_GRADIENT);
                    G2.fill(BIGCENTER_BACKGROUND);

                    final java.awt.geom.Ellipse2D BIGCENTER_FOREGROUNDFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4532710313796997, IMAGE_HEIGHT * 0.4532710313796997, IMAGE_WIDTH * 0.09345793724060059, IMAGE_HEIGHT * 0.09345793724060059);
                    final java.awt.geom.Point2D BIGCENTER_FOREGROUNDFRAME_START = new java.awt.geom.Point2D.Double(0, BIGCENTER_FOREGROUNDFRAME.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGCENTER_FOREGROUNDFRAME_STOP = new java.awt.geom.Point2D.Double(0, BIGCENTER_FOREGROUNDFRAME.getBounds2D().getMaxY() );
                    final float[] BIGCENTER_FOREGROUNDFRAME_FRACTIONS = 
                    {
                        0.0f,
                        0.47f,
                        1.0f
                    };
                    final java.awt.Color[] BIGCENTER_FOREGROUNDFRAME_COLORS = 
                    {
                        new java.awt.Color(191, 191, 191, 255),
                        new java.awt.Color(56, 57, 61, 255),
                        new java.awt.Color(143, 144, 146, 255)
                    };
                    final java.awt.LinearGradientPaint BIGCENTER_FOREGROUNDFRAME_GRADIENT = new java.awt.LinearGradientPaint(BIGCENTER_FOREGROUNDFRAME_START, BIGCENTER_FOREGROUNDFRAME_STOP, BIGCENTER_FOREGROUNDFRAME_FRACTIONS, BIGCENTER_FOREGROUNDFRAME_COLORS);
                    G2.setPaint(BIGCENTER_FOREGROUNDFRAME_GRADIENT);
                    G2.fill(BIGCENTER_FOREGROUNDFRAME);

                    final java.awt.geom.Ellipse2D BIGCENTER_FOREGROUND = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4579439163208008, IMAGE_HEIGHT * 0.4579439163208008, IMAGE_WIDTH * 0.08411216735839844, IMAGE_HEIGHT * 0.08411216735839844);
                    final java.awt.geom.Point2D BIGCENTER_FOREGROUND_START = new java.awt.geom.Point2D.Double(0, BIGCENTER_FOREGROUND.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGCENTER_FOREGROUND_STOP = new java.awt.geom.Point2D.Double(0, BIGCENTER_FOREGROUND.getBounds2D().getMaxY() );
                    final float[] BIGCENTER_FOREGROUND_FRACTIONS = 
                    {
                        0.0f,
                        0.21f,
                        0.5f,
                        0.78f,
                        1.0f
                    };
                    final java.awt.Color[] BIGCENTER_FOREGROUND_COLORS = 
                    {
                        new java.awt.Color(191, 191, 191, 255),
                        new java.awt.Color(94, 93, 99, 255),
                        new java.awt.Color(43, 42, 47, 255),
                        new java.awt.Color(78, 79, 81, 255),
                        new java.awt.Color(143, 144, 146, 255)
                    };
                    final java.awt.LinearGradientPaint BIGCENTER_FOREGROUND_GRADIENT = new java.awt.LinearGradientPaint(BIGCENTER_FOREGROUND_START, BIGCENTER_FOREGROUND_STOP, BIGCENTER_FOREGROUND_FRACTIONS, BIGCENTER_FOREGROUND_COLORS);
                    G2.setPaint(BIGCENTER_FOREGROUND_GRADIENT);
                    G2.fill(BIGCENTER_FOREGROUND);
                    break;
                    
                case BIG_CHROME_KNOB:
                    //G2.drawImage(KNOB_FACTORY.create_KNOB_Image((int) Math.ceil(IMAGE_WIDTH * 0.14018690586090088), eu.hansolo.steelseries.tools.KnobType.BIG_CHROME_KNOB), (int) Math.ceil(IMAGE_WIDTH * 0.42990654706954956), (int) Math.ceil(IMAGE_WIDTH * 0.42990654706954956), null);
                    final java.awt.geom.Ellipse2D CHROMEKNOB_BACKFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.42990654706954956, IMAGE_HEIGHT * 0.42990654706954956, IMAGE_WIDTH * 0.14018690586090088, IMAGE_HEIGHT * 0.14018690586090088);
                    final java.awt.geom.Point2D CHROMEKNOB_BACKFRAME_START = new java.awt.geom.Point2D.Double( (0.46261682242990654 * IMAGE_WIDTH), (0.4392523364485981 * IMAGE_HEIGHT) );
                    final java.awt.geom.Point2D CHROMEKNOB_BACKFRAME_STOP = new java.awt.geom.Point2D.Double( ((0.46261682242990654 + 0.0718114890783315) * IMAGE_WIDTH), ((0.4392523364485981 + 0.1149224055539082) * IMAGE_HEIGHT) );
                    final float[] CHROMEKNOB_BACKFRAME_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_BACKFRAME_COLORS = 
                    {
                        new java.awt.Color(129, 139, 140, 255),
                        new java.awt.Color(166, 171, 175, 255)
                    };
                    final java.awt.LinearGradientPaint CHROMEKNOB_BACKFRAME_GRADIENT = new java.awt.LinearGradientPaint(CHROMEKNOB_BACKFRAME_START, CHROMEKNOB_BACKFRAME_STOP, CHROMEKNOB_BACKFRAME_FRACTIONS, CHROMEKNOB_BACKFRAME_COLORS);
                    G2.setPaint(CHROMEKNOB_BACKFRAME_GRADIENT);
                    G2.fill(CHROMEKNOB_BACKFRAME);

                    final java.awt.geom.Ellipse2D CHROMEKNOB_BACK = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.43457943201065063, IMAGE_HEIGHT * 0.43457943201065063, IMAGE_WIDTH * 0.13084113597869873, IMAGE_HEIGHT * 0.13084113597869873);                    
                    final java.awt.geom.Point2D CHROMEKNOB_BACK_CENTER = new java.awt.geom.Point2D.Double(CHROMEKNOB_BACK.getCenterX(), CHROMEKNOB_BACK.getCenterY());
                    final float[] CHROMEKNOB_BACK_FRACTIONS = 
                    {
                        0.0f,
                        0.09f,
                        0.12f,
                        0.16f,
                        0.25f,
                        0.29f,
                        0.33f,
                        0.38f,
                        0.48f,
                        0.52f,
                        0.65f,
                        0.69f,
                        0.8f,
                        0.83f,
                        0.87f,
                        0.97f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_BACK_COLORS = 
                    {
                        new java.awt.Color(255, 255, 255, 255),
                        new java.awt.Color(255, 255, 255, 255),
                        new java.awt.Color(136, 136, 138, 255),
                        new java.awt.Color(164, 185, 190, 255),
                        new java.awt.Color(158, 179, 182, 255),
                        new java.awt.Color(112, 112, 112, 255),
                        new java.awt.Color(221, 227, 227, 255),
                        new java.awt.Color(155, 176, 179, 255),
                        new java.awt.Color(156, 176, 177, 255),
                        new java.awt.Color(254, 255, 255, 255),
                        new java.awt.Color(255, 255, 255, 255),
                        new java.awt.Color(156, 180, 180, 255),
                        new java.awt.Color(198, 209, 211, 255),
                        new java.awt.Color(246, 248, 247, 255),
                        new java.awt.Color(204, 216, 216, 255),
                        new java.awt.Color(164, 188, 190, 255),
                        new java.awt.Color(255, 255, 255, 255)
                    };
                    final eu.hansolo.steelseries.tools.ConicalGradientPaint CHROMEKNOB_BACK_GRADIENT = new eu.hansolo.steelseries.tools.ConicalGradientPaint(false, CHROMEKNOB_BACK_CENTER, 0, CHROMEKNOB_BACK_FRACTIONS, CHROMEKNOB_BACK_COLORS);
                    G2.setPaint(CHROMEKNOB_BACK_GRADIENT);
                    G2.fill(CHROMEKNOB_BACK);

                    final java.awt.geom.Ellipse2D CHROMEKNOB_FOREFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4672897160053253, IMAGE_HEIGHT * 0.4672897160053253, IMAGE_WIDTH * 0.06542053818702698, IMAGE_HEIGHT * 0.06542053818702698);
                    final java.awt.geom.Point2D CHROMEKNOB_FOREFRAME_START = new java.awt.geom.Point2D.Double( (0.48130841121495327 * IMAGE_WIDTH), (0.4719626168224299 * IMAGE_HEIGHT) );
                    final java.awt.geom.Point2D CHROMEKNOB_FOREFRAME_STOP = new java.awt.geom.Point2D.Double( ((0.48130841121495327 + 0.033969662360372466) * IMAGE_WIDTH), ((0.4719626168224299 + 0.05036209552904459) * IMAGE_HEIGHT) );
                    final float[] CHROMEKNOB_FOREFRAME_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_FOREFRAME_COLORS = 
                    {
                        new java.awt.Color(225, 235, 232, 255),
                        new java.awt.Color(196, 207, 207, 255)
                    };
                    final java.awt.LinearGradientPaint CHROMEKNOB_FOREFRAME_GRADIENT = new java.awt.LinearGradientPaint(CHROMEKNOB_FOREFRAME_START, CHROMEKNOB_FOREFRAME_STOP, CHROMEKNOB_FOREFRAME_FRACTIONS, CHROMEKNOB_FOREFRAME_COLORS);
                    G2.setPaint(CHROMEKNOB_FOREFRAME_GRADIENT);
                    G2.fill(CHROMEKNOB_FOREFRAME);

                    final java.awt.geom.Ellipse2D CHROMEKNOB_FORE = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4719626307487488, IMAGE_HEIGHT * 0.4719626307487488, IMAGE_WIDTH * 0.05607473850250244, IMAGE_HEIGHT * 0.05607473850250244);
                    final java.awt.geom.Point2D CHROMEKNOB_FORE_START = new java.awt.geom.Point2D.Double( (0.48130841121495327 * IMAGE_WIDTH), (0.4766355140186916 * IMAGE_HEIGHT) );
                    final java.awt.geom.Point2D CHROMEKNOB_FORE_STOP = new java.awt.geom.Point2D.Double( ((0.48130841121495327 + 0.03135661140957459) * IMAGE_WIDTH), ((0.4766355140186916 + 0.04648808818065655) * IMAGE_HEIGHT) );
                    final float[] CHROMEKNOB_FORE_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_FORE_COLORS = 
                    {
                        new java.awt.Color(237, 239, 237, 255),
                        new java.awt.Color(148, 161, 161, 255)
                    };
                    final java.awt.LinearGradientPaint CHROMEKNOB_FORE_GRADIENT = new java.awt.LinearGradientPaint(CHROMEKNOB_FORE_START, CHROMEKNOB_FORE_STOP, CHROMEKNOB_FORE_FRACTIONS, CHROMEKNOB_FORE_COLORS);
                    G2.setPaint(CHROMEKNOB_FORE_GRADIENT);
                    G2.fill(CHROMEKNOB_FORE);
                    break;    
            }
        }
                              
        // Draw min bottom
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.MIN_BOTTOM))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.336448609828949), (int) (IMAGE_HEIGHT * 0.8037382960319519), null);           
        }

        // Draw max bottom post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.MAX_BOTTOM))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.6261682510375977), (int) (IMAGE_HEIGHT * 0.8037382960319519), null);           
        }

        // Draw min center bottom post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.MAX_CENTER_BOTTOM))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.5233644843101501), (int) (IMAGE_HEIGHT * 0.8317757248878479) , null);
        }

        // Draw max center top post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.MAX_CENTER_TOP))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.5233644843101501), (int) (IMAGE_HEIGHT * 0.13084112107753754), null);
        }

        // Draw max right post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.MAX_RIGHT))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.8317757248878479), (int) (IMAGE_HEIGHT * 0.514018714427948), null);
        }

        // Draw min left post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.MIN_LEFT))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.13084112107753754), (int) (IMAGE_HEIGHT * 0.514018714427948), null);
        }

        // Draw lower center post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.LOWER_CENTER))
        {
            switch (getKnobType())
            {
                
                case SMALL_STD_KNOB:            
                    //G2.drawImage(CENTER_KNOB, (int) (IMAGE_WIDTH * 0.4579439163208008), (int)(IMAGE_HEIGHT * 0.6915887594223022), null);
                    final java.awt.geom.Ellipse2D LOWERCENTER_KNOB_FRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4579439163208008, IMAGE_HEIGHT * 0.6915887594223022, IMAGE_WIDTH * 0.08411216735839844, IMAGE_HEIGHT * 0.08411216735839844);
                    final java.awt.geom.Point2D LOWERCENTER_KNOB_FRAME_START = new java.awt.geom.Point2D.Double(0, LOWERCENTER_KNOB_FRAME.getBounds2D().getMinY());
                    final java.awt.geom.Point2D LOWERCENTER_KNOB_FRAME_STOP = new java.awt.geom.Point2D.Double(0, LOWERCENTER_KNOB_FRAME.getBounds2D().getMaxY());
                    final float[] LOWERCENTER_KNOB_FRAME_FRACTIONS =
                    {
                        0.0f,
                        0.46f,
                        1.0f
                    };
                    final java.awt.Color[] LOWERCENTER_KNOB_FRAME_COLORS =
                    {
                        new java.awt.Color(180, 180, 180, 255),
                        new java.awt.Color(63, 63, 63, 255),
                        new java.awt.Color(40, 40, 40, 255)
                    };

                    final java.awt.LinearGradientPaint LOWERCENTER_KNOB_FRAME_GRADIENT = new java.awt.LinearGradientPaint(LOWERCENTER_KNOB_FRAME_START, LOWERCENTER_KNOB_FRAME_STOP, LOWERCENTER_KNOB_FRAME_FRACTIONS, LOWERCENTER_KNOB_FRAME_COLORS);
                    G2.setPaint(LOWERCENTER_KNOB_FRAME_GRADIENT);
                    G2.fill(LOWERCENTER_KNOB_FRAME);

                    final java.awt.geom.Ellipse2D LOWERCENTER_KNOB_MAIN = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4672897160053253, IMAGE_HEIGHT * 0.7009345889091492, IMAGE_WIDTH * 0.06542053818702698, IMAGE_HEIGHT * 0.06542056798934937);
                    final java.awt.geom.Point2D LOWERCENTER_KNOB_MAIN_START = new java.awt.geom.Point2D.Double(0, LOWERCENTER_KNOB_MAIN.getBounds2D().getMinY());
                    final java.awt.geom.Point2D LOWERCENTER_KNOB_MAIN_STOP = new java.awt.geom.Point2D.Double(0, LOWERCENTER_KNOB_MAIN.getBounds2D().getMaxY());
                    final float[] LOWERCENTER_KNOB_MAIN_FRACTIONS =
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] LOWERCENTER_KNOB_MAIN_COLORS =
                    {
                        new java.awt.Color(217, 217, 217, 255),
                        new java.awt.Color(191, 191, 191, 255)
                    };

                    final java.awt.LinearGradientPaint LOWERCENTER_KNOB_MAIN_GRADIENT = new java.awt.LinearGradientPaint(LOWERCENTER_KNOB_MAIN_START, LOWERCENTER_KNOB_MAIN_STOP, LOWERCENTER_KNOB_MAIN_FRACTIONS, LOWERCENTER_KNOB_MAIN_COLORS);
                    G2.setPaint(LOWERCENTER_KNOB_MAIN_GRADIENT);
                    G2.fill(LOWERCENTER_KNOB_MAIN);

                    final java.awt.geom.Ellipse2D LOWERCENTER_KNOB_INNERSHADOW = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4672897160053253, IMAGE_HEIGHT * 0.7009345889091492, IMAGE_WIDTH * 0.06542053818702698, IMAGE_HEIGHT * 0.06542056798934937);
                    final java.awt.geom.Point2D LOWERCENTER_KNOB_INNERSHADOW_CENTER = new java.awt.geom.Point2D.Double((0.4953271028037383 * IMAGE_WIDTH), (0.7242990654205608 * IMAGE_HEIGHT));
                    final float[] LOWERCENTER_KNOB_INNERSHADOW_FRACTIONS =
                    {
                        0.0f,
                        0.75f,
                        0.76f,
                        1.0f
                    };
                    final java.awt.Color[] LOWERCENTER_KNOB_INNERSHADOW_COLORS =
                    {
                        new java.awt.Color(0, 0, 0, 0),
                        new java.awt.Color(0, 0, 0, 0),
                        new java.awt.Color(0, 0, 0, 1),
                        new java.awt.Color(0, 0, 0, 51)
                    };
                    final java.awt.RadialGradientPaint LOWERCENTER_KNOB_INNERSHADOW_GRADIENT = new java.awt.RadialGradientPaint(LOWERCENTER_KNOB_INNERSHADOW_CENTER, (float) (0.03271028037383177 * IMAGE_WIDTH), LOWERCENTER_KNOB_INNERSHADOW_FRACTIONS, LOWERCENTER_KNOB_INNERSHADOW_COLORS);
                    G2.setPaint(LOWERCENTER_KNOB_INNERSHADOW_GRADIENT);
                    G2.fill(LOWERCENTER_KNOB_INNERSHADOW);
                    break;
                    
                case BIG_STD_KNOB:
                    final java.awt.geom.Ellipse2D BIGLOWERCENTER_BACKGROUNDFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4392523467540741, IMAGE_HEIGHT * 0.672897219657898, IMAGE_WIDTH * 0.1214953362941742, IMAGE_HEIGHT * 0.1214953064918518);
                    final java.awt.geom.Point2D BIGLOWERCENTER_BACKGROUNDFRAME_START = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_BACKGROUNDFRAME.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGLOWERCENTER_BACKGROUNDFRAME_STOP = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_BACKGROUNDFRAME.getBounds2D().getMaxY() );
                    final float[] BIGLOWERCENTER_BACKGROUNDFRAME_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] BIGLOWERCENTER_BACKGROUNDFRAME_COLORS = 
                    {
                        new java.awt.Color(129, 133, 136, 255),
                        new java.awt.Color(61, 61, 73, 255)
                    };
                    final java.awt.LinearGradientPaint BIGLOWERCENTER_BACKGROUNDFRAME_GRADIENT = new java.awt.LinearGradientPaint(BIGLOWERCENTER_BACKGROUNDFRAME_START, BIGLOWERCENTER_BACKGROUNDFRAME_STOP, BIGLOWERCENTER_BACKGROUNDFRAME_FRACTIONS, BIGLOWERCENTER_BACKGROUNDFRAME_COLORS);
                    G2.setPaint(BIGLOWERCENTER_BACKGROUNDFRAME_GRADIENT);
                    G2.fill(BIGLOWERCENTER_BACKGROUNDFRAME);

                    final java.awt.geom.Ellipse2D BIGLOWERCENTER_BACKGROUND = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.44392523169517517, IMAGE_HEIGHT * 0.677570104598999, IMAGE_WIDTH * 0.11214950680732727, IMAGE_HEIGHT * 0.11214953660964966);
                    final java.awt.geom.Point2D BIGLOWERCENTER_BACKGROUND_START = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_BACKGROUND.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGLOWERCENTER_BACKGROUND_STOP = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_BACKGROUND.getBounds2D().getMaxY() );
                    final float[] BIGLOWERCENTER_BACKGROUND_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] BIGLOWERCENTER_BACKGROUND_COLORS = 
                    {
                        new java.awt.Color(26, 27, 32, 255),
                        new java.awt.Color(96, 97, 102, 255)
                    };
                    final java.awt.LinearGradientPaint BIGLOWERCENTER_BACKGROUND_GRADIENT = new java.awt.LinearGradientPaint(BIGLOWERCENTER_BACKGROUND_START, BIGLOWERCENTER_BACKGROUND_STOP, BIGLOWERCENTER_BACKGROUND_FRACTIONS, BIGLOWERCENTER_BACKGROUND_COLORS);
                    G2.setPaint(BIGLOWERCENTER_BACKGROUND_GRADIENT);
                    G2.fill(BIGLOWERCENTER_BACKGROUND);

                    final java.awt.geom.Ellipse2D BIGLOWERCENTER_FOREGROUNDFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4532710313796997, IMAGE_HEIGHT * 0.6869158744812012, IMAGE_WIDTH * 0.09345793724060059, IMAGE_HEIGHT * 0.09345793724060059);
                    final java.awt.geom.Point2D BIGLOWERCENTER_FOREGROUNDFRAME_START = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_FOREGROUNDFRAME.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGLOWERCENTER_FOREGROUNDFRAME_STOP = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_FOREGROUNDFRAME.getBounds2D().getMaxY() );
                    final float[] BIGLOWERCENTER_FOREGROUNDFRAME_FRACTIONS = 
                    {
                        0.0f,
                        0.47f,
                        1.0f
                    };
                    final java.awt.Color[] BIGLOWERCENTER_FOREGROUNDFRAME_COLORS = 
                    {
                        new java.awt.Color(191, 191, 191, 255),
                        new java.awt.Color(56, 57, 61, 255),
                        new java.awt.Color(143, 144, 146, 255)
                    };
                    final java.awt.LinearGradientPaint BIGLOWERCENTER_FOREGROUNDFRAME_GRADIENT = new java.awt.LinearGradientPaint(BIGLOWERCENTER_FOREGROUNDFRAME_START, BIGLOWERCENTER_FOREGROUNDFRAME_STOP, BIGLOWERCENTER_FOREGROUNDFRAME_FRACTIONS, BIGLOWERCENTER_FOREGROUNDFRAME_COLORS);
                    G2.setPaint(BIGLOWERCENTER_FOREGROUNDFRAME_GRADIENT);
                    G2.fill(BIGLOWERCENTER_FOREGROUNDFRAME);

                    final java.awt.geom.Ellipse2D BIGLOWERCENTER_FOREGROUND = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4579439163208008, IMAGE_HEIGHT * 0.6915887594223022, IMAGE_WIDTH * 0.08411216735839844, IMAGE_HEIGHT * 0.08411216735839844);
                    final java.awt.geom.Point2D BIGLOWERCENTER_FOREGROUND_START = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_FOREGROUND.getBounds2D().getMinY() );
                    final java.awt.geom.Point2D BIGLOWERCENTER_FOREGROUND_STOP = new java.awt.geom.Point2D.Double(0, BIGLOWERCENTER_FOREGROUND.getBounds2D().getMaxY() );
                    final float[] BIGLOWERCENTER_FOREGROUND_FRACTIONS = 
                    {
                        0.0f,
                        0.21f,
                        0.5f,
                        0.78f,
                        1.0f
                    };
                    final java.awt.Color[] BIGLOWERCENTER_FOREGROUND_COLORS = 
                    {
                        new java.awt.Color(191, 191, 191, 255),
                        new java.awt.Color(94, 93, 99, 255),
                        new java.awt.Color(43, 42, 47, 255),
                        new java.awt.Color(78, 79, 81, 255),
                        new java.awt.Color(143, 144, 146, 255)
                    };
                    final java.awt.LinearGradientPaint BIGLOWERCENTER_FOREGROUND_GRADIENT = new java.awt.LinearGradientPaint(BIGLOWERCENTER_FOREGROUND_START, BIGLOWERCENTER_FOREGROUND_STOP, BIGLOWERCENTER_FOREGROUND_FRACTIONS, BIGLOWERCENTER_FOREGROUND_COLORS);
                    G2.setPaint(BIGLOWERCENTER_FOREGROUND_GRADIENT);
                    G2.fill(BIGLOWERCENTER_FOREGROUND);
                    break;
                    
                case BIG_CHROME_KNOB:
                    final java.awt.geom.Ellipse2D CHROMEKNOB_BACKFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4000000059604645, IMAGE_HEIGHT * 0.6333333253860474, IMAGE_WIDTH * 0.20000001788139343, IMAGE_HEIGHT * 0.19999998807907104);
                    final java.awt.geom.Point2D CHROMEKNOB_BACKFRAME_START = new java.awt.geom.Point2D.Double( (0.44666666666666666 * IMAGE_WIDTH), (0.6466666666666666 * IMAGE_HEIGHT) );
                    final java.awt.geom.Point2D CHROMEKNOB_BACKFRAME_STOP = new java.awt.geom.Point2D.Double( ((0.44666666666666666 + 0.10245105775175295) * IMAGE_WIDTH), ((0.6466666666666666 + 0.16395596525690903) * IMAGE_HEIGHT) );
                    final float[] CHROMEKNOB_BACKFRAME_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_BACKFRAME_COLORS = 
                    {
                        new java.awt.Color(129, 139, 140, 255),
                        new java.awt.Color(166, 171, 175, 255)
                    };
                    final java.awt.LinearGradientPaint CHROMEKNOB_BACKFRAME_GRADIENT = new java.awt.LinearGradientPaint(CHROMEKNOB_BACKFRAME_START, CHROMEKNOB_BACKFRAME_STOP, CHROMEKNOB_BACKFRAME_FRACTIONS, CHROMEKNOB_BACKFRAME_COLORS);
                    G2.setPaint(CHROMEKNOB_BACKFRAME_GRADIENT);
                    G2.fill(CHROMEKNOB_BACKFRAME);

                    final java.awt.geom.Ellipse2D CHROMEKNOB_BACK = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.40666666626930237, IMAGE_HEIGHT * 0.6399999856948853, IMAGE_WIDTH * 0.18666663765907288, IMAGE_HEIGHT * 0.18666666746139526);                    
                    final java.awt.geom.Point2D CHROMEKNOB_BACK_CENTER = new java.awt.geom.Point2D.Double(CHROMEKNOB_BACK.getCenterX(), CHROMEKNOB_BACK.getCenterY());
                    final float[] CHROMEKNOB_BACK_FRACTIONS = 
                    {
                        0.0f,
                        0.09f,
                        0.12f,
                        0.16f,
                        0.25f,
                        0.29f,
                        0.33f,
                        0.38f,
                        0.48f,
                        0.52f,
                        0.65f,
                        0.69f,
                        0.8f,
                        0.83f,
                        0.87f,
                        0.97f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_BACK_COLORS = 
                    {
                        new java.awt.Color(255, 255, 255, 255),
                        new java.awt.Color(255, 255, 255, 255),
                        new java.awt.Color(136, 136, 138, 255),
                        new java.awt.Color(164, 185, 190, 255),
                        new java.awt.Color(158, 179, 182, 255),
                        new java.awt.Color(112, 112, 112, 255),
                        new java.awt.Color(221, 227, 227, 255),
                        new java.awt.Color(155, 176, 179, 255),
                        new java.awt.Color(156, 176, 177, 255),
                        new java.awt.Color(254, 255, 255, 255),
                        new java.awt.Color(255, 255, 255, 255),
                        new java.awt.Color(156, 180, 180, 255),
                        new java.awt.Color(198, 209, 211, 255),
                        new java.awt.Color(246, 248, 247, 255),
                        new java.awt.Color(204, 216, 216, 255),
                        new java.awt.Color(164, 188, 190, 255),
                        new java.awt.Color(255, 255, 255, 255)
                    };
                    final eu.hansolo.steelseries.tools.ConicalGradientPaint CHROMEKNOB_BACK_GRADIENT = new eu.hansolo.steelseries.tools.ConicalGradientPaint(false, CHROMEKNOB_BACK_CENTER, 0, CHROMEKNOB_BACK_FRACTIONS, CHROMEKNOB_BACK_COLORS);
                    G2.setPaint(CHROMEKNOB_BACK_GRADIENT);
                    G2.fill(CHROMEKNOB_BACK);

                    final java.awt.geom.Ellipse2D CHROMEKNOB_FOREFRAME = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.4533333480358124, IMAGE_HEIGHT * 0.6866666674613953, IMAGE_WIDTH * 0.09333333373069763, IMAGE_HEIGHT * 0.09333330392837524);
                    final java.awt.geom.Point2D CHROMEKNOB_FOREFRAME_START = new java.awt.geom.Point2D.Double( (0.47333333333333333 * IMAGE_WIDTH), (0.6933333333333334 * IMAGE_HEIGHT) );
                    final java.awt.geom.Point2D CHROMEKNOB_FOREFRAME_STOP = new java.awt.geom.Point2D.Double( ((0.47333333333333333 + 0.04846338496746472) * IMAGE_WIDTH), ((0.6933333333333334 + 0.07184992295477029) * IMAGE_HEIGHT) );
                    final float[] CHROMEKNOB_FOREFRAME_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_FOREFRAME_COLORS = 
                    {
                        new java.awt.Color(225, 235, 232, 255),
                        new java.awt.Color(196, 207, 207, 255)
                    };
                    final java.awt.LinearGradientPaint CHROMEKNOB_FOREFRAME_GRADIENT = new java.awt.LinearGradientPaint(CHROMEKNOB_FOREFRAME_START, CHROMEKNOB_FOREFRAME_STOP, CHROMEKNOB_FOREFRAME_FRACTIONS, CHROMEKNOB_FOREFRAME_COLORS);
                    G2.setPaint(CHROMEKNOB_FOREFRAME_GRADIENT);
                    G2.fill(CHROMEKNOB_FOREFRAME);

                    final java.awt.geom.Ellipse2D CHROMEKNOB_FORE = new java.awt.geom.Ellipse2D.Double(IMAGE_WIDTH * 0.46000000834465027, IMAGE_HEIGHT * 0.6933333277702332, IMAGE_WIDTH * 0.08000001311302185, IMAGE_HEIGHT * 0.07999998331069946);
                    final java.awt.geom.Point2D CHROMEKNOB_FORE_START = new java.awt.geom.Point2D.Double( (0.47333333333333333 * IMAGE_WIDTH), (0.7 * IMAGE_HEIGHT) );
                    final java.awt.geom.Point2D CHROMEKNOB_FORE_STOP = new java.awt.geom.Point2D.Double( ((0.47333333333333333 + 0.04473543227765974) * IMAGE_WIDTH), ((0.7 + 0.06632300580440334) * IMAGE_HEIGHT) );
                    final float[] CHROMEKNOB_FORE_FRACTIONS = 
                    {
                        0.0f,
                        1.0f
                    };
                    final java.awt.Color[] CHROMEKNOB_FORE_COLORS = 
                    {
                        new java.awt.Color(237, 239, 237, 255),
                        new java.awt.Color(148, 161, 161, 255)
                    };
                    final java.awt.LinearGradientPaint CHROMEKNOB_FORE_GRADIENT = new java.awt.LinearGradientPaint(CHROMEKNOB_FORE_START, CHROMEKNOB_FORE_STOP, CHROMEKNOB_FORE_FRACTIONS, CHROMEKNOB_FORE_COLORS);
                    G2.setPaint(CHROMEKNOB_FORE_GRADIENT);
                    G2.fill(CHROMEKNOB_FORE);
                    break;
            }
        }

        // Draw small gauge right post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.SMALL_GAUGE_MAX_RIGHT))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.7803738117218018), (int) (IMAGE_HEIGHT * 0.44859811663627625), null);
        }

        // Draw small gauge left post
        if (POST_POSITION_LIST.contains(eu.hansolo.steelseries.tools.PostPosition.SMALL_GAUGE_MIN_LEFT))
        {
            G2.drawImage(SINGLE_POST, (int) (IMAGE_WIDTH * 0.1822429895401001), (int) (IMAGE_HEIGHT * 0.44859811663627625), null);
        }

        G2.dispose();

        return image;
    }
    
    /**
     * Creates a single alignment post image that could be placed on all the positions where it is needed
     * @param WIDTH
     * @return a buffered image that contains a single alignment post
     */
    private java.awt.image.BufferedImage create_KNOB_Image(final int WIDTH)        
    {
        return create_KNOB_Image(WIDTH, eu.hansolo.steelseries.tools.KnobType.SMALL_STD_KNOB);
    }
    
    /**
     * Creates a single alignment post image that could be placed on all the positions where it is needed
     * @param WIDTH
     * @param KNOB_TYPE
     * @return a buffered image that contains a single alignment post of the given type
     */
    private java.awt.image.BufferedImage create_KNOB_Image(final int WIDTH, final eu.hansolo.steelseries.tools.KnobType KNOB_TYPE)
    {
        return KNOB_FACTORY.create_KNOB_Image(WIDTH, KNOB_TYPE);
    }
    
    /**
     * Returns the image of the threshold indicator.
     * @param WIDTH
     * @return the threshold image that is used
     */
    protected java.awt.image.BufferedImage create_THRESHOLD_Image(final int WIDTH)
    {        
        return create_THRESHOLD_Image(WIDTH, 0);
    }

    protected java.awt.image.BufferedImage create_THRESHOLD_Image(final int WIDTH, final double ROTATION_OFFSET)
    {
        if (WIDTH <= 22) // 22 is needed because otherwise the image size could be smaller than 1
        {
            return GFX_CONF.createCompatibleImage(1, 1, java.awt.Transparency.TRANSLUCENT);
        }

        final int IMAGE_HEIGHT = (int) (WIDTH * 0.046728972);
        final int IMAGE_WIDTH = (int) (IMAGE_HEIGHT * 0.9);

        final java.awt.image.BufferedImage IMAGE = GFX_CONF.createCompatibleImage(IMAGE_WIDTH, IMAGE_HEIGHT, java.awt.Transparency.TRANSLUCENT);
        final java.awt.Graphics2D G2 = IMAGE.createGraphics();
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);

        G2.rotate(ROTATION_OFFSET, IMAGE_WIDTH / 2.0, IMAGE_HEIGHT / 2.0);

        final java.awt.geom.GeneralPath THRESHOLD = new java.awt.geom.GeneralPath();
        THRESHOLD.setWindingRule(java.awt.geom.GeneralPath.WIND_EVEN_ODD);
        THRESHOLD.moveTo(IMAGE_WIDTH * 0.5, 0.1);
        THRESHOLD.lineTo(IMAGE_WIDTH * 0.9, IMAGE_HEIGHT * 0.9);
        THRESHOLD.lineTo(IMAGE_WIDTH * 0.1, IMAGE_HEIGHT * 0.9);
        THRESHOLD.lineTo(IMAGE_WIDTH * 0.5, 0.1);
        THRESHOLD.closePath();

        final java.awt.geom.Point2D THRESHOLD_START = new java.awt.geom.Point2D.Double(0, THRESHOLD.getBounds2D().getMaxY());
        final java.awt.geom.Point2D THRESHOLD_STOP = new java.awt.geom.Point2D.Double(0, THRESHOLD.getBounds2D().getMinY());

        final float[] THRESHOLD_FRACTIONS =
        {
            0.0f,
            0.3f,
            0.59f,
            1.0f
        };
        final java.awt.Color[] THRESHOLD_COLORS =
        {
            new java.awt.Color(82, 0, 0, 255),
            new java.awt.Color(252, 29, 0, 255),
            new java.awt.Color(252, 29, 0, 255),
            new java.awt.Color(82, 0, 0, 255)
        };
        final java.awt.LinearGradientPaint THRESHOLD_GRADIENT = new java.awt.LinearGradientPaint(THRESHOLD_START, THRESHOLD_STOP, THRESHOLD_FRACTIONS, THRESHOLD_COLORS);
        G2.setPaint(THRESHOLD_GRADIENT);
        G2.fill(THRESHOLD);

        G2.setColor(java.awt.Color.WHITE);
        G2.setStroke(new java.awt.BasicStroke(1.0f, java.awt.BasicStroke.CAP_BUTT, java.awt.BasicStroke.JOIN_MITER));
        G2.draw(THRESHOLD);

        G2.dispose();

        return IMAGE;
    }

    /**
     * Returns the image of the MinMeasuredValue and MaxMeasuredValue dependend
     * @param WIDTH
     * @param COLOR
     * @return the image of the min or max measured value
     */
    protected java.awt.image.BufferedImage create_MEASURED_VALUE_Image(final int WIDTH, final java.awt.Color COLOR)
    {        
        return create_MEASURED_VALUE_Image(WIDTH, COLOR, 0);
    }

    /**
     * Returns the image of the MinMeasuredValue and MaxMeasuredValue dependend
     * @param WIDTH
     * @param COLOR
     * @param ROTATION_OFFSET
     * @return the image of the min or max measured value
     */
    protected java.awt.image.BufferedImage create_MEASURED_VALUE_Image(final int WIDTH, final java.awt.Color COLOR, final double ROTATION_OFFSET)
    {
        if (WIDTH <= 36) // 36 is needed otherwise the image size could be smaller than 1
        {
            return GFX_CONF.createCompatibleImage(1, 1, java.awt.Transparency.TRANSLUCENT);
        }

        final int IMAGE_HEIGHT = (int) (WIDTH * 0.0280373832);
        final int IMAGE_WIDTH = IMAGE_HEIGHT;

        final java.awt.image.BufferedImage IMAGE = GFX_CONF.createCompatibleImage(IMAGE_WIDTH, IMAGE_HEIGHT, java.awt.Transparency.TRANSLUCENT);
        final java.awt.Graphics2D G2 = IMAGE.createGraphics();
        G2.setRenderingHint(java.awt.RenderingHints.KEY_ANTIALIASING, java.awt.RenderingHints.VALUE_ANTIALIAS_ON);

        G2.rotate(ROTATION_OFFSET, IMAGE_WIDTH / 2.0, IMAGE_HEIGHT / 2.0);

        final java.awt.geom.GeneralPath INDICATOR = new java.awt.geom.GeneralPath();
        INDICATOR.setWindingRule(java.awt.geom.GeneralPath.WIND_EVEN_ODD);
        INDICATOR.moveTo(IMAGE_WIDTH * 0.5, IMAGE_HEIGHT);
        INDICATOR.lineTo(0.0, 0.0);
        INDICATOR.lineTo(IMAGE_WIDTH, 0.0);
        INDICATOR.closePath();

        G2.setColor(COLOR);
        G2.fill(INDICATOR);

        G2.dispose();

        return IMAGE;
    }

    /**
     * Returns the image of the pointer. This pointer is centered in the gauge and of PointerType FG_TYPE1.
     * @param WIDTH
     * @return the pointer image that is used in all gauges that have a centered pointer
     */
    protected java.awt.image.BufferedImage create_POINTER_Image(final int WIDTH)
    {
        return create_POINTER_Image(WIDTH, eu.hansolo.steelseries.tools.PointerType.TYPE1);
    }

    /**
     * Returns the image of the pointer. This pointer is centered in the gauge.
     * @param WIDTH
     * @param POINTER_TYPE
     * @return the pointer image that is used in all gauges that have a centered pointer
     */
    protected java.awt.image.BufferedImage create_POINTER_Image(final int WIDTH, final eu.hansolo.steelseries.tools.PointerType POINTER_TYPE)
    {
        if (getPointerColor() != eu.hansolo.steelseries.tools.ColorDef.CUSTOM)
        {
            return POINTER_FACTORY.createStandardPointer(WIDTH, POINTER_TYPE, getPointerColor());
        }
        else
        {
            return POINTER_FACTORY.createStandardPointer(WIDTH, POINTER_TYPE, getPointerColor(), getModel().getCustomPointerColorObject());
        }
    }

    /**
     * Returns the image of the pointer. This pointer is centered in the gauge.
     * @param WIDTH
     * @param POINTER_TYPE
     * @param POINTER_COLOR
     * @return the pointer image that is used in all gauges that have a centered pointer
     */
    protected java.awt.image.BufferedImage create_POINTER_Image(final int WIDTH, final eu.hansolo.steelseries.tools.PointerType POINTER_TYPE, final eu.hansolo.steelseries.tools.ColorDef POINTER_COLOR)
    {        
        return POINTER_FACTORY.createStandardPointer(WIDTH, POINTER_TYPE, POINTER_COLOR);        
    }
    
    /**
     * Returns the image of the pointer. This pointer is centered in the gauge.
     * @param WIDTH
     * @param POINTER_TYPE
     * @param POINTER_COLOR
     * @param CUSTOM_POINTER_COLOR 
     * @return the pointer image that is used in all gauges that have a centered pointer
     */
    protected java.awt.image.BufferedImage create_POINTER_Image(final int WIDTH, final eu.hansolo.steelseries.tools.PointerType POINTER_TYPE, final eu.hansolo.steelseries.tools.ColorDef POINTER_COLOR, final eu.hansolo.steelseries.tools.CustomColorDef CUSTOM_POINTER_COLOR)
    {        
        return POINTER_FACTORY.createStandardPointer(WIDTH, POINTER_TYPE, POINTER_COLOR, CUSTOM_POINTER_COLOR);        
    }
    
    /**
     * Returns the image of the pointer shadow. This shadow is centered in the gauge
     * @param WIDTH
     * @return the pointer shadow image that is used in all gauges that have a centered pointer
     */
    protected java.awt.image.BufferedImage create_POINTER_SHADOW_Image(final int WIDTH)
    {
        return create_POINTER_SHADOW_Image(WIDTH, eu.hansolo.steelseries.tools.PointerType.TYPE1);
    }

    /**
     * Returns the image of the pointer shadow. This shadow is centered in the gauge
     * @param WIDTH
     * @param POINTER_TYPE 
     * @return the pointer shadow image that is used in all gauges that have a centered pointer
     */
    protected java.awt.image.BufferedImage create_POINTER_SHADOW_Image(final int WIDTH, final eu.hansolo.steelseries.tools.PointerType POINTER_TYPE)
    {
        return POINTER_FACTORY.createStandardPointerShadow(WIDTH, POINTER_TYPE);
    }

    /**
     * Returns the image of the glasseffect with a centered knob
     * @param WIDTH
     * @return the foreground image that will be used (in principle only the glass effect)
     */
    protected java.awt.image.BufferedImage create_FOREGROUND_Image(final int WIDTH)
    {
        switch (getFrameType())
        {
            case ROUND:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH);
            case SQUARE:
                return FOREGROUND_FACTORY.createLinearForeground(WIDTH, WIDTH);
            default:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH);
        }        
    }

    /**
     * Returns the image of the glasseffect and a centered knob if wanted
     * @param WIDTH
     * @param WITH_CENTER_KNOB
     * @return the foreground image that will be used (in principle only the glass effect)
     */
    protected java.awt.image.BufferedImage create_FOREGROUND_Image(final int WIDTH, final boolean WITH_CENTER_KNOB)
    {
        switch (getFrameType())
        {
            case ROUND:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH, WITH_CENTER_KNOB);
            case SQUARE:
                return FOREGROUND_FACTORY.createLinearForeground(WIDTH, WIDTH, WITH_CENTER_KNOB);
            default:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH, WITH_CENTER_KNOB);
        }        
    }   
    
    /**
     * Returns the image of the selected (FG_TYPE1, FG_TYPE2, FG_TYPE3) glasseffect, the centered knob (if wanted)
     * @param WIDTH
     * @param WITH_CENTER_KNOB
     * @param TYPE
     * @return the foreground image that will be used
     */
    protected java.awt.image.BufferedImage create_FOREGROUND_Image(final int WIDTH, final boolean WITH_CENTER_KNOB, final eu.hansolo.steelseries.tools.ForegroundType TYPE)
    {
        return create_FOREGROUND_Image(WIDTH, WITH_CENTER_KNOB, TYPE, null);
    }
    
    /**
     * Returns the image of the selected (FG_TYPE1, FG_TYPE2, FG_TYPE3) glasseffect, the centered knob (if wanted)
     * @param WIDTH
     * @param WITH_CENTER_KNOB
     * @param TYPE
     * @param IMAGE 
     * @return the foreground image that will be used
     */
    protected java.awt.image.BufferedImage create_FOREGROUND_Image(final int WIDTH, final boolean WITH_CENTER_KNOB, final eu.hansolo.steelseries.tools.ForegroundType TYPE, final java.awt.image.BufferedImage IMAGE)
    {
        switch (getFrameType())
        {
            case ROUND:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH, WITH_CENTER_KNOB, TYPE, IMAGE);
            case SQUARE:
                return FOREGROUND_FACTORY.createLinearForeground(WIDTH, WIDTH, WITH_CENTER_KNOB, IMAGE);
            default:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH, WITH_CENTER_KNOB, eu.hansolo.steelseries.tools.ForegroundType.FG_TYPE1, IMAGE);
        } 
    }
            
    /**
     * Returns the image that will be displayed if the gauge is disabled
     * @param WIDTH
     * @return the disabled image that will be displayed if the gauge is disabled
     */
    protected java.awt.image.BufferedImage create_DISABLED_Image(final int WIDTH)
    {
        return DISABLED_FACTORY.createRadialDisabled(WIDTH);
    }
    // 

    // 
    /**
     * Calculates the rectangle that specifies the area that is available
     * for painting the gauge. This means that if the component has insets
     * that are larger than 0, these will be taken into account.
     */
    @Override
    public void calcInnerBounds()
    {
        final java.awt.Insets INSETS = getInsets();
        final int SIZE = (getWidth() - INSETS.left - INSETS.right) <= (getHeight() - INSETS.top - INSETS.bottom) ? (getWidth() - INSETS.left - INSETS.right) : (getHeight() - INSETS.top - INSETS.bottom); 
        if (getWidth() - INSETS.left - INSETS.right < getHeight() - INSETS.top - INSETS.bottom)
        {                        
            INNER_BOUNDS.setBounds(INSETS.left, INSETS.top, getWidth() - INSETS.left - INSETS.right, getHeight() - INSETS.top - INSETS.bottom);                        
        }
        else
        {
            INNER_BOUNDS.setBounds(INSETS.left + (int) (((double) (getWidth() - INSETS.left - INSETS.right) - (double) (getHeight() - INSETS.top - INSETS.bottom)) / 2.0), INSETS.top, getHeight() - INSETS.top - INSETS.bottom, getHeight() - INSETS.top - INSETS.bottom);
        }
        GAUGE_BOUNDS.setBounds(INSETS.left, INSETS.top, SIZE, SIZE);
    }
        
    /**
     * Returns the rectangle that specifies the area that is available
     * for painting the gauge. This means that if the component has insets
     * that are larger than 0, these will be taken into account.
     * If you add a border to the component the gauge will be drawn smaller
     * but within the border.
     * @return rectangle which describes the area that is available for painting
     */
    @Override
    public java.awt.Rectangle getInnerBounds()
    {
        return INNER_BOUNDS;
    }

    public java.awt.Rectangle getGaugeBounds()
    {
        return GAUGE_BOUNDS;
    }
    
    @Override
    public java.awt.Dimension getMinimumSize()
    {        
        return new java.awt.Dimension(200, 200);
    }
    
    @Override
    public void setPreferredSize(final java.awt.Dimension DIM)
    {        
        super.setPreferredSize(DIM);
        calcInnerBounds();
        init(DIM.width, DIM.width);        
        setInitialized(true);
        revalidate();
        repaint();
    }
    
    @Override
    public void setSize(final int WIDTH, final int HEIGHT)
    {
        super.setSize(WIDTH, WIDTH);
        calcInnerBounds();
        init(WIDTH, WIDTH);        
        setInitialized(true);
        revalidate();
        repaint();
    }
    
    @Override
    public void setSize(final java.awt.Dimension DIM)
    {
        super.setSize(DIM);
        calcInnerBounds();
        init(DIM.width, DIM.width);        
        setInitialized(true);
        revalidate();
        repaint();
    }
    
    @Override
    public void setBounds(final java.awt.Rectangle BOUNDS)
    {
        super.setBounds(BOUNDS);
        calcInnerBounds();
        init(BOUNDS.width, BOUNDS.width);        
        setInitialized(true);
        revalidate();
        repaint();
    }
    
    @Override
    public void setBounds(final int X, final int Y, final int WIDTH, final int HEIGHT)
    {
        super.setBounds(X, Y, WIDTH, WIDTH);
        calcInnerBounds();
        init(WIDTH, WIDTH);        
        setInitialized(true);
        revalidate();
        repaint();
    }
    // 

    // 
    @Override
    public void componentResized(final java.awt.event.ComponentEvent EVENT)
    {        
        final int SIZE = getWidth() <= getHeight() ? getWidth() : getHeight();                        
        if (getParent().getLayout() == null)
        {
            if (SIZE < getMinimumSize().width || SIZE < getMinimumSize().height)
            {
                setSize(getMinimumSize().width, getMinimumSize().height);
            }
            else
            {
                setSize(SIZE, SIZE);
            }
        }
        else
        {
            if (SIZE < getMinimumSize().width || SIZE < getMinimumSize().height)
            {            
                setPreferredSize(getMinimumSize());            
            }
            else
            {
                setPreferredSize(new java.awt.Dimension(SIZE, SIZE));
            }
        }
                
        calcInnerBounds();
                
        recreateLedImages();
        if (isLedOn())
        {
            setCurrentLedImage(getLedImageOn());
        }
        else
        {
            setCurrentLedImage(getLedImageOff());
        }        
        getModel().setSize(getLocation().x, getLocation().y, SIZE, SIZE);        
        init(getInnerBounds().width, getInnerBounds().height);
        revalidate();
        repaint();
    }
    // 
    
    @Override
    public String toString()
    {        
        return "AbstractRadial";        
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy