Class: Kungfuig::Color

Inherits:
Object
  • Object
show all
Defined in:
lib/kungfuig/color.rb

Overview

rubocop:disable Metrics/ClassLength Dealing with colors

Constant Summary collapse

HEXVAL =

Table for conversion to hex

('0'..'9').to_a.concat(('A'..'F').to_a).freeze
BRIGHTNESS_DEFAULT =

Default value for #darken, #lighten etc.

0.2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Color

Constructor. Inits to white (#FFFFFF) by default, or accepts any params supported by #parse.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/kungfuig/color.rb', line 37

def initialize(*args)
  @r = 255
  @g = 255
  @b = 255
  @a = 255

  if args.size.between?(3, 4)
    self.r = args[0]
    self.g = args[1]
    self.b = args[2]
    self.a = args[3] if args[3]
  else
    set(*args)
  end
end

Instance Attribute Details

#aObject (readonly)

Implements a color (r,g,b + a) with conversion to/from web format (eg #aabbcc), and with a number of utilities to lighten, darken and blend values.



28
29
30
# File 'lib/kungfuig/color.rb', line 28

def a
  @a
end

#bObject (readonly)

Implements a color (r,g,b + a) with conversion to/from web format (eg #aabbcc), and with a number of utilities to lighten, darken and blend values.



28
29
30
# File 'lib/kungfuig/color.rb', line 28

def b
  @b
end

#gObject (readonly)

Implements a color (r,g,b + a) with conversion to/from web format (eg #aabbcc), and with a number of utilities to lighten, darken and blend values.



28
29
30
# File 'lib/kungfuig/color.rb', line 28

def g
  @g
end

#rObject (readonly)

Implements a color (r,g,b + a) with conversion to/from web format (eg #aabbcc), and with a number of utilities to lighten, darken and blend values.



28
29
30
# File 'lib/kungfuig/color.rb', line 28

def r
  @r
end

Class Method Details

.blend(col1, col2, amt) ⇒ Object

Class-level version for explicit blends of two values, useful with constants



228
229
230
231
# File 'lib/kungfuig/color.rb', line 228

def self.blend(col1, col2, amt)
  col1, col2 = [col1, col2].map { |c| Color.parse c }
  col1.blend(col2, amt)
end

.parse(*args) ⇒ Object

rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/MethodLength Attempt to read in a string and parse it into values



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/kungfuig/color.rb', line 82

def self.parse(*args)
  case args.size
  when 0 then return nil
  when 1
    case val = args.first
    when Color then val
    when Fixnum then Color.new(val, val, val) # Single value, assume grayscale
    when String
      str = val.to_s.upcase[/[0-9A-F]{3,8}/] || ''
      Color.new(*case str.length
                 when 3, 4 then str.scan(/[0-9A-F]/)
                 when 6, 8 then str.scan(/[0-9A-F]{2}/)
                 else 'FF'
                 end.map { |c| Integer("0x#{c}") })
    end
  when 2 # assume gray + alpha
    val, alpha = args
    Color.new(val, val, val, alpha)
  when 3, 4 then Color.new(*args)
  end
end

.preset(type) ⇒ Object

rubocop:disable Metrics/CyclomaticComplexity



245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/kungfuig/color.rb', line 245

def self.preset type
  Color.parse case type
              when :label then '#999999'
              when :success then '#468847'
              when :warning then '#F89406'
              when :important then '#B94A48'
              when :fatal then '#B94A48'
              when :error then '#FF0000'
              when :info then '#3A87AD'
              when :inverse then '#333333'
              else type
              end
end

.to_xterm256(text, color, bold: true, italic: false, underline: false, reverse: false, foreground: true) ⇒ Object

rubocop:disable Metrics/ParameterLists



234
235
236
237
238
239
240
241
# File 'lib/kungfuig/color.rb', line 234

def self.to_xterm256(text, color, bold: true, italic: false, underline: false, reverse: false, foreground: true)
  color = Color.preset(color) unless color.is_a?(Color)
  [
    color.to_esc(true, bold: bold, italic: italic, underline: underline, reverse: reverse, foreground: foreground),
    text,
    "\e[0m"
  ].join
end

Instance Method Details

#==(other) ⇒ Object

Test for equality, accepts string vals as well, eg Color.new(‘aaa’) == ‘#AAAAAA’ => true



66
67
68
69
70
# File 'lib/kungfuig/color.rb', line 66

def ==(other)
  val = Color.parse(other)
  return false if val.nil?
  r == val.r && g == val.g && b == val.b && a == val.a
end

#blend(other, amt) ⇒ Object

rubocop:disable Metrics/AbcSize Blend to a color amt % towards another color value, eg red.blend(blue, 0.5) will be purple, white.blend(black, 0.5) will be gray, etc.



209
210
211
212
213
214
215
216
217
218
# File 'lib/kungfuig/color.rb', line 209

def blend(other, amt)
  other = Color.parse(other)
  return Color.new(self) if amt <= 0 || other.nil?
  return Color.new(other) if amt >= 1.0
  Color.new(self).tap do |val|
    val.r += ((other.r - val.r) * amt).to_i
    val.g += ((other.g - val.g) * amt).to_i
    val.b += ((other.b - val.b) * amt).to_i
  end
end

#blend!(other, amt) ⇒ Object

In place version of #blend



222
223
224
225
# File 'lib/kungfuig/color.rb', line 222

def blend!(other, amt)
  set(blend(other, amt))
  self
end

#darken(amt = BRIGHTNESS_DEFAULT) ⇒ Object

Darken a color towards full black. 0.0 is a no-op, 1.0 will return #000000



179
180
181
182
183
184
185
186
187
# File 'lib/kungfuig/color.rb', line 179

def darken(amt = BRIGHTNESS_DEFAULT)
  return self if amt <= 0
  return BLACK if amt >= 1.0
  Color.new(self).tap do |val|
    val.r -= (val.r * amt).to_i
    val.g -= (val.g * amt).to_i
    val.b -= (val.b * amt).to_i
  end
end

#darken!(amt = BRIGHTNESS_DEFAULT) ⇒ Object

In place version of #darken



190
191
192
# File 'lib/kungfuig/color.rb', line 190

def darken!(amt = BRIGHTNESS_DEFAULT)
  set(darken(amt))
end

#grayscaleObject

Convert to grayscale, using perception-based weighting



195
196
197
198
199
# File 'lib/kungfuig/color.rb', line 195

def grayscale
  Color.new(self).tap do |val|
    val.r = val.g = val.b = (0.2126 * val.r + 0.7152 * val.g + 0.0722 * val.b)
  end
end

#grayscale!Object

In place version of #grayscale



202
203
204
# File 'lib/kungfuig/color.rb', line 202

def grayscale!
  set(grayscale)
end

#grayscale?Boolean

Returns:

  • (Boolean)


158
159
160
# File 'lib/kungfuig/color.rb', line 158

def grayscale?
  @r == @g && @g == @b
end

#inspectObject

rubocop:enable Metrics/MethodLength rubocop:enable Metrics/CyclomaticComplexity



106
107
108
109
# File 'lib/kungfuig/color.rb', line 106

def inspect
  id = format('%x', object_id << 1)
  "#<#{self.class.name}:0x#{id.rjust(14, '0')} 💻=“\\e[#{to_esc(true)}#{to_esc(false)}\e[0mm” 🗔=“#{self}”>"
end

#lighten(amt = BRIGHTNESS_DEFAULT) ⇒ Object

Lighten color towards white. 0.0 is a no-op, 1.0 will return #FFFFFF



163
164
165
166
167
168
169
170
171
# File 'lib/kungfuig/color.rb', line 163

def lighten(amt = BRIGHTNESS_DEFAULT)
  return self if amt <= 0
  return WHITE if amt >= 1.0
  Color.new(self).tap do |val|
    val.r += ((255 - val.r) * amt).to_i
    val.g += ((255 - val.g) * amt).to_i
    val.b += ((255 - val.b) * amt).to_i
  end
end

#lighten!(amt = BRIGHTNESS_DEFAULT) ⇒ Object

In place version of #lighten



174
175
176
# File 'lib/kungfuig/color.rb', line 174

def lighten!(amt = BRIGHTNESS_DEFAULT)
  set(lighten(amt))
end

#opaque?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/kungfuig/color.rb', line 150

def opaque?
  @a == 255
end

#set(*args) ⇒ Object

All-purpose setter - pass in another Color, ‘#000000’, rgb vals… whatever



54
55
56
57
58
59
60
61
62
63
# File 'lib/kungfuig/color.rb', line 54

def set(*args)
  val = Color.parse(*args)
  unless val.nil?
    self.r = val.r
    self.g = val.g
    self.b = val.b
    self.a = val.a
  end
  self
end

#to_esc(surround = true, bold: true, italic: false, underline: false, reverse: false, foreground: true) ⇒ Object

rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/PerceivedComplexity rubocop:disable Metrics/ParameterLists Color as used in 256-color terminal escape sequences



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/kungfuig/color.rb', line 119

def to_esc(surround = true, bold: true, italic: false, underline: false, reverse: false, foreground: true)
  result = if grayscale?
             (r > 239) ? 15 : (r / 10).floor + 232
           else
             16 + 36 * (r / 51).floor + 6 * (g / 51).floor + (b / 51).floor
           end

  esc = [
    bold ? '01' : nil,
    italic ? '03' : nil,
    underline ? '04' : nil,
    reverse ? '07' : nil,
    foreground ? '38' : '48',
    '05',
    result
  ].compact.join(';')

  surround ? "\e[#{esc}m" : esc
end

#to_rgb(add_hash = true) ⇒ Object

rubocop:enable Metrics/ParameterLists rubocop:enable Metrics/PerceivedComplexity rubocop:enable Metrics/CyclomaticComplexity



142
143
144
# File 'lib/kungfuig/color.rb', line 142

def to_rgb(add_hash = true)
  (add_hash ? '#' : '') + to_hex(r) + to_hex(g) + to_hex(b)
end

#to_rgba(add_hash = true) ⇒ Object



146
147
148
# File 'lib/kungfuig/color.rb', line 146

def to_rgba(add_hash = true)
  to_rgb(add_hash) + to_hex(a)
end

#to_s(add_hash = true) ⇒ Object



111
112
113
# File 'lib/kungfuig/color.rb', line 111

def to_s(add_hash = true)
  trans? ? to_rgba(add_hash) : to_rgb(add_hash)
end

#trans?Boolean

Returns:

  • (Boolean)


154
155
156
# File 'lib/kungfuig/color.rb', line 154

def trans?
  !opaque?
end