mirror of
https://github.com/Mjokfox/color_picker.git
synced 2024-11-21 02:14:01 -05:00
522 lines
17 KiB
Lua
522 lines
17 KiB
Lua
local hexcol_color_picker = {}
|
|
local playermodes = {}
|
|
|
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
|
dofile(modpath.."/converters.lua")
|
|
|
|
local width = tonumber(minetest.settings:get("hexcol_color_picker_map_size")) or 64
|
|
|
|
local mapUpdateTimeout = tonumber(minetest.settings:get("hexcol_color_picker_mapUpdateTimeout")) or 1
|
|
|
|
local height = width
|
|
|
|
local invmode = minetest.settings:get_bool("hexcol_color_picker_invmode") or false
|
|
|
|
local favmode = minetest.settings:get_bool("hexcol_color_picker_favorites") ~= false
|
|
|
|
local dropdown_stuff = {"2,0.3;3,0.7","5.5,0.3;3,0.7"}
|
|
local more_hexcols = {}
|
|
local more_hexcol_amount = 0
|
|
local more_hexcol_dropdown = ""
|
|
|
|
local set_formname
|
|
if invmode then
|
|
set_formname = ""
|
|
-- Disable default creative inventory
|
|
local creative = rawget(_G, "creative") or rawget(_G, "creative_inventory")
|
|
if creative then
|
|
function creative.set_creative_formspec(player, start_i, pagenum)
|
|
return
|
|
end
|
|
end
|
|
-- Disable sfinv inventory
|
|
local sfinv = rawget(_G, "sfinv")
|
|
if sfinv then
|
|
sfinv.enabled = false
|
|
end
|
|
else
|
|
set_formname = "hexcol_color_picker:picker"
|
|
end
|
|
|
|
local left_dropdown = "map,sliders"
|
|
if favmode then
|
|
left_dropdown = left_dropdown .. ",favorites"
|
|
end
|
|
|
|
-- helper function
|
|
local function TableConcat(t1,t2)
|
|
for i=1,#t2 do
|
|
t1[#t1+1] = t2[i]
|
|
end
|
|
return t1
|
|
end
|
|
|
|
-- color sliders
|
|
local function assemble_sliders(player,x,y,w,h)
|
|
-- labels
|
|
local buf = {}
|
|
local user = playermodes[player:get_player_name()]
|
|
if (not user) then return buf end
|
|
local hexcol_id = more_hexcols[tonumber(user.hexcol_selected_index)]
|
|
local dropdown_index = user.dropdown_index
|
|
local bars = user.bars
|
|
local r,g,b
|
|
local labels = {"H","S","V"}
|
|
local units = {"\u{00B0}","%%","%%"}
|
|
local maxs = {360,100,100}
|
|
local steps = {36,10,10}
|
|
|
|
-- set r,g,b and change labels if necessary
|
|
if (dropdown_index == "2") then
|
|
r,g,b = hsv_to_rgb(bars[1]/360,bars[2]/100,bars[3]/100)
|
|
else if (dropdown_index == "3") then
|
|
labels[3] = "L"
|
|
r,g,b = hsl_to_rgb(bars[1]/360,bars[2]/100,bars[3]/100)
|
|
else if (dropdown_index == "4") then
|
|
labels = {"L","C","h"}
|
|
maxs = {100,100,360}
|
|
units = {"%%","%%","\u{00B0}"}
|
|
steps = {10,10,36}
|
|
r,g,b = lch_to_rgb(bars[1]/100,bars[2]/100,bars[3])
|
|
else
|
|
labels = {"R","G","B"}
|
|
units = {"","",""}
|
|
maxs = {15,15,15}
|
|
steps = {1,1,1}
|
|
r,g,b = tonumber(bars[1]),tonumber(bars[2]),tonumber(bars[3])
|
|
end end end
|
|
local hexr,hexg,hexb = toHex(r),toHex(g),toHex(b)
|
|
-- preview color
|
|
local label = "click me!"
|
|
local temp = minetest.formspec_escape(";")
|
|
if (r==4 and g==2 and b==0) then label = "Nice"
|
|
else if (r==6 and g==2 and b==1) then label = temp .."3"
|
|
else if (r==6 and g==6 and b==6) then label = "Feeling devious today.."
|
|
else if (r==7 and g==7 and b==7) then label = "Feeling lucky today.." end end end end
|
|
buf[#buf + 1] = "item_image_button[".. x..",".. y+h ..";"..w..","..5*h..";hexcol:".. hexcol_id .. hexr .. hexg .. hexb ..";hexcol:".. hexcol_id .. hexr .. hexg .. hexb ..";"..label.."]"
|
|
|
|
-- generate the sliders
|
|
y=y+5*h
|
|
for i=1,3 do
|
|
buf[#buf + 1] = "label[".. x-0.4 ..",".. y+(i+0.5)*h ..";".. labels[i] .."]" -- label showing what kind of slider
|
|
buf[#buf + 1] = "scrollbaroptions[min=0;max=".. maxs[i] ..";smallstep=".. steps[i] .."]" -- options
|
|
buf[#buf + 1] = "scrollbar[".. x ..",".. y + i*h ..";".. w ..",".. h ..";horizontal;bar" .. i .. ";" .. bars[i] .. "]" -- slider itself
|
|
|
|
-- slider exact value showing
|
|
buf[#buf + 1] = "scroll_container[".. x + w + 0.3 ..",".. y + i*h + h*0.2 ..";1,0.6;bar" .. i .. ";vertical;1]"
|
|
if (dropdown_index == "1") then
|
|
for n = 0, maxs[i] do
|
|
buf[#buf + 1] = ("label[0,%s;%s".. units[i] .."]"):format(n + h*0.3, toHex(n))
|
|
end
|
|
else
|
|
for n = 0, maxs[i] do
|
|
buf[#buf + 1] = ("label[0,%s;%s".. units[i] .."]"):format(n + h*0.3, n)
|
|
end
|
|
end
|
|
buf[#buf + 1] = "scroll_container_end[]"
|
|
end
|
|
return buf
|
|
end
|
|
|
|
-- color map
|
|
local function assemble_map(player,x_off,y_off)
|
|
local buf = {}
|
|
local user = playermodes[player:get_player_name()]
|
|
if (not user) then return buf end
|
|
local hexcol_id = more_hexcols[tonumber(user.hexcol_selected_index)]
|
|
local dropdown_index = user.dropdown_index
|
|
local saturation = user.saturation
|
|
local size = 12.8/(width + height)
|
|
buf[#buf + 1] = "label[".. x_off + (width*size)/2 - string.len("click any color!")/15 ..",".. y_off + 0.5 ..";click any color!]"
|
|
local label = "saturation"
|
|
if (dropdown_index == "4") then label = "chroma " end
|
|
if (dropdown_index == "1") then label = "red" end
|
|
buf[#buf + 1] = "label[".. x_off + 7.5 - string.len(label)/15 ..",".. y_off + 0.5 ..";".. label .."]"
|
|
y_off=y_off+1
|
|
-- saturation slider
|
|
local max = 10
|
|
local step = 1;
|
|
if (dropdown_index == "1") then max = 15; step = 1 end
|
|
buf[#buf + 1] = "scrollbaroptions[min=0;max=".. max ..";smallstep=".. step ..";thumbsize=1]"
|
|
buf[#buf + 1] = "scrollbar[".. x_off + 7 ..",".. y_off ..";0.5,6.4;vertical;saturation;".. saturation .."]"
|
|
-- full map
|
|
|
|
local size_increase = 1.5
|
|
local y_axis,x_axis = "lightness","hue"
|
|
local hexr,hexg,hexb
|
|
local ohexr,ohexg,ohexb
|
|
local temp_width = 1;
|
|
local old_x = 0;
|
|
local map_optimization = true;
|
|
if (dropdown_index == "1") then
|
|
local temp_size = 0.4
|
|
local r,g,b
|
|
for y = 0,15 do
|
|
for x = 0,15 do
|
|
r,g,b = 15-saturation,y%16,x%16
|
|
hexr,hexg,hexb = toHex(r),toHex(g),toHex(b)
|
|
buf[#buf + 1] = "item_image_button[".. x*temp_size + x_off ..",".. y*temp_size + y_off ..";"..(temp_size*size_increase)..","..(temp_size*size_increase)..";hexcol:".. hexcol_id .. hexr .. hexg .. hexb ..";hexcol:".. hexcol_id .. hexr .. hexg .. hexb ..";]"
|
|
end
|
|
end
|
|
y_axis,x_axis = "green","blue"
|
|
else
|
|
for y = 0,height-1 do
|
|
for x = 0,width-1 do
|
|
-- set r,g,b using the selected mapping method
|
|
local r,g,b = 0,0,0;
|
|
if (dropdown_index == "2") then
|
|
y_axis,x_axis = "value","hue"
|
|
r,g,b = hsv_to_rgb(x / width,1-saturation/10,(height-y) / height)
|
|
else if (dropdown_index == "3") then
|
|
r,g,b = hsl_to_rgb(x / width,1-saturation/10,(height-y) / height)
|
|
else if (dropdown_index == "4") then
|
|
y_axis = "p lightness"
|
|
r,g,b = lch_to_rgb((height-y) / height, 1-saturation/10, 360*(x / width))
|
|
else
|
|
y_axis = "chroma"
|
|
r,g,b = lch_to_rgb(1-saturation/10, (height-y) / height, 360*(x / width))
|
|
end end end
|
|
|
|
hexr,hexg,hexb = toHex(r),toHex(g),toHex(b)
|
|
if (x==0) then
|
|
ohexr,ohexg,ohexb = hexr,hexg,hexb
|
|
end
|
|
|
|
if (map_optimization) then
|
|
if (ohexr == hexr and ohexg == hexg and ohexb == hexb) then
|
|
temp_width = temp_width + 1
|
|
if (temp_width == 2) then old_x = x end
|
|
else
|
|
-- use hexcol mod to display the buttons as their blocks
|
|
if temp_width == 1 then
|
|
old_x = x
|
|
end
|
|
buf[#buf + 1] = "item_image_button[".. old_x*size + x_off ..",".. y*size + y_off ..";"..size*(temp_width-1+size_increase)..","..(size*size_increase)..";hexcol:".. hexcol_id .. ohexr .. ohexg .. ohexb ..";hexcol:".. hexcol_id .. ohexr .. ohexg .. ohexb ..";]"
|
|
temp_width = 1
|
|
old_x = x;
|
|
end
|
|
ohexr,ohexg,ohexb = hexr,hexg,hexb
|
|
else
|
|
buf[#buf + 1] = "item_image_button[".. x*size + x_off ..",".. y*size + y_off ..";"..(size*size_increase)..","..(size*size_increase)..";hexcol:".. hexcol_id .. ohexr .. ohexg .. ohexb ..";hexcol:".. hexcol_id .. ohexr .. ohexg .. ohexb ..";]"
|
|
end
|
|
|
|
end
|
|
if (map_optimization) then
|
|
if (temp_width>1) then
|
|
buf[#buf + 1] = "item_image_button[".. old_x*size + x_off ..",".. y*size + y_off ..";"..(size)*(temp_width-2+size_increase)..","..(size*size_increase)..";hexcol:".. hexcol_id .. ohexr .. ohexg .. ohexb ..";hexcol:".. hexcol_id .. ohexr .. ohexg .. ohexb ..";]"
|
|
temp_width = 1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
buf[#buf + 1] = "vertlabel[".. x_off-0.3 ..",".. y_off + (height*size)/2 - string.len(y_axis)/7 ..";".. y_axis .."]"
|
|
buf[#buf + 1] = "label[".. x_off + (width*size)/2 - string.len(x_axis)/15 ..",".. y_off+(height*size)+0.3 ..";".. x_axis .."]"
|
|
return buf
|
|
end
|
|
|
|
local function assemble_favorites(player,x,y,max_width,max_height)
|
|
local buf = {}
|
|
local name = player:get_player_name()
|
|
local size = 1
|
|
local j = 0
|
|
local favlist = playermodes[name].favs
|
|
if #favlist == 0 then
|
|
buf[#buf + 1] = "label["..x + max_width/2 - string.len("no favorites :c")/15 ..",".. y + max_height/2 .. ";no favorites :c]"
|
|
else
|
|
for i = #favlist, 1, -1 do
|
|
if (j/max_width >= max_height) then
|
|
break
|
|
end
|
|
buf[#buf + 1] = "item_image_button[".. x + (j%max_width)*1.1*size ..",".. y + (math.floor(j/max_width))*1.1*size ..";"..size..","..size..";"..favlist[i]..";"..favlist[i]..";]"
|
|
j = j+1
|
|
end
|
|
end
|
|
return buf
|
|
end
|
|
|
|
|
|
local function draw_trash(x,y)
|
|
return "list[detached:trash;main;"..x..".1,"..y..".1;1,1;0]"..
|
|
"image["..x..".1,"..y..".1;1,1;cdb_clear.png]"..
|
|
"tooltip["..x..".1,"..y..".1;1,1;Trash Item]"
|
|
end
|
|
|
|
local function draw_favorites(x,y)
|
|
return "list[detached:favorites;main;"..x..".1,"..y..".1;1,1;0]"..
|
|
"image["..x..".1,"..y..".1;1,1;server_favorite.png]"..
|
|
"tooltip["..x..".1,"..y..".1;1,1;Favorite Item]"
|
|
end
|
|
|
|
local function draw_clear_favorites(x,y)
|
|
return "image_button["..x..","..y..";1,1;server_favorite_delete.png;clear_favs;]"..
|
|
"tooltip["..x..".1,"..y..".1;1,1;clear favorites]"
|
|
end
|
|
|
|
local function assemble_colorspace(player)
|
|
local user = playermodes[player:get_player_name()]
|
|
if (not user) then return end
|
|
-- stuff always in formspec
|
|
user.fs = {
|
|
"formspec_version[7]",
|
|
"size[10.7,14]",
|
|
"padding[0.05, 0.05]",
|
|
"dropdown[".. dropdown_stuff[1] ..";mapping_type;" .. left_dropdown .. ";" .. user.mapping_type_index ..";true]" ,
|
|
"dropdown[".. dropdown_stuff[2] ..";color_space;rgb,hsv,hsl,Oklab;" .. user.dropdown_index ..";true]" ,
|
|
"container[1,1]"
|
|
}
|
|
local x_off,y_off = 1,0
|
|
local fs2 = {}
|
|
if (user.mapping_type_index == "1") then fs2 = assemble_map(player,x_off,y_off)
|
|
else if (user.mapping_type_index == "2") then fs2 = assemble_sliders(player,x_off,y_off,6.5,0.8)
|
|
else if (user.mapping_type_index == "3") then fs2 = assemble_favorites(player,x_off,y_off+1,6,6) end end end
|
|
TableConcat(user.fs, fs2);
|
|
user.fs[#user.fs+1] = "container_end[]"
|
|
user.fs[#user.fs+1] = "list[current_player;main;0.5,9;8,4]"
|
|
user.fs[#user.fs+1] = draw_trash(0.5,7.8)
|
|
if (favmode) then user.fs[#user.fs+1] = draw_favorites(0.5,6.7) end
|
|
user.fs[#user.fs+1] = "listring[current_player;main]"
|
|
if (user.mapping_type_index == "3") then
|
|
user.fs[#user.fs+1] = "listring[detached:favorites;main]"
|
|
user.fs[#user.fs+1] = draw_clear_favorites(0.5,5.6)
|
|
else
|
|
user.fs[#user.fs+1] = "listring[detached:trash;main]"
|
|
end
|
|
if (more_hexcol_amount > 1) then
|
|
user.fs[#user.fs+1] = "dropdown[6.5,0.3;2,0.7;hexcol_selected;".. more_hexcol_dropdown ..";".. user.hexcol_selected_index ..";true]"
|
|
end
|
|
end
|
|
|
|
local trash = minetest.create_detached_inventory("trash", {
|
|
on_put = function(inv, listname, index, stack, player)
|
|
inv:set_stack(listname, index, nil)
|
|
end,
|
|
})
|
|
trash:set_size("main", 1)
|
|
|
|
local function fav_exists(player, s)
|
|
local user = playermodes[player:get_player_name()]
|
|
for i, v in ipairs(user.favs) do
|
|
if v == s then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
local function remove_fav(player, s)
|
|
local user = playermodes[player:get_player_name()]
|
|
for i, v in ipairs(user.favs) do
|
|
if v == s then
|
|
table.remove(user.favs, i)
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
local function clear_favs(player)
|
|
playermodes[player:get_player_name()].favs = {}
|
|
player:get_meta():set_string("hexcol_color_favorites", "")
|
|
end
|
|
|
|
|
|
local favorites_list = minetest.create_detached_inventory("favorites", {
|
|
allow_put = function(inv, listname, index, stack, player)
|
|
local user = playermodes[player:get_player_name()]
|
|
if (fav_exists(player,stack:get_name())) then
|
|
remove_fav(player,stack:get_name())
|
|
else
|
|
table.insert(user.favs,stack:get_name())
|
|
end
|
|
if (user.mapping_type_index == "3") then
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
player:get_meta():set_string("hexcol_color_favorites", minetest.write_json(playermodes[player:get_player_name()].favs))
|
|
return 0
|
|
end,
|
|
})
|
|
favorites_list:set_size("main", 1)
|
|
|
|
-- helper function
|
|
function hexcol_color_picker.show_formspec(player)
|
|
local name = player:get_player_name()
|
|
local user = playermodes[name]
|
|
if (not user) then return end
|
|
if (user.mapping_type_index == "1") then
|
|
local now = os.time()
|
|
local difftime = os.difftime(now,user.LastUpdate)
|
|
if (not user.job_active) then
|
|
if (difftime > mapUpdateTimeout) then
|
|
user.job_active = true
|
|
|
|
assemble_colorspace(player);
|
|
hexcol_color_picker.send_formspec(player, table.concat(user.fs))
|
|
user.LastUpdate = now
|
|
minetest.after(mapUpdateTimeout - difftime, function ()
|
|
if (not playermodes[player:get_player_name()]) then return end
|
|
user.job_active = false
|
|
end
|
|
)
|
|
else
|
|
user.job_active = true
|
|
minetest.after(mapUpdateTimeout - difftime,
|
|
function()
|
|
if (not playermodes[player:get_player_name()]) then return end
|
|
assemble_colorspace(player)
|
|
hexcol_color_picker.send_formspec(player, table.concat(user.fs))
|
|
user.LastUpdate = os.time()
|
|
user.job_active = false
|
|
end
|
|
)
|
|
end
|
|
end
|
|
else
|
|
-- not map active
|
|
assemble_colorspace(player);
|
|
hexcol_color_picker.send_formspec(player, table.concat(user.fs))
|
|
end
|
|
|
|
end
|
|
|
|
function hexcol_color_picker.send_formspec(player, fs)
|
|
if invmode then
|
|
player:set_inventory_formspec(fs)
|
|
else
|
|
minetest.show_formspec(player:get_player_name(), "hexcol_color_picker:picker", fs)
|
|
end
|
|
end
|
|
|
|
-- register item
|
|
if (minetest.settings:get_bool("hexcol_color_picker_item") ~= false) then
|
|
minetest.register_craftitem("hexcol_color_picker:picker", {
|
|
description = "color picker",
|
|
inventory_image = "cspace.png",
|
|
on_secondary_use = function(itemstack, player, pointed_thing)
|
|
hexcol_color_picker.show_formspec(player)
|
|
end,
|
|
on_place = function(itemstack, player, pointed_thing)
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
})
|
|
end
|
|
-- register button in inventory
|
|
if unified_inventory then
|
|
unified_inventory.register_button("hexcol_color_picker:picker", {
|
|
type = "image",
|
|
image = "cspace.png",
|
|
tooltip = "Color Picker",
|
|
action = function (player)
|
|
hexcol_color_picker.show_formspec(player)
|
|
end,
|
|
hide_lite = false,
|
|
})
|
|
end
|
|
|
|
-- player does stuff in formspec
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= set_formname then return end
|
|
local user = playermodes[player:get_player_name()]
|
|
if (not user) then return end
|
|
pcall(function ()
|
|
for key,value in pairs(fields) do
|
|
-- minetest.chat_send_all(key .. ": " .. value)
|
|
if (string.sub(key,1,7) == "hexcol:") then
|
|
local inv = player:get_inventory()
|
|
inv:add_item("main",key .." 99");
|
|
end
|
|
if (string.sub(key,1,3) == "bar") then
|
|
user.bars[tonumber(string.sub(key,4,4))] = value.split(value, ":")[2]
|
|
if (value.split(value, ":")[1] == "CHG") then
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
end
|
|
end
|
|
if (fields.saturation) then
|
|
local temp = minetest.explode_scrollbar_event(fields.saturation)
|
|
if temp.type == "CHG" then
|
|
user.saturation = temp.value
|
|
if (user.dropdown_index == "1" and tonumber(user.saturation) > 15) then
|
|
user.saturation = 15;
|
|
end
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
end
|
|
if (fields.mapping_type) then
|
|
if (fields.mapping_type ~= user.mapping_type_index) then
|
|
user.mapping_type_index = fields.mapping_type
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
end
|
|
if (fields.color_space) then
|
|
if (fields.color_space ~= user.dropdown_index) then
|
|
if (user.mapping_type_index == "2") then
|
|
user.bars[1],user.bars[2],user.bars[3] = convert_inverse(user.bars,user.dropdown_index,fields.color_space)
|
|
end
|
|
user.dropdown_index = fields.color_space
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
end
|
|
if (fields.clear_favs) then
|
|
clear_favs(player)
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
if (fields.hexcol_selected) then
|
|
if (fields.hexcol_selected ~= user.hexcol_selected_index) then
|
|
user.hexcol_selected_index = fields.hexcol_selected
|
|
hexcol_color_picker.show_formspec(player)
|
|
end
|
|
end
|
|
end)
|
|
end)
|
|
|
|
minetest.register_on_mods_loaded(function()
|
|
if (hexcol) then
|
|
for key,value in pairs(hexcol.hexnodes) do
|
|
if (value == "") then value = "base" end
|
|
more_hexcol_amount = more_hexcol_amount + 1
|
|
if (more_hexcol_dropdown == "") then
|
|
more_hexcol_dropdown = value
|
|
else
|
|
more_hexcol_dropdown = more_hexcol_dropdown .. "," .. value
|
|
end
|
|
more_hexcols[more_hexcol_amount] = key;
|
|
end
|
|
if more_hexcol_amount > 1 then
|
|
dropdown_stuff = {"2,0.3;2,0.7","4.25,0.3;2,0.7"}
|
|
end
|
|
else
|
|
more_hexcols[1] = ""
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_joinplayer(function(player, last_login)
|
|
local name = player:get_player_name()
|
|
if (not playermodes[name]) then
|
|
playermodes[name] = {}
|
|
local user = playermodes[name]
|
|
user.saturation = 0;
|
|
user.mapping_type_index = "2"
|
|
user.dropdown_index = "3"
|
|
user.bars = {"0","100","50"}
|
|
user.fs = {}
|
|
user.LastUpdate = os.time()
|
|
user.job_active = false
|
|
user.hexcol_selected_index = "1"
|
|
if (favmode) then
|
|
if (player:get_meta():contains("hexcol_color_favorites"))then
|
|
user.favs = minetest.parse_json(player:get_meta():get_string("hexcol_color_favorites")) or {}
|
|
else
|
|
user.favs = {}
|
|
end
|
|
end
|
|
end
|
|
if (invmode) then
|
|
assemble_colorspace(player);
|
|
player:set_inventory_formspec(table.concat(playermodes[name].fs))
|
|
end
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player, timed_out)
|
|
local name = player:get_player_name()
|
|
if (favmode) then player:get_meta():set_string("hexcol_color_favorites", minetest.write_json(playermodes[name].favs)) end
|
|
if (playermodes[name]) then playermodes[name] = nil end
|
|
end)
|