lighttroupe/luz

View on GitHub
utils/color.rb

Summary

Maintainability
B
4 hrs
Test Coverage
class Color
    DEFAULT_COLOR = [1.0,1.0,1.0,1.0]        # NOTE: look at the places that use Color.new before thinking about changing this ;)

    def initialize(color = DEFAULT_COLOR)
        set(color)
    end

    attr_accessor :red, :green, :blue, :alpha
    def alpha
        @alpha || 1.0
    end

    def self.new_from_rgba_bytes(rgba)
        c = Color.new
        c.red, c.green, c.blue, c.alpha = *rgba.collect { |component| component / 255.0 }
        c
    end

    def set(color)
        if color.is_a?(Array)
            @red, @green, @blue, @alpha = color[0].clamp(0.0, 1.0), color[1].clamp(0.0, 1.0), color[2].clamp(0.0, 1.0), (color[3] || 1.0).clamp(0.0, 1.0)
        elsif color.is_a?(Color)
            @red, @green, @blue, @alpha = color.red, color.green, color.blue, color.alpha
        end
        self
    end

    def multiply(amt)
        @red = (red * amt).clamp(0.0, 1.0)
        @green = (green * amt).clamp(0.0, 1.0)
        @blue = (blue * amt).clamp(0.0, 1.0)
        @alpha = (alpha * amt).clamp(0.0, 1.0)
        self
    end

    def fade_to(amount, color)
        Color.new([amount.scale(red, color.red), amount.scale(green, color.green), amount.scale(blue, color.blue), amount.scale(alpha, color.alpha)])
    end

    def gdk_color
        return Gdk::Color.new(red * 65535, green * 65535, blue * 65535)
    end

    def gdk_alpha
        alpha * 65535
    end

    def to_a
        [red, green, blue, alpha]
    end
    alias :gl_color :to_a
    alias :cairo_color :to_a

    def gl_color=(rhs)
        @red, @green, @blue, @alpha = *rhs
    end

    def set_gl_color(rhs)
        @red, @green, @blue, @alpha = *rhs
        self
    end

    def gl_color_with_full_alpha
        return [red, green, blue, 1.0]
    end
    alias :cairo_color_with_full_alpha :gl_color_with_full_alpha

    def gl_color_without_alpha
        return [red, green, blue]
    end
    alias :cairo_color_without_alpha :gl_color_without_alpha

    def alpha_multiply(amount)
        return Color.new([red, green, blue, alpha * amount])
    end

    def with_alpha(amount)
        return Color.new([red, green, blue, amount])
    end

    def to_s
        sprintf("#%02x%02x%02x%02x", red * 255, blue * 255, green * 255, alpha * 255)
    end

    def from_s(str)
        if str =~ /\#[0-9a-f]{8}/
            red, green, blue, alpha = $1, $2, $3, $4
        end
        self
    end

    # Returns the HSL colour encoding of the RGB value.
    def to_hsl
        min   = [@red, @green, @blue].min
        max   = [@red, @green, @blue].max
        delta = (max - min).to_f
        lum   = (max + min) / 2.0

        if delta <= 1e-5  # close to 0.0, so it's a grey
            hue = 0
            sat = 0
        else
            if (lum - 0.5) <= 1e-5
                sat = delta / (max + min).to_f
            else
                sat = delta / (2 - max - min).to_f
            end

            if @red == max
                hue = (@green - @blue) / delta.to_f
            elsif @green == max
                hue = (2.0 + @blue - @red) / delta.to_f
            elsif (@blue - max) <= 1e-5
                hue = (4.0 + @red - @green) / delta.to_f
            end
            hue /= 6.0

            hue += 1 if hue < 0
            hue -= 1 if hue > 1
        end

        return [hue, sat, lum]
    end

    def from_hsl(hue, sat, lum, ignored = nil)
        return set([0.0,0.0,0.0]) if lum == 0.0                # if luminosity is zero, the colour is always black
        return set([1.0,1.0,1.0]) if lum == 1.0                # if luminosity is one, the colour is always white
        return set([lum, lum, lum]) if sat <= 1e-5        # if saturation is zero, the colour is always a greyscale colour

        if (lum - 0.5) < 1e-5
            tmp2 = lum * (1.0 + sat.to_f)
        else
            tmp2 = lum + sat - (lum * sat.to_f)
        end
        tmp1 = 2.0 * lum - tmp2

        t3 = [ hue + 1.0 / 3.0, hue, hue - 1.0 / 3.0 ]
        t3 = t3.map { |tmp3|
            tmp3 += 1.0 if tmp3 < 1e-5
            tmp3 -= 1.0 if (tmp3 - 1.0) > 1e-5
            tmp3
        }

        rgb = t3.map do |tmp3|
            if ((6.0 * tmp3) - 1.0) < 1e-5
                tmp1 + ((tmp2 - tmp1) * tmp3 * 6.0)
            elsif ((2.0 * tmp3) - 1.0) < 1e-5
                tmp2
            elsif ((3.0 * tmp3) - 2.0) < 1e-5
                tmp1 + (tmp2 - tmp1) * ((2 / 3.0) - tmp3) * 6.0
            else
                tmp1
            end
        end

        set(rgb)
    end
end