1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-02-09 10:10:04 +08:00

feat(cpicker): add hwb color-mix

This commit is contained in:
Eric Wong 2024-07-18 18:31:54 +08:00
parent 85f97eedb2
commit b0f1e65b35
2 changed files with 393 additions and 387 deletions

View File

@ -1,365 +1,379 @@
local M = {} local M = {}
local color_mix_buf local color_mix_buf
local color_mix_win local color_mix_win
local color_mix_color1 local color_mix_color1
local color_mix_color2 local color_mix_color2
local color_mix_color3 local color_mix_color3
local color_mix_p1 = 0.5 local color_mix_p1 = 0.5
local color_mix_p2 = 0.5 local color_mix_p2 = 0.5
local available_methods = { 'srgb', 'hsl' } -- https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method
local available_hue_methods = { 'shorter', 'longer', 'increasing', 'decreasing' } local available_methods = { 'srgb', 'hsl', 'hwb' }
local method = 'srgb' local available_hue_methods = { 'shorter', 'longer', 'increasing', 'decreasing' }
local hue_interpolation_method = 'shorter' local method = 'srgb'
local hi = require('spacevim.api.vim.highlight') local hue_interpolation_method = 'shorter'
local notify = require('spacevim.api.notify') local hi = require('spacevim.api.vim.highlight')
local util = require('cpicker.util') local notify = require('spacevim.api.notify')
local color = require('spacevim.api.color') local util = require('cpicker.util')
local color = require('spacevim.api.color')
local function get_mix_method()
if method == 'hsl' then local function get_mix_method()
return 'hsl ' .. hue_interpolation_method if method == 'hsl' then
else return 'hsl ' .. hue_interpolation_method
return method else
end return method
end end
end
local function get_method()
local rst = '' local function get_method()
for _, m in ipairs(available_methods) do local rst = ''
if m == method then for _, m in ipairs(available_methods) do
rst = rst .. '<' .. m .. '>' if m == method then
else rst = rst .. '<' .. m .. '>'
rst = rst .. ' ' .. m .. ' ' else
end rst = rst .. ' ' .. m .. ' '
end end
return rst end
end return rst
end
local function get_hue_method()
local rst = '' local function get_hue_method()
for _, m in ipairs(available_hue_methods) do local rst = ''
if m == hue_interpolation_method then for _, m in ipairs(available_hue_methods) do
rst = rst .. '<' .. m .. '>' if m == hue_interpolation_method then
else rst = rst .. '<' .. m .. '>'
rst = rst .. ' ' .. m .. ' ' else
end rst = rst .. ' ' .. m .. ' '
end end
return rst end
end return rst
end
local function update_color_mix_buftext()
local r3, g3, b3 local function update_color_mix_buftext()
if method == 'srgb' then local r3, g3, b3
local r1, g1, b1 = color.hex2rgb(color_mix_color1) if method == 'srgb' then
local r2, g2, b2 = color.hex2rgb(color_mix_color2) local r1, g1, b1 = color.hex2rgb(color_mix_color1)
local p1, p2 local r2, g2, b2 = color.hex2rgb(color_mix_color2)
if color_mix_p1 == 0 and color_mix_p2 == 0 then local p1, p2
p1 = 0.5 if color_mix_p1 == 0 and color_mix_p2 == 0 then
p2 = 0.5 p1 = 0.5
else p2 = 0.5
p1 = color_mix_p1 / (color_mix_p1 + color_mix_p2) else
p2 = color_mix_p2 / (color_mix_p1 + color_mix_p2) p1 = color_mix_p1 / (color_mix_p1 + color_mix_p2)
end p2 = color_mix_p2 / (color_mix_p1 + color_mix_p2)
r3, g3, b3 = r1 * p1 + r2 * p2, g1 * p1 + g2 * p2, b1 * p1 + b2 * p2 end
elseif method == 'hsl' then r3, g3, b3 = r1 * p1 + r2 * p2, g1 * p1 + g2 * p2, b1 * p1 + b2 * p2
local h1, s1, l1 = color.rgb2hsl(color.hex2rgb(color_mix_color1)) elseif method == 'hsl' or method == 'hwb' then
local h2, s2, l2 = color.rgb2hsl(color.hex2rgb(color_mix_color2)) local h1, s1, l1, w1, b1
local h3 local h2, s2, l2, w2, b2
local p1, p2 if method == 'hsl' then
if color_mix_p1 == 0 and color_mix_p2 == 0 then h1, s1, l1 = color.rgb2hsl(color.hex2rgb(color_mix_color1))
p1 = 0.5 h2, s2, l2 = color.rgb2hsl(color.hex2rgb(color_mix_color2))
p2 = 0.5 elseif method == 'hwb' then
else h1, w1, b1 = color.rgb2hwb(color.hex2rgb(color_mix_color1))
p1 = color_mix_p1 / (color_mix_p1 + color_mix_p2) h2, w2, b2 = color.rgb2hwb(color.hex2rgb(color_mix_color2))
p2 = color_mix_p2 / (color_mix_p1 + color_mix_p2) end
end local h3
if hue_interpolation_method == 'shorter' then local p1, p2
if h2 >= h1 then if color_mix_p1 == 0 and color_mix_p2 == 0 then
if h2 - h1 <= 180 then p1 = 0.5
h3 = h1 * p1 + h2 * p2 p2 = 0.5
else else
h3 = (h1 + 360) * p1 + h2 * p2 p1 = color_mix_p1 / (color_mix_p1 + color_mix_p2)
end p2 = color_mix_p2 / (color_mix_p1 + color_mix_p2)
else end
if h1 - h2 <= 180 then if hue_interpolation_method == 'shorter' then
h3 = h1 * p1 + h2 * p2 if h2 >= h1 then
else if h2 - h1 <= 180 then
h3 = h1 * p1 + (h2 + 360) * p2 h3 = h1 * p1 + h2 * p2
end else
end h3 = (h1 + 360) * p1 + h2 * p2
elseif hue_interpolation_method == 'longer' then end
if h2 >= h1 then else
if h2 - h1 >= 180 then if h1 - h2 <= 180 then
h3 = h1 * p1 + h2 * p2 h3 = h1 * p1 + h2 * p2
else else
h3 = (h1 + 360) * p1 + h2 * p2 h3 = h1 * p1 + (h2 + 360) * p2
end end
else end
if h1 - h2 >= 180 then elseif hue_interpolation_method == 'longer' then
h3 = h1 * p1 + h2 * p2 if h2 >= h1 then
else if h2 - h1 >= 180 then
h3 = h1 * p1 + (h2 + 360) * p2 h3 = h1 * p1 + h2 * p2
end else
end h3 = (h1 + 360) * p1 + h2 * p2
elseif hue_interpolation_method == 'increasing' then end
if h1 <= h2 then else
h3 = h1 * p1 + h2 * p2 if h1 - h2 >= 180 then
else h3 = h1 * p1 + h2 * p2
h3 = h1 * p1 + (h2 + 360) * p2 else
end h3 = h1 * p1 + (h2 + 360) * p2
elseif hue_interpolation_method == 'decreasing' then end
if h1 >= h2 then end
h3 = h1 * p1 + h2 * p2 elseif hue_interpolation_method == 'increasing' then
else if h1 <= h2 then
h3 = (h1 + 360) * p1 + h2 * p2 h3 = h1 * p1 + h2 * p2
end else
end h3 = h1 * p1 + (h2 + 360) * p2
if h3 >= 360 then end
h3 = h3 - 360 elseif hue_interpolation_method == 'decreasing' then
end if h1 >= h2 then
r3, g3, b3 = color.hsl2rgb(h3, s1 * p1 + s2 * p2, l1 * p1 + l2 * p2) h3 = h1 * p1 + h2 * p2
end else
color_mix_color3 = color.rgb2hex(r3, g3, b3) h3 = (h1 + 360) * p1 + h2 * p2
local normal_bg = hi.group2dict('Normal').guibg end
local normal_fg = hi.group2dict('Normal').guifg end
if if h3 >= 360 then
math.abs(util.get_hsl_l(normal_bg) - util.get_hsl_l(color_mix_color3)) h3 = h3 - 360
> math.abs(util.get_hsl_l(color_mix_color3) - util.get_hsl_l(normal_fg)) end
then if method == 'hsl' then
hi.hi({ r3, g3, b3 = color.hsl2rgb(h3, s1 * p1 + s2 * p2, l1 * p1 + l2 * p2)
name = 'SpaceVimPickerMixColor3Code', elseif method == 'hwb' then
guifg = color_mix_color3, r3, g3, b3 = color.hwb2rgb(h3, w1 * p1 + w2 * p2, b1 * p1 + b2 * p2)
guibg = normal_bg, end
bold = 1, end
}) -- 验证结果 https://products.aspose.app/svg/zh/color-mixer
else color_mix_color3 = color.rgb2hex(r3, g3, b3)
hi.hi({ local normal_bg = hi.group2dict('Normal').guibg
name = 'SpaceVimPickerMixColor3Code', local normal_fg = hi.group2dict('Normal').guifg
guifg = color_mix_color3, if
guibg = normal_fg, math.abs(util.get_hsl_l(normal_bg) - util.get_hsl_l(color_mix_color3))
bold = 1, > math.abs(util.get_hsl_l(color_mix_color3) - util.get_hsl_l(normal_fg))
}) then
end hi.hi({
hi.hi({ name = 'SpaceVimPickerMixColor3Code',
name = 'SpaceVimPickerMixColor3Background', guifg = color_mix_color3,
guibg = color_mix_color3, guibg = normal_bg,
guifg = color_mix_color3, bold = 1,
}) })
local rst = {} else
table.insert( hi.hi({
rst, name = 'SpaceVimPickerMixColor3Code',
' ' guifg = color_mix_color3,
.. color_mix_color1 guibg = normal_fg,
.. ' ' bold = 1,
.. 'P1:' })
.. string.format(' %3s%%', math.floor(color_mix_p1 * 100 + 0.5)) end
.. ' ' hi.hi({
.. util.generate_bar(color_mix_p1, '+') name = 'SpaceVimPickerMixColor3Background',
) guibg = color_mix_color3,
table.insert( guifg = color_mix_color3,
rst, })
' ' local rst = {}
.. color_mix_color2 table.insert(
.. ' ' rst,
.. 'P2:' ' '
.. string.format(' %3s%%', math.floor(color_mix_p2 * 100 + 0.5)) .. color_mix_color1
.. ' ' .. ' '
.. util.generate_bar(color_mix_p2, '+') .. 'P1:'
) .. string.format(' %3s%%', math.floor(color_mix_p1 * 100 + 0.5))
table.insert(rst, ' method:' .. get_method()) .. ' '
table.insert(rst, ' hue:' .. get_hue_method()) .. util.generate_bar(color_mix_p1, '+')
table.insert(rst, ' ') )
table.insert( table.insert(
rst, rst,
' ======= ' .. color_mix_color3 .. ' ' ' '
) .. color_mix_color2
table.insert( .. ' '
rst, .. 'P2:'
' ======= ' .. string.format(' %3s%%', math.floor(color_mix_p2 * 100 + 0.5))
.. string.format( .. ' '
'color-mix(in %s, %s %3s%%, %3s %3s%%) ', .. util.generate_bar(color_mix_p2, '+')
get_mix_method(), )
color_mix_color1, table.insert(rst, ' method:' .. get_method())
math.floor(color_mix_p1 * 100 + 0.5), table.insert(rst, ' hue:' .. get_hue_method())
color_mix_color2, table.insert(rst, ' ')
math.floor(color_mix_p2 * 100 + 0.5) table.insert(
) rst,
) ' ======= '
vim.api.nvim_set_option_value('modifiable', true, { .. color_mix_color3
buf = color_mix_buf, .. ' '
}) )
vim.api.nvim_buf_set_lines(color_mix_buf, 0, -1, false, rst) table.insert(
vim.api.nvim_set_option_value('modifiable', false, { rst,
buf = color_mix_buf, ' ======= '
}) .. string.format(
end 'color-mix(in %s, %s %3s%%, %3s %3s%%) ',
get_mix_method(),
local function increase_p_f(p) color_mix_color1,
if p <= 0.99 then math.floor(color_mix_p1 * 100 + 0.5),
p = p + 0.01 color_mix_color2,
elseif p < 1 then math.floor(color_mix_p2 * 100 + 0.5)
p = 1 )
end )
return p vim.api.nvim_set_option_value('modifiable', true, {
end buf = color_mix_buf,
})
local function reduce_p_f(p) vim.api.nvim_buf_set_lines(color_mix_buf, 0, -1, false, rst)
if p >= 0.01 then vim.api.nvim_set_option_value('modifiable', false, {
p = p - 0.01 buf = color_mix_buf,
elseif p > 0 then })
p = 0 end
end
return p local function increase_p_f(p)
end if p <= 0.99 then
p = p + 0.01
local function next_hue_method() elseif p < 1 then
for i, v in ipairs(available_hue_methods) do p = 1
if v == hue_interpolation_method then end
if i == #available_hue_methods then return p
return available_hue_methods[1] end
else
return available_hue_methods[i + 1] local function reduce_p_f(p)
end if p >= 0.01 then
end p = p - 0.01
end elseif p > 0 then
end p = 0
end
local function previous_hue_method() return p
for i, v in ipairs(available_hue_methods) do end
if v == hue_interpolation_method then
if i == 1 then local function next_hue_method()
return available_hue_methods[#available_hue_methods] for i, v in ipairs(available_hue_methods) do
else if v == hue_interpolation_method then
return available_hue_methods[i - 1] if i == #available_hue_methods then
end return available_hue_methods[1]
end else
end return available_hue_methods[i + 1]
end end
end
local function next_mix_method() end
for i, v in ipairs(available_methods) do end
if v == method then
if i == #available_methods then local function previous_hue_method()
return available_methods[1] for i, v in ipairs(available_hue_methods) do
else if v == hue_interpolation_method then
return available_methods[i + 1] if i == 1 then
end return available_hue_methods[#available_hue_methods]
end else
end return available_hue_methods[i - 1]
end end
end
local function previous_mix_method() end
for i, v in ipairs(available_methods) do end
if v == method then
if i == 1 then local function next_mix_method()
return available_methods[#available_methods] for i, v in ipairs(available_methods) do
else if v == method then
return available_methods[i - 1] if i == #available_methods then
end return available_methods[1]
end else
end return available_methods[i + 1]
end end
end
local function increase_p() end
if vim.fn.line('.') == 1 then end
color_mix_p1 = increase_p_f(color_mix_p1)
elseif vim.fn.line('.') == 2 then local function previous_mix_method()
color_mix_p2 = increase_p_f(color_mix_p2) for i, v in ipairs(available_methods) do
elseif vim.fn.line('.') == 3 then if v == method then
method = next_mix_method() if i == 1 then
elseif vim.fn.line('.') == 4 then return available_methods[#available_methods]
hue_interpolation_method = next_hue_method() else
end return available_methods[i - 1]
update_color_mix_buftext() end
end end
end
local function reduce_p() end
if vim.fn.line('.') == 1 then
color_mix_p1 = reduce_p_f(color_mix_p1) local function increase_p()
elseif vim.fn.line('.') == 2 then if vim.fn.line('.') == 1 then
color_mix_p2 = reduce_p_f(color_mix_p2) color_mix_p1 = increase_p_f(color_mix_p1)
elseif vim.fn.line('.') == 3 then elseif vim.fn.line('.') == 2 then
method = previous_mix_method() color_mix_p2 = increase_p_f(color_mix_p2)
elseif vim.fn.line('.') == 4 then elseif vim.fn.line('.') == 3 then
hue_interpolation_method = previous_hue_method() method = next_mix_method()
end elseif vim.fn.line('.') == 4 then
update_color_mix_buftext() hue_interpolation_method = next_hue_method()
end end
update_color_mix_buftext()
local function copy_color_mix() end
local from, to = vim
.regex([[#[0123456789ABCDEF]\+\|color-mix([^)]*)]]) local function reduce_p()
:match_str(vim.fn.getline('.')) if vim.fn.line('.') == 1 then
if from then color_mix_p1 = reduce_p_f(color_mix_p1)
vim.fn.setreg('+', string.sub(vim.fn.getline('.'), from, to + 1)) elseif vim.fn.line('.') == 2 then
notify.notify('copied:' .. string.sub(vim.fn.getline('.'), from, to + 1)) color_mix_p2 = reduce_p_f(color_mix_p2)
end elseif vim.fn.line('.') == 3 then
end method = previous_mix_method()
elseif vim.fn.line('.') == 4 then
M.color_mix = function(hex1, hex2) hue_interpolation_method = previous_hue_method()
color_mix_color1 = hex1 or '#000000' end
color_mix_color2 = hex2 or '#FFFFFF' update_color_mix_buftext()
hi.hi({ end
name = 'SpaceVimPickerMixColor1',
guifg = color_mix_color1, local function copy_color_mix()
bold = 1, local from, to =
}) vim.regex([[#[0123456789ABCDEF]\+\|color-mix([^)]*)]]):match_str(vim.fn.getline('.'))
hi.hi({ if from then
name = 'SpaceVimPickerMixColor2', vim.fn.setreg('+', string.sub(vim.fn.getline('.'), from, to + 1))
guifg = color_mix_color2, notify.notify('copied:' .. string.sub(vim.fn.getline('.'), from, to + 1))
bold = 1, end
}) end
if not color_mix_buf or not vim.api.nvim_win_is_valid(color_mix_buf) then
color_mix_buf = vim.api.nvim_create_buf(false, false) M.color_mix = function(hex1, hex2)
vim.api.nvim_set_option_value('buftype', 'nofile', { color_mix_color1 = hex1 or '#000000'
buf = color_mix_buf, color_mix_color2 = hex2 or '#FFFFFF'
}) hi.hi({
vim.api.nvim_set_option_value('filetype', 'spacevim_cpicker_mix', { name = 'SpaceVimPickerMixColor1',
buf = color_mix_buf, guifg = color_mix_color1,
}) bold = 1,
vim.api.nvim_set_option_value('bufhidden', 'wipe', { })
buf = color_mix_buf, hi.hi({
}) name = 'SpaceVimPickerMixColor2',
vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', 'l', '', { guifg = color_mix_color2,
callback = increase_p, bold = 1,
}) })
vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', 'h', '', { if not color_mix_buf or not vim.api.nvim_win_is_valid(color_mix_buf) then
callback = reduce_p, color_mix_buf = vim.api.nvim_create_buf(false, false)
}) vim.api.nvim_set_option_value('buftype', 'nofile', {
vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', '<Right>', '', { buf = color_mix_buf,
callback = increase_p, })
}) vim.api.nvim_set_option_value('filetype', 'spacevim_cpicker_mix', {
vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', '<Left>', '', { buf = color_mix_buf,
callback = reduce_p, })
}) vim.api.nvim_set_option_value('bufhidden', 'wipe', {
vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', 'q', '', { buf = color_mix_buf,
callback = function() })
vim.api.nvim_win_close(color_mix_win, true) vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', 'l', '', {
end, callback = increase_p,
}) })
vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', '<Cr>', '', { vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', 'h', '', {
callback = copy_color_mix, callback = reduce_p,
}) })
end vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', '<Right>', '', {
if not color_mix_win or not vim.api.nvim_win_is_valid(color_mix_win) then callback = increase_p,
color_mix_win = vim.api.nvim_open_win(color_mix_buf, true, { })
relative = 'cursor', vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', '<Left>', '', {
border = 'single', callback = reduce_p,
width = 75, })
height = 7, vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', 'q', '', {
row = 1, callback = function()
col = 1, vim.api.nvim_win_close(color_mix_win, true)
}) end,
end })
vim.api.nvim_set_option_value('number', false, { vim.api.nvim_buf_set_keymap(color_mix_buf, 'n', '<Cr>', '', {
win = color_mix_win, callback = copy_color_mix,
}) })
vim.api.nvim_set_option_value('winhighlight', 'NormalFloat:Normal,FloatBorder:WinSeparator', { end
win = color_mix_win, if not color_mix_win or not vim.api.nvim_win_is_valid(color_mix_win) then
}) color_mix_win = vim.api.nvim_open_win(color_mix_buf, true, {
vim.api.nvim_set_option_value('modifiable', false, { relative = 'cursor',
buf = color_mix_buf, border = 'single',
}) width = 75,
update_color_mix_buftext() height = 7,
end row = 1,
return M col = 1,
})
end
vim.api.nvim_set_option_value('number', false, {
win = color_mix_win,
})
vim.api.nvim_set_option_value('winhighlight', 'NormalFloat:Normal,FloatBorder:WinSeparator', {
win = color_mix_win,
})
vim.api.nvim_set_option_value('modifiable', false, {
buf = color_mix_buf,
})
update_color_mix_buftext()
end
return M

