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.FrameType frameType;
    private eu.hansolo.steelseries.tools.Direction tickmarkDirection;
    // Foreground related
    private eu.hansolo.steelseries.tools.ForegroundType foregroundType;
    // LCD related variables
    private boolean valueCoupled;
    private String lcdUnitString;
    private boolean lcdUnitStringVisible;
    private boolean lcdScientificFormat;
    private double lcdValue;
    private boolean lcdVisible;
    private boolean digitalFont;
    private java.awt.Font lcdValueFont;
    private java.awt.Font lcdUnitFont;
    private boolean useCustomLcdUnitFont;
    protected static final java.awt.Font LCD_STANDARD_FONT = new java.awt.Font("Verdana", 1, 24);  
    protected static final java.awt.Font LCD_DIGITAL_FONT = eu.hansolo.steelseries.tools.Util.INSTANCE.getDigitalFont().deriveFont(24);
    private java.awt.Font customLcdUnitFont;
    private eu.hansolo.steelseries.tools.LcdColor lcdColor;
    private java.awt.Paint customLcdBackground;
    private java.awt.Color customLcdForeground;
    private int lcdDecimals;       
    private final org.pushingpixels.trident.Timeline LCD_TIMELINE;
    // Pointer related variables
    private eu.hansolo.steelseries.tools.PointerType pointerType;
    private eu.hansolo.steelseries.tools.ColorDef pointerColor;
    private eu.hansolo.steelseries.tools.CustomColorDef customPointerColor;
    // Knob related variables
    private eu.hansolo.steelseries.tools.KnobType knobType;
    // Animation related variables
    private final 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 final org.pushingpixels.trident.callback.TimelineCallback TIMELINE_CALLBACK;
    // 
    
    // 
    public AbstractRadial()
    {
        super();           
        frameType = eu.hansolo.steelseries.tools.FrameType.ROUND;
        foregroundType = eu.hansolo.steelseries.tools.ForegroundType.FG_TYPE1;
        valueCoupled = true;            
        lcdUnitStringVisible = false;
        lcdScientificFormat = false;
        lcdValue = 0;   
        lcdVisible = false;
        digitalFont = false;                        
        customLcdUnitFont = new java.awt.Font("Verdana", 1, 24);
        lcdColor = eu.hansolo.steelseries.tools.LcdColor.WHITE_LCD;
        customLcdBackground = java.awt.Color.BLACK;
        customLcdForeground = java.awt.Color.WHITE;
        lcdDecimals = 0;        
        LCD_TIMELINE = new org.pushingpixels.trident.Timeline(this);
        lcdUnitString = getUnitString();        
        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;
        pointerType = eu.hansolo.steelseries.tools.PointerType.TYPE1;
        pointerColor = eu.hansolo.steelseries.tools.ColorDef.RED;
        customPointerColor = new eu.hansolo.steelseries.tools.CustomColorDef(java.awt.Color.RED);
        knobType = eu.hansolo.steelseries.tools.KnobType.SMALL_KNOB;
        setLedPositionX(0.6);
        setLedPositionY(0.4);        
        addComponentListener(this);
        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();
        TIMELINE_CALLBACK = 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)
            {
                final double CURRENT_VALUE = getValue();

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

                // Check if current value exceeds minMeasuredValue
                if (CURRENT_VALUE < getMinMeasuredValue())
                {
                    setMinMeasuredValue(CURRENT_VALUE);
                }
            }
        };
        TIMELINE.addCallback(TIMELINE_CALLBACK);
    }
    // 
    
    //           
    /**
     * 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);        
        recreateAllImages();
        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 this.frameType;
    }
    
    /**
     * 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)
    {
        this.frameType = FRAME_TYPE;
        recreateAllImages();
        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 this.foregroundType;
    }
    
    /**
     * 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)
    {
        this.foregroundType = FOREGROUND_TYPE;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.FOREGROUND);
        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();
            }

            final double OVERALL_RANGE = getMaxValue() - getMinValue();
            final double RANGE = Math.abs(getValue() - VALUE);
            final double FRACTION = RANGE / OVERALL_RANGE;

            if (isAutoResetToZero())
            {
                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.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
                            setPeakValue(getValue());
                            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)
                    {
                        final double CURRENT_VALUE = getValue();

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

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

                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));

                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();
            }
            else
            {
                TIMELINE.addPropertyToInterpolate("value", getValue(), VALUE);
                TIMELINE.setEase(STANDARD_EASING);
                TIMELINE.setDuration((long) (getStdTimeToValue() * FRACTION));
                TIMELINE.play();
            }
        }
    }
   
    /**
     * 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;
    }

    /**
     * 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();
    }
    
    /**
     * 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;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.TICKMARKS);
        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 this.pointerType;
    }

    /**
     * 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)
    {
        this.pointerType = POINTER_TYPE;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER_SHADOW);
        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 this.pointerColor;
    }

    /**
     * Sets the color of the pointer
     * @param POINTER_COLOR
     */
    public void setPointerColor(final eu.hansolo.steelseries.tools.ColorDef POINTER_COLOR)
    {
        this.pointerColor = POINTER_COLOR;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER);
        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 this.customPointerColor.COLOR;
    }
    
    /**
     * Sets the color from which the custom pointer color is calculated
     * @param COLOR 
     */
    public void setCustomPointerColor(final java.awt.Color COLOR)
    {
        this.customPointerColor = new eu.hansolo.steelseries.tools.CustomColorDef(COLOR);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER);
        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 this.customPointerColor;
    }
    
    /**
     * Returns the type of the knob
     * @return the type of the knob
     */
    public eu.hansolo.steelseries.tools.KnobType getKnobType()
    {
        return this.knobType;
    }
    
    /**
     * Sets the type of the knob
     * @param KNOB_TYPE 
     */
    public void setKnobType(final eu.hansolo.steelseries.tools.KnobType KNOB_TYPE)
    {
        this.knobType = KNOB_TYPE;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POSTS);
        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 this.lcdVisible;
    }
    
    /**
     * Enables or disables the visibility of the lcd display
     * @param LCD_VISIBLE 
     */
    public void setLcdVisible(final boolean LCD_VISIBLE)
    {
        this.lcdVisible = LCD_VISIBLE;
        repaint(getInnerBounds());
    }
    
    @Override
    public boolean isValueCoupled()
    {
        return this.valueCoupled;
    }
    
    @Override
    public void setValueCoupled(final boolean VALUE_COUPLED)
    {
        this.valueCoupled = 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 (LCD_TIMELINE.getState() == org.pushingpixels.trident.Timeline.TimelineState.PLAYING_FORWARD || LCD_TIMELINE.getState() == org.pushingpixels.trident.Timeline.TimelineState.PLAYING_REVERSE)
        {
            LCD_TIMELINE.abort();
        }
        LCD_TIMELINE.addPropertyToInterpolate("lcdValue", this.lcdValue, LCD_VALUE);
        LCD_TIMELINE.setEase(new org.pushingpixels.trident.ease.Spline(0.5f));
  
        LCD_TIMELINE.play();
    }

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

    @Override
    public void setLcdUnitString(final String UNIT_STRING)
    {
        this.lcdUnitString = UNIT_STRING;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public boolean isLcdUnitStringVisible()
    {
        return lcdUnitStringVisible;
    }

    @Override
    public void setLcdUnitStringVisible(final boolean UNIT_STRING_VISIBLE)
    {
        this.lcdUnitStringVisible = UNIT_STRING_VISIBLE;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public boolean isDigitalFont()
    {
        return this.digitalFont;
    }

    @Override
    public void setDigitalFont(final boolean DIGITAL_FONT)
    {
        this.digitalFont = DIGITAL_FONT;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public boolean getUseCustomLcdUnitFont()
    {
        return this.useCustomLcdUnitFont;
    }

    @Override
    public void setUseCustomLcdUnitFont(final boolean USE_CUSTOM_LCD_UNIT_FONT)
    {
        useCustomLcdUnitFont = USE_CUSTOM_LCD_UNIT_FONT;
        repaint(getInnerBounds());
    }

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

    @Override
    public void setCustomLcdUnitFont(final java.awt.Font CUSTOM_LCD_UNIT_FONT)
    {
        customLcdUnitFont = CUSTOM_LCD_UNIT_FONT;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

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

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

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

    @Override
    public void setLcdColor(final eu.hansolo.steelseries.tools.LcdColor COLOR)
    {
        this.lcdColor = COLOR;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }

    @Override
    public java.awt.Paint getCustomLcdBackground()
    {
        return this.customLcdBackground;
    }
    
    @Override
    public void setCustomLcdBackground(final java.awt.Paint CUSTOM_LCD_BACKGROUND)
    {
        this.customLcdBackground = CUSTOM_LCD_BACKGROUND;
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    @Override
    public java.awt.Color getCustomLcdForeground()
    {
        return this.customLcdForeground;
    }
    
    @Override
    public void setCustomLcdForeground(final java.awt.Color CUSTOM_LCD_FOREGROUND)
    {
        this.customLcdForeground = CUSTOM_LCD_FOREGROUND;
        init(getInnerBounds().width, getInnerBounds().height);
        repaint(getInnerBounds());
    }
    
    @Override
    public String formatLcdValue(final double VALUE)
    {
        final StringBuilder DEC_BUFFER = new StringBuilder();
        DEC_BUFFER.append("0");

        if (this.lcdDecimals > 0)
        {
            DEC_BUFFER.append(".");
        }

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

        if(lcdScientificFormat)
        {
            DEC_BUFFER.append("E0");
        }

        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 this.lcdScientificFormat;
    }

    @Override
    public void setLcdScientificFormat(boolean LCD_SCIENTIFIC_FORMAT)
    {
        lcdScientificFormat = LCD_SCIENTIFIC_FORMAT;
        repaint(getInnerBounds());
    }
    
    @Override
    public java.awt.Font getLcdValueFont()
    {
        return this.lcdValueFont;
    }
    
    @Override
    public void setLcdValueFont(final java.awt.Font LCD_VALUE_FONT)
    {
        this.lcdValueFont = LCD_VALUE_FONT;
        repaint(getInnerBounds());
    }
    
    @Override
    public java.awt.Font getLcdUnitFont()
    {
        return this.lcdUnitFont;
    }
    
    @Override
    public void setLcdUnitFont(final java.awt.Font LCD_UNIT_FONT)
    {
        this.lcdUnitFont = LCD_UNIT_FONT;
        repaint(getInnerBounds());
    }
    // 

    // 
    /**
     * Fills the EnumSet with all ImageTypes that are needed for initialization     
     */
    protected void createInitialImages()
    {
        {
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.FRAME);
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.BACKGROUND);
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POSTS);        
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.TICKMARKS);
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.TITLE);     
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER);
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER_SHADOW);
            IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.FOREGROUND);        
        }
    }

    @Override
    protected void recreateAllImages()
    {
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.FRAME);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.BACKGROUND);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POSTS);
        //IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.BARGRAPHTRACK);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.TRACK);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.TICKMARKS);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.TITLE);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.THRESHOLD);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LOW);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.HIGH);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.LCD);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.POINTER_SHADOW);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.FOREGROUND);
        IMAGES_TO_UPDATE.add(eu.hansolo.steelseries.tools.ImageType.DISABLED);
    }
    
    /**
     * 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)
    {
        if (WIDTH <= 0)
        {
            return null;
        }
        
        final java.awt.image.BufferedImage 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 ROUND:
                G2.drawImage(BACKGROUND_FACTORY.createRadialBackground(WIDTH, getBackgroundColor(), getCustomBackground()), 0, 0, null);
                break;
            case SQUARE:
                G2.drawImage(BACKGROUND_FACTORY.createLinearBackground(WIDTH, WIDTH, getBackgroundColor(), getCustomBackground()), 0, 0, null);
                break;
            default:
                G2.drawImage(BACKGROUND_FACTORY.createRadialBackground(WIDTH, getBackgroundColor(), getCustomBackground()), 0, 0, null);
                break;
        }

        // Draw the custom layer if selected
        if (isCustomLayerVisible())
        {
            G2.drawImage(UTIL.getScaledInstance(getCustomLayer(), IMAGE_WIDTH, IMAGE_HEIGHT, java.awt.RenderingHints.VALUE_INTERPOLATION_BICUBIC, true), 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(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 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.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 buffered image containing the background with the selected background design
     */
    protected java.awt.image.BufferedImage create_TITLE_Image(final int WIDTH, final String TITLE, final String UNIT_STRING)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(10, 10, java.awt.Transparency.TRANSLUCENT);
        }
        
        final java.awt.image.BufferedImage 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)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(10, 10, java.awt.Transparency.TRANSLUCENT);
        }

        final java.awt.image.BufferedImage IMAGE = GFX_CONF.createCompatibleImage(WIDTH, 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.setRenderingHint(java.awt.RenderingHints.KEY_RENDERING, java.awt.RenderingHints.VALUE_RENDER_QUALITY);
        //G2.setRenderingHint(java.awt.RenderingHints.KEY_DITHERING, java.awt.RenderingHints.VALUE_DITHER_ENABLE);
        //G2.setRenderingHint(java.awt.RenderingHints.KEY_ALPHA_INTERPOLATION, java.awt.RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        //G2.setRenderingHint(java.awt.RenderingHints.KEY_COLOR_RENDERING, java.awt.RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        G2.setRenderingHint(java.awt.RenderingHints.KEY_STROKE_CONTROL, java.awt.RenderingHints.VALUE_STROKE_PURE);
        //G2.setRenderingHint(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING, java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        final int IMAGE_WIDTH = IMAGE.getWidth();
        final int IMAGE_HEIGHT = IMAGE.getHeight();

        // Background rectangle
        final java.awt.geom.Point2D BACKGROUND_START = new java.awt.geom.Point2D.Double(0.0, 0.0);
        final java.awt.geom.Point2D BACKGROUND_STOP = new java.awt.geom.Point2D.Double(0.0, IMAGE_HEIGHT);

        final float[] BACKGROUND_FRACTIONS =
        {
            0.0f,
            0.08f,
            0.92f,
            1.0f
        };

        final java.awt.Color[] BACKGROUND_COLORS =
        {
            new java.awt.Color(0.3f, 0.3f, 0.3f, 1.0f),
            new java.awt.Color(0.4f, 0.4f, 0.4f, 1.0f),
            new java.awt.Color(0.4f, 0.4f, 0.4f, 1.0f),
            new java.awt.Color(0.9f, 0.9f, 0.9f, 1.0f)
        };

        final java.awt.LinearGradientPaint BACKGROUND_GRADIENT = new java.awt.LinearGradientPaint(BACKGROUND_START, BACKGROUND_STOP, BACKGROUND_FRACTIONS, BACKGROUND_COLORS);
        final double BACKGROUND_CORNER_RADIUS = IMAGE_WIDTH * 0.078125f;
        //final double BACKGROUND_CORNER_RADIUS = IMAGE_WIDTH * 0.09375f;
        final java.awt.geom.RoundRectangle2D BACKGROUND = new java.awt.geom.RoundRectangle2D.Double(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, BACKGROUND_CORNER_RADIUS, BACKGROUND_CORNER_RADIUS);
        G2.setPaint(BACKGROUND_GRADIENT);
        G2.fill(BACKGROUND);

        // Foreground rectangle
        final java.awt.geom.Point2D FOREGROUND_START = new java.awt.geom.Point2D.Double(0.0, 1.0);
        final java.awt.geom.Point2D FOREGROUND_STOP = new java.awt.geom.Point2D.Double(0.0, IMAGE_HEIGHT - 1);

        final float[] FOREGROUND_FRACTIONS =
        {
            0.0f,
            0.03f,
            0.49f,
            0.5f,
            1.0f
        };
                
        final java.awt.Color[] FOREGROUND_COLORS =
        {
            LCD_COLOR.GRADIENT_START_COLOR,
            LCD_COLOR.GRADIENT_FRACTION1_COLOR,
            LCD_COLOR.GRADIENT_FRACTION2_COLOR,
            LCD_COLOR.GRADIENT_FRACTION3_COLOR,
            LCD_COLOR.GRADIENT_STOP_COLOR
        };
                
        if (LCD_COLOR == eu.hansolo.steelseries.tools.LcdColor.CUSTOM)
        {
            G2.setPaint(CUSTOM_LCD_BACKGROUND);
        }
        else
        {
            final java.awt.LinearGradientPaint FOREGROUND_GRADIENT = new java.awt.LinearGradientPaint(FOREGROUND_START, FOREGROUND_STOP, FOREGROUND_FRACTIONS, FOREGROUND_COLORS);
            G2.setPaint(FOREGROUND_GRADIENT);
        }
                final double FOREGROUND_CORNER_RADIUS = BACKGROUND.getArcWidth() - 1;
        final java.awt.geom.RoundRectangle2D FOREGROUND = new java.awt.geom.RoundRectangle2D.Double(1, 1, IMAGE_WIDTH - 2, IMAGE_HEIGHT - 2, FOREGROUND_CORNER_RADIUS, FOREGROUND_CORNER_RADIUS);        
        G2.fill(FOREGROUND);

        G2.dispose();

        return 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)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(200, 200, java.awt.Transparency.TRANSLUCENT);
        }

        final java.awt.image.BufferedImage 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
        final float LINE_WIDTH;
        switch (getGaugeType())
        {
            case TYPE1:
                LINE_WIDTH = (float) Math.toDegrees(Math.PI / 2.0 - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            case TYPE2:
                LINE_WIDTH = (float) Math.toDegrees(Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            case TYPE3:
                LINE_WIDTH = (float) Math.toDegrees(1.5 * Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            case TYPE4:
                LINE_WIDTH = (float) Math.toDegrees(2.0 * Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
            default:
                LINE_WIDTH = (float) Math.toDegrees(2.0 * Math.PI - FREE_AREA_ANGLE) * 0.00166666666f * WIDTH * 0.0066666f;
                break;
                
        }                
        final java.awt.BasicStroke STD_STROKE = new java.awt.BasicStroke(LINE_WIDTH, 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;
        }
        
        G2.setStroke(STD_STROKE);           
        double fraction = 0;
        // Draw track from TRACK_START to TRACK_SECTION
        for (double alpha = ALPHA_START; alpha >= ALPHA_SECTION; alpha -= (ANGLE_STEP / 10), fraction += 0.1)
        {
            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; alpha >= ALPHA_STOP; alpha -= (ANGLE_STEP / 10), fraction += 0.1)
        {
            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 tickmarks.
     * @param WIDTH
     * @param FREE_AREA_ANGLE
     * @param OFFSET
     * @param MIN_VALUE
     * @param MAX_VALUE
     * @param ANGLE_STEP
     * @param TICK_LABEL_PERIOD
     * @param SCALE_DIVIDER_POWER
     * @param TRACK_START_COLOR
     * @param TRACK_SECTION_COLOR
     * @param TRACK_STOP_COLOR
     * @param ROTATION_OFFSET
     * @return the tickmarks image that is used
     */
    protected java.awt.image.BufferedImage create_TICKMARKS_Image(final int WIDTH, final double FREE_AREA_ANGLE, final double OFFSET, final double MIN_VALUE, final double MAX_VALUE, final double ANGLE_STEP, final int TICK_LABEL_PERIOD, final int SCALE_DIVIDER_POWER, final java.awt.Color TRACK_START_COLOR, final java.awt.Color TRACK_SECTION_COLOR, final java.awt.Color TRACK_STOP_COLOR, final double ROTATION_OFFSET)
    {
        return create_TICKMARKS_Image(WIDTH, FREE_AREA_ANGLE, OFFSET, MIN_VALUE, MAX_VALUE, ANGLE_STEP, TICK_LABEL_PERIOD, SCALE_DIVIDER_POWER, true, true, null);
    }

    /**
     * Returns the image of the tickmarks.
     * @param WIDTH
     * @param FREE_AREA_ANGLE
     * @param OFFSET
     * @param MIN_VALUE
     * @param MAX_VALUE
     * @param ANGLE_STEP
     * @param TICK_LABEL_PERIOD
     * @param SCALE_DIVIDER_POWER
     * @param DRAW_TICKS
     * @param DRAW_TICK_LABELS
     * @param TICKMARK_SECTIONS
     * @return the tickmarks image that is used
     */
    protected java.awt.image.BufferedImage create_TICKMARKS_Image(final int WIDTH, final double FREE_AREA_ANGLE, final double OFFSET, final double MIN_VALUE, final double MAX_VALUE, final double ANGLE_STEP, final int TICK_LABEL_PERIOD, final int SCALE_DIVIDER_POWER, final boolean DRAW_TICKS, final boolean DRAW_TICK_LABELS, final java.util.ArrayList TICKMARK_SECTIONS)
    {
        return create_TICKMARKS_Image(WIDTH, FREE_AREA_ANGLE, OFFSET, MIN_VALUE, MAX_VALUE, ANGLE_STEP, TICK_LABEL_PERIOD, SCALE_DIVIDER_POWER, DRAW_TICKS, DRAW_TICK_LABELS, TICKMARK_SECTIONS, 0.38f, 0.09f, new java.awt.geom.Point2D.Double(WIDTH / 2.0, WIDTH / 2.0));
    }

    /**
     * Returns the image of the tickmarks
     * @param WIDTH
     * @param FREE_AREA_ANGLE
     * @param OFFSET
     * @param MIN_VALUE
     * @param MAX_VALUE
     * @param ANGLE_STEP
     * @param TICK_LABEL_PERIOD
     * @param SCALE_DIVIDER_POWER
     * @param DRAW_TICKS
     * @param DRAW_TICK_LABELS
     * @param TICKMARK_SECTIONS
     * @param RADIUS_FACTOR
     * @param TEXT_DISTANCE_FACTOR
     * @param CENTER
     * @return the tickmark image that is used
     */
    protected java.awt.image.BufferedImage create_TICKMARKS_Image(final int WIDTH, final double FREE_AREA_ANGLE, final double OFFSET, final double MIN_VALUE, final double MAX_VALUE, final double ANGLE_STEP, final int TICK_LABEL_PERIOD, final int SCALE_DIVIDER_POWER, final boolean DRAW_TICKS, final boolean DRAW_TICK_LABELS, final java.util.ArrayList TICKMARK_SECTIONS, final float RADIUS_FACTOR, final float TEXT_DISTANCE_FACTOR, final java.awt.geom.Point2D CENTER)
    {
        return create_TICKMARKS_Image(WIDTH, FREE_AREA_ANGLE, OFFSET, MIN_VALUE, MAX_VALUE, ANGLE_STEP, TICK_LABEL_PERIOD, 0, SCALE_DIVIDER_POWER, DRAW_TICKS, DRAW_TICK_LABELS, TICKMARK_SECTIONS, RADIUS_FACTOR, TEXT_DISTANCE_FACTOR, CENTER, eu.hansolo.steelseries.tools.Direction.CLOCKWISE, null);
    }
    
    /**
     * Returns the image of the tickmarks
     * @param WIDTH
     * @param FREE_AREA_ANGLE
     * @param ROTATION_OFFSET
     * @param MIN_VALUE
     * @param MAX_VALUE
     * @param ANGLE_STEP
     * @param TICK_LABEL_PERIOD
     * @param TICK_LABEL_ROTATION_OFFSET
     * @param SCALE_DIVIDER_POWER
     * @param DRAW_TICKS
     * @param DRAW_TICK_LABELS
     * @param TICKMARK_SECTIONS
     * @param RADIUS_FACTOR
     * @param TEXT_DISTANCE_FACTOR
     * @param CENTER
     * @param DIRECTION
     * @param OFFSET 
     * @return the tickmark image that is used
     */    
    protected java.awt.image.BufferedImage create_TICKMARKS_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 int TICK_LABEL_PERIOD, final double TICK_LABEL_ROTATION_OFFSET, final int SCALE_DIVIDER_POWER, final boolean DRAW_TICKS, final boolean DRAW_TICK_LABELS, final java.util.ArrayList TICKMARK_SECTIONS, final float RADIUS_FACTOR, final float TEXT_DISTANCE_FACTOR, final java.awt.geom.Point2D CENTER, final eu.hansolo.steelseries.tools.Direction DIRECTION, final java.awt.geom.Point2D OFFSET)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(200, 200, java.awt.Transparency.TRANSLUCENT);
        }
                        
        final java.awt.image.BufferedImage 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_FRACTIONALMETRICS, java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        G2.setRenderingHint(java.awt.RenderingHints.KEY_STROKE_CONTROL, java.awt.RenderingHints.VALUE_STROKE_PURE);
        G2.setRenderingHint(java.awt.RenderingHints.KEY_TEXT_ANTIALIASING, java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        final int IMAGE_WIDTH = IMAGE.getWidth();
        //final int IMAGE_HEIGHT = IMAGE.getHeight();

        if (!DRAW_TICKS && !DRAW_TICK_LABELS)
        {
            G2.dispose();
            return IMAGE;
        }

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

        // Definitions
        final java.awt.Font STD_FONT = new java.awt.Font("Verdana", 0, (int) (0.04 * WIDTH));
        final java.awt.BasicStroke STD_STROKE = new java.awt.BasicStroke(1.0f, java.awt.BasicStroke.CAP_ROUND, java.awt.BasicStroke.JOIN_BEVEL);
        final java.awt.BasicStroke MEDIUM_STROKE = new java.awt.BasicStroke(0.5f, java.awt.BasicStroke.CAP_ROUND, java.awt.BasicStroke.JOIN_BEVEL);
        final java.awt.BasicStroke THIN_STROKE = new java.awt.BasicStroke(0.3f, java.awt.BasicStroke.CAP_ROUND, java.awt.BasicStroke.JOIN_BEVEL);
        final java.awt.BasicStroke VERY_THIN_STROKE = new java.awt.BasicStroke(0.1f, java.awt.BasicStroke.CAP_ROUND, java.awt.BasicStroke.JOIN_BEVEL);
        final int TEXT_DISTANCE = (int) (TEXT_DISTANCE_FACTOR * WIDTH);
        final int TICK_01_LENGTH = (int) (0.01 * WIDTH);
        final int TICK_1_LENGTH = (int) (0.0133333333 * WIDTH);
        final int TICK_5_LENGTH = (int) (0.02 * WIDTH);
        final int TICK_10_LENGTH = (int) (0.03 * WIDTH);
        final int TICK_100_LENGTH = (int) (0.04 * WIDTH);

        // Create the ticks itself
        final float RADIUS = IMAGE_WIDTH * RADIUS_FACTOR;

        // Draw ticks
        final java.awt.geom.Point2D INNER_POINT = new java.awt.geom.Point2D.Double(0,0);
        final java.awt.geom.Point2D OUTER_POINT = new java.awt.geom.Point2D.Double(0,0);
        final java.awt.geom.Point2D TEXT_POINT = new java.awt.geom.Point2D.Double(0,0);
        final java.awt.geom.Line2D TICK = new java.awt.geom.Line2D.Double(0, 0, 1, 1);
        int counter = 0;

        G2.setFont(STD_FONT);

        double sinValue = 0;
        double cosValue = 0;

        // Quarter circle:            0.5 * Math.PI
        // Half circle:               1.0 * Math.PI
        // ThreeQuarter circle:       1.5 * Math.PI
        // Full circle:               2.0 * Math.PI
        // Direction clockwise:       alpha -= ALPHA_STEP
        // Direction counterclockwise alpha += ALPHA_STEP
        // StartPoint offset top clock: Math.PI
        // StartPoint offset right clock: 0.5 * Math.PI
        // StartPoint offset bottom clock: 0
        // StartPoint offset left clock: -0.5 * Math.PI

        // OFFSET
        //final double TOP = Math.PI;
        //final double RIGHT = -0.5 * Math.PI;
        //final double BOTTOM = 0;
        //final double LEFT = 0.5 * Math.PI;

        final double ALPHA_START = -ROTATION_OFFSET - (FREE_AREA_ANGLE / 2.0); // offset angle for the tickmarks

        // The range from min to max
        final double RANGE = MAX_VALUE - MIN_VALUE;

        /*
         * Different styled tickmarks will be drawn after different intervals.
         * e.g. a small, light dot will be drawn every step whereas a strong bar
         * will be drawn after every 100 steps. Sometimes a step of one for the
         * small, light dot is too fine grained. In this case the whole step
         * scaling can be raised to the next power of ten of the values shown.
         */
        final int STEP_MULTIPLIER = (int) (Math.pow(10, SCALE_DIVIDER_POWER));

        final double SCALED_ANGLE_STEP = ANGLE_STEP * STEP_MULTIPLIER;        

        final int ONE_POINT_STEP = STEP_MULTIPLIER;
        final int FIVE_POINT_STEP = 5 * STEP_MULTIPLIER;
        final int TEN_POINT_STEP = 10 * STEP_MULTIPLIER;
        final int HUNDRED_POINT_STEP = 100 * STEP_MULTIPLIER;

        /*  Calculation of thresholds where to show/hide tickmarks dependent on the size of the gauge (full, threequarter, twoquarter, quarter)
         *  The RANGE_THRESHOLD_N value defines the threshold where the tickmarks change.
         *  e.g. If the max value of a full radial gauge is smaller than 20, the smallest tickmarks will be drawn
         *  This means for a half radial gauge (two quarter) the max value must be smaller than 10, for a quarter gauge smaller than 5
         */
        final float RANGE_THRESHOLD_FACTOR = (int) Math.toDegrees((RANGE * SCALED_ANGLE_STEP) + FREE_AREA_ANGLE) / 360f;
        final int RANGE_THRESHOLD_20 = (int) (20 * RANGE_THRESHOLD_FACTOR); // if range smaller than 20
        final int RANGE_THRESHOLD_500 = (int) (300 * RANGE_THRESHOLD_FACTOR); // if range larger than 300
        final int RANGE_THRESHOLD_1000 = (int) (800 * RANGE_THRESHOLD_FACTOR); // if range larger than 800

        // alpha => angle for the tickmarks
        // valueCounter => value for the tickmarks
        for (double alpha = ALPHA_START, valueCounter = MIN_VALUE; valueCounter <= MAX_VALUE; alpha -= SCALED_ANGLE_STEP, valueCounter += STEP_MULTIPLIER)
        {
            if (TICKMARK_SECTIONS != null && !TICKMARK_SECTIONS.isEmpty())
            {
                if (isTickmarkSectionsVisible())
                {
                    for (eu.hansolo.steelseries.tools.Section section : TICKMARK_SECTIONS)
                    {
                        if (valueCounter >= section.getStart() && valueCounter <= section.getStop())
                        {
                            G2.setColor(section.getColor());
                            break;
                        }
                        else if (isTickmarkColorFromThemeEnabled())
                        {
                            G2.setColor(getBackgroundColor().LABEL_COLOR);
                        }
                        else
                        {
                            G2.setColor(getTickmarkColor());
                        }
                    }
                }
                else
                {
                    if (isTickmarkColorFromThemeEnabled())
                    {
                        G2.setColor(getBackgroundColor().LABEL_COLOR);
                    }
                    else
                    {
                        G2.setColor(getTickmarkColor());
                    }
                }
            }
            else
            {
                if (isTickmarkColorFromThemeEnabled())
                {
                    G2.setColor(getBackgroundColor().LABEL_COLOR);
                }
                else
                {
                    G2.setColor(getTickmarkColor());
                }
            }

            G2.setStroke(MEDIUM_STROKE);
            sinValue = Math.sin(alpha);
            cosValue = Math.cos(alpha);
            TEXT_POINT.setLocation(CENTER.getX() + (RADIUS - TEXT_DISTANCE) * sinValue, CENTER.getY() + (RADIUS - TEXT_DISTANCE) * cosValue);
            INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TICK_1_LENGTH) * sinValue, CENTER.getY() + (RADIUS - TICK_1_LENGTH) * cosValue);
            OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);

            // Very thin tickmark every 0.1 unit
            if (counter % ONE_POINT_STEP == 0 && RANGE <= RANGE_THRESHOLD_20 && Double.compare(alpha, ALPHA_START) != 0)
            {
                if (DRAW_TICKS)
                {
                    G2.setStroke(VERY_THIN_STROKE);
                    for (double innerAlpha = alpha + SCALED_ANGLE_STEP; innerAlpha > alpha; innerAlpha -= SCALED_ANGLE_STEP / 10.0)
                    {
                        INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TICK_01_LENGTH) * Math.sin(innerAlpha), CENTER.getY() + (RADIUS - TICK_01_LENGTH) * Math.cos(innerAlpha));
                        OUTER_POINT.setLocation(CENTER.getX() + RADIUS * Math.sin(innerAlpha), CENTER.getY() + RADIUS * Math.cos(innerAlpha));
                        TICK.setLine(INNER_POINT, OUTER_POINT);
                        G2.draw(TICK);
                    }
                }
            }

            // Thin tickmark every 1 unit
            if (counter % ONE_POINT_STEP == 0 && counter % FIVE_POINT_STEP != 0 && counter % TEN_POINT_STEP != 0 && counter % HUNDRED_POINT_STEP != 0 && RANGE < RANGE_THRESHOLD_500)
            {
                if (DRAW_TICKS)
                {
                    G2.setStroke(THIN_STROKE);
                    INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TICK_1_LENGTH) * sinValue, CENTER.getY() + (RADIUS - TICK_1_LENGTH) * cosValue);
                    OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
                    TICK.setLine(INNER_POINT, OUTER_POINT);
                    G2.draw(TICK);
                }
            }

            // Medium tickmark every 5 units
            if (counter % FIVE_POINT_STEP == 0 && counter % TEN_POINT_STEP != 0 && counter % HUNDRED_POINT_STEP != 0 && RANGE < RANGE_THRESHOLD_1000)
            {
                if (DRAW_TICKS)
                {
                    G2.setStroke(MEDIUM_STROKE);
                    INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TICK_5_LENGTH) * sinValue, CENTER.getY() + (RADIUS - TICK_5_LENGTH) * cosValue);
                    OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
                    TICK.setLine(INNER_POINT, OUTER_POINT);
                    G2.draw(TICK);
                }
            }

            // Standard tickmark every 10 units
            if (counter % TEN_POINT_STEP == 0 && counter % HUNDRED_POINT_STEP != 0 || counter == 0 && RANGE < RANGE_THRESHOLD_1000)
            {
                if (DRAW_TICKS)
                {
                    G2.setStroke(STD_STROKE);
                    INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TICK_10_LENGTH) * sinValue, CENTER.getY() + (RADIUS - TICK_10_LENGTH) * cosValue);
                    OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
                    TICK.setLine(INNER_POINT, OUTER_POINT);
                    G2.draw(TICK);
                }
            }

            // Longer standard tickmark every 100 units
            if (counter == HUNDRED_POINT_STEP)
            {
                if (DRAW_TICKS)
                {
                    G2.setStroke(STD_STROKE);
                    INNER_POINT.setLocation(CENTER.getX() + (RADIUS - TICK_100_LENGTH) * sinValue, CENTER.getY() + (RADIUS - TICK_100_LENGTH) * cosValue);
                    OUTER_POINT.setLocation(CENTER.getX() + RADIUS * sinValue, CENTER.getY() + RADIUS * cosValue);
                    TICK.setLine(INNER_POINT, OUTER_POINT);

                    G2.draw(TICK);
                }

                counter = 0;
            }

            // Draw the tickmark labels dependend of the direction (clockwise or counter clockwise)
            if (DRAW_TICK_LABELS)
            {
                if (isCustomTickmarkLabelsEnabled())
                {
                    // Draw custom tickmark labels if selected
                    for (double tickLabel : getCustomTickmarkLabels())
                    {
                        if (Double.compare(valueCounter, tickLabel) == 0)
                        {
                            switch (DIRECTION)
                            {
                                case CLOCKWISE:
                                    G2.fill(UTIL.rotateTextAroundCenter(G2, String.valueOf((int) valueCounter), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), Math.toDegrees(Math.PI - alpha + TICK_LABEL_ROTATION_OFFSET)));
                                    break;

                                case COUNTER_CLOCKWISE:
                                    G2.fill(UTIL.rotateTextAroundCenter(G2, String.valueOf((int) (MAX_VALUE - valueCounter)), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), Math.toDegrees(Math.PI - alpha + TICK_LABEL_ROTATION_OFFSET)));
                                    break;
                            }
                        }
                    }
                }
                else
                {
                    // Draw the standard tickmark labels
                    if (valueCounter % TICK_LABEL_PERIOD == 0)
                    {
                        switch (DIRECTION)
                        {
                            case CLOCKWISE:
                                G2.fill(UTIL.rotateTextAroundCenter(G2, String.valueOf((int) valueCounter), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), Math.toDegrees(Math.PI - alpha + TICK_LABEL_ROTATION_OFFSET)));
                                break;

                            case COUNTER_CLOCKWISE:
                                G2.fill(UTIL.rotateTextAroundCenter(G2, String.valueOf((int) (MAX_VALUE - valueCounter)), (int) TEXT_POINT.getX(), (int) TEXT_POINT.getY(), Math.toDegrees(Math.PI - alpha + TICK_LABEL_ROTATION_OFFSET)));
                                break;
                        }
                    }
                }
            }

            counter += STEP_MULTIPLIER;
        }

        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)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(200, 200, java.awt.Transparency.TRANSLUCENT);
        }

        final java.awt.image.BufferedImage 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.round(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_KNOB:
                    //G2.drawImage(CENTER_KNOB, (int) ((IMAGE_WIDTH - CENTER_KNOB.getWidth()) / 2.0), (int) ((IMAGE_HEIGHT - CENTER_KNOB.getHeight()) / 2.0), 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_KNOB:
                    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;
            }
        }
                              
        // 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_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_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;
            }
        }

        // 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_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)
    {
        if (WIDTH <= 0)
        {
            return GFX_CONF.createCompatibleImage(10, 10, java.awt.Transparency.TRANSLUCENT);
        }

        final java.awt.image.BufferedImage 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(KNOB_TYPE)
        {
            case SMALL_KNOB:
                final java.awt.geom.Ellipse2D POST_FRAME = new java.awt.geom.Ellipse2D.Double(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
                final java.awt.geom.Point2D POST_FRAME_START = new java.awt.geom.Point2D.Double(0, POST_FRAME.getBounds2D().getMinY());
                final java.awt.geom.Point2D POST_FRAME_STOP = new java.awt.geom.Point2D.Double(0, POST_FRAME.getBounds2D().getMaxY());
                final float[] POST_FRAME_FRACTIONS =
                {
                    0.0f,
                    0.46f,
                    1.0f
                };
                final java.awt.Color[] POST_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 POST_FRAME_GRADIENT = new java.awt.LinearGradientPaint(POST_FRAME_START, POST_FRAME_STOP, POST_FRAME_FRACTIONS, POST_FRAME_COLORS);
                G2.setPaint(POST_FRAME_GRADIENT);
                G2.fill(POST_FRAME);

                final java.awt.geom.Ellipse2D POST_MAIN = new java.awt.geom.Ellipse2D.Double((IMAGE_WIDTH - IMAGE_WIDTH * 0.77) / 2.0, (IMAGE_WIDTH - IMAGE_WIDTH * 0.77) / 2.0, IMAGE_WIDTH * 0.77, IMAGE_WIDTH * 0.77);
                final java.awt.geom.Point2D POST_MAIN_START = new java.awt.geom.Point2D.Double(0, POST_MAIN.getBounds2D().getMinY());
                final java.awt.geom.Point2D POST_MAIN_STOP = new java.awt.geom.Point2D.Double(0, POST_MAIN.getBounds2D().getMaxY());
                final float[] POST_MAIN_FRACTIONS =
                {
                    0.0f,
                    1.0f
                };
                final java.awt.Color[] POST_MAIN_COLORS =
                {
                    new java.awt.Color(217, 217, 217, 255),
                    new java.awt.Color(191, 191, 191, 255)
                };

                final java.awt.LinearGradientPaint POST_MAIN_GRADIENT = new java.awt.LinearGradientPaint(POST_MAIN_START, POST_MAIN_STOP, POST_MAIN_FRACTIONS, POST_MAIN_COLORS);
                G2.setPaint(POST_MAIN_GRADIENT);
                G2.fill(POST_MAIN);

                final java.awt.geom.Ellipse2D POST_INNERSHADOW = new java.awt.geom.Ellipse2D.Double((IMAGE_WIDTH - IMAGE_WIDTH * 0.77) / 2.0, (IMAGE_WIDTH - IMAGE_WIDTH * 0.77) / 2.0, IMAGE_WIDTH * 0.77, IMAGE_WIDTH * 0.77);
                final java.awt.geom.Point2D POST_INNERSHADOW_CENTER = new java.awt.geom.Point2D.Double(POST_INNERSHADOW.getCenterX(), POST_INNERSHADOW.getCenterY());
                final float[] POST_INNERSHADOW_FRACTIONS =
                {
                    0.0f,
                    0.75f,
                    0.76f,
                    1.0f
                };
                final java.awt.Color[] POST_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 POST_INNERSHADOW_GRADIENT = new java.awt.RadialGradientPaint(POST_INNERSHADOW_CENTER, (float) (POST_INNERSHADOW.getWidth() / 2.0), POST_INNERSHADOW_FRACTIONS, POST_INNERSHADOW_COLORS);
                G2.setPaint(POST_INNERSHADOW_GRADIENT);
                G2.fill(POST_INNERSHADOW);
                break;
            
            case BIG_KNOB:
                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;
        }
        G2.dispose();
        
        return IMAGE;
    }
    
    /**
     * 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(10, 10, 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(10, 10, 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(), customPointerColor);
        }
    }

    /**
     * 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)
    {
        switch (getFrameType())
        {
            case ROUND:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH, WITH_CENTER_KNOB, TYPE);
            case SQUARE:
                return FOREGROUND_FACTORY.createLinearForeground(WIDTH, WIDTH, WITH_CENTER_KNOB);
            default:
                return FOREGROUND_FACTORY.createRadialForeground(WIDTH, WITH_CENTER_KNOB);
        } 
    }
    
    /**
     * 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);
        repaint();
    }
    
    @Override
    public void setSize(final int WIDTH, final int HEIGHT)
    {
        super.setSize(WIDTH, WIDTH);
        calcInnerBounds();
        init(WIDTH, WIDTH);        
        setInitialized(true);
        repaint();
    }
    
    @Override
    public void setSize(final java.awt.Dimension DIM)
    {
        super.setPreferredSize(DIM);
        calcInnerBounds();
        init(DIM.width, DIM.width);        
        setInitialized(true);
        repaint();
    }
    // 

    // 
    @Override
    public void componentResized(final java.awt.event.ComponentEvent EVENT)
    {        
        final int SIZE = this.getWidth() <= this.getHeight() ? this.getWidth() : this.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());
        }

        recreateAllImages();

        init(getInnerBounds().width, getInnerBounds().height);
        revalidate();
        repaint();
    }
    // 
    
    @Override
    public String toString()
    {        
        return "AbstractRadial";
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy