-- Color picker logic, ported from the C callbacks that used to live in editor.c -- -- Layer 0 elements: -- 0 background -- 1 sv square (HSV rect, hue in color channel 0) -- 2 hue bar (HSV rect) -- 3 sv select outline -- 4 sv select (HSV rect) -- 5 hex string input area -- 6 hue select bar -- 7-18 saved color slots local state = { hsv = {0, 0, 0}, rgb = {0, 0, 0, 1}, saved = {}, hex_string = "#000000FF", hex_len = 8, } for i = 1, 12 do state.saved[i] = {0, 0, 0, 0} end local function update_hex_string() state.hex_string = string.format("#%02X%02X%02X%02X", math.floor(state.rgb[1]*255 + 0.5), math.floor(state.rgb[2]*255 + 0.5), math.floor(state.rgb[3]*255 + 0.5), math.floor(state.rgb[4]*255 + 0.5)) state.hex_len = 8 ui.set_string(0, 0, state.hex_string) end local function sv_pick(s, v) s = math.max(0, math.min(1, s)) v = math.max(0, math.min(1, v)) state.hsv[2] = s state.hsv[3] = v ui.set_pos(0, 4, s*130 - 2, 130 - v*130 - 2) for corner = 0, 3 do ui.set_corner_color(0, 4, corner, state.hsv[1], s, v, 1) end ui.set_pos(0, 3, s*130 - 3, 130 - v*130 - 3) state.rgb[1], state.rgb[2], state.rgb[3] = ui.hsv_to_rgb(state.hsv[1], state.hsv[2], state.hsv[3]) update_hex_string() end local function hue_set(h) h = math.max(0, math.min(1, h)) state.hsv[1] = h -- sv square and sv select keep their per-corner s/v, only hue changes for _, drawable in ipairs({1, 4}) do for corner = 0, 3 do local _, s, v, a = ui.get_corner_color(0, drawable, corner) ui.set_corner_color(0, drawable, corner, h, s, v, a) end end ui.set_pos(0, 6, 134, 2 + h*130) state.rgb[1], state.rgb[2], state.rgb[3] = ui.hsv_to_rgb(state.hsv[1], state.hsv[2], state.hsv[3]) update_hex_string() end local function hex_string_highlight(value) for corner = 0, 3 do local r, g, _, _ = ui.get_corner_color(0, 5, corner) ui.set_corner_color(0, 5, corner, r, g, value, value) end end local function set_saved(index, color) state.saved[index] = {color[1], color[2], color[3], color[4]} local element = 6 + index for corner = 0, 3 do local _, _, _, a = ui.get_corner_color(0, element, corner) ui.set_corner_color(0, element, corner, color[1], color[2], color[3], a) end end function on_button(layer, element, x, y, button, action, mods) if element == 1 then -- sv square if action == PRESS and button == MOUSE_LEFT then ui.focus(layer, element) sv_pick(x, 1 - y) elseif action == RELEASE and button == MOUSE_LEFT then ui.blur() end return true elseif element == 2 then -- hue bar if action == PRESS and button == MOUSE_LEFT then ui.focus(layer, element) hue_set(y) elseif action == RELEASE and button == MOUSE_LEFT then ui.blur() end return true elseif element == 5 then -- hex string input if action == PRESS and button == MOUSE_LEFT then ui.focus(layer, element) hex_string_highlight(1) end return true elseif element >= 7 and element <= 18 then -- saved color slots local index = element - 6 if action == PRESS then if button == MOUSE_LEFT then local saved = state.saved[index] state.rgb = {saved[1], saved[2], saved[3], saved[4]} state.hsv[1], state.hsv[2], state.hsv[3] = ui.rgb_to_hsv(state.rgb[1], state.rgb[2], state.rgb[3]) hue_set(state.hsv[1]) sv_pick(state.hsv[2], state.hsv[3]) elseif button == MOUSE_RIGHT then set_saved(index, state.rgb) elseif button == MOUSE_MIDDLE then set_saved(index, {0, 0, 0, 0}) end end return true end return false end function on_cursor(layer, element, x, y) if ui.is_focused(0, 1) then -- dragging the sv square sv_pick(x, 1 - y) return true elseif ui.is_focused(0, 2) then -- dragging the hue bar hue_set(y) return true end return false end function on_scroll(layer, element, x, y) if element == 2 then -- hue bar hue_set(state.hsv[1] + y*0.01) return true end return false end function on_key(layer, element, key, action, mods) if element ~= 5 then return false end if action == PRESS then if key == KEY_ESCAPE then state.rgb[1], state.rgb[2], state.rgb[3] = ui.hsv_to_rgb(state.hsv[1], state.hsv[2], state.hsv[3]) update_hex_string() ui.blur() elseif key == KEY_ENTER then local s = state.hex_string state.rgb[1] = (tonumber(s:sub(2, 3), 16) or 0) / 255 state.rgb[2] = (tonumber(s:sub(4, 5), 16) or 0) / 255 state.rgb[3] = (tonumber(s:sub(6, 7), 16) or 0) / 255 state.rgb[4] = (tonumber(s:sub(8, 9), 16) or 0) / 255 state.hsv[1], state.hsv[2], state.hsv[3] = ui.rgb_to_hsv(state.rgb[1], state.rgb[2], state.rgb[3]) hue_set(state.hsv[1]) sv_pick(state.hsv[2], state.hsv[3]) ui.blur() elseif key == KEY_BACKSPACE then if state.hex_len > 0 then state.hex_string = state.hex_string:sub(1, state.hex_len) state.hex_len = state.hex_len - 1 ui.set_string(0, 0, state.hex_string) end end end -- consume all keys while the hex input is focused return true end function on_text(layer, element, codepoint) if element ~= 5 then return false end if codepoint < 128 then local ch = string.char(codepoint):upper() if ch:match("[0-9A-F]") and state.hex_len < 8 then state.hex_string = state.hex_string .. ch state.hex_len = state.hex_len + 1 ui.set_string(0, 0, state.hex_string) end end return true end function on_deselect(layer, element) if element == 5 then hex_string_highlight(0) end end -- runs once at container load ui.set_string(0, 0, state.hex_string)