View File

@ -176,29 +176,21 @@ end
color.hwb2rgb = function(h, w, b) color.hwb2rgb = function(h, w, b)
if w + b >= 1 then if w + b >= 1 then
local gray = w / (w + b) local grey = w / (w + b)
return gray, gray, gray return grey, grey, grey
end end
local r, g, b = color.hsl2rgb(h, 1, 0.5) local R, G, B = color.hsl2rgb(h, 1, 0.5)
r = r * (1 - w - b) + w local function f(c)
if r > 1 then c = c * (1 - w - b) + w
r = 1 if c > 1 then
elseif r < 0 then return 1
r = 0 elseif c <= 0 then
return 0
else
return c
end
end end
g = g * (1 - w - b) + w return f(R), f(G), f(B)
if g > 1 then
g = 1
elseif g < 0 then
g = 0
end
b = b * (1 - w - b) + w
if b > 1 then
b = 1
elseif b < 0 then
b = 0
end
return r, g, b
end end
color.rgb2hwb = function(r, g, b) color.rgb2hwb = function(r, g, b)
@ -221,7 +213,7 @@ color.cmyk2hwb = function(c, m, y, k)
end end
color.hwb2hsl = function(h, w, b) color.hwb2hsl = function(h, w, b)
return color.rgb2hwb(color.hwb2rgb(h, w, b)) return color.rgb2hsl(color.hwb2rgb(h, w, b))
end end
color.hwb2hsv = function(h, w, b) color.hwb2hsv = function(h, w, b)